Author: eiytoq
Date: 2026-04-09T06:14:54-07:00
New Revision: a8a83ec1729dad170471c6bc48ef874ff76a3342

URL: 
https://github.com/llvm/llvm-project/commit/a8a83ec1729dad170471c6bc48ef874ff76a3342
DIFF: 
https://github.com/llvm/llvm-project/commit/a8a83ec1729dad170471c6bc48ef874ff76a3342.diff

LOG: [Clang] Fix Itanium mangling crash for local lambda in ctor/dtor (#181068)

Fixes #176395 

Note: I need someone to help me merge this PR, since I don't have commit
access.

Added: 
    clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ItaniumMangle.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 945b07dbe1a62..4e71022b947e6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -447,6 +447,7 @@ Bug Fixes to C++ Support
 - Fix an error using an initializer list with array new for a type that is not 
default-constructible. (#GH81157)
 - We no longer consider conversion operators when copy-initializing from the 
same type. This was non
   conforming and could lead to recursive constraint satisfaction checking. 
(#GH149443)
+- Fixed a crash in Itanium C++ name mangling for a lambda in a local class 
field initializer inside a constructor/destructor. (#GH176395)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp
index d21faaa87558d..f58faa03bfa8c 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -513,6 +513,10 @@ class CXXNameMangler {
   void mangleUnscopedTemplateName(GlobalDecl GD, const DeclContext *DC,
                                   const AbiTagList *AdditionalAbiTags);
   void mangleSourceName(const IdentifierInfo *II);
+  void mangleConstructorName(const CXXConstructorDecl *CCD,
+                             const AbiTagList *AdditionalAbiTags);
+  void mangleDestructorName(const CXXDestructorDecl *CDD,
+                            const AbiTagList *AdditionalAbiTags);
   void mangleRegCallName(const IdentifierInfo *II);
   void mangleDeviceStubName(const IdentifierInfo *II);
   void mangleOCLDeviceStubName(const IdentifierInfo *II);
@@ -1687,48 +1691,12 @@ void CXXNameMangler::mangleUnqualifiedName(
   case DeclarationName::ObjCMultiArgSelector:
     llvm_unreachable("Can't mangle Objective-C selector names here!");
 
-  case DeclarationName::CXXConstructorName: {
-    const CXXRecordDecl *InheritedFrom = nullptr;
-    TemplateName InheritedTemplateName;
-    const TemplateArgumentList *InheritedTemplateArgs = nullptr;
-    if (auto Inherited =
-            cast<CXXConstructorDecl>(ND)->getInheritedConstructor()) {
-      InheritedFrom = Inherited.getConstructor()->getParent();
-      InheritedTemplateName =
-          TemplateName(Inherited.getConstructor()->getPrimaryTemplate());
-      InheritedTemplateArgs =
-          Inherited.getConstructor()->getTemplateSpecializationArgs();
-    }
-
-    if (ND == Structor)
-      // If the named decl is the C++ constructor we're mangling, use the type
-      // we were given.
-      mangleCXXCtorType(static_cast<CXXCtorType>(StructorType), InheritedFrom);
-    else
-      // Otherwise, use the complete constructor name. This is relevant if a
-      // class with a constructor is declared within a constructor.
-      mangleCXXCtorType(Ctor_Complete, InheritedFrom);
-
-    // FIXME: The template arguments are part of the enclosing prefix or
-    // nested-name, but it's more convenient to mangle them here.
-    if (InheritedTemplateArgs)
-      mangleTemplateArgs(InheritedTemplateName, *InheritedTemplateArgs);
-
-    writeAbiTags(ND, AdditionalAbiTags);
+  case DeclarationName::CXXConstructorName:
+    mangleConstructorName(cast<CXXConstructorDecl>(ND), AdditionalAbiTags);
     break;
-  }
 
   case DeclarationName::CXXDestructorName:
-    if (ND == Structor)
-      // If the named decl is the C++ destructor we're mangling, use the type 
we
-      // were given.
-      mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
-    else
-      // Otherwise, use the complete destructor name. This is relevant if a
-      // class with a destructor is declared within a destructor.
-      mangleCXXDtorType(Dtor_Complete);
-    assert(ND);
-    writeAbiTags(ND, AdditionalAbiTags);
+    mangleDestructorName(cast<CXXDestructorDecl>(ND), AdditionalAbiTags);
     break;
 
   case DeclarationName::CXXOperatorName:
@@ -1755,6 +1723,50 @@ void CXXNameMangler::mangleUnqualifiedName(
   }
 }
 
+void CXXNameMangler::mangleConstructorName(
+    const CXXConstructorDecl *CCD, const AbiTagList *AdditionalAbiTags) {
+  const CXXRecordDecl *InheritedFrom = nullptr;
+  TemplateName InheritedTemplateName;
+  const TemplateArgumentList *InheritedTemplateArgs = nullptr;
+  if (const auto Inherited = CCD->getInheritedConstructor()) {
+    InheritedFrom = Inherited.getConstructor()->getParent();
+    InheritedTemplateName =
+        TemplateName(Inherited.getConstructor()->getPrimaryTemplate());
+    InheritedTemplateArgs =
+        Inherited.getConstructor()->getTemplateSpecializationArgs();
+  }
+
+  if (CCD == Structor)
+    // If the named decl is the C++ constructor we're mangling, use the type
+    // we were given.
+    mangleCXXCtorType(static_cast<CXXCtorType>(StructorType), InheritedFrom);
+  else
+    // Otherwise, use the complete constructor name. This is relevant if a
+    // class with a constructor is declared within a constructor.
+    mangleCXXCtorType(Ctor_Complete, InheritedFrom);
+
+  // FIXME: The template arguments are part of the enclosing prefix or
+  // nested-name, but it's more convenient to mangle them here.
+  if (InheritedTemplateArgs)
+    mangleTemplateArgs(InheritedTemplateName, *InheritedTemplateArgs);
+
+  writeAbiTags(CCD, AdditionalAbiTags);
+}
+
+void CXXNameMangler::mangleDestructorName(const CXXDestructorDecl *CDD,
+                                          const AbiTagList *AdditionalAbiTags) 
{
+  if (CDD == Structor)
+    // If the named decl is the C++ destructor we're mangling, use the type we
+    // were given.
+    mangleCXXDtorType(static_cast<CXXDtorType>(StructorType));
+  else
+    // Otherwise, use the complete destructor name. This is relevant if a
+    // class with a destructor is declared within a destructor.
+    mangleCXXDtorType(Dtor_Complete);
+  assert(CDD);
+  writeAbiTags(CDD, AdditionalAbiTags);
+}
+
 void CXXNameMangler::mangleRegCallName(const IdentifierInfo *II) {
   // <source-name> ::= <positive length number> __regcall3__ <identifier>
   // <number> ::= [n] <non-negative decimal integer>
@@ -2207,6 +2219,29 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, 
bool NoFunction) {
   if (mangleSubstitution(ND))
     return;
 
+  // Constructors and destructors can't be represented as a plain GlobalDecl,
+  // and prefix mangling only needs their spelling.
+  if (isa<CXXConstructorDecl>(ND)) {
+    if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND);
+        const TemplateDecl *TD = FD->getPrimaryTemplate()) {
+      mangleTemplatePrefix(TD);
+      mangleTemplateArgs(asTemplateName(TD),
+                         *FD->getTemplateSpecializationArgs());
+    } else {
+      manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
+      mangleConstructorName(cast<CXXConstructorDecl>(ND), nullptr);
+    }
+    addSubstitution(ND);
+    return;
+  }
+
+  if (isa<CXXDestructorDecl>(ND)) {
+    manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
+    mangleDestructorName(cast<CXXDestructorDecl>(ND), nullptr);
+    addSubstitution(ND);
+    return;
+  }
+
   // Check if we have a template-prefix or a closure-prefix.
   const TemplateArgumentList *TemplateArgs = nullptr;
   if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) {

diff  --git a/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp 
b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
new file mode 100644
index 0000000000000..2c0269ecdaec5
--- /dev/null
+++ b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -O2 -emit-llvm -o 
/dev/null %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -O2 
-disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
+
+struct E {
+  E();
+  template<typename T>
+  E(T t);
+  ~E();
+};
+
+E::E() {
+  struct {
+    // CHECK-DAG: _ZTSN1EC13$_012anotherValueMUlvE_E
+    int anotherValue = [x = 1] { return x; }();
+  } obj;
+}
+
+template<typename T>
+E::E(T t) {
+  struct {
+    // CHECK-DAG: _ZTSN1EC1IiEUt_UlvE_E
+    int anotherValue = [x = 1] { return x; }();
+  } obj;
+}
+
+E::~E() {
+  struct {
+    // CHECK-DAG: _ZTSN1ED13$_012anotherValueMUlvE_E
+    int anotherValue = [x = 2] { return x; }();
+  } obj;
+}
+
+E e(1);


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

Reply via email to