[c++20] Fix some ambiguities in our mangling of lambdas with explicit
template parameters. This finishes the implementation of the proposal described in https://github.com/itanium-cxx-abi/cxx-abi/issues/31. (We already implemented the <lambda-sig> extensions, but didn't take them into account when computing mangling numbers, and didn't deal properly with expanded parameter packs, and didn't disambiguate between different levels of template parameters in manglings.) llvm-svn: 371004
This commit is contained in:
parent
33b8a55329
commit
7ac42374ab
|
@ -170,6 +170,8 @@ public:
|
||||||
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
|
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
|
||||||
raw_ostream &) = 0;
|
raw_ostream &) = 0;
|
||||||
|
|
||||||
|
virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;
|
||||||
|
|
||||||
static bool classof(const MangleContext *C) {
|
static bool classof(const MangleContext *C) {
|
||||||
return C->getKind() == MK_Itanium;
|
return C->getKind() == MK_Itanium;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "clang/AST/DeclBase.h"
|
#include "clang/AST/DeclBase.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
|
#include "clang/AST/ASTLambda.h"
|
||||||
#include "clang/AST/ASTMutationListener.h"
|
#include "clang/AST/ASTMutationListener.h"
|
||||||
#include "clang/AST/Attr.h"
|
#include "clang/AST/Attr.h"
|
||||||
#include "clang/AST/AttrIterator.h"
|
#include "clang/AST/AttrIterator.h"
|
||||||
|
@ -1043,6 +1044,12 @@ DeclContext *DeclContext::getLookupParent() {
|
||||||
getLexicalParent()->getRedeclContext()->isRecord())
|
getLexicalParent()->getRedeclContext()->isRecord())
|
||||||
return getLexicalParent();
|
return getLexicalParent();
|
||||||
|
|
||||||
|
// A lookup within the call operator of a lambda never looks in the lambda
|
||||||
|
// class; instead, skip to the context in which that closure type is
|
||||||
|
// declared.
|
||||||
|
if (isLambdaCallOperator(this))
|
||||||
|
return getParent()->getParent();
|
||||||
|
|
||||||
return getParent();
|
return getParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,10 +19,12 @@
|
||||||
#include "CXXABI.h"
|
#include "CXXABI.h"
|
||||||
#include "clang/AST/ASTContext.h"
|
#include "clang/AST/ASTContext.h"
|
||||||
#include "clang/AST/DeclCXX.h"
|
#include "clang/AST/DeclCXX.h"
|
||||||
|
#include "clang/AST/Mangle.h"
|
||||||
#include "clang/AST/MangleNumberingContext.h"
|
#include "clang/AST/MangleNumberingContext.h"
|
||||||
#include "clang/AST/RecordLayout.h"
|
#include "clang/AST/RecordLayout.h"
|
||||||
#include "clang/AST/Type.h"
|
#include "clang/AST/Type.h"
|
||||||
#include "clang/Basic/TargetInfo.h"
|
#include "clang/Basic/TargetInfo.h"
|
||||||
|
#include "llvm/ADT/FoldingSet.h"
|
||||||
#include "llvm/ADT/iterator.h"
|
#include "llvm/ADT/iterator.h"
|
||||||
|
|
||||||
using namespace clang;
|
using namespace clang;
|
||||||
|
@ -73,10 +75,33 @@ struct DecompositionDeclName {
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
|
template<typename T> bool isDenseMapKeyEmpty(T V) {
|
||||||
|
return llvm::DenseMapInfo<T>::isEqual(
|
||||||
|
V, llvm::DenseMapInfo<T>::getEmptyKey());
|
||||||
|
}
|
||||||
|
template<typename T> bool isDenseMapKeyTombstone(T V) {
|
||||||
|
return llvm::DenseMapInfo<T>::isEqual(
|
||||||
|
V, llvm::DenseMapInfo<T>::getTombstoneKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
Optional<bool> areDenseMapKeysEqualSpecialValues(T LHS, T RHS) {
|
||||||
|
bool LHSEmpty = isDenseMapKeyEmpty(LHS);
|
||||||
|
bool RHSEmpty = isDenseMapKeyEmpty(RHS);
|
||||||
|
if (LHSEmpty || RHSEmpty)
|
||||||
|
return LHSEmpty && RHSEmpty;
|
||||||
|
|
||||||
|
bool LHSTombstone = isDenseMapKeyTombstone(LHS);
|
||||||
|
bool RHSTombstone = isDenseMapKeyTombstone(RHS);
|
||||||
|
if (LHSTombstone || RHSTombstone)
|
||||||
|
return LHSTombstone && RHSTombstone;
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
struct DenseMapInfo<DecompositionDeclName> {
|
struct DenseMapInfo<DecompositionDeclName> {
|
||||||
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
|
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
|
||||||
using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>;
|
|
||||||
static DecompositionDeclName getEmptyKey() {
|
static DecompositionDeclName getEmptyKey() {
|
||||||
return {ArrayInfo::getEmptyKey()};
|
return {ArrayInfo::getEmptyKey()};
|
||||||
}
|
}
|
||||||
|
@ -88,10 +113,10 @@ struct DenseMapInfo<DecompositionDeclName> {
|
||||||
return llvm::hash_combine_range(Key.begin(), Key.end());
|
return llvm::hash_combine_range(Key.begin(), Key.end());
|
||||||
}
|
}
|
||||||
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
|
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
|
||||||
if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey()))
|
if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
|
||||||
return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey());
|
LHS.Bindings, RHS.Bindings))
|
||||||
if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey()))
|
return *Result;
|
||||||
return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey());
|
|
||||||
return LHS.Bindings.size() == RHS.Bindings.size() &&
|
return LHS.Bindings.size() == RHS.Bindings.size() &&
|
||||||
std::equal(LHS.begin(), LHS.end(), RHS.begin());
|
std::equal(LHS.begin(), LHS.end(), RHS.begin());
|
||||||
}
|
}
|
||||||
|
@ -103,29 +128,32 @@ namespace {
|
||||||
/// Keeps track of the mangled names of lambda expressions and block
|
/// Keeps track of the mangled names of lambda expressions and block
|
||||||
/// literals within a particular context.
|
/// literals within a particular context.
|
||||||
class ItaniumNumberingContext : public MangleNumberingContext {
|
class ItaniumNumberingContext : public MangleNumberingContext {
|
||||||
llvm::DenseMap<const Type *, unsigned> ManglingNumbers;
|
ItaniumMangleContext *Mangler;
|
||||||
|
llvm::StringMap<unsigned> LambdaManglingNumbers;
|
||||||
|
unsigned BlockManglingNumber = 0;
|
||||||
llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
|
llvm::DenseMap<const IdentifierInfo *, unsigned> VarManglingNumbers;
|
||||||
llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
|
llvm::DenseMap<const IdentifierInfo *, unsigned> TagManglingNumbers;
|
||||||
llvm::DenseMap<DecompositionDeclName, unsigned>
|
llvm::DenseMap<DecompositionDeclName, unsigned>
|
||||||
DecompsitionDeclManglingNumbers;
|
DecompsitionDeclManglingNumbers;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
|
ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}
|
||||||
const FunctionProtoType *Proto =
|
|
||||||
CallOperator->getType()->getAs<FunctionProtoType>();
|
|
||||||
ASTContext &Context = CallOperator->getASTContext();
|
|
||||||
|
|
||||||
FunctionProtoType::ExtProtoInfo EPI;
|
unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
|
||||||
EPI.Variadic = Proto->isVariadic();
|
const CXXRecordDecl *Lambda = CallOperator->getParent();
|
||||||
QualType Key =
|
assert(Lambda->isLambda());
|
||||||
Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), EPI);
|
|
||||||
Key = Context.getCanonicalType(Key);
|
// Computation of the <lambda-sig> is non-trivial and subtle. Rather than
|
||||||
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
|
// duplicating it here, just mangle the <lambda-sig> directly.
|
||||||
|
llvm::SmallString<128> LambdaSig;
|
||||||
|
llvm::raw_svector_ostream Out(LambdaSig);
|
||||||
|
Mangler->mangleLambdaSig(Lambda, Out);
|
||||||
|
|
||||||
|
return ++LambdaManglingNumbers[LambdaSig];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getManglingNumber(const BlockDecl *BD) override {
|
unsigned getManglingNumber(const BlockDecl *BD) override {
|
||||||
const Type *Ty = nullptr;
|
return ++BlockManglingNumber;
|
||||||
return ++ManglingNumbers[Ty];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getStaticLocalNumber(const VarDecl *VD) override {
|
unsigned getStaticLocalNumber(const VarDecl *VD) override {
|
||||||
|
@ -154,10 +182,13 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class ItaniumCXXABI : public CXXABI {
|
class ItaniumCXXABI : public CXXABI {
|
||||||
|
private:
|
||||||
|
std::unique_ptr<MangleContext> Mangler;
|
||||||
protected:
|
protected:
|
||||||
ASTContext &Context;
|
ASTContext &Context;
|
||||||
public:
|
public:
|
||||||
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
|
ItaniumCXXABI(ASTContext &Ctx)
|
||||||
|
: Mangler(Ctx.createMangleContext()), Context(Ctx) {}
|
||||||
|
|
||||||
MemberPointerInfo
|
MemberPointerInfo
|
||||||
getMemberPointerInfo(const MemberPointerType *MPT) const override {
|
getMemberPointerInfo(const MemberPointerType *MPT) const override {
|
||||||
|
@ -218,7 +249,8 @@ public:
|
||||||
|
|
||||||
std::unique_ptr<MangleNumberingContext>
|
std::unique_ptr<MangleNumberingContext>
|
||||||
createMangleNumberingContext() const override {
|
createMangleNumberingContext() const override {
|
||||||
return std::make_unique<ItaniumNumberingContext>();
|
return std::make_unique<ItaniumNumberingContext>(
|
||||||
|
cast<ItaniumMangleContext>(Mangler.get()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -170,6 +170,8 @@ public:
|
||||||
|
|
||||||
void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
|
void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;
|
||||||
|
|
||||||
|
void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) override;
|
||||||
|
|
||||||
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
|
bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
|
||||||
// Lambda closure types are already numbered.
|
// Lambda closure types are already numbered.
|
||||||
if (isLambda(ND))
|
if (isLambda(ND))
|
||||||
|
@ -424,6 +426,7 @@ public:
|
||||||
void mangleName(const NamedDecl *ND);
|
void mangleName(const NamedDecl *ND);
|
||||||
void mangleType(QualType T);
|
void mangleType(QualType T);
|
||||||
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
|
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
|
||||||
|
void mangleLambdaSig(const CXXRecordDecl *Lambda);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -550,7 +553,7 @@ private:
|
||||||
void mangleTemplateArgs(const TemplateArgumentList &AL);
|
void mangleTemplateArgs(const TemplateArgumentList &AL);
|
||||||
void mangleTemplateArg(TemplateArgument A);
|
void mangleTemplateArg(TemplateArgument A);
|
||||||
|
|
||||||
void mangleTemplateParameter(unsigned Index);
|
void mangleTemplateParameter(unsigned Depth, unsigned Index);
|
||||||
|
|
||||||
void mangleFunctionParam(const ParmVarDecl *parm);
|
void mangleFunctionParam(const ParmVarDecl *parm);
|
||||||
|
|
||||||
|
@ -965,7 +968,7 @@ void CXXNameMangler::mangleUnscopedTemplateName(
|
||||||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
||||||
assert(!AdditionalAbiTags &&
|
assert(!AdditionalAbiTags &&
|
||||||
"template template param cannot have abi tags");
|
"template template param cannot have abi tags");
|
||||||
mangleTemplateParameter(TTP->getIndex());
|
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||||
} else if (isa<BuiltinTemplateDecl>(ND)) {
|
} else if (isa<BuiltinTemplateDecl>(ND)) {
|
||||||
mangleUnscopedName(ND, AdditionalAbiTags);
|
mangleUnscopedName(ND, AdditionalAbiTags);
|
||||||
} else {
|
} else {
|
||||||
|
@ -1686,16 +1689,42 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
|
||||||
// ::= Tn <type> # template non-type parameter
|
// ::= Tn <type> # template non-type parameter
|
||||||
// ::= Tt <template-param-decl>* E # template template parameter
|
// ::= Tt <template-param-decl>* E # template template parameter
|
||||||
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
|
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
|
||||||
if (isa<TemplateTypeParmDecl>(Decl)) {
|
if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) {
|
||||||
|
if (Ty->isParameterPack())
|
||||||
|
Out << "Tp";
|
||||||
Out << "Ty";
|
Out << "Ty";
|
||||||
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
|
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
|
||||||
Out << "Tn";
|
if (Tn->isExpandedParameterPack()) {
|
||||||
mangleType(Tn->getType());
|
for (unsigned I = 0, N = Tn->getNumExpansionTypes(); I != N; ++I) {
|
||||||
|
Out << "Tn";
|
||||||
|
mangleType(Tn->getExpansionType(I));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QualType T = Tn->getType();
|
||||||
|
if (Tn->isParameterPack()) {
|
||||||
|
Out << "Tp";
|
||||||
|
T = T->castAs<PackExpansionType>()->getPattern();
|
||||||
|
}
|
||||||
|
Out << "Tn";
|
||||||
|
mangleType(T);
|
||||||
|
}
|
||||||
} else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
|
} else if (auto *Tt = dyn_cast<TemplateTemplateParmDecl>(Decl)) {
|
||||||
Out << "Tt";
|
if (Tt->isExpandedParameterPack()) {
|
||||||
for (auto *Param : *Tt->getTemplateParameters())
|
for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N;
|
||||||
mangleTemplateParamDecl(Param);
|
++I) {
|
||||||
Out << "E";
|
Out << "Tt";
|
||||||
|
for (auto *Param : *Tt->getExpansionTemplateParameters(I))
|
||||||
|
mangleTemplateParamDecl(Param);
|
||||||
|
Out << "E";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (Tt->isParameterPack())
|
||||||
|
Out << "Tp";
|
||||||
|
Out << "Tt";
|
||||||
|
for (auto *Param : *Tt->getTemplateParameters())
|
||||||
|
mangleTemplateParamDecl(Param);
|
||||||
|
Out << "E";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1726,12 +1755,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Out << "Ul";
|
Out << "Ul";
|
||||||
for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
|
mangleLambdaSig(Lambda);
|
||||||
mangleTemplateParamDecl(D);
|
|
||||||
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
|
|
||||||
getAs<FunctionProtoType>();
|
|
||||||
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
|
|
||||||
Lambda->getLambdaStaticInvoker());
|
|
||||||
Out << "E";
|
Out << "E";
|
||||||
|
|
||||||
// The number is omitted for the first closure type with a given
|
// The number is omitted for the first closure type with a given
|
||||||
|
@ -1746,6 +1770,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
|
||||||
Out << '_';
|
Out << '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CXXNameMangler::mangleLambdaSig(const CXXRecordDecl *Lambda) {
|
||||||
|
for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
|
||||||
|
mangleTemplateParamDecl(D);
|
||||||
|
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
|
||||||
|
getAs<FunctionProtoType>();
|
||||||
|
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
|
||||||
|
Lambda->getLambdaStaticInvoker());
|
||||||
|
}
|
||||||
|
|
||||||
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
|
void CXXNameMangler::manglePrefix(NestedNameSpecifier *qualifier) {
|
||||||
switch (qualifier->getKind()) {
|
switch (qualifier->getKind()) {
|
||||||
case NestedNameSpecifier::Global:
|
case NestedNameSpecifier::Global:
|
||||||
|
@ -1852,7 +1885,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,
|
||||||
|
|
||||||
// <template-template-param> ::= <template-param>
|
// <template-template-param> ::= <template-param>
|
||||||
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
|
||||||
mangleTemplateParameter(TTP->getIndex());
|
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||||
} else {
|
} else {
|
||||||
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
|
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
|
||||||
if (isa<BuiltinTemplateDecl>(ND))
|
if (isa<BuiltinTemplateDecl>(ND))
|
||||||
|
@ -1885,8 +1918,8 @@ void CXXNameMangler::mangleType(TemplateName TN) {
|
||||||
goto HaveDecl;
|
goto HaveDecl;
|
||||||
|
|
||||||
HaveDecl:
|
HaveDecl:
|
||||||
if (isa<TemplateTemplateParmDecl>(TD))
|
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
|
||||||
mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
|
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||||
else
|
else
|
||||||
mangleName(TD);
|
mangleName(TD);
|
||||||
break;
|
break;
|
||||||
|
@ -2964,7 +2997,7 @@ void CXXNameMangler::mangleType(const MemberPointerType *T) {
|
||||||
|
|
||||||
// <type> ::= <template-param>
|
// <type> ::= <template-param>
|
||||||
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
|
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
|
||||||
mangleTemplateParameter(T->getIndex());
|
mangleTemplateParameter(T->getDepth(), T->getIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
// <type> ::= <template-param>
|
// <type> ::= <template-param>
|
||||||
|
@ -3535,7 +3568,7 @@ void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {
|
||||||
|
|
||||||
case Decl::NonTypeTemplateParm:
|
case Decl::NonTypeTemplateParm:
|
||||||
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
|
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
|
||||||
mangleTemplateParameter(PD->getIndex());
|
mangleTemplateParameter(PD->getDepth(), PD->getIndex());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4264,13 +4297,13 @@ recurse:
|
||||||
Out << "sZ";
|
Out << "sZ";
|
||||||
const NamedDecl *Pack = SPE->getPack();
|
const NamedDecl *Pack = SPE->getPack();
|
||||||
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
|
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
|
||||||
mangleTemplateParameter(TTP->getIndex());
|
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
|
||||||
else if (const NonTypeTemplateParmDecl *NTTP
|
else if (const NonTypeTemplateParmDecl *NTTP
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(Pack))
|
= dyn_cast<NonTypeTemplateParmDecl>(Pack))
|
||||||
mangleTemplateParameter(NTTP->getIndex());
|
mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
|
||||||
else if (const TemplateTemplateParmDecl *TempTP
|
else if (const TemplateTemplateParmDecl *TempTP
|
||||||
= dyn_cast<TemplateTemplateParmDecl>(Pack))
|
= dyn_cast<TemplateTemplateParmDecl>(Pack))
|
||||||
mangleTemplateParameter(TempTP->getIndex());
|
mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
|
||||||
else
|
else
|
||||||
mangleFunctionParam(cast<ParmVarDecl>(Pack));
|
mangleFunctionParam(cast<ParmVarDecl>(Pack));
|
||||||
break;
|
break;
|
||||||
|
@ -4557,13 +4590,21 @@ void CXXNameMangler::mangleTemplateArg(TemplateArgument A) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleTemplateParameter(unsigned Index) {
|
void CXXNameMangler::mangleTemplateParameter(unsigned Depth, unsigned Index) {
|
||||||
// <template-param> ::= T_ # first template parameter
|
// <template-param> ::= T_ # first template parameter
|
||||||
// ::= T <parameter-2 non-negative number> _
|
// ::= T <parameter-2 non-negative number> _
|
||||||
if (Index == 0)
|
// ::= TL <L-1 non-negative number> __
|
||||||
Out << "T_";
|
// ::= TL <L-1 non-negative number> _
|
||||||
else
|
// <parameter-2 non-negative number> _
|
||||||
Out << 'T' << (Index - 1) << '_';
|
//
|
||||||
|
// The latter two manglings are from a proposal here:
|
||||||
|
// https://github.com/itanium-cxx-abi/cxx-abi/issues/31#issuecomment-528122117
|
||||||
|
Out << 'T';
|
||||||
|
if (Depth != 0)
|
||||||
|
Out << 'L' << (Depth - 1) << '_';
|
||||||
|
if (Index != 0)
|
||||||
|
Out << (Index - 1);
|
||||||
|
Out << '_';
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleSeqID(unsigned SeqID) {
|
void CXXNameMangler::mangleSeqID(unsigned SeqID) {
|
||||||
|
@ -5080,6 +5121,12 @@ void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_os
|
||||||
llvm_unreachable("Can't mangle string literals");
|
llvm_unreachable("Can't mangle string literals");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ItaniumMangleContextImpl::mangleLambdaSig(const CXXRecordDecl *Lambda,
|
||||||
|
raw_ostream &Out) {
|
||||||
|
CXXNameMangler Mangler(*this, Out);
|
||||||
|
Mangler.mangleLambdaSig(Lambda);
|
||||||
|
}
|
||||||
|
|
||||||
ItaniumMangleContext *
|
ItaniumMangleContext *
|
||||||
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
|
ItaniumMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags) {
|
||||||
return new ItaniumMangleContextImpl(Context, Diags);
|
return new ItaniumMangleContextImpl(Context, Diags);
|
||||||
|
|
|
@ -407,6 +407,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(
|
||||||
MethodType, MethodTypeInfo, SC_None,
|
MethodType, MethodTypeInfo, SC_None,
|
||||||
/*isInline=*/true, ConstexprKind, EndLoc);
|
/*isInline=*/true, ConstexprKind, EndLoc);
|
||||||
Method->setAccess(AS_public);
|
Method->setAccess(AS_public);
|
||||||
|
if (!TemplateParams)
|
||||||
|
Class->addDecl(Method);
|
||||||
|
|
||||||
// Temporarily set the lexical declaration context to the current
|
// Temporarily set the lexical declaration context to the current
|
||||||
// context, so that the Scope stack matches the lexical nesting.
|
// context, so that the Scope stack matches the lexical nesting.
|
||||||
|
@ -418,9 +420,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(
|
||||||
TemplateParams,
|
TemplateParams,
|
||||||
Method) : nullptr;
|
Method) : nullptr;
|
||||||
if (TemplateMethod) {
|
if (TemplateMethod) {
|
||||||
TemplateMethod->setLexicalDeclContext(CurContext);
|
|
||||||
TemplateMethod->setAccess(AS_public);
|
TemplateMethod->setAccess(AS_public);
|
||||||
Method->setDescribedFunctionTemplate(TemplateMethod);
|
Method->setDescribedFunctionTemplate(TemplateMethod);
|
||||||
|
Class->addDecl(TemplateMethod);
|
||||||
|
TemplateMethod->setLexicalDeclContext(CurContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add parameters.
|
// Add parameters.
|
||||||
|
@ -1641,8 +1644,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
|
||||||
? CallOperator->getDescribedFunctionTemplate()
|
? CallOperator->getDescribedFunctionTemplate()
|
||||||
: cast<Decl>(CallOperator);
|
: cast<Decl>(CallOperator);
|
||||||
|
|
||||||
|
// FIXME: Is this really the best choice? Keeping the lexical decl context
|
||||||
|
// set as CurContext seems more faithful to the source.
|
||||||
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
|
TemplateOrNonTemplateCallOperatorDecl->setLexicalDeclContext(Class);
|
||||||
Class->addDecl(TemplateOrNonTemplateCallOperatorDecl);
|
|
||||||
|
|
||||||
PopExpressionEvaluationContext();
|
PopExpressionEvaluationContext();
|
||||||
|
|
||||||
|
|
|
@ -33,9 +33,68 @@ void call_inline_func() {
|
||||||
inline_func();
|
inline_func();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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_(
|
||||||
|
void use_pack() { pack(arr1, arr2); }
|
||||||
|
|
||||||
|
inline void collision() {
|
||||||
|
auto a = []<typename T, template<typename U, T> typename>{};
|
||||||
|
auto b = []<typename T, template<typename U, U> typename>{};
|
||||||
|
auto c = []<typename T, template<typename U, T> typename>{};
|
||||||
|
a.operator()<int, X>();
|
||||||
|
// CHECK: @_ZZ9collisionvENKUlTyTtTyTnT_EvE_clIi1XEEDav
|
||||||
|
b.operator()<int, X>();
|
||||||
|
// CHECK: @_ZZ9collisionvENKUlTyTtTyTnTL0__EvE_clIi1XEEDav
|
||||||
|
c.operator()<int, X>();
|
||||||
|
// CHECK: @_ZZ9collisionvENKUlTyTtTyTnT_EvE0_clIi1XEEDav
|
||||||
|
}
|
||||||
|
void use_collision() { collision(); }
|
||||||
|
|
||||||
template<typename> void f() {
|
template<typename> void f() {
|
||||||
// CHECK: define linkonce_odr {{.*}} @_ZZ1fIiEvvENKUlT_E_clIiEEDaS0_(
|
// CHECK: define linkonce_odr {{.*}} @_ZZ1fIiEvvENKUlT_E_clIiEEDaS0_(
|
||||||
auto x = [](auto){};
|
auto x = [](auto){};
|
||||||
x(0);
|
x(0);
|
||||||
}
|
}
|
||||||
void use_f() { f<int>(); }
|
void use_f() { f<int>(); }
|
||||||
|
|
||||||
|
template<typename> struct Y {
|
||||||
|
template<int> struct Z {};
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename ...T> void expanded() {
|
||||||
|
auto x = []<T..., template<T> typename...>{};
|
||||||
|
auto y = []<int, template<int> typename>{};
|
||||||
|
auto z = []<int, int, template<int> typename, template<int> typename>{};
|
||||||
|
// FIXME: Should we really require 'template' for y and z?
|
||||||
|
x.template operator()<(T())..., Y<T>::template Z...>();
|
||||||
|
y.template operator()<0, Y<int>::Z>();
|
||||||
|
y.template operator()<1, Y<int>::Z>();
|
||||||
|
z.template operator()<1, 2, Y<int>::Z, Y<float>::Z>();
|
||||||
|
}
|
||||||
|
void use_expanded() {
|
||||||
|
// CHECK: @_ZZ8expandedIJEEvvENKUlvE_clIJEJEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJEEvvENKUlTniTtTniEvE_clILi0EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJEEvvENKUlTniTtTniEvE_clILi1EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJEEvvENKUlTniTniTtTniETtTniEvE_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav(
|
||||||
|
expanded<>();
|
||||||
|
|
||||||
|
// FIXME: Should we really be using J...E for arguments corresponding to an
|
||||||
|
// expanded parameter pack?
|
||||||
|
// Note that the <lambda-sig>s of 'x' and 'y' collide here, after pack expansion.
|
||||||
|
// CHECK: @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE_clIJLi0EEJN1YIiE1ZEEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE0_clILi0EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiEEvvENKUlTniTtTniEvE0_clILi1EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiEEvvENKUlTniTniTtTniETtTniEvE_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav(
|
||||||
|
expanded<int>();
|
||||||
|
|
||||||
|
// Note that the <lambda-sig>s of 'x' and 'z' collide here, after pack expansion.
|
||||||
|
// CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTniTtTniETtTniEvE_clIJLi0ELi0EEJN1YIiE1ZES4_EEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTtTniEvE_clILi0EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTtTniEvE_clILi1EN1YIiE1ZEEEDav(
|
||||||
|
// CHECK: @_ZZ8expandedIJiiEEvvENKUlTniTniTtTniETtTniEvE0_clILi1ELi2EN1YIiE1ZENS2_IfE1ZEEEDav(
|
||||||
|
expanded<int, int>();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue