]> granicus.if.org Git - clang/commitdiff
implement codegen for functions whose function body type don't match
authorChris Lattner <sabre@nondot.org>
Sun, 2 Dec 2007 06:27:33 +0000 (06:27 +0000)
committerChris Lattner <sabre@nondot.org>
Sun, 2 Dec 2007 06:27:33 +0000 (06:27 +0000)
their prototype.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44506 91177308-0d34-0410-b5e6-96231b3b80d8

CodeGen/CodeGenFunction.cpp
CodeGen/CodeGenModule.cpp
CodeGen/CodeGenModule.h
test/CodeGen/functions.c [new file with mode: 0644]

index 0da5fcdaaafae902aa28cbcadffa178f4306f9ad..190da77b2b7f5b926973bc000ab54239f26d5b70 100644 (file)
@@ -58,8 +58,42 @@ void CodeGenFunction::GenerateCode(const FunctionDecl *FD) {
     getContext().getTypeSize(getContext().getPointerType(getContext().VoidTy),
                              SourceLocation()));
   
-  CurFn = cast<llvm::Function>(CGM.GetAddrOfGlobalDecl(FD));
   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();
+  }
   
   assert(CurFn->isDeclaration() && "Function already has body?");
   
index b76d5e35eefc92e64a9993c2e5a716d7f5a3f7a7..51f758c542298cbae820a3eefd7959e8e903db2a 100644 (file)
@@ -31,6 +31,18 @@ CodeGenModule::CodeGenModule(ASTContext &C, const LangOptions &LO,
   : Context(C), Features(LO), TheModule(M), TheTargetData(TD), Diags(diags),
     Types(C, M, TD), MemCpyFn(0), CFConstantStringClassRef(0) {}
 
+
+/// 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 CodeGenModule::ReplaceMapValuesWith(llvm::Constant *OldVal,
+                                         llvm::Constant *NewVal) {
+  for (llvm::DenseMap<const Decl*, llvm::Constant*>::iterator 
+       I = GlobalDeclMap.begin(), E = GlobalDeclMap.end(); I != E; ++I)
+    if (I->second == OldVal) I->second = NewVal;
+}
+
+
 llvm::Constant *CodeGenModule::GetAddrOfGlobalDecl(const ValueDecl *D) {
   // See if it is already in the map.
   llvm::Constant *&Entry = GlobalDeclMap[D];
index c4867c0bfaf1e77116402fe996fa0914dfbb5d68..dd4c006a125a391fa8861816c2988d09e82a8b96 100644 (file)
@@ -68,6 +68,15 @@ public:
   
   llvm::Constant *GetAddrOfGlobalDecl(const ValueDecl *D);
   
+  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".
   ///
diff --git a/test/CodeGen/functions.c b/test/CodeGen/functions.c
new file mode 100644 (file)
index 0000000..09cb978
--- /dev/null
@@ -0,0 +1,11 @@
+// RUN: clang %s -emit-llvm
+int g();
+
+int foo(int i) {
+       return g(i);
+}
+
+int g(int i) {
+       return g(i);
+}
+