w6c: emit length for string-literal .len (fix #14, align cstage to wwstage)
A string literal is TY_UNTYPED_STR, not TY_STR, so `"abc".len` missed the typed slice/str pseudo-field gate in cgen.c's N_DOT and fell to the final base-eval fallback, which left AX=.ptr — `.len` returned the pointer instead of the length. wwstage's cgdot catch-all already did the BX->AX shuffle, so the two stages diverged (rule-10). Align cstage UP: the N_DOT fallback emits MOVQ BX,AX for `.len`. `.ptr` is unchanged (already returned AX); `.cap` deliberately not added (wwstage catch-all is ptr/len only — mirror exactly). byte-id was blind here: no bootstrap source uses literal `.len` (lengths are hardcoded around literals), so the gate never exercised it. New test 801 pins both dimensions (cstage run + cs==ww byte-id) over len/empty/multibyte/ptr-deref/arg-passthrough rows.
This commit is contained in:
@@ -22616,10 +22616,11 @@ fn cgdot(c: *cgen, n: *node) void = {
|
||||
};
|
||||
};
|
||||
// Non-ident base pseudo-field: e.g. `"abc".ptr` / `"abc".len`.
|
||||
// Evaluate the str-producing expression — that leaves
|
||||
// (AX=ptr, BX=len). Then `.ptr` returns AX as is; `.len`
|
||||
// shuffles BX→AX. Mirrors what C cgen does (it just evaluates
|
||||
// the literal and picks the half it wants).
|
||||
// A string literal is TY_UNTYPED_STR, so it misses the typed
|
||||
// slice/str gate above and lands here. Evaluate the str-producing
|
||||
// expression — that leaves (AX=ptr, BX=len). Then `.ptr` returns
|
||||
// AX as is; `.len` shuffles BX→AX. cstage cgen.c was aligned UP
|
||||
// to this shuffle in #14 (it had returned the ptr for `.len`).
|
||||
if (streq(fld, "ptr")) { cgexpr(c, lhs); return; };
|
||||
if (streq(fld, "len")) {
|
||||
cgexpr(c, lhs);
|
||||
|
||||
Reference in New Issue
Block a user