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