1e5dd7070Spatrick //===-- ReachableCode.cpp - Code Reachability Analysis --------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // This file implements a flow-sensitive, path-insensitive analysis of
10e5dd7070Spatrick // determining reachable blocks within a CFG.
11e5dd7070Spatrick //
12e5dd7070Spatrick //===----------------------------------------------------------------------===//
13e5dd7070Spatrick
14e5dd7070Spatrick #include "clang/Analysis/Analyses/ReachableCode.h"
15e5dd7070Spatrick #include "clang/AST/Expr.h"
16e5dd7070Spatrick #include "clang/AST/ExprCXX.h"
17e5dd7070Spatrick #include "clang/AST/ExprObjC.h"
18e5dd7070Spatrick #include "clang/AST/ParentMap.h"
19e5dd7070Spatrick #include "clang/AST/StmtCXX.h"
20e5dd7070Spatrick #include "clang/Analysis/AnalysisDeclContext.h"
21e5dd7070Spatrick #include "clang/Analysis/CFG.h"
22e5dd7070Spatrick #include "clang/Basic/Builtins.h"
23e5dd7070Spatrick #include "clang/Basic/SourceManager.h"
24e5dd7070Spatrick #include "clang/Lex/Preprocessor.h"
25e5dd7070Spatrick #include "llvm/ADT/BitVector.h"
26e5dd7070Spatrick #include "llvm/ADT/SmallVector.h"
27*12c85518Srobert #include <optional>
28e5dd7070Spatrick
29e5dd7070Spatrick using namespace clang;
30e5dd7070Spatrick
31e5dd7070Spatrick //===----------------------------------------------------------------------===//
32e5dd7070Spatrick // Core Reachability Analysis routines.
33e5dd7070Spatrick //===----------------------------------------------------------------------===//
34e5dd7070Spatrick
isEnumConstant(const Expr * Ex)35e5dd7070Spatrick static bool isEnumConstant(const Expr *Ex) {
36e5dd7070Spatrick const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
37e5dd7070Spatrick if (!DR)
38e5dd7070Spatrick return false;
39e5dd7070Spatrick return isa<EnumConstantDecl>(DR->getDecl());
40e5dd7070Spatrick }
41e5dd7070Spatrick
isTrivialExpression(const Expr * Ex)42e5dd7070Spatrick static bool isTrivialExpression(const Expr *Ex) {
43e5dd7070Spatrick Ex = Ex->IgnoreParenCasts();
44e5dd7070Spatrick return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
45e5dd7070Spatrick isa<CXXBoolLiteralExpr>(Ex) || isa<ObjCBoolLiteralExpr>(Ex) ||
46e5dd7070Spatrick isa<CharacterLiteral>(Ex) ||
47e5dd7070Spatrick isEnumConstant(Ex);
48e5dd7070Spatrick }
49e5dd7070Spatrick
isTrivialDoWhile(const CFGBlock * B,const Stmt * S)50e5dd7070Spatrick static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S) {
51e5dd7070Spatrick // Check if the block ends with a do...while() and see if 'S' is the
52e5dd7070Spatrick // condition.
53e5dd7070Spatrick if (const Stmt *Term = B->getTerminatorStmt()) {
54e5dd7070Spatrick if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
55e5dd7070Spatrick const Expr *Cond = DS->getCond()->IgnoreParenCasts();
56e5dd7070Spatrick return Cond == S && isTrivialExpression(Cond);
57e5dd7070Spatrick }
58e5dd7070Spatrick }
59e5dd7070Spatrick return false;
60e5dd7070Spatrick }
61e5dd7070Spatrick
isBuiltinUnreachable(const Stmt * S)62e5dd7070Spatrick static bool isBuiltinUnreachable(const Stmt *S) {
63e5dd7070Spatrick if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
64e5dd7070Spatrick if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
65e5dd7070Spatrick return FDecl->getIdentifier() &&
66e5dd7070Spatrick FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
67e5dd7070Spatrick return false;
68e5dd7070Spatrick }
69e5dd7070Spatrick
isBuiltinAssumeFalse(const CFGBlock * B,const Stmt * S,ASTContext & C)70e5dd7070Spatrick static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
71e5dd7070Spatrick ASTContext &C) {
72e5dd7070Spatrick if (B->empty()) {
73e5dd7070Spatrick // Happens if S is B's terminator and B contains nothing else
74e5dd7070Spatrick // (e.g. a CFGBlock containing only a goto).
75e5dd7070Spatrick return false;
76e5dd7070Spatrick }
77*12c85518Srobert if (std::optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
78e5dd7070Spatrick if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
79e5dd7070Spatrick return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
80e5dd7070Spatrick }
81e5dd7070Spatrick }
82e5dd7070Spatrick return false;
83e5dd7070Spatrick }
84e5dd7070Spatrick
isDeadReturn(const CFGBlock * B,const Stmt * S)85e5dd7070Spatrick static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
86e5dd7070Spatrick // Look to see if the current control flow ends with a 'return', and see if
87e5dd7070Spatrick // 'S' is a substatement. The 'return' may not be the last element in the
88e5dd7070Spatrick // block, or may be in a subsequent block because of destructors.
89e5dd7070Spatrick const CFGBlock *Current = B;
90e5dd7070Spatrick while (true) {
91*12c85518Srobert for (const CFGElement &CE : llvm::reverse(*Current)) {
92*12c85518Srobert if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
93e5dd7070Spatrick if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
94e5dd7070Spatrick if (RS == S)
95e5dd7070Spatrick return true;
96e5dd7070Spatrick if (const Expr *RE = RS->getRetValue()) {
97e5dd7070Spatrick RE = RE->IgnoreParenCasts();
98e5dd7070Spatrick if (RE == S)
99e5dd7070Spatrick return true;
100e5dd7070Spatrick ParentMap PM(const_cast<Expr *>(RE));
101e5dd7070Spatrick // If 'S' is in the ParentMap, it is a subexpression of
102e5dd7070Spatrick // the return statement.
103e5dd7070Spatrick return PM.getParent(S);
104e5dd7070Spatrick }
105e5dd7070Spatrick }
106e5dd7070Spatrick break;
107e5dd7070Spatrick }
108e5dd7070Spatrick }
109e5dd7070Spatrick // Note also that we are restricting the search for the return statement
110e5dd7070Spatrick // to stop at control-flow; only part of a return statement may be dead,
111e5dd7070Spatrick // without the whole return statement being dead.
112e5dd7070Spatrick if (Current->getTerminator().isTemporaryDtorsBranch()) {
113e5dd7070Spatrick // Temporary destructors have a predictable control flow, thus we want to
114e5dd7070Spatrick // look into the next block for the return statement.
115e5dd7070Spatrick // We look into the false branch, as we know the true branch only contains
116e5dd7070Spatrick // the call to the destructor.
117e5dd7070Spatrick assert(Current->succ_size() == 2);
118e5dd7070Spatrick Current = *(Current->succ_begin() + 1);
119e5dd7070Spatrick } else if (!Current->getTerminatorStmt() && Current->succ_size() == 1) {
120e5dd7070Spatrick // If there is only one successor, we're not dealing with outgoing control
121e5dd7070Spatrick // flow. Thus, look into the next block.
122e5dd7070Spatrick Current = *Current->succ_begin();
123e5dd7070Spatrick if (Current->pred_size() > 1) {
124e5dd7070Spatrick // If there is more than one predecessor, we're dealing with incoming
125e5dd7070Spatrick // control flow - if the return statement is in that block, it might
126e5dd7070Spatrick // well be reachable via a different control flow, thus it's not dead.
127e5dd7070Spatrick return false;
128e5dd7070Spatrick }
129e5dd7070Spatrick } else {
130e5dd7070Spatrick // We hit control flow or a dead end. Stop searching.
131e5dd7070Spatrick return false;
132e5dd7070Spatrick }
133e5dd7070Spatrick }
134e5dd7070Spatrick llvm_unreachable("Broke out of infinite loop.");
135e5dd7070Spatrick }
136e5dd7070Spatrick
getTopMostMacro(SourceLocation Loc,SourceManager & SM)137e5dd7070Spatrick static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM) {
138e5dd7070Spatrick assert(Loc.isMacroID());
139e5dd7070Spatrick SourceLocation Last;
140ec727ea7Spatrick do {
141e5dd7070Spatrick Last = Loc;
142e5dd7070Spatrick Loc = SM.getImmediateMacroCallerLoc(Loc);
143ec727ea7Spatrick } while (Loc.isMacroID());
144e5dd7070Spatrick return Last;
145e5dd7070Spatrick }
146e5dd7070Spatrick
147e5dd7070Spatrick /// Returns true if the statement is expanded from a configuration macro.
isExpandedFromConfigurationMacro(const Stmt * S,Preprocessor & PP,bool IgnoreYES_NO=false)148e5dd7070Spatrick static bool isExpandedFromConfigurationMacro(const Stmt *S,
149e5dd7070Spatrick Preprocessor &PP,
150e5dd7070Spatrick bool IgnoreYES_NO = false) {
151e5dd7070Spatrick // FIXME: This is not very precise. Here we just check to see if the
152e5dd7070Spatrick // value comes from a macro, but we can do much better. This is likely
153e5dd7070Spatrick // to be over conservative. This logic is factored into a separate function
154e5dd7070Spatrick // so that we can refine it later.
155e5dd7070Spatrick SourceLocation L = S->getBeginLoc();
156e5dd7070Spatrick if (L.isMacroID()) {
157e5dd7070Spatrick SourceManager &SM = PP.getSourceManager();
158e5dd7070Spatrick if (IgnoreYES_NO) {
159e5dd7070Spatrick // The Objective-C constant 'YES' and 'NO'
160e5dd7070Spatrick // are defined as macros. Do not treat them
161e5dd7070Spatrick // as configuration values.
162e5dd7070Spatrick SourceLocation TopL = getTopMostMacro(L, SM);
163e5dd7070Spatrick StringRef MacroName = PP.getImmediateMacroName(TopL);
164e5dd7070Spatrick if (MacroName == "YES" || MacroName == "NO")
165e5dd7070Spatrick return false;
166e5dd7070Spatrick } else if (!PP.getLangOpts().CPlusPlus) {
167e5dd7070Spatrick // Do not treat C 'false' and 'true' macros as configuration values.
168e5dd7070Spatrick SourceLocation TopL = getTopMostMacro(L, SM);
169e5dd7070Spatrick StringRef MacroName = PP.getImmediateMacroName(TopL);
170e5dd7070Spatrick if (MacroName == "false" || MacroName == "true")
171e5dd7070Spatrick return false;
172e5dd7070Spatrick }
173e5dd7070Spatrick return true;
174e5dd7070Spatrick }
175e5dd7070Spatrick return false;
176e5dd7070Spatrick }
177e5dd7070Spatrick
178e5dd7070Spatrick static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
179e5dd7070Spatrick
180e5dd7070Spatrick /// Returns true if the statement represents a configuration value.
181e5dd7070Spatrick ///
182e5dd7070Spatrick /// A configuration value is something usually determined at compile-time
183e5dd7070Spatrick /// to conditionally always execute some branch. Such guards are for
184e5dd7070Spatrick /// "sometimes unreachable" code. Such code is usually not interesting
185e5dd7070Spatrick /// to report as unreachable, and may mask truly unreachable code within
186e5dd7070Spatrick /// those blocks.
isConfigurationValue(const Stmt * S,Preprocessor & PP,SourceRange * SilenceableCondVal=nullptr,bool IncludeIntegers=true,bool WrappedInParens=false)187e5dd7070Spatrick static bool isConfigurationValue(const Stmt *S,
188e5dd7070Spatrick Preprocessor &PP,
189e5dd7070Spatrick SourceRange *SilenceableCondVal = nullptr,
190e5dd7070Spatrick bool IncludeIntegers = true,
191e5dd7070Spatrick bool WrappedInParens = false) {
192e5dd7070Spatrick if (!S)
193e5dd7070Spatrick return false;
194e5dd7070Spatrick
195e5dd7070Spatrick if (const auto *Ex = dyn_cast<Expr>(S))
196e5dd7070Spatrick S = Ex->IgnoreImplicit();
197e5dd7070Spatrick
198e5dd7070Spatrick if (const auto *Ex = dyn_cast<Expr>(S))
199e5dd7070Spatrick S = Ex->IgnoreCasts();
200e5dd7070Spatrick
201e5dd7070Spatrick // Special case looking for the sigil '()' around an integer literal.
202e5dd7070Spatrick if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
203e5dd7070Spatrick if (!PE->getBeginLoc().isMacroID())
204e5dd7070Spatrick return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
205e5dd7070Spatrick IncludeIntegers, true);
206e5dd7070Spatrick
207e5dd7070Spatrick if (const Expr *Ex = dyn_cast<Expr>(S))
208e5dd7070Spatrick S = Ex->IgnoreCasts();
209e5dd7070Spatrick
210e5dd7070Spatrick bool IgnoreYES_NO = false;
211e5dd7070Spatrick
212e5dd7070Spatrick switch (S->getStmtClass()) {
213e5dd7070Spatrick case Stmt::CallExprClass: {
214e5dd7070Spatrick const FunctionDecl *Callee =
215e5dd7070Spatrick dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
216e5dd7070Spatrick return Callee ? Callee->isConstexpr() : false;
217e5dd7070Spatrick }
218e5dd7070Spatrick case Stmt::DeclRefExprClass:
219e5dd7070Spatrick return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
220e5dd7070Spatrick case Stmt::ObjCBoolLiteralExprClass:
221e5dd7070Spatrick IgnoreYES_NO = true;
222*12c85518Srobert [[fallthrough]];
223e5dd7070Spatrick case Stmt::CXXBoolLiteralExprClass:
224e5dd7070Spatrick case Stmt::IntegerLiteralClass: {
225e5dd7070Spatrick const Expr *E = cast<Expr>(S);
226e5dd7070Spatrick if (IncludeIntegers) {
227e5dd7070Spatrick if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
228e5dd7070Spatrick *SilenceableCondVal = E->getSourceRange();
229*12c85518Srobert return WrappedInParens ||
230*12c85518Srobert isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
231e5dd7070Spatrick }
232e5dd7070Spatrick return false;
233e5dd7070Spatrick }
234e5dd7070Spatrick case Stmt::MemberExprClass:
235e5dd7070Spatrick return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
236e5dd7070Spatrick case Stmt::UnaryExprOrTypeTraitExprClass:
237e5dd7070Spatrick return true;
238e5dd7070Spatrick case Stmt::BinaryOperatorClass: {
239e5dd7070Spatrick const BinaryOperator *B = cast<BinaryOperator>(S);
240e5dd7070Spatrick // Only include raw integers (not enums) as configuration
241e5dd7070Spatrick // values if they are used in a logical or comparison operator
242e5dd7070Spatrick // (not arithmetic).
243e5dd7070Spatrick IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
244e5dd7070Spatrick return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
245e5dd7070Spatrick IncludeIntegers) ||
246e5dd7070Spatrick isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
247e5dd7070Spatrick IncludeIntegers);
248e5dd7070Spatrick }
249e5dd7070Spatrick case Stmt::UnaryOperatorClass: {
250e5dd7070Spatrick const UnaryOperator *UO = cast<UnaryOperator>(S);
251e5dd7070Spatrick if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
252e5dd7070Spatrick return false;
253e5dd7070Spatrick bool SilenceableCondValNotSet =
254e5dd7070Spatrick SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
255e5dd7070Spatrick bool IsSubExprConfigValue =
256e5dd7070Spatrick isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
257e5dd7070Spatrick IncludeIntegers, WrappedInParens);
258e5dd7070Spatrick // Update the silenceable condition value source range only if the range
259e5dd7070Spatrick // was set directly by the child expression.
260e5dd7070Spatrick if (SilenceableCondValNotSet &&
261e5dd7070Spatrick SilenceableCondVal->getBegin().isValid() &&
262e5dd7070Spatrick *SilenceableCondVal ==
263e5dd7070Spatrick UO->getSubExpr()->IgnoreCasts()->getSourceRange())
264e5dd7070Spatrick *SilenceableCondVal = UO->getSourceRange();
265e5dd7070Spatrick return IsSubExprConfigValue;
266e5dd7070Spatrick }
267e5dd7070Spatrick default:
268e5dd7070Spatrick return false;
269e5dd7070Spatrick }
270e5dd7070Spatrick }
271e5dd7070Spatrick
isConfigurationValue(const ValueDecl * D,Preprocessor & PP)272e5dd7070Spatrick static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
273e5dd7070Spatrick if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
274e5dd7070Spatrick return isConfigurationValue(ED->getInitExpr(), PP);
275e5dd7070Spatrick if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
276e5dd7070Spatrick // As a heuristic, treat globals as configuration values. Note
277e5dd7070Spatrick // that we only will get here if Sema evaluated this
278e5dd7070Spatrick // condition to a constant expression, which means the global
279e5dd7070Spatrick // had to be declared in a way to be a truly constant value.
280e5dd7070Spatrick // We could generalize this to local variables, but it isn't
281e5dd7070Spatrick // clear if those truly represent configuration values that
282e5dd7070Spatrick // gate unreachable code.
283e5dd7070Spatrick if (!VD->hasLocalStorage())
284e5dd7070Spatrick return true;
285e5dd7070Spatrick
286e5dd7070Spatrick // As a heuristic, locals that have been marked 'const' explicitly
287e5dd7070Spatrick // can be treated as configuration values as well.
288e5dd7070Spatrick return VD->getType().isLocalConstQualified();
289e5dd7070Spatrick }
290e5dd7070Spatrick return false;
291e5dd7070Spatrick }
292e5dd7070Spatrick
293e5dd7070Spatrick /// Returns true if we should always explore all successors of a block.
shouldTreatSuccessorsAsReachable(const CFGBlock * B,Preprocessor & PP)294e5dd7070Spatrick static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
295e5dd7070Spatrick Preprocessor &PP) {
296e5dd7070Spatrick if (const Stmt *Term = B->getTerminatorStmt()) {
297e5dd7070Spatrick if (isa<SwitchStmt>(Term))
298e5dd7070Spatrick return true;
299e5dd7070Spatrick // Specially handle '||' and '&&'.
300e5dd7070Spatrick if (isa<BinaryOperator>(Term)) {
301e5dd7070Spatrick return isConfigurationValue(Term, PP);
302e5dd7070Spatrick }
303*12c85518Srobert // Do not treat constexpr if statement successors as unreachable in warnings
304*12c85518Srobert // since the point of these statements is to determine branches at compile
305*12c85518Srobert // time.
306*12c85518Srobert if (const auto *IS = dyn_cast<IfStmt>(Term);
307*12c85518Srobert IS != nullptr && IS->isConstexpr())
308*12c85518Srobert return true;
309e5dd7070Spatrick }
310e5dd7070Spatrick
311e5dd7070Spatrick const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
312e5dd7070Spatrick return isConfigurationValue(Cond, PP);
313e5dd7070Spatrick }
314e5dd7070Spatrick
scanFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable,Preprocessor * PP,bool IncludeSometimesUnreachableEdges)315e5dd7070Spatrick static unsigned scanFromBlock(const CFGBlock *Start,
316e5dd7070Spatrick llvm::BitVector &Reachable,
317e5dd7070Spatrick Preprocessor *PP,
318e5dd7070Spatrick bool IncludeSometimesUnreachableEdges) {
319e5dd7070Spatrick unsigned count = 0;
320e5dd7070Spatrick
321e5dd7070Spatrick // Prep work queue
322e5dd7070Spatrick SmallVector<const CFGBlock*, 32> WL;
323e5dd7070Spatrick
324e5dd7070Spatrick // The entry block may have already been marked reachable
325e5dd7070Spatrick // by the caller.
326e5dd7070Spatrick if (!Reachable[Start->getBlockID()]) {
327e5dd7070Spatrick ++count;
328e5dd7070Spatrick Reachable[Start->getBlockID()] = true;
329e5dd7070Spatrick }
330e5dd7070Spatrick
331e5dd7070Spatrick WL.push_back(Start);
332e5dd7070Spatrick
333e5dd7070Spatrick // Find the reachable blocks from 'Start'.
334e5dd7070Spatrick while (!WL.empty()) {
335e5dd7070Spatrick const CFGBlock *item = WL.pop_back_val();
336e5dd7070Spatrick
337e5dd7070Spatrick // There are cases where we want to treat all successors as reachable.
338e5dd7070Spatrick // The idea is that some "sometimes unreachable" code is not interesting,
339e5dd7070Spatrick // and that we should forge ahead and explore those branches anyway.
340e5dd7070Spatrick // This allows us to potentially uncover some "always unreachable" code
341e5dd7070Spatrick // within the "sometimes unreachable" code.
342e5dd7070Spatrick // Look at the successors and mark then reachable.
343*12c85518Srobert std::optional<bool> TreatAllSuccessorsAsReachable;
344e5dd7070Spatrick if (!IncludeSometimesUnreachableEdges)
345e5dd7070Spatrick TreatAllSuccessorsAsReachable = false;
346e5dd7070Spatrick
347e5dd7070Spatrick for (CFGBlock::const_succ_iterator I = item->succ_begin(),
348e5dd7070Spatrick E = item->succ_end(); I != E; ++I) {
349e5dd7070Spatrick const CFGBlock *B = *I;
350e5dd7070Spatrick if (!B) do {
351e5dd7070Spatrick const CFGBlock *UB = I->getPossiblyUnreachableBlock();
352e5dd7070Spatrick if (!UB)
353e5dd7070Spatrick break;
354e5dd7070Spatrick
355*12c85518Srobert if (!TreatAllSuccessorsAsReachable) {
356e5dd7070Spatrick assert(PP);
357e5dd7070Spatrick TreatAllSuccessorsAsReachable =
358e5dd7070Spatrick shouldTreatSuccessorsAsReachable(item, *PP);
359e5dd7070Spatrick }
360e5dd7070Spatrick
361*12c85518Srobert if (*TreatAllSuccessorsAsReachable) {
362e5dd7070Spatrick B = UB;
363e5dd7070Spatrick break;
364e5dd7070Spatrick }
365e5dd7070Spatrick }
366e5dd7070Spatrick while (false);
367e5dd7070Spatrick
368e5dd7070Spatrick if (B) {
369e5dd7070Spatrick unsigned blockID = B->getBlockID();
370e5dd7070Spatrick if (!Reachable[blockID]) {
371e5dd7070Spatrick Reachable.set(blockID);
372e5dd7070Spatrick WL.push_back(B);
373e5dd7070Spatrick ++count;
374e5dd7070Spatrick }
375e5dd7070Spatrick }
376e5dd7070Spatrick }
377e5dd7070Spatrick }
378e5dd7070Spatrick return count;
379e5dd7070Spatrick }
380e5dd7070Spatrick
scanMaybeReachableFromBlock(const CFGBlock * Start,Preprocessor & PP,llvm::BitVector & Reachable)381e5dd7070Spatrick static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
382e5dd7070Spatrick Preprocessor &PP,
383e5dd7070Spatrick llvm::BitVector &Reachable) {
384e5dd7070Spatrick return scanFromBlock(Start, Reachable, &PP, true);
385e5dd7070Spatrick }
386e5dd7070Spatrick
387e5dd7070Spatrick //===----------------------------------------------------------------------===//
388e5dd7070Spatrick // Dead Code Scanner.
389e5dd7070Spatrick //===----------------------------------------------------------------------===//
390e5dd7070Spatrick
391e5dd7070Spatrick namespace {
392e5dd7070Spatrick class DeadCodeScan {
393e5dd7070Spatrick llvm::BitVector Visited;
394e5dd7070Spatrick llvm::BitVector &Reachable;
395e5dd7070Spatrick SmallVector<const CFGBlock *, 10> WorkList;
396e5dd7070Spatrick Preprocessor &PP;
397e5dd7070Spatrick ASTContext &C;
398e5dd7070Spatrick
399e5dd7070Spatrick typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
400e5dd7070Spatrick DeferredLocsTy;
401e5dd7070Spatrick
402e5dd7070Spatrick DeferredLocsTy DeferredLocs;
403e5dd7070Spatrick
404e5dd7070Spatrick public:
DeadCodeScan(llvm::BitVector & reachable,Preprocessor & PP,ASTContext & C)405e5dd7070Spatrick DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
406e5dd7070Spatrick : Visited(reachable.size()),
407e5dd7070Spatrick Reachable(reachable),
408e5dd7070Spatrick PP(PP), C(C) {}
409e5dd7070Spatrick
410e5dd7070Spatrick void enqueue(const CFGBlock *block);
411e5dd7070Spatrick unsigned scanBackwards(const CFGBlock *Start,
412e5dd7070Spatrick clang::reachable_code::Callback &CB);
413e5dd7070Spatrick
414e5dd7070Spatrick bool isDeadCodeRoot(const CFGBlock *Block);
415e5dd7070Spatrick
416e5dd7070Spatrick const Stmt *findDeadCode(const CFGBlock *Block);
417e5dd7070Spatrick
418e5dd7070Spatrick void reportDeadCode(const CFGBlock *B,
419e5dd7070Spatrick const Stmt *S,
420e5dd7070Spatrick clang::reachable_code::Callback &CB);
421e5dd7070Spatrick };
422e5dd7070Spatrick }
423e5dd7070Spatrick
enqueue(const CFGBlock * block)424e5dd7070Spatrick void DeadCodeScan::enqueue(const CFGBlock *block) {
425e5dd7070Spatrick unsigned blockID = block->getBlockID();
426e5dd7070Spatrick if (Reachable[blockID] || Visited[blockID])
427e5dd7070Spatrick return;
428e5dd7070Spatrick Visited[blockID] = true;
429e5dd7070Spatrick WorkList.push_back(block);
430e5dd7070Spatrick }
431e5dd7070Spatrick
isDeadCodeRoot(const clang::CFGBlock * Block)432e5dd7070Spatrick bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
433e5dd7070Spatrick bool isDeadRoot = true;
434e5dd7070Spatrick
435e5dd7070Spatrick for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
436e5dd7070Spatrick E = Block->pred_end(); I != E; ++I) {
437e5dd7070Spatrick if (const CFGBlock *PredBlock = *I) {
438e5dd7070Spatrick unsigned blockID = PredBlock->getBlockID();
439e5dd7070Spatrick if (Visited[blockID]) {
440e5dd7070Spatrick isDeadRoot = false;
441e5dd7070Spatrick continue;
442e5dd7070Spatrick }
443e5dd7070Spatrick if (!Reachable[blockID]) {
444e5dd7070Spatrick isDeadRoot = false;
445e5dd7070Spatrick Visited[blockID] = true;
446e5dd7070Spatrick WorkList.push_back(PredBlock);
447e5dd7070Spatrick continue;
448e5dd7070Spatrick }
449e5dd7070Spatrick }
450e5dd7070Spatrick }
451e5dd7070Spatrick
452e5dd7070Spatrick return isDeadRoot;
453e5dd7070Spatrick }
454e5dd7070Spatrick
isValidDeadStmt(const Stmt * S)455e5dd7070Spatrick static bool isValidDeadStmt(const Stmt *S) {
456e5dd7070Spatrick if (S->getBeginLoc().isInvalid())
457e5dd7070Spatrick return false;
458e5dd7070Spatrick if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
459e5dd7070Spatrick return BO->getOpcode() != BO_Comma;
460e5dd7070Spatrick return true;
461e5dd7070Spatrick }
462e5dd7070Spatrick
findDeadCode(const clang::CFGBlock * Block)463e5dd7070Spatrick const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
464e5dd7070Spatrick for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
465*12c85518Srobert if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
466e5dd7070Spatrick const Stmt *S = CS->getStmt();
467e5dd7070Spatrick if (isValidDeadStmt(S))
468e5dd7070Spatrick return S;
469e5dd7070Spatrick }
470e5dd7070Spatrick
471e5dd7070Spatrick CFGTerminator T = Block->getTerminator();
472e5dd7070Spatrick if (T.isStmtBranch()) {
473e5dd7070Spatrick const Stmt *S = T.getStmt();
474e5dd7070Spatrick if (S && isValidDeadStmt(S))
475e5dd7070Spatrick return S;
476e5dd7070Spatrick }
477e5dd7070Spatrick
478e5dd7070Spatrick return nullptr;
479e5dd7070Spatrick }
480e5dd7070Spatrick
SrcCmp(const std::pair<const CFGBlock *,const Stmt * > * p1,const std::pair<const CFGBlock *,const Stmt * > * p2)481e5dd7070Spatrick static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
482e5dd7070Spatrick const std::pair<const CFGBlock *, const Stmt *> *p2) {
483e5dd7070Spatrick if (p1->second->getBeginLoc() < p2->second->getBeginLoc())
484e5dd7070Spatrick return -1;
485e5dd7070Spatrick if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
486e5dd7070Spatrick return 1;
487e5dd7070Spatrick return 0;
488e5dd7070Spatrick }
489e5dd7070Spatrick
scanBackwards(const clang::CFGBlock * Start,clang::reachable_code::Callback & CB)490e5dd7070Spatrick unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
491e5dd7070Spatrick clang::reachable_code::Callback &CB) {
492e5dd7070Spatrick
493e5dd7070Spatrick unsigned count = 0;
494e5dd7070Spatrick enqueue(Start);
495e5dd7070Spatrick
496e5dd7070Spatrick while (!WorkList.empty()) {
497e5dd7070Spatrick const CFGBlock *Block = WorkList.pop_back_val();
498e5dd7070Spatrick
499e5dd7070Spatrick // It is possible that this block has been marked reachable after
500e5dd7070Spatrick // it was enqueued.
501e5dd7070Spatrick if (Reachable[Block->getBlockID()])
502e5dd7070Spatrick continue;
503e5dd7070Spatrick
504e5dd7070Spatrick // Look for any dead code within the block.
505e5dd7070Spatrick const Stmt *S = findDeadCode(Block);
506e5dd7070Spatrick
507e5dd7070Spatrick if (!S) {
508e5dd7070Spatrick // No dead code. Possibly an empty block. Look at dead predecessors.
509e5dd7070Spatrick for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
510e5dd7070Spatrick E = Block->pred_end(); I != E; ++I) {
511e5dd7070Spatrick if (const CFGBlock *predBlock = *I)
512e5dd7070Spatrick enqueue(predBlock);
513e5dd7070Spatrick }
514e5dd7070Spatrick continue;
515e5dd7070Spatrick }
516e5dd7070Spatrick
517e5dd7070Spatrick // Specially handle macro-expanded code.
518e5dd7070Spatrick if (S->getBeginLoc().isMacroID()) {
519e5dd7070Spatrick count += scanMaybeReachableFromBlock(Block, PP, Reachable);
520e5dd7070Spatrick continue;
521e5dd7070Spatrick }
522e5dd7070Spatrick
523e5dd7070Spatrick if (isDeadCodeRoot(Block)) {
524e5dd7070Spatrick reportDeadCode(Block, S, CB);
525e5dd7070Spatrick count += scanMaybeReachableFromBlock(Block, PP, Reachable);
526e5dd7070Spatrick }
527e5dd7070Spatrick else {
528e5dd7070Spatrick // Record this statement as the possibly best location in a
529e5dd7070Spatrick // strongly-connected component of dead code for emitting a
530e5dd7070Spatrick // warning.
531e5dd7070Spatrick DeferredLocs.push_back(std::make_pair(Block, S));
532e5dd7070Spatrick }
533e5dd7070Spatrick }
534e5dd7070Spatrick
535e5dd7070Spatrick // If we didn't find a dead root, then report the dead code with the
536e5dd7070Spatrick // earliest location.
537e5dd7070Spatrick if (!DeferredLocs.empty()) {
538e5dd7070Spatrick llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
539*12c85518Srobert for (const auto &I : DeferredLocs) {
540*12c85518Srobert const CFGBlock *Block = I.first;
541e5dd7070Spatrick if (Reachable[Block->getBlockID()])
542e5dd7070Spatrick continue;
543*12c85518Srobert reportDeadCode(Block, I.second, CB);
544e5dd7070Spatrick count += scanMaybeReachableFromBlock(Block, PP, Reachable);
545e5dd7070Spatrick }
546e5dd7070Spatrick }
547e5dd7070Spatrick
548e5dd7070Spatrick return count;
549e5dd7070Spatrick }
550e5dd7070Spatrick
GetUnreachableLoc(const Stmt * S,SourceRange & R1,SourceRange & R2)551e5dd7070Spatrick static SourceLocation GetUnreachableLoc(const Stmt *S,
552e5dd7070Spatrick SourceRange &R1,
553e5dd7070Spatrick SourceRange &R2) {
554e5dd7070Spatrick R1 = R2 = SourceRange();
555e5dd7070Spatrick
556e5dd7070Spatrick if (const Expr *Ex = dyn_cast<Expr>(S))
557e5dd7070Spatrick S = Ex->IgnoreParenImpCasts();
558e5dd7070Spatrick
559e5dd7070Spatrick switch (S->getStmtClass()) {
560e5dd7070Spatrick case Expr::BinaryOperatorClass: {
561e5dd7070Spatrick const BinaryOperator *BO = cast<BinaryOperator>(S);
562e5dd7070Spatrick return BO->getOperatorLoc();
563e5dd7070Spatrick }
564e5dd7070Spatrick case Expr::UnaryOperatorClass: {
565e5dd7070Spatrick const UnaryOperator *UO = cast<UnaryOperator>(S);
566e5dd7070Spatrick R1 = UO->getSubExpr()->getSourceRange();
567e5dd7070Spatrick return UO->getOperatorLoc();
568e5dd7070Spatrick }
569e5dd7070Spatrick case Expr::CompoundAssignOperatorClass: {
570e5dd7070Spatrick const CompoundAssignOperator *CAO = cast<CompoundAssignOperator>(S);
571e5dd7070Spatrick R1 = CAO->getLHS()->getSourceRange();
572e5dd7070Spatrick R2 = CAO->getRHS()->getSourceRange();
573e5dd7070Spatrick return CAO->getOperatorLoc();
574e5dd7070Spatrick }
575e5dd7070Spatrick case Expr::BinaryConditionalOperatorClass:
576e5dd7070Spatrick case Expr::ConditionalOperatorClass: {
577e5dd7070Spatrick const AbstractConditionalOperator *CO =
578e5dd7070Spatrick cast<AbstractConditionalOperator>(S);
579e5dd7070Spatrick return CO->getQuestionLoc();
580e5dd7070Spatrick }
581e5dd7070Spatrick case Expr::MemberExprClass: {
582e5dd7070Spatrick const MemberExpr *ME = cast<MemberExpr>(S);
583e5dd7070Spatrick R1 = ME->getSourceRange();
584e5dd7070Spatrick return ME->getMemberLoc();
585e5dd7070Spatrick }
586e5dd7070Spatrick case Expr::ArraySubscriptExprClass: {
587e5dd7070Spatrick const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(S);
588e5dd7070Spatrick R1 = ASE->getLHS()->getSourceRange();
589e5dd7070Spatrick R2 = ASE->getRHS()->getSourceRange();
590e5dd7070Spatrick return ASE->getRBracketLoc();
591e5dd7070Spatrick }
592e5dd7070Spatrick case Expr::CStyleCastExprClass: {
593e5dd7070Spatrick const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
594e5dd7070Spatrick R1 = CSC->getSubExpr()->getSourceRange();
595e5dd7070Spatrick return CSC->getLParenLoc();
596e5dd7070Spatrick }
597e5dd7070Spatrick case Expr::CXXFunctionalCastExprClass: {
598e5dd7070Spatrick const CXXFunctionalCastExpr *CE = cast <CXXFunctionalCastExpr>(S);
599e5dd7070Spatrick R1 = CE->getSubExpr()->getSourceRange();
600e5dd7070Spatrick return CE->getBeginLoc();
601e5dd7070Spatrick }
602e5dd7070Spatrick case Stmt::CXXTryStmtClass: {
603e5dd7070Spatrick return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
604e5dd7070Spatrick }
605e5dd7070Spatrick case Expr::ObjCBridgedCastExprClass: {
606e5dd7070Spatrick const ObjCBridgedCastExpr *CSC = cast<ObjCBridgedCastExpr>(S);
607e5dd7070Spatrick R1 = CSC->getSubExpr()->getSourceRange();
608e5dd7070Spatrick return CSC->getLParenLoc();
609e5dd7070Spatrick }
610e5dd7070Spatrick default: ;
611e5dd7070Spatrick }
612e5dd7070Spatrick R1 = S->getSourceRange();
613e5dd7070Spatrick return S->getBeginLoc();
614e5dd7070Spatrick }
615e5dd7070Spatrick
reportDeadCode(const CFGBlock * B,const Stmt * S,clang::reachable_code::Callback & CB)616e5dd7070Spatrick void DeadCodeScan::reportDeadCode(const CFGBlock *B,
617e5dd7070Spatrick const Stmt *S,
618e5dd7070Spatrick clang::reachable_code::Callback &CB) {
619e5dd7070Spatrick // Classify the unreachable code found, or suppress it in some cases.
620e5dd7070Spatrick reachable_code::UnreachableKind UK = reachable_code::UK_Other;
621e5dd7070Spatrick
622e5dd7070Spatrick if (isa<BreakStmt>(S)) {
623e5dd7070Spatrick UK = reachable_code::UK_Break;
624e5dd7070Spatrick } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
625e5dd7070Spatrick isBuiltinAssumeFalse(B, S, C)) {
626e5dd7070Spatrick return;
627e5dd7070Spatrick }
628e5dd7070Spatrick else if (isDeadReturn(B, S)) {
629e5dd7070Spatrick UK = reachable_code::UK_Return;
630e5dd7070Spatrick }
631e5dd7070Spatrick
632e5dd7070Spatrick SourceRange SilenceableCondVal;
633e5dd7070Spatrick
634e5dd7070Spatrick if (UK == reachable_code::UK_Other) {
635e5dd7070Spatrick // Check if the dead code is part of the "loop target" of
636e5dd7070Spatrick // a for/for-range loop. This is the block that contains
637e5dd7070Spatrick // the increment code.
638e5dd7070Spatrick if (const Stmt *LoopTarget = B->getLoopTarget()) {
639e5dd7070Spatrick SourceLocation Loc = LoopTarget->getBeginLoc();
640e5dd7070Spatrick SourceRange R1(Loc, Loc), R2;
641e5dd7070Spatrick
642e5dd7070Spatrick if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
643e5dd7070Spatrick const Expr *Inc = FS->getInc();
644e5dd7070Spatrick Loc = Inc->getBeginLoc();
645e5dd7070Spatrick R2 = Inc->getSourceRange();
646e5dd7070Spatrick }
647e5dd7070Spatrick
648e5dd7070Spatrick CB.HandleUnreachable(reachable_code::UK_Loop_Increment,
649e5dd7070Spatrick Loc, SourceRange(), SourceRange(Loc, Loc), R2);
650e5dd7070Spatrick return;
651e5dd7070Spatrick }
652e5dd7070Spatrick
653e5dd7070Spatrick // Check if the dead block has a predecessor whose branch has
654e5dd7070Spatrick // a configuration value that *could* be modified to
655e5dd7070Spatrick // silence the warning.
656e5dd7070Spatrick CFGBlock::const_pred_iterator PI = B->pred_begin();
657e5dd7070Spatrick if (PI != B->pred_end()) {
658e5dd7070Spatrick if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
659e5dd7070Spatrick const Stmt *TermCond =
660e5dd7070Spatrick PredBlock->getTerminatorCondition(/* strip parens */ false);
661e5dd7070Spatrick isConfigurationValue(TermCond, PP, &SilenceableCondVal);
662e5dd7070Spatrick }
663e5dd7070Spatrick }
664e5dd7070Spatrick }
665e5dd7070Spatrick
666e5dd7070Spatrick SourceRange R1, R2;
667e5dd7070Spatrick SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
668e5dd7070Spatrick CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2);
669e5dd7070Spatrick }
670e5dd7070Spatrick
671e5dd7070Spatrick //===----------------------------------------------------------------------===//
672e5dd7070Spatrick // Reachability APIs.
673e5dd7070Spatrick //===----------------------------------------------------------------------===//
674e5dd7070Spatrick
675e5dd7070Spatrick namespace clang { namespace reachable_code {
676e5dd7070Spatrick
anchor()677e5dd7070Spatrick void Callback::anchor() { }
678e5dd7070Spatrick
ScanReachableFromBlock(const CFGBlock * Start,llvm::BitVector & Reachable)679e5dd7070Spatrick unsigned ScanReachableFromBlock(const CFGBlock *Start,
680e5dd7070Spatrick llvm::BitVector &Reachable) {
681e5dd7070Spatrick return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
682e5dd7070Spatrick }
683e5dd7070Spatrick
FindUnreachableCode(AnalysisDeclContext & AC,Preprocessor & PP,Callback & CB)684e5dd7070Spatrick void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
685e5dd7070Spatrick Callback &CB) {
686e5dd7070Spatrick
687e5dd7070Spatrick CFG *cfg = AC.getCFG();
688e5dd7070Spatrick if (!cfg)
689e5dd7070Spatrick return;
690e5dd7070Spatrick
691e5dd7070Spatrick // Scan for reachable blocks from the entrance of the CFG.
692e5dd7070Spatrick // If there are no unreachable blocks, we're done.
693e5dd7070Spatrick llvm::BitVector reachable(cfg->getNumBlockIDs());
694e5dd7070Spatrick unsigned numReachable =
695e5dd7070Spatrick scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
696e5dd7070Spatrick if (numReachable == cfg->getNumBlockIDs())
697e5dd7070Spatrick return;
698e5dd7070Spatrick
699e5dd7070Spatrick // If there aren't explicit EH edges, we should include the 'try' dispatch
700e5dd7070Spatrick // blocks as roots.
701e5dd7070Spatrick if (!AC.getCFGBuildOptions().AddEHEdges) {
702*12c85518Srobert for (const CFGBlock *B : cfg->try_blocks())
703*12c85518Srobert numReachable += scanMaybeReachableFromBlock(B, PP, reachable);
704e5dd7070Spatrick if (numReachable == cfg->getNumBlockIDs())
705e5dd7070Spatrick return;
706e5dd7070Spatrick }
707e5dd7070Spatrick
708e5dd7070Spatrick // There are some unreachable blocks. We need to find the root blocks that
709e5dd7070Spatrick // contain code that should be considered unreachable.
710*12c85518Srobert for (const CFGBlock *block : *cfg) {
711e5dd7070Spatrick // A block may have been marked reachable during this loop.
712e5dd7070Spatrick if (reachable[block->getBlockID()])
713e5dd7070Spatrick continue;
714e5dd7070Spatrick
715e5dd7070Spatrick DeadCodeScan DS(reachable, PP, AC.getASTContext());
716e5dd7070Spatrick numReachable += DS.scanBackwards(block, CB);
717e5dd7070Spatrick
718e5dd7070Spatrick if (numReachable == cfg->getNumBlockIDs())
719e5dd7070Spatrick return;
720e5dd7070Spatrick }
721e5dd7070Spatrick }
722e5dd7070Spatrick
723e5dd7070Spatrick }} // end namespace clang::reachable_code
724