Implement template support for CapturedStmt

- Sema tests added and CodeGen tests are pending

Differential Revision: http://llvm-reviews.chandlerc.com/D728



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@181101 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Stmt.cpp b/lib/AST/Stmt.cpp
index 0db97d2..5b29c07 100644
--- a/lib/AST/Stmt.cpp
+++ b/lib/AST/Stmt.cpp
@@ -1049,12 +1049,13 @@
       + FirstCaptureOffset);
 }
 
-CapturedStmt::CapturedStmt(Stmt *S, ArrayRef<Capture> Captures,
+CapturedStmt::CapturedStmt(Stmt *S, CapturedRegionKind Kind,
+                           ArrayRef<Capture> Captures,
                            ArrayRef<Expr *> CaptureInits,
                            CapturedDecl *CD,
                            RecordDecl *RD)
   : Stmt(CapturedStmtClass), NumCaptures(Captures.size()),
-    TheCapturedDecl(CD), TheRecordDecl(RD) {
+    CapDeclAndKind(CD, Kind), TheRecordDecl(RD) {
   assert( S && "null captured statement");
   assert(CD && "null captured declaration for captured statement");
   assert(RD && "null record declaration for captured statement");
@@ -1074,11 +1075,12 @@
 
 CapturedStmt::CapturedStmt(EmptyShell Empty, unsigned NumCaptures)
   : Stmt(CapturedStmtClass, Empty), NumCaptures(NumCaptures),
-    TheCapturedDecl(0), TheRecordDecl(0) {
+    CapDeclAndKind(0, CR_Default), TheRecordDecl(0) {
   getStoredStmts()[NumCaptures] = 0;
 }
 
 CapturedStmt *CapturedStmt::Create(ASTContext &Context, Stmt *S,
+                                   CapturedRegionKind Kind,
                                    ArrayRef<Capture> Captures,
                                    ArrayRef<Expr *> CaptureInits,
                                    CapturedDecl *CD,
@@ -1102,7 +1104,7 @@
   }
 
   void *Mem = Context.Allocate(Size);
-  return new (Mem) CapturedStmt(S, Captures, CaptureInits, CD, RD);
+  return new (Mem) CapturedStmt(S, Kind, Captures, CaptureInits, CD, RD);
 }
 
 CapturedStmt *CapturedStmt::CreateDeserialized(ASTContext &Context,
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index 42d4590..16cc43a 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -2981,7 +2981,8 @@
 }
 
 void Sema::ActOnCapturedRegionStart(SourceLocation Loc, Scope *CurScope,
-                                    CapturedRegionKind Kind, unsigned NumParams) {
+                                    CapturedRegionKind Kind,
+                                    unsigned NumParams) {
   CapturedDecl *CD = 0;
   RecordDecl *RD = CreateCapturedStmtRecordDecl(CD, Loc, NumParams);
 
@@ -2996,13 +2997,10 @@
   PushExpressionEvaluationContext(PotentiallyEvaluated);
 }
 
-void Sema::ActOnCapturedRegionError(bool IsInstantiation) {
+void Sema::ActOnCapturedRegionError() {
   DiscardCleanupsInEvaluationContext();
   PopExpressionEvaluationContext();
 
-  if (!IsInstantiation)
-    PopDeclContext();
-
   CapturedRegionScopeInfo *RSI = getCurCapturedRegion();
   RecordDecl *Record = RSI->TheRecordDecl;
   Record->setInvalidDecl();
@@ -3014,6 +3012,7 @@
   ActOnFields(/*Scope=*/0, Record->getLocation(), Record, Fields,
               SourceLocation(), SourceLocation(), /*AttributeList=*/0);
 
+  PopDeclContext();
   PopFunctionScopeInfo();
 }
 
@@ -3027,12 +3026,16 @@
   CapturedDecl *CD = RSI->TheCapturedDecl;
   RecordDecl *RD = RSI->TheRecordDecl;
 
-  CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, Captures,
+  CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S,
+                                           RSI->CapRegionKind, Captures,
                                            CaptureInits, CD, RD);
 
   CD->setBody(Res->getCapturedStmt());
   RD->completeDefinition();
 
+  DiscardCleanupsInEvaluationContext();
+  PopExpressionEvaluationContext();
+
   PopDeclContext();
   PopFunctionScopeInfo();
 
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 99cb282..0fcde81 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -9449,7 +9449,18 @@
 template<typename Derived>
 StmtResult
 TreeTransform<Derived>::TransformCapturedStmt(CapturedStmt *S) {
-  llvm_unreachable("not implement yet");
+  SourceLocation Loc = S->getLocStart();
+  unsigned NumParams = S->getCapturedDecl()->getNumParams();
+  getSema().ActOnCapturedRegionStart(Loc, /*CurScope*/0,
+                                     S->getCapturedRegionKind(), NumParams);
+  StmtResult Body = getDerived().TransformStmt(S->getCapturedStmt());
+
+  if (Body.isInvalid()) {
+    getSema().ActOnCapturedRegionError();
+    return StmtError();
+  }
+
+  return getSema().ActOnCapturedRegionEnd(Body.take());
 }
 
 } // end namespace clang
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 5d72614..e1357ba 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -382,8 +382,9 @@
 
 void ASTStmtReader::VisitCapturedStmt(CapturedStmt *S) {
   VisitStmt(S);
-  S->TheCapturedDecl = ReadDeclAs<CapturedDecl>(Record, Idx);
-  S->TheRecordDecl = ReadDeclAs<RecordDecl>(Record, Idx);
+  S->setCapturedDecl(ReadDeclAs<CapturedDecl>(Record, Idx));
+  S->setCapturedRegionKind(static_cast<CapturedRegionKind>(Record[Idx++]));
+  S->setCapturedRecordDecl(ReadDeclAs<RecordDecl>(Record, Idx));
 
   // Capture inits
   for (CapturedStmt::capture_init_iterator I = S->capture_init_begin(),
@@ -393,7 +394,7 @@
 
   // Body
   S->setCapturedStmt(Reader.ReadSubStmt());
-  S->TheCapturedDecl->setBody(S->getCapturedStmt());
+  S->getCapturedDecl()->setBody(S->getCapturedStmt());
 
   // Captures
   for (CapturedStmt::capture_iterator I = S->capture_begin(),
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7d28247..5f7ac01 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -290,7 +290,10 @@
   // NumCaptures
   Record.push_back(std::distance(S->capture_begin(), S->capture_end()));
 
+  // CapturedDecl and captured region kind
   Writer.AddDeclRef(S->getCapturedDecl(), Record);
+  Record.push_back(S->getCapturedRegionKind());
+
   Writer.AddDeclRef(S->getCapturedRecordDecl(), Record);
 
   // Capture inits