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..3f8e43f0fbcb6 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: File 0, 351:35 -> 352:12 = (#0 - #1) + return rc; // CHECK-NOT: Gap +} + 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..7c76555e3300b --- /dev/null +++ b/compiler-rt/test/profile/Linux/coverage-statement-expression.cpp @@ -0,0 +1,21 @@ +// 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 + +// 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) + // 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|} +// clang-format on