From 21a987d1ac00aa7100a7abd48896c944475775c7 Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 12 Jun 2015 23:26:42 +0000 Subject: [PATCH] Fix returning error message in LLVMLinkModules On error, the temporary output stream wouldn't be flushed and therefore the caller would see an empty error message. Patch by Antoine Pitrou Differential Revision: http://reviews.llvm.org/D10241 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239646 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Linker/LinkModules.cpp | 4 ++- unittests/Linker/LinkModulesTest.cpp | 40 ++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/lib/Linker/LinkModules.cpp b/lib/Linker/LinkModules.cpp index 1b7a33168f1..b47d2685d42 100644 --- a/lib/Linker/LinkModules.cpp +++ b/lib/Linker/LinkModules.cpp @@ -1802,7 +1802,9 @@ LLVMBool LLVMLinkModules(LLVMModuleRef Dest, LLVMModuleRef Src, LLVMBool Result = Linker::LinkModules( D, unwrap(Src), [&](const DiagnosticInfo &DI) { DI.print(DP); }); - if (OutMessages && Result) + if (OutMessages && Result) { + Stream.flush(); *OutMessages = strdup(Message.c_str()); + } return Result; } diff --git a/unittests/Linker/LinkModulesTest.cpp b/unittests/Linker/LinkModulesTest.cpp index b4689cba560..58a3e72f63e 100644 --- a/unittests/Linker/LinkModulesTest.cpp +++ b/unittests/Linker/LinkModulesTest.cpp @@ -15,6 +15,7 @@ #include "llvm/IR/Module.h" #include "llvm/Linker/Linker.h" #include "llvm/Support/SourceMgr.h" +#include "llvm-c/Linker.h" #include "gtest/gtest.h" using namespace llvm; @@ -125,6 +126,22 @@ TEST_F(LinkModuleTest, BlockAddress) { delete LinkedModule; } +static Module *getExternal(LLVMContext &Ctx, StringRef FuncName) { + // Create a module with an empty externally-linked function + Module *M = new Module("ExternalModule", Ctx); + FunctionType *FTy = FunctionType::get( + Type::getVoidTy(Ctx), Type::getInt8PtrTy(Ctx), false /*=isVarArgs*/); + + Function *F = + Function::Create(FTy, Function::ExternalLinkage, FuncName, M); + F->setCallingConv(CallingConv::C); + + BasicBlock *BB = BasicBlock::Create(Ctx, "", F); + IRBuilder<> Builder(BB); + Builder.CreateRetVoid(); + return M; +} + static Module *getInternal(LLVMContext &Ctx) { Module *InternalM = new Module("InternalModule", Ctx); FunctionType *FTy = FunctionType::get( @@ -178,4 +195,27 @@ TEST_F(LinkModuleTest, TypeMerge) { M1->getNamedGlobal("t2")->getType()); } +TEST_F(LinkModuleTest, CAPISuccess) { + std::unique_ptr DestM(getExternal(Ctx, "foo")); + std::unique_ptr SourceM(getExternal(Ctx, "bar")); + char *errout = nullptr; + LLVMBool result = LLVMLinkModules(wrap(DestM.get()), wrap(SourceM.get()), + LLVMLinkerDestroySource, &errout); + EXPECT_EQ(0, result); + EXPECT_EQ(nullptr, errout); + // "bar" is present in destination module + EXPECT_NE(nullptr, DestM->getFunction("bar")); +} + +TEST_F(LinkModuleTest, CAPIFailure) { + // Symbol clash between two modules + std::unique_ptr DestM(getExternal(Ctx, "foo")); + std::unique_ptr SourceM(getExternal(Ctx, "foo")); + char *errout = nullptr; + LLVMBool result = LLVMLinkModules(wrap(DestM.get()), wrap(SourceM.get()), + LLVMLinkerDestroySource, &errout); + EXPECT_EQ(1, result); + EXPECT_STREQ("Linking globals named 'foo': symbol multiply defined!", errout); +} + } // end anonymous namespace