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