17330f729Sjoerg //===-- ReachableCode.cpp - Code Reachability Analysis --------------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements a flow-sensitive, path-insensitive analysis of
107330f729Sjoerg // determining reachable blocks within a CFG.
117330f729Sjoerg //
127330f729Sjoerg //===----------------------------------------------------------------------===//
137330f729Sjoerg
147330f729Sjoerg #include "clang/Analysis/Analyses/ReachableCode.h"
157330f729Sjoerg #include "clang/AST/Expr.h"
167330f729Sjoerg #include "clang/AST/ExprCXX.h"
177330f729Sjoerg #include "clang/AST/ExprObjC.h"
187330f729Sjoerg #include "clang/AST/ParentMap.h"
197330f729Sjoerg #include "clang/AST/StmtCXX.h"
207330f729Sjoerg #include "clang/Analysis/AnalysisDeclContext.h"
217330f729Sjoerg #include "clang/Analysis/CFG.h"
22*e038c9c4Sjoerg #include "clang/Basic/Builtins.h"
237330f729Sjoerg #include "clang/Basic/SourceManager.h"
247330f729Sjoerg #include "clang/Lex/Preprocessor.h"
257330f729Sjoerg #include "llvm/ADT/BitVector.h"
267330f729Sjoerg #include "llvm/ADT/SmallVector.h"
277330f729Sjoerg
287330f729Sjoerg using namespace clang;
297330f729Sjoerg
307330f729Sjoerg //===----------------------------------------------------------------------===//
317330f729Sjoerg // Core Reachability Analysis routines.
327330f729Sjoerg //===----------------------------------------------------------------------===//
337330f729Sjoerg
isEnumConstant(const Expr * Ex)347330f729Sjoerg static bool isEnumConstant(const Expr *Ex) {
357330f729Sjoerg const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
367330f729Sjoerg if (!DR)
377330f729Sjoerg return false;
387330f729Sjoerg return isa<EnumConstantDecl>(DR->getDecl());
397330f729Sjoerg }
407330f729Sjoerg
isTrivialExpression(const Expr * Ex)417330f729Sjoerg static bool isTrivialExpression(const Expr *Ex) {
427330f729Sjoerg Ex = Ex->IgnoreParenCasts();
437330f729Sjoerg return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
447330f729Sjoerg isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) ||
457330f729Sjoerg isa<CharacterLiteral>(Ex) ||
467330f729Sjoerg isEnumConstant(Ex);
477330f729Sjoerg }
487330f729Sjoerg
isTrivialDoWhile(const CFGBlock * B,const Stmt * S)497330f729Sjoerg static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
507330f729Sjoerg // Check if the block ends with a do...while() and see if 'S' is the
517330f729Sjoerg // condition.
527330f729Sjoerg if (const Stmt *Term = B->getTerminatorStmt()) {
537330f729Sjoerg if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
547330f729Sjoerg const Expr *Cond = DS->getCond()->IgnoreParenCasts();
557330f729Sjoerg return Cond == S && isTrivialExpression(Cond);
567330f729Sjoerg }
577330f729Sjoerg }
587330f729Sjoerg return false;
597330f729Sjoerg }
607330f729Sjoerg
isBuiltinUnreachable(const Stmt * S)617330f729Sjoerg static bool isBuiltinUnreachable(const Stmt *S) {
627330f729Sjoerg if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
637330f729Sjoerg if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
647330f729Sjoerg return FDecl->getIdentifier() &&
657330f729Sjoerg FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
667330f729Sjoerg return false;
677330f729Sjoerg }
687330f729Sjoerg
isBuiltinAssumeFalse(const CFGBlock * B,const Stmt * S,ASTContext & C)697330f729Sjoerg static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
707330f729Sjoerg ASTContext &C) {
717330f729Sjoerg if (B->empty()) {
727330f729Sjoerg // Happens if S is B's terminator and B contains nothing else
737330f729Sjoerg // (e.g. a CFGBlock containing only a goto).
747330f729Sjoerg return false;
757330f729Sjoerg }
767330f729Sjoerg if (Optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
777330f729Sjoerg if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
787330f729Sjoerg return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
797330f729Sjoerg }
807330f729Sjoerg }
817330f729Sjoerg return false;
827330f729Sjoerg }
837330f729Sjoerg
isDeadReturn(const CFGBlock * B,const Stmt * S)847330f729Sjoerg static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
857330f729Sjoerg // Look to see if the current control flow ends with a 'return', and see if
867330f729Sjoerg // 'S' is a substatement. The 'return' may not be the last element in the
877330f729Sjoerg // block, or may be in a subsequent block because of destructors.
887330f729Sjoerg const CFGBlock *Current = B;
897330f729Sjoerg while (true) {
907330f729Sjoerg for (CFGBlock::const_reverse_iterator I = Current->rbegin(),
917330f729Sjoerg E = Current->rend();
927330f729Sjoerg I != E; ++I) {
937330f729Sjoerg if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
947330f729Sjoerg if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
957330f729Sjoerg if (RS == S)
967330f729Sjoerg return true;
977330f729Sjoerg if (const Expr *RE = RS->getRetValue()) {
987330f729Sjoerg RE = RE->IgnoreParenCasts();
997330f729Sjoerg if (RE == S)
1007330f729Sjoerg return true;
1017330f729Sjoerg ParentMap PM(const_cast<Expr *>(RE));
1027330f729Sjoerg // If 'S' is in the ParentMap, it is a subexpression of
1037330f729Sjoerg // the return statement.
1047330f729Sjoerg return PM.getParent(S);
1057330f729Sjoerg }
1067330f729Sjoerg }
1077330f729Sjoerg break;
1087330f729Sjoerg }
1097330f729Sjoerg }
1107330f729Sjoerg // Note also that we are restricting the search for the return statement
1117330f729Sjoerg // to stop at control-flow; only part of a return statement may be dead,
1127330f729Sjoerg // without the whole return statement being dead.
1137330f729Sjoerg if (Current->getTerminator().isTemporaryDtorsBranch()) {
1147330f729Sjoerg // Temporary destructors have a predictable control flow, thus we want to
1157330f729Sjoerg // look into the next block for the return statement.
1167330f729Sjoerg // We look into the false branch, as we know the true branch only contains
1177330f729Sjoerg // the call to the destructor.
1187330f729Sjoerg assert(Current->succ_size() == 2);
1197330f729Sjoerg Current = *(Current->succ_begin() + 1);
1207330f729Sjoerg } else if (!Current->getTerminatorStmt() && Current->succ_size() == 1) {
1217330f729Sjoerg // If there is only one successor, we're not dealing with outgoing control
1227330f729Sjoerg // flow. Thus, look into the next block.
1237330f729Sjoerg Current = *Current->succ_begin();
1247330f729Sjoerg if (Current->pred_size() > 1) {
1257330f729Sjoerg // If there is more than one predecessor, we're dealing with incoming
1267330f729Sjoerg // control flow - if the return statement is in that block, it might
1277330f729Sjoerg // well be reachable via a different control flow, thus it's not dead.
1287330f729Sjoerg return false;
1297330f729Sjoerg }
1307330f729Sjoerg } else {
1317330f729Sjoerg // We hit control flow or a dead end. Stop searching.
1327330f729Sjoerg return false;
1337330f729Sjoerg }
1347330f729Sjoerg }
1357330f729Sjoerg llvm_unreachable("Broke out of infinite loop.");
1367330f729Sjoerg }
1377330f729Sjoerg
getTopMostMacro(SourceLocation Loc,SourceManager & SM)1387330f729Sjoerg static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
1397330f729Sjoerg assert(Loc.isMacroID());
1407330f729Sjoerg SourceLocation Last;
141*e038c9c4Sjoerg do {
1427330f729Sjoerg Last = Loc;
1437330f729Sjoerg Loc = SM.getImmediateMacroCallerLoc(Loc);
144*e038c9c4Sjoerg } while (Loc.isMacroID());
1457330f729Sjoerg return Last;
1467330f729Sjoerg }
1477330f729Sjoerg
1487330f729Sjoerg /// Returns true if the statement is expanded from a configuration macro.
isExpandedFromConfigurationMacro(const Stmt * S,Preprocessor & PP,bool IgnoreYES_NO=false)1497330f729Sjoerg static bool isExpandedFromConfigurationMacro(const Stmt *S,
1507330f729Sjoerg Preprocessor &PP,
1517330f729Sjoerg bool IgnoreYES_NO = false) {
1527330f729Sjoerg // FIXME: This is not very precise. Here we just check to see if the
1537330f729Sjoerg // value comes from a macro, but we can do much better. This is likely
1547330f729Sjoerg // to be over conservative. This logic is factored into a separate function
1557330f729Sjoerg // so that we can refine it later.
1567330f729Sjoerg SourceLocation L = S->getBeginLoc();
1577330f729Sjoerg if (L.isMacroID()) {
1587330f729Sjoerg SourceManager &SM = PP.getSourceManager();
1597330f729Sjoerg if (IgnoreYES_NO) {
1607330f729Sjoerg // The Objective-C constant 'YES' and 'NO'
1617330f729Sjoerg // are defined as macros. Do not treat them
1627330f729Sjoerg // as configuration values.
1637330f729Sjoerg SourceLocation TopL = getTopMostMacro(L, SM);
1647330f729Sjoerg StringRef MacroName = PP.getImmediateMacroName(TopL);
1657330f729Sjoerg if (MacroName == "YES" || MacroName == "NO")
1667330f729Sjoerg return false;
1677330f729Sjoerg } else if (!PP.getLangOpts().CPlusPlus) {
1687330f729Sjoerg // Do not treat C 'false' and 'true' macros as configuration values.
1697330f729Sjoerg SourceLocation TopL = getTopMostMacro(L, SM);
1707330f729Sjoerg StringRef MacroName = PP.getImmediateMacroName(TopL);
1717330f729Sjoerg if (MacroName == "false" || MacroName == "true")
1727330f729Sjoerg return false;
1737330f729Sjoerg }
1747330f729Sjoerg return true;
1757330f729Sjoerg }
1767330f729Sjoerg return false;
1777330f729Sjoerg }
1787330f729Sjoerg
1797330f729Sjoerg static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
1807330f729Sjoerg
1817330f729Sjoerg /// Returns true if the statement represents a configuration value.
1827330f729Sjoerg ///
1837330f729Sjoerg /// A configuration value is something usually determined at compile-time
1847330f729Sjoerg /// to conditionally always execute some branch. Such guards are for
1857330f729Sjoerg /// "sometimes unreachable" code. Such code is usually not interesting
1867330f729Sjoerg /// to report as unreachable, and may mask truly unreachable code within
1877330f729Sjoerg /// those blocks.
isConfigurationValue(const Stmt * S,Preprocessor & PP,SourceRange * SilenceableCondVal=nullptr,bool IncludeIntegers=true,bool WrappedInParens=false)1887330f729Sjoerg static bool isConfigurationValue(const Stmt *S,
1897330f729Sjoerg Preprocessor &PP,
1907330f729Sjoerg SourceRange *SilenceableCondVal = nullptr,
1917330f729Sjoerg bool IncludeIntegers = true,
1927330f729Sjoerg bool WrappedInParens = false) {
1937330f729Sjoerg if (!S)
1947330f729Sjoerg return false;
1957330f729Sjoerg
1967330f729Sjoerg if (const auto *Ex = dyn_cast<Expr>(S))
1977330f729Sjoerg S = Ex->IgnoreImplicit();
1987330f729Sjoerg
1997330f729Sjoerg if (const auto *Ex = dyn_cast<Expr>(S))
2007330f729Sjoerg S = Ex->IgnoreCasts();
2017330f729Sjoerg
2027330f729Sjoerg // Special case looking for the sigil '()' around an integer literal.
2037330f729Sjoerg if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
2047330f729Sjoerg if (!PE->getBeginLoc().isMacroID())
2057330f729Sjoerg return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
2067330f729Sjoerg IncludeIntegers, true);
2077330f729Sjoerg
2087330f729Sjoerg if (const Expr *Ex = dyn_cast<Expr>(S))
2097330f729Sjoerg S = Ex->IgnoreCasts();
2107330f729Sjoerg
2117330f729Sjoerg bool IgnoreYES_NO = false;
2127330f729Sjoerg
2137330f729Sjoerg switch (S->getStmtClass()) {
2147330f729Sjoerg case Stmt::CallExprClass: {
2157330f729Sjoerg const FunctionDecl *Callee =
2167330f729Sjoerg dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
2177330f729Sjoerg return Callee ? Callee->isConstexpr() : false;
2187330f729Sjoerg }
2197330f729Sjoerg case Stmt::DeclRefExprClass:
2207330f729Sjoerg return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
2217330f729Sjoerg case Stmt::ObjCBoolLiteralExprClass:
2227330f729Sjoerg IgnoreYES_NO = true;
2237330f729Sjoerg LLVM_FALLTHROUGH;
2247330f729Sjoerg case Stmt::CXXBoolLiteralExprClass:
2257330f729Sjoerg case Stmt::IntegerLiteralClass: {
2267330f729Sjoerg const Expr *E = cast<Expr>(S);
2277330f729Sjoerg if (IncludeIntegers) {
2287330f729Sjoerg if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
2297330f729Sjoerg *SilenceableCondVal = E->getSourceRange();
2307330f729Sjoerg return WrappedInParens || isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
2317330f729Sjoerg }
2327330f729Sjoerg return false;
2337330f729Sjoerg }
2347330f729Sjoerg case Stmt::MemberExprClass:
2357330f729Sjoerg return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
2367330f729Sjoerg case Stmt::UnaryExprOrTypeTraitExprClass:
2377330f729Sjoerg return true;
2387330f729Sjoerg case Stmt::BinaryOperatorClass: {
2397330f729Sjoerg const BinaryOperator *B = cast<BinaryOperator>(S);
2407330f729Sjoerg // Only include raw integers (not enums) as configuration
2417330f729Sjoerg // values if they are used in a logical or comparison operator
2427330f729Sjoerg // (not arithmetic).
2437330f729Sjoerg IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
2447330f729Sjoerg return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
2457330f729Sjoerg IncludeIntegers) ||
2467330f729Sjoerg isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
2477330f729Sjoerg IncludeIntegers);
2487330f729Sjoerg }
2497330f729Sjoerg case Stmt::UnaryOperatorClass: {
2507330f729Sjoerg const UnaryOperator *UO = cast<UnaryOperator>(S);
2517330f729Sjoerg if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
2527330f729Sjoerg return false;
2537330f729Sjoerg bool SilenceableCondValNotSet =
2547330f729Sjoerg SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
2557330f729Sjoerg bool IsSubExprConfigValue =
2567330f729Sjoerg isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
2577330f729Sjoerg IncludeIntegers, WrappedInParens);
2587330f729Sjoerg // Update the silenceable condition value source range only if the range
2597330f729Sjoerg // was set directly by the child expression.
2607330f729Sjoerg if (SilenceableCondValNotSet &&
2617330f729Sjoerg SilenceableCondVal->getBegin().isValid() &&
2627330f729Sjoerg *SilenceableCondVal ==
2637330f729Sjoerg UO->getSubExpr()->IgnoreCasts()->getSourceRange())
2647330f729Sjoerg *SilenceableCondVal = UO->getSourceRange();
2657330f729Sjoerg return IsSubExprConfigValue;
2667330f729Sjoerg }
2677330f729Sjoerg default:
2687330f729Sjoerg return false;
2697330f729Sjoerg }
2707330f729Sjoerg }
2717330f729Sjoerg
isConfigurationValue(const ValueDecl * D,Preprocessor & PP)2727330f729Sjoerg static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
2737330f729Sjoerg if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
2747330f729Sjoerg return isConfigurationValue(ED->getInitExpr(), PP);
2757330f729Sjoerg if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
2767330f729Sjoerg // As a heuristic, treat globals as configuration values. Note
2777330f729Sjoerg // that we only will get here if Sema evaluated this
2787330f729Sjoerg // condition to a constant expression, which means the global
2797330f729Sjoerg // had to be declared in a way to be a truly constant value.
2807330f729Sjoerg // We could generalize this to local variables, but it isn't
2817330f729Sjoerg // clear if those truly represent configuration values that
2827330f729Sjoerg // gate unreachable code.
2837330f729Sjoerg if (!VD->hasLocalStorage())
2847330f729Sjoerg return true;
2857330f729Sjoerg
2867330f729Sjoerg // As a heuristic, locals that have been marked 'const' explicitly
2877330f729Sjoerg // can be treated as configuration values as well.
2887330f729Sjoerg return VD->getType().isLocalConstQualified();
2897330f729Sjoerg }
2907330f729Sjoerg return false;
2917330f729Sjoerg }
2927330f729Sjoerg
2937330f729Sjoerg /// Returns true if we should always explore all successors of a block.
shouldTreatSuccessorsAsReachable(const CFGBlock * B,Preprocessor & PP)2947330f729Sjoerg static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
2957330f729Sjoerg Preprocessor &PP) {
2967330f729Sjoerg if (const Stmt *Term = B->getTerminatorStmt()) {
2977330f729Sjoerg if (isa<SwitchStmt>(Term))
2987330f729Sjoerg return true;
2997330f729Sjoerg // Specially handle '||' and '&&'.
3007330f729Sjoerg if (isa<BinaryOperator>(Term)) {
3017330f729Sjoerg return isConfigurationValue(Term, PP);
3027330f729Sjoerg }
3037330f729Sjoerg }
3047330f729Sjoerg
3057330f729Sjoerg const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
3067330f729Sjoerg return isConfigurationValue(Cond, PP);
3077330f729Sjoerg }
3087330f729Sjoerg
scanFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable,Preprocessor * PP,bool IncludeSometimesUnreachableEdges)3097330f729Sjoerg static unsigned scanFromBlock(const CFGBlock *Start,
3107330f729Sjoerg llvm::BitVector &Reachable,
3117330f729Sjoerg Preprocessor *PP,
3127330f729Sjoerg bool IncludeSometimesUnreachableEdges) {
3137330f729Sjoerg unsigned count = 0;
3147330f729Sjoerg
3157330f729Sjoerg // Prep work queue
3167330f729Sjoerg SmallVector<const CFGBlock*, 32> WL;
3177330f729Sjoerg
3187330f729Sjoerg // The entry block may have already been marked reachable
3197330f729Sjoerg // by the caller.
3207330f729Sjoerg if (!Reachable[Start->getBlockID()]) {
3217330f729Sjoerg ++count;
3227330f729Sjoerg Reachable[Start->getBlockID()] = true;
3237330f729Sjoerg }
3247330f729Sjoerg
3257330f729Sjoerg WL.push_back(Start);
3267330f729Sjoerg
3277330f729Sjoerg // Find the reachable blocks from 'Start'.
3287330f729Sjoerg while (!WL.empty()) {
3297330f729Sjoerg const CFGBlock *item = WL.pop_back_val();
3307330f729Sjoerg
3317330f729Sjoerg // There are cases where we want to treat all successors as reachable.
3327330f729Sjoerg // The idea is that some "sometimes unreachable" code is not interesting,
3337330f729Sjoerg // and that we should forge ahead and explore those branches anyway.
3347330f729Sjoerg // This allows us to potentially uncover some "always unreachable" code
3357330f729Sjoerg // within the "sometimes unreachable" code.
3367330f729Sjoerg // Look at the successors and mark then reachable.
3377330f729Sjoerg Optional<bool> TreatAllSuccessorsAsReachable;
3387330f729Sjoerg if (!IncludeSometimesUnreachableEdges)
3397330f729Sjoerg TreatAllSuccessorsAsReachable = false;
3407330f729Sjoerg
3417330f729Sjoerg for (CFGBlock::const_succ_iterator I = item->succ_begin(),
3427330f729Sjoerg E = item->succ_end(); I != E; ++I) {
3437330f729Sjoerg const CFGBlock *B = *I;
3447330f729Sjoerg if (!B) do {
3457330f729Sjoerg const CFGBlock *UB = I->getPossiblyUnreachableBlock();
3467330f729Sjoerg if (!UB)
3477330f729Sjoerg break;
3487330f729Sjoerg
3497330f729Sjoerg if (!TreatAllSuccessorsAsReachable.hasValue()) {
3507330f729Sjoerg assert(PP);
3517330f729Sjoerg TreatAllSuccessorsAsReachable =
3527330f729Sjoerg shouldTreatSuccessorsAsReachable(item, *PP);
3537330f729Sjoerg }
3547330f729Sjoerg
3557330f729Sjoerg if (TreatAllSuccessorsAsReachable.getValue()) {
3567330f729Sjoerg B = UB;
3577330f729Sjoerg break;
3587330f729Sjoerg }
3597330f729Sjoerg }
3607330f729Sjoerg while (false);
3617330f729Sjoerg
3627330f729Sjoerg if (B) {
3637330f729Sjoerg unsigned blockID = B->getBlockID();
3647330f729Sjoerg if (!Reachable[blockID]) {
3657330f729Sjoerg Reachable.set(blockID);
3667330f729Sjoerg WL.push_back(B);
3677330f729Sjoerg ++count;
3687330f729Sjoerg }
3697330f729Sjoerg }
3707330f729Sjoerg }
3717330f729Sjoerg }
3727330f729Sjoerg return count;
3737330f729Sjoerg }
3747330f729Sjoerg
scanMaybeReachableFromBlock(const CFGBlock * Start,Preprocessor & PP,llvm::BitVector & Reachable)3757330f729Sjoerg static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
3767330f729Sjoerg Preprocessor &PP,
3777330f729Sjoerg llvm::BitVector &Reachable) {
3787330f729Sjoerg return scanFromBlock(Start, Reachable, &PP, true);
3797330f729Sjoerg }
3807330f729Sjoerg
3817330f729Sjoerg //===----------------------------------------------------------------------===//
3827330f729Sjoerg // Dead Code Scanner.
3837330f729Sjoerg //===----------------------------------------------------------------------===//
3847330f729Sjoerg
3857330f729Sjoerg namespace {
3867330f729Sjoerg class DeadCodeScan {
3877330f729Sjoerg llvm::BitVector Visited;
3887330f729Sjoerg llvm::BitVector &Reachable;
3897330f729Sjoerg SmallVector<const CFGBlock *, 10> WorkList;
3907330f729Sjoerg Preprocessor &PP;
3917330f729Sjoerg ASTContext &C;
3927330f729Sjoerg
3937330f729Sjoerg typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
3947330f729Sjoerg DeferredLocsTy;
3957330f729Sjoerg
3967330f729Sjoerg DeferredLocsTy DeferredLocs;
3977330f729Sjoerg
3987330f729Sjoerg public:
DeadCodeScan(llvm::BitVector & reachable,Preprocessor & PP,ASTContext & C)3997330f729Sjoerg DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
4007330f729Sjoerg : Visited(reachable.size()),
4017330f729Sjoerg Reachable(reachable),
4027330f729Sjoerg PP(PP), C(C) {}
4037330f729Sjoerg
4047330f729Sjoerg void enqueue(const CFGBlock *block);
4057330f729Sjoerg unsigned scanBackwards(const CFGBlock *Start,
4067330f729Sjoerg clang::reachable_code::Callback &CB);
4077330f729Sjoerg
4087330f729Sjoerg bool isDeadCodeRoot(const CFGBlock *Block);
4097330f729Sjoerg
4107330f729Sjoerg const Stmt *findDeadCode(const CFGBlock *Block);
4117330f729Sjoerg
4127330f729Sjoerg void reportDeadCode(const CFGBlock *B,
4137330f729Sjoerg const Stmt *S,
4147330f729Sjoerg clang::reachable_code::Callback &CB);
4157330f729Sjoerg };
4167330f729Sjoerg }
4177330f729Sjoerg
enqueue(const CFGBlock * block)4187330f729Sjoerg void DeadCodeScan::enqueue(const CFGBlock *block) {
4197330f729Sjoerg unsigned blockID = block->getBlockID();
4207330f729Sjoerg if (Reachable[blockID] || Visited[blockID])
4217330f729Sjoerg return;
4227330f729Sjoerg Visited[blockID] = true;
4237330f729Sjoerg WorkList.push_back(block);
4247330f729Sjoerg }
4257330f729Sjoerg
isDeadCodeRoot(const clang::CFGBlock * Block)4267330f729Sjoerg bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
4277330f729Sjoerg bool isDeadRoot = true;
4287330f729Sjoerg
4297330f729Sjoerg for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
4307330f729Sjoerg E = Block->pred_end(); I != E; ++I) {
4317330f729Sjoerg if (const CFGBlock *PredBlock = *I) {
4327330f729Sjoerg unsigned blockID = PredBlock->getBlockID();
4337330f729Sjoerg if (Visited[blockID]) {
4347330f729Sjoerg isDeadRoot = false;
4357330f729Sjoerg continue;
4367330f729Sjoerg }
4377330f729Sjoerg if (!Reachable[blockID]) {
4387330f729Sjoerg isDeadRoot = false;
4397330f729Sjoerg Visited[blockID] = true;
4407330f729Sjoerg WorkList.push_back(PredBlock);
4417330f729Sjoerg continue;
4427330f729Sjoerg }
4437330f729Sjoerg }
4447330f729Sjoerg }
4457330f729Sjoerg
4467330f729Sjoerg return isDeadRoot;
4477330f729Sjoerg }
4487330f729Sjoerg
isValidDeadStmt(const Stmt * S)4497330f729Sjoerg static bool isValidDeadStmt(const Stmt *S) {
4507330f729Sjoerg if (S->getBeginLoc().isInvalid())
4517330f729Sjoerg return false;
4527330f729Sjoerg if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
4537330f729Sjoerg return BO->getOpcode() != BO_Comma;
4547330f729Sjoerg return true;
4557330f729Sjoerg }
4567330f729Sjoerg
findDeadCode(const clang::CFGBlock * Block)4577330f729Sjoerg const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
4587330f729Sjoerg for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
4597330f729Sjoerg if (Optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
4607330f729Sjoerg const Stmt *S = CS->getStmt();
4617330f729Sjoerg if (isValidDeadStmt(S))
4627330f729Sjoerg return S;
4637330f729Sjoerg }
4647330f729Sjoerg
4657330f729Sjoerg CFGTerminator T = Block->getTerminator();
4667330f729Sjoerg if (T.isStmtBranch()) {
4677330f729Sjoerg const Stmt *S = T.getStmt();
4687330f729Sjoerg if (S && isValidDeadStmt(S))
4697330f729Sjoerg return S;
4707330f729Sjoerg }
4717330f729Sjoerg
4727330f729Sjoerg return nullptr;
4737330f729Sjoerg }
4747330f729Sjoerg
SrcCmp(const std::pair<const CFGBlock *,const Stmt * > * p1,const std::pair<const CFGBlock *,const Stmt * > * p2)4757330f729Sjoerg static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
4767330f729Sjoerg const std::pair<const CFGBlock *, const Stmt *> *p2) {
4777330f729Sjoerg if (p1->second->getBeginLoc() < p2->second->getBeginLoc())
4787330f729Sjoerg return -1;
4797330f729Sjoerg if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
4807330f729Sjoerg return 1;
4817330f729Sjoerg return 0;
4827330f729Sjoerg }
4837330f729Sjoerg
scanBackwards(const clang::CFGBlock * Start,clang::reachable_code::Callback & CB)4847330f729Sjoerg unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
4857330f729Sjoerg clang::reachable_code::Callback &CB) {
4867330f729Sjoerg
4877330f729Sjoerg unsigned count = 0;
4887330f729Sjoerg enqueue(Start);
4897330f729Sjoerg
4907330f729Sjoerg while (!WorkList.empty()) {
4917330f729Sjoerg const CFGBlock *Block = WorkList.pop_back_val();
4927330f729Sjoerg
4937330f729Sjoerg // It is possible that this block has been marked reachable after
4947330f729Sjoerg // it was enqueued.
4957330f729Sjoerg if (Reachable[Block->getBlockID()])
4967330f729Sjoerg continue;
4977330f729Sjoerg
4987330f729Sjoerg // Look for any dead code within the block.
4997330f729Sjoerg const Stmt *S = findDeadCode(Block);
5007330f729Sjoerg
5017330f729Sjoerg if (!S) {
5027330f729Sjoerg // No dead code. Possibly an empty block. Look at dead predecessors.
5037330f729Sjoerg for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
5047330f729Sjoerg E = Block->pred_end(); I != E; ++I) {
5057330f729Sjoerg if (const CFGBlock *predBlock = *I)
5067330f729Sjoerg enqueue(predBlock);
5077330f729Sjoerg }
5087330f729Sjoerg continue;
5097330f729Sjoerg }
5107330f729Sjoerg
5117330f729Sjoerg // Specially handle macro-expanded code.
5127330f729Sjoerg if (S->getBeginLoc().isMacroID()) {
5137330f729Sjoerg count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5147330f729Sjoerg continue;
5157330f729Sjoerg }
5167330f729Sjoerg
5177330f729Sjoerg if (isDeadCodeRoot(Block)) {
5187330f729Sjoerg reportDeadCode(Block, S, CB);
5197330f729Sjoerg count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5207330f729Sjoerg }
5217330f729Sjoerg else {
5227330f729Sjoerg // Record this statement as the possibly best location in a
5237330f729Sjoerg // strongly-connected component of dead code for emitting a
5247330f729Sjoerg // warning.
5257330f729Sjoerg DeferredLocs.push_back(std::make_pair(Block, S));
5267330f729Sjoerg }
5277330f729Sjoerg }
5287330f729Sjoerg
5297330f729Sjoerg // If we didn't find a dead root, then report the dead code with the
5307330f729Sjoerg // earliest location.
5317330f729Sjoerg if (!DeferredLocs.empty()) {
5327330f729Sjoerg llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
5337330f729Sjoerg for (DeferredLocsTy::iterator I = DeferredLocs.begin(),
5347330f729Sjoerg E = DeferredLocs.end(); I != E; ++I) {
5357330f729Sjoerg const CFGBlock *Block = I->first;
5367330f729Sjoerg if (Reachable[Block->getBlockID()])
5377330f729Sjoerg continue;
5387330f729Sjoerg reportDeadCode(Block, I->second, CB);
5397330f729Sjoerg count += scanMaybeReachableFromBlock(Block, PP, Reachable);
5407330f729Sjoerg }
5417330f729Sjoerg }
5427330f729Sjoerg
5437330f729Sjoerg return count;
5447330f729Sjoerg }
5457330f729Sjoerg
GetUnreachableLoc(const Stmt * S,SourceRange & R1,SourceRange & R2)5467330f729Sjoerg static SourceLocation GetUnreachableLoc(const Stmt *S,
5477330f729Sjoerg SourceRange &R1,
5487330f729Sjoerg SourceRange &R2) {
5497330f729Sjoerg R1 = R2 = SourceRange();
5507330f729Sjoerg
5517330f729Sjoerg if (const Expr *Ex = dyn_cast<Expr>(S))
5527330f729Sjoerg S = Ex->IgnoreParenImpCasts();
5537330f729Sjoerg
5547330f729Sjoerg switch (S->getStmtClass()) {
5557330f729Sjoerg case Expr::BinaryOperatorClass: {
5567330f729Sjoerg const BinaryOperator *BO = cast<BinaryOperator>(S);
5577330f729Sjoerg return BO->getOperatorLoc();
5587330f729Sjoerg }
5597330f729Sjoerg case Expr::UnaryOperatorClass: {
5607330f729Sjoerg const UnaryOperator *UO = cast<UnaryOperator>(S);
5617330f729Sjoerg R1 = UO->getSubExpr()->getSourceRange();
5627330f729Sjoerg return UO->getOperatorLoc();
5637330f729Sjoerg }
5647330f729Sjoerg case Expr::CompoundAssignOperatorClass: {
5657330f729Sjoerg const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
5667330f729Sjoerg R1 = CAO->getLHS()->getSourceRange();
5677330f729Sjoerg R2 = CAO->getRHS()->getSourceRange();
5687330f729Sjoerg return CAO->getOperatorLoc();
5697330f729Sjoerg }
5707330f729Sjoerg case Expr::BinaryConditionalOperatorClass:
5717330f729Sjoerg case Expr::ConditionalOperatorClass: {
5727330f729Sjoerg const AbstractConditionalOperator *CO =
5737330f729Sjoerg cast<AbstractConditionalOperator>(S);
5747330f729Sjoerg return CO->getQuestionLoc();
5757330f729Sjoerg }
5767330f729Sjoerg case Expr::MemberExprClass: {
5777330f729Sjoerg const MemberExpr *ME = cast<MemberExpr>(S);
5787330f729Sjoerg R1 = ME->getSourceRange();
5797330f729Sjoerg return ME->getMemberLoc();
5807330f729Sjoerg }
5817330f729Sjoerg case Expr::ArraySubscriptExprClass: {
5827330f729Sjoerg const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
5837330f729Sjoerg R1 = ASE->getLHS()->getSourceRange();
5847330f729Sjoerg R2 = ASE->getRHS()->getSourceRange();
5857330f729Sjoerg return ASE->getRBracketLoc();
5867330f729Sjoerg }
5877330f729Sjoerg case Expr::CStyleCastExprClass: {
5887330f729Sjoerg const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
5897330f729Sjoerg R1 = CSC->getSubExpr()->getSourceRange();
5907330f729Sjoerg return CSC->getLParenLoc();
5917330f729Sjoerg }
5927330f729Sjoerg case Expr::CXXFunctionalCastExprClass: {
5937330f729Sjoerg const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
5947330f729Sjoerg R1 = CE->getSubExpr()->getSourceRange();
5957330f729Sjoerg return CE->getBeginLoc();
5967330f729Sjoerg }
5977330f729Sjoerg case Stmt::CXXTryStmtClass: {
5987330f729Sjoerg return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
5997330f729Sjoerg }
6007330f729Sjoerg case Expr::ObjCBridgedCastExprClass: {
6017330f729Sjoerg const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
6027330f729Sjoerg R1 = CSC->getSubExpr()->getSourceRange();
6037330f729Sjoerg return CSC->getLParenLoc();
6047330f729Sjoerg }
6057330f729Sjoerg default: ;
6067330f729Sjoerg }
6077330f729Sjoerg R1 = S->getSourceRange();
6087330f729Sjoerg return S->getBeginLoc();
6097330f729Sjoerg }
6107330f729Sjoerg
reportDeadCode(const CFGBlock * B,const Stmt * S,clang::reachable_code::Callback & CB)6117330f729Sjoerg void DeadCodeScan::reportDeadCode(const CFGBlock *B,
6127330f729Sjoerg const Stmt *S,
6137330f729Sjoerg clang::reachable_code::Callback &CB) {
6147330f729Sjoerg // Classify the unreachable code found, or suppress it in some cases.
6157330f729Sjoerg reachable_code::UnreachableKind UK = reachable_code::UK_Other;
6167330f729Sjoerg
6177330f729Sjoerg if (isa<BreakStmt>(S)) {
6187330f729Sjoerg UK = reachable_code::UK_Break;
6197330f729Sjoerg } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
6207330f729Sjoerg isBuiltinAssumeFalse(B, S, C)) {
6217330f729Sjoerg return;
6227330f729Sjoerg }
6237330f729Sjoerg else if (isDeadReturn(B, S)) {
6247330f729Sjoerg UK = reachable_code::UK_Return;
6257330f729Sjoerg }
6267330f729Sjoerg
6277330f729Sjoerg SourceRange SilenceableCondVal;
6287330f729Sjoerg
6297330f729Sjoerg if (UK == reachable_code::UK_Other) {
6307330f729Sjoerg // Check if the dead code is part of the "loop target" of
6317330f729Sjoerg // a for/for-range loop. This is the block that contains
6327330f729Sjoerg // the increment code.
6337330f729Sjoerg if (const Stmt *LoopTarget = B->getLoopTarget()) {
6347330f729Sjoerg SourceLocation Loc = LoopTarget->getBeginLoc();
6357330f729Sjoerg SourceRange R1(Loc, Loc), R2;
6367330f729Sjoerg
6377330f729Sjoerg if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
6387330f729Sjoerg const Expr *Inc = FS->getInc();
6397330f729Sjoerg Loc = Inc->getBeginLoc();
6407330f729Sjoerg R2 = Inc->getSourceRange();
6417330f729Sjoerg }
6427330f729Sjoerg
6437330f729Sjoerg CB.HandleUnreachable(reachable_code::UK_Loop_Increment,
6447330f729Sjoerg Loc, SourceRange(), SourceRange(Loc, Loc), R2);
6457330f729Sjoerg return;
6467330f729Sjoerg }
6477330f729Sjoerg
6487330f729Sjoerg // Check if the dead block has a predecessor whose branch has
6497330f729Sjoerg // a configuration value that *could* be modified to
6507330f729Sjoerg // silence the warning.
6517330f729Sjoerg CFGBlock::const_pred_iterator PI = B->pred_begin();
6527330f729Sjoerg if (PI != B->pred_end()) {
6537330f729Sjoerg if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
6547330f729Sjoerg const Stmt *TermCond =
6557330f729Sjoerg PredBlock->getTerminatorCondition(/* strip parens */ false);
6567330f729Sjoerg isConfigurationValue(TermCond, PP, &SilenceableCondVal);
6577330f729Sjoerg }
6587330f729Sjoerg }
6597330f729Sjoerg }
6607330f729Sjoerg
6617330f729Sjoerg SourceRange R1, R2;
6627330f729Sjoerg SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
6637330f729Sjoerg CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2);
6647330f729Sjoerg }
6657330f729Sjoerg
6667330f729Sjoerg //===----------------------------------------------------------------------===//
6677330f729Sjoerg // Reachability APIs.
6687330f729Sjoerg //===----------------------------------------------------------------------===//
6697330f729Sjoerg
6707330f729Sjoerg namespace clang { namespace reachable_code {
6717330f729Sjoerg
anchor()6727330f729Sjoerg void Callback::anchor() { }
6737330f729Sjoerg
ScanReachableFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable)6747330f729Sjoerg unsigned ScanReachableFromBlock(const CFGBlock *Start,
6757330f729Sjoerg llvm::BitVector &Reachable) {
6767330f729Sjoerg return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
6777330f729Sjoerg }
6787330f729Sjoerg
FindUnreachableCode(AnalysisDeclContext & AC,Preprocessor & PP,Callback & CB)6797330f729Sjoerg void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
6807330f729Sjoerg Callback &CB) {
6817330f729Sjoerg
6827330f729Sjoerg CFG *cfg = AC.getCFG();
6837330f729Sjoerg if (!cfg)
6847330f729Sjoerg return;
6857330f729Sjoerg
6867330f729Sjoerg // Scan for reachable blocks from the entrance of the CFG.
6877330f729Sjoerg // If there are no unreachable blocks, we're done.
6887330f729Sjoerg llvm::BitVector reachable(cfg->getNumBlockIDs());
6897330f729Sjoerg unsigned numReachable =
6907330f729Sjoerg scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
6917330f729Sjoerg if (numReachable == cfg->getNumBlockIDs())
6927330f729Sjoerg return;
6937330f729Sjoerg
6947330f729Sjoerg // If there aren't explicit EH edges, we should include the 'try' dispatch
6957330f729Sjoerg // blocks as roots.
6967330f729Sjoerg if (!AC.getCFGBuildOptions().AddEHEdges) {
6977330f729Sjoerg for (CFG::try_block_iterator I = cfg->try_blocks_begin(),
6987330f729Sjoerg E = cfg->try_blocks_end() ; I != E; ++I) {
6997330f729Sjoerg numReachable += scanMaybeReachableFromBlock(*I, PP, reachable);
7007330f729Sjoerg }
7017330f729Sjoerg if (numReachable == cfg->getNumBlockIDs())
7027330f729Sjoerg return;
7037330f729Sjoerg }
7047330f729Sjoerg
7057330f729Sjoerg // There are some unreachable blocks. We need to find the root blocks that
7067330f729Sjoerg // contain code that should be considered unreachable.
7077330f729Sjoerg for (CFG::iterator I = cfg->begin(), E = cfg->end(); I != E; ++I) {
7087330f729Sjoerg const CFGBlock *block = *I;
7097330f729Sjoerg // A block may have been marked reachable during this loop.
7107330f729Sjoerg if (reachable[block->getBlockID()])
7117330f729Sjoerg continue;
7127330f729Sjoerg
7137330f729Sjoerg DeadCodeScan DS(reachable, PP, AC.getASTContext());
7147330f729Sjoerg numReachable += DS.scanBackwards(block, CB);
7157330f729Sjoerg
7167330f729Sjoerg if (numReachable == cfg->getNumBlockIDs())
7177330f729Sjoerg return;
7187330f729Sjoerg }
7197330f729Sjoerg }
7207330f729Sjoerg
7217330f729Sjoerg }} // end namespace clang::reachable_code
722