[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