aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar zinc <zinc@downsta.ir> 2026-10-14 17:00:26 +0330
committerGravatar zinc <zinc@downsta.ir> 2026-10-14 17:00:26 +0330
commit6ef2efb750622819a3ba3ae9ee061e512c1266d6 (patch)
tree2c99f8f8691780bf6c57cccf405115f7b84ba0d1
parentprototypes: parameters may be unnamed, int f(int, int*); (appendix b.2.13) (diff)
len: len on a char* is an error with typecheck off too (appendix b.2.14)
-rw-r--r--docs/SPEC.md4
-rw-r--r--src/compiler/builtins.zc3
-rw-r--r--tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc4
-rw-r--r--tests/conformance/known.txt1
4 files changed, 6 insertions, 6 deletions
diff --git a/docs/SPEC.md b/docs/SPEC.md
index 128f961..dd04cde 100644
--- a/docs/SPEC.md
+++ b/docs/SPEC.md
@@ -490,7 +490,7 @@ pn(pop(a)); pn(a.pop()); pn(a.len()); // 4 3 2
a[2]; // zy: index 2 out of range (length 2)
```
-3.13.5 the length of a non-array (`len("text")` on a `char*`) is unspecified when `typecheck` is off (it reads word 0) and error: len needs an array under `typecheck on;`. use `rt.len_w` for word strings and `len` for `bstr`.
+3.13.5 `len` on a `char*` is error: len needs an array, not a char* when `typecheck` is off, and error: len needs an array under `typecheck on;`. use `rt.len_w` for word strings and `len` for `bstr`.
### 3.14 constant expressions
@@ -1117,7 +1117,7 @@ each item gives a minimal program, the expected behavior (per this spec) and the
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. 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.
+14. fixed (3.13.5): `len(s)` on a `char*` used to return word 0 of the string when `typecheck` was off; it is now a compile error.
15. duplicate `case` labels are not diagnosed (4.7.2).
16. a local `const` cannot be used in a constant expression (b.1.7).
17. fixed: a bad float or character literal in a function's first statement was not reported (1.4).
diff --git a/src/compiler/builtins.zc b/src/compiler/builtins.zc
index 6dc586a..cbc380e 100644
--- a/src/compiler/builtins.zc
+++ b/src/compiler/builtins.zc
@@ -706,7 +706,8 @@ int array_len(word t) {
return 0;
}
if (t[0] == TY_ARR) { op(O_DROP); lit(t[3]); }
- else { tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); }
+ else { if (!tc_on && t[0] == TY_PTR && t[4][0] == TY_CHAR) serr("len needs an array, not a char* (use rt.len_w, or a bstr)"); // b.2.14: it would read word 0
+ tcneed(t[0] == TY_DYN || t == tword, "len needs an array", t); if (argloc >= 0) { op(O_DROP); vaddr(o3cache[argloc] + 1); op(O_LD); } else if (o3on && t[0] == TY_DYN) op(O_LD); else callname(s_dlen); }
xty = tint;
xlenloc = -1; xstamp = 0;
if (a >= 0 && t[0] == TY_DYN && t[3]) xlenloc = a; // the whole expression is len of a fixed array
diff --git a/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc b/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
index b0d0d45..0953328 100644
--- a/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
+++ b/tests/conformance/9-appendix-b/b2_14_len_char_ptr_typecheck_off.zc
@@ -1,5 +1,5 @@
-// expect: 3/
-// spec appendix b.2.14: len(char*) with typecheck off returns word 0
+// expect error: len needs an array, not a char*
+// spec 3.13.5 and appendix b.2.14: len on a char* is an error with typecheck off too
include rt;
void pn(int x) { rt.put_n(x); rt.put_c(10); }
typecheck off;
diff --git a/tests/conformance/known.txt b/tests/conformance/known.txt
index 2fbd331..8e6ea97 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
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
9-appendix-b/b2_16_local_const_in_const_expr.zc zy c appendix b.2.16 confirmed; 3.14.2 documents it
1-source/ident_tags_as_variables_glued_star.zc zc0 b u*d with visible u and d is read as a recast (no code); zy follows 1.6.3