Small fix for the error path, based on the implementation for lambdas.

Hi doug.gregor,

http://llvm-reviews.chandlerc.com/D433

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D433?vs=1049&id=1109#toc

Files:
  include/clang/AST/Decl.h
  include/clang/Basic/DiagnosticSemaKinds.td
  include/clang/Sema/ScopeInfo.h
  include/clang/Sema/Sema.h
  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
  test/Sema/captured-statements.c
  test/SemaCXX/captured-statements.cpp
Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1465,6 +1465,7 @@
   bool HasImplicitReturnZero : 1;
   bool IsLateTemplateParsed : 1;
   bool IsConstexpr : 1;
+  bool IsCapturedRegion : 1;
 
   /// \brief Indicates if the function was a definition but its body was
   /// skipped.
@@ -1553,7 +1554,9 @@
       HasWrittenPrototype(true), IsDeleted(false), IsTrivial(false),
       IsDefaulted(false), IsExplicitlyDefaulted(false),
       HasImplicitReturnZero(false), IsLateTemplateParsed(false),
-      IsConstexpr(isConstexprSpecified), HasSkippedBody(false),
+      IsConstexpr(isConstexprSpecified),
+      IsCapturedRegion(false),
+      HasSkippedBody(false),
       EndRangeLoc(NameInfo.getEndLoc()),
       TemplateOrSpecialization(),
       DNLoc(NameInfo.getInfo()) {}
@@ -1732,6 +1735,10 @@
   bool isConstexpr() const { return IsConstexpr; }
   void setConstexpr(bool IC) { IsConstexpr = IC; }
 
+  /// \brief Whether this is the function for a captured statement.
+  bool isCapturedRegion() const { return IsCapturedRegion; }
+  void setCapturedRegion(bool v = true) { IsCapturedRegion = v; }
+
   /// \brief Whether this function has been deleted.
   ///
   /// A function that is "deleted" (via the C++0x "= delete" syntax)
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4713,6 +4713,9 @@
     "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: include/clang/Sema/ScopeInfo.h
===================================================================
--- include/clang/Sema/ScopeInfo.h
+++ include/clang/Sema/ScopeInfo.h
@@ -73,7 +73,8 @@
   enum ScopeKind {
     SK_Function,
     SK_Block,
-    SK_Lambda
+    SK_Lambda,
+    SK_CapturedRegion
   };
   
 public:
@@ -319,7 +320,8 @@
 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 +463,8 @@
   }
 
   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 +495,46 @@
   }
 };
 
+/// \brief Retains information about a captured region.
+class CapturedRegionScopeInfo: public CapturingScopeInfo {
+public:
+
+  enum CapturedRegionKind {
+    CR_Default
+  };
+
+  /// \brief The helper function.
+  FunctionDecl *TheFunctionDecl;
+  /// \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, FunctionDecl *FD,
+                          RecordDecl *RD, CapturedRegionKind K)
+    : CapturingScopeInfo(Diag, ImpCap_CapturedRegion),
+      TheFunctionDecl(FD), 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: include/clang/Sema/Sema.h
===================================================================
--- include/clang/Sema/Sema.h
+++ 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"
@@ -173,6 +174,7 @@
 namespace sema {
   class AccessedEntity;
   class BlockScopeInfo;
+  class CapturedRegionScopeInfo;
   class CapturingScopeInfo;
   class CompoundScopeInfo;
   class DelayedDiagnostic;
@@ -902,6 +904,9 @@
   void PushFunctionScope();
   void PushBlockScope(Scope *BlockScope, BlockDecl *Block);
   void PushLambdaScope(CXXRecordDecl *Lambda, CXXMethodDecl *CallOperator);
+  void PushCapturedRegionScope(Scope *RegionScope, FunctionDecl *FD,
+                               RecordDecl *RD,
+                               sema::CapturedRegionScopeInfo::CapturedRegionKind K);
   void PopFunctionScopeInfo(const sema::AnalysisBasedWarnings::Policy *WP =0,
                             const Decl *D = 0, const BlockExpr *blkExpr = 0);
 
@@ -922,6 +927,9 @@
   /// \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; }
 
@@ -2712,6 +2720,13 @@
   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(FunctionDecl *&FD,
+                                           SourceLocation Loc,
+                                           IdentifierInfo *MangledName);
   const VarDecl *getCopyElisionCandidate(QualType ReturnType, Expr *E,
                                          bool AllowFunctionParameters);
 
Index: lib/Frontend/PrintPreprocessedOutput.cpp
===================================================================
--- lib/Frontend/PrintPreprocessedOutput.cpp
+++ lib/Frontend/PrintPreprocessedOutput.cpp
@@ -128,6 +128,7 @@
                            SrcMgr::CharacteristicKind FileType,
                            FileID PrevFID);
   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);
@@ -316,6 +317,15 @@
   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 MacroInfo *MI) {
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp
+++ 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 @@
     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: lib/Sema/ScopeInfo.cpp
===================================================================
--- lib/Sema/ScopeInfo.cpp
+++ lib/Sema/ScopeInfo.cpp
@@ -187,3 +187,4 @@
 FunctionScopeInfo::~FunctionScopeInfo() { }
 BlockScopeInfo::~BlockScopeInfo() { }
 LambdaScopeInfo::~LambdaScopeInfo() { }
+CapturedRegionScopeInfo::~CapturedRegionScopeInfo() { }
Index: lib/Sema/Sema.cpp
===================================================================
--- lib/Sema/Sema.cpp
+++ lib/Sema/Sema.cpp
@@ -799,6 +799,9 @@
   while (true) {
     if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC)) {
       DC = DC->getParent();
+    } else if (isa<FunctionDecl>(DC) &&
+               cast<FunctionDecl>(DC)->isCapturedRegion()) {
+      DC = DC->getParent();
     } else if (isa<CXXMethodDecl>(DC) &&
                cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
                cast<CXXRecordDecl>(DC->getParent())->isLambda()) {
@@ -1302,3 +1305,16 @@
   E = ExprError();
   return true;
 }
+
+void Sema::PushCapturedRegionScope(Scope *S, FunctionDecl *FD, RecordDecl *RD,
+                                   CapturedRegionScopeInfo::CapturedRegionKind K) {
+  FunctionScopes.push_back(new CapturedRegionScopeInfo(getDiagnostics(),
+                           S, FD, RD, K));
+}
+
+CapturedRegionScopeInfo *Sema::getCurCapturedRegion() {
+  if (FunctionScopes.empty())
+    return 0;
+
+  return dyn_cast<CapturedRegionScopeInfo>(FunctionScopes.back());
+}
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -10598,6 +10598,34 @@
   // 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, 
@@ -10749,6 +10777,9 @@
              cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call &&
              cast<CXXRecordDecl>(DC->getParent())->isLambda())
       ParentDC = DC->getParent()->getParent();
+    else if (isa<FunctionDecl>(DC) &&
+             cast<FunctionDecl>(DC)->isCapturedRegion())
+      ParentDC = DC->getParent();
     else {
       if (BuildAndDiagnose)
         diagnoseUncapturableValueReference(*this, Loc, Var, DC);
@@ -10777,7 +10808,7 @@
     }
 
     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).
@@ -10933,8 +10964,31 @@
                         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: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp
+++ lib/Sema/SemaExprCXX.cpp
@@ -701,6 +701,7 @@
       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++;
@@ -734,6 +735,20 @@
       Lambda->addDecl(Field);
       ThisExpr = new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit=*/true);
     }
+
+    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: lib/Sema/SemaLambda.cpp
===================================================================
--- lib/Sema/SemaLambda.cpp
+++ lib/Sema/SemaLambda.cpp
@@ -791,6 +791,7 @@
       CaptureDefault = LCD_ByCopy;
       break;
 
+    case CapturingScopeInfo::ImpCap_CapturedRegion:
     case CapturingScopeInfo::ImpCap_LambdaByref:
       CaptureDefault = LCD_ByRef;
       break;
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -2304,6 +2304,12 @@
   CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
   QualType FnRetType = CurCap->ReturnType;
 
+  if (CapturedRegionScopeInfo *CurRegion =
+        dyn_cast<CapturedRegionScopeInfo>(CurCap)) {
+    Diag(ReturnLoc, diag::err_return_in_captured_stmt) << CurRegion->getRegionName();
+    return StmtError();
+  }
+
   // For blocks/lambdas with implicit return types, we check each return
   // statement individually, and deduce the common return type when the block
   // or lambda is completed.
@@ -2850,3 +2856,148 @@
                                     GetNameFromUnqualifiedId(Name),
                                     Nested);
 }
+
+RecordDecl*
+Sema::CreateCapturedStmtRecordDecl(FunctionDecl *&FD, SourceLocation Loc,
+                                   IdentifierInfo *MangledName)
+{
+  DeclContext *DC = CurContext;
+  while (!(DC->isFunctionOrMethod() || DC->isRecord() || DC->isFileContext()))
+    DC = DC->getParent();
+
+  IdentifierInfo *Id = &PP.getIdentifierTable().get("capture");
+  RecordDecl *RD = 0;
+  if (getLangOpts().CPlusPlus)
+    RD = CXXRecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, Id);
+  else
+    RD = RecordDecl::Create(Context, TTK_Struct, DC, Loc, Loc, Id);
+
+  DC->addDecl(RD);
+  RD->setImplicit();
+  RD->startDefinition();
+
+  // The capture helper function returns void and takes a single argument,
+  // a pointer to the captured record.
+  {
+    QualType ParamType = Context.getPointerType(Context.getTagDeclType(RD));
+
+    FunctionProtoType::ExtProtoInfo EPI;
+    QualType FunctionTy = Context.getFunctionType(Context.VoidTy,
+                                                  &ParamType, 1, EPI);
+
+    TypeSourceInfo *FunctionTyInfo
+      = Context.getTrivialTypeSourceInfo(FunctionTy);
+
+    FD = FunctionDecl::Create(Context, CurContext, SourceLocation(),
+                              SourceLocation(), MangledName, FunctionTy,
+                              FunctionTyInfo, SC_None, SC_None);
+
+    DC->addDecl(FD);
+
+    IdentifierInfo *IdThis = &PP.getIdentifierTable().get("this");
+    ParmVarDecl *Param
+      = ParmVarDecl::Create(Context, FD, SourceLocation(), SourceLocation(),
+                            IdThis, ParamType,
+                            Context.getTrivialTypeSourceInfo(ParamType),
+                            SC_None, SC_None, /* DefaultArg =*/0);
+    FD->setParams(Param);
+    FD->setImplicit(true);
+    FD->setUsed(true);
+    FD->setCapturedRegion();
+  }
+
+  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());
+  }
+}
+
+// Helper functions are required to be internal, not mangling accross
+// translation units.
+static IdentifierInfo *GetMangledHelperName(Sema &S) {
+  static unsigned count = 0;
+  StringRef name("__captured_stmt_helperV");
+  return &S.PP.getIdentifierTable().get((name + llvm::Twine(count++)).str());
+}
+
+void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
+                                    CapturedRegionScopeInfo::CapturedRegionKind Kind) {
+  IdentifierInfo *MangledName = GetMangledHelperName(*this);
+  FunctionDecl *FD = 0;
+  RecordDecl *RD = CreateCapturedStmtRecordDecl(FD, Loc, MangledName);
+
+  // Enter the capturing scope for this captured region.
+  PushCapturedRegionScope(CurScope, FD, RD, Kind);
+
+  if (CurScope)
+    PushDeclContext(CurScope, FD);
+  else
+    CurContext = FD;
+
+  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);
+
+  FunctionDecl *FD = RSI->TheFunctionDecl;
+  RecordDecl *RD = RSI->TheRecordDecl;
+
+  CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, Captures,
+                                           CaptureInits, FD, RD);
+
+  FD->setBody(Res->getCapturedStmt());
+  RD->completeDefinition();
+
+  PopDeclContext();
+  PopFunctionScopeInfo();
+
+  return Owned(Res);
+}
Index: test/Sema/captured-statements.c
===================================================================
--- /dev/null
+++ test/Sema/captured-statements.c
@@ -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)}}
+    }();
+  }
+}
Index: test/SemaCXX/captured-statements.cpp
===================================================================
--- /dev/null
+++ test/SemaCXX/captured-statements.cpp
@@ -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
+  }
+};
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to