/// The region's ending location.
Optional<SourceLocation> LocEnd;
- /// Whether this region should be emitted after its parent is emitted.
- bool DeferRegion;
-
/// Whether this region is a gap region. The count from a gap region is set
/// as the line execution count if there are no other regions on the line.
bool GapRegion;
public:
SourceMappingRegion(Counter Count, Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd, bool DeferRegion = false,
- bool GapRegion = false)
- : Count(Count), LocStart(LocStart), LocEnd(LocEnd),
- DeferRegion(DeferRegion), GapRegion(GapRegion) {}
+ Optional<SourceLocation> LocEnd, bool GapRegion = false)
+ : Count(Count), LocStart(LocStart), LocEnd(LocEnd), GapRegion(GapRegion) {
+ }
SourceMappingRegion(Counter Count, Optional<Counter> FalseCount,
Optional<SourceLocation> LocStart,
- Optional<SourceLocation> LocEnd, bool DeferRegion = false,
- bool GapRegion = false)
+ Optional<SourceLocation> LocEnd, bool GapRegion = false)
: Count(Count), FalseCount(FalseCount), LocStart(LocStart),
- LocEnd(LocEnd), DeferRegion(DeferRegion), GapRegion(GapRegion) {}
+ LocEnd(LocEnd), GapRegion(GapRegion) {}
const Counter &getCounter() const { return Count; }
return *LocEnd;
}
- bool isDeferred() const { return DeferRegion; }
-
- void setDeferred(bool Deferred) { DeferRegion = Deferred; }
-
bool isGap() const { return GapRegion; }
void setGap(bool Gap) { GapRegion = Gap; }
/// A stack of currently live regions.
std::vector<SourceMappingRegion> RegionStack;
- /// The currently deferred region: its end location and count can be set once
- /// its parent has been popped from the region stack.
- Optional<SourceMappingRegion> DeferredRegion;
-
CounterExpressionBuilder Builder;
/// A location in the most recently visited file or macro.
/// expressions cross file or macro boundaries.
SourceLocation MostRecentLocation;
- /// Location of the last terminated region.
- Optional<std::pair<SourceLocation, size_t>> LastTerminatedRegion;
+ /// Whether the visitor at a terminate statement.
+ bool HasTerminateStmt = false;
+
+ /// Gap region counter after terminate statement.
+ Counter GapRegionCounter;
/// Return a counter for the subtraction of \c RHS from \c LHS
Counter subtractCounters(Counter LHS, Counter RHS) {
if (StartLoc && !FalseCount.hasValue()) {
MostRecentLocation = *StartLoc;
- completeDeferred(Count, MostRecentLocation);
}
- RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc,
- FalseCount.hasValue());
+ RegionStack.emplace_back(Count, FalseCount, StartLoc, EndLoc);
return RegionStack.size() - 1;
}
- /// Complete any pending deferred region by setting its end location and
- /// count, and then pushing it onto the region stack.
- size_t completeDeferred(Counter Count, SourceLocation DeferredEndLoc) {
- size_t Index = RegionStack.size();
- if (!DeferredRegion)
- return Index;
-
- // Consume the pending region.
- SourceMappingRegion DR = DeferredRegion.getValue();
- DeferredRegion = None;
-
- // If the region ends in an expansion, find the expansion site.
- FileID StartFile = SM.getFileID(DR.getBeginLoc());
- if (SM.getFileID(DeferredEndLoc) != StartFile) {
- if (isNestedIn(DeferredEndLoc, StartFile)) {
- do {
- DeferredEndLoc = getIncludeOrExpansionLoc(DeferredEndLoc);
- } while (StartFile != SM.getFileID(DeferredEndLoc));
- } else {
- return Index;
- }
- }
-
- // The parent of this deferred region ends where the containing decl ends,
- // so the region isn't useful.
- if (DR.getBeginLoc() == DeferredEndLoc)
- return Index;
-
- // If we're visiting statements in non-source order (e.g switch cases or
- // a loop condition) we can't construct a sensible deferred region.
- if (!SpellingRegion(SM, DR.getBeginLoc(), DeferredEndLoc).isInSourceOrder())
- return Index;
-
- DR.setGap(true);
- DR.setCounter(Count);
- DR.setEndLoc(DeferredEndLoc);
- handleFileExit(DeferredEndLoc);
- RegionStack.push_back(DR);
- 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()) {
/// function's \c SourceRegions.
void popRegions(size_t ParentIndex) {
assert(RegionStack.size() >= ParentIndex && "parent not in stack");
- bool ParentOfDeferredRegion = false;
while (RegionStack.size() > ParentIndex) {
SourceMappingRegion &Region = RegionStack.back();
if (Region.hasStartLoc()) {
assert(SM.isWrittenInSameFile(Region.getBeginLoc(), EndLoc));
assert(SpellingRegion(SM, Region).isInSourceOrder());
SourceRegions.push_back(Region);
-
- if (ParentOfDeferredRegion) {
- ParentOfDeferredRegion = false;
-
- // If there's an existing deferred region, keep the old one, because
- // it means there are two consecutive returns (or a similar pattern).
- if (!DeferredRegion.hasValue() &&
- // File IDs aren't gathered within macro expansions, so it isn't
- // useful to try and create a deferred region inside of one.
- !EndLoc.isMacroID())
- DeferredRegion =
- SourceMappingRegion(Counter::getZero(), EndLoc, None);
}
- } else if (Region.isDeferred()) {
- assert(!ParentOfDeferredRegion && "Consecutive deferred regions");
- 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");
}
/// Return the currently active region.
handleFileExit(StartLoc);
if (!Region.hasStartLoc())
Region.setStartLoc(StartLoc);
-
- completeDeferred(Region.getCounter(), StartLoc);
}
/// Mark \c S as a terminator, starting a zero region.
if (!Region.hasEndLoc())
Region.setEndLoc(EndLoc);
pushRegion(Counter::getZero());
- auto &ZeroRegion = getRegion();
- ZeroRegion.setDeferred(true);
- LastTerminatedRegion = {EndLoc, RegionStack.size()};
+ HasTerminateStmt = true;
}
/// Find a valid gap range between \p AfterLoc and \p BeforeLoc.
Optional<SourceRange> findGapAreaBetween(SourceLocation AfterLoc,
SourceLocation BeforeLoc) {
+ // If AfterLoc is in function-like macro, use the right parenthesis
+ // location.
+ if (AfterLoc.isMacroID()) {
+ FileID FID = SM.getFileID(AfterLoc);
+ const SrcMgr::ExpansionInfo *EI = &SM.getSLocEntry(FID).getExpansion();
+ if (EI->isFunctionMacroExpansion())
+ AfterLoc = EI->getExpansionLocEnd();
+ }
+
size_t StartDepth = locationDepth(AfterLoc);
size_t EndDepth = locationDepth(BeforeLoc);
while (!SM.isWrittenInSameFile(AfterLoc, BeforeLoc)) {
// 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}};
}
CoverageMappingModuleGen &CVM,
llvm::DenseMap<const Stmt *, unsigned> &CounterMap, SourceManager &SM,
const LangOptions &LangOpts)
- : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap),
- DeferredRegion(None) {}
+ : CoverageMappingBuilder(CVM, SM, LangOpts), CounterMap(CounterMap) {}
/// Write the mapping data to the output stream
void write(llvm::raw_ostream &OS) {
llvm::SmallVector<unsigned, 8> VirtualFileMapping;
gatherFileIDs(VirtualFileMapping);
SourceRegionFilter Filter = emitExpansionRegions();
- assert(!DeferredRegion && "Deferred region never completed");
emitSourceRegions(Filter);
gatherSkippedRegions();
void VisitStmt(const Stmt *S) {
if (S->getBeginLoc().isValid())
extendRegion(S);
+ const Stmt *LastStmt = nullptr;
+ bool SaveTerminateStmt = HasTerminateStmt;
+ HasTerminateStmt = false;
+ GapRegionCounter = Counter::getZero();
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 && HasTerminateStmt && !dyn_cast<AttributedStmt>(Child)) {
+ auto Gap = findGapAreaBetween(getEnd(LastStmt), getStart(Child));
+ if (Gap)
+ fillGapAreaWithCount(Gap->getBegin(), Gap->getEnd(),
+ GapRegionCounter);
+ SaveTerminateStmt = true;
+ HasTerminateStmt = false;
+ }
this->Visit(Child);
+ LastStmt = Child;
+ }
+ if (SaveTerminateStmt)
+ HasTerminateStmt = true;
handleFileExit(getEnd(S));
}
void VisitDecl(const Decl *D) {
- assert(!DeferredRegion && "Deferred region never completed");
-
Stmt *Body = D->getBody();
// Do not propagate region counts into system headers.
propagateCounts(getRegionCounter(Body), Body,
/*VisitChildren=*/!Defaulted);
assert(RegionStack.empty() && "Regions entered but never exited");
-
- // Discard the last uncompleted deferred region in a decl, if one exists.
- // This prevents lines at the end of a function containing only whitespace
- // or closing braces from being marked as uncovered.
- DeferredRegion = None;
}
void VisitReturnStmt(const ReturnStmt *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);
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);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ if (BodyHasTerminateStmt)
+ HasTerminateStmt = true;
+ }
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
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());
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ }
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
subtractCounters(CondCount, BodyCount));
+
+ if (BodyHasTerminateStmt)
+ HasTerminateStmt = true;
}
void VisitForStmt(const ForStmt *S) {
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;
Counter OutCount = addCounters(BodyBC.BreakCount, IncrementBC.BreakCount,
subtractCounters(CondCount, BodyCount));
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ if (BodyHasTerminateStmt)
+ HasTerminateStmt = true;
+ }
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
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)
addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ if (BodyHasTerminateStmt)
+ HasTerminateStmt = true;
+ }
// Create Branch Region around condition.
createBranchRegion(S->getCond(), BodyCount,
addCounters(ParentCount, BackedgeCount, BC.ContinueCount);
Counter OutCount =
addCounters(BC.BreakCount, subtractCounters(LoopCount, BodyCount));
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ }
}
void VisitSwitchStmt(const SwitchStmt *S) {
// 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) {
Counter ExitCount = getRegionCounter(S);
SourceLocation ExitLoc = getEnd(S);
pushRegion(ExitCount);
+ GapRegionCounter = ExitCount;
// Ensure that handleFileExit recognizes when the end location is located
// in a different file.
else
pushRegion(Count, getStart(S));
+ GapRegionCounter = Count;
+
if (const auto *CS = dyn_cast<CaseStmt>(S)) {
Visit(CS->getLHS());
if (const Expr *RHS = CS->getRHS())
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);
- if (OutCount != ParentCount)
+ if (OutCount != ParentCount) {
pushRegion(OutCount);
+ GapRegionCounter = OutCount;
+ }
// Create Branch Region around condition.
createBranchRegion(S->getCond(), ThenCount,
int main() { // CHECK: File 0, [[@LINE]]:12 -> {{[0-9]+}}:2 = #0
int cnt = 0; // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = #0
while(cnt < 100) { // CHECK: File 0, [[@LINE]]:20 -> [[@LINE+3]]:4 = #1
- break;
+ break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:5 = 0
++cnt; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = 0
} // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = #0
while(cnt < 100) { // CHECK: File 0, [[@LINE]]:20 -> [[@LINE+6]]:4 = #2
{
- break;
+ break; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+1]]:7 = 0
++cnt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+3]]:4 = 0
- }
+ } // CHECK: Gap,File 0, [[@LINE]]:6 -> [[@LINE+1]]:5 = 0
++cnt;
} // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = ((#0 + #3) - #4)
while(cnt < 100) { // CHECK: File 0, [[@LINE]]:20 -> [[@LINE+7]]:4 = #3
// CHECK-NEXT: File 0, [[@LINE+1]]:8 -> [[@LINE+1]]:16 = #3
if(cnt == 0) { // CHECK: File 0, [[@LINE]]:18 -> [[@LINE+3]]:6 = #4
- break;
+ break; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+1]]:7 = 0
++cnt; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+1]]:6 = 0
- }
+ } // CHECK: Gap,File 0, [[@LINE]]:6 -> [[@LINE+1]]:5 = (#3 - #4)
++cnt; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = (#3 - #4)
} // CHECK-NEXT: File 0, [[@LINE+1]]:9 -> [[@LINE+1]]:18 = (#0 + #6)
while(cnt < 100) { // CHECK: File 0, [[@LINE]]:20 -> [[@LINE+8]]:4 = #5
// CHECK-INIT-LIST-LABEL: _Z5Test4v:
std::map<int, int> 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<int, int>{{0, 0}}; // CHECK-INIT-LIST-NEXT: [[@LINE]]:3 -> [[@LINE]]:36 = 0
}
// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -emit-llvm-only -main-file-name continue.c %s | FileCheck %s
-int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+22]]:2 = #0
+int main() { // CHECK: File 0, [[@LINE]]:12 -> [[@LINE+23]]:2 = #0
int j = 0; // CHECK-NEXT: File 0, [[@LINE+3]]:18 -> [[@LINE+3]]:24 = (#0 + #1)
// CHECK-NEXT: Branch,File 0, [[@LINE+2]]:18 -> [[@LINE+2]]:24 = #1, #0
// CHECK-NEXT: File 0, [[@LINE+1]]:26 -> [[@LINE+1]]:29 = #1
- for(int i = 0; i < 20; ++i) { // CHECK: File 0, [[@LINE]]:31 -> [[@LINE+17]]:4 = #1
- if(i < 10) { // CHECK: File 0, [[@LINE]]:16 -> [[@LINE+13]]:6 = #2
+ for(int i = 0; i < 20; ++i) { // CHECK: File 0, [[@LINE]]:31 -> [[@LINE+18]]:4 = #1
+ if(i < 10) { // CHECK: File 0, [[@LINE]]:16 -> [[@LINE+14]]:6 = #2
if(i < 5) { // CHECK: File 0, [[@LINE]]:17 -> [[@LINE+3]]:8 = #3
- continue;
- j = 1; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+1]]:8 = 0
- } else { // CHECK: File 0, [[@LINE]]:14 -> [[@LINE+2]]:8 = (#2 - #3)
+ continue; // CHECK-NEXT: Gap,File 0, [[@LINE]]:18 -> [[@LINE+1]]:9 = 0
+ j = 1; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+1]]:8 = 0
+ } else { // CHECK: File 0, [[@LINE]]:14 -> [[@LINE+2]]:8 = (#2 - #3)
j = 2;
- }
- j = 3; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+6]]:6 = (#2 - #3)
- if(i < 7) { // CHECK: File 0, [[@LINE]]:17 -> [[@LINE+3]]:8 = #4
- continue;
- j = 4; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+1]]:8 = 0
- } else j = 5; // CHECK: File 0, [[@LINE]]:14 -> [[@LINE]]:19 = ((#2 - #3) - #4)
- j = 6; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+1]]:6 = ((#2 - #3) - #4)
- } else // CHECK: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:12 = (#1 - #2)
- j = 7;
- j = 8; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = ((#1 - #3) - #4)
+ } // CHECK-NEXT: Gap,File 0, [[@LINE]]:8 -> [[@LINE+1]]:7 = (#2 - #3)
+ j = 3; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+7]]:6 = (#2 - #3)
+ if(i < 7) { // CHECK: File 0, [[@LINE]]:17 -> [[@LINE+3]]:8 = #4
+ continue; // CHECK-NEXT: Gap,File 0, [[@LINE]]:18 -> [[@LINE+1]]:9 = 0
+ j = 4; // CHECK-NEXT: File 0, [[@LINE]]:9 -> [[@LINE+1]]:8 = 0
+ } else j = 5; // CHECK: File 0, [[@LINE]]:14 -> [[@LINE]]:19 = ((#2 - #3) - #4)
+ // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:20 -> [[@LINE+1]]:7 = ((#2 - #3) - #4)
+ j = 6; // CHECK-NEXT: File 0, [[@LINE]]:7 -> [[@LINE+1]]:6 = ((#2 - #3) - #4)
+ } else // CHECK: File 0, [[@LINE+1]]:7 -> [[@LINE+1]]:12 = (#1 - #2)
+ j = 7; // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+1]]:5 = ((#1 - #3) - #4)
+ j = 8; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = ((#1 - #3) - #4)
}
}
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
+} // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:14 = #1
+++ /dev/null
-// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -std=c++11 -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -fexceptions -fcxx-exceptions -emit-llvm-only -triple %itanium_abi_triple -main-file-name deferred-region.cpp -I %S/Inputs %s | FileCheck %s
-
-#define IF if
-#define STMT(S) S
-
-// CHECK-LABEL: _Z3fooi:
-void foo(int x) {
- if (x == 0) {
- return;
- } // CHECK-NOT: Gap,File 0, [[@LINE]]:4
- //< Don't complete the last deferred region in a decl, even though it may
- //< leave some whitespace marked with the same counter as the final return.
-}
-
-// CHECK-LABEL: _Z4foooi:
-void fooo(int x) {
- if (x == 0) {
- return;
- } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = (#0 - #1)
-
- if (x == 1) {
- return;
- } // CHECK-NOT: Gap,File 0, [[@LINE]]:4
-
-}
-
-// CHECK-LABEL: _Z3bazv:
-void baz() { // CHECK: [[@LINE]]:12 -> [[@LINE+2]]:2
- return; // CHECK-NOT: File
-}
-
-// CHECK-LABEL: _Z3mazv:
-void maz() {
- if (true)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
-
- return; // CHECK-NOT: Gap
-}
-
-// CHECK-LABEL: _Z4maazv:
-void maaz() {
- if (true)
- return; // CHECK: Gap,File 0, [[@LINE]]:11
- else
- return; // CHECK-NOT: Gap,File 0, [[@LINE]]
-}
-
-// CHECK-LABEL: _Z5maaazv:
-void maaaz() {
- if (true) {
- return;
- } else { // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE]]:10
- return; // CHECK-NOT: Gap,File 0, [[@LINE]]
- }
-}
-
-// CHECK-LABEL: _Z3bari:
-void bar(int x) {
- IF (x)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
-
- IF (!x)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = ((#0 - #1) - #2)
-
- foo(x);
-}
-
-// CHECK-LABEL: _Z4quuxi:
-// Deferred regions are not emitted within macro expansions.
-void quux(int x) {
- STMT(
- if (x == 0)
- return;)
-
- // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+2]]
-
- if (x == 1)
- STMT(return;)
-
- // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+3]]
-
- STMT(
- if (x == 2)
- return;
-
- // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+2]]
-
- if (x == 3)
- return;
- )
-}
-
-// CHECK-LABEL: _Z8weird_ifv:
-void weird_if() {
- int i = 0;
-
- if (false)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
-
- 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)
-
- }
-
- if (false)
- return; // CHECK-NOT: Gap,File 0, [[@LINE]]:11
-}
-
-// CHECK-LABEL: _Z8for_loopv:
-void for_loop() {
- if (false)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
-
- for (int i = 0; i < 10; ++i) {
- if (i % 2 == 0)
- continue; // CHECK: Gap,File 0, [[@LINE]]:15 -> [[@LINE+2]]:5 = (#2 - #3)
-
- if (i % 5 == 0)
- break; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:5 = ((#2 - #3) - #4)
-
- int x = i; // CHECK: [[@LINE]]:5 -> [[@LINE+3]]:4 = ((#2 - #3) - #4)
- return; // CHECK-NOT: [[@LINE]]:11 -> [[@LINE+2]]
-
- }
-}
-
-struct Error {};
-
-// CHECK-LABEL: _Z10while_loopv:
-void while_loop() {
- if (false)
- return; // CHECK: Gap,File 0, [[@LINE]]:11 -> [[@LINE+2]]:3 = (#0 - #1)
-
- int x = 0;
- while (++x < 10) {
- if (x == 1)
- continue; // CHECK: Gap,File 0, [[@LINE]]:15 -> [[@LINE+2]]:5 = (#2 - #3)
-
- while (++x < 4) {
- if (x == 3)
- break; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+2]]:7 = (#4 - #5)
-
- while (++x < 5) {}
- }
-
- if (x == 0)
- throw Error(); // CHECK: Gap,File 0, [[@LINE]]:20 -> [[@LINE+2]]:5 = ((#2 - #3) - #7)
-
- while (++x < 9) {
- if (x == 0)
- break; // CHECK-NOT: [[@LINE]]:14 -> [[@LINE+2]]
-
- }
- }
-}
-
-// CHECK-LABEL: _Z5gotosv:
-void gotos() {
- if (false)
- goto out; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:3 = (#0 - #1)
-
- return; // CHECK: [[@LINE]]:3 -> [[@LINE+4]]:2 = (#0 - #1)
-
-out:
- return; // CHECK-NOT: Gap,File 0, [[@LINE]]:8
-}
-
-// CHECK-LABEL: _Z8switchesv:
-void switches() {
- int x;
- switch (x) {
- case 0:
- return;
- default:
- return; // CHECK-NOT: Gap,File 0, [[@LINE]]
- }
-}
-
-#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-LABEL: _Z7includev:
-void include() {
- included_func();
-}
-
-int main() {
- foo(0);
- foo(1);
- fooo(0);
- fooo(1);
- maz();
- maaz();
- maaaz();
- baz();
- bar(0);
- bar(1);
- quux(0);
- quux(1);
- quux(2);
- quux(3);
- weird_if();
- for_loop();
- while_loop();
- gotos();
- include();
- return 0;
-}
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 = #3
+ int k = 3; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+1]]:4 = #3
+ } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = ((#0 + #3) - #1)
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)
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 - #1)
+ goto b; // CHECK: File 0, [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1)
+ // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:10 -> [[@LINE+1]]:1 = (#0 - #1)
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;
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 - #1) - #2)
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;
#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 - #1)
+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
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 = (#2 - #3)
+ goto c; // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE]]:11 = (#2 - #3)
+ // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:12 -> [[@LINE+1]]:3 = (#2 - #3)
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 + #7) - #1)
func(); // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:2 = ((#0 + #7) - #1)
test1(0);
test2(2);
// 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
}
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 = (#1 - #2)
} // 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
// 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 = (#1 - #2)
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 - #2)
int j = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = (#0 - #2)
}
// 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]]:4 -> [[@LINE+1]]:3 = #1
int x = 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:2 = #1
}
}
// CHECK-NEXT: main
-int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+38]]:2 = #0
+int main() { // CHECK-NEXT: File 0, [[@LINE]]:12 -> [[@LINE+39]]:2 = #0
int i = 0;
switch(i) { // CHECK-NEXT: Gap,File 0, [[@LINE]]:13 -> [[@LINE+8]]:10 = 0
case 0: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #2
i = 1; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2)
- break;
+ break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0
case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = #3
i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3)
- break;
+ break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0
default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = #4
break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #4, (#0 - #4)
- } // CHECK-NEXT: File 0, [[@LINE-1]]:10 -> [[@LINE+1]]:3 = #1
- switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+26]]:2 = #1
- case 0: // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+6]]:10 = 0
+ } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = #1
+ switch(i) { // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+27]]:2 = #1
+ case 0: // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+7]]:10 = 0
i = 1; // CHECK-NEXT: File 0, [[@LINE-1]]:3 -> [[@LINE+1]]:10 = #6
break; // CHECK-NEXT: Branch,File 0, [[@LINE-2]]:3 -> [[@LINE-2]]:9 = #6, (#1 - #6)
+ // CHECK-NEXT: Gap,File 0, [[@LINE-1]]:11 -> [[@LINE+1]]:3 = 0
case 1: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:10 = #7
i = 2; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #7, (#1 - #7)
default: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+1]]:10 = (#7 + #8)
break; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:10 = #8, (#1 - #8)
- } // CHECK-NEXT: File 0, [[@LINE-1]]:10 -> [[@LINE+2]]:3 = #5
+ } // CHECK-NEXT: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = #5
// CHECK-NEXT: File 0, [[@LINE+1]]:3 -> [[@LINE+17]]:2 = #5
switch(i) { // CHECK-NEXT: Branch,File 0, [[@LINE]]:10 -> [[@LINE]]:11 = ((((#5 - #10) - #11) - #12) - #13), (((#10 + #11) + #12) + #13)
// CHECK-NEXT: Gap,File 0, [[@LINE-1]]:13 -> [[@LINE+8]]:11 = 0
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)
}
i = 23; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #2, (#0 - #2)
case 2: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#2 + #3)
i = 11; // CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #3, (#0 - #3)
- break;
+ break; // CHECK-NEXT: Gap,File 0, [[@LINE]]:11 -> [[@LINE+1]]:3 = 0
case 3: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+4]]:10 = #4
// CHECK-NEXT: Branch,File 0, [[@LINE-1]]:3 -> [[@LINE-1]]:9 = #4, (#0 - #4)
case 4: // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+2]]:10 = (#4 + #5)
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)
}
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: File 0, [[@LINE-1]]:16 -> [[@LINE+3]]:5 = (#2 - #3)
// 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
--- /dev/null
+// RUN: %clang_cc1 -mllvm -emptyline-comment-coverage=false -fprofile-instrument=clang -fcoverage-mapping -dump-coverage-mapping -fexceptions -fcxx-exceptions -emit-llvm-only -triple %itanium_abi_triple -main-file-name terminate-statements.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
+ ; // CHECK: Gap,File 0, [[@LINE]]:6 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 1; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+int f3() {
+ for (int a = 1; a < 9; a--)
+ return a; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+int f4(int i) {
+ while (i > 0) {
+ i++;
+ return i;
+ } // CHECK: File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+int f5(int i) {
+ do {
+ return i;
+ } while (i > 0); // CHECK: Gap,File 0, [[@LINE]]:19 -> [[@LINE+1]]:3 = (0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (0 - #1)
+}
+
+int f6() {
+ int arr[] = {1, 2, 3, 4};
+ for (int i : arr) {
+ return i;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+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; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = (#0 - #1)
+ if (i == 2) // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+5]]:2 = (#0 - #1)
+ return 2; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = ((#0 - #1) - #2)
+ if (i == 3) // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE+3]]:2 = ((#0 - #1) - #2)
+ return 3; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = (((#0 - #1) - #2) - #3)
+ return 4; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (((#0 - #1) - #2) - #3)
+}
+
+int f9(int i) {
+ if (i == 1)
+ return 1; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:8 = (#0 - #1)
+ else if (i == 2) // CHECK-NEXT: File 0, [[@LINE]]:8 -> [[@LINE+1]]:13 = (#0 - #1)
+ return 2; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = ((#0 - #1) - #2)
+ return 3; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = ((#0 - #1) - #2)
+}
+
+int f10(int i) {
+ if (i == 1) {
+ return 0;
+ if (i == 2) // CHECK: Gap,File 0, [[@LINE-1]]:14 -> [[@LINE]]:5 = 0
+ return 0;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = ((#0 - #1) - #2)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = ((#0 - #1) - #2)
+}
+
+int f11(int i) {
+ if (i == 1)
+ i = 2;
+ else
+ return 0; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:3 = #1
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = #1
+}
+
+int f12(int i) {
+ int x = 1;
+ if (x == 1) {
+ if (x == 1) {
+ return 0;
+ }
+ } else if (x == 2) {
+ x = 2;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #2)
+ return 1; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #2)
+}
+
+int f13(int i) {
+ if (i == 1) {
+ return 0; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:5 = 0
+ if (i == 2) { // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+3]]:4 = 0
+ i++;
+ }
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+int f14(int i) {
+ while (i == 0) {
+ while (i < 10) {
+ i++;
+ return 0;
+ }
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #2)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #2)
+}
+
+int f15(int i) {
+ while (i == 0) {
+ return 0; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+1]]:5 = 0
+ while (i < 10) { // CHECK-NEXT: File 0, [[@LINE]]:5 -> [[@LINE+3]]:4 = 0
+ i++;
+ }
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+1]]:3 = (#0 - #1)
+ return 0; // CHECK-NEXT: File 0, [[@LINE]]:3 -> [[@LINE]]:11 = (#0 - #1)
+}
+
+int f16(int i) {
+ while (i == 0) {
+ break;
+ return 0;
+ }
+ return 0; // CHECK-NOT: Gap,File 0, [[@LINE-1]]
+}
+
+#define IF if
+#define STMT(S) S
+
+// CHECK-LABEL: _Z3fooi:
+void foo(int x) {
+ if (x == 0) {
+ return;
+ } // CHECK-NOT: Gap,File 0, [[@LINE]]:4
+ //< Don't complete the last deferred region in a decl, even though it may
+ //< leave some whitespace marked with the same counter as the final return.
+}
+
+// CHECK-LABEL: _Z4foooi:
+void fooo(int x) {
+ if (x == 0) {
+ return;
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ if (x == 1) {
+ return;
+ } // CHECK-NOT: Gap,File 0, [[@LINE]]:4
+
+}
+
+// CHECK-LABEL: _Z3bazv:
+void baz() { // CHECK: [[@LINE]]:12 -> [[@LINE+2]]:2
+ return; // CHECK-NOT: File
+}
+
+// CHECK-LABEL: _Z4maazv:
+void maaz() {
+ if (true)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12
+ else
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]
+}
+
+// CHECK-LABEL: _Z5maaazv:
+void maaaz() {
+ if (true) {
+ return;
+ } else { // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE]]:10
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]
+ }
+}
+
+// CHECK-LABEL: _Z3bari:
+void bar(int x) {
+ IF (x)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ IF (!x)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = ((#0 - #1) - #2)
+
+ foo(x);
+}
+
+// CHECK-LABEL: _Z4quuxi:
+void quux(int x) {
+ STMT(
+ if (x == 0)
+ return;)
+
+ // CHECK: Gap,File 0, [[@LINE-2]]:13 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ if (x == 1)
+ STMT(return;)
+
+ // CHECK: Gap,File 0, [[@LINE-2]]:18 -> [[@LINE+2]]:3 = ((#0 - #1) - #2)
+
+ STMT(
+ if (x == 2)
+ return;
+
+ // CHECK-NOT: [[@LINE-2]]:{{.*}} -> [[@LINE+2]]
+
+ if (x == 3)
+ return;
+ )
+}
+
+// CHECK-LABEL: _Z8weird_ifv:
+void weird_if() {
+ int i = 0;
+
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ 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]]:14 -> [[@LINE+2]]:5 = (#3 - #4)
+ // CHECK: [[@LINE+1]]:5 -> [[@LINE+1]]:11 = (#3 - #4)
+ return;
+
+ } // CHECK: Gap,File 0, [[@LINE]]:4 -> [[@LINE+2]]:3 = ((#0 - #1) - #3)
+
+ if (false)
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]:11
+}
+
+// CHECK-LABEL: _Z8for_loopv:
+void for_loop() {
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ for (int i = 0; i < 10; ++i) {
+ if (i % 2 == 0)
+ continue; // CHECK: Gap,File 0, [[@LINE]]:16 -> [[@LINE+2]]:5 = (#2 - #3)
+
+ if (i % 5 == 0)
+ break; // CHECK: Gap,File 0, [[@LINE]]:13 -> [[@LINE+2]]:5 = ((#2 - #3) - #4)
+
+ int x = i; // CHECK: [[@LINE]]:5 -> [[@LINE+1]]:11 = ((#2 - #3) - #4)
+ return; // CHECK-NOT: [[@LINE]]:11 -> [[@LINE+2]]
+
+ }
+}
+
+struct Error {};
+
+// CHECK-LABEL: _Z10while_loopv:
+void while_loop() {
+ if (false)
+ return; // CHECK: Gap,File 0, [[@LINE]]:12 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ int x = 0;
+ while (++x < 10) {
+ if (x == 1)
+ continue; // CHECK: Gap,File 0, [[@LINE]]:16 -> [[@LINE+2]]:5 = (#2 - #3)
+
+ while (++x < 4) {
+ if (x == 3)
+ break; // CHECK: Gap,File 0, [[@LINE]]:15 -> [[@LINE+2]]:7 = (#4 - #5)
+
+ while (++x < 5) {}
+ }
+
+ if (x == 0)
+ throw Error(); // CHECK: Gap,File 0, [[@LINE]]:21 -> [[@LINE+2]]:5 = ((#2 - #3) - #7)
+
+ while (++x < 9) {
+ if (x == 0)
+ break; // CHECK-NOT: [[@LINE]]:14 -> [[@LINE+2]]
+
+ }
+ }
+}
+
+// CHECK-LABEL: _Z5gotosv:
+void gotos() {
+ if (false)
+ goto out; // CHECK: Gap,File 0, [[@LINE]]:14 -> [[@LINE+2]]:3 = (#0 - #1)
+
+ return; // CHECK: [[@LINE]]:3 -> [[@LINE]]:9 = (#0 - #1)
+
+out:
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]:8
+}
+
+// CHECK-LABEL: _Z8switchesv:
+void switches() {
+ int x;
+ switch (x) {
+ case 0:
+ return;
+ default:
+ return; // CHECK-NOT: Gap,File 0, [[@LINE]]
+ }
+}
+
+#include "deferred-region-helper.h"
+// CHECK-LABEL: _Z13included_funcv:
+// CHECK: Gap,File 0, 2:13 -> 3:5 = #1
+// CHECK: Gap,File 0, 3:12 -> 4:3 = (#0 - #1)
+
+// CHECK-LABEL: _Z7includev:
+void include() {
+ included_func();
+}
+
+int main() {
+ foo(0);
+ foo(1);
+ fooo(0);
+ fooo(1);
+ maaz();
+ maaaz();
+ baz();
+ bar(0);
+ bar(1);
+ quux(0);
+ quux(1);
+ quux(2);
+ quux(3);
+ weird_if();
+ for_loop();
+ while_loop();
+ gotos();
+ include();
+ return 0;
+}
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)
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
// CHECK-COVERAGE: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover
// CHECK-COVERAGE-NEXT: ---
-// CHECK-COVERAGE-NEXT: runtime-counter-relocation.c 4 1 75.00% 1 0 100.00% 5 2 60.00%
+// CHECK-COVERAGE-NEXT: runtime-counter-relocation.c 4 1 75.00% 1 0 100.00% 5 1 80.00%
// CHECK-COVERAGE-NEXT: ---
-// CHECK-COVERAGE-NEXT: TOTAL 4 1 75.00% 1 0 100.00% 5 2 60.00%
+// CHECK-COVERAGE-NEXT: TOTAL 4 1 75.00% 1 0 100.00% 5 1 80.00%
extern int __llvm_profile_is_continuous_mode_enabled(void);