From 8895443a42db4045aad8e4b42cd5dd2ad6ffa7d7 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 28 Oct 2020 17:30:05 -0400 Subject: [PATCH] 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. --- gcc/cp/constexpr.c | 10 ++++------ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor8.C diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index c959b532ec3..b46824f128d 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 00000000000..3048110ede3 --- /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" } -- 2.30.2