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;
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)
{
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 ()));
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
--- /dev/null
+// PR c++/124926
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+template <typename T, typename U>
+constexpr bool is_same_v = false;
+
+template <typename T>
+constexpr bool is_same_v<T, T> = true;
+
+// Class template
+template <typename>
+struct C1 {
+ template <typename> struct Inner {};
+};
+
+template <typename T>
+constexpr auto vt1 = ^^C1<T>::template Inner;
+constexpr auto r1 = vt1<int>;
+typename [:r1:]<int> a;
+static_assert(r1 == ^^C1<int>::template Inner);
+static_assert(is_same_v<decltype(a), C1<int>::Inner<int>>);
+
+// Class template with typename
+template <typename>
+struct C6 {
+ template <typename> struct Inner {};
+};
+
+template <typename T>
+constexpr auto vt6 = ^^typename C6<T>::template Inner<T>;
+constexpr auto r6 = vt6<int>;
+typename [:r6:] d;
+static_assert(r6 == ^^C6<int>::template Inner<int>);
+static_assert(is_same_v<decltype(d), C6<int>::Inner<int>>);
+
+// Variable template
+template <typename>
+struct C2 {
+ template <typename> static constexpr int Inner = 42;
+};
+
+template <typename T>
+constexpr auto vt2 = ^^C2<T>::template Inner;
+constexpr auto r2 = vt2<int>;
+constexpr int i = template [:r2:]<int>;
+static_assert(i == 42);
+static_assert(vt2<int> == ^^C2<int>::template Inner);
+
+// Function template
+template <typename>
+struct C3 {
+ template <typename T> static constexpr int Inner (T t) { return t; };
+};
+template <typename T>
+constexpr auto vt3 = ^^C3<T>::template Inner;
+constexpr auto r3 = vt3<int>;
+static_assert(template [:r3:](42) == 42);
+static_assert(vt3<int> == ^^C3<int>::template Inner);
+
+// Alias template
+template <typename>
+struct C4 {
+ template <typename T> using Inner = C4<T>;
+};
+template <typename T>
+constexpr auto vt4 = ^^C4<T>::template Inner;
+constexpr auto r4 = vt4<int>;
+typename [:r4:]<int> b;
+static_assert(is_same_v<decltype(b), C4<int>>);
+static_assert(vt4<int> == ^^C4<int>::template Inner);
+
+// Alias template with typename
+template<typename T> struct X { };
+
+template <typename>
+struct C5 {
+ template <typename T> using Inner = X<T>;
+};
+template <typename T>
+constexpr auto vt5 = ^^typename C5<T>::template Inner<T>;
+constexpr auto r5 = vt5<int>;
+typename [:r5:] c;
+static_assert(is_same_v<decltype(c), X<int>>);
+static_assert(vt5<int> == ^^C5<int>::template Inner<int>);