1524b3c18SFangrui Song //===-- ReachableCode.cpp - Code Reachability Analysis --------------------===//
27296de9aSTed Kremenek //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67296de9aSTed Kremenek //
77296de9aSTed Kremenek //===----------------------------------------------------------------------===//
87296de9aSTed Kremenek //
97296de9aSTed Kremenek // This file implements a flow-sensitive, path-insensitive analysis of
107296de9aSTed Kremenek // determining reachable blocks within a CFG.
117296de9aSTed Kremenek //
127296de9aSTed Kremenek //===----------------------------------------------------------------------===//
137296de9aSTed Kremenek
143a02247dSChandler Carruth #include "clang/Analysis/Analyses/ReachableCode.h"
15552eeaa9STed Kremenek #include "clang/AST/Expr.h"
16552eeaa9STed Kremenek #include "clang/AST/ExprCXX.h"
1731168b07SJohn McCall #include "clang/AST/ExprObjC.h"
18f3c93bb6STed Kremenek #include "clang/AST/ParentMap.h"
190d9593ddSChandler Carruth #include "clang/AST/StmtCXX.h"
2050657f6bSGeorge Karpenkov #include "clang/Analysis/AnalysisDeclContext.h"
213a02247dSChandler Carruth #include "clang/Analysis/CFG.h"
22979da9a4SReid Kleckner #include "clang/Basic/Builtins.h"
23552eeaa9STed Kremenek #include "clang/Basic/SourceManager.h"
240d9593ddSChandler Carruth #include "clang/Lex/Preprocessor.h"
253a02247dSChandler Carruth #include "llvm/ADT/BitVector.h"
263a02247dSChandler Carruth #include "llvm/ADT/SmallVector.h"
277296de9aSTed Kremenek
287296de9aSTed Kremenek using namespace clang;
297296de9aSTed Kremenek
307d47caceSTed Kremenek //===----------------------------------------------------------------------===//
317d47caceSTed Kremenek // Core Reachability Analysis routines.
327d47caceSTed Kremenek //===----------------------------------------------------------------------===//
33552eeaa9STed Kremenek
isEnumConstant(const Expr * Ex)345441c188STed Kremenek static bool isEnumConstant(const Expr *Ex) {
355441c188STed Kremenek const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
365441c188STed Kremenek if (!DR)
375441c188STed Kremenek return false;
385441c188STed Kremenek return isa<EnumConstantDecl>(DR->getDecl());
395441c188STed Kremenek }
405441c188STed Kremenek
isTrivialExpression(const Expr * Ex)415441c188STed Kremenek static bool isTrivialExpression(const Expr *Ex) {
420a69cabdSTed Kremenek Ex = Ex->IgnoreParenCasts();
435441c188STed Kremenek return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
44c10830b3STed Kremenek isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) ||
45c10830b3STed Kremenek isa<CharacterLiteral>(Ex) ||
465441c188STed Kremenek isEnumConstant(Ex);
475441c188STed Kremenek }
485441c188STed Kremenek
isTrivialDoWhile(const CFGBlock * B,const Stmt * S)49ad8753c0STed Kremenek static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
501de2e14fSTed Kremenek // Check if the block ends with a do...while() and see if 'S' is the
511de2e14fSTed Kremenek // condition.
524e53032dSArtem Dergachev if (const Stmt *Term = B->getTerminatorStmt()) {
531a8641c1STed Kremenek if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
54d4576318STed Kremenek const Expr *Cond = DS->getCond()->IgnoreParenCasts();
551a8641c1STed Kremenek return Cond == S && isTrivialExpression(Cond);
561de2e14fSTed Kremenek }
571a8641c1STed Kremenek }
58ad8753c0STed Kremenek return false;
59ad8753c0STed Kremenek }
601de2e14fSTed Kremenek
isBuiltinUnreachable(const Stmt * S)6146103e0eSAlex Lorenz static bool isBuiltinUnreachable(const Stmt *S) {
6246103e0eSAlex Lorenz if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
6346103e0eSAlex Lorenz if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
6446103e0eSAlex Lorenz return FDecl->getIdentifier() &&
6546103e0eSAlex Lorenz FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
6646103e0eSAlex Lorenz return false;
6746103e0eSAlex Lorenz }
6846103e0eSAlex Lorenz
isBuiltinAssumeFalse(const CFGBlock * B,const Stmt * S,ASTContext & C)69758fbaceSNico Weber static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
70758fbaceSNico Weber ASTContext &C) {
71758fbaceSNico Weber if (B->empty()) {
72758fbaceSNico Weber // Happens if S is B's terminator and B contains nothing else
73758fbaceSNico Weber // (e.g. a CFGBlock containing only a goto).
74758fbaceSNico Weber return false;
75758fbaceSNico Weber }
76758fbaceSNico Weber if (Optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
77758fbaceSNico Weber if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
78758fbaceSNico Weber return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
79758fbaceSNico Weber }
80758fbaceSNico Weber }
81758fbaceSNico Weber return false;
82758fbaceSNico Weber }
83758fbaceSNico Weber
isDeadReturn(const CFGBlock * B,const Stmt * S)84f3c93bb6STed Kremenek static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
855fbdc93dSManuel Klimek // Look to see if the current control flow ends with a 'return', and see if
865fbdc93dSManuel Klimek // 'S' is a substatement. The 'return' may not be the last element in the
875fbdc93dSManuel Klimek // block, or may be in a subsequent block because of destructors.
885fbdc93dSManuel Klimek const CFGBlock *Current = B;
895fbdc93dSManuel Klimek while (true) {
90eb1c7c13SKazu Hirata for (const CFGElement &CE : llvm::reverse(*Current)) {
91eb1c7c13SKazu Hirata if (Optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
925441c188STed Kremenek if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
93ad8753c0STed Kremenek if (RS == S)
94ad8753c0STed Kremenek return true;
95ad8753c0STed Kremenek if (const Expr *RE = RS->getRetValue()) {
96f3c93bb6STed Kremenek RE = RE->IgnoreParenCasts();
97f3c93bb6STed Kremenek if (RE == S)
98f3c93bb6STed Kremenek return true;
99f3c93bb6STed Kremenek ParentMap PM(const_cast<Expr *>(RE));
100f3c93bb6STed Kremenek // If 'S' is in the ParentMap, it is a subexpression of
1015fbdc93dSManuel Klimek // the return statement.
102f3c93bb6STed Kremenek return PM.getParent(S);
1037549f0f9STed Kremenek }
1041a8641c1STed Kremenek }
1050a69cabdSTed Kremenek break;
1065441c188STed Kremenek }
1075441c188STed Kremenek }
1085fbdc93dSManuel Klimek // Note also that we are restricting the search for the return statement
1095fbdc93dSManuel Klimek // to stop at control-flow; only part of a return statement may be dead,
1105fbdc93dSManuel Klimek // without the whole return statement being dead.
1115fbdc93dSManuel Klimek if (Current->getTerminator().isTemporaryDtorsBranch()) {
1125fbdc93dSManuel Klimek // Temporary destructors have a predictable control flow, thus we want to
1135fbdc93dSManuel Klimek // look into the next block for the return statement.
1145fbdc93dSManuel Klimek // We look into the false branch, as we know the true branch only contains
1155fbdc93dSManuel Klimek // the call to the destructor.
1165fbdc93dSManuel Klimek assert(Current->succ_size() == 2);
1175fbdc93dSManuel Klimek Current = *(Current->succ_begin() + 1);
1184e53032dSArtem Dergachev } else if (!Current->getTerminatorStmt() && Current->succ_size() == 1) {
1195fbdc93dSManuel Klimek // If there is only one successor, we're not dealing with outgoing control
1205fbdc93dSManuel Klimek // flow. Thus, look into the next block.
1215fbdc93dSManuel Klimek Current = *Current->succ_begin();
1225fbdc93dSManuel Klimek if (Current->pred_size() > 1) {
1235fbdc93dSManuel Klimek // If there is more than one predecessor, we're dealing with incoming
1245fbdc93dSManuel Klimek // control flow - if the return statement is in that block, it might
1255fbdc93dSManuel Klimek // well be reachable via a different control flow, thus it's not dead.
1260a69cabdSTed Kremenek return false;
127cc893386STed Kremenek }
1285fbdc93dSManuel Klimek } else {
1295fbdc93dSManuel Klimek // We hit control flow or a dead end. Stop searching.
1305fbdc93dSManuel Klimek return false;
1315fbdc93dSManuel Klimek }
1325fbdc93dSManuel Klimek }
1335fbdc93dSManuel Klimek llvm_unreachable("Broke out of infinite loop.");
1345fbdc93dSManuel Klimek }
135cc893386STed Kremenek
getTopMostMacro(SourceLocation Loc,SourceManager & SM)1362dd810a3STed Kremenek static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
1372dd810a3STed Kremenek assert(Loc.isMacroID());
1382dd810a3STed Kremenek SourceLocation Last;
139772f4826SSeija Kijin do {
1402dd810a3STed Kremenek Last = Loc;
1412dd810a3STed Kremenek Loc = SM.getImmediateMacroCallerLoc(Loc);
142772f4826SSeija Kijin } while (Loc.isMacroID());
1432dd810a3STed Kremenek return Last;
1442dd810a3STed Kremenek }
1452dd810a3STed Kremenek
1466d9bb56cSTed Kremenek /// Returns true if the statement is expanded from a configuration macro.
isExpandedFromConfigurationMacro(const Stmt * S,Preprocessor & PP,bool IgnoreYES_NO=false)1472dd810a3STed Kremenek static bool isExpandedFromConfigurationMacro(const Stmt *S,
1482dd810a3STed Kremenek Preprocessor &PP,
1492dd810a3STed Kremenek bool IgnoreYES_NO = false) {
1506d9bb56cSTed Kremenek // FIXME: This is not very precise. Here we just check to see if the
1516d9bb56cSTed Kremenek // value comes from a macro, but we can do much better. This is likely
1526d9bb56cSTed Kremenek // to be over conservative. This logic is factored into a separate function
1536d9bb56cSTed Kremenek // so that we can refine it later.
154f2ceec48SStephen Kelly SourceLocation L = S->getBeginLoc();
1552dd810a3STed Kremenek if (L.isMacroID()) {
1566615f2b3SAlex Lorenz SourceManager &SM = PP.getSourceManager();
1572dd810a3STed Kremenek if (IgnoreYES_NO) {
1582dd810a3STed Kremenek // The Objective-C constant 'YES' and 'NO'
1592dd810a3STed Kremenek // are defined as macros. Do not treat them
1602dd810a3STed Kremenek // as configuration values.
1612dd810a3STed Kremenek SourceLocation TopL = getTopMostMacro(L, SM);
1622dd810a3STed Kremenek StringRef MacroName = PP.getImmediateMacroName(TopL);
1632dd810a3STed Kremenek if (MacroName == "YES" || MacroName == "NO")
1642dd810a3STed Kremenek return false;
1656615f2b3SAlex Lorenz } else if (!PP.getLangOpts().CPlusPlus) {
1666615f2b3SAlex Lorenz // Do not treat C 'false' and 'true' macros as configuration values.
1676615f2b3SAlex Lorenz SourceLocation TopL = getTopMostMacro(L, SM);
1686615f2b3SAlex Lorenz StringRef MacroName = PP.getImmediateMacroName(TopL);
1696615f2b3SAlex Lorenz if (MacroName == "false" || MacroName == "true")
1706615f2b3SAlex Lorenz return false;
1712dd810a3STed Kremenek }
1722dd810a3STed Kremenek return true;
1732dd810a3STed Kremenek }
1742dd810a3STed Kremenek return false;
1756d9bb56cSTed Kremenek }
1766d9bb56cSTed Kremenek
177f5ae0bc6STed Kremenek static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
178f5ae0bc6STed Kremenek
1796d9bb56cSTed Kremenek /// Returns true if the statement represents a configuration value.
1806d9bb56cSTed Kremenek ///
1816d9bb56cSTed Kremenek /// A configuration value is something usually determined at compile-time
1826d9bb56cSTed Kremenek /// to conditionally always execute some branch. Such guards are for
1836d9bb56cSTed Kremenek /// "sometimes unreachable" code. Such code is usually not interesting
1846d9bb56cSTed Kremenek /// to report as unreachable, and may mask truly unreachable code within
1856d9bb56cSTed Kremenek /// those blocks.
isConfigurationValue(const Stmt * S,Preprocessor & PP,SourceRange * SilenceableCondVal=nullptr,bool IncludeIntegers=true,bool WrappedInParens=false)186c980afc5STed Kremenek static bool isConfigurationValue(const Stmt *S,
1872dd810a3STed Kremenek Preprocessor &PP,
188ec3bbf49STed Kremenek SourceRange *SilenceableCondVal = nullptr,
189ec3bbf49STed Kremenek bool IncludeIntegers = true,
190ec3bbf49STed Kremenek bool WrappedInParens = false) {
1916d9bb56cSTed Kremenek if (!S)
1926d9bb56cSTed Kremenek return false;
1936d9bb56cSTed Kremenek
194e64aee87SBruno Ricci if (const auto *Ex = dyn_cast<Expr>(S))
195e64aee87SBruno Ricci S = Ex->IgnoreImplicit();
19643ee05e8STim Shen
197e64aee87SBruno Ricci if (const auto *Ex = dyn_cast<Expr>(S))
1986f375e56STed Kremenek S = Ex->IgnoreCasts();
1996f375e56STed Kremenek
200ec3bbf49STed Kremenek // Special case looking for the sigil '()' around an integer literal.
201ec3bbf49STed Kremenek if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
202f2ceec48SStephen Kelly if (!PE->getBeginLoc().isMacroID())
203ec3bbf49STed Kremenek return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
204ec3bbf49STed Kremenek IncludeIntegers, true);
205ec3bbf49STed Kremenek
2066d9bb56cSTed Kremenek if (const Expr *Ex = dyn_cast<Expr>(S))
2076f375e56STed Kremenek S = Ex->IgnoreCasts();
2086d9bb56cSTed Kremenek
209ab57a155STed Kremenek bool IgnoreYES_NO = false;
210ab57a155STed Kremenek
2116d9bb56cSTed Kremenek switch (S->getStmtClass()) {
2122766ad27STed Kremenek case Stmt::CallExprClass: {
2132766ad27STed Kremenek const FunctionDecl *Callee =
2142766ad27STed Kremenek dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
2152766ad27STed Kremenek return Callee ? Callee->isConstexpr() : false;
2162766ad27STed Kremenek }
217f5ae0bc6STed Kremenek case Stmt::DeclRefExprClass:
218f5ae0bc6STed Kremenek return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
219ab57a155STed Kremenek case Stmt::ObjCBoolLiteralExprClass:
220ab57a155STed Kremenek IgnoreYES_NO = true;
2214dc0b1acSReid Kleckner LLVM_FALLTHROUGH;
222ab57a155STed Kremenek case Stmt::CXXBoolLiteralExprClass:
223ec3bbf49STed Kremenek case Stmt::IntegerLiteralClass: {
224ab57a155STed Kremenek const Expr *E = cast<Expr>(S);
225ec3bbf49STed Kremenek if (IncludeIntegers) {
226ec3bbf49STed Kremenek if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
227ec3bbf49STed Kremenek *SilenceableCondVal = E->getSourceRange();
22823d5fe62SNico Weber return WrappedInParens ||
22923d5fe62SNico Weber isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
230ec3bbf49STed Kremenek }
231ec3bbf49STed Kremenek return false;
232ec3bbf49STed Kremenek }
233f5ae0bc6STed Kremenek case Stmt::MemberExprClass:
234f5ae0bc6STed Kremenek return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
2356d9bb56cSTed Kremenek case Stmt::UnaryExprOrTypeTraitExprClass:
2366d9bb56cSTed Kremenek return true;
2376d9bb56cSTed Kremenek case Stmt::BinaryOperatorClass: {
2386d9bb56cSTed Kremenek const BinaryOperator *B = cast<BinaryOperator>(S);
239c980afc5STed Kremenek // Only include raw integers (not enums) as configuration
240c980afc5STed Kremenek // values if they are used in a logical or comparison operator
241c980afc5STed Kremenek // (not arithmetic).
242c980afc5STed Kremenek IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
243ec3bbf49STed Kremenek return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
244ec3bbf49STed Kremenek IncludeIntegers) ||
245ec3bbf49STed Kremenek isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
246ec3bbf49STed Kremenek IncludeIntegers);
2476d9bb56cSTed Kremenek }
2486d9bb56cSTed Kremenek case Stmt::UnaryOperatorClass: {
2496d9bb56cSTed Kremenek const UnaryOperator *UO = cast<UnaryOperator>(S);
2506541c798SRichard Trieu if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
251569ad73dSAlex Lorenz return false;
252569ad73dSAlex Lorenz bool SilenceableCondValNotSet =
253569ad73dSAlex Lorenz SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
254569ad73dSAlex Lorenz bool IsSubExprConfigValue =
255ec3bbf49STed Kremenek isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
256ec3bbf49STed Kremenek IncludeIntegers, WrappedInParens);
257569ad73dSAlex Lorenz // Update the silenceable condition value source range only if the range
258569ad73dSAlex Lorenz // was set directly by the child expression.
259569ad73dSAlex Lorenz if (SilenceableCondValNotSet &&
260569ad73dSAlex Lorenz SilenceableCondVal->getBegin().isValid() &&
261569ad73dSAlex Lorenz *SilenceableCondVal ==
262569ad73dSAlex Lorenz UO->getSubExpr()->IgnoreCasts()->getSourceRange())
263569ad73dSAlex Lorenz *SilenceableCondVal = UO->getSourceRange();
264569ad73dSAlex Lorenz return IsSubExprConfigValue;
2656d9bb56cSTed Kremenek }
2666d9bb56cSTed Kremenek default:
2676d9bb56cSTed Kremenek return false;
2686d9bb56cSTed Kremenek }
2696d9bb56cSTed Kremenek }
2706d9bb56cSTed Kremenek
isConfigurationValue(const ValueDecl * D,Preprocessor & PP)271f5ae0bc6STed Kremenek static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
272f5ae0bc6STed Kremenek if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
273f5ae0bc6STed Kremenek return isConfigurationValue(ED->getInitExpr(), PP);
274f5ae0bc6STed Kremenek if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
275f5ae0bc6STed Kremenek // As a heuristic, treat globals as configuration values. Note
276f5ae0bc6STed Kremenek // that we only will get here if Sema evaluated this
277f5ae0bc6STed Kremenek // condition to a constant expression, which means the global
278f5ae0bc6STed Kremenek // had to be declared in a way to be a truly constant value.
279f5ae0bc6STed Kremenek // We could generalize this to local variables, but it isn't
280f5ae0bc6STed Kremenek // clear if those truly represent configuration values that
281f5ae0bc6STed Kremenek // gate unreachable code.
282f5ae0bc6STed Kremenek if (!VD->hasLocalStorage())
283f5ae0bc6STed Kremenek return true;
284f5ae0bc6STed Kremenek
285f5ae0bc6STed Kremenek // As a heuristic, locals that have been marked 'const' explicitly
286f5ae0bc6STed Kremenek // can be treated as configuration values as well.
287f5ae0bc6STed Kremenek return VD->getType().isLocalConstQualified();
288f5ae0bc6STed Kremenek }
289f5ae0bc6STed Kremenek return false;
290f5ae0bc6STed Kremenek }
291f5ae0bc6STed Kremenek
2926d9bb56cSTed Kremenek /// Returns true if we should always explore all successors of a block.
shouldTreatSuccessorsAsReachable(const CFGBlock * B,Preprocessor & PP)2932dd810a3STed Kremenek static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
2942dd810a3STed Kremenek Preprocessor &PP) {
2954e53032dSArtem Dergachev if (const Stmt *Term = B->getTerminatorStmt()) {
2966999d025STed Kremenek if (isa<SwitchStmt>(Term))
2976999d025STed Kremenek return true;
298782f003cSTed Kremenek // Specially handle '||' and '&&'.
299ec3bbf49STed Kremenek if (isa<BinaryOperator>(Term)) {
3002dd810a3STed Kremenek return isConfigurationValue(Term, PP);
301782f003cSTed Kremenek }
302ec3bbf49STed Kremenek }
3036999d025STed Kremenek
304ec3bbf49STed Kremenek const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
305ec3bbf49STed Kremenek return isConfigurationValue(Cond, PP);
3066d9bb56cSTed Kremenek }
3076d9bb56cSTed Kremenek
scanFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable,Preprocessor * PP,bool IncludeSometimesUnreachableEdges)3087d47caceSTed Kremenek static unsigned scanFromBlock(const CFGBlock *Start,
3097d47caceSTed Kremenek llvm::BitVector &Reachable,
3102dd810a3STed Kremenek Preprocessor *PP,
3117d47caceSTed Kremenek bool IncludeSometimesUnreachableEdges) {
3127296de9aSTed Kremenek unsigned count = 0;
3137296de9aSTed Kremenek
3147296de9aSTed Kremenek // Prep work queue
315bd913713STed Kremenek SmallVector<const CFGBlock*, 32> WL;
316bd913713STed Kremenek
317bd913713STed Kremenek // The entry block may have already been marked reachable
318bd913713STed Kremenek // by the caller.
319bd913713STed Kremenek if (!Reachable[Start->getBlockID()]) {
3207296de9aSTed Kremenek ++count;
321bd913713STed Kremenek Reachable[Start->getBlockID()] = true;
322bd913713STed Kremenek }
323bd913713STed Kremenek
324bd913713STed Kremenek WL.push_back(Start);
3257296de9aSTed Kremenek
3267296de9aSTed Kremenek // Find the reachable blocks from 'Start'.
3277296de9aSTed Kremenek while (!WL.empty()) {
328bd913713STed Kremenek const CFGBlock *item = WL.pop_back_val();
3297296de9aSTed Kremenek
3306d9bb56cSTed Kremenek // There are cases where we want to treat all successors as reachable.
3316d9bb56cSTed Kremenek // The idea is that some "sometimes unreachable" code is not interesting,
3326d9bb56cSTed Kremenek // and that we should forge ahead and explore those branches anyway.
3336d9bb56cSTed Kremenek // This allows us to potentially uncover some "always unreachable" code
3346d9bb56cSTed Kremenek // within the "sometimes unreachable" code.
3357296de9aSTed Kremenek // Look at the successors and mark then reachable.
336782f003cSTed Kremenek Optional<bool> TreatAllSuccessorsAsReachable;
3377d47caceSTed Kremenek if (!IncludeSometimesUnreachableEdges)
3387d47caceSTed Kremenek TreatAllSuccessorsAsReachable = false;
339782f003cSTed Kremenek
340bd913713STed Kremenek for (CFGBlock::const_succ_iterator I = item->succ_begin(),
34108da9781STed Kremenek E = item->succ_end(); I != E; ++I) {
34208da9781STed Kremenek const CFGBlock *B = *I;
3436d9bb56cSTed Kremenek if (!B) do {
3446d9bb56cSTed Kremenek const CFGBlock *UB = I->getPossiblyUnreachableBlock();
3456d9bb56cSTed Kremenek if (!UB)
3466d9bb56cSTed Kremenek break;
3476d9bb56cSTed Kremenek
348452db157SKazu Hirata if (!TreatAllSuccessorsAsReachable) {
3492dd810a3STed Kremenek assert(PP);
350782f003cSTed Kremenek TreatAllSuccessorsAsReachable =
3512dd810a3STed Kremenek shouldTreatSuccessorsAsReachable(item, *PP);
3522dd810a3STed Kremenek }
353782f003cSTed Kremenek
354*ca4af13eSKazu Hirata if (*TreatAllSuccessorsAsReachable) {
3556d9bb56cSTed Kremenek B = UB;
3566d9bb56cSTed Kremenek break;
3576d9bb56cSTed Kremenek }
35808da9781STed Kremenek }
3596d9bb56cSTed Kremenek while (false);
3606d9bb56cSTed Kremenek
36108da9781STed Kremenek if (B) {
3627296de9aSTed Kremenek unsigned blockID = B->getBlockID();
3637296de9aSTed Kremenek if (!Reachable[blockID]) {
3647296de9aSTed Kremenek Reachable.set(blockID);
3657296de9aSTed Kremenek WL.push_back(B);
366bd913713STed Kremenek ++count;
3677296de9aSTed Kremenek }
3687296de9aSTed Kremenek }
3697296de9aSTed Kremenek }
37008da9781STed Kremenek }
3717296de9aSTed Kremenek return count;
3727296de9aSTed Kremenek }
373552eeaa9STed Kremenek
scanMaybeReachableFromBlock(const CFGBlock * Start,Preprocessor & PP,llvm::BitVector & Reachable)3747d47caceSTed Kremenek static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
3752dd810a3STed Kremenek Preprocessor &PP,
3767d47caceSTed Kremenek llvm::BitVector &Reachable) {
3772dd810a3STed Kremenek return scanFromBlock(Start, Reachable, &PP, true);
3787d47caceSTed Kremenek }
3797d47caceSTed Kremenek
3807d47caceSTed Kremenek //===----------------------------------------------------------------------===//
3817d47caceSTed Kremenek // Dead Code Scanner.
3827d47caceSTed Kremenek //===----------------------------------------------------------------------===//
3837d47caceSTed Kremenek
3847d47caceSTed Kremenek namespace {
3857d47caceSTed Kremenek class DeadCodeScan {
3867d47caceSTed Kremenek llvm::BitVector Visited;
3877d47caceSTed Kremenek llvm::BitVector &Reachable;
3887d47caceSTed Kremenek SmallVector<const CFGBlock *, 10> WorkList;
3892dd810a3STed Kremenek Preprocessor &PP;
390758fbaceSNico Weber ASTContext &C;
3917d47caceSTed Kremenek
3927d47caceSTed Kremenek typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
3937d47caceSTed Kremenek DeferredLocsTy;
3947d47caceSTed Kremenek
3957d47caceSTed Kremenek DeferredLocsTy DeferredLocs;
3967d47caceSTed Kremenek
3977d47caceSTed Kremenek public:
DeadCodeScan(llvm::BitVector & reachable,Preprocessor & PP,ASTContext & C)398758fbaceSNico Weber DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
3997d47caceSTed Kremenek : Visited(reachable.size()),
4002dd810a3STed Kremenek Reachable(reachable),
401758fbaceSNico Weber PP(PP), C(C) {}
4027d47caceSTed Kremenek
4037d47caceSTed Kremenek void enqueue(const CFGBlock *block);
4047d47caceSTed Kremenek unsigned scanBackwards(const CFGBlock *Start,
4057d47caceSTed Kremenek clang::reachable_code::Callback &CB);
4067d47caceSTed Kremenek
4077d47caceSTed Kremenek bool isDeadCodeRoot(const CFGBlock *Block);
4087d47caceSTed Kremenek
4097d47caceSTed Kremenek const Stmt *findDeadCode(const CFGBlock *Block);
4107d47caceSTed Kremenek
4117d47caceSTed Kremenek void reportDeadCode(const CFGBlock *B,
4127d47caceSTed Kremenek const Stmt *S,
4137d47caceSTed Kremenek clang::reachable_code::Callback &CB);
4147d47caceSTed Kremenek };
415ab9db510SAlexander Kornienko }
4167d47caceSTed Kremenek
enqueue(const CFGBlock * block)4177d47caceSTed Kremenek void DeadCodeScan::enqueue(const CFGBlock *block) {
4187d47caceSTed Kremenek unsigned blockID = block->getBlockID();
4197d47caceSTed Kremenek if (Reachable[blockID] || Visited[blockID])
4207d47caceSTed Kremenek return;
4217d47caceSTed Kremenek Visited[blockID] = true;
4227d47caceSTed Kremenek WorkList.push_back(block);
4237d47caceSTed Kremenek }
4247d47caceSTed Kremenek
isDeadCodeRoot(const clang::CFGBlock * Block)4257d47caceSTed Kremenek bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
4267d47caceSTed Kremenek bool isDeadRoot = true;
4277d47caceSTed Kremenek
4287d47caceSTed Kremenek for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
4297d47caceSTed Kremenek E = Block->pred_end(); I != E; ++I) {
4307d47caceSTed Kremenek if (const CFGBlock *PredBlock = *I) {
4317d47caceSTed Kremenek unsigned blockID = PredBlock->getBlockID();
4327d47caceSTed Kremenek if (Visited[blockID]) {
4337d47caceSTed Kremenek isDeadRoot = false;
4347d47caceSTed Kremenek continue;
4357d47caceSTed Kremenek }
4367d47caceSTed Kremenek if (!Reachable[blockID]) {
4377d47caceSTed Kremenek isDeadRoot = false;
4387d47caceSTed Kremenek Visited[blockID] = true;
4397d47caceSTed Kremenek WorkList.push_back(PredBlock);
4407d47caceSTed Kremenek continue;
4417d47caceSTed Kremenek }
4427d47caceSTed Kremenek }
4437d47caceSTed Kremenek }
4447d47caceSTed Kremenek
4457d47caceSTed Kremenek return isDeadRoot;
4467d47caceSTed Kremenek }
4477d47caceSTed Kremenek
isValidDeadStmt(const Stmt * S)4487d47caceSTed Kremenek static bool isValidDeadStmt(const Stmt *S) {
449f2ceec48SStephen Kelly if (S->getBeginLoc().isInvalid())
4507d47caceSTed Kremenek return false;
4517d47caceSTed Kremenek if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
4527d47caceSTed Kremenek return BO->getOpcode() != BO_Comma;
4537d47caceSTed Kremenek return true;
4547d47caceSTed Kremenek }
4557d47caceSTed Kremenek
findDeadCode(const clang::CFGBlock * Block)4567d47caceSTed Kremenek const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
4577d47caceSTed Kremenek for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
4587d47caceSTed Kremenek if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
4597d47caceSTed Kremenek const Stmt *S = CS->getStmt();
4607d47caceSTed Kremenek if (isValidDeadStmt(S))
4617d47caceSTed Kremenek return S;
4627d47caceSTed Kremenek }
4637d47caceSTed Kremenek
4644e53032dSArtem Dergachev CFGTerminator T = Block->getTerminator();
4654e53032dSArtem Dergachev if (T.isStmtBranch()) {
4667d47caceSTed Kremenek const Stmt *S = T.getStmt();
4674e53032dSArtem Dergachev if (S && isValidDeadStmt(S))
4687d47caceSTed Kremenek return S;
4697d47caceSTed Kremenek }
4707d47caceSTed Kremenek
47125542943SCraig Topper return nullptr;
4727d47caceSTed Kremenek }
4737d47caceSTed Kremenek
SrcCmp(const std::pair<const CFGBlock *,const Stmt * > * p1,const std::pair<const CFGBlock *,const Stmt * > * p2)4744cadf292SBenjamin Kramer static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
4754cadf292SBenjamin Kramer const std::pair<const CFGBlock *, const Stmt *> *p2) {
476f2ceec48SStephen Kelly if (p1->second->getBeginLoc() < p2->second->getBeginLoc())
4774cadf292SBenjamin Kramer return -1;
478f2ceec48SStephen Kelly if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
4794cadf292SBenjamin Kramer return 1;
4804cadf292SBenjamin Kramer return 0;
4814cadf292SBenjamin Kramer }
4824cadf292SBenjamin Kramer
scanBackwards(const clang::CFGBlock * Start,clang::reachable_code::Callback & CB)4837d47caceSTed Kremenek unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
4847d47caceSTed Kremenek clang::reachable_code::Callback &CB) {
4857d47caceSTed Kremenek
4867d47caceSTed Kremenek unsigned count = 0;
4877d47caceSTed Kremenek enqueue(Start);
4887d47caceSTed Kremenek
4897d47caceSTed Kremenek while (!WorkList.empty()) {
4907d47caceSTed Kremenek const CFGBlock *Block = WorkList.pop_back_val();
4917d47caceSTed Kremenek
4927d47caceSTed Kremenek // It is possible that this block has been marked reachable after
4937d47caceSTed Kremenek // it was enqueued.
4947d47caceSTed Kremenek if (Reachable[Block->getBlockID()])
4957d47caceSTed Kremenek continue;
4967d47caceSTed Kremenek
4977d47caceSTed Kremenek // Look for any dead code within the block.
4987d47caceSTed Kremenek const Stmt *S = findDeadCode(Block);
4997d47caceSTed Kremenek
5007d47caceSTed Kremenek if (!S) {
5017d47caceSTed Kremenek // No dead code. Possibly an empty block. Look at dead predecessors.
5027d47caceSTed Kremenek for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
5037d47caceSTed Kremenek E = Block->pred_end(); I != E; ++I) {
5047d47caceSTed Kremenek if (const CFGBlock *predBlock = *I)
5057d47caceSTed Kremenek enqueue(predBlock);
5067d47caceSTed Kremenek }
5077d47caceSTed Kremenek continue;
5087d47caceSTed Kremenek }
5097d47caceSTed Kremenek
5107d47caceSTed Kremenek // Specially handle macro-expanded code.
511f2ceec48SStephen Kelly if (S->getBeginLoc().isMacroID()) {
5122dd810a3STed Kremenek count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5137d47caceSTed Kremenek continue;
5147d47caceSTed Kremenek }
5157d47caceSTed Kremenek
5167d47caceSTed Kremenek if (isDeadCodeRoot(Block)) {
5177d47caceSTed Kremenek reportDeadCode(Block, S, CB);
5182dd810a3STed Kremenek count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5197d47caceSTed Kremenek }
5207d47caceSTed Kremenek else {
5217d47caceSTed Kremenek // Record this statement as the possibly best location in a
5227d47caceSTed Kremenek // strongly-connected component of dead code for emitting a
5237d47caceSTed Kremenek // warning.
5247d47caceSTed Kremenek DeferredLocs.push_back(std::make_pair(Block, S));
5257d47caceSTed Kremenek }
5267d47caceSTed Kremenek }
5277d47caceSTed Kremenek
5287d47caceSTed Kremenek // If we didn't find a dead root, then report the dead code with the
5297d47caceSTed Kremenek // earliest location.
5307d47caceSTed Kremenek if (!DeferredLocs.empty()) {
5314cadf292SBenjamin Kramer llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
53223d5fe62SNico Weber for (const auto &I : DeferredLocs) {
53323d5fe62SNico Weber const CFGBlock *Block = I.first;
5347d47caceSTed Kremenek if (Reachable[Block->getBlockID()])
5357d47caceSTed Kremenek continue;
53623d5fe62SNico Weber reportDeadCode(Block, I.second, CB);
5372dd810a3STed Kremenek count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5387d47caceSTed Kremenek }
5397d47caceSTed Kremenek }
5407d47caceSTed Kremenek
5417d47caceSTed Kremenek return count;
5427d47caceSTed Kremenek }
5437d47caceSTed Kremenek
GetUnreachableLoc(const Stmt * S,SourceRange & R1,SourceRange & R2)5447d47caceSTed Kremenek static SourceLocation GetUnreachableLoc(const Stmt *S,
5457d47caceSTed Kremenek SourceRange &R1,
5467d47caceSTed Kremenek SourceRange &R2) {
5477d47caceSTed Kremenek R1 = R2 = SourceRange();
5487d47caceSTed Kremenek
5497d47caceSTed Kremenek if (const Expr *Ex = dyn_cast<Expr>(S))
5507d47caceSTed Kremenek S = Ex->IgnoreParenImpCasts();
5517d47caceSTed Kremenek
5527d47caceSTed Kremenek switch (S->getStmtClass()) {
5537d47caceSTed Kremenek case Expr::BinaryOperatorClass: {
5547d47caceSTed Kremenek const BinaryOperator *BO = cast<BinaryOperator>(S);
5557d47caceSTed Kremenek return BO->getOperatorLoc();
5567d47caceSTed Kremenek }
5577d47caceSTed Kremenek case Expr::UnaryOperatorClass: {
5587d47caceSTed Kremenek const UnaryOperator *UO = cast<UnaryOperator>(S);
5597d47caceSTed Kremenek R1 = UO->getSubExpr()->getSourceRange();
5607d47caceSTed Kremenek return UO->getOperatorLoc();
5617d47caceSTed Kremenek }
5627d47caceSTed Kremenek case Expr::CompoundAssignOperatorClass: {
5637d47caceSTed Kremenek const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
5647d47caceSTed Kremenek R1 = CAO->getLHS()->getSourceRange();
5657d47caceSTed Kremenek R2 = CAO->getRHS()->getSourceRange();
5667d47caceSTed Kremenek return CAO->getOperatorLoc();
5677d47caceSTed Kremenek }
5687d47caceSTed Kremenek case Expr::BinaryConditionalOperatorClass:
5697d47caceSTed Kremenek case Expr::ConditionalOperatorClass: {
5707d47caceSTed Kremenek const AbstractConditionalOperator *CO =
5717d47caceSTed Kremenek cast<AbstractConditionalOperator>(S);
5727d47caceSTed Kremenek return CO->getQuestionLoc();
5737d47caceSTed Kremenek }
5747d47caceSTed Kremenek case Expr::MemberExprClass: {
5757d47caceSTed Kremenek const MemberExpr *ME = cast<MemberExpr>(S);
5767d47caceSTed Kremenek R1 = ME->getSourceRange();
5777d47caceSTed Kremenek return ME->getMemberLoc();
5787d47caceSTed Kremenek }
5797d47caceSTed Kremenek case Expr::ArraySubscriptExprClass: {
5807d47caceSTed Kremenek const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
5817d47caceSTed Kremenek R1 = ASE->getLHS()->getSourceRange();
5827d47caceSTed Kremenek R2 = ASE->getRHS()->getSourceRange();
5837d47caceSTed Kremenek return ASE->getRBracketLoc();
5847d47caceSTed Kremenek }
5857d47caceSTed Kremenek case Expr::CStyleCastExprClass: {
5867d47caceSTed Kremenek const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
5877d47caceSTed Kremenek R1 = CSC->getSubExpr()->getSourceRange();
5887d47caceSTed Kremenek return CSC->getLParenLoc();
5897d47caceSTed Kremenek }
5907d47caceSTed Kremenek case Expr::CXXFunctionalCastExprClass: {
5917d47caceSTed Kremenek const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
5927d47caceSTed Kremenek R1 = CE->getSubExpr()->getSourceRange();
593f2ceec48SStephen Kelly return CE->getBeginLoc();
5947d47caceSTed Kremenek }
5957d47caceSTed Kremenek case Stmt::CXXTryStmtClass: {
5967d47caceSTed Kremenek return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
5977d47caceSTed Kremenek }
5987d47caceSTed Kremenek case Expr::ObjCBridgedCastExprClass: {
5997d47caceSTed Kremenek const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
6007d47caceSTed Kremenek R1 = CSC->getSubExpr()->getSourceRange();
6017d47caceSTed Kremenek return CSC->getLParenLoc();
6027d47caceSTed Kremenek }
6037d47caceSTed Kremenek default: ;
6047d47caceSTed Kremenek }
6057d47caceSTed Kremenek R1 = S->getSourceRange();
606f2ceec48SStephen Kelly return S->getBeginLoc();
6077d47caceSTed Kremenek }
6087d47caceSTed Kremenek
reportDeadCode(const CFGBlock * B,const Stmt * S,clang::reachable_code::Callback & CB)6097d47caceSTed Kremenek void DeadCodeScan::reportDeadCode(const CFGBlock *B,
6107d47caceSTed Kremenek const Stmt *S,
6117d47caceSTed Kremenek clang::reachable_code::Callback &CB) {
612f3c93bb6STed Kremenek // Classify the unreachable code found, or suppress it in some cases.
6131a8641c1STed Kremenek reachable_code::UnreachableKind UK = reachable_code::UK_Other;
6141a8641c1STed Kremenek
615ad8753c0STed Kremenek if (isa<BreakStmt>(S)) {
616ad8753c0STed Kremenek UK = reachable_code::UK_Break;
617758fbaceSNico Weber } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
618758fbaceSNico Weber isBuiltinAssumeFalse(B, S, C)) {
6197d47caceSTed Kremenek return;
620ad8753c0STed Kremenek }
621f3c93bb6STed Kremenek else if (isDeadReturn(B, S)) {
622f3c93bb6STed Kremenek UK = reachable_code::UK_Return;
623f3c93bb6STed Kremenek }
6247d47caceSTed Kremenek
625ec3bbf49STed Kremenek SourceRange SilenceableCondVal;
626ec3bbf49STed Kremenek
6271421037eSTed Kremenek if (UK == reachable_code::UK_Other) {
6281421037eSTed Kremenek // Check if the dead code is part of the "loop target" of
6291421037eSTed Kremenek // a for/for-range loop. This is the block that contains
6301421037eSTed Kremenek // the increment code.
6311421037eSTed Kremenek if (const Stmt *LoopTarget = B->getLoopTarget()) {
632f2ceec48SStephen Kelly SourceLocation Loc = LoopTarget->getBeginLoc();
6331421037eSTed Kremenek SourceRange R1(Loc, Loc), R2;
6341421037eSTed Kremenek
6351421037eSTed Kremenek if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
6361421037eSTed Kremenek const Expr *Inc = FS->getInc();
637f2ceec48SStephen Kelly Loc = Inc->getBeginLoc();
6381421037eSTed Kremenek R2 = Inc->getSourceRange();
6391421037eSTed Kremenek }
6401421037eSTed Kremenek
6411421037eSTed Kremenek CB.HandleUnreachable(reachable_code::UK_Loop_Increment,
642ec3bbf49STed Kremenek Loc, SourceRange(), SourceRange(Loc, Loc), R2);
6431421037eSTed Kremenek return;
6441421037eSTed Kremenek }
645ec3bbf49STed Kremenek
646ec3bbf49STed Kremenek // Check if the dead block has a predecessor whose branch has
647ec3bbf49STed Kremenek // a configuration value that *could* be modified to
648ec3bbf49STed Kremenek // silence the warning.
649ec3bbf49STed Kremenek CFGBlock::const_pred_iterator PI = B->pred_begin();
650ec3bbf49STed Kremenek if (PI != B->pred_end()) {
651ec3bbf49STed Kremenek if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
652ec3bbf49STed Kremenek const Stmt *TermCond =
653ec3bbf49STed Kremenek PredBlock->getTerminatorCondition(/* strip parens */ false);
654ec3bbf49STed Kremenek isConfigurationValue(TermCond, PP, &SilenceableCondVal);
655ec3bbf49STed Kremenek }
656ec3bbf49STed Kremenek }
6571421037eSTed Kremenek }
6581421037eSTed Kremenek
6597d47caceSTed Kremenek SourceRange R1, R2;
6607d47caceSTed Kremenek SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
661ec3bbf49STed Kremenek CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2);
6627d47caceSTed Kremenek }
6637d47caceSTed Kremenek
6647d47caceSTed Kremenek //===----------------------------------------------------------------------===//
6657d47caceSTed Kremenek // Reachability APIs.
6667d47caceSTed Kremenek //===----------------------------------------------------------------------===//
6677d47caceSTed Kremenek
6687d47caceSTed Kremenek namespace clang { namespace reachable_code {
6697d47caceSTed Kremenek
anchor()6707d47caceSTed Kremenek void Callback::anchor() { }
6717d47caceSTed Kremenek
ScanReachableFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable)6727d47caceSTed Kremenek unsigned ScanReachableFromBlock(const CFGBlock *Start,
6737d47caceSTed Kremenek llvm::BitVector &Reachable) {
67425542943SCraig Topper return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
6757d47caceSTed Kremenek }
6767d47caceSTed Kremenek
FindUnreachableCode(AnalysisDeclContext & AC,Preprocessor & PP,Callback & CB)6772dd810a3STed Kremenek void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
6782dd810a3STed Kremenek Callback &CB) {
6792dd810a3STed Kremenek
680552eeaa9STed Kremenek CFG *cfg = AC.getCFG();
681552eeaa9STed Kremenek if (!cfg)
682552eeaa9STed Kremenek return;
683552eeaa9STed Kremenek
684bd913713STed Kremenek // Scan for reachable blocks from the entrance of the CFG.
685552eeaa9STed Kremenek // If there are no unreachable blocks, we're done.
686bd913713STed Kremenek llvm::BitVector reachable(cfg->getNumBlockIDs());
6877d47caceSTed Kremenek unsigned numReachable =
6882dd810a3STed Kremenek scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
689552eeaa9STed Kremenek if (numReachable == cfg->getNumBlockIDs())
690552eeaa9STed Kremenek return;
691552eeaa9STed Kremenek
692bd913713STed Kremenek // If there aren't explicit EH edges, we should include the 'try' dispatch
693bd913713STed Kremenek // blocks as roots.
694bd913713STed Kremenek if (!AC.getCFGBuildOptions().AddEHEdges) {
69562abc184SNico Weber for (const CFGBlock *B : cfg->try_blocks())
69662abc184SNico Weber numReachable += scanMaybeReachableFromBlock(B, PP, reachable);
697bd913713STed Kremenek if (numReachable == cfg->getNumBlockIDs())
698bd913713STed Kremenek return;
699bd913713STed Kremenek }
700552eeaa9STed Kremenek
701bd913713STed Kremenek // There are some unreachable blocks. We need to find the root blocks that
702bd913713STed Kremenek // contain code that should be considered unreachable.
70323d5fe62SNico Weber for (const CFGBlock *block : *cfg) {
704bd913713STed Kremenek // A block may have been marked reachable during this loop.
705bd913713STed Kremenek if (reachable[block->getBlockID()])
706552eeaa9STed Kremenek continue;
707552eeaa9STed Kremenek
708758fbaceSNico Weber DeadCodeScan DS(reachable, PP, AC.getASTContext());
709bd913713STed Kremenek numReachable += DS.scanBackwards(block, CB);
710552eeaa9STed Kremenek
711bd913713STed Kremenek if (numReachable == cfg->getNumBlockIDs())
712bd913713STed Kremenek return;
713bd913713STed Kremenek }
714552eeaa9STed Kremenek }
715552eeaa9STed Kremenek
716ab9db510SAlexander Kornienko }} // end namespace clang::reachable_code
717