For this testcase, the cleanup that is supposed to happen if initialization throws was wrongly being run on the normal control path as well. This turns out to be because the EH-only handling in gimple_push_cleanup didn't apply to conditional cleanups such as we have for nothrow new, since we check whether the result is non-null before proceeding with the initialization.
Tested x86_64-pc-linux-gnu, applying to trunk as obvious. PR c++/104007 gcc/ChangeLog: * gimplify.c (gimple_push_cleanup): Handle eh_only in conditional context. gcc/testsuite/ChangeLog: * g++.dg/eh/new2.C: New test. --- gcc/gimplify.cc | 1 + gcc/testsuite/g++.dg/eh/new2.C | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 gcc/testsuite/g++.dg/eh/new2.C diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index ab9874a2438..bf2f60cce9a 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -6885,6 +6885,7 @@ gimple_push_cleanup (tree var, tree cleanup, bool eh_only, gimple_seq *pre_p, cleanup = build3 (COND_EXPR, void_type_node, flag, cleanup, NULL); gimplify_stmt (&cleanup, &cleanup_stmts); wce = gimple_build_wce (cleanup_stmts); + gimple_wce_set_cleanup_eh_only (wce, eh_only); gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, ffalse); gimplify_seq_add_stmt (&gimplify_ctxp->conditional_cleanups, wce); diff --git a/gcc/testsuite/g++.dg/eh/new2.C b/gcc/testsuite/g++.dg/eh/new2.C new file mode 100644 index 00000000000..d4a1abfbf85 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/new2.C @@ -0,0 +1,10 @@ +// PR c++/104007 +// { dg-do run } + +extern "C" void abort(); +#include <new> + +struct S { ~S() { abort(); } }; +int main() { + new (std::nothrow) S[1]; +} base-commit: 76fe494230477a69f8fa8c8ca2d493acaf343eb1 -- 2.27.0