[clang] [Clang] Fix Itanium mangling crash for local lambda in ctor/dtor (PR #181068)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Apr 5 15:07:43 PDT 2026
https://github.com/eiytoq updated https://github.com/llvm/llvm-project/pull/181068
>From 6d662091c3f992f0621cdb607ee8f749d019ecfc Mon Sep 17 00:00:00 2001
From: eiytoq <eiytoq at outlook.com>
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);
More information about the cfe-commits
mailing list