xref: /freebsd-src/contrib/llvm-project/clang/lib/Analysis/ReachableCode.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
10b57cec5SDimitry Andric //===-- ReachableCode.cpp - Code Reachability Analysis --------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements a flow-sensitive, path-insensitive analysis of
100b57cec5SDimitry Andric // determining reachable blocks within a CFG.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ReachableCode.h"
1506c3fb27SDimitry Andric #include "clang/AST/Attr.h"
160b57cec5SDimitry Andric #include "clang/AST/Expr.h"
170b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
180b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h"
190b57cec5SDimitry Andric #include "clang/AST/ParentMap.h"
20*0fca6ea1SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h"
210b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h"
220b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
230b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
24480093f4SDimitry Andric #include "clang/Basic/Builtins.h"
250b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h"
260b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h"
270b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h"
280b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
29bdd1243dSDimitry Andric #include <optional>
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric using namespace clang;
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
340b57cec5SDimitry Andric // Core Reachability Analysis routines.
350b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric static bool isEnumConstant(const Expr *Ex) {
380b57cec5SDimitry Andric   const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
390b57cec5SDimitry Andric   if (!DR)
400b57cec5SDimitry Andric     return false;
410b57cec5SDimitry Andric   return isa<EnumConstantDecl>(DR->getDecl());
420b57cec5SDimitry Andric }
430b57cec5SDimitry Andric 
440b57cec5SDimitry Andric static bool isTrivialExpression(const Expr *Ex) {
450b57cec5SDimitry Andric   Ex = Ex->IgnoreParenCasts();
460b57cec5SDimitry Andric   return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
470b57cec5SDimitry Andric          isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) ||
480b57cec5SDimitry Andric          isa<CharacterLiteral>(Ex) ||
490b57cec5SDimitry Andric          isEnumConstant(Ex);
500b57cec5SDimitry Andric }
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
530b57cec5SDimitry Andric   // Check if the block ends with a do...while() and see if 'S' is the
540b57cec5SDimitry Andric   // condition.
550b57cec5SDimitry Andric   if (const Stmt *Term = B->getTerminatorStmt()) {
560b57cec5SDimitry Andric     if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
570b57cec5SDimitry Andric       const Expr *Cond = DS->getCond()->IgnoreParenCasts();
580b57cec5SDimitry Andric       return Cond == S && isTrivialExpression(Cond);
590b57cec5SDimitry Andric     }
600b57cec5SDimitry Andric   }
610b57cec5SDimitry Andric   return false;
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric 
640b57cec5SDimitry Andric static bool isBuiltinUnreachable(const Stmt *S) {
650b57cec5SDimitry Andric   if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
660b57cec5SDimitry Andric     if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
670b57cec5SDimitry Andric       return FDecl->getIdentifier() &&
680b57cec5SDimitry Andric              FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
690b57cec5SDimitry Andric   return false;
700b57cec5SDimitry Andric }
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
730b57cec5SDimitry Andric                                  ASTContext &C) {
740b57cec5SDimitry Andric   if (B->empty())  {
750b57cec5SDimitry Andric     // Happens if S is B's terminator and B contains nothing else
760b57cec5SDimitry Andric     // (e.g. a CFGBlock containing only a goto).
770b57cec5SDimitry Andric     return false;
780b57cec5SDimitry Andric   }
79bdd1243dSDimitry Andric   if (std::optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
800b57cec5SDimitry Andric     if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
810b57cec5SDimitry Andric       return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
820b57cec5SDimitry Andric     }
830b57cec5SDimitry Andric   }
840b57cec5SDimitry Andric   return false;
850b57cec5SDimitry Andric }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
880b57cec5SDimitry Andric   // Look to see if the current control flow ends with a 'return', and see if
890b57cec5SDimitry Andric   // 'S' is a substatement. The 'return' may not be the last element in the
900b57cec5SDimitry Andric   // block, or may be in a subsequent block because of destructors.
910b57cec5SDimitry Andric   const CFGBlock *Current = B;
920b57cec5SDimitry Andric   while (true) {
93349cc55cSDimitry Andric     for (const CFGElement &CE : llvm::reverse(*Current)) {
94bdd1243dSDimitry Andric       if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
950b57cec5SDimitry Andric         if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
960b57cec5SDimitry Andric           if (RS == S)
970b57cec5SDimitry Andric             return true;
980b57cec5SDimitry Andric           if (const Expr *RE = RS->getRetValue()) {
990b57cec5SDimitry Andric             RE = RE->IgnoreParenCasts();
1000b57cec5SDimitry Andric             if (RE == S)
1010b57cec5SDimitry Andric               return true;
1020b57cec5SDimitry Andric             ParentMap PM(const_cast<Expr *>(RE));
1030b57cec5SDimitry Andric             // If 'S' is in the ParentMap, it is a subexpression of
1040b57cec5SDimitry Andric             // the return statement.
1050b57cec5SDimitry Andric             return PM.getParent(S);
1060b57cec5SDimitry Andric           }
1070b57cec5SDimitry Andric         }
1080b57cec5SDimitry Andric         break;
1090b57cec5SDimitry Andric       }
1100b57cec5SDimitry Andric     }
1110b57cec5SDimitry Andric     // Note also that we are restricting the search for the return statement
1120b57cec5SDimitry Andric     // to stop at control-flow; only part of a return statement may be dead,
1130b57cec5SDimitry Andric     // without the whole return statement being dead.
1140b57cec5SDimitry Andric     if (Current->getTerminator().isTemporaryDtorsBranch()) {
1150b57cec5SDimitry Andric       // Temporary destructors have a predictable control flow, thus we want to
1160b57cec5SDimitry Andric       // look into the next block for the return statement.
1170b57cec5SDimitry Andric       // We look into the false branch, as we know the true branch only contains
1180b57cec5SDimitry Andric       // the call to the destructor.
1190b57cec5SDimitry Andric       assert(Current->succ_size() == 2);
1200b57cec5SDimitry Andric       Current = *(Current->succ_begin() + 1);
1210b57cec5SDimitry Andric     } else if (!Current->getTerminatorStmt() && Current->succ_size() == 1) {
1220b57cec5SDimitry Andric       // If there is only one successor, we're not dealing with outgoing control
1230b57cec5SDimitry Andric       // flow. Thus, look into the next block.
1240b57cec5SDimitry Andric       Current = *Current->succ_begin();
1250b57cec5SDimitry Andric       if (Current->pred_size() > 1) {
1260b57cec5SDimitry Andric         // If there is more than one predecessor, we're dealing with incoming
1270b57cec5SDimitry Andric         // control flow - if the return statement is in that block, it might
1280b57cec5SDimitry Andric         // well be reachable via a different control flow, thus it's not dead.
1290b57cec5SDimitry Andric         return false;
1300b57cec5SDimitry Andric       }
1310b57cec5SDimitry Andric     } else {
1320b57cec5SDimitry Andric       // We hit control flow or a dead end. Stop searching.
1330b57cec5SDimitry Andric       return false;
1340b57cec5SDimitry Andric     }
1350b57cec5SDimitry Andric   }
1360b57cec5SDimitry Andric   llvm_unreachable("Broke out of infinite loop.");
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric 
1390b57cec5SDimitry Andric static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
1400b57cec5SDimitry Andric   assert(Loc.isMacroID());
1410b57cec5SDimitry Andric   SourceLocation Last;
1425ffd83dbSDimitry Andric   do {
1430b57cec5SDimitry Andric     Last = Loc;
1440b57cec5SDimitry Andric     Loc = SM.getImmediateMacroCallerLoc(Loc);
1455ffd83dbSDimitry Andric   } while (Loc.isMacroID());
1460b57cec5SDimitry Andric   return Last;
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric /// Returns true if the statement is expanded from a configuration macro.
1500b57cec5SDimitry Andric static bool isExpandedFromConfigurationMacro(const Stmt *S,
1510b57cec5SDimitry Andric                                              Preprocessor &PP,
1520b57cec5SDimitry Andric                                              bool IgnoreYES_NO = false) {
1530b57cec5SDimitry Andric   // FIXME: This is not very precise.  Here we just check to see if the
1540b57cec5SDimitry Andric   // value comes from a macro, but we can do much better.  This is likely
1550b57cec5SDimitry Andric   // to be over conservative.  This logic is factored into a separate function
1560b57cec5SDimitry Andric   // so that we can refine it later.
1570b57cec5SDimitry Andric   SourceLocation L = S->getBeginLoc();
1580b57cec5SDimitry Andric   if (L.isMacroID()) {
1590b57cec5SDimitry Andric     SourceManager &SM = PP.getSourceManager();
1600b57cec5SDimitry Andric     if (IgnoreYES_NO) {
1610b57cec5SDimitry Andric       // The Objective-C constant 'YES' and 'NO'
1620b57cec5SDimitry Andric       // are defined as macros.  Do not treat them
1630b57cec5SDimitry Andric       // as configuration values.
1640b57cec5SDimitry Andric       SourceLocation TopL = getTopMostMacro(L, SM);
1650b57cec5SDimitry Andric       StringRef MacroName = PP.getImmediateMacroName(TopL);
1660b57cec5SDimitry Andric       if (MacroName == "YES" || MacroName == "NO")
1670b57cec5SDimitry Andric         return false;
1680b57cec5SDimitry Andric     } else if (!PP.getLangOpts().CPlusPlus) {
1690b57cec5SDimitry Andric       // Do not treat C 'false' and 'true' macros as configuration values.
1700b57cec5SDimitry Andric       SourceLocation TopL = getTopMostMacro(L, SM);
1710b57cec5SDimitry Andric       StringRef MacroName = PP.getImmediateMacroName(TopL);
1720b57cec5SDimitry Andric       if (MacroName == "false" || MacroName == "true")
1730b57cec5SDimitry Andric         return false;
1740b57cec5SDimitry Andric     }
1750b57cec5SDimitry Andric     return true;
1760b57cec5SDimitry Andric   }
1770b57cec5SDimitry Andric   return false;
1780b57cec5SDimitry Andric }
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric /// Returns true if the statement represents a configuration value.
1830b57cec5SDimitry Andric ///
1840b57cec5SDimitry Andric /// A configuration value is something usually determined at compile-time
1850b57cec5SDimitry Andric /// to conditionally always execute some branch.  Such guards are for
1860b57cec5SDimitry Andric /// "sometimes unreachable" code.  Such code is usually not interesting
1870b57cec5SDimitry Andric /// to report as unreachable, and may mask truly unreachable code within
1880b57cec5SDimitry Andric /// those blocks.
1890b57cec5SDimitry Andric static bool isConfigurationValue(const Stmt *S,
1900b57cec5SDimitry Andric                                  Preprocessor &PP,
1910b57cec5SDimitry Andric                                  SourceRange *SilenceableCondVal = nullptr,
1920b57cec5SDimitry Andric                                  bool IncludeIntegers = true,
1930b57cec5SDimitry Andric                                  bool WrappedInParens = false) {
1940b57cec5SDimitry Andric   if (!S)
1950b57cec5SDimitry Andric     return false;
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   if (const auto *Ex = dyn_cast<Expr>(S))
1980b57cec5SDimitry Andric     S = Ex->IgnoreImplicit();
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric   if (const auto *Ex = dyn_cast<Expr>(S))
2010b57cec5SDimitry Andric     S = Ex->IgnoreCasts();
2020b57cec5SDimitry Andric 
2030b57cec5SDimitry Andric   // Special case looking for the sigil '()' around an integer literal.
2040b57cec5SDimitry Andric   if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
2050b57cec5SDimitry Andric     if (!PE->getBeginLoc().isMacroID())
2060b57cec5SDimitry Andric       return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
2070b57cec5SDimitry Andric                                   IncludeIntegers, true);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   if (const Expr *Ex = dyn_cast<Expr>(S))
2100b57cec5SDimitry Andric     S = Ex->IgnoreCasts();
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   bool IgnoreYES_NO = false;
2130b57cec5SDimitry Andric 
2140b57cec5SDimitry Andric   switch (S->getStmtClass()) {
2150b57cec5SDimitry Andric     case Stmt::CallExprClass: {
2160b57cec5SDimitry Andric       const FunctionDecl *Callee =
2170b57cec5SDimitry Andric         dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
2180b57cec5SDimitry Andric       return Callee ? Callee->isConstexpr() : false;
2190b57cec5SDimitry Andric     }
2200b57cec5SDimitry Andric     case Stmt::DeclRefExprClass:
2210b57cec5SDimitry Andric       return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
2220b57cec5SDimitry Andric     case Stmt::ObjCBoolLiteralExprClass:
2230b57cec5SDimitry Andric       IgnoreYES_NO = true;
224bdd1243dSDimitry Andric       [[fallthrough]];
2250b57cec5SDimitry Andric     case Stmt::CXXBoolLiteralExprClass:
2260b57cec5SDimitry Andric     case Stmt::IntegerLiteralClass: {
2270b57cec5SDimitry Andric       const Expr *E = cast<Expr>(S);
2280b57cec5SDimitry Andric       if (IncludeIntegers) {
2290b57cec5SDimitry Andric         if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
2300b57cec5SDimitry Andric           *SilenceableCondVal = E->getSourceRange();
231349cc55cSDimitry Andric         return WrappedInParens ||
232349cc55cSDimitry Andric                isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
2330b57cec5SDimitry Andric       }
2340b57cec5SDimitry Andric       return false;
2350b57cec5SDimitry Andric     }
2360b57cec5SDimitry Andric     case Stmt::MemberExprClass:
2370b57cec5SDimitry Andric       return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
2380b57cec5SDimitry Andric     case Stmt::UnaryExprOrTypeTraitExprClass:
2390b57cec5SDimitry Andric       return true;
2400b57cec5SDimitry Andric     case Stmt::BinaryOperatorClass: {
2410b57cec5SDimitry Andric       const BinaryOperator *B = cast<BinaryOperator>(S);
2420b57cec5SDimitry Andric       // Only include raw integers (not enums) as configuration
2430b57cec5SDimitry Andric       // values if they are used in a logical or comparison operator
2440b57cec5SDimitry Andric       // (not arithmetic).
2450b57cec5SDimitry Andric       IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
2460b57cec5SDimitry Andric       return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
2470b57cec5SDimitry Andric                                   IncludeIntegers) ||
2480b57cec5SDimitry Andric              isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
2490b57cec5SDimitry Andric                                   IncludeIntegers);
2500b57cec5SDimitry Andric     }
2510b57cec5SDimitry Andric     case Stmt::UnaryOperatorClass: {
2520b57cec5SDimitry Andric       const UnaryOperator *UO = cast<UnaryOperator>(S);
253a7dea167SDimitry Andric       if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
2540b57cec5SDimitry Andric         return false;
2550b57cec5SDimitry Andric       bool SilenceableCondValNotSet =
2560b57cec5SDimitry Andric           SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
2570b57cec5SDimitry Andric       bool IsSubExprConfigValue =
2580b57cec5SDimitry Andric           isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
2590b57cec5SDimitry Andric                                IncludeIntegers, WrappedInParens);
2600b57cec5SDimitry Andric       // Update the silenceable condition value source range only if the range
2610b57cec5SDimitry Andric       // was set directly by the child expression.
2620b57cec5SDimitry Andric       if (SilenceableCondValNotSet &&
2630b57cec5SDimitry Andric           SilenceableCondVal->getBegin().isValid() &&
2640b57cec5SDimitry Andric           *SilenceableCondVal ==
2650b57cec5SDimitry Andric               UO->getSubExpr()->IgnoreCasts()->getSourceRange())
2660b57cec5SDimitry Andric         *SilenceableCondVal = UO->getSourceRange();
2670b57cec5SDimitry Andric       return IsSubExprConfigValue;
2680b57cec5SDimitry Andric     }
2690b57cec5SDimitry Andric     default:
2700b57cec5SDimitry Andric       return false;
2710b57cec5SDimitry Andric   }
2720b57cec5SDimitry Andric }
2730b57cec5SDimitry Andric 
2740b57cec5SDimitry Andric static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
2750b57cec5SDimitry Andric   if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
2760b57cec5SDimitry Andric     return isConfigurationValue(ED->getInitExpr(), PP);
2770b57cec5SDimitry Andric   if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2780b57cec5SDimitry Andric     // As a heuristic, treat globals as configuration values.  Note
2790b57cec5SDimitry Andric     // that we only will get here if Sema evaluated this
2800b57cec5SDimitry Andric     // condition to a constant expression, which means the global
2810b57cec5SDimitry Andric     // had to be declared in a way to be a truly constant value.
2820b57cec5SDimitry Andric     // We could generalize this to local variables, but it isn't
2830b57cec5SDimitry Andric     // clear if those truly represent configuration values that
2840b57cec5SDimitry Andric     // gate unreachable code.
2850b57cec5SDimitry Andric     if (!VD->hasLocalStorage())
2860b57cec5SDimitry Andric       return true;
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric     // As a heuristic, locals that have been marked 'const' explicitly
2890b57cec5SDimitry Andric     // can be treated as configuration values as well.
2900b57cec5SDimitry Andric     return VD->getType().isLocalConstQualified();
2910b57cec5SDimitry Andric   }
2920b57cec5SDimitry Andric   return false;
2930b57cec5SDimitry Andric }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric /// Returns true if we should always explore all successors of a block.
2960b57cec5SDimitry Andric static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
2970b57cec5SDimitry Andric                                              Preprocessor &PP) {
2980b57cec5SDimitry Andric   if (const Stmt *Term = B->getTerminatorStmt()) {
2990b57cec5SDimitry Andric     if (isa<SwitchStmt>(Term))
3000b57cec5SDimitry Andric       return true;
3010b57cec5SDimitry Andric     // Specially handle '||' and '&&'.
3020b57cec5SDimitry Andric     if (isa<BinaryOperator>(Term)) {
3030b57cec5SDimitry Andric       return isConfigurationValue(Term, PP);
3040b57cec5SDimitry Andric     }
305bdd1243dSDimitry Andric     // Do not treat constexpr if statement successors as unreachable in warnings
306bdd1243dSDimitry Andric     // since the point of these statements is to determine branches at compile
307bdd1243dSDimitry Andric     // time.
308bdd1243dSDimitry Andric     if (const auto *IS = dyn_cast<IfStmt>(Term);
309bdd1243dSDimitry Andric         IS != nullptr && IS->isConstexpr())
310bdd1243dSDimitry Andric       return true;
3110b57cec5SDimitry Andric   }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
3140b57cec5SDimitry Andric   return isConfigurationValue(Cond, PP);
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric static unsigned scanFromBlock(const CFGBlock *Start,
3180b57cec5SDimitry Andric                               llvm::BitVector &Reachable,
3190b57cec5SDimitry Andric                               Preprocessor *PP,
3200b57cec5SDimitry Andric                               bool IncludeSometimesUnreachableEdges) {
3210b57cec5SDimitry Andric   unsigned count = 0;
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   // Prep work queue
3240b57cec5SDimitry Andric   SmallVector<const CFGBlock*, 32> WL;
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   // The entry block may have already been marked reachable
3270b57cec5SDimitry Andric   // by the caller.
3280b57cec5SDimitry Andric   if (!Reachable[Start->getBlockID()]) {
3290b57cec5SDimitry Andric     ++count;
3300b57cec5SDimitry Andric     Reachable[Start->getBlockID()] = true;
3310b57cec5SDimitry Andric   }
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric   WL.push_back(Start);
3340b57cec5SDimitry Andric 
3350b57cec5SDimitry Andric   // Find the reachable blocks from 'Start'.
3360b57cec5SDimitry Andric   while (!WL.empty()) {
3370b57cec5SDimitry Andric     const CFGBlock *item = WL.pop_back_val();
3380b57cec5SDimitry Andric 
3390b57cec5SDimitry Andric     // There are cases where we want to treat all successors as reachable.
3400b57cec5SDimitry Andric     // The idea is that some "sometimes unreachable" code is not interesting,
3410b57cec5SDimitry Andric     // and that we should forge ahead and explore those branches anyway.
3420b57cec5SDimitry Andric     // This allows us to potentially uncover some "always unreachable" code
3430b57cec5SDimitry Andric     // within the "sometimes unreachable" code.
3440b57cec5SDimitry Andric     // Look at the successors and mark then reachable.
345bdd1243dSDimitry Andric     std::optional<bool> TreatAllSuccessorsAsReachable;
3460b57cec5SDimitry Andric     if (!IncludeSometimesUnreachableEdges)
3470b57cec5SDimitry Andric       TreatAllSuccessorsAsReachable = false;
3480b57cec5SDimitry Andric 
3490b57cec5SDimitry Andric     for (CFGBlock::const_succ_iterator I = item->succ_begin(),
3500b57cec5SDimitry Andric          E = item->succ_end(); I != E; ++I) {
3510b57cec5SDimitry Andric       const CFGBlock *B = *I;
3520b57cec5SDimitry Andric       if (!B) do {
3530b57cec5SDimitry Andric         const CFGBlock *UB = I->getPossiblyUnreachableBlock();
3540b57cec5SDimitry Andric         if (!UB)
3550b57cec5SDimitry Andric           break;
3560b57cec5SDimitry Andric 
35781ad6265SDimitry Andric         if (!TreatAllSuccessorsAsReachable) {
3580b57cec5SDimitry Andric           assert(PP);
3590b57cec5SDimitry Andric           TreatAllSuccessorsAsReachable =
3600b57cec5SDimitry Andric             shouldTreatSuccessorsAsReachable(item, *PP);
3610b57cec5SDimitry Andric         }
3620b57cec5SDimitry Andric 
36381ad6265SDimitry Andric         if (*TreatAllSuccessorsAsReachable) {
3640b57cec5SDimitry Andric           B = UB;
3650b57cec5SDimitry Andric           break;
3660b57cec5SDimitry Andric         }
3670b57cec5SDimitry Andric       }
3680b57cec5SDimitry Andric       while (false);
3690b57cec5SDimitry Andric 
3700b57cec5SDimitry Andric       if (B) {
3710b57cec5SDimitry Andric         unsigned blockID = B->getBlockID();
3720b57cec5SDimitry Andric         if (!Reachable[blockID]) {
3730b57cec5SDimitry Andric           Reachable.set(blockID);
3740b57cec5SDimitry Andric           WL.push_back(B);
3750b57cec5SDimitry Andric           ++count;
3760b57cec5SDimitry Andric         }
3770b57cec5SDimitry Andric       }
3780b57cec5SDimitry Andric     }
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric   return count;
3810b57cec5SDimitry Andric }
3820b57cec5SDimitry Andric 
3830b57cec5SDimitry Andric static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
3840b57cec5SDimitry Andric                                             Preprocessor &PP,
3850b57cec5SDimitry Andric                                             llvm::BitVector &Reachable) {
3860b57cec5SDimitry Andric   return scanFromBlock(Start, Reachable, &PP, true);
3870b57cec5SDimitry Andric }
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3900b57cec5SDimitry Andric // Dead Code Scanner.
3910b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
3920b57cec5SDimitry Andric 
3930b57cec5SDimitry Andric namespace {
3940b57cec5SDimitry Andric   class DeadCodeScan {
3950b57cec5SDimitry Andric     llvm::BitVector Visited;
3960b57cec5SDimitry Andric     llvm::BitVector &Reachable;
3970b57cec5SDimitry Andric     SmallVector<const CFGBlock *, 10> WorkList;
3980b57cec5SDimitry Andric     Preprocessor &PP;
3990b57cec5SDimitry Andric     ASTContext &C;
4000b57cec5SDimitry Andric 
4010b57cec5SDimitry Andric     typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
4020b57cec5SDimitry Andric     DeferredLocsTy;
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric     DeferredLocsTy DeferredLocs;
4050b57cec5SDimitry Andric 
4060b57cec5SDimitry Andric   public:
4070b57cec5SDimitry Andric     DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
4080b57cec5SDimitry Andric     : Visited(reachable.size()),
4090b57cec5SDimitry Andric       Reachable(reachable),
4100b57cec5SDimitry Andric       PP(PP), C(C) {}
4110b57cec5SDimitry Andric 
4120b57cec5SDimitry Andric     void enqueue(const CFGBlock *block);
4130b57cec5SDimitry Andric     unsigned scanBackwards(const CFGBlock *Start,
4140b57cec5SDimitry Andric     clang::reachable_code::Callback &CB);
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric     bool isDeadCodeRoot(const CFGBlock *Block);
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric     const Stmt *findDeadCode(const CFGBlock *Block);
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric     void reportDeadCode(const CFGBlock *B,
4210b57cec5SDimitry Andric                         const Stmt *S,
4220b57cec5SDimitry Andric                         clang::reachable_code::Callback &CB);
4230b57cec5SDimitry Andric   };
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric 
4260b57cec5SDimitry Andric void DeadCodeScan::enqueue(const CFGBlock *block) {
4270b57cec5SDimitry Andric   unsigned blockID = block->getBlockID();
4280b57cec5SDimitry Andric   if (Reachable[blockID] || Visited[blockID])
4290b57cec5SDimitry Andric     return;
4300b57cec5SDimitry Andric   Visited[blockID] = true;
4310b57cec5SDimitry Andric   WorkList.push_back(block);
4320b57cec5SDimitry Andric }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
4350b57cec5SDimitry Andric   bool isDeadRoot = true;
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
4380b57cec5SDimitry Andric        E = Block->pred_end(); I != E; ++I) {
4390b57cec5SDimitry Andric     if (const CFGBlock *PredBlock = *I) {
4400b57cec5SDimitry Andric       unsigned blockID = PredBlock->getBlockID();
4410b57cec5SDimitry Andric       if (Visited[blockID]) {
4420b57cec5SDimitry Andric         isDeadRoot = false;
4430b57cec5SDimitry Andric         continue;
4440b57cec5SDimitry Andric       }
4450b57cec5SDimitry Andric       if (!Reachable[blockID]) {
4460b57cec5SDimitry Andric         isDeadRoot = false;
4470b57cec5SDimitry Andric         Visited[blockID] = true;
4480b57cec5SDimitry Andric         WorkList.push_back(PredBlock);
4490b57cec5SDimitry Andric         continue;
4500b57cec5SDimitry Andric       }
4510b57cec5SDimitry Andric     }
4520b57cec5SDimitry Andric   }
4530b57cec5SDimitry Andric 
4540b57cec5SDimitry Andric   return isDeadRoot;
4550b57cec5SDimitry Andric }
4560b57cec5SDimitry Andric 
457*0fca6ea1SDimitry Andric // Check if the given `DeadStmt` is a coroutine statement and is a substmt of
458*0fca6ea1SDimitry Andric // the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`.
459*0fca6ea1SDimitry Andric static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block) {
460*0fca6ea1SDimitry Andric   // The coroutine statement, co_return, co_await, or co_yield.
461*0fca6ea1SDimitry Andric   const Stmt *CoroStmt = nullptr;
462*0fca6ea1SDimitry Andric   // Find the first coroutine statement after the DeadStmt in the block.
463*0fca6ea1SDimitry Andric   bool AfterDeadStmt = false;
464*0fca6ea1SDimitry Andric   for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I != E;
465*0fca6ea1SDimitry Andric        ++I)
466*0fca6ea1SDimitry Andric     if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
467*0fca6ea1SDimitry Andric       const Stmt *S = CS->getStmt();
468*0fca6ea1SDimitry Andric       if (S == DeadStmt)
469*0fca6ea1SDimitry Andric         AfterDeadStmt = true;
470*0fca6ea1SDimitry Andric       if (AfterDeadStmt &&
471*0fca6ea1SDimitry Andric           // For simplicity, we only check simple coroutine statements.
472*0fca6ea1SDimitry Andric           (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
473*0fca6ea1SDimitry Andric         CoroStmt = S;
474*0fca6ea1SDimitry Andric         break;
475*0fca6ea1SDimitry Andric       }
476*0fca6ea1SDimitry Andric     }
477*0fca6ea1SDimitry Andric   if (!CoroStmt)
478*0fca6ea1SDimitry Andric     return false;
479*0fca6ea1SDimitry Andric   struct Checker : RecursiveASTVisitor<Checker> {
480*0fca6ea1SDimitry Andric     const Stmt *DeadStmt;
481*0fca6ea1SDimitry Andric     bool CoroutineSubStmt = false;
482*0fca6ea1SDimitry Andric     Checker(const Stmt *S) : DeadStmt(S) {}
483*0fca6ea1SDimitry Andric     bool VisitStmt(const Stmt *S) {
484*0fca6ea1SDimitry Andric       if (S == DeadStmt)
485*0fca6ea1SDimitry Andric         CoroutineSubStmt = true;
486*0fca6ea1SDimitry Andric       return true;
487*0fca6ea1SDimitry Andric     }
488*0fca6ea1SDimitry Andric     // Statements captured in the CFG can be implicit.
489*0fca6ea1SDimitry Andric     bool shouldVisitImplicitCode() const { return true; }
490*0fca6ea1SDimitry Andric   };
491*0fca6ea1SDimitry Andric   Checker checker(DeadStmt);
492*0fca6ea1SDimitry Andric   checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
493*0fca6ea1SDimitry Andric   return checker.CoroutineSubStmt;
494*0fca6ea1SDimitry Andric }
495*0fca6ea1SDimitry Andric 
496*0fca6ea1SDimitry Andric static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
4970b57cec5SDimitry Andric   if (S->getBeginLoc().isInvalid())
4980b57cec5SDimitry Andric     return false;
4990b57cec5SDimitry Andric   if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
5000b57cec5SDimitry Andric     return BO->getOpcode() != BO_Comma;
501*0fca6ea1SDimitry Andric   // Coroutine statements are never considered dead statements, because removing
502*0fca6ea1SDimitry Andric   // them may change the function semantic if it is the only coroutine statement
503*0fca6ea1SDimitry Andric   // of the coroutine.
504*0fca6ea1SDimitry Andric   return !isInCoroutineStmt(S, Block);
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric 
5070b57cec5SDimitry Andric const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
5080b57cec5SDimitry Andric   for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
509bdd1243dSDimitry Andric     if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
5100b57cec5SDimitry Andric       const Stmt *S = CS->getStmt();
511*0fca6ea1SDimitry Andric       if (isValidDeadStmt(S, Block))
5120b57cec5SDimitry Andric         return S;
5130b57cec5SDimitry Andric     }
5140b57cec5SDimitry Andric 
5150b57cec5SDimitry Andric   CFGTerminator T = Block->getTerminator();
5160b57cec5SDimitry Andric   if (T.isStmtBranch()) {
5170b57cec5SDimitry Andric     const Stmt *S = T.getStmt();
518*0fca6ea1SDimitry Andric     if (S && isValidDeadStmt(S, Block))
5190b57cec5SDimitry Andric       return S;
5200b57cec5SDimitry Andric   }
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric   return nullptr;
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric 
5250b57cec5SDimitry Andric static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
5260b57cec5SDimitry Andric                   const std::pair<const CFGBlock *, const Stmt *> *p2) {
5270b57cec5SDimitry Andric   if (p1->second->getBeginLoc() < p2->second->getBeginLoc())
5280b57cec5SDimitry Andric     return -1;
5290b57cec5SDimitry Andric   if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
5300b57cec5SDimitry Andric     return 1;
5310b57cec5SDimitry Andric   return 0;
5320b57cec5SDimitry Andric }
5330b57cec5SDimitry Andric 
5340b57cec5SDimitry Andric unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
5350b57cec5SDimitry Andric                                      clang::reachable_code::Callback &CB) {
5360b57cec5SDimitry Andric 
5370b57cec5SDimitry Andric   unsigned count = 0;
5380b57cec5SDimitry Andric   enqueue(Start);
5390b57cec5SDimitry Andric 
5400b57cec5SDimitry Andric   while (!WorkList.empty()) {
5410b57cec5SDimitry Andric     const CFGBlock *Block = WorkList.pop_back_val();
5420b57cec5SDimitry Andric 
5430b57cec5SDimitry Andric     // It is possible that this block has been marked reachable after
5440b57cec5SDimitry Andric     // it was enqueued.
5450b57cec5SDimitry Andric     if (Reachable[Block->getBlockID()])
5460b57cec5SDimitry Andric       continue;
5470b57cec5SDimitry Andric 
5480b57cec5SDimitry Andric     // Look for any dead code within the block.
5490b57cec5SDimitry Andric     const Stmt *S = findDeadCode(Block);
5500b57cec5SDimitry Andric 
5510b57cec5SDimitry Andric     if (!S) {
5520b57cec5SDimitry Andric       // No dead code.  Possibly an empty block.  Look at dead predecessors.
5530b57cec5SDimitry Andric       for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
5540b57cec5SDimitry Andric            E = Block->pred_end(); I != E; ++I) {
5550b57cec5SDimitry Andric         if (const CFGBlock *predBlock = *I)
5560b57cec5SDimitry Andric           enqueue(predBlock);
5570b57cec5SDimitry Andric       }
5580b57cec5SDimitry Andric       continue;
5590b57cec5SDimitry Andric     }
5600b57cec5SDimitry Andric 
5610b57cec5SDimitry Andric     // Specially handle macro-expanded code.
5620b57cec5SDimitry Andric     if (S->getBeginLoc().isMacroID()) {
5630b57cec5SDimitry Andric       count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5640b57cec5SDimitry Andric       continue;
5650b57cec5SDimitry Andric     }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric     if (isDeadCodeRoot(Block)) {
5680b57cec5SDimitry Andric       reportDeadCode(Block, S, CB);
5690b57cec5SDimitry Andric       count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5700b57cec5SDimitry Andric     }
5710b57cec5SDimitry Andric     else {
5720b57cec5SDimitry Andric       // Record this statement as the possibly best location in a
5730b57cec5SDimitry Andric       // strongly-connected component of dead code for emitting a
5740b57cec5SDimitry Andric       // warning.
5750b57cec5SDimitry Andric       DeferredLocs.push_back(std::make_pair(Block, S));
5760b57cec5SDimitry Andric     }
5770b57cec5SDimitry Andric   }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric   // If we didn't find a dead root, then report the dead code with the
5800b57cec5SDimitry Andric   // earliest location.
5810b57cec5SDimitry Andric   if (!DeferredLocs.empty()) {
5820b57cec5SDimitry Andric     llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
583349cc55cSDimitry Andric     for (const auto &I : DeferredLocs) {
584349cc55cSDimitry Andric       const CFGBlock *Block = I.first;
5850b57cec5SDimitry Andric       if (Reachable[Block->getBlockID()])
5860b57cec5SDimitry Andric         continue;
587349cc55cSDimitry Andric       reportDeadCode(Block, I.second, CB);
5880b57cec5SDimitry Andric       count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5890b57cec5SDimitry Andric     }
5900b57cec5SDimitry Andric   }
5910b57cec5SDimitry Andric 
5920b57cec5SDimitry Andric   return count;
5930b57cec5SDimitry Andric }
5940b57cec5SDimitry Andric 
5950b57cec5SDimitry Andric static SourceLocation GetUnreachableLoc(const Stmt *S,
5960b57cec5SDimitry Andric                                         SourceRange &R1,
5970b57cec5SDimitry Andric                                         SourceRange &R2) {
5980b57cec5SDimitry Andric   R1 = R2 = SourceRange();
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric   if (const Expr *Ex = dyn_cast<Expr>(S))
6010b57cec5SDimitry Andric     S = Ex->IgnoreParenImpCasts();
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric   switch (S->getStmtClass()) {
6040b57cec5SDimitry Andric     case Expr::BinaryOperatorClass: {
6050b57cec5SDimitry Andric       const BinaryOperator *BO = cast<BinaryOperator>(S);
6060b57cec5SDimitry Andric       return BO->getOperatorLoc();
6070b57cec5SDimitry Andric     }
6080b57cec5SDimitry Andric     case Expr::UnaryOperatorClass: {
6090b57cec5SDimitry Andric       const UnaryOperator *UO = cast<UnaryOperator>(S);
6100b57cec5SDimitry Andric       R1 = UO->getSubExpr()->getSourceRange();
6110b57cec5SDimitry Andric       return UO->getOperatorLoc();
6120b57cec5SDimitry Andric     }
6130b57cec5SDimitry Andric     case Expr::CompoundAssignOperatorClass: {
6140b57cec5SDimitry Andric       const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
6150b57cec5SDimitry Andric       R1 = CAO->getLHS()->getSourceRange();
6160b57cec5SDimitry Andric       R2 = CAO->getRHS()->getSourceRange();
6170b57cec5SDimitry Andric       return CAO->getOperatorLoc();
6180b57cec5SDimitry Andric     }
6190b57cec5SDimitry Andric     case Expr::BinaryConditionalOperatorClass:
6200b57cec5SDimitry Andric     case Expr::ConditionalOperatorClass: {
6210b57cec5SDimitry Andric       const AbstractConditionalOperator *CO =
6220b57cec5SDimitry Andric       cast<AbstractConditionalOperator>(S);
6230b57cec5SDimitry Andric       return CO->getQuestionLoc();
6240b57cec5SDimitry Andric     }
6250b57cec5SDimitry Andric     case Expr::MemberExprClass: {
6260b57cec5SDimitry Andric       const MemberExpr *ME = cast<MemberExpr>(S);
6270b57cec5SDimitry Andric       R1 = ME->getSourceRange();
6280b57cec5SDimitry Andric       return ME->getMemberLoc();
6290b57cec5SDimitry Andric     }
6300b57cec5SDimitry Andric     case Expr::ArraySubscriptExprClass: {
6310b57cec5SDimitry Andric       const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
6320b57cec5SDimitry Andric       R1 = ASE->getLHS()->getSourceRange();
6330b57cec5SDimitry Andric       R2 = ASE->getRHS()->getSourceRange();
6340b57cec5SDimitry Andric       return ASE->getRBracketLoc();
6350b57cec5SDimitry Andric     }
6360b57cec5SDimitry Andric     case Expr::CStyleCastExprClass: {
6370b57cec5SDimitry Andric       const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
6380b57cec5SDimitry Andric       R1 = CSC->getSubExpr()->getSourceRange();
6390b57cec5SDimitry Andric       return CSC->getLParenLoc();
6400b57cec5SDimitry Andric     }
6410b57cec5SDimitry Andric     case Expr::CXXFunctionalCastExprClass: {
6420b57cec5SDimitry Andric       const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
6430b57cec5SDimitry Andric       R1 = CE->getSubExpr()->getSourceRange();
6440b57cec5SDimitry Andric       return CE->getBeginLoc();
6450b57cec5SDimitry Andric     }
6460b57cec5SDimitry Andric     case Stmt::CXXTryStmtClass: {
6470b57cec5SDimitry Andric       return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
6480b57cec5SDimitry Andric     }
6490b57cec5SDimitry Andric     case Expr::ObjCBridgedCastExprClass: {
6500b57cec5SDimitry Andric       const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
6510b57cec5SDimitry Andric       R1 = CSC->getSubExpr()->getSourceRange();
6520b57cec5SDimitry Andric       return CSC->getLParenLoc();
6530b57cec5SDimitry Andric     }
6540b57cec5SDimitry Andric     default: ;
6550b57cec5SDimitry Andric   }
6560b57cec5SDimitry Andric   R1 = S->getSourceRange();
6570b57cec5SDimitry Andric   return S->getBeginLoc();
6580b57cec5SDimitry Andric }
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric void DeadCodeScan::reportDeadCode(const CFGBlock *B,
6610b57cec5SDimitry Andric                                   const Stmt *S,
6620b57cec5SDimitry Andric                                   clang::reachable_code::Callback &CB) {
6630b57cec5SDimitry Andric   // Classify the unreachable code found, or suppress it in some cases.
6640b57cec5SDimitry Andric   reachable_code::UnreachableKind UK = reachable_code::UK_Other;
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric   if (isa<BreakStmt>(S)) {
6670b57cec5SDimitry Andric     UK = reachable_code::UK_Break;
6680b57cec5SDimitry Andric   } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
6690b57cec5SDimitry Andric              isBuiltinAssumeFalse(B, S, C)) {
6700b57cec5SDimitry Andric     return;
6710b57cec5SDimitry Andric   }
6720b57cec5SDimitry Andric   else if (isDeadReturn(B, S)) {
6730b57cec5SDimitry Andric     UK = reachable_code::UK_Return;
6740b57cec5SDimitry Andric   }
6750b57cec5SDimitry Andric 
67606c3fb27SDimitry Andric   const auto *AS = dyn_cast<AttributedStmt>(S);
67706c3fb27SDimitry Andric   bool HasFallThroughAttr =
67806c3fb27SDimitry Andric       AS && hasSpecificAttr<FallThroughAttr>(AS->getAttrs());
67906c3fb27SDimitry Andric 
6800b57cec5SDimitry Andric   SourceRange SilenceableCondVal;
6810b57cec5SDimitry Andric 
6820b57cec5SDimitry Andric   if (UK == reachable_code::UK_Other) {
6830b57cec5SDimitry Andric     // Check if the dead code is part of the "loop target" of
6840b57cec5SDimitry Andric     // a for/for-range loop.  This is the block that contains
6850b57cec5SDimitry Andric     // the increment code.
6860b57cec5SDimitry Andric     if (const Stmt *LoopTarget = B->getLoopTarget()) {
6870b57cec5SDimitry Andric       SourceLocation Loc = LoopTarget->getBeginLoc();
6880b57cec5SDimitry Andric       SourceRange R1(Loc, Loc), R2;
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric       if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
6910b57cec5SDimitry Andric         const Expr *Inc = FS->getInc();
6920b57cec5SDimitry Andric         Loc = Inc->getBeginLoc();
6930b57cec5SDimitry Andric         R2 = Inc->getSourceRange();
6940b57cec5SDimitry Andric       }
6950b57cec5SDimitry Andric 
69606c3fb27SDimitry Andric       CB.HandleUnreachable(reachable_code::UK_Loop_Increment, Loc,
69706c3fb27SDimitry Andric                            SourceRange(), SourceRange(Loc, Loc), R2,
69806c3fb27SDimitry Andric                            HasFallThroughAttr);
6990b57cec5SDimitry Andric       return;
7000b57cec5SDimitry Andric     }
7010b57cec5SDimitry Andric 
7020b57cec5SDimitry Andric     // Check if the dead block has a predecessor whose branch has
7030b57cec5SDimitry Andric     // a configuration value that *could* be modified to
7040b57cec5SDimitry Andric     // silence the warning.
7050b57cec5SDimitry Andric     CFGBlock::const_pred_iterator PI = B->pred_begin();
7060b57cec5SDimitry Andric     if (PI != B->pred_end()) {
7070b57cec5SDimitry Andric       if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
7080b57cec5SDimitry Andric         const Stmt *TermCond =
7090b57cec5SDimitry Andric             PredBlock->getTerminatorCondition(/* strip parens */ false);
7100b57cec5SDimitry Andric         isConfigurationValue(TermCond, PP, &SilenceableCondVal);
7110b57cec5SDimitry Andric       }
7120b57cec5SDimitry Andric     }
7130b57cec5SDimitry Andric   }
7140b57cec5SDimitry Andric 
7150b57cec5SDimitry Andric   SourceRange R1, R2;
7160b57cec5SDimitry Andric   SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
71706c3fb27SDimitry Andric   CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2, HasFallThroughAttr);
7180b57cec5SDimitry Andric }
7190b57cec5SDimitry Andric 
7200b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7210b57cec5SDimitry Andric // Reachability APIs.
7220b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric namespace clang { namespace reachable_code {
7250b57cec5SDimitry Andric 
7260b57cec5SDimitry Andric void Callback::anchor() { }
7270b57cec5SDimitry Andric 
7280b57cec5SDimitry Andric unsigned ScanReachableFromBlock(const CFGBlock *Start,
7290b57cec5SDimitry Andric                                 llvm::BitVector &Reachable) {
7300b57cec5SDimitry Andric   return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
7310b57cec5SDimitry Andric }
7320b57cec5SDimitry Andric 
7330b57cec5SDimitry Andric void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
7340b57cec5SDimitry Andric                          Callback &CB) {
7350b57cec5SDimitry Andric 
7360b57cec5SDimitry Andric   CFG *cfg = AC.getCFG();
7370b57cec5SDimitry Andric   if (!cfg)
7380b57cec5SDimitry Andric     return;
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   // Scan for reachable blocks from the entrance of the CFG.
7410b57cec5SDimitry Andric   // If there are no unreachable blocks, we're done.
7420b57cec5SDimitry Andric   llvm::BitVector reachable(cfg->getNumBlockIDs());
7430b57cec5SDimitry Andric   unsigned numReachable =
7440b57cec5SDimitry Andric     scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
7450b57cec5SDimitry Andric   if (numReachable == cfg->getNumBlockIDs())
7460b57cec5SDimitry Andric     return;
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric   // If there aren't explicit EH edges, we should include the 'try' dispatch
7490b57cec5SDimitry Andric   // blocks as roots.
7500b57cec5SDimitry Andric   if (!AC.getCFGBuildOptions().AddEHEdges) {
751349cc55cSDimitry Andric     for (const CFGBlock *B : cfg->try_blocks())
752349cc55cSDimitry Andric       numReachable += scanMaybeReachableFromBlock(B, PP, reachable);
7530b57cec5SDimitry Andric     if (numReachable == cfg->getNumBlockIDs())
7540b57cec5SDimitry Andric       return;
7550b57cec5SDimitry Andric   }
7560b57cec5SDimitry Andric 
7570b57cec5SDimitry Andric   // There are some unreachable blocks.  We need to find the root blocks that
7580b57cec5SDimitry Andric   // contain code that should be considered unreachable.
759349cc55cSDimitry Andric   for (const CFGBlock *block : *cfg) {
7600b57cec5SDimitry Andric     // A block may have been marked reachable during this loop.
7610b57cec5SDimitry Andric     if (reachable[block->getBlockID()])
7620b57cec5SDimitry Andric       continue;
7630b57cec5SDimitry Andric 
7640b57cec5SDimitry Andric     DeadCodeScan DS(reachable, PP, AC.getASTContext());
7650b57cec5SDimitry Andric     numReachable += DS.scanBackwards(block, CB);
7660b57cec5SDimitry Andric 
7670b57cec5SDimitry Andric     if (numReachable == cfg->getNumBlockIDs())
7680b57cec5SDimitry Andric       return;
7690b57cec5SDimitry Andric   }
7700b57cec5SDimitry Andric }
7710b57cec5SDimitry Andric 
7720b57cec5SDimitry Andric }} // end namespace clang::reachable_code
773