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

-- >8 --

A lambda within a default template argument used in some template-id
may have a smaller template depth than the context of the template-id.
For example, the lambda in v1's default template argument has template
depth 1, and in v2's has template depth 2, but the template-ids v1<0>
and v2<0> which uses these default arguments appear in a depth 3 template
context.  So add_extra_args will ultimately return args with depth 3 --
too many args for the lambda, leading to a bogus substitution.

This patch fixes this by trimming the result of add_extra_args to match
the template depth of the lambda.  A new LAMBDA_EXPR_TEMPLATE_DEPTH field
is added that tracks the template-ness of a lambda;

        PR c++/116567

gcc/cp/ChangeLog:

        * pt.cc (tsubst_lambda_expr): For a deferred-substitution lambda,
        trim the augmented template arguments to match the template depth
        of the lambda.

gcc/testsuite/ChangeLog:

        * g++.dg/cpp2a/lambda-targ7.C: New test.
---
 gcc/cp/pt.cc                              | 11 +++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 30 +++++++++++++++++++++++
 2 files changed, 41 insertions(+)
 create mode 100644 gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C

diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 747e627f547..c49a26b4f5e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -19699,6 +19699,17 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t 
complain, tree in_decl)
       LAMBDA_EXPR_EXTRA_ARGS (t) = build_extra_args (t, args, complain);
       return t;
     }
+  if (LAMBDA_EXPR_EXTRA_ARGS (t))
+    {
+      /* If we deferred substitution into this lambda, then it's probably from
+        a context (e.g. default template argument context) which may have fewer
+        levels than the current context it's embedded in.  Adjust the result of
+        add_extra_args accordingly.  */
+      tree ctx_parms = DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (oldfn));
+      if (generic_lambda_fn_p (oldfn))
+       ctx_parms = TREE_CHAIN (ctx_parms);
+      args = get_innermost_template_args (args, TMPL_PARMS_DEPTH (ctx_parms));
+    }
 
   tree r = build_lambda_expr ();
 
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
new file mode 100644
index 00000000000..c5c0525908e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C
@@ -0,0 +1,30 @@
+// PR c++/116567
+// { dg-do compile { target c++20 } }
+
+template<auto N, auto F = []{}>
+bool v1 = true;
+
+template<auto N, auto F = [](auto){}>
+bool v1g = true;
+
+template<class T>
+struct A {
+  template<auto N, auto F = []{}>
+  static inline bool v2 = true;
+
+  template<auto N, auto F = [](auto){}>
+  static inline bool v2g = true;
+
+  template<class U>
+  struct B {
+    template<class V>
+    static void f() {
+      v1<0> && v1g<0>;
+      v2<0> && v2g<0>;
+    }
+  };
+};
+
+auto main() -> int {
+  A<int>::B<int>::f<int>();
+}
-- 
2.46.0.519.g2e7b89e038

Reply via email to