diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:49 +0000 |
commit | 2298981669bf3bd63335a4be179bc0f96823a8f4 (patch) | |
tree | 1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/Sema/AnalysisBasedWarnings.cpp | |
parent | 9a83721404652cea39e9f02ae3e3b5c964602a5c (diff) |
Notes
Diffstat (limited to 'lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 118 |
1 files changed, 64 insertions, 54 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index c818d40c77712..ce01909f18589 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -1,9 +1,8 @@ //=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -250,6 +249,10 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, CFG *cfg = AC.getCFG(); if (!cfg) return; + // If the exit block is unreachable, skip processing the function. + if (cfg->getExit().pred_empty()) + return; + // Emit diagnostic if a recursive function call is detected for all paths. if (checkForRecursiveFunctionCall(FD, cfg)) S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function); @@ -395,7 +398,8 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { for (const auto *B : *cfg) { if (!live[B->getBlockID()]) { if (B->pred_begin() == B->pred_end()) { - if (B->getTerminator() && isa<CXXTryStmt>(B->getTerminator())) + const Stmt *Term = B->getTerminatorStmt(); + if (Term && isa<CXXTryStmt>(Term)) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. count += reachable_code::ScanReachableFromBlock(B, live); @@ -443,7 +447,8 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { // No more CFGElements in the block? if (ri == re) { - if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { + const Stmt *Term = B.getTerminatorStmt(); + if (Term && isa<CXXTryStmt>(Term)) { HasAbnormalEdge = true; continue; } @@ -615,7 +620,7 @@ struct CheckFallThroughDiagnostics { /// of a noreturn function. We assume that functions and blocks not marked /// noreturn will return. static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, - const BlockExpr *blkExpr, + QualType BlockType, const CheckFallThroughDiagnostics &CD, AnalysisDeclContext &AC, sema::FunctionScopeInfo *FSI) { @@ -636,9 +641,8 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, HasNoReturn = MD->hasAttr<NoReturnAttr>(); } else if (isa<BlockDecl>(D)) { - QualType BlockTy = blkExpr->getType(); if (const FunctionType *FT = - BlockTy->getPointeeType()->getAs<FunctionType>()) { + BlockType->getPointeeType()->getAs<FunctionType>()) { if (FT->getReturnType()->isVoidType()) ReturnsVoid = true; if (FT->getNoReturnAttr()) @@ -995,7 +999,8 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) S.Diag(BE->getBeginLoc(), diag::warn_uninit_byref_blockvar_captured_by_block) - << VD->getDeclName(); + << VD->getDeclName() + << VD->getType().getQualifiers().hasObjCLifetime(); else DiagUninitUse(S, VD, Use, true); } @@ -1073,7 +1078,7 @@ namespace { BlockQueue.pop_front(); if (!P) continue; - const Stmt *Term = P->getTerminator(); + const Stmt *Term = P->getTerminatorStmt(); if (Term && isa<SwitchStmt>(Term)) continue; // Switch statement, good. @@ -1171,7 +1176,7 @@ namespace { } static const Stmt *getLastStmt(const CFGBlock &B) { - if (const Stmt *Term = B.getTerminator()) + if (const Stmt *Term = B.getTerminatorStmt()) return Term; for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), ElemEnd = B.rend(); @@ -1277,11 +1282,11 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, if (L.isMacroID()) continue; if (S.getLangOpts().CPlusPlus11) { - const Stmt *Term = B->getTerminator(); + const Stmt *Term = B->getTerminatorStmt(); // Skip empty cases. while (B->empty() && !Term && B->succ_size() == 1) { B = *B->succ_begin(); - Term = B->getTerminator(); + Term = B->getTerminatorStmt(); } if (!(B->empty() && Term && isa<BreakStmt>(Term))) { Preprocessor &PP = S.getPreprocessor(); @@ -1639,15 +1644,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { return ONS; } - // Helper functions - void warnLockMismatch(unsigned DiagID, StringRef Kind, Name LockName, - SourceLocation Loc) { - // Gracefully handle rare cases when the analysis can't get a more - // precise source location. - if (!Loc.isValid()) - Loc = FunLocation; - PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind << LockName); - Warnings.emplace_back(std::move(Warning), getNotes()); + OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) { + return LocLocked.isValid() + ? getNotes(PartialDiagnosticAt( + LocLocked, S.PDiag(diag::note_locked_here) << Kind)) + : getNotes(); } public: @@ -1678,22 +1679,34 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc) override { - warnLockMismatch(diag::warn_unlock_but_no_lock, Kind, LockName, Loc); - } - - void handleIncorrectUnlockKind(StringRef Kind, Name LockName, - LockKind Expected, LockKind Received, - SourceLocation Loc) override { if (Loc.isInvalid()) Loc = FunLocation; - PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_kind_mismatch) - << Kind << LockName << Received - << Expected); + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock) + << Kind << LockName); Warnings.emplace_back(std::move(Warning), getNotes()); } - void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation Loc) override { - warnLockMismatch(diag::warn_double_lock, Kind, LockName, Loc); + void handleIncorrectUnlockKind(StringRef Kind, Name LockName, + LockKind Expected, LockKind Received, + SourceLocation LocLocked, + SourceLocation LocUnlock) override { + if (LocUnlock.isInvalid()) + LocUnlock = FunLocation; + PartialDiagnosticAt Warning( + LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch) + << Kind << LockName << Received << Expected); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); + } + + void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked, + SourceLocation LocDoubleLock) override { + if (LocDoubleLock.isInvalid()) + LocDoubleLock = FunLocation; + PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock) + << Kind << LockName); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); } void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, @@ -1720,13 +1733,8 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind << LockName); - if (LocLocked.isValid()) { - PartialDiagnosticAt Note(LocLocked, S.PDiag(diag::note_locked_here) - << Kind); - Warnings.emplace_back(std::move(Warning), getNotes(Note)); - return; - } - Warnings.emplace_back(std::move(Warning), getNotes()); + Warnings.emplace_back(std::move(Warning), + makeLockedHereNote(LocLocked, Kind)); } void handleExclusiveAndShared(StringRef Kind, Name LockName, @@ -2003,7 +2011,7 @@ static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { void clang::sema:: AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, sema::FunctionScopeInfo *fscope, - const Decl *D, const BlockExpr *blkExpr) { + const Decl *D, QualType BlockType) { // We avoid doing analysis-based warnings when there are errors for // two reasons: @@ -2082,16 +2090,16 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Register the expressions with the CFGBuilder. for (const auto &D : fscope->PossiblyUnreachableDiags) { - if (D.stmt) - AC.registerForcedBlockExpression(D.stmt); + for (const Stmt *S : D.Stmts) + AC.registerForcedBlockExpression(S); } if (AC.getCFG()) { analyzed = true; for (const auto &D : fscope->PossiblyUnreachableDiags) { - bool processed = false; - if (D.stmt) { - const CFGBlock *block = AC.getBlockForRegisteredExpression(D.stmt); + bool AllReachable = true; + for (const Stmt *S : D.Stmts) { + const CFGBlock *block = AC.getBlockForRegisteredExpression(S); CFGReverseBlockReachabilityAnalysis *cra = AC.getCFGReachablityAnalysis(); // FIXME: We should be able to assert that block is non-null, but @@ -2099,15 +2107,17 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // edge cases; see test/Sema/vla-2.c. if (block && cra) { // Can this block be reached from the entrance? - if (cra->isReachable(&AC.getCFG()->getEntry(), block)) - S.Diag(D.Loc, D.PD); - processed = true; + if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) { + AllReachable = false; + break; + } } + // If we cannot map to a basic block, assume the statement is + // reachable. } - if (!processed) { - // Emit the warning anyway if we cannot map to a basic block. + + if (AllReachable) S.Diag(D.Loc, D.PD); - } } } @@ -2127,7 +2137,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, : (fscope->isCoroutine() ? CheckFallThroughDiagnostics::MakeForCoroutine(D) : CheckFallThroughDiagnostics::MakeForFunction(D))); - CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC, fscope); + CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope); } // Warning: check for unreachable code |