Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch is an attempt to implement (part of?) P2280, Using unknown
pointers and references in constant expressions.  (Note that R4 seems to
only allow References to unknown/Accesses via this, but not Pointers to
unknown.)

This patch works to the extent that the test case added in [expr.const]
works as expected, as well as the test in
<https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2280r4.html#the-this-pointer>

Most importantly, the proposal makes this compile:

  template <typename T, size_t N>
  constexpr auto array_size(T (&)[N]) -> size_t {
      return N;
  }

  void check(int const (&param)[3]) {
      constexpr auto s = array_size(param);
      static_assert (s == 3);
  }

and I think it would be a pity not to have it in GCC 14.

What still doesn't work (and I don't know if it should) is the test in $3.2:

  struct A2 { constexpr int f() { return 0; } };
  struct B2 : virtual A2 {};
  void f2(B2 &b) { constexpr int k = b.f(); }

where we say
error: '* & b' is not a constant expression

        PR c++/106650

gcc/cp/ChangeLog:

        * constexpr.cc (cxx_eval_constant_expression): Allow reference to
        unknown as per P2280.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp0x/constexpr-array-ptr6.C: Remove dg-error.
        * g++.dg/cpp0x/constexpr-ref12.C: Likewise.
        * g++.dg/cpp1y/lambda-generic-const10.C: Likewise.
        * g++.dg/cpp0x/constexpr-ref13.C: New test.
        * g++.dg/cpp1z/constexpr-ref1.C: New test.
        * g++.dg/cpp1z/constexpr-ref2.C: New test.
        * g++.dg/cpp2a/constexpr-ref1.C: New test.
---
 gcc/cp/constexpr.cc                           |  2 +
 .../g++.dg/cpp0x/constexpr-array-ptr6.C       |  2 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C  |  4 +-
 gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C  | 25 +++++++++
 .../g++.dg/cpp1y/lambda-generic-const10.C     |  2 +-
 gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C   | 26 +++++++++
 gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C   | 23 ++++++++
 gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C   | 54 +++++++++++++++++++
 8 files changed, 134 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C

diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index 344107d494b..d5e487801cc 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -7378,6 +7378,8 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, 
tree t,
          r = build_constructor (TREE_TYPE (t), NULL);
          TREE_CONSTANT (r) = true;
        }
+      else if (TYPE_REF_P (TREE_TYPE (t)))
+       /* P2280 allows references to unknown.  */;
       else
        {
          if (!ctx->quiet)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C
index 1c065120314..d212665e51f 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-array-ptr6.C
@@ -12,7 +12,7 @@ constexpr auto sz_d = size(array_double);
 static_assert(sz_d == 3, "Array size failure");
 
 void f(bool (&param)[2]) {
-  static_assert(size(param) == 2, "Array size failure"); // { dg-error "" }
+  static_assert(size(param) == 2, "Array size failure");
   short data[] = {-1, 2, -45, 6, 88, 99, -345};
   static_assert(size(data) == 7, "Array size failure");
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C
index 7c3ce66b4c9..f4500144946 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref12.C
@@ -40,7 +40,7 @@ void f(a ap, a& arp)
   static_assert (g(ar2),"");   // { dg-error "constant" }
   static_assert (h(ar2),"");   // { dg-error "constant" }
 
-  static_assert (arp.g(),"");  // { dg-error "constant" }
-  static_assert (g(arp),"");   // { dg-error "constant" }
+  static_assert (arp.g(),"");
+  static_assert (g(arp),"");
   static_assert (h(arp),"");   // { dg-error "constant" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C 
b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C
new file mode 100644
index 00000000000..4be729c2301
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ref13.C
@@ -0,0 +1,25 @@
+// P2280R4 - Using unknown pointers and references in constant expressions
+// PR c++/106650
+// { dg-do compile { target c++11 } }
+
+using size_t = decltype(sizeof(42));
+
+template <typename T, size_t N>
+constexpr auto array_size(T (&)[N]) -> size_t {
+    return N;
+}
+
+void check(int const (&param)[3]) {
+    int local[] = {1, 2, 3};
+    constexpr auto s0 = array_size(local);
+    constexpr auto s1 = array_size(param);
+}
+
+template <typename T, size_t N>
+constexpr size_t array_size_ptr(T (*)[N]) {
+    return N;
+}
+
+void check_ptr(int const (*param)[3]) {
+    constexpr auto s2 = array_size_ptr(param); // { dg-error "not a constant" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C 
b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
index 2f48dae4746..47a49f58419 100644
--- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const10.C
@@ -11,7 +11,7 @@ int main()
   constexpr auto x = f(); //ok, call constexpr const non-static method
 
   [](auto const &f) {
-    constexpr auto x = f();    // { dg-error "" }
+    constexpr auto x = f();
   }(f);
 
   [&]() {
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C
new file mode 100644
index 00000000000..82771814a80
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref1.C
@@ -0,0 +1,26 @@
+// P2280R4 - Using unknown pointers and references in constant expressions
+// PR c++/106650
+// { dg-do compile { target c++17 } }
+
+#include <type_traits>
+
+template <typename T, typename U>
+constexpr bool is_type(U &&)
+{
+    return std::is_same_v<T, std::decay_t<U>>;
+}
+
+auto visitor = [](auto&& v) {
+    if constexpr(is_type<int>(v)) {
+        // ...
+    } else if constexpr(is_type<char>(v)) {
+        // ...
+    }
+};
+
+void
+g (int i)
+{
+  visitor (i);
+  constexpr bool b = is_type<int>(i);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C 
b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C
new file mode 100644
index 00000000000..ca734378141
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-ref2.C
@@ -0,0 +1,23 @@
+// P2280R4 - Using unknown pointers and references in constant expressions
+// PR c++/106650
+// { dg-do compile { target c++17 } }
+
+template <bool V>
+struct Widget {
+   struct Config {
+      static constexpr bool value = V;
+   } config;
+
+   void f() {
+       if constexpr (config.value) {
+          // ...
+       }
+   }
+};
+
+void
+g ()
+{
+  Widget<false> w;
+  w.f();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C 
b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C
new file mode 100644
index 00000000000..36866306684
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-ref1.C
@@ -0,0 +1,54 @@
+// P2280R4 - Using unknown pointers and references in constant expressions
+// PR c++/106650
+// { dg-do compile { target c++20 } }
+
+#include <typeinfo>
+
+using size_t = decltype(sizeof(42));
+
+template <typename T, size_t N>
+constexpr size_t array_size(T (&)[N]) {
+  return N;
+}
+
+void use_array(int const (&gold_medal_mel)[2]) {
+  constexpr auto gold = array_size(gold_medal_mel);     // OK
+}
+
+constexpr auto olympic_mile() {
+  const int ledecky = 1500;
+  return []{ return ledecky; };
+}
+static_assert(olympic_mile()() == 1500);                // OK
+
+struct Swim {
+  constexpr int phelps() { return 28; }
+  virtual constexpr int lochte() { return 12; }
+  int coughlin = 12;
+};
+
+constexpr int how_many(Swim& swam) {
+  Swim* p = &swam;
+  return (p + 1 - 1)->phelps();
+}
+
+void splash(Swim& swam) {
+  static_assert(swam.phelps() == 28);           // OK
+  static_assert((&swam)->phelps() == 28);       // OK
+
+  Swim* pswam = &swam;
+  static_assert(pswam->phelps() == 28);         // { dg-error 
"non-constant|not usable" }
+
+  static_assert(how_many(swam) == 28);          // OK
+  static_assert(Swim().lochte() == 12);         // OK
+
+  static_assert(swam.lochte() == 12);           // { dg-error 
"non-constant|not a constant" }
+
+  static_assert(swam.coughlin == 12);           // { dg-error 
"non-constant|not a constant" }
+}
+
+extern Swim dc;
+extern Swim& trident;
+
+constexpr auto& sandeno   = typeid(dc);         // OK, can only be typeid(Swim)
+constexpr auto& gallagher = typeid(trident);    // { dg-error "not usable" }

base-commit: 231bb992592a9e1bd7ce6583131acb1874c8e34e
-- 
2.41.0

Reply via email to