Skip to content

[Clang] Fix the mangling of lambdas #89204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,7 @@ Bug Fixes to C++ Support
- Fix a crash in requires expression with templated base class member function. Fixes (#GH84020).
- Fix a crash caused by defined struct in a type alias template when the structure
has fields with dependent type. Fixes (#GH75221).
- Fix the Itanium mangling of lambdas defined in a member of a local class (#GH88906)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rjmccall do you think this should come with an ABI tag to get the old mangling behavior?


Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ class LangOptionsBase {
/// - the parameter list of a template template parameter
Ver17,

/// Attempt to be ABI-compatible with code generated by Clang 18.0.x.
/// This causes clang to revert some fixes to the mangling of lambdas
/// in the initializers of members of local classes.
Ver18,

/// Conform to the underlying platform's C and C++ ABIs as closely
/// as we can.
Latest
Expand Down
18 changes: 9 additions & 9 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1062,33 +1062,35 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
// ::= <local-name>
//
const DeclContext *DC = Context.getEffectiveDeclContext(ND);
bool IsLambda = isLambda(ND);

// If this is an extern variable declared locally, the relevant DeclContext
// is that of the containing namespace, or the translation unit.
// FIXME: This is a hack; extern variables declared locally should have
// a proper semantic declaration context!
if (isLocalContainerContext(DC) && ND->hasLinkage() && !isLambda(ND))
if (isLocalContainerContext(DC) && ND->hasLinkage() && !IsLambda)
while (!DC->isNamespace() && !DC->isTranslationUnit())
DC = Context.getEffectiveParentContext(DC);
else if (GetLocalClassDecl(ND)) {
else if (GetLocalClassDecl(ND) &&
(!IsLambda || isCompatibleWith(LangOptions::ClangABI::Ver18))) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

assert(!isa<LinkageSpecDecl>(DC) && "context cannot be LinkageSpecDecl");

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

// Closures can require a nested-name mangling even if they're semantically
// in the global namespace.
if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
mangleNestedNameWithClosurePrefix(GD, PrefixND, AdditionalAbiTags);
return;
}

if (isLocalContainerContext(DC)) {
mangleLocalName(GD, AdditionalAbiTags);
return;
}

if (DC->isTranslationUnit() || isStdNamespace(DC)) {
// Check if we have a template.
const TemplateArgumentList *TemplateArgs = nullptr;
Expand Down Expand Up @@ -2201,8 +2203,6 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (NoFunction && isLocalContainerContext(DC))
return;

assert(!isLocalContainerContext(DC));

const NamedDecl *ND = cast<NamedDecl>(DC);
if (mangleSubstitution(ND))
return;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3655,6 +3655,9 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
case LangOptions::ClangABI::Ver17:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "17.0");
break;
case LangOptions::ClangABI::Ver18:
GenerateArg(Consumer, OPT_fclang_abi_compat_EQ, "18.0");
break;
case LangOptions::ClangABI::Latest:
break;
}
Expand Down Expand Up @@ -4162,6 +4165,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.setClangABICompat(LangOptions::ClangABI::Ver15);
else if (Major <= 17)
Opts.setClangABICompat(LangOptions::ClangABI::Ver17);
else if (Major <= 18)
Opts.setClangABICompat(LangOptions::ClangABI::Ver18);
} else if (Ver != "latest") {
Diags.Report(diag::err_drv_invalid_value)
<< A->getAsString(Args) << A->getValue();
Expand Down
46 changes: 46 additions & 0 deletions clang/test/CodeGenCXX/mangle-lambdas-gh88906.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu %s -emit-llvm -mconstructor-aliases -o - | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fclang-abi-compat=18 %s -emit-llvm -mconstructor-aliases -o - | FileCheck --check-prefix=CLANG18 %s
// RUN: %clang_cc1 -triple i386-pc-win32 %s -emit-llvm -mconstructor-aliases -o - | FileCheck --check-prefix=MSABI %s


class func {
public:
template <typename T>
func(T){};
template <typename T, typename U>
func(T, U){};
};

void GH88906(){
class Test{
public:
func a{[]{ }, []{ }};
func b{[]{ }};
func c{[]{ }};
} test;
}

// 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-LABEL: define internal void @_ZN4funcC2IN7GH889064Test1aMUlvE_ENS3_UlvE0_EEET_T0_
// CHECK-LABEL: define internal void @_ZN4funcC2IN7GH889064Test1bMUlvE_EEET_
// CHECK-LABEL: define internal void @_ZN4funcC2IN7GH889064Test1cMUlvE_EEET_

// CLANG18-LABEL: define internal void @_ZZ7GH88906vEN4TestC2Ev
// CLANG18: call void @_ZN4funcC2IZ7GH88906vEN4TestUlvE_EZ7GH88906vENS1_UlvE0_EEET_T0_
// CLANG18: call void @_ZN4funcC2IZ7GH88906vEN4TestUlvE_EEET_
// CLANG18: call void @_ZN4funcC2IZ7GH88906vEN4TestUlvE_EEET_



// MSABI-LABEL: define internal x86_thiscallcc noundef ptr @"??0Test@?1??GH88906@@YAXXZ@QAE@XZ"
// MSABI: call x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@a@Test@?1??GH88906@@YAXXZ@V<lambda_2>@12?1??3@YAXXZ@@func@@QAE@V<lambda_1>@a@Test@?1??GH88906@@YAXXZ@V<lambda_2>@23?1??4@YAXXZ@@Z"
// MSABI: call x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@b@Test@?1??GH88906@@YAXXZ@@func@@QAE@V<lambda_1>@b@Test@?1??GH88906@@YAXXZ@@Z"
// MSABI: call x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@c@Test@?1??GH88906@@YAXXZ@@func@@QAE@V<lambda_1>@c@Test@?1??GH88906@@YAXXZ@@Z"

// MSABI-LABEL: define internal x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@a@Test@?1??GH88906@@YAXXZ@V<lambda_2>@12?1??3@YAXXZ@@func@@QAE@V<lambda_1>@a@Test@?1??GH88906@@YAXXZ@V<lambda_2>@23?1??4@YAXXZ@@Z"
// MSABI-LABEL: define internal x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@b@Test@?1??GH88906@@YAXXZ@@func@@QAE@V<lambda_1>@b@Test@?1??GH88906@@YAXXZ@@Z"
// MSABI-LABEL: define internal x86_thiscallcc noundef ptr @"??$?0V<lambda_1>@c@Test@?1??GH88906@@YAXXZ@@func@@QAE@V<lambda_1>@c@Test@?1??GH88906@@YAXXZ@@Z"