From f7bafc77ba12bb1beb665243a0334cd81e024728 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 15 Mar 2011 04:57:38 +0000 Subject: [PATCH] Split warnings from -Wuninitialized-experimental into "must-be-initialized" and "may-be-initialized" warnings, each controlled by different flags. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@127666 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Analysis/Analyses/UninitializedValues.h | 3 +- include/clang/Basic/DiagnosticGroups.td | 7 +- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++ lib/Analysis/UninitializedValues.cpp | 64 +++++++++++++------ lib/Sema/AnalysisBasedWarnings.cpp | 28 +++++--- test/Sema/uninit-variables.c | 2 +- 6 files changed, 77 insertions(+), 33 deletions(-) diff --git a/include/clang/Analysis/Analyses/UninitializedValues.h b/include/clang/Analysis/Analyses/UninitializedValues.h index 2c41bbf6d0..b966f3a90f 100644 --- a/include/clang/Analysis/Analyses/UninitializedValues.h +++ b/include/clang/Analysis/Analyses/UninitializedValues.h @@ -29,7 +29,8 @@ public: virtual ~UninitVariablesHandler(); virtual void handleUseOfUninitVariable(const Expr *ex, - const VarDecl *vd) {} + const VarDecl *vd, + bool isAlwaysUninit) {} }; void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index e5cd51c96c..31d9ef389d 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -136,7 +136,8 @@ def Switch : DiagGroup<"switch", [SwitchEnum]>; def Trigraphs : DiagGroup<"trigraphs">; def : DiagGroup<"type-limits">; -def Uninitialized : DiagGroup<"uninitialized">; + +def UninitializedMaybe : DiagGroup<"uninitialized-maybe">; def UnknownPragmas : DiagGroup<"unknown-pragmas">; def UnknownAttributes : DiagGroup<"unknown-attributes">; def UnnamedTypeTemplateArgs : DiagGroup<"unnamed-type-template-args">; @@ -199,6 +200,10 @@ def Unused : DiagGroup<"unused", UnusedValue, UnusedVariable]>, DiagCategory<"Unused Entity Issue">; +def Uninitialized : DiagGroup<"uninitialized", + [UninitializedMaybe]>, + DiagCategory<"Uninitialized Value Issues">; + // Format settings. def FormatSecurity : DiagGroup<"format-security">; def Format : DiagGroup<"format", diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 3a6c43c269..641fa3f07b 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -868,11 +868,17 @@ def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup; def warn_uninit_var : Warning<"variable %0 is possibly uninitialized when used here">, InGroup>, DefaultIgnore; +def warn_maybe_uninit_var : + Warning<"variable %0 is possibly uninitialized when used here">, + InGroup, DefaultIgnore; def note_uninit_var_def : Note< "variable %0 is declared here">; def warn_uninit_var_captured_by_block : Warning< "variable %0 is possibly uninitialized when captured by block">, InGroup>, DefaultIgnore; +def warn_maybe_uninit_var_captured_by_block : Warning< + "variable %0 is possibly uninitialized when captured by block">, + InGroup, DefaultIgnore; def note_var_fixit_add_initialization : Note< "add initialization to silence this warning">; def err_init_incomplete_type : Error<"initialization of incomplete type %0">; diff --git a/lib/Analysis/UninitializedValues.cpp b/lib/Analysis/UninitializedValues.cpp index 4aa62254da..f651b474a0 100644 --- a/lib/Analysis/UninitializedValues.cpp +++ b/lib/Analysis/UninitializedValues.cpp @@ -74,14 +74,26 @@ llvm::Optional DeclToIndex::getValueIndex(const VarDecl *d) { // CFGBlockValues: dataflow values for CFG blocks. //====------------------------------------------------------------------------// -enum Value { Initialized = 0, Uninitialized = 1 }; +// These values are defined in such a way that a merge can be done using +// a bitwise OR. +enum Value { Unknown = 0x0, /* 00 */ + Initialized = 0x1, /* 01 */ + Uninitialized = 0x2, /* 10 */ + MayUninitialized = 0x3 /* 11 */ }; + +static bool isUninitialized(const Value v) { + return v >= Uninitialized; +} +static bool isAlwaysUninit(const Value v) { + return v == Uninitialized; +} class ValueVector { llvm::BitVector vec; public: ValueVector() {} - ValueVector(unsigned size) : vec(size) {} - void resize(unsigned n) { vec.resize(n); } + ValueVector(unsigned size) : vec(size << 1) {} + void resize(unsigned n) { vec.resize(n << 1); } void merge(const ValueVector &rhs) { vec |= rhs.vec; } bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; } void reset() { vec.reset(); } @@ -96,11 +108,17 @@ public: ~reference() {} reference &operator=(Value v) { - vv.vec[idx] = (v == Initialized ? false : true); + vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false; + vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false; return *this; } + operator Value() { + unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0); + return (Value) x; + } + bool operator==(Value v) { - return vv.vec[idx] == (v == Initialized ? false : true); + return v = operator Value(); } }; @@ -346,7 +364,8 @@ public: currentVoidCast(0), flagBlockUses(flagBlockUses) {} const CFG &getCFG() { return cfg; } - void reportUninit(const DeclRefExpr *ex, const VarDecl *vd); + void reportUninit(const DeclRefExpr *ex, const VarDecl *vd, + bool isAlwaysUninit); void VisitBlockExpr(BlockExpr *be); void VisitDeclStmt(DeclStmt *ds); @@ -366,8 +385,8 @@ public: } void TransferFunctions::reportUninit(const DeclRefExpr *ex, - const VarDecl *vd) { - if (handler) handler->handleUseOfUninitVariable(ex, vd); + const VarDecl *vd, bool isAlwaysUnit) { + if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit); } FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) { @@ -416,8 +435,9 @@ void TransferFunctions::VisitBlockExpr(BlockExpr *be) { if (vd->getAttr() || !vd->hasLocalStorage() || !isTrackedVar(vd)) continue; - if (vals[vd] == Uninitialized) - handler->handleUseOfUninitVariable(be, vd); + Value v = vals[vd]; + if (isUninitialized(v)) + handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v)); } } @@ -468,9 +488,9 @@ void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) { Visit(bo->getLHS()); ValueVector::reference val = vals[vd]; - if (val == Uninitialized) { + if (isUninitialized(val)) { if (bo->getOpcode() != BO_Assign) - reportUninit(res.getDeclRefExpr(), vd); + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); val = Initialized; } return; @@ -496,10 +516,11 @@ void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) { res.getDeclRefExpr()); Visit(uo->getSubExpr()); - ValueVector::reference bit = vals[vd]; - if (bit == Uninitialized) { - reportUninit(res.getDeclRefExpr(), vd); - bit = Initialized; + ValueVector::reference val = vals[vd]; + if (isUninitialized(val)) { + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); + // Don't cascade warnings. + val = Initialized; } return; } @@ -526,10 +547,13 @@ void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) { SaveAndRestore lastDR(currentDR, res.getDeclRefExpr()); Visit(ce->getSubExpr()); - if (currentVoidCast != ce && vals[vd] == Uninitialized) { - reportUninit(res.getDeclRefExpr(), vd); - // Don't cascade warnings. - vals[vd] = Initialized; + if (currentVoidCast != ce) { + Value val = vals[vd]; + if (isUninitialized(val)) { + reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val)); + // Don't cascade warnings. + vals[vd] = Initialized; + } } return; } diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 2da100ec82..e71f2dfb86 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -377,18 +377,20 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, // -Wuninitialized //===----------------------------------------------------------------------===// +typedef std::pair UninitUse; + namespace { struct SLocSort { - bool operator()(const Expr *a, const Expr *b) { - SourceLocation aLoc = a->getLocStart(); - SourceLocation bLoc = b->getLocStart(); + bool operator()(const UninitUse &a, const UninitUse &b) { + SourceLocation aLoc = a.first->getLocStart(); + SourceLocation bLoc = b.first->getLocStart(); return aLoc.getRawEncoding() < bLoc.getRawEncoding(); } }; class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector UsesVec; + typedef llvm::SmallVector UsesVec; typedef llvm::DenseMap UsesMap; UsesMap *uses; @@ -398,7 +400,8 @@ public: flushDiagnostics(); } - void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) { + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd, + bool isAlwaysUninit) { if (!uses) uses = new UsesMap(); @@ -406,7 +409,7 @@ public: if (!vec) vec = new UsesVec(); - vec->push_back(ex); + vec->push_back(std::make_pair(ex, isAlwaysUninit)); } void flushDiagnostics() { @@ -426,13 +429,18 @@ public: for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) { - if (const DeclRefExpr *dr = dyn_cast(*vi)) { - S.Diag(dr->getLocStart(), diag::warn_uninit_var) + const bool isAlwaysUninit = vi->second; + if (const DeclRefExpr *dr = dyn_cast(vi->first)) { + S.Diag(dr->getLocStart(), + isAlwaysUninit ? diag::warn_uninit_var + : diag::warn_maybe_uninit_var) << vd->getDeclName() << dr->getSourceRange(); } else { - const BlockExpr *be = cast(*vi); - S.Diag(be->getLocStart(), diag::warn_uninit_var_captured_by_block) + const BlockExpr *be = cast(vi->first); + S.Diag(be->getLocStart(), + isAlwaysUninit ? diag::warn_uninit_var_captured_by_block + : diag::warn_maybe_uninit_var_captured_by_block) << vd->getDeclName(); } diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c index bb29552901..79dbfa8895 100644 --- a/test/Sema/uninit-variables.c +++ b/test/Sema/uninit-variables.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -Wuninitialized-maybe -fsyntax-only -fblocks %s -verify int test1() { int x; // expected-note{{variable 'x' is declared here}} expected-note{{add initialization to silence this warning}} -- 2.40.0