From 3e71e980c611ac9f00565564bd1e647194f74321 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:07:12 +0330 Subject: closures: allow 24 parameters, like functions (was 19) --- tests/langerrors/closure_params_25.zc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 tests/langerrors/closure_params_25.zc (limited to 'tests/langerrors') diff --git a/tests/langerrors/closure_params_25.zc b/tests/langerrors/closure_params_25.zc new file mode 100644 index 0000000..0444007 --- /dev/null +++ b/tests/langerrors/closure_params_25.zc @@ -0,0 +1,3 @@ +// expect: too many parameters +include rt; +fn main() { let f = fn(int a1,int a2,int a3,int a4,int a5,int a6,int a7,int a8,int a9,int a10,int a11,int a12,int a13,int a14,int a15,int a16,int a17,int a18,int a19,int a20,int a21,int a22,int a23,int a24, int a25) { return 0; }; return 0; } -- cgit v1.2.3 From a752292b54e22a8024b9d9162762edd2efa533b5 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:10:42 +0330 Subject: fndef: a second definition of a function in the same module is 'is defined twice' (appendix b.2.3) --- src/compiler/decl.zc | 4 ++++ tests/conformance/known.txt | 1 - tests/langerrors/fn_defined_twice.zc | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/langerrors/fn_defined_twice.zc (limited to 'tests/langerrors') diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc index 0870756..6794373 100644 --- a/src/compiler/decl.zc +++ b/src/compiler/decl.zc @@ -285,6 +285,10 @@ int fndef(int chk, int rty, int ret, int n) { if (rty || ntp) typed = 1; if (!dnm) dnm = n; s = lookup(n); + if (s >= ubase && skind[s] == K_FN && (sflag[s] & F_DEF) && !(sflag[s] & F_TPL) && !ginst && !ntp) { // appendix b.2.3: the same name in the same module + word qn = n; if (module_name) qn = module_symbol(n); + if (rt.eq_w(sname[s], qn)) serrn(n, "is defined twice"); + } if (s < 0 || s < ubase || skind[s] != K_FN || (sflag[s] & F_DEF)) { s = addsym(n, K_FN, 0); sflag[s] = 0; diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt index 13ef43c..ff67f6b 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -5,7 +5,6 @@ 5-declarations/enum_member_names_earlier_b2.zc zy a appendix b.2.2 confirmed: enum members can't name earlier members 5-declarations/fn_prototype_after_definition_b4.zc zy a appendix b.2.4 confirmed: a prototype after the definition hides it 5-declarations/fn_prototype_unnamed_params_b13.zc zy a appendix b.2.13 confirmed (message now: doesn't match its earlier declaration) -5-declarations/fn_redefined_b3.zc zy a appendix b.2.3 confirmed: a plain redefinition silently shadows the first 5-declarations/global_float_init_b7.zc zy a appendix b.2.7 confirmed: float global initializer rejected 5-declarations/include_in_function_b9.zc zy a appendix b.2.9 confirmed: include in a body gives "return outside a function" 9-appendix-b/b2_05_ternary_int_float.zc zy a appendix b.2.5 confirmed diff --git a/tests/langerrors/fn_defined_twice.zc b/tests/langerrors/fn_defined_twice.zc new file mode 100644 index 0000000..7af57e8 --- /dev/null +++ b/tests/langerrors/fn_defined_twice.zc @@ -0,0 +1,4 @@ +// expect: f: is defined twice +int f() { return 1; } +int f() { return 2; } +fn main() { return f(); } -- cgit v1.2.3 From 19cdaa91b74da17a78809433ff7e6a2c084d8385 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:11:59 +0330 Subject: fndef: a prototype after a definition in the same module keeps the definition (appendix b.2.4) --- src/compiler/decl.zc | 9 +++++---- tests/conformance/known.txt | 1 - tests/langerrors/proto_after_def_mismatch.zc | 4 ++++ 3 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 tests/langerrors/proto_after_def_mismatch.zc (limited to 'tests/langerrors') diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc index 6794373..67aceb1 100644 --- a/src/compiler/decl.zc +++ b/src/compiler/decl.zc @@ -280,16 +280,17 @@ int body() { // into stype, checked against any earlier prototype or prescan result, and // where the o3 region for an o3 function is handed to the core) int fndef(int chk, int rty, int ret, int n) { - int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline; + int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline, redef; o3nxt = 0; if (rty || ntp) typed = 1; if (!dnm) dnm = n; s = lookup(n); - if (s >= ubase && skind[s] == K_FN && (sflag[s] & F_DEF) && !(sflag[s] & F_TPL) && !ginst && !ntp) { // appendix b.2.3: the same name in the same module + redef = 0; // a function this module already defined: a prototype after it keeps it (b.2.4), a second body is defined twice (b.2.3) + if (s >= ubase && skind[s] == K_FN && (sflag[s] & F_DEF) && !(sflag[s] & F_TPL) && !ginst && !ntp) { word qn = n; if (module_name) qn = module_symbol(n); - if (rt.eq_w(sname[s], qn)) serrn(n, "is defined twice"); + redef = rt.eq_w(sname[s], qn); } - if (s < 0 || s < ubase || skind[s] != K_FN || (sflag[s] & F_DEF)) { + if (!redef && (s < 0 || s < ubase || skind[s] != K_FN || (sflag[s] & F_DEF))) { s = addsym(n, K_FN, 0); sflag[s] = 0; } diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt index ff67f6b..7b2082c 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -3,7 +3,6 @@ # appendix b.2.8 (a global named in an initializer is its address) is documented behavior per 5.3.2 and 3.14.2: no entry 4-statements/o3_outside_function_ordinary_block.zc zy c top-level o3 { } is rejected; spec 4.10.2 says it is an ordinary block 5-declarations/enum_member_names_earlier_b2.zc zy a appendix b.2.2 confirmed: enum members can't name earlier members -5-declarations/fn_prototype_after_definition_b4.zc zy a appendix b.2.4 confirmed: a prototype after the definition hides it 5-declarations/fn_prototype_unnamed_params_b13.zc zy a appendix b.2.13 confirmed (message now: doesn't match its earlier declaration) 5-declarations/global_float_init_b7.zc zy a appendix b.2.7 confirmed: float global initializer rejected 5-declarations/include_in_function_b9.zc zy a appendix b.2.9 confirmed: include in a body gives "return outside a function" diff --git a/tests/langerrors/proto_after_def_mismatch.zc b/tests/langerrors/proto_after_def_mismatch.zc new file mode 100644 index 0000000..94a04e6 --- /dev/null +++ b/tests/langerrors/proto_after_def_mismatch.zc @@ -0,0 +1,4 @@ +// expect: f: doesn't match its earlier declaration +int f(int a) { return a; } +int f(int a, int b); +fn main() { return f(1); } -- cgit v1.2.3 From d93000c4b5ff7b3dda0e59a4d333b0463e745e04 Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:14:02 +0330 Subject: include: written inside a function body is 'include is top level only' (appendix b.2.9) --- src/compiler/builtins.zc | 1 + tests/conformance/5-declarations/include_in_function_b9.zc | 2 +- tests/conformance/known.txt | 1 - tests/langerrors/include_in_function.zc | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 tests/langerrors/include_in_function.zc (limited to 'tests/langerrors') diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc index d04c444..d6a58fb 100644 --- a/src/compiler/builtins.zc +++ b/src/compiler/builtins.zc @@ -312,6 +312,7 @@ int inc_compile(char* buf, char* name, char*.d dir) { int kw_include() { int pp, sv; char* path; char* buf; stmtonly(); + if (infn) { die("include is top level only"); return 0; } // appendix b.2.9 next(); if (tk == T_ID) { while (1) { diff --git a/tests/conformance/5-declarations/include_in_function_b9.zc b/tests/conformance/5-declarations/include_in_function_b9.zc index cccaea5..64f170c 100644 --- a/tests/conformance/5-declarations/include_in_function_b9.zc +++ b/tests/conformance/5-declarations/include_in_function_b9.zc @@ -1,4 +1,4 @@ -// expect error: include +// expect error: include is top level only // spec 5.12.7 and appendix b.2.9: expected an error saying include is top level only include rt; void pn(int x) { rt.put_n(x); rt.put_c(10); } diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt index 044b862..8415b18 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -4,7 +4,6 @@ 4-statements/o3_outside_function_ordinary_block.zc zy c top-level o3 { } is rejected; spec 4.10.2 says it is an ordinary block 5-declarations/enum_member_names_earlier_b2.zc zy a appendix b.2.2 confirmed: enum members can't name earlier members 5-declarations/fn_prototype_unnamed_params_b13.zc zy c spec 5.2.1 says prototype parameter names are required, and a type name alone is read as an untyped parameter of that name (paramstart); b.2.13 is a spec choice, not fixed -5-declarations/include_in_function_b9.zc zy a appendix b.2.9 confirmed: include in a body gives "return outside a function" 9-appendix-b/b2_05_ternary_int_float.zc zy a appendix b.2.5 confirmed 9-appendix-b/b2_06_bool_normalises.zc zy a appendix b.2.6 confirmed 9-appendix-b/b2_10_recovery_hides_errors.zc zy c appendix b.2.10 confirmed; by design per 8.2 diff --git a/tests/langerrors/include_in_function.zc b/tests/langerrors/include_in_function.zc new file mode 100644 index 0000000..06136f9 --- /dev/null +++ b/tests/langerrors/include_in_function.zc @@ -0,0 +1,2 @@ +// expect: include is top level only +fn main() { include std; return 0; } -- cgit v1.2.3 From ccbc77c2d3fa348d0de6f32fc540468401e6880b Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:50:41 +0330 Subject: lexer: a block comment that is never closed is 'unterminated comment' (appendix b.2.11) --- docs/SPEC.md | 4 ++-- src/compiler/lex.zc | 2 ++ tests/conformance/1-source/comment_block_unclosed.zc | 3 ++- tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc | 2 +- tests/conformance/known.txt | 1 - tests/langerrors/unterminated_comment_docs.zc | 4 ++++ 6 files changed, 11 insertions(+), 5 deletions(-) create mode 100644 tests/langerrors/unterminated_comment_docs.zc (limited to 'tests/langerrors') diff --git a/docs/SPEC.md b/docs/SPEC.md index 529b5bf..cc94451 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -24,7 +24,7 @@ this is the reference for the zc language. it is written from `src/compiler/comp 1.2.1 `//` starts a comment that runs to the end of the line. -1.2.2 `/* ... */` is a block comment. block comments do not nest. a block comment that is never closed runs to the end of the unit and is not an error. +1.2.2 `/* ... */` is a block comment. block comments do not nest. a block comment that is never closed is error: unterminated comment. 1.2.3 comments are not tokens, but `docs on;` (5.14) and `hints` (4.12) read them: `//` lines directly above a declaration document it, and `//:` lines are implementation notes that document nothing. an inline block comment right before a numeric literal marks the literal as intentional for the magic-number hint. neither changes the generated code. @@ -1114,7 +1114,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the 8. not a bug: a global initializer that names another global uses the other global's address (5.3.2, 3.14.2): `int a = 5; int b = a + 1;` gives `b` the value `&a + 1`. 9. fixed (5.12.7): `include std;` inside a function body gave `return outside a function`; it is now error: include is top level only. 10. a syntax error hides errors in the statements skipped by recovery: `int a = ; int b = 3 +;` reports only the first error (8.2). by design, but easy to miss. -11. an unterminated `/* ...` comment is accepted silently (1.2.2); an unterminated string literal is only reported as a later syntax error. +11. fixed (1.2.2): an unterminated `/* ...` comment was accepted silently; it is error: unterminated comment. (an unterminated string literal is still only reported as a later syntax error.) 12. `x as int * y` parses `int*` as the type (3.2.3). 13. prototypes need parameter names: `int f(int);` => `expected a name, found ')'`. 14. `len(s)` on a `char*` returns word 0 of the string when `typecheck` is off. diff --git a/src/compiler/lex.zc b/src/compiler/lex.zc index d06b81b..2763333 100644 --- a/src/compiler/lex.zc +++ b/src/compiler/lex.zc @@ -428,6 +428,7 @@ int docblock(int nl) { doc_char(c); if (c == 10) bol = 1; } + if (ch < 0) { tline = line; serr("unterminated comment"); } while (dn && (dbuf[dn - 1] == 32 || dbuf[dn - 1] == 9 || dbuf[dn - 1] == 10 || dbuf[dn - 1] == 13)) dn--; doc_char(10); dlast = cl; docpending = 1; if (adj) dn = 0; @@ -489,6 +490,7 @@ int lex1() { if (docs_on) { docblock(nl); tglue = 0; continue; } nextch(); while (ch >= 0) { if (ch == '*') { nextch(); if (ch == '/') break; } else nextch(); } + if (ch < 0) { tline = line; serr("unterminated comment"); } // a /* with no */ (spec 1.2.2) nextch(); tglue = 0; continue; } tline = line; toff = cpos() - 1; tbuf[0] = '/'; oplex(1); return 0; diff --git a/tests/conformance/1-source/comment_block_unclosed.zc b/tests/conformance/1-source/comment_block_unclosed.zc index 4ae34e7..cb410f9 100644 --- a/tests/conformance/1-source/comment_block_unclosed.zc +++ b/tests/conformance/1-source/comment_block_unclosed.zc @@ -1,4 +1,5 @@ -// expect: 4/ +// expect error: unterminated comment +// spec 1.2.2: a block comment that is never closed is an error include rt; fn main() { rt.put_n(4); rt.put_c(10); return 0; } /* never closed: rt.put_n(9); diff --git a/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc b/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc index e6e6bbf..ce4b236 100644 --- a/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc +++ b/tests/conformance/9-appendix-b/b2_11_unterminated_comment.zc @@ -1,4 +1,4 @@ -// expect error: unterminated +// expect error: unterminated comment // spec appendix b.2.11: an unterminated /* is accepted silently include rt; void pn(int x) { rt.put_n(x); rt.put_c(10); } diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt index 8550c07..f666106 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -4,7 +4,6 @@ 4-statements/o3_outside_function_ordinary_block.zc zy c top-level o3 { } is rejected; spec 4.10.2 says it is an ordinary block 5-declarations/fn_prototype_unnamed_params_b13.zc zy c spec 5.2.1 says prototype parameter names are required, and a type name alone is read as an untyped parameter of that name (paramstart); b.2.13 is a spec choice, not fixed 9-appendix-b/b2_10_recovery_hides_errors.zc zy c appendix b.2.10 confirmed; by design per 8.2 -9-appendix-b/b2_11_unterminated_comment.zc zy c appendix b.2.11 confirmed, but spec 1.2.2 says an unclosed block comment is not an error 9-appendix-b/b2_12_as_int_star.zc zy c appendix b.2.12 confirmed, but spec 3.2.3 documents it (parenthesise) 9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc zy c appendix b.2.14 confirmed, but spec 3.13.5 leaves it unspecified 9-appendix-b/b2_15_duplicate_case.zc zy c appendix b.2.15 confirmed; 4.7.2 says duplicates are allowed diff --git a/tests/langerrors/unterminated_comment_docs.zc b/tests/langerrors/unterminated_comment_docs.zc new file mode 100644 index 0000000..02f4335 --- /dev/null +++ b/tests/langerrors/unterminated_comment_docs.zc @@ -0,0 +1,4 @@ +// expect: unterminated comment +docs on; +fn main() { return 0; } +/* never closed, with docs on -- cgit v1.2.3 From 77d2f8a44e2503796a7ef5c170e11811a4f7fcfd Mon Sep 17 00:00:00 2001 From: zinc Date: Wed, 14 Oct 2026 16:58:59 +0330 Subject: prototypes: parameters may be unnamed, int f(int, int*); (appendix b.2.13) --- docs/SPEC.md | 4 ++-- src/compiler/decl.zc | 13 +++++++++++-- .../5-declarations/fn_prototype_unnamed_pointer_params.zc | 8 ++++++++ tests/conformance/known.txt | 1 - tests/langerrors/param_unnamed_with_body.zc | 3 +++ 5 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc create mode 100644 tests/langerrors/param_unnamed_with_body.zc (limited to 'tests/langerrors') diff --git a/docs/SPEC.md b/docs/SPEC.md index 30d547d..128f961 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -683,7 +683,7 @@ node*.u make() { ... } // owned result (.u) fn f(a, b) { ... } // untyped; types are inferred fn f(int a, b) { ... } // parameters may mix T first(T* p) { ... } // generic -int proto(int n); // prototype (parameter names are required) +int proto(int n); // prototype (int proto(int); also works: a prototype's parameter names are optional) ``` a bare `name(params) { ... }` with no `fn` and no type is not a function declaration (error: expected a declaration). @@ -1116,7 +1116,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the 10. a syntax error hides errors in the statements skipped by recovery: `int a = ; int b = 3 +;` reports only the first error (8.2). by design, but easy to miss. 11. fixed (1.2.2): an unterminated `/* ...` comment was accepted silently; it is error: unterminated comment. (an unterminated string literal is still only reported as a later syntax error.) 12. settled (3.2.3): `x as int * y` parses `int*` as the type. this is the rule (the type is read greedily, as zc0 does too), so the program is a syntax error. -13. prototypes need parameter names: `int f(int);` => `expected a name, found ')'`. +13. fixed (5.2.1): a prototype's parameters may be unnamed (`int f(int, int*);`). a lone type name counts as a type only in a prototype; with a body it is still the parameter's name, and an unnamed typed parameter there is `a parameter needs a name`. 14. `len(s)` on a `char*` returns word 0 of the string when `typecheck` is off. 15. duplicate `case` labels are not diagnosed (4.7.2). 16. a local `const` cannot be used in a constant expression (b.1.7). diff --git a/src/compiler/decl.zc b/src/compiler/decl.zc index e9500c4..87281ad 100644 --- a/src/compiler/decl.zc +++ b/src/compiler/decl.zc @@ -282,7 +282,7 @@ int body() { // into stype, checked against any earlier prototype or prescan result, and // where the o3 region for an o3 function is handed to the core) int fndef(int chk, int rty, int ret, int n) { - int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline, redef; + int s, np = 0, tags = 0, t, sig, i; char*[24] pn; word[24] pt; word[24] pty; int typed = 0, ft, explicit_rty = !!rty, o3f = o3nxt, lo, hi, pk, lt, lend, lfl = tline, redef, amb = 0, nonm = 0; o3nxt = 0; if (rty || ntp) typed = 1; if (!dnm) dnm = n; @@ -327,7 +327,9 @@ int fndef(int chk, int rty, int ret, int n) { } else if (tv == s_d) t = 2; else die("a parameter tag is .m or .d"); next(); } - pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff); pn[np] = name(); + pnoffs[np] = toff; pnplaces[np] = tpack(); rs_note(RS_PARAM, toff); + if (!pk && !t && tk == T_ID && istypename(tv)) amb = amb | (1 << np); // int f(int): a name, or a type if this is a prototype + if (pk && tk == T_OP && (tv == s_comma || tv == s_rp)) { pn[np] = 0; nonm = 1; } else pn[np] = name(); // int f(int*, int): a prototype's parameters may be unnamed if (o3f && pty[np] == tword) serr("o3 parameters need a type"); if (np >= 12 && t) die("only the first 12 parameters can be tagged"); pt[np] = t; @@ -338,6 +340,13 @@ int fndef(int chk, int rty, int ret, int n) { } } expect(s_rp); + if (is_op(s_semi)) { // a prototype: a lone type name is an unnamed parameter of that type (b.2.13) + i = 0; + while (i < np) { + if (((amb >> i) & 1) && pn[i]) { t = lookup(pn[i]); if (t >= 0 && skind[t] == K_TYPE) { pty[i] = sval[t]; typed = 1; } } + i++; + } + } else if (nonm) serr("a parameter needs a name"); sig = ret + np + np + tags * 64; if ((sflag[s] & F_SIG) && !(sflag[s] & F_PRE)) { if (ssig[s] != sig) serrn(n, "doesn't match its earlier declaration"); diff --git a/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc b/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc new file mode 100644 index 0000000..7136bee --- /dev/null +++ b/tests/conformance/5-declarations/fn_prototype_unnamed_pointer_params.zc @@ -0,0 +1,8 @@ +// expect: 7/ +// spec 5.2.1: a prototype's parameters may be unnamed, pointers included +include rt; +void pn(int x) { rt.put_n(x); rt.put_c(10); } +int f(int, int*); +fn main() { int[1] a; a[0] = 5; pn(f(2, a)); return 0; } +int f(int k, int* p) { return k + p[0]; } +// zc0: skip diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt index 7cb703e..2fbd331 100644 --- a/tests/conformance/known.txt +++ b/tests/conformance/known.txt @@ -2,7 +2,6 @@ # class a: self-hosted compiler bug; b: zc0 deviation (appendix a/b); c: spec issue to settle # appendix b.2.8 (a global named in an initializer is its address) is documented behavior per 5.3.2 and 3.14.2: no entry 4-statements/o3_outside_function_ordinary_block.zc zy c top-level o3 { } is rejected; spec 4.10.2 says it is an ordinary block -5-declarations/fn_prototype_unnamed_params_b13.zc zy c spec 5.2.1 says prototype parameter names are required, and a type name alone is read as an untyped parameter of that name (paramstart); b.2.13 is a spec choice, not fixed 9-appendix-b/b2_10_recovery_hides_errors.zc zy c appendix b.2.10 confirmed; by design per 8.2 9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc zy c appendix b.2.14 confirmed, but spec 3.13.5 leaves it unspecified 9-appendix-b/b2_15_duplicate_case.zc zy c appendix b.2.15 confirmed; 4.7.2 says duplicates are allowed diff --git a/tests/langerrors/param_unnamed_with_body.zc b/tests/langerrors/param_unnamed_with_body.zc new file mode 100644 index 0000000..bf96698 --- /dev/null +++ b/tests/langerrors/param_unnamed_with_body.zc @@ -0,0 +1,3 @@ +// expect: a parameter needs a name +int f(int*) { return 1; } +fn main() { return 0; } -- cgit v1.2.3