Skip to content

Commit 954a3de

Browse files
authored
Reland [Coverage] Fix region termination for GNU statement expressions (llvm#132222)
Relands llvm#130976 with adjustments to test requirements. Calls to __noreturn__ functions result in region termination for coverage mapping. But this creates incorrect coverage results when __noreturn__ functions (or other constructs that result in region termination) occur within [GNU statement expressions][1]. In this scenario an extra gap region is introduced within VisitStmt, such that if the following line does not introduce a new region it is unconditionally counted as uncovered. This change adjusts the mapping such that terminate statements within statement expressions do not propagate that termination state after the statement expression is processed. [1]: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html Fixes llvm#124296
1 parent 79079c9 commit 954a3de

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

clang/lib/CodeGen/CoverageMappingGen.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder
15051505
handleFileExit(getEnd(S));
15061506
}
15071507

1508+
void VisitStmtExpr(const StmtExpr *E) {
1509+
Visit(E->getSubStmt());
1510+
// Any region termination (such as a noreturn CallExpr) within the statement
1511+
// expression has been handled by visiting the sub-statement. The visitor
1512+
// cannot be at a terminate statement leaving the statement expression.
1513+
HasTerminateStmt = false;
1514+
}
1515+
15081516
void VisitDecl(const Decl *D) {
15091517
Stmt *Body = D->getBody();
15101518

clang/test/CoverageMapping/terminate-statements.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,12 @@ int elsecondnoret(void) {
346346
return 0;
347347
}
348348

349+
// CHECK-LABEL: _Z18statementexprnoretb:
350+
int statementexprnoret(bool crash) {
351+
int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1)
352+
return rc; // CHECK-NOT: Gap
353+
}
354+
349355
int main() {
350356
foo(0);
351357
foo(1);
@@ -368,5 +374,6 @@ int main() {
368374
ornoret();
369375
abstractcondnoret();
370376
elsecondnoret();
377+
statementexprnoret(false);
371378
return 0;
372379
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// REQUIRES: lld-available
2+
// XFAIL: powerpc64-target-arch
3+
4+
// RUN: %clangxx_profgen -std=gnu++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+
11+
// clang-format off
12+
__attribute__ ((__noreturn__))
13+
void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void)
14+
_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void)
15+
// CHECK: [[@LINE]]| |
16+
int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main(
17+
int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc =
18+
printf("coverage after foo is present\n"); // CHECK: [[@LINE]]| 1| printf(
19+
// CHECK: [[@LINE]]| |
20+
int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 =
21+
printf("coverage after bar is present\n"); // CHECK: [[@LINE]]| 1| printf(
22+
return rc + rc2; // CHECK: [[@LINE]]| 1| return rc
23+
} // CHECK: [[@LINE]]| 1|}
24+
// clang-format on

0 commit comments

Comments
 (0)