Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -448,6 +448,22 @@ InstVisitor::visit(I); } +static void forEachInstructionAndFunctionUser( + const Use &TheUse, SmallPtrSet &Visited, + llvm::function_ref InstCallback, + llvm::function_ref FuncCallback) { + Value *User = TheUse.getUser(); + if (!Visited.insert(User).second) + return; + if (Instruction *I = dyn_cast(User)) + InstCallback(I); + else if (Function *F = dyn_cast(User)) + FuncCallback(F); + else + for (const Use &TheNextUse : User->materialized_uses()) + forEachInstructionAndFunctionUser(TheNextUse, Visited, InstCallback, + FuncCallback); +} void Verifier::visitGlobalValue(const GlobalValue &GV) { Assert(!GV.isDeclaration() || GV.hasExternalLinkage() || @@ -467,6 +483,29 @@ 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; + for (const Use &TheUse : GV.materialized_uses()) + forEachInstructionAndFunctionUser( + TheUse, Visited, + [&](Instruction *I) { + Assert(I->getParent() && I->getParent()->getParent(), + "Global is referenced by parentless instruction!", &GV, + GV.getParent(), I); + Assert(I->getParent()->getParent()->getParent() == GV.getParent(), + "Global is referenced in a different module!", &GV, + GV.getParent(), I, I->getParent()->getParent(), + I->getParent()->getParent()->getParent()); + }, + [&](Function *F) { + Assert(F->getParent() == GV.getParent(), + "Global is used by function in a different module", &GV, + GV.getParent(), F, F->getParent()); + }); } void Verifier::visitGlobalVariable(const GlobalVariable &GV) { Index: unittests/IR/VerifierTest.cpp =================================================================== --- unittests/IR/VerifierTest.cpp +++ 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"