diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/Analysis/ReachableCode.cpp | 20 | ||||
-rw-r--r-- | clang/lib/Sema/AnalysisBasedWarnings.cpp | 10 |
2 files changed, 25 insertions, 5 deletions
diff --git a/clang/lib/Analysis/ReachableCode.cpp b/clang/lib/Analysis/ReachableCode.cpp index 69d000c03ba..a2f3203762f 100644 --- a/clang/lib/Analysis/ReachableCode.cpp +++ b/clang/lib/Analysis/ReachableCode.cpp @@ -218,11 +218,21 @@ static bool isConfigurationValue(const Stmt *S, } case Stmt::UnaryOperatorClass: { const UnaryOperator *UO = cast<UnaryOperator>(S); - if (SilenceableCondVal) - *SilenceableCondVal = UO->getSourceRange(); - return UO->getOpcode() == UO_LNot && - isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal, - IncludeIntegers, WrappedInParens); + if (UO->getOpcode() != UO_LNot) + return false; + bool SilenceableCondValNotSet = + SilenceableCondVal && SilenceableCondVal->getBegin().isInvalid(); + bool IsSubExprConfigValue = + isConfigurationValue(UO->getSubExpr(), PP, SilenceableCondVal, + IncludeIntegers, WrappedInParens); + // Update the silenceable condition value source range only if the range + // was set directly by the child expression. + if (SilenceableCondValNotSet && + SilenceableCondVal->getBegin().isValid() && + *SilenceableCondVal == + UO->getSubExpr()->IgnoreCasts()->getSourceRange()) + *SilenceableCondVal = UO->getSourceRange(); + return IsSubExprConfigValue; } default: return false; diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 5953d020b4f..a987a8ce0b3 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -56,6 +56,8 @@ using namespace clang; namespace { class UnreachableCodeHandler : public reachable_code::Callback { Sema &S; + SourceRange PreviousSilenceableCondVal; + public: UnreachableCodeHandler(Sema &s) : S(s) {} @@ -64,6 +66,14 @@ namespace { SourceRange SilenceableCondVal, SourceRange R1, SourceRange R2) override { + // Avoid reporting multiple unreachable code diagnostics that are + // triggered by the same conditional value. + if (PreviousSilenceableCondVal.isValid() && + SilenceableCondVal.isValid() && + PreviousSilenceableCondVal == SilenceableCondVal) + return; + PreviousSilenceableCondVal = SilenceableCondVal; + unsigned diag = diag::warn_unreachable; switch (UK) { case reachable_code::UK_Break: |