Hi, When casting from bool, the result is either 0 or 1, any other value violates @safe code, so enforce that it is never invalid.
This patch does that by lowering rvalue reads into `(bool & 1)'. Bootstrapped and regression tested on x86_64-linux-gnu/-mx32/-m32, committed to mainline, and backported to the gcc-11, gcc-10 and gcc-9 release branches. Regards, Iain --- gcc/d/ChangeLog: PR d/96435 * d-convert.cc (convert_for_rvalue): New function. * d-tree.h (convert_for_rvalue): Declare. * expr.cc (ExprVisitor::visit (CastExp *)): Use convert_for_rvalue. (build_return_dtor): Likewise. gcc/testsuite/ChangeLog: PR d/96435 * gdc.dg/torture/pr96435.d: New test. --- gcc/d/d-convert.cc | 36 ++++++++++++++++++++++++++ gcc/d/d-tree.h | 1 + gcc/d/expr.cc | 13 ++++++---- gcc/testsuite/gdc.dg/torture/pr96435.d | 21 +++++++++++++++ 4 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gdc.dg/torture/pr96435.d diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc index 237c084acf5..d43485dca77 100644 --- a/gcc/d/d-convert.cc +++ b/gcc/d/d-convert.cc @@ -602,6 +602,42 @@ convert_expr (tree exp, Type *etype, Type *totype) return result ? result : convert (build_ctype (totype), exp); } +/* Return a TREE represenwation of EXPR, whose type has been converted from + * ETYPE to TOTYPE, and is being used in an rvalue context. */ + +tree +convert_for_rvalue (tree expr, Type *etype, Type *totype) +{ + tree result = NULL_TREE; + + Type *ebtype = etype->toBasetype (); + Type *tbtype = totype->toBasetype (); + + switch (ebtype->ty) + { + case Tbool: + /* If casting from bool, the result is either 0 or 1, any other value + violates @safe code, so enforce that it is never invalid. */ + if (CONSTANT_CLASS_P (expr)) + result = d_truthvalue_conversion (expr); + else + { + /* Reinterpret the boolean as an integer and test the first bit. + The generated code should end up being equivalent to: + *cast(ubyte *)&expr & 1; */ + machine_mode bool_mode = TYPE_MODE (TREE_TYPE (expr)); + tree mtype = lang_hooks.types.type_for_mode (bool_mode, 1); + result = fold_build2 (BIT_AND_EXPR, mtype, + build_vconvert (mtype, expr), + build_one_cst (mtype)); + } + + result = convert (build_ctype (tbtype), result); + break; + } + + return result ? result : convert_expr (expr, etype, totype); +} /* Apply semantics of assignment to a value of type TOTYPE to EXPR (e.g., pointer = array -> pointer = &array[0]) diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index b03d60a5c0e..f210b8b1a6e 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -598,6 +598,7 @@ extern bool decl_with_nonnull_addr_p (const_tree); extern tree d_truthvalue_conversion (tree); extern tree d_convert (tree, tree); extern tree convert_expr (tree, Type *, Type *); +extern tree convert_for_rvalue (tree, Type *, Type *); extern tree convert_for_assignment (tree, Type *, Type *); extern tree convert_for_argument (tree, Parameter *); extern tree convert_for_condition (tree, Type *); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index b78778eb8ef..99ca958c7c4 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1491,7 +1491,7 @@ public: if (tbtype->ty == Tvoid) this->result_ = build_nop (build_ctype (tbtype), result); else - this->result_ = convert_expr (result, ebtype, tbtype); + this->result_ = convert_for_rvalue (result, ebtype, tbtype); } /* Build a delete expression. */ @@ -3169,11 +3169,14 @@ build_return_dtor (Expression *e, Type *type, TypeFunction *tf) tree result = build_expr (e); /* Convert for initializing the DECL_RESULT. */ - result = convert_expr (result, e->type, type); - - /* If we are returning a reference, take the address. */ if (tf->isref) - result = build_address (result); + { + /* If we are returning a reference, take the address. */ + result = convert_expr (result, e->type, type); + result = build_address (result); + } + else + result = convert_for_rvalue (result, e->type, type); /* The decl to store the return expression. */ tree decl = DECL_RESULT (cfun->decl); diff --git a/gcc/testsuite/gdc.dg/torture/pr96435.d b/gcc/testsuite/gdc.dg/torture/pr96435.d new file mode 100644 index 00000000000..c6d8785ec5b --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/pr96435.d @@ -0,0 +1,21 @@ +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=96435 +// { dg-do run } + +@safe bool test96435() +{ + int[2] array = [16, 678]; + union U { int i; bool b; } + U u; + u.i = 0xDEADBEEF; + assert(array[u.b] == 678); + return u.b; +} + +@safe void main() +{ + auto b = test96435(); + if (b) + assert(true); + if (!b) + assert(false); +} -- 2.30.2