NoQ created this revision.
NoQ added reviewers: dcoughlin, xazax.hun, a_sidorin, rnkovacs,
mikhail.ramalho, Szelethus, baloghadamsoftware, Charusso.
Herald added subscribers: cfe-commits, zzheng, whisperity.
Herald added a project: clang.
This conversion does indeed save some code, but i plan to add support for more
kinds of terminators that aren't necessarily based on statements, and as i do,
it becomes more and more confusing to have it implicitly convertible to a `Stmt
*`.
Repository:
rC Clang
https://reviews.llvm.org/D61814
Files:
clang/include/clang/Analysis/CFG.h
clang/include/clang/Analysis/ProgramPoint.h
clang/lib/Analysis/CFG.cpp
clang/lib/Analysis/CFGStmtMap.cpp
clang/lib/Analysis/Consumed.cpp
clang/lib/Analysis/LiveVariables.cpp
clang/lib/Analysis/ProgramPoint.cpp
clang/lib/Analysis/ReachableCode.cpp
clang/lib/Analysis/ThreadSafety.cpp
clang/lib/Analysis/UninitializedValues.cpp
clang/lib/Sema/AnalysisBasedWarnings.cpp
clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
clang/lib/StaticAnalyzer/Core/BugReporter.cpp
clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
Index: clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
+++ clang/lib/StaticAnalyzer/Core/PathDiagnostic.cpp
@@ -794,7 +794,7 @@
if (auto SP = P.getAs<StmtPoint>())
return SP->getStmt();
if (auto BE = P.getAs<BlockEdge>())
- return BE->getSrc()->getTerminator();
+ return BE->getSrc()->getTerminatorStmt();
if (auto CE = P.getAs<CallEnter>())
return CE->getCallExpr();
if (auto CEE = P.getAs<CallExitEnd>())
Index: clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
+++ clang/lib/StaticAnalyzer/Core/LoopUnrolling.cpp
@@ -234,7 +234,7 @@
ProgramPoint P = N->getLocation();
if (Optional<BlockEntrance> BE = P.getAs<BlockEntrance>())
- S = BE->getBlock()->getTerminator();
+ S = BE->getBlock()->getTerminatorStmt();
if (S == LoopStmt)
return false;
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1861,7 +1861,7 @@
// other constraints) then consider completely unrolling it.
if(AMgr.options.ShouldUnrollLoops) {
unsigned maxBlockVisitOnPath = AMgr.options.maxBlockVisitOnPath;
- const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
+ const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt();
if (Term) {
ProgramStateRef NewState = updateLoopStack(Term, AMgr.getASTContext(),
Pred, maxBlockVisitOnPath);
@@ -1882,7 +1882,7 @@
unsigned int BlockCount = nodeBuilder.getContext().blockCount();
if (BlockCount == AMgr.options.maxBlockVisitOnPath - 1 &&
AMgr.options.ShouldWidenLoops) {
- const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminator();
+ const Stmt *Term = nodeBuilder.getContext().getBlock()->getTerminatorStmt();
if (!(Term &&
(isa<ForStmt>(Term) || isa<WhileStmt>(Term) || isa<DoStmt>(Term))))
return;
@@ -2007,8 +2007,8 @@
if (!BO || !BO->isLogicalOp())
return Condition;
- assert(!B->getTerminator().isTemporaryDtorsBranch() &&
- "Temporary destructor branches handled by processBindTemporary.");
+ assert(B->getTerminator().getKind() == CFGTerminator::StmtBranch &&
+ "Other kinds of branches are handled separately!");
// For logical operations, we still have the case where some branches
// use the traditional "merge" approach and others sink the branch
Index: clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
@@ -275,14 +275,14 @@
}
void CoreEngine::HandleBlockExit(const CFGBlock * B, ExplodedNode *Pred) {
- if (const Stmt *Term = B->getTerminator()) {
+ if (const Stmt *Term = B->getTerminatorStmt()) {
switch (Term->getStmtClass()) {
default:
llvm_unreachable("Analysis for this terminator not implemented.");
case Stmt::CXXBindTemporaryExprClass:
HandleCleanupTemporaryBranch(
- cast<CXXBindTemporaryExpr>(B->getTerminator().getStmt()), B, Pred);
+ cast<CXXBindTemporaryExpr>(Term), B, Pred);
return;
// Model static initializers.
Index: clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
@@ -1494,7 +1494,7 @@
return nullptr;
CFGStmtMap *Map = CurLC->getAnalysisDeclContext()->getCFGStmtMap();
- CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminator();
+ CurTerminatorStmt = Map->getBlock(CurStmt)->getTerminatorStmt();
} else {
return nullptr;
}
@@ -1566,7 +1566,7 @@
ProgramPoint ProgPoint = NI->getLocation();
if (Optional<BlockEdge> BE = ProgPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
- if (const Stmt *term = srcBlk->getTerminator()) {
+ if (const Stmt *term = srcBlk->getTerminatorStmt()) {
if (term == CO) {
bool TookTrueBranch = (*(srcBlk->succ_begin()) == BE->getDst());
if (TookTrueBranch)
@@ -1852,7 +1852,7 @@
// here by looking at the state transition.
if (Optional<BlockEdge> BE = progPoint.getAs<BlockEdge>()) {
const CFGBlock *srcBlk = BE->getSrc();
- if (const Stmt *term = srcBlk->getTerminator())
+ if (const Stmt *term = srcBlk->getTerminatorStmt())
return VisitTerminator(term, N, srcBlk, BE->getDst(), BR, BRC);
return nullptr;
}
Index: clang/lib/StaticAnalyzer/Core/BugReporter.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/BugReporter.cpp
+++ clang/lib/StaticAnalyzer/Core/BugReporter.cpp
@@ -678,7 +678,7 @@
const LocationContext *LC = N->getLocationContext();
const CFGBlock *Src = BE.getSrc();
const CFGBlock *Dst = BE.getDst();
- const Stmt *T = Src->getTerminator();
+ const Stmt *T = Src->getTerminatorStmt();
if (!T)
return;
@@ -1203,7 +1203,7 @@
const CFGBlock *BSrc = BE->getSrc();
ParentMap &PM = PDB.getParentMap();
- if (const Stmt *Term = BSrc->getTerminator()) {
+ if (const Stmt *Term = BSrc->getTerminatorStmt()) {
// Are we jumping past the loop body without ever executing the
// loop (because the condition was false)?
if (isLoop(Term)) {
Index: clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
@@ -204,7 +204,7 @@
return S->getStmt();
}
}
- if (const Stmt *S = CB->getTerminator())
+ if (const Stmt *S = CB->getTerminatorStmt())
return S;
else
return nullptr;
@@ -250,7 +250,7 @@
bool UnreachableCodeChecker::isEmptyCFGBlock(const CFGBlock *CB) {
return CB->getLabel() == nullptr // No labels
&& CB->size() == 0 // No statements
- && !CB->getTerminator(); // No terminator
+ && !CB->getTerminatorStmt(); // No terminator
}
void ento::registerUnreachableCodeChecker(CheckerManager &mgr) {
Index: clang/lib/Sema/AnalysisBasedWarnings.cpp
===================================================================
--- clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -398,7 +398,8 @@
for (const auto *B : *cfg) {
if (!live[B->getBlockID()]) {
if (B->pred_begin() == B->pred_end()) {
- if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator()))
+ const Stmt *Term = B->getTerminatorStmt();
+ if (Term && isa<CXXTryStmt>(Term))
// When not adding EH edges from calls, catch clauses
// can otherwise seem dead. Avoid noting them as dead.
count += reachable_code::ScanReachableFromBlock(B, live);
@@ -446,7 +447,8 @@
// No more CFGElements in the block?
if (ri == re) {
- if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) {
+ const Stmt *Term = B.getTerminatorStmt();
+ if (Term && isa<CXXTryStmt>(Term)) {
HasAbnormalEdge = true;
continue;
}
@@ -1077,7 +1079,7 @@
BlockQueue.pop_front();
if (!P) continue;
- const Stmt *Term = P->getTerminator();
+ const Stmt *Term = P->getTerminatorStmt();
if (Term && isa<SwitchStmt>(Term))
continue; // Switch statement, good.
@@ -1175,7 +1177,7 @@
}
static const Stmt *getLastStmt(const CFGBlock &B) {
- if (const Stmt *Term = B.getTerminator())
+ if (const Stmt *Term = B.getTerminatorStmt())
return Term;
for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(),
ElemEnd = B.rend();
@@ -1281,11 +1283,11 @@
if (L.isMacroID())
continue;
if (S.getLangOpts().CPlusPlus11) {
- const Stmt *Term = B->getTerminator();
+ const Stmt *Term = B->getTerminatorStmt();
// Skip empty cases.
while (B->empty() && !Term && B->succ_size() == 1) {
B = *B->succ_begin();
- Term = B->getTerminator();
+ Term = B->getTerminatorStmt();
}
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
Index: clang/lib/Analysis/UninitializedValues.cpp
===================================================================
--- clang/lib/Analysis/UninitializedValues.cpp
+++ clang/lib/Analysis/UninitializedValues.cpp
@@ -651,7 +651,7 @@
// uninitialized.
for (const auto *Block : cfg) {
unsigned BlockID = Block->getBlockID();
- const Stmt *Term = Block->getTerminator();
+ const Stmt *Term = Block->getTerminatorStmt();
if (SuccsVisited[BlockID] && SuccsVisited[BlockID] < Block->succ_size() &&
Term) {
// This block inevitably leads to the use. If we have an edge from here
Index: clang/lib/Analysis/ThreadSafety.cpp
===================================================================
--- clang/lib/Analysis/ThreadSafety.cpp
+++ clang/lib/Analysis/ThreadSafety.cpp
@@ -815,7 +815,7 @@
// Find the source location of the last statement in the block, if the
// block is not empty.
- if (const Stmt *S = CurrBlock->getTerminator()) {
+ if (const Stmt *S = CurrBlock->getTerminatorStmt()) {
CurrBlockInfo->EntryLoc = CurrBlockInfo->ExitLoc = S->getBeginLoc();
} else {
for (CFGBlock::const_reverse_iterator BI = CurrBlock->rbegin(),
@@ -1499,7 +1499,7 @@
const Stmt *Cond = PredBlock->getTerminatorCondition();
// We don't acquire try-locks on ?: branches, only when its result is used.
- if (!Cond || isa<ConditionalOperator>(PredBlock->getTerminator()))
+ if (!Cond || isa<ConditionalOperator>(PredBlock->getTerminatorStmt()))
return;
bool Negate = false;
@@ -2402,7 +2402,7 @@
// a difference in locksets is probably due to a bug in that block, rather
// than in some other predecessor. In that case, keep the other
// predecessor's lockset.
- if (const Stmt *Terminator = (*PI)->getTerminator()) {
+ if (const Stmt *Terminator = (*PI)->getTerminatorStmt()) {
if (isa<ContinueStmt>(Terminator) || isa<BreakStmt>(Terminator)) {
SpecialBlocks.push_back(*PI);
continue;
@@ -2441,7 +2441,7 @@
// it might also be part of a switch. Also, a subsequent destructor
// might add to the lockset, in which case the real issue might be a
// double lock on the other path.
- const Stmt *Terminator = PrevBlock->getTerminator();
+ const Stmt *Terminator = PrevBlock->getTerminatorStmt();
bool IsLoop = Terminator && isa<ContinueStmt>(Terminator);
FactSet PrevLockset;
Index: clang/lib/Analysis/ReachableCode.cpp
===================================================================
--- clang/lib/Analysis/ReachableCode.cpp
+++ clang/lib/Analysis/ReachableCode.cpp
@@ -48,7 +48,7 @@
static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
// Check if the block ends with a do...while() and see if 'S' is the
// condition.
- if (const Stmt *Term = B->getTerminator()) {
+ if (const Stmt *Term = B->getTerminatorStmt()) {
if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
const Expr *Cond = DS->getCond()->IgnoreParenCasts();
return Cond == S && isTrivialExpression(Cond);
@@ -109,14 +109,15 @@
// Note also that we are restricting the search for the return statement
// to stop at control-flow; only part of a return statement may be dead,
// without the whole return statement being dead.
- if (Current->getTerminator().isTemporaryDtorsBranch()) {
+ if (Current->getTerminator().getKind() ==
+ CFGTerminator::TemporaryDtorsBranch) {
// Temporary destructors have a predictable control flow, thus we want to
// look into the next block for the return statement.
// We look into the false branch, as we know the true branch only contains
// the call to the destructor.
assert(Current->succ_size() == 2);
Current = *(Current->succ_begin() + 1);
- } else if (!Current->getTerminator() && Current->succ_size() == 1) {
+ } else if (!Current->getTerminatorStmt() && Current->succ_size() == 1) {
// If there is only one successor, we're not dealing with outgoing control
// flow. Thus, look into the next block.
Current = *Current->succ_begin();
@@ -292,7 +293,7 @@
/// Returns true if we should always explore all successors of a block.
static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
Preprocessor &PP) {
- if (const Stmt *Term = B->getTerminator()) {
+ if (const Stmt *Term = B->getTerminatorStmt()) {
if (isa<SwitchStmt>(Term))
return true;
// Specially handle '||' and '&&'.
@@ -461,12 +462,11 @@
return S;
}
- if (CFGTerminator T = Block->getTerminator()) {
- if (!T.isTemporaryDtorsBranch()) {
- const Stmt *S = T.getStmt();
- if (isValidDeadStmt(S))
- return S;
- }
+ CFGTerminator T = Block->getTerminator();
+ if (T.getKind() == CFGTerminator::StmtBranch) {
+ const Stmt *S = T.getStmt();
+ if (S && isValidDeadStmt(S))
+ return S;
}
return nullptr;
Index: clang/lib/Analysis/ProgramPoint.cpp
===================================================================
--- clang/lib/Analysis/ProgramPoint.cpp
+++ clang/lib/Analysis/ProgramPoint.cpp
@@ -144,7 +144,7 @@
Out << "Edge: (B" << E.getSrc()->getBlockID() << ", B"
<< E.getDst()->getBlockID() << ')';
- if (const Stmt *T = E.getSrc()->getTerminator()) {
+ if (const Stmt *T = E.getSrc()->getTerminatorStmt()) {
SourceLocation SLoc = T->getBeginLoc();
Out << "\\|Terminator: ";
Index: clang/lib/Analysis/LiveVariables.cpp
===================================================================
--- clang/lib/Analysis/LiveVariables.cpp
+++ clang/lib/Analysis/LiveVariables.cpp
@@ -501,7 +501,7 @@
TransferFunctions TF(*this, val, obs, block);
// Visit the terminator (if any).
- if (const Stmt *term = block->getTerminator())
+ if (const Stmt *term = block->getTerminatorStmt())
TF.Visit(const_cast<Stmt*>(term));
// Apply the transfer function for all Stmts in the block.
Index: clang/lib/Analysis/Consumed.cpp
===================================================================
--- clang/lib/Analysis/Consumed.cpp
+++ clang/lib/Analysis/Consumed.cpp
@@ -76,7 +76,7 @@
static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
// Find the source location of the last statement in the block, if the block
// is not empty.
- if (const Stmt *StmtNode = Block->getTerminator()) {
+ if (const Stmt *StmtNode = Block->getTerminatorStmt()) {
return StmtNode->getBeginLoc();
} else {
for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
Index: clang/lib/Analysis/CFGStmtMap.cpp
===================================================================
--- clang/lib/Analysis/CFGStmtMap.cpp
+++ clang/lib/Analysis/CFGStmtMap.cpp
@@ -70,7 +70,7 @@
// Finally, look at the terminator. If the terminator was already added
// because it is a block-level expression in another block, overwrite
// that mapping.
- if (Stmt *Term = B->getTerminator())
+ if (Stmt *Term = B->getTerminatorStmt())
SM[Term] = B;
}
Index: clang/lib/Analysis/CFG.cpp
===================================================================
--- clang/lib/Analysis/CFG.cpp
+++ clang/lib/Analysis/CFG.cpp
@@ -1956,7 +1956,7 @@
= Blk->beginAutomaticObjDtorsInsert(Blk->end(), B.distance(E), C);
for (LocalScope::const_iterator I = B; I != E; ++I)
InsertPos = Blk->insertAutomaticObjDtor(InsertPos, *I,
- Blk->getTerminator());
+ Blk->getTerminatorStmt());
}
/// prependAutomaticObjLifetimeWithTerminator - Prepend lifetime CFGElements for
@@ -1971,8 +1971,10 @@
BumpVectorContext &C = cfg->getBumpVectorContext();
CFGBlock::iterator InsertPos =
Blk->beginLifetimeEndsInsert(Blk->end(), B.distance(E), C);
- for (LocalScope::const_iterator I = B; I != E; ++I)
- InsertPos = Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminator());
+ for (LocalScope::const_iterator I = B; I != E; ++I) {
+ InsertPos =
+ Blk->insertLifetimeEnds(InsertPos, *I, Blk->getTerminatorStmt());
+ }
}
/// prependAutomaticObjScopeEndWithTerminator - Prepend scope end CFGElements for
@@ -1991,7 +1993,7 @@
LocalScope::const_iterator PlaceToInsert = B;
for (LocalScope::const_iterator I = B; I != E; ++I)
PlaceToInsert = I;
- Blk->insertScopeEnd(InsertPos, *PlaceToInsert, Blk->getTerminator());
+ Blk->insertScopeEnd(InsertPos, *PlaceToInsert, Blk->getTerminatorStmt());
return *PlaceToInsert;
}
@@ -4612,7 +4614,8 @@
}
assert(Context.TerminatorExpr);
CFGBlock *Decision = createBlock(false);
- Decision->setTerminator(CFGTerminator(Context.TerminatorExpr, true));
+ Decision->setTerminator(CFGTerminator(Context.TerminatorExpr,
+ CFGTerminator::TemporaryDtorsBranch));
addSuccessor(Decision, Block, !Context.KnownExecuted.isFalse());
addSuccessor(Decision, FalseSucc ? FalseSucc : Context.Succ,
!Context.KnownExecuted.isTrue());
@@ -4820,7 +4823,7 @@
// If the 'To' has no label or is labeled but the label isn't a
// CaseStmt then filter this edge.
if (const SwitchStmt *S =
- dyn_cast_or_null<SwitchStmt>(From->getTerminator().getStmt())) {
+ dyn_cast_or_null<SwitchStmt>(From->getTerminatorStmt())) {
if (S->isAllEnumCasesCovered()) {
const Stmt *L = To->getLabel();
if (!L || !isa<CaseStmt>(L))
@@ -5055,9 +5058,15 @@
public:
void print(CFGTerminator T) {
- if (T.isTemporaryDtorsBranch())
+ switch (T.getKind()) {
+ case CFGTerminator::StmtBranch:
+ Visit(T.getStmt());
+ break;
+ case CFGTerminator::TemporaryDtorsBranch:
OS << "(Temp Dtor) ";
- Visit(T.getStmt());
+ Visit(T.getStmt());
+ break;
+ }
}
};
@@ -5366,7 +5375,7 @@
}
// Print the terminator of this block.
- if (B.getTerminator()) {
+ if (B.getTerminator().isValid()) {
if (ShowColors)
OS.changeColor(raw_ostream::GREEN);
@@ -5519,7 +5528,7 @@
}
Stmt *CFGBlock::getTerminatorCondition(bool StripParens) {
- Stmt *Terminator = this->Terminator;
+ Stmt *Terminator = getTerminatorStmt();
if (!Terminator)
return nullptr;
Index: clang/include/clang/Analysis/ProgramPoint.h
===================================================================
--- clang/include/clang/Analysis/ProgramPoint.h
+++ clang/include/clang/Analysis/ProgramPoint.h
@@ -257,7 +257,7 @@
}
const Stmt *getTerminator() const {
- return getBlock()->getTerminator();
+ return getBlock()->getTerminatorStmt();
}
private:
Index: clang/include/clang/Analysis/CFG.h
===================================================================
--- clang/include/clang/Analysis/CFG.h
+++ clang/include/clang/Analysis/CFG.h
@@ -494,33 +494,30 @@
/// Represents CFGBlock terminator statement.
///
-/// TemporaryDtorsBranch bit is set to true if the terminator marks a branch
-/// in control flow of destructors of temporaries. In this case terminator
-/// statement is the same statement that branches control flow in evaluation
-/// of matching full expression.
class CFGTerminator {
+public:
+ enum Kind {
+ /// A branch that corresponds to a statement in the code,
+ /// such as an if-statement.
+ StmtBranch,
+ /// A branch in control flow of destructors of temporaries. In this case
+ /// terminator statement is the same statement that branches control flow
+ /// in evaluation of matching full expression.
+ TemporaryDtorsBranch
+ };
+
+private:
llvm::PointerIntPair<Stmt *, 1> Data;
public:
- CFGTerminator() = default;
- CFGTerminator(Stmt *S, bool TemporaryDtorsBranch = false)
- : Data(S, TemporaryDtorsBranch) {}
+ CFGTerminator() { assert(!isValid()); }
+ CFGTerminator(Stmt *S, Kind K = StmtBranch) : Data(S, K) {}
Stmt *getStmt() { return Data.getPointer(); }
const Stmt *getStmt() const { return Data.getPointer(); }
+ Kind getKind() const { return static_cast<Kind>(Data.getInt()); }
- bool isTemporaryDtorsBranch() const { return Data.getInt(); }
-
- operator Stmt *() { return getStmt(); }
- operator const Stmt *() const { return getStmt(); }
-
- Stmt *operator->() { return getStmt(); }
- const Stmt *operator->() const { return getStmt(); }
-
- Stmt &operator*() { return *getStmt(); }
- const Stmt &operator*() const { return *getStmt(); }
-
- explicit operator bool() const { return getStmt(); }
+ bool isValid() { return Data.getOpaqueValue() != nullptr; }
};
/// Represents a single basic block in a source-level CFG.
@@ -836,8 +833,10 @@
void setLoopTarget(const Stmt *loopTarget) { LoopTarget = loopTarget; }
void setHasNoReturnElement() { HasNoReturnElement = true; }
- CFGTerminator getTerminator() { return Terminator; }
- const CFGTerminator getTerminator() const { return Terminator; }
+ CFGTerminator getTerminator() const { return Terminator; }
+
+ Stmt *getTerminatorStmt() { return Terminator.getStmt(); }
+ const Stmt *getTerminatorStmt() const { return Terminator.getStmt(); }
Stmt *getTerminatorCondition(bool StripParens = true);
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits