summaryrefslogtreecommitdiffstats
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/include/clang/Analysis/AnalysisContext.h1
-rw-r--r--clang/include/clang/Analysis/CFG.h31
-rw-r--r--clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h10
-rw-r--r--clang/lib/Analysis/AnalysisDeclContext.cpp2
-rw-r--r--clang/lib/Analysis/CFG.cpp24
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp3
-rw-r--r--clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp1
-rw-r--r--clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp4
-rw-r--r--clang/test/Analysis/analyzer-config.c3
-rw-r--r--clang/test/Analysis/analyzer-config.cpp3
-rw-r--r--clang/test/Analysis/loopexit-cfg-output.cpp476
12 files changed, 558 insertions, 5 deletions
diff --git a/clang/include/clang/Analysis/AnalysisContext.h b/clang/include/clang/Analysis/AnalysisContext.h
index ec7549d4535..cc08e05822d 100644
--- a/clang/include/clang/Analysis/AnalysisContext.h
+++ b/clang/include/clang/Analysis/AnalysisContext.h
@@ -427,6 +427,7 @@ public:
bool addInitializers = false,
bool addTemporaryDtors = false,
bool addLifetime = false,
+ bool addLoopExit = false,
bool synthesizeBodies = false,
bool addStaticInitBranches = false,
bool addCXXNewAllocator = true,
diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h
index 97639bbfade..8cdd7826716 100644
--- a/clang/include/clang/Analysis/CFG.h
+++ b/clang/include/clang/Analysis/CFG.h
@@ -59,6 +59,7 @@ public:
Initializer,
NewAllocator,
LifetimeEnds,
+ LoopExit,
// dtor kind
AutomaticObjectDtor,
DeleteDtor,
@@ -168,6 +169,29 @@ private:
}
};
+/// Represents the point where a loop ends.
+/// This element is is only produced when building the CFG for the static
+/// analyzer and hidden behind the 'cfg-loopexit' analyzer config flag.
+///
+/// Note: a loop exit element can be reached even when the loop body was never
+/// entered.
+class CFGLoopExit : public CFGElement {
+public:
+ explicit CFGLoopExit(const Stmt *stmt)
+ : CFGElement(LoopExit, stmt) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<Stmt *>(Data1.getPointer());
+ }
+
+private:
+ friend class CFGElement;
+ CFGLoopExit() {}
+ static bool isKind(const CFGElement &elem) {
+ return elem.getKind() == LoopExit;
+ }
+};
+
/// Represents the point where the lifetime of an automatic object ends
class CFGLifetimeEnds : public CFGElement {
public:
@@ -728,6 +752,10 @@ public:
Elements.push_back(CFGLifetimeEnds(VD, S), C);
}
+ void appendLoopExit(const Stmt *LoopStmt, BumpVectorContext &C) {
+ Elements.push_back(CFGLoopExit(LoopStmt), C);
+ }
+
void appendDeleteDtor(CXXRecordDecl *RD, CXXDeleteExpr *DE, BumpVectorContext &C) {
Elements.push_back(CFGDeleteDtor(RD, DE), C);
}
@@ -794,6 +822,7 @@ public:
bool AddInitializers;
bool AddImplicitDtors;
bool AddLifetime;
+ bool AddLoopExit;
bool AddTemporaryDtors;
bool AddStaticInitBranches;
bool AddCXXNewAllocator;
@@ -818,7 +847,7 @@ public:
PruneTriviallyFalseEdges(true),
AddEHEdges(false),
AddInitializers(false), AddImplicitDtors(false),
- AddLifetime(false),
+ AddLifetime(false), AddLoopExit(false),
AddTemporaryDtors(false), AddStaticInitBranches(false),
AddCXXNewAllocator(false), AddCXXDefaultInitExprInCtors(false) {}
};
diff --git a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
index 66e1a746ffa..ce50cc582d1 100644
--- a/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ b/clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -214,6 +214,9 @@ private:
/// \sa IncludeLifetimeInCFG
Optional<bool> IncludeLifetimeInCFG;
+ /// \sa IncludeLoopExitInCFG
+ Optional<bool> IncludeLoopExitInCFG;
+
/// \sa mayInlineCXXStandardLibrary
Optional<bool> InlineCXXStandardLibrary;
@@ -418,6 +421,13 @@ public:
/// the values "true" and "false".
bool includeLifetimeInCFG();
+ /// Returns whether or not the end of the loop information should be included
+ /// in the CFG.
+ ///
+ /// This is controlled by the 'cfg-loopexit' config option, which accepts
+ /// the values "true" and "false".
+ bool includeLoopExitInCFG();
+
/// Returns whether or not C++ standard library functions may be considered
/// for inlining.
///
diff --git a/clang/lib/Analysis/AnalysisDeclContext.cpp b/clang/lib/Analysis/AnalysisDeclContext.cpp
index ec15f34fb23..0f123fdc4b3 100644
--- a/clang/lib/Analysis/AnalysisDeclContext.cpp
+++ b/clang/lib/Analysis/AnalysisDeclContext.cpp
@@ -68,6 +68,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
bool addInitializers,
bool addTemporaryDtors,
bool addLifetime,
+ bool addLoopExit,
bool synthesizeBodies,
bool addStaticInitBranch,
bool addCXXNewAllocator,
@@ -79,6 +80,7 @@ AnalysisDeclContextManager::AnalysisDeclContextManager(bool useUnoptimizedCFG,
cfgBuildOptions.AddInitializers = addInitializers;
cfgBuildOptions.AddTemporaryDtors = addTemporaryDtors;
cfgBuildOptions.AddLifetime = addLifetime;
+ cfgBuildOptions.AddLoopExit = addLoopExit;
cfgBuildOptions.AddStaticInitBranches = addStaticInitBranch;
cfgBuildOptions.AddCXXNewAllocator = addCXXNewAllocator;
}
diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp
index 6a77455edee..c47a917bef6 100644
--- a/clang/lib/Analysis/CFG.cpp
+++ b/clang/lib/Analysis/CFG.cpp
@@ -602,6 +602,7 @@ private:
return Visit(S, AddStmtChoice::AlwaysAdd);
}
CFGBlock *addInitializer(CXXCtorInitializer *I);
+ void addLoopExit(const Stmt *LoopStmt);
void addAutomaticObjDtors(LocalScope::const_iterator B,
LocalScope::const_iterator E, Stmt *S);
void addLifetimeEnds(LocalScope::const_iterator B,
@@ -652,6 +653,10 @@ private:
B->appendLifetimeEnds(VD, S, cfg->getBumpVectorContext());
}
+ void appendLoopExit(CFGBlock *B, const Stmt *LoopStmt) {
+ B->appendLoopExit(LoopStmt, cfg->getBumpVectorContext());
+ }
+
void appendDeleteDtor(CFGBlock *B, CXXRecordDecl *RD, CXXDeleteExpr *DE) {
B->appendDeleteDtor(RD, DE, cfg->getBumpVectorContext());
}
@@ -1253,6 +1258,16 @@ static QualType getReferenceInitTemporaryType(ASTContext &Context,
return Init->getType();
}
+
+// TODO: Support adding LoopExit element to the CFG in case where the loop is
+// ended by ReturnStmt, GotoStmt or ThrowExpr.
+void CFGBuilder::addLoopExit(const Stmt *LoopStmt){
+ if(!BuildOpts.AddLoopExit)
+ return;
+ autoCreateBlock();
+ appendLoopExit(Block, LoopStmt);
+}
+
void CFGBuilder::addAutomaticObjHandling(LocalScope::const_iterator B,
LocalScope::const_iterator E,
Stmt *S) {
@@ -2543,6 +2558,8 @@ CFGBlock *CFGBuilder::VisitForStmt(ForStmt *F) {
addAutomaticObjHandling(ScopePos, save_scope_pos.get(), F);
+ addLoopExit(F);
+
// "for" is a control-flow statement. Thus we stop processing the current
// block.
if (Block) {
@@ -2882,6 +2899,7 @@ CFGBlock *CFGBuilder::VisitWhileStmt(WhileStmt *W) {
addLocalScopeForVarDecl(VD);
addAutomaticObjHandling(ScopePos, LoopBeginScopePos, W);
}
+ addLoopExit(W);
// "while" is a control-flow statement. Thus we stop processing the current
// block.
@@ -3045,6 +3063,8 @@ CFGBlock *CFGBuilder::VisitCXXThrowExpr(CXXThrowExpr *T) {
CFGBlock *CFGBuilder::VisitDoStmt(DoStmt *D) {
CFGBlock *LoopSuccessor = nullptr;
+ addLoopExit(D);
+
// "do...while" is a control-flow statement. Thus we stop processing the
// current block.
if (Block) {
@@ -4025,6 +4045,7 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const {
case CFGElement::Statement:
case CFGElement::Initializer:
case CFGElement::NewAllocator:
+ case CFGElement::LoopExit:
case CFGElement::LifetimeEnds:
llvm_unreachable("getDestructorDecl should only be used with "
"ImplicitDtors");
@@ -4442,6 +4463,9 @@ static void print_elem(raw_ostream &OS, StmtPrinterHelper &Helper,
OS << " (Lifetime ends)\n";
+ } else if (Optional<CFGLoopExit> LE = E.getAs<CFGLoopExit>()) {
+ const Stmt *LoopStmt = LE->getLoopStmt();
+ OS << LoopStmt->getStmtClassName() << " (LoopExit)\n";
} else if (Optional<CFGNewAllocator> NE = E.getAs<CFGNewAllocator>()) {
OS << "CFGNewAllocator(";
if (const CXXNewExpr *AllocExpr = NE->getAllocatorExpr())
diff --git a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
index 83e67662e61..10cf079b346 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalysisManager.cpp
@@ -26,7 +26,8 @@ AnalysisManager::AnalysisManager(ASTContext &ctx, DiagnosticsEngine &diags,
Options.includeImplicitDtorsInCFG(),
/*AddInitializers=*/true,
Options.includeTemporaryDtorsInCFG(),
- Options.includeLifetimeInCFG(),
+ Options.includeLifetimeInCFG(),
+ Options.includeLoopExitInCFG(),
Options.shouldSynthesizeBodies(),
Options.shouldConditionalizeStaticInitializers(),
/*addCXXNewAllocator=*/true,
diff --git a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
index d5d6527f4fc..48e3e22af04 100644
--- a/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
+++ b/clang/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
@@ -183,6 +183,11 @@ bool AnalyzerOptions::includeLifetimeInCFG() {
/* Default = */ false);
}
+bool AnalyzerOptions::includeLoopExitInCFG() {
+ return getBooleanOption(IncludeLoopExitInCFG, "cfg-loopexit",
+ /* Default = */ false);
+}
+
bool AnalyzerOptions::mayInlineCXXStandardLibrary() {
return getBooleanOption(InlineCXXStandardLibrary,
"c++-stdlib-inlining",
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 835b3536865..547978ad43c 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -365,6 +365,7 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
return;
case CFGElement::LifetimeEnds:
+ case CFGElement::LoopExit:
return;
}
}
diff --git a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
index d91786f7491..907755683f4 100644
--- a/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ b/clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -578,8 +578,10 @@ getLocationForCaller(const StackFrameContext *SFC,
}
case CFGElement::TemporaryDtor:
case CFGElement::NewAllocator:
- case CFGElement::LifetimeEnds:
llvm_unreachable("not yet implemented!");
+ case CFGElement::LifetimeEnds:
+ case CFGElement::LoopExit:
+ llvm_unreachable("CFGElement kind should not be on callsite!");
}
llvm_unreachable("Unknown CFGElement kind");
diff --git a/clang/test/Analysis/analyzer-config.c b/clang/test/Analysis/analyzer-config.c
index 7bed7cb5e3b..4daea898ecd 100644
--- a/clang/test/Analysis/analyzer-config.c
+++ b/clang/test/Analysis/analyzer-config.c
@@ -14,6 +14,7 @@ void foo() {
// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-implicit-dtors = true
// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -30,4 +31,4 @@ void foo() {
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 18
+// CHECK-NEXT: num-entries = 19
diff --git a/clang/test/Analysis/analyzer-config.cpp b/clang/test/Analysis/analyzer-config.cpp
index 155ee02e839..a08e85e53e4 100644
--- a/clang/test/Analysis/analyzer-config.cpp
+++ b/clang/test/Analysis/analyzer-config.cpp
@@ -25,6 +25,7 @@ public:
// CHECK-NEXT: cfg-conditional-static-initializers = true
// CHECK-NEXT: cfg-implicit-dtors = true
// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -41,4 +42,4 @@ public:
// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 23
+// CHECK-NEXT: num-entries = 24
diff --git a/clang/test/Analysis/loopexit-cfg-output.cpp b/clang/test/Analysis/loopexit-cfg-output.cpp
new file mode 100644
index 00000000000..8e53ce3066b
--- /dev/null
+++ b/clang/test/Analysis/loopexit-cfg-output.cpp
@@ -0,0 +1,476 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-loopexit=true %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B3.1]++
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 12
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: for (...; [B4.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: int i = 0;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop1() {
+ for (int i = 0; i < 12; i++) {
+ i++;
+ }
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: T: for (; ; )
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop2() {
+ for (;;)
+ ;
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: true
+// CHECK-NEXT: T: while [B4.1]
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while1() {
+ while (true) {
+ int i;
+ }
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: int k = 2;
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: l
+// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 42
+// CHECK-NEXT: 4: [B3.2] < [B3.3]
+// CHECK-NEXT: T: while [B3.4]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: int l;
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while2() {
+ int l;
+ while (l < 42)
+ ;
+ int k = 2;
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: while [B3.1]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while3() {
+ while (false) {
+ ;
+ }
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: do ... while [B2.1]
+// CHECK-NEXT: Preds (2): B3 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B3]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile1() {
+ do {
+ } while (false);
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: j
+// CHECK-NEXT: 3: [B1.2]--
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 20
+// CHECK-NEXT: 4: [B2.2] < [B2.3]
+// CHECK-NEXT: T: do ... while [B2.4]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: [B3.1] += [B3.2]
+// CHECK-NEXT: Preds (2): B4 B5
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int j = 2;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile2() {
+ int j = 2;
+ do {
+ j += 2;
+ } while (j < 20);
+ j--;
+ return;
+}
+
+// CHECK: [B10 (ENTRY)]
+// CHECK-NEXT: Succs (1): B9
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B6.2] < [B6.3]
+// CHECK-NEXT: T: for (...; [B6.4]; ...)
+// CHECK-NEXT: Preds (2): B4 B7
+// CHECK-NEXT: Succs (2): B5 B3
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: int j = 1;
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B8.2] < [B8.3]
+// CHECK-NEXT: T: while [B8.4]
+// CHECK-NEXT: Preds (2): B2 B9
+// CHECK-NEXT: Succs (2): B7 B1
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B9.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops1() {
+ int i = -40;
+ while (i < 2) {
+ for (int j = 1; j < 6; j++)
+ i++;
+ }
+}
+
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: i
+// CHECK-NEXT: 3: [B3.2]--
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: do ... while [B4.4]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B6 B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (2): B6 B7
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B7.2] < [B7.3]
+// CHECK-NEXT: T: for (...; [B7.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B8
+// CHECK-NEXT: Succs (2): B5 B1
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B8.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: 4: 1
+// CHECK-NEXT: 5: int j = 1;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops2() {
+ int i = -40;
+ for (int j = 1; j < 6; j++) {
+ do {
+ i++;
+ } while (i < 2);
+ i--;
+ }
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (2): B3 B5
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B3]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: 3: i
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 5: 2
+// CHECK-NEXT: 6: [B4.4] % [B4.5]
+// CHECK-NEXT: 7: [B4.6] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B4.7]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B3 B2
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 5
+// CHECK-NEXT: 4: [B5.2] < [B5.3]
+// CHECK-NEXT: T: while [B5.4]
+// CHECK-NEXT: Preds (2): B2 B6
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: 1
+// CHECK-NEXT: 3: int i = 1;
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B7.1]++
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B8]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 4
+// CHECK-NEXT: 4: [B9.2] == [B9.3]
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+
+// CHECK: [B10]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B10.2] < [B10.3]
+// CHECK-NEXT: T: for (...; [B10.4]; ...)
+// CHECK-NEXT: Preds (2): B7 B11
+// CHECK-NEXT: Succs (2): B9 B6
+
+// CHECK: [B11]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int i = 2;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_break()
+{
+ for(int i = 2; i < 6; i++) {
+ if(i == 4)
+ break;
+ }
+
+ int i = 1;
+ while(i<5){
+ i++;
+ if(i%2)
+ break;
+ }
+
+ return;
+}
OpenPOWER on IntegriCloud