check: type the N_BIN operand of as in the wwstage
An enum OR-fold under `as` ((m.A|m.B) as u32) was never typed: scruttype resolves IDENT/DOT only, and the post-order restamp then re-derived the folded member literals as untyped_int. The unstamped operand missed cgtypeassert's #27b enum-reinterpret gate and lowered as a phantom tagged assert — unconditional exit 1 at runtime on the wwstage leg. checkisas now types an N_BIN lhs and the N_BIN restamp preserves an existing enum stamp. Graduates the #59.9 stattest pin.
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
package wwfixture;
|
||||
|
||||
def protocolversion: i32 = 1;
|
||||
def corpuscount: i32 = 1236;
|
||||
def corpuscount: i32 = 1237;
|
||||
def errorcount: i32 = 314;
|
||||
def compilecount: i32 = 12;
|
||||
def runcount: i32 = 144;
|
||||
def runcount: i32 = 145;
|
||||
def runexitcount: i32 = 766;
|
||||
def nativecount: i32 = 2472;
|
||||
def corpushash: str = "4c8f4a693d2d8193b15f4215610c1d070dc83493b1189af772ca09cad4a69db7";
|
||||
def nativecount: i32 = 2474;
|
||||
def corpushash: str = "7763f2eb34524f67355114f5bdfbf3f64415152a8ec64060fe32a322bdbe1b24";
|
||||
|
||||
type directive = enum i32 {
|
||||
ERROR = 0,
|
||||
|
||||
@@ -3328,6 +3328,22 @@ fn exprtype(c: *checker, e: *syntax.node, hint: *syntax.node) *syntax.node = {
|
||||
};
|
||||
if (k == syntax.nkind.N_BIN) {
|
||||
let tn: *syntax.node = binoptype(c, e);
|
||||
// #59.9: checkisas pre-stamps an enum OR-fold (`(m.A|m.B) as
|
||||
// u32`) TY_ENUM and folds the member N_DOTs to int literals;
|
||||
// this post-order revisit re-derives from those now-untyped
|
||||
// literals and clobbered the stamp, so cgtypeassert's #27b
|
||||
// reinterpret gate missed and emitted a phantom tagged assert
|
||||
// (unconditional exit 1). Keep an existing enum stamp; the
|
||||
// returned tnode contract for callers is unchanged.
|
||||
let pre599: *syntax.tinfo = e.type_: *syntax.tinfo;
|
||||
if (pre599 != nil) {
|
||||
let prech: *syntax.tinfo = tichase(pre599);
|
||||
if (prech != nil) {
|
||||
if (prech.kind == syntax.tykind.TY_ENUM) {
|
||||
return tn;
|
||||
};
|
||||
};
|
||||
};
|
||||
e.type_ = tinfofornode(c, tn): *void;
|
||||
return tn;
|
||||
};
|
||||
@@ -6353,6 +6369,15 @@ fn checkisas(c: *checker, n: *syntax.node) void = {
|
||||
if (n.lhs.kind == syntax.nkind.N_TRYPROP || n.lhs.kind == syntax.nkind.N_TRYUNW) {
|
||||
st = exprtype(c, n.lhs, nil);
|
||||
};
|
||||
// #59.9: an N_BIN operand (`(m.A | m.B) as u32`) was never
|
||||
// typed, so the OR-fold reached cgen unstamped and
|
||||
// cgtypeassert's enum-reinterpret gate (#27b) missed —
|
||||
// lowering a plain enum value as a phantom tagged assert
|
||||
// (unconditional exit 1). cstage types the lhs
|
||||
// unconditionally (cmd/wcc/check.c:2220 cexpr(c, n->lhs)).
|
||||
if (n.lhs.kind == syntax.nkind.N_BIN) {
|
||||
st = exprtype(c, n.lhs, nil);
|
||||
};
|
||||
};
|
||||
let u: *syntax.node = resolvealias(c, unwrapbang(st));
|
||||
if (u == nil) { return; };
|
||||
|
||||
@@ -169,8 +169,13 @@ static const struct ent ents[] = {
|
||||
/* #59.7 siphash graduated to M_ID above (#61 fix) */
|
||||
{ .fixture = "lib/log/logtest.ww",
|
||||
.mode = M_DIVERGE, .cite = "#59.8" },
|
||||
/* #59.9 graduated: the wwstage checker never typed an N_BIN operand
|
||||
* of `as`, so an enum OR-fold reached cgen unstamped and lowered as
|
||||
* a phantom tagged assert (unconditional exit 1). checkisas now
|
||||
* types the N_BIN lhs and the post-order restamp preserves the enum
|
||||
* stamp. Runtime pin: r599_enum_orfold_as. */
|
||||
{ .fixture = "lib/os/stattest.ww",
|
||||
.mode = M_DIVERGE, .cite = "#59.9" },
|
||||
.mode = M_ID, .cite = "#59.9 graduated by the checkisas N_BIN stamp" },
|
||||
/* #59.10 stoftest graduated to M_ID above (#62 fix) */
|
||||
{ .fixture = "lib/ww/syntax/toktest.ww", .inc = "lib/ww",
|
||||
.mode = M_ID, .cite = "#59.11 graduated by #146 str==" },
|
||||
|
||||
16
test/wcc/data/r599_enum_orfold_as/case.ww
Normal file
16
test/wcc/data/r599_enum_orfold_as/case.ww
Normal file
@@ -0,0 +1,16 @@
|
||||
//ww:run
|
||||
// #59.9: an enum member OR-fold under `as`. The pre-fix wwstage
|
||||
// checker never typed the N_BIN operand, so cgtypeassert's enum
|
||||
// reinterpret gate missed and lowered a phantom tagged assert that
|
||||
// unconditionally exited 1.
|
||||
package main;
|
||||
|
||||
type mask = enum u32 { A = 1, B = 2, C = 4 };
|
||||
|
||||
fn main() i32 = {
|
||||
let w: u32 = (mask.A | mask.B | mask.C) as u32;
|
||||
if (w != 7u32) { return 1; };
|
||||
let v: u32 = (mask.A | mask.C) as u32;
|
||||
if (v != 5u32) { return 2; };
|
||||
return 0;
|
||||
};
|
||||
Reference in New Issue
Block a user