[clang] [clang][CoverageMapping] do not emit gap when either end is an `ImplicitValueInitExpr` (PR #89564)

Wentao Zhang via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 22 09:38:03 PDT 2024


https://github.com/whentojump updated https://github.com/llvm/llvm-project/pull/89564

>From abbdb318d62bb2e5ab6f07e7d0fe11f4a06b5a11 Mon Sep 17 00:00:00 2001
From: Wentao Zhang <zhangwt1997 at gmail.com>
Date: Sun, 21 Apr 2024 21:27:01 -0500
Subject: [PATCH 1/4] [clang][CoverageMapping] do not emit gap when either end
 is an ImplicitValueInitExpr

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 64c39c5de351c7..dd8c0577d758ca 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1368,9 +1368,12 @@ struct CounterCoverageMappingBuilder
     for (const Stmt *Child : S->children())
       if (Child) {
         // If last statement contains terminate statements, add a gap area
-        // between the two statements. Skipping attributed statements, because
-        // they don't have valid start location.
-        if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
+        // between the two statements. Skipping attributed statements and
+        // implicit initializations, because they don't have valid source
+        // location.
+        if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child) &&
+            !isa<ImplicitValueInitExpr>(Child) &&
+            !isa<ImplicitValueInitExpr>(LastStmt)) {
           auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
           if (Gap)
             fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),

>From f2931efcc97ce418ab724e2cb052b47ec5c87986 Mon Sep 17 00:00:00 2001
From: Wentao Zhang <zhangwt1997 at gmail.com>
Date: Mon, 22 Apr 2024 11:17:49 -0500
Subject: [PATCH 2/4] add tests

---
 .../CoverageMapping/statement-expression.c    | 36 +++++++++++++++++++
 1 file changed, 36 insertions(+)
 create mode 100644 clang/test/CoverageMapping/statement-expression.c

diff --git a/clang/test/CoverageMapping/statement-expression.c b/clang/test/CoverageMapping/statement-expression.c
new file mode 100644
index 00000000000000..5f9ab5838af342
--- /dev/null
+++ b/clang/test/CoverageMapping/statement-expression.c
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name statement-expression.c %s
+
+// No crash for the following examples, where GNU Statement Expression extension
+// could introduce region terminators (break, goto etc) before implicit
+// initializers in a struct or an array.
+// See https://github.com/llvm/llvm-project/pull/89564
+
+struct Foo {
+  int field1;
+  int field2;
+};
+
+void f1(void) {
+  struct Foo foo = {
+    .field1 = ({
+      switch (0) {
+      case 0:
+        break; // A region terminator
+      }
+      0;
+    }),
+    // ImplicitValueInitExpr introduced here for .field2
+  };
+}
+
+void f2(void) {
+  int arr[3] = {
+    [0] = ({
+        goto L0; // A region terminator
+L0:
+      0;
+    }),
+    // ImplicitValueInitExpr introduced here for subscript [1]
+    [2] = 0,
+  };
+}

>From 6a00626a44b23815b99ad217b0ab9ed8567c19a2 Mon Sep 17 00:00:00 2001
From: Wentao Zhang <zhangwt1997 at gmail.com>
Date: Mon, 22 Apr 2024 11:20:08 -0500
Subject: [PATCH 3/4] Revert "[clang][CoverageMapping] do not emit gap when
 either end is an ImplicitValueInitExpr"

This reverts commit abbdb318d62bb2e5ab6f07e7d0fe11f4a06b5a11.
---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index dd8c0577d758ca..64c39c5de351c7 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1368,12 +1368,9 @@ struct CounterCoverageMappingBuilder
     for (const Stmt *Child : S->children())
       if (Child) {
         // If last statement contains terminate statements, add a gap area
-        // between the two statements. Skipping attributed statements and
-        // implicit initializations, because they don't have valid source
-        // location.
-        if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child) &&
-            !isa<ImplicitValueInitExpr>(Child) &&
-            !isa<ImplicitValueInitExpr>(LastStmt)) {
+        // between the two statements. Skipping attributed statements, because
+        // they don't have valid start location.
+        if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
           auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
           if (Gap)
             fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),

>From c7359ddf8ee689f12fa75ccc3ccff1bfecb2027a Mon Sep 17 00:00:00 2001
From: Wentao Zhang <zhangwt1997 at gmail.com>
Date: Mon, 22 Apr 2024 11:33:41 -0500
Subject: [PATCH 4/4] move into findGapAreaBetween

---
 clang/lib/CodeGen/CoverageMappingGen.cpp | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp
index 64c39c5de351c7..733686d4946b3c 100644
--- a/clang/lib/CodeGen/CoverageMappingGen.cpp
+++ b/clang/lib/CodeGen/CoverageMappingGen.cpp
@@ -1208,6 +1208,12 @@ struct CounterCoverageMappingBuilder
   /// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
   std::optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
                                                 SourceLocation BeforeLoc) {
+    // Some statements (like AttributedStmt and ImplicitValueInitExpr) don't
+    // have valid source locations. Do not emit a gap region if this is the case
+    // in either AfterLoc end or BeforeLoc end.
+    if (AfterLoc.isInvalid() || BeforeLoc.isInvalid())
+      return std::nullopt;
+
     // If AfterLoc is in function-like macro, use the right parenthesis
     // location.
     if (AfterLoc.isMacroID()) {
@@ -1368,9 +1374,8 @@ struct CounterCoverageMappingBuilder
     for (const Stmt *Child : S->children())
       if (Child) {
         // If last statement contains terminate statements, add a gap area
-        // between the two statements. Skipping attributed statements, because
-        // they don't have valid start location.
-        if (LastStmt && HasTerminateStmt && !isa<AttributedStmt>(Child)) {
+        // between the two statements.
+        if (LastStmt && HasTerminateStmt) {
           auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
           if (Gap)
             fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),



More information about the cfe-commits mailing list