wcc/check: #14 reject def-global scalar str index (silent segfault) (both stages)
def S:str = "hi"; S[0] silently segfaulted: a def is a compile-time constant, never materialized as DATA (unlike let), so indexing it emitted an unbacked main.S(SB) reference -> cstage ran into frame garbage, wwstage link-failed. str[i] itself is valid ww (a deliberate Go-like str[i]->u8 byte-index that lib/strings compare/dup depend on), so the fix is narrow: the N_INDEX TY_STR arm now rejects an index whose operand is a bare SK_DEF scalar-str symbol, both stages -- 'cannot index a def-constant str; bind it to a let'. INDEX-ONLY: len(S) and &S are already loud, and a def's .len/.ptr field reads (the load-bearing w6l INTERP) are N_DOT, a different arm, and stay valid. A rule-9 WHY-comment records str[i]->u8 as a sanctioned divergence from Hare's strings.toutf8. The full make-it-work fold (len(S)->2, S[0]->byte) is deferred (#16). byte-id 990-997 8/8. test/wcc/821 table-driven.
This commit is contained in:
@@ -1437,8 +1437,33 @@ cexpr(Checker *c, Node *n)
|
||||
type_name(c->a, u->sub));
|
||||
return n->type = u->sub;
|
||||
}
|
||||
if (u && u->kind == TY_STR)
|
||||
if (u && u->kind == TY_STR) {
|
||||
/* rule-9 divergence-doc (drew .ai/drew-14-ruling.md):
|
||||
* `str[i] -> u8` is a deliberate Go-like direct
|
||||
* byte-index, a SANCTIONED ww divergence from Hare's
|
||||
* `strings::toutf8(s)[i]` (the Hare reference checker
|
||||
* rejects str-index, harec check.c:362). lib/strings
|
||||
* is load-bearing on it (compare/dup/join). */
|
||||
/* #14: a `def` scalar str is an inline compile-time
|
||||
* CONSTANT (def-as-constant; not storage-backed like a
|
||||
* `let`), so it has no address to index — cgen would
|
||||
* load a frame-garbage base and segfault. Only the bare
|
||||
* def-global operand is unindexable; let/param/local +
|
||||
* string-literal operands stay valid. The faithful
|
||||
* def-as-constant splice-index is deferred (no
|
||||
* consumer). */
|
||||
if (n->lhs->kind == N_IDENT) {
|
||||
Sym *s = scope_lookup_prefer(c->cur,
|
||||
c->cur_mod, n->lhs->str);
|
||||
if (s && s->kind == SK_DEF)
|
||||
return n->type = err(c, n->pos,
|
||||
"cannot index a def-constant str "
|
||||
"'%s'; bind it to a `let` (def "
|
||||
"strings are inline constants, not "
|
||||
"storage-backed)", n->lhs->str);
|
||||
}
|
||||
return n->type = ty_u8;
|
||||
}
|
||||
/* `*[N]T` auto-decays to `[N]T` indexing — drill into the
|
||||
* inner T so callers see the element type, matching C's
|
||||
* pointer-to-array semantics. `*[]T` does NOT auto-decay:
|
||||
|
||||
Reference in New Issue
Block a user