clang 24.0.0git
ReachableCode.cpp
Go to the documentation of this file.
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
15#include "clang/AST/Attr.h"
17#include "clang/AST/Expr.h"
18#include "clang/AST/ExprCXX.h"
19#include "clang/AST/ExprObjC.h"
20#include "clang/AST/ParentMap.h"
21#include "clang/AST/StmtCXX.h"
23#include "clang/Analysis/CFG.h"
27#include "llvm/ADT/BitVector.h"
28#include <optional>
29
30using namespace clang;
31
32//===----------------------------------------------------------------------===//
33// Core Reachability Analysis routines.
34//===----------------------------------------------------------------------===//
35
36static bool isEnumConstant(const Expr *Ex) {
37 const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex);
38 if (!DR)
39 return false;
40 return isa<EnumConstantDecl>(DR->getDecl());
41}
42
43static bool isTrivialExpression(const Expr *Ex) {
44 Ex = Ex->IgnoreParenCasts();
45 return isa<IntegerLiteral>(Ex) || isa<StringLiteral>(Ex) ||
49}
50
51static 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 if (const Stmt *Term = B->getTerminatorStmt()) {
55 if (const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
56 const Expr *Cond = DS->getCond()->IgnoreParenCasts();
57 return Cond == S && isTrivialExpression(Cond);
58 }
59 }
60 return false;
61}
62
63static bool isBuiltinUnreachable(const Stmt *S) {
64 if (const auto *DRE = dyn_cast<DeclRefExpr>(S))
65 if (const auto *FDecl = dyn_cast<FunctionDecl>(DRE->getDecl()))
66 return FDecl->getIdentifier() &&
67 FDecl->getBuiltinID() == Builtin::BI__builtin_unreachable;
68 return false;
69}
70
71static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
72 ASTContext &C) {
73 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 return false;
77 }
78 if (std::optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
79 if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
80 return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
81 }
82 }
83 return false;
84}
85
86static 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 const CFGBlock *Current = B;
91 while (true) {
92 for (const CFGElement &CE : llvm::reverse(*Current)) {
93 if (std::optional<CFGStmt> CS = CE.getAs<CFGStmt>()) {
94 if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(CS->getStmt())) {
95 if (RS == S)
96 return true;
97 if (const Expr *RE = RS->getRetValue()) {
98 RE = RE->IgnoreParenCasts();
99 if (RE == S)
100 return true;
101 ParentMap PM(const_cast<Expr *>(RE));
102 // If 'S' is in the ParentMap, it is a subexpression of
103 // the return statement.
104 return PM.getParent(S);
105 }
106 }
107 break;
108 }
109 }
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 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 assert(Current->succ_size() == 2);
119 Current = *(Current->succ_begin() + 1);
120 } 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 Current = *Current->succ_begin();
124 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 return false;
129 }
130 } else {
131 // We hit control flow or a dead end. Stop searching.
132 return false;
133 }
134 }
135 llvm_unreachable("Broke out of infinite loop.");
136}
137
139 assert(Loc.isMacroID());
141 do {
142 Last = Loc;
143 Loc = SM.getImmediateMacroCallerLoc(Loc);
144 } while (Loc.isMacroID());
145 return Last;
146}
147
148/// Returns true if the statement is expanded from a configuration macro.
150 Preprocessor &PP,
151 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.
157 if (L.isMacroID()) {
159 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 SourceLocation TopL = getTopMostMacro(L, SM);
164 StringRef MacroName = PP.getImmediateMacroName(TopL);
165 if (MacroName == "YES" || MacroName == "NO")
166 return false;
167 } else if (!PP.getLangOpts().CPlusPlus) {
168 // Do not treat C 'false' and 'true' macros as configuration values.
169 SourceLocation TopL = getTopMostMacro(L, SM);
170 StringRef MacroName = PP.getImmediateMacroName(TopL);
171 if (MacroName == "false" || MacroName == "true")
172 return false;
173 }
174 return true;
175 }
176 return false;
177}
178
179static 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.
188static bool isConfigurationValue(const Stmt *S,
189 Preprocessor &PP,
190 SourceRange *SilenceableCondVal = nullptr,
191 bool IncludeIntegers = true,
192 bool WrappedInParens = false) {
193 if (!S)
194 return false;
195
196 if (const auto *Ex = dyn_cast<Expr>(S))
197 S = Ex->IgnoreImplicit();
198
199 if (const auto *Ex = dyn_cast<Expr>(S))
200 S = Ex->IgnoreCasts();
201
202 // Special case looking for the sigil '()' around an integer literal.
203 if (const ParenExpr *PE = dyn_cast<ParenExpr>(S))
204 if (!PE->getBeginLoc().isMacroID())
205 return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal,
206 IncludeIntegers, true);
207
208 if (const Expr *Ex = dyn_cast<Expr>(S))
209 S = Ex->IgnoreCasts();
210
211 bool IgnoreYES_NO = false;
212
213 switch (S->getStmtClass()) {
214 case Stmt::CallExprClass: {
215 const FunctionDecl *Callee =
216 dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
217 return Callee ? Callee->isConstexpr() : false;
218 }
219 case Stmt::DeclRefExprClass:
220 return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
221 case Stmt::ObjCBoolLiteralExprClass:
222 IgnoreYES_NO = true;
223 [[fallthrough]];
224 case Stmt::CXXBoolLiteralExprClass:
225 case Stmt::IntegerLiteralClass: {
226 const Expr *E = cast<Expr>(S);
227 if (IncludeIntegers) {
228 if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
229 *SilenceableCondVal = E->getSourceRange();
230 return WrappedInParens ||
231 isExpandedFromConfigurationMacro(E, PP, IgnoreYES_NO);
232 }
233 return false;
234 }
235 case Stmt::MemberExprClass:
236 return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
237 case Stmt::UnaryExprOrTypeTraitExprClass:
238 return true;
239 case Stmt::BinaryOperatorClass: {
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 IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
245 return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal,
246 IncludeIntegers) ||
247 isConfigurationValue(B->getRHS(), PP, SilenceableCondVal,
248 IncludeIntegers);
249 }
250 case Stmt::UnaryOperatorClass: {
251 const UnaryOperator *UO = cast<UnaryOperator>(S);
252 if (UO->getOpcode() != UO_LNot && UO->getOpcode() != UO_Minus)
253 return false;
254 bool SilenceableCondValNotSet =
255 SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
256 bool IsSubExprConfigValue =
257 isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal,
258 IncludeIntegers, WrappedInParens);
259 // Update the silenceable condition value source range only if the range
260 // was set directly by the child expression.
261 if (SilenceableCondValNotSet &&
262 SilenceableCondVal->getBegin().isValid() &&
263 *SilenceableCondVal ==
265 *SilenceableCondVal = UO->getSourceRange();
266 return IsSubExprConfigValue;
267 }
268 default:
269 return false;
270 }
271}
272
273static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
274 if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
275 return isConfigurationValue(ED->getInitExpr(), PP);
276 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 if (!VD->hasLocalStorage())
285 return true;
286
287 // As a heuristic, locals that have been marked 'const' explicitly
288 // can be treated as configuration values as well.
289 return VD->getType().isLocalConstQualified();
290 }
291 return false;
292}
293
294/// Returns true if we should always explore all successors of a block.
296 Preprocessor &PP) {
297 if (const Stmt *Term = B->getTerminatorStmt()) {
298 if (isa<SwitchStmt>(Term))
299 return true;
300 // Specially handle '||' and '&&'.
301 if (isa<BinaryOperator>(Term)) {
302 return isConfigurationValue(Term, PP);
303 }
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 if (const auto *IS = dyn_cast<IfStmt>(Term);
308 IS != nullptr && IS->isConstexpr())
309 return true;
310 }
311
312 const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false);
313 return isConfigurationValue(Cond, PP);
314}
315
316static unsigned scanFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable,
317 Preprocessor *PP,
318 bool IncludeSometimesUnreachableEdges,
319 bool TreatAnalyzerNoReturnAsReturning = false) {
320 unsigned count = 0;
321
322 // Prep work queue
324
325 // The entry block may have already been marked reachable
326 // by the caller.
327 if (!Reachable[Start->getBlockID()]) {
328 ++count;
329 Reachable[Start->getBlockID()] = true;
330 }
331
332 WL.push_back(Start);
333
334 auto MarkReachable = [&](const CFGBlock *B) {
335 unsigned blockID = B->getBlockID();
336 if (!Reachable[blockID]) {
337 Reachable.set(blockID);
338 WL.push_back(B);
339 ++count;
340 }
341 };
342
343 // Find the reachable blocks from 'Start'.
344 while (!WL.empty()) {
345 const CFGBlock *item = WL.pop_back_val();
346
347 // There are cases where we want to treat all successors as reachable.
348 // The idea is that some "sometimes unreachable" code is not interesting,
349 // and that we should forge ahead and explore those branches anyway.
350 // This allows us to potentially uncover some "always unreachable" code
351 // within the "sometimes unreachable" code.
352 // Look at the successors and mark then reachable.
353 std::optional<bool> TreatAllSuccessorsAsReachable;
354 if (!IncludeSometimesUnreachableEdges)
355 TreatAllSuccessorsAsReachable = false;
356
357 // Some callers need to distinguish 'analyzer_noreturn' calls from
358 // 'noreturn' calls, since the code after an 'analyzer_noreturn' call isn't
359 // dead. For those callers (TreatAnalyzerNoReturnAsReturning is true),
360 // continue with the code that follows the call, which the CFG keeps as the
361 // alternate successor of the exit edge.
362 bool FollowAlternate = TreatAnalyzerNoReturnAsReturning &&
364
366 E = item->succ_end(); I != E; ++I) {
367 const CFGBlock *B = *I;
368 if (FollowAlternate) {
369 if (const CFGBlock *Alt = I->getPossiblyUnreachableBlock())
370 MarkReachable(Alt);
371 }
372 if (!B) do {
373 const CFGBlock *UB = I->getPossiblyUnreachableBlock();
374 if (!UB)
375 break;
376
377 if (!TreatAllSuccessorsAsReachable) {
378 assert(PP);
379 TreatAllSuccessorsAsReachable =
381 }
382
383 if (*TreatAllSuccessorsAsReachable) {
384 B = UB;
385 break;
386 }
387 }
388 while (false);
389
390 if (B)
391 MarkReachable(B);
392 }
393 }
394 return count;
395}
396
397static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start,
398 Preprocessor &PP,
399 llvm::BitVector &Reachable) {
400 return scanFromBlock(Start, Reachable, &PP, true,
401 /*TreatAnalyzerNoReturnAsReturning=*/true);
402}
403
404//===----------------------------------------------------------------------===//
405// Dead Code Scanner.
406//===----------------------------------------------------------------------===//
407
408namespace {
409 class DeadCodeScan {
410 llvm::BitVector Visited;
411 llvm::BitVector &Reachable;
412 SmallVector<const CFGBlock *, 10> WorkList;
413 Preprocessor &PP;
414 ASTContext &C;
415
416 typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
417 DeferredLocsTy;
418
419 DeferredLocsTy DeferredLocs;
420
421 public:
422 DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
423 : Visited(reachable.size()),
424 Reachable(reachable),
425 PP(PP), C(C) {}
426
427 void enqueue(const CFGBlock *block);
428 unsigned scanBackwards(const CFGBlock *Start,
429 clang::reachable_code::Callback &CB);
430
431 bool isDeadCodeRoot(const CFGBlock *Block);
432
433 const Stmt *findDeadCode(const CFGBlock *Block);
434
435 void reportDeadCode(const CFGBlock *B,
436 const Stmt *S,
437 clang::reachable_code::Callback &CB);
438 };
439}
440
441void DeadCodeScan::enqueue(const CFGBlock *block) {
442 unsigned blockID = block->getBlockID();
443 if (Reachable[blockID] || Visited[blockID])
444 return;
445 Visited[blockID] = true;
446 WorkList.push_back(block);
447}
448
449bool DeadCodeScan::isDeadCodeRoot(const clang::CFGBlock *Block) {
450 bool isDeadRoot = true;
451
452 for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
453 E = Block->pred_end(); I != E; ++I) {
454 if (const CFGBlock *PredBlock = *I) {
455 unsigned blockID = PredBlock->getBlockID();
456 if (Visited[blockID]) {
457 isDeadRoot = false;
458 continue;
459 }
460 if (!Reachable[blockID]) {
461 isDeadRoot = false;
462 Visited[blockID] = true;
463 WorkList.push_back(PredBlock);
464 continue;
465 }
466 }
467 }
468
469 return isDeadRoot;
470}
471
472// Check if the given `DeadStmt` is a coroutine statement and is a substmt of
473// the coroutine statement. `Block` is the CFGBlock containing the `DeadStmt`.
474static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block) {
475 // The coroutine statement, co_return, co_await, or co_yield.
476 const Stmt *CoroStmt = nullptr;
477 // Find the first coroutine statement after the DeadStmt in the block.
478 bool AfterDeadStmt = false;
479 for (const CFGElement &Elem : *Block)
480 if (std::optional<CFGStmt> CS = Elem.getAs<CFGStmt>()) {
481 const Stmt *S = CS->getStmt();
482 if (S == DeadStmt)
483 AfterDeadStmt = true;
484 if (AfterDeadStmt &&
485 // For simplicity, we only check simple coroutine statements.
486 (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
487 CoroStmt = S;
488 break;
489 }
490 }
491 if (!CoroStmt)
492 return false;
493 struct Checker : DynamicRecursiveASTVisitor {
494 const Stmt *DeadStmt;
495 bool CoroutineSubStmt = false;
496 Checker(const Stmt *S) : DeadStmt(S) {
497 // Statements captured in the CFG can be implicit.
498 ShouldVisitImplicitCode = true;
499 }
500
501 bool VisitStmt(Stmt *S) override {
502 if (S == DeadStmt)
503 CoroutineSubStmt = true;
504 return true;
505 }
506 };
507 Checker checker(DeadStmt);
508 checker.TraverseStmt(const_cast<Stmt *>(CoroStmt));
509 return checker.CoroutineSubStmt;
510}
511
512static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block) {
513 if (S->getBeginLoc().isInvalid())
514 return false;
515 if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(S))
516 return BO->getOpcode() != BO_Comma;
517 // Coroutine statements are never considered dead statements, because removing
518 // them may change the function semantic if it is the only coroutine statement
519 // of the coroutine.
520 return !isInCoroutineStmt(S, Block);
521}
522
523const Stmt *DeadCodeScan::findDeadCode(const clang::CFGBlock *Block) {
524 for (CFGBlock::const_iterator I = Block->begin(), E = Block->end(); I!=E; ++I)
525 if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
526 const Stmt *S = CS->getStmt();
527 if (isValidDeadStmt(S, Block))
528 return S;
529 }
530
531 CFGTerminator T = Block->getTerminator();
532 if (T.isStmtBranch()) {
533 const Stmt *S = T.getStmt();
534 if (S && isValidDeadStmt(S, Block))
535 return S;
536 }
537
538 return nullptr;
539}
540
541static int SrcCmp(const std::pair<const CFGBlock *, const Stmt *> *p1,
542 const std::pair<const CFGBlock *, const Stmt *> *p2) {
543 if (p1->second->getBeginLoc() < p2->second->getBeginLoc())
544 return -1;
545 if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
546 return 1;
547 return 0;
548}
549
550unsigned DeadCodeScan::scanBackwards(const clang::CFGBlock *Start,
551 clang::reachable_code::Callback &CB) {
552
553 unsigned count = 0;
554 enqueue(Start);
555
556 while (!WorkList.empty()) {
557 const CFGBlock *Block = WorkList.pop_back_val();
558
559 // It is possible that this block has been marked reachable after
560 // it was enqueued.
561 if (Reachable[Block->getBlockID()])
562 continue;
563
564 // Look for any dead code within the block.
565 const Stmt *S = findDeadCode(Block);
566
567 if (!S) {
568 // No dead code. Possibly an empty block. Look at dead predecessors.
569 for (CFGBlock::const_pred_iterator I = Block->pred_begin(),
570 E = Block->pred_end(); I != E; ++I) {
571 if (const CFGBlock *predBlock = *I)
572 enqueue(predBlock);
573 }
574 continue;
575 }
576
577 // Specially handle macro-expanded code.
578 if (S->getBeginLoc().isMacroID()) {
579 count += scanMaybeReachableFromBlock(Block, PP, Reachable);
580 continue;
581 }
582
583 if (isDeadCodeRoot(Block)) {
584 reportDeadCode(Block, S, CB);
585 count += scanMaybeReachableFromBlock(Block, PP, Reachable);
586 }
587 else {
588 // Record this statement as the possibly best location in a
589 // strongly-connected component of dead code for emitting a
590 // warning.
591 DeferredLocs.push_back(std::make_pair(Block, S));
592 }
593 }
594
595 // If we didn't find a dead root, then report the dead code with the
596 // earliest location.
597 if (!DeferredLocs.empty()) {
598 llvm::array_pod_sort(DeferredLocs.begin(), DeferredLocs.end(), SrcCmp);
599 for (const auto &I : DeferredLocs) {
600 const CFGBlock *Block = I.first;
601 if (Reachable[Block->getBlockID()])
602 continue;
603 reportDeadCode(Block, I.second, CB);
604 count += scanMaybeReachableFromBlock(Block, PP, Reachable);
605 }
606 }
607
608 return count;
609}
610
612 SourceRange &R1,
613 SourceRange &R2) {
614 R1 = R2 = SourceRange();
615
616 if (const Expr *Ex = dyn_cast<Expr>(S))
617 S = Ex->IgnoreParenImpCasts();
618
619 switch (S->getStmtClass()) {
620 case Expr::BinaryOperatorClass: {
622 return BO->getOperatorLoc();
623 }
624 case Expr::UnaryOperatorClass: {
625 const UnaryOperator *UO = cast<UnaryOperator>(S);
626 R1 = UO->getSubExpr()->getSourceRange();
627 return UO->getOperatorLoc();
628 }
629 case Expr::CompoundAssignOperatorClass: {
631 R1 = CAO->getLHS()->getSourceRange();
632 R2 = CAO->getRHS()->getSourceRange();
633 return CAO->getOperatorLoc();
634 }
635 case Expr::BinaryConditionalOperatorClass:
636 case Expr::ConditionalOperatorClass: {
639 return CO->getQuestionLoc();
640 }
641 case Expr::MemberExprClass: {
642 const MemberExpr *ME = cast<MemberExpr>(S);
643 R1 = ME->getSourceRange();
644 return ME->getMemberLoc();
645 }
646 case Expr::ArraySubscriptExprClass: {
648 R1 = ASE->getLHS()->getSourceRange();
649 R2 = ASE->getRHS()->getSourceRange();
650 return ASE->getRBracketLoc();
651 }
652 case Expr::CStyleCastExprClass: {
653 const CStyleCastExpr *CSC = cast<CStyleCastExpr>(S);
654 R1 = CSC->getSubExpr()->getSourceRange();
655 return CSC->getLParenLoc();
656 }
657 case Expr::CXXFunctionalCastExprClass: {
659 R1 = CE->getSubExpr()->getSourceRange();
660 return CE->getBeginLoc();
661 }
662 case Stmt::CXXTryStmtClass: {
663 return cast<CXXTryStmt>(S)->getHandler(0)->getCatchLoc();
664 }
665 case Expr::ObjCBridgedCastExprClass: {
667 R1 = CSC->getSubExpr()->getSourceRange();
668 return CSC->getLParenLoc();
669 }
670 default: ;
671 }
672 R1 = S->getSourceRange();
673 return S->getBeginLoc();
674}
675
676void DeadCodeScan::reportDeadCode(const CFGBlock *B,
677 const Stmt *S,
678 clang::reachable_code::Callback &CB) {
679 // Classify the unreachable code found, or suppress it in some cases.
681
682 if (isa<BreakStmt>(S)) {
684 } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
685 isBuiltinAssumeFalse(B, S, C)) {
686 return;
687 }
688 else if (isDeadReturn(B, S)) {
690 }
691
692 const auto *AS = dyn_cast<AttributedStmt>(S);
693 bool HasFallThroughAttr =
694 AS && hasSpecificAttr<FallThroughAttr>(AS->getAttrs());
695
696 SourceRange SilenceableCondVal;
697
698 if (UK == reachable_code::UK_Other) {
699 // Check if the dead code is part of the "loop target" of
700 // a for/for-range loop. This is the block that contains
701 // the increment code.
702 if (const Stmt *LoopTarget = B->getLoopTarget()) {
703 SourceLocation Loc = LoopTarget->getBeginLoc();
704 SourceRange R1(Loc, Loc), R2;
705
706 if (const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
707 const Expr *Inc = FS->getInc();
708 Loc = Inc->getBeginLoc();
709 R2 = Inc->getSourceRange();
710 }
711
713 SourceRange(), SourceRange(Loc, Loc), R2,
714 HasFallThroughAttr);
715 return;
716 }
717
718 // Check if the dead block has a predecessor whose branch has
719 // a configuration value that *could* be modified to
720 // silence the warning.
722 if (PI != B->pred_end()) {
723 if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
724 const Stmt *TermCond =
725 PredBlock->getTerminatorCondition(/* strip parens */ false);
726 isConfigurationValue(TermCond, PP, &SilenceableCondVal);
727 }
728 }
729 }
730
731 SourceRange R1, R2;
732 SourceLocation Loc = GetUnreachableLoc(S, R1, R2);
733 CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2, HasFallThroughAttr);
734}
735
736//===----------------------------------------------------------------------===//
737// Reachability APIs.
738//===----------------------------------------------------------------------===//
739
740namespace clang { namespace reachable_code {
741
742void Callback::anchor() { }
743
744unsigned ScanReachableFromBlock(const CFGBlock *Start,
745 llvm::BitVector &Reachable) {
746 return scanFromBlock(Start, Reachable, /* SourceManager* */ nullptr, false);
747}
748
750 Callback &CB) {
751
752 CFG *cfg = AC.getCFG();
753 if (!cfg)
754 return;
755
756 // Scan for reachable blocks from the entrance of the CFG.
757 // If there are no unreachable blocks, we're done.
758 llvm::BitVector reachable(cfg->getNumBlockIDs());
759 unsigned numReachable =
760 scanMaybeReachableFromBlock(&cfg->getEntry(), PP, reachable);
761 if (numReachable == cfg->getNumBlockIDs())
762 return;
763
764 // If there aren't explicit EH edges, we should include the 'try' dispatch
765 // blocks as roots.
766 if (!AC.getCFGBuildOptions().AddEHEdges) {
767 for (const CFGBlock *B : cfg->try_blocks())
768 numReachable += scanMaybeReachableFromBlock(B, PP, reachable);
769 if (numReachable == cfg->getNumBlockIDs())
770 return;
771 }
772
773 // There are some unreachable blocks. We need to find the root blocks that
774 // contain code that should be considered unreachable.
775 for (const CFGBlock *block : *cfg) {
776 // A block may have been marked reachable during this loop.
777 if (reachable[block->getBlockID()])
778 continue;
779
780 DeadCodeScan DS(reachable, PP, AC.getASTContext());
781 numReachable += DS.scanBackwards(block, CB);
782
783 if (numReachable == cfg->getNumBlockIDs())
784 return;
785 }
786}
787
788}} // end namespace clang::reachable_code
This file defines AnalysisDeclContext, a class that manages the analysis context data for context sen...
Defines enum values for all the target-independent builtin functions.
Defines the clang::Expr interface and subclasses for C++ expressions.
Defines the clang::Preprocessor interface.
static SourceLocation getTopMostMacro(SourceLocation Loc, SourceManager &SM)
static bool isEnumConstant(const Expr *Ex)
static bool isInCoroutineStmt(const Stmt *DeadStmt, const CFGBlock *Block)
static unsigned scanFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable, Preprocessor *PP, bool IncludeSometimesUnreachableEdges, bool TreatAnalyzerNoReturnAsReturning=false)
static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B, Preprocessor &PP)
Returns true if we should always explore all successors of a block.
static int SrcCmp(const std::pair< const CFGBlock *, const Stmt * > *p1, const std::pair< const CFGBlock *, const Stmt * > *p2)
static bool isTrivialDoWhile(const CFGBlock *B, const Stmt *S)
static bool isExpandedFromConfigurationMacro(const Stmt *S, Preprocessor &PP, bool IgnoreYES_NO=false)
Returns true if the statement is expanded from a configuration macro.
static bool isValidDeadStmt(const Stmt *S, const clang::CFGBlock *Block)
static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP)
static bool isBuiltinUnreachable(const Stmt *S)
static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S, ASTContext &C)
static bool isDeadReturn(const CFGBlock *B, const Stmt *S)
static unsigned scanMaybeReachableFromBlock(const CFGBlock *Start, Preprocessor &PP, llvm::BitVector &Reachable)
static SourceLocation GetUnreachableLoc(const Stmt *S, SourceRange &R1, SourceRange &R2)
static bool isTrivialExpression(const Expr *Ex)
Defines the SourceManager interface.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
Definition Expr.h:4401
SourceLocation getQuestionLoc() const
Definition Expr.h:4428
AnalysisDeclContext contains the context data for the function, method or block under analysis.
ASTContext & getASTContext() const
CFG::BuildOptions & getCFGBuildOptions()
ArraySubscriptExpr - [C99 6.5.2.1] Array Subscripting.
Definition Expr.h:2769
SourceLocation getRBracketLoc() const
Definition Expr.h:2817
Expr * getLHS()
An array access can be written A[4] or 4[A] (both are equivalent).
Definition Expr.h:2798
A builtin binary operation expression such as "x + y" or "x <= y".
Definition Expr.h:4086
static bool isLogicalOp(Opcode Opc)
Definition Expr.h:4219
Expr * getLHS() const
Definition Expr.h:4136
static bool isComparisonOp(Opcode Opc)
Definition Expr.h:4186
SourceLocation getOperatorLoc() const
Definition Expr.h:4128
Expr * getRHS() const
Definition Expr.h:4138
Represents a single basic block in a source-level CFG.
Definition CFG.h:652
pred_iterator pred_end()
Definition CFG.h:1029
succ_iterator succ_end()
Definition CFG.h:1047
bool hasOnlyAnalyzerNoReturnElement() const
Returns true if the block ends in an 'analyzer_noreturn' call (as opposed to a real 'noreturn' one).
Definition CFG.h:1174
ElementList::const_iterator const_iterator
Definition CFG.h:957
CFGElement back() const
Definition CFG.h:964
bool empty() const
Definition CFG.h:1009
CFGTerminator getTerminator() const
Definition CFG.h:1146
succ_iterator succ_begin()
Definition CFG.h:1046
Stmt * getTerminatorStmt()
Definition CFG.h:1148
const Stmt * getLoopTarget() const
Definition CFG.h:1161
AdjacentBlocks::const_iterator const_pred_iterator
Definition CFG.h:1015
unsigned pred_size() const
Definition CFG.h:1067
const Stmt * getTerminatorCondition(bool StripParens=true) const
Definition CFG.cpp:6533
pred_iterator pred_begin()
Definition CFG.h:1028
unsigned getBlockID() const
Definition CFG.h:1178
AdjacentBlocks::const_iterator const_succ_iterator
Definition CFG.h:1022
unsigned succ_size() const
Definition CFG.h:1064
Represents a top-level expression in a basic block.
Definition CFG.h:55
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
Definition CFG.h:113
bool isTemporaryDtorsBranch() const
Definition CFG.h:618
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
Definition CFG.h:1295
try_block_range try_blocks() const
Definition CFG.h:1428
CFGBlock & getEntry()
Definition CFG.h:1409
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
Definition CFG.h:1488
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr....
Definition Expr.h:4017
SourceLocation getLParenLoc() const
Definition Expr.h:4049
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
Definition ExprCXX.h:1836
SourceLocation getBeginLoc() const LLVM_READONLY
Definition ExprCXX.cpp:976
Expr * getSubExpr()
Definition Expr.h:3774
CompoundAssignOperator - For compound assignments (e.g.
Definition Expr.h:4348
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1294
ValueDecl * getDecl()
Definition Expr.h:1362
DoStmt - This represents a 'do/while' stmt.
Definition Stmt.h:2844
An instance of this object exists for each enum constant that is defined.
Definition Decl.h:3562
This represents one expression.
Definition Expr.h:113
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3134
Expr * IgnoreCasts() LLVM_READONLY
Skip past any casts which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3113
Represents a function declaration or definition.
Definition Decl.h:2059
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3412
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
Definition Expr.h:3601
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers,...
Definition ExprObjC.h:1675
SourceLocation getLParenLoc() const
Definition ExprObjC.h:1698
ParenExpr - This represents a parenthesized expression, e.g.
Definition Expr.h:2230
Stmt * getParent(Stmt *) const
Engages in a tight little dance with the lexer to efficiently preprocess tokens.
SourceManager & getSourceManager() const
StringRef getImmediateMacroName(SourceLocation Loc)
Retrieve the name of the immediate macro expansion.
const LangOptions & getLangOpts() const
ReturnStmt - This represents a return, optionally of an expression: return; return 4;.
Definition Stmt.h:3172
Encodes a location in the source.
This class handles loading and caching of source files into memory.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
A trivial tuple used to represent a source range.
Stmt - This represents one statement.
Definition Stmt.h:85
StmtClass getStmtClass() const
Definition Stmt.h:1505
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:343
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:355
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
Definition Expr.h:2292
SourceLocation getOperatorLoc() const
getOperatorLoc - Return the location of the operator.
Definition Expr.h:2337
Expr * getSubExpr() const
Definition Expr.h:2333
Opcode getOpcode() const
Definition Expr.h:2328
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:713
Represents a variable declaration or definition.
Definition Decl.h:933
virtual void HandleUnreachable(UnreachableKind UK, SourceLocation L, SourceRange ConditionVal, SourceRange R1, SourceRange R2, bool HasFallThroughAttr)=0
bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow)
1) Pops a pointer from the stack 2) Load the value from the pointer 3) Writes the value increased by ...
Definition Interp.h:967
void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP, Callback &CB)
unsigned ScanReachableFromBlock(const CFGBlock *Start, llvm::BitVector &Reachable)
ScanReachableFromBlock - Mark all blocks reachable from Start.
UnreachableKind
Classifications of unreachable code.
Top level wrappers for InstallAPI frontend operations.
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool hasSpecificAttr(const Container &container)
const FunctionProtoType * T
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)
Definition Address.h:327