From 9f143008c73c60e02634d6b433139a035ef7bb65 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sat, 4 Apr 2020 11:04:55 -0400 Subject: [PATCH] c++: Fix reuse of class constants [PR94453] The testcase hit an ICE trying to expand a TARGET_EXPR temporary cached from the other lambda-expression. This patch fixes this in two ways: 1) Avoid reusing a TARGET_EXPR from another function. 2) Avoid ending up with a TARGET_EXPR at all; the use of 'p' had become >>, which doesn't make any sense. gcc/cp/ChangeLog 2020-04-04 Jason Merrill PR c++/94453 * constexpr.c (maybe_constant_value): Use break_out_target_exprs. * expr.c (mark_use) [VIEW_CONVERT_EXPR]: Don't wrap a TARGET_EXPR in NON_LVALUE_EXPR. --- gcc/cp/ChangeLog | 7 +++++ gcc/cp/constexpr.c | 2 +- gcc/cp/expr.c | 22 +++++++++++---- .../g++.dg/cpp0x/lambda/lambda-constexpr1.C | 28 +++++++++++++++++++ 4 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/lambda/lambda-constexpr1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 14038ccfe90..f8229368eb9 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2020-04-04 Jason Merrill + + PR c++/94453 + * constexpr.c (maybe_constant_value): Use break_out_target_exprs. + * expr.c (mark_use) [VIEW_CONVERT_EXPR]: Don't wrap a TARGET_EXPR in + NON_LVALUE_EXPR. + 2020-04-04 Jakub Jelinek PR debug/94441 diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index 91f0c3ba269..8c693ea89ef 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6793,7 +6793,7 @@ maybe_constant_value (tree t, tree decl, bool manifestly_const_eval, r = *cached; if (r != t) { - r = unshare_expr_without_location (r); + r = break_out_target_exprs (r, /*clear_loc*/true); protected_set_expr_location (r, EXPR_LOCATION (t)); } return r; diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c index 04e4418c671..9b535708c57 100644 --- a/gcc/cp/expr.c +++ b/gcc/cp/expr.c @@ -195,11 +195,23 @@ mark_use (tree expr, bool rvalue_p, bool read_p, tree nop = RECUR (op); if (nop == error_mark_node) return error_mark_node; - TREE_OPERAND (expr, 0) = nop; - /* If we're replacing a DECL with a constant, we also need to change - the TREE_CODE of the location wrapper. */ - if (op != nop && rvalue_p) - TREE_SET_CODE (expr, NON_LVALUE_EXPR); + else if (op == nop) + /* No change. */; + else if (DECL_P (nop) || CONSTANT_CLASS_P (nop)) + { + /* Reuse the location wrapper. */ + TREE_OPERAND (expr, 0) = nop; + /* If we're replacing a DECL with a constant, we also need to + change the TREE_CODE of the location wrapper. */ + if (rvalue_p) + TREE_SET_CODE (expr, NON_LVALUE_EXPR); + } + else + { + /* Drop the location wrapper. */ + expr = nop; + protected_set_expr_location (expr, loc); + } return expr; } gcc_fallthrough(); diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-constexpr1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-constexpr1.C new file mode 100644 index 00000000000..7cb1e239ebb --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-constexpr1.C @@ -0,0 +1,28 @@ +// PR c++/94453 +// { dg-do compile { target c++11 } } + +void *ay(); +template f ay() { return *static_cast(ay()); } +template +void bf() { + ay()(); +} +struct az { + template + az(h); + using bk = void (*)(); + bk bl; +}; +template +az::az(h) { bl = bf; } +struct A {}; +void da(az); +void di(A, int); +void dk(A, az, az); +void b() { + int data = 0; + auto n = [] {}; + constexpr auto p = A{}; + auto q = [=] { di(p, data); }; + da([=] { dk(p, n, q); }); +} -- 2.30.2