wcc: &s.len / &s.cap typed as *i64 (closes #13)

TK_AMP early-exit on slice/str .len/.cap pseudo-fields now returns
*i64 instead of legacy *i32. Slice ABI is 24B fixed; LEAQ at the slot
was already correct, only the pointer typing was wrong — store-width
flips from MOVL to MOVQ via the existing primsize-from-tnode path.
&s.ptr untouched (already **T).
This commit is contained in:
2026-05-14 00:21:53 +09:00
parent 6354f5267c
commit f2b47087a2
2 changed files with 109 additions and 4 deletions

View File

@@ -623,6 +623,23 @@ cunop(Checker *c, Node *n)
type_name(c->a, t));
return t->sub;
case TK_AMP: /* address-of */
/* Slice/str pseudo-fields .len/.cap surface as i32 but live
* in 8B-aligned slots in the header (ptr@0, len@8, cap@16).
* Address-of must be typed *i64 so deref-write hits the full
* slot; otherwise *&s.len = N stores 4B (MOVL) and the upper
* 4B leak from whatever the prior MOVQ store of s.len left
* behind. */
if (n->lhs && n->lhs->kind == N_DOT && n->lhs->lhs &&
n->lhs->str &&
(strcmp(n->lhs->str, "len") == 0 ||
strcmp(n->lhs->str, "cap") == 0)) {
Type *bt = n->lhs->lhs->type;
Type *bu = (bt && bt->kind == TY_NAMED) ? bt->under : bt;
if (bu && bu->kind == TY_PTR) bu = bu->sub;
if (bu && bu->kind == TY_NAMED) bu = bu->under;
if (bu && (bu->kind == TY_SLICE || bu->kind == TY_STR))
return type_ptr(c->a, ty_i64);
}
return type_ptr(c->a, t);
default:
return err(c, n->pos, "unsupported unary %s", tokname(n->op));