kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

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 }