The combination of DR 2481 and DR 2126 should allow us to do

  void f()
  {
    constexpr const int &r = 42;
    static_assert(r == 42);
  }

because [expr.const]/4.7 now says that "a temporary object of
non-volatile const-qualified literal type whose lifetime is extended to
that of a variable that is usable in constant expressions" is usable in
a constant expression.

I think the temporary is supposed to be const-qualified, because Core 2481
says so.  I was happy to find out that we already mark the temporary as
const + constexpr in set_up_extended_ref_temp.

But that wasn't enough to make the test above work: references are
traditionally implemented as pointers, so the temporary object will be
(const int &)&D.1234, and verify_constant -> reduced_constant_expression_p
-> initializer_constant_valid_p_1 doesn't think that's OK -- and rightly
so -- the address of a local variable certainly isn't constant.  Therefore
I'm skipping the verify_constant check in cxx_eval_outermost_constant_expr.
(DECL_INITIAL isn't checked because maybe we are still waiting for
initialize_local_var to set it.)

Then we need to be able to evaluate such a reference.  This I do by
seeing through the reference in cxx_eval_constant_expression.  I can't
rely on decl_constant_value to pull out DECL_INITIAL, because the VAR_DECL
isn't DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P, and I think we don't
need to mess with that if we're keeping this purely in constexpr.

I wonder if we should accept

  void f2()
  {
    constexpr int &&r = 42;
    static_assert(r == 42);
  }

Currently we don't -- CP_TYPE_CONST_NON_VOLATILE_P (type) is false in
set_up_extended_ref_temp.

Does this make sense?  Bootstrapped/regtested on x86_64-pc-linux-gnu.

        PR c++/100976
        DR 2481

gcc/cp/ChangeLog:

        * constexpr.c (cxx_eval_constant_expression): For a constexpr
        reference, return its DECL_INITIAL.
        (cxx_eval_outermost_constant_expr): Don't verify the initializer
        for a constexpr variable of reference type.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/constexpr-ref2.C: Remove dg-error.
        * g++.dg/cpp0x/constexpr-temp2.C: New test.
        * g++.dg/cpp23/constexpr-temp1.C: New test.
        * g++.dg/cpp23/constexpr-temp2.C: New test.
---
 gcc/cp/constexpr.c                           | 29 +++++++++++++--
 gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C  |  5 ++-
 gcc/testsuite/g++.dg/cpp0x/constexpr-temp2.C | 15 ++++++++
 gcc/testsuite/g++.dg/cpp23/constexpr-temp1.C | 39 ++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp23/constexpr-temp2.C | 23 ++++++++++++
 5 files changed, 106 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-temp2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/constexpr-temp1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp23/constexpr-temp2.C

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 31fa5b66865..80b4985d055 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -6180,6 +6180,22 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
          return cxx_eval_constant_expression (ctx, r, lval, non_constant_p,
                                               overflow_p);
        }
+      /* DR 2126 amended [expr.const]/4.7 to say that "a temporary object
+        of non-volatile const-qualified literal type whose lifetime is
+        extended to that of a variable that is usable in constant
+        expressions" is usable in a constant expression.  Along with
+        DR 2481 this means that we should accept
+
+          constexpr const int &r = 42;
+          static_assert (r == 42);
+
+        Take a shortcut here rather than using decl_constant_value.  The
+        temporary was marked constexpr in set_up_extended_ref_temp.  */
+      else if (TYPE_REF_P (TREE_TYPE (t))
+              && DECL_DECLARED_CONSTEXPR_P (t)
+              && DECL_INITIAL (t))
+       return cxx_eval_constant_expression (ctx, DECL_INITIAL (t), lval,
+                                            non_constant_p, overflow_p);
       /* fall through */
     case CONST_DECL:
       /* We used to not check lval for CONST_DECL, but darwin.c uses
@@ -7289,10 +7305,17 @@ cxx_eval_outermost_constant_expr (tree t, bool 
allow_non_constant,
   r = cxx_eval_constant_expression (&ctx, r,
                                    false, &non_constant_p, &overflow_p);
 
-  if (!constexpr_dtor)
-    verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
-  else
+  if (object && VAR_P (object)
+      && DECL_DECLARED_CONSTEXPR_P (object)
+      && TYPE_REF_P (TREE_TYPE (object)))
+  /* Circumvent verify_constant, because it ends up calling
+     initializer_constant_valid_p which doesn't like taking
+     the address of a local variable.  But that's OK since
+     DR 2126 + DR 2481, at least in a constexpr context.  */;
+  else if (constexpr_dtor)
     DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (object) = true;
+  else
+    verify_constant (r, allow_non_constant, &non_constant_p, &overflow_p);
 
   unsigned int i;
   tree cleanup;
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C
index 76973638d5f..b7701b849df 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref2.C
@@ -9,9 +9,10 @@ constexpr int& ri2 = er;       // { dg-error "er" }
 
 void f(int j)
 {
+  // Used to be erroneous, but allowed since DR 2481.
   constexpr int i = 42;
-  constexpr int const& ri = i; // { dg-error "" }
+  constexpr int const& ri = i;
 
-  constexpr int& rj = j;       // { dg-error "" }
+  constexpr int& rj = j;
 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-temp2.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-temp2.C
new file mode 100644
index 00000000000..e396264cff3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-temp2.C
@@ -0,0 +1,15 @@
+// DR 2126 - Lifetime-extended temporaries in constant expressions
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert ((X),#X)
+
+typedef const int CI[3];
+constexpr CI &ci = CI{1, 2, 3};
+SA(ci[1] == 2);
+
+void
+g ()
+{
+  constexpr CI &r = CI{1, 2, 3};
+  SA(r[1] == 2);
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-temp1.C 
b/gcc/testsuite/g++.dg/cpp23/constexpr-temp1.C
new file mode 100644
index 00000000000..0d3f4972563
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-temp1.C
@@ -0,0 +1,39 @@
+// PR c++/100976
+// DR 2481 - Cv-qualification of temporary to which a reference is bound
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert ((X),#X)
+
+struct literal {
+    int m;
+    constexpr literal() : m() { }
+    constexpr literal(int n) : m(n) { }
+};
+
+void
+g ()
+{
+  constexpr const int &r = 42;
+  constexpr const int &&rr = 42;
+  constexpr int x = 42;
+  constexpr static int sx = 42;
+  constexpr const auto &rx = x;
+  constexpr const auto &rsx = sx;
+  SA(r == 42);
+  SA(rr == 42);
+  SA(rx == 42);
+  SA(rsx == 42);
+  SA(&rx == &x);
+  SA(&rsx == &sx);
+  const int *pr = &r;
+  const int *prr = &rr;
+}
+
+void
+f ()
+{
+  constexpr const literal &r = { 42 };
+  SA(r.m == 42);
+  constexpr const literal &&rr = { 42 };
+  SA(rr.m == 42);
+}
diff --git a/gcc/testsuite/g++.dg/cpp23/constexpr-temp2.C 
b/gcc/testsuite/g++.dg/cpp23/constexpr-temp2.C
new file mode 100644
index 00000000000..1e1169ac5e1
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/constexpr-temp2.C
@@ -0,0 +1,23 @@
+// PR c++/100976
+// DR 2481 - Cv-qualification of temporary to which a reference is bound
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert ((X),#X)
+
+int
+main ()
+{
+  constexpr const volatile int &r = 42; // { dg-error "cannot bind" }
+  constexpr const volatile int &&rr = 42;
+  constexpr int x = 42;
+  constexpr const volatile auto &rx = x;
+  SA(rr == 42); // { dg-error "non-constant|lvalue-to-rvalue" }
+  SA(rx == 42); // { dg-error "non-constant|lvalue-to-rvalue" }
+
+  int i = 42;
+  constexpr const auto &ri = i;
+  SA(ri == 42); // { dg-error "non-constant|not usable" }
+
+  constexpr const int &missing; // { dg-error "not initialized" }
+  SA ((bool(missing), true));
+}

base-commit: f364cdffa47af574f90f671b2dcf5afa91442741
-- 
2.31.1

Reply via email to