kit

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

parse_init.c (57470B)


      1 /* parse_init.c — runtime and static-storage initializers.
      2  *
      3  * Covers §6.7.9 (initializers):
      4  *   - Runtime aggregate/scalar initializers (init_at, init_elided,
      5  *     init_struct_fields, init_string_at, parse_designator_chain,
      6  *     push_subobject_lv, emit_copy_leaf, emit_walk_copy,
      7  *     emit_struct_copy_into_slot, zero_init_at)
      8  *   - Static-storage object definition (parse_static_init_at,
      9  *     parse_static_string_at, parse_static_const, encode_int_le,
     10  *     pick_object_section, define_static_object, srl_push)
     11  */
     12 
     13 #include "parse/parse_priv.h"
     14 
     15 /* ============================================================
     16  * File-local helpers
     17  * ============================================================ */
     18 
     19 static SrcLoc tok_loc_init(Parser* p, const Tok* t) {
     20   return pp_materialize_loc(p->pp, t->loc);
     21 }
     22 
     23 static const Type* init_field_type_at(const Type* ty, u16 i) {
     24   const Field* f = &ty->rec.fields[i];
     25   return f->type;
     26 }
     27 
     28 static u32 init_field_offset_at(const ABIRecordLayout* L, u16 i) {
     29   return L->fields[i].offset;
     30 }
     31 
     32 /* True if `ty` is char/signed char/unsigned char. */
     33 int is_char_kind(const Type* ty) {
     34   if (!ty) return 0;
     35   return ty->kind == TY_CHAR || ty->kind == TY_SCHAR || ty->kind == TY_UCHAR;
     36 }
     37 
     38 /* Decode the string token at p->cur without advancing. Returns a heap-
     39  * allocated byte buffer (caller frees) and writes length (including NUL)
     40  * to *nlen_out. */
     41 static u8* peek_string_bytes(Parser* p, size_t* nlen_out) {
     42   Tok t = p->cur;
     43   if (t.kind != TOK_STR) perr(p, "internal: peek_string_bytes on non-string");
     44   return decode_string_literal(p, &t, nlen_out);
     45 }
     46 
     47 static u64 decode_lit_unit_le(const u8* src, u32 size) {
     48   u64 v = 0;
     49   u32 i;
     50   if (size > 8u) size = 8u;
     51   for (i = 0; i < size; ++i) v |= (u64)src[i] << (8u * i);
     52   return v;
     53 }
     54 
     55 /* ============================================================
     56  * Runtime initializers
     57  * ============================================================ */
     58 
     59 /* Forward declaration for mutual recursion. */
     60 void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset,
     61              const Type* ty);
     62 
     63 typedef struct InitDesignatorCont {
     64   const Type* parent_ty;
     65   u32 parent_offset;
     66   u32 next_index;
     67 } InitDesignatorCont;
     68 
     69 static void init_aggregate_remainder(Parser* p, FrameSlot slot,
     70                                      const Type* arr_ty, u32 offset,
     71                                      const Type* ty, u32 start_index);
     72 
     73 static void replay_recorded_initializer_expr(Parser* p) {
     74   if (p->replay_len == 0)
     75     perr(p, "internal: empty initializer expression replay");
     76   p->cur = p->replay[0];
     77   p->replay_pos = 1;
     78   p->replay_active = 1;
     79   p->has_next = 0;
     80 }
     81 
     82 static void record_initializer_expr_for_replay(Parser* p) {
     83   u32 len = 0;
     84   u32 cap = 0;
     85   Tok* buf = NULL;
     86   int paren_depth = 0;
     87   int brack_depth = 0;
     88   int brace_depth = 0;
     89 
     90   for (;;) {
     91     if (len == cap) {
     92       u32 new_cap = cap ? cap * 2u : 16u;
     93       Tok* nb = arena_array(p->pool->arena, Tok, new_cap);
     94       if (!nb) perr(p, "out of memory recording initializer expression");
     95       if (buf && len) memcpy(nb, buf, len * sizeof(*buf));
     96       buf = nb;
     97       cap = new_cap;
     98     }
     99     buf[len++] = p->cur;
    100 
    101     if (p->cur.kind == TOK_EOF) break;
    102     if (paren_depth == 0 && brack_depth == 0 && brace_depth == 0 &&
    103         (is_punct(&p->cur, ',') || is_punct(&p->cur, '}'))) {
    104       break;
    105     }
    106 
    107     if (is_punct(&p->cur, '('))
    108       ++paren_depth;
    109     else if (is_punct(&p->cur, ')'))
    110       --paren_depth;
    111     else if (is_punct(&p->cur, '['))
    112       ++brack_depth;
    113     else if (is_punct(&p->cur, ']'))
    114       --brack_depth;
    115     else if (is_punct(&p->cur, '{'))
    116       ++brace_depth;
    117     else if (is_punct(&p->cur, '}'))
    118       --brace_depth;
    119 
    120     advance(p);
    121   }
    122 
    123   p->replay = buf;
    124   p->replay_cap = cap;
    125   p->replay_len = len;
    126   replay_recorded_initializer_expr(p);
    127 }
    128 
    129 static int try_init_aggregate_from_expr(Parser* p, FrameSlot slot,
    130                                         const Type* arr_ty, u32 offset,
    131                                         const Type* ty) {
    132   const Type* expr_ty;
    133   u32 save_depth;
    134   int compatible;
    135 
    136   if (!ty || (ty->kind != TY_STRUCT && ty->kind != TY_UNION)) return 0;
    137   if (is_punct(&p->cur, '{') || is_punct(&p->cur, '.') ||
    138       is_punct(&p->cur, '[')) {
    139     return 0;
    140   }
    141 
    142   record_initializer_expr_for_replay(p);
    143 
    144   save_depth = c_cg_stack_depth(p);
    145   c_cg_codegen_suppress_push(p);
    146   parse_assign_expr(p);
    147   expr_ty = c_cg_top_type(p);
    148   compatible =
    149       type_compatible(type_unqual(p->pool, ty), type_unqual(p->pool, expr_ty));
    150   c_cg_drop_to_depth(p, save_depth);
    151   c_cg_codegen_suppress_pop(p);
    152 
    153   replay_recorded_initializer_expr(p);
    154   if (!compatible) return 0;
    155 
    156   parse_assign_expr(p);
    157   if (!type_compatible(type_unqual(p->pool, ty),
    158                        type_unqual(p->pool, c_cg_top_type(p)))) {
    159     perr(p, "incompatible aggregate initializer");
    160   }
    161   emit_struct_copy_into_slot(p, slot, arr_ty, offset, ty);
    162   return 1;
    163 }
    164 
    165 /* Push the lvalue of a sub-object at byte offset `offset` within the array
    166  * local `slot` (whose type is `arr_ty`), with element type `elem_ty`. */
    167 void push_subobject_lv(Parser* p, FrameSlot slot, const Type* arr_ty,
    168                        u32 offset, const Type* elem_ty) {
    169   c_cg_push_local_typed(p, slot, arr_ty);
    170   /* Fold the byte offset onto the local lvalue's aux; the next
    171    * load/store/addr will bake it into the memop's ea.offset. The result is an
    172    * lvalue of elem_ty backed by the frame slot. */
    173   c_cg_lv_member(p, (i64)offset, elem_ty, /*bf_off=*/0, /*bf_w=*/0, /*ss=*/0);
    174 }
    175 
    176 void zero_object_bytes_at(Parser* p, FrameSlot slot, const Type* arr_ty,
    177                           u32 offset, const Type* ty) {
    178   KitCgMemAccess access = c_cg_mem(p, ty);
    179   push_subobject_lv(p, slot, arr_ty, offset, ty);
    180   c_cg_addr(p);
    181   kit_cg_memset(p->cg, 0, c_abi_sizeof(p->abi, p->pool, ty), access);
    182 }
    183 
    184 static void push_record_field_lv(Parser* p, FrameSlot slot, const Type* arr_ty,
    185                                  u32 rec_offset, const Type* rec_ty,
    186                                  u32 field_index) {
    187   const Field* f = &rec_ty->rec.fields[field_index];
    188   const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, rec_ty);
    189   u32 foff = L->fields[field_index].offset;
    190   u16 bf_off = 0;
    191   u16 bf_w = 0;
    192   u32 bf_ss = 0;
    193   push_subobject_lv(p, slot, arr_ty, rec_offset, rec_ty);
    194   if (f->flags & FIELD_BITFIELD) {
    195     bf_off = L->fields[field_index].bit_offset;
    196     bf_w = L->fields[field_index].bit_width;
    197     bf_ss = L->fields[field_index].storage_size;
    198   }
    199   c_cg_lv_member(p, (i64)foff, f->type, bf_off, bf_w, bf_ss);
    200 }
    201 
    202 /* Emit a load+store for one scalar leaf. */
    203 static void emit_copy_leaf(Parser* p, FrameSlot dst_slot,
    204                            const Type* dst_arr_ty, u32 dst_off,
    205                            FrameSlot src_ptr_slot, const Type* src_ptr_ty,
    206                            u32 src_off, const Type* leaf_ty) {
    207   push_subobject_lv(p, dst_slot, dst_arr_ty, dst_off, leaf_ty);
    208   c_cg_push_local_typed(p, src_ptr_slot, src_ptr_ty);
    209   c_cg_load(p);
    210   /* TOS is now a pointer rvalue (the loaded source pointer). Retag as a
    211    * C-language lvalue with POINTER_RV base, then fold the source byte offset
    212    * onto its aux. The next c_cg_load consumes the EA into the memop. */
    213   c_cg_deref(p, leaf_ty);
    214   c_cg_lv_member(p, (i64)src_off, leaf_ty, 0, 0, 0);
    215   c_cg_load(p);
    216   c_cg_store_void(p);
    217 }
    218 
    219 /* Walk a (possibly nested) aggregate, emitting a leaf load+store for each
    220  * scalar member. */
    221 static void emit_walk_copy(Parser* p, FrameSlot dst_slot,
    222                            const Type* dst_arr_ty, u32 dst_off,
    223                            FrameSlot src_ptr_slot, const Type* src_ptr_ty,
    224                            u32 src_off, const Type* ty) {
    225   if (ty->kind == TY_STRUCT) {
    226     const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
    227     for (u16 i = 0; i < ty->rec.nfields; ++i) {
    228       const Field* f = &ty->rec.fields[i];
    229       if (f->flags & FIELD_BITFIELD) continue;
    230       const Type* fty = init_field_type_at(ty, i);
    231       u32 foff = init_field_offset_at(L, i);
    232       emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + foff, src_ptr_slot,
    233                      src_ptr_ty, src_off + foff, fty);
    234     }
    235     return;
    236   }
    237   if (ty->kind == TY_ARRAY) {
    238     u32 esz = c_abi_sizeof(p->abi, p->pool, ty->arr.elem);
    239     for (u32 i = 0; i < ty->arr.count; ++i) {
    240       emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off + i * esz, src_ptr_slot,
    241                      src_ptr_ty, src_off + i * esz, ty->arr.elem);
    242     }
    243     return;
    244   }
    245   if (ty->kind == TY_UNION) {
    246     u32 sz = c_abi_sizeof(p->abi, p->pool, ty);
    247     const Type* uchar_ty = type_prim(p->pool, TY_UCHAR);
    248     for (u32 i = 0; i < sz; ++i) {
    249       emit_copy_leaf(p, dst_slot, dst_arr_ty, dst_off + i, src_ptr_slot,
    250                      src_ptr_ty, src_off + i, uchar_ty);
    251     }
    252     return;
    253   }
    254   emit_copy_leaf(p, dst_slot, dst_arr_ty, dst_off, src_ptr_slot, src_ptr_ty,
    255                  src_off, ty);
    256 }
    257 
    258 /* Source struct/union value is on top of the cg stack as an lvalue.
    259  * Spill its address into a fresh pointer slot, then walk the type and
    260  * copy each scalar leaf into the destination sub-object. */
    261 void emit_struct_copy_into_slot(Parser* p, FrameSlot dst_slot,
    262                                 const Type* dst_arr_ty, u32 dst_off,
    263                                 const Type* ty) {
    264   const Type* ptr_ty = type_ptr(p->pool, ty);
    265   FrameSlotDesc fsd;
    266   FrameSlot src_ptr_slot;
    267   c_cg_addr(p);
    268   memset(&fsd, 0, sizeof fsd);
    269   fsd.type = ptr_ty;
    270   fsd.size = c_abi_sizeof(p->abi, p->pool, ptr_ty);
    271   fsd.align = c_abi_alignof(p->abi, p->pool, ptr_ty);
    272   fsd.kind = FS_LOCAL;
    273   fsd.flags = FSF_NONE;
    274   src_ptr_slot = c_cg_local(p, &fsd);
    275   c_cg_push_local_typed(p, src_ptr_slot, ptr_ty);
    276   c_cg_swap(p);
    277   c_cg_store_void(p);
    278   emit_walk_copy(p, dst_slot, dst_arr_ty, dst_off, src_ptr_slot, ptr_ty, 0, ty);
    279 }
    280 
    281 /* Recursively zero-initialize the sub-object at `offset` of type `ty`. */
    282 void zero_init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset,
    283                   const Type* ty) {
    284   if (ty->kind == TY_ARRAY) {
    285     u32 esz = c_abi_sizeof(p->abi, p->pool, ty->arr.elem);
    286     for (u32 i = 0; i < ty->arr.count; ++i) {
    287       zero_init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem);
    288     }
    289     return;
    290   }
    291   if (ty->kind == TY_STRUCT) {
    292     const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
    293     for (u16 i = 0; i < ty->rec.nfields; ++i) {
    294       const Field* f = &ty->rec.fields[i];
    295       if (f->flags & FIELD_ZERO_WIDTH) continue;
    296       if (f->flags & FIELD_BITFIELD) {
    297         push_record_field_lv(p, slot, arr_ty, offset, ty, i);
    298         c_cg_push_int(p, 0, f->type);
    299         c_cg_store_void(p);
    300         continue;
    301       }
    302       {
    303         const Type* fty = init_field_type_at(ty, i);
    304         u32 foff = init_field_offset_at(L, i);
    305         zero_init_at(p, slot, arr_ty, offset + foff, fty);
    306       }
    307     }
    308     return;
    309   }
    310   if (ty->kind == TY_UNION) {
    311     if (ty->rec.nfields > 0) {
    312       const Field* f = &ty->rec.fields[0];
    313       if (!(f->flags & FIELD_BITFIELD)) {
    314         zero_init_at(p, slot, arr_ty, offset, f->type);
    315       }
    316     }
    317     return;
    318   }
    319   push_subobject_lv(p, slot, arr_ty, offset, ty);
    320   c_cg_push_int(p, 0, ty);
    321   c_cg_store_void(p);
    322 }
    323 
    324 static void init_field_at(Parser* p, FrameSlot slot, const Type* arr_ty,
    325                           u32 rec_offset, const Type* rec_ty, u32 field_index) {
    326   const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, rec_ty);
    327   const Field* f = &rec_ty->rec.fields[field_index];
    328   if (f->flags & FIELD_ZERO_WIDTH) return;
    329   if (f->flags & FIELD_BITFIELD) {
    330     push_record_field_lv(p, slot, arr_ty, rec_offset, rec_ty, field_index);
    331     parse_assign_expr(p);
    332     to_rvalue(p);
    333     {
    334       const Type* rhs = c_cg_top_type(p);
    335       CSemCheck chk = c_sem_check_assignment(p->pool, f->type, rhs);
    336       if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
    337     }
    338     coerce_top_to_lvalue(p);
    339     c_cg_store_void(p);
    340     return;
    341   }
    342   init_at(p, slot, arr_ty, rec_offset + L->fields[field_index].offset, f->type);
    343 }
    344 
    345 /* Emit byte stores for a string literal initializing a char-array sub-object.
    346  */
    347 static void init_string_at(Parser* p, FrameSlot slot, const Type* arr_ty,
    348                            u32 offset, const Type* elem_ty, u32 count) {
    349   size_t n = 0;
    350   u8* bytes = peek_string_bytes(p, &n);
    351   u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem_ty);
    352   size_t elems = elem_size ? n / elem_size : 0;
    353   size_t copy = elems;
    354   size_t i;
    355   if (copy > count) copy = count;
    356   for (i = 0; i < copy; ++i) {
    357     push_subobject_lv(p, slot, arr_ty, offset + (u32)i * elem_size, elem_ty);
    358     c_cg_push_int(p, (i64)decode_lit_unit_le(bytes + i * elem_size, elem_size),
    359                   elem_ty);
    360     c_cg_store_void(p);
    361   }
    362   for (; i < count; ++i) {
    363     push_subobject_lv(p, slot, arr_ty, offset + (u32)i * elem_size, elem_ty);
    364     c_cg_push_int(p, 0, elem_ty);
    365     c_cg_store_void(p);
    366   }
    367   kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
    368                                          bytes, 0);
    369   advance(p); /* consume TOK_STR */
    370 }
    371 
    372 /* Parse a designator chain (`[const]` and `.ident` repeats) ending at `=`. */
    373 static void parse_designator_chain(Parser* p, const Type* outer_ty,
    374                                    u32 outer_offset, const Type** sub_ty_out,
    375                                    u32* sub_offset_out, u32* top_index_out,
    376                                    InitDesignatorCont* cont_out) {
    377   const Type* cur_ty = outer_ty;
    378   u32 cur_off = outer_offset;
    379   int first = 1;
    380   InitDesignatorCont cont;
    381   memset(&cont, 0, sizeof cont);
    382   for (;;) {
    383     if (is_punct(&p->cur, '[')) {
    384       i64 idx;
    385       u32 esz;
    386       SrcLoc cloc = tok_loc_init(p, &p->cur);
    387       const Type* parent_ty = cur_ty;
    388       u32 parent_off = cur_off;
    389       advance(p);
    390       idx = eval_const_int(p, cloc);
    391       expect_punct(p, ']', "']' after designator index");
    392       if (!cur_ty || cur_ty->kind != TY_ARRAY) {
    393         perr(p, "array designator on non-array");
    394       }
    395       if (idx < 0 || (u32)idx >= cur_ty->arr.count) {
    396         perr(p, "array designator index out of range");
    397       }
    398       esz = c_abi_sizeof(p->abi, p->pool, cur_ty->arr.elem);
    399       cur_off += (u32)idx * esz;
    400       cur_ty = cur_ty->arr.elem;
    401       cont.parent_ty = parent_ty;
    402       cont.parent_offset = parent_off;
    403       cont.next_index = (u32)idx + 1u;
    404       if (first) *top_index_out = (u32)idx;
    405       first = 0;
    406     } else if (is_punct(&p->cur, '.')) {
    407       Sym fname;
    408       const Type* fty;
    409       u32 foff;
    410       const Field* ff;
    411       u16 fi;
    412       u32 selected_index = 0;
    413       int have_selected_index = 0;
    414       const Type* parent_ty = cur_ty;
    415       u32 parent_off = cur_off;
    416       advance(p);
    417       if (p->cur.kind != TOK_IDENT ||
    418           ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) {
    419         perr(p, "expected field name after '.'");
    420       }
    421       fname = tok_ident(&p->cur);
    422       advance(p);
    423       if (!cur_ty || (cur_ty->kind != TY_STRUCT && cur_ty->kind != TY_UNION)) {
    424         perr(p, "field designator on non-record type");
    425       }
    426       if (!find_field(p->abi, p->pool, cur_ty, fname, &fty, &foff, &ff)) {
    427         perr(p, "no such field in designator");
    428       }
    429       cur_off += foff;
    430       for (fi = 0; fi < cur_ty->rec.nfields; ++fi) {
    431         const Field* g = &cur_ty->rec.fields[fi];
    432         if (g->name == fname && fname != 0) {
    433           selected_index = fi;
    434           have_selected_index = 1;
    435           if (first) {
    436             *top_index_out = fi;
    437           }
    438           break;
    439         }
    440         if ((g->flags & FIELD_ANON) &&
    441             (g->type->kind == TY_STRUCT || g->type->kind == TY_UNION)) {
    442           const Type* tmp_ty;
    443           u32 tmp_off;
    444           const Field* tmp_f;
    445           if (find_field(p->abi, p->pool, g->type, fname, &tmp_ty, &tmp_off,
    446                          &tmp_f)) {
    447             selected_index = fi;
    448             have_selected_index = 1;
    449             if (first) {
    450               *top_index_out = fi;
    451             }
    452             break;
    453           }
    454         }
    455       }
    456       if (have_selected_index) {
    457         cont.parent_ty = parent_ty;
    458         cont.parent_offset = parent_off;
    459         cont.next_index = selected_index + 1u;
    460       }
    461       cur_ty = fty;
    462       first = 0;
    463     } else {
    464       break;
    465     }
    466   }
    467   if (first) perr(p, "internal: empty designator chain");
    468   expect_punct(p, '=', "'=' after designator");
    469   *sub_ty_out = cur_ty;
    470   *sub_offset_out = cur_off;
    471   if (cont_out) *cont_out = cont;
    472 }
    473 
    474 static int aggregate_has_index(const Type* ty, u32 index) {
    475   if (!ty) return 0;
    476   if (ty->kind == TY_ARRAY) return index < ty->arr.count;
    477   if (ty->kind == TY_STRUCT) return index < ty->rec.nfields;
    478   return 0;
    479 }
    480 
    481 static int designator_continues_inside(Parser* p, const Type* outer_ty,
    482                                        u32 outer_offset, const Type* top_ty,
    483                                        u32 top_offset,
    484                                        const InitDesignatorCont* cont) {
    485   u32 top_size;
    486   if (!cont || !cont->parent_ty) return 0;
    487   if (cont->parent_ty == outer_ty && cont->parent_offset == outer_offset)
    488     return 0;
    489   if (!aggregate_has_index(cont->parent_ty, cont->next_index)) return 0;
    490   top_size = c_abi_sizeof(p->abi, p->pool, top_ty);
    491   return cont->parent_offset >= top_offset &&
    492          cont->parent_offset - top_offset <= top_size;
    493 }
    494 
    495 static u32 init_struct_fields(Parser* p, FrameSlot slot, const Type* arr_ty,
    496                               u32 offset, const Type* ty, u32 start_field,
    497                               int braced) {
    498   const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
    499   u32 i = start_field;
    500   u32 zero_lo = start_field;
    501   /* A braced list may carry designators that re-target any field, including a
    502    * field earlier than one already seen, so the running position `i` does not
    503    * bound the loop — only '}'/EOF (or, for an unbraced nested list, the field
    504    * count) terminates it. */
    505   for (;;) {
    506     if (braced) {
    507       if (is_punct(&p->cur, '}') || p->cur.kind == TOK_EOF) break;
    508     } else if (i >= ty->rec.nfields) {
    509       break;
    510     }
    511     if (braced && is_punct(&p->cur, '.')) {
    512       const Type* sub_ty;
    513       u32 sub_off;
    514       u32 top_idx = 0;
    515       InitDesignatorCont cont;
    516       parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx, &cont);
    517       while (zero_lo < top_idx) {
    518         const Field* zf = &ty->rec.fields[zero_lo];
    519         if (zf->flags & FIELD_BITFIELD) {
    520           if (!(zf->flags & FIELD_ZERO_WIDTH)) {
    521             push_record_field_lv(p, slot, arr_ty, offset, ty, zero_lo);
    522             c_cg_push_int(p, 0, zf->type);
    523             c_cg_store_void(p);
    524           }
    525         } else {
    526           u32 zoff = offset + L->fields[zero_lo].offset;
    527           zero_init_at(p, slot, arr_ty, zoff, zf->type);
    528         }
    529         ++zero_lo;
    530       }
    531       init_at(p, slot, arr_ty, sub_off, sub_ty);
    532       {
    533         const Field* top_f = &ty->rec.fields[top_idx];
    534         u32 top_off = offset + L->fields[top_idx].offset;
    535         if (designator_continues_inside(p, ty, offset, top_f->type, top_off,
    536                                         &cont) &&
    537             accept_punct(p, ',') && !is_punct(&p->cur, '}')) {
    538           init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset,
    539                                    cont.parent_ty, cont.next_index);
    540         }
    541       }
    542       i = top_idx;
    543       if (zero_lo <= top_idx) zero_lo = top_idx + 1;
    544       goto next_item_struct;
    545     }
    546     if (i >= ty->rec.nfields) {
    547       /* Excess positional initializer with no designator to place it; stop and
    548        * let the caller diagnose the missing '}'. */
    549       break;
    550     }
    551     init_field_at(p, slot, arr_ty, offset, ty, i);
    552     if (zero_lo <= i) zero_lo = i + 1;
    553     if (!braced) {
    554       ++i;
    555       break;
    556     }
    557   next_item_struct:
    558     if (!accept_punct(p, ',')) {
    559       ++i;
    560       break;
    561     }
    562     if (is_punct(&p->cur, '}')) {
    563       ++i;
    564       break;
    565     }
    566     ++i;
    567   }
    568   if (braced) {
    569     u32 j;
    570     for (j = zero_lo; j < ty->rec.nfields; ++j) {
    571       const Field* f = &ty->rec.fields[j];
    572       if (f->flags & FIELD_BITFIELD) {
    573         if (!(f->flags & FIELD_ZERO_WIDTH)) {
    574           push_record_field_lv(p, slot, arr_ty, offset, ty, j);
    575           c_cg_push_int(p, 0, f->type);
    576           c_cg_store_void(p);
    577         }
    578       } else {
    579         u32 foff = offset + L->fields[j].offset;
    580         zero_init_at(p, slot, arr_ty, foff, f->type);
    581       }
    582     }
    583   }
    584   return i;
    585 }
    586 
    587 static void init_aggregate_remainder(Parser* p, FrameSlot slot,
    588                                      const Type* arr_ty, u32 offset,
    589                                      const Type* ty, u32 start_index) {
    590   if (ty->kind == TY_ARRAY) {
    591     u32 esz = c_abi_sizeof(p->abi, p->pool, ty->arr.elem);
    592     u32 i;
    593     for (i = start_index; i < ty->arr.count; ++i) {
    594       init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem);
    595       if (i + 1u >= ty->arr.count) return;
    596       if (!accept_punct(p, ',')) break;
    597       if (is_punct(&p->cur, '}')) break;
    598     }
    599     for (++i; i < ty->arr.count; ++i) {
    600       zero_init_at(p, slot, arr_ty, offset + i * esz, ty->arr.elem);
    601     }
    602     return;
    603   }
    604   if (ty->kind == TY_STRUCT) {
    605     const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
    606     u32 i;
    607     for (i = start_index; i < ty->rec.nfields; ++i) {
    608       init_field_at(p, slot, arr_ty, offset, ty, i);
    609       if (i + 1u >= ty->rec.nfields) return;
    610       if (!accept_punct(p, ',')) break;
    611       if (is_punct(&p->cur, '}')) break;
    612     }
    613     for (++i; i < ty->rec.nfields; ++i) {
    614       const Field* f = &ty->rec.fields[i];
    615       if (f->flags & FIELD_BITFIELD) {
    616         if (!(f->flags & FIELD_ZERO_WIDTH)) {
    617           push_record_field_lv(p, slot, arr_ty, offset, ty, i);
    618           c_cg_push_int(p, 0, f->type);
    619           c_cg_store_void(p);
    620         }
    621       } else {
    622         const Type* fty = init_field_type_at(ty, i);
    623         u32 foff = init_field_offset_at(L, i);
    624         zero_init_at(p, slot, arr_ty, offset + foff, fty);
    625       }
    626     }
    627     return;
    628   }
    629   init_at(p, slot, arr_ty, offset, ty);
    630 }
    631 
    632 void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset,
    633              const Type* ty) {
    634   if (ty->kind == TY_ARRAY) {
    635     const Type* elem_ty = ty->arr.elem;
    636     u32 esz = c_abi_sizeof(p->abi, p->pool, elem_ty);
    637     if (p->cur.kind == TOK_STR &&
    638         string_literal_initializes_array(p, elem_ty, &p->cur)) {
    639       init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count);
    640       return;
    641     }
    642     if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) {
    643       Tok str = peek1(p);
    644       if (string_literal_initializes_array(p, elem_ty, &str)) {
    645         advance(p);
    646         init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count);
    647         accept_punct(p, ',');
    648         expect_punct(p, '}', "'}' after string initializer");
    649         return;
    650       }
    651     }
    652     if (!is_punct(&p->cur, '{')) {
    653       init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0);
    654       return;
    655     }
    656     advance(p); /* '{' */
    657     {
    658       u32 i = 0;
    659       u32 zero_lo = 0;
    660       if (!is_punct(&p->cur, '}')) {
    661         for (;;) {
    662           if (is_punct(&p->cur, '[')) {
    663             const Type* sub_ty;
    664             u32 sub_off;
    665             u32 top_idx = 0;
    666             InitDesignatorCont cont;
    667             parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx,
    668                                    &cont);
    669             while (zero_lo < top_idx) {
    670               zero_init_at(p, slot, arr_ty, offset + zero_lo * esz, elem_ty);
    671               ++zero_lo;
    672             }
    673             init_at(p, slot, arr_ty, sub_off, sub_ty);
    674             if (designator_continues_inside(p, ty, offset, elem_ty,
    675                                             offset + top_idx * esz, &cont) &&
    676                 accept_punct(p, ',') && !is_punct(&p->cur, '}')) {
    677               init_aggregate_remainder(p, slot, arr_ty, cont.parent_offset,
    678                                        cont.parent_ty, cont.next_index);
    679             }
    680             i = top_idx + 1;
    681             if (zero_lo < i) zero_lo = i;
    682           } else {
    683             if (i >= ty->arr.count) {
    684               perr(p, "too many initializers for array");
    685             }
    686             init_at(p, slot, arr_ty, offset + i * esz, elem_ty);
    687             ++i;
    688             if (zero_lo < i) zero_lo = i;
    689           }
    690           if (!accept_punct(p, ',')) break;
    691           if (is_punct(&p->cur, '}')) break;
    692         }
    693       }
    694       expect_punct(p, '}', "'}' after array initializer");
    695       {
    696         u32 j;
    697         for (j = zero_lo; j < ty->arr.count; ++j) {
    698           zero_init_at(p, slot, arr_ty, offset + j * esz, elem_ty);
    699         }
    700       }
    701     }
    702     return;
    703   }
    704   if (ty->kind == TY_STRUCT) {
    705     if (!is_punct(&p->cur, '{')) {
    706       if (try_init_aggregate_from_expr(p, slot, arr_ty, offset, ty)) return;
    707       init_aggregate_remainder(p, slot, arr_ty, offset, ty, 0);
    708       return;
    709     }
    710     advance(p); /* '{' */
    711     zero_object_bytes_at(p, slot, arr_ty, offset, ty);
    712     init_struct_fields(p, slot, arr_ty, offset, ty, 0, /*braced=*/1);
    713     expect_punct(p, '}', "'}' after struct initializer");
    714     return;
    715   }
    716   if (ty->kind == TY_UNION) {
    717     int had_brace = accept_punct(p, '{');
    718     if (!had_brace &&
    719         try_init_aggregate_from_expr(p, slot, arr_ty, offset, ty)) {
    720       return;
    721     }
    722     if (ty->rec.nfields == 0) {
    723       if (had_brace) expect_punct(p, '}', "'}'");
    724       return;
    725     }
    726     if (had_brace && is_punct(&p->cur, '.')) {
    727       const Type* sub_ty;
    728       u32 sub_off;
    729       u32 top_idx = 0;
    730       parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx, NULL);
    731       init_at(p, slot, arr_ty, sub_off, sub_ty);
    732     } else {
    733       const Field* f = &ty->rec.fields[0];
    734       if (!(f->flags & FIELD_BITFIELD)) {
    735         init_at(p, slot, arr_ty, offset, f->type);
    736       }
    737     }
    738     if (had_brace) {
    739       accept_punct(p, ',');
    740       expect_punct(p, '}', "'}' after union initializer");
    741     }
    742     return;
    743   }
    744   /* Scalar (incl. pointer). */
    745   int had_brace = accept_punct(p, '{');
    746   push_subobject_lv(p, slot, arr_ty, offset, ty);
    747   parse_assign_expr(p);
    748   to_rvalue(p);
    749   {
    750     const Type* rhs = c_cg_top_type(p);
    751     CSemCheck chk = c_sem_check_assignment(p->pool, ty, rhs);
    752     if (!chk.ok) perr(p, "%.*s", KIT_SLICE_ARG(kit_slice_cstr(chk.message)));
    753   }
    754   coerce_top_to_lvalue(p);
    755   c_cg_store_void(p);
    756   if (had_brace) {
    757     accept_punct(p, ',');
    758     expect_punct(p, '}', "'}' after scalar initializer");
    759   }
    760 }
    761 
    762 /* ============================================================
    763  * Static-storage initializers
    764  * ============================================================ */
    765 
    766 void encode_int_le(u8* dst, u32 size, i64 v) {
    767   for (u32 i = 0; i < size; ++i) {
    768     dst[i] = (u8)((v >> (8u * i)) & 0xffu);
    769   }
    770 }
    771 
    772 static u64 decode_uint_le(const u8* src, u32 size) {
    773   u64 v = 0;
    774   if (size > 8) size = 8;
    775   for (u32 i = 0; i < size; ++i) {
    776     v |= (u64)src[i] << (8u * i);
    777   }
    778   return v;
    779 }
    780 
    781 static void encode_uint_le(u8* dst, u32 size, u64 v) {
    782   if (size > 8) size = 8;
    783   for (u32 i = 0; i < size; ++i) {
    784     dst[i] = (u8)((v >> (8u * i)) & 0xffu);
    785   }
    786 }
    787 
    788 static void encode_uint128_le(u8* dst, u32 size, u64 lo, u64 hi) {
    789   if (size > 16) size = 16;
    790   for (u32 i = 0; i < size; ++i) {
    791     u64 lane = i < 8u ? lo : hi;
    792     dst[i] = (u8)((lane >> (8u * (i & 7u))) & 0xffu);
    793   }
    794 }
    795 
    796 static void encode_binary128_from_double_le(u8 out[16], double value) {
    797   union {
    798     double d;
    799     u64 u;
    800   } in;
    801   u64 lo = 0;
    802   u64 hi = 0;
    803   u64 frac;
    804   u32 sign;
    805   u32 exp;
    806   in.d = value;
    807   sign = (u32)(in.u >> 63);
    808   exp = (u32)((in.u >> 52) & 0x7ffu);
    809   frac = in.u & 0x000fffffffffffffull;
    810   if (sign) hi |= 1ull << 63;
    811   if (exp == 0x7ffu) {
    812     hi |= (u64)0x7fffu << 48;
    813     if (frac) {
    814       lo |= (frac & 0xfu) << 60;
    815       hi |= frac >> 4;
    816       hi |= 1ull << 47;
    817     }
    818   } else if (exp != 0 || frac != 0) {
    819     i32 e;
    820     u64 sig;
    821     if (exp == 0) {
    822       e = -1022;
    823       sig = frac;
    824       while ((sig & (1ull << 52)) == 0) {
    825         sig <<= 1;
    826         --e;
    827       }
    828       frac = sig & 0x000fffffffffffffull;
    829     } else {
    830       e = (i32)exp - 1023;
    831     }
    832     hi |= (u64)(u32)(e + 16383) << 48;
    833     lo |= (frac & 0xfu) << 60;
    834     hi |= frac >> 4;
    835   }
    836   encode_uint128_le(out, 16, lo, hi);
    837 }
    838 
    839 static double parse_static_float_add(Parser* p);
    840 
    841 static double parse_static_float_primary(Parser* p) {
    842   double v;
    843   if (accept_punct(p, '+')) return parse_static_float_primary(p);
    844   if (accept_punct(p, '-')) return -parse_static_float_primary(p);
    845   if (accept_punct(p, '(')) {
    846     v = parse_static_float_add(p);
    847     expect_punct(p, ')', "')' in floating constant expression");
    848     return v;
    849   }
    850   if (p->cur.kind == TOK_FLT) {
    851     v = parse_float_literal(p, &p->cur);
    852     advance(p);
    853     return v;
    854   }
    855   if (p->cur.kind == TOK_NUM) {
    856     v = (double)parse_int_literal(p, &p->cur);
    857     advance(p);
    858     return v;
    859   }
    860   perr(p, "expected floating constant expression");
    861   return 0.0;
    862 }
    863 
    864 static double parse_static_float_mul(Parser* p) {
    865   double v = parse_static_float_primary(p);
    866   for (;;) {
    867     if (accept_punct(p, '*')) {
    868       v *= parse_static_float_primary(p);
    869     } else if (accept_punct(p, '/')) {
    870       v /= parse_static_float_primary(p);
    871     } else {
    872       return v;
    873     }
    874   }
    875 }
    876 
    877 static double parse_static_float_add(Parser* p) {
    878   double v = parse_static_float_mul(p);
    879   for (;;) {
    880     if (accept_punct(p, '+')) {
    881       v += parse_static_float_mul(p);
    882     } else if (accept_punct(p, '-')) {
    883       v -= parse_static_float_mul(p);
    884     } else {
    885       return v;
    886     }
    887   }
    888 }
    889 
    890 static int try_parse_static_float(Parser* p, u8* dst, u32 size,
    891                                   const Type* ty) {
    892   const Type* uty = type_unqual(p->pool, ty);
    893   double value;
    894   if (!uty || (uty->kind != TY_FLOAT && uty->kind != TY_DOUBLE &&
    895                uty->kind != TY_LDOUBLE)) {
    896     return 0;
    897   }
    898   value = parse_static_float_add(p);
    899   if (uty->kind == TY_FLOAT && size == 4u) {
    900     union {
    901       float f;
    902       u8 b[4];
    903     } u;
    904     u.f = (float)value;
    905     memcpy(dst, u.b, 4);
    906     return 1;
    907   }
    908   if ((uty->kind == TY_DOUBLE || uty->kind == TY_LDOUBLE) && size == 8u) {
    909     union {
    910       double d;
    911       u8 b[8];
    912     } u;
    913     u.d = value;
    914     memcpy(dst, u.b, 8);
    915     return 1;
    916   }
    917   if (uty->kind == TY_LDOUBLE && size == 16u) {
    918     encode_binary128_from_double_le(dst, value);
    919     return 1;
    920   }
    921   perr(p, "unsupported static floating initializer type");
    922   return 0;
    923 }
    924 
    925 /* Encode a string literal at *buf+offset for a char-array sub-object. */
    926 static void parse_static_string_at(Parser* p, u8* buf, u32 buflen, u32 offset,
    927                                    const Type* elem_ty, u32 count) {
    928   size_t n = 0;
    929   u8* bytes = peek_string_bytes(p, &n);
    930   u32 elem_size = c_abi_sizeof(p->abi, p->pool, elem_ty);
    931   size_t elems = elem_size ? n / elem_size : 0;
    932   size_t copy = elems;
    933   size_t copy_bytes;
    934   if (copy > count) copy = count;
    935   copy_bytes = copy * elem_size;
    936   if (offset + (u32)copy_bytes > buflen)
    937     perr(p, "string initializer overflows object");
    938   memcpy(buf + offset, bytes, copy_bytes);
    939   kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
    940                                          bytes, 0);
    941   advance(p);
    942 }
    943 
    944 /* Append one pending relocation to the parser-side list. */
    945 void srl_push(Parser* p, u32 offset, u32 size, ObjSymId target, i64 addend) {
    946   if (p->static_relocs_len == p->static_relocs_cap) {
    947     u32 nc = p->static_relocs_cap ? p->static_relocs_cap * 2u : 4u;
    948     void* nb = arena_array(p->pool->arena, StaticReloc, nc);
    949     if (!nb) perr(p, "out of memory recording static relocs");
    950     if (p->static_relocs && p->static_relocs_len) {
    951       memcpy(nb, p->static_relocs,
    952              p->static_relocs_len * sizeof(*p->static_relocs));
    953     }
    954     p->static_relocs = nb;
    955     p->static_relocs_cap = nc;
    956   }
    957   p->static_relocs[p->static_relocs_len].offset = offset;
    958   p->static_relocs[p->static_relocs_len].size = size;
    959   p->static_relocs[p->static_relocs_len].target = target;
    960   p->static_relocs[p->static_relocs_len].addend = addend;
    961   p->static_relocs[p->static_relocs_len].label = 0;
    962   p->static_relocs[p->static_relocs_len].is_label = 0;
    963   ++p->static_relocs_len;
    964 }
    965 
    966 /* Append one pending label-address relocation (&&label) to the list. */
    967 void srl_push_label(Parser* p, u32 offset, u32 size, CGLabel label,
    968                     i64 addend) {
    969   srl_push(p, offset, size, 0, addend);
    970   p->static_relocs[p->static_relocs_len - 1u].label = label;
    971   p->static_relocs[p->static_relocs_len - 1u].is_label = 1;
    972 }
    973 
    974 typedef enum CStaticConstKind {
    975   C_STATIC_CONST_INT,
    976   C_STATIC_CONST_NULL_PTR,
    977   C_STATIC_CONST_ADDR,
    978   C_STATIC_CONST_LABEL_ADDR, /* &&label in a static pointer initializer */
    979 } CStaticConstKind;
    980 
    981 typedef struct CStaticConst {
    982   CStaticConstKind kind;
    983   CConstInt int_value;
    984   ObjSymId target;
    985   i64 addend;
    986   CGLabel label; /* valid when kind == C_STATIC_CONST_LABEL_ADDR */
    987 } CStaticConst;
    988 
    989 typedef struct StaticRelocSave {
    990   void* relocs;
    991   u32 len;
    992   u32 cap;
    993 } StaticRelocSave;
    994 
    995 static Sym mint_compound_literal_sym(Parser* p) {
    996   static const char prefix[] = "__kit_compound_literal.";
    997   char buf[sizeof(prefix) + 12u];
    998   u32 wlen = 0;
    999   u32 id = ++p->compound_literal_counter;
   1000   for (u32 i = 0; prefix[i] != 0; ++i) {
   1001     buf[wlen++] = prefix[i];
   1002   }
   1003   {
   1004     char digits[12];
   1005     int dn = 0;
   1006     if (id == 0) digits[dn++] = '0';
   1007     while (id) {
   1008       digits[dn++] = (char)('0' + (id % 10u));
   1009       id /= 10u;
   1010     }
   1011     while (dn) buf[wlen++] = digits[--dn];
   1012   }
   1013   return kit_sym_intern(p->pool->c, (KitSlice){.s = buf, .len = wlen});
   1014 }
   1015 
   1016 static void static_relocs_swap_empty(Parser* p, StaticRelocSave* save) {
   1017   save->relocs = p->static_relocs;
   1018   save->len = p->static_relocs_len;
   1019   save->cap = p->static_relocs_cap;
   1020   p->static_relocs = NULL;
   1021   p->static_relocs_len = 0;
   1022   p->static_relocs_cap = 0;
   1023 }
   1024 
   1025 static void static_relocs_restore(Parser* p, const StaticRelocSave* save) {
   1026   p->static_relocs = save->relocs;
   1027   p->static_relocs_len = save->len;
   1028   p->static_relocs_cap = save->cap;
   1029 }
   1030 
   1031 static ObjSymId define_static_compound_literal(Parser* p, const Type* lit_ty,
   1032                                                SrcLoc loc) {
   1033   Decl decl_in;
   1034   DeclId did;
   1035   ObjSymId sym;
   1036   StaticRelocSave relocs;
   1037 
   1038   if (p->cur_func_name != 0) {
   1039     perr(p, "block-scope compound literal is not a static address constant");
   1040   }
   1041   if (lit_ty && lit_ty->kind == TY_ARRAY && lit_ty->arr.incomplete) {
   1042     lit_ty = complete_incomplete_array(p, lit_ty);
   1043   }
   1044 
   1045   memset(&decl_in, 0, sizeof decl_in);
   1046   decl_in.name = mint_compound_literal_sym(p);
   1047   decl_in.type = lit_ty;
   1048   decl_in.loc = loc;
   1049   decl_in.storage = DS_STATIC;
   1050   decl_in.linkage = DL_INTERNAL;
   1051   decl_in.visibility = SV_DEFAULT;
   1052   did = decl_declare(p->decls, &decl_in);
   1053   sym = decl_obj_sym(p->decls, did);
   1054 
   1055   static_relocs_swap_empty(p, &relocs);
   1056   define_static_object(p, sym, decl_in.section_id, lit_ty,
   1057                        lit_ty ? lit_ty->qual : 0, /*has_init=*/1, loc,
   1058                        decl_in.align);
   1059   static_relocs_restore(p, &relocs);
   1060   return sym;
   1061 }
   1062 
   1063 static CStaticConst parse_static_compound_literal_after_type(Parser* p,
   1064                                                              const Type* lit_ty,
   1065                                                              SrcLoc loc) {
   1066   CStaticConst r;
   1067   memset(&r, 0, sizeof r);
   1068   if (!is_punct(&p->cur, '{')) {
   1069     perr(p, "expected compound literal initializer in static initializer");
   1070   }
   1071   r.kind = C_STATIC_CONST_ADDR;
   1072   r.target = define_static_compound_literal(p, lit_ty, loc);
   1073   r.addend = 0;
   1074   return r;
   1075 }
   1076 
   1077 static CConstInt int_bits_for_type(Parser* p, CConstInt v, const Type* ty) {
   1078   u32 sz = c_abi_sizeof(p->abi, p->pool, ty);
   1079   v.type = ty;
   1080   if (sz < 8u) {
   1081     u32 bits = sz * 8u;
   1082     v.lo &= bits ? ((1ull << bits) - 1ull) : 0;
   1083     v.hi = 0;
   1084   } else if (sz == 8u) {
   1085     v.hi = 0;
   1086   } else if (sz < 16u) {
   1087     u32 hi_bits = sz * 8u - 64u;
   1088     v.hi &= hi_bits ? ((1ull << hi_bits) - 1ull) : 0;
   1089   }
   1090   if (ty && ty->kind == TY_BOOL) {
   1091     v.lo = (v.lo || v.hi) ? 1u : 0u;
   1092     v.hi = 0;
   1093   }
   1094   return v;
   1095 }
   1096 
   1097 static void check_static_integer_initializer_range(Parser* p, const Type* ty,
   1098                                                    CConstInt v) {
   1099   const Type* dst = type_unqual(p->pool, ty);
   1100   u32 bits;
   1101   if (!dst || !type_is_int(dst) || dst->kind == TY_BOOL) return;
   1102   if (dst->kind == TY_CHAR) return;
   1103   if (!type_is_signed_integer(dst)) return;
   1104   bits = c_abi_sizeof(p->abi, p->pool, dst) * 8u;
   1105   if (bits < 64u) {
   1106     i64 minv = -(1ll << (bits - 1u));
   1107     i64 maxv = (1ll << (bits - 1u)) - 1ll;
   1108     if (type_is_signed_integer(v.type)) {
   1109       i64 sv = const_int_as_i64(p, v);
   1110       if (sv < minv || sv > maxv) {
   1111         perr(p, "initializer value overflows destination type");
   1112       }
   1113     } else {
   1114       u64 maxu = (u64)maxv;
   1115       if (v.hi != 0 || v.lo > maxu) {
   1116         perr(p, "initializer value overflows destination type");
   1117       }
   1118     }
   1119   }
   1120 }
   1121 
   1122 static CConstInt parse_null_pointer_constant(Parser* p, SrcLoc loc) {
   1123   if (is_punct(&p->cur, '(')) {
   1124     Tok n = peek1(p);
   1125     if (starts_type_name(p, &n)) {
   1126       const Type* cast_ty;
   1127       const Type* cast_unqual;
   1128       advance(p);
   1129       cast_ty = parse_type_name(p);
   1130       cast_unqual = type_unqual(p->pool, cast_ty);
   1131       expect_punct(p, ')', "')' after cast in null pointer constant");
   1132       if (!cast_unqual ||
   1133           (cast_unqual->kind != TY_PTR && cast_unqual->kind != TY_VOID &&
   1134            !type_is_int(cast_unqual))) {
   1135         perr(p, "invalid cast in null pointer constant");
   1136       }
   1137       return parse_null_pointer_constant(p, loc);
   1138     }
   1139     if (is_punct(&n, '(')) {
   1140       advance(p);
   1141       {
   1142         CConstInt v = parse_null_pointer_constant(p, loc);
   1143         expect_punct(p, ')', "')' in null pointer constant");
   1144         return v;
   1145       }
   1146     }
   1147   }
   1148   return eval_const_int_typed(p, loc);
   1149 }
   1150 
   1151 /* Try to parse the current expression as a static initializer address
   1152  * constant. Leaves non-address expressions untouched. */
   1153 static int try_parse_static_address_const(Parser* p, CStaticConst* out) {
   1154   Tok t = p->cur;
   1155   Sym name = 0;
   1156   int saw_amp = 0;
   1157   i64 element_addend = 0;
   1158   i64 byte_addend = 0;
   1159   SymEntry* e;
   1160   const Type* tgt_ty;
   1161   ObjSymId tgt;
   1162   if (t.kind == TOK_STR) {
   1163     size_t n = 0;
   1164     u8* bytes = decode_string_literal(p, &t, &n);
   1165     const Type* elem_ty = string_literal_elem_type(p, &t);
   1166     ObjSymId str_sym = emit_string_literal_to_rodata(p, bytes, n, elem_ty);
   1167     kit_compiler_context(p->c)->heap->free(kit_compiler_context(p->c)->heap,
   1168                                            bytes, 0);
   1169     advance(p);
   1170     out->kind = C_STATIC_CONST_ADDR;
   1171     out->target = str_sym;
   1172     out->addend = 0;
   1173     return 1;
   1174   }
   1175   if (is_punct(&t, '&')) {
   1176     saw_amp = 1;
   1177     advance(p);
   1178     if (is_punct(&p->cur, '(')) {
   1179       Tok n = peek1(p);
   1180       if (starts_type_name(p, &n)) {
   1181         const Type* lit_ty;
   1182         advance(p);
   1183         lit_ty = parse_type_name(p);
   1184         expect_punct(p, ')', "')' after compound literal type-name");
   1185         *out = parse_static_compound_literal_after_type(
   1186             p, lit_ty, pp_materialize_loc(p->pp, t.loc));
   1187         return 1;
   1188       }
   1189     }
   1190     if (p->cur.kind != TOK_IDENT ||
   1191         ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) {
   1192       perr(p, "expected identifier after '&' in static initializer");
   1193     }
   1194     name = tok_ident(&p->cur);
   1195     advance(p);
   1196   } else if (t.kind == TOK_IDENT &&
   1197              ident_kw_inline(p, tok_ident(&t)) == KW_NONE) {
   1198     name = tok_ident(&t);
   1199     advance(p);
   1200   } else {
   1201     return 0;
   1202   }
   1203   e = scope_lookup(p, name);
   1204   if (!e || (e->kind != SEK_GLOBAL && e->kind != SEK_FUNC)) {
   1205     perr(p, "static initializer is not a constant address expression");
   1206   }
   1207   tgt = e->v.sym;
   1208   tgt_ty = e->type;
   1209   if (saw_amp && is_punct(&p->cur, '[')) {
   1210     SrcLoc cloc;
   1211     advance(p);
   1212     cloc = tok_loc_init(p, &p->cur);
   1213     element_addend = eval_const_int(p, cloc);
   1214     expect_punct(p, ']', "']' after array-subscript constant");
   1215     if (tgt_ty && tgt_ty->kind == TY_ARRAY) {
   1216       byte_addend +=
   1217           element_addend * (i64)c_abi_sizeof(p->abi, p->pool, tgt_ty->arr.elem);
   1218     } else {
   1219       byte_addend += element_addend;
   1220     }
   1221   }
   1222   while (is_punct(&p->cur, '+') || is_punct(&p->cur, '-')) {
   1223     int neg = is_punct(&p->cur, '-');
   1224     SrcLoc cloc;
   1225     i64 v;
   1226     advance(p);
   1227     cloc = tok_loc_init(p, &p->cur);
   1228     v = eval_const_int(p, cloc);
   1229     if (neg) v = -v;
   1230     if (tgt_ty && tgt_ty->kind == TY_ARRAY) {
   1231       byte_addend += v * (i64)c_abi_sizeof(p->abi, p->pool, tgt_ty->arr.elem);
   1232     } else if (tgt_ty && tgt_ty->kind == TY_PTR) {
   1233       byte_addend +=
   1234           v * (i64)c_abi_sizeof(p->abi, p->pool, tgt_ty->ptr.pointee);
   1235     } else if (saw_amp) {
   1236       byte_addend += v * (i64)c_abi_sizeof(p->abi, p->pool, tgt_ty);
   1237     } else {
   1238       byte_addend += v;
   1239     }
   1240   }
   1241   out->kind = C_STATIC_CONST_ADDR;
   1242   out->target = tgt;
   1243   out->addend = byte_addend;
   1244   return 1;
   1245 }
   1246 
   1247 static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) {
   1248   CStaticConst r;
   1249   memset(&r, 0, sizeof r);
   1250   r.kind = C_STATIC_CONST_INT;
   1251   if (ty && ty->kind == TY_PTR) {
   1252     if (is_punct(&p->cur, P_AND)) {
   1253       /* GNU labels-as-values: `&&label` in a static pointer initializer,
   1254        * e.g. a direct-threaded dispatch table `static void *tab[] = {...}`. */
   1255       Sym lname;
   1256       SrcLoc lloc;
   1257       advance(p); /* '&&' */
   1258       if (p->cur.kind != TOK_IDENT ||
   1259           ident_kw_inline(p, tok_ident(&p->cur)) != KW_NONE) {
   1260         perr(p, "expected label name after '&&' in static initializer");
   1261       }
   1262       lname = tok_ident(&p->cur);
   1263       lloc = tok_loc_init(p, &p->cur);
   1264       advance(p);
   1265       r.kind = C_STATIC_CONST_LABEL_ADDR;
   1266       r.label = take_label_addr(p, lname, lloc);
   1267       r.addend = 0;
   1268       return r;
   1269     }
   1270     if (is_punct(&p->cur, '(')) {
   1271       Tok n = peek1(p);
   1272       /* Grouping parens around the pointer initializer, e.g. `("str")`,
   1273        * `(&x)`, or `((expr))`. A `(type-name)` is a cast or compound literal
   1274        * and is handled below, so peel only when the inner token does not start
   1275        * a type-name. */
   1276       if (!starts_type_name(p, &n)) {
   1277         advance(p);
   1278         r = parse_static_const(p, ty, loc);
   1279         expect_punct(p, ')', "')' in static pointer initializer");
   1280         return r;
   1281       }
   1282     }
   1283     if (is_punct(&p->cur, '(')) {
   1284       Tok n = peek1(p);
   1285       if (starts_type_name(p, &n)) {
   1286         const Type* cast_ty;
   1287         const Type* cast_unqual;
   1288         advance(p);
   1289         cast_ty = parse_type_name(p);
   1290         cast_unqual = type_unqual(p->pool, cast_ty);
   1291         expect_punct(p, ')', "')' after cast or compound literal type-name");
   1292         if (is_punct(&p->cur, '{')) {
   1293           const Type* lit_unqual = type_unqual(p->pool, cast_ty);
   1294           if (!lit_unqual || lit_unqual->kind != TY_ARRAY) {
   1295             perr(p,
   1296                  "non-array compound literal needs '&' in pointer initializer");
   1297           }
   1298           return parse_static_compound_literal_after_type(p, cast_ty, loc);
   1299         }
   1300         if (!cast_unqual ||
   1301             (cast_unqual->kind != TY_PTR && cast_unqual->kind != TY_VOID &&
   1302              !type_is_int(cast_unqual))) {
   1303           perr(p, "invalid cast in null pointer constant");
   1304         }
   1305         if (cast_unqual->kind == TY_PTR &&
   1306             (p->cur.kind == TOK_STR || is_punct(&p->cur, '&') ||
   1307              (p->cur.kind == TOK_IDENT &&
   1308               ident_kw_inline(p, tok_ident(&p->cur)) == KW_NONE)) &&
   1309             try_parse_static_address_const(p, &r)) {
   1310           return r;
   1311         }
   1312         r.int_value = parse_null_pointer_constant(p, loc);
   1313         if (const_int_as_i64(p, r.int_value) != 0 &&
   1314             cast_unqual->kind == TY_PTR) {
   1315           r.kind = C_STATIC_CONST_INT;
   1316           return r;
   1317         }
   1318         if (const_int_as_i64(p, r.int_value) != 0) {
   1319           perr(p, "static pointer initializer is not a null pointer constant");
   1320         }
   1321         r.kind = C_STATIC_CONST_NULL_PTR;
   1322         return r;
   1323       }
   1324     }
   1325     if (try_parse_static_address_const(p, &r)) return r;
   1326     r.int_value = parse_null_pointer_constant(p, loc);
   1327     if (const_int_as_i64(p, r.int_value) != 0) {
   1328       perr(p, "static pointer initializer is not a null pointer constant");
   1329     }
   1330     r.kind = C_STATIC_CONST_NULL_PTR;
   1331     return r;
   1332   }
   1333   r.int_value = eval_const_int_typed(p, loc);
   1334   check_static_integer_initializer_range(p, ty, r.int_value);
   1335   return r;
   1336 }
   1337 
   1338 static void parse_static_bitfield_at(Parser* p, u8* buf, u32 buflen,
   1339                                      u32 rec_offset, const ABIFieldLayout* fl,
   1340                                      const Type* field_ty) {
   1341   SrcLoc cloc = tok_loc_init(p, &p->cur);
   1342   CStaticConst parsed = parse_static_const(p, field_ty, cloc);
   1343   u32 storage_off = rec_offset + fl->offset;
   1344   u32 storage_size = fl->storage_size;
   1345   u32 width = fl->bit_width;
   1346   u32 lsb = fl->bit_offset;
   1347   u64 ones;
   1348   u64 mask;
   1349   u64 cur;
   1350   u64 val;
   1351   if (parsed.kind != C_STATIC_CONST_INT) {
   1352     perr(p, "bit-field initializer requires integer constant expression");
   1353   }
   1354   if (width == 0) return;
   1355   if (storage_size > 8) perr(p, "bit-field storage unit too wide");
   1356   if (storage_off > buflen || storage_size > buflen - storage_off)
   1357     perr(p, "initializer overflows object");
   1358   ones = width >= 64u ? ~(u64)0 : (((u64)1 << width) - 1u);
   1359   mask = ones << lsb;
   1360   cur = decode_uint_le(buf + storage_off, storage_size);
   1361   val = (int_bits_for_type(p, parsed.int_value, field_ty).lo & ones) << lsb;
   1362   cur = (cur & ~mask) | val;
   1363   encode_uint_le(buf + storage_off, storage_size, cur);
   1364 }
   1365 
   1366 static void parse_static_aggregate_remainder(Parser* p, u8* buf, u32 buflen,
   1367                                              u32 offset, const Type* ty,
   1368                                              u32 start_index) {
   1369   if (ty->kind == TY_ARRAY) {
   1370     const Type* elem = ty->arr.elem;
   1371     u32 esz = c_abi_sizeof(p->abi, p->pool, elem);
   1372     u32 i;
   1373     for (i = start_index; i < ty->arr.count; ++i) {
   1374       parse_static_init_at(p, buf, buflen, offset + i * esz, elem);
   1375       if (i + 1u >= ty->arr.count) return;
   1376       if (!accept_punct(p, ',')) break;
   1377       if (is_punct(&p->cur, '}')) break;
   1378     }
   1379     return;
   1380   }
   1381   if (ty->kind == TY_STRUCT) {
   1382     const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
   1383     u32 i;
   1384     for (i = start_index; i < ty->rec.nfields; ++i) {
   1385       const Field* f = &ty->rec.fields[i];
   1386       if (f->flags & FIELD_BITFIELD) {
   1387         if (!(f->flags & FIELD_ZERO_WIDTH)) {
   1388           parse_static_bitfield_at(p, buf, buflen, offset, &L->fields[i],
   1389                                    f->type);
   1390         }
   1391       } else {
   1392         const Type* fty = init_field_type_at(ty, i);
   1393         u32 foff = init_field_offset_at(L, i);
   1394         parse_static_init_at(p, buf, buflen, offset + foff, fty);
   1395       }
   1396       if (i + 1u >= ty->rec.nfields) return;
   1397       if (!accept_punct(p, ',')) break;
   1398       if (is_punct(&p->cur, '}')) break;
   1399     }
   1400     return;
   1401   }
   1402   parse_static_init_at(p, buf, buflen, offset, ty);
   1403 }
   1404 
   1405 void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset,
   1406                           const Type* ty) {
   1407   /* An aggregate object may be initialized by a (possibly parenthesized)
   1408    * compound literal of its own type: `static T x = (T){...};` or, after macro
   1409    * expansion, `static T x = ((T){...});`. Strip the `(type-name)` cast so the
   1410    * brace body below initializes the object in place; peel grouping parens by
   1411    * recursing and matching the closing ')'. Pointer/scalar targets keep their
   1412    * own handling (parse_static_const / eval_const), where a compound literal
   1413    * can instead yield an address or value. */
   1414   if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION || ty->kind == TY_ARRAY) &&
   1415       is_punct(&p->cur, '(')) {
   1416     Tok n = peek1(p);
   1417     if (starts_type_name(p, &n)) {
   1418       advance(p);
   1419       parse_type_name(p);
   1420       expect_punct(p, ')', "')' after compound literal type-name");
   1421     } else if (is_punct(&n, '(')) {
   1422       advance(p);
   1423       parse_static_init_at(p, buf, buflen, offset, ty);
   1424       expect_punct(p, ')', "')' after parenthesized initializer");
   1425       return;
   1426     }
   1427   }
   1428   if (ty->kind == TY_ARRAY) {
   1429     const Type* elem = ty->arr.elem;
   1430     u32 esz = c_abi_sizeof(p->abi, p->pool, elem);
   1431     u32 i = 0;
   1432     int had_brace;
   1433     if (p->cur.kind == TOK_STR &&
   1434         string_literal_initializes_array(p, elem, &p->cur)) {
   1435       parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count);
   1436       return;
   1437     }
   1438     if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) {
   1439       Tok str = peek1(p);
   1440       if (string_literal_initializes_array(p, elem, &str)) {
   1441         advance(p);
   1442         parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count);
   1443         accept_punct(p, ',');
   1444         expect_punct(p, '}', "'}' after string initializer");
   1445         return;
   1446       }
   1447     }
   1448     had_brace = accept_punct(p, '{');
   1449     if (!had_brace) {
   1450       parse_static_aggregate_remainder(p, buf, buflen, offset, ty, 0);
   1451       return;
   1452     }
   1453     if (!is_punct(&p->cur, '}')) {
   1454       for (;;) {
   1455         if (is_punct(&p->cur, '[')) {
   1456           const Type* sub_ty;
   1457           u32 sub_off;
   1458           u32 top_idx = 0;
   1459           InitDesignatorCont cont;
   1460           parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx,
   1461                                  &cont);
   1462           parse_static_init_at(p, buf, buflen, sub_off, sub_ty);
   1463           if (designator_continues_inside(p, ty, offset, elem,
   1464                                           offset + top_idx * esz, &cont) &&
   1465               accept_punct(p, ',') && !is_punct(&p->cur, '}')) {
   1466             parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset,
   1467                                              cont.parent_ty, cont.next_index);
   1468           }
   1469           i = top_idx + 1;
   1470         } else {
   1471           if (i >= ty->arr.count) {
   1472             perr(p, "too many initializers for array");
   1473           }
   1474           parse_static_init_at(p, buf, buflen, offset + i * esz, elem);
   1475           ++i;
   1476         }
   1477         if (!accept_punct(p, ',')) break;
   1478         if (is_punct(&p->cur, '}')) break;
   1479       }
   1480     }
   1481     expect_punct(p, '}', "'}' after array initializer");
   1482     return;
   1483   }
   1484   if (ty->kind == TY_STRUCT) {
   1485     int had_brace = accept_punct(p, '{');
   1486     const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
   1487     u32 i = 0;
   1488     if (!had_brace) {
   1489       parse_static_aggregate_remainder(p, buf, buflen, offset, ty, 0);
   1490       return;
   1491     }
   1492     /* Designators may re-target any field regardless of the running position
   1493      * `i`, so the loop is bounded by '}'/EOF; `i` only drives positional
   1494      * placement (and is range-checked before use). */
   1495     while (!is_punct(&p->cur, '}') && p->cur.kind != TOK_EOF) {
   1496       const Field* f;
   1497       if (is_punct(&p->cur, '.')) {
   1498         const Type* sub_ty;
   1499         u32 sub_off;
   1500         u32 top_idx = 0;
   1501         InitDesignatorCont cont;
   1502         parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx,
   1503                                &cont);
   1504         parse_static_init_at(p, buf, buflen, sub_off, sub_ty);
   1505         {
   1506           const Field* top_f = &ty->rec.fields[top_idx];
   1507           u32 top_off = offset + L->fields[top_idx].offset;
   1508           if (designator_continues_inside(p, ty, offset, top_f->type, top_off,
   1509                                           &cont) &&
   1510               accept_punct(p, ',') && !is_punct(&p->cur, '}')) {
   1511             parse_static_aggregate_remainder(p, buf, buflen, cont.parent_offset,
   1512                                              cont.parent_ty, cont.next_index);
   1513           }
   1514         }
   1515         i = top_idx + 1;
   1516         if (!accept_punct(p, ',')) break;
   1517         continue;
   1518       }
   1519       if (i >= ty->rec.nfields) break; /* excess positional initializer */
   1520       f = &ty->rec.fields[i];
   1521       if (f->flags & FIELD_BITFIELD) {
   1522         if (!(f->flags & FIELD_ZERO_WIDTH)) {
   1523           parse_static_bitfield_at(p, buf, buflen, offset, &L->fields[i],
   1524                                    f->type);
   1525         }
   1526       } else {
   1527         const Type* fty = init_field_type_at(ty, i);
   1528         u32 foff = init_field_offset_at(L, i);
   1529         parse_static_init_at(p, buf, buflen, offset + foff, fty);
   1530       }
   1531       ++i;
   1532       if (!accept_punct(p, ',')) break;
   1533     }
   1534     expect_punct(p, '}', "'}' after struct initializer");
   1535     return;
   1536   }
   1537   if (ty->kind == TY_UNION) {
   1538     int had_brace = accept_punct(p, '{');
   1539     if (ty->rec.nfields == 0) {
   1540       if (had_brace) expect_punct(p, '}', "'}' after union initializer");
   1541       return;
   1542     }
   1543     if (had_brace && is_punct(&p->cur, '.')) {
   1544       const Type* sub_ty;
   1545       u32 sub_off;
   1546       u32 top_idx = 0;
   1547       parse_designator_chain(p, ty, offset, &sub_ty, &sub_off, &top_idx, NULL);
   1548       (void)top_idx;
   1549       parse_static_init_at(p, buf, buflen, sub_off, sub_ty);
   1550     } else {
   1551       const Field* f = &ty->rec.fields[0];
   1552       if (!(f->flags & FIELD_BITFIELD)) {
   1553         parse_static_init_at(p, buf, buflen, offset, f->type);
   1554       } else if (!(f->flags & FIELD_ZERO_WIDTH)) {
   1555         const ABIRecordLayout* L = c_abi_record_layout(p->abi, p->pool, ty);
   1556         parse_static_bitfield_at(p, buf, buflen, offset, &L->fields[0],
   1557                                  f->type);
   1558       }
   1559     }
   1560     if (had_brace) {
   1561       accept_punct(p, ',');
   1562       expect_punct(p, '}', "'}' after union initializer");
   1563     }
   1564     return;
   1565   }
   1566   /* Scalar / pointer. */
   1567   {
   1568     int had_brace = accept_punct(p, '{');
   1569     SrcLoc cloc = tok_loc_init(p, &p->cur);
   1570     u32 sz = c_abi_sizeof(p->abi, p->pool, ty);
   1571     CStaticConst cv;
   1572     if (offset + sz > buflen) perr(p, "initializer overflows object");
   1573     if (try_parse_static_float(p, buf + offset, sz, ty)) {
   1574       if (had_brace) {
   1575         accept_punct(p, ',');
   1576         expect_punct(p, '}', "'}' after scalar initializer");
   1577       }
   1578       return;
   1579     }
   1580     cv = parse_static_const(p, ty, cloc);
   1581     if (cv.kind == C_STATIC_CONST_ADDR) {
   1582       srl_push(p, offset, sz, cv.target, cv.addend);
   1583     } else if (cv.kind == C_STATIC_CONST_LABEL_ADDR) {
   1584       srl_push_label(p, offset, sz, cv.label, cv.addend);
   1585     } else if (cv.kind == C_STATIC_CONST_NULL_PTR) {
   1586       encode_int_le(buf + offset, sz, 0);
   1587     } else {
   1588       {
   1589         CConstInt bits = int_bits_for_type(p, cv.int_value, ty);
   1590         encode_uint128_le(buf + offset, sz, bits.lo, bits.hi);
   1591       }
   1592     }
   1593     if (had_brace) {
   1594       accept_punct(p, ',');
   1595       expect_punct(p, '}', "'}' after scalar initializer");
   1596     }
   1597   }
   1598 }
   1599 
   1600 static void emit_static_data(Parser* p, const u8* buf, u32 size) {
   1601   u32 pos = 0;
   1602   u32 emitted_relocs = 0;
   1603 
   1604   while (emitted_relocs < p->static_relocs_len) {
   1605     u32 best = p->static_relocs_len;
   1606     u32 best_off = 0xffffffffu;
   1607     for (u32 i = 0; i < p->static_relocs_len; ++i) {
   1608       if (p->static_relocs[i].offset < pos) continue;
   1609       if (p->static_relocs[i].offset < best_off) {
   1610         best = i;
   1611         best_off = p->static_relocs[i].offset;
   1612       }
   1613     }
   1614     if (best == p->static_relocs_len) break;
   1615     if (best_off > size || p->static_relocs[best].size > size - best_off) {
   1616       perr(p, "static initializer relocation overflows object");
   1617     }
   1618     if (best_off > pos) {
   1619       if (buf) {
   1620         kit_cg_data_bytes(p->cg, buf + pos, best_off - pos);
   1621       } else {
   1622         kit_cg_data_zero(p->cg, best_off - pos);
   1623       }
   1624     }
   1625     if (p->static_relocs[best].is_label) {
   1626       kit_cg_data_label_addr(p->cg, p->static_relocs[best].label,
   1627                              p->static_relocs[best].addend,
   1628                              p->static_relocs[best].size, 0);
   1629     } else {
   1630       kit_cg_data_addr(p->cg, p->static_relocs[best].target,
   1631                        p->static_relocs[best].addend,
   1632                        p->static_relocs[best].size, 0);
   1633     }
   1634     pos = best_off + p->static_relocs[best].size;
   1635     ++emitted_relocs;
   1636   }
   1637 
   1638   if (pos < size) {
   1639     if (buf) {
   1640       kit_cg_data_bytes(p->cg, buf + pos, size - pos);
   1641     } else {
   1642       kit_cg_data_zero(p->cg, size - pos);
   1643     }
   1644   }
   1645 }
   1646 
   1647 /* Define a static-storage object. */
   1648 void define_static_object(Parser* p, ObjSymId sym, ObjSecId section_id,
   1649                           const Type* var_ty, u16 quals, int has_init,
   1650                           SrcLoc loc, u32 align_override) {
   1651   u32 size = c_abi_sizeof(p->abi, p->pool, var_ty);
   1652   u32 align = c_abi_alignof(p->abi, p->pool, var_ty);
   1653   KitCgDataDefAttrs attrs;
   1654   if (align_override > align) align = align_override;
   1655   u8* buf = NULL;
   1656   int has_nonzero = 0;
   1657   int has_label_reloc = 0;
   1658 
   1659   if (has_init) {
   1660     buf = (u8*)arena_array(p->pool->arena, u8, size ? size : 1u);
   1661     memset(buf, 0, size);
   1662     p->static_relocs_len = 0;
   1663     parse_static_init_at(p, buf, size, 0, var_ty);
   1664     for (u32 i = 0; i < size; ++i) {
   1665       if (buf[i]) {
   1666         has_nonzero = 1;
   1667         break;
   1668       }
   1669     }
   1670     if (p->static_relocs_len) has_nonzero = 1;
   1671     for (u32 i = 0; i < p->static_relocs_len; ++i) {
   1672       if (p->static_relocs[i].is_label) {
   1673         has_label_reloc = 1;
   1674         break;
   1675       }
   1676     }
   1677   }
   1678 
   1679   memset(&attrs, 0, sizeof attrs);
   1680   attrs.section = section_id;
   1681   attrs.align = align ? align : 1u;
   1682   /* Label-address relocations (&&label) are tied to the enclosing function's
   1683    * label namespace, so the table must be emitted as function-local static
   1684    * data while that function is still open. */
   1685   if (has_label_reloc) {
   1686     attrs.flags |= KIT_CG_DATADEF_FUNCTION_LOCAL;
   1687   }
   1688   if ((quals & Q_CONST) != 0 && has_nonzero) {
   1689     attrs.flags |= KIT_CG_DATADEF_READONLY;
   1690   }
   1691   if (!has_init || !has_nonzero) {
   1692     attrs.flags |= KIT_CG_DATADEF_ZERO_FILL;
   1693   }
   1694 
   1695   kit_cg_data_begin(p->cg, sym, attrs);
   1696   emit_static_data(p, (attrs.flags & KIT_CG_DATADEF_ZERO_FILL) ? NULL : buf,
   1697                    size);
   1698   kit_cg_data_end(p->cg);
   1699   p->static_relocs_len = 0;
   1700   (void)loc;
   1701 }