Updates per review

  Move some code into GenerateCapturedStmtFunction, and remove 'ThisValue'
  from CGCapturedStmtInfo, which was confusing, since we already have
  'this' in C++.

  Added tests for captured statements in a block (and vice-versa), as well
  as a captured statement in a captured statement.  Disallowed capturing
  __block variables in a captured statement, since we don't handle that in
  codegen.

Hi rjmccall, ABataev, gribozavr, doug.gregor,

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

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D640?vs=1548&id=1788#toc

Files:
  include/clang/AST/GlobalDecl.h
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/AST/ItaniumMangle.cpp
  lib/AST/MicrosoftMangle.cpp
  lib/CodeGen/CGExpr.cpp
  lib/CodeGen/CGStmt.cpp
  lib/CodeGen/CodeGenFunction.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Sema/SemaExpr.cpp
  test/CodeGen/captured-statements-nested.c
  test/CodeGen/captured-statements.c
  test/CodeGenCXX/captured-statements.cpp
  test/Sema/captured-statements.c
Index: include/clang/AST/GlobalDecl.h
===================================================================
--- include/clang/AST/GlobalDecl.h
+++ include/clang/AST/GlobalDecl.h
@@ -41,6 +41,7 @@
   GlobalDecl(const VarDecl *D) { Init(D);}
   GlobalDecl(const FunctionDecl *D) { Init(D); }
   GlobalDecl(const BlockDecl *D) { Init(D); }
+  GlobalDecl(const CapturedDecl *D) { Init(D); }
   GlobalDecl(const ObjCMethodDecl *D) { Init(D); }
 
   GlobalDecl(const CXXConstructorDecl *D, CXXCtorType Type)
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -4811,8 +4811,6 @@
     "duration">;
   def err_this_capture : Error<
     "'this' cannot be %select{implicitly |}0captured in this context">;
-  def err_lambda_capture_block : Error<
-    "__block variable %0 cannot be captured in a lambda expression">;
   def err_lambda_capture_anonymous_var : Error<
     "unnamed variable cannot be implicitly captured in a lambda expression">;
   def err_lambda_capture_vm_type : Error<
@@ -4856,6 +4854,9 @@
 
 def err_return_in_captured_stmt : Error<
   "cannot return from %0">;
+def err_capture_block_variable : Error<
+  "__block variable %0 cannot be captured in a "
+  "%select{lambda expression|captured statement}1">;
 
 def err_operator_arrow_circular : Error<
   "circular pointer delegation detected">;
Index: lib/AST/ItaniumMangle.cpp
===================================================================
--- lib/AST/ItaniumMangle.cpp
+++ lib/AST/ItaniumMangle.cpp
@@ -1419,6 +1419,10 @@
     NameStream.flush();
     Out << Name.size() << Name;
     return;
+  } else if (isa<CapturedDecl>(DC)) {
+    // Skip CapturedDecl context.
+    manglePrefix(getEffectiveParentContext(DC), NoFunction);
+    return;
   }
   
   const NamedDecl *ND = cast<NamedDecl>(DC);  
Index: lib/AST/MicrosoftMangle.cpp
===================================================================
--- lib/AST/MicrosoftMangle.cpp
+++ lib/AST/MicrosoftMangle.cpp
@@ -535,6 +535,10 @@
     Context.mangleBlock(BD, Out);
     Out << '@';
     return manglePostfix(DC->getParent(), NoFunction);
+  } else if (isa<CapturedDecl>(DC)) {
+    // Skip CapturedDecl context.
+    manglePostfix(DC->getParent(), NoFunction);
+    return;
   }
 
   if (NoFunction && (isa<FunctionDecl>(DC) || isa<ObjCMethodDecl>(DC)))
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp
+++ lib/CodeGen/CGExpr.cpp
@@ -1793,6 +1793,13 @@
   return CGF.MakeAddrLValue(V, E->getType(), Alignment);
 }
 
+static LValue EmitCapturedFieldLValue(CodeGenFunction &CGF, const FieldDecl *FD,
+                                      llvm::Value *ThisValue) {
+  QualType TagType = CGF.getContext().getTagDeclType(FD->getParent());
+  LValue LV = CGF.MakeNaturalAlignAddrLValue(ThisValue, TagType);
+  return CGF.EmitLValueForField(LV, FD);
+}
+
 LValue CodeGenFunction::EmitDeclRefLValue(const DeclRefExpr *E) {
   const NamedDecl *ND = E->getDecl();
   CharUnits Alignment = getContext().getDeclAlign(ND);
@@ -1844,10 +1851,11 @@
     // Use special handling for lambdas.
     if (!V) {
       if (FieldDecl *FD = LambdaCaptureFields.lookup(VD)) {
-        QualType LambdaTagType = getContext().getTagDeclType(FD->getParent());
-        LValue LambdaLV = MakeNaturalAlignAddrLValue(CXXABIThisValue,
-                                                     LambdaTagType);
-        return EmitLValueForField(LambdaLV, FD);
+        return EmitCapturedFieldLValue(*this, FD, CXXABIThisValue);
+      } else if (CapturedStmtInfo) {
+        if (const FieldDecl *FD = CapturedStmtInfo->lookup(VD))
+          return EmitCapturedFieldLValue(*this, FD,
+                                         CapturedStmtInfo->getContextValue());
       }
 
       assert(isa<BlockDecl>(CurCodeDecl) && E->refersToEnclosingLocal());
Index: lib/CodeGen/CGStmt.cpp
===================================================================
--- lib/CodeGen/CGStmt.cpp
+++ lib/CodeGen/CGStmt.cpp
@@ -22,6 +22,7 @@
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/InlineAsm.h"
 #include "llvm/IR/Intrinsics.h"
+#include "llvm/Support/CallSite.h"
 using namespace clang;
 using namespace CodeGen;
 
@@ -1740,6 +1741,93 @@
   }
 }
 
+/// Generate an outlined function for the body of a CapturedStmt, store any
+/// captured variables into the captured struct, and call the outlined function.
 void CodeGenFunction::EmitCapturedStmt(const CapturedStmt &S) {
-  llvm_unreachable("not implemented yet");
+  const CapturedDecl *CD = S.getCapturedDecl();
+  const RecordDecl *RD = S.getCapturedRecordDecl();
+  QualType RecordTy = getContext().getRecordType(RD);
+  assert(CD->hasBody() && "missing CapturedDecl body");
+
+  // Initialize the captured struct.
+  LValue SlotLV = MakeNaturalAlignAddrLValue(
+                    CreateMemTemp(RecordTy, "agg.captured"), RecordTy);
+
+  RecordDecl::field_iterator CurField = RD->field_begin();
+  for (CapturedStmt::capture_init_iterator I = S.capture_init_begin(),
+                                           E = S.capture_init_end();
+       I != E; ++I, ++CurField) {
+    LValue LV = EmitLValueForFieldInitialization(SlotLV, *CurField);
+    EmitInitializerForField(*CurField, LV, *I, ArrayRef<VarDecl *>());
+  }
+
+  // The function argument is the address of the captured struct.
+  llvm::SmallVector<llvm::Value *, 1> Args;
+  Args.push_back(SlotLV.getAddress());
+
+  // Emit the CapturedDecl
+  CGCapturedStmtInfo CSInfo(S);
+  CodeGenFunction CGF(CGM, true);
+  CGF.CapturedStmtInfo = &CSInfo;
+
+  llvm::Function *F = CGF.GenerateCapturedStmtFunction(CD, RD);
+
+  // Emit call to the helper function.
+  EmitCallOrInvoke(F, Args);
+}
+
+/// Creates the outlined function for a CapturedStmt.
+llvm::Function *
+CodeGenFunction::GenerateCapturedStmtFunction(const CapturedDecl *CD,
+                                              const RecordDecl *RD) {
+  assert(CapturedStmtInfo &&
+    "CapturedStmtInfo should be set when generating the captured function");
+
+  // Check if we should generate debug info for this function.
+  maybeInitializeDebugInfo();
+
+  // Build the argument list.
+  ASTContext &Ctx = CGM.getContext();
+  QualType ContextTagTy = Ctx.getTagDeclType(RD);
+  QualType ContextTy = Ctx.getPointerType(ContextTagTy);
+  FunctionArgList Args;
+  ImplicitParamDecl ContextDecl(const_cast<CapturedDecl*>(CD), SourceLocation(),
+                                /*Id=*/0, ContextTy);
+  Args.push_back(&ContextDecl);
+
+  // Create the function declaration.
+  FunctionType::ExtInfo ExtInfo;
+  const CGFunctionInfo &FuncInfo =
+    CGM.getTypes().arrangeFunctionDeclaration(Ctx.VoidTy, Args, ExtInfo,
+                                              /*IsVariadic=*/false);
+  llvm::FunctionType *FuncLLVMTy = CGM.getTypes().GetFunctionType(FuncInfo);
+
+  llvm::Function *F =
+    llvm::Function::Create(FuncLLVMTy, llvm::GlobalValue::InternalLinkage,
+                           "__captured_stmt", &CGM.getModule());
+  CGM.SetInternalFunctionAttributes(CD, F, FuncInfo);
+
+  // Generate the function.
+  StartFunction(CD, Ctx.VoidTy, F, FuncInfo, Args, CD->getBody()->getLocStart());
+
+  // Set the context parameter in CapturedStmtInfo.
+  llvm::Value *DeclPtr = LocalDeclMap[&ContextDecl];
+  assert(DeclPtr && "missing context parameter for CapturedStmt");
+  CapturedStmtInfo->setContextValue(Builder.CreateLoad(DeclPtr));
+
+  // If 'this' is captured, load it into CXXThisValue.
+  if (CapturedStmtInfo->isCXXThisExprCaptured()) {
+    FieldDecl *FD = CapturedStmtInfo->getThisFieldDecl();
+    LValue LV = MakeNaturalAlignAddrLValue(CapturedStmtInfo->getContextValue(),
+                                           ContextTagTy);
+    LValue ThisLValue = EmitLValueForField(LV, FD);
+
+    CXXThisValue = EmitLoadOfLValue(ThisLValue).getScalarVal();
+  }
+
+  // TODO: lots of code here in GenerateBlockFunction - is any of it needed here?
+  EmitStmt(CD->getBody());
+  FinishFunction(CD->getBodyRBrace());
+
+  return F;
 }
Index: lib/CodeGen/CodeGenFunction.cpp
===================================================================
--- lib/CodeGen/CodeGenFunction.cpp
+++ lib/CodeGen/CodeGenFunction.cpp
@@ -33,6 +33,7 @@
 CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
   : CodeGenTypeCache(cgm), CGM(cgm), Target(cgm.getTarget()),
     Builder(cgm.getModule().getContext()),
+    CapturedStmtInfo(0),
     SanitizePerformTypeCheck(CGM.getSanOpts().Null |
                              CGM.getSanOpts().Alignment |
                              CGM.getSanOpts().ObjectSize |
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -606,6 +606,50 @@
   /// we prefer to insert allocas.
   llvm::AssertingVH<llvm::Instruction> AllocaInsertPt;
 
+  /// \brief API for captured statement code generation.
+  class CGCapturedStmtInfo {
+  public:
+
+    explicit CGCapturedStmtInfo(const CapturedStmt &S)
+      : ThisValue(0), CXXThisFieldDecl(0) {
+
+      RecordDecl::field_iterator Field =
+        S.getCapturedRecordDecl()->field_begin();
+      for (CapturedStmt::capture_iterator I = S.capture_begin(),
+                                          E = S.capture_end();
+           I != E; ++I, ++Field) {
+        if (I->capturesThis())
+          CXXThisFieldDecl = *Field;
+        else
+          CaptureFields[I->getCapturedVar()] = *Field;
+      }
+    }
+
+    void setContextValue(llvm::Value *V) { ThisValue = V; }
+    // \brief Retrieve the value of the context parameter.
+    llvm::Value *getContextValue() const { return ThisValue; }
+
+    /// \brief Lookup the captured field decl for a variable.
+    const FieldDecl *lookup(const VarDecl *VD) const {
+      return CaptureFields.lookup(VD);
+    }
+
+    bool isCXXThisExprCaptured() const { return CXXThisFieldDecl != 0; }
+    FieldDecl *getThisFieldDecl() const { return CXXThisFieldDecl; }
+
+  private:
+    /// \brief Keep the map between VarDecl and FieldDecl.
+    llvm::SmallDenseMap<const VarDecl *, FieldDecl *> CaptureFields;
+
+    /// \brief The base address of the captured record, passed in as the first
+    /// argument of the parallel region function.
+    llvm::Value *ThisValue;
+
+    /// \brief Captured 'this' type.
+    FieldDecl *CXXThisFieldDecl;
+  };
+  CGCapturedStmtInfo *CapturedStmtInfo;
+
   /// BoundsChecking - Emit run-time bounds checks. Higher values mean
   /// potentially higher performance penalties.
   unsigned char BoundsChecking;
@@ -2175,7 +2219,6 @@
   void EmitCaseStmt(const CaseStmt &S);
   void EmitCaseStmtRange(const CaseStmt &S);
   void EmitAsmStmt(const AsmStmt &S);
-  void EmitCapturedStmt(const CapturedStmt &S);
 
   void EmitObjCForCollectionStmt(const ObjCForCollectionStmt &S);
   void EmitObjCAtTryStmt(const ObjCAtTryStmt &S);
@@ -2191,6 +2234,10 @@
   void EmitCXXTryStmt(const CXXTryStmt &S);
   void EmitCXXForRangeStmt(const CXXForRangeStmt &S);
 
+  void EmitCapturedStmt(const CapturedStmt &S);
+  llvm::Function *GenerateCapturedStmtFunction(const CapturedDecl *CD,
+                                               const RecordDecl *RD);
+
   //===--------------------------------------------------------------------===//
   //                         LValue Expression Emission
   //===--------------------------------------------------------------------===//
Index: lib/Sema/SemaExpr.cpp
===================================================================
--- lib/Sema/SemaExpr.cpp
+++ lib/Sema/SemaExpr.cpp
@@ -11161,12 +11161,12 @@
         return true;
       }
     }
-    // Lambdas are not allowed to capture __block variables; they don't
-    // support the expected semantics.
-    if (IsLambda && HasBlocksAttr) {
+    // Lambdas and captured statements are not allowed to capture __block
+    // variables; they don't support the expected semantics.
+    if (HasBlocksAttr && (IsLambda || isa<CapturedRegionScopeInfo>(CSI))) {
       if (BuildAndDiagnose) {
-        Diag(Loc, diag::err_lambda_capture_block) 
-          << Var->getDeclName();
+        Diag(Loc, diag::err_capture_block_variable)
+          << Var->getDeclName() << !IsLambda;
         Diag(Var->getLocation(), diag::note_previous_decl) 
           << Var->getDeclName();
       }
Index: test/CodeGen/captured-statements-nested.c
===================================================================
--- /dev/null
+++ test/CodeGen/captured-statements-nested.c
@@ -0,0 +1,126 @@
+// RUN: %clang_cc1 -fblocks -emit-llvm %s -o %t
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK1
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK2
+
+struct A {
+  int a;
+  float b;
+  char c;
+};
+
+void test_nest_captured_stmt(int param) {
+  int w;
+  // CHECK1: %struct.anon{{.*}} = type { i32*, i32* }
+  // CHECK1: %struct.anon{{.*}} = type { i32*, i32*, i32**, i32* }
+  // CHECK1: [[T:%struct.anon.*]] = type { i32*, i32*, %struct.A*, i32**, i32* }
+  #pragma clang __debug captured
+  {
+    int x;
+    int *y = &w;
+    #pragma clang __debug captured
+    {
+      struct A z;
+      #pragma clang __debug captured
+      {
+        w = x = z.a = 1;
+        *y = param;
+        z.b = 0.1f;
+        z.c = 'c';
+
+        // CHECK1: define internal void @__captured_stmt{{.*}}([[T]]
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+        // CHECK1-NEXT: load %struct.A**
+        // CHECK1-NEXT: getelementptr inbounds %struct.A*
+        // CHECK1-NEXT: store i32 1
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 1
+        // CHECK1-NEXT: load i32**
+        // CHECK1-NEXT: store i32 1
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 0
+        // CHECK1-NEXT: load i32**
+        // CHECK1-NEXT: store i32 1
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 4
+        // CHECK1-NEXT: load i32**
+        // CHECK1-NEXT: load i32*
+        // CHECK1-NEXT: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 3
+        // CHECK1-NEXT: load i32***
+        // CHECK1-NEXT: load i32**
+        // CHECK1-NEXT: store i32
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+        // CHECK1-NEXT: load %struct.A**
+        // CHECK1-NEXT: getelementptr inbounds %struct.A*
+        // CHECK1-NEXT: store float
+        //
+        // CHECK1: getelementptr inbounds [[T]]* {{.*}}, i32 0, i32 2
+        // CHECK1-NEXT: load %struct.A**
+        // CHECK1-NEXT: getelementptr inbounds %struct.A*
+        // CHECK1-NEXT: store i8 99
+      }
+    }
+  }
+}
+
+void test_nest_block() {
+  __block int x;
+  int y;
+  ^{
+    int z;
+    x = z;
+    #pragma clang __debug captured
+    {
+      z = y; // OK
+    }
+  }();
+
+  // CHECK2: define internal void @{{.*}}test_nest_block_block_invoke
+  //
+  // CHECK2: [[Z:%[0-9a-z_]*]] = alloca i32
+  // CHECK2: alloca %struct.anon{{.*}}
+  //
+  // CHECK2: store i32
+  // CHECK2: store i32* [[Z]]
+  //
+  // CHECK2: getelementptr inbounds %struct.anon
+  // CHECK2-NEXT: getelementptr inbounds
+  // CHECK2-NEXT: store i32*
+  //
+  // CHECK2: call void @__captured_stmt
+
+  int a;
+  #pragma clang __debug captured
+  {
+    __block int b;
+    int c;
+    __block int d;
+    ^{
+      b = a;
+      b = c;
+      b = d;
+    }();
+  }
+
+  // CHECK2: alloca %struct.__block_byref_b
+  // CHECK2-NEXT: [[C:%[0-9a-z_]*]] = alloca i32
+  // CHECK2-NEXT: alloca %struct.__block_byref_d
+  //
+  // CHECK2: bitcast %struct.__block_byref_b*
+  // CHECK2-NEXT: store i8*
+  //
+  // CHECK2: [[CapA:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 7
+  //
+  // CHECK2: getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
+  // CHECK2: load i32**
+  // CHECK2: load i32*
+  // CHECK2: store i32 {{.*}}, i32* [[CapA]]
+  //
+  // CHECK2: [[CapC:%[0-9a-z_.]*]] = getelementptr inbounds {{.*}}, i32 0, i32 8
+  // CHECK2-NEXT: [[Val:%[0-9a-z_]*]] = load i32* [[C]]
+  // CHECK2-NEXT: store i32 [[Val]], i32* [[CapC]]
+  //
+  // CHECK2: bitcast %struct.__block_byref_d*
+  // CHECK2-NEXT: store i8*
+}
Index: test/CodeGen/captured-statements.c
===================================================================
--- /dev/null
+++ test/CodeGen/captured-statements.c
@@ -0,0 +1,80 @@
+// RUN: %clang_cc1 -emit-llvm %s -o %t
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-GLOBALS
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
+
+int foo();
+int global;
+
+// Single statement
+void test1() {
+  int i = 0;
+  #pragma clang __debug captured
+  {
+    i++;
+  }
+  // CHECK-1: %struct.anon = type { i32* }
+  //
+  // CHECK-1: test1
+  // CHECK-1: alloca %struct.anon
+  // CHECK-1: getelementptr inbounds %struct.anon*
+  // CHECK-1: store i32* %i
+  // CHECK-1: call void @[[HelperName:__captured_stmt[0-9]+]]
+}
+
+// CHECK-1: define internal void @[[HelperName]](%struct.anon
+// CHECK-1:   getelementptr inbounds %struct.anon{{.*}}, i32 0, i32 0
+// CHECK-1:   load i32**
+// CHECK-1:   load i32*
+// CHECK-1:   add nsw i32
+// CHECK-1:   store i32
+
+// Compound statement with local variable
+void test2(int x) {
+  #pragma clang __debug captured
+  {
+    int i;
+    for (i = 0; i < x; i++)
+      foo();
+  }
+  // CHECK-2: test2
+  // CHECK-2-NOT: %i
+  // CHECK-2: call void @[[HelperName:__captured_stmt[0-9]+]]
+}
+
+// CHECK-2: define internal void @[[HelperName]]
+// CHECK-2-NOT: }
+// CHECK-2:   %i = alloca i32
+
+// Capture array
+void test3() {
+  int arr[] = {1, 2, 3, 4, 5};
+  #pragma clang __debug captured
+  {
+    arr[2] = arr[1];
+  }
+  // CHECK-3: test3
+  // CHECK-3: alloca [5 x i32]
+  // CHECK-3: call void @__captured_stmt
+}
+
+void dont_capture_global() {
+  static int s;
+  extern int e;
+  #pragma clang __debug captured
+  {
+    global++;
+    s++;
+    e++;
+  }
+
+  // CHECK-GLOBALS: %[[Capture:struct\.anon[\.0-9]*]] = type {}
+  // CHECK-GLOBALS: call void @__captured_stmt[[HelperName:[0-9]+]](%[[Capture]]
+}
+
+// CHECK-GLOBALS: define internal void @__captured_stmt[[HelperName]]
+// CHECK-GLOBALS-NOT: ret
+// CHECK-GLOBALS:   load i32* @global
+// CHECK-GLOBALS:   load i32* @
+// CHECK-GLOBALS:   load i32* @e
Index: test/CodeGenCXX/captured-statements.cpp
===================================================================
--- /dev/null
+++ test/CodeGenCXX/captured-statements.cpp
@@ -0,0 +1,97 @@
+// RUN: %clang_cc1 -std=c++11 -emit-llvm %s -o %t
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-1
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-2
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-3
+// RUN: FileCheck %s -input-file=%t -check-prefix=CHECK-4
+
+struct Foo {
+  int x;
+  float y;
+  ~Foo() {}
+};
+
+struct TestClass {
+  int x;
+
+  TestClass() : x(0) {};
+  void MemberFunc() {
+    Foo f;
+    #pragma clang __debug captured
+    {
+      f.y = x;
+    }
+  }
+};
+
+void test1() {
+  TestClass c;
+  c.MemberFunc();
+  // CHECK-1: %[[Capture:struct\.anon[\.0-9]*]] = type { %struct.Foo*, %struct.TestClass* }
+
+  // CHECK-1: define {{.*}} void @_ZN9TestClass10MemberFuncEv
+  // CHECK-1:   alloca %struct.anon
+  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 0
+  // CHECK-1:   store %struct.Foo* %f, %struct.Foo**
+  // CHECK-1:   getelementptr inbounds %[[Capture]]* %{{[^,]*}}, i32 0, i32 1
+  // CHECK-1:   call void @[[HelperName:[A-Za-z0-9_]+]](%[[Capture]]*
+  // CHECK-1:   call void @_ZN3FooD1Ev
+  // CHECK-1:   ret
+}
+
+// CHECK-1: define internal void @[[HelperName]]
+// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 1
+// CHECK-1:   getelementptr inbounds %struct.TestClass* {{[^,]*}}, i32 0, i32 0
+// CHECK-1:   getelementptr inbounds %[[Capture]]* {{[^,]*}}, i32 0, i32 0
+
+void test2(int x) {
+  int y = [&]() {
+    #pragma clang __debug captured
+    {
+      x++;
+    }
+    return x;
+  }();
+
+  // CHECK-2: define void @_Z5test2i
+  // CHECK-2:   call i32 @[[Lambda:["$\w]+]]
+  //
+  // CHECK-2: define internal i32 @[[Lambda]]
+  // CHECK-2:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
+  //
+  // CHECK-2: define internal void @[[HelperName]]
+  // CHECK-2:   getelementptr inbounds %[[Capture]]*
+  // CHECK-2:   load i32**
+  // CHECK-2:   load i32*
+}
+
+void test3(int x) {
+  #pragma clang __debug captured
+  {
+    x = [=]() { return x + 1; } ();
+  }
+
+  // CHECK-3: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }
+
+  // CHECK-3: define void @_Z5test3i(i32 %x)
+  // CHECK-3:   store i32*
+  // CHECK-3:   call void @{{.*}}__captured_stmt
+  // CHECK-3:   ret void
+}
+
+void test4() {
+  #pragma clang __debug captured
+  {
+    Foo f;
+    f.x = 5;
+  }
+  // CHECK-4: %[[Capture:struct\.anon[\.0-9]*]] = type { i32* }
+
+  // CHECK-4: define void @_Z5test3i(i32 %x)
+  // CHECK-4:   store i32*
+  // CHECK-4:   call void @[[HelperName:["$_A-Za-z0-9]+]](%[[Capture:.*]]*
+  // CHECK-4:   ret void
+  //
+  // CHECK-4: define internal void @[[HelperName]]
+  // CHECK-4:   store i32 5, i32*
+  // CHECK-4:   call void @{{.*}}FooD1Ev(%struct.Foo*
+}
Index: test/Sema/captured-statements.c
===================================================================
--- test/Sema/captured-statements.c
+++ test/Sema/captured-statements.c
@@ -49,29 +49,29 @@
 }
 
 void test_nest_block() {
-  __block int x;
+  __block int x; // expected-note {{'x' declared here}}
   int y;
   ^{
     int z;
     #pragma clang __debug captured
     {
-      x = y; // OK
+      x = y; // expected-error{{__block variable 'x' cannot be captured in a captured statement}}
       y = z; // expected-error{{variable is not assignable (missing __block type specifier)}}
       z = y; // OK
     }
   }();
 
-  __block int a;
+  __block int a; // expected-note 2 {{'a' declared here}}
   int b;
   #pragma clang __debug captured
   {
     __block int c;
     int d;
     ^{
-      a = b; // OK
-      a = c; // OK
+      a = b; // expected-error{{__block variable 'a' cannot be captured in a captured statement}}
       b = d; // OK - Consistent with block inside a lambda
-      c = a; // OK
+      c = a; // expected-error{{__block variable 'a' cannot be captured in a captured statement}}
+      c = d; // OK
       d = b; // expected-error{{variable is not assignable (missing __block type specifier)}}
     }();
   }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to