[llvm] [llvm-cov][CoverageMapping] Fix LineCoverageStats incorrectly using gap region count (PR #203740)

Maksim Levental via llvm-commits llvm-commits at lists.llvm.org
Sat Jun 13 19:49:49 PDT 2026


https://github.com/makslevental updated https://github.com/llvm/llvm-project/pull/203740

>From 32e3485a51a5e8a7ce01ff41c1cda55e43f3e6f9 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
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

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 uses a minimal reproducer: a scoped block with a never-taken
early return followed by a statement. The closing "}" produces a gap
region that wraps to the next line, suppressing its execution count.
The extra statement after the if-block is required — without it,
clang emits a region entry (MinRegionCount > 0) and the bug doesn't
trigger.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
 .../Inputs/gap-region-quirk/gap-quirk-v2.cpp  |  23 +++++++++++
 .../gap-region-quirk/gap-quirk.covmapping     | Bin 0 -> 285 bytes
 .../gap-region-quirk/gap-quirk.profdata       | Bin 0 -> 720 bytes
 .../llvm-cov/gap-region-line-coverage.test    |  36 ++++++++++++++++++
 4 files changed, 59 insertions(+)
 create mode 100644 llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk-v2.cpp
 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.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-v2.cpp b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk-v2.cpp
new file mode 100644
index 0000000000000..f235382db64e8
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/Inputs/gap-region-quirk/gap-quirk-v2.cpp
@@ -0,0 +1,23 @@
+// A scoped block with a never-taken early return followed by at least one
+// statement is needed to produce the gap region pattern. Without the extra
+// statement after the if-block, clang emits a region entry on the line after
+// the closing "}" (MinRegionCount > 0) and the bug doesn't trigger. With the
+// extra statement, the closing "}" produces a gap region that wraps forward,
+// and the next line has only a non-entry segment (MinRegionCount == 0).
+bool process(bool err) {
+  {
+    if (err) {
+      return false;
+    }
+    int fd = 1;
+    (void)fd;
+  }
+  int result = 42;
+  (void)result;
+  return true;
+}
+
+int main() {
+  process(false);
+  return 0;
+}
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..3709bdaf1a2b3f9285b4787090328299c80fb0ef
GIT binary patch
literal 285
zcmd1FDa%dHFUw_QfB>NfECLMiQRW3j`N^rp#Yv30iJ5s75V<s{8a5!!l+56xA6lGR
zRIHzylUkOVSCW{cpORV at 57d~Inp^@B&MeYR1mcv;#2lcAZgFN&rhZ9AW>HFfL1Ix!
zrG5_3Ze6H)QT>wK0{!&F0^P#W%%W`FG9$g at f&vBx<%A_loj(N1Y=Cw~w0LrXoNy=W
z at cHG__f;|i0V at Y1y975ABNHbBj{++b1CU~6;AQA*XlUSIW#D6CV`5 at sYz6U{7+G2Q
l7?@ZXn?bx^S9_nErA)oe2{cavWGE0I%w=F?6yafJ0s!KxO)dZc

literal 0
HcmV?d00001

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..3acc509754fcf1cce00538e0b8d6f33f2a924602
GIT binary patch
literal 720
zcmeyLQ&5zjmf6V5fE}!0LKQ!N#y<h&vq6;!KxvpVW+<N#jfQd=VCn?aVIrvXf;N~=
zRB;Dhn8~Q(4<@sq3P5=cQZN^yN-Hd62MfS#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~4ItP=<2C5~a=`0%hD#z5$euk1_`)v*gs`;-rWcPjCpr0vg>YbR(gBm@=3)
L4j2Qb9!diMX9^?n

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..beb91d33d3147
--- /dev/null
+++ b/llvm/test/tools/llvm-cov/gap-region-line-coverage.test
@@ -0,0 +1,36 @@
+// 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 15 ("int result = 42;") follows a scoped block containing
+// a never-taken early return. The gap region from the block's closing "}" wraps
+// to line 15, but line 15 has a non-entry segment with count=1 (the function
+// body continues). LineCoverageStats should report count=1 for line 15.
+//
+// Test inputs generated with (source must be at /tmp for path-equivalence):
+//   cp Inputs/gap-region-quirk/gap-quirk-v2.cpp /tmp/gap-quirk-v2.cpp
+//   %clang -fprofile-instr-generate -fcoverage-mapping -O0 \
+//       -mllvm -enable-name-compression=false \
+//       -c -o /tmp/gap-quirk.o /tmp/gap-quirk-v2.cpp
+//   llvm-cov convert-for-testing /tmp/gap-quirk.o -o gap-quirk.covmapping
+//   %clang -fprofile-instr-generate -fcoverage-mapping -O0 \
+//       -o /tmp/gap-quirk /tmp/gap-quirk-v2.cpp
+//   LLVM_PROFILE_FILE=/tmp/gap-quirk.profraw /tmp/gap-quirk
+//   llvm-profdata merge --sparse /tmp/gap-quirk.profraw -o gap-quirk.profdata
+
+// 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
+
+// Line 15 ("int result = 42;") should show count 1, not 0.
+// SHOW:     15|      1|  int result = 42;
+
+// 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
+
+// Line 15 should NOT be counted as missed (16 total lines, 2 missed).
+// REPORT: Filename{{.*}}Regions{{.*}}Missed Regions{{.*}}Cover{{.*}}Functions{{.*}}Missed Functions{{.*}}Executed{{.*}}Lines{{.*}}Missed Lines{{.*}}Cover
+// REPORT: gap-quirk-v2.cpp{{[[:space:]]+}}5{{[[:space:]]+}}1{{[[:space:]]+}}80.00%{{[[:space:]]+}}2{{[[:space:]]+}}0{{[[:space:]]+}}100.00%{{[[:space:]]+}}16{{[[:space:]]+}}2{{[[:space:]]+}}87.50%



More information about the llvm-commits mailing list