diff options
author | Tareq A. Siraj <tareq.a.sriaj@intel.com> | 2013-04-16 19:37:38 +0000 |
---|---|---|
committer | Tareq A. Siraj <tareq.a.sriaj@intel.com> | 2013-04-16 19:37:38 +0000 |
commit | 6afcf8875d4e447645cd7bf3733dd8e2eb8455dc (patch) | |
tree | 492ea5c7e442ea915d1f9feeafc8b24624942d96 | |
parent | 596eea7cc26979c952a0b177d024787a99b299df (diff) |
Sema for Captured Statements
Add CapturedDecl to be the DeclContext for CapturedStmt, and perform semantic
analysis. Currently captures all variables by reference.
TODO: templates
Author: Ben Langmuir <ben.langmuir@intel.com>
Differential Revision: http://llvm-reviews.chandlerc.com/D433
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@179618 91177308-0d34-0410-b5e6-96231b3b80d8
29 files changed, 515 insertions, 31 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 4260ab0bb2..f7286a0388 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -3165,6 +3165,32 @@ public: } }; +/// \brief This represents the body of a CapturedStmt, and serves as its +/// DeclContext. +class CapturedDecl : public Decl, public DeclContext { +private: + Stmt *Body; + + explicit CapturedDecl(DeclContext *DC) + : Decl(Captured, DC, SourceLocation()), DeclContext(Captured) { } + +public: + static CapturedDecl *Create(ASTContext &C, DeclContext *DC); + + Stmt *getBody() const { return Body; } + void setBody(Stmt *B) { Body = B; } + + // Implement isa/cast/dyncast/etc. + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classofKind(Kind K) { return K == Captured; } + static DeclContext *castToDeclContext(const CapturedDecl *D) { + return static_cast<DeclContext *>(const_cast<CapturedDecl *>(D)); + } + static CapturedDecl *castFromDeclContext(const DeclContext *DC) { + return static_cast<CapturedDecl *>(const_cast<DeclContext *>(DC)); + } +}; + /// \brief Describes a module import declaration, which makes the contents /// of the named module visible in the current translation unit. /// diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index a3e69c0af2..bceb703060 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -1046,6 +1046,7 @@ public: bool isFunctionOrMethod() const { switch (DeclKind) { case Decl::Block: + case Decl::Captured: case Decl::ObjCMethod: return true; default: diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 9b4e481bfd..df41b6fa5a 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1228,8 +1228,9 @@ bool RecursiveASTVisitor<Derived>::TraverseDeclContextHelper(DeclContext *DC) { for (DeclContext::decl_iterator Child = DC->decls_begin(), ChildEnd = DC->decls_end(); Child != ChildEnd; ++Child) { - // BlockDecls are traversed through BlockExprs. - if (!isa<BlockDecl>(*Child)) + // BlockDecls and CapturedDecls are traversed through BlockExprs and + // CapturedStmts respectively. + if (!isa<BlockDecl>(*Child) && !isa<CapturedDecl>(*Child)) TRY_TO(TraverseDecl(*Child)); } @@ -1258,6 +1259,14 @@ DEF_TRAVERSE_DECL(BlockDecl, { return true; }) +DEF_TRAVERSE_DECL(CapturedDecl, { + TRY_TO(TraverseStmt(D->getBody())); + // This return statement makes sure the traversal of nodes in + // decls_begin()/decls_end() (done in the DEF_TRAVERSE_DECL macro) + // is skipped - don't remove it. + return true; + }) + DEF_TRAVERSE_DECL(EmptyDecl, { }) DEF_TRAVERSE_DECL(FileScopeAsmDecl, { @@ -2218,7 +2227,9 @@ DEF_TRAVERSE_STMT(UnresolvedMemberExpr, { DEF_TRAVERSE_STMT(SEHTryStmt, {}) DEF_TRAVERSE_STMT(SEHExceptStmt, {}) DEF_TRAVERSE_STMT(SEHFinallyStmt,{}) -DEF_TRAVERSE_STMT(CapturedStmt, {}) +DEF_TRAVERSE_STMT(CapturedStmt, { + TRY_TO(TraverseDecl(S->getCapturedDecl())); +}) DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { }) DEF_TRAVERSE_STMT(OpaqueValueExpr, { }) diff --git a/include/clang/AST/Stmt.h b/include/clang/AST/Stmt.h index c2cfaa486c..019e678620 100644 --- a/include/clang/AST/Stmt.h +++ b/include/clang/AST/Stmt.h @@ -31,9 +31,9 @@ namespace llvm { namespace clang { class ASTContext; class Attr; + class CapturedDecl; class Decl; class Expr; - class FunctionDecl; class IdentifierInfo; class LabelDecl; class ParmVarDecl; @@ -1959,7 +1959,7 @@ private: unsigned NumCaptures; /// \brief The implicit outlined function. - FunctionDecl *TheFuncDecl; + CapturedDecl *TheCapturedDecl; /// \brief The record for captured variables, a RecordDecl or CXXRecordDecl. RecordDecl *TheRecordDecl; @@ -1967,7 +1967,7 @@ private: /// \brief Construct a captured statement. CapturedStmt(Stmt *S, ArrayRef<Capture> Captures, ArrayRef<Expr *> CaptureInits, - FunctionDecl *FD, RecordDecl *RD); + CapturedDecl *CD, RecordDecl *RD); /// \brief Construct an empty captured statement. CapturedStmt(EmptyShell Empty, unsigned NumCaptures); @@ -1982,7 +1982,7 @@ public: static CapturedStmt *Create(ASTContext &Context, Stmt *S, ArrayRef<Capture> Captures, ArrayRef<Expr *> CaptureInits, - FunctionDecl *FD, RecordDecl *RD); + CapturedDecl *CD, RecordDecl *RD); static CapturedStmt *CreateDeserialized(ASTContext &Context, unsigned NumCaptures); @@ -1994,7 +1994,7 @@ public: } /// \brief Retrieve the outlined function declaration. - const FunctionDecl *getCapturedFunctionDecl() const { return TheFuncDecl; } + CapturedDecl *getCapturedDecl() const { return TheCapturedDecl; } /// \brief Retrieve the record declaration for captured variables. const RecordDecl *getCapturedRecordDecl() const { return TheRecordDecl; } diff --git a/include/clang/Basic/DeclNodes.td b/include/clang/Basic/DeclNodes.td index ebcd81252f..ad2afa7a57 100644 --- a/include/clang/Basic/DeclNodes.td +++ b/include/clang/Basic/DeclNodes.td @@ -73,6 +73,7 @@ def Friend : Decl; def FriendTemplate : Decl; def StaticAssert : Decl; def Block : Decl, DeclContext; +def Captured : Decl, DeclContext; def ClassScopeFunctionSpecialization : Decl; def Import : Decl; def OMPThreadPrivate : Decl; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index cfb1798def..fd9ea51df5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4804,6 +4804,9 @@ let CategoryName = "Lambda Issue" in { "here">; } +def err_return_in_captured_stmt : Error< + "cannot return from %0">; + def err_operator_arrow_circular : Error< "circular pointer delegation detected">; def err_pseudo_dtor_base_not_scalar : Error< diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h index 2295bf437c..a48422a308 100644 --- a/include/clang/Sema/ScopeInfo.h +++ b/include/clang/Sema/ScopeInfo.h @@ -24,6 +24,7 @@ namespace clang { class Decl; class BlockDecl; +class CapturedDecl; class CXXMethodDecl; class ObjCPropertyDecl; class IdentifierInfo; @@ -73,7 +74,8 @@ protected: enum ScopeKind { SK_Function, SK_Block, - SK_Lambda + SK_Lambda, + SK_CapturedRegion }; public: @@ -319,7 +321,8 @@ public: class CapturingScopeInfo : public FunctionScopeInfo { public: enum ImplicitCaptureStyle { - ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block + ImpCap_None, ImpCap_LambdaByval, ImpCap_LambdaByref, ImpCap_Block, + ImpCap_CapturedRegion }; ImplicitCaptureStyle ImpCaptureStyle; @@ -461,7 +464,8 @@ public: } static bool classof(const FunctionScopeInfo *FSI) { - return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda; + return FSI->Kind == SK_Block || FSI->Kind == SK_Lambda + || FSI->Kind == SK_CapturedRegion; } }; @@ -492,6 +496,46 @@ public: } }; +/// \brief Retains information about a captured region. +class CapturedRegionScopeInfo: public CapturingScopeInfo { +public: + + enum CapturedRegionKind { + CR_Default + }; + + /// \brief The CapturedDecl for this statement. + CapturedDecl *TheCapturedDecl; + /// \brief The captured record type. + RecordDecl *TheRecordDecl; + /// \brief This is the enclosing scope of the captured region. + Scope *TheScope; + /// \brief The kind of captured region. + CapturedRegionKind CapRegionKind; + + CapturedRegionScopeInfo(DiagnosticsEngine &Diag, Scope *S, CapturedDecl *CD, + RecordDecl *RD, CapturedRegionKind K) + : CapturingScopeInfo(Diag, ImpCap_CapturedRegion), + TheCapturedDecl(CD), TheRecordDecl(RD), TheScope(S), CapRegionKind(K) + { + Kind = SK_CapturedRegion; + } + + virtual ~CapturedRegionScopeInfo(); + + /// \brief A descriptive name for the kind of captured region this is. + StringRef getRegionName() const { + switch (CapRegionKind) { + case CR_Default: + return "default captured statement"; + } + } + + static bool classof(const FunctionScopeInfo *FSI) { + return FSI->Kind == SK_CapturedRegion; + } +}; + class LambdaScopeInfo : public CapturingScopeInfo { public: /// \brief The class that describes the lambda. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 01e646ef4d..f95d6a4321 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -37,6 +37,7 @@ #include "clang/Sema/LocInfoType.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/Ownership.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/TypoCorrection.h" #include "clang/Sema/Weak.h" #include "llvm/ADT/ArrayRef.h" @@ -65,6 +66,7 @@ namespace clang { class ArrayType; class AttributeList; class BlockDecl; + class CapturedDecl; class CXXBasePath; class CXXBasePaths; class CXXBindTemporaryExpr; @@ -174,6 +176,7 @@ namespace clang { namespace sema { class AccessedEntity; class BlockScopeInfo; + class CapturedRegionScopeInfo; class CapturingScopeInfo; class CompoundScopeInfo; class DelayedDiagnostic; @@ -916,6 +919,9 @@ public: void PushFunctionScope(); void PushBlockScope(Scope *BlockScope, BlockDecl *Block); void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator); + void PushCapturedRegionScope(Scope *RegionScope, CapturedDecl *CD, + RecordDecl *RD, + sema::CapturedRegionScopeInfo::CapturedRegionKind K); void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0, const Decl *D = 0, const BlockExpr *blkExpr = 0); @@ -936,6 +942,9 @@ public: /// \brief Retrieve the current lambda expression, if any. sema::LambdaScopeInfo *getCurLambda(); + /// \brief Retrieve the current captured region, if any. + sema::CapturedRegionScopeInfo *getCurCapturedRegion(); + /// WeakTopLevelDeclDecls - access to \#pragma weak-generated Decls SmallVector<Decl*,2> &WeakTopLevelDecls() { return WeakTopLevelDecl; } @@ -2767,6 +2776,12 @@ public: StmtResult ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope); StmtResult ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope); + void ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope, + sema::CapturedRegionScopeInfo::CapturedRegionKind Kind); + StmtResult ActOnCapturedRegionEnd(Stmt *S); + void ActOnCapturedRegionError(bool IsInstantiation = false); + RecordDecl *CreateCapturedStmtRecordDecl(CapturedDecl *&CD, + SourceLocation Loc); const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E, bool AllowFunctionParameters); diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 04d6a85860..9f5e8b1224 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -963,6 +963,8 @@ namespace clang { DECL_FILE_SCOPE_ASM, /// \brief A BlockDecl record. DECL_BLOCK, + /// \brief A CapturedDecl record. + DECL_CAPTURED, /// \brief A record that stores the set of declarations that are /// lexically stored within a given DeclContext. /// diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 36044826e8..d572335fb3 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -3234,6 +3234,10 @@ MSPropertyDecl *MSPropertyDecl::CreateDeserialized(ASTContext &C, 0, 0); } +CapturedDecl *CapturedDecl::Create(ASTContext &C, DeclContext *DC) { + return new (C) CapturedDecl(DC); +} + EnumConstantDecl *EnumConstantDecl::Create(ASTContext &C, EnumDecl *CD, SourceLocation L, IdentifierInfo *Id, QualType T, diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index 3f23f3d855..402d83683a 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -553,6 +553,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case StaticAssert: case ObjCPropertyImpl: case Block: + case Captured: case TranslationUnit: case UsingDirective: @@ -839,6 +840,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::TranslationUnit: case Decl::LinkageSpec: case Decl::Block: + case Decl::Captured: // There is only one DeclContext for these entities. return this; diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp index e120c6a1f8..2a7b170222 100644 --- a/lib/AST/Stmt.cpp +++ b/lib/AST/Stmt.cpp @@ -1038,12 +1038,12 @@ CapturedStmt::Capture *CapturedStmt::getStoredCaptures() const { CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures, ArrayRef<Expr *> CaptureInits, - FunctionDecl *FD, + CapturedDecl *CD, RecordDecl *RD) : Stmt(CapturedStmtClass), NumCaptures(Captures.size()), - TheFuncDecl(FD), TheRecordDecl(RD) { + TheCapturedDecl(CD), TheRecordDecl(RD) { assert( S && "null captured statement"); - assert(FD && "null function declaration for captured statement"); + assert(CD && "null captured declaration for captured statement"); assert(RD && "null record declaration for captured statement"); // Copy initialization expressions. @@ -1061,14 +1061,14 @@ CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures, CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures) : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures), - TheFuncDecl(0), TheRecordDecl(0) { + TheCapturedDecl(0), TheRecordDecl(0) { getStoredStmts()[NumCaptures] = 0; } CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, ArrayRef<Capture> Captures, ArrayRef<Expr *> CaptureInits, - FunctionDecl *FD, + CapturedDecl *CD, RecordDecl *RD) { // The layout is // @@ -1089,7 +1089,7 @@ CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S, } void *Mem = Context.Allocate(Size); - return new (Mem) CapturedStmt(S, Captures, CaptureInits, FD, RD); + return new (Mem) CapturedStmt(S, Captures, CaptureInits, CD, RD); } CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context, @@ -1106,8 +1106,8 @@ CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context, } Stmt::child_range CapturedStmt::children() { - // Children are captured field initilizers and the statement being captured. - return child_range(getStoredStmts(), getStoredStmts() + NumCaptures + 1); + // Children are captured field initilizers. + return child_range(getStoredStmts(), getStoredStmts() + NumCaptures); } bool CapturedStmt::capturesVariable(const VarDecl *Var) const { diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 469c2846a6..1b2285c794 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -451,7 +451,7 @@ void StmtPrinter::VisitMSAsmStmt(MSAsmStmt *Node) { } void StmtPrinter::VisitCapturedStmt(CapturedStmt *Node) { - PrintStmt(Node->getCapturedStmt()); + PrintStmt(Node->getCapturedDecl()->getBody()); } void StmtPrinter::VisitObjCAtTryStmt(ObjCAtTryStmt *Node) { diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 15bb6a6e45..173ca6cb09 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -70,6 +70,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::Friend: case Decl::FriendTemplate: case Decl::Block: + case Decl::Captured: case Decl::ClassScopeFunctionSpecialization: llvm_unreachable("Declaration should not be in declstmts!"); case Decl::Function: // void X(); diff --git a/lib/Frontend/PrintPreprocessedOutput.cpp b/lib/Frontend/PrintPreprocessedOutput.cpp index 6734d7759b..7e1cae95d7 100644 --- a/lib/Frontend/PrintPreprocessedOutput.cpp +++ b/lib/Frontend/PrintPreprocessedOutput.cpp @@ -137,6 +137,7 @@ public: StringRef RelativePath, const Module *Imported); virtual void Ident(SourceLocation Loc, const std::string &str); + virtual void PragmaCaptured(SourceLocation Loc, StringRef Str); virtual void PragmaComment(SourceLocation Loc, const IdentifierInfo *Kind, const std::string &Str); virtual void PragmaMessage(SourceLocation Loc, StringRef Str); @@ -345,6 +346,15 @@ void PrintPPOutputPPCallbacks::Ident(SourceLocation Loc, const std::string &S) { EmittedTokensOnThisLine = true; } +void PrintPPOutputPPCallbacks::PragmaCaptured(SourceLocation Loc, + StringRef Str) { + startNewLineIfNeeded(); + MoveToLine(Loc); + OS << "#pragma captured"; + + setEmittedDirectiveOnThisLine(); +} + /// MacroDefined - This hook is called whenever a macro definition is seen. void PrintPPOutputPPCallbacks::MacroDefined(const Token &MacroNameTok, const MacroDirective *MD) { diff --git a/lib/Parse/ParsePragma.cpp b/lib/Parse/ParsePragma.cpp index 038636d108..96328e2fb6 100644 --- a/lib/Parse/ParsePragma.cpp +++ b/lib/Parse/ParsePragma.cpp @@ -15,6 +15,7 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Parse/ParseDiagnostic.h" #include "clang/Parse/Parser.h" +#include "clang/Sema/Scope.h" using namespace clang; /// \brief Handle the annotation token produced for #pragma unused(...) @@ -132,7 +133,21 @@ StmtResult Parser::HandlePragmaCaptured() return StmtError(); } - return StmtEmpty(); + SourceLocation Loc = Tok.getLocation(); + + ParseScope CapturedRegionScope(this, Scope::FnScope | Scope::DeclScope); + Actions.ActOnCapturedRegionStart(Loc, getCurScope(), + sema::CapturedRegionScopeInfo::CR_Default); + + StmtResult R = ParseCompoundStatement(); + CapturedRegionScope.Exit(); + + if (R.isInvalid()) { + Actions.ActOnCapturedRegionError(); + return StmtError(); + } + + return Actions.ActOnCapturedRegionEnd(R.get()); } namespace { diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index 4d29a34a73..2f48bec123 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -187,3 +187,4 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { FunctionScopeInfo::~FunctionScopeInfo() { } BlockScopeInfo::~BlockScopeInfo() { } LambdaScopeInfo::~LambdaScopeInfo() { } +CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { } diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 6425f34ff5..203b689aa1 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -802,7 +802,7 @@ DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { - if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) { + if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) { DC = DC->getParent(); } else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -1314,3 +1314,18 @@ IdentifierInfo *Sema::getSuperIdentifier() const { Ident_super = &Context.Idents.get("super"); return Ident_super; } + +void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, + CapturedRegionScopeInfo::CapturedRegionKind K) { + CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(getDiagnostics(), + S, CD, RD, K); + CSI->ReturnType = Context.VoidTy; + FunctionScopes.push_back(CSI); +} + +CapturedRegionScopeInfo *Sema::getCurCapturedRegion() { + if (FunctionScopes.empty()) + return 0; + + return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back()); +} diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index e96c5d40a3..cdfdc09e06 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -10851,6 +10851,34 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, // capture. } +/// \brief Capture the given variable in the captured region. +static ExprResult captureInCapturedRegion(Sema &S, CapturedRegionScopeInfo *RSI, + VarDecl *Var, QualType FieldType, + QualType DeclRefType, + SourceLocation Loc, + bool RefersToEnclosingLocal) { + // The current implemention assumes that all variables are captured + // by references. Since there is no capture by copy, no expression evaluation + // will be needed. + // + RecordDecl *RD = RSI->TheRecordDecl; + + FieldDecl *Field + = FieldDecl::Create(S.Context, RD, Loc, Loc, 0, FieldType, + S.Context.getTrivialTypeSourceInfo(FieldType, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + + Expr *Ref = new (S.Context) DeclRefExpr(Var, RefersToEnclosingLocal, + DeclRefType, VK_LValue, Loc); + Var->setReferenced(true); + Var->setUsed(true); + + return Ref; +} + /// \brief Capture the given variable in the given lambda expression. static ExprResult captureInLambda(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, QualType FieldType, @@ -10991,10 +11019,10 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = FunctionScopes.size() - 1; do { - // Only block literals and lambda expressions can capture; other - // scopes don't work. + // Only block literals, captured statements, and lambda expressions can + // capture; other scopes don't work. DeclContext *ParentDC; - if (isa<BlockDecl>(DC)) + if (isa<BlockDecl>(DC) || isa<CapturedDecl>(DC)) ParentDC = DC->getParent(); else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -11028,7 +11056,7 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, } bool IsBlock = isa<BlockScopeInfo>(CSI); - bool IsLambda = !IsBlock; + bool IsLambda = isa<LambdaScopeInfo>(CSI); // Lambdas are not allowed to capture unnamed variables // (e.g. anonymous unions). @@ -11188,8 +11216,31 @@ bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, SourceLocation(), CaptureType, CopyExpr); Nested = true; continue; - } - + } + + if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) { + // By default, capture variables by reference. + bool ByRef = true; + // Using an LValue reference type is consistent with Lambdas (see below). + CaptureType = Context.getLValueReferenceType(DeclRefType); + + Expr *CopyExpr = 0; + if (BuildAndDiagnose) { + ExprResult Result = captureInCapturedRegion(*this, RSI, Var, + CaptureType, DeclRefType, + Loc, Nested); + if (!Result.isInvalid()) + CopyExpr = Result.take(); + } + + // Actually capture the variable. + if (BuildAndDiagnose) + CSI->addCapture(Var, /*isBlock*/false, ByRef, Nested, Loc, + SourceLocation(), CaptureType, CopyExpr); + Nested = true; + continue; + } + LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CSI); // Determine whether we are capturing by reference or by value. diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index cfc00502c4..89c1bc51c3 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -746,6 +746,7 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || + CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || Explicit) { // This closure can capture 'this'; continue looking upwards. NumClosures++; @@ -778,7 +779,19 @@ void Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit) { Field->setAccess(AS_private); Lambda->addDecl(Field); ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true); + } else if (CapturedRegionScopeInfo *RSI = + dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) { + RecordDecl *RD = RSI->TheRecordDecl; + FieldDecl *Field + = FieldDecl::Create(Context, RD, Loc, Loc, 0, ThisTy, + Context.getTrivialTypeSourceInfo(ThisTy, Loc), + 0, false, ICIS_NoInit); + Field->setImplicit(true); + Field->setAccess(AS_private); + RD->addDecl(Field); + ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); } + bool isNested = NumClosures > 1; CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); } diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 53fa6dafdd..77e6bfd086 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -862,6 +862,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, CaptureDefault = LCD_ByCopy; break; + case CapturingScopeInfo::ImpCap_CapturedRegion: case CapturingScopeInfo::ImpCap_LambdaByref: CaptureDefault = LCD_ByRef; break; diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index b3558a548b..88237b08b2 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2403,6 +2403,10 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { Diag(ReturnLoc, diag::err_noreturn_block_has_return_expr); return StmtError(); } + } else if (CapturedRegionScopeInfo *CurRegion = + dyn_cast<CapturedRegionScopeInfo>(CurCap)) { + Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName(); + return StmtError(); } else { LambdaScopeInfo *LSI = cast<LambdaScopeInfo>(CurCap); if (LSI->CallOperator->getType()->getAs<FunctionType>()->getNoReturnAttr()){ @@ -2914,3 +2918,110 @@ StmtResult |