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

-- >8 --
In compare11.C, the static_assert was wrongly failing because
compare_reflections got a FIELD_DECL and COMPONENT_REF for ^^S::mem.
We shouldn't have created the COMPONENT_REF.  So this patch avoids
creating the COMPONENT_REF by avoiding the finish_qualified_id_expr
call in tsubst_qualified_id when processing a REFLECT_EXPR.

Happily, it fixed some other issues too.

Unfortunately, I found another issue (PR124440) while trying to test
this patch more extensively.  I plan to fix that separately next.

        PR c++/124331

gcc/cp/ChangeLog:

        * pt.cc (tsubst_qualified_id): New reflect_p parameter.  Don't call
        adjust_result_of_qualified_name_lookup and finish_qualified_id_expr
        if reflect_p.
        (tsubst_expr) <case REFLECT_EXPR>: Handle SCOPE_REF specially by
        calling tsubst_qualified_id with reflect_p=true.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/expr13.C: Uncomment the commented out assert.
        * g++.dg/reflect/serialize2.C: Replace #if 0 with #ifdef.
        * g++.dg/reflect/compare11.C: New test.
        * g++.dg/reflect/member21.C: New test.
        * g++.dg/reflect/serialize3.C: New test.
---
 gcc/cp/pt.cc                              | 13 ++++++---
 gcc/testsuite/g++.dg/reflect/compare11.C  | 15 +++++++++++
 gcc/testsuite/g++.dg/reflect/expr13.C     |  3 +--
 gcc/testsuite/g++.dg/reflect/member21.C   | 32 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/reflect/serialize2.C |  3 +--
 gcc/testsuite/g++.dg/reflect/serialize3.C |  5 ++++
 6 files changed, 64 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/reflect/compare11.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/member21.C
 create mode 100644 gcc/testsuite/g++.dg/reflect/serialize3.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index ddf492b3435..7a6476caf89 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -18069,12 +18069,13 @@ tsubst_baselink (tree baselink, tree object_type,
    true if the qualified-id will be a postfix-expression in-and-of
    itself; false if more of the postfix-expression follows the
    QUALIFIED_ID.  ADDRESS_P is true if the qualified-id is the operand
-   of "&".  */
+   of "&".  REFLECT_P is true if we are substituting the operand of
+   a reflect-expression.  */
 
 static tree
 tsubst_qualified_id (tree qualified_id, tree args,
                     tsubst_flags_t complain, tree in_decl,
-                    bool done, bool address_p)
+                    bool done, bool address_p, bool reflect_p = false)
 {
   tree expr;
   tree scope;
@@ -18197,7 +18198,9 @@ tsubst_qualified_id (tree qualified_id, tree args,
   if (expr == error_mark_node && complain & tf_error)
     qualified_name_lookup_error (scope, TREE_OPERAND (qualified_id, 1),
                                 expr, input_location);
-  else if (TYPE_P (scope))
+  /* For ^^S::mem, we do not want to create the dummy object that
+     finish_non_static_data_member would give us.  */
+  else if (TYPE_P (scope) && !reflect_p)
     {
       expr = (adjust_result_of_qualified_name_lookup
              (expr, scope, current_nonlambda_class_type ()));
@@ -23155,6 +23158,10 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
             instantiated entities and so no need to tsubst the annotation
             attribute and we rely on pointer equality of that.  */
          ;
+       else if (TREE_CODE (h) == SCOPE_REF)
+         h = tsubst_qualified_id (h, args, complain, in_decl,
+                                  /*done=*/true, /*address_p=*/false,
+                                  /*reflect_p=*/true);
        else
          {
            /* [expr.reflect] The id-expression of a reflect-expression is
diff --git a/gcc/testsuite/g++.dg/reflect/compare11.C 
b/gcc/testsuite/g++.dg/reflect/compare11.C
new file mode 100644
index 00000000000..d2339543d2c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/compare11.C
@@ -0,0 +1,15 @@
+// PR c++/124331
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template <typename T>
+void f() {
+    constexpr auto ctx = std::meta::access_context::current();
+    static constexpr auto rng = 
std::define_static_array(nonstatic_data_members_of(^^T, ctx));
+    static_assert(rng[0] == ^^T::mem);
+};
+
+struct S { int mem; };
+auto force_instantiation = (f<S>, 0);
diff --git a/gcc/testsuite/g++.dg/reflect/expr13.C 
b/gcc/testsuite/g++.dg/reflect/expr13.C
index 6be27640ed7..14978bc1ecc 100644
--- a/gcc/testsuite/g++.dg/reflect/expr13.C
+++ b/gcc/testsuite/g++.dg/reflect/expr13.C
@@ -16,5 +16,4 @@ constexpr auto foo (S s) {
 }
 
 constexpr auto a = foo (Y { 42 });
-// TODO: This doesn't work: 'const struct X<^^Y::name>' is not the same as 
'const struct X<^^Y::name>'
-//static_assert (std::is_same_v <decltype (a), const X <^^Y::name>>);
+static_assert (std::is_same_v <decltype (a), const X <^^Y::name>>);
diff --git a/gcc/testsuite/g++.dg/reflect/member21.C 
b/gcc/testsuite/g++.dg/reflect/member21.C
new file mode 100644
index 00000000000..48ce3f1631d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/member21.C
@@ -0,0 +1,32 @@
+// PR c++/124331
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct B { consteval virtual int fn() const { return 1; } };
+struct D : B { consteval int fn() const override { return 2; } };
+
+constexpr D d;
+
+template<typename T, typename U>
+void
+f ()
+{
+  static_assert(d.[:^^U::fn:]() == 2);
+  static_assert(d.[:^^D::fn:]() == 2);
+  static_assert(d.U::fn() == 2);
+  static_assert(d.D::fn() == 2);
+  static_assert(d.fn() == 2);
+  // FIXME PR124440
+  //static_assert(d.[:^^T::fn:]() == 2);
+  static_assert(d.[:^^T:]::fn() == 1);
+  static_assert(d.T::fn() == 1);
+  //static_assert(d.[:^^B::fn:]() == 2);
+  static_assert(d.[:^^B:]::fn() == 1);
+  static_assert(d.B::fn() == 1);
+}
+
+void
+g ()
+{
+  f<B, D>();
+}
diff --git a/gcc/testsuite/g++.dg/reflect/serialize2.C 
b/gcc/testsuite/g++.dg/reflect/serialize2.C
index 9b3ae685589..48a7b266b86 100644
--- a/gcc/testsuite/g++.dg/reflect/serialize2.C
+++ b/gcc/testsuite/g++.dg/reflect/serialize2.C
@@ -36,8 +36,7 @@ constexpr std::string
 serialize (S s)
 {
   std::string result = " ";
-#if 0
-  // TODO, this ICEs in tsubst_expr.
+#ifdef TEST_SERIALIZE3
   impl::replicator <^^S::age, ^^S::name> >> [&] <auto m> {
 #else
   impl::replicator <^^Person::age, ^^Person::name> >> [&] <auto m> {
diff --git a/gcc/testsuite/g++.dg/reflect/serialize3.C 
b/gcc/testsuite/g++.dg/reflect/serialize3.C
new file mode 100644
index 00000000000..13367b71572
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/serialize3.C
@@ -0,0 +1,5 @@
+// { dg-do run { target c++26 } }
+// { dg-additional-options "-freflection -O0" }
+
+#define TEST_SERIALIZE3
+#include "serialize2.C"

base-commit: 9c483886957cac7016dc404c2b6aab2ae94574a9
-- 
2.53.0

Reply via email to