Bootstrapped and regtested on x86_64-pc-linux-gnu, OK for trunk?

-- >8 --

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 forcing the expression
  to be an ADDR_EXPR before calling 'maybe_constant_value', and then
  folding it away afterwards.

- 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_non_odr_use_1): Add 'rval' parameter;
        ensure maybe_constant_value doesn't fold away lvalue usages.
        (cp_fold_maybe_rvalue): Pass rval to cp_fold_non_odr_use_1.
        (cp_fold): Pass rval=false 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]>
---
 gcc/cp/cp-gimplify.cc                        | 26 +++++++++++++++-----
 gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C | 14 +++++++++++
 gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C  | 19 ++++++++++++++
 3 files changed, 53 insertions(+), 6 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ice22.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-ref2.C

diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 3c0f415fa87..f8b35700033 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -3080,7 +3080,7 @@ cxx_omp_disregard_value_expr (tree decl, bool shared)
 /* Fold any non-ODR-usages of a constant variable in expression X.  */
 
 static tree
-cp_fold_non_odr_use_1 (tree x)
+cp_fold_non_odr_use_1 (tree x, bool rval)
 {
   tree var = x;
   while (!VAR_P (var))
@@ -3117,8 +3117,18 @@ cp_fold_non_odr_use_1 (tree x)
       && id_equal (DECL_NAME (var), "hardware_destructive_interference_size"))
     return x;
 
-  tree t = maybe_constant_value (x);
-  return TREE_CONSTANT (t) ? t : x;
+  tree r = x;
+  if (rval)
+    r = maybe_constant_value (r);
+  else
+    {
+      location_t loc = location_of (r);
+      r = build_fold_addr_expr_loc (loc, r);
+      r = maybe_constant_value (r);
+      if (TREE_CONSTANT (r))
+       r = build_fold_indirect_ref_loc (loc, r);
+    }
+  return TREE_CONSTANT (r) ? r : x;
 }
 
 /* Fold expression X which is used as an rvalue if RVAL is true.  */
@@ -3133,7 +3143,7 @@ cp_fold_maybe_rvalue (tree x, bool rval, fold_flags_t 
flags)
        x = mark_rvalue_use (x);
       if (rval && (flags & ff_only_non_odr))
        {
-         tree v = cp_fold_non_odr_use_1 (x);
+         tree v = cp_fold_non_odr_use_1 (x, rval);
          if (v != x)
            {
              x = v;
@@ -3411,7 +3421,7 @@ 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);
+         tree r = cp_fold_non_odr_use_1 (x, /*rval=*/false);
          if (r != x)
            return convert_from_reference (cp_fold (r, flags));
        }
@@ -3560,7 +3570,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<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{}>{};
-- 
2.51.0

Reply via email to