Tested x86_64-pc-linux-gnu, applying to trunk. -- 8< --
We were assuming that the result of evaluation of TARGET_EXPR_INITIAL would always be the new value of the temporary, but that's not necessarily true when the initializer is complex (i.e. target_expr_needs_replace). In that case evaluating the initializer initializes the temporary as a side-effect. PR c++/109357 gcc/cp/ChangeLog: * constexpr.cc (cxx_eval_constant_expression) [TARGET_EXPR]: Check for complex initializer. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-dtor15.C: New test. --- gcc/cp/constexpr.cc | 15 +++++++++++---- gcc/testsuite/g++.dg/cpp2a/constexpr-dtor15.C | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-dtor15.C diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 3de60cfd0f8..d1097764b10 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -7230,16 +7230,23 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t, non_constant_p, overflow_p); if (*non_constant_p) break; - /* Adjust the type of the result to the type of the temporary. */ - r = adjust_temp_type (type, r); + /* If the initializer is complex, evaluate it to initialize slot. */ + bool is_complex = target_expr_needs_replace (t); + if (!is_complex) + { + r = unshare_constructor (r); + /* Adjust the type of the result to the type of the temporary. */ + r = adjust_temp_type (type, r); + ctx->global->put_value (slot, r); + } if (TARGET_EXPR_CLEANUP (t) && !CLEANUP_EH_ONLY (t)) ctx->global->cleanups->safe_push (TARGET_EXPR_CLEANUP (t)); - r = unshare_constructor (r); - ctx->global->put_value (slot, r); if (ctx->save_exprs) ctx->save_exprs->safe_push (slot); if (lval) return slot; + if (is_complex) + r = ctx->global->get_value (slot); } break; diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor15.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor15.C new file mode 100644 index 00000000000..d34c27eee45 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-dtor15.C @@ -0,0 +1,19 @@ +// PR c++/109357 +// { dg-do compile { target c++20 } } +// { dg-prune-output "used but never defined" } + +struct basic_string { + char _M_local_buf; + basic_string(); + constexpr basic_string(const char *) {} + constexpr ~basic_string(); + constexpr basic_string& operator=(basic_string); +}; +struct S1 { + basic_string x; + basic_string y; +} s1; +struct s2 { + ~s2(); +}; +s2::~s2() { s1 = {"", ""}; } base-commit: 9964df74a9e99e850bf9b0b6ff5c47133f846db8 -- 2.31.1