annotate clang/lib/Analysis/ReachableCode.cpp @ 222:81f6424ef0e3 llvm-original

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