forked from OSchip/llvm-project
Fix bad mangling of <data-member-prefix> for a closure in the initializer of a variable at global namespace scope.
This implements the direction proposed in https://github.com/itanium-cxx-abi/cxx-abi/pull/126. Differential Revision: https://reviews.llvm.org/D101968
This commit is contained in:
parent
29ac15ab38
commit
5bb7e81c64
|
@ -75,23 +75,6 @@ public:
|
|||
LocalExecTLSModel
|
||||
};
|
||||
|
||||
/// Clang versions with different platform ABI conformance.
|
||||
enum class ClangABI {
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 3.8.x
|
||||
/// (SVN r257626). This causes <1 x long long> to be passed in an
|
||||
/// integer register instead of an SSE register on x64_64.
|
||||
Ver3_8,
|
||||
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 4.0.x
|
||||
/// (SVN r291814). This causes move operations to be ignored when
|
||||
/// determining whether a class type can be passed or returned directly.
|
||||
Ver4,
|
||||
|
||||
/// Conform to the underlying platform's C and C++ ABIs as closely
|
||||
/// as we can.
|
||||
Latest
|
||||
};
|
||||
|
||||
enum StructReturnConventionKind {
|
||||
SRCK_Default, // No special option was passed.
|
||||
SRCK_OnStack, // Small structs on the stack (-fpcc-struct-return).
|
||||
|
|
|
@ -164,13 +164,18 @@ public:
|
|||
Ver9,
|
||||
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 11.0.x
|
||||
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
|
||||
/// (git 2e10b7a39b93). This causes clang to pass unions with a 256-bit
|
||||
/// vector member on the stack instead of using registers, to not properly
|
||||
/// mangle substitutions for template names in some cases, and to mangle
|
||||
/// declaration template arguments without a cast to the parameter type
|
||||
/// even when that can lead to mangling collisions.
|
||||
Ver11,
|
||||
|
||||
/// Attempt to be ABI-compatible with code generated by Clang 12.0.x
|
||||
/// (git 8e464dd76bef). This causes clang to mangle lambdas within
|
||||
/// global-scope inline variables incorrectly.
|
||||
Ver12,
|
||||
|
||||
/// Conform to the underlying platform's C and C++ ABIs as closely
|
||||
/// as we can.
|
||||
Latest
|
||||
|
|
|
@ -539,11 +539,16 @@ private:
|
|||
void mangleNestedName(const TemplateDecl *TD,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs);
|
||||
void mangleNestedNameWithClosurePrefix(GlobalDecl GD,
|
||||
const NamedDecl *PrefixND,
|
||||
const AbiTagList *AdditionalAbiTags);
|
||||
void manglePrefix(NestedNameSpecifier *qualifier);
|
||||
void manglePrefix(const DeclContext *DC, bool NoFunction=false);
|
||||
void manglePrefix(QualType type);
|
||||
void mangleTemplatePrefix(GlobalDecl GD, bool NoFunction=false);
|
||||
void mangleTemplatePrefix(TemplateName Template);
|
||||
const NamedDecl *getClosurePrefix(const Decl *ND);
|
||||
void mangleClosurePrefix(const NamedDecl *ND, bool NoFunction = false);
|
||||
bool mangleUnresolvedTypeOrSimpleId(QualType DestroyedType,
|
||||
StringRef Prefix = "");
|
||||
void mangleOperatorName(DeclarationName Name, unsigned Arity);
|
||||
|
@ -983,6 +988,13 @@ void CXXNameMangler::mangleNameWithAbiTags(GlobalDecl GD,
|
|||
if (Module *M = ND->getOwningModuleForLinkage())
|
||||
mangleModuleName(M);
|
||||
|
||||
// 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 (DC->isTranslationUnit() || isStdNamespace(DC)) {
|
||||
// Check if we have a template.
|
||||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
|
@ -1657,8 +1669,7 @@ void CXXNameMangler::mangleNestedName(GlobalDecl GD,
|
|||
if (GlobalDecl TD = isTemplate(GD, TemplateArgs)) {
|
||||
mangleTemplatePrefix(TD, NoFunction);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
manglePrefix(DC, NoFunction);
|
||||
mangleUnqualifiedName(GD, AdditionalAbiTags);
|
||||
}
|
||||
|
@ -1678,6 +1689,23 @@ void CXXNameMangler::mangleNestedName(const TemplateDecl *TD,
|
|||
Out << 'E';
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleNestedNameWithClosurePrefix(
|
||||
GlobalDecl GD, const NamedDecl *PrefixND,
|
||||
const AbiTagList *AdditionalAbiTags) {
|
||||
// A <closure-prefix> represents a variable or field, not a regular
|
||||
// DeclContext, so needs special handling. In this case we're mangling a
|
||||
// limited form of <nested-name>:
|
||||
//
|
||||
// <nested-name> ::= N <closure-prefix> <closure-type-name> E
|
||||
|
||||
Out << 'N';
|
||||
|
||||
mangleClosurePrefix(PrefixND);
|
||||
mangleUnqualifiedName(GD, AdditionalAbiTags);
|
||||
|
||||
Out << 'E';
|
||||
}
|
||||
|
||||
static GlobalDecl getParentOfLocalEntity(const DeclContext *DC) {
|
||||
GlobalDecl GD;
|
||||
// The Itanium spec says:
|
||||
|
@ -1753,7 +1781,10 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
|
|||
if (D == RD) {
|
||||
mangleUnqualifiedName(RD, AdditionalAbiTags);
|
||||
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
|
||||
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
|
||||
if (const NamedDecl *PrefixND = getClosurePrefix(BD))
|
||||
mangleClosurePrefix(PrefixND, true /*NoFunction*/);
|
||||
else
|
||||
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
|
||||
assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
|
||||
mangleUnqualifiedBlock(BD);
|
||||
} else {
|
||||
|
@ -1803,13 +1834,20 @@ void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
|
|||
mangleLocalName(Block, /* AdditionalAbiTags */ nullptr);
|
||||
return;
|
||||
}
|
||||
manglePrefix(getEffectiveDeclContext(Block));
|
||||
if (const NamedDecl *PrefixND = getClosurePrefix(Block))
|
||||
mangleClosurePrefix(PrefixND);
|
||||
else
|
||||
manglePrefix(DC);
|
||||
mangleUnqualifiedBlock(Block);
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
|
||||
// When trying to be ABI-compatibility with clang 12 and before, mangle a
|
||||
// <data-member-prefix> now, with no substitutions and no <template-args>.
|
||||
if (Decl *Context = Block->getBlockManglingContextDecl()) {
|
||||
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
|
||||
if (getASTContext().getLangOpts().getClangABICompat() <=
|
||||
LangOptions::ClangABI::Ver12 &&
|
||||
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
|
||||
Context->getDeclContext()->isRecord()) {
|
||||
const auto *ND = cast<NamedDecl>(Context);
|
||||
if (ND->getIdentifier()) {
|
||||
|
@ -1882,20 +1920,13 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
|
|||
}
|
||||
|
||||
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
||||
// If the context of a closure type is an initializer for a class member
|
||||
// (static or nonstatic), it is encoded in a qualified name with a final
|
||||
// <prefix> of the form:
|
||||
//
|
||||
// <data-member-prefix> := <member source-name> M
|
||||
//
|
||||
// Technically, the data-member-prefix is part of the <prefix>. However,
|
||||
// since a closure type will always be mangled with a prefix, it's easier
|
||||
// to emit that last part of the prefix here.
|
||||
// When trying to be ABI-compatibility with clang 12 and before, mangle a
|
||||
// <data-member-prefix> now, with no substitutions.
|
||||
if (Decl *Context = Lambda->getLambdaContextDecl()) {
|
||||
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
|
||||
if (getASTContext().getLangOpts().getClangABICompat() <=
|
||||
LangOptions::ClangABI::Ver12 &&
|
||||
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
|
||||
!isa<ParmVarDecl>(Context)) {
|
||||
// FIXME: 'inline auto [a, b] = []{ return ... };' does not get a
|
||||
// reasonable mangling here.
|
||||
if (const IdentifierInfo *Name
|
||||
= cast<NamedDecl>(Context)->getIdentifier()) {
|
||||
mangleSourceName(Name);
|
||||
|
@ -1978,6 +2009,7 @@ void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
|
|||
void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
|
||||
// <prefix> ::= <prefix> <unqualified-name>
|
||||
// ::= <template-prefix> <template-args>
|
||||
// ::= <closure-prefix>
|
||||
// ::= <template-param>
|
||||
// ::= # empty
|
||||
// ::= <substitution>
|
||||
|
@ -1996,11 +2028,14 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
|
|||
if (mangleSubstitution(ND))
|
||||
return;
|
||||
|
||||
// Check if we have a template.
|
||||
// Check if we have a template-prefix or a closure-prefix.
|
||||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) {
|
||||
mangleTemplatePrefix(TD);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
} else if (const NamedDecl *PrefixND = getClosurePrefix(ND)) {
|
||||
mangleClosurePrefix(PrefixND, NoFunction);
|
||||
mangleUnqualifiedName(ND, nullptr);
|
||||
} else {
|
||||
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
|
||||
mangleUnqualifiedName(ND, nullptr);
|
||||
|
@ -2066,6 +2101,50 @@ void CXXNameMangler::mangleTemplatePrefix(GlobalDecl GD,
|
|||
addSubstitution(ND);
|
||||
}
|
||||
|
||||
const NamedDecl *CXXNameMangler::getClosurePrefix(const Decl *ND) {
|
||||
if (getASTContext().getLangOpts().getClangABICompat() <=
|
||||
LangOptions::ClangABI::Ver12)
|
||||
return nullptr;
|
||||
|
||||
const NamedDecl *Context = nullptr;
|
||||
if (auto *Block = dyn_cast<BlockDecl>(ND)) {
|
||||
Context = dyn_cast_or_null<NamedDecl>(Block->getBlockManglingContextDecl());
|
||||
} else if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
|
||||
if (RD->isLambda())
|
||||
Context = dyn_cast_or_null<NamedDecl>(RD->getLambdaContextDecl());
|
||||
}
|
||||
if (!Context)
|
||||
return nullptr;
|
||||
|
||||
// Only lambdas within the initializer of a non-local variable or non-static
|
||||
// data member get a <closure-prefix>.
|
||||
if ((isa<VarDecl>(Context) && cast<VarDecl>(Context)->hasGlobalStorage()) ||
|
||||
isa<FieldDecl>(Context))
|
||||
return Context;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleClosurePrefix(const NamedDecl *ND, bool NoFunction) {
|
||||
// <closure-prefix> ::= [ <prefix> ] <unqualified-name> M
|
||||
// ::= <template-prefix> <template-args> M
|
||||
if (mangleSubstitution(ND))
|
||||
return;
|
||||
|
||||
const TemplateArgumentList *TemplateArgs = nullptr;
|
||||
if (GlobalDecl TD = isTemplate(ND, TemplateArgs)) {
|
||||
mangleTemplatePrefix(TD, NoFunction);
|
||||
mangleTemplateArgs(asTemplateName(TD), *TemplateArgs);
|
||||
} else {
|
||||
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
|
||||
mangleUnqualifiedName(ND, nullptr);
|
||||
}
|
||||
|
||||
Out << 'M';
|
||||
|
||||
addSubstitution(ND);
|
||||
}
|
||||
|
||||
/// Mangles a template name under the production <type>. Required for
|
||||
/// template template arguments.
|
||||
/// <type> ::= <class-enum-type>
|
||||
|
|
|
@ -3509,6 +3509,8 @@ void CompilerInvocation::GenerateLangArgs(const LangOptions &Opts,
|
|||
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "9.0", SA);
|
||||
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver11)
|
||||
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "11.0", SA);
|
||||
else if (Opts.getClangABICompat() == LangOptions::ClangABI::Ver12)
|
||||
GenerateArg(Args, OPT_fclang_abi_compat_EQ, "12.0", SA);
|
||||
|
||||
if (Opts.getSignReturnAddressScope() ==
|
||||
LangOptions::SignReturnAddressScopeKind::All)
|
||||
|
@ -3970,6 +3972,8 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
|||
Opts.setClangABICompat(LangOptions::ClangABI::Ver9);
|
||||
else if (Major <= 11)
|
||||
Opts.setClangABICompat(LangOptions::ClangABI::Ver11);
|
||||
else if (Major <= 12)
|
||||
Opts.setClangABICompat(LangOptions::ClangABI::Ver12);
|
||||
} else if (Ver != "latest") {
|
||||
Diags.Report(diag::err_drv_invalid_value)
|
||||
<< A->getAsString(Args) << A->getValue();
|
||||
|
|
|
@ -13,11 +13,13 @@
|
|||
// RUN: %clang_cc1 -std=c++17 -triple x86_64-linux-gnu -fenable-matrix -fclang-abi-compat=11 %s -emit-llvm -o - \
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17 %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fenable-matrix -fclang-abi-compat=11 %s -emit-llvm -o - \
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17,PRE12-CXX20 %s
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17,PRE12-CXX20,PRE13-CXX20 %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fenable-matrix -fclang-abi-compat=12 %s -emit-llvm -o - \
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17,V12-CXX20,PRE13-CXX20 %s
|
||||
// RUN: %clang_cc1 -std=c++98 -triple x86_64-linux-gnu -fenable-matrix -fclang-abi-compat=latest %s -emit-llvm -o - -Wno-c++11-extensions \
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,V12 %s
|
||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-linux-gnu -fenable-matrix -fclang-abi-compat=latest %s -emit-llvm -o - \
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17,V12-CXX20 %s
|
||||
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17,V12-CXX20,V13-CXX20 %s
|
||||
|
||||
typedef __attribute__((vector_size(8))) long long v1xi64;
|
||||
void clang39(v1xi64) {}
|
||||
|
@ -136,3 +138,12 @@ template void test8<2>(matrix1xN<2> a);
|
|||
void test9(void) __attribute__((enable_if(1, ""))) {}
|
||||
|
||||
}
|
||||
|
||||
#if __cplusplus >= 202002L
|
||||
// PRE13-CXX20: @_Z15observe_lambdasI17inline_var_lambdaMUlvE_17inline_var_lambdaMUlvE0_PiS2_S0_S1_EiT_T0_T1_T2_
|
||||
// V13-CXX20: @_Z15observe_lambdasIN17inline_var_lambdaMUlvE_ENS0_UlvE0_EPiS3_S1_S2_EiT_T0_T1_T2_
|
||||
template <typename T, typename U, typename V, typename W, typename = T, typename = U>
|
||||
int observe_lambdas(T, U, V, W) { return 0; }
|
||||
inline auto inline_var_lambda = observe_lambdas([]{}, []{}, (int*)0, (int*)0);
|
||||
int use_inline_var_lambda() { return inline_var_lambda; }
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,13 @@ namespace non_template {
|
|||
L l;
|
||||
}
|
||||
|
||||
// It's important that this is not in a namespace; we're testing the mangling
|
||||
// of lambdas in top-level inline variables here.
|
||||
inline auto lambda_in_inline_variable = [] {};
|
||||
template<typename T> struct Wrap {};
|
||||
// CHECK-LABEL: define {{.*}} @_Z30test_lambda_in_inline_variable4WrapIN25lambda_in_inline_variableMUlvE_EE
|
||||
void test_lambda_in_inline_variable(Wrap<decltype(lambda_in_inline_variable)>) {}
|
||||
|
||||
namespace lambdas_in_NSDMIs_template_class {
|
||||
template<class T>
|
||||
struct L {
|
||||
|
|
|
@ -38,7 +38,7 @@ template<typename T, int> struct X {};
|
|||
inline auto pack = []<typename ...T, T ...N>(T (&...)[N]) {};
|
||||
int arr1[] = {1};
|
||||
int arr2[] = {1, 2};
|
||||
// CHECK: @_ZNK4packMUlTpTyTpTnT_DpRAT0__S_E_clIJiiEJLi1ELi2EEEEDaS2_(
|
||||
// CHECK: @_ZNK4packMUlTpTyTpTnT_DpRAT0__S0_E_clIJiiEJLi1ELi2EEEEDaS3_(
|
||||
void use_pack() { pack(arr1, arr2); }
|
||||
|
||||
inline void collision() {
|
||||
|
|
Loading…
Reference in New Issue