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:
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