[PATCH] D13954: CodeGen: Fix LLVM assertion if Swift and Clang emit Objective-C class reference in same LLVM module

2015-10-21 Thread Slava Pestov via cfe-commits
slavapestov created this revision.
slavapestov added a reviewer: cfe-commits.
slavapestov set the repository for this revision to rL LLVM.

This patch fixes an issue that can come up when Swift and Clang are emitting 
declarations into the same LLVM module.

Objective-C class literals result in the emission of a global variable named 
OBJC_CLASS_$_. Clang and Swift emit this variable with different 
types, resulting in an LLVM assertion firing. This patch changes Clang to be 
more resilient in the case where the global has already been emitted, wrapping 
it in a cast constexpr instead of crashing.

Repository:
  rL LLVM

http://reviews.llvm.org/D13954

Files:
  lib/CodeGen/CGObjCGNU.cpp
  lib/CodeGen/CGObjCMac.cpp
  lib/CodeGen/CGObjCRuntime.h
  lib/CodeGen/CodeGenModule.cpp

Index: lib/CodeGen/CodeGenModule.cpp
===
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -2739,7 +2739,9 @@
   std::string str = 
 StringClass.empty() ? "OBJC_CLASS_$_NSConstantString" 
 : "OBJC_CLASS_$_" + StringClass;
-  GV = getObjCRuntime().GetClassGlobal(str);
+  GV = getObjCRuntime().GetClassGlobal(str,
+   /*ForDefinition=*/false,
+   /*Weak=*/false);
   // Make sure the result is of the correct type.
   llvm::Type *PTy = llvm::PointerType::getUnqual(Ty);
   V = llvm::ConstantExpr::getBitCast(GV, PTy);
Index: lib/CodeGen/CGObjCRuntime.h
===
--- lib/CodeGen/CGObjCRuntime.h
+++ lib/CodeGen/CGObjCRuntime.h
@@ -268,8 +268,9 @@
   const CodeGen::CGBlockInfo &blockInfo) = 0;
   virtual llvm::Constant *BuildByrefLayout(CodeGen::CodeGenModule &CGM,
QualType T) = 0;
-  virtual llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
-   bool Weak = false) = 0;
+  virtual llvm::Constant *GetClassGlobal(const std::string &Name,
+ bool ForDefinition,
+ bool Weak) = 0;
 
   struct MessageSendInfo {
 const CGFunctionInfo &CallInfo;
Index: lib/CodeGen/CGObjCMac.cpp
===
--- lib/CodeGen/CGObjCMac.cpp
+++ lib/CodeGen/CGObjCMac.cpp
@@ -1260,8 +1260,9 @@
 
   /// GetClassGlobal - Return the global variable for the Objective-C
   /// class of the given name.
-  llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
-   bool Weak = false) override {
+  llvm::Constant *GetClassGlobal(const std::string &Name,
+ bool ForDefinition,
+ bool Weak) override {
 llvm_unreachable("CGObjCMac::GetClassGlobal");
   }
 };
@@ -1362,8 +1363,9 @@
   
   /// GetClassGlobal - Return the global variable for the Objective-C
   /// class of the given name.
-  llvm::GlobalVariable *GetClassGlobal(const std::string &Name,
-   bool Weak = false) override;
+  llvm::Constant *GetClassGlobal(const std::string &Name,
+ bool ForDefinition,
+ bool Weak) override;
 
   /// EmitClassRef - Return a Value*, of type ObjCTypes.ClassPtrTy,
   /// for the given class reference.
@@ -5686,7 +5688,12 @@
   llvm::PointerType::getUnqual(ObjCTypes.ImpnfABITy));
   llvm::Constant *Init = llvm::ConstantStruct::get(ObjCTypes.ClassnfABITy,
Values);
-  llvm::GlobalVariable *GV = GetClassGlobal(ClassName, Weak);
+  llvm::GlobalVariable *GV = cast(
+   GetClassGlobal(ClassName,
+  /*ForDefinition=*/true,
+  Weak));
+  if (Init->getType() != GV->getValueType())
+Init = llvm::ConstantExpr::getBitCast(Init, GV->getValueType());
   GV->setInitializer(Init);
   GV->setSection("__DATA, __objc_data");
   GV->setAlignment(
@@ -5755,7 +5762,7 @@
   llvm::SmallString<64> ObjCClassName(getClassSymbolPrefix());
   llvm::SmallString<64> TClassName;
 
-  llvm::GlobalVariable *SuperClassGV, *IsAGV;
+  llvm::Constant *SuperClassGV, *IsAGV;
 
   // Build the flags for the metaclass.
   bool classIsHidden =
@@ -5777,10 +5784,12 @@
 TClassName = ObjCClassName;
 TClassName += ClassName;
 SuperClassGV = GetClassGlobal(TClassName.str(),
+  /*ForDefinition=*/false,
   ID->getClassInterface()->isWeakImported());
 TClassName = ObjCMetaClassName;
 TClassName += ClassName;
 IsAGV = GetClassGlobal(TClassName.str(),
+   /*ForDefinition=*/false,
ID

Re: [PATCH] D13954: CodeGen: Fix LLVM assertion if Swift and Clang emit Objective-C class reference in same LLVM module

2015-10-24 Thread Slava Pestov via cfe-commits
slavapestov added a subscriber: slavapestov.
slavapestov added a comment.

Unfortunately the asm label attribute doesn’t seem to work in this case, at 
least on Darwin. I get two symbols in the IR, with the asm label having the \01 
prefix from MangleContext::mangleName():

@"\01OBJC_CLASS_$_NSNumber" = common global %struct.art_class* null, align 8
  
@"OBJC_CLASS_$_NSNumber" = external global %struct._class_t

As for the diagnostic, is this what you had in mind?

commit 4d4f15ffc4d6a72357fa4cee8e2197a03afe6b51
Author: Slava Pestov 
Date:   Fri Oct 23 23:57:56 2015 -0700

  CodeGen: More robust handling of type conflicts in GetClassGlobal()

diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 31e98b9..e5ef767 100644

- a/lib/CodeGen/CGObjCMac.cpp

+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -6692,16 +6692,31 @@ CGObjCNonFragileABIMac::GetClassGlobal(const 
std::string &Name,

  llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
   

- if (!GV)
- GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
- false, L, nullptr, Name);

+  // If it doesn't exist, create it with the right type.
+  if (!GV) {
+return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
+false, L, nullptr, Name);
+  }

  assert(GV->getLinkage() == L);
   

- if (ForDefinition ||
- GV->getValueType() == ObjCTypes.ClassnfABITy)

+  // If it already exists, we might need to bitcast.
+  if (GV->getValueType() == ObjCTypes.ClassnfABITy)

  return GV;
   

+  if (ForDefinition) {
+DiagnosticsEngine &Diags = CGM.getDiags();
+unsigned DiagID = Diags.getCustomDiagID(
+DiagnosticsEngine::Error,
+"global variable %0 already defined with wrong type");
+Diags.Report(SourceLocation(), DiagID) << Name;
+
+// Return a new global in this case, with the right type, since the caller
+// doesn't expect a constexpr
+return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
+false, L, nullptr, Name);
+  }
+

  return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ClassnfABIPtrTy);

}


Repository:
  rL LLVM

http://reviews.llvm.org/D13954



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D13954: CodeGen: Fix LLVM assertion if Swift and Clang emit Objective-C class reference in same LLVM module

2015-10-24 Thread Slava Pestov via cfe-commits
Unfortunately the asm label attribute doesn’t seem to work in this case, at 
least on Darwin. I get two symbols in the IR, with the asm label having the \01 
prefix from MangleContext::mangleName():

@"\01OBJC_CLASS_$_NSNumber" = common global %struct.art_class* null, align 8
  
@"OBJC_CLASS_$_NSNumber" = external global %struct._class_t 

As for the diagnostic, is this what you had in mind?

commit 4d4f15ffc4d6a72357fa4cee8e2197a03afe6b51
Author: Slava Pestov 
Date:   Fri Oct 23 23:57:56 2015 -0700

CodeGen: More robust handling of type conflicts in GetClassGlobal()

diff --git a/lib/CodeGen/CGObjCMac.cpp b/lib/CodeGen/CGObjCMac.cpp
index 31e98b9..e5ef767 100644
--- a/lib/CodeGen/CGObjCMac.cpp
+++ b/lib/CodeGen/CGObjCMac.cpp
@@ -6692,16 +6692,31 @@ CGObjCNonFragileABIMac::GetClassGlobal(const 
std::string &Name,
 
   llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
 
-  if (!GV)
-GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
-  false, L, nullptr, Name);
+  // If it doesn't exist, create it with the right type.
+  if (!GV) {
+return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
+false, L, nullptr, Name);
+  }
 
   assert(GV->getLinkage() == L);
 
-  if (ForDefinition ||
-  GV->getValueType() == ObjCTypes.ClassnfABITy)
+  // If it already exists, we might need to bitcast.
+  if (GV->getValueType() == ObjCTypes.ClassnfABITy)
 return GV;
 
+  if (ForDefinition) {
+DiagnosticsEngine &Diags = CGM.getDiags();
+unsigned DiagID = Diags.getCustomDiagID(
+DiagnosticsEngine::Error,
+"global variable %0 already defined with wrong type");
+Diags.Report(SourceLocation(), DiagID) << Name;
+
+// Return a new global in this case, with the right type, since the caller
+// doesn't expect a constexpr
+return new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
+false, L, nullptr, Name);
+  }
+
   return llvm::ConstantExpr::getBitCast(GV, ObjCTypes.ClassnfABIPtrTy);
 }
 
> On Oct 21, 2015, at 1:18 PM, John McCall  wrote:
> 
> rjmccall added a comment.
> 
> It just occurred to me that there is a way to test this in Clang with the 
> asm-label extension:
> 
>  int Foo_class asm("OBJC_CLASS_$_Foo");
> 
> Of course, you'll have to actually use it from somewhere, or define it, in 
> order for it to actually show up in the IR and cause a conflict.
> 
> You should probably also test that we do something sane if the caller is 
> making a definition but one already exists.  An error counts as "sane"; just 
> make sure you return a GlobalVariable of the right type.  There's model code 
> for this in GetOrCreateLLVMFunction, although it's okay for the diagnostic 
> here to be worse than that one.
> 
> 
> Repository:
>  rL LLVM
> 
> http://reviews.llvm.org/D13954
> 
> 
> 

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits