From 10ab2e45436c50e4cfe1024839280d85fdc2082c Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Tue, 7 Jun 2016 10:07:51 +0000 Subject: [PATCH] Reapply [Coverage] Fix an assertion failure if the definition of an unused function spans multiple files. We have an assertion failure if, for example, the definition of an unused inline function starts in one macro and ends in another. This patch fixes the issue by finding the common ancestor of the start and end locations of that function's body and changing the locations accordingly. Thanks to NAKAMURA Takumi for helping with fixing the test failure on Windows. Differential Revision: http://reviews.llvm.org/D20997 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@271995 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CoverageMappingGen.cpp | 42 ++++++++++++++----- test/CoverageMapping/Inputs/ends_a_scope_only | 1 + .../Inputs/starts_a_scope_only | 1 + test/CoverageMapping/unused_function.cpp | 37 ++++++++++++++++ 4 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 test/CoverageMapping/Inputs/ends_a_scope_only create mode 100644 test/CoverageMapping/Inputs/starts_a_scope_only create mode 100644 test/CoverageMapping/unused_function.cpp diff --git a/lib/CodeGen/CoverageMappingGen.cpp b/lib/CodeGen/CoverageMappingGen.cpp index bd34e1c5a8..44c90e30cd 100644 --- a/lib/CodeGen/CoverageMappingGen.cpp +++ b/lib/CodeGen/CoverageMappingGen.cpp @@ -130,6 +130,16 @@ public: return strcmp(SM.getBufferName(SM.getSpellingLoc(Loc)), "") == 0; } + /// \brief Check whether \c Loc is included or expanded from \c Parent. + bool isNestedIn(SourceLocation Loc, FileID Parent) { + do { + Loc = getIncludeOrExpansionLoc(Loc); + if (Loc.isInvalid()) + return false; + } while (!SM.isInFileID(Loc, Parent)); + return true; + } + /// \brief Get the start of \c S ignoring macro arguments and builtin macros. SourceLocation getStart(const Stmt *S) { SourceLocation Loc = S->getLocStart(); @@ -310,7 +320,27 @@ struct EmptyCoverageMappingBuilder : public CoverageMappingBuilder { if (!D->hasBody()) return; auto Body = D->getBody(); - SourceRegions.emplace_back(Counter(), getStart(Body), getEnd(Body)); + SourceLocation Start = getStart(Body); + SourceLocation End = getEnd(Body); + if (!SM.isWrittenInSameFile(Start, End)) { + // Walk up to find the common ancestor. + // Correct the locations accordingly. + FileID StartFileID = SM.getFileID(Start); + FileID EndFileID = SM.getFileID(End); + while (StartFileID != EndFileID && !isNestedIn(End, StartFileID)) { + Start = getIncludeOrExpansionLoc(Start); + assert(Start.isValid() && + "Declaration start location not nested within a known region"); + StartFileID = SM.getFileID(Start); + } + while (StartFileID != EndFileID) { + End = getPreciseTokenLocEnd(getIncludeOrExpansionLoc(End)); + assert(End.isValid() && + "Declaration end location not nested within a known region"); + EndFileID = SM.getFileID(End); + } + } + SourceRegions.emplace_back(Counter(), Start, End); } /// \brief Write the mapping data to the output stream @@ -471,16 +501,6 @@ struct CounterCoverageMappingBuilder MostRecentLocation = getIncludeOrExpansionLoc(MostRecentLocation); } - /// \brief Check whether \c Loc is included or expanded from \c Parent. - bool isNestedIn(SourceLocation Loc, FileID Parent) { - do { - Loc = getIncludeOrExpansionLoc(Loc); - if (Loc.isInvalid()) - return false; - } while (!SM.isInFileID(Loc, Parent)); - return true; - } - /// \brief Adjust regions and state when \c NewLoc exits a file. /// /// If moving from our most recently tracked location to \c NewLoc exits any diff --git a/test/CoverageMapping/Inputs/ends_a_scope_only b/test/CoverageMapping/Inputs/ends_a_scope_only new file mode 100644 index 0000000000..5c34318c21 --- /dev/null +++ b/test/CoverageMapping/Inputs/ends_a_scope_only @@ -0,0 +1 @@ +} diff --git a/test/CoverageMapping/Inputs/starts_a_scope_only b/test/CoverageMapping/Inputs/starts_a_scope_only new file mode 100644 index 0000000000..98232c64fc --- /dev/null +++ b/test/CoverageMapping/Inputs/starts_a_scope_only @@ -0,0 +1 @@ +{ diff --git a/test/CoverageMapping/unused_function.cpp b/test/CoverageMapping/unused_function.cpp new file mode 100644 index 0000000000..6a46b1d2af --- /dev/null +++ b/test/CoverageMapping/unused_function.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only %s | FileCheck %s + +#define START_SCOPE { +#define END_SCOPE } + +// CHECK: {{_Z2f0v|\?f0@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:20 = 0 +inline void f0() {} + +// CHECK: {{_Z2f1v|\?f1@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:31 = 0 +inline void f1() START_SCOPE } + +// CHECK: {{_Z2f2v|\?f2@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:29 = 0 +inline void f2() { END_SCOPE + +// CHECK: {{_Z2f3v|\?f3@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+1]]:39 = 0 +inline void f3() START_SCOPE END_SCOPE + +// CHECK: {{_Z2f4v|\?f4@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+2]]:10 -> [[@LINE+3]]:2 = 0 +inline void f4() +#include "Inputs/starts_a_scope_only" +} + +// CHECK: {{_Z2f5v|\?f5@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+1]]:18 -> [[@LINE+2]]:36 = 0 +inline void f5() { +#include "Inputs/ends_a_scope_only" + +// CHECK: {{_Z2f6v|\?f6@@YAXXZ}}: +// CHECK-NEXT: File 0, [[@LINE+2]]:10 -> [[@LINE+3]]:36 = 0 +inline void f6() +#include "Inputs/starts_a_scope_only" +#include "Inputs/ends_a_scope_only" -- 2.50.1