llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Kristina Bessonova (chbessonova)

<details>
<summary>Changes</summary>

Lambdas appearing in default member initializers of members of local classes 
were previously mangled as if they belonged only to the class scope, ignoring 
the enclosing function-local context.

This caused different (but same-named) local classes to produce identical 
closure type mangling and corresponding RTTI/IR collisions.

Consider the following example:
```
  void foo() {
    {
      struct T {
        std::function&lt;void()&gt; a = [](){ std::cout &lt;&lt; "a"; };
      } t;
      t.a();
    }
    {
      struct T {
        std::function&lt;void()&gt; a = [](){ std::cout &lt;&lt; "b"; };
      } t;
      t.a();
    }
  }
```

The expected output is `ab` (and GCC-compiled code behaves accordingly), while 
clang previously printed `aa` because the second `T::a` definition never 
reached IR generation due to the missing `&lt;local-name&gt;` encoding and 
discriminator required to distinguish the two local `T` definitions.

---
Full diff: https://github.com/llvm/llvm-project/pull/206740.diff


4 Files Affected:

- (modified) clang/lib/AST/ItaniumMangle.cpp (+12-8) 
- (modified) clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp (+3-3) 
- (modified) clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp (+6-6) 
- (added) clang/test/CodeGenCXX/mangle-lambdas-in-dmi-local-class.cpp (+65) 


``````````diff
diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index e5cdd6f31c507..e014b45a5da93 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -530,7 +530,8 @@ class CXXNameMangler {
                         ArrayRef<TemplateArgument> Args);
   void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
                                          const NamedDecl *PrefixND,
-                                         ArrayRef<StringRef> 
AdditionalAbiTags);
+                                         ArrayRef<StringRef> AdditionalAbiTags,
+                                         bool NoFunction = false);
   void manglePrefix(NestedNameSpecifier Qualifier);
   void manglePrefix(const DeclContext *DC, bool NoFunction=false);
   void manglePrefix(QualType type);
@@ -1067,10 +1068,8 @@ void CXXNameMangler::mangleNameWithAbiTags(
   //         ::= <local-name>
   //
   const DeclContext *DC = Context.getEffectiveDeclContext(ND);
-  bool IsLambda = isLambda(ND);
 
-  if (GetLocalClassDecl(ND) &&
-      (!IsLambda || isCompatibleWith(LangOptions::ClangABI::Ver18))) {
+  if (GetLocalClassDecl(ND)) {
     mangleLocalName(GD, AdditionalAbiTags);
     return;
   }
@@ -1845,7 +1844,7 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl 
*TD,
 
 void CXXNameMangler::mangleNestedNameWithClosurePrefix(
     GlobalDecl GD, const NamedDecl *PrefixND,
-    ArrayRef<StringRef> AdditionalAbiTags) {
+    ArrayRef<StringRef> AdditionalAbiTags, bool NoFunction) {
   // A <closure-prefix> represents a variable or field, not a regular
   // DeclContext, so needs special handling. In this case we're mangling a
   // limited form of <nested-name>:
@@ -1854,7 +1853,7 @@ void CXXNameMangler::mangleNestedNameWithClosurePrefix(
 
   Out << 'N';
 
-  mangleClosurePrefix(PrefixND);
+  mangleClosurePrefix(PrefixND, NoFunction);
   mangleUnqualifiedName(GD, nullptr, AdditionalAbiTags);
 
   Out << 'E';
@@ -1945,8 +1944,13 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
       mangleUnqualifiedBlock(BD);
     } else {
       const NamedDecl *ND = cast<NamedDecl>(D);
-      mangleNestedName(GD, Context.getEffectiveDeclContext(ND),
-                       AdditionalAbiTags, true /*NoFunction*/);
+      const NamedDecl *PrefixND = getClosurePrefix(ND);
+      if (PrefixND && !isCompatibleWith(LangOptions::ClangABI::Ver18))
+        mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags,
+                                          true /*NoFunction*/);
+      else
+        mangleNestedName(GD, Context.getEffectiveDeclContext(ND),
+                         AdditionalAbiTags, true /*NoFunction*/);
     }
   } else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
     // Mangle a block in a default parameter; see above explanation for
diff --git a/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp 
b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
index 95283dad4a933..bd7b60b816fa7 100644
--- a/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
+++ b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
@@ -10,7 +10,7 @@ struct E {
 
 E::E() {
   struct {
-    // CHECK-DAG: _ZTSN1EC13$_012anotherValueMUlvE_E
+    // CHECK-DAG: _ZTSZN1EC1EvEN3$_012anotherValueMUlvE_E
     int anotherValue = [x = 1] { return x; }();
   } obj;
 }
@@ -18,14 +18,14 @@ E::E() {
 template<typename T>
 E::E(T t) {
   struct {
-    // CHECK-DAG: _ZTSN1EC1IiEUt_12anotherValueMUlvE_E
+    // CHECK-DAG: _ZTSZN1ED1EvEN3$_012anotherValueMUlvE_E
     int anotherValue = [x = 1] { return x; }();
   } obj;
 }
 
 E::~E() {
   struct {
-    // CHECK-DAG: _ZTSN1ED13$_012anotherValueMUlvE_E
+    // CHECK-DAG: _ZTSZN1EC1IiEET_ENUt_12anotherValueMUlvE_E
     int anotherValue = [x = 2] { return x; }();
   } obj;
 }
diff --git a/clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp 
b/clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp
index e7592cec5da77..ba99906d358be 100644
--- a/clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp
+++ b/clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp
@@ -21,13 +21,13 @@ void GH88906(){
 }
 
 // CHECK-LABEL: define internal void @_ZZ7GH88906vEN4TestC2Ev
-// CHECK: call void @_ZN4funcC2IN7GH889064Test1aMUlvE_ENS3_UlvE0_EEET_T0_
-// CHECK: call void @_ZN4funcC2IN7GH889064Test1bMUlvE_EEET_
-// CHECK: call void @_ZN4funcC2IN7GH889064Test1cMUlvE_EEET_
+// CHECK: call void 
@_ZN4funcC2IZ7GH88906vEN4Test1aMUlvE_EZ7GH88906vENS2_UlvE0_EEET_T0_
+// CHECK: call void @_ZN4funcC2IZ7GH88906vEN4Test1bMUlvE_EEET_
+// CHECK: call void @_ZN4funcC2IZ7GH88906vEN4Test1cMUlvE_EEET_
 
-// CHECK-LABEL: define internal void 
@_ZN4funcC2IN7GH889064Test1aMUlvE_ENS3_UlvE0_EEET_T0_
-// CHECK-LABEL: define internal void @_ZN4funcC2IN7GH889064Test1bMUlvE_EEET_
-// CHECK-LABEL: define internal void @_ZN4funcC2IN7GH889064Test1cMUlvE_EEET_
+// CHECK-LABEL: define internal void 
@_ZN4funcC2IZ7GH88906vEN4Test1aMUlvE_EZ7GH88906vENS2_UlvE0_EEET_T0_
+// CHECK-LABEL: define internal void @_ZN4funcC2IZ7GH88906vEN4Test1bMUlvE_EEET_
+// CHECK-LABEL: define internal void @_ZN4funcC2IZ7GH88906vEN4Test1cMUlvE_EEET_
 
 // CLANG18-LABEL: define internal void @_ZZ7GH88906vEN4TestC2Ev
 // CLANG18: call void 
@_ZN4funcC2IZ7GH88906vEN4TestUlvE_EZ7GH88906vENS1_UlvE0_EEET_T0_
diff --git a/clang/test/CodeGenCXX/mangle-lambdas-in-dmi-local-class.cpp 
b/clang/test/CodeGenCXX/mangle-lambdas-in-dmi-local-class.cpp
new file mode 100644
index 0000000000000..479ce23dc53ab
--- /dev/null
+++ b/clang/test/CodeGenCXX/mangle-lambdas-in-dmi-local-class.cpp
@@ -0,0 +1,65 @@
+// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -I%S -std=c++20 -o - 
| FileCheck %s
+
+// Ensure that local classes mangled with <local-name> while mangling a lamda
+// in default member initializer.
+
+// Itanium ABI 5.1.2
+// Names
+// <...> Entities declared within a function, including members of local 
classes, are mangled with <local-name>. Entities declared in a namespace or 
class scope are mangled with <nested-name>. <...>
+
+#include <typeinfo>
+
+void foo() {
+  {
+    struct Test {
+      const std::type_info& a = typeid([] {});
+      const std::type_info& b = typeid([] {});
+    } T;
+  }
+
+  {
+    struct Test {
+      const std::type_info& a = typeid([] {});
+      const std::type_info& b = typeid([] {});
+    } T;
+  }
+}
+
+// _Z
+// TI
+// Z3foovE         ; local-name scope
+//   N
+//     4Test
+//       1a        ; member a
+//         M       ; member-initializer context
+//           UlvE_ ; lambda closure type
+//   E
+
+// CHECK: @_ZTIZ3foovEN4Test1aMUlvE_E
+// CHECK: @_ZTSZ3foovEN4Test1aMUlvE_E
+// CHECK: @_ZTIZ3foovEN4Test1bMUlvE_E
+// CHECK: @_ZTSZ3foovEN4Test1bMUlvE_E
+
+// _Z
+// TI
+// Z3foovE         ; local-name scope
+//   N
+//     4Test
+//       1a        ; member a
+//         M       ; member-initializer context
+//           UlvE_ ; lambda closure type
+//   E
+//   _0            ; second local 'Test' definition
+
+// CHECK: @_ZTIZ3foovEN4Test1aMUlvE_E_0
+// CHECK: @_ZTSZ3foovEN4Test1aMUlvE_E_0
+// CHECK: @_ZTIZ3foovEN4Test1bMUlvE_E_0
+// CHECK: @_ZTSZ3foovEN4Test1bMUlvE_E_0
+
+// CHECK-LABEL: @_ZZ3foovEN4TestC2Ev
+// CHECK: store ptr @_ZTIZ3foovEN4Test1aMUlvE_E
+// CHECK: store ptr @_ZTIZ3foovEN4Test1bMUlvE_E
+
+// CHECK-LABEL: @_ZZ3foovEN4TestC2E_0v
+// CHECK: store ptr @_ZTIZ3foovEN4Test1aMUlvE_E_0
+// CHECK: store ptr @_ZTIZ3foovEN4Test1bMUlvE_E_0

``````````

</details>


https://github.com/llvm/llvm-project/pull/206740
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to