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 *-*-* } 
} }

Reply via email to