decl.c (6135B)
1 /* DeclTable โ C declaration semantics above the public CG API. 2 * 3 * Maps DeclId โ Decl record. Allocates a KitCgSym for any non-typedef, 4 * non-auto/register decl with linkage. 5 * 6 * Identifier *lookup* is not handled here โ that lives on the parser's 7 * scope stack so block scopes and shadowing fall out naturally. DeclTable 8 * is just the C-language layer above CG: storage class, linkage, 9 * static-locals, tentative defs, and global initializers. 10 * 11 * v1 surface is intentionally minimal: just enough for the spine corpus 12 * (functions; ints; static locals) plus the hooks DESIGN.md ยง5.3.1 13 * commits to. Tentative-definition coalescing, COMDAT, and aliases are 14 * stubs at the API edge; their full semantics arrive with the multi-TU 15 * corpus. */ 16 17 #include "decl/decl.h" 18 19 #include <string.h> 20 21 struct DeclTable { 22 Compiler* c; 23 Pool* pool; 24 KitCg* cg; 25 Decl* slots; /* index 0 reserved as DECL_NONE */ 26 u32 nslots; 27 u32 cap; 28 }; 29 30 #define DECL_INITIAL_CAP 16u 31 32 static void decls_grow(DeclTable* t, u32 want) { 33 Heap* h = kit_compiler_context(t->c)->heap; 34 u32 cap = t->cap; 35 Decl* nb; 36 if (cap >= want) return; 37 while (cap < want) cap = cap ? cap * 2u : DECL_INITIAL_CAP; 38 nb = (Decl*)h->alloc(h, sizeof(Decl) * cap, _Alignof(Decl)); 39 if (t->slots) { 40 memcpy(nb, t->slots, sizeof(Decl) * t->nslots); 41 h->free(h, t->slots, sizeof(Decl) * t->cap); 42 } 43 t->slots = nb; 44 t->cap = cap; 45 } 46 47 DeclTable* decl_new(Compiler* c, Pool* pool, KitCg* cg) { 48 Heap* h = kit_compiler_context(c)->heap; 49 DeclTable* t = 50 (DeclTable*)h->alloc(h, sizeof(DeclTable), _Alignof(DeclTable)); 51 memset(t, 0, sizeof *t); 52 t->c = c; 53 t->pool = pool; 54 t->cg = cg; 55 decls_grow(t, 1); 56 memset(&t->slots[0], 0, sizeof(Decl)); 57 t->nslots = 1; 58 return t; 59 } 60 61 void decl_free(DeclTable* t) { 62 Heap* h; 63 if (!t) return; 64 h = kit_compiler_context(t->c)->heap; 65 if (t->slots) h->free(h, t->slots, sizeof(Decl) * t->cap); 66 h->free(h, t, sizeof(*t)); 67 } 68 69 static KitCgSymbolAttrs decl_sym_attrs(const Decl* d) { 70 KitCgSymbolAttrs a; 71 memset(&a, 0, sizeof a); 72 a.bind = (d->linkage == DL_EXTERNAL) ? KIT_SB_GLOBAL : KIT_SB_LOCAL; 73 if (d->flags & DF_WEAK) a.bind = KIT_SB_WEAK; 74 a.visibility = (KitCgVisibility)d->visibility; 75 if (d->flags & DF_USED) a.flags |= KIT_CG_SYM_USED; 76 return a; 77 } 78 79 static KitCgInlinePolicy decl_inline_policy(const Decl* d) { 80 if (d->flags & DF_NOINLINE) return KIT_CG_INLINE_NEVER; 81 if (d->flags & DF_ALWAYS_INLINE) return KIT_CG_INLINE_ALWAYS; 82 if (d->flags & DF_INLINE) return KIT_CG_INLINE_HINT; 83 return KIT_CG_INLINE_DEFAULT; 84 } 85 86 /* Build the public CG declaration for an already-validated Decl and emit it. 87 * Returns the resulting KitCgSym. Emission is idempotent for a name that 88 * already has a symbol: kit_cg_decl reuses the existing symbol and only 89 * refreshes attributes (e.g. promoting a strong global to weak). */ 90 static ObjSymId decl_emit_cg_sym(DeclTable* t, const Decl* slot) { 91 KitCgDecl decl; 92 memset(&decl, 0, sizeof decl); 93 decl.kind = (slot->type && slot->type->kind == TY_FUNC) ? KIT_CG_DECL_FUNC 94 : KIT_CG_DECL_OBJECT; 95 decl.display_name = slot->name; 96 /* An asm label (`extern T f(...) __asm__("name")`) is the verbatim linker 97 * symbol name: it bypasses C name mangling, including the Mach-O leading 98 * underscore. The Darwin system headers spell the underscore themselves 99 * (e.g. realpath's `__asm("_realpath$DARWIN_EXTSN")`), so routing the label 100 * back through kit_cg_c_linkage_name would double it. Only mangle the plain 101 * source name. */ 102 decl.linkage_name = 103 slot->asm_name ? slot->asm_name : kit_cg_c_linkage_name(t->c, slot->name); 104 decl.type = type_cg_id_in_pool(t->c, t->pool, slot->type); 105 decl.sym = decl_sym_attrs(slot); 106 if (decl.kind == KIT_CG_DECL_FUNC) { 107 if (slot->flags & DF_NORETURN) decl.as.func.flags |= KIT_CG_FUNC_NORETURN; 108 decl.as.func.inline_policy = decl_inline_policy(slot); 109 decl.as.func.section = slot->section_id; 110 decl.as.func.debug_type = 111 type_cg_debug_in_pool(t->cg, t->c, t->pool, slot->type); 112 decl.as.func.wasm_import_module = slot->wasm_import_module; 113 decl.as.func.wasm_import_name = slot->wasm_import_name; 114 } else { 115 if (slot->flags & DF_THREAD) decl.as.object.flags |= KIT_CG_OBJ_TLS; 116 decl.as.object.section = slot->section_id; 117 decl.as.object.align = slot->align; 118 decl.as.object.debug_type = 119 type_cg_debug_in_pool(t->cg, t->c, t->pool, slot->type); 120 } 121 return kit_cg_decl(t->cg, decl); 122 } 123 124 DeclId decl_declare(DeclTable* t, const Decl* in) { 125 DeclId id; 126 Decl* slot; 127 decls_grow(t, t->nslots + 1); 128 id = (DeclId)t->nslots++; 129 slot = &t->slots[id]; 130 *slot = *in; 131 slot->id = id; 132 if (slot->obj_sym == OBJ_SYM_NONE && slot->name && 133 slot->storage != DS_TYPEDEF && slot->storage != DS_AUTO && 134 slot->storage != DS_REGISTER) { 135 if (slot->flags & DF_WEAK) { 136 if (slot->linkage != DL_EXTERNAL) 137 compiler_panic(t->c, slot->loc, 138 "weak attribute requires external linkage"); 139 } 140 slot->obj_sym = decl_emit_cg_sym(t, slot); 141 } 142 return id; 143 } 144 145 void decl_apply_redecl_flags(DeclTable* t, DeclId id, u32 new_flags) { 146 Decl* slot; 147 if (id == DECL_NONE || id >= t->nslots) return; 148 slot = &t->slots[id]; 149 /* C lets the `weak` attribute appear on any declaration; if a later 150 * redeclaration or the definition introduces it, the already-emitted symbol 151 * must become weak too. Other redeclaration-merge flags don't affect the 152 * emitted symbol, so weak is all we re-apply here. */ 153 if (!(new_flags & DF_WEAK) || (slot->flags & DF_WEAK)) return; 154 if (slot->linkage != DL_EXTERNAL) 155 compiler_panic(t->c, slot->loc, "weak attribute requires external linkage"); 156 slot->flags |= DF_WEAK; 157 if (slot->obj_sym != OBJ_SYM_NONE) decl_emit_cg_sym(t, slot); 158 } 159 160 const Decl* decl_get(const DeclTable* t, DeclId id) { 161 if (!t || id == DECL_NONE || id >= t->nslots) return NULL; 162 return &t->slots[id]; 163 } 164 165 ObjSymId decl_obj_sym(const DeclTable* t, DeclId id) { 166 const Decl* d = decl_get(t, id); 167 return d ? d->obj_sym : OBJ_SYM_NONE; 168 }