complain, in_decl);
if (argvec == error_mark_node)
r = error_mark_node;
+ else if (cxx_dialect >= cxx20 && dependent_scope_p (context))
+ {
+ /* See maybe_dependent_member_ref. */
+ tree name = TYPE_IDENTIFIER (t);
+ tree fullname = name;
+ if (instantiates_primary_template_p (t))
+ fullname = build_nt (TEMPLATE_ID_EXPR, name,
+ INNERMOST_TEMPLATE_ARGS (argvec));
+ return build_typename_type (context, name, fullname,
+ typename_type);
+ }
else
{
r = lookup_template_class (t, argvec, in_decl, context,
return init;
}
+/* If T is a reference to a dependent member of the current instantiation C and
+ we are trying to refer to that member in a partial instantiation of C,
+ return a SCOPE_REF; otherwise, return NULL_TREE.
+
+ This can happen when forming a C++20 alias template deduction guide, as in
+ PR96199. */
+
+static tree
+maybe_dependent_member_ref (tree t, tree args, tsubst_flags_t complain,
+ tree in_decl)
+{
+ if (cxx_dialect < cxx20)
+ return NULL_TREE;
+
+ tree ctx = context_for_name_lookup (t);
+ if (!CLASS_TYPE_P (ctx))
+ return NULL_TREE;
+
+ ctx = tsubst (ctx, args, complain, in_decl);
+ if (dependent_scope_p (ctx))
+ return build_qualified_name (NULL_TREE, ctx, DECL_NAME (t),
+ /*template_p=*/false);
+
+ return NULL_TREE;
+}
+
/* Like tsubst, but deals with expressions. This function just replaces
template parms; to finish processing the resultant expression, use
tsubst_copy_and_build or tsubst_expr. */
if (args == NULL_TREE)
return scalar_constant_value (t);
+ if (tree ref = maybe_dependent_member_ref (t, args, complain, in_decl))
+ return ref;
+
/* Unfortunately, we cannot just call lookup_name here.
Consider:
return t;
case VAR_DECL:
+ if (tree ref = maybe_dependent_member_ref (t, args, complain, in_decl))
+ return ref;
+ gcc_fallthrough();
case FUNCTION_DECL:
if (DECL_LANG_SPECIFIC (t) && DECL_TEMPLATE_INFO (t))
r = tsubst (t, args, complain, in_decl);
--- /dev/null
+// PR c++/96199
+// { dg-do compile { target c++2a } }
+
+template<int> struct A1 { };
+template<int&> struct A2 { };
+template<class> struct A3 { };
+
+int i;
+template<typename V, int> struct B {
+ enum E { X };
+ B(A1<X>, V) { }
+
+ constexpr static V& ir = i;
+ B(A2<ir>, V) { }
+
+ B(A3<E>, V);
+};
+
+// template<class T, int I> B(A1<B<T,I>::X>,T) -> B<T,I>;
+// template<class T, int I> B(A2<B<T,I>::ir>,T) -> B<T,I>;
+// template<class T, int I> B(A3<typename B<T,I>::E>,T) -> B<T,I>;
+
+template <typename T> using U = B<T, 1>;
+
+// template<class T> B(A1<B<T,1>::X>,T) -> B<T,1>;
+// template<class T> B(A2<B<T,1>::ir>,T) -> B<T,1>;
+// template<class T> B(A3<typename B<T,1>::E>,T) -> B<T,1>;
+
+int j;
+template <> struct B<int, 1> {
+ using V = int;
+
+ enum E { X = 1 };
+ B(A1<X>, V) { }
+
+ constexpr static V& ir = j;
+ B(A2<ir>, V) { }
+
+ B(A3<E>, V);
+};
+
+U u1 { A1<1>(), 42 };
+U u2 { A2<j>(), 42 };
+U u3 { A3<U<int>::E>(), 42 };