On Thu, 5 Sep 2024, Patrick Palka wrote: > 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;
Oops, disregard this last sentence, it's a vestige from an earlier version of this patch before it occurred to me we can freely obtain the template depth of a lambda through its operator()'s TEMPLATE_DECL. > > 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 > >