PR c++/90393 - ICE with thow in ?:
My previous patch for 64372 was incomplete: it only stopped making the non-throw argument into an rvalue, lvalue_kind still considered the ?: expression to be an rvalue, leaving us worse than before. PR c++/64372, DR 1560 - Gratuitous lvalue-to-rvalue conversion in ?: * tree.c (lvalue_kind): Handle throw in one arm. * typeck.c (rationalize_conditional_expr): Likewise. (cp_build_modify_expr): Likewise. From-SVN: r274550
This commit is contained in:
parent
d321551cea
commit
7148dede8a
8 changed files with 85 additions and 20 deletions
|
@ -1,3 +1,12 @@
|
|||
2019-08-15 Jason Merrill <jason@redhat.com>
|
||||
|
||||
PR c++/90393 - ICE with thow in ?:
|
||||
|
||||
PR c++/64372, DR 1560 - Gratuitous lvalue-to-rvalue conversion in ?:
|
||||
* tree.c (lvalue_kind): Handle throw in one arm.
|
||||
* typeck.c (rationalize_conditional_expr): Likewise.
|
||||
(cp_build_modify_expr): Likewise.
|
||||
|
||||
2019-08-14 Jason Merrill <jason@redhat.com>
|
||||
|
||||
Implement P0848R3, Conditionally Trivial Special Member Functions.
|
||||
|
|
|
@ -236,10 +236,23 @@ lvalue_kind (const_tree ref)
|
|||
gcc_assert (!type_dependent_expression_p (CONST_CAST_TREE (ref)));
|
||||
goto default_;
|
||||
}
|
||||
op1_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 1)
|
||||
? TREE_OPERAND (ref, 1)
|
||||
: TREE_OPERAND (ref, 0));
|
||||
op2_lvalue_kind = lvalue_kind (TREE_OPERAND (ref, 2));
|
||||
{
|
||||
tree op1 = TREE_OPERAND (ref, 1);
|
||||
if (!op1) op1 = TREE_OPERAND (ref, 0);
|
||||
tree op2 = TREE_OPERAND (ref, 2);
|
||||
op1_lvalue_kind = lvalue_kind (op1);
|
||||
op2_lvalue_kind = lvalue_kind (op2);
|
||||
if (!op1_lvalue_kind != !op2_lvalue_kind)
|
||||
{
|
||||
/* The second or the third operand (but not both) is a
|
||||
throw-expression; the result is of the type
|
||||
and value category of the other. */
|
||||
if (op1_lvalue_kind && TREE_CODE (op2) == THROW_EXPR)
|
||||
op2_lvalue_kind = op1_lvalue_kind;
|
||||
else if (op2_lvalue_kind && TREE_CODE (op1) == THROW_EXPR)
|
||||
op1_lvalue_kind = op2_lvalue_kind;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MODOP_EXPR:
|
||||
|
|
|
@ -2308,13 +2308,15 @@ rationalize_conditional_expr (enum tree_code code, tree t,
|
|||
complain);
|
||||
}
|
||||
|
||||
tree op1 = TREE_OPERAND (t, 1);
|
||||
if (TREE_CODE (op1) != THROW_EXPR)
|
||||
op1 = cp_build_unary_op (code, op1, false, complain);
|
||||
tree op2 = TREE_OPERAND (t, 2);
|
||||
if (TREE_CODE (op2) != THROW_EXPR)
|
||||
op2 = cp_build_unary_op (code, op2, false, complain);
|
||||
|
||||
return
|
||||
build_conditional_expr (loc, TREE_OPERAND (t, 0),
|
||||
cp_build_unary_op (code, TREE_OPERAND (t, 1), false,
|
||||
complain),
|
||||
cp_build_unary_op (code, TREE_OPERAND (t, 2), false,
|
||||
complain),
|
||||
complain);
|
||||
build_conditional_expr (loc, TREE_OPERAND (t, 0), op1, op2, complain);
|
||||
}
|
||||
|
||||
/* Given the TYPE of an anonymous union field inside T, return the
|
||||
|
@ -8160,8 +8162,9 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
|||
if (!lvalue_or_else (lhs, lv_assign, complain))
|
||||
return error_mark_node;
|
||||
|
||||
tree op1 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 1),
|
||||
modifycode, rhs, complain);
|
||||
tree op1 = TREE_OPERAND (lhs, 1);
|
||||
if (TREE_CODE (op1) != THROW_EXPR)
|
||||
op1 = cp_build_modify_expr (loc, op1, modifycode, rhs, complain);
|
||||
/* When sanitizing undefined behavior, even when rhs doesn't need
|
||||
stabilization at this point, the sanitization might add extra
|
||||
SAVE_EXPRs in there and so make sure there is no tree sharing
|
||||
|
@ -8170,8 +8173,9 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
|||
if (sanitize_flags_p (SANITIZE_UNDEFINED
|
||||
| SANITIZE_UNDEFINED_NONDEFAULT))
|
||||
rhs = unshare_expr (rhs);
|
||||
tree op2 = cp_build_modify_expr (loc, TREE_OPERAND (lhs, 2),
|
||||
modifycode, rhs, complain);
|
||||
tree op2 = TREE_OPERAND (lhs, 2);
|
||||
if (TREE_CODE (op2) != THROW_EXPR)
|
||||
op2 = cp_build_modify_expr (loc, op2, modifycode, rhs, complain);
|
||||
tree cond = build_conditional_expr (input_location,
|
||||
TREE_OPERAND (lhs, 0), op1, op2,
|
||||
complain);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
// { dg-do compile { target c++11 } }
|
||||
|
||||
bool b;
|
||||
int i;
|
||||
// { dg-final { scan-assembler "_Z1fIiEDTquL_Z1bEfp_twLi42EET_" } }
|
||||
template <class T> auto f (T t) -> decltype(b?t:throw 42) { return 0; }
|
||||
template <class T> auto f (T t) -> decltype(b?t:throw 42) { return i; }
|
||||
// { dg-final { scan-assembler "_Z2f2IiEDTquL_Z1bEfp_trET_" } }
|
||||
template <class T> auto f2 (T t) -> decltype(b?t:throw) { return 0; }
|
||||
template <class T> auto f2 (T t) -> decltype(b?t:throw) { return i; }
|
||||
|
||||
int main()
|
||||
{
|
||||
|
|
13
gcc/testsuite/g++.dg/expr/cond15.C
Normal file
13
gcc/testsuite/g++.dg/expr/cond15.C
Normal file
|
@ -0,0 +1,13 @@
|
|||
// PR c++/90393
|
||||
|
||||
struct S {
|
||||
S();
|
||||
S(const S&) {}
|
||||
};
|
||||
|
||||
S f() {
|
||||
const S m;
|
||||
return true ? m : throw 0;
|
||||
}
|
||||
|
||||
int main() {}
|
25
gcc/testsuite/g++.dg/expr/cond16.C
Normal file
25
gcc/testsuite/g++.dg/expr/cond16.C
Normal file
|
@ -0,0 +1,25 @@
|
|||
// PR c++/90393
|
||||
// { dg-do run }
|
||||
|
||||
int c, d;
|
||||
|
||||
struct string {
|
||||
string(const char *p): s(p) { ++c; }
|
||||
~string() { ++d; }
|
||||
string(const string& str): s(str.s) { ++c; }
|
||||
const char* s;
|
||||
bool empty() const { return !s; }
|
||||
};
|
||||
|
||||
string foo()
|
||||
{
|
||||
string s("foo");
|
||||
return s.empty() ? throw "empty" : s;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo();
|
||||
if (c != d)
|
||||
__builtin_abort();
|
||||
}
|
|
@ -22,8 +22,8 @@ void fn(int i)
|
|||
(i ? throw X() : throw X()); // ok, void
|
||||
|
||||
(i ? i : j) = 1; // ok, int &
|
||||
(i ? throw X() : j) = 1; // { dg-error "" } non-lvalue
|
||||
(i ? j : throw X()) = 1; // { dg-error "" } non-lvalue
|
||||
(i ? throw X() : j) = 1; // ok, int &
|
||||
(i ? j : throw X()) = 1; // ok, int &
|
||||
(i ? throw X() : throw X()) = 1; // { dg-error "" } void
|
||||
|
||||
(i ? (void)1 : i++); // { dg-error "" } ANSI forbids
|
||||
|
|
|
@ -35,8 +35,8 @@ void fn(int i)
|
|||
(i ? throw X() : throw X()); // ok, void
|
||||
|
||||
(i ? i : j) = 1; // ok, int &
|
||||
(i ? throw X() : j) = 1; // { dg-error "lvalue" }
|
||||
(i ? j : throw X()) = 1; // { dg-error "lvalue" }
|
||||
(i ? throw X() : j) = 1; // ok, int &
|
||||
(i ? j : throw X()) = 1; // ok, int &
|
||||
(i ? throw X() : throw X()) = 1; // { dg-error "lvalue" }
|
||||
|
||||
(i ? (void)1 : i++); // { dg-error "throw-expression" }
|
||||
|
|
Loading…
Add table
Reference in a new issue