summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp213
1 files changed, 177 insertions, 36 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 1295339..93e3ecf 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -25,6 +25,7 @@
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/Analyses/CFGReachabilityAnalysis.h"
+#include "clang/Analysis/Analyses/Consumed.h"
#include "clang/Analysis/Analyses/ReachableCode.h"
#include "clang/Analysis/Analyses/ThreadSafety.h"
#include "clang/Analysis/Analyses/UninitializedValues.h"
@@ -438,22 +439,22 @@ static bool SuggestInitializationFixit(Sema &S, const VarDecl *VD) {
<< FixItHint::CreateInsertion(VD->getLocation(), "__block ");
return true;
}
-
+
// Don't issue a fixit if there is already an initializer.
if (VD->getInit())
return false;
-
- // Suggest possible initialization (if any).
- std::string Init = S.getFixItZeroInitializerForType(VariableTy);
- if (Init.empty())
- return false;
// Don't suggest a fixit inside macros.
if (VD->getLocEnd().isMacroID())
return false;
SourceLocation Loc = S.PP.getLocForEndOfToken(VD->getLocEnd());
-
+
+ // Suggest possible initialization (if any).
+ std::string Init = S.getFixItZeroInitializerForType(VariableTy, Loc);
+ if (Init.empty())
+ return false;
+
S.Diag(Loc, diag::note_var_fixit_add_initialization) << VD->getDeclName()
<< FixItHint::CreateInsertion(Loc, Init);
return true;
@@ -492,6 +493,31 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
bool IsCapturedByBlock) {
bool Diagnosed = false;
+ switch (Use.getKind()) {
+ case UninitUse::Always:
+ S.Diag(Use.getUser()->getLocStart(), diag::warn_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock
+ << Use.getUser()->getSourceRange();
+ return;
+
+ case UninitUse::AfterDecl:
+ case UninitUse::AfterCall:
+ S.Diag(VD->getLocation(), diag::warn_sometimes_uninit_var)
+ << VD->getDeclName() << IsCapturedByBlock
+ << (Use.getKind() == UninitUse::AfterDecl ? 4 : 5)
+ << const_cast<DeclContext*>(VD->getLexicalDeclContext())
+ << VD->getSourceRange();
+ S.Diag(Use.getUser()->getLocStart(), diag::note_uninit_var_use)
+ << IsCapturedByBlock << Use.getUser()->getSourceRange();
+ return;
+
+ case UninitUse::Maybe:
+ case UninitUse::Sometimes:
+ // Carry on to report sometimes-uninitialized branches, if possible,
+ // or a 'may be used uninitialized' diagnostic otherwise.
+ break;
+ }
+
// Diagnose each branch which leads to a sometimes-uninitialized use.
for (UninitUse::branch_iterator I = Use.branch_begin(), E = Use.branch_end();
I != E; ++I) {
@@ -514,14 +540,10 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
: (I->Output ? "1" : "0");
FixItHint Fixit1, Fixit2;
- switch (Term->getStmtClass()) {
+ switch (Term ? Term->getStmtClass() : Stmt::DeclStmtClass) {
default:
// Don't know how to report this. Just fall back to 'may be used
- // uninitialized'. This happens for range-based for, which the user
- // can't explicitly fix.
- // FIXME: This also happens if the first use of a variable is always
- // uninitialized, eg "for (int n; n < 10; ++n)". We should report that
- // with the 'is uninitialized' diagnostic.
+ // uninitialized'. FIXME: Can this happen?
continue;
// "condition is true / condition is false".
@@ -582,6 +604,17 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
else
Fixit1 = FixItHint::CreateReplacement(Range, FixitStr);
break;
+ case Stmt::CXXForRangeStmtClass:
+ if (I->Output == 1) {
+ // The use occurs if a range-based for loop's body never executes.
+ // That may be impossible, and there's no syntactic fix for this,
+ // so treat it as a 'may be uninitialized' case.
+ continue;
+ }
+ DiagKind = 1;
+ Str = "for";
+ Range = cast<CXXForRangeStmt>(Term)->getRangeInit()->getSourceRange();
+ break;
// "condition is true / loop is exited".
case Stmt::DoStmtClass:
@@ -618,9 +651,7 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use,
}
if (!Diagnosed)
- S.Diag(Use.getUser()->getLocStart(),
- Use.getKind() == UninitUse::Always ? diag::warn_uninit_var
- : diag::warn_maybe_uninit_var)
+ S.Diag(Use.getUser()->getLocStart(), diag::warn_maybe_uninit_var)
<< VD->getDeclName() << IsCapturedByBlock
<< Use.getUser()->getSourceRange();
}
@@ -1123,7 +1154,7 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
// Show the first time the object was read.
S.Diag(FirstRead->getLocStart(), DiagKind)
- << ObjectKind << D << FunctionKind
+ << int(ObjectKind) << D << int(FunctionKind)
<< FirstRead->getSourceRange();
// Print all the other accesses as notes.
@@ -1154,7 +1185,7 @@ struct SLocSort {
class UninitValsDiagReporter : public UninitVariablesHandler {
Sema &S;
typedef SmallVector<UninitUse, 2> UsesVec;
- typedef std::pair<UsesVec*, bool> MappedType;
+ typedef llvm::PointerIntPair<UsesVec *, 1, bool> MappedType;
// Prefer using MapVector to DenseMap, so that iteration order will be
// the same as insertion order. This is needed to obtain a deterministic
// order of diagnostics when calling flushDiagnostics().
@@ -1172,19 +1203,18 @@ public:
uses = new UsesMap();
MappedType &V = (*uses)[vd];
- UsesVec *&vec = V.first;
- if (!vec)
- vec = new UsesVec();
+ if (!V.getPointer())
+ V.setPointer(new UsesVec());
return V;
}
void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) {
- getUses(vd).first->push_back(use);
+ getUses(vd).getPointer()->push_back(use);
}
void handleSelfInit(const VarDecl *vd) {
- getUses(vd).second = true;
+ getUses(vd).setInt(true);
}
void flushDiagnostics() {
@@ -1195,8 +1225,8 @@ public:
const VarDecl *vd = i->first;
const MappedType &V = i->second;
- UsesVec *vec = V.first;
- bool hasSelfInit = V.second;
+ UsesVec *vec = V.getPointer();
+ bool hasSelfInit = V.getInt();
// Specially handle the case where we have uses of an uninitialized
// variable, but the root cause is an idiomatic self-init. We want
@@ -1233,7 +1263,9 @@ public:
private:
static bool hasAlwaysUninitializedUse(const UsesVec* vec) {
for (UsesVec::const_iterator i = vec->begin(), e = vec->end(); i != e; ++i) {
- if (i->getKind() == UninitUse::Always) {
+ if (i->getKind() == UninitUse::Always ||
+ i->getKind() == UninitUse::AfterCall ||
+ i->getKind() == UninitUse::AfterDecl) {
return true;
}
}
@@ -1242,12 +1274,8 @@ private:
};
}
-
-//===----------------------------------------------------------------------===//
-// -Wthread-safety
-//===----------------------------------------------------------------------===//
namespace clang {
-namespace thread_safety {
+namespace {
typedef SmallVector<PartialDiagnosticAt, 1> OptionalNotes;
typedef std::pair<PartialDiagnosticAt, OptionalNotes> DelayedDiag;
typedef std::list<DelayedDiag> DiagList;
@@ -1262,7 +1290,13 @@ struct SortDiagBySourceLocation {
return SM.isBeforeInTranslationUnit(left.first.first, right.first.first);
}
};
+}}
+//===----------------------------------------------------------------------===//
+// -Wthread-safety
+//===----------------------------------------------------------------------===//
+namespace clang {
+namespace thread_safety {
namespace {
class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
Sema &S;
@@ -1413,6 +1447,102 @@ class ThreadSafetyReporter : public clang::thread_safety::ThreadSafetyHandler {
}
//===----------------------------------------------------------------------===//
+// -Wconsumed
+//===----------------------------------------------------------------------===//
+
+namespace clang {
+namespace consumed {
+namespace {
+class ConsumedWarningsHandler : public ConsumedWarningsHandlerBase {
+
+ Sema &S;
+ DiagList Warnings;
+
+public:
+
+ ConsumedWarningsHandler(Sema &S) : S(S) {}
+
+ void emitDiagnostics() {
+ Warnings.sort(SortDiagBySourceLocation(S.getSourceManager()));
+
+ for (DiagList::iterator I = Warnings.begin(), E = Warnings.end();
+ I != E; ++I) {
+
+ const OptionalNotes &Notes = I->second;
+ S.Diag(I->first.first, I->first.second);
+
+ for (unsigned NoteI = 0, NoteN = Notes.size(); NoteI != NoteN; ++NoteI) {
+ S.Diag(Notes[NoteI].first, Notes[NoteI].second);
+ }
+ }
+ }
+
+ void warnLoopStateMismatch(SourceLocation Loc, StringRef VariableName) {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_loop_state_mismatch) <<
+ VariableName);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnParamReturnTypestateMismatch(SourceLocation Loc,
+ StringRef VariableName,
+ StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_return_typestate_mismatch) << VariableName <<
+ ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnParamTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_param_typestate_mismatch) << ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnReturnTypestateForUnconsumableType(SourceLocation Loc,
+ StringRef TypeName) {
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_for_unconsumable_type) << TypeName);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnReturnTypestateMismatch(SourceLocation Loc, StringRef ExpectedState,
+ StringRef ObservedState) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_return_typestate_mismatch) << ExpectedState << ObservedState);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnUseOfTempInInvalidState(StringRef MethodName, StringRef State,
+ SourceLocation Loc) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(
+ diag::warn_use_of_temp_in_invalid_state) << MethodName << State);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+
+ void warnUseInInvalidState(StringRef MethodName, StringRef VariableName,
+ StringRef State, SourceLocation Loc) {
+
+ PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_use_in_invalid_state) <<
+ MethodName << VariableName << State);
+
+ Warnings.push_back(DelayedDiag(Warning, OptionalNotes()));
+ }
+};
+}}}
+
+//===----------------------------------------------------------------------===//
// AnalysisBasedWarnings - Worker object used by Sema to execute analysis-based
// warnings on a function, method, or block.
//===----------------------------------------------------------------------===//
@@ -1421,6 +1551,7 @@ clang::sema::AnalysisBasedWarnings::Policy::Policy() {
enableCheckFallThrough = 1;
enableCheckUnreachable = 0;
enableThreadSafetyAnalysis = 0;
+ enableConsumedAnalysis = 0;
}
clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
@@ -1441,7 +1572,9 @@ clang::sema::AnalysisBasedWarnings::AnalysisBasedWarnings(Sema &s)
DefaultPolicy.enableThreadSafetyAnalysis = (unsigned)
(D.getDiagnosticLevel(diag::warn_double_lock, SourceLocation()) !=
DiagnosticsEngine::Ignored);
-
+ DefaultPolicy.enableConsumedAnalysis = (unsigned)
+ (D.getDiagnosticLevel(diag::warn_use_in_invalid_state, SourceLocation()) !=
+ DiagnosticsEngine::Ignored);
}
static void flushDiagnostics(Sema &S, sema::FunctionScopeInfo *fscope) {
@@ -1486,10 +1619,11 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
const Stmt *Body = D->getBody();
assert(Body);
+ // Construct the analysis context with the specified CFG build options.
AnalysisDeclContext AC(/* AnalysisDeclContextManager */ 0, D);
// 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.
+ // explosion for destructors that can result and the compile time hit.
AC.getCFGBuildOptions().PruneTriviallyFalseEdges = true;
AC.getCFGBuildOptions().AddEHEdges = false;
AC.getCFGBuildOptions().AddInitializers = true;
@@ -1502,7 +1636,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
// 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 || P.enableThreadSafetyAnalysis) {
+ if (P.enableCheckUnreachable || P.enableThreadSafetyAnalysis ||
+ P.enableConsumedAnalysis) {
// Unreachable code analysis and thread safety require a linearized CFG.
AC.getCFGBuildOptions().setAllAlwaysAdd();
}
@@ -1518,8 +1653,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
.setAlwaysAdd(Stmt::AttributedStmtClass);
}
- // Construct the analysis context with the specified CFG build options.
-
+
// Emit delayed diagnostics.
if (!fscope->PossiblyUnreachableDiags.empty()) {
bool analyzed = false;
@@ -1606,6 +1740,13 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
Reporter.emitDiagnostics();
}
+ // Check for violations of consumed properties.
+ if (P.enableConsumedAnalysis) {
+ consumed::ConsumedWarningsHandler WarningHandler(S);
+ consumed::ConsumedAnalyzer Analyzer(WarningHandler);
+ Analyzer.run(AC);
+ }
+
if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart())
!= DiagnosticsEngine::Ignored ||
Diags.getDiagnosticLevel(diag::warn_sometimes_uninit_var,D->getLocStart())
OpenPOWER on IntegriCloud