diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-20 19:44:39 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-20 19:44:39 +0000 |
commit | 9e8c92a9c9b949bbb0408fbbd9a58e34894b6efc (patch) | |
tree | 9579005bf62f65f14d6478c74c2c36096d691398 /lib | |
parent | 86211df4d28f6fb3c48ab09f02a011e8570d8b1c (diff) |
Basic support for name mangling of C++11 lambda expressions. Because
name mangling in the Itanium C++ ABI for lambda expressions is so
dependent on context, we encode the number used to encode each lambda
as part of the lambda closure type, and maintain this value within
Sema.
Note that there are a several pieces still missing:
- We still get the linkage of lambda expressions wrong
- We aren't properly numbering or mangling lambda expressions that
occur in default function arguments or in data member initializers.
- We aren't (de-)serializing the lambda numbering tables
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150982 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/ASTContext.cpp | 7 | ||||
-rw-r--r-- | lib/AST/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 9 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 39 | ||||
-rw-r--r-- | lib/AST/LambdaMangleContext.cpp | 30 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 14 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 3 | ||||
-rw-r--r-- | lib/Serialization/ASTReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 1 |
10 files changed, 100 insertions, 8 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index cc651f9c9c..e0056da60b 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -6748,6 +6748,13 @@ size_t ASTContext::getSideTableAllocatedMemory() const { + llvm::capacity_in_bytes(ClassScopeSpecializationPattern); } +unsigned ASTContext::getLambdaManglingNumber(CXXMethodDecl *CallOperator) { + CXXRecordDecl *Lambda = CallOperator->getParent(); + return LambdaMangleContexts[Lambda->getDeclContext()] + .getManglingNumber(CallOperator); +} + + void ASTContext::setParameterIndex(const ParmVarDecl *D, unsigned int index) { ParamIndices[D] = index; } diff --git a/lib/AST/CMakeLists.txt b/lib/AST/CMakeLists.txt index 1f0100a580..651bcc4857 100644 --- a/lib/AST/CMakeLists.txt +++ b/lib/AST/CMakeLists.txt @@ -28,6 +28,7 @@ add_clang_library(clangAST InheritViz.cpp ItaniumCXXABI.cpp ItaniumMangle.cpp + LambdaMangleContext.cpp Mangle.cpp MicrosoftCXXABI.cpp MicrosoftMangle.cpp diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index f52f881050..cbc5950f83 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -764,7 +764,8 @@ LambdaExpr::LambdaExpr(QualType T, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, - SourceLocation ClosingBrace) + SourceLocation ClosingBrace, + unsigned ManglingNumber) : Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary, T->isDependentType(), T->isDependentType(), T->isDependentType(), /*ContainsUnexpandedParameterPack=*/false), @@ -785,6 +786,7 @@ LambdaExpr::LambdaExpr(QualType T, ASTContext &Context = Class->getASTContext(); Data.NumCaptures = NumCaptures; Data.NumExplicitCaptures = 0; + Data.ManglingNumber = ManglingNumber; Data.Captures = (Capture *)Context.Allocate(sizeof(Capture) * NumCaptures); Capture *ToCapture = Data.Captures; for (unsigned I = 0, N = Captures.size(); I != N; ++I) { @@ -824,7 +826,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, ArrayRef<Expr *> CaptureInits, ArrayRef<VarDecl *> ArrayIndexVars, ArrayRef<unsigned> ArrayIndexStarts, - SourceLocation ClosingBrace) { + SourceLocation ClosingBrace, + unsigned ManglingNumber) { // Determine the type of the expression (i.e., the type of the // function object we're creating). QualType T = Context.getTypeDeclType(Class); @@ -837,7 +840,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, ArrayIndexStarts, - ClosingBrace); + ClosingBrace, ManglingNumber); } LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures, diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 4843716909..a0bb6c74c3 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -122,6 +122,13 @@ public: } bool getNextDiscriminator(const NamedDecl *ND, unsigned &disc) { + // Lambda closure types with external linkage (indicated by a + // non-zero lambda mangling number) have their own numbering scheme, so + // they do not need a discriminator. + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(ND)) + if (RD->isLambda() && RD->getLambdaManglingNumber() > 0) + return false; + unsigned &discriminator = Uniquifier[ND]; if (!discriminator) discriminator = ++Discriminator; @@ -1076,6 +1083,38 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND, break; } + // <unnamed-type-name> ::= <closure-type-name> + // + // <closure-type-name> ::= Ul <lambda-sig> E [ <nonnegative number> ] _ + // <lambda-sig> ::= <parameter-type>+ # Parameter types or 'v' for 'void'. + if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(TD)) { + if (Record->isLambda()) { + // FIXME: Figure out if we're in a function body, default argument, + // or initializer for a class member. + + Out << "Ul"; + DeclarationName Name + = getASTContext().DeclarationNames.getCXXOperatorName(OO_Call); + const FunctionProtoType *Proto + = cast<CXXMethodDecl>(*Record->lookup(Name).first)->getType()-> + getAs<FunctionProtoType>(); + mangleBareFunctionType(Proto, /*MangleReturnType=*/false); + Out << "E"; + + // The number is omitted for the first closure type with a given + // <lambda-sig> in a given context; it is n-2 for the nth closure type + // (in lexical order) with that same <lambda-sig> and context. + // + // The AST keeps track of the number for us. + if (unsigned Number = Record->getLambdaManglingNumber()) { + if (Number > 1) + mangleNumber(Number - 2); + } + Out << '_'; + break; + } + } + // Get a unique id for the anonymous struct. uint64_t AnonStructId = Context.getAnonymousStructId(TD); diff --git a/lib/AST/LambdaMangleContext.cpp b/lib/AST/LambdaMangleContext.cpp new file mode 100644 index 0000000000..f5272a7fdb --- /dev/null +++ b/lib/AST/LambdaMangleContext.cpp @@ -0,0 +1,30 @@ +//===--- LambdaMangleContext.cpp - Context for mangling lambdas -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the LambdaMangleContext class, which keeps track of +// the Itanium C++ ABI mangling numbers for lambda expressions. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/LambdaMangleContext.h" +#include "clang/AST/DeclCXX.h" + +using namespace clang; + +unsigned LambdaMangleContext::getManglingNumber(CXXMethodDecl *CallOperator) { + const FunctionProtoType *Proto + = CallOperator->getType()->getAs<FunctionProtoType>(); + ASTContext &Context = CallOperator->getASTContext(); + + QualType Key = Context.getFunctionType(Context.VoidTy, + Proto->arg_type_begin(), + Proto->getNumArgs(), + FunctionProtoType::ExtProtoInfo()); + Key = Context.getCanonicalType(Key); + return ++ManglingNumbers[Key->castAs<FunctionProtoType>()]; +} diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 0d33e30183..fecf7b7765 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -886,8 +886,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( BodyScope.Exit(); if (!Stmt.isInvalid()) - return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), - getCurScope()); + return Actions.ActOnLambdaExpr(LambdaBeginLoc, Stmt.take(), getCurScope()); Actions.ActOnLambdaError(LambdaBeginLoc, getCurScope()); return ExprError(); diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 1a362d48e2..d1f87a2c18 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -483,7 +483,9 @@ static void addBlockPointerConversion(Sema &S, } ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, - Scope *CurScope, bool IsInstantiation) { + Scope *CurScope, + llvm::Optional<unsigned> ManglingNumber, + bool IsInstantiation) { // Leave the expression-evaluation context. DiscardCleanupsInEvaluationContext(); PopExpressionEvaluationContext(); @@ -633,11 +635,19 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, if (LambdaExprNeedsCleanups) ExprNeedsCleanups = true; + // If we don't already have a mangling number for this lambda expression, + // allocate one now. + if (!ManglingNumber) { + // FIXME: Default arguments, data member initializers are special. + ManglingNumber = Context.getLambdaManglingNumber(CallOperator); + } + LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, Captures, ExplicitParams, ExplicitResultType, CaptureInits, ArrayIndexVars, - ArrayIndexStarts, Body->getLocEnd()); + ArrayIndexStarts, Body->getLocEnd(), + *ManglingNumber); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 8a47a37d1c..7e095f7336 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7769,8 +7769,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { return ExprError(); } + unsigned ManglingNumber = E->getLambdaClass()->getLambdaManglingNumber(); return getSema().ActOnLambdaExpr(E->getLocStart(), Body.take(), - /*CurScope=*/0, + /*CurScope=*/0, ManglingNumber, /*IsInstantiation=*/true); } diff --git a/lib/Serialization/ASTReaderDecl.cpp b/lib/Serialization/ASTReaderDecl.cpp index 6e044fd0db..b7d6a91dfe 100644 --- a/lib/Serialization/ASTReaderDecl.cpp +++ b/lib/Serialization/ASTReaderDecl.cpp @@ -1105,6 +1105,7 @@ void ASTDeclReader::ReadCXXDefinitionData( = static_cast<CXXRecordDecl::LambdaDefinitionData &>(Data); Lambda.NumCaptures = Record[Idx++]; Lambda.NumExplicitCaptures = Record[Idx++]; + Lambda.ManglingNumber = Record[Idx++]; Lambda.Captures = (Capture*)Reader.Context.Allocate(sizeof(Capture)*Lambda.NumCaptures); Capture *ToCapture = Lambda.Captures; diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 48b14e3bd7..add89ea8e2 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -4332,6 +4332,7 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec CXXRecordDecl::LambdaDefinitionData &Lambda = D->getLambdaData(); Record.push_back(Lambda.NumCaptures); Record.push_back(Lambda.NumExplicitCaptures); + Record.push_back(Lambda.ManglingNumber); for (unsigned I = 0, N = Lambda.NumCaptures; I != N; ++I) { LambdaExpr::Capture &Capture = Lambda.Captures[I]; AddSourceLocation(Capture.getLocation(), Record); |