diff --git a/clang/lib/CodeGen/CoverageMappingGen.cpp b/clang/lib/CodeGen/CoverageMappingGen.cpp --- a/clang/lib/CodeGen/CoverageMappingGen.cpp +++ b/clang/lib/CodeGen/CoverageMappingGen.cpp @@ -556,8 +556,8 @@ /// expressions cross file or macro boundaries. SourceLocation MostRecentLocation; - /// Location of the last terminated region. - Optional> LastTerminatedRegion; + /// If there is a return, co_return, goto or throw inside. + bool HasTerminateStmt = false; /// Return a counter for the subtraction of \c RHS from \c LHS Counter subtractCounters(Counter LHS, Counter RHS) { @@ -590,7 +590,6 @@ if (StartLoc && !FalseCount.hasValue()) { MostRecentLocation = *StartLoc; - completeDeferred(Count, MostRecentLocation); } RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc, @@ -640,27 +639,6 @@ return Index; } - /// Complete a deferred region created after a terminated region at the - /// top-level. - void completeTopLevelDeferredRegion(Counter Count, - SourceLocation DeferredEndLoc) { - if (DeferredRegion || !LastTerminatedRegion) - return; - - if (LastTerminatedRegion->second != RegionStack.size()) - return; - - SourceLocation Start = LastTerminatedRegion->first; - if (SM.getFileID(Start) != SM.getMainFileID()) - return; - - SourceMappingRegion DR = RegionStack.back(); - DR.setStartLoc(Start); - DR.setDeferred(false); - DeferredRegion = DR; - completeDeferred(Count, DeferredEndLoc); - } - size_t locationDepth(SourceLocation Loc) { size_t Depth = 0; while (Loc.isValid()) { @@ -764,12 +742,6 @@ ParentOfDeferredRegion = true; } RegionStack.pop_back(); - - // If the zero region pushed after the last terminated region no longer - // exists, clear its cached information. - if (LastTerminatedRegion && - RegionStack.size() < LastTerminatedRegion->second) - LastTerminatedRegion = None; } assert(!ParentOfDeferredRegion && "Deferred region with no parent"); } @@ -967,9 +939,10 @@ if (!Region.hasEndLoc()) Region.setEndLoc(EndLoc); pushRegion(Counter::getZero()); - auto &ZeroRegion = getRegion(); - ZeroRegion.setDeferred(true); - LastTerminatedRegion = {EndLoc, RegionStack.size()}; + if (!HasTerminateStmt) { + auto &ZeroRegion = getRegion(); + ZeroRegion.setDeferred(true); + } } /// Find a valid gap range between \p AfterLoc and \p BeforeLoc. @@ -1004,7 +977,8 @@ // file, the range may not be in source order. if (AfterLoc.isMacroID() || BeforeLoc.isMacroID()) return None; - if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) + if (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc) || + !SpellingRegion(SM, AfterLoc, BeforeLoc).isInSourceOrder()) return None; return {{AfterLoc, BeforeLoc}}; } @@ -1056,9 +1030,31 @@ void VisitStmt(const Stmt *S) { if (S->getBeginLoc().isValid()) extendRegion(S); + const Stmt *LastStmt = nullptr; + bool LastStmtHasTerminateStmt = false; + bool SaveTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; for (const Stmt *Child : S->children()) - if (Child) + 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 && LastStmtHasTerminateStmt && + !dyn_cast(Child)) { + auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child)); + if (Gap) + fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), + Counter::getZero()); + LastStmtHasTerminateStmt = false; + SaveTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + } this->Visit(Child); + LastStmt = Child; + LastStmtHasTerminateStmt = HasTerminateStmt; + } + if (SaveTerminateStmt) + HasTerminateStmt = true; handleFileExit(getEnd(S)); } @@ -1093,6 +1089,7 @@ extendRegion(S); if (S->getRetValue()) Visit(S->getRetValue()); + HasTerminateStmt = true; terminateRegion(S); } @@ -1105,6 +1102,7 @@ extendRegion(S); if (S->getOperand()) Visit(S->getOperand()); + HasTerminateStmt = true; terminateRegion(S); } @@ -1112,16 +1110,18 @@ extendRegion(E); if (E->getSubExpr()) Visit(E->getSubExpr()); + HasTerminateStmt = true; terminateRegion(E); } - void VisitGotoStmt(const GotoStmt *S) { terminateRegion(S); } + void VisitGotoStmt(const GotoStmt *S) { + HasTerminateStmt = true; + terminateRegion(S); + } void VisitLabelStmt(const LabelStmt *S) { Counter LabelCount = getRegionCounter(S); SourceLocation Start = getStart(S); - completeTopLevelDeferredRegion(LabelCount, Start); - completeDeferred(LabelCount, Start); // We can't extendRegion here or we risk overlapping with our new region. handleFileExit(Start); pushRegion(LabelCount, Start); @@ -1150,8 +1150,10 @@ // Terminate the region when we hit a noreturn function. // (This is helpful dealing with switch statements.) QualType CalleeType = E->getCallee()->getType(); - if (getFunctionExtInfo(*CalleeType).getNoReturn()) + if (getFunctionExtInfo(*CalleeType).getNoReturn()) { + HasTerminateStmt = true; terminateRegion(E); + } } void VisitWhileStmt(const WhileStmt *S) { @@ -1166,6 +1168,9 @@ Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); BreakContinue BC = BreakContinueStack.pop_back_val(); + bool BodyHasTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + // Go back to handle the condition. Counter CondCount = addCounters(ParentCount, BackedgeCount, BC.ContinueCount); @@ -1185,6 +1190,9 @@ // Create Branch Region around condition. createBranchRegion(S->getCond(), BodyCount, subtractCounters(CondCount, BodyCount)); + + if (BodyHasTerminateStmt) + HasTerminateStmt = true; } void VisitDoStmt(const DoStmt *S) { @@ -1199,6 +1207,9 @@ propagateCounts(addCounters(ParentCount, BodyCount), S->getBody()); BreakContinue BC = BreakContinueStack.pop_back_val(); + bool BodyHasTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + Counter CondCount = addCounters(BackedgeCount, BC.ContinueCount); propagateCounts(CondCount, S->getCond()); @@ -1210,6 +1221,9 @@ // Create Branch Region around condition. createBranchRegion(S->getCond(), BodyCount, subtractCounters(CondCount, BodyCount)); + + if (BodyHasTerminateStmt) + HasTerminateStmt = true; } void VisitForStmt(const ForStmt *S) { @@ -1230,6 +1244,9 @@ Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); BreakContinue BodyBC = BreakContinueStack.pop_back_val(); + bool BodyHasTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + // The increment is essentially part of the body but it needs to include // the count for all the continue statements. BreakContinue IncrementBC; @@ -1260,6 +1277,9 @@ // Create Branch Region around condition. createBranchRegion(S->getCond(), BodyCount, subtractCounters(CondCount, BodyCount)); + + if (BodyHasTerminateStmt) + HasTerminateStmt = true; } void VisitCXXForRangeStmt(const CXXForRangeStmt *S) { @@ -1277,6 +1297,9 @@ Counter BackedgeCount = propagateCounts(BodyCount, S->getBody()); BreakContinue BC = BreakContinueStack.pop_back_val(); + bool BodyHasTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + // The body count applies to the area immediately after the range. auto Gap = findGapAreaBetween(S->getRParenLoc(), getStart(S->getBody())); if (Gap) @@ -1292,6 +1315,9 @@ // Create Branch Region around condition. createBranchRegion(S->getCond(), BodyCount, subtractCounters(LoopCount, BodyCount)); + + if (BodyHasTerminateStmt) + HasTerminateStmt = true; } void VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S) { @@ -1336,8 +1362,7 @@ // the unreachable code at the beginning of the switch body. size_t Index = pushRegion(Counter::getZero(), getStart(CS)); getRegion().setGap(true); - for (const auto *Child : CS->children()) - Visit(Child); + Visit(Body); // Set the end for the body of the switch, if it isn't already set. for (size_t i = RegionStack.size(); i != Index; --i) { @@ -1435,12 +1460,18 @@ Counter ElseCount = subtractCounters(ParentCount, ThenCount); if (const Stmt *Else = S->getElse()) { + bool ThenHasTerminateStmt = HasTerminateStmt; + HasTerminateStmt = false; + // The 'else' count applies to the area immediately after the 'then'. Gap = findGapAreaBetween(getEnd(S->getThen()), getStart(Else)); if (Gap) fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(), ElseCount); extendRegion(Else); OutCount = addCounters(OutCount, propagateCounts(ElseCount, Else)); + + if (ThenHasTerminateStmt) + HasTerminateStmt = true; } else OutCount = addCounters(OutCount, ElseCount); diff --git a/clang/test/CoverageMapping/classtemplate.cpp b/clang/test/CoverageMapping/classtemplate.cpp --- a/clang/test/CoverageMapping/classtemplate.cpp +++ b/clang/test/CoverageMapping/classtemplate.cpp @@ -80,7 +80,7 @@ // CHECK-INIT-LIST-LABEL: _Z5Test4v: std::map Test4() { // CHECK-INIT-LIST: File 0, [[@LINE]]:28 -> [[@LINE+3]]:2 = #0 - abort(); + abort(); // CHECK-INIT-LIST-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0 return std::map{{0, 0}}; // CHECK-INIT-LIST-NEXT: [[@LINE]]:3 -> [[@LINE]]:36 = 0 } diff --git a/clang/test/CoverageMapping/coroutine.cpp b/clang/test/CoverageMapping/coroutine.cpp --- a/clang/test/CoverageMapping/coroutine.cpp +++ b/clang/test/CoverageMapping/coroutine.cpp @@ -44,5 +44,5 @@ } else { // CHECK-NEXT: File 0, [[@LINE-3]]:15 -> [[@LINE]]:4 = #1 co_return x + 42; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE-1]]:10 = (#0 - #1) } // CHECK-NEXT: File 0, [[@LINE-2]]:10 -> [[@LINE]]:4 = (#0 - #1) - co_return x; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = #1 -} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE]]:2 = #1 + co_return x; // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:14 = #1 diff --git a/clang/test/CoverageMapping/deferred-region.cpp b/clang/test/CoverageMapping/deferred-region.cpp --- a/clang/test/CoverageMapping/deferred-region.cpp +++ b/clang/test/CoverageMapping/deferred-region.cpp @@ -16,7 +16,7 @@ void fooo(int x) { if (x == 0) { return; - } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = (#0 - #1) + } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = 0 if (x == 1) { return; @@ -32,7 +32,7 @@ // CHECK-LABEL: _Z3mazv: void maz() { if (true) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 return; // CHECK-NOT: Gap } @@ -40,7 +40,7 @@ // CHECK-LABEL: _Z4maazv: void maaz() { if (true) - return; // CHECK: Gap,File 0, [[@LINE]]:11 + return; else return; // CHECK-NOT: Gap,File 0, [[@LINE]] } @@ -49,7 +49,7 @@ void maaaz() { if (true) { return; - } else { // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE]]:10 + } else { return; // CHECK-NOT: Gap,File 0, [[@LINE]] } } @@ -57,10 +57,10 @@ // CHECK-LABEL: _Z3bari: void bar(int x) { IF (x) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 IF (!x) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = ((#0 - #1) - #2) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 foo(x); } @@ -95,18 +95,18 @@ int i = 0; if (false) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 if (false) i++; if (i + 100 > 0) { // CHECK: [[@LINE]]:20 -> [[@LINE+6]]:4 = #3 if (false) // CHECK: [[@LINE+1]]:7 -> [[@LINE+1]]:13 = #4 - return; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:5 = (#3 - #4) - // CHECK: [[@LINE+1]]:5 -> [[@LINE+3]]:4 = (#3 - #4) - return; // CHECK: Gap,File 0, [[@LINE]]:5 -> [[@LINE+4]]:3 = ((#0 - #1) - #3) + return; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+2]]:5 = 0 + // CHECK: [[@LINE+1]]:5 -> [[@LINE+1]]:11 = (#3 - #4) + return; - } + } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = 0 if (false) return; // CHECK-NOT: Gap,File 0, [[@LINE]]:11 @@ -115,7 +115,7 @@ // CHECK-LABEL: _Z8for_loopv: void for_loop() { if (false) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 for (int i = 0; i < 10; ++i) { if (i % 2 == 0) @@ -135,7 +135,7 @@ // CHECK-LABEL: _Z10while_loopv: void while_loop() { if (false) - return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1) + return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = 0 int x = 0; while (++x < 10) { @@ -150,7 +150,7 @@ } if (x == 0) - throw Error(); // CHECK: Gap,File 0, [[@LINE]]:20 -> [[@LINE+2]]:5 = ((#2 - #3) - #7) + throw Error(); // CHECK: Gap,File 0, [[@LINE]]:21 -> [[@LINE+2]]:5 = 0 while (++x < 9) { if (x == 0) @@ -163,9 +163,9 @@ // CHECK-LABEL: _Z5gotosv: void gotos() { if (false) - goto out; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:3 = (#0 - #1) + goto out; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+2]]:3 = 0 - return; // CHECK: [[@LINE]]:3 -> [[@LINE+4]]:2 = (#0 - #1) + return; // CHECK: [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1) out: return; // CHECK-NOT: Gap,File 0, [[@LINE]]:8 @@ -185,7 +185,7 @@ #include "deferred-region-helper.h" // CHECK-LABEL: _Z13included_funcv: // CHECK: Gap,File 0, 2:13 -> 3:5 = #1 -// CHECK: Gap,File 0, 3:11 -> 4:3 = (#0 - #1) +// CHECK: Gap,File 0, 3:12 -> 4:3 = 0 // CHECK-LABEL: _Z7includev: void include() { diff --git a/clang/test/CoverageMapping/label.cpp b/clang/test/CoverageMapping/label.cpp --- a/clang/test/CoverageMapping/label.cpp +++ b/clang/test/CoverageMapping/label.cpp @@ -13,10 +13,10 @@ int j = 1; } int m = 2; - } else - goto x; // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = (#1 - #2) - int k = 3; // CHECK-NEXT: File 0, [[@LINE-1]]:13 -> [[@LINE]]:5 = #3 - } // CHECK-NEXT: File 0, [[@LINE-1]]:5 -> [[@LINE]]:4 = #3 + } else // CHECK: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:13 = (#1 - #2) + goto x; // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:5 = 0 + int k = 3; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = #3 + } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = 0 static int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:2 = ((#0 + #3) - #1) ++j; if(j == 1) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = ((#0 + #3) - #1) @@ -27,9 +27,9 @@ void test1(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2 = #0 if(x == 0) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = #0 goto a; // CHECK: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1 - // CHECK-NEXT: File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = (#0 - #1) - goto b; // CHECK: File 0, [[@LINE]]:3 -> [[@LINE+5]]:2 = (#0 - #1) - // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:9 -> [[@LINE+1]]:1 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = 0 + goto b; // CHECK: File 0, [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:10 -> [[@LINE+1]]:1 = 0 a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+3]]:2 = #2 b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2 = #3 x = x + 1; @@ -39,11 +39,11 @@ void test2(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2 = #0 if(x == 0) // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE]]:12 = #0 goto a; // CHECK: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = #1 - // CHECK: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+3]]:8 = (#0 - #1) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+3]]:8 = (#0 - #1) // CHECK-NEXT: File 0, [[@LINE+2]]:8 -> [[@LINE+3]]:11 = (#0 - #1) // CHECK-NEXT: File 0, [[@LINE+1]]:11 -> [[@LINE+1]]:17 = (#0 - #1) else if(x == 1) // CHECK: File 0, [[@LINE+1]]:5 -> [[@LINE+1]]:11 = #2 - goto b; // CHECK-NEXT: File 0, [[@LINE]]:11 -> [[@LINE+1]]:1 = #3 + goto b; // CHECK-NEXT: Gap,File 0, [[@LINE]]:12 -> [[@LINE+1]]:1 = 0 a: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+3]]:2 = #3 b: // CHECK-NEXT: File 0, [[@LINE]]:1 -> [[@LINE+2]]:2 = #4 x = x + 1; @@ -53,8 +53,8 @@ #define a b void test3() { if (0) - goto b; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:1 = [[retnCount:#[0-9]+]] -a: // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:2 = [[retnCount]] (Expanded file = 1) + goto b; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+1]]:1 = 0 +a: // CHECK-NEXT: Expansion,File 0, [[@LINE]]:1 -> [[@LINE]]:2 = [[retnCount:#[0-9]+]] (Expanded file = 1) return; // CHECK-NEXT: File 0, [[@LINE-1]]:2 -> [[@LINE]]:9 = [[retnCount]] } #undef a @@ -66,16 +66,16 @@ a: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+12]]:4 = #2 if(i < 3) // CHECK-NEXT: File 0, [[@LINE]]:8 -> [[@LINE]]:13 = #2 goto e; // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:13 = #3 - // CHECK-NEXT: File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:5 = (#2 - #3) - goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+8]]:4 = (#2 - #3) - // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = #4 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:5 = 0 + goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = (#2 - #3) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = 0 b: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+6]]:4 = #4 j = 2; c: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:4 = #5 j = 1; // CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+2]]:4 = #6 e: f: ; // CHECK-NEXT: File 0, [[@LINE]]:6 -> [[@LINE+1]]:4 = #7 - } + } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = 0 func(); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:2 = ((#0 + #7) - #1) test1(0); test2(2); diff --git a/clang/test/CoverageMapping/moremacros.c b/clang/test/CoverageMapping/moremacros.c --- a/clang/test/CoverageMapping/moremacros.c +++ b/clang/test/CoverageMapping/moremacros.c @@ -17,7 +17,7 @@ if (!argc) LBRAC return 0; // CHECK-NEXT: Expansion,File 0, [[@LINE+1]]:3 -> [[@LINE+1]]:8 = #2 - RBRAC // CHECK-NEXT: [[@LINE]]:8 -> [[@LINE+8]]:3 = (#0 - #2) + RBRAC // CHECK-NEXT: [[@LINE]]:8 -> [[@LINE+8]]:3 = 0 // CHECK-NEXT: File 0, [[@LINE+6]]:3 -> [[@LINE+17]]:2 = (#0 - #2) // CHECK-NEXT: File 0, [[@LINE+5]]:7 -> [[@LINE+5]]:12 = (#0 - #2) @@ -27,7 +27,7 @@ // CHECK-NEXT: File 0, [[@LINE+1]]:19 -> [[@LINE+3]]:4 = #3 if (!argc) LBRAC return 0; - } // CHECK-NEXT: [[@LINE]]:4 -> [[@LINE+5]]:3 = ((#0 - #2) - #3) + } // CHECK-NEXT: [[@LINE]]:4 -> [[@LINE+5]]:3 = 0 // CHECK-NEXT: File 0, [[@LINE+3]]:3 -> [[@LINE+7]]:2 = ((#0 - #2) - #3) // CHECK-NEXT: File 0, [[@LINE+2]]:7 -> [[@LINE+2]]:12 = ((#0 - #2) - #3) diff --git a/clang/test/CoverageMapping/return.c b/clang/test/CoverageMapping/return.c --- a/clang/test/CoverageMapping/return.c +++ b/clang/test/CoverageMapping/return.c @@ -2,7 +2,7 @@ // CHECK: func void func() { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+3]]:2 = #0 - return; + return; // CHECK-NEXT: Gap,File 0, [[@LINE]]:10 -> [[@LINE+1]]:3 = 0 int i = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = 0 } @@ -14,7 +14,7 @@ for(int i = 0; i < 10; ++i) { // CHECK: File 0, [[@LINE]]:31 -> {{[0-9]+}}:4 = #1 // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:13 = #1 if(i > 2) { // CHECK: File 0, [[@LINE]]:15 -> [[@LINE+2]]:6 = #2 - return; // CHECK-NEXT: File 0, [[@LINE+1]]:6 -> [[@LINE+3]]:5 = (#1 - #2) + return; // CHECK-NEXT: Gap,File 0, [[@LINE+1]]:6 -> [[@LINE+3]]:5 = 0 } // CHECK-NEXT: File 0, [[@LINE+2]]:5 -> {{[0-9]+}}:4 = (#1 - #2) // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:14 = (#1 - #2) if(i == 3) { // CHECK: File 0, [[@LINE]]:16 -> [[@LINE+2]]:6 = #3 @@ -28,13 +28,14 @@ // CHECK-NEXT: func3 void func3(int x) { // CHECK-NEXT: File 0, [[@LINE]]:19 -> {{[0-9]+}}:2 = #0 // CHECK-NEXT: File 0, [[@LINE+1]]:6 -> [[@LINE+1]]:11 = #0 - if(x > 5) { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+6]]:4 = #1 + if(x > 5) { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+7]]:4 = #1 while(x >= 9) { // CHECK-NEXT: File 0, [[@LINE]]:11 -> [[@LINE]]:17 = #1 - return; // CHECK: File 0, [[@LINE-1]]:19 -> [[@LINE+2]]:6 = #2 + return; // CHECK: File 0, [[@LINE-1]]:19 -> [[@LINE+3]]:6 = #2 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:7 = 0 --x; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+1]]:6 = 0 - } + } // CHECK-NEXT: Gap,File 0, [[@LINE]]:6 -> [[@LINE+1]]:5 = 0 int i = 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = (#1 - #2) - } + } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = 0 int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = (#0 - #2) } diff --git a/clang/test/CoverageMapping/switch.cpp b/clang/test/CoverageMapping/switch.cpp --- a/clang/test/CoverageMapping/switch.cpp +++ b/clang/test/CoverageMapping/switch.cpp @@ -1,14 +1,16 @@ // RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -std=c++1z -triple %itanium_abi_triple -main-file-name switch.cpp %s | FileCheck %s // CHECK: foo -void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+9]]:2 = #0 +void foo(int i) { // CHECK-NEXT: File 0, [[@LINE]]:17 -> [[@LINE+11]]:2 = #0 switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = ((#0 - #2) - #3), (#2 + #3) - // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+4]]:10 = 0 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+5]]:10 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:11 = #2 return; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #3 break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) - } // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:10 -> [[@LINE+1]]:3 = #1 + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:10 -> [[@LINE+2]]:3 = #1 + } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = 0 int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #1 } @@ -93,7 +95,7 @@ case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #2 return 0; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2) - + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 = #3 return 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #3, (#0 - #3) } @@ -120,12 +122,14 @@ void abort(void) __attribute((noreturn)); // CHECK: noret -int noret(int x) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+9]]:2 - switch (x) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+6]]:14 = 0 +int noret(int x) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> [[@LINE+11]]:2 + switch (x) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+8]]:14 = 0 default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:12 abort(); // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #2, (#0 - #2) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+1]]:3 = 0 case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:13 return 5; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE+1]]:3 = 0 case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:14 return 10; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) } diff --git a/clang/test/CoverageMapping/switchmacro.c b/clang/test/CoverageMapping/switchmacro.c --- a/clang/test/CoverageMapping/switchmacro.c +++ b/clang/test/CoverageMapping/switchmacro.c @@ -10,13 +10,13 @@ if (i == 1) // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE]]:15 = #2 // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:9 -> [[@LINE-1]]:15 = #3, (#2 - #3) return 0; // CHECK: File 0, [[@LINE]]:7 -> [[@LINE]]:15 = #3 - // CHECK-NEXT: File 0, [[@LINE-1]]:15 -> [[@LINE+3]]:5 = (#2 - #3) + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:16 -> [[@LINE+3]]:5 = 0 // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:5 -> [[@LINE+2]]:8 = (#2 - #3) (Expanded file = 1) // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> {{[0-9]+}}:11 = (#2 - #3) FOO(1); case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:13 = ((#2 + #4) - #3) // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4) - return 2; // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+6]]:3 = #5 + return 2; // CHECK-NEXT: Gap,File 0, [[@LINE]]:14 -> [[@LINE+4]]:3 = 0 // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:6 = 0 // CHECK-NEXT: File 0, [[@LINE+1]]:6 -> {{[0-9]+}}:11 = 0 diff --git a/clang/test/CoverageMapping/terminate-statements.cpp b/clang/test/CoverageMapping/terminate-statements.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CoverageMapping/terminate-statements.cpp @@ -0,0 +1,130 @@ +// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name deferred-region.cpp -I %S/Inputs %s | FileCheck %s + +int f1() { + return 0; + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE]]:3 = 0 +} + +int f2(int i) { + if (i) + return 0; + else + ; + return 1; // CHECK: Gap,File 0, [[@LINE-1]]:6 -> [[@LINE]]:3 = 0 +} + +int f3() { + for (int a = 1; a < 9; a--) + return a; + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 +} + +int f4(int i) { + while (i > 0) { + i++; + return i; + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f5(int i) { + do { + return i; + } while (i > 0); + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:19 -> [[@LINE]]:3 = 0 +} + +int f6() { + int arr[] = {1, 2, 3, 4}; + for (int i : arr) { + return i; + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f7() { + { + { + return 0; + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:6 -> [[@LINE]]:5 = 0 + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f8(int i) { + if (i == 1) + return 1; + if (i == 2) // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 + return 2; + if (i == 3) // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 + return 3; + return 4; // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 +} + +int f9(int i) { + if (i == 1) + return 1; + else if (i == 2) + return 2; + return 3; // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 +} + +int f10(int i) { + if (i == 1) { + return 0; + if (i == 2) // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:5 = 0 + return 0; + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f11(int i) { + if (i == 1) + i = 2; + else + return 0; + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:3 = 0 +} + +int f12(int i) { + int x = 1; + if (x == 1) { + if (x == 1) { + return 0; + } + } else if (x == 2) { + x = 2; + } + return 1; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f13(int i) { + if (i == 1) { + return 0; + if (i == 2) { // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:5 = 0 + i++; + } + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f14(int i) { + while (i == 0) { + while (i < 10) { + i++; + return 0; + } + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} + +int f15(int i) { + while (i == 0) { + return 0; + while (i < 10) { // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:5 = 0 + i++; + } + } + return 0; // CHECK: Gap,File 0, [[@LINE-1]]:4 -> [[@LINE]]:3 = 0 +} diff --git a/clang/test/CoverageMapping/trycatch.cpp b/clang/test/CoverageMapping/trycatch.cpp --- a/clang/test/CoverageMapping/trycatch.cpp +++ b/clang/test/CoverageMapping/trycatch.cpp @@ -13,7 +13,7 @@ void func(int i) { // CHECK-NEXT: File 0, [[@LINE]]:18 -> {{[0-9]+}}:2 = #0 // CHECK-NEXT: File 0, [[@LINE+1]]:6 -> [[@LINE+1]]:11 = #0 if(i % 2) { // CHECK: File 0, [[@LINE]]:13 -> [[@LINE+4]]:4 = #1 - throw Error(); + throw Error(); // CHECK-NEXT: Gap,File 0, [[@LINE]]:19 -> [[@LINE+1]]:5 = 0 int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+2]]:4 = 0 // CHECK: File 0, [[@LINE+1]]:10 -> [[@LINE+2]]:27 = (#0 - #1) } else if(i == 8) // CHECK-NEXT: File 0, [[@LINE]]:13 -> [[@LINE]]:19 = (#0 - #1) diff --git a/clang/test/CoverageMapping/unreachable-macro.c b/clang/test/CoverageMapping/unreachable-macro.c --- a/clang/test/CoverageMapping/unreachable-macro.c +++ b/clang/test/CoverageMapping/unreachable-macro.c @@ -6,6 +6,7 @@ void counters_in_macro_following_unreachable() { // CHECK-NEXT: File 0, [[@LINE-1]]:48 -> {{[0-9]+}}:2 = #0 return; + // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:10 -> [[@LINE+3]]:3 = 0 // CHECK-NEXT: Expansion,File 0, [[@LINE+2]]:3 -> [[@LINE+2]]:8 = 0 // CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+2]]:2 = 0 WHILE