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