diff options
-rw-r--r-- | gcc/d/d-convert.cc | 36 | ||||
-rw-r--r-- | gcc/d/d-tree.h | 1 | ||||
-rw-r--r-- | gcc/d/expr.cc | 13 | ||||
-rw-r--r-- | gcc/testsuite/gdc.dg/torture/pr96435.d | 21 |
4 files changed, 66 insertions, 5 deletions
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc index 237c084..d43485d 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 b03d60a..f210b8b 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 b78778e..99ca958 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 0000000..c6d8785 --- /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); +} |