kit

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

parse_type.c (61640B)


      1 /* parse_type.c — decl-specs, struct/union/enum, declarators,
      2  * __attribute__ parsing. */
      3 
      4 #include "parse/parse_priv.h"
      5 
      6 /* ============================================================
      7  * Type helpers
      8  * ============================================================ */
      9 
     10 static const Type* ty_int(Parser* p) { return type_prim(p->pool, TY_INT); }
     11 static const Type* ty_size_t(Parser* p) {
     12   return c_abi_size_type(p->abi, p->pool);
     13 }
     14 
     15 /* __int128 is a 16-byte scalar that the ABI, runtime ti3 helpers, and the
     16  * HAS_INT128 capability only support on 64-bit targets (matching GCC/Clang,
     17  * which reject __int128 on 32-bit architectures). Gate on the target pointer
     18  * width: ptr_size == 8 means 64-bit (rv64/x64/aa64) and int128 is available;
     19  * a 32-bit target (rv32, with a 4-byte pointer) has no working int128. */
     20 static int target_has_int128(Parser* p) {
     21   return kit_compiler_target_spec(p->c).ptr_size == 8;
     22 }
     23 
     24 /* ============================================================
     25  * GNU __attribute__ (Phase 1 — parse + carry; no semantic wire-up)
     26  * ============================================================ */
     27 
     28 static const struct {
     29   const char* name;
     30   AttrKind kind;
     31   AttrArgShape shape;
     32 } kAttrTable[] = {
     33     {"packed", ATTR_PACKED, AS_NONE},
     34     {"aligned", ATTR_ALIGNED, AS_INT_OPT},
     35     {"section", ATTR_SECTION, AS_STRING},
     36     {"used", ATTR_USED, AS_NONE},
     37     {"noreturn", ATTR_NORETURN, AS_NONE},
     38     {"alias", ATTR_ALIAS, AS_STRING},
     39     {"weak", ATTR_WEAK, AS_NONE},
     40     {"visibility", ATTR_VISIBILITY, AS_STRING},
     41     {"always_inline", ATTR_ALWAYS_INLINE, AS_NONE},
     42     {"noinline", ATTR_NOINLINE, AS_NONE},
     43     {"unused", ATTR_UNUSED, AS_NONE},
     44     {"deprecated", ATTR_DEPRECATED, AS_OPAQUE},
     45     {"warn_unused_result", ATTR_WARN_UNUSED_RESULT, AS_NONE},
     46     {"format", ATTR_FORMAT, AS_FORMAT},
     47     {"nonnull", ATTR_NONNULL, AS_OPAQUE},
     48     {"returns_nonnull", ATTR_RETURNS_NONNULL, AS_NONE},
     49     {"pure", ATTR_PURE, AS_NONE},
     50     {"const", ATTR_CONST, AS_NONE},
     51     {"malloc", ATTR_MALLOC, AS_OPAQUE},
     52     {"nothrow", ATTR_NOTHROW, AS_NONE},
     53     {"leaf", ATTR_LEAF, AS_NONE},
     54     {"cold", ATTR_COLD, AS_NONE},
     55     {"hot", ATTR_HOT, AS_NONE},
     56     {"constructor", ATTR_CONSTRUCTOR, AS_INT_OPT},
     57     {"destructor", ATTR_DESTRUCTOR, AS_INT_OPT},
     58     {"cleanup", ATTR_CLEANUP, AS_IDENT},
     59     {"mode", ATTR_MODE, AS_IDENT},
     60     {"vector_size", ATTR_VECTOR_SIZE, AS_INT},
     61     {"transparent_union", ATTR_TRANSPARENT_UNION, AS_NONE},
     62     {"gnu_inline", ATTR_GNU_INLINE, AS_NONE},
     63     {"fallthrough", ATTR_FALLTHROUGH, AS_NONE},
     64     {"sentinel", ATTR_SENTINEL, AS_OPAQUE},
     65     {"no_instrument_function", ATTR_NO_INSTRUMENT_FUNCTION, AS_NONE},
     66     {"no_sanitize", ATTR_NO_SANITIZE, AS_OPAQUE},
     67     {"import_module", ATTR_IMPORT_MODULE, AS_STRING},
     68     {"import_name", ATTR_IMPORT_NAME, AS_STRING},
     69 };
     70 
     71 static SrcLoc tok_loc(Parser* p, const Tok* t) {
     72   return pp_materialize_loc(p->pp, t->loc);
     73 }
     74 
     75 static void attr_canon_range(const char* s, size_t len, const char** out_p,
     76                              size_t* out_len);
     77 
     78 static int accept_kw(Parser* p, CKw k) {
     79   if (is_kw(p, &p->cur, k)) {
     80     advance(p);
     81     return 1;
     82   }
     83   return 0;
     84 }
     85 
     86 static int attr_sym_canon_eq(Parser* p, Sym sym, const char* want) {
     87   KitSlice sym_sl = kit_sym_str(p->pool->c, sym);
     88   size_t len = sym_sl.len;
     89   const char* s = sym_sl.s;
     90   const char* cs;
     91   size_t clen;
     92   if (!s) return 0;
     93   attr_canon_range(s, len, &cs, &clen);
     94   return kit_slice_eq_cstr((KitSlice){.s = cs, .len = clen}, want);
     95 }
     96 
     97 static const Type* attrs_apply_type_mode(Parser* p, const Type* base,
     98                                          const Attr* attrs) {
     99   for (const Attr* a = attrs; a; a = a->next) {
    100     if (a->kind != ATTR_MODE || a->nargs == 0) continue;
    101     if (attr_sym_canon_eq(p, a->v.sym, "TI")) {
    102       const Type* u = type_unqual(p->pool, base);
    103       int is_unsigned = u && type_is_int(u) && type_is_signed_integer(u) == 0;
    104       if (!target_has_int128(p)) {
    105         perr(p, "__int128 is not supported on the target architecture");
    106       }
    107       return type_prim(p->pool, is_unsigned ? TY_UINT128 : TY_INT128);
    108     }
    109   }
    110   return base;
    111 }
    112 
    113 int starts_attr(const Parser* p) {
    114   return p->cur.kind == TOK_IDENT && tok_ident(&p->cur) == p->sym_attribute;
    115 }
    116 
    117 static void skip_balanced_parens(Parser* p);
    118 
    119 static int slice_has_prefix(KitSlice s, KitSlice prefix) {
    120   return s.len >= prefix.len && memcmp(s.s, prefix.s, prefix.len) == 0;
    121 }
    122 
    123 static int starts_darwin_availability(const Parser* p) {
    124   KitSlice s;
    125   if (p->cur.kind != TOK_IDENT) return 0;
    126   s = kit_sym_str(p->pool->c, tok_ident(&p->cur));
    127   return slice_has_prefix(s, KIT_SLICE_LIT("__AVAILABILITY")) ||
    128          slice_has_prefix(s, KIT_SLICE_LIT("__API_AVAILABLE")) ||
    129          slice_has_prefix(s, KIT_SLICE_LIT("__API_DEPRECATED")) ||
    130          slice_has_prefix(s, KIT_SLICE_LIT("__API_UNAVAILABLE"));
    131 }
    132 
    133 static int starts_asm_label(const Parser* p) {
    134   return is_kw(p, &p->cur, KW_ASM) || is_kw(p, &p->cur, KW_BUILTIN_ASM);
    135 }
    136 
    137 static void parse_and_discard_darwin_availability(Parser* p) {
    138   advance(p);
    139   if (is_punct(&p->cur, '(')) skip_balanced_parens(p);
    140 }
    141 
    142 static Sym parse_asm_label(Parser* p) {
    143   Sym label = 0;
    144   advance(p); /* asm / __asm / __asm__ */
    145   expect_punct(p, '(', "'(' after asm label");
    146   if (p->cur.kind != TOK_STR) {
    147     perr(p, "expected string literal in asm label");
    148   }
    149   /* Capture the label string for the declarator currently being parsed. For a
    150    * `register T x __asm__("r10")` local this is the hard register name the
    151    * variable binds to. Other asm labels (symbol renames) are still effectively
    152    * ignored by callers that do not consume DeclaratorInfo.asm_label. */
    153   {
    154     Tok t = p->cur;
    155     size_t nlen = 0;
    156     u8* bytes = decode_string_literal(p, &t, &nlen);
    157     u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0;
    158     label = kit_sym_intern(p->pool->c,
    159                            (KitSlice){.s = (const char*)bytes, .len = ilen});
    160     kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
    161                                            bytes, 0);
    162   }
    163   do {
    164     advance(p);
    165   } while (p->cur.kind == TOK_STR);
    166   expect_punct(p, ')', "')' after asm label");
    167   return label;
    168 }
    169 
    170 static void parse_attrs_and_asm_into(Parser* p, Attr** attrs_out,
    171                                      Attr** local_attrs, Sym* asm_label_out) {
    172   for (;;) {
    173     if (starts_attr(p)) {
    174       if (attrs_out)
    175         parse_attrs_into(p, attrs_out);
    176       else
    177         parse_attrs_into(p, local_attrs);
    178       continue;
    179     }
    180     if (starts_asm_label(p)) {
    181       Sym label = parse_asm_label(p);
    182       if (asm_label_out) *asm_label_out = label;
    183       continue;
    184     }
    185     if (starts_darwin_availability(p)) {
    186       parse_and_discard_darwin_availability(p);
    187       continue;
    188     }
    189     break;
    190   }
    191 }
    192 
    193 static void parse_and_discard_attrs_or_asm(Parser* p) {
    194   for (;;) {
    195     if (starts_attr(p)) {
    196       parse_and_discard_attributes(p);
    197       continue;
    198     }
    199     if (starts_asm_label(p)) {
    200       (void)parse_asm_label(p);
    201       continue;
    202     }
    203     if (starts_darwin_availability(p)) {
    204       parse_and_discard_darwin_availability(p);
    205       continue;
    206     }
    207     break;
    208   }
    209 }
    210 
    211 static void attr_canon_range(const char* s, size_t len, const char** out_p,
    212                              size_t* out_len) {
    213   if (len >= 4 && s[0] == '_' && s[1] == '_' && s[len - 1] == '_' &&
    214       s[len - 2] == '_') {
    215     *out_p = s + 2;
    216     *out_len = len - 4;
    217     return;
    218   }
    219   *out_p = s;
    220   *out_len = len;
    221 }
    222 
    223 static AttrKind classify_attr(Parser* p, Sym name, AttrArgShape* shape_out) {
    224   KitSlice name_sl = kit_sym_str(p->pool->c, name);
    225   size_t len = name_sl.len;
    226   const char* s = name_sl.s;
    227   const char* cs;
    228   size_t clen;
    229   size_t i;
    230   if (!s) {
    231     *shape_out = AS_OPAQUE;
    232     return ATTR_UNKNOWN;
    233   }
    234   attr_canon_range(s, len, &cs, &clen);
    235   for (i = 0; i < sizeof(kAttrTable) / sizeof(kAttrTable[0]); ++i) {
    236     const char* tn = kAttrTable[i].name;
    237     if (kit_slice_eq_cstr((KitSlice){.s = cs, .len = clen}, tn)) {
    238       *shape_out = kAttrTable[i].shape;
    239       return kAttrTable[i].kind;
    240     }
    241   }
    242   *shape_out = AS_OPAQUE;
    243   return ATTR_UNKNOWN;
    244 }
    245 
    246 static void skip_balanced_parens(Parser* p) {
    247   int depth;
    248   if (!is_punct(&p->cur, '(')) perr(p, "internal: skip_balanced_parens");
    249   depth = 1;
    250   advance(p);
    251   while (depth > 0) {
    252     if (p->cur.kind == TOK_EOF) {
    253       perr(p, "unexpected EOF inside attribute arguments");
    254     }
    255     if (is_punct(&p->cur, '('))
    256       ++depth;
    257     else if (is_punct(&p->cur, ')')) {
    258       --depth;
    259       if (depth == 0) {
    260         advance(p);
    261         return;
    262       }
    263     }
    264     advance(p);
    265   }
    266 }
    267 
    268 static void parse_attr_args(Parser* p, Attr* a, AttrArgShape shape,
    269                             const char* attr_diag_name) {
    270   if (!is_punct(&p->cur, '(')) {
    271     if (shape == AS_NONE || shape == AS_OPTIONAL || shape == AS_INT_OPT ||
    272         shape == AS_OPAQUE) {
    273       return;
    274     }
    275     perr(p, "attribute '%.*s' expects '(' arguments",
    276          KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name)));
    277   }
    278   switch (shape) {
    279     case AS_NONE: {
    280       advance(p); /* '(' */
    281       if (!accept_punct(p, ')')) {
    282         perr(p, "attribute '%.*s' takes no arguments",
    283              KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name)));
    284       }
    285       return;
    286     }
    287     case AS_OPTIONAL: {
    288       skip_balanced_parens(p);
    289       return;
    290     }
    291     case AS_INT:
    292     case AS_INT_OPT: {
    293       SrcLoc loc;
    294       advance(p); /* '(' */
    295       if (is_punct(&p->cur, ')')) {
    296         if (shape == AS_INT) {
    297           perr(p, "attribute '%.*s' expects an integer argument",
    298                KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name)));
    299         }
    300         advance(p);
    301         return;
    302       }
    303       loc = tok_loc(p, &p->cur);
    304       a->v.i = eval_const_int(p, loc);
    305       if (a->kind == ATTR_ALIGNED && a->v.i > 0 &&
    306           (((u64)a->v.i & ((u64)a->v.i - 1u)) != 0)) {
    307         perr(p, "attribute 'aligned' argument must be a power of two");
    308       }
    309       a->nargs = 1;
    310       expect_punct(p, ')', "')' after attribute integer argument");
    311       return;
    312     }
    313     case AS_STRING: {
    314       advance(p); /* '(' */
    315       if (p->cur.kind != TOK_STR) {
    316         perr(p, "attribute '%.*s' expects a string literal",
    317              KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name)));
    318       }
    319       {
    320         Tok t = p->cur;
    321         size_t nlen = 0;
    322         u8* bytes = decode_string_literal(p, &t, &nlen);
    323         u32 ilen = (nlen > 0) ? (u32)(nlen - 1) : 0;
    324         a->v.sym = kit_sym_intern(
    325             p->pool->c, (KitSlice){.s = (const char*)bytes, .len = ilen});
    326         kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
    327                                                bytes, 0);
    328       }
    329       a->nargs = 1;
    330       advance(p);
    331       expect_punct(p, ')', "')' after attribute string argument");
    332       return;
    333     }
    334     case AS_IDENT: {
    335       advance(p); /* '(' */
    336       if (p->cur.kind != TOK_IDENT) {
    337         perr(p, "attribute '%.*s' expects an identifier",
    338              KIT_SLICE_ARG(kit_slice_cstr(attr_diag_name)));
    339       }
    340       a->v.sym = tok_ident(&p->cur);
    341       a->nargs = 1;
    342       advance(p);
    343       expect_punct(p, ')', "')' after attribute identifier argument");
    344       return;
    345     }
    346     case AS_FORMAT: {
    347       SrcLoc mloc, nloc;
    348       i64 mv, nv;
    349       advance(p); /* '(' */
    350       if (p->cur.kind != TOK_IDENT) {
    351         perr(p, "attribute 'format' expects (archetype, m, n)");
    352       }
    353       advance(p);
    354       expect_punct(p, ',', "',' after format archetype");
    355       mloc = tok_loc(p, &p->cur);
    356       mv = eval_const_int(p, mloc);
    357       expect_punct(p, ',', "',' after format string-index");
    358       nloc = tok_loc(p, &p->cur);
    359       nv = eval_const_int(p, nloc);
    360       if (mv < 0 || mv > 0xFFFF || nv < 0 || nv > 0xFFFF) {
    361         perr(p, "attribute 'format' indices out of range");
    362       }
    363       a->v.format.fmt_idx = (u16)mv;
    364       a->v.format.first = (u16)nv;
    365       a->nargs = 3;
    366       expect_punct(p, ')', "')' after format arguments");
    367       return;
    368     }
    369     case AS_OPAQUE:
    370     default: {
    371       skip_balanced_parens(p);
    372       return;
    373     }
    374   }
    375 }
    376 
    377 Attr* parse_attribute_spec_list(Parser* p) {
    378   Attr* head = NULL;
    379   Attr* tail = NULL;
    380   while (starts_attr(p)) {
    381     SrcLoc kw_loc = tok_loc(p, &p->cur);
    382     advance(p); /* __attribute__ */
    383     expect_punct(p, '(', "'(' after __attribute__");
    384     expect_punct(p, '(', "'((' after __attribute__");
    385     for (;;) {
    386       Sym aname;
    387       AttrArgShape shape;
    388       Attr* a;
    389       const char* diag_name;
    390       size_t diag_len;
    391       const char* canon;
    392       size_t canon_len;
    393       while (accept_punct(p, ',')) { /* skip */
    394       }
    395       if (is_punct(&p->cur, ')')) break;
    396       if (p->cur.kind != TOK_IDENT) {
    397         perr(p, "expected attribute name");
    398       }
    399       aname = tok_ident(&p->cur);
    400       a = arena_new(p->pool->arena, Attr);
    401       if (!a) perr(p, "out of memory in parse_attribute_spec_list");
    402       memset(a, 0, sizeof *a);
    403       a->loc = tok_loc(p, &p->cur);
    404       a->name = aname;
    405       a->kind = (u16)classify_attr(p, aname, &shape);
    406       advance(p);
    407       {
    408         KitSlice aname_sl = kit_sym_str(p->pool->c, aname);
    409         diag_name = aname_sl.s;
    410         diag_len = aname_sl.len;
    411       }
    412       attr_canon_range(diag_name, diag_len, &canon, &canon_len);
    413       (void)canon;
    414       (void)canon_len;
    415       parse_attr_args(p, a, shape, diag_name ? diag_name : "<unknown>");
    416       if (tail)
    417         tail->next = a;
    418       else
    419         head = a;
    420       tail = a;
    421       if (!accept_punct(p, ',')) break;
    422     }
    423     expect_punct(p, ')', "')' after attribute list");
    424     expect_punct(p, ')', "'))' after attribute list");
    425     (void)kw_loc;
    426   }
    427   return head;
    428 }
    429 
    430 void parse_and_discard_attributes(Parser* p) {
    431   (void)parse_attribute_spec_list(p);
    432 }
    433 
    434 /* Append `add` to the end of `*head` (linked via Attr.next). */
    435 void attr_list_append(Attr** head, Attr* add) {
    436   if (!add) return;
    437   if (!*head) {
    438     *head = add;
    439     return;
    440   }
    441   Attr* tail = *head;
    442   while (tail->next) tail = tail->next;
    443   tail->next = add;
    444 }
    445 
    446 /* If `starts_attr`, parse and append to `*sink`. No-op otherwise. */
    447 void parse_attrs_into(Parser* p, Attr** sink) {
    448   if (starts_attr(p)) attr_list_append(sink, parse_attribute_spec_list(p));
    449 }
    450 
    451 #define PARSE_ATTR_ALIGNED_DEFAULT 16u
    452 
    453 static void attrs_to_record_opts(const Attr* a, TypeRecordOpts* opts) {
    454   for (; a; a = a->next) {
    455     if (a->kind == ATTR_PACKED) {
    456       opts->packed = 1;
    457     } else if (a->kind == ATTR_ALIGNED) {
    458       u32 v = (a->nargs == 0) ? PARSE_ATTR_ALIGNED_DEFAULT : (u32)a->v.i;
    459       if (v > opts->align_override) opts->align_override = (u16)v;
    460     }
    461   }
    462 }
    463 
    464 static void attrs_to_field(const Attr* a, Field* f) {
    465   for (; a; a = a->next) {
    466     if (a->kind == ATTR_PACKED) {
    467       f->packed = 1;
    468     } else if (a->kind == ATTR_ALIGNED) {
    469       u32 v = (a->nargs == 0) ? PARSE_ATTR_ALIGNED_DEFAULT : (u32)a->v.i;
    470       if (v > f->align_override) f->align_override = (u16)v;
    471     }
    472   }
    473 }
    474 
    475 u32 attrs_pick_aligned(const Attr* a) {
    476   u32 best = 0;
    477   for (; a; a = a->next) {
    478     if (a->kind == ATTR_ALIGNED) {
    479       u32 v = (a->nargs == 0) ? PARSE_ATTR_ALIGNED_DEFAULT : (u32)a->v.i;
    480       if (v > best) best = v;
    481     }
    482   }
    483   return best;
    484 }
    485 
    486 static int is_power_of_two_u32(u32 v) { return v != 0 && (v & (v - 1u)) == 0; }
    487 
    488 static void validate_atomic_operand(Parser* p, const Type* ty) {
    489   if (!ty) perr(p, "_Atomic requires an object type");
    490   if (ty->qual) perr(p, "_Atomic operand must not be qualified");
    491   if (ty->kind == TY_ARRAY || ty->kind == TY_FUNC || ty->kind == TY_VOID) {
    492     perr(p, "_Atomic operand must be an object type");
    493   }
    494 }
    495 
    496 void validate_decl_type_constraints(Parser* p, const DeclSpecs* specs,
    497                                     const Type* ty, int is_function,
    498                                     int is_member) {
    499   const Type* u = ty ? type_unqual(p->pool, ty) : NULL;
    500   if (!u) return;
    501   if (specs->quals & Q_RESTRICT) {
    502     perr(p, "restrict requires pointer type");
    503   }
    504   if ((ty->qual & Q_RESTRICT) && ty->kind != TY_PTR) {
    505     perr(p, "restrict requires pointer type");
    506   }
    507   if (is_member) {
    508     if (specs->storage != DS_AUTO || specs->storage_explicit) {
    509       perr(p, "storage-class specifier is invalid for struct member");
    510     }
    511     if (specs->flags & DF_INLINE)
    512       perr(p, "inline is invalid for struct member");
    513     if (specs->flags & DF_NORETURN)
    514       perr(p, "_Noreturn is invalid for struct member");
    515     if (specs->flags & DF_THREAD)
    516       perr(p, "_Thread_local is invalid for struct member");
    517   }
    518   if (u->kind == TY_VOID && !is_function && specs->storage != DS_TYPEDEF) {
    519     perr(p, "object may not have void type");
    520   }
    521   if ((specs->flags & DF_INLINE) && !is_function) {
    522     perr(p, "inline may only appear on a function declaration");
    523   }
    524   if ((specs->flags & DF_NORETURN) && !is_function) {
    525     perr(p, "_Noreturn may only appear on a function declaration");
    526   }
    527   if ((specs->flags & DF_THREAD) &&
    528       (is_function || specs->storage == DS_TYPEDEF)) {
    529     perr(p, "_Thread_local may only appear on object declarations");
    530   }
    531   if (specs->align) {
    532     u32 natural = 0;
    533     if (!is_power_of_two_u32(specs->align)) {
    534       perr(p, "_Alignas requires a power-of-two alignment");
    535     }
    536     if (is_function || specs->storage == DS_TYPEDEF) {
    537       perr(p, "_Alignas is invalid on this declaration");
    538     }
    539     if (u->kind == TY_VOID || u->kind == TY_FUNC) {
    540       perr(p, "_Alignas requires an object type");
    541     }
    542     natural = c_abi_alignof(p->abi, p->pool, ty);
    543     if (specs->align < natural) {
    544       perr(p, "_Alignas cannot weaken natural alignment");
    545     }
    546   }
    547 }
    548 
    549 /* ============================================================
    550  * resolve_type_specs
    551  * ============================================================ */
    552 
    553 const Type* resolve_type_specs(Parser* p, const TypeSpecAccum* a, SrcLoc loc) {
    554   if (!a->saw_explicit_type) return NULL;
    555   if (a->long_count > 2) {
    556     compiler_panic(p->c, loc, "too many long type specifiers");
    557   }
    558   if (a->saw_void) {
    559     if (a->saw_char || a->saw_int || a->saw_short || a->long_count ||
    560         a->saw_signed || a->saw_unsigned || a->saw_bool || a->saw_float ||
    561         a->saw_double) {
    562       compiler_panic(p->c, loc, "conflicting type specifiers (void mixed)");
    563     }
    564     return type_void(p->pool);
    565   }
    566   if (a->saw_bool) {
    567     if (a->saw_char || a->saw_int || a->saw_short || a->long_count ||
    568         a->saw_signed || a->saw_unsigned || a->saw_float || a->saw_double) {
    569       compiler_panic(p->c, loc, "conflicting type specifiers (_Bool mixed)");
    570     }
    571     return type_prim(p->pool, TY_BOOL);
    572   }
    573   if (a->saw_char) {
    574     if (a->saw_int || a->saw_short || a->long_count || a->saw_float ||
    575         a->saw_double) {
    576       compiler_panic(p->c, loc, "conflicting type specifiers (char mixed)");
    577     }
    578     if (a->saw_unsigned) return type_prim(p->pool, TY_UCHAR);
    579     if (a->saw_signed) return type_prim(p->pool, TY_SCHAR);
    580     return type_prim(p->pool, TY_CHAR);
    581   }
    582   if (a->saw_float) {
    583     if (a->saw_int || a->saw_short || a->long_count || a->saw_signed ||
    584         a->saw_unsigned || a->saw_double) {
    585       compiler_panic(p->c, loc, "conflicting type specifiers (float mixed)");
    586     }
    587     return type_prim(p->pool, TY_FLOAT);
    588   }
    589   if (a->saw_double) {
    590     if (a->saw_int || a->saw_short || a->saw_signed || a->saw_unsigned ||
    591         a->long_count > 1) {
    592       compiler_panic(p->c, loc, "conflicting type specifiers (double mixed)");
    593     }
    594     return type_prim(p->pool, a->long_count ? TY_LDOUBLE : TY_DOUBLE);
    595   }
    596   if (a->saw_short) {
    597     if (a->long_count) {
    598       compiler_panic(p->c, loc, "conflicting type specifiers (short long)");
    599     }
    600     return type_prim(p->pool, a->saw_unsigned ? TY_USHORT : TY_SHORT);
    601   }
    602   if (a->saw_int128) {
    603     if (!target_has_int128(p)) {
    604       perr(p, "__int128 is not supported on the target architecture");
    605     }
    606     return type_prim(p->pool, a->saw_unsigned ? TY_UINT128 : TY_INT128);
    607   }
    608   if (a->long_count == 2) {
    609     return type_prim(p->pool, a->saw_unsigned ? TY_ULLONG : TY_LLONG);
    610   }
    611   if (a->long_count == 1) {
    612     return type_prim(p->pool, a->saw_unsigned ? TY_ULONG : TY_LONG);
    613   }
    614   if (a->saw_unsigned) return type_prim(p->pool, TY_UINT);
    615   if (a->saw_signed || a->saw_int) return type_prim(p->pool, TY_INT);
    616   return type_prim(p->pool, TY_INT);
    617 }
    618 
    619 /* ============================================================
    620  * parse_decl_specs
    621  * ============================================================ */
    622 
    623 static int is_typeof_spelling(const Parser* p, const Tok* t) {
    624   Sym s;
    625   if (!p || !t || t->kind != TOK_IDENT) return 0;
    626   s = tok_ident(t);
    627   return s == p->sym_typeof_alias || s == p->sym_typeof_alias2;
    628 }
    629 
    630 static const Type* parse_typeof_specifier(Parser* p) {
    631   const Type* ty;
    632   advance(p); /* __typeof / __typeof__ */
    633   expect_punct(p, '(', "'(' after __typeof");
    634   if (starts_type_name(p, &p->cur)) {
    635     ty = parse_type_name(p);
    636   } else {
    637     /* Preserve the frontend Type without emitting operand side effects. This
    638      * retains qualified, array, and function types instead of applying the
    639      * usual value conversions. */
    640     c_const_guard_not_eval_push(p);
    641     c_cg_codegen_suppress_push(p);
    642     parse_expr(p);
    643     ty = c_cg_top_type(p);
    644     c_cg_drop(p);
    645     c_cg_codegen_suppress_pop(p);
    646     c_const_guard_not_eval_pop(p);
    647   }
    648   expect_punct(p, ')', "')' after __typeof operand");
    649   return ty;
    650 }
    651 
    652 int parse_decl_specs(Parser* p, DeclSpecs* out) {
    653   TypeSpecAccum acc;
    654   SrcLoc loc;
    655   int seen = 0;
    656   int storage_seen = 0;
    657   const Type* tagged_ty = NULL;
    658   memset(&acc, 0, sizeof acc);
    659   out->type = NULL;
    660   out->storage = DS_AUTO;
    661   out->flags = DF_NONE;
    662   out->quals = 0;
    663   out->storage_explicit = 0;
    664   out->pad = 0;
    665   out->align = 0;
    666   out->vla_byte_slot = FRAME_SLOT_NONE;
    667   out->vla_bounds = NULL;
    668   out->attrs = NULL;
    669   loc = tok_loc(p, &p->cur);
    670   for (;;) {
    671     Tok t = p->cur;
    672     /* Classify the token's keyword identity exactly once per iteration; the
    673      * decl-spec dispatch below compares against this instead of re-deciding
    674      * keyword-ness per candidate (was ~26 is_kw probes/token). */
    675     CKw tkw = classify_kw(p, &t);
    676     if (starts_attr(p)) {
    677       Attr* a = parse_attribute_spec_list(p);
    678       if (a) {
    679         Attr* tail = a;
    680         while (tail->next) tail = tail->next;
    681         tail->next = out->attrs;
    682         out->attrs = a;
    683       }
    684       seen = 1;
    685       continue;
    686     }
    687     if (is_typeof_spelling(p, &t)) {
    688       if (tagged_ty || acc.saw_explicit_type) {
    689         perr(p, "conflicting type specifiers (__typeof mixed)");
    690       }
    691       tagged_ty = parse_typeof_specifier(p);
    692       acc.saw_explicit_type = 1;
    693       seen = 1;
    694       continue;
    695     }
    696     if (tkw == KW_STRUCT || tkw == KW_UNION) {
    697       TypeKind kind = tkw == KW_STRUCT ? TY_STRUCT : TY_UNION;
    698       Attr* anon_attrs = NULL;
    699       if (tagged_ty || acc.saw_explicit_type) {
    700         perr(p, "conflicting type specifiers (struct/union mixed)");
    701       }
    702       advance(p);
    703       tagged_ty = parse_struct_or_union(p, kind, &anon_attrs);
    704       attr_list_append(&out->attrs, anon_attrs);
    705       acc.saw_explicit_type = 1;
    706       seen = 1;
    707       continue;
    708     }
    709     if (tkw == KW_ENUM) {
    710       Attr* anon_attrs = NULL;
    711       if (tagged_ty || acc.saw_explicit_type) {
    712         perr(p, "conflicting type specifiers (enum mixed)");
    713       }
    714       advance(p);
    715       tagged_ty = parse_enum(p, &anon_attrs);
    716       attr_list_append(&out->attrs, anon_attrs);
    717       acc.saw_explicit_type = 1;
    718       seen = 1;
    719       continue;
    720     }
    721     if (tkw == KW_VOID) {
    722       acc.saw_void = 1;
    723       acc.saw_explicit_type = 1;
    724       advance(p);
    725       seen = 1;
    726     } else if (tkw == KW_CHAR) {
    727       acc.saw_char = 1;
    728       acc.saw_explicit_type = 1;
    729       advance(p);
    730       seen = 1;
    731     } else if (tkw == KW_INT) {
    732       acc.saw_int = 1;
    733       acc.saw_explicit_type = 1;
    734       advance(p);
    735       seen = 1;
    736     } else if (tkw == KW_SHORT) {
    737       acc.saw_short = 1;
    738       acc.saw_explicit_type = 1;
    739       advance(p);
    740       seen = 1;
    741     } else if (tkw == KW_LONG) {
    742       acc.long_count++;
    743       acc.saw_explicit_type = 1;
    744       advance(p);
    745       seen = 1;
    746     } else if (tkw == KW_SIGNED) {
    747       acc.saw_signed = 1;
    748       acc.saw_explicit_type = 1;
    749       advance(p);
    750       seen = 1;
    751     } else if (tkw == KW_UNSIGNED) {
    752       acc.saw_unsigned = 1;
    753       acc.saw_explicit_type = 1;
    754       advance(p);
    755       seen = 1;
    756     } else if (tkw == KW_BOOL) {
    757       acc.saw_bool = 1;
    758       acc.saw_explicit_type = 1;
    759       advance(p);
    760       seen = 1;
    761     } else if (tkw == KW_FLOAT || tkw == KW_FLOAT16) {
    762       reject_general_regs_only_fp(p, "floating-point types");
    763       /* _Float16 is intentionally aliased to 32-bit float (a deliberate
    764        * approximation; see test/parse/cases/float16_01_decl, which asserts
    765        * sizeof(_Float16) == sizeof(float)). Real 16-bit semantics would be a
    766        * separate feature. */
    767       acc.saw_float = 1;
    768       acc.saw_explicit_type = 1;
    769       advance(p);
    770       seen = 1;
    771     } else if (tkw == KW_DOUBLE) {
    772       reject_general_regs_only_fp(p, "floating-point types");
    773       acc.saw_double = 1;
    774       acc.saw_explicit_type = 1;
    775       advance(p);
    776       seen = 1;
    777     } else if (t.kind == TOK_IDENT && tok_ident(&t) == p->sym_int128) {
    778       acc.saw_int128 = 1;
    779       acc.saw_explicit_type = 1;
    780       advance(p);
    781       seen = 1;
    782     } else if (t.kind == TOK_IDENT && tok_ident(&t) == p->sym_int128_t) {
    783       acc.saw_int128 = 1;
    784       acc.saw_signed = 1;
    785       acc.saw_explicit_type = 1;
    786       advance(p);
    787       seen = 1;
    788     } else if (t.kind == TOK_IDENT && tok_ident(&t) == p->sym_uint128_t) {
    789       acc.saw_int128 = 1;
    790       acc.saw_unsigned = 1;
    791       acc.saw_explicit_type = 1;
    792       advance(p);
    793       seen = 1;
    794     } else if (tkw == KW_STATIC) {
    795       if (storage_seen) perr(p, "multiple storage-class specifiers");
    796       storage_seen = 1;
    797       out->storage_explicit = 1;
    798       out->storage = DS_STATIC;
    799       advance(p);
    800       seen = 1;
    801     } else if (tkw == KW_EXTERN) {
    802       if (storage_seen) perr(p, "multiple storage-class specifiers");
    803       storage_seen = 1;
    804       out->storage_explicit = 1;
    805       out->storage = DS_EXTERN;
    806       advance(p);
    807       seen = 1;
    808     } else if (tkw == KW_CONST) {
    809       out->quals |= Q_CONST;
    810       advance(p);
    811       seen = 1;
    812     } else if (tkw == KW_VOLATILE) {
    813       out->quals |= Q_VOLATILE;
    814       advance(p);
    815       seen = 1;
    816     } else if (tkw == KW_RESTRICT) {
    817       out->quals |= Q_RESTRICT;
    818       advance(p);
    819       seen = 1;
    820     } else if (tkw == KW_ATOMIC) {
    821       Tok n = peek1(p);
    822       if (is_punct(&n, '(')) {
    823         const Type* inner;
    824         if (tagged_ty || acc.saw_explicit_type) {
    825           perr(p, "conflicting type specifiers (_Atomic(T) mixed)");
    826         }
    827         advance(p); /* `_Atomic` */
    828         advance(p); /* `(` */
    829         inner = parse_type_name(p);
    830         expect_punct(p, ')', "')' after _Atomic type");
    831         validate_atomic_operand(p, inner);
    832         tagged_ty = type_qualified(p->pool, inner, Q_ATOMIC);
    833         acc.saw_explicit_type = 1;
    834         seen = 1;
    835         continue;
    836       }
    837       out->quals |= Q_ATOMIC;
    838       advance(p);
    839       seen = 1;
    840     } else if (tkw == KW_TYPEDEF) {
    841       if (storage_seen) perr(p, "multiple storage-class specifiers");
    842       storage_seen = 1;
    843       out->storage_explicit = 1;
    844       out->storage = DS_TYPEDEF;
    845       advance(p);
    846       seen = 1;
    847     } else if (tkw == KW_ALIGNAS) {
    848       u32 a = 0;
    849       advance(p); /* `_Alignas` */
    850       expect_punct(p, '(', "'(' after _Alignas");
    851       if (starts_type_name(p, &p->cur)) {
    852         const Type* tn = parse_type_name(p);
    853         a = c_abi_alignof(p->abi, p->pool, tn);
    854       } else {
    855         i64 v = eval_const_int(p, tok_loc(p, &p->cur));
    856         if (v < 0) perr(p, "_Alignas requires a non-negative alignment");
    857         a = (u32)v;
    858       }
    859       if (a != 0 && !is_power_of_two_u32(a)) {
    860         perr(p, "_Alignas requires a power-of-two alignment");
    861       }
    862       expect_punct(p, ')', "')' after _Alignas argument");
    863       if (a > out->align) out->align = a;
    864       seen = 1;
    865     } else if (tkw == KW_INLINE) {
    866       out->flags |= DF_INLINE;
    867       advance(p);
    868       seen = 1;
    869     } else if (tkw == KW_THREAD_LOCAL) {
    870       out->flags |= DF_THREAD;
    871       advance(p);
    872       seen = 1;
    873     } else if (tkw == KW_NORETURN) {
    874       out->flags |= DF_NORETURN;
    875       advance(p);
    876       seen = 1;
    877     } else if (tkw == KW_REGISTER) {
    878       if (storage_seen) perr(p, "multiple storage-class specifiers");
    879       storage_seen = 1;
    880       out->storage_explicit = 1;
    881       out->storage = DS_REGISTER;
    882       advance(p);
    883       seen = 1;
    884     } else if (tkw == KW_AUTO) {
    885       if (storage_seen) perr(p, "multiple storage-class specifiers");
    886       storage_seen = 1;
    887       out->storage_explicit = 1;
    888       out->storage = DS_AUTO;
    889       advance(p);
    890       seen = 1;
    891     } else if (!acc.saw_explicit_type && !tagged_ty && t.kind == TOK_IDENT &&
    892                tkw == KW_NONE) {
    893       /* tkw == KW_NONE here is exactly ident_kw_inline(t)==KW_NONE: this is the
    894        * terminal else-if, so every keyword/alias branch above already failed.
    895        */
    896       if (tok_ident(&t) == p->sym_b_va_list) {
    897         if (!p->type_b_va_list)
    898           p->type_b_va_list = c_abi_va_list_type(p->abi, p->pool);
    899         tagged_ty = p->type_b_va_list;
    900         acc.saw_explicit_type = 1;
    901         advance(p);
    902         seen = 1;
    903         continue;
    904       }
    905       SymEntry* e = scope_lookup(p, tok_ident(&t));
    906       if (e && e->kind == SEK_TYPEDEF) {
    907         tagged_ty = e->type;
    908         if (e->vla_byte_slot != FRAME_SLOT_NONE) {
    909           out->vla_byte_slot = e->vla_byte_slot;
    910           out->vla_bounds = e->vla_bounds;
    911         }
    912         acc.saw_explicit_type = 1;
    913         advance(p);
    914         seen = 1;
    915         continue;
    916       }
    917       break;
    918     } else {
    919       break;
    920     }
    921   }
    922   if (seen) {
    923     if (tagged_ty) {
    924       out->type = tagged_ty;
    925     } else {
    926       out->type = resolve_type_specs(p, &acc, loc);
    927       if (!out->type) {
    928         out->type = ty_int(p);
    929       }
    930     }
    931     out->type = attrs_apply_type_mode(p, out->type, out->attrs);
    932     if (out->type && out->quals) {
    933       out->type = type_qualified(p->pool, out->type,
    934                                  (u16)(out->type->qual | out->quals));
    935     }
    936   }
    937   return seen;
    938 }
    939 
    940 /* ============================================================
    941  * struct / union / enum
    942  * ============================================================ */
    943 
    944 int find_field(KitCompiler* abi, Pool* pool, const Type* rec, Sym name,
    945                const Type** out_type, u32* out_offset,
    946                const Field** out_field) {
    947   if (!rec || (rec->kind != TY_STRUCT && rec->kind != TY_UNION)) return 0;
    948   const ABIRecordLayout* L = c_abi_record_layout(abi, pool, rec);
    949   if (!L) return 0;
    950   for (u16 i = 0; i < rec->rec.nfields; ++i) {
    951     const Field* f = &rec->rec.fields[i];
    952     if (f->name == name && name != 0) {
    953       *out_type = f->type;
    954       *out_offset = L->fields[i].offset;
    955       *out_field = f;
    956       return 1;
    957     }
    958     if ((f->flags & FIELD_ANON) &&
    959         (f->type->kind == TY_STRUCT || f->type->kind == TY_UNION)) {
    960       const Type* inner_ty = NULL;
    961       u32 inner_off = 0;
    962       const Field* inner_f = NULL;
    963       if (find_field(abi, pool, f->type, name, &inner_ty, &inner_off,
    964                      &inner_f)) {
    965         *out_type = inner_ty;
    966         *out_offset = L->fields[i].offset + inner_off;
    967         *out_field = inner_f;
    968         return 1;
    969       }
    970     }
    971   }
    972   return 0;
    973 }
    974 
    975 typedef struct MemberNameSeen {
    976   Sym name;
    977   struct MemberNameSeen* next;
    978 } MemberNameSeen;
    979 
    980 static int member_name_seen(MemberNameSeen* names, Sym name) {
    981   for (; names; names = names->next) {
    982     if (names->name == name) return 1;
    983   }
    984   return 0;
    985 }
    986 
    987 static void member_name_add(Parser* p, MemberNameSeen** names, Sym name) {
    988   MemberNameSeen* n;
    989   if (!name) return;
    990   n = arena_new(p->pool->arena, MemberNameSeen);
    991   if (!n) perr(p, "out of memory tracking struct members");
    992   n->name = name;
    993   n->next = *names;
    994   *names = n;
    995 }
    996 
    997 static void validate_and_add_field(Parser* p, TypeRecordBuilder* b,
    998                                    const DeclSpecs* specs, Field* f,
    999                                    MemberNameSeen** names, u32* field_count,
   1000                                    int* saw_flexible) {
   1001   int is_flexible =
   1002       f->type && f->type->kind == TY_ARRAY && f->type->arr.incomplete;
   1003   validate_decl_type_constraints(p, specs, f->type, /*is_function=*/0,
   1004                                  /*is_member=*/1);
   1005   if ((f->flags & FIELD_BITFIELD) && specs->align) {
   1006     perr(p, "_Alignas is invalid on bit-field");
   1007   }
   1008   if (f->name && member_name_seen(*names, f->name)) {
   1009     perr(p, "duplicate member name");
   1010   }
   1011   if (*saw_flexible) perr(p, "flexible array member must be last");
   1012   if (is_flexible) {
   1013     if (*field_count == 0)
   1014       perr(p, "flexible array member cannot be only member");
   1015     f->flags |= FIELD_FLEXIBLE_ARRAY;
   1016     *saw_flexible = 1;
   1017   }
   1018   member_name_add(p, names, f->name);
   1019   type_record_field(b, *f);
   1020   ++*field_count;
   1021 }
   1022 
   1023 static void parse_member_decls(Parser* p, TypeRecordBuilder* b) {
   1024   MemberNameSeen* names = NULL;
   1025   u32 field_count = 0;
   1026   int saw_flexible = 0;
   1027   while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) {
   1028     DeclSpecs specs;
   1029     if (!parse_decl_specs(p, &specs)) {
   1030       perr(p, "expected member declaration");
   1031     }
   1032     if (is_punct(&p->cur, ';')) {
   1033       if (specs.type &&
   1034           (specs.type->kind == TY_STRUCT || specs.type->kind == TY_UNION)) {
   1035         Field f;
   1036         memset(&f, 0, sizeof f);
   1037         f.name = 0;
   1038         f.type = specs.type;
   1039         f.flags = FIELD_ANON;
   1040         validate_and_add_field(p, b, &specs, &f, &names, &field_count,
   1041                                &saw_flexible);
   1042         advance(p);
   1043         continue;
   1044       }
   1045       perr(p, "declaration without declarator must be anonymous aggregate");
   1046     }
   1047     for (;;) {
   1048       Sym mname = 0;
   1049       SrcLoc mloc = tok_loc(p, &p->cur);
   1050       const Type* mty;
   1051       Field f;
   1052       memset(&f, 0, sizeof f);
   1053       if (is_punct(&p->cur, ':')) {
   1054         advance(p);
   1055         if (!type_is_int(specs.type)) perr(p, "bit-field has non-integer type");
   1056         i64 w = eval_const_int(p, mloc);
   1057         if (w < 0) perr(p, "negative bit-field width");
   1058         if (w > (i64)c_abi_sizeof(p->abi, p->pool, specs.type) * 8) {
   1059           perr(p, "bit-field width exceeds its type width");
   1060         }
   1061         f.name = 0;
   1062         f.type = specs.type;
   1063         f.bitfield_width = (u16)w;
   1064         f.flags = FIELD_BITFIELD;
   1065         if (w == 0) f.flags |= FIELD_ZERO_WIDTH;
   1066         attrs_to_field(specs.attrs, &f);
   1067         if (specs.align > f.align_override) f.align_override = (u16)specs.align;
   1068         validate_and_add_field(p, b, &specs, &f, &names, &field_count,
   1069                                &saw_flexible);
   1070         if (!accept_punct(p, ',')) break;
   1071         continue;
   1072       }
   1073       Attr* mattrs = NULL;
   1074       mty = parse_declarator_full_ex(p, specs.type, /*allow_abstract=*/0,
   1075                                      &mname, &mloc, &mattrs);
   1076       if (accept_punct(p, ':')) {
   1077         if (!type_is_int(mty)) perr(p, "bit-field has non-integer type");
   1078         i64 w = eval_const_int(p, mloc);
   1079         if (w < 0) perr(p, "negative bit-field width");
   1080         if (w == 0 && mname != 0)
   1081           perr(p, "zero-width bit-field must be unnamed");
   1082         if (w > (i64)c_abi_sizeof(p->abi, p->pool, mty) * 8) {
   1083           perr(p, "bit-field width exceeds its type width");
   1084         }
   1085         f.name = mname;
   1086         f.type = mty;
   1087         f.bitfield_width = (u16)w;
   1088         f.flags = FIELD_BITFIELD;
   1089         if (w == 0) f.flags |= FIELD_ZERO_WIDTH;
   1090       } else {
   1091         f.name = mname;
   1092         f.type = mty;
   1093         f.flags = FIELD_NONE;
   1094       }
   1095       attrs_to_field(specs.attrs, &f);
   1096       attrs_to_field(mattrs, &f);
   1097       {
   1098         Attr* trailing = NULL;
   1099         parse_attrs_into(p, &trailing);
   1100         attrs_to_field(trailing, &f);
   1101       }
   1102       if (specs.align > f.align_override) f.align_override = (u16)specs.align;
   1103       validate_and_add_field(p, b, &specs, &f, &names, &field_count,
   1104                              &saw_flexible);
   1105       if (!accept_punct(p, ',')) break;
   1106     }
   1107     expect_punct(p, ';', "';' after struct member declaration");
   1108   }
   1109 }
   1110 
   1111 const Type* parse_struct_or_union(Parser* p, TypeKind kind,
   1112                                   Attr** anon_attrs_out) {
   1113   Sym tag_name = 0;
   1114   SrcLoc tag_loc;
   1115   TagDeclKind tdk = (kind == TY_STRUCT) ? TAG_STRUCT : TAG_UNION;
   1116   Attr* rec_attrs = NULL;
   1117   parse_attrs_into(p, &rec_attrs);
   1118   tag_loc = tok_loc(p, &p->cur);
   1119   if (p->cur.kind == TOK_IDENT &&
   1120       ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) {
   1121     tag_name = tok_ident(&p->cur);
   1122     advance(p);
   1123   }
   1124   int has_body = is_punct(&p->cur, '{');
   1125   if (!has_body && tag_name == 0) {
   1126     perr(p, "expected tag name or '{' after struct/union");
   1127   }
   1128   if (!has_body) {
   1129     TagEntry* e = tag_lookup(p, tag_name);
   1130     if (e) {
   1131       if (e->kind != tdk) {
   1132         perr(p, "use of tag with wrong kind (struct vs union)");
   1133       }
   1134       attr_list_append(&e->attrs, rec_attrs);
   1135       return e->type;
   1136     }
   1137     {
   1138       TagId tid = type_tag_new(p->pool, tdk, tag_name, tag_loc);
   1139       Type* t = type_record_forward(p->pool, kind, tid, tag_name);
   1140       TagEntry* te = tag_define(p, tag_name, tdk, t, /*complete=*/0);
   1141       attr_list_append(&te->attrs, rec_attrs);
   1142       return t;
   1143     }
   1144   }
   1145   Type* target = NULL;
   1146   TagEntry* existing = tag_name ? tag_lookup_local(p, tag_name) : NULL;
   1147   TagEntry* te = NULL;
   1148   if (existing) {
   1149     if (existing->kind != tdk) {
   1150       perr(p, "tag redeclared with wrong kind");
   1151     }
   1152     if (existing->complete) {
   1153       perr(p, "redefinition of tag");
   1154     }
   1155     target = existing->type;
   1156     te = existing;
   1157   } else {
   1158     TagId tid = type_tag_new(p->pool, tdk, tag_name, tag_loc);
   1159     target = type_record_forward(p->pool, kind, tid, tag_name);
   1160     if (tag_name) {
   1161       te = tag_define(p, tag_name, tdk, target, /*complete=*/0);
   1162     }
   1163   }
   1164   if (te) {
   1165     attr_list_append(&te->attrs, rec_attrs);
   1166   } else if (anon_attrs_out) {
   1167     attr_list_append(anon_attrs_out, rec_attrs);
   1168   }
   1169   expect_punct(p, '{', "'{' to start aggregate body");
   1170   TypeRecordOpts begin_opts;
   1171   memset(&begin_opts, 0, sizeof begin_opts);
   1172   {
   1173     u32 pack_align = pp_pack_alignment(p->pp);
   1174     if (pack_align > 65535u) pack_align = 65535u;
   1175     begin_opts.max_align = (u16)pack_align;
   1176   }
   1177   attrs_to_record_opts(rec_attrs, &begin_opts);
   1178   TypeRecordBuilder* b = type_record_begin_ex(p->pool, kind, target->rec.tag_id,
   1179                                               tag_name, begin_opts);
   1180   parse_member_decls(p, b);
   1181   expect_punct(p, '}', "'}' after aggregate body");
   1182   TypeRecordOpts trailing_opts;
   1183   memset(&trailing_opts, 0, sizeof trailing_opts);
   1184   {
   1185     Attr* trailing_attrs = NULL;
   1186     parse_attrs_into(p, &trailing_attrs);
   1187     attrs_to_record_opts(trailing_attrs, &trailing_opts);
   1188     if (te) {
   1189       attr_list_append(&te->attrs, trailing_attrs);
   1190     } else if (anon_attrs_out) {
   1191       attr_list_append(anon_attrs_out, trailing_attrs);
   1192     }
   1193   }
   1194   {
   1195     const Type* fresh = type_record_end(p->pool, b);
   1196     target->rec.packed = fresh->rec.packed;
   1197     target->rec.max_align = fresh->rec.max_align;
   1198     target->rec.align_override = fresh->rec.align_override;
   1199     type_record_install(target, (Field*)fresh->rec.fields, fresh->rec.nfields);
   1200   }
   1201   if (trailing_opts.packed) target->rec.packed = 1;
   1202   if (trailing_opts.align_override > target->rec.align_override)
   1203     target->rec.align_override = trailing_opts.align_override;
   1204   if (te) te->complete = 1;
   1205   return target;
   1206 }
   1207 
   1208 const Type* parse_enum(Parser* p, Attr** anon_attrs_out) {
   1209   Sym tag_name = 0;
   1210   SrcLoc tag_loc;
   1211   Attr* rec_attrs = NULL;
   1212   parse_attrs_into(p, &rec_attrs);
   1213   tag_loc = tok_loc(p, &p->cur);
   1214   if (p->cur.kind == TOK_IDENT &&
   1215       ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) {
   1216     tag_name = tok_ident(&p->cur);
   1217     advance(p);
   1218   }
   1219   /* C23 §6.7.2.2: an optional fixed underlying type — `enum [tag] : T` —
   1220    * may follow the tag (or `enum`), in both the defining and the
   1221    * forward-declaring forms. T is an integer type-specifier list; we reuse
   1222    * the type-name parser and adopt T as the enum's representation type. */
   1223   const Type* underlying = ty_int(p);
   1224   int has_fixed_type = 0;
   1225   if (accept_punct(p, ':')) {
   1226     underlying = parse_type_name(p);
   1227     has_fixed_type = 1;
   1228   }
   1229   int has_body = is_punct(&p->cur, '{');
   1230   if (!has_body && tag_name == 0) {
   1231     perr(p, "expected tag name or '{' after enum");
   1232   }
   1233   if (!has_body) {
   1234     TagEntry* e = tag_lookup(p, tag_name);
   1235     if (e && e->kind == TAG_ENUM) {
   1236       attr_list_append(&e->attrs, rec_attrs);
   1237       return e->type;
   1238     }
   1239     if (e) {
   1240       perr(p, "tag redeclared with wrong kind");
   1241     }
   1242     if (!has_fixed_type) {
   1243       perr(p, "enum tag declared without definition");
   1244     }
   1245     /* C23 `enum E : T;` with no enumerators is a forward declaration carrying a
   1246      * fixed underlying type. Record an *incomplete* tag (so the type knows T)
   1247      * that a later `enum E : T { ... }` can complete; a redefinition is only
   1248      * diagnosed once an enumerator body actually arrives. */
   1249     {
   1250       TagId ftid = type_tag_new(p->pool, TAG_ENUM, tag_name, tag_loc);
   1251       const Type* fet = type_enum(p->pool, ftid, tag_name, underlying);
   1252       TagEntry* te =
   1253           tag_define(p, tag_name, TAG_ENUM, (Type*)fet, /*complete=*/0);
   1254       attr_list_append(&te->attrs, rec_attrs);
   1255       return fet;
   1256     }
   1257   }
   1258   TagId tid = type_tag_new(p->pool, TAG_ENUM, tag_name, tag_loc);
   1259   const Type* et = type_enum(p->pool, tid, tag_name, underlying);
   1260   expect_punct(p, '{', "'{'");
   1261   i64 next_val = 0;
   1262   /* Collect enumerators so the enum Type can carry them into CG/debug info
   1263    * (DW_TAG_enumerator). Geometric growth from the arena keeps it allocation-
   1264    * light; the arena never frees, but enum bodies are small. */
   1265   EnumConst* consts = NULL;
   1266   u32 nconsts = 0, consts_cap = 0;
   1267   for (;;) {
   1268     Sym name;
   1269     SrcLoc nloc = tok_loc(p, &p->cur);
   1270     SymEntry* e;
   1271     if (p->cur.kind != TOK_IDENT ||
   1272         ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) {
   1273       perr(p, "expected enumerator name");
   1274     }
   1275     name = tok_ident(&p->cur);
   1276     advance(p);
   1277     i64 val = next_val;
   1278     if (accept_punct(p, '=')) {
   1279       val = eval_const_int(p, nloc);
   1280     }
   1281     if (scope_lookup_current(p, name)) {
   1282       perr(p, "redefinition of enumerator");
   1283     }
   1284     e = scope_define(p, name, SEK_ENUM_CST, et);
   1285     e->v.enum_value = val;
   1286     next_val = val + 1;
   1287     if (nconsts == consts_cap) {
   1288       u32 newcap = consts_cap ? consts_cap * 2u : 8u;
   1289       EnumConst* grown = arena_array(p->pool->arena, EnumConst, newcap);
   1290       if (grown && consts) memcpy(grown, consts, nconsts * sizeof(EnumConst));
   1291       consts = grown;
   1292       consts_cap = grown ? newcap : 0;
   1293     }
   1294     if (consts && nconsts < UINT16_MAX) {
   1295       consts[nconsts].name = name;
   1296       consts[nconsts].value = val;
   1297       nconsts++;
   1298     }
   1299     if (!accept_punct(p, ',')) break;
   1300     if (is_punct(&p->cur, '}')) break;
   1301   }
   1302   expect_punct(p, '}', "'}' after enumerator list");
   1303   ((Type*)et)->enm.consts = consts;
   1304   ((Type*)et)->enm.nconsts = (u16)nconsts;
   1305   parse_attrs_into(p, &rec_attrs);
   1306   if (tag_name) {
   1307     TagEntry* existing = tag_lookup_local(p, tag_name);
   1308     if (existing) {
   1309       if (existing->kind != TAG_ENUM) {
   1310         perr(p, "tag redeclared with wrong kind");
   1311       }
   1312       if (existing->complete) {
   1313         perr(p, "redefinition of enum tag");
   1314       }
   1315       existing->complete = 1;
   1316       attr_list_append(&existing->attrs, rec_attrs);
   1317     } else {
   1318       TagEntry* te = tag_define(p, tag_name, TAG_ENUM, (Type*)et,
   1319                                 /*complete=*/1);
   1320       attr_list_append(&te->attrs, rec_attrs);
   1321     }
   1322   } else if (anon_attrs_out) {
   1323     attr_list_append(anon_attrs_out, rec_attrs);
   1324   }
   1325   return et;
   1326 }
   1327 
   1328 /* ============================================================
   1329  * starts_type_name, parse_pointer_layer, parse_type_name
   1330  * ============================================================ */
   1331 
   1332 int starts_type_name(const Parser* p, const Tok* t) {
   1333   if (t->kind != TOK_IDENT) return 0;
   1334   if (is_typeof_spelling(p, t)) return 1;
   1335   CKw k = ident_kw_inline(p, tok_ident(t));
   1336   switch (k) {
   1337     case KW_VOID:
   1338     case KW_CHAR:
   1339     case KW_SHORT:
   1340     case KW_INT:
   1341     case KW_LONG:
   1342     case KW_FLOAT:
   1343     case KW_FLOAT16:
   1344     case KW_DOUBLE:
   1345     case KW_SIGNED:
   1346     case KW_UNSIGNED:
   1347     case KW_BOOL:
   1348     case KW_STRUCT:
   1349     case KW_UNION:
   1350     case KW_ENUM:
   1351     case KW_CONST:
   1352     case KW_VOLATILE:
   1353     case KW_RESTRICT:
   1354     case KW_ATOMIC:
   1355     case KW_STATIC:
   1356     case KW_EXTERN:
   1357     case KW_INLINE:
   1358     case KW_NORETURN:
   1359     case KW_REGISTER:
   1360     case KW_AUTO:
   1361     case KW_TYPEDEF:
   1362     case KW_ALIGNAS:
   1363     case KW_THREAD_LOCAL:
   1364       return 1;
   1365     case KW_NONE: {
   1366       if (tok_ident(t) == p->sym_b_va_list) return 1;
   1367       if (tok_ident(t) == p->sym_int128 || tok_ident(t) == p->sym_int128_t ||
   1368           tok_ident(t) == p->sym_uint128_t)
   1369         return 1;
   1370       SymEntry* e = scope_lookup((Parser*)p, tok_ident(t));
   1371       return e && e->kind == SEK_TYPEDEF;
   1372     }
   1373     default:
   1374       return 0;
   1375   }
   1376 }
   1377 
   1378 const Type* parse_pointer_layer(Parser* p, const Type* base) {
   1379   while (accept_punct(p, '*')) {
   1380     u16 q = 0;
   1381     base = type_ptr(p->pool, base);
   1382     for (;;) {
   1383       if (accept_kw(p, KW_CONST)) {
   1384         q |= Q_CONST;
   1385         continue;
   1386       }
   1387       if (accept_kw(p, KW_VOLATILE)) {
   1388         q |= Q_VOLATILE;
   1389         continue;
   1390       }
   1391       if (accept_kw(p, KW_RESTRICT)) {
   1392         q |= Q_RESTRICT;
   1393         continue;
   1394       }
   1395       if (accept_kw(p, KW_ATOMIC)) {
   1396         q |= Q_ATOMIC;
   1397         continue;
   1398       }
   1399       if (starts_attr(p)) {
   1400         parse_and_discard_attributes(p);
   1401         continue;
   1402       }
   1403       break;
   1404     }
   1405     if (q) base = type_qualified(p->pool, base, q);
   1406   }
   1407   return base;
   1408 }
   1409 
   1410 const Type* parse_type_name(Parser* p) {
   1411   DeclSpecs specs;
   1412   Sym dummy_name = 0;
   1413   SrcLoc dummy_loc = {0, 0, 0};
   1414   if (!parse_decl_specs(p, &specs)) {
   1415     perr(p, "expected type-name");
   1416   }
   1417   return parse_declarator_full(p, specs.type, /*allow_abstract=*/1, &dummy_name,
   1418                                &dummy_loc);
   1419 }
   1420 
   1421 /* ============================================================
   1422  * Declarator suffix helpers
   1423  * (DeclSuffix / DSuffKind defined in parse_priv.h)
   1424  * ============================================================ */
   1425 
   1426 static void param_vla_record_bound(Parser* p, Tok* toks, u32 ntoks,
   1427                                    int has_expr) {
   1428   ParamVLABoundExpr* b;
   1429   if (p->param_vla_bound_len >=
   1430       sizeof p->param_vla_bounds / sizeof p->param_vla_bounds[0]) {
   1431     perr(p, "too many VLA dimensions per parameter");
   1432   }
   1433   b = &p->param_vla_bounds[p->param_vla_bound_len++];
   1434   b->toks = toks;
   1435   b->ntoks = ntoks;
   1436   b->has_expr = (u8)(has_expr ? 1 : 0);
   1437 }
   1438 
   1439 static void parse_param_array_bound(Parser* p, DeclSuffix* out) {
   1440   Tok* toks = NULL;
   1441   u32 ntoks = 0;
   1442   u32 cap = 0;
   1443   int depth = 1;
   1444   int has_expr = 0;
   1445 
   1446   out->incomplete = 1;
   1447   if (accept_punct(p, ']')) {
   1448     param_vla_record_bound(p, NULL, 0, 0);
   1449     return;
   1450   }
   1451   while (depth > 0) {
   1452     Tok t = p->cur;
   1453     if (t.kind == TOK_EOF) {
   1454       perr(p, "unexpected EOF in parameter array bound");
   1455     }
   1456     if (is_punct(&t, '[')) {
   1457       ++depth;
   1458     } else if (is_punct(&t, ']')) {
   1459       --depth;
   1460       if (depth == 0) break;
   1461     }
   1462     if (ntoks == cap) {
   1463       u32 nc = cap ? cap * 2u : 4u;
   1464       Tok* nb = arena_array(p->pool->arena, Tok, nc);
   1465       if (toks && ntoks) memcpy(nb, toks, sizeof(Tok) * ntoks);
   1466       toks = nb;
   1467       cap = nc;
   1468     }
   1469     toks[ntoks++] = t;
   1470     has_expr = 1;
   1471     advance(p);
   1472   }
   1473   if (ntoks == 1 && toks[0].kind == TOK_PUNCT && tok_punct(&toks[0]) == '*') {
   1474     has_expr = 0;
   1475   }
   1476   if (ntoks == 1 && toks[0].kind == TOK_NUM) {
   1477     i64 count = parse_int_literal(p, &toks[0]);
   1478     if (count <= 0 || (u64)count > UINT32_MAX) {
   1479       perr(p, "array bound must be positive");
   1480     }
   1481     out->count = (u32)count;
   1482     out->incomplete = 0;
   1483     out->vla = 0;
   1484     expect_punct(p, ']', "']' after array size");
   1485     return;
   1486   }
   1487   param_vla_record_bound(p, toks, ntoks, has_expr);
   1488   expect_punct(p, ']', "']' after array size");
   1489 }
   1490 
   1491 int parse_decl_suffix(Parser* p, DeclSuffix* out) {
   1492   if (accept_punct(p, '[')) {
   1493     out->kind = DS_ARRAY;
   1494     out->count = 0;
   1495     out->incomplete = 0;
   1496     out->vla = 0;
   1497     for (;;) {
   1498       if (accept_kw(p, KW_STATIC) || accept_kw(p, KW_CONST) ||
   1499           accept_kw(p, KW_VOLATILE) || accept_kw(p, KW_RESTRICT) ||
   1500           accept_kw(p, KW_ATOMIC)) {
   1501         continue;
   1502       }
   1503       break;
   1504     }
   1505     if (p->in_param_decl) {
   1506       parse_param_array_bound(p, out);
   1507       return 1;
   1508     }
   1509     if (accept_punct(p, ']')) {
   1510       out->incomplete = 1;
   1511       return 1;
   1512     }
   1513     {
   1514       Tok t = p->cur;
   1515       /* A VLA is a block-scope-only feature (§6.7.6.2¶4): at file scope every
   1516        * declared array bound must be an integer constant expression. Route all
   1517        * file-scope bounds through eval_const_int below, so a non-constant bound
   1518        * becomes a clean "non-constant ... in constant expression" diagnostic
   1519        * instead of entering the VLA codegen path — which assumes an active
   1520        * function frame (c_cg_local/alloca/branch) and, with none at file scope,
   1521        * silently miscompiles or hangs. */
   1522       int is_const_start =
   1523           p->cur_func_name == 0 || t.kind == TOK_NUM || t.kind == TOK_CHR;
   1524       if (t.kind == TOK_FLT) {
   1525         perr(p, "array bound requires integer type");
   1526       }
   1527       if (!is_const_start && t.kind == TOK_IDENT) {
   1528         SymEntry* e = scope_lookup(p, tok_ident(&t));
   1529         if (e && e->kind == SEK_ENUM_CST) is_const_start = 1;
   1530         if (!is_const_start) {
   1531           CKw k = ident_kw_inline(p, tok_ident(&t));
   1532           if (k == KW_SIZEOF || k == KW_ALIGNOF) is_const_start = 1;
   1533         }
   1534       }
   1535       if (is_const_start) {
   1536         SrcLoc cloc = tok_loc(p, &p->cur);
   1537         i64 v = eval_const_int(p, cloc);
   1538         if (v < 0) perr(p, "negative array size");
   1539         out->count = (u32)v;
   1540       } else {
   1541         FrameSlotDesc fsd;
   1542         if (p->vla_pending_count_len >=
   1543             sizeof p->vla_pending_count_slots /
   1544                 sizeof p->vla_pending_count_slots[0]) {
   1545           perr(p, "too many VLA dimensions per declarator");
   1546         }
   1547         out->vla = 1;
   1548         memset(&fsd, 0, sizeof fsd);
   1549         fsd.type = ty_size_t(p);
   1550         fsd.size = c_abi_sizeof(p->abi, p->pool, fsd.type);
   1551         fsd.align = c_abi_alignof(p->abi, p->pool, fsd.type);
   1552         fsd.kind = FS_LOCAL;
   1553         out->vla_count_slot = c_cg_local(p, &fsd);
   1554         parse_assign_expr(p);
   1555         to_rvalue(p);
   1556         c_cg_push_local_typed(p, out->vla_count_slot, fsd.type);
   1557         c_cg_swap(p);
   1558         coerce_top_to_lvalue(p);
   1559         c_cg_store_void(p);
   1560         p->vla_pending = 1;
   1561         ++p->vla_mark;
   1562         p->vla_pending_count_slot = out->vla_count_slot;
   1563         p->vla_pending_count_slots[p->vla_pending_count_len++] =
   1564             out->vla_count_slot;
   1565       }
   1566     }
   1567     expect_punct(p, ']', "']' after array size");
   1568     return 1;
   1569   }
   1570   if (accept_punct(p, '(')) {
   1571     out->kind = DS_FUNC;
   1572     out->params = NULL;
   1573     out->nparams = 0;
   1574     out->variadic = 0;
   1575     parse_param_list(p, &out->params, &out->nparams, &out->variadic);
   1576     expect_punct(p, ')', "')' after parameter list");
   1577     return 1;
   1578   }
   1579   return 0;
   1580 }
   1581 
   1582 const Type* apply_decl_suffix(Parser* p, const Type* base,
   1583                               const DeclSuffix* s) {
   1584   if (s->kind == DS_ARRAY) {
   1585     if (base && base->kind == TY_FUNC) {
   1586       perr(p, "array of function type is invalid");
   1587     }
   1588     if (base && base->kind == TY_VOID) {
   1589       perr(p, "array of void type is invalid");
   1590     }
   1591     /* C11 6.7.6.2p1: an array's element type must be complete. Completeness is
   1592      * fixed where the array declarator is formed, so an incomplete record stays
   1593      * an error here even if its tag is completed later (or never) -- this is
   1594      * the constraint that rejects `struct N { struct N a[10]; }` while a
   1595      * pointer element (`struct N *a[10]`) stays legal because a pointer is
   1596      * complete. Element incompleteness is checked only for records: VLAs share
   1597      * the array `incomplete` flag, so an incomplete-array element cannot be
   1598      * told apart from a valid VLA element here and is intentionally not
   1599      * diagnosed. */
   1600     if (base && (base->kind == TY_STRUCT || base->kind == TY_UNION) &&
   1601         base->rec.incomplete) {
   1602       if (base->rec.tag) {
   1603         perr(p, "array has incomplete element type '%s %.*s'",
   1604              base->kind == TY_UNION ? "union" : "struct",
   1605              KIT_SLICE_ARG(kit_sym_str(p->pool->c, base->rec.tag)));
   1606       }
   1607       perr(p, "array has incomplete element type");
   1608     }
   1609     return type_array(p->pool, base, s->count, s->incomplete || s->vla);
   1610   }
   1611   {
   1612     const Type** ptypes = NULL;
   1613     if (base && base->kind == TY_ARRAY) {
   1614       perr(p, "function returning array is invalid");
   1615     }
   1616     if (base && base->kind == TY_FUNC) {
   1617       perr(p, "function returning function is invalid");
   1618     }
   1619     if (s->nparams) {
   1620       ptypes =
   1621           (const Type**)arena_array(p->pool->arena, const Type*, s->nparams);
   1622       for (u16 i = 0; i < s->nparams; ++i) ptypes[i] = s->params[i].type;
   1623     }
   1624     return type_func(p->pool, base, ptypes, s->nparams, (int)s->variadic);
   1625   }
   1626 }
   1627 
   1628 /* ============================================================
   1629  * parse_declarator_full, parse_declarator_full_ex, parse_declarator
   1630  * ============================================================ */
   1631 
   1632 const Type* parse_declarator_full(Parser* p, const Type* base,
   1633                                   int allow_abstract, Sym* name_out,
   1634                                   SrcLoc* loc_out) {
   1635   return parse_declarator_full_ex(p, base, allow_abstract, name_out, loc_out,
   1636                                   NULL);
   1637 }
   1638 
   1639 const Type* parse_declarator_full_ex(Parser* p, const Type* base,
   1640                                      int allow_abstract, Sym* name_out,
   1641                                      SrcLoc* loc_out, Attr** attrs_out) {
   1642   return parse_declarator_full_info(p, base, allow_abstract, name_out, loc_out,
   1643                                     attrs_out, NULL);
   1644 }
   1645 
   1646 const Type* parse_declarator_full_info(Parser* p, const Type* base,
   1647                                        int allow_abstract, Sym* name_out,
   1648                                        SrcLoc* loc_out, Attr** attrs_out,
   1649                                        DeclaratorInfo* info_out) {
   1650   Attr* local_attrs = NULL;
   1651   Sym asm_label = 0;
   1652   base = parse_pointer_layer(p, base);
   1653 
   1654   Sym name = 0;
   1655   SrcLoc nloc = {0, 0, 0};
   1656   u8 nptrs_inner = 0;
   1657   u16 inner_quals[8];
   1658   u8 nptrs_nested = 0;
   1659   u16 nested_quals[8];
   1660   int has_inner_parens = 0;
   1661   DeclSuffix inner_suffs[8];
   1662   int n_inner_suffs = 0;
   1663 
   1664   if (is_punct(&p->cur, '(')) {
   1665     Tok n = peek1(p);
   1666     int is_inner = 0;
   1667     if (is_punct(&n, '*')) {
   1668       is_inner = 1;
   1669     } else if (n.kind == TOK_IDENT &&
   1670                ident_kw_inline(p, tok_ident(&n)) == KW_NONE) {
   1671       SymEntry* e = scope_lookup(p, tok_ident(&n));
   1672       if (!(e && e->kind == SEK_TYPEDEF)) is_inner = 1;
   1673     }
   1674     if (is_inner) {
   1675       has_inner_parens = 1;
   1676       advance(p); /* '(' */
   1677       while (accept_punct(p, '*')) {
   1678         u16 q = 0;
   1679         if (nptrs_inner >= 8) perr(p, "too many pointer levels");
   1680         for (;;) {
   1681           if (accept_kw(p, KW_CONST)) {
   1682             q |= Q_CONST;
   1683             continue;
   1684           }
   1685           if (accept_kw(p, KW_VOLATILE)) {
   1686             q |= Q_VOLATILE;
   1687             continue;
   1688           }
   1689           if (accept_kw(p, KW_RESTRICT)) {
   1690             q |= Q_RESTRICT;
   1691             continue;
   1692           }
   1693           if (accept_kw(p, KW_ATOMIC)) {
   1694             q |= Q_ATOMIC;
   1695             continue;
   1696           }
   1697           if (starts_attr(p) || starts_asm_label(p)) {
   1698             parse_and_discard_attrs_or_asm(p);
   1699             continue;
   1700           }
   1701           break;
   1702         }
   1703         inner_quals[nptrs_inner++] = q;
   1704       }
   1705       if (p->cur.kind == TOK_IDENT &&
   1706           ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) {
   1707         name = tok_ident(&p->cur);
   1708         nloc = tok_loc(p, &p->cur);
   1709         advance(p);
   1710       } else if (is_punct(&p->cur, '(')) {
   1711         Tok nn = peek1(p);
   1712         if (!is_punct(&nn, '*')) {
   1713           if (!allow_abstract) perr(p, "expected declarator name");
   1714           goto after_inner_name;
   1715         }
   1716         advance(p); /* nested '(' */
   1717         while (accept_punct(p, '*')) {
   1718           u16 q = 0;
   1719           if (nptrs_nested >= 8) perr(p, "too many pointer levels");
   1720           for (;;) {
   1721             if (accept_kw(p, KW_CONST)) {
   1722               q |= Q_CONST;
   1723               continue;
   1724             }
   1725             if (accept_kw(p, KW_VOLATILE)) {
   1726               q |= Q_VOLATILE;
   1727               continue;
   1728             }
   1729             if (accept_kw(p, KW_RESTRICT)) {
   1730               q |= Q_RESTRICT;
   1731               continue;
   1732             }
   1733             if (accept_kw(p, KW_ATOMIC)) {
   1734               q |= Q_ATOMIC;
   1735               continue;
   1736             }
   1737             if (starts_attr(p) || starts_asm_label(p)) {
   1738               parse_and_discard_attrs_or_asm(p);
   1739               continue;
   1740             }
   1741             break;
   1742           }
   1743           nested_quals[nptrs_nested++] = q;
   1744         }
   1745         if (p->cur.kind == TOK_IDENT &&
   1746             ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) {
   1747           name = tok_ident(&p->cur);
   1748           nloc = tok_loc(p, &p->cur);
   1749           advance(p);
   1750         } else if (!allow_abstract) {
   1751           perr(p, "expected declarator name");
   1752         }
   1753         parse_and_discard_attrs_or_asm(p);
   1754         expect_punct(p, ')', "')' after nested declarator");
   1755       } else if (!allow_abstract) {
   1756         perr(p, "expected declarator name");
   1757       }
   1758     after_inner_name:
   1759       parse_and_discard_attrs_or_asm(p);
   1760       while (n_inner_suffs < 8) {
   1761         if (!parse_decl_suffix(p, &inner_suffs[n_inner_suffs])) break;
   1762         ++n_inner_suffs;
   1763         parse_and_discard_attrs_or_asm(p);
   1764       }
   1765       expect_punct(p, ')', "')' after inner declarator");
   1766     }
   1767   }
   1768 
   1769   if (!has_inner_parens) {
   1770     if (p->cur.kind == TOK_IDENT &&
   1771         ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE) {
   1772       name = tok_ident(&p->cur);
   1773       nloc = tok_loc(p, &p->cur);
   1774       advance(p);
   1775     } else if (!allow_abstract) {
   1776       perr(p, "expected declarator name");
   1777     }
   1778   }
   1779 
   1780   parse_attrs_and_asm_into(p, attrs_out, &local_attrs, &asm_label);
   1781 
   1782   DeclSuffix suffs[8];
   1783   int nsuffs = 0;
   1784   DeclSuffix* final_fn_suff = NULL;
   1785   if (info_out) memset(info_out, 0, sizeof *info_out);
   1786   while (nsuffs < 8) {
   1787     if (!parse_decl_suffix(p, &suffs[nsuffs])) break;
   1788     ++nsuffs;
   1789     parse_attrs_and_asm_into(p, attrs_out, &local_attrs, &asm_label);
   1790   }
   1791   base = attrs_apply_type_mode(p, base, attrs_out ? *attrs_out : local_attrs);
   1792   if (nsuffs == 8 && (is_punct(&p->cur, '[') || is_punct(&p->cur, '('))) {
   1793     perr(p, "too many declarator suffixes (raise the cap if needed)");
   1794   }
   1795   if (n_inner_suffs > 0 && inner_suffs[0].kind == DS_FUNC) {
   1796     final_fn_suff = &inner_suffs[0];
   1797   } else if (n_inner_suffs == 0 && nptrs_inner == 0 && nsuffs > 0 &&
   1798              suffs[0].kind == DS_FUNC) {
   1799     final_fn_suff = &suffs[0];
   1800   }
   1801   for (int i = nsuffs - 1; i >= 0; --i) {
   1802     base = apply_decl_suffix(p, base, &suffs[i]);
   1803   }
   1804 
   1805   for (int i = (int)nptrs_inner - 1; i >= 0; --i) {
   1806     base = type_ptr(p->pool, base);
   1807     if (inner_quals[i]) {
   1808       base = type_qualified(p->pool, base, inner_quals[i]);
   1809     }
   1810   }
   1811 
   1812   for (int i = n_inner_suffs - 1; i >= 0; --i) {
   1813     base = apply_decl_suffix(p, base, &inner_suffs[i]);
   1814   }
   1815 
   1816   for (int i = (int)nptrs_nested - 1; i >= 0; --i) {
   1817     base = type_ptr(p->pool, base);
   1818     if (nested_quals[i]) {
   1819       base = type_qualified(p->pool, base, nested_quals[i]);
   1820     }
   1821   }
   1822 
   1823   if (info_out && base && base->kind == TY_FUNC && final_fn_suff) {
   1824     info_out->fn_params = final_fn_suff->params;
   1825     info_out->fn_nparams = final_fn_suff->nparams;
   1826     info_out->fn_variadic = final_fn_suff->variadic;
   1827   }
   1828   if (info_out) info_out->asm_label = asm_label;
   1829   if (name_out) *name_out = name;
   1830   if (loc_out) *loc_out = nloc;
   1831   return base;
   1832 }
   1833 
   1834 const Type* parse_declarator(Parser* p, const Type* base, Sym* name_out,
   1835                              SrcLoc* loc_out) {
   1836   return parse_declarator_full(p, base, /*allow_abstract=*/0, name_out,
   1837                                loc_out);
   1838 }
   1839 
   1840 /* ============================================================
   1841  * complete_incomplete_array
   1842  * ============================================================ */
   1843 
   1844 const Type* complete_incomplete_array(Parser* p, const Type* ty) {
   1845   const Type* elem;
   1846   if (!ty || ty->kind != TY_ARRAY || !ty->arr.incomplete) return ty;
   1847   elem = ty->arr.elem;
   1848   if (p->cur.kind == TOK_STR &&
   1849       string_literal_initializes_array(p, elem, &p->cur)) {
   1850     Tok t = p->cur;
   1851     size_t n = 0;
   1852     u8* bytes = decode_string_literal(p, &t, &n);
   1853     u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem);
   1854     kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
   1855                                            bytes, 0);
   1856     return type_array(p->pool, elem, elem_size ? (u32)(n / elem_size) : 0,
   1857                       /*incomplete=*/0);
   1858   }
   1859   if (is_punct(&p->cur, '{')) {
   1860     u32 cnt;
   1861     record_braced_block(p);
   1862     cnt = count_recorded_top_level_items(p->replay, p->replay_len);
   1863     if (cnt == 1 && p->replay_len >= 3 && p->replay[1].kind == TOK_STR &&
   1864         string_literal_initializes_array(p, elem, &p->replay[1])) {
   1865       Tok t = p->replay[1];
   1866       size_t n = 0;
   1867       u8* bytes = decode_string_literal(p, &t, &n);
   1868       u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem);
   1869       kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
   1870                                              bytes, 0);
   1871       cnt = elem_size ? (u32)(n / elem_size) : 0;
   1872     }
   1873     replay_rewind(p);
   1874     return type_array(p->pool, elem, cnt, /*incomplete=*/0);
   1875   }
   1876   perr(p, "initializer cannot complete incomplete array type");
   1877 }