diff options
| author | 2019-01-27 16:42:12 +0000 | |
|---|---|---|
| committer | 2019-01-27 16:42:12 +0000 | |
| commit | b773203fb58f3ef282fb69c832d8710cab5bc82d (patch) | |
| tree | e75913f147570fbd75169647b144df85b88a038c /gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp | |
| parent | tweak errno in previous (diff) | |
| download | wireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.tar.xz wireguard-openbsd-b773203fb58f3ef282fb69c832d8710cab5bc82d.zip | |
Import LLVM 7.0.1 release including clang, lld and lldb.
Diffstat (limited to 'gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp')
| -rw-r--r-- | gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp | 322 |
1 files changed, 127 insertions, 195 deletions
diff --git a/gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 0033edf326a..ed240f4ed29 100644 --- a/gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/gnu/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -90,7 +90,7 @@ namespace { } S.Diag(L, diag) << R1 << R2; - + SourceLocation Open = SilenceableCondVal.getBegin(); if (Open.isValid()) { SourceLocation Close = SilenceableCondVal.getEnd(); @@ -122,7 +122,7 @@ static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { } namespace { -/// \brief Warn on logical operator errors in CFGBuilder +/// Warn on logical operator errors in CFGBuilder class LogicalErrorHandler : public CFGCallback { Sema &S; @@ -200,60 +200,41 @@ static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { return false; } -// All blocks are in one of three states. States are ordered so that blocks -// can only move to higher states. -enum RecursiveState { - FoundNoPath, - FoundPath, - FoundPathWithNoRecursiveCall -}; - -// Returns true if there exists a path to the exit block and every path -// to the exit block passes through a call to FD. +// Returns true if every path from the entry block passes through a call to FD. static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { + llvm::SmallPtrSet<CFGBlock *, 16> Visited; + llvm::SmallVector<CFGBlock *, 16> WorkList; + // Keep track of whether we found at least one recursive path. + bool foundRecursion = false; const unsigned ExitID = cfg->getExit().getBlockID(); - // Mark all nodes as FoundNoPath, then set the status of the entry block. - SmallVector<RecursiveState, 16> States(cfg->getNumBlockIDs(), FoundNoPath); - States[cfg->getEntry().getBlockID()] = FoundPathWithNoRecursiveCall; + // Seed the work list with the entry block. + WorkList.push_back(&cfg->getEntry()); - // Make the processing stack and seed it with the entry block. - SmallVector<CFGBlock *, 16> Stack; - Stack.push_back(&cfg->getEntry()); + while (!WorkList.empty()) { + CFGBlock *Block = WorkList.pop_back_val(); - while (!Stack.empty()) { - CFGBlock *CurBlock = Stack.back(); - Stack.pop_back(); - - unsigned ID = CurBlock->getBlockID(); - RecursiveState CurState = States[ID]; - - if (CurState == FoundPathWithNoRecursiveCall) { - // Found a path to the exit node without a recursive call. - if (ExitID == ID) - return false; + for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { + if (CFGBlock *SuccBlock = *I) { + if (!Visited.insert(SuccBlock).second) + continue; - // Only change state if the block has a recursive call. - if (hasRecursiveCallInPath(FD, *CurBlock)) - CurState = FoundPath; - } + // Found a path to the exit node without a recursive call. + if (ExitID == SuccBlock->getBlockID()) + return false; - // Loop over successor blocks and add them to the Stack if their state - // changes. - for (auto I = CurBlock->succ_begin(), E = CurBlock->succ_end(); I != E; ++I) - if (*I) { - unsigned next_ID = (*I)->getBlockID(); - if (States[next_ID] < CurState) { - States[next_ID] = CurState; - Stack.push_back(*I); + // If the successor block contains a recursive call, end analysis there. + if (hasRecursiveCallInPath(FD, *SuccBlock)) { + foundRecursion = true; + continue; } + + WorkList.push_back(SuccBlock); } + } } - - // Return true if the exit node is reachable, and only reachable through - // a recursive call. - return States[ExitID] == FoundPath; + return foundRecursion; } static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, @@ -269,10 +250,6 @@ 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->getLocStart(), diag::warn_infinite_recursive_function); @@ -281,114 +258,62 @@ static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, //===----------------------------------------------------------------------===// // Check for throw in a non-throwing function. //===----------------------------------------------------------------------===// -enum ThrowState { - FoundNoPathForThrow, - FoundPathForThrow, - FoundPathWithNoThrowOutFunction, -}; -static bool isThrowCaught(const CXXThrowExpr *Throw, - const CXXCatchStmt *Catch) { - const Type *CaughtType = Catch->getCaughtType().getTypePtrOrNull(); - if (!CaughtType) - return true; - const Type *ThrowType = nullptr; - if (Throw->getSubExpr()) - ThrowType = Throw->getSubExpr()->getType().getTypePtrOrNull(); - if (!ThrowType) - return false; - if (ThrowType->isReferenceType()) - ThrowType = ThrowType->castAs<ReferenceType>() - ->getPointeeType() - ->getUnqualifiedDesugaredType(); - if (CaughtType->isReferenceType()) - CaughtType = CaughtType->castAs<ReferenceType>() - ->getPointeeType() - ->getUnqualifiedDesugaredType(); - if (ThrowType->isPointerType() && CaughtType->isPointerType()) { - ThrowType = ThrowType->getPointeeType()->getUnqualifiedDesugaredType(); - CaughtType = CaughtType->getPointeeType()->getUnqualifiedDesugaredType(); - } - if (CaughtType == ThrowType) - return true; - const CXXRecordDecl *CaughtAsRecordType = - CaughtType->getAsCXXRecordDecl(); - const CXXRecordDecl *ThrowTypeAsRecordType = ThrowType->getAsCXXRecordDecl(); - if (CaughtAsRecordType && ThrowTypeAsRecordType) - return ThrowTypeAsRecordType->isDerivedFrom(CaughtAsRecordType); - return false; -} +/// Determine whether an exception thrown by E, unwinding from ThrowBlock, +/// can reach ExitBlock. +static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, + CFG *Body) { + SmallVector<CFGBlock *, 16> Stack; + llvm::BitVector Queued(Body->getNumBlockIDs()); -static bool isThrowCaughtByHandlers(const CXXThrowExpr *CE, - const CXXTryStmt *TryStmt) { - for (unsigned H = 0, E = TryStmt->getNumHandlers(); H < E; ++H) { - if (isThrowCaught(CE, TryStmt->getHandler(H))) - return true; - } - return false; -} + Stack.push_back(&ThrowBlock); + Queued[ThrowBlock.getBlockID()] = true; -static bool doesThrowEscapePath(CFGBlock Block, SourceLocation &OpLoc) { - for (const auto &B : Block) { - if (B.getKind() != CFGElement::Statement) - continue; - const auto *CE = dyn_cast<CXXThrowExpr>(B.getAs<CFGStmt>()->getStmt()); - if (!CE) - continue; + while (!Stack.empty()) { + CFGBlock &UnwindBlock = *Stack.back(); + Stack.pop_back(); - OpLoc = CE->getThrowLoc(); - for (const auto &I : Block.succs()) { - if (!I.isReachable()) + for (auto &Succ : UnwindBlock.succs()) { + if (!Succ.isReachable() || Queued[Succ->getBlockID()]) continue; - if (const auto *Terminator = - dyn_cast_or_null<CXXTryStmt>(I->getTerminator())) - if (isThrowCaughtByHandlers(CE, Terminator)) - return false; + + if (Succ->getBlockID() == Body->getExit().getBlockID()) + return true; + + if (auto *Catch = + dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) { + QualType Caught = Catch->getCaughtType(); + if (Caught.isNull() || // catch (...) catches everything + !E->getSubExpr() || // throw; is considered cuaght by any handler + S.handlerCanCatch(Caught, E->getSubExpr()->getType())) + // Exception doesn't escape via this path. + break; + } else { + Stack.push_back(Succ); + Queued[Succ->getBlockID()] = true; + } } - return true; } + return false; } -static bool hasThrowOutNonThrowingFunc(SourceLocation &OpLoc, CFG *BodyCFG) { - - unsigned ExitID = BodyCFG->getExit().getBlockID(); - - SmallVector<ThrowState, 16> States(BodyCFG->getNumBlockIDs(), - FoundNoPathForThrow); - States[BodyCFG->getEntry().getBlockID()] = FoundPathWithNoThrowOutFunction; - - SmallVector<CFGBlock *, 16> Stack; - Stack.push_back(&BodyCFG->getEntry()); - while (!Stack.empty()) { - CFGBlock *CurBlock = Stack.pop_back_val(); - - unsigned ID = CurBlock->getBlockID(); - ThrowState CurState = States[ID]; - if (CurState == FoundPathWithNoThrowOutFunction) { - if (ExitID == ID) +static void visitReachableThrows( + CFG *BodyCFG, + llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) { + llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); + clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); + for (CFGBlock *B : *BodyCFG) { + if (!Reachable[B->getBlockID()]) + continue; + for (CFGElement &E : *B) { + Optional<CFGStmt> S = E.getAs<CFGStmt>(); + if (!S) continue; - - if (doesThrowEscapePath(*CurBlock, OpLoc)) - CurState = FoundPathForThrow; + if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) + Visit(Throw, *B); } - - // Loop over successor blocks and add them to the Stack if their state - // changes. - for (const auto &I : CurBlock->succs()) - if (I.isReachable()) { - unsigned NextID = I->getBlockID(); - if (NextID == ExitID && CurState == FoundPathForThrow) { - States[NextID] = CurState; - } else if (States[NextID] < CurState) { - States[NextID] = CurState; - Stack.push_back(I); - } - } } - // Return true if the exit node is reachable, and only reachable through - // a throw expression. - return States[ExitID] == FoundPathForThrow; } static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, @@ -405,7 +330,7 @@ static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, S.Diag(FD->getLocation(), diag::note_throw_in_dtor) << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() << FD->getExceptionSpecSourceRange(); - } else + } else S.Diag(FD->getLocation(), diag::note_throw_in_function) << FD->getExceptionSpecSourceRange(); } @@ -418,14 +343,15 @@ static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, return; if (BodyCFG->getExit().pred_empty()) return; - SourceLocation OpLoc; - if (hasThrowOutNonThrowingFunc(OpLoc, BodyCFG)) - EmitDiagForCXXThrowInNonThrowingFunc(S, OpLoc, FD); + visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { + if (throwEscapes(S, Throw, Block, BodyCFG)) + EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); + }); } static bool isNoexcept(const FunctionDecl *FD) { const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); - if (FPT->isNothrow(FD->getASTContext()) || FD->hasAttr<NoThrowAttr>()) + if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()) return true; return false; } @@ -491,9 +417,10 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { CFGBlock::FilterOptions FO; FO.IgnoreDefaultsWithCoveredEnums = 1; - for (CFGBlock::filtered_pred_iterator - I = cfg->getExit().filtered_pred_start_end(FO); I.hasMore(); ++I) { - const CFGBlock& B = **I; + for (CFGBlock::filtered_pred_iterator I = + cfg->getExit().filtered_pred_start_end(FO); + I.hasMore(); ++I) { + const CFGBlock &B = **I; if (!live[B.getBlockID()]) continue; @@ -598,18 +525,18 @@ struct CheckFallThroughDiagnostics { bool isVirtualMethod = false; if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) isVirtualMethod = Method->isVirtual(); - + // Don't suggest that template instantiations be marked "noreturn" bool isTemplateInstantiation = false; if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) isTemplateInstantiation = Function->isTemplateInstantiation(); - + if (!isVirtualMethod && !isTemplateInstantiation) D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function; else D.diag_NeverFallThroughOrReturn = 0; - + D.funMode = Function; return D; } @@ -683,18 +610,19 @@ struct CheckFallThroughDiagnostics { } // anonymous namespace -/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a +/// CheckFallThroughForBody - Check that we don't fall off the end of a /// function that should return a value. Check that we don't fall off the end /// 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, - const CheckFallThroughDiagnostics& CD, - AnalysisDeclContext &AC) { + const CheckFallThroughDiagnostics &CD, + AnalysisDeclContext &AC, + sema::FunctionScopeInfo *FSI) { bool ReturnsVoid = false; bool HasNoReturn = false; - bool IsCoroutine = S.getCurFunction() && S.getCurFunction()->isCoroutine(); + bool IsCoroutine = FSI->isCoroutine(); if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) @@ -726,10 +654,15 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, SourceLocation LBrace = Body->getLocStart(), RBrace = Body->getLocEnd(); auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { if (IsCoroutine) - S.Diag(Loc, DiagID) << S.getCurFunction()->CoroutinePromise->getType(); + S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); else S.Diag(Loc, DiagID); }; + + // cpu_dispatch functions permit empty function bodies for ICC compatibility. + if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion()) + return; + // Either in a function body compound statement, or a function-try-block. switch (CheckFallThrough(AC)) { case UnknownFallThrough: @@ -1293,7 +1226,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction) { // Only perform this analysis when using [[]] attributes. There is no good // workflow for this warning when not using C++11. There is no good way to - // silence the warning (no attribute is available) unless we are using + // silence the warning (no attribute is available) unless we are using // [[]] attributes. One could use pragmas to silence the warning, but as a // general solution that is gross and not in the spirit of this warning. // @@ -1461,8 +1394,8 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, // Sort by first use so that we emit the warnings in a deterministic order. SourceManager &SM = S.getSourceManager(); - std::sort(UsesByStmt.begin(), UsesByStmt.end(), - [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { + llvm::sort(UsesByStmt.begin(), UsesByStmt.end(), + [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { return SM.isBeforeInTranslationUnit(LHS.first->getLocStart(), RHS.first->getLocStart()); }); @@ -1559,7 +1492,7 @@ class UninitValsDiagReporter : public UninitVariablesHandler { // order of diagnostics when calling flushDiagnostics(). typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; UsesMap uses; - + public: UninitValsDiagReporter(Sema &S) : S(S) {} ~UninitValsDiagReporter() override { flushDiagnostics(); } @@ -1575,11 +1508,11 @@ public: const UninitUse &use) override { getUses(vd).getPointer()->push_back(use); } - + void handleSelfInit(const VarDecl *vd) override { getUses(vd).setInt(true); } - + void flushDiagnostics() { for (const auto &P : uses) { const VarDecl *vd = P.first; @@ -1588,7 +1521,7 @@ public: UsesVec *vec = V.getPointer(); bool hasSelfInit = V.getInt(); - // Specially handle the case where we have uses of an uninitialized + // Specially handle the case where we have uses of an uninitialized // variable, but the root cause is an idiomatic self-init. We want // to report the diagnostic at the self-init since that is the root cause. if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) @@ -1600,8 +1533,8 @@ public: // Sort the uses by their SourceLocations. While not strictly // guaranteed to produce them in line/column order, this will provide // a stable ordering. - std::sort(vec->begin(), vec->end(), - [](const UninitUse &a, const UninitUse &b) { + llvm::sort(vec->begin(), vec->end(), + [](const UninitUse &a, const UninitUse &b) { // Prefer a more confident report over a less confident one. if (a.getKind() != b.getKind()) return a.getKind() > b.getKind(); @@ -1618,7 +1551,7 @@ public: break; } } - + // Release the uses vector. delete vec; } @@ -1674,7 +1607,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); return OptionalNotes(1, FNote); } return OptionalNotes(); @@ -1685,7 +1618,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); ONS.push_back(std::move(FNote)); } return ONS; @@ -1699,7 +1632,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { if (Verbose && CurrentFunction) { PartialDiagnosticAt FNote(CurrentFunction->getBody()->getLocStart(), S.PDiag(diag::note_thread_warning_in_fun) - << CurrentFunction->getNameAsString()); + << CurrentFunction); ONS.push_back(std::move(FNote)); } return ONS; @@ -1723,7 +1656,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { void setVerbose(bool b) { Verbose = b; } - /// \brief Emit all buffered diagnostics in order of sourcelocation. + /// Emit all buffered diagnostics in order of sourcelocation. /// We need to output diagnostics produced while iterating through /// the lockset in deterministic order, so this function orders diagnostics /// and outputs them. @@ -1815,7 +1748,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { diag::warn_variable_requires_any_lock: diag::warn_var_deref_requires_any_lock; PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) - << D->getNameAsString() << getLockKindFromAccessKind(AK)); + << D << getLockKindFromAccessKind(AK)); Warnings.emplace_back(std::move(Warning), getNotes()); } @@ -1843,7 +1776,7 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D->getNameAsString() + << D << LockName << LK); PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) << *PossibleMatch); @@ -1873,12 +1806,11 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { break; } PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind - << D->getNameAsString() + << D << LockName << LK); if (Verbose && POK == POK_VarAccess) { PartialDiagnosticAt Note(D->getLocation(), - S.PDiag(diag::note_guarded_by_declared_here) - << D->getNameAsString()); + S.PDiag(diag::note_guarded_by_declared_here)); Warnings.emplace_back(std::move(Warning), getNotes(Note)); } else Warnings.emplace_back(std::move(Warning), getNotes()); @@ -1933,10 +1865,10 @@ namespace clang { namespace consumed { namespace { class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { - + Sema &S; DiagList Warnings; - + public: ConsumedWarningsHandler(Sema &S) : S(S) {} @@ -1957,28 +1889,28 @@ public: Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnParamReturnTypestateMismatch(SourceLocation Loc, StringRef VariableName, StringRef ExpectedState, StringRef ObservedState) override { - + PartialDiagnosticAt Warning(Loc, S.PDiag( diag::warn_param_return_typestate_mismatch) << VariableName << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState) override { - + PartialDiagnosticAt Warning(Loc, S.PDiag( diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnReturnTypestateForUnconsumableType(SourceLocation Loc, StringRef TypeName) override { PartialDiagnosticAt Warning(Loc, S.PDiag( @@ -1986,28 +1918,28 @@ public: Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, StringRef ObservedState) override { - + PartialDiagnosticAt Warning(Loc, S.PDiag( diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, SourceLocation Loc) override { - + PartialDiagnosticAt Warning(Loc, S.PDiag( diag::warn_use_of_temp_in_invalid_state) << MethodName << State); Warnings.emplace_back(std::move(Warning), OptionalNotes()); } - + void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, StringRef State, SourceLocation Loc) override { - + PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << MethodName << VariableName << State); @@ -2095,7 +2027,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, flushDiagnostics(S, fscope); return; } - + const Stmt *Body = D->getBody(); assert(Body); @@ -2181,7 +2113,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (!analyzed) flushDiagnostics(S, fscope); } - + // Warning: check missing 'return' if (P.enableCheckFallThrough) { const CheckFallThroughDiagnostics &CD = @@ -2194,7 +2126,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, : (fscope->isCoroutine() ? CheckFallThroughDiagnostics::MakeForCoroutine(D) : CheckFallThroughDiagnostics::MakeForFunction(D))); - CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); + CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC, fscope); } // Warning: check for unreachable code |
