On 3/10/26 6:44 PM, Marek Polacek wrote:
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
Maybe let's name the parameter something that's more about the semantics we want than why we want those semantics, say "lookup_only"?
OK either way.
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 treetsubst_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
