szepet created this revision.
szepet added reviewers: dcoughlin, NoQ, zaks.anna, xazax.hun, a.sidorin.
Herald added subscribers: dkrupp, baloghadamsoftware, whisperity.
Based on the CFGLoopEntrance element, it is possible to have a CFG driven
LocationContext update which contains loop information as well.
Updated the loop unrolling feature as well to use purely the LocationContext
stack and not implement its own.
https://reviews.llvm.org/D41151
Files:
include/clang/Analysis/AnalysisDeclContext.h
include/clang/Analysis/ProgramPoint.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
lib/Analysis/AnalysisDeclContext.cpp
lib/StaticAnalyzer/Core/CoreEngine.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
lib/StaticAnalyzer/Core/LoopUnrolling.cpp
test/Analysis/loop-unrolling.cpp
Index: test/Analysis/loop-unrolling.cpp
===================================================================
--- test/Analysis/loop-unrolling.cpp
+++ test/Analysis/loop-unrolling.cpp
@@ -373,7 +373,6 @@
return 0;
}
-
void pr34943() {
for (int i = 0; i < 6L; ++i) {
clang_analyzer_numTimesReached(); // expected-warning {{6}}
Index: lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -13,11 +13,11 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
-#include "clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h"
using namespace clang;
using namespace ento;
@@ -28,56 +28,36 @@
struct LoopState {
private:
enum Kind { Normal, Unrolled } K;
- const Stmt *LoopStmt;
- const LocationContext *LCtx;
- unsigned maxStep;
- LoopState(Kind InK, const Stmt *S, const LocationContext *L, unsigned N)
- : K(InK), LoopStmt(S), LCtx(L), maxStep(N) {}
+ unsigned MaxStep;
+ LoopState(Kind InK, unsigned N) : K(InK), MaxStep(N) {}
public:
- static LoopState getNormal(const Stmt *S, const LocationContext *L,
- unsigned N) {
- return LoopState(Normal, S, L, N);
- }
- static LoopState getUnrolled(const Stmt *S, const LocationContext *L,
- unsigned N) {
- return LoopState(Unrolled, S, L, N);
- }
+ static LoopState getNormal(unsigned N) { return LoopState(Normal, N); }
+ static LoopState getUnrolled(unsigned N) { return LoopState(Unrolled, N); }
bool isUnrolled() const { return K == Unrolled; }
- unsigned getMaxStep() const { return maxStep; }
- const Stmt *getLoopStmt() const { return LoopStmt; }
- const LocationContext *getLocationContext() const { return LCtx; }
+ unsigned getMaxStep() const { return MaxStep; }
bool operator==(const LoopState &X) const {
- return K == X.K && LoopStmt == X.LoopStmt;
+ return K == X.K && MaxStep == X.MaxStep;
}
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(K);
- ID.AddPointer(LoopStmt);
- ID.AddPointer(LCtx);
- ID.AddInteger(maxStep);
+ ID.AddInteger(MaxStep);
}
};
-// The tracked stack of loops. The stack indicates that which loops the
-// simulated element contained by. The loops are marked depending if we decided
-// to unroll them.
-// TODO: The loop stack should not need to be in the program state since it is
-// lexical in nature. Instead, the stack of loops should be tracked in the
-// LocationContext.
-REGISTER_LIST_WITH_PROGRAMSTATE(LoopStack, LoopState)
+// The map of the currently simulated loops which are marked depending if we
+// decided to unroll them.
+REGISTER_MAP_WITH_PROGRAMSTATE(LoopMap, const LoopContext *, LoopState)
namespace clang {
namespace ento {
static bool isLoopStmt(const Stmt *S) {
return S && (isa<ForStmt>(S) || isa<WhileStmt>(S) || isa<DoStmt>(S));
}
-ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State) {
- auto LS = State->get<LoopStack>();
- if (!LS.isEmpty() && LS.getHead().getLoopStmt() == LoopStmt)
- State = State->set<LoopStack>(LS.getTail());
- return State;
+ProgramStateRef processLoopEnd(const LoopContext *LC, ProgramStateRef State) {
+ return State->remove<LoopMap>(LC);
}
static internal::Matcher<Stmt> simpleCondition(StringRef BindName) {
@@ -157,7 +137,8 @@
hasUnaryOperand(declRefExpr(
to(varDecl(allOf(equalsBoundNode("initVarName"),
hasType(isInteger())))))))),
- unless(hasBody(hasSuspiciousStmt("initVarName")))).bind("forLoop");
+ unless(hasBody(hasSuspiciousStmt("initVarName"))))
+ .bind("forLoop");
}
static bool isPossiblyEscaped(const VarDecl *VD, ExplodedNode *N) {
@@ -236,59 +217,55 @@
ProgramPoint P = N->getLocation();
if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
S = BE->getBlock()->getTerminator();
+ else if (Optional<LoopEnter> LE = P.getAs<LoopEnter>())
+ S = LE->getLoopStmt();
if (S == LoopStmt)
return false;
N = N->getFirstPred();
}
-
llvm_unreachable("Reached root without encountering the previous step");
}
-// updateLoopStack is called on every basic block, therefore it needs to be fast
-ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
- ExplodedNode *Pred, unsigned maxVisitOnPath) {
+// updateLoopStates is called on every basic block, therefore it needs to be
+// fast
+ProgramStateRef updateLoopStates(const LoopContext *LoopCtx, ASTContext &ASTCtx,
+ ExplodedNode *Pred, unsigned MaxVisitOnPath) {
auto State = Pred->getState();
- auto LCtx = Pred->getLocationContext();
+ auto LM = State->get<LoopMap>();
+ auto LoopStmt = LoopCtx->getLoopStmt();
- if (!isLoopStmt(LoopStmt))
- return State;
+ assert((!LM.contains(LoopCtx) ||
+ (LM.contains(LoopCtx) &&
+ Pred->getLocation().getKind() == ProgramPoint::BlockEdgeKind)) &&
+ "LoopEnter Block encountered for an already entered loop");
- auto LS = State->get<LoopStack>();
- if (!LS.isEmpty() && LoopStmt == LS.getHead().getLoopStmt() &&
- LCtx == LS.getHead().getLocationContext()) {
- if (LS.getHead().isUnrolled() && madeNewBranch(Pred, LoopStmt)) {
- State = State->set<LoopStack>(LS.getTail());
- State = State->add<LoopStack>(
- LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
- }
- return State;
- }
- unsigned maxStep;
- if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, maxStep)) {
- State = State->add<LoopStack>(
- LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
- return State;
- }
+ if (LM.contains(LoopCtx) && LM.lookup(LoopCtx)->isUnrolled() &&
+ madeNewBranch(Pred, LoopStmt))
+ return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
- unsigned outerStep = (LS.isEmpty() ? 1 : LS.getHead().getMaxStep());
+ if (LM.contains(LoopCtx))
+ return State;
- unsigned innerMaxStep = maxStep * outerStep;
- if (innerMaxStep > MAXIMUM_STEP_UNROLLED)
- State = State->add<LoopStack>(
- LoopState::getNormal(LoopStmt, LCtx, maxVisitOnPath));
+ unsigned MaxStep;
+ if (!shouldCompletelyUnroll(LoopStmt, ASTCtx, Pred, MaxStep))
+ return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
+
+ const auto OuterLoopCtx =
+ cast_or_null<LoopContext>(Pred->getLocationContext()->getCurrentLoop());
+ unsigned OuterStep =
+ (OuterLoopCtx ? LM.lookup(OuterLoopCtx)->getMaxStep() : 1);
+ unsigned InnerMaxStep = MaxStep * OuterStep;
+ if (InnerMaxStep > MAXIMUM_STEP_UNROLLED)
+ return State->set<LoopMap>(LoopCtx, LoopState::getNormal(MaxVisitOnPath));
else
- State = State->add<LoopStack>(
- LoopState::getUnrolled(LoopStmt, LCtx, innerMaxStep));
- return State;
+ return State->set<LoopMap>(LoopCtx, LoopState::getUnrolled(InnerMaxStep));
}
-bool isUnrolledState(ProgramStateRef State) {
- auto LS = State->get<LoopStack>();
- if (LS.isEmpty() || !LS.getHead().isUnrolled())
- return false;
- return true;
-}
-}
+bool isUnrolledLoopContext(const LoopContext *LC, ProgramStateRef State) {
+ auto LM = State->get<LoopMap>();
+ return LM.contains(LC) && LM.lookup(LC)->isUnrolled();
}
+} // namespace ento
+} // namespace clang
Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -312,7 +312,12 @@
// Step 4: Generate the CallExit and leave the callee's context.
// CleanedNodes -> CEENode
- CallExitEnd Loc(calleeCtx, callerCtx);
+ const LocationContext *ExitContext = calleeCtx->getParent();
+ while (!dyn_cast<StackFrameContext>(ExitContext) &&
+ !dyn_cast<LoopContext>(ExitContext)) {
+ ExitContext = ExitContext->getParent();
+ }
+ CallExitEnd Loc(calleeCtx, ExitContext);
bool isNew;
ProgramStateRef CEEState = (*I == CEBNode) ? state : (*I)->getState();
ExplodedNode *CEENode = G.getNode(Loc, CEEState, false, &isNew);
@@ -408,13 +413,18 @@
const LocationContext *CurLC = Pred->getLocationContext();
const StackFrameContext *CallerSFC = CurLC->getCurrentStackFrame();
- const LocationContext *ParentOfCallee = CallerSFC;
+
+ while (!dyn_cast<StackFrameContext>(CurLC) && !dyn_cast<LoopContext>(CurLC)) {
+ CurLC = CurLC->getParent();
+ }
+
+ const LocationContext *ParentOfCallee = CurLC;
if (Call.getKind() == CE_Block &&
!cast<BlockCall>(Call).isConversionFromLambda()) {
const BlockDataRegion *BR = cast<BlockCall>(Call).getBlockRegion();
assert(BR && "If we have the block definition we should have its region");
AnalysisDeclContext *BlockCtx = AMgr.getAnalysisDeclContext(D);
- ParentOfCallee = BlockCtx->getBlockInvocationContext(CallerSFC,
+ ParentOfCallee = BlockCtx->getBlockInvocationContext(CurLC,
cast<BlockDecl>(D),
BR);
}
Index: lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -367,6 +367,9 @@
case CFGElement::LoopExit:
ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
return;
+ case CFGElement::LoopEntrance:
+ ProcessLoopEntrance(E.castAs<CFGLoopEntrance>().getLoopStmt(), Pred);
+ return;
case CFGElement::LifetimeEnds:
return;
}
@@ -512,20 +515,49 @@
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
-void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+void ExprEngine::ProcessLoopEntrance(const Stmt *LoopStmt, ExplodedNode *Pred) {
PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
- S->getLocStart(),
- "Error evaluating end of the loop");
+ LoopStmt->getLocStart(),
+ "Error evaluating enter of the loop");
+
ExplodedNodeSet Dst;
- Dst.Add(Pred);
NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
ProgramStateRef NewState = Pred->getState();
- if(AMgr.options.shouldUnrollLoops())
- NewState = processLoopEnd(S, NewState);
+ const LocationContext *PrevLC = Pred->getLocationContext();
+ const LoopContext *LoopCtx =
+ PrevLC->getAnalysisDeclContext()->getLoopContext(PrevLC, LoopStmt);
+ LoopEnter LE(LoopStmt, LoopCtx);
- LoopExit PP(S, Pred->getLocationContext());
- Bldr.generateNode(PP, NewState, Pred);
+ if (AMgr.options.shouldUnrollLoops()) {
+ NewState = updateLoopStates(LoopCtx, AMgr.getASTContext(), Pred,
+ AMgr.getAnalyzerOptions().maxBlockVisitOnPath);
+ }
+
+ Bldr.generateNode(LE, NewState, Pred);
+ // Enqueue the new nodes onto the work list.
+ Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
+void ExprEngine::ProcessLoopExit(const Stmt *LoopStmt, ExplodedNode *Pred) {
+ PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+ LoopStmt->getLocStart(),
+ "Error evaluating end of the loop");
+
+ ExplodedNodeSet Dst;
+ NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+ ProgramStateRef NewState = Pred->getState();
+ const LocationContext *NewLCtx = Pred->getLocationContext();
+
+ if (NewLCtx->getKind() == LocationContext::Loop &&
+ cast<LoopContext>(NewLCtx)->getLoopStmt() == LoopStmt) {
+ if (AMgr.options.shouldUnrollLoops()) {
+ NewState = processLoopEnd(cast<LoopContext>(NewLCtx), NewState);
+ }
+ NewLCtx = NewLCtx->getParent();
+ }
+ LoopExit LE(LoopStmt, NewLCtx);
+ Bldr.generateNode(LE, NewState, Pred);
// Enqueue the new nodes onto the work list.
Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
}
@@ -1556,23 +1588,31 @@
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) {
PrettyStackTraceLocationContext CrashInfo(Pred->getLocationContext());
+
// If we reach a loop which has a known bound (and meets
// other constraints) then consider completely unrolling it.
if(AMgr.options.shouldUnrollLoops()) {
- unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
- const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
- if (Term) {
- ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
- Pred, maxBlockVisitOnPath);
+ do {
+ unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
+ const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
+
+ if (!(Term &&
+ (isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term))))
+ break;
+
+ ProgramStateRef NewState =
+ updateLoopStates(Pred->getLocationContext()->getCurrentLoop(),
+ AMgr.getASTContext(), Pred, maxBlockVisitOnPath);
if (NewState != Pred->getState()) {
ExplodedNode *UpdatedNode = nodeBuilder.generateNode(NewState, Pred);
if (!UpdatedNode)
return;
Pred = UpdatedNode;
}
- }
- // Is we are inside an unrolled loop then no need the check the counters.
- if(isUnrolledState(Pred->getState()))
+ } while (false);
+ // If we are inside an unrolled loop then no need the check the counters.
+ if (isUnrolledLoopContext(Pred->getLocationContext()->getCurrentLoop(),
+ Pred->getState()))
return;
}
@@ -2750,6 +2790,12 @@
break;
}
+ case ProgramPoint::LoopEnterKind: {
+ LoopEnter LE = Loc.castAs<LoopEnter>();
+ Out << "LoopEnter: " << LE.getLoopStmt()->getStmtClassName();
+ break;
+ }
+
case ProgramPoint::PreImplicitCallKind: {
ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PreCall: ";
@@ -2900,6 +2946,11 @@
Out << "Entering scope";
// FIXME: Add more info once ScopeContext is activated.
break;
+ case LocationContext::Loop:
+ Out << "Entering loop: ";
+ cast<LoopContext>(LC)->getLoopStmt()->printPretty(
+ Out, nullptr, PrintingPolicy(LangOptions()));
+ break;
}
Out << "\\l";
}
Index: lib/StaticAnalyzer/Core/CoreEngine.cpp
===================================================================
--- lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -275,6 +275,7 @@
Loc.getAs<PostInitializer>() ||
Loc.getAs<PostImplicitCall>() ||
Loc.getAs<CallExitEnd>() ||
+ Loc.getAs<LoopEnter>() ||
Loc.getAs<LoopExit>());
HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
break;
@@ -332,8 +333,10 @@
ExplodedNodeSet dstNodes;
BlockEntrance BE(Blk, Pred->getLocationContext());
NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
+ const LocationContext *NewLC = Pred->getLocationContext();
SubEng.processCFGBlockEntrance(L, nodeBuilder, Pred);
+ BE = BlockEntrance(Blk, NewLC);
// Auto-generate a node.
if (!nodeBuilder.hasGeneratedNodes()) {
nodeBuilder.generateNode(Pred->State, Pred);
@@ -568,6 +571,7 @@
// Do not create extra nodes. Move to the next CFG element.
if (N->getLocation().getAs<PostInitializer>() ||
N->getLocation().getAs<PostImplicitCall>()||
+ N->getLocation().getAs<LoopEnter>() ||
N->getLocation().getAs<LoopExit>()) {
WList->enqueue(N, Block, Idx+1);
return;
@@ -637,7 +641,8 @@
for (ExplodedNodeSet::iterator I = Set.begin(), E = Set.end(); I != E; ++I) {
ExplodedNode *N = *I;
// If we are in an inlined call, generate CallExitBegin node.
- if (N->getLocationContext()->getParent()) {
+ if (isa<StackFrameContext>(N->getLocationContext()) &&
+ N->getLocationContext()->getParent()) {
N = generateCallExitBeginNode(N, RS);
if (N)
WList->enqueue(N);
Index: lib/Analysis/AnalysisDeclContext.cpp
===================================================================
--- lib/Analysis/AnalysisDeclContext.cpp
+++ lib/Analysis/AnalysisDeclContext.cpp
@@ -313,6 +313,12 @@
return getLocationContextManager().getStackFrame(this, Parent, S, Blk, Idx);
}
+const LoopContext *
+AnalysisDeclContext::getLoopContext(const LocationContext *Parent,
+ const Stmt *LoopStmt) {
+ return getLocationContextManager().getLoopContext(this, Parent, LoopStmt);
+}
+
const BlockInvocationContext *
AnalysisDeclContext::getBlockInvocationContext(const LocationContext *parent,
const clang::BlockDecl *BD,
@@ -365,6 +371,10 @@
Profile(ID, getAnalysisDeclContext(), getParent(), Enter);
}
+void LoopContext::Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, getAnalysisDeclContext(), getParent(), LoopStmt);
+}
+
void BlockInvocationContext::Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, getAnalysisDeclContext(), getParent(), BD, ContextData);
}
@@ -415,6 +425,13 @@
return getLocationContext<ScopeContext, Stmt>(ctx, parent, s);
}
+const LoopContext *
+LocationContextManager::getLoopContext(AnalysisDeclContext *Ctx,
+ const LocationContext *Parent,
+ const Stmt *LoopStmt) {
+ return getLocationContext<LoopContext, Stmt>(Ctx, Parent, LoopStmt);
+}
+
const BlockInvocationContext *
LocationContextManager::getBlockInvocationContext(AnalysisDeclContext *ctx,
const LocationContext *parent,
@@ -447,6 +464,16 @@
return nullptr;
}
+const LoopContext *LocationContext::getCurrentLoop() const {
+ const LocationContext *LC = this;
+ while (LC) {
+ if (const LoopContext *LoopCtx = dyn_cast<LoopContext>(LC))
+ return LoopCtx;
+ LC = LC->getParent();
+ }
+ return nullptr;
+}
+
bool LocationContext::inTopFrame() const {
return getCurrentStackFrame()->inTopFrame();
}
@@ -484,6 +511,11 @@
<< cast<BlockInvocationContext>(LCtx)->getContextData()
<< ")\n";
break;
+ case Loop:
+ OS << Indent << " (loop context: "
+ << cast<LoopContext>(LCtx)->getLoopStmt()->getStmtClassName()
+ << ")\n";
+ break;
}
}
}
Index: include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/LoopUnrolling.h
@@ -34,15 +34,15 @@
/// Returns if the given State indicates that is inside a completely unrolled
/// loop.
-bool isUnrolledState(ProgramStateRef State);
+bool isUnrolledLoopContext(const LoopContext *LC, ProgramStateRef State);
/// Updates the stack of loops contained by the ProgramState.
-ProgramStateRef updateLoopStack(const Stmt *LoopStmt, ASTContext &ASTCtx,
- ExplodedNode* Pred, unsigned maxVisitOnPath);
+ProgramStateRef updateLoopStates(const LoopContext *LC, ASTContext &ASTCtx,
+ ExplodedNode *Pred, unsigned MaxVisitOnPath);
/// Updates the given ProgramState. In current implementation it removes the top
/// element of the stack of loops.
-ProgramStateRef processLoopEnd(const Stmt *LoopStmt, ProgramStateRef State);
+ProgramStateRef processLoopEnd(const LoopContext *LC, ProgramStateRef State);
} // end namespace ento
} // end namespace clang
Index: include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
===================================================================
--- include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
+++ include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
@@ -196,6 +196,8 @@
void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
+ void ProcessLoopEntrance(const Stmt *S, ExplodedNode *Pred);
+
void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
@@ -219,7 +221,7 @@
void processCFGBlockEntrance(const BlockEdge &L,
NodeBuilderWithSinks &nodeBuilder,
ExplodedNode *Pred) override;
-
+
/// ProcessBranch - Called by CoreEngine. Used to generate successor
/// nodes by processing the 'effects' of a branch condition.
void processBranch(const Stmt *Condition, const Stmt *Term,
Index: include/clang/Analysis/ProgramPoint.h
===================================================================
--- include/clang/Analysis/ProgramPoint.h
+++ include/clang/Analysis/ProgramPoint.h
@@ -83,6 +83,7 @@
PostImplicitCallKind,
MinImplicitCallKind = PreImplicitCallKind,
MaxImplicitCallKind = PostImplicitCallKind,
+ LoopEnterKind,
LoopExitKind,
EpsilonKind};
@@ -615,7 +616,7 @@
///
/// The call exit is simulated with a sequence of nodes, which occur between
/// CallExitBegin and CallExitEnd. The following operations occur between the
-/// two program points:
+/// two preogram points:
/// - CallExitBegin
/// - Bind the return value
/// - Run Remove dead bindings (to clean up the dead symbols from the callee).
@@ -655,6 +656,23 @@
}
};
+class LoopEnter : public ProgramPoint {
+public:
+ LoopEnter(const Stmt *LoopStmt, const LocationContext *LC)
+ : ProgramPoint(LoopStmt, nullptr, LoopEnterKind, LC) {}
+
+ const Stmt *getLoopStmt() const {
+ return static_cast<const Stmt *>(getData1());
+ }
+
+private:
+ friend class ProgramPoint;
+ LoopEnter() {}
+ static bool isKind(const ProgramPoint &Location) {
+ return Location.getKind() == LoopEnterKind;
+ }
+};
+
/// Represents a point when we exit a loop.
/// When this ProgramPoint is encountered we can be sure that the symbolic
/// execution of the corresponding LoopStmt is finished on the given path.
Index: include/clang/Analysis/AnalysisDeclContext.h
===================================================================
--- include/clang/Analysis/AnalysisDeclContext.h
+++ include/clang/Analysis/AnalysisDeclContext.h
@@ -36,6 +36,7 @@
class LocationContextManager;
class StackFrameContext;
class BlockInvocationContext;
+class LoopContext;
class AnalysisDeclContextManager;
class LocationContext;
@@ -185,7 +186,10 @@
const Stmt *S,
const CFGBlock *Blk,
unsigned Idx);
-
+
+ const LoopContext *getLoopContext(const LocationContext *Parent,
+ const Stmt *LoopStmt);
+
const BlockInvocationContext *
getBlockInvocationContext(const LocationContext *parent,
const BlockDecl *BD,
@@ -214,7 +218,7 @@
class LocationContext : public llvm::FoldingSetNode {
public:
- enum ContextKind { StackFrame, Scope, Block };
+ enum ContextKind { StackFrame, Scope, Block, Loop };
private:
ContextKind Kind;
@@ -260,6 +264,8 @@
const StackFrameContext *getCurrentStackFrame() const;
+ const LoopContext *getCurrentLoop() const;
+
/// Return true if the current LocationContext has no caller context.
virtual bool inTopFrame() const;
@@ -320,6 +326,31 @@
}
};
+class LoopContext : public LocationContext {
+ const Stmt *LoopStmt;
+
+ friend class LocationContextManager;
+ LoopContext(AnalysisDeclContext *Ctx, const LocationContext *Parent,
+ const Stmt *LS)
+ : LocationContext(Loop, Ctx, Parent), LoopStmt(LS) {}
+
+public:
+ ~LoopContext() override {}
+
+ const Stmt *getLoopStmt() const { return LoopStmt; }
+
+ void Profile(llvm::FoldingSetNodeID &ID) override;
+
+ static void Profile(llvm::FoldingSetNodeID &ID, AnalysisDeclContext *Ctx,
+ const LocationContext *Parent, const Stmt *LS) {
+ ProfileCommon(ID, Scope, Ctx, Parent, LS);
+ }
+
+ static bool classof(const LocationContext *Ctx) {
+ return Ctx->getKind() == Loop;
+ }
+};
+
class ScopeContext : public LocationContext {
const Stmt *Enter;
@@ -390,7 +421,11 @@
const ScopeContext *getScope(AnalysisDeclContext *ctx,
const LocationContext *parent,
const Stmt *s);
-
+
+ const LoopContext *getLoopContext(AnalysisDeclContext *Ctx,
+ const LocationContext *Parent,
+ const Stmt *LoopStmt);
+
const BlockInvocationContext *
getBlockInvocationContext(AnalysisDeclContext *ctx,
const LocationContext *parent,
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits