Handle global variable definitions which change the type of a definition, such as:
extern int x[];
void foo() { x[0] = 1; }
int x[10];
void bar() { x[0] = 1; }



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44509 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CodeGen/CGExpr.cpp b/CodeGen/CGExpr.cpp
index 93f3d71..e7bd712 100644
--- a/CodeGen/CGExpr.cpp
+++ b/CodeGen/CGExpr.cpp
@@ -268,8 +268,10 @@
     llvm::Value *V = LocalDeclMap[D];
     assert(V && "BlockVarDecl not entered in LocalDeclMap?");
     return LValue::MakeAddr(V);
-  } else if (isa<FunctionDecl>(D) || isa<FileVarDecl>(D)) {
-    return LValue::MakeAddr(CGM.GetAddrOfGlobalDecl(D));
+  } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
+    return LValue::MakeAddr(CGM.GetAddrOfFunctionDecl(FD, false));
+  } else if (const FileVarDecl *FVD = dyn_cast<FileVarDecl>(D)) {
+    return LValue::MakeAddr(CGM.GetAddrOfFileVarDecl(FVD, false));
   }
   assert(0 && "Unimp declref");
   //an invalid LValue, but the assert will
diff --git a/CodeGen/CodeGenFunction.cpp b/CodeGen/CodeGenFunction.cpp
index aa9d2c6..3ee7d1f 100644
--- a/CodeGen/CodeGenFunction.cpp
+++ b/CodeGen/CodeGenFunction.cpp
@@ -59,42 +59,7 @@
                              SourceLocation()));
   
   CurFuncDecl = FD;
-  llvm::Constant *CurFnC = CGM.GetAddrOfGlobalDecl(FD);
-  if (!(CurFn = dyn_cast<llvm::Function>(CurFnC))) {
-    // If CurFnC is not a constant, it must be a bitcast of another function.
-    llvm::ConstantExpr *CurFnCE = cast<llvm::ConstantExpr>(CurFnC);
-    assert(CurFnCE->getOpcode() == llvm::Instruction::BitCast &&
-           "Unexpected name collision");
-    llvm::Function *OtherFunc = cast<llvm::Function>(CurFnCE->getOperand(0));
-    
-    // This happens if there is a prototype for a function (e.g. "int f()") and
-    // then a definition of a different type (e.g. "int f(int x)").  Start by
-    // making a new function of the correct type, RAUW, then steal the name.
-    const llvm::PointerType *PTy = cast<llvm::PointerType>(CurFnC->getType());
-    const llvm::FunctionType *FTy =
-      cast<llvm::FunctionType>(PTy->getElementType());
-    CurFn = new llvm::Function(FTy, llvm::Function::ExternalLinkage, "",
-                               &CGM.getModule());
-    CurFn->takeName(OtherFunc);
-    
-    // Replace uses of OtherFunc with the Function we will endow with a body.
-    llvm::Constant *NewPtrForOldDecl = 
-      llvm::ConstantExpr::getBitCast(CurFn, OtherFunc->getType());
-    OtherFunc->replaceAllUsesWith(NewPtrForOldDecl);
-    
-    // Make sure the GlobalDecl map for FD is up-to-date.
-    CGM.ChangeGlobalDeclMap(FD, CurFn);
-    
-    // FIXME: Update the globaldeclmap for the previous decl of this name.  We
-    // really want a way to walk all of these, but we don't have it yet.  This
-    // is incredibly slow!
-    CGM.ReplaceMapValuesWith(OtherFunc, NewPtrForOldDecl);
-    
-    // Ok, delete the old function now, which is dead.
-    assert(OtherFunc->isDeclaration() && "Shouldn't replace non-declaration");
-    OtherFunc->eraseFromParent();
-  }
-  
+  CurFn = cast<llvm::Function>(CGM.GetAddrOfFunctionDecl(FD, true));
   assert(CurFn->isDeclaration() && "Function already has body?");
   
   // TODO: Set up linkage and many other things.  Note, this is a simple 
diff --git a/CodeGen/CodeGenModule.cpp b/CodeGen/CodeGenModule.cpp
index 7ef4fe1..727d9fb 100644
--- a/CodeGen/CodeGenModule.cpp
+++ b/CodeGen/CodeGenModule.cpp
@@ -43,41 +43,123 @@
 }
 
 
-llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) {
-  // See if it is already in the map.
+llvm::Constant *CodeGenModule::GetAddrOfFunctionDecl(const FunctionDecl *D,
+                                                     bool isDefinition) {
+  // See if it is already in the map.  If so, just return it.
   llvm::Constant *&Entry = GlobalDeclMap[D];
   if (Entry) return Entry;
   
-  QualType ASTTy = cast<ValueDecl>(D)->getType();
-  const llvm::Type *Ty = getTypes().ConvertType(ASTTy);
-  if (isa<FunctionDecl>(D)) {
-    // Check to see if the function already exists.
-    if (llvm::Function *F = getModule().getFunction(D->getName())) {
-      // If so, make sure it is the correct type.
-      return Entry = llvm::ConstantExpr::getBitCast(F,
-                                                    llvm::PointerType::get(Ty));
-    }
-    
+  const llvm::Type *Ty = getTypes().ConvertType(D->getType());
+  
+  // Check to see if the function already exists.
+  llvm::Function *F = getModule().getFunction(D->getName());
+  const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
+
+  // If it doesn't already exist, just create and return an entry.
+  if (F == 0) {
     // FIXME: param attributes for sext/zext etc.
-    const llvm::FunctionType *FTy = cast<llvm::FunctionType>(Ty);
     return Entry = new llvm::Function(FTy, llvm::Function::ExternalLinkage,
                                       D->getName(), &getModule());
   }
   
-  assert(isa<FileVarDecl>(D) && "Unknown global decl!");
-  
-  if (llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName())) {
-    // If so, make sure it is the correct type.
-    return Entry = llvm::ConstantExpr::getBitCast(GV,
-                                                  llvm::PointerType::get(Ty));
+  // If the pointer type matches, just return it.
+  llvm::Type *PFTy = llvm::PointerType::get(Ty);
+  if (PFTy == F->getType()) return Entry = F;
     
+  // If this isn't a definition, just return it casted to the right type.
+  if (!isDefinition)
+    return Entry = llvm::ConstantExpr::getBitCast(F, PFTy);
+  
+  // Otherwise, we have a definition after a prototype with the wrong type.
+  // F is the Function* for the one with the wrong type, we must make a new
+  // Function* and update everything that used F (a declaration) with the new
+  // Function* (which will be a definition).
+  //
+  // This happens if there is a prototype for a function (e.g. "int f()") and
+  // then a definition of a different type (e.g. "int f(int x)").  Start by
+  // making a new function of the correct type, RAUW, then steal the name.
+  llvm::Function *NewFn = new llvm::Function(FTy, 
+                                             llvm::Function::ExternalLinkage,
+                                             "", &getModule());
+  NewFn->takeName(F);
+  
+  // Replace uses of F with the Function we will endow with a body.
+  llvm::Constant *NewPtrForOldDecl = 
+    llvm::ConstantExpr::getBitCast(NewFn, F->getType());
+  F->replaceAllUsesWith(NewPtrForOldDecl);
+  
+  // FIXME: Update the globaldeclmap for the previous decl of this name.  We
+  // really want a way to walk all of these, but we don't have it yet.  This
+  // is incredibly slow!
+  ReplaceMapValuesWith(F, NewPtrForOldDecl);
+  
+  // Ok, delete the old function now, which is dead.
+  assert(F->isDeclaration() && "Shouldn't replace non-declaration");
+  F->eraseFromParent();
+
+  // Return the new function which has the right type.
+  return Entry = NewFn;
+}
+
+llvm::Constant *CodeGenModule::GetAddrOfFileVarDecl(const FileVarDecl *D,
+                                                    bool isDefinition) {
+  // See if it is already in the map.
+  llvm::Constant *&Entry = GlobalDeclMap[D];
+  if (Entry) return Entry;
+  
+  const llvm::Type *Ty = getTypes().ConvertType(D->getType());
+
+  // Check to see if the global already exists.
+  llvm::GlobalVariable *GV = getModule().getGlobalVariable(D->getName());
+
+  // If it doesn't already exist, just create and return an entry.
+  if (GV == 0) {
+    return Entry = new llvm::GlobalVariable(Ty, false, 
+                                            llvm::GlobalValue::ExternalLinkage,
+                                            0, D->getName(), &getModule());
   }
   
-  return Entry = new llvm::GlobalVariable(Ty, false, 
-                                          llvm::GlobalValue::ExternalLinkage,
-                                          0, D->getName(), &getModule());
+  // If the pointer type matches, just return it.
+  llvm::Type *PTy = llvm::PointerType::get(Ty);
+  if (PTy == GV->getType()) return Entry = GV;
+  
+  // If this isn't a definition, just return it casted to the right type.
+  if (!isDefinition)
+    return Entry = llvm::ConstantExpr::getBitCast(GV, PTy);
+  
+  
+  // Otherwise, we have a definition after a prototype with the wrong type.
+  // GV is the GlobalVariable* for the one with the wrong type, we must make a
+  /// new GlobalVariable* and update everything that used GV (a declaration)
+  // with the new GlobalVariable* (which will be a definition).
+  //
+  // This happens if there is a prototype for a global (e.g. "extern int x[];")
+  // and then a definition of a different type (e.g. "int x[10];").  Start by
+  // making a new global of the correct type, RAUW, then steal the name.
+  llvm::GlobalVariable *NewGV = 
+    new llvm::GlobalVariable(Ty, false, llvm::GlobalValue::ExternalLinkage,
+                             0, D->getName(), &getModule());
+  NewGV->takeName(GV);
+  
+  // Replace uses of GV with the globalvalue we will endow with a body.
+  llvm::Constant *NewPtrForOldDecl = 
+    llvm::ConstantExpr::getBitCast(NewGV, GV->getType());
+  GV->replaceAllUsesWith(NewPtrForOldDecl);
+  
+  // FIXME: Update the globaldeclmap for the previous decl of this name.  We
+  // really want a way to walk all of these, but we don't have it yet.  This
+  // is incredibly slow!
+  ReplaceMapValuesWith(GV, NewPtrForOldDecl);
+  
+  // Ok, delete the old global now, which is dead.
+  assert(GV->isDeclaration() && "Shouldn't replace non-declaration");
+  GV->eraseFromParent();
+  
+  // Return the new global which has the right type.
+  return Entry = NewGV;
 }
 
+
 void CodeGenModule::EmitFunction(const FunctionDecl *FD) {
   // If this is not a prototype, emit the body.
   if (FD->getBody())
@@ -307,14 +389,16 @@
 }
 
 void CodeGenModule::EmitGlobalVar(const FileVarDecl *D) {
-  llvm::GlobalVariable *GV = cast<llvm::GlobalVariable>(GetAddrOfGlobalDecl(D));
-  
-  // If the storage class is external and there is no initializer, just leave it
-  // as a declaration.
+  // If this is just a forward declaration of the variable, don't emit it now,
+  // allow it to be emitted lazily on its first use.
   if (D->getStorageClass() == VarDecl::Extern && D->getInit() == 0)
     return;
-
-  // Otherwise, convert the initializer, or use zero if appropriate.
+  
+  // Get the global, forcing it to be a direct reference.
+  llvm::GlobalVariable *GV = 
+    cast<llvm::GlobalVariable>(GetAddrOfFileVarDecl(D, true));
+  
+  // Convert the initializer, or use zero if appropriate.
   llvm::Constant *Init = 0;
   if (D->getInit() == 0) {
     Init = llvm::Constant::getNullValue(GV->getType()->getElementType());
diff --git a/CodeGen/CodeGenModule.h b/CodeGen/CodeGenModule.h
index dd4c006..027c830 100644
--- a/CodeGen/CodeGenModule.h
+++ b/CodeGen/CodeGenModule.h
@@ -66,16 +66,11 @@
   CodeGenTypes &getTypes() { return Types; }
   Diagnostic &getDiags() const { return Diags; }
   
-  llvm::Constant *GetAddrOfGlobalDecl(const ValueDecl *D);
+  llvm::Constant *GetAddrOfFunctionDecl(const FunctionDecl *D,
+                                        bool isDefinition);
+  llvm::Constant *GetAddrOfFileVarDecl(const FileVarDecl *D,
+                                       bool isDefinition);
   
-  void ChangeGlobalDeclMap(const Decl *Decl, llvm::Constant *NewVal) {
-    GlobalDeclMap[Decl] = NewVal;
-  }
-  
-  /// ReplaceMapValuesWith - This is a really slow and bad function that
-  /// searches for any entries in GlobalDeclMap that point to OldVal, changing
-  /// them to point to NewVal.  This is badbadbad, FIXME!
-  void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal);
   
   /// getBuiltinLibFunction - Given a builtin id for a function like
   /// "__builtin_fabsf", return a Function* for "fabsf".
@@ -92,6 +87,13 @@
   llvm::Constant *EmitGlobalInit(const Expr *Expression);
   
   void PrintStats() {}
+  
+private:
+  /// ReplaceMapValuesWith - This is a really slow and bad function that
+  /// searches for any entries in GlobalDeclMap that point to OldVal, changing
+  /// them to point to NewVal.  This is badbadbad, FIXME!
+  void ReplaceMapValuesWith(llvm::Constant *OldVal, llvm::Constant *NewVal);
+  
 };
 }  // end namespace CodeGen
 }  // end namespace clang
diff --git a/test/CodeGen/globalinit.c b/test/CodeGen/globalinit.c
index 7087669..e94027c 100644
--- a/test/CodeGen/globalinit.c
+++ b/test/CodeGen/globalinit.c
@@ -2,3 +2,9 @@
 
 int A[10] = { 1,2,3,4,5 };
 
+
+extern int x[];
+void foo() { x[0] = 1; }
+int x[10];
+void bar() { x[0] = 1; }
+