diff options
author | Fariborz Jahanian <fjahanian@apple.com> | 2012-11-28 23:12:17 +0000 |
---|---|---|
committer | Fariborz Jahanian <fjahanian@apple.com> | 2012-11-28 23:12:17 +0000 |
commit | b15c8984ea300624fbbde385d3907667ce1043fa (patch) | |
tree | 81bea997c8078dba2e7a52181299f2df85b0dfd2 | |
parent | a70c3f8738cc123ded68c183cedd6e93df670c2f (diff) |
objective-C blocks: Make sure that identical logic is used
in deciding a copy/dispose field is needed in a byref structure
and when generating the copy/dispose helpers. In certain
cases, these fields were being added but no copy/dispose was
being generated. This was uncovered in ARC, but not in MRR.
// rdar://12759433
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@168825 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 112 | ||||
-rw-r--r-- | lib/CodeGen/CGBlocks.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.cpp | 4 | ||||
-rw-r--r-- | lib/CodeGen/CGDebugInfo.h | 2 | ||||
-rw-r--r-- | lib/Rewrite/Frontend/RewriteModernObjC.cpp | 2 | ||||
-rw-r--r-- | lib/Rewrite/Frontend/RewriteObjC.cpp | 2 | ||||
-rw-r--r-- | test/CodeGenObjC/block-byref-variable-layout.m | 9 |
8 files changed, 53 insertions, 88 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 1503090dd5..b7d3f1fbcc 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -860,11 +860,8 @@ public: return cudaConfigureCallDecl; } - /// Builds the struct used for __block variables. - QualType BuildByRefType(StringRef DeclName, QualType Ty) const; - /// Returns true iff we need copy/dispose helpers for the given type. - bool BlockRequiresCopying(QualType Ty) const; + bool BlockRequiresCopying(QualType Ty, const VarDecl *D); /// Returns true, if given type has a known lifetime. HasByrefExtendedLayout is set diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c4dbf5d46f..7fee560534 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -4361,17 +4361,45 @@ QualType ASTContext::getBlockDescriptorExtendedType() const { return getTagDeclType(BlockDescriptorExtendedType); } -bool ASTContext::BlockRequiresCopying(QualType Ty) const { - if (Ty->isObjCRetainableType()) +/// BlockRequiresCopying - Returns true if byref variable "D" of type "Ty" +/// requires copy/dispose. Note that this must match the logic +/// in buildByrefHelpers. +bool ASTContext::BlockRequiresCopying(QualType Ty, + const VarDecl *D) { + if (const CXXRecordDecl *record = Ty->getAsCXXRecordDecl()) { + const Expr *copyExpr = getBlockVarCopyInits(D); + if (!copyExpr && record->hasTrivialDestructor()) return false; + return true; - if (getLangOpts().CPlusPlus) { - if (const RecordType *RT = Ty->getAs<RecordType>()) { - CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); - return RD->hasConstCopyConstructor(); - + } + + if (!Ty->isObjCRetainableType()) return false; + + Qualifiers qs = Ty.getQualifiers(); + + // If we have lifetime, that dominates. + if (Qualifiers::ObjCLifetime lifetime = qs.getObjCLifetime()) { + assert(getLangOpts().ObjCAutoRefCount); + + switch (lifetime) { + case Qualifiers::OCL_None: llvm_unreachable("impossible"); + + // These are just bits as far as the runtime is concerned. + case Qualifiers::OCL_ExplicitNone: + case Qualifiers::OCL_Autoreleasing: + return false; + + // Tell the runtime that this is ARC __weak, called by the + // byref routines. + case Qualifiers::OCL_Weak: + // ARC __strong __block variables need to be retained. + case Qualifiers::OCL_Strong: + return true; } + llvm_unreachable("fell out of lifetime switch!"); } - return false; + return (Ty->isBlockPointerType() || isObjCNSObjectType(Ty) || + Ty->isObjCObjectPointerType()); } bool ASTContext::getByrefLifetime(QualType Ty, @@ -4397,74 +4425,6 @@ bool ASTContext::getByrefLifetime(QualType Ty, return true; } -QualType -ASTContext::BuildByRefType(StringRef DeclName, QualType Ty) const { - // type = struct __Block_byref_1_X { - // void *__isa; - // struct __Block_byref_1_X *__forwarding; - // unsigned int __flags; - // unsigned int __size; - // void *__copy_helper; // as needed - // void *__destroy_help // as needed - // void *__byref_variable_layout; // Extended layout info. for byref variable as needed - // int X; - // } * - - bool HasCopyAndDispose = BlockRequiresCopying(Ty); - bool HasByrefExtendedLayout; - Qualifiers::ObjCLifetime Lifetime; - - // FIXME: Move up - SmallString<36> Name; - llvm::raw_svector_ostream(Name) << "__Block_byref_" << - ++UniqueBlockByRefTypeID << '_' << DeclName; - RecordDecl *T; - T = CreateRecordDecl(*this, TTK_Struct, TUDecl, &Idents.get(Name.str())); - T->startDefinition(); - QualType Int32Ty = IntTy; - assert(getIntWidth(IntTy) == 32 && "non-32bit int not supported"); - QualType FieldTypes[] = { - getPointerType(VoidPtrTy), - getPointerType(getTagDeclType(T)), - Int32Ty, - Int32Ty, - getPointerType(VoidPtrTy), - getPointerType(VoidPtrTy), - getPointerType(VoidPtrTy), - Ty - }; - - StringRef FieldNames[] = { - "__isa", - "__forwarding", - "__flags", - "__size", - "__copy_helper", - "__destroy_helper", - "__byref_variable_layout", - DeclName, - }; - bool ByrefKnownLifetime = getByrefLifetime(Ty, Lifetime, HasByrefExtendedLayout); - for (size_t i = 0; i < 8; ++i) { - if (!HasCopyAndDispose && i >=4 && i <= 5) - continue; - if ((!ByrefKnownLifetime || !HasByrefExtendedLayout) && i == 6) - continue; - FieldDecl *Field = FieldDecl::Create(*this, T, SourceLocation(), - SourceLocation(), - &Idents.get(FieldNames[i]), - FieldTypes[i], /*TInfo=*/0, - /*BitWidth=*/0, /*Mutable=*/false, - ICIS_NoInit); - Field->setAccess(AS_public); - T->addDecl(Field); - } - - T->completeDefinition(); - - return getPointerType(getTagDeclType(T)); -} - TypedefDecl *ASTContext::getObjCInstanceTypeDecl() { if (!ObjCInstanceTypeDecl) ObjCInstanceTypeDecl = TypedefDecl::Create(*this, diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp index 06fd624759..3302221fc8 100644 --- a/lib/CodeGen/CGBlocks.cpp +++ b/lib/CodeGen/CGBlocks.cpp @@ -1922,9 +1922,8 @@ llvm::Type *CodeGenFunction::BuildByRefType(const VarDecl *D) { // int32_t __size; types.push_back(Int32Ty); - - bool HasCopyAndDispose = - (Ty->isObjCRetainableType()) || getContext().getBlockVarCopyInits(D); + // Note that this must match *exactly* the logic in buildByrefHelpers. + bool HasCopyAndDispose = getContext().BlockRequiresCopying(Ty, D); if (HasCopyAndDispose) { /// void *__copy_helper; types.push_back(Int8PtrTy); diff --git a/lib/CodeGen/CGDebugInfo.cpp b/lib/CodeGen/CGDebugInfo.cpp index 8a66dff3d2..96cfd28e54 100644 --- a/lib/CodeGen/CGDebugInfo.cpp +++ b/lib/CodeGen/CGDebugInfo.cpp @@ -2229,7 +2229,7 @@ void CGDebugInfo::EmitFunctionEnd(CGBuilderTy &Builder) { // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. // See BuildByRefType. -llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, +llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *XOffset) { SmallVector<llvm::Value *, 5> EltTys; @@ -2248,7 +2248,7 @@ llvm::DIType CGDebugInfo::EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, EltTys.push_back(CreateMemberType(Unit, FType, "__flags", &FieldOffset)); EltTys.push_back(CreateMemberType(Unit, FType, "__size", &FieldOffset)); - bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type); + bool HasCopyAndDispose = CGM.getContext().BlockRequiresCopying(Type, VD); if (HasCopyAndDispose) { FType = CGM.getContext().getPointerType(CGM.getContext().VoidTy); EltTys.push_back(CreateMemberType(Unit, FType, "__copy_helper", diff --git a/lib/CodeGen/CGDebugInfo.h b/lib/CodeGen/CGDebugInfo.h index efa6b86d86..99f29e8323 100644 --- a/lib/CodeGen/CGDebugInfo.h +++ b/lib/CodeGen/CGDebugInfo.h @@ -243,7 +243,7 @@ private: // EmitTypeForVarWithBlocksAttr - Build up structure info for the byref. // See BuildByRefType. - llvm::DIType EmitTypeForVarWithBlocksAttr(const ValueDecl *VD, + llvm::DIType EmitTypeForVarWithBlocksAttr(const VarDecl *VD, uint64_t *OffSet); /// getContextDescriptor - Get context info for the decl. diff --git a/lib/Rewrite/Frontend/RewriteModernObjC.cpp b/lib/Rewrite/Frontend/RewriteModernObjC.cpp index 4b56b3720a..19acb94925 100644 --- a/lib/Rewrite/Frontend/RewriteModernObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteModernObjC.cpp @@ -5053,7 +5053,7 @@ void RewriteModernObjC::RewriteByRefVar(VarDecl *ND, bool firstDecl, // Add void *__Block_byref_id_object_copy; // void *__Block_byref_id_object_dispose; if needed. QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND); if (HasCopyAndDispose) { ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; diff --git a/lib/Rewrite/Frontend/RewriteObjC.cpp b/lib/Rewrite/Frontend/RewriteObjC.cpp index a6dcc6b8d8..982c730d28 100644 --- a/lib/Rewrite/Frontend/RewriteObjC.cpp +++ b/lib/Rewrite/Frontend/RewriteObjC.cpp @@ -4309,7 +4309,7 @@ void RewriteObjC::RewriteByRefVar(VarDecl *ND) { // Add void *__Block_byref_id_object_copy; // void *__Block_byref_id_object_dispose; if needed. QualType Ty = ND->getType(); - bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty); + bool HasCopyAndDispose = Context->BlockRequiresCopying(Ty, ND); if (HasCopyAndDispose) { ByrefType += " void (*__Block_byref_id_object_copy)(void*, void*);\n"; ByrefType += " void (*__Block_byref_id_object_dispose)(void*);\n"; diff --git a/test/CodeGenObjC/block-byref-variable-layout.m b/test/CodeGenObjC/block-byref-variable-layout.m index 1e8bcbc11b..6030661af4 100644 --- a/test/CodeGenObjC/block-byref-variable-layout.m +++ b/test/CodeGenObjC/block-byref-variable-layout.m @@ -1,5 +1,14 @@ // RUN: %clang_cc1 -fblocks -fobjc-arc -fobjc-runtime-has-weak -triple x86_64-apple-darwin -O0 -emit-llvm %s -o - | FileCheck %s +// rdar://12759433 +@class NSString; + +void Test12759433() { + __block __unsafe_unretained NSString *uuByref = (__bridge NSString *)(void*)0x102030405060708; + void (^block)() = ^{ uuByref = 0; }; + block(); +} +// CHECK: %struct.__block_byref_uuByref = type { i8*, %struct.__block_byref_uuByref*, i32, i32, [[ZERO:%.*]]* } int main() { __block __weak id wid; __block long XXX; |