kit

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

parse.c (71321B)


      1 /* parse.c — residual C11 parser core.
      2  *
      3  * Contains:
      4  *   - kw_names[] table (used by parse_c to intern keywords)
      5  *   - Diagnostics/token helpers (perr, advance, peek1, fetch_tok, ...)
      6  *   - Scope/tag operations
      7  *   - Type helpers (ty_int, ty_size_t)
      8  *   - Local-variable slot allocation (make_local, make_local_aligned)
      9  *   - Static-local symbol naming (mint_static_local_sym)
     10  *   - Declaration driver (parse_init_declarator, parse_local_decl)
     11  *   - TU-level driver (parse_param_list, declare_function,
     12  *     parse_function_body, parse_external_decl, parse_translation_unit,
     13  *     parse_c)
     14  *
     15  * All expression, type, initializer, and statement code lives in
     16  * parse_expr.c, parse_type.c, parse_init.c, and parse_stmt.c. */
     17 
     18 #include <stdarg.h>
     19 #include <string.h>
     20 
     21 #include "parse/parse_priv.h"
     22 
     23 /* ============================================================
     24  * Keywords
     25  * ============================================================ */
     26 
     27 static const char* const kw_names[KW_COUNT] = {
     28     NULL,
     29     "auto",
     30     "break",
     31     "case",
     32     "char",
     33     "const",
     34     "continue",
     35     "default",
     36     "do",
     37     "double",
     38     "else",
     39     "enum",
     40     "extern",
     41     "float",
     42     "_Float16",
     43     "for",
     44     "goto",
     45     "if",
     46     "inline",
     47     "int",
     48     "long",
     49     "register",
     50     "restrict",
     51     "return",
     52     "short",
     53     "signed",
     54     "sizeof",
     55     "static",
     56     "struct",
     57     "switch",
     58     "typedef",
     59     "union",
     60     "unsigned",
     61     "void",
     62     "volatile",
     63     "while",
     64     "_Bool",
     65     "_Complex",
     66     "_Imaginary",
     67     "_Alignas",
     68     "_Alignof",
     69     "_Atomic",
     70     "_Generic",
     71     "_Noreturn",
     72     "_Static_assert",
     73     "_Thread_local",
     74     "asm",
     75     "__asm__",
     76 };
     77 
     78 /* ============================================================
     79  * Diagnostics
     80  * ============================================================ */
     81 
     82 static SrcLoc tok_loc(Parser* p, const Tok* t) {
     83   return pp_materialize_loc(p->pp, t->loc);
     84 }
     85 
     86 _Noreturn void perr(Parser* p, const char* fmt, ...) {
     87   va_list ap;
     88   SrcLoc loc = tok_loc(p, &p->cur);
     89   va_start(ap, fmt);
     90   compiler_panicv(p->c, loc, fmt, ap);
     91 }
     92 
     93 void reject_general_regs_only_fp(Parser* p, const char* what) {
     94   if (!p->general_regs_only) return;
     95   perr(p, "-mgeneral-regs-only rejects %.*s",
     96        KIT_SLICE_ARG(kit_slice_cstr(what)));
     97 }
     98 
     99 /* ============================================================
    100  * Token helpers
    101  * ============================================================ */
    102 
    103 /* Width of an encoding prefix on a string-literal spelling: 0 for ordinary,
    104  * 1 for L/u/U, 2 for u8. */
    105 static size_t str_prefix_len(u16 flags) {
    106   if (flags & TF_STR_U8) return 2;
    107   if (flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) return 1;
    108   return 0;
    109 }
    110 
    111 #define STR_ENC_MASK (TF_STR_WIDE | TF_STR_U8 | TF_STR_U16 | TF_STR_U32)
    112 
    113 /* Fuse two adjacent TOK_STR tokens into one per C11 §6.4.5 ¶5. */
    114 static Tok fuse_string_lits(Parser* p, Tok a, Tok b) {
    115   u16 ae = (u16)(a.flags & STR_ENC_MASK);
    116   u16 be = (u16)(b.flags & STR_ENC_MASK);
    117   u16 fused_enc;
    118   KitSlice a_sl = pp_text_slice(p->pp, &a);
    119   KitSlice b_sl = pp_text_slice(p->pp, &b);
    120   size_t alen = a_sl.len, blen = b_sl.len;
    121   const char* as = a_sl.s;
    122   const char* bs = b_sl.s;
    123   size_t apfx, bpfx;
    124   size_t a_content_len, b_content_len;
    125   size_t out_pfx_len;
    126   size_t out_len;
    127   Heap* h = kit_compiler_context(p->c)->heap;
    128   char* buf;
    129   size_t k = 0;
    130   Tok out;
    131   if (!as || !bs) perr(p, "bad string literal in concatenation");
    132   if (ae != 0 && be != 0 && ae != be) {
    133     perr(p,
    134          "concatenating string literals with incompatible "
    135          "encoding prefixes");
    136   }
    137   fused_enc = ae ? ae : be;
    138   apfx = str_prefix_len(a.flags);
    139   bpfx = str_prefix_len(b.flags);
    140   if (alen < apfx + 2 || as[apfx] != '"' || as[alen - 1] != '"' ||
    141       blen < bpfx + 2 || bs[bpfx] != '"' || bs[blen - 1] != '"') {
    142     perr(p, "malformed string literal in concatenation");
    143   }
    144   a_content_len = alen - apfx - 2;
    145   b_content_len = blen - bpfx - 2;
    146   out_pfx_len = ae ? apfx : bpfx;
    147   out_len = out_pfx_len + 1 + a_content_len + b_content_len + 1;
    148   buf = (char*)h->alloc(h, out_len, 1);
    149   if (!buf) perr(p, "out of memory fusing string literals");
    150   if (out_pfx_len) {
    151     const char* src = ae ? as : bs;
    152     memcpy(buf + k, src, out_pfx_len);
    153     k += out_pfx_len;
    154   }
    155   buf[k++] = '"';
    156   if (a_content_len) {
    157     memcpy(buf + k, as + apfx + 1, a_content_len);
    158     k += a_content_len;
    159   }
    160   if (b_content_len) {
    161     memcpy(buf + k, bs + bpfx + 1, b_content_len);
    162     k += b_content_len;
    163   }
    164   buf[k++] = '"';
    165   out = a;
    166   out.text =
    167       text_sym_ref(kit_sym_intern(p->pool->c, (KitSlice){.s = buf, .len = k}));
    168   out.flags = (u16)((a.flags & ~STR_ENC_MASK) | fused_enc);
    169   h->free(h, buf, 0);
    170   return out;
    171 }
    172 
    173 /* Pull one logical token from pp, collapsing adjacent TOK_STR runs. */
    174 static Tok fetch_tok(Parser* p) {
    175   Tok t;
    176   if (p->has_pending) {
    177     t = p->pending;
    178     p->has_pending = 0;
    179   } else {
    180     pp_next_parse(p->pp, &t);
    181   }
    182   if (t.kind != TOK_STR) return t;
    183   for (;;) {
    184     Tok n;
    185     pp_next_parse(p->pp, &n);
    186     if (n.kind != TOK_STR) {
    187       p->pending = n;
    188       p->has_pending = 1;
    189       return t;
    190     }
    191     t = fuse_string_lits(p, t, n);
    192   }
    193 }
    194 
    195 void advance(Parser* p) {
    196   if (p->replay_active) {
    197     if (p->replay_pos < p->replay_len) {
    198       p->cur = p->replay[p->replay_pos++];
    199       return;
    200     }
    201     p->replay_active = 0;
    202   }
    203   if (p->function_replay_active) {
    204     if (p->function_replay_pos < p->function_replay_len) {
    205       p->cur = p->function_replay[p->function_replay_pos++];
    206       return;
    207     }
    208     p->function_replay_active = 0;
    209     if (p->function_replay_hold) {
    210       memset(&p->cur, 0, sizeof p->cur);
    211       p->cur.kind = TOK_EOF;
    212       return;
    213     }
    214   }
    215   if (p->has_next) {
    216     p->cur = p->next;
    217     p->has_next = 0;
    218   } else {
    219     p->cur = fetch_tok(p);
    220   }
    221 }
    222 
    223 Tok peek1(Parser* p) {
    224   if (p->replay_active && p->replay_pos < p->replay_len) {
    225     return p->replay[p->replay_pos];
    226   }
    227   if (p->function_replay_active &&
    228       p->function_replay_pos < p->function_replay_len) {
    229     return p->function_replay[p->function_replay_pos];
    230   }
    231   if (!p->has_next) {
    232     p->next = fetch_tok(p);
    233     p->has_next = 1;
    234   }
    235   return p->next;
    236 }
    237 
    238 void expect_punct(Parser* p, u32 punct, const char* what) {
    239   if (!accept_punct(p, punct)) {
    240     perr(p, "expected %.*s", KIT_SLICE_ARG(kit_slice_cstr(what)));
    241   }
    242 }
    243 
    244 int accept_punct(Parser* p, u32 punct) {
    245   if (is_punct(&p->cur, punct)) {
    246     advance(p);
    247     return 1;
    248   }
    249   return 0;
    250 }
    251 
    252 /* Record tokens from the current `{` through the matching `}` into the
    253  * parser's replay buffer. */
    254 void record_braced_block(Parser* p) {
    255   int depth = 0;
    256   if (!is_punct(&p->cur, '{')) perr(p, "internal: record on non-'{'");
    257   p->replay_len = 0;
    258   for (;;) {
    259     if (p->replay_len == p->replay_cap) {
    260       u32 new_cap = p->replay_cap ? p->replay_cap * 2 : 32;
    261       Tok* nv = arena_array(p->pool->arena, Tok, new_cap);
    262       if (!nv) perr(p, "out of memory in record_braced_block");
    263       if (p->replay && p->replay_len) {
    264         memcpy(nv, p->replay, p->replay_len * sizeof(Tok));
    265       }
    266       p->replay = nv;
    267       p->replay_cap = new_cap;
    268     }
    269     p->replay[p->replay_len++] = p->cur;
    270     if (is_punct(&p->cur, '{')) {
    271       ++depth;
    272     } else if (is_punct(&p->cur, '}')) {
    273       --depth;
    274       if (depth == 0) break;
    275     } else if (p->cur.kind == TOK_EOF) {
    276       perr(p, "unexpected end of file in initializer");
    277     }
    278     advance(p);
    279   }
    280 }
    281 
    282 /* After record_braced_block, rewind to replay from the start. */
    283 void replay_rewind(Parser* p) {
    284   if (p->replay_len == 0) perr(p, "internal: replay_rewind with empty buffer");
    285   p->cur = p->replay[0];
    286   p->replay_pos = 1;
    287   p->replay_active = 1;
    288   p->has_next = 0;
    289 }
    290 
    291 /* Buffer a whole function body without feeding its already-preprocessed tokens
    292  * back through pp.  The dedicated replay stream lets initializer replay nest
    293  * normally during each semantic pass. */
    294 static void record_function_body(Parser* p) {
    295   Tok* body = NULL;
    296   u32 len = 0;
    297   u32 cap = 0;
    298   int depth = 0;
    299   if (!is_punct(&p->cur, '{')) perr(p, "internal: function body is not '{'");
    300   for (;;) {
    301     if (len == cap) {
    302       u32 next_cap = cap ? cap * 2u : 128u;
    303       Tok* next = arena_array(p->pool->arena, Tok, next_cap);
    304       if (!next) perr(p, "out of memory recording function body");
    305       if (body && len) memcpy(next, body, sizeof(Tok) * len);
    306       body = next;
    307       cap = next_cap;
    308     }
    309     body[len++] = p->cur;
    310     if (is_punct(&p->cur, '{')) {
    311       ++depth;
    312     } else if (is_punct(&p->cur, '}')) {
    313       --depth;
    314       if (depth == 0) break;
    315     } else if (p->cur.kind == TOK_EOF) {
    316       perr(p, "unexpected end of file in function body");
    317     }
    318     advance(p);
    319   }
    320   p->function_replay = body;
    321   p->function_replay_len = len;
    322   p->function_replay_pos = 1;
    323   p->function_replay_active = 1;
    324   p->function_replay_hold = 1;
    325   p->cur = body[0];
    326   p->has_next = 0;
    327 }
    328 
    329 static void rewind_function_body(Parser* p, int hold_at_end) {
    330   if (!p->function_replay || !p->function_replay_len)
    331     perr(p, "internal: empty function body replay");
    332   p->cur = p->function_replay[0];
    333   p->function_replay_pos = 1;
    334   p->function_replay_active = 1;
    335   p->function_replay_hold = hold_at_end ? 1u : 0u;
    336   p->has_next = 0;
    337 }
    338 
    339 /* Count top-level items in a recorded brace list. */
    340 u32 count_recorded_top_level_items(const Tok* vec, u32 len) {
    341   u32 count;
    342   u32 i;
    343   int depth = 0;
    344   if (len < 2) return 0;
    345   if (len == 2) return 0; /* `{}` */
    346   count = 1;
    347   for (i = 1; i < len - 1; ++i) {
    348     const Tok* t = &vec[i];
    349     if (is_punct(t, '{') || is_punct(t, '(') || is_punct(t, '['))
    350       ++depth;
    351     else if (is_punct(t, '}') || is_punct(t, ')') || is_punct(t, ']'))
    352       --depth;
    353     else if (depth == 0 && is_punct(t, ','))
    354       ++count;
    355   }
    356   if (is_punct(&vec[len - 2], ',')) --count;
    357   return count;
    358 }
    359 
    360 /* ============================================================
    361  * Scopes
    362  * ============================================================ */
    363 
    364 /* A scope only builds its hashmap index once it holds more than this many
    365  * entries; below it the linear LIFO scan is cheaper than a hashed lookup and
    366  * needs no allocation. The bound is a constant, so even pre-index scopes are
    367  * O(1) per lookup. */
    368 #define SCOPE_INDEX_THRESHOLD 12u
    369 
    370 Scope* scope_new(Parser* p, Scope* parent) {
    371   Scope* s = arena_new(p->pool->arena, Scope);
    372   if (!s) perr(p, "out of memory in scope_new");
    373   memset(s, 0, sizeof *s);
    374   s->parent = parent;
    375   s->saved_vla_mark = p->vla_mark;
    376   return s;
    377 }
    378 
    379 void scope_push(Parser* p) { p->scope = scope_new(p, p->scope); }
    380 
    381 void scope_pop(Parser* p) {
    382   if (p->scope) {
    383     /* Unwind the binding cache: walk the popped scope's LIFO list head-first
    384      * (newest define first) so multiple same-scope shadows of one Sym restore
    385      * to the pre-scope value. e->shadowed is the binding that was current when
    386      * e was defined, i.e. the value bind[name] must return once this scope is
    387      * gone. */
    388     SymEntry* e;
    389     for (e = p->scope->entries; e; e = e->next)
    390       if (e->name) BindingTab_set(&p->bind, e->name, e->shadowed);
    391     p->vla_mark = p->scope->saved_vla_mark;
    392     p->scope = p->scope->parent;
    393   }
    394 }
    395 
    396 /* Build a scope's name->entry index from its existing LIFO list. Insert
    397  * newest-first with try_insert (which keeps the first writer) so the head — the
    398  * current binding a linear scan would return — wins on shadowing. */
    399 static void scope_entries_index_build(Parser* p, Scope* s) {
    400   SymEntry* e;
    401   SymEntryMap_init_cap(&s->emap, &p->pool->arena_heap, 64u);
    402   for (e = s->entries; e; e = e->next)
    403     if (e->name) (void)SymEntryMap_try_insert(&s->emap, e->name, e, NULL);
    404 }
    405 
    406 static void scope_entries_index_put(Parser* p, Scope* s, SymEntry* e) {
    407   if (!e->name)
    408     return; /* anonymous: never name-looked-up, keep off the index */
    409   if (s->emap.cap) {
    410     (void)SymEntryMap_set(&s->emap, e->name, e); /* newest define wins */
    411   } else if (s->nentries > SCOPE_INDEX_THRESHOLD) {
    412     scope_entries_index_build(p, s);
    413   }
    414 }
    415 
    416 static SymEntry* scope_entries_find(Scope* s, Sym name) {
    417   SymEntry* e;
    418   if (name && s->emap.cap) {
    419     SymEntry** v = SymEntryMap_get(&s->emap, name);
    420     return v ? *v : NULL;
    421   }
    422   for (e = s->entries; e; e = e->next)
    423     if (e->name == name) return e;
    424   return NULL;
    425 }
    426 
    427 SymEntry* scope_define(Parser* p, Sym name, SymEntryKind kind,
    428                        const Type* type) {
    429   SymEntry* e = arena_new(p->pool->arena, SymEntry);
    430   Scope* s = p->scope;
    431   if (!e) perr(p, "out of memory in scope_define");
    432   memset(e, 0, sizeof *e);
    433   e->name = name;
    434   e->kind = (u8)kind;
    435   e->type = type;
    436   if (name) e->shadowed = BindingTab_get(&p->bind, name);
    437   e->next = s->entries;
    438   s->entries = e;
    439   s->nentries++;
    440   scope_entries_index_put(p, s, e);
    441   if (name) BindingTab_set(&p->bind, name, e);
    442   return e;
    443 }
    444 
    445 SymEntry* scope_lookup_current(Parser* p, Sym name) {
    446   return p->scope ? scope_entries_find(p->scope, name) : NULL;
    447 }
    448 
    449 /* Walk the scope chain starting at `from` (inclusive), returning the first
    450  * binding for `name`. scope_lookup is the common case starting at p->scope; a
    451  * caller that has already probed the current scope can start at its parent. */
    452 static SymEntry* scope_lookup_from(Scope* from, Sym name) {
    453   Scope* s;
    454   for (s = from; s; s = s->parent) {
    455     SymEntry* e = scope_entries_find(s, name);
    456     if (e) return e;
    457   }
    458   return NULL;
    459 }
    460 
    461 SymEntry* scope_lookup(Parser* p, Sym name) {
    462   /* Sym-keyed cache: the innermost-visible binding in one load. Equivalent to
    463    * scope_lookup_from(p->scope, name) by construction (the cache tracks the
    464    * newest define per scope and unwinds on pop); no caller passes name == 0. */
    465   return name ? BindingTab_get(&p->bind, name) : NULL;
    466 }
    467 
    468 static void sym_set_decl(SymEntry* e, DeclId id, DeclStorage storage,
    469                          DeclLinkage linkage, u32 flags, DeclState state) {
    470   e->decl_id = id;
    471   e->storage = (u8)storage;
    472   e->linkage = (u8)linkage;
    473   e->decl_flags = flags;
    474   e->decl_state = (u8)state;
    475   e->defined = (state == DSTATE_DEFINED || state == DSTATE_FUNC_DEFINED);
    476 }
    477 
    478 static SymEntry* external_func_lookup(Parser* p, Sym name) {
    479   SymEntry** v = name ? ExternalFuncMap_get(&p->external_funcs, name) : NULL;
    480   return v ? *v : NULL;
    481 }
    482 
    483 static void external_func_remember(Parser* p, Sym name, SymEntry* entry) {
    484   if (!entry || !name) return;
    485   (void)ExternalFuncMap_set(&p->external_funcs, name, entry); /* newest wins */
    486 }
    487 
    488 static int is_ordinary_decl_kind(SymEntryKind k) {
    489   return k == SEK_LOCAL || k == SEK_GLOBAL || k == SEK_FUNC ||
    490          k == SEK_TYPEDEF || k == SEK_ENUM_CST;
    491 }
    492 
    493 /* Apply the same-scope redefinition rule against `prior` (the binding present
    494  * before the new entry is installed): reject an ordinary-kind redeclaration
    495  * unless it is a typedef of a compatible type. */
    496 static void reject_redef_on(Parser* p, const SymEntry* prior, SymEntryKind kind,
    497                             const Type* type) {
    498   if (!prior || !is_ordinary_decl_kind((SymEntryKind)prior->kind)) return;
    499   if (prior->kind == SEK_TYPEDEF && kind == SEK_TYPEDEF &&
    500       type_compatible(prior->type, type)) {
    501     return;
    502   }
    503   perr(p, "redefinition of identifier");
    504 }
    505 
    506 /* Fused redefinition-check + define: one hash+probe on the scope index reads
    507  * the prior binding (for the redef rule) AND installs the new entry, instead of
    508  * probing the same key twice (a get for the redef check then a set in
    509  * scope_define). Behavior is identical to a redef check followed by
    510  *   return scope_define(p, name, kind, type);
    511  * — the redef rule fires on the captured prior before the new entry shadows it,
    512  * and the LIFO list + newest-wins index semantics are preserved. Use this only
    513  * at the rejecting declaration sites; plain scope_define stays for the
    514  * non-rejecting redeclaration-merge sites. */
    515 static SymEntry* scope_define_checked(Parser* p, Sym name, SymEntryKind kind,
    516                                       const Type* type) {
    517   SymEntry* e = arena_new(p->pool->arena, SymEntry);
    518   Scope* s = p->scope;
    519   SymEntry* prior;
    520   if (!e) perr(p, "out of memory in scope_define_checked");
    521   memset(e, 0, sizeof *e);
    522   e->name = name;
    523   e->kind = (u8)kind;
    524   e->type = type;
    525   /* The shadowed binding is the current innermost-visible one (== bind_get),
    526    * not `prior`: prior is the current-scope prior (used only for the redef
    527    * rule) and may be NULL while an outer binding exists, which must be the
    528    * value restored on pop. */
    529   if (name) e->shadowed = BindingTab_get(&p->bind, name);
    530   if (name && s->emap.cap) {
    531     /* Active index: prepend to the LIFO list, then fold the prior-read and the
    532      * index install into a single probe (newest define wins). */
    533     SymEntry* old = NULL;
    534     e->next = s->entries;
    535     s->entries = e;
    536     s->nentries++;
    537     (void)SymEntryMap_replace(&s->emap, name, e, &old);
    538     prior = old;
    539   } else {
    540     /* No index yet (or anonymous): capture the prior binding before the prepend
    541      * shadows it, then mirror scope_entries_index_put's threshold-trip build.
    542      * Anonymous entries (name == 0) stay off the index, as before. */
    543     prior = scope_entries_find(s, name);
    544     e->next = s->entries;
    545     s->entries = e;
    546     s->nentries++;
    547     if (name && s->nentries > SCOPE_INDEX_THRESHOLD)
    548       scope_entries_index_build(p, s);
    549   }
    550   reject_redef_on(p, prior, kind, type);
    551   if (name) BindingTab_set(&p->bind, name, e);
    552   return e;
    553 }
    554 
    555 static void tag_index_build(Parser* p, Scope* s) {
    556   TagEntry* e;
    557   TagEntryMap_init_cap(&s->tmap, &p->pool->arena_heap, 64u);
    558   for (e = s->tags; e; e = e->next)
    559     if (e->name) (void)TagEntryMap_try_insert(&s->tmap, e->name, e, NULL);
    560 }
    561 
    562 static void tag_index_put(Parser* p, Scope* s, TagEntry* e) {
    563   if (!e->name) return; /* anonymous struct/union: not name-looked-up */
    564   if (s->tmap.cap) {
    565     (void)TagEntryMap_set(&s->tmap, e->name, e);
    566   } else if (s->ntags > SCOPE_INDEX_THRESHOLD) {
    567     tag_index_build(p, s);
    568   }
    569 }
    570 
    571 static TagEntry* tag_find_in(Scope* s, Sym name) {
    572   TagEntry* e;
    573   if (name && s->tmap.cap) {
    574     TagEntry** v = TagEntryMap_get(&s->tmap, name);
    575     return v ? *v : NULL;
    576   }
    577   for (e = s->tags; e; e = e->next)
    578     if (e->name == name) return e;
    579   return NULL;
    580 }
    581 
    582 TagEntry* tag_define(Parser* p, Sym name, TagDeclKind kind, Type* type,
    583                      int complete) {
    584   TagEntry* e = arena_new(p->pool->arena, TagEntry);
    585   Scope* s = p->scope;
    586   if (!e) perr(p, "out of memory in tag_define");
    587   memset(e, 0, sizeof *e);
    588   e->name = name;
    589   e->kind = (u8)kind;
    590   e->complete = (u8)(complete ? 1 : 0);
    591   e->type = type;
    592   e->next = s->tags;
    593   s->tags = e;
    594   s->ntags++;
    595   tag_index_put(p, s, e);
    596   return e;
    597 }
    598 
    599 TagEntry* tag_lookup(Parser* p, Sym name) {
    600   Scope* s;
    601   for (s = p->scope; s; s = s->parent) {
    602     TagEntry* e = tag_find_in(s, name);
    603     if (e) return e;
    604   }
    605   return NULL;
    606 }
    607 
    608 TagEntry* tag_lookup_local(Parser* p, Sym name) {
    609   return tag_find_in(p->scope, name);
    610 }
    611 
    612 /* ============================================================
    613  * Type helpers
    614  * ============================================================ */
    615 
    616 static const Type* ty_size_t(Parser* p) {
    617   return c_abi_size_type(p->abi, p->pool);
    618 }
    619 
    620 /* C owns conventional function selection; CG owns the guard/check lowering.
    621  * BASIC follows GCC's classic character-buffer threshold, STRONG covers every
    622  * local array (including arrays nested in records) plus address-taken locals,
    623  * and dynamic alloca selects either mode. */
    624 static int stack_type_selects(Parser* p, const Type* type, int strong) {
    625   u16 i;
    626   if (!type) return 0;
    627   if (type->kind == TY_ARRAY) {
    628     if (strong) return 1;
    629     if ((type->arr.elem->kind == TY_CHAR ||
    630          type->arr.elem->kind == TY_SCHAR ||
    631          type->arr.elem->kind == TY_UCHAR) &&
    632         !type->arr.incomplete &&
    633         c_abi_sizeof(p->abi, p->pool, type) >= 8u)
    634       return 1;
    635     return stack_type_selects(p, type->arr.elem, strong);
    636   }
    637   if (type->kind == TY_STRUCT || type->kind == TY_UNION) {
    638     for (i = 0; i < type->rec.nfields; ++i) {
    639       if (stack_type_selects(p, type->rec.fields[i].type, strong)) return 1;
    640     }
    641   }
    642   return 0;
    643 }
    644 
    645 void c_stack_protector_enable(Parser* p) {
    646   if (!p || p->stack_protector_mode == KIT_STACK_PROTECTOR_NONE)
    647     return;
    648   if (p->stack_protector_scan) {
    649     p->stack_protector_scan_selected = 1;
    650     return;
    651   }
    652   if (p->stack_protector_enabled || !p->cur_func_emits) return;
    653   kit_cg_stack_protector_enable(p->cg);
    654   p->stack_protector_enabled = 1;
    655 }
    656 
    657 void c_stack_protector_note_type(Parser* p, const Type* type) {
    658   if (!p || p->stack_protector_mode == KIT_STACK_PROTECTOR_NONE ||
    659       p->stack_protector_mode == KIT_STACK_PROTECTOR_ALL)
    660     return;
    661   if (stack_type_selects(
    662           p, type,
    663           p->stack_protector_mode == KIT_STACK_PROTECTOR_STRONG))
    664     c_stack_protector_enable(p);
    665 }
    666 
    667 void c_stack_protector_note_address(Parser* p) {
    668   if (p && p->stack_protector_mode == KIT_STACK_PROTECTOR_STRONG)
    669     c_stack_protector_enable(p);
    670 }
    671 
    672 /* ============================================================
    673  * Local-variable slot allocation
    674  * ============================================================ */
    675 
    676 FrameSlot make_local_aligned(Parser* p, Sym name, const Type* type, SrcLoc loc,
    677                              u32 align_override) {
    678   FrameSlotDesc fsd;
    679   FrameSlot s;
    680   SymEntry* e;
    681   u32 nat = c_abi_alignof(p->abi, p->pool, type);
    682   c_stack_protector_note_type(p, type);
    683   memset(&fsd, 0, sizeof fsd);
    684   fsd.type = type;
    685   fsd.name = name;
    686   fsd.loc = loc;
    687   fsd.size = c_abi_sizeof(p->abi, p->pool, type);
    688   fsd.align = (align_override > nat) ? align_override : nat;
    689   fsd.kind = FS_LOCAL;
    690   fsd.flags = FSF_NONE;
    691   s = c_cg_local(p, &fsd);
    692   e = scope_define_checked(p, name, SEK_LOCAL, type);
    693   e->v.slot = s;
    694   sym_set_decl(e, DECL_NONE, DS_AUTO, DL_NONE, DF_NONE, DSTATE_DEFINED);
    695   return s;
    696 }
    697 
    698 FrameSlot make_local(Parser* p, Sym name, const Type* type, SrcLoc loc) {
    699   return make_local_aligned(p, name, type, loc, 0);
    700 }
    701 
    702 static FrameSlot make_vla_size_slot(Parser* p) {
    703   FrameSlotDesc fsd;
    704   memset(&fsd, 0, sizeof fsd);
    705   fsd.type = ty_size_t(p);
    706   fsd.size = c_abi_sizeof(p->abi, p->pool, fsd.type);
    707   fsd.align = c_abi_alignof(p->abi, p->pool, fsd.type);
    708   fsd.kind = FS_LOCAL;
    709   return c_cg_local(p, &fsd);
    710 }
    711 
    712 static void store_top_to_size_slot(Parser* p, FrameSlot slot) {
    713   c_cg_push_local_typed(p, slot, ty_size_t(p));
    714   c_cg_swap(p);
    715   coerce_top_to_lvalue(p);
    716   c_cg_store_void(p);
    717 }
    718 
    719 static void reset_vla_pending(Parser* p) {
    720   p->vla_pending = 0;
    721   p->vla_pending_count_slot = FRAME_SLOT_NONE;
    722   p->vla_pending_count_len = 0;
    723 }
    724 
    725 static VLABound* add_vla_bound(Parser* p, VLABound* head, const Type* array_ty,
    726                                FrameSlot byte_slot, FrameSlot count_slot) {
    727   VLABound* b = arena_znew(p->pool->arena, VLABound);
    728   b->array_ty = array_ty;
    729   b->byte_slot = byte_slot;
    730   b->count_slot = count_slot;
    731   b->next = head;
    732   return b;
    733 }
    734 
    735 static int build_vla_size(Parser* p, const Type* ty, u32* count_idx,
    736                           VLABound** bounds, FrameSlot* out_slot,
    737                           u32* out_static_size, SrcLoc loc) {
    738   if (!ty || ty->kind != TY_ARRAY) {
    739     *out_static_size = c_abi_sizeof(p->abi, p->pool, ty);
    740     *out_slot = FRAME_SLOT_NONE;
    741     return 0;
    742   }
    743 
    744   FrameSlot count_slot = FRAME_SLOT_NONE;
    745   int count_dynamic = 0;
    746   if (ty->arr.incomplete) {
    747     if (*count_idx >= p->vla_pending_count_len) {
    748       perr(p, "missing VLA bound for declarator");
    749     }
    750     count_slot = p->vla_pending_count_slots[(*count_idx)++];
    751     count_dynamic = 1;
    752   }
    753 
    754   FrameSlot elem_slot = FRAME_SLOT_NONE;
    755   u32 elem_static_size = 0;
    756   int elem_dynamic = build_vla_size(p, ty->arr.elem, count_idx, bounds,
    757                                     &elem_slot, &elem_static_size, loc);
    758 
    759   if (count_dynamic || elem_dynamic) {
    760     FrameSlot byte_slot = make_vla_size_slot(p);
    761     c_cg_set_loc(p, loc);
    762     if (count_dynamic) {
    763       c_cg_push_local_typed(p, count_slot, ty_size_t(p));
    764       c_cg_load(p);
    765     } else {
    766       c_cg_push_int(p, (i64)ty->arr.count, ty_size_t(p));
    767     }
    768     if (elem_dynamic) {
    769       c_cg_push_local_typed(p, elem_slot, ty_size_t(p));
    770       c_cg_load(p);
    771     } else {
    772       c_cg_push_int(p, (i64)elem_static_size, ty_size_t(p));
    773     }
    774     c_cg_binop(p, BO_IMUL);
    775     store_top_to_size_slot(p, byte_slot);
    776     *bounds = add_vla_bound(p, *bounds, ty, byte_slot, count_slot);
    777     *out_slot = byte_slot;
    778     *out_static_size = 0;
    779     return 1;
    780   }
    781 
    782   *out_slot = FRAME_SLOT_NONE;
    783   *out_static_size = ty->arr.count * elem_static_size;
    784   return 0;
    785 }
    786 
    787 static FrameSlot finish_vla_layout(Parser* p, const Type* ty, SrcLoc loc,
    788                                    VLABound** bounds_out) {
    789   FrameSlot byte_slot = FRAME_SLOT_NONE;
    790   u32 static_size = 0;
    791   u32 count_idx = 0;
    792   *bounds_out = NULL;
    793   if (!build_vla_size(p, ty, &count_idx, bounds_out, &byte_slot, &static_size,
    794                       loc)) {
    795     perr(p, "VLA declarator did not produce a runtime size");
    796   }
    797   if (count_idx != p->vla_pending_count_len) {
    798     perr(p, "unused VLA bound in declarator");
    799   }
    800   reset_vla_pending(p);
    801   return byte_slot;
    802 }
    803 
    804 static int type_array_depth(const Type* ty) {
    805   int n = 0;
    806   while (ty && ty->kind == TY_ARRAY) {
    807     ++n;
    808     ty = ty->arr.elem;
    809   }
    810   return n;
    811 }
    812 
    813 static void eval_param_vla_count(Parser* p, const ParamVLABoundExpr* expr,
    814                                  FrameSlot slot) {
    815   Tok save_cur = p->cur;
    816   Tok save_next = p->next;
    817   int save_has_next = p->has_next;
    818   Tok* save_replay = p->replay;
    819   u32 save_cap = p->replay_cap;
    820   u32 save_len = p->replay_len;
    821   u32 save_pos = p->replay_pos;
    822   u8 save_active = p->replay_active;
    823   Tok* replay;
    824 
    825   if (!expr->has_expr || expr->ntoks == 0) {
    826     perr(p, "missing VLA parameter bound");
    827   }
    828   replay = arena_array(p->pool->arena, Tok, expr->ntoks + 1u);
    829   memcpy(replay, expr->toks, sizeof(Tok) * expr->ntoks);
    830   memset(&replay[expr->ntoks], 0, sizeof(Tok));
    831   replay[expr->ntoks].kind = TOK_EOF;
    832 
    833   p->cur = replay[0];
    834   p->next.kind = TOK_EOF;
    835   p->has_next = 0;
    836   p->replay = replay;
    837   p->replay_cap = expr->ntoks + 1u;
    838   p->replay_len = expr->ntoks + 1u;
    839   p->replay_pos = 1;
    840   p->replay_active = 1;
    841 
    842   parse_assign_expr(p);
    843   to_rvalue(p);
    844   if (p->cur.kind != TOK_EOF) {
    845     perr(p, "unexpected token in VLA parameter bound");
    846   }
    847   store_top_to_size_slot(p, slot);
    848 
    849   p->cur = save_cur;
    850   p->next = save_next;
    851   p->has_next = save_has_next;
    852   p->replay = save_replay;
    853   p->replay_cap = save_cap;
    854   p->replay_len = save_len;
    855   p->replay_pos = save_pos;
    856   p->replay_active = save_active;
    857 }
    858 
    859 static VLABound* build_param_vla_bounds(Parser* p, const ParamInfo* info,
    860                                         SrcLoc loc) {
    861   const Type* root = info->declared_type;
    862   u32 dim_skip = 0;
    863   u32 need;
    864   VLABound* bounds = NULL;
    865 
    866   if (!root || info->vla_bound_len == 0) return NULL;
    867   if (root->kind == TY_ARRAY) {
    868     dim_skip = 1;
    869     root = root->arr.elem;
    870   } else if (root->kind == TY_PTR) {
    871     root = root->ptr.pointee;
    872   }
    873   need = (u32)type_array_depth(root);
    874   if (need == 0) return NULL;
    875   if (dim_skip + need > info->vla_bound_len) {
    876     perr(p, "missing VLA parameter bound");
    877   }
    878 
    879   reset_vla_pending(p);
    880   for (u32 i = 0; i < need; ++i) {
    881     const ParamVLABoundExpr* expr = &info->vla_bounds[dim_skip + i];
    882     FrameSlot slot = make_vla_size_slot(p);
    883     eval_param_vla_count(p, expr, slot);
    884     p->vla_pending = 1;
    885     p->vla_pending_count_slots[p->vla_pending_count_len++] = slot;
    886   }
    887   (void)finish_vla_layout(p, root, loc, &bounds);
    888   return bounds;
    889 }
    890 
    891 /* ============================================================
    892  * Static-local symbol naming
    893  * ============================================================ */
    894 
    895 /* Mint a unique linker name for a static local: `<orig>.<counter>`. */
    896 Sym mint_static_local_sym(Parser* p, Sym orig) {
    897   KitSlice orig_sl = kit_sym_str(p->pool->c, orig);
    898   size_t olen = orig_sl.len;
    899   const char* on = orig_sl.s;
    900   char buf[128];
    901   u32 wlen = 0;
    902   u32 id = ++p->static_local_counter;
    903   if (olen > 100) olen = 100;
    904   for (size_t i = 0; i < olen && wlen < sizeof buf - 1; ++i) {
    905     buf[wlen++] = on[i];
    906   }
    907   if (wlen < sizeof buf - 1) buf[wlen++] = '.';
    908   {
    909     char digits[12];
    910     int dn = 0;
    911     if (id == 0) digits[dn++] = '0';
    912     while (id) {
    913       digits[dn++] = (char)('0' + (id % 10));
    914       id /= 10;
    915     }
    916     while (dn && wlen < sizeof buf - 1) buf[wlen++] = digits[--dn];
    917   }
    918   return kit_sym_intern(p->pool->c, (KitSlice){.s = buf, .len = wlen});
    919 }
    920 
    921 /* ============================================================
    922  * Declarations
    923  * ============================================================ */
    924 
    925 /* Parse a single init-declarator after the decl-specs have been consumed. */
    926 static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty,
    927                                   const DeclSpecs* specs, SrcLoc fname_loc,
    928                                   const Attr* dattrs, Sym asm_label,
    929                                   ObjSecId* out_section_id, u32* out_decl_flags,
    930                                   Sym* out_alias_target);
    931 
    932 static void parse_init_declarator(Parser* p, const DeclSpecs* specs) {
    933   SrcLoc loc;
    934   Sym name;
    935   DeclaratorInfo dinfo;
    936   const Type* var_ty = parse_declarator_full_info(
    937       p, specs->type, /*allow_abstract=*/0, &name, &loc, NULL, &dinfo);
    938   if ((specs->flags & DF_THREAD) && specs->storage != DS_STATIC &&
    939       specs->storage != DS_EXTERN) {
    940     perr(p, "block-scope _Thread_local requires static or extern");
    941   }
    942   validate_decl_type_constraints(p, specs, var_ty,
    943                                  var_ty && var_ty->kind == TY_FUNC,
    944                                  /*is_member=*/0);
    945 
    946   if (specs->storage == DS_TYPEDEF) {
    947     if (is_punct(&p->cur, '=')) {
    948       perr(p, "typedef declarator cannot have initializer");
    949     }
    950     {
    951       SymEntry* e = scope_define_checked(p, name, SEK_TYPEDEF, var_ty);
    952       sym_set_decl(e, DECL_NONE, DS_TYPEDEF, DL_NONE, specs->flags,
    953                    DSTATE_DECLARED);
    954       if (p->vla_pending && var_ty && var_ty->kind == TY_ARRAY) {
    955         VLABound* bounds = NULL;
    956         FrameSlot byte_slot = finish_vla_layout(p, var_ty, loc, &bounds);
    957         e->vla_byte_slot = byte_slot;
    958         e->vla_bounds = bounds;
    959       } else if (specs->vla_byte_slot != FRAME_SLOT_NONE) {
    960         e->vla_byte_slot = specs->vla_byte_slot;
    961         e->vla_bounds = specs->vla_bounds;
    962       }
    963     }
    964     (void)loc;
    965     return;
    966   }
    967 
    968   if (var_ty && var_ty->kind == TY_FUNC) {
    969     ObjSecId section_id;
    970     u32 decl_flags;
    971     Sym alias_target;
    972     if ((specs->storage == DS_AUTO && specs->storage_explicit) ||
    973         specs->storage == DS_REGISTER || specs->storage == DS_STATIC) {
    974       perr(p,
    975            "invalid storage-class specifier for block-scope function "
    976            "declaration");
    977     }
    978     if (is_punct(&p->cur, '=')) {
    979       perr(p, "function declarator cannot have initializer");
    980     }
    981     if (p->stack_protector_scan) {
    982       SymEntry* prior = scope_lookup(p, name);
    983       SymEntry* e = scope_lookup_current(p, name);
    984       if (!e) e = scope_define(p, name, SEK_FUNC, var_ty);
    985       e->v.sym = prior && prior->kind == SEK_FUNC ? prior->v.sym
    986                                                   : OBJ_SYM_NONE;
    987       sym_set_decl(e, prior ? prior->decl_id : DECL_NONE, DS_EXTERN,
    988                    prior ? (DeclLinkage)prior->linkage : DL_EXTERNAL,
    989                    prior ? prior->decl_flags : DF_NONE, DSTATE_DECLARED);
    990     } else {
    991       (void)declare_function(p, name, var_ty, specs, loc, NULL,
    992                              dinfo.asm_label, &section_id, &decl_flags,
    993                              &alias_target);
    994     }
    995     (void)section_id;
    996     (void)decl_flags;
    997     (void)alias_target;
    998     return;
    999   }
   1000 
   1001   if (specs->storage == DS_STATIC) {
   1002     Decl decl_in;
   1003     DeclId did;
   1004     ObjSymId sym;
   1005     SymEntry* e;
   1006     Sym lname;
   1007     int has_init;
   1008     u32 align_eff;
   1009     has_init = accept_punct(p, '=');
   1010     /* Complete `T x[] = {...}` before declaring the symbol so the registered
   1011      * (CG) type carries the real element count. Backends such as the C target
   1012      * derive function-local label-table sizes from the symbol's type, so the
   1013      * declared type must already be the completed array. */
   1014     if (has_init && var_ty && var_ty->kind == TY_ARRAY &&
   1015         var_ty->arr.incomplete) {
   1016       var_ty = complete_incomplete_array(p, var_ty);
   1017     }
   1018     if (p->stack_protector_scan) {
   1019       e = scope_define_checked(p, name, SEK_GLOBAL, var_ty);
   1020       e->v.sym = OBJ_SYM_NONE;
   1021       sym_set_decl(e, DECL_NONE, DS_STATIC, DL_NONE, DF_STATIC_LOCAL,
   1022                    DSTATE_DEFINED);
   1023       if (has_init) {
   1024         if ((var_ty->kind == TY_ARRAY || var_ty->kind == TY_STRUCT ||
   1025              var_ty->kind == TY_UNION) &&
   1026             is_punct(&p->cur, '{')) {
   1027           init_at(p, FRAME_SLOT_NONE, var_ty, 0, var_ty);
   1028         } else {
   1029           parse_assign_expr(p);
   1030           c_cg_drop(p);
   1031         }
   1032       }
   1033       return;
   1034     }
   1035     lname = mint_static_local_sym(p, name);
   1036     memset(&decl_in, 0, sizeof decl_in);
   1037     decl_in.name = lname;
   1038     decl_in.asm_name = dinfo.asm_label;
   1039     decl_in.type = var_ty;
   1040     decl_in.loc = loc;
   1041     decl_in.storage = DS_STATIC;
   1042     decl_in.linkage = DL_INTERNAL;
   1043     decl_in.visibility = SV_DEFAULT;
   1044     decl_in.flags = DF_STATIC_LOCAL | (specs->flags & DF_THREAD);
   1045     attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in);
   1046     did = decl_declare(p->decls, &decl_in);
   1047     sym = decl_obj_sym(p->decls, did);
   1048     e = scope_define_checked(p, name, SEK_GLOBAL, var_ty);
   1049     e->v.sym = sym;
   1050     sym_set_decl(e, did, DS_STATIC, DL_NONE, decl_in.flags, DSTATE_DEFINED);
   1051     align_eff = (specs->align > decl_in.align) ? specs->align : decl_in.align;
   1052     define_static_object(p, sym, decl_in.section_id, var_ty, specs->quals,
   1053                          has_init, loc, align_eff);
   1054     return;
   1055   }
   1056 
   1057   if (specs->storage == DS_EXTERN) {
   1058     Decl decl_in;
   1059     DeclId did;
   1060     ObjSymId sym;
   1061     SymEntry* e;
   1062     SymEntry* prior;
   1063     if (accept_punct(p, '=')) {
   1064       perr(p, "block-scope extern with initializer not supported");
   1065     }
   1066     prior = scope_lookup(p, name);
   1067     if (p->stack_protector_scan) {
   1068       e = scope_lookup_current(p, name);
   1069       if (!e) e = scope_define(p, name, SEK_GLOBAL, var_ty);
   1070       e->v.sym = prior && prior->kind == SEK_GLOBAL ? prior->v.sym
   1071                                                     : OBJ_SYM_NONE;
   1072       sym_set_decl(e, prior ? prior->decl_id : DECL_NONE, DS_EXTERN,
   1073                    prior ? (DeclLinkage)prior->linkage : DL_EXTERNAL,
   1074                    prior ? prior->decl_flags : DF_NONE, DSTATE_DECLARED);
   1075       return;
   1076     }
   1077     if (prior && prior->kind == SEK_GLOBAL) {
   1078       SymEntry* cur = scope_lookup_current(p, name);
   1079       const Type* composite = NULL;
   1080       CSemCheck chk =
   1081           c_sem_check_redeclaration(p->pool, prior->type, var_ty, &composite);
   1082       if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
   1083       if (cur && cur->kind != SEK_GLOBAL) {
   1084         perr(p, "redefinition of identifier");
   1085       }
   1086       if (cur) return;
   1087       e = scope_define(p, name, SEK_GLOBAL, var_ty);
   1088       e->v.sym = prior->v.sym;
   1089       sym_set_decl(e, prior->decl_id, DS_EXTERN, (DeclLinkage)prior->linkage,
   1090                    prior->decl_flags, (DeclState)prior->decl_state);
   1091       return;
   1092     }
   1093     memset(&decl_in, 0, sizeof decl_in);
   1094     decl_in.name = name;
   1095     decl_in.asm_name = dinfo.asm_label;
   1096     decl_in.type = var_ty;
   1097     decl_in.loc = loc;
   1098     decl_in.storage = DS_EXTERN;
   1099     decl_in.linkage = DL_EXTERNAL;
   1100     decl_in.visibility = p->default_visibility;
   1101     decl_in.flags = specs->flags & DF_THREAD;
   1102     attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in);
   1103     did = decl_declare(p->decls, &decl_in);
   1104     sym = decl_obj_sym(p->decls, did);
   1105     e = scope_define_checked(p, name, SEK_GLOBAL, var_ty);
   1106     e->v.sym = sym;
   1107     sym_set_decl(e, did, DS_EXTERN, DL_EXTERNAL, decl_in.flags,
   1108                  DSTATE_DECLARED);
   1109     return;
   1110   }
   1111 
   1112   if (var_ty && var_ty->kind == TY_ARRAY &&
   1113       (p->vla_pending || specs->vla_byte_slot != FRAME_SLOT_NONE)) {
   1114     const Type* elem_ty = var_ty->arr.elem;
   1115     const Type* ptr_ty = type_ptr(p->pool, elem_ty);
   1116     FrameSlot byte_slot;
   1117     FrameSlot ptr_slot;
   1118     SymEntry* sym_entry;
   1119     VLABound* bounds = NULL;
   1120     c_stack_protector_enable(p); /* VLA lowers through dynamic alloca. */
   1121     if (p->vla_pending) {
   1122       byte_slot = finish_vla_layout(p, var_ty, loc, &bounds);
   1123       ++p->vla_mark;
   1124     } else {
   1125       byte_slot = specs->vla_byte_slot;
   1126       bounds = specs->vla_bounds;
   1127     }
   1128     ptr_slot = make_local(p, name, ptr_ty, loc);
   1129     c_cg_set_loc(p, loc);
   1130     c_cg_push_local_typed(p, byte_slot, ty_size_t(p));
   1131     c_cg_load(p);
   1132     c_cg_alloca(p);
   1133     c_cg_push_local_typed(p, ptr_slot, ptr_ty);
   1134     c_cg_swap(p);
   1135     c_cg_store_void(p);
   1136     sym_entry = scope_lookup(p, name);
   1137     if (sym_entry && sym_entry->kind == SEK_LOCAL) {
   1138       sym_entry->vla_byte_slot = byte_slot;
   1139       sym_entry->vla_bounds = bounds;
   1140     }
   1141     if (accept_punct(p, '=')) {
   1142       perr(p, "VLA initializers are not allowed (§6.7.9 ¶3)");
   1143     }
   1144     return;
   1145   }
   1146   /* Non-VLA local. */
   1147   {
   1148     int has_init = is_punct(&p->cur, '=');
   1149     FrameSlot s;
   1150     if (has_init && var_ty && var_ty->kind == TY_ARRAY &&
   1151         var_ty->arr.incomplete) {
   1152       advance(p); /* '=' */
   1153       var_ty = complete_incomplete_array(p, var_ty);
   1154       s = make_local_aligned(p, name, var_ty, loc, specs->align);
   1155       if (specs->storage == DS_REGISTER) {
   1156         SymEntry* e = scope_lookup_current(p, name);
   1157         if (e && e->kind == SEK_LOCAL) {
   1158           e->storage = DS_REGISTER;
   1159           e->reg_asm_name = dinfo.asm_label;
   1160         }
   1161       }
   1162       c_cg_set_loc(p, loc);
   1163       init_at(p, s, var_ty, 0, var_ty);
   1164       return;
   1165     }
   1166     s = make_local_aligned(p, name, var_ty, loc, specs->align);
   1167     if (specs->storage == DS_REGISTER) {
   1168       SymEntry* e = scope_lookup_current(p, name);
   1169       if (e && e->kind == SEK_LOCAL) {
   1170         e->storage = DS_REGISTER;
   1171         e->reg_asm_name = dinfo.asm_label;
   1172       }
   1173     }
   1174     if (accept_punct(p, '=')) {
   1175       c_cg_set_loc(p, loc);
   1176       if ((var_ty->kind == TY_STRUCT || var_ty->kind == TY_UNION) &&
   1177           !is_punct(&p->cur, '{')) {
   1178         parse_assign_expr(p);
   1179         emit_struct_copy_into_slot(p, s, var_ty, 0, var_ty);
   1180       } else if (var_ty->kind == TY_ARRAY || var_ty->kind == TY_STRUCT ||
   1181                  var_ty->kind == TY_UNION) {
   1182         init_at(p, s, var_ty, 0, var_ty);
   1183       } else {
   1184         c_cg_push_local_typed(p, s, var_ty);
   1185         parse_assign_expr(p);
   1186         to_rvalue(p);
   1187         {
   1188           const Type* rhs = c_cg_top_type(p);
   1189           CSemCheck chk = c_sem_check_assignment(p->pool, var_ty, rhs);
   1190           if (!chk.ok)
   1191             perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
   1192         }
   1193         coerce_top_to_lvalue(p);
   1194         c_cg_store_void(p);
   1195       }
   1196     } else if (p->auto_var_init == KIT_AUTOVAR_ZERO && var_ty &&
   1197                !(var_ty->kind == TY_ARRAY && var_ty->arr.incomplete)) {
   1198       /* -ftrivial-auto-var-init=zero: an automatic variable with no explicit
   1199        * initializer is implicitly zeroed (clang/gcc semantics). When the
   1200        * variable is fully written before any read the store is dead and the
   1201        * optimizer drops it. VLAs and incomplete arrays are left alone. */
   1202       c_cg_set_loc(p, loc);
   1203       /* Zero the whole object in one memset rather than recursing to one store
   1204        * per scalar leaf. The per-leaf path is O(leaves^2) on large aggregates
   1205        * (each leaf store stashes a fresh frontend temp, growing g->nlocals,
   1206        * which api_local_const_address_taken then re-scans on every store) and
   1207        * explodes under ASAN — e.g. a 28 KB manifest local in src/api/package.c
   1208        * stalled the debug bootstrap for minutes. memset is also what gcc/clang
   1209        * emit for -ftrivial-auto-var-init=zero. */
   1210       zero_object_bytes_at(p, s, var_ty, 0, var_ty);
   1211     }
   1212   }
   1213 }
   1214 
   1215 void parse_local_decl(Parser* p, const DeclSpecs* specs) {
   1216   if (accept_punct(p, ';')) return;
   1217   parse_init_declarator(p, specs);
   1218   while (accept_punct(p, ',')) {
   1219     parse_init_declarator(p, specs);
   1220   }
   1221   expect_punct(p, ';', "';' after declaration");
   1222 }
   1223 
   1224 /* ============================================================
   1225  * External (top-level) declarations
   1226  * ============================================================ */
   1227 
   1228 void parse_param_list(Parser* p, ParamInfo** infos_out, u16* nparams_out,
   1229                       u8* variadic_out) {
   1230   ParamInfo* infos;
   1231   u32 cap = 4;
   1232   u32 n = 0;
   1233   *variadic_out = 0;
   1234   *infos_out = NULL;
   1235   *nparams_out = 0;
   1236 
   1237   if (is_punct(&p->cur, ')')) {
   1238     return;
   1239   }
   1240   if (is_kw(p, &p->cur, KW_VOID)) {
   1241     Tok n2 = peek1(p);
   1242     if (is_punct(&n2, ')')) {
   1243       advance(p); /* `void` */
   1244       return;     /* `(void)` */
   1245     }
   1246   }
   1247 
   1248   infos = (ParamInfo*)arena_array(p->pool->arena, ParamInfo, cap);
   1249   for (;;) {
   1250     DeclSpecs specs;
   1251     Sym pname = 0;
   1252     SrcLoc ploc = {0, 0, 0};
   1253     const Type* pty;
   1254     if (accept_punct(p, P_ELLIPSIS)) {
   1255       if (n == 0) perr(p, "ellipsis requires a preceding parameter");
   1256       *variadic_out = 1;
   1257       break;
   1258     }
   1259     if (!parse_decl_specs(p, &specs)) {
   1260       perr(p, "expected parameter type");
   1261     }
   1262     if ((specs.storage_explicit && specs.storage != DS_REGISTER) ||
   1263         specs.storage == DS_TYPEDEF || (specs.flags & DF_THREAD)) {
   1264       perr(p, "invalid storage-class specifier in parameter declaration");
   1265     }
   1266     p->param_vla_bound_len = 0;
   1267     p->in_param_decl++;
   1268     pty = parse_declarator_full(p, specs.type, /*allow_abstract=*/1, &pname,
   1269                                 &ploc);
   1270     p->in_param_decl--;
   1271     const Type* declared_pty = pty;
   1272     if (pty && pty->kind == TY_ARRAY) {
   1273       pty = type_ptr(p->pool, pty->arr.elem);
   1274     } else if (pty && pty->kind == TY_FUNC) {
   1275       pty = type_ptr(p->pool, pty);
   1276     }
   1277     if (pty && pty->kind == TY_VOID) {
   1278       perr(p, "'void' must be the only parameter");
   1279     }
   1280     validate_decl_type_constraints(p, &specs, pty, /*is_function=*/0,
   1281                                    /*is_member=*/0);
   1282     if (pname) {
   1283       for (u32 pi = 0; pi < n; ++pi) {
   1284         if (infos[pi].name == pname) perr(p, "redefinition of parameter");
   1285       }
   1286     }
   1287     if (n == cap) {
   1288       cap *= 2;
   1289       ParamInfo* nbuf = (ParamInfo*)arena_array(p->pool->arena, ParamInfo, cap);
   1290       memcpy(nbuf, infos, sizeof(ParamInfo) * n);
   1291       infos = nbuf;
   1292     }
   1293     infos[n].name = pname;
   1294     infos[n].type = pty;
   1295     infos[n].declared_type = declared_pty;
   1296     infos[n].loc = ploc;
   1297     infos[n].vla_bounds = NULL;
   1298     infos[n].vla_bound_len = p->param_vla_bound_len;
   1299     if (p->param_vla_bound_len) {
   1300       ParamVLABoundExpr* bounds = arena_array(p->pool->arena, ParamVLABoundExpr,
   1301                                               p->param_vla_bound_len);
   1302       memcpy(bounds, p->param_vla_bounds,
   1303              sizeof(ParamVLABoundExpr) * p->param_vla_bound_len);
   1304       infos[n].vla_bounds = bounds;
   1305     }
   1306     ++n;
   1307     if (!accept_punct(p, ',')) break;
   1308   }
   1309   *infos_out = infos;
   1310   *nparams_out = (u16)n;
   1311 }
   1312 
   1313 static SymEntry* declare_function(Parser* p, Sym fname, const Type* fn_ty,
   1314                                   const DeclSpecs* specs, SrcLoc fname_loc,
   1315                                   const Attr* dattrs, Sym asm_label,
   1316                                   ObjSecId* out_section_id, u32* out_decl_flags,
   1317                                   Sym* out_alias_target) {
   1318   SymEntry* visible;
   1319   if (out_section_id) *out_section_id = OBJ_SEC_NONE;
   1320   if (out_decl_flags) *out_decl_flags = 0;
   1321   if (out_alias_target) *out_alias_target = 0;
   1322   SymEntry* existing = scope_lookup_current(p, fname);
   1323   if (existing && existing->kind != SEK_FUNC) {
   1324     perr(p, "redefinition of identifier");
   1325   }
   1326   if (existing && existing->kind == SEK_FUNC) {
   1327     const Type* composite = NULL;
   1328     CSemCheck chk =
   1329         c_sem_check_redeclaration(p->pool, existing->type, fn_ty, &composite);
   1330     if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
   1331     if (specs->storage == DS_STATIC && existing->linkage == DL_EXTERNAL) {
   1332       perr(p, "static declaration follows non-static declaration");
   1333     }
   1334     existing->type = composite ? composite : existing->type;
   1335     Decl tmp;
   1336     memset(&tmp, 0, sizeof tmp);
   1337     attr_list_to_decl(p->c, p->decls, specs->attrs, &tmp);
   1338     attr_list_to_decl(p->c, p->decls, dattrs, &tmp);
   1339     if (out_section_id) *out_section_id = tmp.section_id;
   1340     if (out_decl_flags) *out_decl_flags = tmp.flags;
   1341     if (out_alias_target) *out_alias_target = tmp.alias_target;
   1342     decl_apply_redecl_flags(p->decls, existing->decl_id, tmp.flags);
   1343     external_func_remember(p, fname, existing);
   1344     return existing;
   1345   }
   1346   /* `existing` is provably NULL here (both branches above perr or return), so
   1347    * the current scope has no binding for fname. Skip re-probing it: walk from
   1348    * the parent scope. */
   1349   visible = scope_lookup_from(p->scope ? p->scope->parent : NULL, fname);
   1350   if (!existing && visible && visible->kind == SEK_FUNC) {
   1351     existing = visible;
   1352   }
   1353   if (!existing) {
   1354     existing = external_func_lookup(p, fname);
   1355   }
   1356   if (existing) {
   1357     const Type* composite = NULL;
   1358     CSemCheck chk =
   1359         c_sem_check_redeclaration(p->pool, existing->type, fn_ty, &composite);
   1360     if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
   1361     if (specs->storage == DS_STATIC && existing->linkage == DL_EXTERNAL) {
   1362       perr(p, "static declaration follows non-static declaration");
   1363     }
   1364     if (scope_lookup_current(p, fname) != existing) {
   1365       SymEntry* e = scope_define(p, fname, SEK_FUNC,
   1366                                  composite ? composite : existing->type);
   1367       e->v.sym = existing->v.sym;
   1368       sym_set_decl(e, existing->decl_id, (DeclStorage)existing->storage,
   1369                    (DeclLinkage)existing->linkage, existing->decl_flags,
   1370                    (DeclState)existing->decl_state);
   1371       existing = e;
   1372     } else if (composite) {
   1373       existing->type = composite;
   1374     }
   1375     {
   1376       Decl tmp;
   1377       memset(&tmp, 0, sizeof tmp);
   1378       attr_list_to_decl(p->c, p->decls, specs->attrs, &tmp);
   1379       attr_list_to_decl(p->c, p->decls, dattrs, &tmp);
   1380       if (out_section_id) *out_section_id = tmp.section_id;
   1381       if (out_decl_flags) *out_decl_flags = tmp.flags;
   1382       if (out_alias_target) *out_alias_target = tmp.alias_target;
   1383       decl_apply_redecl_flags(p->decls, existing->decl_id, tmp.flags);
   1384     }
   1385     external_func_remember(p, fname, existing);
   1386     return existing;
   1387   }
   1388   {
   1389     Decl decl_in;
   1390     DeclId did;
   1391     ObjSymId fsym;
   1392     SymEntry* e;
   1393     memset(&decl_in, 0, sizeof decl_in);
   1394     decl_in.name = fname;
   1395     decl_in.asm_name = asm_label;
   1396     decl_in.type = fn_ty;
   1397     decl_in.loc = fname_loc;
   1398     decl_in.storage =
   1399         (specs->storage == DS_STATIC ||
   1400          ((specs->flags & DF_INLINE) && specs->storage != DS_EXTERN))
   1401             ? DS_STATIC
   1402             : DS_EXTERN;
   1403     decl_in.linkage =
   1404         (decl_in.storage == DS_STATIC) ? DL_INTERNAL : DL_EXTERNAL;
   1405     decl_in.visibility =
   1406         decl_in.linkage == DL_EXTERNAL ? p->default_visibility : SV_DEFAULT;
   1407     attr_list_to_decl(p->c, p->decls, specs->attrs, &decl_in);
   1408     attr_list_to_decl(p->c, p->decls, dattrs, &decl_in);
   1409     /* The `inline` specifier is a keyword carried on specs->flags, separate from
   1410      * the __attribute__ flags attr_list_to_decl applies. It must be merged onto
   1411      * the decl so decl_inline_policy() sees it on both the recorded symbol attrs
   1412      * (decl_declare below) and the returned decl flags (out_decl_flags, used to
   1413      * build the function descriptor). Without this, `static inline` functions
   1414      * silently fell back to the DEFAULT inline policy — only the always_inline /
   1415      * noinline attributes reached codegen — so a `static inline` body got no
   1416      * stronger inlining than a plain static one. */
   1417     decl_in.flags |= (specs->flags & DF_INLINE);
   1418     did = decl_declare(p->decls, &decl_in);
   1419     fsym = decl_obj_sym(p->decls, did);
   1420     e = scope_define(p, fname, SEK_FUNC, fn_ty);
   1421     e->v.sym = fsym;
   1422     sym_set_decl(e, did, decl_in.storage, decl_in.linkage, decl_in.flags,
   1423                  DSTATE_DECLARED);
   1424     external_func_remember(p, fname, e);
   1425     if (out_section_id) *out_section_id = decl_in.section_id;
   1426     if (out_decl_flags) *out_decl_flags = decl_in.flags;
   1427     if (out_alias_target) *out_alias_target = decl_in.alias_target;
   1428     return e;
   1429   }
   1430 }
   1431 
   1432 static void parse_function_body(Parser* p, ObjSymId fsym, const Type* fn_ty,
   1433                                 const ABIFuncInfo* abi, const ParamInfo* infos,
   1434                                 u16 nparams, SrcLoc fname_loc,
   1435                                 ObjSecId section_id, u32 decl_flags) {
   1436   CGFuncDesc fd;
   1437   CGParamDesc* pds = NULL;
   1438 
   1439   memset(&fd, 0, sizeof fd);
   1440   fd.sym = fsym;
   1441   fd.text_section_id = section_id;
   1442   fd.group_id = OBJ_GROUP_NONE;
   1443   fd.fn_type = fn_ty;
   1444   fd.abi = abi;
   1445   fd.params = NULL;
   1446   fd.nparams = nparams;
   1447   fd.loc = fname_loc;
   1448   if (decl_flags & DF_NORETURN) fd.flags |= CGFD_NORETURN;
   1449   if (decl_flags & DF_NOINLINE)
   1450     fd.inline_policy = KIT_CG_INLINE_NEVER;
   1451   else if (decl_flags & DF_ALWAYS_INLINE)
   1452     fd.inline_policy = KIT_CG_INLINE_ALWAYS;
   1453   else if (decl_flags & DF_INLINE)
   1454     fd.inline_policy = KIT_CG_INLINE_HINT;
   1455 
   1456   if (nparams) {
   1457     pds = (CGParamDesc*)arena_array(p->pool->arena, CGParamDesc, nparams);
   1458     memset(pds, 0, sizeof(CGParamDesc) * nparams);
   1459     for (u16 i = 0; i < nparams; ++i) {
   1460       pds[i].index = i;
   1461       pds[i].name = infos[i].name;
   1462       pds[i].type = infos[i].type;
   1463       pds[i].slot = FRAME_SLOT_NONE;
   1464       pds[i].abi = &abi->params[i];
   1465       pds[i].incoming = NULL;
   1466       pds[i].nincoming = 0;
   1467       pds[i].loc = infos[i].loc;
   1468     }
   1469     fd.params = pds;
   1470   }
   1471 
   1472   scope_push(p); /* parameter scope */
   1473   GotoLabel* saved_goto_labels = p->goto_labels;
   1474   SwitchCtx* saved_switch = p->cur_switch;
   1475   u8 saved_computed_goto = p->computed_goto_emitted;
   1476   p->goto_labels = NULL;
   1477   p->cur_switch = NULL;
   1478   p->computed_goto_emitted = 0;
   1479   c_cg_set_loc(p, fname_loc);
   1480   /* Record whether this body emits before func_begin (which is itself gated on
   1481    * emit-enabled): goto-label allocation keys off this, not the momentary
   1482    * suppress_codegen depth, so a label first referenced inside a constant-false
   1483    * region still gets a real CG-label id rather than the suppression sentinel.
   1484    */
   1485   p->cur_func_emits = (u8)c_cg_emit_enabled(p);
   1486   p->stack_protector_enabled = 0;
   1487   c_cg_func_begin(p, &fd);
   1488 
   1489   for (u16 i = 0; i < nparams; ++i) {
   1490     FrameSlotDesc fsd;
   1491     FrameSlot s;
   1492     SymEntry* e;
   1493     memset(&fsd, 0, sizeof fsd);
   1494     fsd.type = infos[i].type;
   1495     fsd.name = infos[i].name;
   1496     fsd.loc = infos[i].loc;
   1497     fsd.size = c_abi_sizeof(p->abi, p->pool, infos[i].type);
   1498     fsd.align = c_abi_alignof(p->abi, p->pool, infos[i].type);
   1499     fsd.kind = FS_PARAM;
   1500     fsd.flags = FSF_NONE;
   1501     s = c_cg_param_slot(p, i, &fsd);
   1502     pds[i].slot = s;
   1503     if (infos[i].name) {
   1504       e = scope_define_checked(p, infos[i].name, SEK_LOCAL, infos[i].type);
   1505       e->v.slot = s;
   1506       sym_set_decl(e, DECL_NONE, DS_AUTO, DL_NONE, DF_NONE, DSTATE_DEFINED);
   1507       e->vla_bounds = build_param_vla_bounds(p, &infos[i], infos[i].loc);
   1508     }
   1509   }
   1510 
   1511   if (p->stack_protector_mode == KIT_STACK_PROTECTOR_ALL ||
   1512       p->stack_protector_preselected)
   1513     c_stack_protector_enable(p);
   1514 
   1515   parse_compound_stmt(p);
   1516   if (fn_ty->fn.ret && fn_ty->fn.ret->kind != TY_VOID &&
   1517       fn_ty->fn.ret->kind != TY_STRUCT && fn_ty->fn.ret->kind != TY_UNION) {
   1518     c_cg_push_int(p, 0, fn_ty->fn.ret);
   1519     c_cg_ret(p, 1);
   1520   } else {
   1521     c_cg_ret(p, 0);
   1522   }
   1523   for (GotoLabel* gl = p->goto_labels; gl; gl = gl->next) {
   1524     if (!gl->placed) {
   1525       compiler_panic(p->c, gl->first_use, "goto to undefined label");
   1526     }
   1527   }
   1528   p->goto_labels = saved_goto_labels;
   1529   p->cur_switch = saved_switch;
   1530   p->computed_goto_emitted = saved_computed_goto;
   1531   c_cg_func_end(p);
   1532   scope_pop(p);
   1533 }
   1534 
   1535 /* Parse one external declaration. */
   1536 static void parse_external_decl(Parser* p) {
   1537   DeclSpecs specs;
   1538   Sym name;
   1539   SrcLoc loc;
   1540   const Type* base_ty;
   1541   Attr* dattrs = NULL;
   1542   DeclaratorInfo dinfo;
   1543 
   1544   if (!parse_decl_specs(p, &specs)) {
   1545     perr(p, "expected declaration");
   1546   }
   1547   if (specs.storage == DS_AUTO && specs.storage_explicit) {
   1548     perr(p, "invalid storage-class specifier at file scope");
   1549   }
   1550 
   1551   if (accept_punct(p, ';')) return;
   1552 
   1553   if (specs.storage == DS_TYPEDEF) {
   1554     for (;;) {
   1555       Sym tname = 0;
   1556       SrcLoc tloc = {0, 0, 0};
   1557       const Type* tty =
   1558           parse_declarator_full(p, specs.type,
   1559                                 /*allow_abstract=*/0, &tname, &tloc);
   1560       validate_decl_type_constraints(p, &specs, tty,
   1561                                      tty && tty->kind == TY_FUNC,
   1562                                      /*is_member=*/0);
   1563       if (is_punct(&p->cur, '=')) {
   1564         perr(p, "typedef declarator cannot have initializer");
   1565       }
   1566       {
   1567         SymEntry* te = scope_define_checked(p, tname, SEK_TYPEDEF, tty);
   1568         sym_set_decl(te, DECL_NONE, DS_TYPEDEF, DL_NONE, specs.flags,
   1569                      DSTATE_DECLARED);
   1570       }
   1571       (void)tloc;
   1572       if (!accept_punct(p, ',')) break;
   1573     }
   1574     expect_punct(p, ';', "';' after typedef declaration");
   1575     return;
   1576   }
   1577 
   1578   base_ty = parse_declarator_full_info(p, specs.type, /*allow_abstract=*/0,
   1579                                        &name, &loc, &dattrs, &dinfo);
   1580 
   1581   if (base_ty && base_ty->kind == TY_FUNC) {
   1582     ParamInfo* infos = NULL;
   1583     u16 nparams = 0;
   1584     const Type* fn_ty;
   1585     const ABIFuncInfo* abi;
   1586     SymEntry* fent;
   1587 
   1588     fn_ty = base_ty;
   1589     infos = dinfo.fn_params;
   1590     nparams = dinfo.fn_nparams;
   1591     validate_decl_type_constraints(p, &specs, fn_ty, /*is_function=*/1,
   1592                                    /*is_member=*/0);
   1593     abi = c_abi_func_info(p->abi, p->pool, fn_ty);
   1594 
   1595     ObjSecId fn_section_id;
   1596     u32 fn_decl_flags;
   1597     Sym fn_alias_target;
   1598     fent =
   1599         declare_function(p, name, fn_ty, &specs, loc, dattrs, dinfo.asm_label,
   1600                          &fn_section_id, &fn_decl_flags, &fn_alias_target);
   1601     attr_list_append(&fent->attrs, dattrs);
   1602 
   1603     if (is_punct(&p->cur, '{')) {
   1604       int suppress_body_codegen = specs.storage == DS_EXTERN &&
   1605                                   ((specs.flags | fn_decl_flags) & DF_INLINE);
   1606       if (fent->defined) perr(p, "redefinition of function");
   1607       fent->defined = 1;
   1608       fent->decl_state = DSTATE_FUNC_DEFINED;
   1609       Sym saved_func_name = p->cur_func_name;
   1610       const Type* saved_func_ret = p->cur_func_ret;
   1611       u8 saved_func_emits = p->cur_func_emits;
   1612       p->cur_func_name = name;
   1613       p->cur_func_ret = fn_ty->fn.ret;
   1614       if (p->stack_protector_mode == KIT_STACK_PROTECTOR_BASIC ||
   1615           p->stack_protector_mode == KIT_STACK_PROTECTOR_STRONG) {
   1616         record_function_body(p);
   1617         p->stack_protector_scan = 1;
   1618         p->stack_protector_scan_selected = 0;
   1619         c_cg_codegen_suppress_push(p);
   1620         parse_function_body(p, fent->v.sym, fn_ty, abi, infos, nparams, loc,
   1621                             fn_section_id, fn_decl_flags);
   1622         c_cg_codegen_suppress_pop(p);
   1623         p->stack_protector_scan = 0;
   1624         p->stack_protector_preselected =
   1625             p->stack_protector_scan_selected ? 1u : 0u;
   1626         rewind_function_body(p, 0);
   1627       }
   1628       if (suppress_body_codegen) c_cg_codegen_suppress_push(p);
   1629       parse_function_body(p, fent->v.sym, fn_ty, abi, infos, nparams, loc,
   1630                           fn_section_id, fn_decl_flags);
   1631       if (suppress_body_codegen) c_cg_codegen_suppress_pop(p);
   1632       p->stack_protector_preselected = 0;
   1633       p->function_replay_active = 0;
   1634       p->function_replay_hold = 0;
   1635       p->cur_func_name = saved_func_name;
   1636       p->cur_func_ret = saved_func_ret;
   1637       p->cur_func_emits = saved_func_emits;
   1638       return;
   1639     }
   1640     if (accept_punct(p, ';')) {
   1641       if (fn_alias_target != 0) {
   1642         SymEntry* te = scope_lookup(p, fn_alias_target);
   1643         if (!te) {
   1644           const char* nm = kit_sym_str(p->pool->c, fn_alias_target).s;
   1645           compiler_panic(p->c, loc, "alias target '%.*s' is undefined",
   1646                          KIT_SLICE_ARG(kit_slice_cstr(nm ? nm : "?")));
   1647         }
   1648         KitCgAlias alias;
   1649         memset(&alias, 0, sizeof alias);
   1650         alias.display_name = name;
   1651         alias.linkage_name = kit_cg_c_linkage_name(p->c, name);
   1652         alias.target = te->v.sym;
   1653         alias.sym.bind =
   1654             (fn_decl_flags & DF_WEAK) ? KIT_SB_WEAK : KIT_SB_GLOBAL;
   1655         {
   1656           const Decl* fd = decl_get(p->decls, fent->decl_id);
   1657           alias.sym.visibility =
   1658               fd ? (KitCgVisibility)fd->visibility : KIT_CG_VIS_DEFAULT;
   1659         }
   1660         if (kit_cg_alias(p->cg, alias) == KIT_CG_SYM_NONE) {
   1661           const char* nm = kit_sym_str(p->pool->c, fn_alias_target).s;
   1662           compiler_panic(p->c, loc, "alias target '%.*s' is undefined",
   1663                          KIT_SLICE_ARG(kit_slice_cstr(nm ? nm : "?")));
   1664         }
   1665       }
   1666       return;
   1667     }
   1668     perr(p, "expected '{' or ';' after function declarator");
   1669   }
   1670 
   1671   /* Global object declaration. */
   1672   for (;;) {
   1673     int has_init = is_punct(&p->cur, '=');
   1674     int is_pure_extern =
   1675         (specs.storage == DS_EXTERN || specs.storage == DS_REGISTER) &&
   1676         !has_init;
   1677     SymEntry* existing = scope_lookup_current(p, name);
   1678     ObjSymId sym = OBJ_SYM_NONE;
   1679     ObjSecId section_id = OBJ_SEC_NONE;
   1680     SymEntry* e = NULL;
   1681 
   1682     if (existing && existing->kind != SEK_GLOBAL) {
   1683       perr(p, "redefinition of identifier");
   1684     }
   1685     validate_decl_type_constraints(p, &specs, base_ty, /*is_function=*/0,
   1686                                    /*is_member=*/0);
   1687 
   1688     if (existing && existing->kind == SEK_GLOBAL) {
   1689       const Type* composite = NULL;
   1690       CSemCheck chk = c_sem_check_redeclaration(p->pool, existing->type,
   1691                                                 base_ty, &composite);
   1692       if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
   1693       if (specs.storage == DS_STATIC && existing->linkage == DL_EXTERNAL) {
   1694         perr(p, "static declaration follows non-static declaration");
   1695       }
   1696       sym = existing->v.sym;
   1697       e = existing;
   1698       if (has_init && e->defined) {
   1699         perr(p, "redefinition of object");
   1700       }
   1701       if (composite) e->type = composite;
   1702       base_ty = e->type;
   1703     } else {
   1704       Decl decl_in;
   1705       DeclId did;
   1706       memset(&decl_in, 0, sizeof decl_in);
   1707       decl_in.name = name;
   1708       decl_in.asm_name = dinfo.asm_label;
   1709       decl_in.type = base_ty;
   1710       decl_in.loc = loc;
   1711       if (specs.storage == DS_STATIC) {
   1712         decl_in.storage = DS_STATIC;
   1713         decl_in.linkage = DL_INTERNAL;
   1714       } else {
   1715         decl_in.storage = DS_EXTERN;
   1716         decl_in.linkage = DL_EXTERNAL;
   1717       }
   1718       decl_in.visibility =
   1719           decl_in.linkage == DL_EXTERNAL ? p->default_visibility : SV_DEFAULT;
   1720       decl_in.flags = specs.flags & DF_THREAD;
   1721       attr_list_to_decl(p->c, p->decls, specs.attrs, &decl_in);
   1722       attr_list_to_decl(p->c, p->decls, dattrs, &decl_in);
   1723       did = decl_declare(p->decls, &decl_in);
   1724       sym = decl_obj_sym(p->decls, did);
   1725       section_id = decl_in.section_id;
   1726       e = scope_define(p, name, SEK_GLOBAL, base_ty);
   1727       e->v.sym = sym;
   1728       sym_set_decl(e, did, decl_in.storage, decl_in.linkage, decl_in.flags,
   1729                    DSTATE_DECLARED);
   1730     }
   1731     attr_list_append(&e->attrs, dattrs);
   1732 
   1733     u32 attr_align = attrs_pick_aligned(specs.attrs);
   1734     {
   1735       u32 a2 = attrs_pick_aligned(dattrs);
   1736       if (a2 > attr_align) attr_align = a2;
   1737     }
   1738     u32 align_eff = (specs.align > attr_align) ? specs.align : attr_align;
   1739 
   1740     if (has_init) {
   1741       if (e) e->defined = 1;
   1742       if (e) e->decl_state = DSTATE_DEFINED;
   1743       advance(p); /* '=' */
   1744       if (base_ty && base_ty->kind == TY_ARRAY && base_ty->arr.incomplete) {
   1745         const Type* completed = complete_incomplete_array(p, base_ty);
   1746         if (completed != base_ty) {
   1747           base_ty = completed;
   1748           if (e) e->type = base_ty;
   1749         }
   1750       }
   1751       define_static_object(p, sym, section_id, base_ty, specs.quals,
   1752                            /*has_init=*/1, loc, align_eff);
   1753     } else if (!is_pure_extern) {
   1754       if (e && e->decl_state == DSTATE_DECLARED) {
   1755         e->decl_state = DSTATE_TENTATIVE;
   1756       }
   1757       define_static_object(p, sym, section_id, base_ty, specs.quals,
   1758                            /*has_init=*/0, loc, align_eff);
   1759     }
   1760 
   1761     if (!accept_punct(p, ',')) break;
   1762     dattrs = NULL;
   1763     base_ty = parse_declarator_full_info(p, specs.type, /*allow_abstract=*/0,
   1764                                          &name, &loc, &dattrs, &dinfo);
   1765     if (base_ty && base_ty->kind == TY_FUNC) {
   1766       perr(p, "function declarator in object declaration list");
   1767     }
   1768   }
   1769   expect_punct(p, ';', "';' after global declaration");
   1770 }
   1771 
   1772 static void parse_file_scope_asm(Parser* p) {
   1773   u8* bytes;
   1774   size_t nbytes;
   1775   advance(p); /* asm / __asm__ */
   1776   for (;;) {
   1777     if (is_kw(p, &p->cur,
   1778               KW_VOLATILE)) { /* matches `volatile` and `__volatile__` */
   1779       advance(p);
   1780       continue;
   1781     }
   1782     break;
   1783   }
   1784   expect_punct(p, '(', "'(' after file-scope asm");
   1785   if (p->cur.kind != TOK_STR) {
   1786     perr(p, "expected string literal in file-scope asm");
   1787   }
   1788   bytes = decode_string_literal(p, &p->cur, &nbytes);
   1789   advance(p);
   1790   expect_punct(p, ')', "')' after file-scope asm");
   1791   expect_punct(p, ';', "';' after file-scope asm");
   1792   if (nbytes > 0) --nbytes; /* drop decode_string_literal's trailing NUL */
   1793   if (c_cg_emit_enabled(p)) {
   1794     KitSlice asm_src = {{(const char*)bytes}, nbytes};
   1795     kit_cg_file_scope_asm(p->cg, asm_src);
   1796   }
   1797 }
   1798 
   1799 static void parse_translation_unit(Parser* p) {
   1800   while (p->cur.kind != TOK_EOF) {
   1801     if (p->cur.kind == TOK_NEWLINE || is_pp_hash(&p->cur)) {
   1802       advance(p);
   1803       continue;
   1804     }
   1805     if (is_kw(p, &p->cur, KW_STATIC_ASSERT)) {
   1806       parse_static_assert(p);
   1807       continue;
   1808     }
   1809     if (is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM)) {
   1810       parse_file_scope_asm(p);
   1811       continue;
   1812     }
   1813     if (accept_punct(p, ';')) {
   1814       continue;
   1815     }
   1816     parse_external_decl(p);
   1817   }
   1818 }
   1819 
   1820 /* ============================================================
   1821  * Entry point
   1822  * ============================================================ */
   1823 
   1824 static u8 parser_default_visibility(KitSymVis vis) {
   1825   switch (vis) {
   1826     case KIT_SV_HIDDEN:
   1827     case KIT_SV_INTERNAL:
   1828       return SV_HIDDEN;
   1829     case KIT_SV_PROTECTED:
   1830       return SV_PROTECTED;
   1831     case KIT_SV_DEFAULT:
   1832     default:
   1833       return SV_DEFAULT;
   1834   }
   1835 }
   1836 
   1837 void parse_c(Compiler* c, Pool* pool, Pp* pp, DeclTable* decls, CG* cg,
   1838              KitSymVis default_visibility, int auto_var_init,
   1839              int stack_protector,
   1840              uint64_t disabled_backend_features) {
   1841   Parser p;
   1842   CKw i;
   1843   u32 syscall_i;
   1844 
   1845   memset(&p, 0, sizeof p);
   1846   p.c = c;
   1847   p.pp = pp;
   1848   p.decls = decls;
   1849   p.cg = cg;
   1850   p.abi = c;
   1851   p.pool = pool;
   1852   p.default_visibility = parser_default_visibility(default_visibility);
   1853   p.auto_var_init = (u8)auto_var_init;
   1854   p.stack_protector_mode = (u8)stack_protector;
   1855   p.general_regs_only =
   1856       (disabled_backend_features & KIT_CG_BACKEND_SIMD) != 0;
   1857 
   1858   /* Index storage for the scope/tag tables and the external-function table all
   1859    * comes from the arena via the pool's shared arena-heap facade. */
   1860   ExternalFuncMap_init(&p.external_funcs, &p.pool->arena_heap);
   1861   KwTab_init(&p.kw_map, &p.pool->arena_heap);
   1862   BindingTab_init(&p.bind, &p.pool->arena_heap);
   1863 
   1864   for (i = (CKw)1; i < KW_COUNT; ++i) {
   1865     p.kw_sym[i] = kit_sym_intern(p.pool->c, kit_slice_cstr(kw_names[i]));
   1866     (void)KwTab_set(&p.kw_map, p.kw_sym[i], (u8)i); /* canonical keyword */
   1867   }
   1868 
   1869   p.sym_b_alloca = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_alloca"));
   1870   p.sym_b_ctz = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_ctz"));
   1871   p.sym_b_ctzl = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_ctzl"));
   1872   p.sym_b_ctzll = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_ctzll"));
   1873   p.sym_b_clz = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_clz"));
   1874   p.sym_b_clzl = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_clzl"));
   1875   p.sym_b_clzll = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_clzll"));
   1876   p.sym_b_trap = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_trap"));
   1877   p.sym_b_unreachable =
   1878       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_unreachable"));
   1879   p.sym_b_return_address =
   1880       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_return_address"));
   1881   p.sym_b_frame_address =
   1882       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_frame_address"));
   1883   p.sym_b_readcyclecounter =
   1884       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_readcyclecounter"));
   1885   for (syscall_i = 0; syscall_i < 7u; ++syscall_i) {
   1886     char name[16];
   1887     memcpy(name, "__kit_syscall", 13u);
   1888     name[13] = (char)('0' + syscall_i);
   1889     name[14] = '\0';
   1890     p.sym_kit_syscall[syscall_i] =
   1891         kit_sym_intern(p.pool->c, kit_slice_cstr(name));
   1892   }
   1893   p.sym_b_memcpy = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_memcpy"));
   1894   p.sym_b_memmove =
   1895       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_memmove"));
   1896   p.sym_b_memcmp = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_memcmp"));
   1897   p.sym_b_memset = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_memset"));
   1898   p.sym_b_clear_cache =
   1899       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin___clear_cache"));
   1900   p.sym_b_isnan = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_isnan"));
   1901   p.sym_b_fabs = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_fabs"));
   1902   p.sym_b_fabsf = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_fabsf"));
   1903   p.sym_b_fabsl = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_fabsl"));
   1904   p.sym_b_inf = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_inf"));
   1905   p.sym_b_inff = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_inff"));
   1906   p.sym_b_infl = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_infl"));
   1907   p.sym_b_huge_val =
   1908       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_huge_val"));
   1909   p.sym_b_huge_valf =
   1910       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_huge_valf"));
   1911   p.sym_b_huge_vall =
   1912       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_huge_vall"));
   1913   p.sym_b_nan = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_nan"));
   1914   p.sym_b_nanf = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_nanf"));
   1915   p.sym_b_nanl = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_nanl"));
   1916   p.sym_b_isless = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_isless"));
   1917   p.sym_b_islessequal =
   1918       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_islessequal"));
   1919   p.sym_b_isgreater =
   1920       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_isgreater"));
   1921   p.sym_b_isgreaterequal =
   1922       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_isgreaterequal"));
   1923   p.sym_b_islessgreater =
   1924       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_islessgreater"));
   1925   p.sym_b_isunordered =
   1926       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_isunordered"));
   1927   p.sym_func = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__func__"));
   1928   p.sym_func_gcc = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__FUNCTION__"));
   1929   p.sym_pretty_func_gcc =
   1930       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__PRETTY_FUNCTION__"));
   1931   p.sym_b_expect = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_expect"));
   1932   p.sym_b_offsetof =
   1933       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_offsetof"));
   1934   p.sym_b_constant_p =
   1935       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_constant_p"));
   1936   p.sym_b_va_list =
   1937       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_va_list"));
   1938   p.sym_b_va_start =
   1939       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_va_start"));
   1940   p.sym_b_va_arg = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_va_arg"));
   1941   p.sym_b_va_end = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_va_end"));
   1942   p.sym_b_va_copy =
   1943       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__builtin_va_copy"));
   1944   p.sym_attribute = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__attribute__"));
   1945   p.sym_volatile_alias =
   1946       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__volatile__"));
   1947   p.sym_alignof_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__alignof__"));
   1948   p.sym_typeof_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__typeof"));
   1949   p.sym_typeof_alias2 =
   1950       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__typeof__"));
   1951   p.sym_asm_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__asm"));
   1952   p.sym_inline_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__inline"));
   1953   p.sym_inline_alias2 = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__inline__"));
   1954   /* __restrict / __restrict__: GCC keyword spellings of `restrict`. glibc
   1955    * headers use these as real keywords (and #undef any fallback macro under
   1956    * __GNUC__), so recognize them in the parser, not just via a pp macro. */
   1957   p.sym_restrict_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__restrict"));
   1958   p.sym_restrict_alias2 =
   1959       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__restrict__"));
   1960   p.sym_thread_alias = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__thread"));
   1961   /* GNU alias spellings -> their canonical CKw. Registered after the canonical
   1962    * keywords above so the canonical mapping always wins (matching the old
   1963    * ident_kw_inline fall-through, which scanned kw_sym[] before the aliases).
   1964    */
   1965   (void)KwTab_set(&p.kw_map, p.sym_alignof_alias, (u8)KW_ALIGNOF);
   1966   (void)KwTab_set(&p.kw_map, p.sym_asm_alias, (u8)KW_BUILTIN_ASM);
   1967   (void)KwTab_set(&p.kw_map, p.sym_inline_alias, (u8)KW_INLINE);
   1968   (void)KwTab_set(&p.kw_map, p.sym_inline_alias2, (u8)KW_INLINE);
   1969   (void)KwTab_set(&p.kw_map, p.sym_restrict_alias, (u8)KW_RESTRICT);
   1970   (void)KwTab_set(&p.kw_map, p.sym_restrict_alias2, (u8)KW_RESTRICT);
   1971   (void)KwTab_set(&p.kw_map, p.sym_thread_alias, (u8)KW_THREAD_LOCAL);
   1972   (void)KwTab_set(&p.kw_map, p.sym_volatile_alias, (u8)KW_VOLATILE);
   1973   p.sym_int128 = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__int128"));
   1974   p.sym_int128_t = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__int128_t"));
   1975   p.sym_uint128_t = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__uint128_t"));
   1976   p.sym_a_load_n = kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_load_n"));
   1977   p.sym_a_store_n =
   1978       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_store_n"));
   1979   p.sym_a_exchange_n =
   1980       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_exchange_n"));
   1981   p.sym_a_fetch_add =
   1982       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_add"));
   1983   p.sym_a_fetch_sub =
   1984       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_sub"));
   1985   p.sym_a_fetch_and =
   1986       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_and"));
   1987   p.sym_a_fetch_or =
   1988       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_or"));
   1989   p.sym_a_fetch_xor =
   1990       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_xor"));
   1991   p.sym_a_fetch_nand =
   1992       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_fetch_nand"));
   1993   p.sym_a_cas_n =
   1994       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_compare_exchange_n"));
   1995   p.sym_a_always_lock_free =
   1996       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_always_lock_free"));
   1997   p.sym_a_is_lock_free =
   1998       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_is_lock_free"));
   1999   p.sym_a_thread_fence =
   2000       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_thread_fence"));
   2001   p.sym_a_signal_fence =
   2002       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__atomic_signal_fence"));
   2003   p.sym_sync_synchronize =
   2004       kit_sym_intern(p.pool->c, KIT_SLICE_LIT("__sync_synchronize"));
   2005 
   2006   p.scope = scope_new(&p, NULL);
   2007 
   2008   p.cur = fetch_tok(&p);
   2009 
   2010   parse_translation_unit(&p);
   2011 }