cmd+rt+selfhost+test: graduate alloc to (*T | nomem) / ([]T | nomem)
Per Hare convention, alloc is a typed builtin that returns a tagged
union carrying nomem as the OOM variant. Callers spell their policy:
`alloc(T)!` aborts on OOM (the old behavior), `alloc(T)?` propagates
when the enclosing fn already returns nomem.
cstage: check builds TY_TAGGED{*T | nomem} (or {[]T | nomem}); cgen
emits AX=tag, DX=ptr per the general tagged-return ABI (the (*T|!void)
nullable-ptr fold gated in ea76ee4 keeps this clean). wwstage cgalloc
mirrors. rt/alloc.s zeroes AX on syscall error so the builtin's null
check sees a clean 0 instead of mmap's -errno leaking through as a
poisoned pointer.
Migration: 3 `!` sites in test/wcc/700_e2e.c, 1 `!` site in
rt/ensure.ww (preserves the pre-existing sizeof bug tracked by #27),
1 `?` site in selfhost/test/tagged_ptr_ret.ww (allocbox exercises
real `?` propagation against a (*T | nomem) return).
130/130 tests green, 994_w6c_ww + 995_self_rebuild stage byte-identity
preserved. Follow-ups #31 (wwstage checkletassign leniency), #32
(wwstage slice-form gap), #33 (tagged_ptr_ret.ww make-test wiring).
This commit is contained in:
@@ -985,7 +985,22 @@ cexpr(Checker *c, Node *n)
|
||||
scope_lookup_in_module(c->cur, c->cur_mod, "alloc"))) {
|
||||
Type *t = cexpr(c, n->list);
|
||||
Type *def = type_default(t);
|
||||
n->type = type_ptr(c->a, def ? def : ty_void);
|
||||
Type *pt = type_ptr(c->a, def ? def : ty_void);
|
||||
/* Task #30 — graduate to Hare's `(*T | nomem)` shape;
|
||||
* the cgen branches on rt_alloc's null return to emit
|
||||
* the nomem variant. Two-variant union with TY_PTR +
|
||||
* TY_NAMED(nomem) does not trip the nullable-pointer
|
||||
* fold (#25), so the result rides the general AX=tag,
|
||||
* DX=ptr ABI both stages already share. */
|
||||
Type *tt = newtype(c->a, TY_TAGGED);
|
||||
Tparam *vp = amalloc(c->a, sizeof *vp);
|
||||
Tparam *ve = amalloc(c->a, sizeof *ve);
|
||||
vp->type = pt; vp->next = ve;
|
||||
ve->type = ty_nomem; ve->next = NULL;
|
||||
tt->params = vp;
|
||||
tt->size = 16;
|
||||
tt->align = 8;
|
||||
n->type = tt;
|
||||
n->lhs->type = ty_err;
|
||||
return n->type;
|
||||
}
|
||||
@@ -1046,7 +1061,22 @@ cexpr(Checker *c, Node *n)
|
||||
!(c->cur_mod &&
|
||||
scope_lookup_in_module(c->cur, c->cur_mod, "alloc"))) {
|
||||
(void)cexpr(c, n->list->next);
|
||||
n->type = type_slice(c->a, ty_u8);
|
||||
Type *st = type_slice(c->a, ty_u8);
|
||||
/* Task #30 — slice form graduates the same way:
|
||||
* `alloc([], n)` now returns `([]T | nomem)`. Slot is
|
||||
* 8 (tag) + 24 (slice payload) = 32B. The element type
|
||||
* defaults to u8 here; the let-init shortcut in
|
||||
* cmd/w6c/cgen.c N_LET drives the real element size
|
||||
* from the declared slice type. */
|
||||
Type *tt = newtype(c->a, TY_TAGGED);
|
||||
Tparam *vs = amalloc(c->a, sizeof *vs);
|
||||
Tparam *ve = amalloc(c->a, sizeof *ve);
|
||||
vs->type = st; vs->next = ve;
|
||||
ve->type = ty_nomem; ve->next = NULL;
|
||||
tt->params = vs;
|
||||
tt->size = 32;
|
||||
tt->align = 8;
|
||||
n->type = tt;
|
||||
n->lhs->type = ty_err;
|
||||
return n->type;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user