Index: include/llvm/ProfileData/Coverage/CoverageMapping.h =================================================================== --- include/llvm/ProfileData/Coverage/CoverageMapping.h +++ include/llvm/ProfileData/Coverage/CoverageMapping.h @@ -506,7 +506,7 @@ /// This is the main interface to get coverage information, using a profile to /// fill out execution counts. class CoverageMapping { - StringSet<> FunctionNames; + StringMap> FunctionAndFileNames; std::vector Functions; std::vector> FuncHashMismatches; std::vector> FuncCounterMismatches; Index: lib/ProfileData/Coverage/CoverageMapping.cpp =================================================================== --- lib/ProfileData/Coverage/CoverageMapping.cpp +++ lib/ProfileData/Coverage/CoverageMapping.cpp @@ -207,9 +207,21 @@ else OrigFuncName = getFuncNameWithoutPrefix(OrigFuncName, Record.Filenames[0]); - // Don't load records for functions we've already seen. - if (!FunctionNames.insert(OrigFuncName).second) - return Error::success(); + // Don't load records for (filename, functions) pairs we've already seen. + if (Record.Filenames.empty()) { + if (!FunctionAndFileNames[""].insert(OrigFuncName).second) { + return Error::success(); + } + } else { + bool AlreadyLoaded = true; + for (const auto &Filename : Record.Filenames) { + if (FunctionAndFileNames[Filename].insert(OrigFuncName).second) { + AlreadyLoaded = false; + } + } + if (AlreadyLoaded) + return Error::success(); + } CounterMappingContext Ctx(Record.Expressions); Index: test/tools/llvm-cov/multiple-objects.test =================================================================== --- test/tools/llvm-cov/multiple-objects.test +++ test/tools/llvm-cov/multiple-objects.test @@ -6,6 +6,11 @@ REPORT-NEXT: --- REPORT-NEXT: header.h{{ +}}25{{ +}}14{{ +}}44.00% +# Make sure that both use_1.cc and use_2.cc have coverage reported. +# Before https://reviews.llvm.org/D46478, only one of them used to be reported. +REPORT-NEXT: use_1.cc{{ +}}1{{ +}}0{{ +}}100.00% +REPORT-NEXT: use_2.cc{{ +}}2{{ +}}0{{ +}}100.00% + Instructions for regenerating the test: clang -std=c++11 -mllvm -enable-name-compression=false -fprofile-instr-generate -fcoverage-mapping use_1.cc -o use_1 Index: unittests/ProfileData/CoverageMappingTest.cpp =================================================================== --- unittests/ProfileData/CoverageMappingTest.cpp +++ unittests/ProfileData/CoverageMappingTest.cpp @@ -859,17 +859,38 @@ TEST_P(CoverageMappingTest, skip_duplicate_function_record) { ProfileWriter.addRecord({"func", 0x1234, {1}}, Err); + // This record should be loaded. startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + addCMR(Counter::getCounter(0), "file3", 1, 1, 9, 9); + // This record should be skipped. startFunction("func", 0x1234); addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + // This record should be loaded. + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "file2", 1, 1, 9, 9); + addCMR(Counter::getCounter(0), "file3", 1, 1, 9, 9); + + // This record should be loaded. + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "file3", 1, 1, 9, 9); + addCMR(Counter::getCounter(0), "file4", 1, 1, 9, 9); + + // This record should be skipped. + startFunction("func", 0x1234); + addCMR(Counter::getCounter(0), "file4", 1, 1, 9, 9); + addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9); + EXPECT_THAT_ERROR(loadCoverageMapping(), Succeeded()); auto Funcs = LoadedCoverage->getCoveredFunctions(); unsigned NumFuncs = std::distance(Funcs.begin(), Funcs.end()); - ASSERT_EQ(1U, NumFuncs); + ASSERT_EQ(3U, NumFuncs); + + for (const auto &Func : Funcs) + ASSERT_EQ(2U, std::distance(Func.Filenames.begin(), Func.Filenames.end())); } // FIXME: Use ::testing::Combine() when llvm updates its copy of googletest.