[clang] e9c9db3 - PR58819: Correct linkage and mangling of lambdas in inline static member initializers
David Blaikie via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 3 21:57:59 PDT 2023
Author: David Blaikie
Date: 2023-04-04T04:45:32Z
New Revision: e9c9db34a9b04706937e9dd764d1d97ca84337b6
URL: https://github.com/llvm/llvm-project/commit/e9c9db34a9b04706937e9dd764d1d97ca84337b6
DIFF: https://github.com/llvm/llvm-project/commit/e9c9db34a9b04706937e9dd764d1d97ca84337b6.diff
LOG: PR58819: Correct linkage and mangling of lambdas in inline static member initializers
https://llvm.org/pr58819 - clang is giving an externally visible lambda in a static data member internal linkage and the wrong linkage name.
Looks like we should be classifying this case the same as a non-static data member, so far as I can tell from the ABI docs and template examples (seems like the non-template inline-defined case should be the same).
This is a change in ABI, but not sure it qualifies as an ABI break as far as Apple and Sony are concerned - do you folks want this change? (it should fix the example in the bug where a static member in such a lambda ends up bifurcated, and I don't /think/ it'll break existing code since the symbol was previously internal anyway)
Looks like GCC has got this mangling slightly wrong (so we'd still end up with GCC+Clang bifurcation of the local static in the lambda, function address inequality, etc) in that they miss the variable name in the mangling in the non-template case. GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107741
Differential Revision: https://reviews.llvm.org/D138247
Added:
Modified:
clang/lib/Sema/SemaLambda.cpp
clang/test/CodeGenCXX/mangle-lambdas.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index c633a5080996b..a809968b66032 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -283,12 +283,14 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
Normal,
DefaultArgument,
DataMember,
- StaticDataMember,
InlineVariable,
- VariableTemplate,
+ TemplatedVariable,
Concept
} Kind = Normal;
+ bool IsInNonspecializedTemplate =
+ inTemplateInstantiation() || CurContext->isDependentContext();
+
// Default arguments of member function parameters that appear in a class
// definition, as well as the initializers of data members, receive special
// treatment. Identify them.
@@ -299,15 +301,15 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
if (LexicalDC->isRecord())
Kind = DefaultArgument;
} else if (VarDecl *Var = dyn_cast<VarDecl>(ManglingContextDecl)) {
- if (Var->getDeclContext()->isRecord())
- Kind = StaticDataMember;
- else if (Var->getMostRecentDecl()->isInline())
+ if (Var->getMostRecentDecl()->isInline())
Kind = InlineVariable;
+ else if (Var->getDeclContext()->isRecord() && IsInNonspecializedTemplate)
+ Kind = TemplatedVariable;
else if (Var->getDescribedVarTemplate())
- Kind = VariableTemplate;
+ Kind = TemplatedVariable;
else if (auto *VTS = dyn_cast<VarTemplateSpecializationDecl>(Var)) {
if (!VTS->isExplicitSpecialization())
- Kind = VariableTemplate;
+ Kind = TemplatedVariable;
}
} else if (isa<FieldDecl>(ManglingContextDecl)) {
Kind = DataMember;
@@ -319,12 +321,9 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// Itanium ABI [5.1.7]:
// In the following contexts [...] the one-definition rule requires closure
// types in
diff erent translation units to "correspond":
- bool IsInNonspecializedTemplate =
- inTemplateInstantiation() || CurContext->isDependentContext();
switch (Kind) {
case Normal: {
- // -- the bodies of non-exported nonspecialized template functions
- // -- the bodies of inline functions
+ // -- the bodies of inline or templated functions
if ((IsInNonspecializedTemplate &&
!(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) ||
isInInlineFunction(CurContext)) {
@@ -341,21 +340,13 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC) {
// however the ManglingContextDecl is important for the purposes of
// re-forming the template argument list of the lambda for constraint
// evaluation.
- case StaticDataMember:
- // -- the initializers of nonspecialized static members of template classes
- if (!IsInNonspecializedTemplate)
- return std::make_tuple(nullptr, ManglingContextDecl);
- // Fall through to get the current context.
- [[fallthrough]];
-
case DataMember:
- // -- the in-class initializers of class members
+ // -- default member initializers
case DefaultArgument:
// -- default arguments appearing in class definitions
case InlineVariable:
- // -- the initializers of inline variables
- case VariableTemplate:
- // -- the initializers of templated variables
+ case TemplatedVariable:
+ // -- the initializers of inline or templated variables
return std::make_tuple(
&Context.getManglingNumberContext(ASTContext::NeedExtraManglingDecl,
ManglingContextDecl),
diff --git a/clang/test/CodeGenCXX/mangle-lambdas.cpp b/clang/test/CodeGenCXX/mangle-lambdas.cpp
index c10f7add32933..5a7de97c91858 100644
--- a/clang/test/CodeGenCXX/mangle-lambdas.cpp
+++ b/clang/test/CodeGenCXX/mangle-lambdas.cpp
@@ -290,6 +290,17 @@ template void ft4<int>();
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZZ3ft4IiEvvEN2lc2mfEiEd_NKUlvE_clEv
+extern int ExternalVariable;
+struct StaticInlineMember {
+ static constexpr auto x = [] { return ExternalVariable; };
+};
+
+// CHECK-LABEL: define void @_Z23test_StaticInlineMemberv
+// CHECK: call {{.*}} @_ZNK18StaticInlineMember1xMUlvE_clEv
+void test_StaticInlineMember() {
+ StaticInlineMember::x();
+}
+
// Check linkage of the various lambdas.
// CHECK-LABEL: define linkonce_odr noundef i32 @_ZZ11inline_funciENKUlvE_clEv
// CHECK: ret i32 1
More information about the cfe-commits
mailing list