commit 12b4f3c5b47994a7fc4a4b85d587295914c148d9 parent 396214b995f7cee9b41f1d2038dd59e79d8c1a07 Author: Ryan Sepassi <rsepassi@gmail.com> Date: Tue, 19 May 2026 17:36:18 -0700 Fix C record and array parameter lowering Diffstat:
17 files changed, 268 insertions(+), 101 deletions(-)
diff --git a/lang/c/c.c b/lang/c/c.c @@ -213,7 +213,7 @@ CfreeStatus cfree_c_compile(CfreeCompiler* c, if (!lex || !pp || cg_st != CFREE_OK || !cg) compiler_panic(c, c_no_loc(), "C compiler out of memory"); cfree_frontend_metrics_scope_begin(c, "compile.c.decl_new"); - decls = decl_new(c, cg); + decls = decl_new(c, pool, cg); cfree_frontend_metrics_scope_end(c, "compile.c.decl_new"); cfree_frontend_metrics_scope_end(c, "compile.c.setup"); diff --git a/lang/c/decl/decl.c b/lang/c/decl/decl.c @@ -22,6 +22,7 @@ struct DeclTable { Compiler* c; + Pool* pool; CfreeCg* cg; Decl* slots; /* index 0 reserved as DECL_NONE */ u32 nslots; @@ -45,12 +46,13 @@ static void decls_grow(DeclTable* t, u32 want) { t->cap = cap; } -DeclTable* decl_new(Compiler* c, CfreeCg* cg) { +DeclTable* decl_new(Compiler* c, Pool* pool, CfreeCg* cg) { Heap* h = cfree_compiler_context(c)->heap; DeclTable* t = (DeclTable*)h->alloc(h, sizeof(DeclTable), _Alignof(DeclTable)); memset(t, 0, sizeof *t); t->c = c; + t->pool = pool; t->cg = cg; decls_grow(t, 1); memset(&t->slots[0], 0, sizeof(Decl)); @@ -99,7 +101,7 @@ DeclId decl_declare(DeclTable* t, const Decl* in) { : CFREE_CG_DECL_OBJECT; decl.display_name = slot->name; decl.linkage_name = cfree_cg_c_linkage_name(t->c, slot->name); - decl.type = pcg_tid(t->c, slot->type); + decl.type = type_cg_id_in_pool(t->c, t->pool, slot->type); decl.sym = decl_sym_attrs(slot); if (decl.kind == CFREE_CG_DECL_FUNC) { if (slot->flags & DF_NORETURN) diff --git a/lang/c/decl/decl.h b/lang/c/decl/decl.h @@ -86,7 +86,7 @@ typedef struct Decl { Sym alias_target; /* target name for __attribute__((alias("..."))); 0=none */ } Decl; -DeclTable* decl_new(Compiler*, CfreeCg*); +DeclTable* decl_new(Compiler*, Pool*, CfreeCg*); void decl_free(DeclTable*); DeclId decl_declare(DeclTable*, const Decl*); diff --git a/lang/c/parse/cg_adapter.c b/lang/c/parse/cg_adapter.c @@ -2,14 +2,16 @@ #include "parse/parse_priv.h" -CfreeCgTypeId pcg_tid(Compiler* c, const Type* ty) { return type_cg_id(c, ty); } +CfreeCgTypeId pcg_tid(Parser* p, const Type* ty) { + return type_cg_id_in_pool(p->c, p->pool, ty); +} static u32 pcg_sizeof(Parser* p, const Type* ty) { - return (u32)cfree_cg_type_size(p->c, pcg_tid(p->c, ty)); + return (u32)cfree_cg_type_size(p->c, pcg_tid(p, ty)); } static u32 pcg_alignof(Parser* p, const Type* ty) { - return (u32)cfree_cg_type_align(p->c, pcg_tid(p->c, ty)); + return (u32)cfree_cg_type_align(p->c, pcg_tid(p, ty)); } #define PCG_VALUE_LVALUE 1u @@ -30,7 +32,7 @@ static u8 pcg_lvalue_flags_for_type(const Type* ty) { CfreeCgMemAccess pcg_mem(Parser* p, const Type* ty) { CfreeCgMemAccess m; memset(&m, 0, sizeof m); - m.type = pcg_tid(p->c, ty); + m.type = pcg_tid(p, ty); m.align = pcg_alignof(p, ty); if (ty && (ty->qual & Q_VOLATILE)) m.flags |= CFREE_CG_MEM_VOLATILE; return m; @@ -318,7 +320,7 @@ FrameSlot pcg_local(Parser* p, const FrameSlotDesc* fsd) { attrs.name = fsd->name; attrs.align = fsd->align; if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_LOCAL_ADDRESS_TAKEN; - return cfree_cg_local(p->cg, pcg_tid(p->c, fsd->type), attrs); + return cfree_cg_local(p->cg, pcg_tid(p, fsd->type), attrs); } FrameSlot pcg_param_slot(Parser* p, u32 index, const FrameSlotDesc* fsd) { @@ -327,7 +329,7 @@ FrameSlot pcg_param_slot(Parser* p, u32 index, const FrameSlotDesc* fsd) { attrs.name = fsd->name; attrs.align = fsd->align; if (fsd->flags & FSF_ADDR_TAKEN) attrs.flags |= CFREE_CG_LOCAL_ADDRESS_TAKEN; - return cfree_cg_param(p->cg, index, pcg_tid(p->c, fsd->type), attrs); + return cfree_cg_param(p->cg, index, pcg_tid(p, fsd->type), attrs); } void pcg_param(Parser* p, const CGParamDesc* pd) { @@ -341,7 +343,7 @@ void pcg_func_begin(Parser* p, const CGFuncDesc* fd) { void pcg_push_int(Parser* p, i64 v, const Type* ty) { if (pcg_emit_enabled(p)) { - cfree_cg_push_int(p->cg, (uint64_t)v, pcg_tid(p->c, ty)); + cfree_cg_push_int(p->cg, (uint64_t)v, pcg_tid(p, ty)); } pcg_push_type(p, ty); if (v == 0 && p->cg_type_sp) { @@ -350,7 +352,7 @@ void pcg_push_int(Parser* p, i64 v, const Type* ty) { } void pcg_push_float(Parser* p, double v, const Type* ty) { - if (pcg_emit_enabled(p)) cfree_cg_push_float(p->cg, v, pcg_tid(p->c, ty)); + if (pcg_emit_enabled(p)) cfree_cg_push_float(p->cg, v, pcg_tid(p, ty)); pcg_push_type(p, ty); } @@ -450,7 +452,7 @@ void pcg_convert(Parser* p, const Type* dst) { int di = type_is_int(dst) || type_is_ptr(dst); int sf = pcg_type_is_fp(src); int df = pcg_type_is_fp(dst); - CfreeCgTypeId id = pcg_tid(p->c, dst); + CfreeCgTypeId id = pcg_tid(p, dst); int emit = pcg_emit_enabled(p); if (src == dst) return; if (type_is_ptr(src) && type_is_ptr(dst)) { @@ -493,14 +495,14 @@ void pcg_convert(Parser* p, const Type* dst) { void pcg_inc_dec(Parser* p, BinOp op, int post) { const Type* ty = pcg_top_type(p); if (pcg_emit_enabled(p)) { - cfree_cg_inc_dec(p->cg, pcg_int_binop(op), post, pcg_tid(p->c, ty), + cfree_cg_inc_dec(p->cg, pcg_int_binop(op), post, pcg_tid(p, ty), pcg_mem(p, ty)); } } void pcg_call(Parser* p, u32 nargs, const Type* fn_type) { if (pcg_emit_enabled(p)) { - cfree_cg_call_default(p->cg, nargs, pcg_tid(p->c, fn_type)); + cfree_cg_call_default(p->cg, nargs, pcg_tid(p, fn_type)); } for (u32 i = 0; i < nargs + 1u; ++i) pcg_drop_type(p); if (fn_type && fn_type->kind == TY_FUNC && fn_type->fn.ret->kind != TY_VOID) { @@ -533,14 +535,14 @@ void pcg_ret(Parser* p, int has_value) { void pcg_alloca(Parser* p) { if (pcg_emit_enabled(p)) { cfree_cg_alloca(p->cg, 16, - pcg_tid(p->c, type_ptr(p->pool, type_void(p->pool)))); + pcg_tid(p, type_ptr(p->pool, type_void(p->pool)))); } pcg_drop_type(p); pcg_push_type(p, type_ptr(p->pool, type_void(p->pool))); } void pcg_va_arg(Parser* p, const Type* ty) { - if (pcg_emit_enabled(p)) cfree_cg_vararg_next(p->cg, pcg_tid(p->c, ty)); + if (pcg_emit_enabled(p)) cfree_cg_vararg_next(p->cg, pcg_tid(p, ty)); pcg_drop_type(p); pcg_push_type(p, ty); } @@ -598,7 +600,7 @@ void pcg_intrinsic_unary_to_int(Parser* p, IntrinKind k) { : CFREE_CG_INTRIN_POPCOUNT; const Type* ity = type_prim(p->pool, TY_INT); if (pcg_emit_enabled(p)) { - cfree_cg_intrinsic(p->cg, ck, 1, pcg_tid(p->c, ity)); + cfree_cg_intrinsic(p->cg, ck, 1, pcg_tid(p, ity)); } pcg_retag_top(p, ity); } @@ -627,7 +629,7 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, for (u32 i = 0; i < nout; ++i) { o[i].constraint = cfree_sym_intern(p->c, outs[i].str ? outs[i].str : ""); o[i].name = outs[i].name; - o[i].type = pcg_tid(p->c, outs[i].type); + o[i].type = pcg_tid(p, outs[i].type); o[i].dir = CFREE_CG_ASM_OUT; } } @@ -636,7 +638,7 @@ void pcg_inline_asm(Parser* p, const char* tmpl, const AsmConstraint* outs, for (u32 i = 0; i < nin; ++i) { in[i].constraint = cfree_sym_intern(p->c, ins[i].str ? ins[i].str : ""); in[i].name = ins[i].name; - in[i].type = pcg_tid(p->c, ins[i].type); + in[i].type = pcg_tid(p, ins[i].type); in[i].dir = (ins[i].dir == ASM_INOUT) ? CFREE_CG_ASM_INOUT : CFREE_CG_ASM_IN; } diff --git a/lang/c/parse/cg_public_compat.h b/lang/c/parse/cg_public_compat.h @@ -167,7 +167,7 @@ typedef struct CGFuncDesc { typedef struct Parser Parser; -CfreeCgTypeId pcg_tid(Compiler*, const Type*); +CfreeCgTypeId pcg_tid(Parser*, const Type*); CfreeCgMemAccess pcg_mem(Parser*, const Type*); const Type* pcg_top_type(Parser*); const Type* pcg_top2_type(Parser*); diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -419,7 +419,7 @@ u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { CfreeCgSym emit_string_to_rodata(Parser* p, const u8* bytes, size_t n) { const Type* arr_ty = type_array(p->pool, type_prim(p->pool, TY_CHAR), (u32)n, 0); - return cfree_cg_const_data(p->cg, bytes, n, 1u, pcg_tid(p->c, arr_ty)); + return cfree_cg_const_data(p->cg, bytes, n, 1u, pcg_tid(p, arr_ty)); } CfreeCgSym emit_string_literal_to_rodata(Parser* p, const u8* bytes, @@ -429,7 +429,7 @@ CfreeCgSym emit_string_literal_to_rodata(Parser* p, const u8* bytes, u32 count = elem_size ? (u32)(nbytes / elem_size) : 0; const Type* arr_ty = type_array(p->pool, elem_ty, count, 0); return cfree_cg_const_data(p->cg, bytes, nbytes, c_abi_alignof(p->abi, elem_ty), - pcg_tid(p->c, arr_ty)); + pcg_tid(p, arr_ty)); } /* ============================================================ @@ -1018,7 +1018,7 @@ i64 eval_const_int(Parser* p, SrcLoc loc) { static void decay_array_to_pointer(Parser* p, const Type* arr_ty) { const Type* ptr_ty = type_ptr(p->pool, arr_ty->arr.elem); - if (pcg_emit_enabled(p)) cfree_cg_addr_offset(p->cg, 0, pcg_tid(p->c, ptr_ty)); + if (pcg_emit_enabled(p)) cfree_cg_addr_offset(p->cg, 0, pcg_tid(p, ptr_ty)); pcg_retag_top(p, ptr_ty); } @@ -1120,7 +1120,7 @@ static CfreeCgSym builtin_libcall_sym(Parser* p, const char* name, decl.kind = CFREE_CG_DECL_FUNC; decl.display_name = source_name; decl.linkage_name = cfree_cg_c_linkage_name(p->c, source_name); - decl.type = pcg_tid(p->c, fn_ty); + decl.type = pcg_tid(p, fn_ty); decl.sym.bind = CFREE_SB_GLOBAL; decl.sym.visibility = CFREE_CG_VIS_DEFAULT; return cfree_cg_decl(p->cg, decl); @@ -1375,7 +1375,7 @@ static int parse_builtin_overflow_call(Parser* p, Sym name, SrcLoc loc) { cg_set_loc(p->cg, loc); if (pcg_emit_enabled(p)) { - cfree_cg_intrinsic(p->cg, info.intrin, 2, pcg_tid(p->c, op_ty)); + cfree_cg_intrinsic(p->cg, info.intrin, 2, pcg_tid(p, op_ty)); } pcg_drop_type(p); pcg_drop_type(p); @@ -2017,26 +2017,20 @@ static void parse_postfix(Parser* p) { } if (!elem) perr(p, "subscript on incomplete pointee"); { - FrameSlot vla_size_slot = vla_size_slot_for_type(vla_bounds, elem); - if (vla_size_slot != FRAME_SLOT_NONE) { - cg_push_local_typed(p->cg, vla_size_slot, ty_size_t(p)); - cg_load(p->cg); - cg_binop(p->cg, BO_IMUL); - } else { - u32 esz = c_abi_sizeof(p->abi, elem); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } - } - } - cg_binop(p->cg, BO_IADD); - cg_deref(p->cg, elem); - { FrameSlot elem_vla_slot = vla_size_slot_for_type(vla_bounds, elem); if (elem_vla_slot != FRAME_SLOT_NONE) { + cg_push_local_typed(p->cg, elem_vla_slot, ty_size_t(p)); + cg_load(p->cg); + cg_binop(p->cg, BO_IMUL); + cg_binop(p->cg, BO_IADD); + cg_deref(p->cg, elem); p->last_pushed_vla_slot = elem_vla_slot; p->last_pushed_vla_bounds = vla_bounds; + } else { + if (pcg_emit_enabled(p)) cfree_cg_index(p->cg, 0); + pcg_drop_type(p); + pcg_retag_top(p, elem); + pcg_set_top_lvalue(p); } } } diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -70,7 +70,7 @@ void push_subobject_lv(Parser* p, FrameSlot slot, const Type* arr_ty, const Type* elem_ptr_ty = type_ptr(p->pool, elem_ty); cg_push_local_typed(p->cg, slot, arr_ty); if (pcg_emit_enabled(p)) { - cfree_cg_addr_offset(p->cg, (i64)offset, pcg_tid(p->c, elem_ptr_ty)); + cfree_cg_addr_offset(p->cg, (i64)offset, pcg_tid(p, elem_ptr_ty)); } pcg_retag_top(p, elem_ptr_ty); cg_deref(p->cg, elem_ty); @@ -96,7 +96,7 @@ static void emit_copy_leaf(Parser* p, FrameSlot dst_slot, cg_push_local_typed(p->cg, src_ptr_slot, src_ptr_ty); cg_load(p->cg); if (pcg_emit_enabled(p)) { - cfree_cg_addr_offset(p->cg, (i64)src_off, pcg_tid(p->c, leaf_ptr_ty)); + cfree_cg_addr_offset(p->cg, (i64)src_off, pcg_tid(p, leaf_ptr_ty)); } pcg_retag_top(p, leaf_ptr_ty); cg_deref(p->cg, leaf_ty); diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -1233,6 +1233,17 @@ static void parse_param_array_bound(Parser* p, DeclSuffix* out) { if (ntoks == 1 && toks[0].kind == TOK_PUNCT && toks[0].v.punct == '*') { has_expr = 0; } + if (ntoks == 1 && toks[0].kind == TOK_NUM) { + i64 count = parse_int_literal(p, &toks[0]); + if (count <= 0 || (u64)count > UINT32_MAX) { + perr(p, "array bound must be positive"); + } + out->count = (u32)count; + out->incomplete = 0; + out->vla = 0; + expect_punct(p, ']', "']' after array size"); + return; + } param_vla_record_bound(p, toks, ntoks, has_expr); expect_punct(p, ']', "']' after array size"); } diff --git a/lang/c/type/type.c b/lang/c/type/type.c @@ -29,11 +29,21 @@ struct TypeListNode { Type ty; }; +typedef struct CgRecordMemo CgRecordMemo; +struct CgRecordMemo { + CgRecordMemo* next; + const CfreeCompiler* compiler; + const Type* type; + CfreeCgTypeId id; +}; + typedef struct PoolTypeCache { /* Direct slots for void + primitive kinds (TY_VOID..TY_LDOUBLE). */ const Type* prim[NUM_PRIM_KINDS]; /* Linked list of every other type allocated through this pool. */ TypeListNode* derived; + /* Completed record layout ids are compiler-local. */ + CgRecordMemo* cg_record_memos; /* Tag id allocator (1-based; TAG_NONE = 0). */ u32 next_tag; } PoolTypeCache; @@ -504,92 +514,161 @@ static CfreeCgTypeId type_cg_builtin(CfreeCompiler* c, TypeKind kind) { return CFREE_CG_TYPE_NONE; } -static CfreeCgTypeId type_cg_id_walk(CfreeCompiler* c, Pool* p, const Type* t, - const Type* pending_record) { +static int same_record_type(const Type* a, const Type* b) { + if (a == b) return 1; + if (!a || !b) return 0; + if (a->kind != b->kind) return 0; + if (a->kind != TY_STRUCT && a->kind != TY_UNION) return 0; + return a->rec.tag_id != TAG_NONE && a->rec.tag_id == b->rec.tag_id; +} + +typedef enum TypeCgMode { + TYPE_CG_VALUE, + TYPE_CG_RECORD_FIELD, +} TypeCgMode; + +typedef struct TypeCgLower { + CfreeCompiler* c; + Pool* p; + PoolTypeCache* cache; +} TypeCgLower; + +static CfreeCgTypeId type_cg_lower(TypeCgLower* l, const Type* t, + TypeCgMode mode); + +static CfreeCgTypeId type_cg_record_memo_get(PoolTypeCache* cache, + CfreeCompiler* c, const Type* t) { + if (!cache) return CFREE_CG_TYPE_NONE; + for (CgRecordMemo* m = cache->cg_record_memos; m; m = m->next) { + if (m->compiler == c && (m->type == t || same_record_type(m->type, t))) { + return m->id; + } + } + return CFREE_CG_TYPE_NONE; +} + +static void type_cg_record_memo_put(Pool* p, PoolTypeCache* cache, + CfreeCompiler* c, const Type* t, + CfreeCgTypeId id) { + CgRecordMemo* m; + if (!p || !cache || !c || !t || id == CFREE_CG_TYPE_NONE) return; + if (t->kind != TY_STRUCT && t->kind != TY_UNION) return; + if (t->rec.incomplete) return; + for (m = cache->cg_record_memos; m; m = m->next) { + if (m->compiler == c && (m->type == t || same_record_type(m->type, t))) { + m->id = id; + return; + } + } + m = arena_new(p->arena, CgRecordMemo); + if (!m) return; + m->compiler = c; + m->type = t; + m->id = id; + m->next = cache->cg_record_memos; + cache->cg_record_memos = m; +} + +static CfreeCgTypeId type_cg_record_layout(TypeCgLower* l, const Type* t) { + CfreeCgField* fields = NULL; + CfreeCgRecordDesc desc; CfreeCgTypeId id; - if (!c || !t) return CFREE_CG_TYPE_NONE; - id = type_cg_builtin(c, (TypeKind)t->kind); + if (!l || !t || (t->kind != TY_STRUCT && t->kind != TY_UNION)) { + return CFREE_CG_TYPE_NONE; + } + if (t->rec.incomplete) return type_cg_builtin(l->c, TY_VOID); + id = type_cg_record_memo_get(l->cache, l->c, t); + if (id != CFREE_CG_TYPE_NONE) return id; + if (t->rec.nfields) { + fields = arena_zarray(l->p->arena, CfreeCgField, t->rec.nfields); + if (!fields) return CFREE_CG_TYPE_NONE; + for (u32 i = 0; i < t->rec.nfields; ++i) { + fields[i].name = t->rec.fields[i].name; + fields[i].type = + type_cg_lower(l, t->rec.fields[i].type, TYPE_CG_RECORD_FIELD); + fields[i].align_override = t->rec.fields[i].align_override; + if (t->rec.fields[i].flags & FIELD_BITFIELD) { + fields[i].flags |= CFREE_CG_FIELD_BITFIELD; + fields[i].bit_width = t->rec.fields[i].bitfield_width; + fields[i].bit_signed = + type_is_signed_integer_for_cg(t->rec.fields[i].type); + if (t->rec.fields[i].flags & FIELD_ZERO_WIDTH) { + fields[i].flags |= CFREE_CG_FIELD_ZERO_WIDTH; + } + } + if (t->rec.fields[i].packed && fields[i].align_override == 0) { + fields[i].align_override = 1; + } + if (t->rec.packed && fields[i].align_override == 0) { + fields[i].align_override = 1; + } + } + } + memset(&desc, 0, sizeof desc); + desc.tag = t->rec.tag; + desc.fields = fields; + desc.nfields = t->rec.nfields; + desc.is_union = t->kind == TY_UNION; + desc.align_override = t->rec.align_override; + id = cfree_cg_type_record_ex(l->c, &desc); + type_cg_record_memo_put(l->p, l->cache, l->c, t, id); + return id; +} + +static CfreeCgTypeId type_cg_lower(TypeCgLower* l, const Type* t, + TypeCgMode mode) { + CfreeCgTypeId id; + if (!l || !t) return CFREE_CG_TYPE_NONE; + id = type_cg_builtin(l->c, (TypeKind)t->kind); if (id != CFREE_CG_TYPE_NONE) return id; switch ((TypeKind)t->kind) { - case TY_PTR: { - const Type* pointee = t->ptr.pointee; - if (pointee == pending_record) { - pointee = type_void(p); + case TY_PTR: + if (mode == TYPE_CG_RECORD_FIELD) { + return cfree_cg_type_ptr(l->c, type_cg_builtin(l->c, TY_VOID), 0); } return cfree_cg_type_ptr( - c, type_cg_id_walk(c, p, pointee, pending_record), 0); - } + l->c, type_cg_lower(l, t->ptr.pointee, TYPE_CG_VALUE), 0); case TY_ARRAY: - return cfree_cg_type_array( - c, type_cg_id_walk(c, p, t->arr.elem, pending_record), t->arr.count); + return cfree_cg_type_array(l->c, type_cg_lower(l, t->arr.elem, mode), + t->arr.count); case TY_FUNC: { CfreeCgFuncParam* params = NULL; CfreeCgFuncSig sig; memset(&sig, 0, sizeof sig); - sig.ret = type_cg_id_walk(c, p, t->fn.ret, pending_record); + sig.ret = type_cg_lower(l, t->fn.ret, TYPE_CG_VALUE); sig.nparams = t->fn.nparams; sig.abi_variadic = t->fn.variadic; sig.call_conv = CFREE_CG_CC_TARGET_C; if (t->fn.nparams) { - params = arena_zarray(p->arena, CfreeCgFuncParam, t->fn.nparams); + params = arena_zarray(l->p->arena, CfreeCgFuncParam, t->fn.nparams); + if (!params) return CFREE_CG_TYPE_NONE; for (u32 i = 0; i < t->fn.nparams; ++i) { params[i].type = - type_cg_id_walk(c, p, t->fn.params[i], pending_record); + type_cg_lower(l, t->fn.params[i], TYPE_CG_RECORD_FIELD); } } sig.params = params; - return cfree_cg_type_func(c, sig); + return cfree_cg_type_func(l->c, sig); } case TY_STRUCT: - case TY_UNION: { - CfreeCgField* fields = NULL; - CfreeCgRecordDesc desc; - if (t->rec.nfields) { - fields = arena_zarray(p->arena, CfreeCgField, t->rec.nfields); - for (u32 i = 0; i < t->rec.nfields; ++i) { - fields[i].name = t->rec.fields[i].name; - fields[i].type = type_cg_id_walk(c, p, t->rec.fields[i].type, t); - fields[i].align_override = t->rec.fields[i].align_override; - if (t->rec.fields[i].flags & FIELD_BITFIELD) { - fields[i].flags |= CFREE_CG_FIELD_BITFIELD; - fields[i].bit_width = t->rec.fields[i].bitfield_width; - fields[i].bit_signed = - type_is_signed_integer_for_cg(t->rec.fields[i].type); - if (t->rec.fields[i].flags & FIELD_ZERO_WIDTH) { - fields[i].flags |= CFREE_CG_FIELD_ZERO_WIDTH; - } - } - if (t->rec.fields[i].packed && fields[i].align_override == 0) { - fields[i].align_override = 1; - } - if (t->rec.packed && fields[i].align_override == 0) { - fields[i].align_override = 1; - } - } - } - memset(&desc, 0, sizeof desc); - desc.tag = t->rec.tag; - desc.fields = fields; - desc.nfields = t->rec.nfields; - desc.is_union = t->kind == TY_UNION; - desc.align_override = t->rec.align_override; - return cfree_cg_type_record_ex(c, &desc); - } + case TY_UNION: + return type_cg_record_layout(l, t); case TY_ENUM: - return cfree_cg_type_enum( - c, t->enm.tag, type_cg_id_walk(c, p, t->enm.base, pending_record), - NULL, 0); + return cfree_cg_type_enum(l->c, t->enm.tag, + type_cg_lower(l, t->enm.base, mode), NULL, 0); default: - if (id != CFREE_CG_TYPE_NONE) { - return cfree_cg_type_alias(c, 0, id); - } return CFREE_CG_TYPE_NONE; } } CfreeCgTypeId type_cg_id_in_pool(CfreeCompiler* c, Pool* p, const Type* t) { + TypeCgLower l; if (!p) return CFREE_CG_TYPE_NONE; - return type_cg_id_walk(c, p, t, NULL); + memset(&l, 0, sizeof l); + l.c = c; + l.p = p; + l.cache = cache_get(p); + return type_cg_lower(&l, t, TYPE_CG_VALUE); } CfreeCgTypeId type_cg_id(CfreeCompiler* c, const Type* t) { diff --git a/test/parse/cases/6_5_02_array_param_2d_subscript_store.c b/test/parse/cases/6_5_02_array_param_2d_subscript_store.c @@ -0,0 +1,11 @@ +typedef unsigned char U8; + +static void set_component(U8 pixels[2][4], int row, int component, U8 value) { + pixels[row][component] = value; +} + +int test_main(void) { + U8 pixels[2][4] = {{0}}; + set_component(pixels, 1, 2, 7); + return pixels[1][2]; +} diff --git a/test/parse/cases/6_5_02_array_param_2d_subscript_store.expected b/test/parse/cases/6_5_02_array_param_2d_subscript_store.expected @@ -0,0 +1 @@ +7 diff --git a/test/parse/cases/6_7_2_1_06_mutual_struct_ptr.c b/test/parse/cases/6_7_2_1_06_mutual_struct_ptr.c @@ -0,0 +1,21 @@ +/* Mutually recursive structs through pointers: A holds B*, B holds A*. + * Walking either type for CG-id construction needs cycle-breaking that + * tracks every record currently being walked (not just the immediate + * one), otherwise the walk infinite-recurses A→B*→A→B*... and stack- + * overflows. */ +struct A; +struct B; +struct A { + int x; + struct B *b; +}; +struct B { + int y; + struct A *a; +}; +int test_main(void) { + struct B b = {30, 0}; + struct A a = {12, &b}; + b.a = &a; + return b.a->x + a.b->y; +} diff --git a/test/parse/cases/6_7_2_1_06_mutual_struct_ptr.expected b/test/parse/cases/6_7_2_1_06_mutual_struct_ptr.expected @@ -0,0 +1 @@ +42 diff --git a/test/parse/cases/6_7_2_1_12_mutual_record_pointers.c b/test/parse/cases/6_7_2_1_12_mutual_record_pointers.c @@ -0,0 +1,12 @@ +struct A { + struct B *b; +}; + +struct B { + struct A *a; +}; + +int test_main(void) { + struct A a; + return sizeof(a) == sizeof(void *) ? 0 : 1; +} diff --git a/test/parse/cases/6_7_2_1_13_forward_record_ptr_before_offsetof.c b/test/parse/cases/6_7_2_1_13_forward_record_ptr_before_offsetof.c @@ -0,0 +1,17 @@ +struct B; + +struct A { + struct B *b; +}; + +int f(struct A a) { + return a.b != 0; +} + +struct B { + int x; +}; + +int test_main(void) { + return (int)__builtin_offsetof(struct B, x); +} diff --git a/test/parse/cases/6_7_2_1_14_record_pointer_field_access.c b/test/parse/cases/6_7_2_1_14_record_pointer_field_access.c @@ -0,0 +1,15 @@ +struct B { + int x; +}; + +struct A { + struct B *b; +}; + +int test_main(void) { + struct B b; + struct A a; + b.x = 42; + a.b = &b; + return a.b->x; +} diff --git a/test/parse/cases/6_7_2_1_14_record_pointer_field_access.expected b/test/parse/cases/6_7_2_1_14_record_pointer_field_access.expected @@ -0,0 +1 @@ +42