aboutsummaryrefslogtreecommitdiff
path: root/lib/CodeGen/CGObjCGNU.cpp
diff options
context:
space:
mode:
authorChris Lattner <sabre@nondot.org>2009-06-15 01:09:11 +0000
committerChris Lattner <sabre@nondot.org>2009-06-15 01:09:11 +0000
commit2a8e4e1d8548dc3e30d7c9ba92127c7884a11448 (patch)
tree8c5a92b6e4f50d27dd9f18d5d50d19f9550e974f /lib/CodeGen/CGObjCGNU.cpp
parent7df71ac778e5918883c826fdb3fff7d0feffc677 (diff)
"GCC emits an __objc_class_name_{classname} symbol for every class, and a corresponding reference to this symbol for every compilation unit that references the class. This causes linker errors when you try linking a program which references some classes but doesn't define them. The attached patch implements this support in clang, so you can compile a class with clang, reference it in a file compiled with GCC, and have it all work correctly."
Patch by David Chisnall! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73364 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CGObjCGNU.cpp')
-rw-r--r--lib/CodeGen/CGObjCGNU.cpp33
1 files changed, 29 insertions, 4 deletions
diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
index a70f718a76..912479f0b0 100644
--- a/lib/CodeGen/CGObjCGNU.cpp
+++ b/lib/CodeGen/CGObjCGNU.cpp
@@ -104,6 +104,7 @@ private:
std::vector<llvm::Constant*> &V, const std::string &Name="");
llvm::GlobalVariable *ObjCIvarOffsetVariable(const ObjCInterfaceDecl *ID,
const ObjCIvarDecl *Ivar);
+ void EmitClassRef(const std::string &className);
public:
CGObjCGNU(CodeGen::CodeGenModule &cgm);
virtual llvm::Constant *GenerateConstantString(const ObjCStringLiteral *);
@@ -168,15 +169,31 @@ public:
} // end anonymous namespace
+/// Emits a reference to a dummy variable which is emitted with each class.
+/// This ensures that a linker error will be generated when trying to link
+/// together modules where a referenced class is not defined.
+void CGObjCGNU::EmitClassRef(const std::string &className){
+ std::string symbolRef = "__objc_class_ref_" + className;
+ // Don't emit two copies of the same symbol
+ if (TheModule.getGlobalVariable(symbolRef)) return;
+ std::string symbolName = "__objc_class_name_" + className;
+ llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(symbolName);
+ if (!ClassSymbol) {
+ ClassSymbol = new llvm::GlobalVariable(LongTy, false,
+ llvm::GlobalValue::ExternalLinkage, 0, symbolName, &TheModule);
+ }
+ new llvm::GlobalVariable(ClassSymbol->getType(), true,
+ llvm::GlobalValue::CommonLinkage, ClassSymbol, symbolRef, &TheModule);
+}
static std::string SymbolNameForClass(const std::string &ClassName) {
- return "___objc_class_name_" + ClassName;
+ return "_OBJC_CLASS_" + ClassName;
}
static std::string SymbolNameForMethod(const std::string &ClassName, const
std::string &CategoryName, const std::string &MethodName, bool isClassMethod)
{
- return "._objc_method_" + ClassName +"("+CategoryName+")"+
+ return "_OBJC_METHOD_" + ClassName + "("+CategoryName+")"+
(isClassMethod ? "+" : "-") + MethodName;
}
@@ -217,6 +234,7 @@ CGObjCGNU::CGObjCGNU(CodeGen::CodeGenModule &cgm)
llvm::Value *CGObjCGNU::GetClass(CGBuilderTy &Builder,
const ObjCInterfaceDecl *OID) {
llvm::Value *ClassName = CGM.GetAddrOfConstantCString(OID->getNameAsString());
+ EmitClassRef(OID->getNameAsString());
ClassName = Builder.CreateStructGEP(ClassName, 0);
std::vector<const llvm::Type*> Params(1, PtrToInt8Ty);
@@ -831,14 +849,21 @@ void CGObjCGNU::GenerateClass(const ObjCImplementationDecl *OID) {
const ObjCInterfaceDecl * SuperClassDecl =
OID->getClassInterface()->getSuperClass();
std::string SuperClassName;
- if (SuperClassDecl)
+ if (SuperClassDecl) {
SuperClassName = SuperClassDecl->getNameAsString();
+ EmitClassRef(SuperClassName);
+ }
// Get the class name
ObjCInterfaceDecl *ClassDecl =
const_cast<ObjCInterfaceDecl *>(OID->getClassInterface());
std::string ClassName = ClassDecl->getNameAsString();
-
+ // Emit the symbol that is used to generate linker errors if this class is
+ // referenced in other modules but not declared.
+ new llvm::GlobalVariable(LongTy, false, llvm::GlobalValue::ExternalLinkage,
+ llvm::ConstantInt::get(LongTy, 0), "__objc_class_name_" + ClassName,
+ &TheModule);
+
// Get the size of instances.
int instanceSize = Context.getASTObjCImplementationLayout(OID).getSize() / 8;