diff options
| -rw-r--r-- | clang/include/clang/Analysis/Analyses/ReachableCode.h | 4 | ||||
| -rw-r--r-- | clang/include/clang/Analysis/CFG.h | 6 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
| -rw-r--r-- | clang/lib/Analysis/CFG.cpp | 5 | ||||
| -rw-r--r-- | clang/lib/Analysis/ReachableCode.cpp | 62 | ||||
| -rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 15 | ||||
| -rw-r--r-- | clang/test/Sema/warn-unreachable.c | 35 |
7 files changed, 107 insertions, 22 deletions
diff --git a/clang/include/clang/Analysis/Analyses/ReachableCode.h b/clang/include/clang/Analysis/Analyses/ReachableCode.h index a328ea2c8f9..90a6d014f58 100644 --- a/clang/include/clang/Analysis/Analyses/ReachableCode.h +++ b/clang/include/clang/Analysis/Analyses/ReachableCode.h @@ -50,7 +50,9 @@ class Callback { public: virtual ~Callback() {} virtual void HandleUnreachable(UnreachableKind UK, - SourceLocation L, SourceRange R1, + SourceLocation L, + SourceRange ConditionVal, + SourceRange R1, SourceRange R2) = 0; }; diff --git a/clang/include/clang/Analysis/CFG.h b/clang/include/clang/Analysis/CFG.h index c05d440ef3c..123d1443a2b 100644 --- a/clang/include/clang/Analysis/CFG.h +++ b/clang/include/clang/Analysis/CFG.h @@ -623,10 +623,10 @@ public: CFGTerminator getTerminator() { return Terminator; } const CFGTerminator getTerminator() const { return Terminator; } - Stmt *getTerminatorCondition(); + Stmt *getTerminatorCondition(bool StripParens = true); - const Stmt *getTerminatorCondition() const { - return const_cast<CFGBlock*>(this)->getTerminatorCondition(); + const Stmt *getTerminatorCondition(bool StripParens = true) const { + return const_cast<CFGBlock*>(this)->getTerminatorCondition(StripParens); } const Stmt *getLoopTarget() const { return LoopTarget; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index f7efbbd2efc..704bf1f1054 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -373,6 +373,8 @@ def warn_unreachable_return : Warning< def warn_unreachable_loop_increment : Warning< "loop will run at most once (loop increment never executed)">, InGroup<UnreachableCodeLoopIncrement>, DefaultIgnore; +def note_unreachable_silence : Note< + "silence by adding parentheses to mark code as explicitly dead">; /// Built-in functions. def ext_implicit_lib_function_decl : ExtWarn< diff --git a/clang/lib/Analysis/CFG.cpp b/clang/lib/Analysis/CFG.cpp index ad5cf69cd70..13ac92e86f2 100644 --- a/clang/lib/Analysis/CFG.cpp +++ b/clang/lib/Analysis/CFG.cpp @@ -4112,7 +4112,7 @@ void CFGBlock::printTerminator(raw_ostream &OS, TPrinter.print(getTerminator()); } -Stmt *CFGBlock::getTerminatorCondition() { +Stmt *CFGBlock::getTerminatorCondition(bool StripParens) { Stmt *Terminator = this->Terminator; if (!Terminator) return NULL; @@ -4171,6 +4171,9 @@ Stmt *CFGBlock::getTerminatorCondition() { return Terminator; } + if (!StripParens) + return E; + return E ? E->IgnoreParens() : NULL; } diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 53e03de64ed..7c8ea39dc56 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -133,10 +133,17 @@ static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP); /// those blocks. static bool isConfigurationValue(const Stmt *S, Preprocessor &PP, - bool IncludeIntegers = true) { + SourceRange *SilenceableCondVal = nullptr, + bool IncludeIntegers = true, + bool WrappedInParens = false) { if (!S) return false; + // Special case looking for the sigil '()' around an integer literal. + if (const ParenExpr *PE = dyn_cast<ParenExpr>(S)) + return isConfigurationValue(PE->getSubExpr(), PP, SilenceableCondVal, + IncludeIntegers, true); + if (const Expr *Ex = dyn_cast<Expr>(S)) S = Ex->IgnoreParenCasts(); @@ -148,9 +155,15 @@ static bool isConfigurationValue(const Stmt *S, } case Stmt::DeclRefExprClass: return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP); - case Stmt::IntegerLiteralClass: - return IncludeIntegers ? isExpandedFromConfigurationMacro(S, PP) - : false; + case Stmt::IntegerLiteralClass: { + const IntegerLiteral *E = cast<IntegerLiteral>(S); + if (IncludeIntegers) { + if (SilenceableCondVal && !SilenceableCondVal->getBegin().isValid()) + *SilenceableCondVal = E->getSourceRange(); + return WrappedInParens || isExpandedFromConfigurationMacro(E, PP); + } + return false; + } case Stmt::MemberExprClass: return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP); case Stmt::ObjCBoolLiteralExprClass: @@ -163,13 +176,18 @@ static bool isConfigurationValue(const Stmt *S, // values if they are used in a logical or comparison operator // (not arithmetic). IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp()); - return isConfigurationValue(B->getLHS(), PP, IncludeIntegers) || - isConfigurationValue(B->getRHS(), PP, IncludeIntegers); + return isConfigurationValue(B->getLHS(), PP, SilenceableCondVal, + IncludeIntegers) || + isConfigurationValue(B->getRHS(), PP, SilenceableCondVal, + IncludeIntegers); } case Stmt::UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(S); + if (SilenceableCondVal) + *SilenceableCondVal = UO->getSourceRange(); return UO->getOpcode() == UO_LNot && - isConfigurationValue(UO->getSubExpr(), PP); + isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal, + IncludeIntegers, WrappedInParens); } default: return false; @@ -204,11 +222,13 @@ static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B, if (isa<SwitchStmt>(Term)) return true; // Specially handle '||' and '&&'. - if (isa<BinaryOperator>(Term)) + if (isa<BinaryOperator>(Term)) { return isConfigurationValue(Term, PP); + } } - return isConfigurationValue(B->getTerminatorCondition(), PP); + const Stmt *Cond = B->getTerminatorCondition(/* stripParens */ false); + return isConfigurationValue(Cond, PP); } static unsigned scanFromBlock(const CFGBlock *Start, @@ -314,9 +334,9 @@ namespace { const Stmt *findDeadCode(const CFGBlock *Block); void reportDeadCode(const CFGBlock *B, - const Stmt *S, - clang::reachable_code::Callback &CB); - }; + const Stmt *S, + clang::reachable_code::Callback &CB); + }; } void DeadCodeScan::enqueue(const CFGBlock *block) { @@ -529,6 +549,8 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B, UK = reachable_code::UK_Return; } + SourceRange SilenceableCondVal; + if (UK == reachable_code::UK_Other) { // Check if the dead code is part of the "loop target" of // a for/for-range loop. This is the block that contains @@ -544,14 +566,26 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B, } CB.HandleUnreachable(reachable_code::UK_Loop_Increment, - Loc, SourceRange(Loc, Loc), R2); + Loc, SourceRange(), SourceRange(Loc, Loc), R2); return; } + + // Check if the dead block has a predecessor whose branch has + // a configuration value that *could* be modified to + // silence the warning. + CFGBlock::const_pred_iterator PI = B->pred_begin(); + if (PI != B->pred_end()) { + if (const CFGBlock *PredBlock = PI->getPossiblyUnreachableBlock()) { + const Stmt *TermCond = + PredBlock->getTerminatorCondition(/* strip parens */ false); + isConfigurationValue(TermCond, PP, &SilenceableCondVal); + } + } } SourceRange R1, R2; SourceLocation Loc = GetUnreachableLoc(S, R1, R2); - CB.HandleUnreachable(UK, Loc, R1, R2); + CB.HandleUnreachable(UK, Loc, SilenceableCondVal, R1, R2); } //===----------------------------------------------------------------------===// diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index efaf966562c..75d7060e2d8 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -66,7 +66,9 @@ namespace { UnreachableCodeHandler(Sema &s) : S(s) {} void HandleUnreachable(reachable_code::UnreachableKind UK, - SourceLocation L, SourceRange R1, + SourceLocation L, + SourceRange SilenceableCondVal, + SourceRange R1, SourceRange R2) override { unsigned diag = diag::warn_unreachable; switch (UK) { @@ -84,6 +86,17 @@ namespace { } S.Diag(L, diag) << R1 << R2; + + SourceLocation Open = SilenceableCondVal.getBegin(); + if (Open.isValid()) { + SourceLocation Close = SilenceableCondVal.getEnd(); + Close = S.PP.getLocForEndOfToken(Close); + if (Close.isValid()) { + S.Diag(Open, diag::note_unreachable_silence) + << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") + << FixItHint::CreateInsertion(Close, ")"); + } + } } }; } diff --git a/clang/test/Sema/warn-unreachable.c b/clang/test/Sema/warn-unreachable.c index 9cd87a7343b..0d229659573 100644 --- a/clang/test/Sema/warn-unreachable.c +++ b/clang/test/Sema/warn-unreachable.c @@ -257,7 +257,7 @@ int test_config_constant(int x) { calledFun(); // no-warning return 1; } - if (!1) { + if (!1) { // expected-note {{silence by adding parentheses to mark code as explicitly dead}} calledFun(); // expected-warning {{will never be executed}} return 1; } @@ -268,7 +268,7 @@ int test_config_constant(int x) { if (x > 10) return CONFIG_CONSTANT ? calledFun() : calledFun(); // no-warning else - return 1 ? + return 1 ? // expected-note {{silence by adding parentheses to mark code as explicitly dead}} calledFun() : calledFun(); // expected-warning {{will never be executed}} } @@ -365,3 +365,34 @@ int test_break_preceded_by_noreturn_SUPPRESSED(int i) { } #pragma clang diagnostic pop + +// Test "silencing" with parentheses. +void test_with_paren_silencing(int x) { + if (0) calledFun(); // expected-warning {{will never be executed}} expected-note {{silence by adding parentheses to mark code as explicitly dead}} + if ((0)) calledFun(); // no-warning + + if (1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} + calledFun(); + else + calledFun(); // expected-warning {{will never be executed}} + + if ((1)) + calledFun(); + else + calledFun(); // no-warning + + if (!1) // expected-note {{silence by adding parentheses to mark code as explicitly dead}} + calledFun(); // expected-warning {{code will never be executed}} + else + calledFun(); + + if ((!1)) + calledFun(); // no-warning + else + calledFun(); + + if (!(1)) + calledFun(); // no-warning + else + calledFun(); +} |

