Bootstrapped and regtested on x86_64-pc-linux-gnu, does this look
OK for trunk/15/14?

-- >8 --

In r15-123 and r14-11434 we unconditionally set processing_template_decl
when substituting the context of an UNBOUND_CLASS_TEMPLATE, in order to
handle instantiation of the dependently scoped friend declaration

  template<int N>
  template<class T>
  friend class A<N>::B;

where the scope A<N> remains dependent after instantiation.  But this
turns out to misbehave for the UNBOUND_CLASS_TEMPLATE in the below
testcase

  g<[]{}>::template fn

since with the flag set substituting the args of test3 into the lambda
causes us to defer the substitution and yield a lambda that still looks
dependent, which in turn make g<[]{}> still dependent and not suitable
for qualified name lookup.

This patch restricts setting processing_template_decl during
UNBOUND_CLASS_TEMPLATE substitution to the case where there are multiple
levels of captured template parameters, as in the friend declaration.
(This means we need to substitute the template parameter list(s) first,
which makes sense since they lexically appear first.)

        PR c++/119981
        PR c++/119378

gcc/cp/ChangeLog:

        * pt.cc (tsubst) <case UNBOUND_CLASS_TEMPLATE>: Substitute
        into template parameter list first.  When substituting the
        context, only set processing_template_decl if there's more
        than one level of template parameters.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-targ15.C: New test.
---
 gcc/cp/pt.cc                               | 20 +++++++++++++-------
 gcc/testsuite/g++.dg/cpp2a/lambda-targ15.C | 17 +++++++++++++++++
 2 files changed, 30 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ15.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index e8d342f99f6d..26ed9de430c0 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -17181,18 +17181,24 @@ tsubst (tree t, tree args, tsubst_flags_t complain, 
tree in_decl)
 
     case UNBOUND_CLASS_TEMPLATE:
       {
-       ++processing_template_decl;
-       tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args,
-                                         complain, in_decl);
-       --processing_template_decl;
        tree name = TYPE_IDENTIFIER (t);
+       if (name == error_mark_node)
+         return error_mark_node;
+
        tree parm_list = DECL_TEMPLATE_PARMS (TYPE_NAME (t));
+       parm_list = tsubst_template_parms (parm_list, args, complain);
+       if (parm_list == error_mark_node)
+         return error_mark_node;
 
-       if (ctx == error_mark_node || name == error_mark_node)
+       if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1)
+         ++processing_template_decl;
+       tree ctx = tsubst_entering_scope (TYPE_CONTEXT (t), args,
+                                         complain, in_decl);
+       if (parm_list && TMPL_PARMS_DEPTH (parm_list) > 1)
+         --processing_template_decl;
+       if (ctx == error_mark_node)
          return error_mark_node;
 
-       if (parm_list)
-         parm_list = tsubst_template_parms (parm_list, args, complain);
        return make_unbound_class_template (ctx, name, parm_list, complain);
       }
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ15.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ15.C
new file mode 100644
index 000000000000..90160a52a6ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ15.C
@@ -0,0 +1,17 @@
+// PR c++/119981
+// { dg-do compile { target c++20 } }
+
+template<template<class> class P>
+struct mp_copy_if{};
+
+template<auto Fn>
+struct g {
+  template<class> struct fn{};
+};
+
+template<typename>
+void test3() {
+  mp_copy_if<g<[]{}>::template fn> b;
+}
+
+template void test3<int>();
-- 
2.49.0.459.gf65182a99e

Reply via email to