10b57cec5SDimitry Andric //=- AnalysisBasedWarnings.cpp - Sema warnings based on libAnalysis -*- C++ -*-=// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This file defines analysis_warnings::[Policy,Executor]. 100b57cec5SDimitry Andric // Together they are used by Sema to issue warnings based on inexpensive 110b57cec5SDimitry Andric // static analysis algorithms in libAnalysis. 120b57cec5SDimitry Andric // 130b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 140b57cec5SDimitry Andric 150b57cec5SDimitry Andric #include "clang/Sema/AnalysisBasedWarnings.h" 160b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h" 170b57cec5SDimitry Andric #include "clang/AST/DeclObjC.h" 180b57cec5SDimitry Andric #include "clang/AST/EvaluatedExprVisitor.h" 190b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h" 200b57cec5SDimitry Andric #include "clang/AST/ExprObjC.h" 210b57cec5SDimitry Andric #include "clang/AST/ParentMap.h" 220b57cec5SDimitry Andric #include "clang/AST/RecursiveASTVisitor.h" 230b57cec5SDimitry Andric #include "clang/AST/StmtCXX.h" 240b57cec5SDimitry Andric #include "clang/AST/StmtObjC.h" 250b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h" 260b57cec5SDimitry Andric #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" 270b57cec5SDimitry Andric #include "clang/Analysis/Analyses/Consumed.h" 280b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ReachableCode.h" 290b57cec5SDimitry Andric #include "clang/Analysis/Analyses/ThreadSafety.h" 300b57cec5SDimitry Andric #include "clang/Analysis/Analyses/UninitializedValues.h" 310b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h" 320b57cec5SDimitry Andric #include "clang/Analysis/CFG.h" 330b57cec5SDimitry Andric #include "clang/Analysis/CFGStmtMap.h" 340b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h" 350b57cec5SDimitry Andric #include "clang/Basic/SourceManager.h" 360b57cec5SDimitry Andric #include "clang/Lex/Preprocessor.h" 370b57cec5SDimitry Andric #include "clang/Sema/ScopeInfo.h" 380b57cec5SDimitry Andric #include "clang/Sema/SemaInternal.h" 390b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 400b57cec5SDimitry Andric #include "llvm/ADT/MapVector.h" 410b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h" 420b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 430b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 440b57cec5SDimitry Andric #include "llvm/Support/Casting.h" 450b57cec5SDimitry Andric #include <algorithm> 460b57cec5SDimitry Andric #include <deque> 470b57cec5SDimitry Andric #include <iterator> 480b57cec5SDimitry Andric 490b57cec5SDimitry Andric using namespace clang; 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 520b57cec5SDimitry Andric // Unreachable code analysis. 530b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 540b57cec5SDimitry Andric 550b57cec5SDimitry Andric namespace { 560b57cec5SDimitry Andric class UnreachableCodeHandler : public reachable_code::Callback { 570b57cec5SDimitry Andric Sema &S; 580b57cec5SDimitry Andric SourceRange PreviousSilenceableCondVal; 590b57cec5SDimitry Andric 600b57cec5SDimitry Andric public: 610b57cec5SDimitry Andric UnreachableCodeHandler(Sema &s) : S(s) {} 620b57cec5SDimitry Andric 630b57cec5SDimitry Andric void HandleUnreachable(reachable_code::UnreachableKind UK, 640b57cec5SDimitry Andric SourceLocation L, 650b57cec5SDimitry Andric SourceRange SilenceableCondVal, 660b57cec5SDimitry Andric SourceRange R1, 670b57cec5SDimitry Andric SourceRange R2) override { 680b57cec5SDimitry Andric // Avoid reporting multiple unreachable code diagnostics that are 690b57cec5SDimitry Andric // triggered by the same conditional value. 700b57cec5SDimitry Andric if (PreviousSilenceableCondVal.isValid() && 710b57cec5SDimitry Andric SilenceableCondVal.isValid() && 720b57cec5SDimitry Andric PreviousSilenceableCondVal == SilenceableCondVal) 730b57cec5SDimitry Andric return; 740b57cec5SDimitry Andric PreviousSilenceableCondVal = SilenceableCondVal; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric unsigned diag = diag::warn_unreachable; 770b57cec5SDimitry Andric switch (UK) { 780b57cec5SDimitry Andric case reachable_code::UK_Break: 790b57cec5SDimitry Andric diag = diag::warn_unreachable_break; 800b57cec5SDimitry Andric break; 810b57cec5SDimitry Andric case reachable_code::UK_Return: 820b57cec5SDimitry Andric diag = diag::warn_unreachable_return; 830b57cec5SDimitry Andric break; 840b57cec5SDimitry Andric case reachable_code::UK_Loop_Increment: 850b57cec5SDimitry Andric diag = diag::warn_unreachable_loop_increment; 860b57cec5SDimitry Andric break; 870b57cec5SDimitry Andric case reachable_code::UK_Other: 880b57cec5SDimitry Andric break; 890b57cec5SDimitry Andric } 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric S.Diag(L, diag) << R1 << R2; 920b57cec5SDimitry Andric 930b57cec5SDimitry Andric SourceLocation Open = SilenceableCondVal.getBegin(); 940b57cec5SDimitry Andric if (Open.isValid()) { 950b57cec5SDimitry Andric SourceLocation Close = SilenceableCondVal.getEnd(); 960b57cec5SDimitry Andric Close = S.getLocForEndOfToken(Close); 970b57cec5SDimitry Andric if (Close.isValid()) { 980b57cec5SDimitry Andric S.Diag(Open, diag::note_unreachable_silence) 990b57cec5SDimitry Andric << FixItHint::CreateInsertion(Open, "/* DISABLES CODE */ (") 1000b57cec5SDimitry Andric << FixItHint::CreateInsertion(Close, ")"); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric } 1030b57cec5SDimitry Andric } 1040b57cec5SDimitry Andric }; 1050b57cec5SDimitry Andric } // anonymous namespace 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric /// CheckUnreachable - Check for unreachable code. 1080b57cec5SDimitry Andric static void CheckUnreachable(Sema &S, AnalysisDeclContext &AC) { 1090b57cec5SDimitry Andric // As a heuristic prune all diagnostics not in the main file. Currently 1100b57cec5SDimitry Andric // the majority of warnings in headers are false positives. These 1110b57cec5SDimitry Andric // are largely caused by configuration state, e.g. preprocessor 1120b57cec5SDimitry Andric // defined code, etc. 1130b57cec5SDimitry Andric // 1140b57cec5SDimitry Andric // Note that this is also a performance optimization. Analyzing 1150b57cec5SDimitry Andric // headers many times can be expensive. 1160b57cec5SDimitry Andric if (!S.getSourceManager().isInMainFile(AC.getDecl()->getBeginLoc())) 1170b57cec5SDimitry Andric return; 1180b57cec5SDimitry Andric 1190b57cec5SDimitry Andric UnreachableCodeHandler UC(S); 1200b57cec5SDimitry Andric reachable_code::FindUnreachableCode(AC, S.getPreprocessor(), UC); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric namespace { 1240b57cec5SDimitry Andric /// Warn on logical operator errors in CFGBuilder 1250b57cec5SDimitry Andric class LogicalErrorHandler : public CFGCallback { 1260b57cec5SDimitry Andric Sema &S; 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric public: 1290b57cec5SDimitry Andric LogicalErrorHandler(Sema &S) : CFGCallback(), S(S) {} 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric static bool HasMacroID(const Expr *E) { 1320b57cec5SDimitry Andric if (E->getExprLoc().isMacroID()) 1330b57cec5SDimitry Andric return true; 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // Recurse to children. 1360b57cec5SDimitry Andric for (const Stmt *SubStmt : E->children()) 1370b57cec5SDimitry Andric if (const Expr *SubExpr = dyn_cast_or_null<Expr>(SubStmt)) 1380b57cec5SDimitry Andric if (HasMacroID(SubExpr)) 1390b57cec5SDimitry Andric return true; 1400b57cec5SDimitry Andric 1410b57cec5SDimitry Andric return false; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric 1440b57cec5SDimitry Andric void compareAlwaysTrue(const BinaryOperator *B, bool isAlwaysTrue) override { 1450b57cec5SDimitry Andric if (HasMacroID(B)) 1460b57cec5SDimitry Andric return; 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric SourceRange DiagRange = B->getSourceRange(); 1490b57cec5SDimitry Andric S.Diag(B->getExprLoc(), diag::warn_tautological_overlap_comparison) 1500b57cec5SDimitry Andric << DiagRange << isAlwaysTrue; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric void compareBitwiseEquality(const BinaryOperator *B, 1540b57cec5SDimitry Andric bool isAlwaysTrue) override { 1550b57cec5SDimitry Andric if (HasMacroID(B)) 1560b57cec5SDimitry Andric return; 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric SourceRange DiagRange = B->getSourceRange(); 1590b57cec5SDimitry Andric S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_always) 1600b57cec5SDimitry Andric << DiagRange << isAlwaysTrue; 1610b57cec5SDimitry Andric } 162*a7dea167SDimitry Andric 163*a7dea167SDimitry Andric void compareBitwiseOr(const BinaryOperator *B) override { 164*a7dea167SDimitry Andric if (HasMacroID(B)) 165*a7dea167SDimitry Andric return; 166*a7dea167SDimitry Andric 167*a7dea167SDimitry Andric SourceRange DiagRange = B->getSourceRange(); 168*a7dea167SDimitry Andric S.Diag(B->getExprLoc(), diag::warn_comparison_bitwise_or) << DiagRange; 169*a7dea167SDimitry Andric } 170*a7dea167SDimitry Andric 171*a7dea167SDimitry Andric static bool hasActiveDiagnostics(DiagnosticsEngine &Diags, 172*a7dea167SDimitry Andric SourceLocation Loc) { 173*a7dea167SDimitry Andric return !Diags.isIgnored(diag::warn_tautological_overlap_comparison, Loc) || 174*a7dea167SDimitry Andric !Diags.isIgnored(diag::warn_comparison_bitwise_or, Loc); 175*a7dea167SDimitry Andric } 1760b57cec5SDimitry Andric }; 1770b57cec5SDimitry Andric } // anonymous namespace 1780b57cec5SDimitry Andric 1790b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1800b57cec5SDimitry Andric // Check for infinite self-recursion in functions 1810b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric // Returns true if the function is called anywhere within the CFGBlock. 1840b57cec5SDimitry Andric // For member functions, the additional condition of being call from the 1850b57cec5SDimitry Andric // this pointer is required. 1860b57cec5SDimitry Andric static bool hasRecursiveCallInPath(const FunctionDecl *FD, CFGBlock &Block) { 1870b57cec5SDimitry Andric // Process all the Stmt's in this block to find any calls to FD. 1880b57cec5SDimitry Andric for (const auto &B : Block) { 1890b57cec5SDimitry Andric if (B.getKind() != CFGElement::Statement) 1900b57cec5SDimitry Andric continue; 1910b57cec5SDimitry Andric 1920b57cec5SDimitry Andric const CallExpr *CE = dyn_cast<CallExpr>(B.getAs<CFGStmt>()->getStmt()); 1930b57cec5SDimitry Andric if (!CE || !CE->getCalleeDecl() || 1940b57cec5SDimitry Andric CE->getCalleeDecl()->getCanonicalDecl() != FD) 1950b57cec5SDimitry Andric continue; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Skip function calls which are qualified with a templated class. 1980b57cec5SDimitry Andric if (const DeclRefExpr *DRE = 1990b57cec5SDimitry Andric dyn_cast<DeclRefExpr>(CE->getCallee()->IgnoreParenImpCasts())) { 2000b57cec5SDimitry Andric if (NestedNameSpecifier *NNS = DRE->getQualifier()) { 2010b57cec5SDimitry Andric if (NNS->getKind() == NestedNameSpecifier::TypeSpec && 2020b57cec5SDimitry Andric isa<TemplateSpecializationType>(NNS->getAsType())) { 2030b57cec5SDimitry Andric continue; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric 2080b57cec5SDimitry Andric const CXXMemberCallExpr *MCE = dyn_cast<CXXMemberCallExpr>(CE); 2090b57cec5SDimitry Andric if (!MCE || isa<CXXThisExpr>(MCE->getImplicitObjectArgument()) || 2100b57cec5SDimitry Andric !MCE->getMethodDecl()->isVirtual()) 2110b57cec5SDimitry Andric return true; 2120b57cec5SDimitry Andric } 2130b57cec5SDimitry Andric return false; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Returns true if every path from the entry block passes through a call to FD. 2170b57cec5SDimitry Andric static bool checkForRecursiveFunctionCall(const FunctionDecl *FD, CFG *cfg) { 2180b57cec5SDimitry Andric llvm::SmallPtrSet<CFGBlock *, 16> Visited; 2190b57cec5SDimitry Andric llvm::SmallVector<CFGBlock *, 16> WorkList; 2200b57cec5SDimitry Andric // Keep track of whether we found at least one recursive path. 2210b57cec5SDimitry Andric bool foundRecursion = false; 2220b57cec5SDimitry Andric 2230b57cec5SDimitry Andric const unsigned ExitID = cfg->getExit().getBlockID(); 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric // Seed the work list with the entry block. 2260b57cec5SDimitry Andric WorkList.push_back(&cfg->getEntry()); 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric while (!WorkList.empty()) { 2290b57cec5SDimitry Andric CFGBlock *Block = WorkList.pop_back_val(); 2300b57cec5SDimitry Andric 2310b57cec5SDimitry Andric for (auto I = Block->succ_begin(), E = Block->succ_end(); I != E; ++I) { 2320b57cec5SDimitry Andric if (CFGBlock *SuccBlock = *I) { 2330b57cec5SDimitry Andric if (!Visited.insert(SuccBlock).second) 2340b57cec5SDimitry Andric continue; 2350b57cec5SDimitry Andric 2360b57cec5SDimitry Andric // Found a path to the exit node without a recursive call. 2370b57cec5SDimitry Andric if (ExitID == SuccBlock->getBlockID()) 2380b57cec5SDimitry Andric return false; 2390b57cec5SDimitry Andric 2400b57cec5SDimitry Andric // If the successor block contains a recursive call, end analysis there. 2410b57cec5SDimitry Andric if (hasRecursiveCallInPath(FD, *SuccBlock)) { 2420b57cec5SDimitry Andric foundRecursion = true; 2430b57cec5SDimitry Andric continue; 2440b57cec5SDimitry Andric } 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric WorkList.push_back(SuccBlock); 2470b57cec5SDimitry Andric } 2480b57cec5SDimitry Andric } 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric return foundRecursion; 2510b57cec5SDimitry Andric } 2520b57cec5SDimitry Andric 2530b57cec5SDimitry Andric static void checkRecursiveFunction(Sema &S, const FunctionDecl *FD, 2540b57cec5SDimitry Andric const Stmt *Body, AnalysisDeclContext &AC) { 2550b57cec5SDimitry Andric FD = FD->getCanonicalDecl(); 2560b57cec5SDimitry Andric 2570b57cec5SDimitry Andric // Only run on non-templated functions and non-templated members of 2580b57cec5SDimitry Andric // templated classes. 2590b57cec5SDimitry Andric if (FD->getTemplatedKind() != FunctionDecl::TK_NonTemplate && 2600b57cec5SDimitry Andric FD->getTemplatedKind() != FunctionDecl::TK_MemberSpecialization) 2610b57cec5SDimitry Andric return; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric CFG *cfg = AC.getCFG(); 2640b57cec5SDimitry Andric if (!cfg) return; 2650b57cec5SDimitry Andric 2660b57cec5SDimitry Andric // If the exit block is unreachable, skip processing the function. 2670b57cec5SDimitry Andric if (cfg->getExit().pred_empty()) 2680b57cec5SDimitry Andric return; 2690b57cec5SDimitry Andric 2700b57cec5SDimitry Andric // Emit diagnostic if a recursive function call is detected for all paths. 2710b57cec5SDimitry Andric if (checkForRecursiveFunctionCall(FD, cfg)) 2720b57cec5SDimitry Andric S.Diag(Body->getBeginLoc(), diag::warn_infinite_recursive_function); 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2760b57cec5SDimitry Andric // Check for throw in a non-throwing function. 2770b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 2780b57cec5SDimitry Andric 2790b57cec5SDimitry Andric /// Determine whether an exception thrown by E, unwinding from ThrowBlock, 2800b57cec5SDimitry Andric /// can reach ExitBlock. 2810b57cec5SDimitry Andric static bool throwEscapes(Sema &S, const CXXThrowExpr *E, CFGBlock &ThrowBlock, 2820b57cec5SDimitry Andric CFG *Body) { 2830b57cec5SDimitry Andric SmallVector<CFGBlock *, 16> Stack; 2840b57cec5SDimitry Andric llvm::BitVector Queued(Body->getNumBlockIDs()); 2850b57cec5SDimitry Andric 2860b57cec5SDimitry Andric Stack.push_back(&ThrowBlock); 2870b57cec5SDimitry Andric Queued[ThrowBlock.getBlockID()] = true; 2880b57cec5SDimitry Andric 2890b57cec5SDimitry Andric while (!Stack.empty()) { 2900b57cec5SDimitry Andric CFGBlock &UnwindBlock = *Stack.back(); 2910b57cec5SDimitry Andric Stack.pop_back(); 2920b57cec5SDimitry Andric 2930b57cec5SDimitry Andric for (auto &Succ : UnwindBlock.succs()) { 2940b57cec5SDimitry Andric if (!Succ.isReachable() || Queued[Succ->getBlockID()]) 2950b57cec5SDimitry Andric continue; 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric if (Succ->getBlockID() == Body->getExit().getBlockID()) 2980b57cec5SDimitry Andric return true; 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric if (auto *Catch = 3010b57cec5SDimitry Andric dyn_cast_or_null<CXXCatchStmt>(Succ->getLabel())) { 3020b57cec5SDimitry Andric QualType Caught = Catch->getCaughtType(); 3030b57cec5SDimitry Andric if (Caught.isNull() || // catch (...) catches everything 3040b57cec5SDimitry Andric !E->getSubExpr() || // throw; is considered cuaght by any handler 3050b57cec5SDimitry Andric S.handlerCanCatch(Caught, E->getSubExpr()->getType())) 3060b57cec5SDimitry Andric // Exception doesn't escape via this path. 3070b57cec5SDimitry Andric break; 3080b57cec5SDimitry Andric } else { 3090b57cec5SDimitry Andric Stack.push_back(Succ); 3100b57cec5SDimitry Andric Queued[Succ->getBlockID()] = true; 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric } 3140b57cec5SDimitry Andric 3150b57cec5SDimitry Andric return false; 3160b57cec5SDimitry Andric } 3170b57cec5SDimitry Andric 3180b57cec5SDimitry Andric static void visitReachableThrows( 3190b57cec5SDimitry Andric CFG *BodyCFG, 3200b57cec5SDimitry Andric llvm::function_ref<void(const CXXThrowExpr *, CFGBlock &)> Visit) { 3210b57cec5SDimitry Andric llvm::BitVector Reachable(BodyCFG->getNumBlockIDs()); 3220b57cec5SDimitry Andric clang::reachable_code::ScanReachableFromBlock(&BodyCFG->getEntry(), Reachable); 3230b57cec5SDimitry Andric for (CFGBlock *B : *BodyCFG) { 3240b57cec5SDimitry Andric if (!Reachable[B->getBlockID()]) 3250b57cec5SDimitry Andric continue; 3260b57cec5SDimitry Andric for (CFGElement &E : *B) { 3270b57cec5SDimitry Andric Optional<CFGStmt> S = E.getAs<CFGStmt>(); 3280b57cec5SDimitry Andric if (!S) 3290b57cec5SDimitry Andric continue; 3300b57cec5SDimitry Andric if (auto *Throw = dyn_cast<CXXThrowExpr>(S->getStmt())) 3310b57cec5SDimitry Andric Visit(Throw, *B); 3320b57cec5SDimitry Andric } 3330b57cec5SDimitry Andric } 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric static void EmitDiagForCXXThrowInNonThrowingFunc(Sema &S, SourceLocation OpLoc, 3370b57cec5SDimitry Andric const FunctionDecl *FD) { 3380b57cec5SDimitry Andric if (!S.getSourceManager().isInSystemHeader(OpLoc) && 3390b57cec5SDimitry Andric FD->getTypeSourceInfo()) { 3400b57cec5SDimitry Andric S.Diag(OpLoc, diag::warn_throw_in_noexcept_func) << FD; 3410b57cec5SDimitry Andric if (S.getLangOpts().CPlusPlus11 && 3420b57cec5SDimitry Andric (isa<CXXDestructorDecl>(FD) || 3430b57cec5SDimitry Andric FD->getDeclName().getCXXOverloadedOperator() == OO_Delete || 3440b57cec5SDimitry Andric FD->getDeclName().getCXXOverloadedOperator() == OO_Array_Delete)) { 3450b57cec5SDimitry Andric if (const auto *Ty = FD->getTypeSourceInfo()->getType()-> 3460b57cec5SDimitry Andric getAs<FunctionProtoType>()) 3470b57cec5SDimitry Andric S.Diag(FD->getLocation(), diag::note_throw_in_dtor) 3480b57cec5SDimitry Andric << !isa<CXXDestructorDecl>(FD) << !Ty->hasExceptionSpec() 3490b57cec5SDimitry Andric << FD->getExceptionSpecSourceRange(); 3500b57cec5SDimitry Andric } else 3510b57cec5SDimitry Andric S.Diag(FD->getLocation(), diag::note_throw_in_function) 3520b57cec5SDimitry Andric << FD->getExceptionSpecSourceRange(); 3530b57cec5SDimitry Andric } 3540b57cec5SDimitry Andric } 3550b57cec5SDimitry Andric 3560b57cec5SDimitry Andric static void checkThrowInNonThrowingFunc(Sema &S, const FunctionDecl *FD, 3570b57cec5SDimitry Andric AnalysisDeclContext &AC) { 3580b57cec5SDimitry Andric CFG *BodyCFG = AC.getCFG(); 3590b57cec5SDimitry Andric if (!BodyCFG) 3600b57cec5SDimitry Andric return; 3610b57cec5SDimitry Andric if (BodyCFG->getExit().pred_empty()) 3620b57cec5SDimitry Andric return; 3630b57cec5SDimitry Andric visitReachableThrows(BodyCFG, [&](const CXXThrowExpr *Throw, CFGBlock &Block) { 3640b57cec5SDimitry Andric if (throwEscapes(S, Throw, Block, BodyCFG)) 3650b57cec5SDimitry Andric EmitDiagForCXXThrowInNonThrowingFunc(S, Throw->getThrowLoc(), FD); 3660b57cec5SDimitry Andric }); 3670b57cec5SDimitry Andric } 3680b57cec5SDimitry Andric 3690b57cec5SDimitry Andric static bool isNoexcept(const FunctionDecl *FD) { 3700b57cec5SDimitry Andric const auto *FPT = FD->getType()->castAs<FunctionProtoType>(); 3710b57cec5SDimitry Andric if (FPT->isNothrow() || FD->hasAttr<NoThrowAttr>()) 3720b57cec5SDimitry Andric return true; 3730b57cec5SDimitry Andric return false; 3740b57cec5SDimitry Andric } 3750b57cec5SDimitry Andric 3760b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3770b57cec5SDimitry Andric // Check for missing return value. 3780b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 3790b57cec5SDimitry Andric 3800b57cec5SDimitry Andric enum ControlFlowKind { 3810b57cec5SDimitry Andric UnknownFallThrough, 3820b57cec5SDimitry Andric NeverFallThrough, 3830b57cec5SDimitry Andric MaybeFallThrough, 3840b57cec5SDimitry Andric AlwaysFallThrough, 3850b57cec5SDimitry Andric NeverFallThroughOrReturn 3860b57cec5SDimitry Andric }; 3870b57cec5SDimitry Andric 3880b57cec5SDimitry Andric /// CheckFallThrough - Check that we don't fall off the end of a 3890b57cec5SDimitry Andric /// Statement that should return a value. 3900b57cec5SDimitry Andric /// 3910b57cec5SDimitry Andric /// \returns AlwaysFallThrough iff we always fall off the end of the statement, 3920b57cec5SDimitry Andric /// MaybeFallThrough iff we might or might not fall off the end, 3930b57cec5SDimitry Andric /// NeverFallThroughOrReturn iff we never fall off the end of the statement or 3940b57cec5SDimitry Andric /// return. We assume NeverFallThrough iff we never fall off the end of the 3950b57cec5SDimitry Andric /// statement but we may return. We assume that functions not marked noreturn 3960b57cec5SDimitry Andric /// will return. 3970b57cec5SDimitry Andric static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { 3980b57cec5SDimitry Andric CFG *cfg = AC.getCFG(); 3990b57cec5SDimitry Andric if (!cfg) return UnknownFallThrough; 4000b57cec5SDimitry Andric 4010b57cec5SDimitry Andric // The CFG leaves in dead things, and we don't want the dead code paths to 4020b57cec5SDimitry Andric // confuse us, so we mark all live things first. 4030b57cec5SDimitry Andric llvm::BitVector live(cfg->getNumBlockIDs()); 4040b57cec5SDimitry Andric unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), 4050b57cec5SDimitry Andric live); 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric bool AddEHEdges = AC.getAddEHEdges(); 4080b57cec5SDimitry Andric if (!AddEHEdges && count != cfg->getNumBlockIDs()) 4090b57cec5SDimitry Andric // When there are things remaining dead, and we didn't add EH edges 4100b57cec5SDimitry Andric // from CallExprs to the catch clauses, we have to go back and 4110b57cec5SDimitry Andric // mark them as live. 4120b57cec5SDimitry Andric for (const auto *B : *cfg) { 4130b57cec5SDimitry Andric if (!live[B->getBlockID()]) { 4140b57cec5SDimitry Andric if (B->pred_begin() == B->pred_end()) { 4150b57cec5SDimitry Andric const Stmt *Term = B->getTerminatorStmt(); 4160b57cec5SDimitry Andric if (Term && isa<CXXTryStmt>(Term)) 4170b57cec5SDimitry Andric // When not adding EH edges from calls, catch clauses 4180b57cec5SDimitry Andric // can otherwise seem dead. Avoid noting them as dead. 4190b57cec5SDimitry Andric count += reachable_code::ScanReachableFromBlock(B, live); 4200b57cec5SDimitry Andric continue; 4210b57cec5SDimitry Andric } 4220b57cec5SDimitry Andric } 4230b57cec5SDimitry Andric } 4240b57cec5SDimitry Andric 4250b57cec5SDimitry Andric // Now we know what is live, we check the live precessors of the exit block 4260b57cec5SDimitry Andric // and look for fall through paths, being careful to ignore normal returns, 4270b57cec5SDimitry Andric // and exceptional paths. 4280b57cec5SDimitry Andric bool HasLiveReturn = false; 4290b57cec5SDimitry Andric bool HasFakeEdge = false; 4300b57cec5SDimitry Andric bool HasPlainEdge = false; 4310b57cec5SDimitry Andric bool HasAbnormalEdge = false; 4320b57cec5SDimitry Andric 4330b57cec5SDimitry Andric // Ignore default cases that aren't likely to be reachable because all 4340b57cec5SDimitry Andric // enums in a switch(X) have explicit case statements. 4350b57cec5SDimitry Andric CFGBlock::FilterOptions FO; 4360b57cec5SDimitry Andric FO.IgnoreDefaultsWithCoveredEnums = 1; 4370b57cec5SDimitry Andric 4380b57cec5SDimitry Andric for (CFGBlock::filtered_pred_iterator I = 4390b57cec5SDimitry Andric cfg->getExit().filtered_pred_start_end(FO); 4400b57cec5SDimitry Andric I.hasMore(); ++I) { 4410b57cec5SDimitry Andric const CFGBlock &B = **I; 4420b57cec5SDimitry Andric if (!live[B.getBlockID()]) 4430b57cec5SDimitry Andric continue; 4440b57cec5SDimitry Andric 4450b57cec5SDimitry Andric // Skip blocks which contain an element marked as no-return. They don't 4460b57cec5SDimitry Andric // represent actually viable edges into the exit block, so mark them as 4470b57cec5SDimitry Andric // abnormal. 4480b57cec5SDimitry Andric if (B.hasNoReturnElement()) { 4490b57cec5SDimitry Andric HasAbnormalEdge = true; 4500b57cec5SDimitry Andric continue; 4510b57cec5SDimitry Andric } 4520b57cec5SDimitry Andric 4530b57cec5SDimitry Andric // Destructors can appear after the 'return' in the CFG. This is 4540b57cec5SDimitry Andric // normal. We need to look pass the destructors for the return 4550b57cec5SDimitry Andric // statement (if it exists). 4560b57cec5SDimitry Andric CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); 4570b57cec5SDimitry Andric 4580b57cec5SDimitry Andric for ( ; ri != re ; ++ri) 4590b57cec5SDimitry Andric if (ri->getAs<CFGStmt>()) 4600b57cec5SDimitry Andric break; 4610b57cec5SDimitry Andric 4620b57cec5SDimitry Andric // No more CFGElements in the block? 4630b57cec5SDimitry Andric if (ri == re) { 4640b57cec5SDimitry Andric const Stmt *Term = B.getTerminatorStmt(); 4650b57cec5SDimitry Andric if (Term && isa<CXXTryStmt>(Term)) { 4660b57cec5SDimitry Andric HasAbnormalEdge = true; 4670b57cec5SDimitry Andric continue; 4680b57cec5SDimitry Andric } 4690b57cec5SDimitry Andric // A labeled empty statement, or the entry block... 4700b57cec5SDimitry Andric HasPlainEdge = true; 4710b57cec5SDimitry Andric continue; 4720b57cec5SDimitry Andric } 4730b57cec5SDimitry Andric 4740b57cec5SDimitry Andric CFGStmt CS = ri->castAs<CFGStmt>(); 4750b57cec5SDimitry Andric const Stmt *S = CS.getStmt(); 4760b57cec5SDimitry Andric if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { 4770b57cec5SDimitry Andric HasLiveReturn = true; 4780b57cec5SDimitry Andric continue; 4790b57cec5SDimitry Andric } 4800b57cec5SDimitry Andric if (isa<ObjCAtThrowStmt>(S)) { 4810b57cec5SDimitry Andric HasFakeEdge = true; 4820b57cec5SDimitry Andric continue; 4830b57cec5SDimitry Andric } 4840b57cec5SDimitry Andric if (isa<CXXThrowExpr>(S)) { 4850b57cec5SDimitry Andric HasFakeEdge = true; 4860b57cec5SDimitry Andric continue; 4870b57cec5SDimitry Andric } 4880b57cec5SDimitry Andric if (isa<MSAsmStmt>(S)) { 4890b57cec5SDimitry Andric // TODO: Verify this is correct. 4900b57cec5SDimitry Andric HasFakeEdge = true; 4910b57cec5SDimitry Andric HasLiveReturn = true; 4920b57cec5SDimitry Andric continue; 4930b57cec5SDimitry Andric } 4940b57cec5SDimitry Andric if (isa<CXXTryStmt>(S)) { 4950b57cec5SDimitry Andric HasAbnormalEdge = true; 4960b57cec5SDimitry Andric continue; 4970b57cec5SDimitry Andric } 4980b57cec5SDimitry Andric if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) 4990b57cec5SDimitry Andric == B.succ_end()) { 5000b57cec5SDimitry Andric HasAbnormalEdge = true; 5010b57cec5SDimitry Andric continue; 5020b57cec5SDimitry Andric } 5030b57cec5SDimitry Andric 5040b57cec5SDimitry Andric HasPlainEdge = true; 5050b57cec5SDimitry Andric } 5060b57cec5SDimitry Andric if (!HasPlainEdge) { 5070b57cec5SDimitry Andric if (HasLiveReturn) 5080b57cec5SDimitry Andric return NeverFallThrough; 5090b57cec5SDimitry Andric return NeverFallThroughOrReturn; 5100b57cec5SDimitry Andric } 5110b57cec5SDimitry Andric if (HasAbnormalEdge || HasFakeEdge || HasLiveReturn) 5120b57cec5SDimitry Andric return MaybeFallThrough; 5130b57cec5SDimitry Andric // This says AlwaysFallThrough for calls to functions that are not marked 5140b57cec5SDimitry Andric // noreturn, that don't return. If people would like this warning to be more 5150b57cec5SDimitry Andric // accurate, such functions should be marked as noreturn. 5160b57cec5SDimitry Andric return AlwaysFallThrough; 5170b57cec5SDimitry Andric } 5180b57cec5SDimitry Andric 5190b57cec5SDimitry Andric namespace { 5200b57cec5SDimitry Andric 5210b57cec5SDimitry Andric struct CheckFallThroughDiagnostics { 5220b57cec5SDimitry Andric unsigned diag_MaybeFallThrough_HasNoReturn; 5230b57cec5SDimitry Andric unsigned diag_MaybeFallThrough_ReturnsNonVoid; 5240b57cec5SDimitry Andric unsigned diag_AlwaysFallThrough_HasNoReturn; 5250b57cec5SDimitry Andric unsigned diag_AlwaysFallThrough_ReturnsNonVoid; 5260b57cec5SDimitry Andric unsigned diag_NeverFallThroughOrReturn; 5270b57cec5SDimitry Andric enum { Function, Block, Lambda, Coroutine } funMode; 5280b57cec5SDimitry Andric SourceLocation FuncLoc; 5290b57cec5SDimitry Andric 5300b57cec5SDimitry Andric static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { 5310b57cec5SDimitry Andric CheckFallThroughDiagnostics D; 5320b57cec5SDimitry Andric D.FuncLoc = Func->getLocation(); 5330b57cec5SDimitry Andric D.diag_MaybeFallThrough_HasNoReturn = 5340b57cec5SDimitry Andric diag::warn_falloff_noreturn_function; 5350b57cec5SDimitry Andric D.diag_MaybeFallThrough_ReturnsNonVoid = 5360b57cec5SDimitry Andric diag::warn_maybe_falloff_nonvoid_function; 5370b57cec5SDimitry Andric D.diag_AlwaysFallThrough_HasNoReturn = 5380b57cec5SDimitry Andric diag::warn_falloff_noreturn_function; 5390b57cec5SDimitry Andric D.diag_AlwaysFallThrough_ReturnsNonVoid = 5400b57cec5SDimitry Andric diag::warn_falloff_nonvoid_function; 5410b57cec5SDimitry Andric 5420b57cec5SDimitry Andric // Don't suggest that virtual functions be marked "noreturn", since they 5430b57cec5SDimitry Andric // might be overridden by non-noreturn functions. 5440b57cec5SDimitry Andric bool isVirtualMethod = false; 5450b57cec5SDimitry Andric if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) 5460b57cec5SDimitry Andric isVirtualMethod = Method->isVirtual(); 5470b57cec5SDimitry Andric 5480b57cec5SDimitry Andric // Don't suggest that template instantiations be marked "noreturn" 5490b57cec5SDimitry Andric bool isTemplateInstantiation = false; 5500b57cec5SDimitry Andric if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) 5510b57cec5SDimitry Andric isTemplateInstantiation = Function->isTemplateInstantiation(); 5520b57cec5SDimitry Andric 5530b57cec5SDimitry Andric if (!isVirtualMethod && !isTemplateInstantiation) 5540b57cec5SDimitry Andric D.diag_NeverFallThroughOrReturn = 5550b57cec5SDimitry Andric diag::warn_suggest_noreturn_function; 5560b57cec5SDimitry Andric else 5570b57cec5SDimitry Andric D.diag_NeverFallThroughOrReturn = 0; 5580b57cec5SDimitry Andric 5590b57cec5SDimitry Andric D.funMode = Function; 5600b57cec5SDimitry Andric return D; 5610b57cec5SDimitry Andric } 5620b57cec5SDimitry Andric 5630b57cec5SDimitry Andric static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { 5640b57cec5SDimitry Andric CheckFallThroughDiagnostics D; 5650b57cec5SDimitry Andric D.FuncLoc = Func->getLocation(); 5660b57cec5SDimitry Andric D.diag_MaybeFallThrough_HasNoReturn = 0; 5670b57cec5SDimitry Andric D.diag_MaybeFallThrough_ReturnsNonVoid = 5680b57cec5SDimitry Andric diag::warn_maybe_falloff_nonvoid_coroutine; 5690b57cec5SDimitry Andric D.diag_AlwaysFallThrough_HasNoReturn = 0; 5700b57cec5SDimitry Andric D.diag_AlwaysFallThrough_ReturnsNonVoid = 5710b57cec5SDimitry Andric diag::warn_falloff_nonvoid_coroutine; 5720b57cec5SDimitry Andric D.funMode = Coroutine; 5730b57cec5SDimitry Andric return D; 5740b57cec5SDimitry Andric } 5750b57cec5SDimitry Andric 5760b57cec5SDimitry Andric static CheckFallThroughDiagnostics MakeForBlock() { 5770b57cec5SDimitry Andric CheckFallThroughDiagnostics D; 5780b57cec5SDimitry Andric D.diag_MaybeFallThrough_HasNoReturn = 5790b57cec5SDimitry Andric diag::err_noreturn_block_has_return_expr; 5800b57cec5SDimitry Andric D.diag_MaybeFallThrough_ReturnsNonVoid = 5810b57cec5SDimitry Andric diag::err_maybe_falloff_nonvoid_block; 5820b57cec5SDimitry Andric D.diag_AlwaysFallThrough_HasNoReturn = 5830b57cec5SDimitry Andric diag::err_noreturn_block_has_return_expr; 5840b57cec5SDimitry Andric D.diag_AlwaysFallThrough_ReturnsNonVoid = 5850b57cec5SDimitry Andric diag::err_falloff_nonvoid_block; 5860b57cec5SDimitry Andric D.diag_NeverFallThroughOrReturn = 0; 5870b57cec5SDimitry Andric D.funMode = Block; 5880b57cec5SDimitry Andric return D; 5890b57cec5SDimitry Andric } 5900b57cec5SDimitry Andric 5910b57cec5SDimitry Andric static CheckFallThroughDiagnostics MakeForLambda() { 5920b57cec5SDimitry Andric CheckFallThroughDiagnostics D; 5930b57cec5SDimitry Andric D.diag_MaybeFallThrough_HasNoReturn = 5940b57cec5SDimitry Andric diag::err_noreturn_lambda_has_return_expr; 5950b57cec5SDimitry Andric D.diag_MaybeFallThrough_ReturnsNonVoid = 5960b57cec5SDimitry Andric diag::warn_maybe_falloff_nonvoid_lambda; 5970b57cec5SDimitry Andric D.diag_AlwaysFallThrough_HasNoReturn = 5980b57cec5SDimitry Andric diag::err_noreturn_lambda_has_return_expr; 5990b57cec5SDimitry Andric D.diag_AlwaysFallThrough_ReturnsNonVoid = 6000b57cec5SDimitry Andric diag::warn_falloff_nonvoid_lambda; 6010b57cec5SDimitry Andric D.diag_NeverFallThroughOrReturn = 0; 6020b57cec5SDimitry Andric D.funMode = Lambda; 6030b57cec5SDimitry Andric return D; 6040b57cec5SDimitry Andric } 6050b57cec5SDimitry Andric 6060b57cec5SDimitry Andric bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, 6070b57cec5SDimitry Andric bool HasNoReturn) const { 6080b57cec5SDimitry Andric if (funMode == Function) { 6090b57cec5SDimitry Andric return (ReturnsVoid || 6100b57cec5SDimitry Andric D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, 6110b57cec5SDimitry Andric FuncLoc)) && 6120b57cec5SDimitry Andric (!HasNoReturn || 6130b57cec5SDimitry Andric D.isIgnored(diag::warn_noreturn_function_has_return_expr, 6140b57cec5SDimitry Andric FuncLoc)) && 6150b57cec5SDimitry Andric (!ReturnsVoid || 6160b57cec5SDimitry Andric D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); 6170b57cec5SDimitry Andric } 6180b57cec5SDimitry Andric if (funMode == Coroutine) { 6190b57cec5SDimitry Andric return (ReturnsVoid || 6200b57cec5SDimitry Andric D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || 6210b57cec5SDimitry Andric D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, 6220b57cec5SDimitry Andric FuncLoc)) && 6230b57cec5SDimitry Andric (!HasNoReturn); 6240b57cec5SDimitry Andric } 6250b57cec5SDimitry Andric // For blocks / lambdas. 6260b57cec5SDimitry Andric return ReturnsVoid && !HasNoReturn; 6270b57cec5SDimitry Andric } 6280b57cec5SDimitry Andric }; 6290b57cec5SDimitry Andric 6300b57cec5SDimitry Andric } // anonymous namespace 6310b57cec5SDimitry Andric 6320b57cec5SDimitry Andric /// CheckFallThroughForBody - Check that we don't fall off the end of a 6330b57cec5SDimitry Andric /// function that should return a value. Check that we don't fall off the end 6340b57cec5SDimitry Andric /// of a noreturn function. We assume that functions and blocks not marked 6350b57cec5SDimitry Andric /// noreturn will return. 6360b57cec5SDimitry Andric static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, 6370b57cec5SDimitry Andric QualType BlockType, 6380b57cec5SDimitry Andric const CheckFallThroughDiagnostics &CD, 6390b57cec5SDimitry Andric AnalysisDeclContext &AC, 6400b57cec5SDimitry Andric sema::FunctionScopeInfo *FSI) { 6410b57cec5SDimitry Andric 6420b57cec5SDimitry Andric bool ReturnsVoid = false; 6430b57cec5SDimitry Andric bool HasNoReturn = false; 6440b57cec5SDimitry Andric bool IsCoroutine = FSI->isCoroutine(); 6450b57cec5SDimitry Andric 6460b57cec5SDimitry Andric if (const auto *FD = dyn_cast<FunctionDecl>(D)) { 6470b57cec5SDimitry Andric if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) 6480b57cec5SDimitry Andric ReturnsVoid = CBody->getFallthroughHandler() != nullptr; 6490b57cec5SDimitry Andric else 6500b57cec5SDimitry Andric ReturnsVoid = FD->getReturnType()->isVoidType(); 6510b57cec5SDimitry Andric HasNoReturn = FD->isNoReturn(); 6520b57cec5SDimitry Andric } 6530b57cec5SDimitry Andric else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { 6540b57cec5SDimitry Andric ReturnsVoid = MD->getReturnType()->isVoidType(); 6550b57cec5SDimitry Andric HasNoReturn = MD->hasAttr<NoReturnAttr>(); 6560b57cec5SDimitry Andric } 6570b57cec5SDimitry Andric else if (isa<BlockDecl>(D)) { 6580b57cec5SDimitry Andric if (const FunctionType *FT = 6590b57cec5SDimitry Andric BlockType->getPointeeType()->getAs<FunctionType>()) { 6600b57cec5SDimitry Andric if (FT->getReturnType()->isVoidType()) 6610b57cec5SDimitry Andric ReturnsVoid = true; 6620b57cec5SDimitry Andric if (FT->getNoReturnAttr()) 6630b57cec5SDimitry Andric HasNoReturn = true; 6640b57cec5SDimitry Andric } 6650b57cec5SDimitry Andric } 6660b57cec5SDimitry Andric 6670b57cec5SDimitry Andric DiagnosticsEngine &Diags = S.getDiagnostics(); 6680b57cec5SDimitry Andric 6690b57cec5SDimitry Andric // Short circuit for compilation speed. 6700b57cec5SDimitry Andric if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) 6710b57cec5SDimitry Andric return; 6720b57cec5SDimitry Andric SourceLocation LBrace = Body->getBeginLoc(), RBrace = Body->getEndLoc(); 6730b57cec5SDimitry Andric auto EmitDiag = [&](SourceLocation Loc, unsigned DiagID) { 6740b57cec5SDimitry Andric if (IsCoroutine) 6750b57cec5SDimitry Andric S.Diag(Loc, DiagID) << FSI->CoroutinePromise->getType(); 6760b57cec5SDimitry Andric else 6770b57cec5SDimitry Andric S.Diag(Loc, DiagID); 6780b57cec5SDimitry Andric }; 6790b57cec5SDimitry Andric 6800b57cec5SDimitry Andric // cpu_dispatch functions permit empty function bodies for ICC compatibility. 6810b57cec5SDimitry Andric if (D->getAsFunction() && D->getAsFunction()->isCPUDispatchMultiVersion()) 6820b57cec5SDimitry Andric return; 6830b57cec5SDimitry Andric 6840b57cec5SDimitry Andric // Either in a function body compound statement, or a function-try-block. 6850b57cec5SDimitry Andric switch (CheckFallThrough(AC)) { 6860b57cec5SDimitry Andric case UnknownFallThrough: 6870b57cec5SDimitry Andric break; 6880b57cec5SDimitry Andric 6890b57cec5SDimitry Andric case MaybeFallThrough: 6900b57cec5SDimitry Andric if (HasNoReturn) 6910b57cec5SDimitry Andric EmitDiag(RBrace, CD.diag_MaybeFallThrough_HasNoReturn); 6920b57cec5SDimitry Andric else if (!ReturnsVoid) 6930b57cec5SDimitry Andric EmitDiag(RBrace, CD.diag_MaybeFallThrough_ReturnsNonVoid); 6940b57cec5SDimitry Andric break; 6950b57cec5SDimitry Andric case AlwaysFallThrough: 6960b57cec5SDimitry Andric if (HasNoReturn) 6970b57cec5SDimitry Andric EmitDiag(RBrace, CD.diag_AlwaysFallThrough_HasNoReturn); 6980b57cec5SDimitry Andric else if (!ReturnsVoid) 6990b57cec5SDimitry Andric EmitDiag(RBrace, CD.diag_AlwaysFallThrough_ReturnsNonVoid); 7000b57cec5SDimitry Andric break; 7010b57cec5SDimitry Andric case NeverFallThroughOrReturn: 7020b57cec5SDimitry Andric if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { 7030b57cec5SDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 7040b57cec5SDimitry Andric S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 0 << FD; 7050b57cec5SDimitry Andric } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 7060b57cec5SDimitry Andric S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn) << 1 << MD; 7070b57cec5SDimitry Andric } else { 7080b57cec5SDimitry Andric S.Diag(LBrace, CD.diag_NeverFallThroughOrReturn); 7090b57cec5SDimitry Andric } 7100b57cec5SDimitry Andric } 7110b57cec5SDimitry Andric break; 7120b57cec5SDimitry Andric case NeverFallThrough: 7130b57cec5SDimitry Andric break; 7140b57cec5SDimitry Andric } 7150b57cec5SDimitry Andric } 7160b57cec5SDimitry Andric 7170b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7180b57cec5SDimitry Andric // -Wuninitialized 7190b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 7200b57cec5SDimitry Andric 7210b57cec5SDimitry Andric namespace { 7220b57cec5SDimitry Andric /// ContainsReference - A visitor class to search for references to 7230b57cec5SDimitry Andric /// a particular declaration (the needle) within any evaluated component of an 7240b57cec5SDimitry Andric /// expression (recursively). 7250b57cec5SDimitry Andric class ContainsReference : public ConstEvaluatedExprVisitor<ContainsReference> { 7260b57cec5SDimitry Andric bool FoundReference; 7270b57cec5SDimitry Andric const DeclRefExpr *Needle; 7280b57cec5SDimitry Andric 7290b57cec5SDimitry Andric public: 7300b57cec5SDimitry Andric typedef ConstEvaluatedExprVisitor<ContainsReference> Inherited; 7310b57cec5SDimitry Andric 7320b57cec5SDimitry Andric ContainsReference(ASTContext &Context, const DeclRefExpr *Needle) 7330b57cec5SDimitry Andric : Inherited(Context), FoundReference(false), Needle(Needle) {} 7340b57cec5SDimitry Andric 7350b57cec5SDimitry Andric void VisitExpr(const Expr *E) { 7360b57cec5SDimitry Andric // Stop evaluating if we already have a reference. 7370b57cec5SDimitry Andric if (FoundReference) 7380b57cec5SDimitry Andric return; 7390b57cec5SDimitry Andric 7400b57cec5SDimitry Andric Inherited::VisitExpr(E); 7410b57cec5SDimitry Andric } 7420b57cec5SDimitry Andric 7430b57cec5SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *E) { 7440b57cec5SDimitry Andric if (E == Needle) 7450b57cec5SDimitry Andric FoundReference = true; 7460b57cec5SDimitry Andric else 7470b57cec5SDimitry Andric Inherited::VisitDeclRefExpr(E); 7480b57cec5SDimitry Andric } 7490b57cec5SDimitry Andric 7500b57cec5SDimitry Andric bool doesContainReference() const { return FoundReference; } 7510b57cec5SDimitry Andric }; 7520b57cec5SDimitry Andric } // anonymous namespace 7530b57cec5SDimitry Andric 7540b57cec5SDimitry Andric static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { 7550b57cec5SDimitry Andric QualType VariableTy = VD->getType().getCanonicalType(); 7560b57cec5SDimitry Andric if (VariableTy->isBlockPointerType() && 7570b57cec5SDimitry Andric !VD->hasAttr<BlocksAttr>()) { 7580b57cec5SDimitry Andric S.Diag(VD->getLocation(), diag::note_block_var_fixit_add_initialization) 7590b57cec5SDimitry Andric << VD->getDeclName() 7600b57cec5SDimitry Andric << FixItHint::CreateInsertion(VD->getLocation(), "__block "); 7610b57cec5SDimitry Andric return true; 7620b57cec5SDimitry Andric } 7630b57cec5SDimitry Andric 7640b57cec5SDimitry Andric // Don't issue a fixit if there is already an initializer. 7650b57cec5SDimitry Andric if (VD->getInit()) 7660b57cec5SDimitry Andric return false; 7670b57cec5SDimitry Andric 7680b57cec5SDimitry Andric // Don't suggest a fixit inside macros. 7690b57cec5SDimitry Andric if (VD->getEndLoc().isMacroID()) 7700b57cec5SDimitry Andric return false; 7710b57cec5SDimitry Andric 7720b57cec5SDimitry Andric SourceLocation Loc = S.getLocForEndOfToken(VD->getEndLoc()); 7730b57cec5SDimitry Andric 7740b57cec5SDimitry Andric // Suggest possible initialization (if any). 7750b57cec5SDimitry Andric std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc); 7760b57cec5SDimitry Andric if (Init.empty()) 7770b57cec5SDimitry Andric return false; 7780b57cec5SDimitry Andric 7790b57cec5SDimitry Andric S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() 7800b57cec5SDimitry Andric << FixItHint::CreateInsertion(Loc, Init); 7810b57cec5SDimitry Andric return true; 7820b57cec5SDimitry Andric } 7830b57cec5SDimitry Andric 7840b57cec5SDimitry Andric /// Create a fixit to remove an if-like statement, on the assumption that its 7850b57cec5SDimitry Andric /// condition is CondVal. 7860b57cec5SDimitry Andric static void CreateIfFixit(Sema &S, const Stmt *If, const Stmt *Then, 7870b57cec5SDimitry Andric const Stmt *Else, bool CondVal, 7880b57cec5SDimitry Andric FixItHint &Fixit1, FixItHint &Fixit2) { 7890b57cec5SDimitry Andric if (CondVal) { 7900b57cec5SDimitry Andric // If condition is always true, remove all but the 'then'. 7910b57cec5SDimitry Andric Fixit1 = FixItHint::CreateRemoval( 7920b57cec5SDimitry Andric CharSourceRange::getCharRange(If->getBeginLoc(), Then->getBeginLoc())); 7930b57cec5SDimitry Andric if (Else) { 7940b57cec5SDimitry Andric SourceLocation ElseKwLoc = S.getLocForEndOfToken(Then->getEndLoc()); 7950b57cec5SDimitry Andric Fixit2 = 7960b57cec5SDimitry Andric FixItHint::CreateRemoval(SourceRange(ElseKwLoc, Else->getEndLoc())); 7970b57cec5SDimitry Andric } 7980b57cec5SDimitry Andric } else { 7990b57cec5SDimitry Andric // If condition is always false, remove all but the 'else'. 8000b57cec5SDimitry Andric if (Else) 8010b57cec5SDimitry Andric Fixit1 = FixItHint::CreateRemoval(CharSourceRange::getCharRange( 8020b57cec5SDimitry Andric If->getBeginLoc(), Else->getBeginLoc())); 8030b57cec5SDimitry Andric else 8040b57cec5SDimitry Andric Fixit1 = FixItHint::CreateRemoval(If->getSourceRange()); 8050b57cec5SDimitry Andric } 8060b57cec5SDimitry Andric } 8070b57cec5SDimitry Andric 8080b57cec5SDimitry Andric /// DiagUninitUse -- Helper function to produce a diagnostic for an 8090b57cec5SDimitry Andric /// uninitialized use of a variable. 8100b57cec5SDimitry Andric static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, 8110b57cec5SDimitry Andric bool IsCapturedByBlock) { 8120b57cec5SDimitry Andric bool Diagnosed = false; 8130b57cec5SDimitry Andric 8140b57cec5SDimitry Andric switch (Use.getKind()) { 8150b57cec5SDimitry Andric case UninitUse::Always: 8160b57cec5SDimitry Andric S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_var) 8170b57cec5SDimitry Andric << VD->getDeclName() << IsCapturedByBlock 8180b57cec5SDimitry Andric << Use.getUser()->getSourceRange(); 8190b57cec5SDimitry Andric return; 8200b57cec5SDimitry Andric 8210b57cec5SDimitry Andric case UninitUse::AfterDecl: 8220b57cec5SDimitry Andric case UninitUse::AfterCall: 8230b57cec5SDimitry Andric S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var) 8240b57cec5SDimitry Andric << VD->getDeclName() << IsCapturedByBlock 8250b57cec5SDimitry Andric << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5) 8260b57cec5SDimitry Andric << const_cast<DeclContext*>(VD->getLexicalDeclContext()) 8270b57cec5SDimitry Andric << VD->getSourceRange(); 8280b57cec5SDimitry Andric S.Diag(Use.getUser()->getBeginLoc(), diag::note_uninit_var_use) 8290b57cec5SDimitry Andric << IsCapturedByBlock << Use.getUser()->getSourceRange(); 8300b57cec5SDimitry Andric return; 8310b57cec5SDimitry Andric 8320b57cec5SDimitry Andric case UninitUse::Maybe: 8330b57cec5SDimitry Andric case UninitUse::Sometimes: 8340b57cec5SDimitry Andric // Carry on to report sometimes-uninitialized branches, if possible, 8350b57cec5SDimitry Andric // or a 'may be used uninitialized' diagnostic otherwise. 8360b57cec5SDimitry Andric break; 8370b57cec5SDimitry Andric } 8380b57cec5SDimitry Andric 8390b57cec5SDimitry Andric // Diagnose each branch which leads to a sometimes-uninitialized use. 8400b57cec5SDimitry Andric for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end(); 8410b57cec5SDimitry Andric I != E; ++I) { 8420b57cec5SDimitry Andric assert(Use.getKind() == UninitUse::Sometimes); 8430b57cec5SDimitry Andric 8440b57cec5SDimitry Andric const Expr *User = Use.getUser(); 8450b57cec5SDimitry Andric const Stmt *Term = I->Terminator; 8460b57cec5SDimitry Andric 8470b57cec5SDimitry Andric // Information used when building the diagnostic. 8480b57cec5SDimitry Andric unsigned DiagKind; 8490b57cec5SDimitry Andric StringRef Str; 8500b57cec5SDimitry Andric SourceRange Range; 8510b57cec5SDimitry Andric 8520b57cec5SDimitry Andric // FixIts to suppress the diagnostic by removing the dead condition. 8530b57cec5SDimitry Andric // For all binary terminators, branch 0 is taken if the condition is true, 8540b57cec5SDimitry Andric // and branch 1 is taken if the condition is false. 8550b57cec5SDimitry Andric int RemoveDiagKind = -1; 8560b57cec5SDimitry Andric const char *FixitStr = 8570b57cec5SDimitry Andric S.getLangOpts().CPlusPlus ? (I->Output ? "true" : "false") 8580b57cec5SDimitry Andric : (I->Output ? "1" : "0"); 8590b57cec5SDimitry Andric FixItHint Fixit1, Fixit2; 8600b57cec5SDimitry Andric 8610b57cec5SDimitry Andric switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) { 8620b57cec5SDimitry Andric default: 8630b57cec5SDimitry Andric // Don't know how to report this. Just fall back to 'may be used 8640b57cec5SDimitry Andric // uninitialized'. FIXME: Can this happen? 8650b57cec5SDimitry Andric continue; 8660b57cec5SDimitry Andric 8670b57cec5SDimitry Andric // "condition is true / condition is false". 8680b57cec5SDimitry Andric case Stmt::IfStmtClass: { 8690b57cec5SDimitry Andric const IfStmt *IS = cast<IfStmt>(Term); 8700b57cec5SDimitry Andric DiagKind = 0; 8710b57cec5SDimitry Andric Str = "if"; 8720b57cec5SDimitry Andric Range = IS->getCond()->getSourceRange(); 8730b57cec5SDimitry Andric RemoveDiagKind = 0; 8740b57cec5SDimitry Andric CreateIfFixit(S, IS, IS->getThen(), IS->getElse(), 8750b57cec5SDimitry Andric I->Output, Fixit1, Fixit2); 8760b57cec5SDimitry Andric break; 8770b57cec5SDimitry Andric } 8780b57cec5SDimitry Andric case Stmt::ConditionalOperatorClass: { 8790b57cec5SDimitry Andric const ConditionalOperator *CO = cast<ConditionalOperator>(Term); 8800b57cec5SDimitry Andric DiagKind = 0; 8810b57cec5SDimitry Andric Str = "?:"; 8820b57cec5SDimitry Andric Range = CO->getCond()->getSourceRange(); 8830b57cec5SDimitry Andric RemoveDiagKind = 0; 8840b57cec5SDimitry Andric CreateIfFixit(S, CO, CO->getTrueExpr(), CO->getFalseExpr(), 8850b57cec5SDimitry Andric I->Output, Fixit1, Fixit2); 8860b57cec5SDimitry Andric break; 8870b57cec5SDimitry Andric } 8880b57cec5SDimitry Andric case Stmt::BinaryOperatorClass: { 8890b57cec5SDimitry Andric const BinaryOperator *BO = cast<BinaryOperator>(Term); 8900b57cec5SDimitry Andric if (!BO->isLogicalOp()) 8910b57cec5SDimitry Andric continue; 8920b57cec5SDimitry Andric DiagKind = 0; 8930b57cec5SDimitry Andric Str = BO->getOpcodeStr(); 8940b57cec5SDimitry Andric Range = BO->getLHS()->getSourceRange(); 8950b57cec5SDimitry Andric RemoveDiagKind = 0; 8960b57cec5SDimitry Andric if ((BO->getOpcode() == BO_LAnd && I->Output) || 8970b57cec5SDimitry Andric (BO->getOpcode() == BO_LOr && !I->Output)) 8980b57cec5SDimitry Andric // true && y -> y, false || y -> y. 8990b57cec5SDimitry Andric Fixit1 = FixItHint::CreateRemoval( 9000b57cec5SDimitry Andric SourceRange(BO->getBeginLoc(), BO->getOperatorLoc())); 9010b57cec5SDimitry Andric else 9020b57cec5SDimitry Andric // false && y -> false, true || y -> true. 9030b57cec5SDimitry Andric Fixit1 = FixItHint::CreateReplacement(BO->getSourceRange(), FixitStr); 9040b57cec5SDimitry Andric break; 9050b57cec5SDimitry Andric } 9060b57cec5SDimitry Andric 9070b57cec5SDimitry Andric // "loop is entered / loop is exited". 9080b57cec5SDimitry Andric case Stmt::WhileStmtClass: 9090b57cec5SDimitry Andric DiagKind = 1; 9100b57cec5SDimitry Andric Str = "while"; 9110b57cec5SDimitry Andric Range = cast<WhileStmt>(Term)->getCond()->getSourceRange(); 9120b57cec5SDimitry Andric RemoveDiagKind = 1; 9130b57cec5SDimitry Andric Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 9140b57cec5SDimitry Andric break; 9150b57cec5SDimitry Andric case Stmt::ForStmtClass: 9160b57cec5SDimitry Andric DiagKind = 1; 9170b57cec5SDimitry Andric Str = "for"; 9180b57cec5SDimitry Andric Range = cast<ForStmt>(Term)->getCond()->getSourceRange(); 9190b57cec5SDimitry Andric RemoveDiagKind = 1; 9200b57cec5SDimitry Andric if (I->Output) 9210b57cec5SDimitry Andric Fixit1 = FixItHint::CreateRemoval(Range); 9220b57cec5SDimitry Andric else 9230b57cec5SDimitry Andric Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 9240b57cec5SDimitry Andric break; 9250b57cec5SDimitry Andric case Stmt::CXXForRangeStmtClass: 9260b57cec5SDimitry Andric if (I->Output == 1) { 9270b57cec5SDimitry Andric // The use occurs if a range-based for loop's body never executes. 9280b57cec5SDimitry Andric // That may be impossible, and there's no syntactic fix for this, 9290b57cec5SDimitry Andric // so treat it as a 'may be uninitialized' case. 9300b57cec5SDimitry Andric continue; 9310b57cec5SDimitry Andric } 9320b57cec5SDimitry Andric DiagKind = 1; 9330b57cec5SDimitry Andric Str = "for"; 9340b57cec5SDimitry Andric Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange(); 9350b57cec5SDimitry Andric break; 9360b57cec5SDimitry Andric 9370b57cec5SDimitry Andric // "condition is true / loop is exited". 9380b57cec5SDimitry Andric case Stmt::DoStmtClass: 9390b57cec5SDimitry Andric DiagKind = 2; 9400b57cec5SDimitry Andric Str = "do"; 9410b57cec5SDimitry Andric Range = cast<DoStmt>(Term)->getCond()->getSourceRange(); 9420b57cec5SDimitry Andric RemoveDiagKind = 1; 9430b57cec5SDimitry Andric Fixit1 = FixItHint::CreateReplacement(Range, FixitStr); 9440b57cec5SDimitry Andric break; 9450b57cec5SDimitry Andric 9460b57cec5SDimitry Andric // "switch case is taken". 9470b57cec5SDimitry Andric case Stmt::CaseStmtClass: 9480b57cec5SDimitry Andric DiagKind = 3; 9490b57cec5SDimitry Andric Str = "case"; 9500b57cec5SDimitry Andric Range = cast<CaseStmt>(Term)->getLHS()->getSourceRange(); 9510b57cec5SDimitry Andric break; 9520b57cec5SDimitry Andric case Stmt::DefaultStmtClass: 9530b57cec5SDimitry Andric DiagKind = 3; 9540b57cec5SDimitry Andric Str = "default"; 9550b57cec5SDimitry Andric Range = cast<DefaultStmt>(Term)->getDefaultLoc(); 9560b57cec5SDimitry Andric break; 9570b57cec5SDimitry Andric } 9580b57cec5SDimitry Andric 9590b57cec5SDimitry Andric S.Diag(Range.getBegin(), diag::warn_sometimes_uninit_var) 9600b57cec5SDimitry Andric << VD->getDeclName() << IsCapturedByBlock << DiagKind 9610b57cec5SDimitry Andric << Str << I->Output << Range; 9620b57cec5SDimitry Andric S.Diag(User->getBeginLoc(), diag::note_uninit_var_use) 9630b57cec5SDimitry Andric << IsCapturedByBlock << User->getSourceRange(); 9640b57cec5SDimitry Andric if (RemoveDiagKind != -1) 9650b57cec5SDimitry Andric S.Diag(Fixit1.RemoveRange.getBegin(), diag::note_uninit_fixit_remove_cond) 9660b57cec5SDimitry Andric << RemoveDiagKind << Str << I->Output << Fixit1 << Fixit2; 9670b57cec5SDimitry Andric 9680b57cec5SDimitry Andric Diagnosed = true; 9690b57cec5SDimitry Andric } 9700b57cec5SDimitry Andric 9710b57cec5SDimitry Andric if (!Diagnosed) 9720b57cec5SDimitry Andric S.Diag(Use.getUser()->getBeginLoc(), diag::warn_maybe_uninit_var) 9730b57cec5SDimitry Andric << VD->getDeclName() << IsCapturedByBlock 9740b57cec5SDimitry Andric << Use.getUser()->getSourceRange(); 9750b57cec5SDimitry Andric } 9760b57cec5SDimitry Andric 9770b57cec5SDimitry Andric /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an 9780b57cec5SDimitry Andric /// uninitialized variable. This manages the different forms of diagnostic 9790b57cec5SDimitry Andric /// emitted for particular types of uses. Returns true if the use was diagnosed 9800b57cec5SDimitry Andric /// as a warning. If a particular use is one we omit warnings for, returns 9810b57cec5SDimitry Andric /// false. 9820b57cec5SDimitry Andric static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, 9830b57cec5SDimitry Andric const UninitUse &Use, 9840b57cec5SDimitry Andric bool alwaysReportSelfInit = false) { 9850b57cec5SDimitry Andric if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Use.getUser())) { 9860b57cec5SDimitry Andric // Inspect the initializer of the variable declaration which is 9870b57cec5SDimitry Andric // being referenced prior to its initialization. We emit 9880b57cec5SDimitry Andric // specialized diagnostics for self-initialization, and we 9890b57cec5SDimitry Andric // specifically avoid warning about self references which take the 9900b57cec5SDimitry Andric // form of: 9910b57cec5SDimitry Andric // 9920b57cec5SDimitry Andric // int x = x; 9930b57cec5SDimitry Andric // 9940b57cec5SDimitry Andric // This is used to indicate to GCC that 'x' is intentionally left 9950b57cec5SDimitry Andric // uninitialized. Proven code paths which access 'x' in 9960b57cec5SDimitry Andric // an uninitialized state after this will still warn. 9970b57cec5SDimitry Andric if (const Expr *Initializer = VD->getInit()) { 9980b57cec5SDimitry Andric if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) 9990b57cec5SDimitry Andric return false; 10000b57cec5SDimitry Andric 10010b57cec5SDimitry Andric ContainsReference CR(S.Context, DRE); 10020b57cec5SDimitry Andric CR.Visit(Initializer); 10030b57cec5SDimitry Andric if (CR.doesContainReference()) { 10040b57cec5SDimitry Andric S.Diag(DRE->getBeginLoc(), diag::warn_uninit_self_reference_in_init) 10050b57cec5SDimitry Andric << VD->getDeclName() << VD->getLocation() << DRE->getSourceRange(); 10060b57cec5SDimitry Andric return true; 10070b57cec5SDimitry Andric } 10080b57cec5SDimitry Andric } 10090b57cec5SDimitry Andric 10100b57cec5SDimitry Andric DiagUninitUse(S, VD, Use, false); 10110b57cec5SDimitry Andric } else { 10120b57cec5SDimitry Andric const BlockExpr *BE = cast<BlockExpr>(Use.getUser()); 10130b57cec5SDimitry Andric if (VD->getType()->isBlockPointerType() && !VD->hasAttr<BlocksAttr>()) 10140b57cec5SDimitry Andric S.Diag(BE->getBeginLoc(), 10150b57cec5SDimitry Andric diag::warn_uninit_byref_blockvar_captured_by_block) 10160b57cec5SDimitry Andric << VD->getDeclName() 10170b57cec5SDimitry Andric << VD->getType().getQualifiers().hasObjCLifetime(); 10180b57cec5SDimitry Andric else 10190b57cec5SDimitry Andric DiagUninitUse(S, VD, Use, true); 10200b57cec5SDimitry Andric } 10210b57cec5SDimitry Andric 10220b57cec5SDimitry Andric // Report where the variable was declared when the use wasn't within 10230b57cec5SDimitry Andric // the initializer of that declaration & we didn't already suggest 10240b57cec5SDimitry Andric // an initialization fixit. 10250b57cec5SDimitry Andric if (!SuggestInitializationFixit(S, VD)) 10260b57cec5SDimitry Andric S.Diag(VD->getBeginLoc(), diag::note_var_declared_here) 10270b57cec5SDimitry Andric << VD->getDeclName(); 10280b57cec5SDimitry Andric 10290b57cec5SDimitry Andric return true; 10300b57cec5SDimitry Andric } 10310b57cec5SDimitry Andric 10320b57cec5SDimitry Andric namespace { 10330b57cec5SDimitry Andric class FallthroughMapper : public RecursiveASTVisitor<FallthroughMapper> { 10340b57cec5SDimitry Andric public: 10350b57cec5SDimitry Andric FallthroughMapper(Sema &S) 10360b57cec5SDimitry Andric : FoundSwitchStatements(false), 10370b57cec5SDimitry Andric S(S) { 10380b57cec5SDimitry Andric } 10390b57cec5SDimitry Andric 10400b57cec5SDimitry Andric bool foundSwitchStatements() const { return FoundSwitchStatements; } 10410b57cec5SDimitry Andric 10420b57cec5SDimitry Andric void markFallthroughVisited(const AttributedStmt *Stmt) { 10430b57cec5SDimitry Andric bool Found = FallthroughStmts.erase(Stmt); 10440b57cec5SDimitry Andric assert(Found); 10450b57cec5SDimitry Andric (void)Found; 10460b57cec5SDimitry Andric } 10470b57cec5SDimitry Andric 10480b57cec5SDimitry Andric typedef llvm::SmallPtrSet<const AttributedStmt*, 8> AttrStmts; 10490b57cec5SDimitry Andric 10500b57cec5SDimitry Andric const AttrStmts &getFallthroughStmts() const { 10510b57cec5SDimitry Andric return FallthroughStmts; 10520b57cec5SDimitry Andric } 10530b57cec5SDimitry Andric 10540b57cec5SDimitry Andric void fillReachableBlocks(CFG *Cfg) { 10550b57cec5SDimitry Andric assert(ReachableBlocks.empty() && "ReachableBlocks already filled"); 10560b57cec5SDimitry Andric std::deque<const CFGBlock *> BlockQueue; 10570b57cec5SDimitry Andric 10580b57cec5SDimitry Andric ReachableBlocks.insert(&Cfg->getEntry()); 10590b57cec5SDimitry Andric BlockQueue.push_back(&Cfg->getEntry()); 10600b57cec5SDimitry Andric // Mark all case blocks reachable to avoid problems with switching on 10610b57cec5SDimitry Andric // constants, covered enums, etc. 10620b57cec5SDimitry Andric // These blocks can contain fall-through annotations, and we don't want to 10630b57cec5SDimitry Andric // issue a warn_fallthrough_attr_unreachable for them. 10640b57cec5SDimitry Andric for (const auto *B : *Cfg) { 10650b57cec5SDimitry Andric const Stmt *L = B->getLabel(); 10660b57cec5SDimitry Andric if (L && isa<SwitchCase>(L) && ReachableBlocks.insert(B).second) 10670b57cec5SDimitry Andric BlockQueue.push_back(B); 10680b57cec5SDimitry Andric } 10690b57cec5SDimitry Andric 10700b57cec5SDimitry Andric while (!BlockQueue.empty()) { 10710b57cec5SDimitry Andric const CFGBlock *P = BlockQueue.front(); 10720b57cec5SDimitry Andric BlockQueue.pop_front(); 10730b57cec5SDimitry Andric for (CFGBlock::const_succ_iterator I = P->succ_begin(), 10740b57cec5SDimitry Andric E = P->succ_end(); 10750b57cec5SDimitry Andric I != E; ++I) { 10760b57cec5SDimitry Andric if (*I && ReachableBlocks.insert(*I).second) 10770b57cec5SDimitry Andric BlockQueue.push_back(*I); 10780b57cec5SDimitry Andric } 10790b57cec5SDimitry Andric } 10800b57cec5SDimitry Andric } 10810b57cec5SDimitry Andric 10820b57cec5SDimitry Andric bool checkFallThroughIntoBlock(const CFGBlock &B, int &AnnotatedCnt, 10830b57cec5SDimitry Andric bool IsTemplateInstantiation) { 10840b57cec5SDimitry Andric assert(!ReachableBlocks.empty() && "ReachableBlocks empty"); 10850b57cec5SDimitry Andric 10860b57cec5SDimitry Andric int UnannotatedCnt = 0; 10870b57cec5SDimitry Andric AnnotatedCnt = 0; 10880b57cec5SDimitry Andric 10890b57cec5SDimitry Andric std::deque<const CFGBlock*> BlockQueue(B.pred_begin(), B.pred_end()); 10900b57cec5SDimitry Andric while (!BlockQueue.empty()) { 10910b57cec5SDimitry Andric const CFGBlock *P = BlockQueue.front(); 10920b57cec5SDimitry Andric BlockQueue.pop_front(); 10930b57cec5SDimitry Andric if (!P) continue; 10940b57cec5SDimitry Andric 10950b57cec5SDimitry Andric const Stmt *Term = P->getTerminatorStmt(); 10960b57cec5SDimitry Andric if (Term && isa<SwitchStmt>(Term)) 10970b57cec5SDimitry Andric continue; // Switch statement, good. 10980b57cec5SDimitry Andric 10990b57cec5SDimitry Andric const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(P->getLabel()); 11000b57cec5SDimitry Andric if (SW && SW->getSubStmt() == B.getLabel() && P->begin() == P->end()) 11010b57cec5SDimitry Andric continue; // Previous case label has no statements, good. 11020b57cec5SDimitry Andric 11030b57cec5SDimitry Andric const LabelStmt *L = dyn_cast_or_null<LabelStmt>(P->getLabel()); 11040b57cec5SDimitry Andric if (L && L->getSubStmt() == B.getLabel() && P->begin() == P->end()) 11050b57cec5SDimitry Andric continue; // Case label is preceded with a normal label, good. 11060b57cec5SDimitry Andric 11070b57cec5SDimitry Andric if (!ReachableBlocks.count(P)) { 11080b57cec5SDimitry Andric for (CFGBlock::const_reverse_iterator ElemIt = P->rbegin(), 11090b57cec5SDimitry Andric ElemEnd = P->rend(); 11100b57cec5SDimitry Andric ElemIt != ElemEnd; ++ElemIt) { 11110b57cec5SDimitry Andric if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) { 11120b57cec5SDimitry Andric if (const AttributedStmt *AS = asFallThroughAttr(CS->getStmt())) { 11130b57cec5SDimitry Andric // Don't issue a warning for an unreachable fallthrough 11140b57cec5SDimitry Andric // attribute in template instantiations as it may not be 11150b57cec5SDimitry Andric // unreachable in all instantiations of the template. 11160b57cec5SDimitry Andric if (!IsTemplateInstantiation) 11170b57cec5SDimitry Andric S.Diag(AS->getBeginLoc(), 11180b57cec5SDimitry Andric diag::warn_fallthrough_attr_unreachable); 11190b57cec5SDimitry Andric markFallthroughVisited(AS); 11200b57cec5SDimitry Andric ++AnnotatedCnt; 11210b57cec5SDimitry Andric break; 11220b57cec5SDimitry Andric } 11230b57cec5SDimitry Andric // Don't care about other unreachable statements. 11240b57cec5SDimitry Andric } 11250b57cec5SDimitry Andric } 11260b57cec5SDimitry Andric // If there are no unreachable statements, this may be a special 11270b57cec5SDimitry Andric // case in CFG: 11280b57cec5SDimitry Andric // case X: { 11290b57cec5SDimitry Andric // A a; // A has a destructor. 11300b57cec5SDimitry Andric // break; 11310b57cec5SDimitry Andric // } 11320b57cec5SDimitry Andric // // <<<< This place is represented by a 'hanging' CFG block. 11330b57cec5SDimitry Andric // case Y: 11340b57cec5SDimitry Andric continue; 11350b57cec5SDimitry Andric } 11360b57cec5SDimitry Andric 11370b57cec5SDimitry Andric const Stmt *LastStmt = getLastStmt(*P); 11380b57cec5SDimitry Andric if (const AttributedStmt *AS = asFallThroughAttr(LastStmt)) { 11390b57cec5SDimitry Andric markFallthroughVisited(AS); 11400b57cec5SDimitry Andric ++AnnotatedCnt; 11410b57cec5SDimitry Andric continue; // Fallthrough annotation, good. 11420b57cec5SDimitry Andric } 11430b57cec5SDimitry Andric 11440b57cec5SDimitry Andric if (!LastStmt) { // This block contains no executable statements. 11450b57cec5SDimitry Andric // Traverse its predecessors. 11460b57cec5SDimitry Andric std::copy(P->pred_begin(), P->pred_end(), 11470b57cec5SDimitry Andric std::back_inserter(BlockQueue)); 11480b57cec5SDimitry Andric continue; 11490b57cec5SDimitry Andric } 11500b57cec5SDimitry Andric 11510b57cec5SDimitry Andric ++UnannotatedCnt; 11520b57cec5SDimitry Andric } 11530b57cec5SDimitry Andric return !!UnannotatedCnt; 11540b57cec5SDimitry Andric } 11550b57cec5SDimitry Andric 11560b57cec5SDimitry Andric // RecursiveASTVisitor setup. 11570b57cec5SDimitry Andric bool shouldWalkTypesOfTypeLocs() const { return false; } 11580b57cec5SDimitry Andric 11590b57cec5SDimitry Andric bool VisitAttributedStmt(AttributedStmt *S) { 11600b57cec5SDimitry Andric if (asFallThroughAttr(S)) 11610b57cec5SDimitry Andric FallthroughStmts.insert(S); 11620b57cec5SDimitry Andric return true; 11630b57cec5SDimitry Andric } 11640b57cec5SDimitry Andric 11650b57cec5SDimitry Andric bool VisitSwitchStmt(SwitchStmt *S) { 11660b57cec5SDimitry Andric FoundSwitchStatements = true; 11670b57cec5SDimitry Andric return true; 11680b57cec5SDimitry Andric } 11690b57cec5SDimitry Andric 11700b57cec5SDimitry Andric // We don't want to traverse local type declarations. We analyze their 11710b57cec5SDimitry Andric // methods separately. 11720b57cec5SDimitry Andric bool TraverseDecl(Decl *D) { return true; } 11730b57cec5SDimitry Andric 11740b57cec5SDimitry Andric // We analyze lambda bodies separately. Skip them here. 11750b57cec5SDimitry Andric bool TraverseLambdaExpr(LambdaExpr *LE) { 11760b57cec5SDimitry Andric // Traverse the captures, but not the body. 11770b57cec5SDimitry Andric for (const auto &C : zip(LE->captures(), LE->capture_inits())) 11780b57cec5SDimitry Andric TraverseLambdaCapture(LE, &std::get<0>(C), std::get<1>(C)); 11790b57cec5SDimitry Andric return true; 11800b57cec5SDimitry Andric } 11810b57cec5SDimitry Andric 11820b57cec5SDimitry Andric private: 11830b57cec5SDimitry Andric 11840b57cec5SDimitry Andric static const AttributedStmt *asFallThroughAttr(const Stmt *S) { 11850b57cec5SDimitry Andric if (const AttributedStmt *AS = dyn_cast_or_null<AttributedStmt>(S)) { 11860b57cec5SDimitry Andric if (hasSpecificAttr<FallThroughAttr>(AS->getAttrs())) 11870b57cec5SDimitry Andric return AS; 11880b57cec5SDimitry Andric } 11890b57cec5SDimitry Andric return nullptr; 11900b57cec5SDimitry Andric } 11910b57cec5SDimitry Andric 11920b57cec5SDimitry Andric static const Stmt *getLastStmt(const CFGBlock &B) { 11930b57cec5SDimitry Andric if (const Stmt *Term = B.getTerminatorStmt()) 11940b57cec5SDimitry Andric return Term; 11950b57cec5SDimitry Andric for (CFGBlock::const_reverse_iterator ElemIt = B.rbegin(), 11960b57cec5SDimitry Andric ElemEnd = B.rend(); 11970b57cec5SDimitry Andric ElemIt != ElemEnd; ++ElemIt) { 11980b57cec5SDimitry Andric if (Optional<CFGStmt> CS = ElemIt->getAs<CFGStmt>()) 11990b57cec5SDimitry Andric return CS->getStmt(); 12000b57cec5SDimitry Andric } 12010b57cec5SDimitry Andric // Workaround to detect a statement thrown out by CFGBuilder: 12020b57cec5SDimitry Andric // case X: {} case Y: 12030b57cec5SDimitry Andric // case X: ; case Y: 12040b57cec5SDimitry Andric if (const SwitchCase *SW = dyn_cast_or_null<SwitchCase>(B.getLabel())) 12050b57cec5SDimitry Andric if (!isa<SwitchCase>(SW->getSubStmt())) 12060b57cec5SDimitry Andric return SW->getSubStmt(); 12070b57cec5SDimitry Andric 12080b57cec5SDimitry Andric return nullptr; 12090b57cec5SDimitry Andric } 12100b57cec5SDimitry Andric 12110b57cec5SDimitry Andric bool FoundSwitchStatements; 12120b57cec5SDimitry Andric AttrStmts FallthroughStmts; 12130b57cec5SDimitry Andric Sema &S; 12140b57cec5SDimitry Andric llvm::SmallPtrSet<const CFGBlock *, 16> ReachableBlocks; 12150b57cec5SDimitry Andric }; 12160b57cec5SDimitry Andric } // anonymous namespace 12170b57cec5SDimitry Andric 12180b57cec5SDimitry Andric static StringRef getFallthroughAttrSpelling(Preprocessor &PP, 12190b57cec5SDimitry Andric SourceLocation Loc) { 12200b57cec5SDimitry Andric TokenValue FallthroughTokens[] = { 12210b57cec5SDimitry Andric tok::l_square, tok::l_square, 12220b57cec5SDimitry Andric PP.getIdentifierInfo("fallthrough"), 12230b57cec5SDimitry Andric tok::r_square, tok::r_square 12240b57cec5SDimitry Andric }; 12250b57cec5SDimitry Andric 12260b57cec5SDimitry Andric TokenValue ClangFallthroughTokens[] = { 12270b57cec5SDimitry Andric tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), 12280b57cec5SDimitry Andric tok::coloncolon, PP.getIdentifierInfo("fallthrough"), 12290b57cec5SDimitry Andric tok::r_square, tok::r_square 12300b57cec5SDimitry Andric }; 12310b57cec5SDimitry Andric 1232*a7dea167SDimitry Andric bool PreferClangAttr = !PP.getLangOpts().CPlusPlus17 && !PP.getLangOpts().C2x; 12330b57cec5SDimitry Andric 12340b57cec5SDimitry Andric StringRef MacroName; 12350b57cec5SDimitry Andric if (PreferClangAttr) 12360b57cec5SDimitry Andric MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 12370b57cec5SDimitry Andric if (MacroName.empty()) 12380b57cec5SDimitry Andric MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); 12390b57cec5SDimitry Andric if (MacroName.empty() && !PreferClangAttr) 12400b57cec5SDimitry Andric MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); 1241*a7dea167SDimitry Andric if (MacroName.empty()) { 1242*a7dea167SDimitry Andric if (!PreferClangAttr) 1243*a7dea167SDimitry Andric MacroName = "[[fallthrough]]"; 1244*a7dea167SDimitry Andric else if (PP.getLangOpts().CPlusPlus) 1245*a7dea167SDimitry Andric MacroName = "[[clang::fallthrough]]"; 1246*a7dea167SDimitry Andric else 1247*a7dea167SDimitry Andric MacroName = "__attribute__((fallthrough))"; 1248*a7dea167SDimitry Andric } 12490b57cec5SDimitry Andric return MacroName; 12500b57cec5SDimitry Andric } 12510b57cec5SDimitry Andric 12520b57cec5SDimitry Andric static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, 12530b57cec5SDimitry Andric bool PerFunction) { 12540b57cec5SDimitry Andric FallthroughMapper FM(S); 12550b57cec5SDimitry Andric FM.TraverseStmt(AC.getBody()); 12560b57cec5SDimitry Andric 12570b57cec5SDimitry Andric if (!FM.foundSwitchStatements()) 12580b57cec5SDimitry Andric return; 12590b57cec5SDimitry Andric 12600b57cec5SDimitry Andric if (PerFunction && FM.getFallthroughStmts().empty()) 12610b57cec5SDimitry Andric return; 12620b57cec5SDimitry Andric 12630b57cec5SDimitry Andric CFG *Cfg = AC.getCFG(); 12640b57cec5SDimitry Andric 12650b57cec5SDimitry Andric if (!Cfg) 12660b57cec5SDimitry Andric return; 12670b57cec5SDimitry Andric 12680b57cec5SDimitry Andric FM.fillReachableBlocks(Cfg); 12690b57cec5SDimitry Andric 12700b57cec5SDimitry Andric for (const CFGBlock *B : llvm::reverse(*Cfg)) { 12710b57cec5SDimitry Andric const Stmt *Label = B->getLabel(); 12720b57cec5SDimitry Andric 12730b57cec5SDimitry Andric if (!Label || !isa<SwitchCase>(Label)) 12740b57cec5SDimitry Andric continue; 12750b57cec5SDimitry Andric 12760b57cec5SDimitry Andric int AnnotatedCnt; 12770b57cec5SDimitry Andric 12780b57cec5SDimitry Andric bool IsTemplateInstantiation = false; 12790b57cec5SDimitry Andric if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(AC.getDecl())) 12800b57cec5SDimitry Andric IsTemplateInstantiation = Function->isTemplateInstantiation(); 12810b57cec5SDimitry Andric if (!FM.checkFallThroughIntoBlock(*B, AnnotatedCnt, 12820b57cec5SDimitry Andric IsTemplateInstantiation)) 12830b57cec5SDimitry Andric continue; 12840b57cec5SDimitry Andric 12850b57cec5SDimitry Andric S.Diag(Label->getBeginLoc(), 12860b57cec5SDimitry Andric PerFunction ? diag::warn_unannotated_fallthrough_per_function 12870b57cec5SDimitry Andric : diag::warn_unannotated_fallthrough); 12880b57cec5SDimitry Andric 12890b57cec5SDimitry Andric if (!AnnotatedCnt) { 12900b57cec5SDimitry Andric SourceLocation L = Label->getBeginLoc(); 12910b57cec5SDimitry Andric if (L.isMacroID()) 12920b57cec5SDimitry Andric continue; 1293*a7dea167SDimitry Andric 12940b57cec5SDimitry Andric const Stmt *Term = B->getTerminatorStmt(); 12950b57cec5SDimitry Andric // Skip empty cases. 12960b57cec5SDimitry Andric while (B->empty() && !Term && B->succ_size() == 1) { 12970b57cec5SDimitry Andric B = *B->succ_begin(); 12980b57cec5SDimitry Andric Term = B->getTerminatorStmt(); 12990b57cec5SDimitry Andric } 13000b57cec5SDimitry Andric if (!(B->empty() && Term && isa<BreakStmt>(Term))) { 13010b57cec5SDimitry Andric Preprocessor &PP = S.getPreprocessor(); 13020b57cec5SDimitry Andric StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); 13030b57cec5SDimitry Andric SmallString<64> TextToInsert(AnnotationSpelling); 13040b57cec5SDimitry Andric TextToInsert += "; "; 1305*a7dea167SDimitry Andric S.Diag(L, diag::note_insert_fallthrough_fixit) 1306*a7dea167SDimitry Andric << AnnotationSpelling 1307*a7dea167SDimitry Andric << FixItHint::CreateInsertion(L, TextToInsert); 13080b57cec5SDimitry Andric } 1309*a7dea167SDimitry Andric S.Diag(L, diag::note_insert_break_fixit) 1310*a7dea167SDimitry Andric << FixItHint::CreateInsertion(L, "break; "); 13110b57cec5SDimitry Andric } 13120b57cec5SDimitry Andric } 13130b57cec5SDimitry Andric 13140b57cec5SDimitry Andric for (const auto *F : FM.getFallthroughStmts()) 13150b57cec5SDimitry Andric S.Diag(F->getBeginLoc(), diag::err_fallthrough_attr_invalid_placement); 13160b57cec5SDimitry Andric } 13170b57cec5SDimitry Andric 13180b57cec5SDimitry Andric static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, 13190b57cec5SDimitry Andric const Stmt *S) { 13200b57cec5SDimitry Andric assert(S); 13210b57cec5SDimitry Andric 13220b57cec5SDimitry Andric do { 13230b57cec5SDimitry Andric switch (S->getStmtClass()) { 13240b57cec5SDimitry Andric case Stmt::ForStmtClass: 13250b57cec5SDimitry Andric case Stmt::WhileStmtClass: 13260b57cec5SDimitry Andric case Stmt::CXXForRangeStmtClass: 13270b57cec5SDimitry Andric case Stmt::ObjCForCollectionStmtClass: 13280b57cec5SDimitry Andric return true; 13290b57cec5SDimitry Andric case Stmt::DoStmtClass: { 13300b57cec5SDimitry Andric Expr::EvalResult Result; 13310b57cec5SDimitry Andric if (!cast<DoStmt>(S)->getCond()->EvaluateAsInt(Result, Ctx)) 13320b57cec5SDimitry Andric return true; 13330b57cec5SDimitry Andric return Result.Val.getInt().getBoolValue(); 13340b57cec5SDimitry Andric } 13350b57cec5SDimitry Andric default: 13360b57cec5SDimitry Andric break; 13370b57cec5SDimitry Andric } 13380b57cec5SDimitry Andric } while ((S = PM.getParent(S))); 13390b57cec5SDimitry Andric 13400b57cec5SDimitry Andric return false; 13410b57cec5SDimitry Andric } 13420b57cec5SDimitry Andric 13430b57cec5SDimitry Andric static void diagnoseRepeatedUseOfWeak(Sema &S, 13440b57cec5SDimitry Andric const sema::FunctionScopeInfo *CurFn, 13450b57cec5SDimitry Andric const Decl *D, 13460b57cec5SDimitry Andric const ParentMap &PM) { 13470b57cec5SDimitry Andric typedef sema::FunctionScopeInfo::WeakObjectProfileTy WeakObjectProfileTy; 13480b57cec5SDimitry Andric typedef sema::FunctionScopeInfo::WeakObjectUseMap WeakObjectUseMap; 13490b57cec5SDimitry Andric typedef sema::FunctionScopeInfo::WeakUseVector WeakUseVector; 13500b57cec5SDimitry Andric typedef std::pair<const Stmt *, WeakObjectUseMap::const_iterator> 13510b57cec5SDimitry Andric StmtUsesPair; 13520b57cec5SDimitry Andric 13530b57cec5SDimitry Andric ASTContext &Ctx = S.getASTContext(); 13540b57cec5SDimitry Andric 13550b57cec5SDimitry Andric const WeakObjectUseMap &WeakMap = CurFn->getWeakObjectUses(); 13560b57cec5SDimitry Andric 13570b57cec5SDimitry Andric // Extract all weak objects that are referenced more than once. 13580b57cec5SDimitry Andric SmallVector<StmtUsesPair, 8> UsesByStmt; 13590b57cec5SDimitry Andric for (WeakObjectUseMap::const_iterator I = WeakMap.begin(), E = WeakMap.end(); 13600b57cec5SDimitry Andric I != E; ++I) { 13610b57cec5SDimitry Andric const WeakUseVector &Uses = I->second; 13620b57cec5SDimitry Andric 13630b57cec5SDimitry Andric // Find the first read of the weak object. 13640b57cec5SDimitry Andric WeakUseVector::const_iterator UI = Uses.begin(), UE = Uses.end(); 13650b57cec5SDimitry Andric for ( ; UI != UE; ++UI) { 13660b57cec5SDimitry Andric if (UI->isUnsafe()) 13670b57cec5SDimitry Andric break; 13680b57cec5SDimitry Andric } 13690b57cec5SDimitry Andric 13700b57cec5SDimitry Andric // If there were only writes to this object, don't warn. 13710b57cec5SDimitry Andric if (UI == UE) 13720b57cec5SDimitry Andric continue; 13730b57cec5SDimitry Andric 13740b57cec5SDimitry Andric // If there was only one read, followed by any number of writes, and the 13750b57cec5SDimitry Andric // read is not within a loop, don't warn. Additionally, don't warn in a 13760b57cec5SDimitry Andric // loop if the base object is a local variable -- local variables are often 13770b57cec5SDimitry Andric // changed in loops. 13780b57cec5SDimitry Andric if (UI == Uses.begin()) { 13790b57cec5SDimitry Andric WeakUseVector::const_iterator UI2 = UI; 13800b57cec5SDimitry Andric for (++UI2; UI2 != UE; ++UI2) 13810b57cec5SDimitry Andric if (UI2->isUnsafe()) 13820b57cec5SDimitry Andric break; 13830b57cec5SDimitry Andric 13840b57cec5SDimitry Andric if (UI2 == UE) { 13850b57cec5SDimitry Andric if (!isInLoop(Ctx, PM, UI->getUseExpr())) 13860b57cec5SDimitry Andric continue; 13870b57cec5SDimitry Andric 13880b57cec5SDimitry Andric const WeakObjectProfileTy &Profile = I->first; 13890b57cec5SDimitry Andric if (!Profile.isExactProfile()) 13900b57cec5SDimitry Andric continue; 13910b57cec5SDimitry Andric 13920b57cec5SDimitry Andric const NamedDecl *Base = Profile.getBase(); 13930b57cec5SDimitry Andric if (!Base) 13940b57cec5SDimitry Andric Base = Profile.getProperty(); 13950b57cec5SDimitry Andric assert(Base && "A profile always has a base or property."); 13960b57cec5SDimitry Andric 13970b57cec5SDimitry Andric if (const VarDecl *BaseVar = dyn_cast<VarDecl>(Base)) 13980b57cec5SDimitry Andric if (BaseVar->hasLocalStorage() && !isa<ParmVarDecl>(Base)) 13990b57cec5SDimitry Andric continue; 14000b57cec5SDimitry Andric } 14010b57cec5SDimitry Andric } 14020b57cec5SDimitry Andric 14030b57cec5SDimitry Andric UsesByStmt.push_back(StmtUsesPair(UI->getUseExpr(), I)); 14040b57cec5SDimitry Andric } 14050b57cec5SDimitry Andric 14060b57cec5SDimitry Andric if (UsesByStmt.empty()) 14070b57cec5SDimitry Andric return; 14080b57cec5SDimitry Andric 14090b57cec5SDimitry Andric // Sort by first use so that we emit the warnings in a deterministic order. 14100b57cec5SDimitry Andric SourceManager &SM = S.getSourceManager(); 14110b57cec5SDimitry Andric llvm::sort(UsesByStmt, 14120b57cec5SDimitry Andric [&SM](const StmtUsesPair &LHS, const StmtUsesPair &RHS) { 14130b57cec5SDimitry Andric return SM.isBeforeInTranslationUnit(LHS.first->getBeginLoc(), 14140b57cec5SDimitry Andric RHS.first->getBeginLoc()); 14150b57cec5SDimitry Andric }); 14160b57cec5SDimitry Andric 14170b57cec5SDimitry Andric // Classify the current code body for better warning text. 14180b57cec5SDimitry Andric // This enum should stay in sync with the cases in 14190b57cec5SDimitry Andric // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 14200b57cec5SDimitry Andric // FIXME: Should we use a common classification enum and the same set of 14210b57cec5SDimitry Andric // possibilities all throughout Sema? 14220b57cec5SDimitry Andric enum { 14230b57cec5SDimitry Andric Function, 14240b57cec5SDimitry Andric Method, 14250b57cec5SDimitry Andric Block, 14260b57cec5SDimitry Andric Lambda 14270b57cec5SDimitry Andric } FunctionKind; 14280b57cec5SDimitry Andric 14290b57cec5SDimitry Andric if (isa<sema::BlockScopeInfo>(CurFn)) 14300b57cec5SDimitry Andric FunctionKind = Block; 14310b57cec5SDimitry Andric else if (isa<sema::LambdaScopeInfo>(CurFn)) 14320b57cec5SDimitry Andric FunctionKind = Lambda; 14330b57cec5SDimitry Andric else if (isa<ObjCMethodDecl>(D)) 14340b57cec5SDimitry Andric FunctionKind = Method; 14350b57cec5SDimitry Andric else 14360b57cec5SDimitry Andric FunctionKind = Function; 14370b57cec5SDimitry Andric 14380b57cec5SDimitry Andric // Iterate through the sorted problems and emit warnings for each. 14390b57cec5SDimitry Andric for (const auto &P : UsesByStmt) { 14400b57cec5SDimitry Andric const Stmt *FirstRead = P.first; 14410b57cec5SDimitry Andric const WeakObjectProfileTy &Key = P.second->first; 14420b57cec5SDimitry Andric const WeakUseVector &Uses = P.second->second; 14430b57cec5SDimitry Andric 14440b57cec5SDimitry Andric // For complicated expressions like 'a.b.c' and 'x.b.c', WeakObjectProfileTy 14450b57cec5SDimitry Andric // may not contain enough information to determine that these are different 14460b57cec5SDimitry Andric // properties. We can only be 100% sure of a repeated use in certain cases, 14470b57cec5SDimitry Andric // and we adjust the diagnostic kind accordingly so that the less certain 14480b57cec5SDimitry Andric // case can be turned off if it is too noisy. 14490b57cec5SDimitry Andric unsigned DiagKind; 14500b57cec5SDimitry Andric if (Key.isExactProfile()) 14510b57cec5SDimitry Andric DiagKind = diag::warn_arc_repeated_use_of_weak; 14520b57cec5SDimitry Andric else 14530b57cec5SDimitry Andric DiagKind = diag::warn_arc_possible_repeated_use_of_weak; 14540b57cec5SDimitry Andric 14550b57cec5SDimitry Andric // Classify the weak object being accessed for better warning text. 14560b57cec5SDimitry Andric // This enum should stay in sync with the cases in 14570b57cec5SDimitry Andric // warn_arc_repeated_use_of_weak and warn_arc_possible_repeated_use_of_weak. 14580b57cec5SDimitry Andric enum { 14590b57cec5SDimitry Andric Variable, 14600b57cec5SDimitry Andric Property, 14610b57cec5SDimitry Andric ImplicitProperty, 14620b57cec5SDimitry Andric Ivar 14630b57cec5SDimitry Andric } ObjectKind; 14640b57cec5SDimitry Andric 14650b57cec5SDimitry Andric const NamedDecl *KeyProp = Key.getProperty(); 14660b57cec5SDimitry Andric if (isa<VarDecl>(KeyProp)) 14670b57cec5SDimitry Andric ObjectKind = Variable; 14680b57cec5SDimitry Andric else if (isa<ObjCPropertyDecl>(KeyProp)) 14690b57cec5SDimitry Andric ObjectKind = Property; 14700b57cec5SDimitry Andric else if (isa<ObjCMethodDecl>(KeyProp)) 14710b57cec5SDimitry Andric ObjectKind = ImplicitProperty; 14720b57cec5SDimitry Andric else if (isa<ObjCIvarDecl>(KeyProp)) 14730b57cec5SDimitry Andric ObjectKind = Ivar; 14740b57cec5SDimitry Andric else 14750b57cec5SDimitry Andric llvm_unreachable("Unexpected weak object kind!"); 14760b57cec5SDimitry Andric 14770b57cec5SDimitry Andric // Do not warn about IBOutlet weak property receivers being set to null 14780b57cec5SDimitry Andric // since they are typically only used from the main thread. 14790b57cec5SDimitry Andric if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp)) 14800b57cec5SDimitry Andric if (Prop->hasAttr<IBOutletAttr>()) 14810b57cec5SDimitry Andric continue; 14820b57cec5SDimitry Andric 14830b57cec5SDimitry Andric // Show the first time the object was read. 14840b57cec5SDimitry Andric S.Diag(FirstRead->getBeginLoc(), DiagKind) 14850b57cec5SDimitry Andric << int(ObjectKind) << KeyProp << int(FunctionKind) 14860b57cec5SDimitry Andric << FirstRead->getSourceRange(); 14870b57cec5SDimitry Andric 14880b57cec5SDimitry Andric // Print all the other accesses as notes. 14890b57cec5SDimitry Andric for (const auto &Use : Uses) { 14900b57cec5SDimitry Andric if (Use.getUseExpr() == FirstRead) 14910b57cec5SDimitry Andric continue; 14920b57cec5SDimitry Andric S.Diag(Use.getUseExpr()->getBeginLoc(), 14930b57cec5SDimitry Andric diag::note_arc_weak_also_accessed_here) 14940b57cec5SDimitry Andric << Use.getUseExpr()->getSourceRange(); 14950b57cec5SDimitry Andric } 14960b57cec5SDimitry Andric } 14970b57cec5SDimitry Andric } 14980b57cec5SDimitry Andric 14990b57cec5SDimitry Andric namespace { 15000b57cec5SDimitry Andric class UninitValsDiagReporter : public UninitVariablesHandler { 15010b57cec5SDimitry Andric Sema &S; 15020b57cec5SDimitry Andric typedef SmallVector<UninitUse, 2> UsesVec; 15030b57cec5SDimitry Andric typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType; 15040b57cec5SDimitry Andric // Prefer using MapVector to DenseMap, so that iteration order will be 15050b57cec5SDimitry Andric // the same as insertion order. This is needed to obtain a deterministic 15060b57cec5SDimitry Andric // order of diagnostics when calling flushDiagnostics(). 15070b57cec5SDimitry Andric typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; 15080b57cec5SDimitry Andric UsesMap uses; 15090b57cec5SDimitry Andric 15100b57cec5SDimitry Andric public: 15110b57cec5SDimitry Andric UninitValsDiagReporter(Sema &S) : S(S) {} 15120b57cec5SDimitry Andric ~UninitValsDiagReporter() override { flushDiagnostics(); } 15130b57cec5SDimitry Andric 15140b57cec5SDimitry Andric MappedType &getUses(const VarDecl *vd) { 15150b57cec5SDimitry Andric MappedType &V = uses[vd]; 15160b57cec5SDimitry Andric if (!V.getPointer()) 15170b57cec5SDimitry Andric V.setPointer(new UsesVec()); 15180b57cec5SDimitry Andric return V; 15190b57cec5SDimitry Andric } 15200b57cec5SDimitry Andric 15210b57cec5SDimitry Andric void handleUseOfUninitVariable(const VarDecl *vd, 15220b57cec5SDimitry Andric const UninitUse &use) override { 15230b57cec5SDimitry Andric getUses(vd).getPointer()->push_back(use); 15240b57cec5SDimitry Andric } 15250b57cec5SDimitry Andric 15260b57cec5SDimitry Andric void handleSelfInit(const VarDecl *vd) override { 15270b57cec5SDimitry Andric getUses(vd).setInt(true); 15280b57cec5SDimitry Andric } 15290b57cec5SDimitry Andric 15300b57cec5SDimitry Andric void flushDiagnostics() { 15310b57cec5SDimitry Andric for (const auto &P : uses) { 15320b57cec5SDimitry Andric const VarDecl *vd = P.first; 15330b57cec5SDimitry Andric const MappedType &V = P.second; 15340b57cec5SDimitry Andric 15350b57cec5SDimitry Andric UsesVec *vec = V.getPointer(); 15360b57cec5SDimitry Andric bool hasSelfInit = V.getInt(); 15370b57cec5SDimitry Andric 15380b57cec5SDimitry Andric // Specially handle the case where we have uses of an uninitialized 15390b57cec5SDimitry Andric // variable, but the root cause is an idiomatic self-init. We want 15400b57cec5SDimitry Andric // to report the diagnostic at the self-init since that is the root cause. 15410b57cec5SDimitry Andric if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) 15420b57cec5SDimitry Andric DiagnoseUninitializedUse(S, vd, 15430b57cec5SDimitry Andric UninitUse(vd->getInit()->IgnoreParenCasts(), 15440b57cec5SDimitry Andric /* isAlwaysUninit */ true), 15450b57cec5SDimitry Andric /* alwaysReportSelfInit */ true); 15460b57cec5SDimitry Andric else { 15470b57cec5SDimitry Andric // Sort the uses by their SourceLocations. While not strictly 15480b57cec5SDimitry Andric // guaranteed to produce them in line/column order, this will provide 15490b57cec5SDimitry Andric // a stable ordering. 15500b57cec5SDimitry Andric llvm::sort(vec->begin(), vec->end(), 15510b57cec5SDimitry Andric [](const UninitUse &a, const UninitUse &b) { 15520b57cec5SDimitry Andric // Prefer a more confident report over a less confident one. 15530b57cec5SDimitry Andric if (a.getKind() != b.getKind()) 15540b57cec5SDimitry Andric return a.getKind() > b.getKind(); 15550b57cec5SDimitry Andric return a.getUser()->getBeginLoc() < b.getUser()->getBeginLoc(); 15560b57cec5SDimitry Andric }); 15570b57cec5SDimitry Andric 15580b57cec5SDimitry Andric for (const auto &U : *vec) { 15590b57cec5SDimitry Andric // If we have self-init, downgrade all uses to 'may be uninitialized'. 15600b57cec5SDimitry Andric UninitUse Use = hasSelfInit ? UninitUse(U.getUser(), false) : U; 15610b57cec5SDimitry Andric 15620b57cec5SDimitry Andric if (DiagnoseUninitializedUse(S, vd, Use)) 15630b57cec5SDimitry Andric // Skip further diagnostics for this variable. We try to warn only 15640b57cec5SDimitry Andric // on the first point at which a variable is used uninitialized. 15650b57cec5SDimitry Andric break; 15660b57cec5SDimitry Andric } 15670b57cec5SDimitry Andric } 15680b57cec5SDimitry Andric 15690b57cec5SDimitry Andric // Release the uses vector. 15700b57cec5SDimitry Andric delete vec; 15710b57cec5SDimitry Andric } 15720b57cec5SDimitry Andric 15730b57cec5SDimitry Andric uses.clear(); 15740b57cec5SDimitry Andric } 15750b57cec5SDimitry Andric 15760b57cec5SDimitry Andric private: 15770b57cec5SDimitry Andric static bool hasAlwaysUninitializedUse(const UsesVec* vec) { 15780b57cec5SDimitry Andric return std::any_of(vec->begin(), vec->end(), [](const UninitUse &U) { 15790b57cec5SDimitry Andric return U.getKind() == UninitUse::Always || 15800b57cec5SDimitry Andric U.getKind() == UninitUse::AfterCall || 15810b57cec5SDimitry Andric U.getKind() == UninitUse::AfterDecl; 15820b57cec5SDimitry Andric }); 15830b57cec5SDimitry Andric } 15840b57cec5SDimitry Andric }; 15850b57cec5SDimitry Andric } // anonymous namespace 15860b57cec5SDimitry Andric 15870b57cec5SDimitry Andric namespace clang { 15880b57cec5SDimitry Andric namespace { 15890b57cec5SDimitry Andric typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes; 15900b57cec5SDimitry Andric typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag; 15910b57cec5SDimitry Andric typedef std::list<DelayedDiag> DiagList; 15920b57cec5SDimitry Andric 15930b57cec5SDimitry Andric struct SortDiagBySourceLocation { 15940b57cec5SDimitry Andric SourceManager &SM; 15950b57cec5SDimitry Andric SortDiagBySourceLocation(SourceManager &SM) : SM(SM) {} 15960b57cec5SDimitry Andric 15970b57cec5SDimitry Andric bool operator()(const DelayedDiag &left, const DelayedDiag &right) { 15980b57cec5SDimitry Andric // Although this call will be slow, this is only called when outputting 15990b57cec5SDimitry Andric // multiple warnings. 16000b57cec5SDimitry Andric return SM.isBeforeInTranslationUnit(left.first.first, right.first.first); 16010b57cec5SDimitry Andric } 16020b57cec5SDimitry Andric }; 16030b57cec5SDimitry Andric } // anonymous namespace 16040b57cec5SDimitry Andric } // namespace clang 16050b57cec5SDimitry Andric 16060b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16070b57cec5SDimitry Andric // -Wthread-safety 16080b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16090b57cec5SDimitry Andric namespace clang { 16100b57cec5SDimitry Andric namespace threadSafety { 16110b57cec5SDimitry Andric namespace { 16120b57cec5SDimitry Andric class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { 16130b57cec5SDimitry Andric Sema &S; 16140b57cec5SDimitry Andric DiagList Warnings; 16150b57cec5SDimitry Andric SourceLocation FunLocation, FunEndLocation; 16160b57cec5SDimitry Andric 16170b57cec5SDimitry Andric const FunctionDecl *CurrentFunction; 16180b57cec5SDimitry Andric bool Verbose; 16190b57cec5SDimitry Andric 16200b57cec5SDimitry Andric OptionalNotes getNotes() const { 16210b57cec5SDimitry Andric if (Verbose && CurrentFunction) { 16220b57cec5SDimitry Andric PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 16230b57cec5SDimitry Andric S.PDiag(diag::note_thread_warning_in_fun) 16240b57cec5SDimitry Andric << CurrentFunction); 16250b57cec5SDimitry Andric return OptionalNotes(1, FNote); 16260b57cec5SDimitry Andric } 16270b57cec5SDimitry Andric return OptionalNotes(); 16280b57cec5SDimitry Andric } 16290b57cec5SDimitry Andric 16300b57cec5SDimitry Andric OptionalNotes getNotes(const PartialDiagnosticAt &Note) const { 16310b57cec5SDimitry Andric OptionalNotes ONS(1, Note); 16320b57cec5SDimitry Andric if (Verbose && CurrentFunction) { 16330b57cec5SDimitry Andric PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 16340b57cec5SDimitry Andric S.PDiag(diag::note_thread_warning_in_fun) 16350b57cec5SDimitry Andric << CurrentFunction); 16360b57cec5SDimitry Andric ONS.push_back(std::move(FNote)); 16370b57cec5SDimitry Andric } 16380b57cec5SDimitry Andric return ONS; 16390b57cec5SDimitry Andric } 16400b57cec5SDimitry Andric 16410b57cec5SDimitry Andric OptionalNotes getNotes(const PartialDiagnosticAt &Note1, 16420b57cec5SDimitry Andric const PartialDiagnosticAt &Note2) const { 16430b57cec5SDimitry Andric OptionalNotes ONS; 16440b57cec5SDimitry Andric ONS.push_back(Note1); 16450b57cec5SDimitry Andric ONS.push_back(Note2); 16460b57cec5SDimitry Andric if (Verbose && CurrentFunction) { 16470b57cec5SDimitry Andric PartialDiagnosticAt FNote(CurrentFunction->getBody()->getBeginLoc(), 16480b57cec5SDimitry Andric S.PDiag(diag::note_thread_warning_in_fun) 16490b57cec5SDimitry Andric << CurrentFunction); 16500b57cec5SDimitry Andric ONS.push_back(std::move(FNote)); 16510b57cec5SDimitry Andric } 16520b57cec5SDimitry Andric return ONS; 16530b57cec5SDimitry Andric } 16540b57cec5SDimitry Andric 16550b57cec5SDimitry Andric OptionalNotes makeLockedHereNote(SourceLocation LocLocked, StringRef Kind) { 16560b57cec5SDimitry Andric return LocLocked.isValid() 16570b57cec5SDimitry Andric ? getNotes(PartialDiagnosticAt( 16580b57cec5SDimitry Andric LocLocked, S.PDiag(diag::note_locked_here) << Kind)) 16590b57cec5SDimitry Andric : getNotes(); 16600b57cec5SDimitry Andric } 16610b57cec5SDimitry Andric 16620b57cec5SDimitry Andric public: 16630b57cec5SDimitry Andric ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) 16640b57cec5SDimitry Andric : S(S), FunLocation(FL), FunEndLocation(FEL), 16650b57cec5SDimitry Andric CurrentFunction(nullptr), Verbose(false) {} 16660b57cec5SDimitry Andric 16670b57cec5SDimitry Andric void setVerbose(bool b) { Verbose = b; } 16680b57cec5SDimitry Andric 16690b57cec5SDimitry Andric /// Emit all buffered diagnostics in order of sourcelocation. 16700b57cec5SDimitry Andric /// We need to output diagnostics produced while iterating through 16710b57cec5SDimitry Andric /// the lockset in deterministic order, so this function orders diagnostics 16720b57cec5SDimitry Andric /// and outputs them. 16730b57cec5SDimitry Andric void emitDiagnostics() { 16740b57cec5SDimitry Andric Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 16750b57cec5SDimitry Andric for (const auto &Diag : Warnings) { 16760b57cec5SDimitry Andric S.Diag(Diag.first.first, Diag.first.second); 16770b57cec5SDimitry Andric for (const auto &Note : Diag.second) 16780b57cec5SDimitry Andric S.Diag(Note.first, Note.second); 16790b57cec5SDimitry Andric } 16800b57cec5SDimitry Andric } 16810b57cec5SDimitry Andric 16820b57cec5SDimitry Andric void handleInvalidLockExp(StringRef Kind, SourceLocation Loc) override { 16830b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_cannot_resolve_lock) 16840b57cec5SDimitry Andric << Loc); 16850b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 16860b57cec5SDimitry Andric } 16870b57cec5SDimitry Andric 16880b57cec5SDimitry Andric void handleUnmatchedUnlock(StringRef Kind, Name LockName, 16890b57cec5SDimitry Andric SourceLocation Loc) override { 16900b57cec5SDimitry Andric if (Loc.isInvalid()) 16910b57cec5SDimitry Andric Loc = FunLocation; 16920b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock) 16930b57cec5SDimitry Andric << Kind << LockName); 16940b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 16950b57cec5SDimitry Andric } 16960b57cec5SDimitry Andric 16970b57cec5SDimitry Andric void handleIncorrectUnlockKind(StringRef Kind, Name LockName, 16980b57cec5SDimitry Andric LockKind Expected, LockKind Received, 16990b57cec5SDimitry Andric SourceLocation LocLocked, 17000b57cec5SDimitry Andric SourceLocation LocUnlock) override { 17010b57cec5SDimitry Andric if (LocUnlock.isInvalid()) 17020b57cec5SDimitry Andric LocUnlock = FunLocation; 17030b57cec5SDimitry Andric PartialDiagnosticAt Warning( 17040b57cec5SDimitry Andric LocUnlock, S.PDiag(diag::warn_unlock_kind_mismatch) 17050b57cec5SDimitry Andric << Kind << LockName << Received << Expected); 17060b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), 17070b57cec5SDimitry Andric makeLockedHereNote(LocLocked, Kind)); 17080b57cec5SDimitry Andric } 17090b57cec5SDimitry Andric 17100b57cec5SDimitry Andric void handleDoubleLock(StringRef Kind, Name LockName, SourceLocation LocLocked, 17110b57cec5SDimitry Andric SourceLocation LocDoubleLock) override { 17120b57cec5SDimitry Andric if (LocDoubleLock.isInvalid()) 17130b57cec5SDimitry Andric LocDoubleLock = FunLocation; 17140b57cec5SDimitry Andric PartialDiagnosticAt Warning(LocDoubleLock, S.PDiag(diag::warn_double_lock) 17150b57cec5SDimitry Andric << Kind << LockName); 17160b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), 17170b57cec5SDimitry Andric makeLockedHereNote(LocLocked, Kind)); 17180b57cec5SDimitry Andric } 17190b57cec5SDimitry Andric 17200b57cec5SDimitry Andric void handleMutexHeldEndOfScope(StringRef Kind, Name LockName, 17210b57cec5SDimitry Andric SourceLocation LocLocked, 17220b57cec5SDimitry Andric SourceLocation LocEndOfScope, 17230b57cec5SDimitry Andric LockErrorKind LEK) override { 17240b57cec5SDimitry Andric unsigned DiagID = 0; 17250b57cec5SDimitry Andric switch (LEK) { 17260b57cec5SDimitry Andric case LEK_LockedSomePredecessors: 17270b57cec5SDimitry Andric DiagID = diag::warn_lock_some_predecessors; 17280b57cec5SDimitry Andric break; 17290b57cec5SDimitry Andric case LEK_LockedSomeLoopIterations: 17300b57cec5SDimitry Andric DiagID = diag::warn_expecting_lock_held_on_loop; 17310b57cec5SDimitry Andric break; 17320b57cec5SDimitry Andric case LEK_LockedAtEndOfFunction: 17330b57cec5SDimitry Andric DiagID = diag::warn_no_unlock; 17340b57cec5SDimitry Andric break; 17350b57cec5SDimitry Andric case LEK_NotLockedAtEndOfFunction: 17360b57cec5SDimitry Andric DiagID = diag::warn_expecting_locked; 17370b57cec5SDimitry Andric break; 17380b57cec5SDimitry Andric } 17390b57cec5SDimitry Andric if (LocEndOfScope.isInvalid()) 17400b57cec5SDimitry Andric LocEndOfScope = FunEndLocation; 17410b57cec5SDimitry Andric 17420b57cec5SDimitry Andric PartialDiagnosticAt Warning(LocEndOfScope, S.PDiag(DiagID) << Kind 17430b57cec5SDimitry Andric << LockName); 17440b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), 17450b57cec5SDimitry Andric makeLockedHereNote(LocLocked, Kind)); 17460b57cec5SDimitry Andric } 17470b57cec5SDimitry Andric 17480b57cec5SDimitry Andric void handleExclusiveAndShared(StringRef Kind, Name LockName, 17490b57cec5SDimitry Andric SourceLocation Loc1, 17500b57cec5SDimitry Andric SourceLocation Loc2) override { 17510b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc1, 17520b57cec5SDimitry Andric S.PDiag(diag::warn_lock_exclusive_and_shared) 17530b57cec5SDimitry Andric << Kind << LockName); 17540b57cec5SDimitry Andric PartialDiagnosticAt Note(Loc2, S.PDiag(diag::note_lock_exclusive_and_shared) 17550b57cec5SDimitry Andric << Kind << LockName); 17560b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes(Note)); 17570b57cec5SDimitry Andric } 17580b57cec5SDimitry Andric 17590b57cec5SDimitry Andric void handleNoMutexHeld(StringRef Kind, const NamedDecl *D, 17600b57cec5SDimitry Andric ProtectedOperationKind POK, AccessKind AK, 17610b57cec5SDimitry Andric SourceLocation Loc) override { 17620b57cec5SDimitry Andric assert((POK == POK_VarAccess || POK == POK_VarDereference) && 17630b57cec5SDimitry Andric "Only works for variables"); 17640b57cec5SDimitry Andric unsigned DiagID = POK == POK_VarAccess? 17650b57cec5SDimitry Andric diag::warn_variable_requires_any_lock: 17660b57cec5SDimitry Andric diag::warn_var_deref_requires_any_lock; 17670b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) 17680b57cec5SDimitry Andric << D << getLockKindFromAccessKind(AK)); 17690b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 17700b57cec5SDimitry Andric } 17710b57cec5SDimitry Andric 17720b57cec5SDimitry Andric void handleMutexNotHeld(StringRef Kind, const NamedDecl *D, 17730b57cec5SDimitry Andric ProtectedOperationKind POK, Name LockName, 17740b57cec5SDimitry Andric LockKind LK, SourceLocation Loc, 17750b57cec5SDimitry Andric Name *PossibleMatch) override { 17760b57cec5SDimitry Andric unsigned DiagID = 0; 17770b57cec5SDimitry Andric if (PossibleMatch) { 17780b57cec5SDimitry Andric switch (POK) { 17790b57cec5SDimitry Andric case POK_VarAccess: 17800b57cec5SDimitry Andric DiagID = diag::warn_variable_requires_lock_precise; 17810b57cec5SDimitry Andric break; 17820b57cec5SDimitry Andric case POK_VarDereference: 17830b57cec5SDimitry Andric DiagID = diag::warn_var_deref_requires_lock_precise; 17840b57cec5SDimitry Andric break; 17850b57cec5SDimitry Andric case POK_FunctionCall: 17860b57cec5SDimitry Andric DiagID = diag::warn_fun_requires_lock_precise; 17870b57cec5SDimitry Andric break; 17880b57cec5SDimitry Andric case POK_PassByRef: 17890b57cec5SDimitry Andric DiagID = diag::warn_guarded_pass_by_reference; 17900b57cec5SDimitry Andric break; 17910b57cec5SDimitry Andric case POK_PtPassByRef: 17920b57cec5SDimitry Andric DiagID = diag::warn_pt_guarded_pass_by_reference; 17930b57cec5SDimitry Andric break; 17940b57cec5SDimitry Andric } 17950b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 17960b57cec5SDimitry Andric << D 17970b57cec5SDimitry Andric << LockName << LK); 17980b57cec5SDimitry Andric PartialDiagnosticAt Note(Loc, S.PDiag(diag::note_found_mutex_near_match) 17990b57cec5SDimitry Andric << *PossibleMatch); 18000b57cec5SDimitry Andric if (Verbose && POK == POK_VarAccess) { 18010b57cec5SDimitry Andric PartialDiagnosticAt VNote(D->getLocation(), 18020b57cec5SDimitry Andric S.PDiag(diag::note_guarded_by_declared_here) 18030b57cec5SDimitry Andric << D->getNameAsString()); 18040b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes(Note, VNote)); 18050b57cec5SDimitry Andric } else 18060b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes(Note)); 18070b57cec5SDimitry Andric } else { 18080b57cec5SDimitry Andric switch (POK) { 18090b57cec5SDimitry Andric case POK_VarAccess: 18100b57cec5SDimitry Andric DiagID = diag::warn_variable_requires_lock; 18110b57cec5SDimitry Andric break; 18120b57cec5SDimitry Andric case POK_VarDereference: 18130b57cec5SDimitry Andric DiagID = diag::warn_var_deref_requires_lock; 18140b57cec5SDimitry Andric break; 18150b57cec5SDimitry Andric case POK_FunctionCall: 18160b57cec5SDimitry Andric DiagID = diag::warn_fun_requires_lock; 18170b57cec5SDimitry Andric break; 18180b57cec5SDimitry Andric case POK_PassByRef: 18190b57cec5SDimitry Andric DiagID = diag::warn_guarded_pass_by_reference; 18200b57cec5SDimitry Andric break; 18210b57cec5SDimitry Andric case POK_PtPassByRef: 18220b57cec5SDimitry Andric DiagID = diag::warn_pt_guarded_pass_by_reference; 18230b57cec5SDimitry Andric break; 18240b57cec5SDimitry Andric } 18250b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(DiagID) << Kind 18260b57cec5SDimitry Andric << D 18270b57cec5SDimitry Andric << LockName << LK); 18280b57cec5SDimitry Andric if (Verbose && POK == POK_VarAccess) { 18290b57cec5SDimitry Andric PartialDiagnosticAt Note(D->getLocation(), 18300b57cec5SDimitry Andric S.PDiag(diag::note_guarded_by_declared_here)); 18310b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes(Note)); 18320b57cec5SDimitry Andric } else 18330b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 18340b57cec5SDimitry Andric } 18350b57cec5SDimitry Andric } 18360b57cec5SDimitry Andric 18370b57cec5SDimitry Andric void handleNegativeNotHeld(StringRef Kind, Name LockName, Name Neg, 18380b57cec5SDimitry Andric SourceLocation Loc) override { 18390b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, 18400b57cec5SDimitry Andric S.PDiag(diag::warn_acquire_requires_negative_cap) 18410b57cec5SDimitry Andric << Kind << LockName << Neg); 18420b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 18430b57cec5SDimitry Andric } 18440b57cec5SDimitry Andric 18450b57cec5SDimitry Andric void handleFunExcludesLock(StringRef Kind, Name FunName, Name LockName, 18460b57cec5SDimitry Andric SourceLocation Loc) override { 18470b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_fun_excludes_mutex) 18480b57cec5SDimitry Andric << Kind << FunName << LockName); 18490b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 18500b57cec5SDimitry Andric } 18510b57cec5SDimitry Andric 18520b57cec5SDimitry Andric void handleLockAcquiredBefore(StringRef Kind, Name L1Name, Name L2Name, 18530b57cec5SDimitry Andric SourceLocation Loc) override { 18540b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, 18550b57cec5SDimitry Andric S.PDiag(diag::warn_acquired_before) << Kind << L1Name << L2Name); 18560b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 18570b57cec5SDimitry Andric } 18580b57cec5SDimitry Andric 18590b57cec5SDimitry Andric void handleBeforeAfterCycle(Name L1Name, SourceLocation Loc) override { 18600b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, 18610b57cec5SDimitry Andric S.PDiag(diag::warn_acquired_before_after_cycle) << L1Name); 18620b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), getNotes()); 18630b57cec5SDimitry Andric } 18640b57cec5SDimitry Andric 18650b57cec5SDimitry Andric void enterFunction(const FunctionDecl* FD) override { 18660b57cec5SDimitry Andric CurrentFunction = FD; 18670b57cec5SDimitry Andric } 18680b57cec5SDimitry Andric 18690b57cec5SDimitry Andric void leaveFunction(const FunctionDecl* FD) override { 18700b57cec5SDimitry Andric CurrentFunction = nullptr; 18710b57cec5SDimitry Andric } 18720b57cec5SDimitry Andric }; 18730b57cec5SDimitry Andric } // anonymous namespace 18740b57cec5SDimitry Andric } // namespace threadSafety 18750b57cec5SDimitry Andric } // namespace clang 18760b57cec5SDimitry Andric 18770b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 18780b57cec5SDimitry Andric // -Wconsumed 18790b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 18800b57cec5SDimitry Andric 18810b57cec5SDimitry Andric namespace clang { 18820b57cec5SDimitry Andric namespace consumed { 18830b57cec5SDimitry Andric namespace { 18840b57cec5SDimitry Andric class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase { 18850b57cec5SDimitry Andric 18860b57cec5SDimitry Andric Sema &S; 18870b57cec5SDimitry Andric DiagList Warnings; 18880b57cec5SDimitry Andric 18890b57cec5SDimitry Andric public: 18900b57cec5SDimitry Andric 18910b57cec5SDimitry Andric ConsumedWarningsHandler(Sema &S) : S(S) {} 18920b57cec5SDimitry Andric 18930b57cec5SDimitry Andric void emitDiagnostics() override { 18940b57cec5SDimitry Andric Warnings.sort(SortDiagBySourceLocation(S.getSourceManager())); 18950b57cec5SDimitry Andric for (const auto &Diag : Warnings) { 18960b57cec5SDimitry Andric S.Diag(Diag.first.first, Diag.first.second); 18970b57cec5SDimitry Andric for (const auto &Note : Diag.second) 18980b57cec5SDimitry Andric S.Diag(Note.first, Note.second); 18990b57cec5SDimitry Andric } 19000b57cec5SDimitry Andric } 19010b57cec5SDimitry Andric 19020b57cec5SDimitry Andric void warnLoopStateMismatch(SourceLocation Loc, 19030b57cec5SDimitry Andric StringRef VariableName) override { 19040b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) << 19050b57cec5SDimitry Andric VariableName); 19060b57cec5SDimitry Andric 19070b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19080b57cec5SDimitry Andric } 19090b57cec5SDimitry Andric 19100b57cec5SDimitry Andric void warnParamReturnTypestateMismatch(SourceLocation Loc, 19110b57cec5SDimitry Andric StringRef VariableName, 19120b57cec5SDimitry Andric StringRef ExpectedState, 19130b57cec5SDimitry Andric StringRef ObservedState) override { 19140b57cec5SDimitry Andric 19150b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag( 19160b57cec5SDimitry Andric diag::warn_param_return_typestate_mismatch) << VariableName << 19170b57cec5SDimitry Andric ExpectedState << ObservedState); 19180b57cec5SDimitry Andric 19190b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19200b57cec5SDimitry Andric } 19210b57cec5SDimitry Andric 19220b57cec5SDimitry Andric void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 19230b57cec5SDimitry Andric StringRef ObservedState) override { 19240b57cec5SDimitry Andric 19250b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag( 19260b57cec5SDimitry Andric diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState); 19270b57cec5SDimitry Andric 19280b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19290b57cec5SDimitry Andric } 19300b57cec5SDimitry Andric 19310b57cec5SDimitry Andric void warnReturnTypestateForUnconsumableType(SourceLocation Loc, 19320b57cec5SDimitry Andric StringRef TypeName) override { 19330b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag( 19340b57cec5SDimitry Andric diag::warn_return_typestate_for_unconsumable_type) << TypeName); 19350b57cec5SDimitry Andric 19360b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19370b57cec5SDimitry Andric } 19380b57cec5SDimitry Andric 19390b57cec5SDimitry Andric void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState, 19400b57cec5SDimitry Andric StringRef ObservedState) override { 19410b57cec5SDimitry Andric 19420b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag( 19430b57cec5SDimitry Andric diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState); 19440b57cec5SDimitry Andric 19450b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19460b57cec5SDimitry Andric } 19470b57cec5SDimitry Andric 19480b57cec5SDimitry Andric void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State, 19490b57cec5SDimitry Andric SourceLocation Loc) override { 19500b57cec5SDimitry Andric 19510b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag( 19520b57cec5SDimitry Andric diag::warn_use_of_temp_in_invalid_state) << MethodName << State); 19530b57cec5SDimitry Andric 19540b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19550b57cec5SDimitry Andric } 19560b57cec5SDimitry Andric 19570b57cec5SDimitry Andric void warnUseInInvalidState(StringRef MethodName, StringRef VariableName, 19580b57cec5SDimitry Andric StringRef State, SourceLocation Loc) override { 19590b57cec5SDimitry Andric 19600b57cec5SDimitry Andric PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) << 19610b57cec5SDimitry Andric MethodName << VariableName << State); 19620b57cec5SDimitry Andric 19630b57cec5SDimitry Andric Warnings.emplace_back(std::move(Warning), OptionalNotes()); 19640b57cec5SDimitry Andric } 19650b57cec5SDimitry Andric }; 19660b57cec5SDimitry Andric } // anonymous namespace 19670b57cec5SDimitry Andric } // namespace consumed 19680b57cec5SDimitry Andric } // namespace clang 19690b57cec5SDimitry Andric 19700b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19710b57cec5SDimitry Andric // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based 19720b57cec5SDimitry Andric // warnings on a function, method, or block. 19730b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 19740b57cec5SDimitry Andric 19750b57cec5SDimitry Andric clang::sema::AnalysisBasedWarnings::Policy::Policy() { 19760b57cec5SDimitry Andric enableCheckFallThrough = 1; 19770b57cec5SDimitry Andric enableCheckUnreachable = 0; 19780b57cec5SDimitry Andric enableThreadSafetyAnalysis = 0; 19790b57cec5SDimitry Andric enableConsumedAnalysis = 0; 19800b57cec5SDimitry Andric } 19810b57cec5SDimitry Andric 19820b57cec5SDimitry Andric static unsigned isEnabled(DiagnosticsEngine &D, unsigned diag) { 19830b57cec5SDimitry Andric return (unsigned)!D.isIgnored(diag, SourceLocation()); 19840b57cec5SDimitry Andric } 19850b57cec5SDimitry Andric 19860b57cec5SDimitry Andric clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) 19870b57cec5SDimitry Andric : S(s), 19880b57cec5SDimitry Andric NumFunctionsAnalyzed(0), 19890b57cec5SDimitry Andric NumFunctionsWithBadCFGs(0), 19900b57cec5SDimitry Andric NumCFGBlocks(0), 19910b57cec5SDimitry Andric MaxCFGBlocksPerFunction(0), 19920b57cec5SDimitry Andric NumUninitAnalysisFunctions(0), 19930b57cec5SDimitry Andric NumUninitAnalysisVariables(0), 19940b57cec5SDimitry Andric MaxUninitAnalysisVariablesPerFunction(0), 19950b57cec5SDimitry Andric NumUninitAnalysisBlockVisits(0), 19960b57cec5SDimitry Andric MaxUninitAnalysisBlockVisitsPerFunction(0) { 19970b57cec5SDimitry Andric 19980b57cec5SDimitry Andric using namespace diag; 19990b57cec5SDimitry Andric DiagnosticsEngine &D = S.getDiagnostics(); 20000b57cec5SDimitry Andric 20010b57cec5SDimitry Andric DefaultPolicy.enableCheckUnreachable = 20020b57cec5SDimitry Andric isEnabled(D, warn_unreachable) || 20030b57cec5SDimitry Andric isEnabled(D, warn_unreachable_break) || 20040b57cec5SDimitry Andric isEnabled(D, warn_unreachable_return) || 20050b57cec5SDimitry Andric isEnabled(D, warn_unreachable_loop_increment); 20060b57cec5SDimitry Andric 20070b57cec5SDimitry Andric DefaultPolicy.enableThreadSafetyAnalysis = 20080b57cec5SDimitry Andric isEnabled(D, warn_double_lock); 20090b57cec5SDimitry Andric 20100b57cec5SDimitry Andric DefaultPolicy.enableConsumedAnalysis = 20110b57cec5SDimitry Andric isEnabled(D, warn_use_in_invalid_state); 20120b57cec5SDimitry Andric } 20130b57cec5SDimitry Andric 20140b57cec5SDimitry Andric static void flushDiagnostics(Sema &S, const sema::FunctionScopeInfo *fscope) { 20150b57cec5SDimitry Andric for (const auto &D : fscope->PossiblyUnreachableDiags) 20160b57cec5SDimitry Andric S.Diag(D.Loc, D.PD); 20170b57cec5SDimitry Andric } 20180b57cec5SDimitry Andric 20190b57cec5SDimitry Andric void clang::sema:: 20200b57cec5SDimitry Andric AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, 20210b57cec5SDimitry Andric sema::FunctionScopeInfo *fscope, 20220b57cec5SDimitry Andric const Decl *D, QualType BlockType) { 20230b57cec5SDimitry Andric 20240b57cec5SDimitry Andric // We avoid doing analysis-based warnings when there are errors for 20250b57cec5SDimitry Andric // two reasons: 20260b57cec5SDimitry Andric // (1) The CFGs often can't be constructed (if the body is invalid), so 20270b57cec5SDimitry Andric // don't bother trying. 20280b57cec5SDimitry Andric // (2) The code already has problems; running the analysis just takes more 20290b57cec5SDimitry Andric // time. 20300b57cec5SDimitry Andric DiagnosticsEngine &Diags = S.getDiagnostics(); 20310b57cec5SDimitry Andric 20320b57cec5SDimitry Andric // Do not do any analysis if we are going to just ignore them. 20330b57cec5SDimitry Andric if (Diags.getIgnoreAllWarnings() || 20340b57cec5SDimitry Andric (Diags.getSuppressSystemWarnings() && 20350b57cec5SDimitry Andric S.SourceMgr.isInSystemHeader(D->getLocation()))) 20360b57cec5SDimitry Andric return; 20370b57cec5SDimitry Andric 20380b57cec5SDimitry Andric // For code in dependent contexts, we'll do this at instantiation time. 20390b57cec5SDimitry Andric if (cast<DeclContext>(D)->isDependentContext()) 20400b57cec5SDimitry Andric return; 20410b57cec5SDimitry Andric 20420b57cec5SDimitry Andric if (Diags.hasUncompilableErrorOccurred()) { 20430b57cec5SDimitry Andric // Flush out any possibly unreachable diagnostics. 20440b57cec5SDimitry Andric flushDiagnostics(S, fscope); 20450b57cec5SDimitry Andric return; 20460b57cec5SDimitry Andric } 20470b57cec5SDimitry Andric 20480b57cec5SDimitry Andric const Stmt *Body = D->getBody(); 20490b57cec5SDimitry Andric assert(Body); 20500b57cec5SDimitry Andric 20510b57cec5SDimitry Andric // Construct the analysis context with the specified CFG build options. 20520b57cec5SDimitry Andric AnalysisDeclContext AC(/* AnalysisDeclContextManager */ nullptr, D); 20530b57cec5SDimitry Andric 20540b57cec5SDimitry Andric // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 20550b57cec5SDimitry Andric // explosion for destructors that can result and the compile time hit. 20560b57cec5SDimitry Andric AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; 20570b57cec5SDimitry Andric AC.getCFGBuildOptions().AddEHEdges = false; 20580b57cec5SDimitry Andric AC.getCFGBuildOptions().AddInitializers = true; 20590b57cec5SDimitry Andric AC.getCFGBuildOptions().AddImplicitDtors = true; 20600b57cec5SDimitry Andric AC.getCFGBuildOptions().AddTemporaryDtors = true; 20610b57cec5SDimitry Andric AC.getCFGBuildOptions().AddCXXNewAllocator = false; 20620b57cec5SDimitry Andric AC.getCFGBuildOptions().AddCXXDefaultInitExprInCtors = true; 20630b57cec5SDimitry Andric 20640b57cec5SDimitry Andric // Force that certain expressions appear as CFGElements in the CFG. This 20650b57cec5SDimitry Andric // is used to speed up various analyses. 20660b57cec5SDimitry Andric // FIXME: This isn't the right factoring. This is here for initial 20670b57cec5SDimitry Andric // prototyping, but we need a way for analyses to say what expressions they 20680b57cec5SDimitry Andric // expect to always be CFGElements and then fill in the BuildOptions 20690b57cec5SDimitry Andric // appropriately. This is essentially a layering violation. 20700b57cec5SDimitry Andric if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis || 20710b57cec5SDimitry Andric P.enableConsumedAnalysis) { 20720b57cec5SDimitry Andric // Unreachable code analysis and thread safety require a linearized CFG. 20730b57cec5SDimitry Andric AC.getCFGBuildOptions().setAllAlwaysAdd(); 20740b57cec5SDimitry Andric } 20750b57cec5SDimitry Andric else { 20760b57cec5SDimitry Andric AC.getCFGBuildOptions() 20770b57cec5SDimitry Andric .setAlwaysAdd(Stmt::BinaryOperatorClass) 20780b57cec5SDimitry Andric .setAlwaysAdd(Stmt::CompoundAssignOperatorClass) 20790b57cec5SDimitry Andric .setAlwaysAdd(Stmt::BlockExprClass) 20800b57cec5SDimitry Andric .setAlwaysAdd(Stmt::CStyleCastExprClass) 20810b57cec5SDimitry Andric .setAlwaysAdd(Stmt::DeclRefExprClass) 20820b57cec5SDimitry Andric .setAlwaysAdd(Stmt::ImplicitCastExprClass) 20830b57cec5SDimitry Andric .setAlwaysAdd(Stmt::UnaryOperatorClass) 20840b57cec5SDimitry Andric .setAlwaysAdd(Stmt::AttributedStmtClass); 20850b57cec5SDimitry Andric } 20860b57cec5SDimitry Andric 2087*a7dea167SDimitry Andric // Install the logical handler. 20880b57cec5SDimitry Andric llvm::Optional<LogicalErrorHandler> LEH; 2089*a7dea167SDimitry Andric if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { 20900b57cec5SDimitry Andric LEH.emplace(S); 20910b57cec5SDimitry Andric AC.getCFGBuildOptions().Observer = &*LEH; 20920b57cec5SDimitry Andric } 20930b57cec5SDimitry Andric 20940b57cec5SDimitry Andric // Emit delayed diagnostics. 20950b57cec5SDimitry Andric if (!fscope->PossiblyUnreachableDiags.empty()) { 20960b57cec5SDimitry Andric bool analyzed = false; 20970b57cec5SDimitry Andric 20980b57cec5SDimitry Andric // Register the expressions with the CFGBuilder. 20990b57cec5SDimitry Andric for (const auto &D : fscope->PossiblyUnreachableDiags) { 21000b57cec5SDimitry Andric for (const Stmt *S : D.Stmts) 21010b57cec5SDimitry Andric AC.registerForcedBlockExpression(S); 21020b57cec5SDimitry Andric } 21030b57cec5SDimitry Andric 21040b57cec5SDimitry Andric if (AC.getCFG()) { 21050b57cec5SDimitry Andric analyzed = true; 21060b57cec5SDimitry Andric for (const auto &D : fscope->PossiblyUnreachableDiags) { 21070b57cec5SDimitry Andric bool AllReachable = true; 21080b57cec5SDimitry Andric for (const Stmt *S : D.Stmts) { 21090b57cec5SDimitry Andric const CFGBlock *block = AC.getBlockForRegisteredExpression(S); 21100b57cec5SDimitry Andric CFGReverseBlockReachabilityAnalysis *cra = 21110b57cec5SDimitry Andric AC.getCFGReachablityAnalysis(); 21120b57cec5SDimitry Andric // FIXME: We should be able to assert that block is non-null, but 21130b57cec5SDimitry Andric // the CFG analysis can skip potentially-evaluated expressions in 21140b57cec5SDimitry Andric // edge cases; see test/Sema/vla-2.c. 21150b57cec5SDimitry Andric if (block && cra) { 21160b57cec5SDimitry Andric // Can this block be reached from the entrance? 21170b57cec5SDimitry Andric if (!cra->isReachable(&AC.getCFG()->getEntry(), block)) { 21180b57cec5SDimitry Andric AllReachable = false; 21190b57cec5SDimitry Andric break; 21200b57cec5SDimitry Andric } 21210b57cec5SDimitry Andric } 21220b57cec5SDimitry Andric // If we cannot map to a basic block, assume the statement is 21230b57cec5SDimitry Andric // reachable. 21240b57cec5SDimitry Andric } 21250b57cec5SDimitry Andric 21260b57cec5SDimitry Andric if (AllReachable) 21270b57cec5SDimitry Andric S.Diag(D.Loc, D.PD); 21280b57cec5SDimitry Andric } 21290b57cec5SDimitry Andric } 21300b57cec5SDimitry Andric 21310b57cec5SDimitry Andric if (!analyzed) 21320b57cec5SDimitry Andric flushDiagnostics(S, fscope); 21330b57cec5SDimitry Andric } 21340b57cec5SDimitry Andric 21350b57cec5SDimitry Andric // Warning: check missing 'return' 21360b57cec5SDimitry Andric if (P.enableCheckFallThrough) { 21370b57cec5SDimitry Andric const CheckFallThroughDiagnostics &CD = 21380b57cec5SDimitry Andric (isa<BlockDecl>(D) 21390b57cec5SDimitry Andric ? CheckFallThroughDiagnostics::MakeForBlock() 21400b57cec5SDimitry Andric : (isa<CXXMethodDecl>(D) && 21410b57cec5SDimitry Andric cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && 21420b57cec5SDimitry Andric cast<CXXMethodDecl>(D)->getParent()->isLambda()) 21430b57cec5SDimitry Andric ? CheckFallThroughDiagnostics::MakeForLambda() 21440b57cec5SDimitry Andric : (fscope->isCoroutine() 21450b57cec5SDimitry Andric ? CheckFallThroughDiagnostics::MakeForCoroutine(D) 21460b57cec5SDimitry Andric : CheckFallThroughDiagnostics::MakeForFunction(D))); 21470b57cec5SDimitry Andric CheckFallThroughForBody(S, D, Body, BlockType, CD, AC, fscope); 21480b57cec5SDimitry Andric } 21490b57cec5SDimitry Andric 21500b57cec5SDimitry Andric // Warning: check for unreachable code 21510b57cec5SDimitry Andric if (P.enableCheckUnreachable) { 21520b57cec5SDimitry Andric // Only check for unreachable code on non-template instantiations. 21530b57cec5SDimitry Andric // Different template instantiations can effectively change the control-flow 21540b57cec5SDimitry Andric // and it is very difficult to prove that a snippet of code in a template 21550b57cec5SDimitry Andric // is unreachable for all instantiations. 21560b57cec5SDimitry Andric bool isTemplateInstantiation = false; 21570b57cec5SDimitry Andric if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) 21580b57cec5SDimitry Andric isTemplateInstantiation = Function->isTemplateInstantiation(); 21590b57cec5SDimitry Andric if (!isTemplateInstantiation) 21600b57cec5SDimitry Andric CheckUnreachable(S, AC); 21610b57cec5SDimitry Andric } 21620b57cec5SDimitry Andric 21630b57cec5SDimitry Andric // Check for thread safety violations 21640b57cec5SDimitry Andric if (P.enableThreadSafetyAnalysis) { 21650b57cec5SDimitry Andric SourceLocation FL = AC.getDecl()->getLocation(); 21660b57cec5SDimitry Andric SourceLocation FEL = AC.getDecl()->getEndLoc(); 21670b57cec5SDimitry Andric threadSafety::ThreadSafetyReporter Reporter(S, FL, FEL); 21680b57cec5SDimitry Andric if (!Diags.isIgnored(diag::warn_thread_safety_beta, D->getBeginLoc())) 21690b57cec5SDimitry Andric Reporter.setIssueBetaWarnings(true); 21700b57cec5SDimitry Andric if (!Diags.isIgnored(diag::warn_thread_safety_verbose, D->getBeginLoc())) 21710b57cec5SDimitry Andric Reporter.setVerbose(true); 21720b57cec5SDimitry Andric 21730b57cec5SDimitry Andric threadSafety::runThreadSafetyAnalysis(AC, Reporter, 21740b57cec5SDimitry Andric &S.ThreadSafetyDeclCache); 21750b57cec5SDimitry Andric Reporter.emitDiagnostics(); 21760b57cec5SDimitry Andric } 21770b57cec5SDimitry Andric 21780b57cec5SDimitry Andric // Check for violations of consumed properties. 21790b57cec5SDimitry Andric if (P.enableConsumedAnalysis) { 21800b57cec5SDimitry Andric consumed::ConsumedWarningsHandler WarningHandler(S); 21810b57cec5SDimitry Andric consumed::ConsumedAnalyzer Analyzer(WarningHandler); 21820b57cec5SDimitry Andric Analyzer.run(AC); 21830b57cec5SDimitry Andric } 21840b57cec5SDimitry Andric 21850b57cec5SDimitry Andric if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) || 21860b57cec5SDimitry Andric !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) || 21870b57cec5SDimitry Andric !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc())) { 21880b57cec5SDimitry Andric if (CFG *cfg = AC.getCFG()) { 21890b57cec5SDimitry Andric UninitValsDiagReporter reporter(S); 21900b57cec5SDimitry Andric UninitVariablesAnalysisStats stats; 21910b57cec5SDimitry Andric std::memset(&stats, 0, sizeof(UninitVariablesAnalysisStats)); 21920b57cec5SDimitry Andric runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC, 21930b57cec5SDimitry Andric reporter, stats); 21940b57cec5SDimitry Andric 21950b57cec5SDimitry Andric if (S.CollectStats && stats.NumVariablesAnalyzed > 0) { 21960b57cec5SDimitry Andric ++NumUninitAnalysisFunctions; 21970b57cec5SDimitry Andric NumUninitAnalysisVariables += stats.NumVariablesAnalyzed; 21980b57cec5SDimitry Andric NumUninitAnalysisBlockVisits += stats.NumBlockVisits; 21990b57cec5SDimitry Andric MaxUninitAnalysisVariablesPerFunction = 22000b57cec5SDimitry Andric std::max(MaxUninitAnalysisVariablesPerFunction, 22010b57cec5SDimitry Andric stats.NumVariablesAnalyzed); 22020b57cec5SDimitry Andric MaxUninitAnalysisBlockVisitsPerFunction = 22030b57cec5SDimitry Andric std::max(MaxUninitAnalysisBlockVisitsPerFunction, 22040b57cec5SDimitry Andric stats.NumBlockVisits); 22050b57cec5SDimitry Andric } 22060b57cec5SDimitry Andric } 22070b57cec5SDimitry Andric } 22080b57cec5SDimitry Andric 22090b57cec5SDimitry Andric bool FallThroughDiagFull = 22100b57cec5SDimitry Andric !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getBeginLoc()); 22110b57cec5SDimitry Andric bool FallThroughDiagPerFunction = !Diags.isIgnored( 22120b57cec5SDimitry Andric diag::warn_unannotated_fallthrough_per_function, D->getBeginLoc()); 22130b57cec5SDimitry Andric if (FallThroughDiagFull || FallThroughDiagPerFunction || 22140b57cec5SDimitry Andric fscope->HasFallthroughStmt) { 22150b57cec5SDimitry Andric DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); 22160b57cec5SDimitry Andric } 22170b57cec5SDimitry Andric 22180b57cec5SDimitry Andric if (S.getLangOpts().ObjCWeak && 22190b57cec5SDimitry Andric !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, D->getBeginLoc())) 22200b57cec5SDimitry Andric diagnoseRepeatedUseOfWeak(S, fscope, D, AC.getParentMap()); 22210b57cec5SDimitry Andric 22220b57cec5SDimitry Andric 22230b57cec5SDimitry Andric // Check for infinite self-recursion in functions 22240b57cec5SDimitry Andric if (!Diags.isIgnored(diag::warn_infinite_recursive_function, 22250b57cec5SDimitry Andric D->getBeginLoc())) { 22260b57cec5SDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 22270b57cec5SDimitry Andric checkRecursiveFunction(S, FD, Body, AC); 22280b57cec5SDimitry Andric } 22290b57cec5SDimitry Andric } 22300b57cec5SDimitry Andric 22310b57cec5SDimitry Andric // Check for throw out of non-throwing function. 22320b57cec5SDimitry Andric if (!Diags.isIgnored(diag::warn_throw_in_noexcept_func, D->getBeginLoc())) 22330b57cec5SDimitry Andric if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 22340b57cec5SDimitry Andric if (S.getLangOpts().CPlusPlus && isNoexcept(FD)) 22350b57cec5SDimitry Andric checkThrowInNonThrowingFunc(S, FD, AC); 22360b57cec5SDimitry Andric 22370b57cec5SDimitry Andric // If none of the previous checks caused a CFG build, trigger one here 2238*a7dea167SDimitry Andric // for the logical error handler. 2239*a7dea167SDimitry Andric if (LogicalErrorHandler::hasActiveDiagnostics(Diags, D->getBeginLoc())) { 22400b57cec5SDimitry Andric AC.getCFG(); 22410b57cec5SDimitry Andric } 22420b57cec5SDimitry Andric 22430b57cec5SDimitry Andric // Collect statistics about the CFG if it was built. 22440b57cec5SDimitry Andric if (S.CollectStats && AC.isCFGBuilt()) { 22450b57cec5SDimitry Andric ++NumFunctionsAnalyzed; 22460b57cec5SDimitry Andric if (CFG *cfg = AC.getCFG()) { 22470b57cec5SDimitry Andric // If we successfully built a CFG for this context, record some more 22480b57cec5SDimitry Andric // detail information about it. 22490b57cec5SDimitry Andric NumCFGBlocks += cfg->getNumBlockIDs(); 22500b57cec5SDimitry Andric MaxCFGBlocksPerFunction = std::max(MaxCFGBlocksPerFunction, 22510b57cec5SDimitry Andric cfg->getNumBlockIDs()); 22520b57cec5SDimitry Andric } else { 22530b57cec5SDimitry Andric ++NumFunctionsWithBadCFGs; 22540b57cec5SDimitry Andric } 22550b57cec5SDimitry Andric } 22560b57cec5SDimitry Andric } 22570b57cec5SDimitry Andric 22580b57cec5SDimitry Andric void clang::sema::AnalysisBasedWarnings::PrintStats() const { 22590b57cec5SDimitry Andric llvm::errs() << "\n*** Analysis Based Warnings Stats:\n"; 22600b57cec5SDimitry Andric 22610b57cec5SDimitry Andric unsigned NumCFGsBuilt = NumFunctionsAnalyzed - NumFunctionsWithBadCFGs; 22620b57cec5SDimitry Andric unsigned AvgCFGBlocksPerFunction = 22630b57cec5SDimitry Andric !NumCFGsBuilt ? 0 : NumCFGBlocks/NumCFGsBuilt; 22640b57cec5SDimitry Andric llvm::errs() << NumFunctionsAnalyzed << " functions analyzed (" 22650b57cec5SDimitry Andric << NumFunctionsWithBadCFGs << " w/o CFGs).\n" 22660b57cec5SDimitry Andric << " " << NumCFGBlocks << " CFG blocks built.\n" 22670b57cec5SDimitry Andric << " " << AvgCFGBlocksPerFunction 22680b57cec5SDimitry Andric << " average CFG blocks per function.\n" 22690b57cec5SDimitry Andric << " " << MaxCFGBlocksPerFunction 22700b57cec5SDimitry Andric << " max CFG blocks per function.\n"; 22710b57cec5SDimitry Andric 22720b57cec5SDimitry Andric unsigned AvgUninitVariablesPerFunction = !NumUninitAnalysisFunctions ? 0 22730b57cec5SDimitry Andric : NumUninitAnalysisVariables/NumUninitAnalysisFunctions; 22740b57cec5SDimitry Andric unsigned AvgUninitBlockVisitsPerFunction = !NumUninitAnalysisFunctions ? 0 22750b57cec5SDimitry Andric : NumUninitAnalysisBlockVisits/NumUninitAnalysisFunctions; 22760b57cec5SDimitry Andric llvm::errs() << NumUninitAnalysisFunctions 22770b57cec5SDimitry Andric << " functions analyzed for uninitialiazed variables\n" 22780b57cec5SDimitry Andric << " " << NumUninitAnalysisVariables << " variables analyzed.\n" 22790b57cec5SDimitry Andric << " " << AvgUninitVariablesPerFunction 22800b57cec5SDimitry Andric << " average variables per function.\n" 22810b57cec5SDimitry Andric << " " << MaxUninitAnalysisVariablesPerFunction 22820b57cec5SDimitry Andric << " max variables per function.\n" 22830b57cec5SDimitry Andric << " " << NumUninitAnalysisBlockVisits << " block visits.\n" 22840b57cec5SDimitry Andric << " " << AvgUninitBlockVisitsPerFunction 22850b57cec5SDimitry Andric << " average block visits per function.\n" 22860b57cec5SDimitry Andric << " " << MaxUninitAnalysisBlockVisitsPerFunction 22870b57cec5SDimitry Andric << " max block visits per function.\n"; 22880b57cec5SDimitry Andric } 2289