Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -462,6 +462,18 @@ InstVisitor::visit(I); } +// Helper to recursively iterate over indirect users. By +// returning false, the callback can ask to stop recursing +// further. +static void forEachUser(const Value *User, + SmallPtrSet &Visited, + llvm::function_ref Callback) { + if (!Visited.insert(User).second) + return; + for (const Value *TheNextUser : User->users()) + if (Callback(TheNextUser)) + forEachUser(TheNextUser, Visited, Callback); +} void Verifier::visitGlobalValue(const GlobalValue &GV) { Assert(!GV.isDeclaration() || GV.hasExternalLinkage() || @@ -481,6 +493,30 @@ if (GV.isDeclarationForLinker()) Assert(!GV.hasComdat(), "Declaration may not be in a Comdat!", &GV); + + // Verify that this GlobalValue is only used in this module. + // This map is used to avoid visiting uses twice. We can arrive at a user + // twice, if they have multiple operands. In particular for very large + // constant expressions, we can arrive at a particular user many times. + SmallPtrSet Visited; + forEachUser(&GV, Visited, [&](const Value *V) -> bool { + if (const Instruction *I = dyn_cast(V)) { + if (!I->getParent() || !I->getParent()->getParent()) + CheckFailed("Global is referenced by parentless instruction!", &GV, + M, I); + else if (I->getParent()->getParent()->getParent() != M) + CheckFailed("Global is referenced in a different module!", &GV, + M, I, I->getParent()->getParent(), + I->getParent()->getParent()->getParent()); + return false; + } else if (const Function *F = dyn_cast(V)) { + if (F->getParent() != M) + CheckFailed("Global is used by function in a different module", &GV, + M, F, F->getParent()); + return false; + } + return true; + }); } void Verifier::visitGlobalVariable(const GlobalVariable &GV) { Index: llvm/trunk/unittests/IR/VerifierTest.cpp =================================================================== --- llvm/trunk/unittests/IR/VerifierTest.cpp +++ llvm/trunk/unittests/IR/VerifierTest.cpp @@ -64,7 +64,7 @@ LLVMContext &C = getGlobalContext(); Module M1("M1", C); Module M2("M2", C); - Module M3("M2", C); + Module M3("M3", C); FunctionType *FTy = FunctionType::get(Type::getInt32Ty(C), /*isVarArg=*/false); Function *F1 = cast(M1.getOrInsertFunction("foo1", FTy)); Function *F2 = cast(M2.getOrInsertFunction("foo2", FTy)); @@ -86,7 +86,21 @@ std::string Error; raw_string_ostream ErrorOS(Error); - EXPECT_FALSE(verifyModule(M2, &ErrorOS)); + EXPECT_TRUE(verifyModule(M2, &ErrorOS)); + EXPECT_TRUE(StringRef(ErrorOS.str()) + .equals("Global is used by function in a different module\n" + "i32 ()* @foo2\n" + "; ModuleID = 'M2'\n" + "i32 ()* @foo3\n" + "; ModuleID = 'M3'\n" + "Global is referenced in a different module!\n" + "i32 ()* @foo2\n" + "; ModuleID = 'M2'\n" + " %call = call i32 @foo2()\n" + "i32 ()* @foo1\n" + "; ModuleID = 'M1'\n")); + + Error.clear(); EXPECT_TRUE(verifyModule(M1, &ErrorOS)); EXPECT_TRUE(StringRef(ErrorOS.str()).equals( "Referencing function in another module!\n"