[cfe-commits] r73364 - /cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
Chris Lattner
sabre at nondot.org
Sun Jun 14 18:09:12 PDT 2009
Author: lattner
Date: Sun Jun 14 20:09:11 2009
New Revision: 73364
URL: http://llvm.org/viewvc/llvm-project?rev=73364&view=rev
Log:
"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!
Modified:
cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
Modified: cfe/trunk/lib/CodeGen/CGObjCGNU.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCGNU.cpp?rev=73364&r1=73363&r2=73364&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCGNU.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCGNU.cpp Sun Jun 14 20:09:11 2009
@@ -104,6 +104,7 @@
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 @@
} // 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 @@
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 @@
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;
More information about the cfe-commits
mailing list