]> granicus.if.org Git - clang/commitdiff
Sema for Captured Statements
authorTareq A. Siraj <tareq.a.sriaj@intel.com>
Tue, 16 Apr 2013 19:37:38 +0000 (19:37 +0000)
committerTareq A. Siraj <tareq.a.sriaj@intel.com>
Tue, 16 Apr 2013 19:37:38 +0000 (19:37 +0000)
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:
include/clang/AST/Decl.h
include/clang/AST/DeclBase.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/Stmt.h
include/clang/Basic/DeclNodes.td
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Sema/ScopeInfo.h
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/Decl.cpp
lib/AST/DeclBase.cpp
lib/AST/Stmt.cpp
lib/AST/StmtPrinter.cpp
lib/CodeGen/CGDecl.cpp
lib/Frontend/PrintPreprocessedOutput.cpp
lib/Parse/ParsePragma.cpp
lib/Sema/ScopeInfo.cpp
lib/Sema/Sema.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
lib/Sema/SemaLambda.cpp
lib/Sema/SemaStmt.cpp
lib/Serialization/ASTCommon.cpp
lib/Serialization/ASTReaderDecl.cpp
lib/Serialization/ASTWriterDecl.cpp
test/Sema/captured-statements.c [new file with mode: 0644]
test/SemaCXX/captured-statements.cpp [new file with mode: 0644]
tools/libclang/CIndex.cpp
tools/libclang/RecursiveASTVisitor.h

index 4260ab0bb204079777214f3ed916afd7fd805abb..f7286a0388e379f08f90eb31ce5617af296a00d5 100644 (file)
@@ -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.
 ///
index a3e69c0af294c0868b6be8d6fb435be4cbdc2596..bceb7030600172a62499b94997beb00225991d06 100644 (file)
@@ -1046,6 +1046,7 @@ public:
   bool isFunctionOrMethod() const {
     switch (DeclKind) {
     case Decl::Block:
+    case Decl::Captured:
     case Decl::ObjCMethod:
       return true;
     default:
index 9b4e481bfda5516d116456f5e93e2726698faf57..df41b6fa5ae4010f19b012feab0460fdccdf6110 100644 (file)
@@ -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, { })
index c2cfaa486c251d6808a7bef41bdc8371e99dac41..019e67862057d0477f18fb668ea5e85d7fbbb838 100644 (file)
@@ -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; }
index ebcd81252fbb8428e5b5c18c97aebea8857e2428..ad2afa7a57cd2c9253b64ee86eaffaf1a3c41f7a 100644 (file)
@@ -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;
index cfb1798def41229ec95def88d3ca1bfe51ea1190..fd9ea51df5be46a46d963a552a14a2c4ec92002b 100644 (file)
@@ -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<
index 2295bf437cb3bc6aee7e2c1f296216e35cf7d750..a48422a30895b50e11dd3bd888723ea20895ab3d 100644 (file)
@@ -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.
index 01e646ef4dbe3fe43130ff1d33b751dad53ec856..f95d6a4321d256f0f05162ba7749dc9eae7ecca1 100644 (file)
@@ -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);
 
index 04d6a85860c71d3b61c4eea132cc85273e8f60e9..9f5e8b12240f2bf244391c8aae174509eebd9659 100644 (file)
@@ -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.
       ///
index 36044826e83905bfc9636ba851d2a449c1b4cfdf..d572335fb3dae235b60f2fea00702cd816b047d1 100644 (file)
@@ -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,
index 3f23f3d855cf09083f78eef3998b8e56f3274c51..402d83683aaab955fa8ee09beddb74eee75df0bf 100644 (file)
@@ -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;
 
index e120c6a1f87de86c5807bdeae00c4b644ac3532e..2a7b170222067bffb6d05460cb709b9663f28482 100644 (file)
@@ -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 {
index 469c2846a6456a35498c627cd6a65a586d66fc25..1b2285c7948b3670c31bcd4a267513db1bc467b8 100644 (file)
@@ -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) {
index 15bb6a6e45ea1620b89fb25948c6ed5d62144fb7..173ca6cb09d1f18e502834553a6463e6f18c6d63 100644 (file)
@@ -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();
index 6734d7759b4da91a08e044e7a8bf4acf441bf0e8..7e1cae95d7e5ed9c2e604aaf87976c56f1fdce8a 100644 (file)
@@ -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) {
index 038636d10801ff440af980339cbc9753ac6bd5fb..96328e2fb6e51d3a68c8a6967b3b40590f7c2e66 100644 (file)
@@ -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 {
index 4d29a34a73ef92530bffef7e0fba4e95f8cc442a..2f48bec123bf66919621269a450297dcc8cea9a6 100644 (file)
@@ -187,3 +187,4 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
 FunctionScopeInfo::~FunctionScopeInfo() { }
 BlockScopeInfo::~BlockScopeInfo() { }
 LambdaScopeInfo::~LambdaScopeInfo() { }
+CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { }
index 6425f34ff5fe723345fc5bda832bbb75fd1aaf9c..203b689aa131be460bed392df31e61174066d4bf 100644 (file)
@@ -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());
+}
index e96c5d40a3d71dee395ebaae513414e8c707724d..cdfdc09e06ed6b510bdbaba4653854ef87a28ad5 100644 (file)
@@ -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.
index cfc00502c4114067fd1dca1b40f028273b30cf85..89c1bc51c304383945cd42fd0cfa43ae25e230cc 100644 (file)
@@ -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);
   }
index 53fa6dafdd3b99436ef359830df1bcacac769138..77e6bfd086652d282133843a072fed48b55eec4a 100644 (file)
@@ -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;
index b3558a548b607bedfe66bffa9d3ea44ce075f68c..88237b08b2bb5c49cd39bcab0db87dbde1756afe 100644 (file)
@@ -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 Sema::ActOnMSDependentExistsStmt(SourceLocation KeywordLoc,
                                     GetNameFromUnqualifiedId(Name),
                                     Nested);
 }
+
+RecordDecl*
+Sema::CreateCapturedStmtRecordDecl(CapturedDecl *&CD, SourceLocation Loc)
+{
+  DeclContext *DC = CurContext;
+  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+    DC = DC->getParent();
+
+  RecordDecl *RD = 0;
+  if (getLangOpts().CPlusPlus)
+    RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+  else
+    RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, /*Id=*/0);
+
+  DC->addDecl(RD);
+  RD->setImplicit();
+  RD->startDefinition();
+
+  CD = CapturedDecl::Create(Context, CurContext);
+  DC->addDecl(CD);
+
+  return RD;
+}
+
+static void buildCapturedStmtCaptureList(
+    SmallVectorImpl<CapturedStmt::Capture> &Captures,
+    SmallVectorImpl<Expr *> &CaptureInits,
+    ArrayRef<CapturingScopeInfo::Capture> Candidates) {
+
+  typedef ArrayRef<CapturingScopeInfo::Capture>::const_iterator CaptureIter;
+  for (CaptureIter Cap = Candidates.begin(); Cap != Candidates.end(); ++Cap) {
+
+    if (Cap->isThisCapture()) {
+      Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
+                                               CapturedStmt::VCK_This));
+      CaptureInits.push_back(Cap->getCopyExpr());
+      continue;
+    }
+
+    assert(Cap->isReferenceCapture() &&
+           "non-reference capture not yet implemented");
+
+    Captures.push_back(CapturedStmt::Capture(Cap->getLocation(),
+                                             CapturedStmt::VCK_ByRef,
+                                             Cap->getVariable()));
+    CaptureInits.push_back(Cap->getCopyExpr());
+  }
+}
+
+void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
+                                    CapturedRegionScopeInfo::CapturedRegionKind Kind) {
+  CapturedDecl *CD = 0;
+  RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc);
+
+  // Enter the capturing scope for this captured region.
+  PushCapturedRegionScope(CurScope, CD, RD, Kind);
+
+  if (CurScope)
+    PushDeclContext(CurScope, CD);
+  else
+    CurContext = CD;
+
+  PushExpressionEvaluationContext(PotentiallyEvaluated);
+}
+
+void Sema::ActOnCapturedRegionError(bool IsInstantiation) {
+  DiscardCleanupsInEvaluationContext();
+  PopExpressionEvaluationContext();
+
+  if (!IsInstantiation)
+    PopDeclContext();
+
+  CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
+  RecordDecl *Record = RSI->TheRecordDecl;
+  Record->setInvalidDecl();
+
+  SmallVector<Decl*, 4> Fields;
+  for (RecordDecl::field_iterator I = Record->field_begin(),
+                                  E = Record->field_end(); I != E; ++I)
+    Fields.push_back(*I);
+  ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields,
+              SourceLocation(), SourceLocation(), /*AttributeList=*/0);
+
+  PopFunctionScopeInfo();
+}
+
+StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
+  CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
+
+  SmallVector<CapturedStmt::Capture, 4> Captures;
+  SmallVector<Expr *, 4> CaptureInits;
+  buildCapturedStmtCaptureList(Captures, CaptureInits, RSI->Captures);
+
+  CapturedDecl *CD = RSI->TheCapturedDecl;
+  RecordDecl *RD = RSI->TheRecordDecl;
+
+  CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, Captures,
+                                           CaptureInits, CD, RD);
+
+  CD->setBody(Res->getCapturedStmt());
+  RD->completeDefinition();
+
+  PopDeclContext();
+  PopFunctionScopeInfo();
+
+  return Owned(Res);
+}
index e8cc1553aa686acfcb049f05fb40350eac982bea..24b268f36df20819a9e8db1f415e32c39f4d5b72 100644 (file)
@@ -119,6 +119,7 @@ serialization::getDefinitiveDeclContext(const DeclContext *DC) {
   case Decl::CXXConversion:
   case Decl::ObjCMethod:
   case Decl::Block:
+  case Decl::Captured:
     // Objective C categories, category implementations, and class
     // implementations can only be defined in one place.
   case Decl::ObjCCategory:
@@ -203,6 +204,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) {
   case Decl::FriendTemplate:
   case Decl::StaticAssert:
   case Decl::Block:
+  case Decl::Captured:
   case Decl::ClassScopeFunctionSpecialization:
   case Decl::Import:
   case Decl::OMPThreadPrivate:
index 02295d09be491a5c41c0ab18eae51900e796d662..949f593434c2ea9d579e62246fe0f7ff0b48c178 100644 (file)
@@ -266,6 +266,7 @@ namespace clang {
     void VisitFriendTemplateDecl(FriendTemplateDecl *D);
     void VisitStaticAssertDecl(StaticAssertDecl *D);
     void VisitBlockDecl(BlockDecl *BD);
+    void VisitCapturedDecl(CapturedDecl *CD);
     void VisitEmptyDecl(EmptyDecl *D);
 
     std::pair<uint64_t, uint64_t> VisitDeclContext(DeclContext *DC);
@@ -994,6 +995,10 @@ void ASTDeclReader::VisitBlockDecl(BlockDecl *BD) {
                   captures.end(), capturesCXXThis);
 }
 
+void ASTDeclReader::VisitCapturedDecl(CapturedDecl *) {
+  llvm_unreachable("not implemented yet");
+}
+
 void ASTDeclReader::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
   VisitDecl(D);
   D->setLanguage((LinkageSpecDecl::LanguageIDs)Record[Idx++]);
@@ -2146,6 +2151,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) {
   case DECL_MS_PROPERTY:
     D = MSPropertyDecl::CreateDeserialized(Context, ID);
     break;
+  case DECL_CAPTURED:
+    llvm_unreachable("not implemented yet");
+    break;
   case DECL_CXX_BASE_SPECIFIERS:
     Error("attempt to read a C++ base-specifier record as a declaration");
     return 0;
index 7d21c584aa2d6fc396270dd0344ee3b160d25f0e..b7ca623d7d38b9884a87e1c4fab2699fe39f0cad 100644 (file)
@@ -103,6 +103,7 @@ namespace clang {
     void VisitFriendTemplateDecl(FriendTemplateDecl *D);
     void VisitStaticAssertDecl(StaticAssertDecl *D);
     void VisitBlockDecl(BlockDecl *D);
+    void VisitCapturedDecl(CapturedDecl *D);
     void VisitEmptyDecl(EmptyDecl *D);
 
     void VisitDeclContext(DeclContext *DC, uint64_t LexicalOffset,
@@ -824,6 +825,10 @@ void ASTDeclWriter::VisitBlockDecl(BlockDecl *D) {
   Code = serialization::DECL_BLOCK;
 }
 
+void ASTDeclWriter::VisitCapturedDecl(CapturedDecl *) {
+  llvm_unreachable("not implemented yet");
+}
+
 void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) {
   VisitDecl(D);
   Record.push_back(D->getLanguage());
diff --git a/test/Sema/captured-statements.c b/test/Sema/captured-statements.c
new file mode 100644 (file)
index 0000000..9285a78
--- /dev/null
@@ -0,0 +1,78 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s -fblocks
+
+void test_gotos() {
+  goto L1; // expected-error {{use of undeclared label 'L1'}}
+  goto L3; // OK
+  #pragma clang __debug captured
+  {
+L1:
+    goto L2; // OK
+L2:
+    goto L3; // expected-error {{use of undeclared label 'L3'}}
+  }
+L3: ;
+}
+
+void test_break_continue() {
+  while (1) {
+    #pragma clang __debug captured
+    {
+      break; // expected-error {{'break' statement not in loop or switch statement}}
+      continue; // expected-error {{'continue' statement not in loop statement}}
+    }
+  }
+}
+
+void test_return() {
+  while (1) {
+    #pragma clang __debug captured
+    {
+      return; // expected-error {{cannot return from default captured statement}}
+    }
+  }
+}
+
+void test_nest() {
+  int x;
+  #pragma clang __debug captured
+  {
+    int y;
+    #pragma clang __debug captured
+    {
+      int z;
+      #pragma clang __debug captured
+      {
+        x = z = y; // OK
+      }
+    }
+  }
+}
+
+void test_nest_block() {
+  __block int x;
+  int y;
+  ^{
+    int z;
+    #pragma clang __debug captured
+    {
+      x = y; // OK
+      y = z; // expected-error{{variable is not assignable (missing __block type specifier)}}
+      z = y; // OK
+    }
+  }();
+
+  __block int a;
+  int b;
+  #pragma clang __debug captured
+  {
+    __block int c;
+    int d;
+    ^{
+      a = b; // OK
+      a = c; // OK
+      b = d; // OK - Consistent with block inside a lambda
+      c = a; // OK
+      d = b; // expected-error{{variable is not assignable (missing __block type specifier)}}
+    }();
+  }
+}
diff --git a/test/SemaCXX/captured-statements.cpp b/test/SemaCXX/captured-statements.cpp
new file mode 100644 (file)
index 0000000..15879a1
--- /dev/null
@@ -0,0 +1,52 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s -fblocks
+
+void test_nest_lambda() {
+  int x;
+  int y;
+  [&,y]() {
+    int z;
+    #pragma clang __debug captured
+    {
+      x = y; // OK
+      y = z; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
+      z = y; // OK
+    }
+  }();
+
+  int a;
+  #pragma clang __debug captured
+  {
+    int b;
+    int c;
+    [&,c]() {
+      a = b; // OK
+      b = c; // OK
+      c = a; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
+    }();
+  }
+}
+
+class test_obj_capture {
+  int a;
+  void b();
+  static void test() {
+    test_obj_capture c;
+    #pragma clang __debug captured
+    { (void)c.a; }  // OK
+    #pragma clang __debug captured
+    { c.b(); }      // OK
+  }
+};
+
+class test_this_capture {
+  int a;
+  void b();
+  void test() {
+    #pragma clang __debug captured
+    { (void)this; } // OK
+    #pragma clang __debug captured
+    { (void)a; }    // OK
+    #pragma clang __debug captured
+    { b(); }        // OK
+  }
+};
index d1aeee04eab3cc9df363ea5474066644edceb24b..95b49fcd2544d16a43efe5d972202835aabce9f7 100644 (file)
@@ -4474,6 +4474,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) {
   case Decl::FileScopeAsm:
   case Decl::StaticAssert:
   case Decl::Block:
+  case Decl::Captured:
   case Decl::Label:  // FIXME: Is this right??
   case Decl::ClassScopeFunctionSpecialization:
   case Decl::Import:
index 592f1687257d030d832a17adc0956c6d46f3a27b..6c9da93b73c93cfc4b59bd9173efa4b3f2170209 100644 (file)
@@ -1170,8 +1170,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));
   }
 
@@ -1200,6 +1201,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, {
@@ -1839,7 +1848,6 @@ DEF_TRAVERSE_STMT(MSDependentExistsStmt, {
 DEF_TRAVERSE_STMT(ReturnStmt, { })
 DEF_TRAVERSE_STMT(SwitchStmt, { })
 DEF_TRAVERSE_STMT(WhileStmt, { })
-DEF_TRAVERSE_STMT(CapturedStmt, { })
 
 DEF_TRAVERSE_STMT(CXXDependentScopeMemberExpr, {
     TRY_TO(TraverseNestedNameSpecifierLoc(S->getQualifierLoc()));
@@ -2141,6 +2149,9 @@ DEF_TRAVERSE_STMT(MSPropertyRefExpr, {})
 DEF_TRAVERSE_STMT(SEHTryStmt, {})
 DEF_TRAVERSE_STMT(SEHExceptStmt, {})
 DEF_TRAVERSE_STMT(SEHFinallyStmt,{})
+DEF_TRAVERSE_STMT(CapturedStmt, {
+  TRY_TO(TraverseDecl(S->getCapturedDecl()));
+})
 
 DEF_TRAVERSE_STMT(CXXOperatorCallExpr, { })
 DEF_TRAVERSE_STMT(OpaqueValueExpr, { })