diff --git a/clang/include/clang/CodeGen/CodeGenABITypes.h b/clang/include/clang/CodeGen/CodeGenABITypes.h --- a/clang/include/clang/CodeGen/CodeGenABITypes.h +++ b/clang/include/clang/CodeGen/CodeGenABITypes.h @@ -28,6 +28,7 @@ #include "clang/CodeGen/CGFunctionInfo.h" namespace llvm { + class Constant; class DataLayout; class Module; class Function; @@ -44,6 +45,7 @@ class DiagnosticsEngine; class HeaderSearchOptions; class ObjCMethodDecl; +class ObjCProtocolDecl; class PreprocessorOptions; namespace CodeGen { @@ -137,6 +139,17 @@ CharUnits DstAlignment, bool IsVolatile, QualType QT); +/// Get a pointer to a protocol object for the given declaration, emitting it if +/// it hasn't already been emitted in this translation unit. Note that the ABI +/// for emitting a protocol reference in code (e.g. for a @protocol expression) +/// in most runtimes is not as simple as just materializing a pointer to this +/// object. +/// \p createProtocolReference is called by the implementation when the protocol +/// \p p references another protocol. +llvm::Constant *emitObjCProtocolObject( + CodeGenModule &CGM, const ObjCProtocolDecl *p, + llvm::function_ref + createProtocolReference); } // end namespace CodeGen } // end namespace clang diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp --- a/clang/lib/CodeGen/CGObjCGNU.cpp +++ b/clang/lib/CodeGen/CGObjCGNU.cpp @@ -617,6 +617,11 @@ llvm::Value *GenerateProtocolRef(CodeGenFunction &CGF, const ObjCProtocolDecl *PD) override; void GenerateProtocol(const ObjCProtocolDecl *PD) override; + + llvm::Constant *getOrEmitProtocol( + const ObjCProtocolDecl *OPD, + llvm::function_ref + createProtocolReference) override; llvm::Function *ModuleInitFunction() override; llvm::FunctionCallee GetPropertyGetFunction() override; llvm::FunctionCallee GetPropertySetFunction() override; @@ -3048,6 +3053,13 @@ return CGF.Builder.CreateBitCast(protocol, llvm::PointerType::getUnqual(T)); } +llvm::Constant *CGObjCGNU::getOrEmitProtocol( + const ObjCProtocolDecl *PD, + llvm::function_ref + createProtocolReference) { + llvm_unreachable("not implemented"); +} + llvm::Constant * CGObjCGNU::GenerateEmptyProtocol(StringRef ProtocolName) { llvm::Constant *ProtocolList = GenerateProtocolList({}); diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp --- a/clang/lib/CodeGen/CGObjCMac.cpp +++ b/clang/lib/CodeGen/CGObjCMac.cpp @@ -1110,7 +1110,7 @@ /// GetOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type /// ProtocolPtrTy. - virtual llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD)=0; + llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD); /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These @@ -1288,10 +1288,15 @@ llvm::Constant *emitMethodList(Twine Name, MethodListType MLT, ArrayRef Methods); - /// GetOrEmitProtocol - Get the protocol object for the given + /// getOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type /// ProtocolPtrTy. - llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override; + /// \p getProtocolReference is called by the implementation when a + /// reference to another protocol is needed. + llvm::Constant *getOrEmitProtocol( + const ObjCProtocolDecl *OPD, + llvm::function_ref + getProtocolReference) override; /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These @@ -1309,9 +1314,11 @@ /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(Twine Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end); + llvm::Constant *EmitProtocolList( + Twine Name, ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end, + llvm::function_ref + getProtocolRef); /// EmitSelector - Return a Value*, of type ObjCTypes.SelectorPtrTy, /// for the given selector. @@ -1471,10 +1478,15 @@ const ObjCIvarDecl *Ivar, unsigned long int offset); - /// GetOrEmitProtocol - Get the protocol object for the given + /// getOrEmitProtocol - Get the protocol object for the given /// declaration, emitting it if necessary. The return value has type /// ProtocolPtrTy. - llvm::Constant *GetOrEmitProtocol(const ObjCProtocolDecl *PD) override; + /// \p getProtocolReference is called by the implementation when a + /// reference to another protocol is needed. + llvm::Constant *getOrEmitProtocol( + const ObjCProtocolDecl *OPD, + llvm::function_ref + createProtocolReference) override; /// GetOrEmitProtocolRef - Get a forward reference to the protocol /// object for the given declaration, emitting it if needed. These @@ -1484,9 +1496,11 @@ /// EmitProtocolList - Generate the list of referenced /// protocols. The return value has type ProtocolListPtrTy. - llvm::Constant *EmitProtocolList(Twine Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end); + llvm::Constant *EmitProtocolList( + Twine Name, ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end, + llvm::function_ref + getProtocolRef); CodeGen::RValue EmitVTableMessageSend(CodeGen::CodeGenFunction &CGF, ReturnValueSlot Return, @@ -3040,6 +3054,13 @@ return GetOrEmitProtocolRef(PD); } +llvm::Constant *CGObjCCommonMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { + return getOrEmitProtocol( + PD, [this](const ObjCProtocolDecl *p) -> llvm::Constant * { + return this->GetProtocolRef(p); + }); +} + llvm::Value *CGObjCCommonMac::EmitClassRefViaRuntime( CodeGenFunction &CGF, const ObjCInterfaceDecl *ID, @@ -3072,7 +3093,10 @@ See EmitProtocolExtension(). */ -llvm::Constant *CGObjCMac::GetOrEmitProtocol(const ObjCProtocolDecl *PD) { +llvm::Constant *CGObjCMac::getOrEmitProtocol( + const ObjCProtocolDecl *PD, + llvm::function_ref + getProtocolRef) { llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()]; // Early exit if a defining object has already been generated. @@ -3095,7 +3119,8 @@ values.add(EmitProtocolExtension(PD, methodLists)); values.add(GetClassName(PD->getObjCRuntimeNameAsString())); values.add(EmitProtocolList("OBJC_PROTOCOL_REFS_" + PD->getName(), - PD->protocol_begin(), PD->protocol_end())); + PD->protocol_begin(), PD->protocol_end(), + getProtocolRef)); values.add(methodLists.emitMethodList(this, PD, ProtocolMethodLists::RequiredInstanceMethods)); values.add(methodLists.emitMethodList(this, PD, @@ -3202,10 +3227,11 @@ Protocol *list[]; }; */ -llvm::Constant * -CGObjCMac::EmitProtocolList(Twine name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end) { +llvm::Constant *CGObjCMac::EmitProtocolList( + Twine name, ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end, + llvm::function_ref + getProtocolRef) { // Just return null for empty protocol lists if (begin == end) return llvm::Constant::getNullValue(ObjCTypes.ProtocolListPtrTy); @@ -3221,7 +3247,11 @@ auto refsArray = values.beginArray(ObjCTypes.ProtocolPtrTy); for (; begin != end; ++begin) { - refsArray.add(GetProtocolRef(*begin)); + auto protocolRef = getProtocolRef(*begin); + if (protocolRef->getType() != ObjCTypes.ProtocolPtrTy) + protocolRef = + llvm::ConstantExpr::getBitCast(protocolRef, ObjCTypes.ProtocolPtrTy); + refsArray.add(protocolRef); } auto count = refsArray.size(); @@ -3421,7 +3451,10 @@ if (Category) { Values.add( EmitProtocolList("OBJC_CATEGORY_PROTOCOLS_" + ExtName.str(), - Category->protocol_begin(), Category->protocol_end())); + Category->protocol_begin(), Category->protocol_end(), + [this](const ObjCProtocolDecl *p) -> llvm::Constant * { + return this->GetProtocolRef(p); + })); } else { Values.addNullPointer(ObjCTypes.ProtocolListPtrTy); } @@ -3563,7 +3596,10 @@ llvm::Constant *Protocols = EmitProtocolList("OBJC_CLASS_PROTOCOLS_" + ID->getName(), Interface->all_referenced_protocol_begin(), - Interface->all_referenced_protocol_end()); + Interface->all_referenced_protocol_end(), + [this](const ObjCProtocolDecl *p) -> llvm::Constant * { + return this->GetProtocolRef(p); + }); unsigned Flags = FragileABI_Class_Factory; if (ID->hasNonZeroConstructors() || ID->hasDestructors()) Flags |= FragileABI_Class_HasCXXStructors; @@ -6423,10 +6459,12 @@ const ObjCInterfaceDecl *OID = ID->getClassInterface(); assert(OID && "CGObjCNonFragileABIMac::BuildClassRoTInitializer"); - values.add(EmitProtocolList("_OBJC_CLASS_PROTOCOLS_$_" - + OID->getObjCRuntimeNameAsString(), - OID->all_referenced_protocol_begin(), - OID->all_referenced_protocol_end())); + values.add(EmitProtocolList( + "_OBJC_CLASS_PROTOCOLS_$_" + OID->getObjCRuntimeNameAsString(), + OID->all_referenced_protocol_begin(), OID->all_referenced_protocol_end(), + [this](const ObjCProtocolDecl *p) -> llvm::Constant * { + return this->GetProtocolRef(p); + })); if (flags & NonFragileABI_Class_Meta) { values.addNullPointer(ObjCTypes.IvarListnfABIPtrTy); @@ -6753,11 +6791,14 @@ SmallString<256> ExtName; llvm::raw_svector_ostream(ExtName) << Interface->getObjCRuntimeNameAsString() << "_$_" << OCD->getName(); - values.add(EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" - + Interface->getObjCRuntimeNameAsString() + "_$_" - + Category->getName(), - Category->protocol_begin(), - Category->protocol_end())); + values.add( + EmitProtocolList("_OBJC_CATEGORY_PROTOCOLS_$_" + + Interface->getObjCRuntimeNameAsString() + "_$_" + + Category->getName(), + Category->protocol_begin(), Category->protocol_end(), + [this](const ObjCProtocolDecl *p) -> llvm::Constant * { + return this->GetProtocolRef(p); + })); values.add(EmitPropertyList("_OBJC_$_PROP_LIST_" + ExtName.str(), OCD, Category, ObjCTypes, false)); values.add(EmitPropertyList("_OBJC_$_CLASS_PROP_LIST_" + ExtName.str(), @@ -7050,7 +7091,7 @@ return Entry; } -/// GetOrEmitProtocol - Generate the protocol meta-data: +/// getOrEmitProtocol - Generate the protocol meta-data: /// @code /// struct _protocol_t { /// id isa; // NULL @@ -7070,8 +7111,10 @@ /// @endcode /// -llvm::Constant *CGObjCNonFragileABIMac::GetOrEmitProtocol( - const ObjCProtocolDecl *PD) { +llvm::Constant *CGObjCNonFragileABIMac::getOrEmitProtocol( + const ObjCProtocolDecl *PD, + llvm::function_ref + getProtocolRef) { llvm::GlobalVariable *Entry = Protocols[PD->getIdentifier()]; // Early exit if a defining object has already been generated. @@ -7091,10 +7134,9 @@ // isa is NULL values.addNullPointer(ObjCTypes.ObjectPtrTy); values.add(GetClassName(PD->getObjCRuntimeNameAsString())); - values.add(EmitProtocolList("_OBJC_$_PROTOCOL_REFS_" - + PD->getObjCRuntimeNameAsString(), - PD->protocol_begin(), - PD->protocol_end())); + values.add(EmitProtocolList( + "_OBJC_$_PROTOCOL_REFS_" + PD->getObjCRuntimeNameAsString(), + PD->protocol_begin(), PD->protocol_end(), getProtocolRef)); values.add(methodLists.emitMethodList(this, PD, ProtocolMethodLists::RequiredInstanceMethods)); values.add(methodLists.emitMethodList(this, PD, @@ -7171,10 +7213,11 @@ /// } /// @endcode /// -llvm::Constant * -CGObjCNonFragileABIMac::EmitProtocolList(Twine Name, - ObjCProtocolDecl::protocol_iterator begin, - ObjCProtocolDecl::protocol_iterator end) { +llvm::Constant *CGObjCNonFragileABIMac::EmitProtocolList( + Twine Name, ObjCProtocolDecl::protocol_iterator begin, + ObjCProtocolDecl::protocol_iterator end, + llvm::function_ref + getProtocolRef) { SmallVector ProtocolRefs; // Just return null for empty protocol lists @@ -7195,8 +7238,13 @@ // A null-terminated array of protocols. auto array = values.beginArray(ObjCTypes.ProtocolnfABIPtrTy); - for (; begin != end; ++begin) - array.add(GetProtocolRef(*begin)); // Implemented??? + for (; begin != end; ++begin) { + auto protocolRef = getProtocolRef(*begin); + if (protocolRef->getType() != ObjCTypes.ProtocolnfABIPtrTy) + protocolRef = llvm::ConstantExpr::getBitCast( + protocolRef, ObjCTypes.ProtocolnfABIPtrTy); + array.add(protocolRef); + } auto count = array.size(); array.addNullPointer(ObjCTypes.ProtocolnfABIPtrTy); diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -211,6 +211,16 @@ /// implementations. virtual void GenerateProtocol(const ObjCProtocolDecl *OPD) = 0; + /// getOrEmitProtocol - Get the protocol object for the given + /// declaration, emitting it if necessary. The return value has type + /// ProtocolPtrTy. + /// \p getProtocolReference is called by the implementation when a + /// reference to another protocol is needed. + virtual llvm::Constant *getOrEmitProtocol( + const ObjCProtocolDecl *OPD, + llvm::function_ref + getProtocolReference) = 0; + /// Generate a function preamble for a method with the specified /// types. diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -13,14 +13,15 @@ //===----------------------------------------------------------------------===// #include "CGObjCRuntime.h" -#include "CGCleanup.h" #include "CGCXXABI.h" +#include "CGCleanup.h" #include "CGRecordLayout.h" #include "CodeGenFunction.h" #include "CodeGenModule.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtObjC.h" #include "clang/CodeGen/CGFunctionInfo.h" +#include "clang/CodeGen/CodeGenABITypes.h" #include "llvm/Support/SaveAndRestore.h" using namespace clang; @@ -383,3 +384,11 @@ CGM.getTypes().GetFunctionType(argsInfo)->getPointerTo(); return MessageSendInfo(argsInfo, signatureType); } + +llvm::Constant *clang::CodeGen::emitObjCProtocolObject( + CodeGenModule &CGM, const ObjCProtocolDecl *protocol, + llvm::function_ref + createProtocolReference) { + return CGM.getObjCRuntime().getOrEmitProtocol(protocol, + createProtocolReference); +}