aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2020-10-28 17:30:05 -0400
committerJason Merrill <jason@redhat.com>2020-10-29 13:09:19 -0400
commit8895443a42db4045aad8e4b42cd5dd2ad6ffa7d7 (patch)
tree86d08ca2e07ec9650266b97e5c53b6eea03c3511 /gcc
parent5afd90c5f36bf45291ca09ef3791f4a574e90d5d (diff)
downloadgcc-8895443a42db4045aad8e4b42cd5dd2ad6ffa7d7.zip
gcc-8895443a42db4045aad8e4b42cd5dd2ad6ffa7d7.tar.gz
gcc-8895443a42db4045aad8e4b42cd5dd2ad6ffa7d7.tar.bz2
c++: Fix constexpr cleanup error handling.
In this testcase, the primary evaluation successfully produces 'true', and then running one of the cleanups hits a double delete, making the whole thing not a valid constant expression. So we were returning 'true' wrapped in a NOP_EXPR to indicate its non-constancy, but evaluating that again is a perfectly acceptable constant expression, so we weren't getting the verbose diagnostic we were looking for. So if non_constant_p gets set other than for overflow, go back to the original expression. With this change, we should never hit the manifestly_const_eval test, and the is-constant-evaluated1.C test passes without it. gcc/cp/ChangeLog: PR c++/97388 * constexpr.c (cxx_eval_outermost_constant_expr): Revert to original expression if evaluation sets non_constant_p. gcc/testsuite/ChangeLog: PR c++/97388 * g++.dg/cpp2a/constexpr-dtor8.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/constexpr.c10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C19
2 files changed, 23 insertions, 6 deletions
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index c959b53..b46824f 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6925,6 +6925,10 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
non_constant_p = true;
}
+ if (non_constant_p)
+ /* If we saw something bad, go back to our argument. The wrapping below is
+ only for the cases of TREE_CONSTANT argument or overflow. */
+ r = t;
if (!non_constant_p && overflow_p)
non_constant_p = true;
@@ -6941,12 +6945,6 @@ cxx_eval_outermost_constant_expr (tree t, bool allow_non_constant,
return r;
else if (non_constant_p && TREE_CONSTANT (r))
{
- /* If __builtin_is_constant_evaluated () was evaluated to true
- and the result is not a valid constant expression, we need to
- punt. */
- if (manifestly_const_eval)
- return cxx_eval_outermost_constant_expr (t, true, strict,
- false, false, object);
/* This isn't actually constant, so unset TREE_CONSTANT.
Don't clear TREE_CONSTANT on ADDR_EXPR, as the middle-end requires
it to be set if it is invariant address, even when it is not
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C
new file mode 100644
index 0000000..3048110
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C
@@ -0,0 +1,19 @@
+// PR c++/97388
+// { dg-do compile { target c++20 } }
+
+struct S {
+ int *s;
+ constexpr S () : s(new int) {}
+ S (const S &) = delete;
+ S &operator= (const S &) = delete;
+ constexpr ~S () { delete s; } // { dg-error "already deallocated" }
+};
+
+constexpr bool
+foo (S v)
+{
+ delete v.s;
+ return true;
+}
+
+static_assert (foo (S ())); // { dg-error "non-constant condition for static assertion" }