https://github.com/justincady updated https://github.com/llvm/llvm-project/pull/130976
>From 6f3557780d06d6a2b1a7f315c49a3ad533d821e5 Mon Sep 17 00:00:00 2001 From: Justin Cady <d...@justincady.com> Date: Wed, 12 Mar 2025 11:23:19 -0400 Subject: [PATCH 1/3] [Coverage] Fix region termination for GNU statement expressions 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 #124296 --- clang/lib/CodeGen/CoverageMappingGen.cpp | 8 ++++++++ .../CoverageMapping/terminate-statements.cpp | 7 +++++++ .../Linux/coverage-statement-expression.cpp | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 compiler-rt/test/profile/Linux/coverage-statement-expression.cpp diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp index f09157771d2b5..73811d15979d5 100644 --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -1505,6 +1505,14 @@ struct CounterCoverageMappingBuilder handleFileExit(getEnd(S)); } + void VisitStmtExpr(const StmtExpr *E) { + Visit(E->getSubStmt()); + // Any region termination (such as a noreturn CallExpr) within the statement + // expression has been handled by visiting the sub-statement. The visitor + // cannot be at a terminate statement leaving the statement expression. + HasTerminateStmt = false; + } + void VisitDecl(const Decl *D) { Stmt *Body = D->getBody(); diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index 0067185fee8e6..d03e35630b317 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -346,6 +346,12 @@ int elsecondnoret(void) { return 0; } +// CHECK-LABEL: _Z18statementexprnoretb +int statementexprnoret(bool crash) { + int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 + return rc; +} + int main() { foo(0); foo(1); @@ -368,5 +374,6 @@ int main() { ornoret(); abstractcondnoret(); elsecondnoret(); + statementexprnoret(false); return 0; } diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp new file mode 100644 index 0000000000000..5894275b941a2 --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_profgen -std=gnu++17 -fuse-ld=lld -fcoverage-mapping -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-cov show %t -instr-profile=%t.profdata 2>&1 | FileCheck %s + +#include <stdio.h> + +__attribute__ ((__noreturn__)) +void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) +_Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) + // CHECK: [[@LINE]]| | +int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main( + int rc = ({ if (argc > 3) foo(); 0; }); // CHECK: [[@LINE]]| 1| int rc = + printf("coverage after foo is present\n"); // CHECK: [[@LINE]]| 1| printf( + // CHECK: [[@LINE]]| | + int rc2 = ({ if (argc > 3) bar(); 0; }); // CHECK: [[@LINE]]| 1| int rc2 = + printf("coverage after bar is present\n"); // CHECK: [[@LINE]]| 1| printf( + return rc + rc2; // CHECK: [[@LINE]]| 1| return rc +} // CHECK: [[@LINE]]| 1|} >From 0dc7ea6a13b34901bb6ca0253ad73e8ef5037244 Mon Sep 17 00:00:00 2001 From: Justin Cady <d...@justincady.com> Date: Fri, 14 Mar 2025 12:32:57 -0400 Subject: [PATCH 2/3] Avoid format warning to preserve readable CHECK lines --- .../test/profile/Linux/coverage-statement-expression.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp index 5894275b941a2..7c76555e3300b 100644 --- a/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -5,6 +5,7 @@ #include <stdio.h> +// clang-format off __attribute__ ((__noreturn__)) void foo(void) { while (1); } // CHECK: [[@LINE]]| 0|void foo(void) _Noreturn void bar(void) { while (1); } // CHECK: [[@LINE]]| 0|_Noreturn void bar(void) @@ -17,3 +18,4 @@ int main(int argc, char **argv) { // CHECK: [[@LINE]]| 1|int main printf("coverage after bar is present\n"); // CHECK: [[@LINE]]| 1| printf( return rc + rc2; // CHECK: [[@LINE]]| 1| return rc } // CHECK: [[@LINE]]| 1|} +// clang-format on >From a7cb1d44a4647ef7bd1b79edadfe8cd4ddf99a92 Mon Sep 17 00:00:00 2001 From: Justin Cady <d...@justincady.com> Date: Mon, 17 Mar 2025 17:12:06 -0400 Subject: [PATCH 3/3] Fix CHECK-NOT with a long pattern --- clang/test/CoverageMapping/terminate-statements.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp index d03e35630b317..3f8e43f0fbcb6 100644 --- a/clang/test/CoverageMapping/terminate-statements.cpp +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -348,8 +348,8 @@ int elsecondnoret(void) { // CHECK-LABEL: _Z18statementexprnoretb int statementexprnoret(bool crash) { - int rc = ({ if (crash) abort(); 0; }); // CHECK-NOT: Gap,File 0, [[@LINE]]:41 -> [[@LINE+1]]:3 = 0 - return rc; + int rc = ({ if (crash) abort(); 0; }); // CHECK: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap } int main() { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits