diff options
author | Douglas Gregor <dgregor@apple.com> | 2012-02-13 15:44:47 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2012-02-13 15:44:47 +0000 |
commit | da8962a6198bc4bf09a38209db99551b2b0a41a0 (patch) | |
tree | f9fb9bbc7de4c93b4deb623c4dd567dccadeaa24 | |
parent | e88a71f00e9dce979dfb409459d54c92e5075a42 (diff) |
Move the storage of lambda captures and capture initializers from
LambdaExpr over to the CXXRecordDecl. This allows us to eliminate the
back-link from the closure type to the LambdaExpr, which will simplify
and lazify AST deserialization.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150393 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 2 | ||||
-rw-r--r-- | include/clang/AST/DeclCXX.h | 51 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 52 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 53 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 75 | ||||
-rw-r--r-- | lib/Sema/SemaLambda.cpp | 9 |
7 files changed, 157 insertions, 90 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 7f1f7356e5..ded3c4b0aa 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -59,7 +59,6 @@ namespace clang { class CXXRecordDecl; class Decl; class FieldDecl; - class LambdaExpr; class MangleContext; class ObjCIvarDecl; class ObjCIvarRefExpr; @@ -164,10 +163,6 @@ class ASTContext : public llvm::RefCountedBase<ASTContext> { llvm::DenseMap<const FunctionDecl*, FunctionDecl*> ClassScopeSpecializationPattern; - /// \brief Mapping from closure types to the lambda expressions that - /// create instances of them. - llvm::DenseMap<const CXXRecordDecl *, LambdaExpr *> Lambdas; - /// \brief Representation of a "canonical" template template parameter that /// is used in canonical template names. class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode { diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f04ad9f356..760e598f75 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -2387,9 +2387,11 @@ private: /// a definition until the definition has been fully processed. bool IsCompleteDefinition : 1; +protected: /// IsBeingDefined - True if this is currently being defined. bool IsBeingDefined : 1; +private: /// IsEmbeddedInDeclarator - True if this tag declaration is /// "embedded" (i.e., defined or declared for the very first time) /// in the syntax of a declarator. diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 46136c3bab..2b56871810 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_AST_DECLCXX_H #include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" #include "clang/AST/Decl.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/UnresolvedSet.h" @@ -555,6 +556,40 @@ class CXXRecordDecl : public RecordDecl { } } *DefinitionData; + /// \brief Describes a C++ closure type (generated by a lambda expression). + struct LambdaDefinitionData : public DefinitionData { + typedef LambdaExpr::Capture Capture; + + LambdaDefinitionData(CXXRecordDecl *D) + : DefinitionData(D), NumCaptures(0), NumExplicitCaptures(0), Extra(0) { + IsLambda = true; + } + + /// \brief The number of captures in this lambda. + unsigned NumCaptures : 16; + + /// \brief The number of explicit captures in this lambda. + unsigned NumExplicitCaptures : 16; + + /// \brief The "extra" data associated with the lambda, including + /// captures, capture initializers, and the body of the lambda. + void *Extra; + + /// \brief Allocate the "extra" data associated with a lambda definition. + void allocateExtra(ArrayRef<Capture> Captures, + ArrayRef<Expr *> CaptureInits, + Stmt *Body); + + /// \brief Retrieve the set of captures. + Capture *getCaptures() const { return reinterpret_cast<Capture *>(Extra); } + + /// \brief Retrieve the set of stored statements, which contains the capture + /// initializers followed by the body of the lambda. + Stmt **getStoredStmts() const { + return reinterpret_cast<Stmt **>(getCaptures() + NumCaptures); + } + }; + struct DefinitionData &data() { assert(DefinitionData && "queried property of class with no definition"); return *DefinitionData; @@ -565,6 +600,13 @@ class CXXRecordDecl : public RecordDecl { return *DefinitionData; } + struct LambdaDefinitionData &getLambdaData() const { + assert(DefinitionData && "queried property of lambda with no definition"); + assert(DefinitionData->IsLambda && + "queried lambda property of non-lambda class"); + return static_cast<LambdaDefinitionData &>(*DefinitionData); + } + /// \brief The template or declaration that this declaration /// describes or was instantiated from, respectively. /// @@ -578,6 +620,7 @@ class CXXRecordDecl : public RecordDecl { TemplateOrInstantiation; friend class DeclContext; + friend class LambdaExpr; /// \brief Notify the class that member has been added. /// @@ -647,6 +690,8 @@ public: SourceLocation StartLoc, SourceLocation IdLoc, IdentifierInfo *Id, CXXRecordDecl* PrevDecl=0, bool DelayTypeCreation = false); + static CXXRecordDecl *CreateLambda(const ASTContext &C, DeclContext *DC, + SourceLocation Loc); static CXXRecordDecl *CreateDeserialized(const ASTContext &C, unsigned ID); bool isDynamicClass() const { @@ -928,12 +973,6 @@ public: /// \brief Determine whether this class describes a lambda function object. bool isLambda() const { return hasDefinition() && data().IsLambda; } - /// \brief Mark this as a closure type from a lambda expression. - void makeLambda() { data().IsLambda = true; } - - /// \brief Set the lambda expression associated with this closure type. - void setLambda(LambdaExpr *Lambda); - /// \brief For a closure type, retrieve the mapping from captured /// variables and this to the non-static data members that store the /// values or references of the captures. diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 14918fa1d3..5037347773 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -1048,12 +1048,6 @@ class LambdaExpr : public Expr { /// \brief The source range that covers the lambda introducer ([...]). SourceRange IntroducerRange; - /// \brief The number of captures in this lambda. - unsigned NumCaptures : 16; - - /// \brief The number of explicit captures in this lambda. - unsigned NumExplicitCaptures : 13; - /// \brief The default capture kind, which is a value of type /// LambdaCaptureDefault. unsigned CaptureDefault : 2; @@ -1163,12 +1157,6 @@ private: ArrayRef<Expr *> CaptureInits, SourceLocation ClosingBrace); - Stmt **getStoredStmts() const { - LambdaExpr *This = const_cast<LambdaExpr *>(this); - return reinterpret_cast<Stmt **>(reinterpret_cast<Capture *>(This + 1) - + NumCaptures); - } - public: /// \brief Construct a new lambda expression. static LambdaExpr *Create(ASTContext &C, @@ -1190,39 +1178,27 @@ public: typedef const Capture *capture_iterator; /// \brief Retrieve an iterator pointing to the first lambda capture. - capture_iterator capture_begin() const { - return reinterpret_cast<const Capture *>(this + 1); - } + capture_iterator capture_begin() const; /// \brief Retrieve an iterator pointing past the end of the /// sequence of lambda captures. - capture_iterator capture_end() const { - return capture_begin() + NumCaptures; - } + capture_iterator capture_end() const; /// \brief Retrieve an iterator pointing to the first explicit /// lambda capture. - capture_iterator explicit_capture_begin() const { - return capture_begin(); - } + capture_iterator explicit_capture_begin() const; /// \brief Retrieve an iterator pointing past the end of the sequence of /// explicit lambda captures. - capture_iterator explicit_capture_end() const { - return capture_begin() + NumExplicitCaptures; - } + capture_iterator explicit_capture_end() const; /// \brief Retrieve an iterator pointing to the first implicit /// lambda capture. - capture_iterator implicit_capture_begin() const { - return explicit_capture_end(); - } + capture_iterator implicit_capture_begin() const; /// \brief Retrieve an iterator pointing past the end of the sequence of /// implicit lambda captures. - capture_iterator implicit_capture_end() const { - return capture_end(); - } + capture_iterator implicit_capture_end() const; /// \brief Iterator that walks over the capture initialization /// arguments. @@ -1230,15 +1206,11 @@ public: /// \brief Retrieve the first initialization argument for this /// lambda expression (which initializes the first capture field). - capture_init_iterator capture_init_begin() const { - return reinterpret_cast<Expr **>(getStoredStmts()); - } + capture_init_iterator capture_init_begin() const; /// \brief Retrieve the iterator pointing one past the last /// initialization argument for this lambda expression. - capture_init_iterator capture_init_end() const { - return capture_init_begin() + NumCaptures; - } + capture_init_iterator capture_init_end() const; /// \brief Retrieve the source range covering the lambda introducer, /// which contains the explicit capture list surrounded by square @@ -1255,9 +1227,7 @@ public: CXXMethodDecl *getCallOperator() const; /// \brief Retrieve the body of the lambda. - CompoundStmt *getBody() const { - return reinterpret_cast<CompoundStmt *>(getStoredStmts()[NumCaptures]); - } + CompoundStmt *getBody() const; /// \brief Determine whether the lambda is mutable, meaning that any /// captures values can be modified. @@ -1276,9 +1246,7 @@ public: return SourceRange(IntroducerRange.getBegin(), ClosingBrace); } - child_range children() { - return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1); - } + child_range children(); friend class ASTStmtReader; friend class ASTStmtWriter; diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index f9d95b121a..257a507b23 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -35,6 +35,35 @@ AccessSpecDecl *AccessSpecDecl::CreateDeserialized(ASTContext &C, unsigned ID) { return new (Mem) AccessSpecDecl(EmptyShell()); } +void CXXRecordDecl::LambdaDefinitionData::allocateExtra( + ArrayRef<LambdaExpr::Capture> Captures, + ArrayRef<Expr *> CaptureInits, + Stmt *Body) { + NumCaptures = Captures.size(); + NumExplicitCaptures = 0; + + ASTContext &Context = Definition->getASTContext(); + this->Extra = Context.Allocate(sizeof(Capture) * Captures.size() + + sizeof(Stmt*) * (Captures.size() + 1)); + + // Copy captures. + Capture *ToCapture = getCaptures(); + for (unsigned I = 0, N = Captures.size(); I != N; ++I) { + if (Captures[I].isExplicit()) + ++NumExplicitCaptures; + + *ToCapture++ = Captures[I]; + } + + // Copy initialization expressions for the non-static data members. + Stmt **Stored = getStoredStmts(); + for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I) + *Stored++ = CaptureInits[I]; + + // Copy the body of the lambda. + *Stored++ = Body; +} + CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D) : UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), @@ -83,6 +112,16 @@ CXXRecordDecl *CXXRecordDecl::Create(const ASTContext &C, TagKind TK, return R; } +CXXRecordDecl *CXXRecordDecl::CreateLambda(const ASTContext &C, DeclContext *DC, + SourceLocation Loc) { + CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TTK_Class, DC, Loc, Loc, + 0, 0); + R->IsBeingDefined = true; + R->DefinitionData = new (C) struct LambdaDefinitionData(R); + C.getTypeDeclType(R, /*PrevDecl=*/0); + return R; +} + CXXRecordDecl * CXXRecordDecl::CreateDeserialized(const ASTContext &C, unsigned ID) { void *Mem = AllocateDeserializedDecl(C, ID, sizeof(CXXRecordDecl)); @@ -969,24 +1008,16 @@ bool CXXRecordDecl::isCLike() const { return isPOD() && data().HasOnlyCMembers; } -void CXXRecordDecl::setLambda(LambdaExpr *Lambda) { - if (!Lambda) - return; - - data().IsLambda = true; - getASTContext().Lambdas[this] = Lambda; -} - void CXXRecordDecl::getCaptureFields( llvm::DenseMap<const VarDecl *, FieldDecl *> &Captures, FieldDecl *&ThisCapture) const { Captures.clear(); ThisCapture = 0; - LambdaExpr *Lambda = getASTContext().Lambdas[this]; + LambdaDefinitionData &Lambda = getLambdaData(); RecordDecl::field_iterator Field = field_begin(); - for (LambdaExpr::capture_iterator C = Lambda->capture_begin(), - CEnd = Lambda->capture_end(); + for (LambdaExpr::Capture *C = Lambda.getCaptures(), + *CEnd = C + Lambda.NumCaptures; C != CEnd; ++C, ++Field) { if (C->capturesThis()) { ThisCapture = *Field; diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index a38488b877..29ff69d312 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -758,30 +758,16 @@ LambdaExpr::LambdaExpr(QualType T, T->isDependentType(), T->isDependentType(), T->isDependentType(), /*ContainsUnexpandedParameterPack=*/false), IntroducerRange(IntroducerRange), - NumCaptures(Captures.size()), - NumExplicitCaptures(0), CaptureDefault(CaptureDefault), ExplicitParams(ExplicitParams), ClosingBrace(ClosingBrace) { assert(CaptureInits.size() == Captures.size() && "Wrong number of arguments"); - - // Copy captures. - // FIXME: Do we need to update "contains unexpanded parameter pack" here? - Capture *ToCapture = reinterpret_cast<Capture *>(this + 1); - for (unsigned I = 0, N = Captures.size(); I != N; ++I) { - if (Captures[I].isExplicit()) - ++NumExplicitCaptures; - *ToCapture++ = Captures[I]; - } - - // Copy initialization expressions for the non-static data members. - Stmt **Stored = getStoredStmts(); - for (unsigned I = 0, N = CaptureInits.size(); I != N; ++I) - *Stored++ = CaptureInits[I]; - - // Copy the body of the lambda. - *Stored++ = getCallOperator()->getBody(); + CXXRecordDecl *Class = getLambdaClass(); + CXXRecordDecl::LambdaDefinitionData &Data = Class->getLambdaData(); + Data.allocateExtra(Captures, CaptureInits, getCallOperator()->getBody()); + + // FIXME: Propagate "has unexpanded parameter pack" bit. } LambdaExpr *LambdaExpr::Create(ASTContext &Context, @@ -804,6 +790,45 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context, ClosingBrace); } +LambdaExpr::capture_iterator LambdaExpr::capture_begin() const { + return getLambdaClass()->getLambdaData().getCaptures(); +} + +LambdaExpr::capture_iterator LambdaExpr::capture_end() const { + struct CXXRecordDecl::LambdaDefinitionData &Data + = getLambdaClass()->getLambdaData(); + return Data.getCaptures() + Data.NumCaptures; +} + +LambdaExpr::capture_iterator LambdaExpr::explicit_capture_begin() const { + return capture_begin(); +} + +LambdaExpr::capture_iterator LambdaExpr::explicit_capture_end() const { + struct CXXRecordDecl::LambdaDefinitionData &Data + = getLambdaClass()->getLambdaData(); + return Data.getCaptures() + Data.NumExplicitCaptures; +} + +LambdaExpr::capture_iterator LambdaExpr::implicit_capture_begin() const { + return explicit_capture_end(); +} + +LambdaExpr::capture_iterator LambdaExpr::implicit_capture_end() const { + return capture_end(); +} + +LambdaExpr::capture_init_iterator LambdaExpr::capture_init_begin() const { + return reinterpret_cast<Expr **>( + getLambdaClass()->getLambdaData().getStoredStmts()); +} + +LambdaExpr::capture_init_iterator LambdaExpr::capture_init_end() const { + struct CXXRecordDecl::LambdaDefinitionData &Data + = getLambdaClass()->getLambdaData(); + return reinterpret_cast<Expr **>(Data.getStoredStmts() + Data.NumCaptures); +} + CXXRecordDecl *LambdaExpr::getLambdaClass() const { return getType()->getAsCXXRecordDecl(); } @@ -819,10 +844,22 @@ CXXMethodDecl *LambdaExpr::getCallOperator() const { return Result; } +/// \brief Retrieve the body of the lambda. +CompoundStmt *LambdaExpr::getBody() const { + return cast<CompoundStmt>(*capture_init_end()); +} + bool LambdaExpr::isMutable() const { return (getCallOperator()->getTypeQualifiers() & Qualifiers::Const) == 0; } +Stmt::child_range LambdaExpr::children() { + struct CXXRecordDecl::LambdaDefinitionData &Data + = getLambdaClass()->getLambdaData(); + return child_range(Data.getStoredStmts(), + Data.getStoredStmts() + Data.NumCaptures + 1); +} + ExprWithCleanups::ExprWithCleanups(Expr *subexpr, ArrayRef<CleanupObject> objects) : Expr(ExprWithCleanupsClass, subexpr->getType(), diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 2bd69edb07..44b388364a 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -28,12 +28,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, DC = DC->getParent(); // Start constructing the lambda class. - CXXRecordDecl *Class = CXXRecordDecl::Create(Context, TTK_Class, DC, - Intro.Range.getBegin(), - /*IdLoc=*/Intro.Range.getBegin(), - /*Id=*/0); - Class->startDefinition(); - Class->makeLambda(); + CXXRecordDecl *Class = CXXRecordDecl::CreateLambda(Context, DC, + Intro.Range.getBegin()); CurContext->addDecl(Class); // Build the call operator; we don't really have all the relevant information @@ -472,7 +468,6 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, CaptureDefault, Captures, ExplicitParams, CaptureInits, Body->getLocEnd()); - Class->setLambda(Lambda); // C++11 [expr.prim.lambda]p2: // A lambda-expression shall not appear in an unevaluated operand |