[clang] [Clang] Fix Itanium mangling crash for local lambda in ctor/dtor (PR #181068)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 3 05:16:49 PDT 2026
https://github.com/eiytoq updated https://github.com/llvm/llvm-project/pull/181068
>From 7cf91845f223d7aa39e403c23aa21ab4688968a6 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Sat, 28 Mar 2026 03:15:19 +0800
Subject: [PATCH 1/2] fix
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/AST/ItaniumMangle.cpp | 107 +++++++++++-------
.../CodeGenCXX/dtor-local-lambda-mangle.cpp | 28 +++++
3 files changed, 97 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..a7fef1f0388ed 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 NamedDecl *ND,
+ const AbiTagList *AdditionalAbiTags);
+ void mangleDestructorName(const NamedDecl *ND,
+ 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(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(ND, AdditionalAbiTags);
break;
case DeclarationName::CXXOperatorName:
@@ -1767,6 +1735,51 @@ void CXXNameMangler::mangleUnqualifiedName(
}
}
+void CXXNameMangler::mangleConstructorName(
+ const NamedDecl *ND, const AbiTagList *AdditionalAbiTags) {
+ 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);
+}
+
+void CXXNameMangler::mangleDestructorName(const NamedDecl *ND,
+ const AbiTagList *AdditionalAbiTags) {
+ 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);
+}
+
void CXXNameMangler::mangleRegCallName(const IdentifierInfo *II) {
// <source-name> ::= <positive length number> __regcall3__ <identifier>
// <number> ::= [n] <non-negative decimal integer>
@@ -2221,6 +2234,22 @@ 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)) {
+ manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
+ mangleConstructorName(ND, nullptr);
+ addSubstitution(ND);
+ return;
+ }
+
+ if (isa<CXXDestructorDecl>(ND)) {
+ manglePrefix(Context.getEffectiveDeclContext(ND), NoFunction);
+ mangleDestructorName(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..49d3621ca00cf
--- /dev/null
+++ b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
@@ -0,0 +1,28 @@
+// 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 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fclang-abi-compat=18 -emit-llvm -o - %s | FileCheck %s
+
+struct E {
+ E();
+ ~E();
+};
+
+E::E() {
+ struct {
+ int anotherValue = [] { return 1; }();
+ } obj;
+}
+
+E::~E() {
+ struct {
+ int anotherValue = [] { return 2; }();
+ } obj;
+}
+
+// CHECK-LABEL: define{{.*}} @"_ZZN1EC1EvEN3$_0C2Ev"
+// CHECK: call{{.*}} @"_ZZN1EC1EvENK3$_012anotherValueMUlvE_clEv"
+// CHECK-LABEL: define{{.*}} @"_ZZN1EC1EvENK3$_012anotherValueMUlvE_clEv"
+
+// CHECK-LABEL: define{{.*}} @"_ZZN1ED1EvEN3$_0C2Ev"
+// CHECK: call{{.*}} @"_ZZN1ED1EvENK3$_012anotherValueMUlvE_clEv"
+// CHECK-LABEL: define{{.*}} @"_ZZN1ED1EvENK3$_012anotherValueMUlvE_clEv"
>From 4386a3b4616dbef40e175c85b480a9f278da53b5 Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
Date: Fri, 3 Apr 2026 20:13:18 +0800
Subject: [PATCH 2/2] address comments
---
.../CodeGenCXX/dtor-local-lambda-mangle.cpp | 20 +++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
index 49d3621ca00cf..8f8a1a1c526ed 100644
--- a/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
+++ b/clang/test/CodeGenCXX/dtor-local-lambda-mangle.cpp
@@ -1,6 +1,6 @@
// 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 -emit-llvm -o - %s | FileCheck %s
-// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fclang-abi-compat=18 -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -O2 -disable-llvm-passes -emit-llvm -o - %s | FileCheck %s
+// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -O2 -disable-llvm-passes -fclang-abi-compat=18 -emit-llvm -o - %s | FileCheck %s
struct E {
E();
@@ -19,10 +19,14 @@ E::~E() {
} obj;
}
-// CHECK-LABEL: define{{.*}} @"_ZZN1EC1EvEN3$_0C2Ev"
-// CHECK: call{{.*}} @"_ZZN1EC1EvENK3$_012anotherValueMUlvE_clEv"
-// CHECK-LABEL: define{{.*}} @"_ZZN1EC1EvENK3$_012anotherValueMUlvE_clEv"
+// CHECK-LABEL: define internal void @"_ZZN1EC1EvEN3$_0C2Ev"
+// CHECK: store i32 %{{.*}}, ptr %anotherValue, align 4, !tbaa ![[CTOR_ACCESS:[0-9]+]]
-// CHECK-LABEL: define{{.*}} @"_ZZN1ED1EvEN3$_0C2Ev"
-// CHECK: call{{.*}} @"_ZZN1ED1EvENK3$_012anotherValueMUlvE_clEv"
-// CHECK-LABEL: define{{.*}} @"_ZZN1ED1EvENK3$_012anotherValueMUlvE_clEv"
+// CHECK-LABEL: define internal void @"_ZZN1ED1EvEN3$_0C2Ev"
+// CHECK: store i32 %{{.*}}, ptr %anotherValue, align 4, !tbaa ![[DTOR_ACCESS:[0-9]+]]
+
+// CHECK: ![[CTOR_ACCESS]] = !{![[CTOR_TYPE:[0-9]+]], ![[INT:[0-9]+]], i64 0}
+// CHECK: ![[CTOR_TYPE]] = !{!"_ZTSZN1EC1EvE3$_0", ![[INT]], i64 0}
+
+// CHECK: ![[DTOR_ACCESS]] = !{![[DTOR_TYPE:[0-9]+]], ![[INT]], i64 0}
+// CHECK: ![[DTOR_TYPE]] = !{!"_ZTSZN1ED1EvE3$_0", ![[INT]], i64 0}
More information about the cfe-commits
mailing list