From 8194d5ae964cf6e359eb0a2eb330d189357debd3 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Fri, 16 Aug 2019 21:34:00 -0400 Subject: [PATCH] PR c++/90393 - ICE with throw in ?: I fixed the DR 1560 implementation properly for GCC 10, but for GCC 9 feel that it's better not to change the meaning of well-formed code. Reverting the incomplete implementation fixes the ICEs. * call.c (build_conditional_expr_1): Revert changes from PR c++/64372 and c++/86205. From-SVN: r274597 --- gcc/cp/ChangeLog | 6 +++ gcc/cp/call.c | 64 ++++++++++++++++------------- gcc/testsuite/g++.dg/cpp1y/dr1560.C | 14 ------- gcc/testsuite/g++.dg/expr/cond15.C | 13 ++++++ gcc/testsuite/g++.dg/expr/cond16.C | 25 +++++++++++ 5 files changed, 80 insertions(+), 42 deletions(-) delete mode 100644 gcc/testsuite/g++.dg/cpp1y/dr1560.C create mode 100644 gcc/testsuite/g++.dg/expr/cond15.C create mode 100644 gcc/testsuite/g++.dg/expr/cond16.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index f40ccc07f0bf..512e4e7ac15f 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,9 @@ +2019-08-16 Jason Merrill + + PR c++/90393 - ICE with throw in ?: + * call.c (build_conditional_expr_1): Revert changes from + PR c++/64372 and c++/86205. + 2019-08-15 Marek Polacek Backported from mainline diff --git a/gcc/cp/call.c b/gcc/cp/call.c index c728a9abedcd..14ddc98f3014 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -5185,46 +5185,56 @@ build_conditional_expr_1 (const op_location_t &loc, arg3_type = unlowered_expr_type (arg3); if (VOID_TYPE_P (arg2_type) || VOID_TYPE_P (arg3_type)) { - /* 'void' won't help in resolving an overloaded expression on the - other side, so require it to resolve by itself. */ - if (arg2_type == unknown_type_node) - { - arg2 = resolve_nondeduced_context_or_error (arg2, complain); - arg2_type = TREE_TYPE (arg2); - } - if (arg3_type == unknown_type_node) - { - arg3 = resolve_nondeduced_context_or_error (arg3, complain); - arg3_type = TREE_TYPE (arg3); - } + /* Do the conversions. We don't these for `void' type arguments + since it can't have any effect and since decay_conversion + does not handle that case gracefully. */ + if (!VOID_TYPE_P (arg2_type)) + arg2 = decay_conversion (arg2, complain); + if (!VOID_TYPE_P (arg3_type)) + arg3 = decay_conversion (arg3, complain); + arg2_type = TREE_TYPE (arg2); + arg3_type = TREE_TYPE (arg3); /* [expr.cond] One of the following shall hold: --The second or the third operand (but not both) is a - throw-expression (_except.throw_); the result is of the type - and value category of the other. + throw-expression (_except.throw_); the result is of the + type of the other and is an rvalue. --Both the second and the third operands have type void; the - result is of type void and is a prvalue. */ + result is of type void and is an rvalue. + + We must avoid calling force_rvalue for expressions of type + "void" because it will complain that their value is being + used. */ if (TREE_CODE (arg2) == THROW_EXPR && TREE_CODE (arg3) != THROW_EXPR) { + if (!VOID_TYPE_P (arg3_type)) + { + arg3 = force_rvalue (arg3, complain); + if (arg3 == error_mark_node) + return error_mark_node; + } + arg3_type = TREE_TYPE (arg3); result_type = arg3_type; - is_glvalue = glvalue_p (arg3); } else if (TREE_CODE (arg2) != THROW_EXPR && TREE_CODE (arg3) == THROW_EXPR) { + if (!VOID_TYPE_P (arg2_type)) + { + arg2 = force_rvalue (arg2, complain); + if (arg2 == error_mark_node) + return error_mark_node; + } + arg2_type = TREE_TYPE (arg2); result_type = arg2_type; - is_glvalue = glvalue_p (arg2); } else if (VOID_TYPE_P (arg2_type) && VOID_TYPE_P (arg3_type)) - { - result_type = void_type_node; - is_glvalue = false; - } + result_type = void_type_node; else { if (complain & tf_error) @@ -5243,6 +5253,7 @@ build_conditional_expr_1 (const op_location_t &loc, return error_mark_node; } + is_glvalue = false; goto valid_operands; } /* [expr.cond] @@ -5360,6 +5371,10 @@ build_conditional_expr_1 (const op_location_t &loc, && same_type_p (arg2_type, arg3_type)) { result_type = arg2_type; + if (processing_template_decl) + /* Let lvalue_kind know this was a glvalue. */ + result_type = cp_build_reference_type (result_type, xvalue_p (arg2)); + arg2 = mark_lvalue_use (arg2); arg3 = mark_lvalue_use (arg3); goto valid_operands; @@ -5557,13 +5572,6 @@ build_conditional_expr_1 (const op_location_t &loc, return error_mark_node; valid_operands: - if (processing_template_decl && is_glvalue) - { - /* Let lvalue_kind know this was a glvalue. */ - tree arg = (result_type == arg2_type ? arg2 : arg3); - result_type = cp_build_reference_type (result_type, xvalue_p (arg)); - } - result = build3_loc (loc, COND_EXPR, result_type, arg1, arg2, arg3); /* If the ARG2 and ARG3 are the same and don't have side-effects, diff --git a/gcc/testsuite/g++.dg/cpp1y/dr1560.C b/gcc/testsuite/g++.dg/cpp1y/dr1560.C deleted file mode 100644 index b21ca98e2797..000000000000 --- a/gcc/testsuite/g++.dg/cpp1y/dr1560.C +++ /dev/null @@ -1,14 +0,0 @@ -// Core 1560 -// { dg-do compile { target c++14 } } - -struct A -{ - A(); - A(const A&) = delete; -}; - -void f(bool b) -{ - A a; - b ? a : throw 42; -} diff --git a/gcc/testsuite/g++.dg/expr/cond15.C b/gcc/testsuite/g++.dg/expr/cond15.C new file mode 100644 index 000000000000..4a9d057a7578 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond15.C @@ -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() {} diff --git a/gcc/testsuite/g++.dg/expr/cond16.C b/gcc/testsuite/g++.dg/expr/cond16.C new file mode 100644 index 000000000000..796828b25c06 --- /dev/null +++ b/gcc/testsuite/g++.dg/expr/cond16.C @@ -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(); +} -- 2.47.2