diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp | 70 |
1 files changed, 53 insertions, 17 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 67762bd..a987a8c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -37,12 +37,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/MapVector.h" -#include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -50,7 +46,6 @@ #include <algorithm> #include <deque> #include <iterator> -#include <vector> using namespace clang; @@ -61,6 +56,8 @@ using namespace clang; namespace { class UnreachableCodeHandler : public reachable_code::Callback { Sema &S; + SourceRange PreviousSilenceableCondVal; + public: UnreachableCodeHandler(Sema &s) : S(s) {} @@ -69,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: @@ -370,7 +375,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { CFGStmt CS = ri->castAs<CFGStmt>(); const Stmt *S = CS.getStmt(); - if (isa<ReturnStmt>(S)) { + if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { HasLiveReturn = true; continue; } @@ -421,7 +426,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_HasNoReturn; unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; - enum { Function, Block, Lambda } funMode; + enum { Function, Block, Lambda, Coroutine } funMode; SourceLocation FuncLoc; static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { @@ -457,6 +462,19 @@ struct CheckFallThroughDiagnostics { return D; } + static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { + CheckFallThroughDiagnostics D; + D.FuncLoc = Func->getLocation(); + D.diag_MaybeFallThrough_HasNoReturn = 0; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::warn_maybe_falloff_nonvoid_coroutine; + D.diag_AlwaysFallThrough_HasNoReturn = 0; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::warn_falloff_nonvoid_coroutine; + D.funMode = Coroutine; + return D; + } + static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -499,7 +517,13 @@ struct CheckFallThroughDiagnostics { (!ReturnsVoid || D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); } - + if (funMode == Coroutine) { + return (ReturnsVoid || + D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || + D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, + FuncLoc)) && + (!HasNoReturn); + } // For blocks / lambdas. return ReturnsVoid && !HasNoReturn; } @@ -519,11 +543,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, bool ReturnsVoid = false; bool HasNoReturn = false; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - ReturnsVoid = FD->getReturnType()->isVoidType(); + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) + ReturnsVoid = CBody->getFallthroughHandler() != nullptr; + else + ReturnsVoid = FD->getReturnType()->isVoidType(); HasNoReturn = FD->isNoReturn(); } - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnsVoid = MD->getReturnType()->isVoidType(); HasNoReturn = MD->hasAttr<NoReturnAttr>(); } @@ -1991,13 +2018,22 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check missing 'return' if (P.enableCheckFallThrough) { + auto IsCoro = [&]() { + if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody())) + return true; + return false; + }; const CheckFallThroughDiagnostics &CD = - (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() - : (isa<CXXMethodDecl>(D) && - cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && - cast<CXXMethodDecl>(D)->getParent()->isLambda()) - ? CheckFallThroughDiagnostics::MakeForLambda() - : CheckFallThroughDiagnostics::MakeForFunction(D)); + (isa<BlockDecl>(D) + ? CheckFallThroughDiagnostics::MakeForBlock() + : (isa<CXXMethodDecl>(D) && + cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && + cast<CXXMethodDecl>(D)->getParent()->isLambda()) + ? CheckFallThroughDiagnostics::MakeForLambda() + : (IsCoro() + ? CheckFallThroughDiagnostics::MakeForCoroutine(D) + : CheckFallThroughDiagnostics::MakeForFunction(D))); CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); } |