wcc/check: reject untyped-float + nil into a tagged dst with no matching variant (wwstage align to cstage)
isassignable's untyped-float (A4) and nil (A5) arms over-accepted a source into a tagged dst where no variant accepts it -> silent over-accept then tag-0 miscompile; cstage louds. Reject (cerr + c.errs+=1). Part of the isassignable tagged-dst over-accept class (#23 fixed arm3; A6/A7 deferred to the B-full nominal arc). test/wcc/836.
This commit is contained in:
@@ -14123,6 +14123,30 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (streq(du.str, "void")) { return false; };
|
||||
if (streq(du.str, "str")) { return false; };
|
||||
};
|
||||
// A4 (#23 float-twin): (T | ...) tagged dst — accept iff a DIRECT
|
||||
// variant is a float type. cstage type_assignable for an
|
||||
// untyped_float src uses type_isfloat (type.c:376 — f32/f64 ONLY,
|
||||
// NOT type_isnum), so an int/enum variant does NOT accept an
|
||||
// untyped float. No direct float variant -> confident reject
|
||||
// (cstage type.c:316 loop returns 0); ww does NOT flatten a
|
||||
// nested-union float variant (#199-alpha). *confident is already
|
||||
// true (:3777). Without it the catch-all (:3972) over-accepts an
|
||||
// untyped float into ANY tagged (silent tag=0). Faithful
|
||||
// flatten+rebox deferred post-CSP (nominal id, #23/#40).
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TNAME) {
|
||||
if (streq(vu.str, "f32")) { return true; };
|
||||
if (streq(vu.str, "f64")) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
@@ -14137,10 +14161,20 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE){ return true; };
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE) { return true; };
|
||||
if (v.kind == nkind.N_TCHAN) { return true; };
|
||||
if (v.kind == nkind.N_TFN) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
// A5: no nullable (ptr/slice/chan/fn) variant -> confident
|
||||
// reject (cstage type.c:316 loop returns 0; nil accepts only
|
||||
// into ptr/slice/chan/fn per type.c:382-385). *confident is
|
||||
// already true (:3777). Without it the catch-all (:3972)
|
||||
// over-accepts nil into ANY tagged (silent). The trailing
|
||||
// fallthrough below stays for a NON-tagged du (nil into a bare
|
||||
// scalar — a separate non-family over-accept, SIBLINGS).
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
|
||||
@@ -3842,6 +3842,30 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (streq(du.str, "void")) { return false; };
|
||||
if (streq(du.str, "str")) { return false; };
|
||||
};
|
||||
// A4 (#23 float-twin): (T | ...) tagged dst — accept iff a DIRECT
|
||||
// variant is a float type. cstage type_assignable for an
|
||||
// untyped_float src uses type_isfloat (type.c:376 — f32/f64 ONLY,
|
||||
// NOT type_isnum), so an int/enum variant does NOT accept an
|
||||
// untyped float. No direct float variant -> confident reject
|
||||
// (cstage type.c:316 loop returns 0); ww does NOT flatten a
|
||||
// nested-union float variant (#199-alpha). *confident is already
|
||||
// true (:3777). Without it the catch-all (:3972) over-accepts an
|
||||
// untyped float into ANY tagged (silent tag=0). Faithful
|
||||
// flatten+rebox deferred post-CSP (nominal id, #23/#40).
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TNAME) {
|
||||
if (streq(vu.str, "f32")) { return true; };
|
||||
if (streq(vu.str, "f64")) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
@@ -3856,10 +3880,20 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE){ return true; };
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE) { return true; };
|
||||
if (v.kind == nkind.N_TCHAN) { return true; };
|
||||
if (v.kind == nkind.N_TFN) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
// A5: no nullable (ptr/slice/chan/fn) variant -> confident
|
||||
// reject (cstage type.c:316 loop returns 0; nil accepts only
|
||||
// into ptr/slice/chan/fn per type.c:382-385). *confident is
|
||||
// already true (:3777). Without it the catch-all (:3972)
|
||||
// over-accepts nil into ANY tagged (silent). The trailing
|
||||
// fallthrough below stays for a NON-tagged du (nil into a bare
|
||||
// scalar — a separate non-family over-accept, SIBLINGS).
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
|
||||
@@ -14123,6 +14123,30 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (streq(du.str, "void")) { return false; };
|
||||
if (streq(du.str, "str")) { return false; };
|
||||
};
|
||||
// A4 (#23 float-twin): (T | ...) tagged dst — accept iff a DIRECT
|
||||
// variant is a float type. cstage type_assignable for an
|
||||
// untyped_float src uses type_isfloat (type.c:376 — f32/f64 ONLY,
|
||||
// NOT type_isnum), so an int/enum variant does NOT accept an
|
||||
// untyped float. No direct float variant -> confident reject
|
||||
// (cstage type.c:316 loop returns 0); ww does NOT flatten a
|
||||
// nested-union float variant (#199-alpha). *confident is already
|
||||
// true (:3777). Without it the catch-all (:3972) over-accepts an
|
||||
// untyped float into ANY tagged (silent tag=0). Faithful
|
||||
// flatten+rebox deferred post-CSP (nominal id, #23/#40).
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
let vu: *node = resolvealias(c, unwrapbang(v));
|
||||
if (vu != nil) {
|
||||
if (vu.kind == nkind.N_TNAME) {
|
||||
if (streq(vu.str, "f32")) { return true; };
|
||||
if (streq(vu.str, "f64")) { return true; };
|
||||
};
|
||||
};
|
||||
v = v.next;
|
||||
};
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
};
|
||||
@@ -14137,10 +14161,20 @@ fn isassignable(c: *checker, dst: *node, src: *node, confident: *bool) bool = {
|
||||
if (du.kind == nkind.N_TTAGGED) {
|
||||
let v: *node = du.list;
|
||||
for (v != nil) {
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE){ return true; };
|
||||
if (v.kind == nkind.N_TPTR) { return true; };
|
||||
if (v.kind == nkind.N_TSLICE) { return true; };
|
||||
if (v.kind == nkind.N_TCHAN) { return true; };
|
||||
if (v.kind == nkind.N_TFN) { return true; };
|
||||
v = v.next;
|
||||
};
|
||||
// A5: no nullable (ptr/slice/chan/fn) variant -> confident
|
||||
// reject (cstage type.c:316 loop returns 0; nil accepts only
|
||||
// into ptr/slice/chan/fn per type.c:382-385). *confident is
|
||||
// already true (:3777). Without it the catch-all (:3972)
|
||||
// over-accepts nil into ANY tagged (silent). The trailing
|
||||
// fallthrough below stays for a NON-tagged du (nil into a bare
|
||||
// scalar — a separate non-family over-accept, SIBLINGS).
|
||||
return false;
|
||||
};
|
||||
*confident = false;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user