Block API patch to do copy ctor of copied-in cxx objects in
copy helper function and dtor of copied cxx objects
in dispose helper functions. __block variables
TBD next.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119011 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
index 3364687..b186c96 100644
--- a/lib/CodeGen/CGBlocks.cpp
+++ b/lib/CodeGen/CGBlocks.cpp
@@ -112,8 +112,11 @@
     }
 
     // Only Decls that escape are added.
-    if (!Info.InnerBlocks.count(D->getDeclContext()))
+    if (!Info.InnerBlocks.count(D->getDeclContext())) {
+      if (BDRE->getCopyConstructorExpr())
+        Info.HasCXXObject = true;
       Info.DeclRefs.push_back(BDRE);
+    }
   }
 
   // Make sure to capture implicit 'self' references due to super calls.
@@ -221,6 +224,9 @@
     // necessary, for example: { ^{ __block int i; ^{ i = 1; }(); }(); }
     if (Info.BlockHasCopyDispose)
       flags |= BLOCK_HAS_COPY_DISPOSE;
+    // This block may import a c++ object.
+    if (Info.HasCXXObject)
+      flags |= BLOCK_HAS_CXX_OBJ;
 
     // __isa
     C = CGM.getNSConcreteStackBlock();
@@ -312,9 +318,11 @@
 
       const BlockDeclRefExpr *BDRE = cast<BlockDeclRefExpr>(E);
       Note.RequiresCopying = BlockRequiresCopying(BDRE);
-      
+      Note.cxxvar_import = 
+        BDRE->getCopyConstructorExpr() ? BDRE : 0;
       const ValueDecl *VD = BDRE->getDecl();
       QualType T = VD->getType();
+
       if (BDRE->isByRef()) {
         Note.flag = BLOCK_FIELD_IS_BYREF;
         if (T.isObjCGCWeak())
@@ -1000,14 +1008,18 @@
         Srcv = Builder.CreateStructGEP(Srcv, index);
         Srcv = Builder.CreateBitCast(Srcv,
                                      llvm::PointerType::get(PtrToInt8Ty, 0));
-        Srcv = Builder.CreateLoad(Srcv);
-
         llvm::Value *Dstv = Builder.CreateStructGEP(DstObj, index);
-        Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty);
-
-        llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag);
-        llvm::Value *F = CGM.getBlockObjectAssign();
-        Builder.CreateCall3(F, Dstv, Srcv, N);
+        if (NoteForHelper[i].cxxvar_import) {
+          CGF.EmitSynthesizedCXXCopyCtor(Dstv, Srcv, 
+                                         NoteForHelper[i].cxxvar_import);
+        }
+        else {
+          Srcv = Builder.CreateLoad(Srcv);
+          Dstv = Builder.CreateBitCast(Dstv, PtrToInt8Ty);
+          llvm::Value *N = llvm::ConstantInt::get(CGF.Int32Ty, flag);
+          llvm::Value *F = CGM.getBlockObjectAssign();
+          Builder.CreateCall3(F, Dstv, Srcv, N);
+        }
       }
     }
   }
@@ -1063,7 +1075,7 @@
     PtrPtrT = llvm::PointerType::get(llvm::PointerType::get(T, 0), 0);
     SrcObj = Builder.CreateBitCast(SrcObj, PtrPtrT);
     SrcObj = Builder.CreateLoad(SrcObj);
-
+    EHScopeStack::stable_iterator CleanupDepth = CGF.EHStack.stable_begin();
     for (unsigned i=0; i < NoteForHelper.size(); ++i) {
       int flag = NoteForHelper[i].flag;
       int index = NoteForHelper[i].index;
@@ -1074,11 +1086,22 @@
         Srcv = Builder.CreateStructGEP(Srcv, index);
         Srcv = Builder.CreateBitCast(Srcv,
                                      llvm::PointerType::get(PtrToInt8Ty, 0));
-        Srcv = Builder.CreateLoad(Srcv);
-
-        BuildBlockRelease(Srcv, flag);
+        if (NoteForHelper[i].cxxvar_import) {
+          const BlockDeclRefExpr *BDRE = NoteForHelper[i].cxxvar_import;
+          const Expr *E = BDRE->getCopyConstructorExpr();
+          QualType ClassTy = E->getType();
+          QualType PtrClassTy = getContext().getPointerType(ClassTy);
+          const llvm::Type *t = CGM.getTypes().ConvertType(PtrClassTy);
+          Srcv = Builder.CreateBitCast(Srcv, t);
+          CGF.PushDestructorCleanup(ClassTy, Srcv);
+        }
+        else {
+          Srcv = Builder.CreateLoad(Srcv);
+          BuildBlockRelease(Srcv, flag);
+        }
       }
     }
+    CGF.PopCleanupBlocks(CleanupDepth);
   }
 
   CGF.FinishFunction();
diff --git a/lib/CodeGen/CGBlocks.h b/lib/CodeGen/CGBlocks.h
index ce721a4..a5f2aa9 100644
--- a/lib/CodeGen/CGBlocks.h
+++ b/lib/CodeGen/CGBlocks.h
@@ -122,6 +122,7 @@
   struct HelperInfo {
     int index;
     int flag;
+    const BlockDeclRefExpr *cxxvar_import;
     bool RequiresCopying;
   };
 
diff --git a/lib/CodeGen/CGClass.cpp b/lib/CodeGen/CGClass.cpp
index d5ecd9f..ae99e03 100644
--- a/lib/CodeGen/CGClass.cpp
+++ b/lib/CodeGen/CGClass.cpp
@@ -1151,6 +1151,64 @@
 }
 
 void
+CodeGenFunction::EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
+                                        llvm::Value *This, llvm::Value *Src,
+                                        CallExpr::const_arg_iterator ArgBeg,
+                                        CallExpr::const_arg_iterator ArgEnd) {
+  if (D->isTrivial()) {
+    assert(ArgBeg + 1 == ArgEnd && "unexpected argcount for trivial ctor");
+    assert(D->isCopyConstructor() && "trivial 1-arg ctor not a copy ctor");
+    EmitAggregateCopy(This, Src, (*ArgBeg)->getType());
+    return;
+  }
+  llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(D, 
+                                                    clang::Ctor_Complete);
+  assert(D->isInstance() &&
+         "Trying to emit a member call expr on a static method!");
+  
+  const FunctionProtoType *FPT = D->getType()->getAs<FunctionProtoType>();
+  
+  CallArgList Args;
+  
+  // Push the this ptr.
+  Args.push_back(std::make_pair(RValue::get(This),
+                                D->getThisType(getContext())));
+  
+  
+  // Push the src ptr.
+  QualType QT = *(FPT->arg_type_begin());
+  const llvm::Type *t = CGM.getTypes().ConvertType(QT);
+  Src = Builder.CreateBitCast(Src, t);
+  Args.push_back(std::make_pair(RValue::get(Src), QT));
+  
+  // Skip over first argument (Src).
+  ++ArgBeg;
+  CallExpr::const_arg_iterator Arg = ArgBeg;
+  for (FunctionProtoType::arg_type_iterator I = FPT->arg_type_begin()+1,
+       E = FPT->arg_type_end(); I != E; ++I, ++Arg) {
+    assert(Arg != ArgEnd && "Running over edge of argument list!");
+    QualType ArgType = *I;
+    Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
+                                  ArgType));
+  }
+  // Either we've emitted all the call args, or we have a call to a
+  // variadic function.
+  assert((Arg == ArgEnd || FPT->isVariadic()) &&
+         "Extra arguments in non-variadic function!");
+  // If we still have any arguments, emit them using the type of the argument.
+  for (; Arg != ArgEnd; ++Arg) {
+    QualType ArgType = Arg->getType();
+    Args.push_back(std::make_pair(EmitCallArg(*Arg, ArgType),
+                                  ArgType));
+  }
+  
+  QualType ResultType = FPT->getResultType();
+  EmitCall(CGM.getTypes().getFunctionInfo(ResultType, Args,
+                                          FPT->getExtInfo()),
+                  Callee, ReturnValueSlot(), Args, D);
+}
+
+void
 CodeGenFunction::EmitDelegateCXXConstructorCall(const CXXConstructorDecl *Ctor,
                                                 CXXCtorType CtorType,
                                                 const FunctionArgList &Args) {
diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp
index a03a1fe..137c54a 100644
--- a/lib/CodeGen/CGExprCXX.cpp
+++ b/lib/CodeGen/CGExprCXX.cpp
@@ -341,6 +341,33 @@
   }
 }
 
+void
+CodeGenFunction::EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, 
+                                            llvm::Value *Src,
+                                            const BlockDeclRefExpr *BDRE) {
+  const Expr *Exp = BDRE->getCopyConstructorExpr();
+  if (const CXXExprWithTemporaries *E = dyn_cast<CXXExprWithTemporaries>(Exp))
+    Exp = E->getSubExpr();
+  assert(isa<CXXConstructExpr>(Exp) && 
+         "EmitSynthesizedCXXCopyCtor - unknown copy ctor expr");
+  const CXXConstructExpr* E = cast<CXXConstructExpr>(Exp);
+  const CXXConstructorDecl *CD = E->getConstructor();
+  RunCleanupsScope Scope(*this);
+  
+  // If we require zero initialization before (or instead of) calling the
+  // constructor, as can be the case with a non-user-provided default
+  // constructor, emit the zero initialization now.
+  // FIXME. Do I still need this for a copy ctor synthesis?
+  if (E->requiresZeroInitialization())
+    EmitNullInitialization(Dest, E->getType());
+  
+  const ConstantArrayType *Array 
+    = getContext().getAsConstantArrayType(E->getType());
+  assert (!Array && "EmitSynthesizedCXXCopyCtor - Copied-in Array");
+  EmitSynthesizedCXXCopyCtorCall(CD, Dest, Src,
+                                 E->arg_begin(), E->arg_end());
+}
+
 /// Check whether the given operator new[] is the global placement
 /// operator new[].
 static bool IsPlacementOperatorNewArray(ASTContext &Ctx,
diff --git a/lib/CodeGen/CodeGenFunction.h b/lib/CodeGen/CodeGenFunction.h
index 1898c08..2e9feef 100644
--- a/lib/CodeGen/CodeGenFunction.h
+++ b/lib/CodeGen/CodeGenFunction.h
@@ -1171,6 +1171,11 @@
                               bool ForVirtualBase, llvm::Value *This,
                               CallExpr::const_arg_iterator ArgBeg,
                               CallExpr::const_arg_iterator ArgEnd);
+  
+  void EmitSynthesizedCXXCopyCtorCall(const CXXConstructorDecl *D,
+                              llvm::Value *This, llvm::Value *Src,
+                              CallExpr::const_arg_iterator ArgBeg,
+                              CallExpr::const_arg_iterator ArgEnd);
 
   void EmitCXXAggrConstructorCall(const CXXConstructorDecl *D,
                                   const ConstantArrayType *ArrayTy,
@@ -1651,6 +1656,9 @@
                                         llvm::GlobalVariable *Addr);
 
   void EmitCXXConstructExpr(const CXXConstructExpr *E, AggValueSlot Dest);
+  
+  void EmitSynthesizedCXXCopyCtor(llvm::Value *Dest, llvm::Value *Src,
+                                  const BlockDeclRefExpr *BDRE);
 
   RValue EmitCXXExprWithTemporaries(const CXXExprWithTemporaries *E,
                                     AggValueSlot Slot
@@ -1799,10 +1807,14 @@
 
   /// NeedsObjCSelf - True if something in this block has an implicit
   /// reference to 'self'.
-  bool NeedsObjCSelf;
-
+  bool NeedsObjCSelf : 1;
+  
+  /// HasCXXObject - True if block has imported c++ object requiring copy
+  /// construction in copy helper and destruction in copy dispose helpers.
+  bool HasCXXObject : 1;
+  
   /// These are initialized by GenerateBlockFunction.
-  bool BlockHasCopyDispose;
+  bool BlockHasCopyDispose : 1;
   CharUnits BlockSize;
   CharUnits BlockAlign;
   llvm::SmallVector<const Expr*, 8> BlockLayout;
diff --git a/test/CodeGenCXX/cxx-block-objects.cpp b/test/CodeGenCXX/cxx-block-objects.cpp
new file mode 100644
index 0000000..b989065
--- /dev/null
+++ b/test/CodeGenCXX/cxx-block-objects.cpp
@@ -0,0 +1,33 @@
+// RUN: %clang_cc1 %s -fblocks -triple x86_64-apple-darwin -emit-llvm -o - | FileCheck %s
+// rdar://8594790
+
+extern "C" {
+extern "C" void *_Block_copy(const void *aBlock);
+extern "C" void _Block_release(const void *aBlock);
+}
+
+class A {
+public:
+        int x;
+        A(const A &o);
+        A();
+        virtual ~A();
+        void hello() const;
+};
+
+int
+main()
+{
+        A a;
+        void (^c)(void) = ((__typeof(^{ a.hello(); }))_Block_copy((const void *)(^{ a.hello(); })));
+        c();
+        _Block_release((const void *)(c));
+        return 0;
+}
+
+// CHECK: define internal void @__copy_helper_block_
+// CHECK: call void @_ZN1AC1ERKS_
+
+
+// CHECK:define internal void @__destroy_helper_block_
+// CHECK: call void @_ZN1AD1Ev