From: Fariborz Jahanian Date: Tue, 12 May 2009 18:14:29 +0000 (+0000) Subject: Patch to implement ivar synthesis of properties declared in protocols X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9820074dd47d37681085e964cd3392ac0b3e67b9;p=clang Patch to implement ivar synthesis of properties declared in protocols only and used in class imllementations (objc2 Nonfragile ABI specific). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71571 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 8b4c89b6e8..335fc40aea 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -535,6 +535,11 @@ public: void CollectObjCIvars(const ObjCInterfaceDecl *OI, llvm::SmallVectorImpl &Fields); + + void CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl &Ivars); + void CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, + llvm::SmallVectorImpl &Ivars); //===--------------------------------------------------------------------===// // Type Operators diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 52eadef75a..ac46180b94 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -685,6 +685,38 @@ void ASTContext::CollectObjCIvars(const ObjCInterfaceDecl *OI, CollectLocalObjCIvars(this, OI, Fields); } +void ASTContext::CollectProtocolSynthesizedIvars(const ObjCProtocolDecl *PD, + llvm::SmallVectorImpl &Ivars) { + for (ObjCContainerDecl::prop_iterator I = PD->prop_begin(*this), + E = PD->prop_end(*this); I != E; ++I) + if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) + Ivars.push_back(Ivar); + + // Also look into nested protocols. + for (ObjCProtocolDecl::protocol_iterator P = PD->protocol_begin(), + E = PD->protocol_end(); P != E; ++P) + CollectProtocolSynthesizedIvars(*P, Ivars); +} + +/// CollectSynthesizedIvars - +/// This routine collect synthesized ivars for the designated class. +/// +void ASTContext::CollectSynthesizedIvars(const ObjCInterfaceDecl *OI, + llvm::SmallVectorImpl &Ivars) { + for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(*this), + E = OI->prop_end(*this); I != E; ++I) { + if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) + Ivars.push_back(Ivar); + } + // Also look into interface's protocol list for properties declared + // in the protocol and whose ivars are synthesized. + for (ObjCInterfaceDecl::protocol_iterator P = OI->protocol_begin(), + PE = OI->protocol_end(); P != PE; ++P) { + ObjCProtocolDecl *PD = (*P); + CollectProtocolSynthesizedIvars(PD, Ivars); + } +} + /// getInterfaceLayoutImpl - Get or compute information about the /// layout of the given interface. /// @@ -704,11 +736,9 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, unsigned FieldCount = D->ivar_size(); // Add in synthesized ivar count if laying out an implementation. if (Impl) { - for (ObjCInterfaceDecl::prop_iterator I = D->prop_begin(*this), - E = D->prop_end(*this); I != E; ++I) - if ((*I)->getPropertyIvarDecl()) - ++FieldCount; - + llvm::SmallVector Ivars; + CollectSynthesizedIvars(D, Ivars); + FieldCount += Ivars.size(); // If there aren't any sythesized ivars then reuse the interface // entry. Note we can't cache this because we simply free all // entries later; however we shouldn't look up implementations @@ -750,11 +780,11 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D, } // And synthesized ivars, if this is an implementation. if (Impl) { - for (ObjCInterfaceDecl::prop_iterator I = D->prop_begin(*this), - E = D->prop_end(*this); I != E; ++I) { - if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) - NewEntry->LayoutField(Ivar, i++, false, StructPacking, *this); - } + // FIXME. Do we need to colltect twice? + llvm::SmallVector Ivars; + CollectSynthesizedIvars(D, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + NewEntry->LayoutField(Ivars[k], i++, false, StructPacking, *this); } // Finally, round the size of the total struct up to the alignment of the diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp index 9d57fcb786..9418d0a255 100644 --- a/lib/CodeGen/CGObjCMac.cpp +++ b/lib/CodeGen/CGObjCMac.cpp @@ -53,15 +53,14 @@ static const ObjCInterfaceDecl *FindIvarInterface(ASTContext &Context, return OID; // Also look in synthesized ivars. - for (ObjCInterfaceDecl::prop_iterator I = OID->prop_begin(Context), - E = OID->prop_end(Context); I != E; ++I) { - if (ObjCIvarDecl *Ivar = (*I)->getPropertyIvarDecl()) { - if (OIVD == Ivar) - return OID; - ++Index; - } + llvm::SmallVector Ivars; + Context.CollectSynthesizedIvars(OID, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) { + if (OIVD == Ivars[k]) + return OID; + ++Index; } - + // Otherwise check in the super class. if (const ObjCInterfaceDecl *Super = OID->getSuperClass()) return FindIvarInterface(Context, Super, OIVD, Index); @@ -3153,14 +3152,13 @@ llvm::Constant *CGObjCCommonMac::BuildIvarLayout( llvm::SmallVector RecFields; const ObjCInterfaceDecl *OI = OMD->getClassInterface(); CGM.getContext().CollectObjCIvars(OI, RecFields); - + // Add this implementations synthesized ivars. - for (ObjCInterfaceDecl::prop_iterator I = OI->prop_begin(CGM.getContext()), - E = OI->prop_end(CGM.getContext()); I != E; ++I) { - if (ObjCIvarDecl *IV = (*I)->getPropertyIvarDecl()) - RecFields.push_back(cast(IV)); - } - + llvm::SmallVector Ivars; + CGM.getContext().CollectSynthesizedIvars(OI, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + RecFields.push_back(cast(Ivars[k])); + if (RecFields.empty()) return llvm::Constant::getNullValue(PtrTy); @@ -4677,10 +4675,12 @@ void CGObjCCommonMac::GetNamedIvarList(const ObjCInterfaceDecl *OID, Res.push_back(*I); } - for (ObjCInterfaceDecl::prop_iterator I = OID->prop_begin(CGM.getContext()), - E = OID->prop_end(CGM.getContext()); I != E; ++I) - if (ObjCIvarDecl *IV = (*I)->getPropertyIvarDecl()) - Res.push_back(IV); + // Also save synthesize ivars. + // FIXME. Why can't we just use passed in Res small vector? + llvm::SmallVector Ivars; + CGM.getContext().CollectSynthesizedIvars(OID, Ivars); + for (unsigned k = 0, e = Ivars.size(); k != e; ++k) + Res.push_back(Ivars[k]); } llvm::Constant *CGObjCNonFragileABIMac::EmitIvarList( diff --git a/test/CodeGenObjC/protocol-property-synth.m b/test/CodeGenObjC/protocol-property-synth.m new file mode 100644 index 0000000000..e91f355231 --- /dev/null +++ b/test/CodeGenObjC/protocol-property-synth.m @@ -0,0 +1,33 @@ +// RUN: clang-cc -triple x86_64-apple-darwin10 -emit-llvm -o %t %s + +@interface BaseClass { + id _delegate; +} +@end + +@protocol MyProtocol +@optional +@property(assign) id delegate; +@end + +@protocol AnotherProtocol +@optional +@property(assign) id myanother; +@end + +@protocol SubProtocol +@property(assign) id another; +@end + +@interface SubClass : BaseClass { +} + +@end + +@implementation BaseClass @end + +@implementation SubClass +@synthesize delegate = _Subdelegate; +@synthesize another; +@synthesize myanother; +@end