https://gcc.gnu.org/g:8990070b4297b913025d564293f97c0440622976

commit r15-7202-g8990070b4297b913025d564293f97c0440622976
Author: Nathaniel Shead <nathanielosh...@gmail.com>
Date:   Thu Jan 23 19:22:04 2025 +1100

    c++: Fix mangling of otherwise unattached class-scope lambdas [PR118245]
    
    This is a step closer to implementing the suggested changes for
    https://github.com/itanium-cxx-abi/cxx-abi/pull/85.  Most lambdas
    defined within a class should have an extra scope of that class so that
    uses across different TUs are properly merged by the linker.  This also
    needs to happen during template instantiation.
    
    While I was working on this I found some other cases where the mangling
    of lambdas was incorrect and causing issues, notably the testcase
    lambda-ctx3.C which currently emits the same mangling for the base class
    and member lambdas, causing mysterious assembler errors since r14-9232.
    
    One notable case not handled either here or in the ABI is what is
    supposed to happen with such unattached lambdas declared in member
    templates; see lambda-uneval22.  I believe that by the C++ standard,
    such lambdas should also dedup across TUs, but this isn't currently
    implemented, and it's not clear exactly how such lambdas should mangle.
    
    Since this should only affect usage of lambdas in unevaluated contexts
    (a C++20 feature) this patch does not add an ABI flag to control this
    behaviour.
    
            PR c++/118245
    
    gcc/cp/ChangeLog:
    
            * cp-tree.h (LAMBDA_EXPR_EXTRA_SCOPE): Adjust comment.
            * parser.cc (cp_parser_class_head): Start (and do not finish)
            lambda scope for all valid types.
            (cp_parser_class_specifier): Finish lambda scope after parsing
            members instead.
            * pt.cc (instantiate_class_template): Add lambda scoping.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/abi/lambda-ctx3.C: New test.
            * g++.dg/cpp2a/lambda-uneval22.C: New test.
            * g++.dg/cpp2a/lambda-uneval23.C: New test.
    
    Signed-off-by: Nathaniel Shead <nathanielosh...@gmail.com>
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/cp-tree.h                             |  3 ++-
 gcc/cp/parser.cc                             | 23 ++++++++++++++---------
 gcc/cp/pt.cc                                 |  6 ++++++
 gcc/testsuite/g++.dg/abi/lambda-ctx3.C       | 27 +++++++++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-uneval22.C | 21 +++++++++++++++++++++
 gcc/testsuite/g++.dg/cpp2a/lambda-uneval23.C |  7 +++++++
 6 files changed, 77 insertions(+), 10 deletions(-)

diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 5e8aefc12893..5d79cf927d92 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1562,7 +1562,8 @@ enum cp_lambda_default_capture_mode_type {
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->locus)
 
 /* The mangling scope for the lambda: FUNCTION_DECL, PARM_DECL, VAR_DECL,
-   FIELD_DECL or NULL_TREE.  If this is NULL_TREE, we have no linkage.  */
+   FIELD_DECL, TYPE_DECL, or NULL_TREE.  If this is NULL_TREE, we have no
+   linkage.  */
 #define LAMBDA_EXPR_EXTRA_SCOPE(NODE) \
   (((struct tree_lambda_expr *)LAMBDA_EXPR_CHECK (NODE))->extra_scope)
 
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 03010089c3c6..2f88e5fcd914 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -27462,6 +27462,8 @@ cp_parser_class_specifier (cp_parser* parser)
   if (!braces.require_open (parser))
     {
       pop_deferring_access_checks ();
+      if (type != error_mark_node)
+       finish_lambda_scope ();
       return error_mark_node;
     }
 
@@ -27526,7 +27528,10 @@ cp_parser_class_specifier (cp_parser* parser)
   if (cp_parser_allow_gnu_extensions_p (parser))
     attributes = cp_parser_gnu_attributes_opt (parser);
   if (type != error_mark_node)
-    type = finish_struct (type, attributes);
+    {
+      type = finish_struct (type, attributes);
+      finish_lambda_scope ();
+    }
   if (nested_name_specifier_p)
     pop_inner_scope (old_scope, scope);
 
@@ -28366,6 +28371,12 @@ cp_parser_class_head (cp_parser* parser,
   if (flag_concepts)
     type = associate_classtype_constraints (type);
 
+  /* Lambdas in bases and members must have the same mangling scope for ABI.
+     We open this scope now, and will close it in cp_parser_class_specifier
+     after parsing the member list.  */
+  if (type && type != error_mark_node)
+    start_lambda_scope (TYPE_NAME (type));
+
   /* We will have entered the scope containing the class; the names of
      base classes should be looked up in that context.  For example:
 
@@ -28380,16 +28391,10 @@ cp_parser_class_head (cp_parser* parser,
   if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
     {
       if (type)
-       {
-         pushclass (type);
-         start_lambda_scope (TYPE_NAME (type));
-       }
+       pushclass (type);
       bases = cp_parser_base_clause (parser);
       if (type)
-       {
-         finish_lambda_scope ();
-         popclass ();
-       }
+       popclass ();
     }
   else
     bases = NULL_TREE;
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 28e05490d06c..0f739d89b35c 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -12606,6 +12606,10 @@ instantiate_class_template (tree type)
   gcc_assert (!DECL_CLASS_SCOPE_P (TYPE_MAIN_DECL (pattern))
              || COMPLETE_OR_OPEN_TYPE_P (TYPE_CONTEXT (type)));
 
+  /* When instantiating nested lambdas, ensure that they get the mangling
+     scope of the new class type.  */
+  start_lambda_scope (TYPE_NAME (type));
+
   base_list = NULL_TREE;
   /* Defer access checking while we substitute into the types named in
      the base-clause.  */
@@ -12967,6 +12971,8 @@ instantiate_class_template (tree type)
   finish_struct_1 (type);
   TYPE_BEING_DEFINED (type) = 0;
 
+  finish_lambda_scope ();
+
   /* Remember if instantiating this class ran into errors, so we can avoid
      instantiating member functions in limit_bad_template_recursion.  We set
      this flag even if the problem was in another instantiation triggered by
diff --git a/gcc/testsuite/g++.dg/abi/lambda-ctx3.C 
b/gcc/testsuite/g++.dg/abi/lambda-ctx3.C
new file mode 100644
index 000000000000..f782f2c0cb50
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/lambda-ctx3.C
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++20 } }
+// { dg-additional-options "-fkeep-inline-functions" }
+// See also https://github.com/itanium-cxx-abi/cxx-abi/pull/85
+
+struct A {
+  decltype([]{ return 1; }) f;
+};
+
+struct B : decltype([]{ return 2; }) {
+  decltype([]{ return 3; }) f;
+};
+
+template <typename T>
+struct C : decltype([]{ return 4; }) {
+  decltype([]{ return 5; }) f;
+};
+
+template struct C<int>;
+template struct C<double>;
+
+// { dg-final { scan-assembler {_ZNK1AUlvE_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1BUlvE_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1BUlvE0_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1CIiEUlvE_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1CIiEUlvE0_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1CIdEUlvE_clEv:} } }
+// { dg-final { scan-assembler {_ZNK1CIdEUlvE0_clEv:} } }
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval22.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval22.C
new file mode 100644
index 000000000000..9c0e8128f108
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval22.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++20 } }
+
+struct S {
+  template <int I>
+  using T = decltype([]{ return I; });
+
+  template <int I>
+  decltype([]{ return I; }) f() { return {}; }
+};
+
+void a(S::T<0>*);  // { dg-error "declared using local type" }
+void b(S::T<1>*);  // { dg-error "declared using local type" }
+void c(decltype(S{}.f<0>())*);  // { dg-error "declared using local type" }
+void d(decltype(S{}.f<1>())*);  // { dg-error "declared using local type" }
+
+int main() {
+  a(nullptr);
+  b(nullptr);
+  c(nullptr);
+  d(nullptr);
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/lambda-uneval23.C 
b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval23.C
new file mode 100644
index 000000000000..fa009f53ff23
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/lambda-uneval23.C
@@ -0,0 +1,7 @@
+// PR c++/118245
+// { dg-do compile { target c++20 } }
+
+template<auto> struct Cask {};
+struct T1 : Cask<[]{}> {
+  Cask<[]{}> c{};
+};

Reply via email to