Revert "Fix bad mangling of <data-member-prefix> for a closure in the initializer of a variable at global namespace scope."

This reverts commit 697ac15a0f, for which
review was not complete. That change was accidentally pushed when
an unrelated change was pushed.
This commit is contained in:
Richard Smith 2021-05-11 17:46:18 -07:00
parent 3978333b71
commit bb726383ac
7 changed files with 39 additions and 128 deletions

View File

@ -75,6 +75,23 @@ 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).

View File

@ -164,18 +164,13 @@ 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

View File

@ -538,16 +538,11 @@ 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);
@ -987,13 +982,6 @@ 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;
@ -1668,7 +1656,8 @@ 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);
}
@ -1688,23 +1677,6 @@ 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:
@ -1780,10 +1752,7 @@ void CXXNameMangler::mangleLocalName(GlobalDecl GD,
if (D == RD) {
mangleUnqualifiedName(RD, AdditionalAbiTags);
} else if (const BlockDecl *BD = dyn_cast<BlockDecl>(D)) {
if (const NamedDecl *PrefixND = getClosurePrefix(BD))
mangleClosurePrefix(PrefixND, true /*NoFunction*/);
else
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
manglePrefix(getEffectiveDeclContext(BD), true /*NoFunction*/);
assert(!AdditionalAbiTags && "Block cannot have additional abi tags");
mangleUnqualifiedBlock(BD);
} else {
@ -1833,20 +1802,13 @@ void CXXNameMangler::mangleBlockForPrefix(const BlockDecl *Block) {
mangleLocalName(Block, /* AdditionalAbiTags */ nullptr);
return;
}
if (const NamedDecl *PrefixND = getClosurePrefix(Block))
mangleClosurePrefix(PrefixND);
else
manglePrefix(DC);
manglePrefix(getEffectiveDeclContext(Block));
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 (getASTContext().getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver12 &&
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
if ((isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
Context->getDeclContext()->isRecord()) {
const auto *ND = cast<NamedDecl>(Context);
if (ND->getIdentifier()) {
@ -1919,13 +1881,20 @@ void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
}
void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
// When trying to be ABI-compatibility with clang 12 and before, mangle a
// <data-member-prefix> now, with no substitutions.
// 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.
if (Decl *Context = Lambda->getLambdaContextDecl()) {
if (getASTContext().getLangOpts().getClangABICompat() <=
LangOptions::ClangABI::Ver12 &&
(isa<VarDecl>(Context) || isa<FieldDecl>(Context)) &&
if ((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);
@ -2008,7 +1977,6 @@ 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>
@ -2027,14 +1995,11 @@ void CXXNameMangler::manglePrefix(const DeclContext *DC, bool NoFunction) {
if (mangleSubstitution(ND))
return;
// Check if we have a template-prefix or a closure-prefix.
// Check if we have a template.
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);
@ -2100,50 +2065,6 @@ 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>

View File

@ -3509,8 +3509,6 @@ 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)
@ -3972,8 +3970,6 @@ 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();

View File

@ -13,13 +13,11 @@
// 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,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: | FileCheck --check-prefixes=CHECK,V39,V5,PRE12,PRE12-CXX17,PRE12-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,V13-CXX20 %s
// RUN: | FileCheck --check-prefixes=CHECK,V39,V5,V12,V12-CXX17,V12-CXX20 %s
typedef __attribute__((vector_size(8))) long long v1xi64;
void clang39(v1xi64) {}
@ -138,12 +136,3 @@ 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

View File

@ -22,13 +22,6 @@ 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 {

View File

@ -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__S0_E_clIJiiEJLi1ELi2EEEEDaS3_(
// CHECK: @_ZNK4packMUlTpTyTpTnT_DpRAT0__S_E_clIJiiEJLi1ELi2EEEEDaS2_(
void use_pack() { pack(arr1, arr2); }
inline void collision() {