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