diff options
-rw-r--r-- | include/clang/AST/TypeLoc.h | 4 | ||||
-rw-r--r-- | include/clang/Sema/ScopeInfo.h | 60 | ||||
-rw-r--r-- | include/clang/Sema/Sema.h | 20 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 7 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 72 | ||||
-rw-r--r-- | test/Parser/objcxx0x-lambda-expressions.mm | 5 |
10 files changed, 141 insertions, 44 deletions
diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 40a9006b78..d2fb12b26e 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1078,6 +1078,10 @@ public: getLocalData()->TrailingReturn = Trailing; } + ArrayRef<ParmVarDecl *> getParams() const { + return ArrayRef<ParmVarDecl *>(getParmArray(), getNumArgs()); + } + // ParmVarDecls* are stored after Info, one for each argument. ParmVarDecl **getParmArray() const { return (ParmVarDecl**) getExtraLocalData(); diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 9ef6d3c4b3..caa4c1a6c8 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -45,11 +45,17 @@ public: /// \brief Retains information about a function, method, or block that is /// currently being parsed. class FunctionScopeInfo { +protected: + enum ScopeKind { + SK_Function, + SK_Block, + SK_Lambda + }; + public: - - /// \brief Whether this scope information structure defined information for - /// a block. - bool IsBlockInfo; + /// \brief What kind of scope we are describing. + /// + ScopeKind Kind; /// \brief Whether this function contains a VLA, @try, try, C++ /// initializer, or anything else that can't be jumped past. @@ -96,7 +102,7 @@ public: } FunctionScopeInfo(DiagnosticsEngine &Diag) - : IsBlockInfo(false), + : Kind(SK_Function), HasBranchProtectedScope(false), HasBranchIntoScope(false), HasIndirectGoto(false), @@ -141,15 +147,55 @@ public: : FunctionScopeInfo(Diag), TheDecl(Block), TheScope(BlockScope), CapturesCXXThis(false) { - IsBlockInfo = true; + Kind = SK_Block; } virtual ~BlockScopeInfo(); - static bool classof(const FunctionScopeInfo *FSI) { return FSI->IsBlockInfo; } + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Block; + } static bool classof(const BlockScopeInfo *BSI) { return true; } }; +class LambdaScopeInfo : public FunctionScopeInfo { +public: + /// \brief The class that describes the lambda. + CXXRecordDecl *Lambda; + + /// \brief A mapping from the set of captured variables to the + /// fields (within the lambda class) that represent the captured variables. + llvm::DenseMap<VarDecl *, FieldDecl *> CapturedVariables; + + /// \brief The list of captured variables, starting with the explicit + /// captures and then finishing with any implicit captures. + // TODO: This is commented out until an implementation of LambdaExpr is + // committed. + // llvm::SmallVector<LambdaExpr::Capture, 4> Captures; + + /// \brief The number of captures in the \c Captures list that are + /// explicit captures. + unsigned NumExplicitCaptures; + + /// \brief The field associated with the captured 'this' pointer. + FieldDecl *ThisCapture; + + LambdaScopeInfo(DiagnosticsEngine &Diag, CXXRecordDecl *Lambda) + : FunctionScopeInfo(Diag), Lambda(Lambda), + NumExplicitCaptures(0), ThisCapture(0) + { + Kind = SK_Lambda; + } + + virtual ~LambdaScopeInfo(); + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_Lambda; + } + static bool classof(const LambdaScopeInfo *BSI) { return true; } + +}; + } } diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 940ae2da98..7bf2de492c 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -767,8 +767,9 @@ public: void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); - void PopFunctionOrBlockScope(const sema::AnalysisBasedWarnings::Policy *WP =0, - const Decl *D = 0, const BlockExpr *blkExpr = 0); + void PushLambdaScope(CXXRecordDecl *Lambda); + void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, + const Decl *D = 0, const BlockExpr *blkExpr = 0); sema::FunctionScopeInfo *getCurFunction() const { return FunctionScopes.back(); @@ -3449,16 +3450,15 @@ public: /// initializer for the declaration 'Dcl'. void ActOnCXXExitDeclInitializer(Scope *S, Decl *Dcl); - /// ActOnLambdaStart - This callback is invoked when a lambda expression is - /// started. - void ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope); - - /// ActOnLambdaArguments - This callback allows processing of lambda arguments. - /// If there are no arguments, this is still invoked. - void ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope); + /// ActOnStartOfLambdaDefinition - This is called just before we start + /// parsing the body of a lambda; it analyzes the explicit captures and + /// arguments, and sets up various data-structures for the body of the + /// lambda. + void ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, Scope *CurScope); /// ActOnLambdaError - If there is an error parsing a lambda, this callback - /// is invoked to pop the information about the lambda from the action impl. + /// is invoked to pop the information about the lambda. void ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope); /// ActOnLambdaExpr - This is called when the body of a lambda expression diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 96f8709ba5..e54858f747 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -711,8 +711,6 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( PrettyStackTraceLoc CrashInfo(PP.getSourceManager(), LambdaBeginLoc, "lambda expression parsing"); - Actions.ActOnLambdaStart(LambdaBeginLoc, getCurScope()); - // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); Declarator D(DS, Declarator::LambdaExprContext); @@ -792,11 +790,10 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( DeclLoc, DeclEndLoc, D, TrailingReturnType), Attr, DeclEndLoc); - - // Inform sema that we are starting a block. - Actions.ActOnLambdaArguments(D, getCurScope()); } + Actions.ActOnStartOfLambdaDefinition(Intro, D, getCurScope()); + // Parse compound-statement. if (!Tok.is(tok::l_brace)) { Diag(Tok, diag::err_expected_lambda_body); diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index c8199042b7..6a77d8c673 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -55,6 +55,7 @@ void FunctionScopeInfo::Clear() { } BlockScopeInfo::~BlockScopeInfo() { } +LambdaScopeInfo::~LambdaScopeInfo() { } PrintingPolicy Sema::getPrintingPolicy() const { PrintingPolicy Policy = Context.getPrintingPolicy(); @@ -828,8 +829,12 @@ void Sema::PushBlockScope(Scope *BlockScope, BlockDecl *Block) { BlockScope, Block)); } -void Sema::PopFunctionOrBlockScope(const AnalysisBasedWarnings::Policy *WP, - const Decl *D, const BlockExpr *blkExpr) { +void Sema::PushLambdaScope(CXXRecordDecl *Lambda) { + FunctionScopes.push_back(new LambdaScopeInfo(getDiagnostics(), Lambda)); +} + +void Sema::PopFunctionScopeInfo(const AnalysisBasedWarnings::Policy *WP, + const Decl *D, const BlockExpr *blkExpr) { FunctionScopeInfo *Scope = FunctionScopes.pop_back_val(); assert(!FunctionScopes.empty() && "mismatched push/pop!"); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index f82026f89f..8353c087d5 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -7207,7 +7207,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (!IsInstantiation) PopDeclContext(); - PopFunctionOrBlockScope(ActivePolicy, dcl); + PopFunctionScopeInfo(ActivePolicy, dcl); // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index ad327ac755..46a47a2215 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -6784,7 +6784,7 @@ namespace { ~ImplicitlyDefinedFunctionScope() { S.PopExpressionEvaluationContext(); - S.PopFunctionOrBlockScope(); + S.PopFunctionScopeInfo(); } }; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 126468ee35..8554e78636 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -8839,7 +8839,7 @@ void Sema::ActOnBlockError(SourceLocation CaretLoc, Scope *CurScope) { // Pop off CurBlock, handle nested blocks. PopDeclContext(); - PopFunctionOrBlockScope(); + PopFunctionScopeInfo(); } /// ActOnBlockStmtExpr - This is called when the body of a block statement @@ -8931,7 +8931,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BlockExpr *Result = new (Context) BlockExpr(BSI->TheDecl, BlockTy); const AnalysisBasedWarnings::Policy &WP = AnalysisWarnings.getDefaultPolicy(); - PopFunctionOrBlockScope(&WP, Result->getBlockDecl(), Result); + PopFunctionScopeInfo(&WP, Result->getBlockDecl(), Result); // If the block isn't obviously global, i.e. it captures anything at // all, mark this full-expression as needing a cleanup. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index e53e5cda62..fd47dc75b2 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4778,20 +4778,68 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, // Lambdas. //===----------------------------------------------------------------------===// -void Sema::ActOnLambdaStart(SourceLocation StartLoc, Scope *CurScope) { - // FIXME: Add lambda-scope - // FIXME: PushDeclContext +void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, + Declarator &ParamInfo, + Scope *CurScope) { + DeclContext *DC = CurContext; + while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isNamespace())) + DC = DC->getParent(); + + // Start constructing the lambda class. + CXXRecordDecl *Class = CXXRecordDecl::Create(Context, TTK_Class, DC, + Intro.Range.getBegin(), + /*IdLoc=*/SourceLocation(), + /*Id=*/0); + Class->startDefinition(); + CurContext->addDecl(Class); + + // Build the call operator; we don't really have all the relevant information + // at this point, but we need something to attach child declarations to. + TypeSourceInfo *MethodTyInfo; + MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); + + DeclarationName MethodName + = Context.DeclarationNames.getCXXOperatorName(OO_Call); + CXXMethodDecl *Method + = CXXMethodDecl::Create(Context, + Class, + ParamInfo.getSourceRange().getEnd(), + DeclarationNameInfo(MethodName, + /*NameLoc=*/SourceLocation()), + MethodTyInfo->getType(), + MethodTyInfo, + /*isStatic=*/false, + SC_None, + /*isInline=*/true, + /*isConstExpr=*/false, + ParamInfo.getSourceRange().getEnd()); + Method->setAccess(AS_public); + Class->addDecl(Method); + Method->setLexicalDeclContext(DC); // FIXME: Is this really correct? + + // Set the parameters on the decl, if specified. + if (isa<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc())) { + FunctionProtoTypeLoc Proto = + cast<FunctionProtoTypeLoc>(MethodTyInfo->getTypeLoc()); + Method->setParams(Proto.getParams()); + CheckParmsForFunctionDef(Method->param_begin(), + Method->param_end(), + /*CheckParameterNames=*/false); + } + + ProcessDeclAttributes(CurScope, Method, ParamInfo); + + // FIXME: There's a bunch of missing checking etc; + // see ActOnBlockArguments + + // Introduce the lambda scope. + PushLambdaScope(Class); // Enter a new evaluation context to insulate the block from any // cleanups from the enclosing full-expression. - PushExpressionEvaluationContext(PotentiallyEvaluated); -} - -void Sema::ActOnLambdaArguments(Declarator &ParamInfo, Scope *CurScope) { - TypeSourceInfo *MethodTyInfo; - MethodTyInfo = GetTypeForDeclarator(ParamInfo, CurScope); + PushExpressionEvaluationContext(PotentiallyEvaluated); - // FIXME: Build CXXMethodDecl + PushDeclContext(CurScope, Method); } void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) { @@ -4800,8 +4848,8 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope) { PopExpressionEvaluationContext(); // Leave the context of the lambda. - // FIXME: PopDeclContext - // FIXME: Pop lambda-scope + PopDeclContext(); + PopFunctionScopeInfo(); } ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, diff --git a/test/Parser/objcxx0x-lambda-expressions.mm b/test/Parser/objcxx0x-lambda-expressions.mm index b9a96d6b2d..5cfb4f8c5a 100644 --- a/test/Parser/objcxx0x-lambda-expressions.mm +++ b/test/Parser/objcxx0x-lambda-expressions.mm @@ -14,10 +14,7 @@ class C { [] {}; // expected-error {{lambda expressions are not supported yet}} [=] (int i) {}; // expected-error {{lambda expressions are not supported yet}} [&] (int) mutable -> void {}; // expected-error {{lambda expressions are not supported yet}} - // FIXME: this error occurs because we do not yet handle lambda scopes - // properly. I did not anticipate it because I thought it was a semantic (not - // syntactic) check. - [foo,bar] () { return 3; }; // expected-error {{void function 'f' should not return a value}} expected-error {{lambda expressions are not supported yet}} + [foo,bar] () { return 3; }; // expected-error {{lambda expressions are not supported yet}} [=,&foo] () {}; // expected-error {{lambda expressions are not supported yet}} [this] () {}; // expected-error {{lambda expressions are not supported yet}} } |