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 /lib/AST/ASTContext.cpp | |
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
Diffstat (limited to 'lib/AST/ASTContext.cpp')
-rw-r--r-- | lib/AST/ASTContext.cpp | 112 |
1 files changed, 36 insertions, 76 deletions
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, |