Here we ICE during instantiation of the dependently scoped template
friend
template<int N>
struct<class T>
friend class A<N>::B;
ultimately because processing_template_decl isn't set during
substitution into the A<N> scope. Since it's naturally a partial
substitution, we need to make sure the flag is set.
For GCC 15, this is already fixed similarly by r15-123.
PR c++/119378
gcc/cp/ChangeLog:
* pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Set
processing_template_decl when substituting the context.
gcc/testsuite/ChangeLog:
* g++.dg/template/friend85.C: New test.
Reviewed-by: Jason Merrill <jason@redhat.com>
case UNBOUND_CLASS_TEMPLATE:
{
+ ++processing_template_decl;
tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, complain,
in_decl, /*entering_scope=*/1);
+ --processing_template_decl;
tree name = TYPE_IDENTIFIER (t);
tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
--- /dev/null
+// PR c++/119378
+
+template<int N>
+struct A {
+ template<class T>
+ struct B;
+};
+
+template<class U>
+struct C {
+ template<int N>
+ template<class T>
+ friend class A<N>::B;
+};
+
+template struct C<int>;