Skip to content

Commit 6f79ddb

Browse files
committed
[Coverage] Fix region creation after try statements
In cases where a terminating statement exists within the try or catch block the coverage mapping can be incorrect. Coverage reports display lines following the last catch block as uncovered, when the lines have been executed. This change adjusts the mapping such that an extra region is only created after a try block if the try itself contains the terminating statement. The testing validates coverage more broadly than the above to ensure other mapping around exception handling does not regress with this change.
1 parent a983c3b commit 6f79ddb

File tree

3 files changed

+152
-4
lines changed

3 files changed

+152
-4
lines changed

clang/lib/CodeGen/CoverageMappingGen.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2123,11 +2123,17 @@ struct CounterCoverageMappingBuilder
21232123
Counter ParentCount = getRegion().getCounter();
21242124
propagateCounts(ParentCount, S->getTryBlock());
21252125

2126+
bool TryHasTerminateStmt = HasTerminateStmt;
2127+
21262128
for (unsigned I = 0, E = S->getNumHandlers(); I < E; ++I)
21272129
Visit(S->getHandler(I));
21282130

2129-
Counter ExitCount = getRegionCounter(S);
2130-
pushRegion(ExitCount);
2131+
if (TryHasTerminateStmt) {
2132+
Counter ExitCount = getRegionCounter(S);
2133+
pushRegion(ExitCount);
2134+
}
2135+
2136+
HasTerminateStmt = TryHasTerminateStmt;
21312137
}
21322138

21332139
void VisitCXXCatchStmt(const CXXCatchStmt *S) {

clang/test/CoverageMapping/trycatch.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,5 @@ int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@
3333
catch(const Warning &w) { // CHECK-NEXT: File 0, [[@LINE]]:27 -> [[@LINE+2]]:4 = #4
3434
j = 0;
3535
}
36-
return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = #1
37-
}
36+
return 0; // CHECK-NOT: File 0
37+
} // CHECK-NOT: File 0
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// REQUIRES: lld-available
2+
// XFAIL: powerpc64-target-arch
3+
4+
// RUN: %clangxx_profgen -std=c++17 -fuse-ld=lld -fcoverage-mapping -o %t %s
5+
// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t
6+
// RUN: llvm-profdata merge -o %t.profdata %t.profraw
7+
// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s
8+
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
12+
#define TRY_AND_CATCH_ALL(x) \
13+
try { \
14+
(x); \
15+
} catch (...) { \
16+
}
17+
18+
#define TRY_MAYBE_CRASH(x) \
19+
try { \
20+
if ((x)) { \
21+
printf("no crash\n"); \
22+
} else { \
23+
abort(); \
24+
} \
25+
} catch (...) { \
26+
}
27+
28+
#define TRY_AND_CATCH_CRASHES(x) \
29+
try { \
30+
(x); \
31+
} catch (...) { \
32+
abort(); \
33+
}
34+
35+
// clang-format off
36+
static
37+
int test_no_exception() { // CHECK: [[@LINE]]| 1|int test_no_exception()
38+
int i = 0; // CHECK: [[@LINE]]| 1| int i
39+
try { // CHECK: [[@LINE]]| 1| try {
40+
i = 1; // CHECK: [[@LINE]]| 1| i =
41+
} catch (...) { // CHECK: [[@LINE]]| 1| } catch (
42+
abort(); // CHECK: [[@LINE]]| 0| abort();
43+
} // CHECK: [[@LINE]]| 0| }
44+
printf("%s: %u\n", __func__, i); // CHECK: [[@LINE]]| 1| printf(
45+
return 0; // CHECK: [[@LINE]]| 1| return
46+
} // CHECK: [[@LINE]]| 1|}
47+
48+
static
49+
int test_no_exception_macro() { // CHECK: [[@LINE]]| 1|int test_no_exception_macro()
50+
int i = 0; // CHECK: [[@LINE]]| 1| int i
51+
TRY_AND_CATCH_ALL(i = 1); // CHECK: [[@LINE]]| 1| TRY_AND_CATCH_ALL(
52+
printf("%s: %u\n", __func__, i); // CHECK: [[@LINE]]| 1| printf(
53+
return 0; // CHECK: [[@LINE]]| 1| return
54+
} // CHECK: [[@LINE]]| 1|}
55+
56+
static
57+
int test_exception() { // CHECK: [[@LINE]]| 1|int test_exception()
58+
try { // CHECK: [[@LINE]]| 1| try {
59+
throw 1; // CHECK: [[@LINE]]| 1| throw
60+
} catch (...) { // CHECK: [[@LINE]]| 1| } catch (
61+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
62+
} // CHECK: [[@LINE]]| 1| }
63+
return 0; // CHECK: [[@LINE]]| 1| return
64+
} // CHECK: [[@LINE]]| 1|}
65+
66+
static
67+
int test_exception_macro() { // CHECK: [[@LINE]]| 1|int test_exception_macro()
68+
TRY_AND_CATCH_ALL(throw 1); // CHECK: [[@LINE]]| 1| TRY_AND_CATCH_ALL(
69+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
70+
return 0; // CHECK: [[@LINE]]| 1| return
71+
} // CHECK: [[@LINE]]| 1|}
72+
73+
static
74+
int test_exception_macro_nested() { // CHECK: [[@LINE]]| 1|int test_exception_macro_nested()
75+
try { // CHECK: [[@LINE]]| 1| try {
76+
TRY_AND_CATCH_ALL(throw 1); // CHECK: [[@LINE]]| 1| TRY_AND_CATCH_ALL(
77+
} catch (...) { // CHECK: [[@LINE]]| 1| } catch (
78+
abort(); // CHECK: [[@LINE]]| 0| abort();
79+
} // CHECK: [[@LINE]]| 0| }
80+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
81+
return 0; // CHECK: [[@LINE]]| 1| return
82+
} // CHECK: [[@LINE]]| 1|}
83+
84+
static
85+
int test_exception_try_crash() { // CHECK: [[@LINE]]| 1|int test_exception_try_crash()
86+
int i = 1; // CHECK: [[@LINE]]| 1| int i
87+
TRY_MAYBE_CRASH(i); // CHECK: [[@LINE]]| 1| TRY_MAYBE_CRASH(
88+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
89+
return 0; // CHECK: [[@LINE]]| 1| return
90+
} // CHECK: [[@LINE]]| 1|}
91+
92+
static
93+
int test_exception_crash() { // CHECK: [[@LINE]]| 1|int test_exception_crash()
94+
int i = 0; // CHECK: [[@LINE]]| 1| int i
95+
TRY_AND_CATCH_CRASHES(i = 1); // CHECK: [[@LINE]]| 1| TRY_AND_CATCH_CRASHES(
96+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
97+
return 0; // CHECK: [[@LINE]]| 1| return
98+
} // CHECK: [[@LINE]]| 1|}
99+
100+
static
101+
int test_conditional(int i) { // CHECK: [[@LINE]]| 1|int test_conditional(int i)
102+
try { // CHECK: [[@LINE]]| 1| try {
103+
if (i % 2 == 0) { // CHECK: [[@LINE]]| 1| if (
104+
printf("%s\n", __func__); // CHECK: [[@LINE]]| 1| printf(
105+
} else { // CHECK: [[@LINE]]| 1| } else {
106+
abort(); // CHECK: [[@LINE]]| 0| abort();
107+
} // CHECK: [[@LINE]]| 0| }
108+
} catch (...) { // CHECK: [[@LINE]]| 1| } catch (
109+
abort(); // CHECK: [[@LINE]]| 0| abort();
110+
} // CHECK: [[@LINE]]| 0| }
111+
return 0; // CHECK: [[@LINE]]| 1| return
112+
}
113+
114+
static
115+
int test_multiple_catch() { // CHECK: [[@LINE]]| 1|int test_multiple_catch()
116+
try { // CHECK: [[@LINE]]| 1| try {
117+
throw 1; // CHECK: [[@LINE]]| 1| throw
118+
} catch (double) { // CHECK: [[@LINE]]| 1| } catch (double)
119+
abort(); // CHECK: [[@LINE]]| 0| abort();
120+
} catch (int) { // CHECK: [[@LINE]]| 1| } catch (int)
121+
printf("int\n"); // CHECK: [[@LINE]]| 1| printf(
122+
} catch (float) { // CHECK: [[@LINE]]| 1| } catch (float)
123+
abort(); // CHECK: [[@LINE]]| 0| abort();
124+
} catch (...) { // CHECK: [[@LINE]]| 0| } catch (
125+
abort(); // CHECK: [[@LINE]]| 0| abort();
126+
} // CHECK: [[@LINE]]| 0| }
127+
return 0; // CHECK: [[@LINE]]| 1| return
128+
} // CHECK: [[@LINE]]| 1|}
129+
130+
int main() { // CHECK: [[@LINE]]| 1|int main()
131+
test_no_exception(); // CHECK: [[@LINE]]| 1| test_no_exception(
132+
test_no_exception_macro(); // CHECK: [[@LINE]]| 1| test_no_exception_macro(
133+
test_exception(); // CHECK: [[@LINE]]| 1| test_exception(
134+
test_exception_macro(); // CHECK: [[@LINE]]| 1| test_exception_macro(
135+
test_exception_macro_nested(); // CHECK: [[@LINE]]| 1| test_exception_macro_nested(
136+
test_exception_try_crash(); // CHECK: [[@LINE]]| 1| test_exception_try_crash(
137+
test_exception_crash(); // CHECK: [[@LINE]]| 1| test_exception_crash(
138+
test_conditional(2); // CHECK: [[@LINE]]| 1| test_conditional(
139+
test_multiple_catch(); // CHECK: [[@LINE]]| 1| test_multiple_catch(
140+
return 0; // CHECK: [[@LINE]]| 1| return
141+
} // CHECK: [[@LINE]]| 1|}
142+
// clang-format on

0 commit comments

Comments
 (0)