From: Nathaniel Shead Date: Sat, 24 Jan 2026 08:34:53 +0000 (+1100) Subject: c++: Fix cp_fold_non_odr_use_1 [PR123557,PR123738] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6bfec5d7b8b87f505d974da8e24240af11b9914e;p=thirdparty%2Fgcc.git c++: Fix cp_fold_non_odr_use_1 [PR123557,PR123738] This fixes two issues with cp_fold_non_odr_use_1: - When called to fold away a reference, it considers the use to not be an lvalue and so 'maybe_constant_value' folds all the way through the nested INDIRECT_REF to a prvalue. Fixed by folding the op0 of the INDIRECT_REF rather than the ref itself and avoiding a double cp_fold_non_odr_use_1. - When used to fold away the initializing expression for an INIT_EXPR, it doesn't mark any new TARGET_EXPRs as eliding. Fixed by reapplying 'set_target_expr_eliding' for the initializer of an INIT_EXPR if it got modified during ff_only_non_odr walk. PR c++/123557 PR c++/123738 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_fold_maybe_rvalue): Call cp_fold_non_odr_use_1 before recursing cp_fold. (cp_fold): Pass op0 to cp_fold_non_odr_use_1 when folding a reference. Reapply set_target_expr_eliding on the initializing expression of an INIT_EXPR. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/constexpr-ice22.C: New test. * g++.dg/cpp2a/constexpr-ref2.C: New test. Signed-off-by: Nathaniel Shead Reviewed-by: Jason Merrill --- diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc index 38cee83ab76..9d96ce99ea9 100644 --- a/gcc/cp/cp-gimplify.cc +++ b/gcc/cp/cp-gimplify.cc @@ -3136,26 +3136,21 @@ cp_fold_maybe_rvalue (tree x, bool rval, fold_flags_t flags) { while (true) { + if (rval && (flags & ff_only_non_odr)) + x = cp_fold_non_odr_use_1 (x); x = cp_fold (x, flags); if (rval) - x = mark_rvalue_use (x); - if (rval && (flags & ff_only_non_odr)) - { - tree v = cp_fold_non_odr_use_1 (x); - if (v != x) - { - x = v; - continue; - } - } - else if (rval && DECL_P (x) - && !TYPE_REF_P (TREE_TYPE (x))) { - tree v = decl_constant_value (x); - if (v != x && v != error_mark_node) + x = mark_rvalue_use (x); + if (!(flags & ff_only_non_odr) + && DECL_P (x) && !TYPE_REF_P (TREE_TYPE (x))) { - x = v; - continue; + tree v = decl_constant_value (x); + if (v != x && v != error_mark_node) + { + x = v; + continue; + } } } break; @@ -3419,9 +3414,9 @@ cp_fold (tree x, fold_flags_t flags) used as lvalues. */ if ((flags & ff_only_non_odr) && REFERENCE_REF_P (x)) { - tree r = cp_fold_non_odr_use_1 (x); - if (r != x) - return convert_from_reference (cp_fold (r, flags)); + op0 = cp_fold_non_odr_use_1 (TREE_OPERAND (x, 0)); + if (op0 != TREE_OPERAND (x, 0)) + return convert_from_reference (cp_fold (op0, flags)); } goto unary; @@ -3568,7 +3563,11 @@ cp_fold (tree x, fold_flags_t flags) if (op0 == error_mark_node || op1 == error_mark_node) x = error_mark_node; else if (op0 != TREE_OPERAND (x, 0) || op1 != TREE_OPERAND (x, 1)) - x = build2_loc (loc, code, TREE_TYPE (x), op0, op1); + { + if (code == INIT_EXPR && op1 != TREE_OPERAND (x, 1)) + set_target_expr_eliding (op1); + x = build2_loc (loc, code, TREE_TYPE (x), op0, op1); + } break; } diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C new file mode 100644 index 00000000000..900c8053a92 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C @@ -0,0 +1,14 @@ +// PR c++/123557 +// { dg-do compile { target c++11 } } + +struct a { + a() = default; + a(a const &) = default; + a(a &&); +}; +struct c { + c(); + a e; +}; +constexpr a b; +c::c() : e(b) {} diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C new file mode 100644 index 00000000000..659beed3a25 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C @@ -0,0 +1,19 @@ +// PR c++/123738 +// { dg-do compile { target c++20 } } + +struct OStringLiteral { + int str = 0; +}; + +template struct OStringHolder { + static constexpr auto & literal = L; +}; + +struct OString { + template constexpr OString(OStringHolder const &): + p(&OStringHolder::literal.str) {} + int const * p; +}; + + +constexpr OString s = OStringHolder{};