On 11/11/20 10:26 AM, Jakub Jelinek wrote:
Hi!
As the testcase shows, CLEANUP_POINT_EXPR (and I think TRY_FINALLY_EXPR too)
suffer from the same problem that I was trying to fix in
r10-3597-g1006c9d4395a939820df76f37c7b085a4a1a003f
for CLEANUP_STMT, namely that if in the middle of the body expression of
those stmts is e.g. return stmt, goto, break or continue (something that
changes *jump_target and makes it start skipping stmts), we then skip the
cleanups too, which is not appropriate - the cleanups were either queued up
during the non-skipping execution of the body (for CLEANUP_POINT_EXPR), or
for TRY_FINALLY_EXPR are relevant already after entering the body block.
Would it make sense to always use a NULL jump_target when evaluating
cleanups?
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2020-11-11 Jakub Jelinek <ja...@redhat.com>
PR c++/97790
* constexpr.c (cxx_eval_constant_expression) <case CLEANUP_POINT_EXPR,
case TRY_FINALLY_EXPR>: For evaluation of cleanups use initially
recorded jump_target pointee rather than whatever ends up in it
after evaluation of the body operand.
* g++.dg/cpp2a/constexpr-dtor9.C: New test.
--- gcc/cp/constexpr.c.jj 2020-11-04 09:35:10.025029335 +0100
+++ gcc/cp/constexpr.c 2020-11-11 13:52:37.538466295 +0100
@@ -6008,6 +6008,7 @@ cxx_eval_constant_expression (const cons
auto_vec<tree, 2> cleanups;
vec<tree> *prev_cleanups = ctx->global->cleanups;
ctx->global->cleanups = &cleanups;
+ tree initial_jump_target = jump_target ? *jump_target : NULL_TREE;
r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0),
lval,
non_constant_p, overflow_p,
@@ -6019,19 +6020,24 @@ cxx_eval_constant_expression (const cons
FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup)
cxx_eval_constant_expression (ctx, cleanup, false,
non_constant_p, overflow_p,
- jump_target);
+ jump_target ? &initial_jump_target
+ : NULL);
}
break;
case TRY_FINALLY_EXPR:
- r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
+ {
+ tree initial_jump_target = jump_target ? *jump_target : NULL_TREE;
+ r = cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 0), lval,
+ non_constant_p, overflow_p,
+ jump_target);
+ if (!*non_constant_p)
+ /* Also evaluate the cleanup. */
+ cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true,
non_constant_p, overflow_p,
- jump_target);
- if (!*non_constant_p)
- /* Also evaluate the cleanup. */
- cxx_eval_constant_expression (ctx, TREE_OPERAND (t, 1), true,
- non_constant_p, overflow_p,
- jump_target);
+ jump_target ? &initial_jump_target
+ : NULL);
+ }
break;
case CLEANUP_STMT:
--- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C.jj 2020-11-11
13:57:16.572334917 +0100
+++ gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C 2020-11-11
13:57:45.510010165 +0100
@@ -0,0 +1,31 @@
+// PR c++/97790
+// { dg-do compile { target c++20 } }
+
+struct S
+{
+ int *d;
+ int n;
+ constexpr S () : d(new int[1]{}), n(1) {}
+ constexpr ~S () { delete [] d; }
+};
+
+constexpr S
+foo ()
+{
+ return S ();
+}
+
+constexpr int
+bar ()
+{
+ return foo ().n;
+}
+
+constexpr int
+baz ()
+{
+ return S ().n;
+}
+
+constexpr int a = baz ();
+constexpr int b = bar ();
Jakub