summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Linker/LinkModules.cpp32
-rw-r--r--test/Linker/2008-06-13-LinkOnceRedefinition.ll8
-rw-r--r--test/Linker/redefinition.ll2
3 files changed, 23 insertions, 19 deletions
diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp
index e9b712f195..1609c6c0e0 100644
--- a/lib/Linker/LinkModules.cpp
+++ b/lib/Linker/LinkModules.cpp
@@ -897,6 +897,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
const Function *SF = I; // SrcFunction
Function *DF = 0;
+ Value *MappedDF;
// If this function is internal or has no name, it doesn't participate in
// linkage.
@@ -973,19 +974,14 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
// Remember this mapping so uses in the source module get remapped
// later by RemapOperand.
ValueMap[SF] = NewDF;
- } else if (SF->isDeclaration()) {
- // We have two functions of the same name but different type and the
- // source is a declaration while the destination is not. Any use of
- // the source must be mapped to the destination, with a cast.
- ValueMap[SF] = ConstantExpr::getBitCast(DF, SF->getType());
+ continue;
} else {
- // We have two functions of the same name but different types and they
- // are both definitions. This is an error.
- return Error(Err, "Function '" + DF->getName() + "' defined as both '" +
- ToStr(SF->getFunctionType(), Src) + "' and '" +
- ToStr(DF->getFunctionType(), Dest) + "'");
+ // We have two functions of the same name but different type. Any use
+ // of the source must be mapped to the destination, with a cast.
+ MappedDF = ConstantExpr::getBitCast(DF, SF->getType());
}
- continue;
+ } else {
+ MappedDF = DF;
}
if (SF->isDeclaration()) {
@@ -993,11 +989,11 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
// the declarations, we aren't adding anything.
if (SF->hasDLLImportLinkage()) {
if (DF->isDeclaration()) {
- ValueMap[SF] = DF;
+ ValueMap[SF] = MappedDF;
DF->setLinkage(SF->getLinkage());
}
} else {
- ValueMap[SF] = DF;
+ ValueMap[SF] = MappedDF;
}
continue;
}
@@ -1005,7 +1001,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
// If DF is external but SF is not, link the external functions, update
// linkage qualifiers.
if (DF->isDeclaration() && !DF->hasDLLImportLinkage()) {
- ValueMap.insert(std::make_pair(SF, DF));
+ ValueMap.insert(std::make_pair(SF, MappedDF));
DF->setLinkage(SF->getLinkage());
continue;
}
@@ -1013,7 +1009,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
// At this point we know that DF has LinkOnce, Weak, or External* linkage.
if (SF->hasWeakLinkage() || SF->hasLinkOnceLinkage() ||
SF->hasCommonLinkage()) {
- ValueMap[SF] = DF;
+ ValueMap[SF] = MappedDF;
// Linkonce+Weak = Weak
// *+External Weak = *
@@ -1027,7 +1023,7 @@ static bool LinkFunctionProtos(Module *Dest, const Module *Src,
if (DF->hasWeakLinkage() || DF->hasLinkOnceLinkage() ||
DF->hasCommonLinkage()) {
// At this point we know that SF has LinkOnce or External* linkage.
- ValueMap[SF] = DF;
+ ValueMap[SF] = MappedDF;
// If the source function has stronger linkage than the destination,
// its body and linkage should override ours.
@@ -1106,10 +1102,10 @@ static bool LinkFunctionBodies(Module *Dest, Module *Src,
// go
for (Module::iterator SF = Src->begin(), E = Src->end(); SF != E; ++SF) {
if (!SF->isDeclaration()) { // No body if function is external
- Function *DF = cast<Function>(ValueMap[SF]); // Destination function
+ Function *DF = dyn_cast<Function>(ValueMap[SF]); // Destination function
// DF not external SF external?
- if (DF->isDeclaration())
+ if (DF && DF->isDeclaration())
// Only provide the function body if there isn't one already.
if (LinkFunctionBody(DF, SF, ValueMap, Err))
return true;
diff --git a/test/Linker/2008-06-13-LinkOnceRedefinition.ll b/test/Linker/2008-06-13-LinkOnceRedefinition.ll
new file mode 100644
index 0000000000..3478880ebd
--- /dev/null
+++ b/test/Linker/2008-06-13-LinkOnceRedefinition.ll
@@ -0,0 +1,8 @@
+; Test linking two functions with different prototypes and two globals
+; in different modules.
+; RUN: llvm-as %s -o %t.foo1.bc -f
+; RUN: llvm-as %s -o %t.foo2.bc -f
+; RUN: echo {define linkonce void @foo(i32 %x) { ret void }} | llvm-as -o %t.foo3.bc -f
+; RUN: llvm-link %t.foo1.bc %t.foo2.bc | llvm-dis
+; RUN: llvm-link %t.foo1.bc %t.foo3.bc | llvm-dis
+define linkonce void @foo() { ret void }
diff --git a/test/Linker/redefinition.ll b/test/Linker/redefinition.ll
index 7be9323445..0ee30d081a 100644
--- a/test/Linker/redefinition.ll
+++ b/test/Linker/redefinition.ll
@@ -6,5 +6,5 @@
; RUN: not llvm-link %t.foo1.bc %t.foo2.bc -o %t.bc |& \
; RUN: grep {Function is already defined}
; RUN: not llvm-link %t.foo1.bc %t.foo3.bc -o %t.bc |& \
-; RUN: grep {Function 'foo' defined as both}
+; RUN: grep {Function is already defined}
define void @foo() { ret void }