https://gcc.gnu.org/g:1949beb7dbe66687542f4a19d316914dd73fe84d
commit r15-9066-g1949beb7dbe66687542f4a19d316914dd73fe84d Author: Jason Merrill <ja...@redhat.com> Date: Sat Mar 29 14:00:55 2025 -0400 c++: lambda in function template signature [PR119401] Here we instantiate the lambda three times in producing A<0>::f: 1) in tsubst_function_type, substituting the type of A<>::f 2) in tsubst_function_decl, substituting the parameters of A<>::f 3) in regenerate_decl_from_template when instantiating A<>::f The first one gets thrown away by maybe_rebuild_function_decl_type. Before r15-7202, we happily built all of them and mangled the result wrongly as lambda #3. After r15-7202, we try to mangle #3 as #1, which breaks because #1 is already mangled as #1. This patch avoids building #3 by suppressing regenerate_decl_from_template if the template signature includes a lambda, fixing the ICE. We now mangle the lambda as #2, which is still wrong. Addressing that should involve not calling tsubst_function_type from tsubst_function_decl, and building the type from the parms types in the first place rather than fixing it up in maybe_rebuild_function_decl_type. PR c++/119401 gcc/cp/ChangeLog: * pt.cc (regenerate_decl_from_template): Don't regenerate if the signature involves a lambda. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/lambda-targ11.C: New test. Diff: --- gcc/cp/pt.cc | 13 +++++++++++++ gcc/testsuite/g++.dg/cpp2a/lambda-targ11.C | 13 +++++++++++++ gcc/testsuite/g++.dg/cpp2a/lambda-targ12.C | 13 +++++++++++++ 3 files changed, 39 insertions(+) diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 417d107d6993..f7c56a107945 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -27238,6 +27238,19 @@ regenerate_decl_from_template (tree decl, tree tmpl, tree args) if (DECL_UNIQUE_FRIEND_P (decl)) goto done; + /* A template with a lambda in the signature also changes type if + regenerated (PR119401). */ + walk_tree_fn find_lambda + = [](tree *tp, int *, void *) + { + if (TREE_CODE (*tp) == LAMBDA_EXPR) + return *tp; + return NULL_TREE; + }; + if (cp_walk_tree_without_duplicates + (&TREE_TYPE (tmpl), find_lambda, nullptr)) + goto done; + /* Use the source location of the definition. */ DECL_SOURCE_LOCATION (decl) = DECL_SOURCE_LOCATION (tmpl); diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ11.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ11.C new file mode 100644 index 000000000000..9f2f743b7eb4 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ11.C @@ -0,0 +1,13 @@ +// PR c++/119401 +// { dg-do compile { target c++20 } } + +template <auto> +struct B {}; +template <int N> +struct A { + void f(B<[]{}>) {} +}; +auto t = &A<0>::f; + +// A<0>::f(B<A<0>::{lambda()#1}{}>) +// { dg-final { scan-assembler "_ZN1AILi0EE1fE1BIXtlNS0_UlvE_EEEE" { xfail *-*-* } } } diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-targ12.C b/gcc/testsuite/g++.dg/cpp2a/lambda-targ12.C new file mode 100644 index 000000000000..bb3f701967f6 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp2a/lambda-targ12.C @@ -0,0 +1,13 @@ +// PR c++/119401 +// { dg-do compile { target c++20 } } + +template <class> +struct B {}; +template <int N> +struct A { + void f(B<decltype([]{})>) {} +}; +auto t = &A<0>::f; + +// A<0>::f(B<A<0>::{lambda()#1}>) +// { dg-final { scan-assembler "_ZN1AILi0EE1fE1BINS0_UlvE_EE" { xfail *-*-* } } }