aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-04-04 11:04:55 -0400
committerJason Merrill <jason@redhat.com>2020-04-04 11:06:31 -0400
commit9f143008c73c60e02634d6b433139a035ef7bb65 (patch)
treedde2a0566499fe03a7c93a2f784d3b3cad280477 /gcc
parent2523d721cfc861a3abea6e97736446c99ba8b52d (diff)
downloadgcc-9f143008c73c60e02634d6b433139a035ef7bb65.zip
gcc-9f143008c73c60e02634d6b433139a035ef7bb65.tar.gz
gcc-9f143008c73c60e02634d6b433139a035ef7bb65.tar.bz2
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 <TARGET_EXPR<NON_LVALUE_EXPR<TARGET_EXPR ...>>>, which doesn't make any sense. gcc/cp/ChangeLog 2020-04-04 Jason Merrill <jason@redhat.com> 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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/constexpr.c2
-rw-r--r--gcc/cp/expr.c22
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-constexpr1.C28
4 files changed, 53 insertions, 6 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 14038cc..f822936 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2020-04-04 Jason Merrill <jason@redhat.com>
+
+ 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 <jakub@redhat.com>
PR debug/94441
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 91f0c3b..8c693ea8 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 04e4418..9b53570 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 0000000..7cb1e23
--- /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 <typename f> f ay() { return *static_cast<f *>(ay()); }
+template <typename h>
+void bf() {
+ ay<h>()();
+}
+struct az {
+ template <typename h>
+ az(h);
+ using bk = void (*)();
+ bk bl;
+};
+template <typename h>
+az::az(h) { bl = bf<h>; }
+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); });
+}