https://gcc.gnu.org/g:6bfec5d7b8b87f505d974da8e24240af11b9914e

commit r16-7213-g6bfec5d7b8b87f505d974da8e24240af11b9914e
Author: Nathaniel Shead <[email protected]>
Date:   Sat Jan 24 19:34:53 2026 +1100

    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 <[email protected]>
    Reviewed-by: Jason Merrill <[email protected]>

Diff:
---
 gcc/cp/cp-gimplify.cc                        | 39 ++++++++++++++--------------
 gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C | 14 ++++++++++
 gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C  | 19 ++++++++++++++
 3 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 38cee83ab763..9d96ce99ea92 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 000000000000..900c8053a929
--- /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 000000000000..659beed3a255
--- /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<auto L> struct OStringHolder {
+    static constexpr auto & literal = L;
+};
+
+struct OString {
+    template<auto L> constexpr OString(OStringHolder<L> const &):
+        p(&OStringHolder<L>::literal.str) {}
+    int const * p;
+};
+
+
+constexpr OString s = OStringHolder<OStringLiteral{}>{};

Reply via email to