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