From: Marek Polacek Date: Wed, 22 Apr 2026 15:36:37 +0000 (-0400) Subject: c++/reflection: reflect on dependent class template [PR124926] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f78cb5ae260a88d9499d1496f3ba6fd54dd04bac;p=thirdparty%2Fgcc.git c++/reflection: reflect on dependent class template [PR124926] Here we issue a bogus error for ^^Cls::template Inner where Inner turns out to be a class type, but we created a SCOPE_REF because we can't know in advance what it will substitute into, and ^^typename Cls::template Inner is invalid. The typename can only be used in ^^typename Cls::template Inner We're taking a reflection so both types and non-types are valid, so I think we shouldn't give the error for ^^, and take the reflection of the TEMPLATE_DECL. PR c++/124926 gcc/cp/ChangeLog: * pt.cc (tsubst_qualified_id): Rename name_lookup_p parameter to reflecting_p. Check !reflecting_p instead of name_lookup_p. Do not give the "instantiation yields a type" error when reflecting_p is true. (tsubst_expr) : Adjust the call to tsubst_qualified_id. gcc/testsuite/ChangeLog: * g++.dg/reflect/dep15.C: New test. Reviewed-by: Patrick Palka --- diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 5d97ca7997f..551c8bcbb68 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -18238,12 +18238,12 @@ 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 "&". NAME_LOOKUP_P is true if we intend to perform name lookup. */ + of "&". REFLECTING_P is true if this SCOPE_REF is an operand of ^^. */ static tree tsubst_qualified_id (tree qualified_id, tree args, tsubst_flags_t complain, tree in_decl, - bool done, bool address_p, bool name_lookup_p = true) + bool done, bool address_p, bool reflecting_p = false) { tree expr; tree scope; @@ -18322,7 +18322,9 @@ tsubst_qualified_id (tree qualified_id, tree args, else expr = lookup_qualified_name (scope, expr, LOOK_want::NORMAL, false); if (TREE_CODE (TREE_CODE (expr) == TEMPLATE_DECL - ? DECL_TEMPLATE_RESULT (expr) : expr) == TYPE_DECL) + ? DECL_TEMPLATE_RESULT (expr) : expr) == TYPE_DECL + /* For ^^T::X, we'll take both types and non-types. */ + && !reflecting_p) { if (complain & tf_error) { @@ -18368,7 +18370,7 @@ tsubst_qualified_id (tree qualified_id, tree args, expr, input_location); /* 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) && name_lookup_p) + else if (TYPE_P (scope) && !reflecting_p) { expr = (adjust_result_of_qualified_name_lookup (expr, scope, current_nonlambda_class_type ())); @@ -23355,7 +23357,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) else if (TREE_CODE (h) == SCOPE_REF) h = tsubst_qualified_id (h, args, complain, in_decl, /*done=*/true, /*address_p=*/false, - /*name_lookup_p=*/false); + /*reflecting_p=*/true); else { /* [expr.reflect] The id-expression of a reflect-expression is diff --git a/gcc/testsuite/g++.dg/reflect/dep15.C b/gcc/testsuite/g++.dg/reflect/dep15.C new file mode 100644 index 00000000000..40273955164 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/dep15.C @@ -0,0 +1,85 @@ +// PR c++/124926 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +template +constexpr bool is_same_v = false; + +template +constexpr bool is_same_v = true; + +// Class template +template +struct C1 { + template struct Inner {}; +}; + +template +constexpr auto vt1 = ^^C1::template Inner; +constexpr auto r1 = vt1; +typename [:r1:] a; +static_assert(r1 == ^^C1::template Inner); +static_assert(is_same_v::Inner>); + +// Class template with typename +template +struct C6 { + template struct Inner {}; +}; + +template +constexpr auto vt6 = ^^typename C6::template Inner; +constexpr auto r6 = vt6; +typename [:r6:] d; +static_assert(r6 == ^^C6::template Inner); +static_assert(is_same_v::Inner>); + +// Variable template +template +struct C2 { + template static constexpr int Inner = 42; +}; + +template +constexpr auto vt2 = ^^C2::template Inner; +constexpr auto r2 = vt2; +constexpr int i = template [:r2:]; +static_assert(i == 42); +static_assert(vt2 == ^^C2::template Inner); + +// Function template +template +struct C3 { + template static constexpr int Inner (T t) { return t; }; +}; +template +constexpr auto vt3 = ^^C3::template Inner; +constexpr auto r3 = vt3; +static_assert(template [:r3:](42) == 42); +static_assert(vt3 == ^^C3::template Inner); + +// Alias template +template +struct C4 { + template using Inner = C4; +}; +template +constexpr auto vt4 = ^^C4::template Inner; +constexpr auto r4 = vt4; +typename [:r4:] b; +static_assert(is_same_v>); +static_assert(vt4 == ^^C4::template Inner); + +// Alias template with typename +template struct X { }; + +template +struct C5 { + template using Inner = X; +}; +template +constexpr auto vt5 = ^^typename C5::template Inner; +constexpr auto r5 = vt5; +typename [:r5:] c; +static_assert(is_same_v>); +static_assert(vt5 == ^^C5::template Inner);