https://github.com/eiytoq updated 
https://github.com/llvm/llvm-project/pull/181068

>From 6d662091c3f992f0621cdb607ee8f749d019ecfc Mon Sep 17 00:00:00 2001
From: eiytoq <[email protected]>
Date: Sun, 5 Apr 2026 09:31:39 +0800
Subject: [PATCH] fix

---
 clang/docs/ReleaseNotes.rst                   |   1 +
 clang/lib/AST/ItaniumMangle.cpp               | 113 ++++++++++++------
 .../CodeGenCXX/dtor-local-lambda-mangle.cpp   |  33 +++++
 3 files changed, 108 insertions(+), 39 deletions(-)
 create mode 100644 clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 1ab3aae640607..ced3bc4a01613 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -411,6 +411,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 eea04b14eaf09..829e8de0ba841 100644
--- a/clang/lib/AST/ItaniumMangle.cpp
+++ b/clang/lib/AST/ItaniumMangle.cpp
@@ -514,6 +514,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);
@@ -1699,48 +1703,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:
@@ -1767,6 +1735,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>
@@ -2221,6 +2233,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