[llvm] [CoverageMapping] Fix LineCoverageStats incorrectly using gap region count (PR #203732)
Maksim Levental via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 13 18:40:44 PDT 2026
https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/203732
>From ea52343da2e053577974e2e7cc45154f47bc38ee Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Sat, 13 Jun 2026 16:33:04 -0700
Subject: [PATCH] [llvm-cov] Add failing test for gap region line coverage bug
LineCoverageStats incorrectly reports lines as uncovered when a gap
region with count=0 wraps into a line that has non-entry segments
with count > 0.
The test demonstrates this with two scoped blocks containing
never-taken early returns. The statement between them ("int result =
42;") and after them ("return true;") are genuinely executed but
reported with count=0 because the gap region from each block's
closing "}" incorrectly suppresses the line's execution count.
Test inputs generated with Apple system clang which produces this
specific segment pattern. Upstream clang does not produce gap regions
in this context.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
.../gap-region-quirk/gap-quirk.covmapping | Bin 0 -> 269 bytes
.../Inputs/gap-region-quirk/gap-quirk.cpp | 28 ++++++++++++++
.../gap-region-quirk/gap-quirk.profdata | Bin 0 -> 728 bytes
.../llvm-cov/gap-region-line-coverage.test | 35 ++++++++++++++++++
4 files changed, 63 insertions(+)
create mode 100644 llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.covmapping
create mode 100644 llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.cpp
create mode 100644 llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.profdata
create mode 100644 llvm/test/tools/llvm-cov/gap-region-line-coverage.test
diff --git a/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.covmapping b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.covmapping
new file mode 100644
index 0000000000000000000000000000000000000000..9b969b483c3f23e89d460cd5bbbabef231d34985
GIT binary patch
literal 269
zcmd1FDa%dHFUw_QfB at kItbz>jQRW3j`N^rp#Ystwxrv#1I$%jjs2VmP%_PRaqF<6*
zAdsF|pj%j)S(L3?W~7%~PykiK_s_-O)$`Q3Vjw at F#nY?BlZ!$7Yt5N9Bl*9Kj4X_-
zOq?Ld&&a4E#>B|N$-t|?%ESPqSQ+>j`WqS=I9M6 at nb??^*ce+uJSIj~ekKMc7RF{U
zj}4 at OlMkeU6Q+R^q=65nfsc`unGddk;n&sP=VmEWZ*v0OBLQ_I!aWR(jFLReOaKXY
BHDdq(
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.cpp b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.cpp
new file mode 100644
index 0000000000000..97e573e50bb24
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.cpp
@@ -0,0 +1,28 @@
+bool process(bool err1, bool err2) {
+ {
+ int fd = 0;
+ (void)fd;
+ if (err1) {
+ return false;
+ }
+ fd = 1;
+ (void)fd;
+ }
+ int result = 42;
+ (void)result;
+ {
+ int fd2 = 0;
+ (void)fd2;
+ if (err2) {
+ return false;
+ }
+ fd2 = 1;
+ (void)fd2;
+ }
+ return true;
+}
+
+int main() {
+ process(false, false);
+ return 0;
+}
diff --git a/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.profdata b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk.profdata
new file mode 100644
index 0000000000000000000000000000000000000000..de47b1163e8d322c97dc20c07939f0cc6d8c1f4c
GIT binary patch
literal 728
zcmeyLQ&5zjmf6V5fE{dLLKQ!O#=ijNvq6;!KxvpV7AT()jfQd=VCn?aVIrvXf;N~=
zRB;DhW>f(v at 4;l4ji}NMQZN^yiYqK+2MfS#fw|{^Iww}~gmqk4#TiU_u!=9(4GCFv
z^FP$_VO4J+&5u<)!VbIm9Y^fqW=`0}?Qw`RG5osP``j#L>TOu~X at K3qz>u4mnI{2d
z!+Zgwp~4ItPzK*W7k^jJQ|BOI!N6bv6_1ZH2PU)R)Z*f#q=*(zuNF@(23Y)|n*}oy
UM#Id8 at L{T9 at x%dRz?4I20Gc at _0ssI2
literal 0
HcmV?d00001
diff --git a/llvm/test/tools/llvm-cov/gap-region-line-coverage.test b/llvm/test/tools/llvm-cov/gap-region-line-coverage.test
new file mode 100644
index 0000000000000..43adaa23b367a
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/gap-region-line-coverage.test
@@ -0,0 +1,35 @@
+// Tests that LineCoverageStats correctly handles lines where a gap region
+// with count=0 wraps into a line that has a non-entry segment with count > 0.
+//
+// In this test, line 11 ("int result = 42;") is between two scoped blocks
+// each containing a never-taken early return. The gap region from the first
+// block's closing "}" wraps to line 11, but line 11 has a non-entry segment
+// with count=1 (the function body continues). LineCoverageStats should
+// report count=1 for line 11, not count=0.
+//
+// Similarly, line 22 ("return true;") is after the second block and has
+// the same issue.
+//
+// Test inputs generated with Apple clang (-O0) which produces the specific
+// gap-region segment pattern needed to trigger this bug.
+
+// RUN: llvm-cov show %S/Inputs/gap-region-quirk/gap-quirk.covmapping \
+// RUN: -instr-profile %S/Inputs/gap-region-quirk/gap-quirk.profdata \
+// RUN: -path-equivalence=/tmp,%S/Inputs/gap-region-quirk \
+// RUN: 2>&1 | FileCheck -check-prefix=SHOW %s
+
+// Lines between the two blocks should show count 1, not 0.
+// SHOW: 11| 1| int result = 42;
+// SHOW: 22| 1| return true;
+
+// RUN: llvm-cov report %S/Inputs/gap-region-quirk/gap-quirk.covmapping \
+// RUN: -instr-profile %S/Inputs/gap-region-quirk/gap-quirk.profdata \
+// RUN: -path-equivalence=/tmp,%S/Inputs/gap-region-quirk \
+// RUN: --show-branch-summary=false \
+// RUN: 2>&1 | FileCheck -check-prefix=REPORT %s
+
+// 22 mapped lines, 4 genuinely missed (lines 6-7, 17-18: never-taken returns).
+// Lines 11 and 22 should NOT be counted as missed.
+// REPORT: TOTAL
+// REPORT-SAME: 22
+// REPORT-SAME: 4
More information about the llvm-commits
mailing list