Skip to content

Commit

Permalink
[c++20] Fix some ambiguities in our mangling of lambdas with explicit
Browse files Browse the repository at this point in the history
template parameters.

This finishes the implementation of the proposal described in
itanium-cxx-abi/cxx-abi#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.)

git-svn-id: http://llvm.org/svn/llvm-project/cfe/trunk@371004 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
rsmith committed Sep 5, 2019
1 parent fd354b3 commit f1c71d7
Show file tree
Hide file tree
Showing 6 changed files with 200 additions and 49 deletions.
2 changes: 2 additions & 0 deletions include/clang/AST/Mangle.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class ItaniumMangleContext : public MangleContext {
virtual void mangleCXXDtorComdat(const CXXDestructorDecl *D,
raw_ostream &) = 0;

virtual void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) = 0;

static bool classof(const MangleContext *C) {
return C->getKind() == MK_Itanium;
}
Expand Down
7 changes: 7 additions & 0 deletions lib/AST/DeclBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

#include "clang/AST/DeclBase.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/ASTMutationListener.h"
#include "clang/AST/Attr.h"
#include "clang/AST/AttrIterator.h"
Expand Down Expand Up @@ -1043,6 +1044,12 @@ DeclContext *DeclContext::getLookupParent() {
getLexicalParent()->getRedeclContext()->isRecord())
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();
}

Expand Down
70 changes: 51 additions & 19 deletions lib/AST/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@
#include "CXXABI.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Mangle.h"
#include "clang/AST/MangleNumberingContext.h"
#include "clang/AST/RecordLayout.h"
#include "clang/AST/Type.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/iterator.h"

using namespace clang;
Expand Down Expand Up @@ -73,10 +75,33 @@ struct DecompositionDeclName {
}

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<>
struct DenseMapInfo<DecompositionDeclName> {
using ArrayInfo = llvm::DenseMapInfo<ArrayRef<const BindingDecl*>>;
using IdentInfo = llvm::DenseMapInfo<const IdentifierInfo*>;
static DecompositionDeclName getEmptyKey() {
return {ArrayInfo::getEmptyKey()};
}
Expand All @@ -88,10 +113,10 @@ struct DenseMapInfo<DecompositionDeclName> {
return llvm::hash_combine_range(Key.begin(), Key.end());
}
static bool isEqual(DecompositionDeclName LHS, DecompositionDeclName RHS) {
if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getEmptyKey()))
return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getEmptyKey());
if (ArrayInfo::isEqual(LHS.Bindings, ArrayInfo::getTombstoneKey()))
return ArrayInfo::isEqual(RHS.Bindings, ArrayInfo::getTombstoneKey());
if (Optional<bool> Result = areDenseMapKeysEqualSpecialValues(
LHS.Bindings, RHS.Bindings))
return *Result;

return LHS.Bindings.size() == RHS.Bindings.size() &&
std::equal(LHS.begin(), LHS.end(), RHS.begin());
}
Expand All @@ -103,29 +128,32 @@ namespace {
/// Keeps track of the mangled names of lambda expressions and block
/// literals within a particular context.
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> TagManglingNumbers;
llvm::DenseMap<DecompositionDeclName, unsigned>
DecompsitionDeclManglingNumbers;

public:
ItaniumNumberingContext(ItaniumMangleContext *Mangler) : Mangler(Mangler) {}

unsigned getManglingNumber(const CXXMethodDecl *CallOperator) override {
const FunctionProtoType *Proto =
CallOperator->getType()->getAs<FunctionProtoType>();
ASTContext &Context = CallOperator->getASTContext();
const CXXRecordDecl *Lambda = CallOperator->getParent();
assert(Lambda->isLambda());

// Computation of the <lambda-sig> is non-trivial and subtle. Rather than
// duplicating it here, just mangle the <lambda-sig> directly.
llvm::SmallString<128> LambdaSig;
llvm::raw_svector_ostream Out(LambdaSig);
Mangler->mangleLambdaSig(Lambda, Out);

FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = Proto->isVariadic();
QualType Key =
Context.getFunctionType(Context.VoidTy, Proto->getParamTypes(), EPI);
Key = Context.getCanonicalType(Key);
return ++ManglingNumbers[Key->castAs<FunctionProtoType>()];
return ++LambdaManglingNumbers[LambdaSig];
}

unsigned getManglingNumber(const BlockDecl *BD) override {
const Type *Ty = nullptr;
return ++ManglingNumbers[Ty];
return ++BlockManglingNumber;
}

unsigned getStaticLocalNumber(const VarDecl *VD) override {
Expand Down Expand Up @@ -154,10 +182,13 @@ class ItaniumNumberingContext : public MangleNumberingContext {
};

class ItaniumCXXABI : public CXXABI {
private:
std::unique_ptr<MangleContext> Mangler;
protected:
ASTContext &Context;
public:
ItaniumCXXABI(ASTContext &Ctx) : Context(Ctx) { }
ItaniumCXXABI(ASTContext &Ctx)
: Mangler(Ctx.createMangleContext()), Context(Ctx) {}

MemberPointerInfo
getMemberPointerInfo(const MemberPointerType *MPT) const override {
Expand Down Expand Up @@ -218,7 +249,8 @@ class ItaniumCXXABI : public CXXABI {

std::unique_ptr<MangleNumberingContext>
createMangleNumberingContext() const override {
return std::make_unique<ItaniumNumberingContext>();
return std::make_unique<ItaniumNumberingContext>(
cast<ItaniumMangleContext>(Mangler.get()));
}
};
}
Expand Down
103 changes: 75 additions & 28 deletions lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class ItaniumMangleContextImpl : public ItaniumMangleContext {

void mangleStringLiteral(const StringLiteral *, raw_ostream &) override;

void mangleLambdaSig(const CXXRecordDecl *Lambda, raw_ostream &) override;

bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) {
// Lambda closure types are already numbered.
if (isLambda(ND))
Expand Down Expand Up @@ -424,6 +426,7 @@ class CXXNameMangler {
void mangleName(const NamedDecl *ND);
void mangleType(QualType T);
void mangleNameOrStandardSubstitution(const NamedDecl *ND);
void mangleLambdaSig(const CXXRecordDecl *Lambda);

private:

Expand Down Expand Up @@ -550,7 +553,7 @@ class CXXNameMangler {
void mangleTemplateArgs(const TemplateArgumentList &AL);
void mangleTemplateArg(TemplateArgument A);

void mangleTemplateParameter(unsigned Index);
void mangleTemplateParameter(unsigned Depth, unsigned Index);

void mangleFunctionParam(const ParmVarDecl *parm);

Expand Down Expand Up @@ -965,7 +968,7 @@ void CXXNameMangler::mangleUnscopedTemplateName(
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
assert(!AdditionalAbiTags &&
"template template param cannot have abi tags");
mangleTemplateParameter(TTP->getIndex());
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
} else if (isa<BuiltinTemplateDecl>(ND)) {
mangleUnscopedName(ND, AdditionalAbiTags);
} else {
Expand Down Expand Up @@ -1686,16 +1689,42 @@ void CXXNameMangler::mangleUnqualifiedBlock(const BlockDecl *Block) {
// ::= Tn <type> # template non-type parameter
// ::= Tt <template-param-decl>* E # template template parameter
void CXXNameMangler::mangleTemplateParamDecl(const NamedDecl *Decl) {
if (isa<TemplateTypeParmDecl>(Decl)) {
if (auto *Ty = dyn_cast<TemplateTypeParmDecl>(Decl)) {
if (Ty->isParameterPack())
Out << "Tp";
Out << "Ty";
} else if (auto *Tn = dyn_cast<NonTypeTemplateParmDecl>(Decl)) {
Out << "Tn";
mangleType(Tn->getType());
if (Tn->isExpandedParameterPack()) {
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)) {
Out << "Tt";
for (auto *Param : *Tt->getTemplateParameters())
mangleTemplateParamDecl(Param);
Out << "E";
if (Tt->isExpandedParameterPack()) {
for (unsigned I = 0, N = Tt->getNumExpansionTemplateParameters(); I != N;
++I) {
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";
}
}
}

Expand Down Expand Up @@ -1726,12 +1755,7 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
}

Out << "Ul";
for (auto *D : Lambda->getLambdaExplicitTemplateParameters())
mangleTemplateParamDecl(D);
const FunctionProtoType *Proto = Lambda->getLambdaTypeInfo()->getType()->
getAs<FunctionProtoType>();
mangleBareFunctionType(Proto, /*MangleReturnType=*/false,
Lambda->getLambdaStaticInvoker());
mangleLambdaSig(Lambda);
Out << "E";

// The number is omitted for the first closure type with a given
Expand All @@ -1746,6 +1770,15 @@ void CXXNameMangler::mangleLambda(const CXXRecordDecl *Lambda) {
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) {
switch (qualifier->getKind()) {
case NestedNameSpecifier::Global:
Expand Down Expand Up @@ -1852,7 +1885,7 @@ void CXXNameMangler::mangleTemplatePrefix(const TemplateDecl *ND,

// <template-template-param> ::= <template-param>
if (const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(ND)) {
mangleTemplateParameter(TTP->getIndex());
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
} else {
manglePrefix(getEffectiveDeclContext(ND), NoFunction);
if (isa<BuiltinTemplateDecl>(ND))
Expand Down Expand Up @@ -1885,8 +1918,8 @@ void CXXNameMangler::mangleType(TemplateName TN) {
goto HaveDecl;

HaveDecl:
if (isa<TemplateTemplateParmDecl>(TD))
mangleTemplateParameter(cast<TemplateTemplateParmDecl>(TD)->getIndex());
if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TD))
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else
mangleName(TD);
break;
Expand Down Expand Up @@ -2964,7 +2997,7 @@ void CXXNameMangler::mangleType(const MemberPointerType *T) {

// <type> ::= <template-param>
void CXXNameMangler::mangleType(const TemplateTypeParmType *T) {
mangleTemplateParameter(T->getIndex());
mangleTemplateParameter(T->getDepth(), T->getIndex());
}

// <type> ::= <template-param>
Expand Down Expand Up @@ -3535,7 +3568,7 @@ void CXXNameMangler::mangleDeclRefExpr(const NamedDecl *D) {

case Decl::NonTypeTemplateParm:
const NonTypeTemplateParmDecl *PD = cast<NonTypeTemplateParmDecl>(D);
mangleTemplateParameter(PD->getIndex());
mangleTemplateParameter(PD->getDepth(), PD->getIndex());
break;
}
}
Expand Down Expand Up @@ -4264,13 +4297,13 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Out << "sZ";
const NamedDecl *Pack = SPE->getPack();
if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Pack))
mangleTemplateParameter(TTP->getIndex());
mangleTemplateParameter(TTP->getDepth(), TTP->getIndex());
else if (const NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(Pack))
mangleTemplateParameter(NTTP->getIndex());
mangleTemplateParameter(NTTP->getDepth(), NTTP->getIndex());
else if (const TemplateTemplateParmDecl *TempTP
= dyn_cast<TemplateTemplateParmDecl>(Pack))
mangleTemplateParameter(TempTP->getIndex());
mangleTemplateParameter(TempTP->getDepth(), TempTP->getIndex());
else
mangleFunctionParam(cast<ParmVarDecl>(Pack));
break;
Expand Down Expand Up @@ -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
// ::= T <parameter-2 non-negative number> _
if (Index == 0)
Out << "T_";
else
Out << 'T' << (Index - 1) << '_';
// ::= TL <L-1 non-negative number> __
// ::= TL <L-1 non-negative number> _
// <parameter-2 non-negative number> _
//
// 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) {
Expand Down Expand Up @@ -5080,6 +5121,12 @@ void ItaniumMangleContextImpl::mangleStringLiteral(const StringLiteral *, raw_os
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::create(ASTContext &Context, DiagnosticsEngine &Diags) {
return new ItaniumMangleContextImpl(Context, Diags);
Expand Down
Loading

0 comments on commit f1c71d7

Please sign in to comment.