erik.pilkington created this revision. erik.pilkington added reviewers: rjmccall, ahatanak, jfb. Herald added a subscriber: dexonsmith.
Some ObjC users declare a `extern` variable named `OBJC_CLASS_$_Foo`, then use it's address as a `Class`. I.e., one could define `isInstanceOfF`: BOOL isInstanceOfF(id c) { extern void OBJC_CLASS_$_F; return [c class] == (Class)&OBJC_CLASS_$_F; } This leads to asserts in clang CodeGen if there is an `@implementation` of `F` in the same TU as an instance of this pattern, because CodeGen assumes that a variable named OBJC_CLASS_$_* has the right type. This patch fixes the problem by RAUWing the old (incorrectly typed) global with a new global, then removing the old global. I know almost nothing about Objective-C runtime stuff, so take this patch with a grain of salt! Fixes rdar://45077269 Repository: rC Clang https://reviews.llvm.org/D53154 Files: clang/lib/CodeGen/CGObjCMac.cpp clang/test/CodeGenObjC/extern-void-class-decl.m Index: clang/test/CodeGenObjC/extern-void-class-decl.m =================================================================== --- /dev/null +++ clang/test/CodeGenObjC/extern-void-class-decl.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -o - | FileCheck %s + +// rdar://45077269 + +extern void OBJC_CLASS_$_f; +Class c = (Class)&OBJC_CLASS_$_f; + +@implementation f @end + +// Check that we override the initializer for c, and that OBJC_CLASS_$_f gets +// the right definition. + +// CHECK: @c = global i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_f" to i8*) +// CHECK: @"OBJC_CLASS_$_f" = global %struct._class_t Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -7188,15 +7188,21 @@ Weak ? llvm::GlobalValue::ExternalWeakLinkage : llvm::GlobalValue::ExternalLinkage; - - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (!GV) { - GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy, - false, L, nullptr, Name); + if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) { + auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L, + nullptr, Name); if (DLLImport) - GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + + if (GV) { + GV->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(NewGV, GV->getType())); + GV->eraseFromParent(); + } + GV = NewGV; + CGM.getModule().getGlobalList().push_back(GV); } assert(GV->getLinkage() == L);
Index: clang/test/CodeGenObjC/extern-void-class-decl.m =================================================================== --- /dev/null +++ clang/test/CodeGenObjC/extern-void-class-decl.m @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -o - | FileCheck %s + +// rdar://45077269 + +extern void OBJC_CLASS_$_f; +Class c = (Class)&OBJC_CLASS_$_f; + +@implementation f @end + +// Check that we override the initializer for c, and that OBJC_CLASS_$_f gets +// the right definition. + +// CHECK: @c = global i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_f" to i8*) +// CHECK: @"OBJC_CLASS_$_f" = global %struct._class_t Index: clang/lib/CodeGen/CGObjCMac.cpp =================================================================== --- clang/lib/CodeGen/CGObjCMac.cpp +++ clang/lib/CodeGen/CGObjCMac.cpp @@ -7188,15 +7188,21 @@ Weak ? llvm::GlobalValue::ExternalWeakLinkage : llvm::GlobalValue::ExternalLinkage; - - llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name); - if (!GV) { - GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy, - false, L, nullptr, Name); + if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) { + auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L, + nullptr, Name); if (DLLImport) - GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass); + + if (GV) { + GV->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(NewGV, GV->getType())); + GV->eraseFromParent(); + } + GV = NewGV; + CGM.getModule().getGlobalList().push_back(GV); } assert(GV->getLinkage() == L);
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits