kit

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

commit ca43ec6ce767098be6c91b8579236b798676fe62
parent 1addbca7986f2322973a21d5708520dc6f284f67
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Fri, 12 Jun 2026 09:50:03 -0700

fix(c): diagnose non-constant file-scope array bounds (no VLA at file scope)

A VLA is block-scope-only (§6.7.6.2¶4), so a file-scope array bound must be an
integer constant expression. The parser routed a non-constant-looking file-scope
bound into the block-scope VLA codegen path, which assumes an active function
frame (pcg_local/alloca/branch): with none it silently miscompiled a bare
identifier bound and hung outright on a bound whose first token isn't the value
(e.g. `buf[n ? 8 : 1]`). Force all file-scope bounds through eval_const_int so a
non-constant bound becomes a clean 'non-constant ... in constant expression'
diagnostic.

Diffstat:
Mlang/c/parse/parse_type.c | 12+++++++++---
Atest/parse/cases_err/6_7_6_2_vla_file_scope.c | 13+++++++++++++
Atest/parse/cases_err/6_7_6_2_vla_file_scope.errpat | 1+
3 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/lang/c/parse/parse_type.c b/lang/c/parse/parse_type.c @@ -1418,9 +1418,15 @@ int parse_decl_suffix(Parser* p, DeclSuffix* out) { } { Tok t = p->cur; - int is_const_start = (t.kind == TOK_NUM || t.kind == TOK_CHR); - if (p->cur_func_name == 0 && t.kind == TOK_PUNCT && t.v.punct == '(') - is_const_start = 1; + /* A VLA is a block-scope-only feature (§6.7.6.2¶4): at file scope every + * declared array bound must be an integer constant expression. Route all + * file-scope bounds through eval_const_int below, so a non-constant bound + * becomes a clean "non-constant ... in constant expression" diagnostic + * instead of entering the VLA codegen path — which assumes an active + * function frame (pcg_local/alloca/branch) and, with none at file scope, + * silently miscompiles or hangs. */ + int is_const_start = + p->cur_func_name == 0 || t.kind == TOK_NUM || t.kind == TOK_CHR; if (t.kind == TOK_FLT) { perr(p, "array bound requires integer type"); } diff --git a/test/parse/cases_err/6_7_6_2_vla_file_scope.c b/test/parse/cases_err/6_7_6_2_vla_file_scope.c @@ -0,0 +1,13 @@ +/* §6.7.6.2¶4: a variable-length array is a block-scope-only feature. A + * file-scope array bound must therefore be an integer constant expression; + * a non-constant bound is a constraint violation. + * + * Regression: the parser used to route a non-constant-looking file-scope + * bound into the block-scope VLA codegen path, which assumes an active + * function frame. With none, it silently miscompiled a bare identifier bound + * and — for a bound whose first token is not the value (here the `?:`) — hung + * the parser outright. It must now diagnose the non-constant bound. */ +static int n; +char buf[n ? 8 : 1]; + +int test_main(void) { return 0; } diff --git a/test/parse/cases_err/6_7_6_2_vla_file_scope.errpat b/test/parse/cases_err/6_7_6_2_vla_file_scope.errpat @@ -0,0 +1 @@ +non-constant identifier in constant expression