kit

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

commit 2bd5ad377b0a0ce27256ec64bfb3fecab5538c70
parent b30bada9e8811cac46685ca575d8d1acd6f69479
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue, 19 May 2026 11:52:12 -0700

Expand C11 parser coverage and literal support

Add wide and UTF literal decoding paths, matching string literal array initialization, and static compound literal handling.

Track multi-dimensional VLA runtime sizes through typedefs and subscripting, fix aa64 stack sizing for spilled wide FP args, and add targeted parse/opt tests including red UTF transcoding coverage.

Diffstat:
Mlang/c/parse/parse.c | 160++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mlang/c/parse/parse_expr.c | 197++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Mlang/c/parse/parse_init.c | 193++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mlang/c/parse/parse_priv.h | 20++++++++++++++++++++
Mlang/c/parse/parse_type.c | 22++++++++++++++++------
Msrc/arch/aa64/opt_coord.c | 2+-
Mtest/opt/opt_test.c | 23+++++++++++++++++++++++
Mtest/parse/CORPUS.md | 1-
Atest/parse/cases/6_4_5_04_wide_string_subscript.c | 6++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_04_wide_string_subscript.expected | 0
Atest/parse/cases/6_4_5_05_utf_string_widths.c | 8++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_05_utf_string_widths.expected | 0
Atest/parse/cases/6_4_5_06_wide_string_ucn_init.c | 7+++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_06_wide_string_ucn_init.expected | 0
Atest/parse/cases/6_4_5_07_wide_string_concat_mixed.c | 9+++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_07_wide_string_concat_mixed.expected | 0
Atest/parse/cases/6_4_5_08_wide_string_array_init.c | 11+++++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_08_wide_string_array_init.expected | 0
Atest/parse/cases/6_4_5_09_utf16_surrogate_pair.c | 6++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_09_utf16_surrogate_pair.expected | 0
Atest/parse/cases/6_4_5_10_utf8_ucn_encoding.c | 8++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_4_5_10_utf8_ucn_encoding.expected | 0
Atest/parse/cases/6_5_66_file_scope_compound_literal_addr.c | 5+++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_5_66_file_scope_compound_literal_addr.expected | 0
Atest/parse/cases/6_5_67_file_scope_compound_literal_nested_reloc.c | 6++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_5_67_file_scope_compound_literal_nested_reloc.expected | 0
Atest/parse/cases/6_5_68_file_scope_compound_literal_struct_addr.c | 10++++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_5_68_file_scope_compound_literal_struct_addr.expected | 0
Atest/parse/cases/6_5_69_file_scope_compound_literal_struct_array.c | 10++++++++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_5_69_file_scope_compound_literal_struct_array.expected | 0
Atest/parse/cases/6_5_70_file_scope_compound_literal_const_addr.c | 5+++++
Rtest/parse/cases/6_9_14_old_style_definition.expected -> test/parse/cases/6_5_70_file_scope_compound_literal_const_addr.expected | 0
Dtest/parse/cases/6_9_14_old_style_definition.c | 10----------
Atest/parse/cases_err/6_4_5_incompatible_string_prefix_concat.c | 3+++
Atest/parse/cases_err/6_4_5_incompatible_string_prefix_concat.errpat | 1+
Atest/parse/cases_err/6_5_block_static_compound_literal.c | 4++++
Atest/parse/cases_err/6_5_block_static_compound_literal.errpat | 1+
Atest/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.c | 5+++++
Atest/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.errpat | 1+
39 files changed, 620 insertions(+), 114 deletions(-)

diff --git a/lang/c/parse/parse.c b/lang/c/parse/parse.c @@ -435,6 +435,110 @@ FrameSlot make_local(Parser* p, Sym name, const Type* type, SrcLoc loc) { return make_local_aligned(p, name, type, loc, 0); } +static FrameSlot make_vla_size_slot(Parser* p) { + FrameSlotDesc fsd; + memset(&fsd, 0, sizeof fsd); + fsd.type = ty_size_t(p); + fsd.size = c_abi_sizeof(p->abi, fsd.type); + fsd.align = c_abi_alignof(p->abi, fsd.type); + fsd.kind = FS_LOCAL; + return cg_local(p->cg, &fsd); +} + +static void store_top_to_size_slot(Parser* p, FrameSlot slot) { + cg_push_local_typed(p->cg, slot, ty_size_t(p)); + cg_swap(p->cg); + cg_store(p->cg); + cg_drop(p->cg); +} + +static void reset_vla_pending(Parser* p) { + p->vla_pending = 0; + p->vla_pending_count_slot = FRAME_SLOT_NONE; + p->vla_pending_count_len = 0; +} + +static VLABound* add_vla_bound(Parser* p, VLABound* head, + const Type* array_ty, FrameSlot byte_slot, + FrameSlot count_slot) { + VLABound* b = arena_znew(p->pool->arena, VLABound); + b->array_ty = array_ty; + b->byte_slot = byte_slot; + b->count_slot = count_slot; + b->next = head; + return b; +} + +static int build_vla_size(Parser* p, const Type* ty, u32* count_idx, + VLABound** bounds, FrameSlot* out_slot, + u32* out_static_size, SrcLoc loc) { + if (!ty || ty->kind != TY_ARRAY) { + *out_static_size = c_abi_sizeof(p->abi, ty); + *out_slot = FRAME_SLOT_NONE; + return 0; + } + + FrameSlot count_slot = FRAME_SLOT_NONE; + int count_dynamic = 0; + if (ty->arr.incomplete) { + if (*count_idx >= p->vla_pending_count_len) { + perr(p, "missing VLA bound for declarator"); + } + count_slot = p->vla_pending_count_slots[(*count_idx)++]; + count_dynamic = 1; + } + + FrameSlot elem_slot = FRAME_SLOT_NONE; + u32 elem_static_size = 0; + int elem_dynamic = + build_vla_size(p, ty->arr.elem, count_idx, bounds, &elem_slot, + &elem_static_size, loc); + + if (count_dynamic || elem_dynamic) { + FrameSlot byte_slot = make_vla_size_slot(p); + cg_set_loc(p->cg, loc); + if (count_dynamic) { + cg_push_local_typed(p->cg, count_slot, ty_size_t(p)); + cg_load(p->cg); + } else { + cg_push_int(p->cg, (i64)ty->arr.count, ty_size_t(p)); + } + if (elem_dynamic) { + cg_push_local_typed(p->cg, elem_slot, ty_size_t(p)); + cg_load(p->cg); + } else { + cg_push_int(p->cg, (i64)elem_static_size, ty_size_t(p)); + } + cg_binop(p->cg, BO_IMUL); + store_top_to_size_slot(p, byte_slot); + *bounds = add_vla_bound(p, *bounds, ty, byte_slot, count_slot); + *out_slot = byte_slot; + *out_static_size = 0; + return 1; + } + + *out_slot = FRAME_SLOT_NONE; + *out_static_size = ty->arr.count * elem_static_size; + return 0; +} + +static FrameSlot finish_vla_layout(Parser* p, const Type* ty, SrcLoc loc, + VLABound** bounds_out) { + FrameSlot byte_slot = FRAME_SLOT_NONE; + u32 static_size = 0; + u32 count_idx = 0; + *bounds_out = NULL; + if (!build_vla_size(p, ty, &count_idx, bounds_out, &byte_slot, &static_size, + loc)) { + perr(p, "VLA declarator did not produce a runtime size"); + } + if (count_idx != p->vla_pending_count_len) { + perr(p, "unused VLA bound in declarator"); + } + reset_vla_pending(p); + return byte_slot; +} + /* ============================================================ * Static-local symbol naming * ============================================================ */ @@ -491,33 +595,13 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { sym_set_decl(e, DECL_NONE, DS_TYPEDEF, DL_NONE, specs->flags, DSTATE_DECLARED); if (p->vla_pending && var_ty && var_ty->kind == TY_ARRAY) { - FrameSlot count_slot = p->vla_pending_count_slot; - const Type* elem_ty = var_ty->arr.elem; - u32 esz = c_abi_sizeof(p->abi, elem_ty); - FrameSlotDesc bsd; - FrameSlot byte_slot; - memset(&bsd, 0, sizeof bsd); - bsd.type = ty_size_t(p); - bsd.size = c_abi_sizeof(p->abi, bsd.type); - bsd.align = c_abi_alignof(p->abi, bsd.type); - bsd.kind = FS_LOCAL; - byte_slot = cg_local(p->cg, &bsd); - cg_set_loc(p->cg, loc); - cg_push_local_typed(p->cg, count_slot, ty_size_t(p)); - to_rvalue(p); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } - cg_push_local_typed(p->cg, byte_slot, ty_size_t(p)); - cg_swap(p->cg); - cg_store(p->cg); - cg_drop(p->cg); + VLABound* bounds = NULL; + FrameSlot byte_slot = finish_vla_layout(p, var_ty, loc, &bounds); e->vla_byte_slot = byte_slot; - p->vla_pending = 0; - p->vla_pending_count_slot = FRAME_SLOT_NONE; + e->vla_bounds = bounds; } else if (specs->vla_byte_slot != FRAME_SLOT_NONE) { e->vla_byte_slot = specs->vla_byte_slot; + e->vla_bounds = specs->vla_bounds; } } (void)loc; @@ -607,39 +691,20 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { return; } - if (var_ty && var_ty->kind == TY_ARRAY && var_ty->arr.incomplete && + if (var_ty && var_ty->kind == TY_ARRAY && (p->vla_pending || specs->vla_byte_slot != FRAME_SLOT_NONE)) { const Type* elem_ty = var_ty->arr.elem; const Type* ptr_ty = type_ptr(p->pool, elem_ty); FrameSlot byte_slot; FrameSlot ptr_slot; SymEntry* sym_entry; + VLABound* bounds = NULL; if (p->vla_pending) { - FrameSlot count_slot = p->vla_pending_count_slot; - u32 esz = c_abi_sizeof(p->abi, elem_ty); - FrameSlotDesc bsd; - memset(&bsd, 0, sizeof bsd); - bsd.type = ty_size_t(p); - bsd.size = c_abi_sizeof(p->abi, bsd.type); - bsd.align = c_abi_alignof(p->abi, bsd.type); - bsd.kind = FS_LOCAL; - byte_slot = cg_local(p->cg, &bsd); + byte_slot = finish_vla_layout(p, var_ty, loc, &bounds); ++p->vla_mark; - p->vla_pending = 0; - p->vla_pending_count_slot = FRAME_SLOT_NONE; - cg_set_loc(p->cg, loc); - cg_push_local_typed(p->cg, count_slot, ty_size_t(p)); - to_rvalue(p); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); - } - cg_push_local_typed(p->cg, byte_slot, ty_size_t(p)); - cg_swap(p->cg); - cg_store(p->cg); - cg_drop(p->cg); } else { byte_slot = specs->vla_byte_slot; + bounds = specs->vla_bounds; } ptr_slot = make_local(p, name, ptr_ty, loc); cg_set_loc(p->cg, loc); @@ -653,6 +718,7 @@ static void parse_init_declarator(Parser* p, const DeclSpecs* specs) { sym_entry = scope_lookup(p, name); if (sym_entry && sym_entry->kind == SEK_LOCAL) { sym_entry->vla_byte_slot = byte_slot; + sym_entry->vla_bounds = bounds; } if (accept_punct(p, '=')) { perr(p, "VLA initializers are not allowed (§6.7.9 ¶3)"); diff --git a/lang/c/parse/parse_expr.c b/lang/c/parse/parse_expr.c @@ -41,6 +41,12 @@ static int type_is_void_ptr(const Type* ty) { ty->ptr.pointee->kind == TY_VOID; } +static const Type* ty_char16(Parser* p) { + return type_prim(p->pool, TY_USHORT); +} + +static const Type* ty_char32(Parser* p) { return type_prim(p->pool, TY_UINT); } + static int pointer_pointees_compatible(Parser* p, const Type* lhs, const Type* rhs) { const Type* lp; @@ -308,14 +314,64 @@ static const Type* float_literal_type(Parser* p, const Tok* t) { return type_prim(p->pool, TY_DOUBLE); } +static int hex_value(int c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +static i64 char_mask_value(i64 v, u32 bits) { + if (bits >= 64u) return v; + return v & (i64)((1ull << bits) - 1ull); +} + +static i64 decode_utf8_char(Parser* p, const char* s, size_t len, size_t* pi, + SrcLoc loc) { + size_t i = *pi; + unsigned char c0; + u32 v; + u32 need; + if (i >= len) compiler_panic(p->c, loc, "truncated character literal"); + c0 = (unsigned char)s[i++]; + if (c0 < 0x80u) { + *pi = i; + return c0; + } + if ((c0 & 0xe0u) == 0xc0u) { + v = c0 & 0x1fu; + need = 1; + } else if ((c0 & 0xf0u) == 0xe0u) { + v = c0 & 0x0fu; + need = 2; + } else if ((c0 & 0xf8u) == 0xf0u) { + v = c0 & 0x07u; + need = 3; + } else { + perr(p, "malformed UTF-8 in wide character literal"); + } + while (need--) { + unsigned char cx; + if (i >= len) compiler_panic(p->c, loc, "truncated UTF-8 character"); + cx = (unsigned char)s[i++]; + if ((cx & 0xc0u) != 0x80u) perr(p, "malformed UTF-8 in wide literal"); + v = (v << 6) | (u32)(cx & 0x3fu); + } + *pi = i; + return (i64)v; +} + static i64 decode_one_char(Parser* p, const char* s, size_t len, size_t* pi, - SrcLoc loc) { + SrcLoc loc, u32 unit_bits) { size_t i = *pi; i64 v; int c; if (i >= len) compiler_panic(p->c, loc, "truncated character literal"); if (s[i] != '\\') { - v = (unsigned char)s[i++]; + if (unit_bits > 8u) + v = decode_utf8_char(p, s, len, &i, loc); + else + v = (unsigned char)s[i++]; *pi = i; return v; } @@ -360,22 +416,30 @@ static i64 decode_one_char(Parser* p, const char* s, size_t len, size_t* pi, i64 hex = 0; int any = 0; while (i < len) { - int d = (unsigned char)s[i]; - int dv; - if (d >= '0' && d <= '9') - dv = d - '0'; - else if (d >= 'a' && d <= 'f') - dv = d - 'a' + 10; - else if (d >= 'A' && d <= 'F') - dv = d - 'A' + 10; - else + int dv = hex_value((unsigned char)s[i]); + if (dv < 0) break; hex = hex * 16 + dv; any = 1; i++; } if (!any) compiler_panic(p->c, loc, "\\x with no hex digits"); - v = hex & 0xff; + v = char_mask_value(hex, unit_bits); + break; + } + case 'u': + case 'U': { + int n = c == 'u' ? 4 : 8; + i64 ucn = 0; + int j; + for (j = 0; j < n; ++j) { + int dv; + if (i >= len) compiler_panic(p->c, loc, "truncated UCN"); + dv = hex_value((unsigned char)s[i++]); + if (dv < 0) compiler_panic(p->c, loc, "malformed UCN"); + ucn = ucn * 16 + dv; + } + v = char_mask_value(ucn, unit_bits); break; } default: @@ -387,7 +451,7 @@ static i64 decode_one_char(Parser* p, const char* s, size_t len, size_t* pi, i++; n++; } - v = oct & 0xff; + v = char_mask_value(oct, unit_bits); } else { v = c; } @@ -397,20 +461,49 @@ static i64 decode_one_char(Parser* p, const char* s, size_t len, size_t* pi, return v; } +const Type* char_literal_type(Parser* p, const Tok* t) { + if (t->flags & TF_STR_U16) return ty_char16(p); + if (t->flags & TF_STR_U32) return ty_char32(p); + return ty_int(p); +} + +const Type* string_literal_elem_type(Parser* p, const Tok* t) { + if (t->flags & TF_STR_WIDE) return ty_int(p); + if (t->flags & TF_STR_U16) return ty_char16(p); + if (t->flags & TF_STR_U32) return ty_char32(p); + return type_prim(p->pool, TY_CHAR); +} + +int string_literal_initializes_array(Parser* p, const Type* elem, + const Tok* t) { + const Type* uelem; + if (!elem || !t || t->kind != TOK_STR) return 0; + uelem = type_unqual(p->pool, elem); + if (!(t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32))) { + return is_char_kind(uelem); + } + return type_compatible(uelem, string_literal_elem_type(p, t)); +} + i64 decode_char_literal(Parser* p, const Tok* t) { size_t len = 0; const char* s = pool_str(p->pool, t->spelling, &len); size_t i = 0; i64 v; + u32 bits = 8; if (!s) perr(p, "bad char literal"); if (t->flags & TF_STR_U8) i = 2; else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) i = 1; + if (t->flags & TF_STR_U16) + bits = 16; + else if (t->flags & (TF_STR_WIDE | TF_STR_U32)) + bits = 32; if (i >= len || s[i] != '\'') perr(p, "malformed character literal"); i++; if (i >= len || s[i] == '\'') perr(p, "empty character literal"); - v = decode_one_char(p, s, len, &i, t->loc); + v = decode_one_char(p, s, len, &i, t->loc, bits); if (i >= len || s[i] != '\'') { perr(p, "multi-character constants are not supported"); } @@ -424,20 +517,28 @@ u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out) { Heap* h = cfree_compiler_heap(p->c); u8* buf; size_t k = 0; + const Type* elem_ty; + u32 elem_size; + u32 bits; if (!s) perr(p, "bad string literal"); if (t->flags & TF_STR_U8) i = 2; else if (t->flags & (TF_STR_WIDE | TF_STR_U16 | TF_STR_U32)) i = 1; + elem_ty = string_literal_elem_type(p, t); + elem_size = c_abi_sizeof(p->abi, elem_ty); + bits = elem_size >= 4u ? 32u : elem_size * 8u; if (i >= len || s[i] != '"') perr(p, "malformed string literal"); i++; - buf = (u8*)h->alloc(h, len + 1, 1); + buf = (u8*)h->alloc(h, (len + 1u) * elem_size, 1); if (!buf) perr(p, "out of memory in string literal"); while (i < len && s[i] != '"') { - i64 ch = decode_one_char(p, s, len, &i, t->loc); - buf[k++] = (u8)ch; + i64 ch = decode_one_char(p, s, len, &i, t->loc, bits); + encode_int_le(buf + k, elem_size, ch); + k += elem_size; } - buf[k++] = 0; + encode_int_le(buf + k, elem_size, 0); + k += elem_size; *nlen_out = k; return buf; } @@ -448,6 +549,16 @@ CfreeCgSym emit_string_to_rodata(Parser* p, const u8* bytes, size_t n) { return cfree_cg_const_data(p->cg, bytes, n, 1u, pcg_tid(p->c, arr_ty)); } +CfreeCgSym emit_string_literal_to_rodata(Parser* p, const u8* bytes, + size_t nbytes, + const Type* elem_ty) { + u32 elem_size = c_abi_sizeof(p->abi, elem_ty); + u32 count = elem_size ? (u32)(nbytes / elem_size) : 0; + const Type* arr_ty = type_array(p->pool, elem_ty, count, 0); + return cfree_cg_const_data(p->cg, bytes, nbytes, c_abi_alignof(p->abi, elem_ty), + pcg_tid(p->c, arr_ty)); +} + /* ============================================================ * Constant expression evaluator (cexpr_*) * ============================================================ */ @@ -989,8 +1100,9 @@ static CConstInt cexpr_unary(Parser* p, SrcLoc loc) { } if (p->cur.kind == TOK_CHR) { i64 v = decode_char_literal(p, &p->cur); + const Type* ty = char_literal_type(p, &p->cur); advance(p); - return cint_make_u64(p, ty_int(p), (u64)v); + return cint_make_u64(p, ty, (u64)v); } if (p->cur.kind == TOK_IDENT) { Sym name = p->cur.v.ident; @@ -1037,6 +1149,13 @@ static void decay_array_to_pointer(Parser* p, const Type* arr_ty) { pcg_retag_top(p, ptr_ty); } +static FrameSlot vla_size_slot_for_type(VLABound* bounds, const Type* ty) { + for (VLABound* b = bounds; b; b = b->next) { + if (b->array_ty == ty) return b->byte_slot; + } + return FRAME_SLOT_NONE; +} + void to_rvalue(Parser* p) { const Type* t = cg_top_type(p->cg); if (t) { @@ -1828,6 +1947,7 @@ static void parse_primary(Parser* p) { if (e->storage == DS_REGISTER) pcg_set_top_register(p); if (e->vla_byte_slot != FRAME_SLOT_NONE) { p->last_pushed_vla_slot = e->vla_byte_slot; + p->last_pushed_vla_bounds = e->vla_bounds; } return; case SEK_GLOBAL: @@ -1844,19 +1964,22 @@ static void parse_primary(Parser* p) { } if (t.kind == TOK_CHR) { i64 v = decode_char_literal(p, &t); + const Type* lty = char_literal_type(p, &t); advance(p); - cg_push_int(p->cg, v, ty_int(p)); + cg_push_int(p->cg, v, lty); return; } if (t.kind == TOK_STR) { size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); - ObjSymId sym = emit_string_to_rodata(p, bytes, n); + const Type* elem_ty = string_literal_elem_type(p, &t); + u32 elem_size = c_abi_sizeof(p->abi, elem_ty); + ObjSymId sym = emit_string_literal_to_rodata(p, bytes, n, elem_ty); cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); { - const Type* char_ty = type_prim(p->pool, TY_CHAR); - const Type* arr_ty = type_array(p->pool, char_ty, (u32)n, 0); + const Type* arr_ty = + type_array(p->pool, elem_ty, elem_size ? (u32)(n / elem_size) : 0, 0); cg_push_global(p->cg, sym, arr_ty); } return; @@ -1915,7 +2038,11 @@ static void cg_record_member_path(Parser* p, const Type* member_ty, } static void parse_postfix(Parser* p) { + VLABound* vla_bounds; + p->last_pushed_vla_slot = FRAME_SLOT_NONE; + p->last_pushed_vla_bounds = NULL; parse_primary(p); + vla_bounds = p->last_pushed_vla_bounds; for (;;) { Tok t = p->cur; if (is_punct(&t, P_INC)) { @@ -2014,13 +2141,29 @@ static void parse_postfix(Parser* p) { perr(p, "invalid subscript: needs one pointer and one integer"); } if (!elem) perr(p, "subscript on incomplete pointee"); - u32 esz = c_abi_sizeof(p->abi, elem); - if (esz != 1) { - cg_push_int(p->cg, (i64)esz, ty_size_t(p)); - cg_binop(p->cg, BO_IMUL); + { + FrameSlot vla_size_slot = vla_size_slot_for_type(vla_bounds, elem); + if (vla_size_slot != FRAME_SLOT_NONE) { + cg_push_local_typed(p->cg, vla_size_slot, ty_size_t(p)); + cg_load(p->cg); + cg_binop(p->cg, BO_IMUL); + } else { + u32 esz = c_abi_sizeof(p->abi, elem); + if (esz != 1) { + cg_push_int(p->cg, (i64)esz, ty_size_t(p)); + cg_binop(p->cg, BO_IMUL); + } + } } cg_binop(p->cg, BO_IADD); cg_deref(p->cg, elem); + { + FrameSlot elem_vla_slot = vla_size_slot_for_type(vla_bounds, elem); + if (elem_vla_slot != FRAME_SLOT_NONE) { + p->last_pushed_vla_slot = elem_vla_slot; + p->last_pushed_vla_bounds = vla_bounds; + } + } } continue; } diff --git a/lang/c/parse/parse_init.c b/lang/c/parse/parse_init.c @@ -37,6 +37,14 @@ static u8* peek_string_bytes(Parser* p, size_t* nlen_out) { return decode_string_literal(p, &t, nlen_out); } +static u64 decode_lit_unit_le(const u8* src, u32 size) { + u64 v = 0; + u32 i; + if (size > 8u) size = 8u; + for (i = 0; i < size; ++i) v |= (u64)src[i] << (8u * i); + return v; +} + /* ============================================================ * Runtime initializers * ============================================================ */ @@ -221,17 +229,20 @@ static void init_string_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, const Type* elem_ty, u32 count) { size_t n = 0; u8* bytes = peek_string_bytes(p, &n); - size_t copy = n; + u32 elem_size = c_abi_sizeof(p->abi, elem_ty); + size_t elems = elem_size ? n / elem_size : 0; + size_t copy = elems; size_t i; if (copy > count) copy = count; for (i = 0; i < copy; ++i) { - push_subobject_lv(p, slot, arr_ty, offset + (u32)i, elem_ty); - cg_push_int(p->cg, (i64)bytes[i], elem_ty); + push_subobject_lv(p, slot, arr_ty, offset + (u32)i * elem_size, elem_ty); + cg_push_int(p->cg, (i64)decode_lit_unit_le(bytes + i * elem_size, elem_size), + elem_ty); cg_store(p->cg); cg_drop(p->cg); } for (; i < count; ++i) { - push_subobject_lv(p, slot, arr_ty, offset + (u32)i, elem_ty); + push_subobject_lv(p, slot, arr_ty, offset + (u32)i * elem_size, elem_ty); cg_push_int(p->cg, 0, elem_ty); cg_store(p->cg); cg_drop(p->cg); @@ -424,12 +435,14 @@ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, if (ty->kind == TY_ARRAY) { const Type* elem_ty = ty->arr.elem; u32 esz = c_abi_sizeof(p->abi, elem_ty); - if (is_char_kind(elem_ty)) { - if (p->cur.kind == TOK_STR) { - init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); - return; - } - if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem_ty, &p->cur)) { + init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); + return; + } + if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + Tok str = peek1(p); + if (string_literal_initializes_array(p, elem_ty, &str)) { advance(p); init_string_at(p, slot, arr_ty, offset, elem_ty, ty->arr.count); accept_punct(p, ','); @@ -654,14 +667,18 @@ static int try_parse_static_float(Parser* p, u8* dst, u32 size, /* Encode a string literal at *buf+offset for a char-array sub-object. */ static void parse_static_string_at(Parser* p, u8* buf, u32 buflen, u32 offset, - u32 count) { + const Type* elem_ty, u32 count) { size_t n = 0; u8* bytes = peek_string_bytes(p, &n); - size_t copy = n; + u32 elem_size = c_abi_sizeof(p->abi, elem_ty); + size_t elems = elem_size ? n / elem_size : 0; + size_t copy = elems; + size_t copy_bytes; if (copy > count) copy = count; - if (offset + (u32)copy > buflen) + copy_bytes = copy * elem_size; + if (offset + (u32)copy_bytes > buflen) perr(p, "string initializer overflows object"); - memcpy(buf + offset, bytes, copy); + memcpy(buf + offset, bytes, copy_bytes); cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); } @@ -700,6 +717,94 @@ typedef struct CStaticConst { i64 addend; } CStaticConst; +typedef struct StaticRelocSave { + void* relocs; + u32 len; + u32 cap; +} StaticRelocSave; + +static Sym mint_compound_literal_sym(Parser* p) { + static const char prefix[] = "__cfree_compound_literal."; + char buf[sizeof(prefix) + 12u]; + u32 wlen = 0; + u32 id = ++p->compound_literal_counter; + for (u32 i = 0; prefix[i] != 0; ++i) { + buf[wlen++] = prefix[i]; + } + { + char digits[12]; + int dn = 0; + if (id == 0) digits[dn++] = '0'; + while (id) { + digits[dn++] = (char)('0' + (id % 10u)); + id /= 10u; + } + while (dn) buf[wlen++] = digits[--dn]; + } + return pool_intern(p->pool, buf, wlen); +} + +static void static_relocs_swap_empty(Parser* p, StaticRelocSave* save) { + save->relocs = p->static_relocs; + save->len = p->static_relocs_len; + save->cap = p->static_relocs_cap; + p->static_relocs = NULL; + p->static_relocs_len = 0; + p->static_relocs_cap = 0; +} + +static void static_relocs_restore(Parser* p, const StaticRelocSave* save) { + p->static_relocs = save->relocs; + p->static_relocs_len = save->len; + p->static_relocs_cap = save->cap; +} + +static ObjSymId define_static_compound_literal(Parser* p, const Type* lit_ty, + SrcLoc loc) { + Decl decl_in; + DeclId did; + ObjSymId sym; + StaticRelocSave relocs; + + if (p->cur_func_name != 0) { + perr(p, "block-scope compound literal is not a static address constant"); + } + if (lit_ty && lit_ty->kind == TY_ARRAY && lit_ty->arr.incomplete) { + lit_ty = complete_incomplete_array(p, lit_ty); + } + + memset(&decl_in, 0, sizeof decl_in); + decl_in.name = mint_compound_literal_sym(p); + decl_in.type = lit_ty; + decl_in.loc = loc; + decl_in.storage = DS_STATIC; + decl_in.linkage = DL_INTERNAL; + decl_in.visibility = SV_DEFAULT; + did = decl_declare(p->decls, &decl_in); + sym = decl_obj_sym(p->decls, did); + + static_relocs_swap_empty(p, &relocs); + define_static_object(p, sym, decl_in.section_id, lit_ty, + lit_ty ? lit_ty->qual : 0, /*has_init=*/1, loc, + decl_in.align); + static_relocs_restore(p, &relocs); + return sym; +} + +static CStaticConst parse_static_compound_literal_after_type(Parser* p, + const Type* lit_ty, + SrcLoc loc) { + CStaticConst r; + memset(&r, 0, sizeof r); + if (!is_punct(&p->cur, '{')) { + perr(p, "expected compound literal initializer in static initializer"); + } + r.kind = C_STATIC_CONST_ADDR; + r.target = define_static_compound_literal(p, lit_ty, loc); + r.addend = 0; + return r; +} + static CConstInt int_bits_for_type(Parser* p, CConstInt v, const Type* ty) { u32 sz = c_abi_sizeof(p->abi, ty); v.type = ty; @@ -787,7 +892,8 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { if (t.kind == TOK_STR) { size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); - ObjSymId str_sym = emit_string_to_rodata(p, bytes, n); + const Type* elem_ty = string_literal_elem_type(p, &t); + ObjSymId str_sym = emit_string_literal_to_rodata(p, bytes, n, elem_ty); cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); advance(p); out->kind = C_STATIC_CONST_ADDR; @@ -798,6 +904,17 @@ static int try_parse_static_address_const(Parser* p, CStaticConst* out) { if (is_punct(&t, '&')) { saw_amp = 1; advance(p); + if (is_punct(&p->cur, '(')) { + Tok n = peek1(p); + if (starts_type_name(p, &n)) { + const Type* lit_ty; + advance(p); + lit_ty = parse_type_name(p); + expect_punct(p, ')', "')' after compound literal type-name"); + *out = parse_static_compound_literal_after_type(p, lit_ty, t.loc); + return 1; + } + } if (p->cur.kind != TOK_IDENT || ident_kw_init(p, p->cur.v.ident) != KW_NONE) { perr(p, "expected identifier after '&' in static initializer"); @@ -858,6 +975,36 @@ static CStaticConst parse_static_const(Parser* p, const Type* ty, SrcLoc loc) { memset(&r, 0, sizeof r); r.kind = C_STATIC_CONST_INT; if (ty && ty->kind == TY_PTR) { + if (is_punct(&p->cur, '(')) { + Tok n = peek1(p); + if (starts_type_name(p, &n)) { + const Type* cast_ty; + const Type* cast_unqual; + advance(p); + cast_ty = parse_type_name(p); + cast_unqual = type_unqual(p->pool, cast_ty); + expect_punct(p, ')', "')' after cast or compound literal type-name"); + if (is_punct(&p->cur, '{')) { + const Type* lit_unqual = type_unqual(p->pool, cast_ty); + if (!lit_unqual || lit_unqual->kind != TY_ARRAY) { + perr(p, + "non-array compound literal needs '&' in pointer initializer"); + } + return parse_static_compound_literal_after_type(p, cast_ty, loc); + } + if (!cast_unqual || + (cast_unqual->kind != TY_PTR && cast_unqual->kind != TY_VOID && + !type_is_int(cast_unqual))) { + perr(p, "invalid cast in null pointer constant"); + } + r.int_value = parse_null_pointer_constant(p, loc); + if (const_int_as_i64(p, r.int_value) != 0) { + perr(p, "static pointer initializer is not a null pointer constant"); + } + r.kind = C_STATIC_CONST_NULL_PTR; + return r; + } + } if (try_parse_static_address_const(p, &r)) return r; r.int_value = parse_null_pointer_constant(p, loc); if (const_int_as_i64(p, r.int_value) != 0) { @@ -907,14 +1054,16 @@ void parse_static_init_at(Parser* p, u8* buf, u32 buflen, u32 offset, u32 esz = c_abi_sizeof(p->abi, elem); u32 i = 0; int had_brace; - if (is_char_kind(elem)) { - if (p->cur.kind == TOK_STR) { - parse_static_string_at(p, buf, buflen, offset, ty->arr.count); - return; - } - if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem, &p->cur)) { + parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count); + return; + } + if (is_punct(&p->cur, '{') && peek1(p).kind == TOK_STR) { + Tok str = peek1(p); + if (string_literal_initializes_array(p, elem, &str)) { advance(p); - parse_static_string_at(p, buf, buflen, offset, ty->arr.count); + parse_static_string_at(p, buf, buflen, offset, elem, ty->arr.count); accept_punct(p, ','); expect_punct(p, '}', "'}' after string initializer"); return; diff --git a/lang/c/parse/parse_priv.h b/lang/c/parse/parse_priv.h @@ -86,6 +86,14 @@ typedef enum SymEntryKind { } SymEntryKind; typedef struct SymEntry SymEntry; +typedef struct VLABound VLABound; +struct VLABound { + const Type* array_ty; + FrameSlot byte_slot; + FrameSlot count_slot; + VLABound* next; +}; + struct SymEntry { Sym name; u8 kind; /* SymEntryKind */ @@ -103,6 +111,7 @@ struct SymEntry { i64 enum_value; } v; FrameSlot vla_byte_slot; + VLABound* vla_bounds; struct Attr* attrs; SymEntry* next; }; @@ -243,9 +252,12 @@ typedef struct Parser { u8 vla_pending; FrameSlot vla_pending_count_slot; + FrameSlot vla_pending_count_slots[8]; + u8 vla_pending_count_len; u32 vla_mark; FrameSlot last_pushed_vla_slot; + VLABound* last_pushed_vla_bounds; u8 in_param_decl; u32 suppress_codegen; @@ -283,6 +295,7 @@ typedef struct DeclSpecs { u8 pad; u32 align; FrameSlot vla_byte_slot; + VLABound* vla_bounds; Attr* attrs; } DeclSpecs; @@ -437,10 +450,17 @@ i64 const_int_as_i64(Parser* p, CConstInt v); i64 parse_int_literal(Parser* p, const Tok* t); double parse_float_literal(Parser* p, const Tok* t); i64 decode_char_literal(Parser* p, const Tok* t); +const Type* char_literal_type(Parser* p, const Tok* t); +const Type* string_literal_elem_type(Parser* p, const Tok* t); +int string_literal_initializes_array(Parser* p, const Type* elem, + const Tok* t); u8* decode_string_literal(Parser* p, const Tok* t, size_t* nlen_out); void to_rvalue(Parser* p); void coerce_top_to_lvalue(Parser* p); CfreeCgSym emit_string_to_rodata(Parser* p, const u8* bytes, size_t n); +CfreeCgSym emit_string_literal_to_rodata(Parser* p, const u8* bytes, + size_t nbytes, + const Type* elem_ty); /* parse_init.c */ void init_at(Parser* p, FrameSlot slot, const Type* arr_ty, u32 offset, diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -515,6 +515,7 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { out->pad = 0; out->align = 0; out->vla_byte_slot = FRAME_SLOT_NONE; + out->vla_bounds = NULL; out->attrs = NULL; loc = tok_loc(&p->cur); for (;;) { @@ -733,6 +734,7 @@ int parse_decl_specs(Parser* p, DeclSpecs* out) { tagged_ty = e->type; if (e->vla_byte_slot != FRAME_SLOT_NONE) { out->vla_byte_slot = e->vla_byte_slot; + out->vla_bounds = e->vla_bounds; } acc.saw_explicit_type = 1; advance(p); @@ -1238,8 +1240,10 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { out->count = (u32)v; } else { FrameSlotDesc fsd; - if (p->vla_pending) { - perr(p, "v1 supports only one VLA dimension per declarator"); + if (p->vla_pending_count_len >= + sizeof p->vla_pending_count_slots / + sizeof p->vla_pending_count_slots[0]) { + perr(p, "too many VLA dimensions per declarator"); } out->vla = 1; memset(&fsd, 0, sizeof fsd); @@ -1258,6 +1262,8 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { p->vla_pending = 1; ++p->vla_mark; p->vla_pending_count_slot = out->vla_count_slot; + p->vla_pending_count_slots[p->vla_pending_count_len++] = + out->vla_count_slot; } } expect_punct(p, ']', "']' after array size"); @@ -1452,24 +1458,28 @@ const Type* complete_incomplete_array(Parser* p, const Type* ty) { const Type* elem; if (!ty || ty->kind != TY_ARRAY || !ty->arr.incomplete) return ty; elem = ty->arr.elem; - if (is_char_kind(elem) && p->cur.kind == TOK_STR) { + if (p->cur.kind == TOK_STR && + string_literal_initializes_array(p, elem, &p->cur)) { Tok t = p->cur; size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); + u32 elem_size = c_abi_sizeof(p->abi, elem); cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); - return type_array(p->pool, elem, (u32)n, /*incomplete=*/0); + return type_array(p->pool, elem, elem_size ? (u32)(n / elem_size) : 0, + /*incomplete=*/0); } if (is_punct(&p->cur, '{')) { u32 cnt; record_braced_block(p); cnt = count_recorded_top_level_items(p->replay, p->replay_len); if (cnt == 1 && p->replay_len >= 3 && p->replay[1].kind == TOK_STR && - is_char_kind(elem)) { + string_literal_initializes_array(p, elem, &p->replay[1])) { Tok t = p->replay[1]; size_t n = 0; u8* bytes = decode_string_literal(p, &t, &n); + u32 elem_size = c_abi_sizeof(p->abi, elem); cfree_compiler_heap(p->c)->free(cfree_compiler_heap(p->c), bytes, 0); - cnt = (u32)n; + cnt = elem_size ? (u32)(n / elem_size) : 0; } replay_rewind(p); return type_array(p->pool, elem, cnt, /*incomplete=*/0); diff --git a/src/arch/aa64/opt_coord.c b/src/arch/aa64/opt_coord.c @@ -279,7 +279,7 @@ static void aa_plan_call(CGTarget* t, const CGCallDesc* d, CGCallPlan* out) { } else { m->dst_kind = CG_CALL_PLAN_STACK; m->stack_offset = stack; - stack += 8; + stack += p->size > 8 ? p->size : 8; } } else { m->cls = RC_INT; diff --git a/test/opt/opt_test.c b/test/opt/opt_test.c @@ -67,6 +67,7 @@ typedef struct TestCtx { CfreeCgTypeId i32; CfreeCgTypeId i64; CfreeCgTypeId f64; + CfreeCgTypeId f128; } TestCtx; static void tc_init_target(TestCtx* tc, CfreeArchKind arch, CfreeOSKind os) { @@ -93,6 +94,7 @@ static void tc_init_target(TestCtx* tc, CfreeArchKind arch, CfreeOSKind os) { tc->i32 = b.id[CFREE_CG_BUILTIN_I32]; tc->i64 = b.id[CFREE_CG_BUILTIN_I64]; tc->f64 = b.id[CFREE_CG_BUILTIN_F64]; + tc->f128 = b.id[CFREE_CG_BUILTIN_F128]; } } @@ -1225,6 +1227,27 @@ static void real_arch_call_plan_layout_one(const RealArchExpect* ex) { ex->name); } + if (ex->arch == CFREE_ARCH_ARM_64) { + CfreeCgTypeId params[10]; + CGABIValue args[10]; + for (u32 i = 0; i < 10; ++i) params[i] = tc.f128; + CfreeCgTypeId fn = make_func_type(&tc, tc.f128, params, 10, 0); + const ABIFuncInfo* abi = abi_cg_func_info(tc.c->abi, fn); + for (u32 i = 0; i < 10; ++i) + args[i] = call_arg_value(tc.f128, &abi->params[i], + op_local_((FrameSlot)(20 + i), tc.f128)); + CGABIValue ret = call_arg_value(tc.f128, &abi->ret, + op_local_(30, tc.f128)); + CGCallDesc d = make_call_desc(&tc, fn, args, 10, ret); + CGCallPlan p; + target->plan_call(target, &d, &p); + EXPECT(p.stack_arg_size == 32, + "aa64 f128 stack-arg size got %u want 32", + (unsigned)p.stack_arg_size); + expect_plan_arg(&p, 8, CG_CALL_PLAN_STACK, RC_FP, 0, 0, "aa64 f128"); + expect_plan_arg(&p, 9, CG_CALL_PLAN_STACK, RC_FP, 0, 16, "aa64 f128"); + } + tc_fini(&tc); } diff --git a/test/parse/CORPUS.md b/test/parse/CORPUS.md @@ -480,7 +480,6 @@ memcpys into before `ret`. | `6_9_11_tentative_multi` | ★ | full TU: `int g; int g;` — two tentative defs merge; `return g+42` | 42 | | `6_9_12_tentative_incomplete_array` | ★ | full TU: `int arr[]; int arr[3];` — tentative + completing decl; `return arr[0]+arr[1]+arr[2]+42` | 42 | | `6_9_13_extern_func_def` | ★ | full TU: `extern int helper(int x){return x+1;}` — extern on a definition; `helper(41)` | 42 | -| `6_9_14_old_style_definition` | RED | K&R-style definition `static int add(a,b) int a; int b; { ... }` | 42 | ## Builtins diff --git a/test/parse/cases/6_4_5_04_wide_string_subscript.c b/test/parse/cases/6_4_5_04_wide_string_subscript.c @@ -0,0 +1,6 @@ +#include <stddef.h> + +int test_main(void) { + const wchar_t* s = L"\x012a"; + return sizeof(L"\x012a") == 8 && s[0] == 298 && s[1] == 0 ? 42 : 0; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_04_wide_string_subscript.expected diff --git a/test/parse/cases/6_4_5_05_utf_string_widths.c b/test/parse/cases/6_4_5_05_utf_string_widths.c @@ -0,0 +1,8 @@ +int test_main(void) { + int score = 0; + if (sizeof(u"*") == 4) score += 10; + if (sizeof(U"*") == 8) score += 10; + if (u'\x1234' == 0x1234) score += 10; + if (U'\U0001f600' == 0x1f600) score += 12; + return score; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_05_utf_string_widths.expected diff --git a/test/parse/cases/6_4_5_06_wide_string_ucn_init.c b/test/parse/cases/6_4_5_06_wide_string_ucn_init.c @@ -0,0 +1,7 @@ +#include <stddef.h> + +int test_main(void) { + wchar_t s[] = L"A\u00a3"; + return (int)sizeof(s) + (s[0] == 65 ? 10 : 0) + + (s[1] == 163 ? 10 : 0) + (s[2] == 0 ? 10 : 0); +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_06_wide_string_ucn_init.expected diff --git a/test/parse/cases/6_4_5_07_wide_string_concat_mixed.c b/test/parse/cases/6_4_5_07_wide_string_concat_mixed.c @@ -0,0 +1,9 @@ +#include <stddef.h> + +int test_main(void) { + const wchar_t* s = L"A" "B" L"\u00a3"; + return sizeof(L"A" "B" L"\u00a3") == 16 && s[0] == 65 && s[1] == 66 && + s[2] == 163 && s[3] == 0 + ? 42 + : 0; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_07_wide_string_concat_mixed.expected diff --git a/test/parse/cases/6_4_5_08_wide_string_array_init.c b/test/parse/cases/6_4_5_08_wide_string_array_init.c @@ -0,0 +1,11 @@ +#include <stddef.h> + +wchar_t g[4] = {L"\x2a"}; + +int test_main(void) { + wchar_t l[3] = L"*"; + return sizeof(g) == 16 && g[0] == 42 && g[1] == 0 && g[3] == 0 && + l[0] == 42 && l[1] == 0 && l[2] == 0 + ? 42 + : 0; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_08_wide_string_array_init.expected diff --git a/test/parse/cases/6_4_5_09_utf16_surrogate_pair.c b/test/parse/cases/6_4_5_09_utf16_surrogate_pair.c @@ -0,0 +1,6 @@ +int test_main(void) { + unsigned short s[] = u"\U0001f600"; + return sizeof(s) == 6 && s[0] == 0xd83d && s[1] == 0xde00 && s[2] == 0 + ? 42 + : 0; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_09_utf16_surrogate_pair.expected diff --git a/test/parse/cases/6_4_5_10_utf8_ucn_encoding.c b/test/parse/cases/6_4_5_10_utf8_ucn_encoding.c @@ -0,0 +1,8 @@ +int test_main(void) { + const char* s = u8"\U0001f600"; + return sizeof(u8"\U0001f600") == 5 && (unsigned char)s[0] == 0xf0 && + (unsigned char)s[1] == 0x9f && (unsigned char)s[2] == 0x98 && + (unsigned char)s[3] == 0x80 && s[4] == 0 + ? 42 + : 0; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_4_5_10_utf8_ucn_encoding.expected diff --git a/test/parse/cases/6_5_66_file_scope_compound_literal_addr.c b/test/parse/cases/6_5_66_file_scope_compound_literal_addr.c @@ -0,0 +1,5 @@ +static int *p = &(int){42}; + +int test_main(void) { + return *p; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_5_66_file_scope_compound_literal_addr.expected diff --git a/test/parse/cases/6_5_67_file_scope_compound_literal_nested_reloc.c b/test/parse/cases/6_5_67_file_scope_compound_literal_nested_reloc.c @@ -0,0 +1,6 @@ +static int x = 41; +static int **pp = (int *[]){&x}; + +int test_main(void) { + return **pp + 1; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_5_67_file_scope_compound_literal_nested_reloc.expected diff --git a/test/parse/cases/6_5_68_file_scope_compound_literal_struct_addr.c b/test/parse/cases/6_5_68_file_scope_compound_literal_struct_addr.c @@ -0,0 +1,10 @@ +struct S { + int a; + int b; +}; + +static struct S *p = &(struct S){.a = 20, .b = 22}; + +int test_main(void) { + return p->a + p->b; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_5_68_file_scope_compound_literal_struct_addr.expected diff --git a/test/parse/cases/6_5_69_file_scope_compound_literal_struct_array.c b/test/parse/cases/6_5_69_file_scope_compound_literal_struct_array.c @@ -0,0 +1,10 @@ +struct S { + int a; + int b; +}; + +static struct S *p = (struct S[]){{10, 12}, {.a = 7, .b = 13}}; + +int test_main(void) { + return p[0].a + p[0].b + p[1].a + p[1].b; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_5_69_file_scope_compound_literal_struct_array.expected diff --git a/test/parse/cases/6_5_70_file_scope_compound_literal_const_addr.c b/test/parse/cases/6_5_70_file_scope_compound_literal_const_addr.c @@ -0,0 +1,5 @@ +static const int *p = &(const int){42}; + +int test_main(void) { + return *p; +} diff --git a/test/parse/cases/6_9_14_old_style_definition.expected b/test/parse/cases/6_5_70_file_scope_compound_literal_const_addr.expected diff --git a/test/parse/cases/6_9_14_old_style_definition.c b/test/parse/cases/6_9_14_old_style_definition.c @@ -1,10 +0,0 @@ -static int add(a, b) -int a; -int b; -{ - return a + b; -} - -int test_main(void) { - return add(20, 22); -} diff --git a/test/parse/cases_err/6_4_5_incompatible_string_prefix_concat.c b/test/parse/cases_err/6_4_5_incompatible_string_prefix_concat.c @@ -0,0 +1,3 @@ +int test_main(void) { + return (int)sizeof(L"x" u"x"); +} diff --git a/test/parse/cases_err/6_4_5_incompatible_string_prefix_concat.errpat b/test/parse/cases_err/6_4_5_incompatible_string_prefix_concat.errpat @@ -0,0 +1 @@ +incompatible encoding prefixes diff --git a/test/parse/cases_err/6_5_block_static_compound_literal.c b/test/parse/cases_err/6_5_block_static_compound_literal.c @@ -0,0 +1,4 @@ +int test_main(void) { + static int *p = (int[]){42}; + return p[0]; +} diff --git a/test/parse/cases_err/6_5_block_static_compound_literal.errpat b/test/parse/cases_err/6_5_block_static_compound_literal.errpat @@ -0,0 +1 @@ +block-scope compound literal is not a static address constant diff --git a/test/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.c b/test/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.c @@ -0,0 +1,5 @@ +static int *p = (int){42}; + +int test_main(void) { + return p[0]; +} diff --git a/test/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.errpat b/test/parse/cases_err/6_5_file_scope_compound_literal_scalar_no_addr.errpat @@ -0,0 +1 @@ +non-array compound literal needs '&'