https://gcc.gnu.org/g:0c80216b7bb0938bff7db230cbefa5bc3e8b3034
commit r14-10652-g0c80216b7bb0938bff7db230cbefa5bc3e8b3034 Author: Patrick Palka <ppa...@redhat.com> Date: Sat Sep 7 14:10:09 2024 -0400 c++: template depth of lambda in default targ [PR116567] For GCC 14, let's narrowly fix this bug by just pruning the result of add_extra_args after the fact to get rid of any unwanted outer levels. 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. Reviewed-by: Jason Merrill <ja...@redhat.com> Diff: --- gcc/cp/pt.cc | 12 +++++++++ gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C | 42 +++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 8e6a7d1a64a4..7135105fc375 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -19679,6 +19679,18 @@ 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 its original + context (e.g. default template argument context) might be unrelated + to the current context it's embedded in. After add_extra_args though, + the innermost levels of 'args' will correspond to the lambda context, + so get rid of all unrelated levels. */ + 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 000000000000..97b42d6ed0c4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ7.C @@ -0,0 +1,42 @@ +// PR c++/116567 +// { dg-do compile { target c++20 } } + +struct X { int n; }; + +template<auto N, auto F = []{ return N; }> +auto v1 = F; + +template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }> +auto v1g = F; + +template<class T> +struct A { + template<auto N, auto F = []{ return N; }> + static inline auto v2 = F; + + template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }> + static inline auto v2g = F; + + template<class U> + struct B { + template<auto N, auto F = []{ return N; }> + static inline auto v3 = F; + + template<auto N, auto F = [](auto y){ return decltype(N){N.n + y}; }> + static inline auto v3g = F; + + template<class V> + static void f() { + static_assert(v1<X{1}>().n == 1); + static_assert(v1g<X{1}>(42).n == 1 + 42); + static_assert(v2<X{2}>().n == 2); + static_assert(v2g<X{2}>(42).n == 2 + 42); + static_assert(v3<X{3}>().n == 3); + static_assert(v3g<X{3}>(42).n == 3 + 42); + } + }; +}; + +int main() { + A<int>::B<int>::f<int>(); +}