27#include "llvm/ADT/BitVector.h"
55 if (
const DoStmt *DS = dyn_cast<DoStmt>(Term)) {
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;
79 if (
const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
80 return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(
C);
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())) {
97 if (
const Expr *RE = RS->getRetValue()) {
98 RE = RE->IgnoreParenCasts();
135 llvm_unreachable(
"Broke out of infinite loop.");
151 bool IgnoreYES_NO =
false) {
165 if (MacroName ==
"YES" || MacroName ==
"NO")
171 if (MacroName ==
"false" || MacroName ==
"true")
191 bool IncludeIntegers =
true,
192 bool WrappedInParens =
false) {
196 if (
const auto *Ex = dyn_cast<Expr>(S))
197 S = Ex->IgnoreImplicit();
199 if (
const auto *Ex = dyn_cast<Expr>(S))
200 S = Ex->IgnoreCasts();
203 if (
const ParenExpr *PE = dyn_cast<ParenExpr>(S))
204 if (!PE->getBeginLoc().isMacroID())
206 IncludeIntegers,
true);
208 if (
const Expr *Ex = dyn_cast<Expr>(S))
209 S = Ex->IgnoreCasts();
211 bool IgnoreYES_NO =
false;
214 case Stmt::CallExprClass: {
216 dyn_cast_or_null<FunctionDecl>(
cast<CallExpr>(S)->getCalleeDecl());
217 return Callee ? Callee->isConstexpr() :
false;
219 case Stmt::DeclRefExprClass:
221 case Stmt::ObjCBoolLiteralExprClass:
224 case Stmt::CXXBoolLiteralExprClass:
225 case Stmt::IntegerLiteralClass: {
227 if (IncludeIntegers) {
228 if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid())
230 return WrappedInParens ||
235 case Stmt::MemberExprClass:
237 case Stmt::UnaryExprOrTypeTraitExprClass:
239 case Stmt::BinaryOperatorClass: {
250 case Stmt::UnaryOperatorClass: {
254 bool SilenceableCondValNotSet =
255 SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid();
256 bool IsSubExprConfigValue =
258 IncludeIntegers, WrappedInParens);
261 if (SilenceableCondValNotSet &&
262 SilenceableCondVal->getBegin().isValid() &&
263 *SilenceableCondVal ==
266 return IsSubExprConfigValue;
276 if (
const VarDecl *VD = dyn_cast<VarDecl>(D)) {
284 if (!VD->hasLocalStorage())
289 return VD->getType().isLocalConstQualified();
307 if (
const auto *IS = dyn_cast<IfStmt>(Term);
308 IS !=
nullptr && IS->isConstexpr())
318 bool IncludeSometimesUnreachableEdges,
319 bool TreatAnalyzerNoReturnAsReturning =
false) {
334 auto MarkReachable = [&](
const CFGBlock *B) {
335 unsigned blockID = B->getBlockID();
336 if (!Reachable[blockID]) {
337 Reachable.set(blockID);
344 while (!WL.empty()) {
345 const CFGBlock *item = WL.pop_back_val();
353 std::optional<bool> TreatAllSuccessorsAsReachable;
354 if (!IncludeSometimesUnreachableEdges)
355 TreatAllSuccessorsAsReachable =
false;
362 bool FollowAlternate = TreatAnalyzerNoReturnAsReturning &&
366 E = item->
succ_end(); I != E; ++I) {
368 if (FollowAlternate) {
369 if (
const CFGBlock *Alt = I->getPossiblyUnreachableBlock())
373 const CFGBlock *UB = I->getPossiblyUnreachableBlock();
377 if (!TreatAllSuccessorsAsReachable) {
379 TreatAllSuccessorsAsReachable =
383 if (*TreatAllSuccessorsAsReachable) {
399 llvm::BitVector &Reachable) {
410 llvm::BitVector Visited;
411 llvm::BitVector &Reachable;
412 SmallVector<const CFGBlock *, 10> WorkList;
416 typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
419 DeferredLocsTy DeferredLocs;
422 DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
423 : Visited(reachable.size()),
424 Reachable(reachable),
427 void enqueue(
const CFGBlock *block);
428 unsigned scanBackwards(
const CFGBlock *Start,
429 clang::reachable_code::Callback &CB);
431 bool isDeadCodeRoot(
const CFGBlock *
Block);
433 const Stmt *findDeadCode(
const CFGBlock *
Block);
435 void reportDeadCode(
const CFGBlock *B,
437 clang::reachable_code::Callback &CB);
441void DeadCodeScan::enqueue(
const CFGBlock *block) {
443 if (Reachable[blockID] || Visited[blockID])
445 Visited[blockID] =
true;
446 WorkList.push_back(block);
449bool DeadCodeScan::isDeadCodeRoot(
const clang::CFGBlock *
Block) {
450 bool isDeadRoot =
true;
453 E =
Block->pred_end(); I != E; ++I) {
454 if (
const CFGBlock *PredBlock = *I) {
455 unsigned blockID = PredBlock->getBlockID();
456 if (Visited[blockID]) {
460 if (!Reachable[blockID]) {
462 Visited[blockID] =
true;
463 WorkList.push_back(PredBlock);
476 const Stmt *CoroStmt =
nullptr;
478 bool AfterDeadStmt =
false;
480 if (std::optional<CFGStmt> CS = Elem.getAs<
CFGStmt>()) {
481 const Stmt *S = CS->getStmt();
483 AfterDeadStmt =
true;
486 (llvm::isa<CoreturnStmt>(S) || llvm::isa<CoroutineSuspendExpr>(S))) {
494 const Stmt *DeadStmt;
495 bool CoroutineSubStmt =
false;
496 Checker(
const Stmt *S) : DeadStmt(S) {
498 ShouldVisitImplicitCode =
true;
501 bool VisitStmt(
Stmt *S)
override {
503 CoroutineSubStmt =
true;
507 Checker checker(DeadStmt);
508 checker.TraverseStmt(
const_cast<Stmt *
>(CoroStmt));
509 return checker.CoroutineSubStmt;
516 return BO->getOpcode() != BO_Comma;
523const Stmt *DeadCodeScan::findDeadCode(
const clang::CFGBlock *
Block) {
525 if (std::optional<CFGStmt> CS = I->getAs<CFGStmt>()) {
526 const Stmt *S = CS->getStmt();
531 CFGTerminator
T =
Block->getTerminator();
532 if (
T.isStmtBranch()) {
533 const Stmt *S =
T.getStmt();
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())
545 if (p2->second->getBeginLoc() < p1->second->getBeginLoc())
550unsigned DeadCodeScan::scanBackwards(
const clang::CFGBlock *Start,
551 clang::reachable_code::Callback &CB) {
556 while (!WorkList.empty()) {
557 const CFGBlock *
Block = WorkList.pop_back_val();
561 if (Reachable[
Block->getBlockID()])
565 const Stmt *S = findDeadCode(
Block);
570 E =
Block->pred_end(); I != E; ++I) {
571 if (
const CFGBlock *predBlock = *I)
583 if (isDeadCodeRoot(
Block)) {
584 reportDeadCode(
Block, S, CB);
591 DeferredLocs.push_back(std::make_pair(
Block, S));
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()])
603 reportDeadCode(
Block, I.second, CB);
616 if (
const Expr *Ex = dyn_cast<Expr>(S))
617 S = Ex->IgnoreParenImpCasts();
620 case Expr::BinaryOperatorClass: {
624 case Expr::UnaryOperatorClass: {
629 case Expr::CompoundAssignOperatorClass: {
635 case Expr::BinaryConditionalOperatorClass:
636 case Expr::ConditionalOperatorClass: {
641 case Expr::MemberExprClass: {
646 case Expr::ArraySubscriptExprClass: {
652 case Expr::CStyleCastExprClass: {
657 case Expr::CXXFunctionalCastExprClass: {
662 case Stmt::CXXTryStmtClass: {
665 case Expr::ObjCBridgedCastExprClass: {
676void DeadCodeScan::reportDeadCode(
const CFGBlock *B,
678 clang::reachable_code::Callback &CB) {
692 const auto *AS = dyn_cast<AttributedStmt>(S);
693 bool HasFallThroughAttr =
696 SourceRange SilenceableCondVal;
703 SourceLocation Loc = LoopTarget->getBeginLoc();
704 SourceRange R1(Loc, Loc), R2;
706 if (
const ForStmt *FS = dyn_cast<ForStmt>(LoopTarget)) {
707 const Expr *
Inc = FS->getInc();
708 Loc =
Inc->getBeginLoc();
709 R2 =
Inc->getSourceRange();
713 SourceRange(), SourceRange(Loc, Loc), R2,
723 if (
const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) {
724 const Stmt *TermCond =
725 PredBlock->getTerminatorCondition(
false);
740namespace clang {
namespace reachable_code {
742void Callback::anchor() { }
745 llvm::BitVector &Reachable) {
759 unsigned numReachable =
775 for (
const CFGBlock *block : *cfg) {
781 numReachable += DS.scanBackwards(block, CB);
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 ...
AbstractConditionalOperator - An abstract base class for ConditionalOperator and BinaryConditionalOpe...
SourceLocation getQuestionLoc() const
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.
SourceLocation getRBracketLoc() const
Expr * getLHS()
An array access can be written A[4] or 4[A] (both are equivalent).
A builtin binary operation expression such as "x + y" or "x <= y".
static bool isLogicalOp(Opcode Opc)
static bool isComparisonOp(Opcode Opc)
SourceLocation getOperatorLoc() const
Represents a single basic block in a source-level CFG.
bool hasOnlyAnalyzerNoReturnElement() const
Returns true if the block ends in an 'analyzer_noreturn' call (as opposed to a real 'noreturn' one).
ElementList::const_iterator const_iterator
CFGTerminator getTerminator() const
succ_iterator succ_begin()
Stmt * getTerminatorStmt()
const Stmt * getLoopTarget() const
AdjacentBlocks::const_iterator const_pred_iterator
unsigned pred_size() const
const Stmt * getTerminatorCondition(bool StripParens=true) const
pred_iterator pred_begin()
unsigned getBlockID() const
AdjacentBlocks::const_iterator const_succ_iterator
unsigned succ_size() const
Represents a top-level expression in a basic block.
std::optional< T > getAs() const
Convert to the specified CFGElement type, returning std::nullopt if this CFGElement is not of the des...
bool isTemporaryDtorsBranch() const
Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.
try_block_range try_blocks() const
unsigned getNumBlockIDs() const
Returns the total number of BlockIDs allocated (which start at 0).
CStyleCastExpr - An explicit cast in C (C99 6.5.4) or a C-style cast in C++ (C++ [expr....
SourceLocation getLParenLoc() const
Represents an explicit C++ type conversion that uses "functional" notation (C++ [expr....
SourceLocation getBeginLoc() const LLVM_READONLY
CompoundAssignOperator - For compound assignments (e.g.
A reference to a declared variable, function, enum, etc.
DoStmt - This represents a 'do/while' stmt.
An instance of this object exists for each enum constant that is defined.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Expr * IgnoreCasts() LLVM_READONLY
Skip past any casts which might surround this expression until reaching a fixed point.
Represents a function declaration or definition.
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
SourceLocation getMemberLoc() const
getMemberLoc - Return the location of the "member", in X->F, it is the location of 'F'.
An Objective-C "bridged" cast expression, which casts between Objective-C pointers and C pointers,...
SourceLocation getLParenLoc() const
ParenExpr - This represents a parenthesized expression, e.g.
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;.
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.
StmtClass getStmtClass() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
SourceLocation getBeginLoc() const LLVM_READONLY
UnaryOperator - This represents the unary-expression's (except sizeof and alignof),...
SourceLocation getOperatorLoc() const
getOperatorLoc - Return the location of the operator.
Expr * getSubExpr() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
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 ...
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)
bool hasSpecificAttr(const Container &container)
const FunctionProtoType * T
DynamicRecursiveASTVisitorBase< false > DynamicRecursiveASTVisitor
U cast(CodeGen::Address addr)