C-parser test corpus
Coverage matrix for test/parse/. Each cases/<name>.c is one row; the
behavioral oracle is test_main's return value mod 256, identical to
test/cg/. Group prefixes track C11 §6.x section numbers; the file
name itself is the case identifier.
This corpus extends test/cg/CORPUS.md upward: cg fixtures drive cg
directly with hand-built Operands and prove codegen primitives in
isolation; the parser cases prove the C front-end issues the right cg
sequence end-to-end. Anything visible at runtime that the parser is
expected to lower must have a parse-level row here.
Test paths per case (run.sh, sourced from test/cg/run.sh):
- D in-process JIT (aarch64 host only) —
parse-runner --jit. - R ELF roundtrip (host-arch agnostic) —
parse-runner --emit→kit-roundtrip→readelf+normalize.pydiff. - E exec via qemu/podman —
parse-runner --emit+start.o→link-exe-runner→ run. - J jit-via-file (aarch64 host only) —
parse-runner --emit→jit-runner.
W (DWARF directives) is reserved; once the parser drives Debug it
will read <name>.dwarf sidecars and reuse cg-check-dwarf.
Sidecars (each missing file uses the documented default):
<name>.expected— integer; default0. Compared mod 256 totest_main's return value.<name>.skip— single-line reason; the runner SKIPs (treated as failure unlessKIT_TEST_ALLOW_SKIP=1).cases_err/<name>.errpat— optional substring assertion against the parser's stderr. Negative cases without an errpat assert only that parse-runner exited nonzero.
Status legend
- ★ landed (case present, parses, exit code matches)
- RED checked-in conformance case that currently fails and should stay red until the implementation diagnoses or accepts it correctly
- · planned (case registered, expected value fixed, parser doesn't accept it yet)
- (deferred) — explicit non-goal for the current pass
Until the parser lands, every row that exercises a parser feature is
expected to FAIL — the build's parse_c stub panics on entry, so paths
D and --emit both report nonzero. The corpus is fixed in advance so
each parser-feature landing flips a known set of · rows to ★ with no
case authoring required mid-implementation.
Spine
Initial landing — proves the harness wiring, diagnostic flow, and
exit-code oracle end to end. Every spine row reduces to a single
int test_main(void) { return EXPR; } with no declarations beyond the
function definition itself.
| Case | Status | Body | Expected |
|---|---|---|---|
6_5_01_return_const |
★ | return 42; |
42 |
6_5_02_add |
★ | return 1 + 2; |
3 |
6_5_03_sub_mul |
★ | return 7 * 3 - 4; |
17 |
6_8_01_if_else |
★ | int x; if (1) x = 7; else x = 99; return x; |
7 |
6_8_02_while_sum |
★ | int s=0,i=0; while (i<10) { s+=i; i++; } return s; |
45 |
6_8_03_for_sum |
★ | int s=0; for (int i=1; i<=10; i++) s+=i; return s; |
55 |
Negative spine (one case per spec area; expands as the parser learns to diagnose more):
| Case | Status | Surface | Notes |
|---|---|---|---|
cases_err/6_5_undeclared |
· | identifier resolution | return q; — no such identifier |
§6.2 Concepts
Most of §6.2 is exercised implicitly by other rows (block scope by
6_8_12, internal/external linkage by 6_7_03/6_7_04, automatic
storage by every local). The cases here pin down behaviors with no
natural home elsewhere.
| Case | Status | Body | Expected |
|---|---|---|---|
6_2_1_01_param_shadow |
★ | helper int f(int x){{int x=42; return x;}}; return f(99); — block decl shadows function parameter |
42 |
6_2_1_02_label_in_nested_block |
★ | goto done; { done: r=42; } — label declared inside nested block has function scope |
42 |
6_2_2_01_extern_in_block_inherits_internal |
· | full TU: static int g=42; int test_main(void){extern int g; return g;} — extern redeclares to inherit internal linkage |
42 |
6_2_3_01_tag_ord_namespace |
★ | struct s { int v; }; int s = 42; struct s t = {0}; return s + t.v; |
42 |
6_2_3_01b_member_namespace_two_structs |
★ | struct A{int x;}; struct B{int x;}; ... return a.x+b.x; — same member name in distinct struct types |
42 |
6_2_3_02_label_namespace |
★ | int s = 0; goto s; s = 99; s: return 42; |
42 |
6_2_4_01_static_keeps_value |
★ | helper int next(){static int n=40; return ++n;}; next(); return next(); |
42 |
6_2_4_02_auto_reinit_each_iteration |
★ | for(int i=0;i<6;i++){int x=i; s+=x;} — local re-initialized each iteration; 0+1+...+5=15 |
15 |
6_2_4_03_static_local_zero_init |
★ | helper int f(){static int n; return ++n;}; f()+f() — static local zero-initialized |
3 |
6_2_5_01_void_func_no_value |
★ | helper void f(int *p){*p=42;} int x; f(&x); return x; |
42 |
6_2_5_01b_unsigned_wrap |
★ | unsigned char u=255; u++; return u; — modular wrap to 0 |
0 |
6_2_5_02_incomplete_array_completed |
★ | full TU: extern int a[]; int a[3]={0,0,42}; ...return a[2]; — incomplete array completed by later definition |
42 |
6_2_7_01_composite_array_size |
· | full TU: extern int a[]; int a[3]={40,0,0}; extern int a[3]; ...sizeof(a)/sizeof(a[0]) — composite type from compatible decls |
42 |
6_2_8_01_char_weakest_align |
★ | return (int)_Alignof(char); — char has alignment 1 |
1 |
§6.3 Conversions
Implicit and explicit conversions. 6_5_23_cast covers narrowing via
explicit cast; rows here fill in the rest of the conversion matrix.
| Case | Status | Body | Expected |
|---|---|---|---|
6_3_1_1_01_char_promotion |
★ | char c = 'A'; return c - '@' + 41; |
42 |
6_3_1_3_01_signed_to_unsigned |
★ | int n = -1; unsigned u = (unsigned)n; return (int)(u & 0xff); |
255 |
6_3_1_3_02_unsigned_narrow |
★ | unsigned u = 0x100002aU; int n = (int)u; return n; |
42 |
6_3_1_4_01_float_to_int |
★ | double d = 42.9; return (int)d; |
42 |
6_3_1_4_02_int_to_float |
★ | int n = 42; double d = n; return (int)d; |
42 |
6_3_1_8_01_usual_arith_mixed |
★ | int s = -1; unsigned u = 1; return (s + u) ? 0 : 42; |
42 |
6_3_2_1_01_array_to_ptr |
★ | int a[3] = {0,0,42}; int *p = a; return p[2]; |
42 |
6_3_2_1_02_func_to_ptr |
★ | helper id; int (*fp)(int) = id; return fp(42); |
42 |
6_3_2_2_01_void_cast_discard |
★ | (void)42; return 42; |
42 |
6_3_2_3_01_null_ptr_cmp |
★ | int *p = 0; return p ? 99 : 42; |
42 |
6_3_2_3_02_void_ptr_roundtrip |
★ | int x=42; void *v=&x; int *p=(int*)v; return *p; |
42 |
6_3_1_2_01_bool_from_ptr |
★ | _Bool b=(int*)&x ? 1 : 0; return b ? 42 : 0; — non-null pointer → _Bool 1 |
42 |
6_3_1_2_02_bool_from_float |
★ | _Bool b = 0.0; return b ? 99 : 42; — zero float → _Bool 0 |
42 |
6_3_1_3_03_uchar_wrap |
★ | int n = -1; unsigned char c = (unsigned char)n; return c; — modular reduction mod 256 |
255 |
6_3_1_8_02_signed_wins |
★ | long a=40; unsigned int b=2; return (int)(a+b); — signed long rank > unsigned int → result is long |
42 |
6_3_2_3_03_null_void_cast |
★ | int *p = (void*)0; return p ? 99 : 42; — (void*)0 is null pointer constant |
42 |
§6.4 Lexical Elements
| Case | Status | Body | Expected |
|---|---|---|---|
6_4_4_4_01_wide_char_ucn |
RED | L'\u00a3' == 163 ? 42 : 0 — universal character names in wide character constants |
42 |
6_4_4_4_02_wide_char_hex_escape |
RED | L'\x012a' == 298 ? 42 : 0 — wide character constants must not be byte-truncated |
42 |
6_4_5_03_wide_string_sizeof |
RED | sizeof(L"*") * 5 + 2 — wide string literal element type/width |
42 |
§6.5 Expressions
Drives the entire expression grammar. One row per production where the
behavior is observable through test_main. Spine rows above repeat
here for completeness once they're real cases.
| Case | Status | Body | Expected |
|---|---|---|---|
6_5_01_return_const |
★ | return 42; |
42 |
6_5_02_add |
★ | return 1 + 2; |
3 |
6_5_03_sub_mul |
★ | return 7 * 3 - 4; |
17 |
6_5_04_div_mod |
★ | return 23 / 4 + 23 % 4; |
8 |
6_5_05_bitwise_and |
★ | return (~3) & 0xff; |
252 |
6_5_06_bitwise_or_xor |
★ | return (0xa5 ^ 0x5a) & 0xff; |
255 |
6_5_07_shift |
★ | return (1<<5) \| (16>>1); |
40 |
6_5_08_unary_neg |
★ | return -7; |
249 |
6_5_09_logical_not |
★ | return !0 + !!5; |
2 |
6_5_10_cmp_eq |
★ | return (5 == 5) + (5 == 6); |
1 |
6_5_11_cmp_lt |
★ | return (-1 < 1); |
1 |
6_5_12_logical_and_skip |
★ | int s=0; (0) && (s=99); return s; |
0 |
6_5_13_logical_or_skip |
★ | int s=0; (1) \|\| (s=99); return s; |
0 |
6_5_14_ternary |
★ | return (5>3) ? 42 : 7; |
42 |
6_5_15_comma |
★ | int x; return (x=1, x=42, x); |
42 |
6_5_16_assign |
★ | int x; x = 42; return x; |
42 |
6_5_17_compound_assign |
★ | int x = 40; x += 2; return x; |
42 |
6_5_18_pre_inc |
★ | int x = 41; return ++x; |
42 |
6_5_19_post_inc |
★ | int x = 42; x++; return x; |
43; reads as 43 |
6_5_20_addr_deref |
★ | int x = 42; int *p = &x; return *p; |
42 |
6_5_21_sizeof_int |
★ | return (int)sizeof(int); |
4 |
6_5_22_sizeof_expr |
★ | int a[7]; return (int)(sizeof(a)/sizeof(int)); |
7 |
6_5_23_cast |
★ | return (int)(unsigned char)(-1); |
255 |
6_5_24_func_call |
★ | helper int id(int x){return x;} + return id(42); |
42 |
6_5_25_unary_plus |
★ | return +42; |
42 |
6_5_26_pre_dec |
★ | int x = 43; return --x; |
42 |
6_5_27_post_dec |
★ | int x = 43; x--; return x; |
42 |
6_5_28_arrow |
★ | struct S{int v;} s={42}; struct S *p=&s; return p->v; |
42 |
6_5_29_compound_literal |
★ | int *p = (int[]){10, 32}; return p[0]+p[1]; |
42 |
6_5_30_generic_selection |
★ | int x=42; return _Generic((x), int: x, default: 0); |
42 |
6_5_31_subscript_commute |
★ | int a[5]={0,0,42,0,0}; return 2[a]; |
42 |
6_5_32_string_subscript |
★ | return "*"[0]; |
42 |
6_5_33_regalloc_spill |
★ | 12-arg sum12(x1+0, ..., x12+0) — exceeds the 10-INT scratch pool, exercises spill_reg/reload_reg and the cg_call avs-in-flight fallback |
78 |
cg_postdec_while_count |
★ | while (n-- > 0) must test the old value after duplicating a register-backed local |
42 |
cg_x64_fp_format_fixed_digits |
★ | fixed decimal digit extraction from 12.375 with a helper call and output calls; repro for x64 caller-saved FP values and post-decrement rounding |
42 |
6_5_36_fp_arith |
★ | (a + b) / b * c - 36.0 over double — pins parser dispatch to BO_FADD/FSUB/FMUL/FDIV |
42 |
6_5_37_fp_int_promote |
★ | int + double — usual arithmetic conversion promotes the int side to double before BO_FADD |
42 |
6_5_38_fp_float_widen |
★ | float + double — float widens to double before BO_FADD |
42 |
6_5_39_float_arith |
★ | float * float stays at single precision (BO_FMUL with type=0) |
42 |
6_5_40_ptr_add |
★ | int *p=a; p=p+3; return *p; — ptr+int with stride scaling (4-byte element) |
42 |
6_5_41_ptr_sub_ptr |
★ | int *p=a+4; int *q=a+1; return (int)(p-q); — pointer subtraction yields ptrdiff |
3 |
6_5_42_ptr_arith_stride |
★ | double a[3]={...}; double *p=a+2; return (int)*p; — stride = sizeof(double) = 8 |
42 |
6_5_43_signed_rshift |
★ | int x=-256; (x>>4)+58 — arithmetic right-shift on signed value |
42 |
6_5_44_relational_all |
★ | (3>1)+(1<3)+(2<=2)+(2>=2)+(1!=2)+(2==2) — covers >, <=, >=, != |
6 |
6_5_45_ptr_eq_null |
★ | (p==0)+(q!=0)+(p!=q) — pointer equality with null and pointer-vs-pointer != |
3 |
6_5_46_ptr_relcmp |
★ | (p<q)+(q>p)+(p<=p) — relational comparison of pointers into same array |
3 |
6_5_46b_cmp_to_bool_init |
★ | _Bool b = (1 != 0); — comparison result is assignable through _Bool conversion |
42 |
6_5_47_ternary_arith_conv |
★ | int c=1; double r = c ? 1 : 2.5; return (int)(r+41.0); — ternary arms get usual arithmetic conversion to double |
42 |
6_5_48_ternary_ptr_null |
★ | int *p = 1 ? &x : 0; return *p; — one arm pointer, other null pointer constant |
42 |
6_5_49_compound_assign_sub |
★ | int x=44; x-=2; return x; — -= operator |
42 |
6_5_50_compound_assign_shift |
★ | int x=336; x>>=3; return x; — >>= operator (336>>3=42) |
42 |
6_5_51_compound_assign_bitwise |
★ | x=0xff; x&=0x7f; x^=0x55; x\|=0x00; — &=, ^=, \|= |
42 |
6_5_52_compound_assign_ptr |
★ | int *p=a; p+=4; return *p; — += with pointer LHS |
42 |
6_5_53_sizeof_vla_runtime |
★ | int n=7; int a[n]; return (int)sizeof(a); — sizeof on VLA evaluated at runtime |
28 |
6_5_54_sizeof_deref_ptr |
★ | double *p=&x; return (int)sizeof(*p); — sizeof on dereferenced pointer; operand not evaluated |
8 |
6_5_55_generic_default_branch |
★ | _Generic((double)x, int: 0, default: 42) — falls through to default |
42 |
6_5_56_compound_literal_struct |
★ | struct S s = (struct S){.a=20,.b=22}; return s.a+s.b; — struct compound literal with designated init |
42 |
6_5_57_unsigned_wrap_add |
★ | unsigned x=0xFFFFFFFFU; x+=1; return (int)(x & 0xff); — unsigned addition wraps modulo 2^32 |
0 |
6_5_58_large_integer_immediates |
★ | 64-bit boundary integer literals including INT64_MAX, top-bit unsigned, and all-ones materialize correctly |
42 |
6_5_71_fp_unary_neg_zero |
★ | -0.0f, -0.0, and unary - on float zero preserve the negative sign bit |
0 |
6_5_65_file_scope_compound_literal |
RED | static int *p = (int[]){42}; return p[0]; — file-scope compound literal has static storage duration |
42 |
6_5_2_5_01_compound_literal_flat_struct |
RED | (struct O){1,2,39} initializes nested struct members without inner braces |
42 |
6_5_2_5_02_compound_literal_designated_continue |
RED | (struct S){.a[1]=20,22,0} continues from the next subobject after a designator |
42 |
6_5_3_4_04_sizeof_vla_param_row |
★ | sizeof(a[0]) where a is an adjusted int a[n][m] parameter is evaluated at runtime |
42 |
6_5_6_01_ptr_diff_assign_to_long |
★ | long d = p - q; — pointer subtraction yields ptrdiff_t and is assignable to a wider integer without a cast |
42 |
§6.5.2.2 Aggregate function arguments
Aggregate-by-value argument passing. The classification boundary on all
three ABIs is 16 bytes: aggregates ≤16B go through ABI_ARG_DIRECT in 1
or 2 GPRs, larger ones through ABI_ARG_INDIRECT with a caller-side
copy (BYVAL). Each row exercises one cell of the (1-reg / 2-reg / copy)
× (homogeneous / mixed-field) matrix.
| Case | Status | Body | Expected |
|---|---|---|---|
6_5_2_2_01_struct_param_1reg |
★ | struct S{int a,b;}; int take(struct S s){return s.a+s.b;} — 8-byte struct, 1-part DIRECT |
42 |
6_5_2_2_02_struct_param_2reg |
★ | struct S{long a,b;}; long take(struct S s){return s.a+s.b;} — 16-byte struct, 2-part DIRECT |
42 |
6_5_2_2_03_struct_param_2reg_mixed |
★ | struct S{int a,b,c,d;}; — 16-byte struct of four ints; 2-part DIRECT with sub-8B chunking |
42 |
6_5_2_2_04_struct_param_large |
★ | struct S{int a[8];}; — 32-byte struct, INDIRECT/BYVAL caller copy |
42 |
6_5_2_2_05_struct_param_with_scalars |
★ | int take(int pre, struct S s, int post) — 2-reg struct between scalar args; arg-cursor accounting |
42 |
§6.6 Constant expressions
| Case | Status | Body | Expected |
|---|---|---|---|
6_6_01_enum_const |
★ | enum { K = 42 }; return K; |
42 |
6_6_02_const_expr_init |
★ | int x = 1+2*3; return x; |
7 |
6_6_03_array_size_const |
★ | int a[3+4] = {0}; return (int)sizeof a / (int)sizeof a[0]; |
7 |
6_6_04_alignof_array_size |
★ | int a[_Alignof(long long)]; return (int)sizeof(a)/sizeof(a[0]); — _Alignof in array-size constant |
8 |
6_6_05_addr_const_static_init |
★ | full TU: static int g=7; static int *p=&g; ...return *p*6; — address constant in static initializer |
42 |
6_6_06_addr_const_arith_init |
★ | full TU: static int arr[4]={0,0,0,42}; static int *p=arr+3; ...return *p; — address constant + ICE in static initializer |
42 |
6_6_07_enum_array_bound |
★ | file scope: typedef enum {A,B,C,N} E; static const int marks[N]={10,12,20}; — enum constant as array bound |
42 |
6_6_08_func_addr_static_init |
★ | static int helper(int x){return x;} + static const FN g = helper; — function designator as static-init address constant (no &) |
42 |
6_6_09_func_addr_array_static |
★ | static const FN ops[2] = {add1, dbl}; — array of function-pointer static-init constants |
42 |
6_6_10_logical_cond_const |
★ | logical && / || and ?: in integer constant expressions |
42 |
§6.7 Declarations
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_01_typedef |
★ | typedef int I; I x = 42; return x; |
42 |
6_7_02_static_local |
★ | static int s = 42; return s; |
42 |
6_7_03_static_global |
★ | static int g = 42; int test_main(void){return g;} |
42 |
6_7_04_extern_resolved |
★ | extern int g; int g = 42; return g; |
42 |
6_7_05_const_qualifier |
★ | const int c = 42; return c; |
42 |
6_7_06_struct_basic |
★ | struct S { int a, b; } s = {10, 32}; return s.a + s.b; |
42 |
6_7_07_union_basic |
★ | union U { int i; char c[4]; } u; u.i = 42; return u.i; |
42 |
6_7_08_enum_basic |
★ | enum E { A = 40, B }; return B + 1; |
42 |
6_7_09_alignof |
★ | return (int)_Alignof(double); |
8 |
6_5_3_4_01_gnu_alignof_alias |
★ | return (int)__alignof__(double) * 5 + 2; — GNU __alignof__ is recognized as an alias for _Alignof |
42 |
§6.7.1 Storage-class specifiers
static/extern/typedef are exercised by 6_7_01–6_7_04; rows here
cover register and other specifier interactions.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_1_01_register_sizeof |
★ | register int x=42; return (int)sizeof(x)>0?x:0; — sizeof is legal on a register variable |
42 |
6_7_1_02_register_multi_decl |
★ | register int x=40, y=2; return x+y; — multi-declarator with register |
42 |
6_7_1_03_thread_local_basic |
★ | _Thread_local int x=42; return x; — _Thread_local accepted as a storage-class specifier on a file-scope object |
42 |
6_7_file_scope_register |
★ | register int x; return sizeof(x)==sizeof(int)?42:1; — GNU-compatible file-scope register declaration accepted |
42 |
§6.7.2 Type specifiers
Each integer/floating type the runtime can return through test_main.
Conversion behavior between types lives in §6.3; rows here only check
that the type round-trips through a declaration and back to int.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_2_01_short |
★ | short x = 42; return x; |
42 |
6_7_2_02_long |
★ | long x = 42L; return (int)x; |
42 |
6_7_2_03_long_long |
★ | long long x = 42LL; return (int)x; |
42 |
6_7_2_04_unsigned |
★ | unsigned x = 42U; return (int)x; |
42 |
6_7_2_01b_unsigned_long_long |
★ | unsigned long long x = 42ULL; return (int)x; — unsigned long long multiset |
42 |
6_7_2_05_signed_char |
★ | signed char c = 42; return c; |
42 |
6_7_2_06_unsigned_char |
★ | unsigned char c = 200; return c; |
200 |
6_7_2_07_unsigned_short |
★ | unsigned short s = 42; return s; |
42 |
6_7_2_08_unsigned_long |
★ | unsigned long x = 42UL; return (int)x; |
42 |
6_7_2_09_bool |
★ | _Bool b = 5; return b ? 42 : 0; |
42 |
6_7_2_10_float |
★ | float f = 42.0f; return (int)f; |
42 |
6_7_2_11_double |
★ | double d = 42.5; return (int)d; |
42 |
6_7_2_12_long_double |
· | long double d = 42.0L; return (int)d; |
42 |
6_7_2_13_complex |
(deferred) | _Complex is optional in C11 |
— |
§6.7.2.1 Structure and union details
Edge cases beyond the basic struct/union rows — bitfields, anonymous members, self-reference through pointers, and forward declarations.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_2_1_01_bitfield |
★ | struct {unsigned a:5, b:3;} s={2,5}; return s.b*8 + s.a; |
42 |
6_7_2_1_02_anon_struct |
★ | struct S{int x; struct{int y;};} s={0,42}; return s.y; |
42 |
6_7_2_1_03_anon_union |
★ | struct S{int x; union{int a,b;};} s; s.x=0; s.a=42; return s.b; |
42 |
6_7_2_1_04_self_ref |
★ | struct N{int v; struct N *next;}; struct N b={42,0}, a={0,&b}; return a.next->v; |
42 |
6_7_2_1_05_forward_tag |
★ | struct S; struct S *p; struct S{int v;}; struct S s={42}; p=&s; return p->v; |
42 |
6_7_2_1_06_flex_array |
(deferred) | flexible array members need allocator support | — |
6_7_2_1_07_signed_bitfield |
★ | struct {signed int s:8;} b={-1}; return (b.s<0)?42:0; — signed bitfield sign extension |
42 |
6_7_2_1_08_zero_width_bitfield |
★ | struct {unsigned a:4; unsigned:0; unsigned b:4;} — zero-width bitfield forces next field into new storage unit |
42 |
6_7_2_1_09_bool_bitfield |
★ | struct {_Bool b:1;} s; s.b=1; return s.b?42:0; — _Bool bitfield |
42 |
6_7_2_1_10_static_bitfield_pack |
★ | static struct {unsigned a:5; unsigned b:3;} g={2,5}; return g.b*8+g.a; — static packed bit-field initializer |
42 |
§6.7.2.2 Enumeration specifiers
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_2_2_01_enum_restart |
★ | enum C{X=20, Y, Z=20, W}; return Y+W; — auto-increment restarts after explicit =; duplicate values allowed (Y=21, W=21) |
42 |
§6.7.2.3 Tags
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_2_3_01_tag_inner_scope |
★ | outer struct S{int v;}; { struct S{int v;}; struct S s={42}; ...} — inner-scope tag shadows outer; distinct types |
42 |
§6.7.3 Type qualifiers
const is covered by 6_7_05_const_qualifier; rows here cover the
remaining qualifier forms and pointer-qualifier interactions.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_3_01_volatile |
★ | volatile int x = 42; return x; |
42 |
6_7_3_02_restrict_param |
★ | helper int rd(int *restrict p){return *p;} + caller |
42 |
6_7_3_03_const_pointer |
★ | int x=42; int *const p=&x; return *p; |
42 |
6_7_3_04_ptr_to_const |
★ | const int x=42; const int *p=&x; return *p; |
42 |
6_7_3_05_atomic |
★ | _Atomic int x = 42; return x; |
42 |
6_7_3_06_repeated_const |
★ | const const int x = 42; return x; — repeated qualifier is idempotent |
42 |
6_7_3_07_const_array_typedef |
★ | typedef int A[3]; const A a={10,20,12}; return a[0]+a[1]+a[2]; — const outside typedef makes elements const |
42 |
§6.7.4 Function specifiers
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_4_01_inline |
★ | static inline int id(int x){return x;} + return id(42); |
42 |
6_7_4_02_noreturn |
★ | full TU: _Noreturn void die(void){for(;;);} int test_main(void){return 42;} (declared, not called) |
42 |
6_7_4_03_extern_inline |
★ | static inline int add1(int x){return x+1;} return add1(41); — inline definition (note: clang extern inline requires non-static external def; case uses static inline form to avoid ODR hazard) |
42 |
6_7_4_04_repeated_inline |
★ | static inline inline int id(int x){return x;} — repeated function specifier is idempotent |
42 |
§6.7.5 Alignment specifier
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_5_01_alignas_obj |
★ | _Alignas(16) static char buf[16]; return (((unsigned long)buf)&15) ? 0 : 42; |
42 |
6_7_5_02_alignas_type |
★ | _Alignas(double) static char buf[8]; return (int)_Alignof(double) * 5 + 2; |
42 |
6_7_5_03_alignas_zero |
· | _Alignas(0) static int x = 42; — _Alignas(0) has no effect; object gets natural alignment |
42 |
6_7_5_04_alignas_multi |
★ | _Alignas(16) _Alignas(8) static char buf[16]; — strictest _Alignas wins |
42 |
§6.7.6 Declarators
Pointer/array/function declarator combinations beyond the basic forms already exercised in §6.5 and §6.7.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_6_01_ptr_to_ptr |
★ | int x=42; int *p=&x; int **pp=&p; return **pp; |
42 |
6_7_6_02_array_2d |
★ | int a[2][3]={{0,0,0},{0,0,42}}; return a[1][2]; |
42 |
6_7_6_03_array_of_ptr |
★ | int x=42; int *a[2]={0,&x}; return *a[1]; |
42 |
6_7_6_04_funcptr_decl |
★ | int id(int x){return x;} int (*fp)(int)=id; return fp(42); |
42 |
6_7_6_05_funcptr_returning_ptr |
★ | helper returns int*; int *(*fp)(int*)=...; return *fp(&x); |
42 |
6_7_6_06_array_static_n |
★ | helper int rd(int p[static 3]){return p[2];}; int a[3]={0,0,42}; return rd(a); |
42 |
6_7_6_07_vla_local |
★ | int n=7; int a[n]; for(int i=0;i<n;i++) a[i]=i*7; return a[n-1]; |
42 |
6_7_6_08_variadic_decl |
★ | helper int sum(int n, ...) summing two ints; sum(2, 20, 22) |
42 |
6_7_6_09_ptr_to_array |
★ | int b[3]={0,0,42}; int (*pa)[3]=&b; return (*pa)[2]; — pointer-to-array declarator |
42 |
6_7_6_10_array_of_funcptr |
★ | int (*ops[2])(int)={add1,sub1}; return ops[0](ops[1](42)); — block-scope array of function pointers |
42 |
6_7_6_11_func_returning_funcptr |
★ | typedef int (*FP)(int); FP getfp(void){return id;} return getfp()(42); — function returning function pointer |
42 |
6_7_6_12_vla_param |
★ | int sum_vla(int n, int a[n]){...} — VLA dimension from earlier param; param adjusted to pointer |
42 |
6_7_6_13_star_in_proto |
★ | int total(int n, int a[*]); int total(int n, int a[n]){...} — [*] in non-definition prototype |
42 |
6_7_6_14_func_param_adjust |
★ | int apply(int f(int), int x){return f(x);} — function parameter adjusted to pointer-to-function |
42 |
6_7_6_15_multidim_vla_local |
RED | int a[n][m]; a[n-1][m-1]=42; return a[5][6]; — multiple VLA dimensions in one declarator |
42 |
6_7_6_16_vla_param_2d |
★ | int a[n][m] parameter passed a 2D array; runtime stride must use m |
42 |
6_7_6_17_vla_param_3d |
★ | int a[n][m][k] parameter passed a 3D array; nested runtime strides must compose |
42 |
6_7_6_18_file_scope_array_bound_paren |
★ | static int marks[(2+5)] = {...}; — parenthesized integer constant expression in a file-scope array bound |
42 |
6_7_6_19_paren_declarator_name |
★ | int (helper)(int x){...} and (helper)(42) — the C grammar lists '(' declarator ')' as a direct-declarator; lua / glibc headers wrap public names in parens to defeat macro expansion |
42 |
6_7_6_20_func_returning_funcptr_no_typedef |
★ | int (*pick(int x))(void){...} — function declarator with an inline function-pointer return type (the classic signal() shape, used by sqlite VFS xDlSym). 6_7_6_11 covers the typedef'd form; this row pins the inline declarator |
42 |
§6.7.7 Type names
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_7_01_abstract_ptr_array_cast |
★ | ((int(*)[3])v)[0][2] — abstract declarator int(*)[3] in cast |
42 |
§6.7.8 Type definitions
6_7_01_typedef covers the simplest case (typedef int I); rows here
cover compound typedef targets.
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_8_01_typedef_struct |
★ | typedef struct{int v;} S; S s={42}; return s.v; |
42 |
6_7_8_02_typedef_funcptr |
★ | typedef int (*FP)(int); int id(int x){return x;} FP f=id; return f(42); |
42 |
6_7_8_03_typedef_array |
★ | typedef int A[3]; A a={0,0,42}; return a[2]; |
42 |
6_7_8_04_typedef_qualified |
★ | typedef const int CI; CI x = 42; return x; |
42 |
6_7_8_05_typedef_vla_size_fixed |
· | int f(int n){typedef int B[n]; n+=10; B a; ...} — VLA typedef captures size at definition |
36 |
6_7_8_06_typedef_multi_decl |
★ | typedef int TWICE, (*PFUNC)(int); — multiple declarators in one typedef |
42 |
§6.7.9 Initialization
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_9_01_scalar_init |
★ | int x = 42; return x; |
42 |
6_7_9_02_array_brace |
★ | int a[3] = {10, 20, 12}; return a[0]+a[1]+a[2]; |
42 |
6_7_9_03_partial_zero |
★ | int a[5] = {42}; return a[0] + a[4]; |
42 |
6_7_9_04_designated |
★ | int a[5] = {[2] = 42}; return a[2]; |
42 |
6_7_9_05_struct_init |
★ | struct S {int a,b;} s={40,2}; return s.a+s.b; |
42 |
6_7_9_06_string_init |
★ | char s[] = "hi"; return s[0]+s[1]+s[2]; |
'h'+'i' |
6_7_9_07_designated_struct |
★ | struct S{int a,b,c;} s={.b=42}; return s.b; |
42 |
6_7_9_08_nested_designated |
★ | int a[2][3] = {[1][2] = 42}; return a[1][2]; |
42 |
6_7_9_09_struct_in_array |
★ | struct P{int x,y;} a[2] = {{0,0},{0,42}}; return a[1].y; |
42 |
6_7_9_10_zero_init_static |
★ | full TU: static int g[3]; int test_main(void){return g[0]+g[1]+g[2]+42;} |
42 |
6_7_9_11_array_size_from_init |
★ | int x[] = {10, 12, 20}; return x[0]+x[1]+x[2]; — array of unknown size; size from init list |
42 |
6_7_9_12_designator_override |
★ | int a[3] = {[1]=99, [1]=42, [0]=0}; — later designator overrides earlier |
42 |
6_7_9_13_string_init_fixed_larger |
★ | char s[6] = "hi"; — char array larger than string literal; excess elements zero-filled (sum = 'h'+'i'+0+0+0+0) |
209 |
6_7_9_14_struct_copy_init |
★ | struct S src={20,22}; struct S dst=src; return dst.a+dst.b; — struct init from compatible struct expression |
42 |
6_7_9_15_union_designated_nonfirst |
★ | union U{int a; int b;} u={.b=42}; return u.b; — designated init of non-first union member |
42 |
6_7_9_16_enum_designator |
★ | enum {X=2}; int a[4]={[X]=42}; return a[X]; — enum constant as array designator |
42 |
6_7_9_17_inconsistent_bracket_init |
★ | struct T{int a[2];int b;} w[2]={{1},2}; — flat init consumed into subaggregate without inner braces |
3 |
6_7_9_18_static_init_string_ptr |
★ | static const S g = { .s = "hi" }; — string literal as address constant in pointer-slot static init |
209 |
6_7_9_19_static_init_string_array |
★ | static const char* const names[2] = {"a","b"}; — array-of-pointer static init with string literals |
42 |
6_7_9_20_array_of_struct_with_array_field |
★ | static const S t[] = { {10u,{1,2}}, {15u,{3,11}} }; — file-scope incomplete array of struct with trailing fixed-size array field |
42 |
6_7_9_21_array_of_struct_size_from_init |
★ | static const S t[] = { {10,12}, {7,13} }; — file-scope incomplete-array-of-struct sized from init list |
44 |
6_7_9_22_static_union_designated_nonfirst |
★ | static union U{int a; int b;} g={.b=42}; return g.b; — static-storage union designated init |
42 |
6_7_9_23_static_ptr_null_const_expr |
★ | static int* p = 1 - 1; return p == 0 ? 42 : 0; — null pointer constant via integer constant expression |
42 |
6_7_9_24_flat_array_init |
RED | int a[2][2] = {1,2,3,36}; — braces may be elided for nested array initialization |
42 |
6_7_9_25_flat_struct_init |
RED | struct O o = {1,2,39}; — braces may be elided for nested struct initialization |
42 |
6_7_9_26_designated_continue_subobject |
RED | struct S s = {.a[1]=20,22,0}; — initializer continues after the designated subobject |
42 |
6_7_9_27_static_flat_array_init |
RED | file-scope static int a[2][2] = {1,2,3,36}; |
42 |
6_7_9_28_static_flat_struct_init |
RED | file-scope static struct O o = {1,2,39}; |
42 |
6_7_9_29_unknown_bound_nested_init |
RED | int a[][2] = {1,2,3,36}; — unknown outer bound is completed from a flat nested initializer |
42 |
6_7_9_30_static_init_neg_float |
★ | static const double tab[2] = { -1.0, 43.0 }; — static initializer of arithmetic type permits unary - on a floating constant (§6.6 arithmetic constant expression) |
42 |
§6.7.10 Static assertions
| Case | Status | Body | Expected |
|---|---|---|---|
6_7_10_01_static_assert_pass |
★ | _Static_assert(sizeof(int) >= 2, "wide int"); return 42; |
42 |
6_7_10_02_static_assert_const |
★ | _Static_assert(1+1 == 2, "math"); return 42; |
42 |
6_7_10_03_static_assert_file_scope |
★ | full TU: _Static_assert(sizeof(long)>=4,"long"); at file scope |
42 |
§6.8 Statements
| Case | Status | Body | Expected |
|---|---|---|---|
6_8_01_if_else |
★ | int x; if (1) x=7; else x=99; return x; |
7 |
6_8_02_while_sum |
★ | sum 0..9 with while |
45 |
6_8_03_for_sum |
★ | sum 1..10 with for |
55 |
6_8_04_do_while |
★ | int i=0; do { i=42; } while (0); return i; |
42 |
6_8_05_break |
★ | for (i=0;;i++) if (i==42) break; return i; |
42 |
6_8_06_continue |
★ | sum of evens in [0,20) via continue |
90 |
6_8_07_switch_case |
★ | three-arm switch returns 42 on case 2 | 42 |
6_8_08_switch_fallthrough |
★ | case 1: r+=10; case 2: r+=20; on input 1 |
30 |
6_8_09_switch_default |
★ | unmatched switch hits default |
7 |
6_8_10_goto_forward |
★ | goto L; r=99; L: return 42; |
42 |
6_8_11_goto_backward |
★ | counter loop built with goto |
10 |
6_8_12_block_scope |
★ | inner { int x=42; } shadows outer |
42 |
6_8_13_compound_decl_mix |
★ | declarations interleaved with statements (C99) | 42 |
6_8_14_return_void |
★ | void f(void){return;}; f(); return 42; |
42 |
6_8_15_null_statement |
★ | for (int i=0;i<42;i++) ; return i; |
42 |
6_8_16_dangling_else |
★ | if (1) if (0) r=1; else r=42; — else binds to inner if |
42 |
6_8_17_switch_char_ctrl |
★ | switch on char c=2; matches case 2 |
42 |
6_8_18_switch_no_match_no_default |
★ | switch(99) with no matching case and no default; r unchanged |
7 |
6_8_19_switch_nested_dup_case |
★ | nested switch with case 1/case 2 in inner — inner case 2 wins |
42 |
6_8_20_switch_hidden_scope |
★ | int x=99; initializer jumped over by switch; case 1: r=42 still reached |
42 |
6_8_21_for_infinite_break |
★ | for(;;){ i++; if(i==42) break; } — infinite loop terminated by break |
42 |
6_8_23_continue_do_while |
★ | continue in do..while restarts the loop; sum of odd i in [1,10] = 1+3+5+7+9 |
25 |
6_8_24_break_switch_in_loop |
★ | break inside switch inside for-loop exits switch, not loop; loop reaches case 3 |
3 |
6_8_25_continue_inside_switch |
★ | continue inside switch's case 0: continues the enclosing for-loop; s=1+3=4 |
4 |
6_8_26_goto_into_nested_block |
★ | goto inner; where label is inside a nested block |
42 |
6_8_27_label_on_null_stmt |
★ | end: ; — label applied to a null statement |
42 |
6_8_28_return_narrow_convert |
★ | unsigned char narrow(int x){return x;} — 298 & 0xff = 42; narrowing on return |
42 |
GNU labels as values (computed goto)
| name | tier | description | exit |
|---|---|---|---|
gnu_labels_as_values_threaded |
★ | direct-threaded bytecode interpreter: function-local static void *const tab[] = {&&op,...} + goto *tab[*pc++]; (3+4)*5 |
35 |
gnu_label_addr_basic |
★ | void *p = &&done; goto *p; — take a label address and branch to it |
7 |
gnu_label_addr_runtime_table |
★ | automatic void *tab[] = {&&even, &&odd}; goto *tab[n&1]; (runtime array of label addresses) |
20 |
gnu_label_addr_mixed_goto |
★ | mixes named goto with computed goto * to address-taken labels |
11 |
gnu_label_addr_compare |
★ | label addresses are comparable: if (next == &&op_halt) where op_halt is also a computed-goto target |
7 |
Negative cases (cases_err/): gnu_label_addr_file_scope (&& outside a function),
gnu_computed_goto_no_targets (goto *p with no address-taken label),
gnu_computed_goto_non_pointer (goto * on a non-pointer), gnu_label_addr_after_computed_goto
(taking a label address after the first computed goto), gnu_label_addr_undefined (&& of an
undefined label).
§6.8.6.4 Aggregate return values
Aggregate-by-value return. Mirrors §6.5.2.2: ≤16B uses ABI_ARG_DIRECT
in 1 or 2 return registers; larger uses ABI_ARG_INDIRECT with the
caller passing a hidden destination pointer (sret) that the callee
memcpys into before ret.
| Case | Status | Body | Expected |
|---|---|---|---|
6_8_6_4_01_struct_return_1reg |
★ | struct S{int a,b;}; struct S mk(void){...} — 8-byte struct returned in one reg |
42 |
6_8_6_4_02_struct_return_2reg |
★ | struct S{long a,b;}; struct S mk(void){...} — 16-byte struct returned across two regs |
42 |
6_8_6_4_03_struct_return_large |
★ | struct S{int a[8];}; struct S mk(void){...} — 32-byte struct returned via sret pointer |
42 |
6_8_6_4_04_struct_return_call_chain |
★ | take(mk()) — 2-reg return immediately fed as 2-reg byval arg with no named local |
42 |
§6.9 External definitions
| Case | Status | Body | Expected |
|---|---|---|---|
6_9_01_two_functions |
★ | helper + caller in one TU | 42 |
6_9_02_recursive_function |
★ | factorial(5) |
120 |
6_9_03_tentative_def |
★ | file-scope int g; (tentative) + use |
0 |
6_9_04_static_func |
★ | static int helper(...) + caller |
42 |
6_9_05_proto_then_def |
★ | forward declaration before body | 42 |
6_9_06_variadic_func |
★ | sum(int n, ...) over va_arg; sum(2,20,22) (paired with builtin_03) |
42 |
6_9_07_global_const |
★ | full TU: const int g = 42; int test_main(void){return g;} |
42 |
6_9_08_global_struct_init |
★ | full TU: struct S{int v;} g={42}; int test_main(void){return g.v;} |
42 |
6_9_09_static_data_array |
★ | full TU: static int g[3] = {0, 0, 42}; int test_main(void){return g[2];} |
42 |
6_9_10_kr_function_def |
(deferred) | K&R-style definitions are C90 carryover; revisit if needed | — |
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_kr_function_def_params |
RED | old-style function definition with declaration-list int add(a,b) int a; int b; |
42 |
6_9_15_kr_function_def_promoted_char |
RED | old-style definition with promoted char parameter declaration |
42 |
6_9_16_block_scope_func_decl |
★ | block-scope int helper(void); has external linkage and calls the later file-scope definition |
42 |
§6.10 Preprocessing directives
Most preprocessor coverage lives under test/pp/; rows here only exist
when a directive interacts with the parse-runner's end-to-end pipeline
in a way test/pp/ cannot catch on its own.
| Case | Status | Body | Expected |
|---|---|---|---|
6_10_warning_directive |
★ | #warning "..." followed by a valid TU — non-fatal diagnostic, parsing continues |
42 |
Builtins
The freestanding runtime advertises a handful of __builtin_* entries
(see doc/builtins.md). Cases here verify the parser routes them
through cg's intrinsic / asm machinery rather than treating them as
ordinary calls.
| Case | Status | Body | Expected |
|---|---|---|---|
builtin_01_alloca |
★ | int *p = (int *)__builtin_alloca(4); *p=42; return *p; |
42 |
builtin_02_expect |
★ | if (__builtin_expect(1, 1)) return 42; return 0; |
42 |
builtin_03_va_list |
★ | uses __builtin_va_start/__builtin_va_arg/__builtin_va_end summing three ints |
42 |
builtin_04_offsetof |
★ | struct S {int a, b;}; return (int)__builtin_offsetof(struct S, b) * 10 + 2; |
42 |
builtin_05_va_copy |
★ | walks varargs twice via __builtin_va_copy |
42 |
builtin_06_atomic_load |
★ | __atomic_load_n(&x, __ATOMIC_RELAXED) — RELAXED-ordered load via LDUR |
42 |
builtin_07_atomic_fetch_add |
★ | __atomic_fetch_add(&x, 2, __ATOMIC_RELAXED) — LL/SC RMW loop |
42 |
builtin_08_atomic_store_n |
★ | __atomic_store_n(&x, 42, __ATOMIC_RELEASE) — RELEASE store via STLR |
42 |
builtin_09_atomic_exchange_n |
★ | __atomic_exchange_n(&x, 99, __ATOMIC_SEQ_CST) — RMW XCHG, returns prior |
42 |
builtin_10_atomic_fetch_sub |
★ | __atomic_fetch_sub with ACQ_REL — LDAXR/STLXR loop |
42 |
builtin_11_atomic_fetch_and |
★ | __atomic_fetch_and with RELAXED — RMW AND combine |
42 |
builtin_12_atomic_fetch_or |
★ | __atomic_fetch_or with ACQUIRE — LDAXR/STXR loop |
42 |
builtin_13_atomic_fetch_xor |
★ | __atomic_fetch_xor with SEQ_CST — RMW EOR combine |
42 |
builtin_14_atomic_long |
★ | 8-byte atomic on long — sf=1 path through ldxr/stxr |
42 |
builtin_15_atomic_pointer |
★ | atomic load of a pointer-typed variable; result deref'd through array | 42 |
builtin_16_atomic_thread_fence |
★ | __atomic_thread_fence(__ATOMIC_SEQ_CST) — emits DMB ISH |
42 |
builtin_17_atomic_cas_success |
★ | __atomic_compare_exchange_n matching path: stores desired, returns 1 |
42 |
builtin_18_atomic_cas_failure |
★ | CAS mismatch: writes prior to *expected, returns 0 | 42 |
builtin_19_atomic_cas_loop |
★ | lock-free increment via CAS retry loop (ACQ_REL/ACQUIRE pair) | 42 |
builtin_20_ctz |
★ | __builtin_ctz(1u<<5) + 37 — count trailing zeros, low-bit case |
42 |
builtin_21_ctz_high |
★ | __builtin_ctz(0x80000000u) - 31 + 42 — high-bit case (31 trailing zeros) |
42 |
builtin_22_ctz_long_widths |
★ | __builtin_ctzl + __builtin_ctzll; operand type selects intrinsic width |
42 |
builtin_23_atomic_long_literal_convert |
★ | store/RMW integer literals converted to unsigned long atomic object type | 42 |
builtin_24_atomic_lock_free |
★ | target-aware lock-free folding through if, &&, and ||; dead 16-byte atomic arms suppress codegen |
42 |
builtin_25_atomic_fetch_nand |
★ | __atomic_fetch_nand lowers to atomic NAND RMW |
42 |
builtin_26_sadd_overflow |
★ | signed/unsigned typed overflow builtins store result and return overflow flag | 42 |
Variadic coverage
Extra rows pinning down the per-class routing on AAPCS64 — the GP and
FP save areas are independent and each va_arg walks its class's
cursor, so mixed and class-only sequences both need direct exercise.
| Case | Status | Body | Expected |
|---|---|---|---|
variadic_01_zero_args |
★ | sum(0) — no ... args; tests that va_start on an empty trailing list still produces a usable cursor |
42 |
variadic_02_many_ints |
★ | 12 variadic ints — exhausts the GP save area (x1..x7) and forces the va_arg stack-overflow path | 42 |
variadic_03_long |
★ | va_arg(ap, long) — 8-byte int via the GP save area |
42 |
variadic_04_pointer |
★ | passes int* through ... and reads them back via va_arg(ap, int*) |
42 |
variadic_05_double |
★ | three doubles through ... — exercises the FP save area v0..v7 and 16-byte stride |
42 |
variadic_06_mixed |
★ | interleaved int/double ...; per-class cursors run independently |
42 |
variadic_07_nested_call |
★ | va_copy to a separate cursor that's passed by va_list* to a helper, then the original cursor walked again |
42 |
Negative cases (cases_err/)
| Case | Status | Surface | Notes |
|---|---|---|---|
6_5_undeclared |
· | identifier resolution | return q; |
6_5_addr_of_bitfield |
RED | lvalue / bit-field | address of a bit-field must be rejected; currently accepted |
6_5_cast_scalar_from_struct |
RED | cast constraints | casting a struct expression to int must be rejected; currently accepted |
6_5_cond_incompatible_ptr |
RED | conditional operator | int * vs double * arms are incompatible; currently accepted |
6_5_lvalue_required |
· | assignment LHS | 1 = 2; |
6_5_lvalue_array_assign |
★ | assignment LHS | assigning to an array object |
6_5_pointer_add_pointer |
RED | pointer arithmetic | p + q for two pointers must be rejected; currently accepted |
6_5_rel_incompatible_ptr |
RED | pointer comparison | relational compare of incompatible pointer types; currently accepted |
6_5_scalar_required_if |
RED | scalar expression | struct expression used as if condition; currently accepted |
6_5_sizeof_bitfield |
RED | sizeof | sizeof cannot be applied to a bit-field; currently accepted |
6_5_sizeof_function |
★ | sizeof | sizeof cannot be applied to a function designator |
6_5_type_mismatch |
· | implicit conversion | assigning int* to int |
6_5_address_of_register |
RED | register storage | taking the address of a register object must be rejected; currently accepted |
6_5_void_pointer_arith |
RED | pointer arithmetic | arithmetic on void * is not C11; currently accepted |
6_6_array_bound_float |
RED | integer constant expr | floating array bound must be rejected; currently accepted |
6_6_static_init_nonconstant |
★ | static initializer | file-scope static initializer from non-constant object |
6_7_redefinition |
· | linkage / scope | two int x = … at file scope |
6_8_break_outside_loop |
· | break/continue scope | break; outside iteration |
6_9_redefinition_function |
· | external definition | two definitions of f |
6_5_member_not_in_struct |
· | member access | s.zzz for unknown field |
6_5_call_non_function |
· | call expression | int x; x(); |
6_5_arrow_on_non_pointer |
· | member access | struct S s; s->v; |
6_5_sizeof_incomplete |
· | sizeof | struct S; return sizeof(struct S); |
6_7_2_storage_class_combo |
· | declaration | static extern int x; |
6_7_2_tag_wrong_kind |
★ | tag | redeclaring a struct tag as a union in the same scope |
6_7_2_1_bitfield_bad_type |
RED | bitfield | float bit-field accepted pending extended-type policy |
6_7_2_1_bitfield_named_zero_width |
★ | bitfield | named zero-width bit-field |
6_7_2_1_bitfield_negative_width |
★ | bitfield | negative bit-field width |
6_7_2_1_bitfield_nonconstant_width |
★ | bitfield | bit-field width that is not an integer constant expression |
6_7_2_two_struct_defs |
· | tag | two struct S { ... }; definitions in same scope |
6_7_2_1_bitfield_too_wide |
· | bitfield | unsigned a:33; exceeds underlying type |
6_7_2_1_duplicate_member |
RED | struct member | duplicate member name in one struct; currently accepted |
6_7_2_1_flex_array_not_last |
RED | flexible array | flexible array member not last; currently accepted |
6_7_2_1_flex_array_only_member |
RED | flexible array | flexible array member in otherwise empty struct; currently accepted |
6_7_2_1_member_static |
RED | struct member specs | storage-class specifier in struct member declaration; currently accepted |
6_7_2_1_member_extern |
RED | struct member specs | storage-class specifier in struct member declaration; currently accepted |
6_7_2_1_member_typedef |
RED | struct member specs | typedef in struct member declaration; currently accepted |
6_7_2_1_member_thread_local |
RED | struct member specs | _Thread_local in struct member declaration; currently accepted |
6_7_2_1_member_inline |
RED | struct member specs | inline in struct member declaration; currently accepted |
6_7_2_1_member_noreturn |
RED | struct member specs | _Noreturn in struct member declaration; currently accepted |
6_7_2_4_atomic_qualified_type |
RED | _Atomic type specifier |
_Atomic(const int) violates C11 constraints; currently accepted |
6_7_2_4_atomic_array_type |
RED | _Atomic type specifier |
_Atomic(int[2]) violates C11 constraints; currently accepted |
6_7_2_4_atomic_atomic_type |
RED | _Atomic type specifier |
nested atomic type violates C11 constraints; currently accepted |
6_7_2_void_object |
RED | object type | object declared with type void; currently accepted |
6_7_3_const_assign |
· | const violation | const int x = 0; x = 1; |
6_7_3_restrict_object |
RED | qualifier constraints | restrict used on a non-pointer object; currently accepted |
6_7_4_inline_object |
RED | function specifier | inline used on an object declaration; currently accepted |
6_7_4_noreturn_object |
RED | function specifier | _Noreturn used on an object declaration; currently accepted |
6_7_5_alignas_weaker_than_natural |
RED | alignment specifier | nonzero _Alignas weaker than natural alignment; currently accepted |
6_7_5_alignas_non_power_of_two |
RED | alignment specifier | invalid _Alignas(3); currently accepted |
6_7_5_alignas_bitfield |
RED | alignment specifier | _Alignas applied to a bit-field; currently accepted |
6_7_5_alignas_typedef |
RED | alignment specifier | _Alignas applied to a typedef declaration; currently accepted |
6_7_5_alignas_function |
RED | alignment specifier | _Alignas applied to a function definition; currently accepted |
6_7_6_param_auto |
RED | parameter declaration | non-register storage-class specifier on parameter; currently accepted |
6_7_6_param_extern |
RED | parameter declaration | non-register storage-class specifier on parameter; currently accepted |
6_7_6_param_typedef |
RED | parameter declaration | typedef storage-class specifier on parameter; currently accepted |
6_7_6_param_thread_local |
RED | parameter declaration | _Thread_local storage-class specifier on parameter; currently accepted |
6_7_6_static_param_scalar |
RED | parameter declaration | static on scalar parameter; currently accepted |
6_7_6_function_returning_array |
★ | function declarator | function returning array |
6_7_6_function_returning_function |
★ | function declarator | function returning function |
6_7_6_variadic_not_last |
★ | function declarator | variadic marker not in final position |
6_7_file_scope_auto |
RED | storage class | auto at file scope; currently accepted |
6_7_storage_class_static_thread_local_function |
RED | storage class | _Thread_local on a function definition; currently accepted |
6_7_thread_local_block_auto |
RED | storage class | block-scope _Thread_local without static/extern; currently accepted |
6_7_thread_local_function |
RED | storage class | _Thread_local on a function definition; currently accepted |
6_7_thread_local_typedef |
RED | storage class | _Thread_local in a typedef declaration; currently accepted |
6_7_type_spec_bool_int |
RED | declaration specifiers | invalid _Bool int specifier combination; currently accepted |
6_7_type_spec_char_int |
RED | declaration specifiers | invalid char int specifier combination; currently accepted |
6_7_type_spec_float_double |
RED | declaration specifiers | invalid float double specifier combination; currently accepted |
6_7_type_spec_long_float |
RED | declaration specifiers | invalid long float specifier combination; currently accepted |
6_7_type_spec_short_char |
RED | declaration specifiers | invalid short char specifier combination; currently accepted |
6_7_type_spec_signed_double |
RED | declaration specifiers | invalid signed double specifier combination; currently accepted |
6_7_type_spec_too_many_longs |
RED | declaration specifiers | invalid long long long specifier combination; currently accepted |
6_7_type_spec_unsigned_double |
RED | declaration specifiers | invalid unsigned double specifier combination; currently accepted |
6_7_9_excess_scalar_init |
★ | initializer | too many initializers for scalar object |
6_7_9_invalid_array_designator |
★ | initializer | array designator index that is not an integer constant expression |
6_7_9_invalid_struct_designator |
★ | initializer | designator names no member of the target struct |
6_7_9_invalid_union_designator |
★ | initializer | designator names no member of the target union |
6_7_10_static_assert_fail |
★ | static assertion | _Static_assert(0, "fail"); |
6_8_case_outside_switch |
· | switch scope | case 1: outside any switch |
6_8_continue_outside_loop |
· | iteration scope | continue; outside iteration |
6_8_default_outside_switch |
· | switch scope | default: outside switch |
6_8_duplicate_case |
· | switch | two case 1: in same switch |
6_8_duplicate_default |
· | switch | two default: labels in same switch |
6_8_goto_undefined_label |
· | goto | goto missing; with no matching label |
6_8_goto_into_vla_scope |
RED | goto | goto into scope of a variably modified object; currently accepted |
6_8_switch_float |
RED | switch | floating controlling expression in switch; currently accepted |
6_8_duplicate_label |
· | label | two L: in the same function |
6_9_void_param_with_other |
· | function declarator | int f(void, int); |
Multi-TU (deferred)
Multi-TU cases live under cases/<name>/{a.c,b.c} (test/link convention)
and exercise inter-TU resolution. Deferred until the single-TU corpus is
green; the harness already builds an ObjBuilder* per TU, so wiring is
mainly extending run.sh to compile each file in a case directory and
hand both objects to link_add_obj.
Non-goals
- Snapshot/golden assembly. Behavioral exit codes only, matching
test/cg. Encoding lock-ins land surgically when a specific instruction-selection guarantee matters. - Diagnostic golden output.
cases_err/only asserts nonzero exit plus optional substring pattern. Full diagnostic snapshot tests are a separate effort. - Cross-arch. AArch64 only; the harness selects target via
target_aarch64_linuxinparse_runner.c. Future x86_64 / RISC-V passes duplicate the runner with the target swapped.