diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp | 476 |
1 files changed, 333 insertions, 143 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 7a14855e..babb8af 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -17,6 +17,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/SourceLocation.h" #include "clang/Lex/Preprocessor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclCXX.h" @@ -25,14 +26,23 @@ #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/StmtVisitor.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/CFG.h" #include "clang/Analysis/Analyses/ReachableCode.h" #include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h" +#include "clang/Analysis/Analyses/ThreadSafety.h" #include "clang/Analysis/CFGStmtMap.h" #include "clang/Analysis/Analyses/UninitializedValues.h" #include "llvm/ADT/BitVector.h" +#include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/ImmutableMap.h" +#include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" +#include <algorithm> +#include <vector> using namespace clang; @@ -86,7 +96,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { // The CFG leaves in dead things, and we don't want the dead code paths to // confuse us, so we mark all live things first. llvm::BitVector live(cfg->getNumBlockIDs()); - unsigned count = reachable_code::ScanReachableFromBlock(cfg->getEntry(), + unsigned count = reachable_code::ScanReachableFromBlock(&cfg->getEntry(), live); bool AddEHEdges = AC.getAddEHEdges(); @@ -101,7 +111,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { if (b.getTerminator() && isa<CXXTryStmt>(b.getTerminator())) // When not adding EH edges from calls, catch clauses // can otherwise seem dead. Avoid noting them as dead. - count += reachable_code::ScanReachableFromBlock(b, live); + count += reachable_code::ScanReachableFromBlock(&b, live); continue; } } @@ -126,31 +136,23 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { if (!live[B.getBlockID()]) continue; + // Skip blocks which contain an element marked as no-return. They don't + // represent actually viable edges into the exit block, so mark them as + // abnormal. + if (B.hasNoReturnElement()) { + HasAbnormalEdge = true; + continue; + } + // Destructors can appear after the 'return' in the CFG. This is // normal. We need to look pass the destructors for the return // statement (if it exists). CFGBlock::const_reverse_iterator ri = B.rbegin(), re = B.rend(); - bool hasNoReturnDtor = false; - - for ( ; ri != re ; ++ri) { - CFGElement CE = *ri; - - // FIXME: The right solution is to just sever the edges in the - // CFG itself. - if (const CFGImplicitDtor *iDtor = ri->getAs<CFGImplicitDtor>()) - if (iDtor->isNoReturn(AC.getASTContext())) { - hasNoReturnDtor = true; - HasFakeEdge = true; - break; - } - - if (isa<CFGStmt>(CE)) + + for ( ; ri != re ; ++ri) + if (isa<CFGStmt>(*ri)) break; - } - - if (hasNoReturnDtor) - continue; - + // No more CFGElements in the block? if (ri == re) { if (B.getTerminator() && isa<CXXTryStmt>(B.getTerminator())) { @@ -163,7 +165,7 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { } CFGStmt CS = cast<CFGStmt>(*ri); - Stmt *S = CS.getStmt(); + const Stmt *S = CS.getStmt(); if (isa<ReturnStmt>(S)) { HasLiveReturn = true; continue; @@ -187,34 +189,13 @@ static ControlFlowKind CheckFallThrough(AnalysisContext &AC) { HasAbnormalEdge = true; continue; } - - bool NoReturnEdge = false; - if (CallExpr *C = dyn_cast<CallExpr>(S)) { - if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) - == B.succ_end()) { - HasAbnormalEdge = true; - continue; - } - Expr *CEE = C->getCallee()->IgnoreParenCasts(); - QualType calleeType = CEE->getType(); - if (calleeType == AC.getASTContext().BoundMemberTy) { - calleeType = Expr::findBoundMemberType(CEE); - assert(!calleeType.isNull() && "analyzing unresolved call?"); - } - if (getFunctionExtInfo(calleeType).getNoReturn()) { - NoReturnEdge = true; - HasFakeEdge = true; - } else if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) { - ValueDecl *VD = DRE->getDecl(); - if (VD->hasAttr<NoReturnAttr>()) { - NoReturnEdge = true; - HasFakeEdge = true; - } - } + if (std::find(B.succ_begin(), B.succ_end(), &cfg->getExit()) + == B.succ_end()) { + HasAbnormalEdge = true; + continue; } - // FIXME: Add noreturn message sends. - if (NoReturnEdge == false) - HasPlainEdge = true; + + HasPlainEdge = true; } if (!HasPlainEdge) { if (HasLiveReturn) @@ -258,7 +239,23 @@ struct CheckFallThroughDiagnostics { if (const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Func)) isVirtualMethod = Method->isVirtual(); - if (!isVirtualMethod) + // Don't suggest that template instantiations be marked "noreturn" + bool isTemplateInstantiation = false; + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Func)) { + switch (Function->getTemplateSpecializationKind()) { + case TSK_Undeclared: + case TSK_ExplicitSpecialization: + break; + + case TSK_ImplicitInstantiation: + case TSK_ExplicitInstantiationDeclaration: + case TSK_ExplicitInstantiationDefinition: + isTemplateInstantiation = true; + break; + } + } + + if (!isVirtualMethod && !isTemplateInstantiation) D.diag_NeverFallThroughOrReturn = diag::warn_suggest_noreturn_function; else @@ -284,25 +281,25 @@ struct CheckFallThroughDiagnostics { return D; } - bool checkDiagnostics(Diagnostic &D, bool ReturnsVoid, + bool checkDiagnostics(DiagnosticsEngine &D, bool ReturnsVoid, bool HasNoReturn) const { if (funMode) { return (ReturnsVoid || D.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!HasNoReturn || D.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr, - FuncLoc) == Diagnostic::Ignored) + FuncLoc) == DiagnosticsEngine::Ignored) && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } // For blocks. return ReturnsVoid && !HasNoReturn && (!ReturnsVoid || D.getDiagnosticLevel(diag::warn_suggest_noreturn_block, FuncLoc) - == Diagnostic::Ignored); + == DiagnosticsEngine::Ignored); } }; @@ -340,7 +337,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, } } - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Short circuit for compilation speed. if (CD.checkDiagnostics(Diags, ReturnsVoid, HasNoReturn)) @@ -369,9 +366,17 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, CD.diag_AlwaysFallThrough_ReturnsNonVoid); break; case NeverFallThroughOrReturn: - if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) - S.Diag(Compound->getLBracLoc(), - CD.diag_NeverFallThroughOrReturn); + if (ReturnsVoid && !HasNoReturn && CD.diag_NeverFallThroughOrReturn) { + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 0 << FD; + } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn) + << 1 << MD; + } else { + S.Diag(Compound->getLBracLoc(), CD.diag_NeverFallThroughOrReturn); + } + } break; case NeverFallThrough: break; @@ -415,13 +420,58 @@ public: }; } +static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) { + // Don't issue a fixit if there is already an initializer. + if (VD->getInit()) + return false; + + // Suggest possible initialization (if any). + const char *initialization = 0; + QualType VariableTy = VD->getType().getCanonicalType(); + + if (VariableTy->isObjCObjectPointerType() || + VariableTy->isBlockPointerType()) { + // Check if 'nil' is defined. + if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) + initialization = " = nil"; + else + initialization = " = 0"; + } + else if (VariableTy->isRealFloatingType()) + initialization = " = 0.0"; + else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) + initialization = " = false"; + else if (VariableTy->isEnumeralType()) + return false; + else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { + if (S.Context.getLangOptions().CPlusPlus0x) + initialization = " = nullptr"; + // Check if 'NULL' is defined. + else if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) + initialization = " = NULL"; + else + initialization = " = 0"; + } + else if (VariableTy->isScalarType()) + initialization = " = 0"; + + if (initialization) { + SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); + S.Diag(loc, diag::note_var_fixit_add_initialization) << VD->getDeclName() + << FixItHint::CreateInsertion(loc, initialization); + return true; + } + return false; +} + /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed /// as a warning. If a pariticular use is one we omit warnings for, returns /// false. static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, - const Expr *E, bool isAlwaysUninit) { + const Expr *E, bool isAlwaysUninit, + bool alwaysReportSelfInit = false) { bool isSelfInit = false; if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) { @@ -441,7 +491,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, // TODO: Should we suppress maybe-uninitialized warnings for // variables initialized in this way? if (const Expr *Initializer = VD->getInit()) { - if (DRE == Initializer->IgnoreParenImpCasts()) + if (!alwaysReportSelfInit && DRE == Initializer->IgnoreParenImpCasts()) return false; ContainsReference CR(S.Context, DRE); @@ -469,54 +519,15 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, } // Report where the variable was declared when the use wasn't within - // the initializer of that declaration. - if (!isSelfInit) + // the initializer of that declaration & we didn't already suggest + // an initialization fixit. + if (!isSelfInit && !SuggestInitializationFixit(S, VD)) S.Diag(VD->getLocStart(), diag::note_uninit_var_def) << VD->getDeclName(); return true; } -static void SuggestInitializationFixit(Sema &S, const VarDecl *VD) { - // Don't issue a fixit if there is already an initializer. - if (VD->getInit()) - return; - - // Suggest possible initialization (if any). - const char *initialization = 0; - QualType VariableTy = VD->getType().getCanonicalType(); - - if (VariableTy->isObjCObjectPointerType() || - VariableTy->isBlockPointerType()) { - // Check if 'nil' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("nil"))) - initialization = " = nil"; - else - initialization = " = 0"; - } - else if (VariableTy->isRealFloatingType()) - initialization = " = 0.0"; - else if (VariableTy->isBooleanType() && S.Context.getLangOptions().CPlusPlus) - initialization = " = false"; - else if (VariableTy->isEnumeralType()) - return; - else if (VariableTy->isPointerType() || VariableTy->isMemberPointerType()) { - // Check if 'NULL' is defined. - if (S.PP.getMacroInfo(&S.getASTContext().Idents.get("NULL"))) - initialization = " = NULL"; - else - initialization = " = 0"; - } - else if (VariableTy->isScalarType()) - initialization = " = 0"; - - if (initialization) { - SourceLocation loc = S.PP.getLocForEndOfToken(VD->getLocEnd()); - S.Diag(loc, diag::note_var_fixit_add_initialization) - << FixItHint::CreateInsertion(loc, initialization); - } -} - typedef std::pair<const Expr*, bool> UninitUse; namespace { @@ -530,8 +541,8 @@ struct SLocSort { class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector<UninitUse, 2> UsesVec; - typedef llvm::DenseMap<const VarDecl *, UsesVec*> UsesMap; + typedef SmallVector<UninitUse, 2> UsesVec; + typedef llvm::DenseMap<const VarDecl *, std::pair<UsesVec*, bool> > UsesMap; UsesMap *uses; public: @@ -539,17 +550,26 @@ public: ~UninitValsDiagReporter() { flushDiagnostics(); } - - void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, - bool isAlwaysUninit) { + + std::pair<UsesVec*, bool> &getUses(const VarDecl *vd) { if (!uses) uses = new UsesMap(); - - UsesVec *&vec = (*uses)[vd]; + + UsesMap::mapped_type &V = (*uses)[vd]; + UsesVec *&vec = V.first; if (!vec) vec = new UsesVec(); - vec->push_back(std::make_pair(ex, isAlwaysUninit)); + return V; + } + + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, + bool isAlwaysUninit) { + getUses(vd).first->push_back(std::make_pair(ex, isAlwaysUninit)); + } + + void handleSelfInit(const VarDecl *vd) { + getUses(vd).second = true; } void flushDiagnostics() { @@ -558,28 +578,34 @@ public: for (UsesMap::iterator i = uses->begin(), e = uses->end(); i != e; ++i) { const VarDecl *vd = i->first; - UsesVec *vec = i->second; - - bool fixitIssued = false; - - // Sort the uses by their SourceLocations. While not strictly - // guaranteed to produce them in line/column order, this will provide - // a stable ordering. - std::sort(vec->begin(), vec->end(), SLocSort()); - - for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; - ++vi) { - if (!DiagnoseUninitializedUse(S, vd, vi->first, - /*isAlwaysUninit=*/vi->second)) - continue; - - // Suggest a fixit hint the first time we diagnose a use of a variable. - if (!fixitIssued) { - SuggestInitializationFixit(S, vd); - fixitIssued = true; + const UsesMap::mapped_type &V = i->second; + + UsesVec *vec = V.first; + bool hasSelfInit = V.second; + + // Specially handle the case where we have uses of an uninitialized + // variable, but the root cause is an idiomatic self-init. We want + // to report the diagnostic at the self-init since that is the root cause. + if (!vec->empty() && hasSelfInit) + DiagnoseUninitializedUse(S, vd, vd->getInit()->IgnoreParenCasts(), + true, /* alwaysReportSelfInit */ true); + else { + // Sort the uses by their SourceLocations. While not strictly + // guaranteed to produce them in line/column order, this will provide + // a stable ordering. + std::sort(vec->begin(), vec->end(), SLocSort()); + + for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; + ++vi) { + if (DiagnoseUninitializedUse(S, vd, vi->first, + /*isAlwaysUninit=*/vi->second)) + // Skip further diagnostics for this variable. We try to warn only + // on the first point at which a variable is used uninitialized. + break; } } - + + // Release the uses vector. delete vec; } delete uses; @@ -587,6 +613,132 @@ public: }; } + +//===----------------------------------------------------------------------===// +// -Wthread-safety +//===----------------------------------------------------------------------===// +namespace clang { +namespace thread_safety { +typedef std::pair<SourceLocation, PartialDiagnostic> DelayedDiag; +typedef llvm::SmallVector<DelayedDiag, 4> DiagList; + +struct SortDiagBySourceLocation { + Sema &S; + SortDiagBySourceLocation(Sema &S) : S(S) {} + + bool operator()(const DelayedDiag &left, const DelayedDiag &right) { + // Although this call will be slow, this is only called when outputting + // multiple warnings. + return S.getSourceManager().isBeforeInTranslationUnit(left.first, + right.first); + } +}; + +class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler { + Sema &S; + DiagList Warnings; + + // Helper functions + void warnLockMismatch(unsigned DiagID, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(DiagID) << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + public: + ThreadSafetyReporter(Sema &S) : S(S) {} + + /// \brief Emit all buffered diagnostics in order of sourcelocation. + /// We need to output diagnostics produced while iterating through + /// the lockset in deterministic order, so this function orders diagnostics + /// and outputs them. + void emitDiagnostics() { + SortDiagBySourceLocation SortDiagBySL(S); + sort(Warnings.begin(), Warnings.end(), SortDiagBySL); + for (DiagList::iterator I = Warnings.begin(), E = Warnings.end(); + I != E; ++I) + S.Diag(I->first, I->second); + } + + void handleInvalidLockExp(SourceLocation Loc) { + PartialDiagnostic Warning = S.PDiag(diag::warn_cannot_resolve_lock) << Loc; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + void handleUnmatchedUnlock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_unlock_but_no_lock, LockName, Loc); + } + + void handleDoubleLock(Name LockName, SourceLocation Loc) { + warnLockMismatch(diag::warn_double_lock, LockName, Loc); + } + + void handleMutexHeldEndOfScope(Name LockName, SourceLocation Loc, + LockErrorKind LEK){ + unsigned DiagID = 0; + switch (LEK) { + case LEK_LockedSomePredecessors: + DiagID = diag::warn_lock_at_end_of_scope; + break; + case LEK_LockedSomeLoopIterations: + DiagID = diag::warn_expecting_lock_held_on_loop; + break; + case LEK_LockedAtEndOfFunction: + DiagID = diag::warn_no_unlock; + break; + } + warnLockMismatch(DiagID, LockName, Loc); + } + + + void handleExclusiveAndShared(Name LockName, SourceLocation Loc1, + SourceLocation Loc2) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_lock_exclusive_and_shared) << LockName; + PartialDiagnostic Note = + S.PDiag(diag::note_lock_exclusive_and_shared) << LockName; + Warnings.push_back(DelayedDiag(Loc1, Warning)); + Warnings.push_back(DelayedDiag(Loc2, Note)); + } + + void handleNoMutexHeld(const NamedDecl *D, ProtectedOperationKind POK, + AccessKind AK, SourceLocation Loc) { + assert((POK == POK_VarAccess || POK == POK_VarDereference) + && "Only works for variables"); + unsigned DiagID = POK == POK_VarAccess? + diag::warn_variable_requires_any_lock: + diag::warn_var_deref_requires_any_lock; + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << getLockKindFromAccessKind(AK); + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleMutexNotHeld(const NamedDecl *D, ProtectedOperationKind POK, + Name LockName, LockKind LK, SourceLocation Loc) { + unsigned DiagID = 0; + switch (POK) { + case POK_VarAccess: + DiagID = diag::warn_variable_requires_lock; + break; + case POK_VarDereference: + DiagID = diag::warn_var_deref_requires_lock; + break; + case POK_FunctionCall: + DiagID = diag::warn_fun_requires_lock; + break; + } + PartialDiagnostic Warning = S.PDiag(DiagID) + << D->getName() << LockName << LK; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } + + void handleFunExcludesLock(Name FunName, Name LockName, SourceLocation Loc) { + PartialDiagnostic Warning = + S.PDiag(diag::warn_fun_excludes_mutex) << FunName << LockName; + Warnings.push_back(DelayedDiag(Loc, Warning)); + } +}; +} +} + //===----------------------------------------------------------------------===// // AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based // warnings on a function, method, or block. @@ -595,6 +747,7 @@ public: clang::sema::AnalysisBasedWarnings::Policy::Policy() { enableCheckFallThrough = 1; enableCheckUnreachable = 0; + enableThreadSafetyAnalysis = 0; } clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) @@ -608,14 +761,18 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s) MaxUninitAnalysisVariablesPerFunction(0), NumUninitAnalysisBlockVisits(0), MaxUninitAnalysisBlockVisitsPerFunction(0) { - Diagnostic &D = S.getDiagnostics(); + DiagnosticsEngine &D = S.getDiagnostics(); DefaultPolicy.enableCheckUnreachable = (unsigned) (D.getDiagnosticLevel(diag::warn_unreachable, SourceLocation()) != - Diagnostic::Ignored); + DiagnosticsEngine::Ignored); + DefaultPolicy.enableThreadSafetyAnalysis = (unsigned) + (D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) != + DiagnosticsEngine::Ignored); + } static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) { - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -635,7 +792,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // don't bother trying. // (2) The code already has problems; running the analysis just takes more // time. - Diagnostic &Diags = S.getDiagnostics(); + DiagnosticsEngine &Diags = S.getDiagnostics(); // Do not do any analysis for declarations in system headers if we are // going to just ignore them. @@ -656,17 +813,43 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, const Stmt *Body = D->getBody(); assert(Body); + AnalysisContext AC(D, 0); + // Don't generate EH edges for CallExprs as we'd like to avoid the n^2 // explosion for destrutors that can result and the compile time hit. - AnalysisContext AC(D, 0, /*useUnoptimizedCFG=*/false, /*addehedges=*/false, - /*addImplicitDtors=*/true, /*addInitializers=*/true); + AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true; + AC.getCFGBuildOptions().AddEHEdges = false; + AC.getCFGBuildOptions().AddInitializers = true; + AC.getCFGBuildOptions().AddImplicitDtors = true; + + // Force that certain expressions appear as CFGElements in the CFG. This + // is used to speed up various analyses. + // FIXME: This isn't the right factoring. This is here for initial + // prototyping, but we need a way for analyses to say what expressions they + // expect to always be CFGElements and then fill in the BuildOptions + // appropriately. This is essentially a layering violation. + if (P.enableCheckUnreachable) { + // Unreachable code analysis requires a linearized CFG. + AC.getCFGBuildOptions().setAllAlwaysAdd(); + } + else { + AC.getCFGBuildOptions() + .setAlwaysAdd(Stmt::BinaryOperatorClass) + .setAlwaysAdd(Stmt::BlockExprClass) + .setAlwaysAdd(Stmt::CStyleCastExprClass) + .setAlwaysAdd(Stmt::DeclRefExprClass) + .setAlwaysAdd(Stmt::ImplicitCastExprClass) + .setAlwaysAdd(Stmt::UnaryOperatorClass); + } + // Construct the analysis context with the specified CFG build options. + // Emit delayed diagnostics. if (!fscope->PossiblyUnreachableDiags.empty()) { bool analyzed = false; // Register the expressions with the CFGBuilder. - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) { @@ -676,7 +859,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (AC.getCFG()) { analyzed = true; - for (llvm::SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator + for (SmallVectorImpl<sema::PossiblyUnreachableDiag>::iterator i = fscope->PossiblyUnreachableDiags.begin(), e = fscope->PossiblyUnreachableDiags.end(); i != e; ++i) @@ -716,11 +899,18 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check for unreachable code if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - + + // Check for thread safety violations + if (P.enableThreadSafetyAnalysis) { + thread_safety::ThreadSafetyReporter Reporter(S); + thread_safety::runThreadSafetyAnalysis(AC, Reporter); + Reporter.emitDiagnostics(); + } + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) - != Diagnostic::Ignored || + != DiagnosticsEngine::Ignored || Diags.getDiagnosticLevel(diag::warn_maybe_uninit_var, D->getLocStart()) - != Diagnostic::Ignored) { + != DiagnosticsEngine::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); UninitVariablesAnalysisStats stats; |