From fc531c2ed3ce456efca946e995544b216b3c16df Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Thu, 12 Nov 2020 10:46:04 +0100 Subject: [PATCH] c++: Fix up constexpr CLEANUP_POINT_EXPR and TRY_FINALLY_EXPR handling [PR97790] 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? I was afraid of that, especially for TRY_FINALLY_EXPR, but it seems that during constexpr evaluation the cleanups will most often be just very simple destructor calls (or calls to cleanup attribute functions). Furthermore, for neither of these 3 tree codes we'll reach that code if jump_target && *jump_target initially (there is a return NULL_TREE much earlier for those except for trees that could embed labels etc. in it and clearly these 3 don't count in that). 2020-11-12 Jakub Jelinek PR c++/97790 * constexpr.c (cxx_eval_constant_expression) : Don't pass jump_target to cxx_eval_constant_expression when evaluating the cleanups. * g++.dg/cpp2a/constexpr-dtor9.C: New test. --- gcc/cp/constexpr.c | 34 +++++++------------- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C | 31 ++++++++++++++++++ 2 files changed, 43 insertions(+), 22 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index b6f9c439a17..e6ab5eecd68 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -6018,8 +6018,7 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, /* Evaluate the cleanups. */ FOR_EACH_VEC_ELT_REVERSE (cleanups, i, cleanup) cxx_eval_constant_expression (ctx, cleanup, false, - non_constant_p, overflow_p, - jump_target); + non_constant_p, overflow_p); } break; @@ -6030,29 +6029,20 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, 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); + non_constant_p, overflow_p); break; case CLEANUP_STMT: - { - tree initial_jump_target = jump_target ? *jump_target : NULL_TREE; - r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, - non_constant_p, overflow_p, - jump_target); - if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) - { - iloc_sentinel ils (loc); - /* Also evaluate the cleanup. If we weren't skipping at the - start of the CLEANUP_BODY, change jump_target temporarily - to &initial_jump_target, so that even a return or break or - continue in the body doesn't skip the cleanup. */ - cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, - non_constant_p, overflow_p, - jump_target ? &initial_jump_target - : NULL); - } - } + r = cxx_eval_constant_expression (ctx, CLEANUP_BODY (t), lval, + non_constant_p, overflow_p, + jump_target); + if (!CLEANUP_EH_ONLY (t) && !*non_constant_p) + { + iloc_sentinel ils (loc); + /* Also evaluate the cleanup. */ + cxx_eval_constant_expression (ctx, CLEANUP_EXPR (t), true, + non_constant_p, overflow_p); + } break; /* These differ from cxx_eval_unary_expression in that this doesn't diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C new file mode 100644 index 00000000000..975e5fcfdfd --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor9.C @@ -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 (); -- 2.30.2