wcc/ww: reject value-less return in a non-void fn (catB-24)
wwstage's checkretassign short-circuited on a value-less `return;`
("skip flagging for now"), so `fn f() i32 = { return; }` built and
RET'd a garbage register. Mirror cstage cmd/wcc/check.c:2428-2439:
the no-value return has type void, then run isassignable(c.fnret,
void) — void→void and void→(T|void) accept, void→i32 is a confident
reject. cstage already rejected; this aligns wwstage's w6c_ww UP.
Regen w6c/wwdump combined.ww (checker embeds in both). Valid-program
codegen unchanged → cs==ww byte-id gate stays green.
This commit is contained in:
@@ -16253,9 +16253,18 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
fn checkretassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) {
|
||||
// bare `return;` — OK iff fnret is void or a tagged union
|
||||
// with a void variant. Skip flagging for now; cgen handles
|
||||
// the void-variant tag synthesis already.
|
||||
// bare `return;` — mirror cstage cmd/wcc/check.c:2428-2439:
|
||||
// the value-less return has type void, then type_assignable
|
||||
// (c.fnret, void). A void fnret or a tagged union carrying a
|
||||
// void variant accepts; a non-void scalar fnret rejects (the
|
||||
// value-less return would RET a garbage register). isassignable
|
||||
// reaches the same verdict (void→void typeeqast; void→tagged via
|
||||
// the void variant; void→i32 a confident primitive mismatch).
|
||||
if (c.fnret == nil) { return; };
|
||||
let vt: *node = mktname(c, "void");
|
||||
let vconf: bool = false;
|
||||
let vok: bool = isassignable(c, c.fnret, vt, &vconf);
|
||||
if (vconf) { if (!vok) { errnotassign(c, c.fnret, vt, "return"); }; };
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
|
||||
@@ -5779,9 +5779,18 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
fn checkretassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) {
|
||||
// bare `return;` — OK iff fnret is void or a tagged union
|
||||
// with a void variant. Skip flagging for now; cgen handles
|
||||
// the void-variant tag synthesis already.
|
||||
// bare `return;` — mirror cstage cmd/wcc/check.c:2428-2439:
|
||||
// the value-less return has type void, then type_assignable
|
||||
// (c.fnret, void). A void fnret or a tagged union carrying a
|
||||
// void variant accepts; a non-void scalar fnret rejects (the
|
||||
// value-less return would RET a garbage register). isassignable
|
||||
// reaches the same verdict (void→void typeeqast; void→tagged via
|
||||
// the void variant; void→i32 a confident primitive mismatch).
|
||||
if (c.fnret == nil) { return; };
|
||||
let vt: *node = mktname(c, "void");
|
||||
let vconf: bool = false;
|
||||
let vok: bool = isassignable(c, c.fnret, vt, &vconf);
|
||||
if (vconf) { if (!vok) { errnotassign(c, c.fnret, vt, "return"); }; };
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
|
||||
@@ -16253,9 +16253,18 @@ fn checkletassign(c: *checker, n: *node) void = {
|
||||
fn checkretassign(c: *checker, n: *node) void = {
|
||||
if (n == nil) { return; };
|
||||
if (n.lhs == nil) {
|
||||
// bare `return;` — OK iff fnret is void or a tagged union
|
||||
// with a void variant. Skip flagging for now; cgen handles
|
||||
// the void-variant tag synthesis already.
|
||||
// bare `return;` — mirror cstage cmd/wcc/check.c:2428-2439:
|
||||
// the value-less return has type void, then type_assignable
|
||||
// (c.fnret, void). A void fnret or a tagged union carrying a
|
||||
// void variant accepts; a non-void scalar fnret rejects (the
|
||||
// value-less return would RET a garbage register). isassignable
|
||||
// reaches the same verdict (void→void typeeqast; void→tagged via
|
||||
// the void variant; void→i32 a confident primitive mismatch).
|
||||
if (c.fnret == nil) { return; };
|
||||
let vt: *node = mktname(c, "void");
|
||||
let vconf: bool = false;
|
||||
let vok: bool = isassignable(c, c.fnret, vt, &vconf);
|
||||
if (vconf) { if (!vok) { errnotassign(c, c.fnret, vt, "return"); }; };
|
||||
return;
|
||||
};
|
||||
if (c.fnret == nil) { return; };
|
||||
|
||||
Reference in New Issue
Block a user