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:
@@ -8433,8 +8433,15 @@ cgexpr(Cg *c, Node *n, Local *locals)
|
||||
ins2(c, A_MOVQ, masym(c, n->str), areg(D_AX));
|
||||
break;
|
||||
}
|
||||
/* fall through to base evaluation; result placeholder */
|
||||
/* Non-ident / untyped-str base pseudo-field: e.g. `"abc".len`
|
||||
* / `"abc".ptr`. A string literal is TY_UNTYPED_STR, not
|
||||
* TY_STR, so it misses the typed slice/str gate above and
|
||||
* lands here. cgexpr leaves (AX=ptr, BX=len); `.ptr` keeps AX,
|
||||
* `.len` shuffles BX→AX. Mirrors wwstage cgdot's catch-all
|
||||
* (selfhost/cmd/wcc/cgenexpr.ww). #14. */
|
||||
cgexpr(c, n->lhs, locals);
|
||||
if (lenfld)
|
||||
ins2(c, A_MOVQ, areg(D_BX), areg(D_AX));
|
||||
dot_done:
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user