diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-07-26 19:28:02 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2021-07-29 16:16:19 +0200 |
commit | 5c9b7408dc578cb2ae142a5c1b724c183497bdb2 (patch) | |
tree | 9d66585f4b9e8f11d44c05275ea7016577471721 | |
parent | 75f2e3f6cbbb79421b12e399498e9c14241359e7 (diff) | |
download | gcc-5c9b7408dc578cb2ae142a5c1b724c183497bdb2.zip gcc-5c9b7408dc578cb2ae142a5c1b724c183497bdb2.tar.gz gcc-5c9b7408dc578cb2ae142a5c1b724c183497bdb2.tar.bz2 |
d: Ensure casting from bool results in either 0 or 1 (PR96435)
If casting from bool, the result is either 0 or 1, any other value
violates @safe code, so enforce that it is never invalid.
PR d/96435
gcc/d/ChangeLog:
* 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:
* gdc.dg/torture/pr96435.d: New test.
-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); +} |