From aa5c0121015143a5f029dcf0518783405133ffc3 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 25 Jan 2011 19:13:48 +0000 Subject: [PATCH] Teach -Wuninitialized-experimental to also warn about uninitialized variables captured by blocks. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124213 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Analysis/Analyses/UninitializedValuesV2.h | 6 ++-- include/clang/Basic/DiagnosticSemaKinds.td | 6 ++-- lib/Analysis/UninitializedValuesV2.cpp | 39 +++++++++++++++++----- lib/Sema/AnalysisBasedWarnings.cpp | 27 +++++++++------ test/Sema/uninit-variables.c | 22 +++++++++++- 5 files changed, 77 insertions(+), 23 deletions(-) diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h index 65390b644..c1fe04079 100644 --- a/include/clang/Analysis/Analyses/UninitializedValuesV2.h +++ b/include/clang/Analysis/Analyses/UninitializedValuesV2.h @@ -17,9 +17,10 @@ namespace clang { +class AnalysisContext; class CFG; class DeclContext; -class DeclRefExpr; +class Expr; class VarDecl; class UninitVariablesHandler { @@ -27,11 +28,12 @@ public: UninitVariablesHandler() {} virtual ~UninitVariablesHandler(); - virtual void handleUseOfUninitVariable(const DeclRefExpr *dr, + virtual void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) {} }; void runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, UninitVariablesHandler &handler); } diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index e31842da4..b18294eb3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -822,10 +822,12 @@ def note_uninit_reference_member : Note< "uninitialized reference member is here">; def warn_field_is_uninit : Warning<"field is uninitialized when used here">, InGroup>; -def warn_var_is_uninit : Warning<"use of uninitialized variable %0">, +def warn_uninit_var : Warning<"use of uninitialized variable %0">, InGroup>, DefaultIgnore; -def note_var_is_uninit : Note< +def note_uninit_var : Note< "variable %0 is possibly uninitialized when used here">; +def note_uninit_var_captured_by_block : Note< + "variable %0 is possibly uninitialized when captured by block">; 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/UninitializedValuesV2.cpp b/lib/Analysis/UninitializedValuesV2.cpp index 4c5488541..4edc1a965 100644 --- a/lib/Analysis/UninitializedValuesV2.cpp +++ b/lib/Analysis/UninitializedValuesV2.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/DenseMap.h" #include "clang/AST/Decl.h" #include "clang/Analysis/CFG.h" +#include "clang/Analysis/AnalysisContext.h" #include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h" #include "clang/Analysis/Analyses/UninitializedValuesV2.h" #include "clang/Analysis/Support/SaveAndRestore.h" @@ -287,16 +288,22 @@ public: class TransferFunctions : public CFGRecStmtVisitor { CFGBlockValues &vals; const CFG &cfg; + AnalysisContext ∾ UninitVariablesHandler *handler; const DeclRefExpr *currentDR; + const bool flagBlockUses; public: TransferFunctions(CFGBlockValues &vals, const CFG &cfg, - UninitVariablesHandler *handler) - : vals(vals), cfg(cfg), handler(handler), currentDR(0) {} + AnalysisContext &ac, + UninitVariablesHandler *handler, + bool flagBlockUses) + : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0), + flagBlockUses(flagBlockUses) {} const CFG &getCFG() { return cfg; } void reportUninit(const DeclRefExpr *ex, const VarDecl *vd); - + + void VisitBlockExpr(BlockExpr *be); void VisitDeclStmt(DeclStmt *ds); void VisitDeclRefExpr(DeclRefExpr *dr); void VisitUnaryOperator(UnaryOperator *uo); @@ -311,6 +318,20 @@ void TransferFunctions::reportUninit(const DeclRefExpr *ex, if (handler) handler->handleUseOfUninitVariable(ex, vd); } +void TransferFunctions::VisitBlockExpr(BlockExpr *be) { + if (!flagBlockUses || !handler) + return; + AnalysisContext::referenced_decls_iterator i, e; + llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl()); + for ( ; i != e; ++i) { + const VarDecl *vd = *i; + if (vd->getAttr() || !vd->hasLocalStorage()) + continue; + if (vals[vd] == Uninitialized) + handler->handleUseOfUninitVariable(be, vd); + } +} + void TransferFunctions::VisitDeclStmt(DeclStmt *ds) { for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end(); DI != DE; ++DI) { @@ -450,8 +471,9 @@ void TransferFunctions::VisitSizeOfAlignOfExpr(SizeOfAlignOfExpr *se) { //====------------------------------------------------------------------------// static bool runOnBlock(const CFGBlock *block, const CFG &cfg, - CFGBlockValues &vals, - UninitVariablesHandler *handler = 0) { + AnalysisContext &ac, CFGBlockValues &vals, + UninitVariablesHandler *handler = 0, + bool flagBlockUses = false) { if (const BinaryOperator *b = getLogicalOperatorInChain(block)) { if (block->pred_size() == 2 && block->succ_size() == 2) { @@ -478,7 +500,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, isFirst = false; } // Apply the transfer function. - TransferFunctions tf(vals, cfg, handler); + TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses); for (CFGBlock::const_iterator I = block->begin(), E = block->end(); I != E; ++I) { if (const CFGStmt *cs = dyn_cast(&*I)) { @@ -490,6 +512,7 @@ static bool runOnBlock(const CFGBlock *block, const CFG &cfg, void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, const CFG &cfg, + AnalysisContext &ac, UninitVariablesHandler &handler) { CFGBlockValues vals(cfg); vals.computeSetOfDeclarations(dc); @@ -502,7 +525,7 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, while (const CFGBlock *block = worklist.dequeue()) { // Did the block change? - bool changed = runOnBlock(block, cfg, vals); + bool changed = runOnBlock(block, cfg, ac, vals); if (changed || !previouslyVisited[block->getBlockID()]) worklist.enqueueSuccessors(block); previouslyVisited[block->getBlockID()] = true; @@ -510,7 +533,7 @@ void clang::runUninitializedVariablesAnalysis(const DeclContext &dc, // Run through the blocks one more time, and report uninitialized variabes. for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) { - runOnBlock(*BI, cfg, vals, &handler); + runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true); } } diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 38284f662..4866c8fb3 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -366,7 +366,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, namespace { struct SLocSort { - bool operator()(const DeclRefExpr *a, const DeclRefExpr *b) { + bool operator()(const Expr *a, const Expr *b) { SourceLocation aLoc = a->getLocStart(); SourceLocation bLoc = b->getLocStart(); return aLoc.getRawEncoding() < bLoc.getRawEncoding(); @@ -375,7 +375,7 @@ struct SLocSort { class UninitValsDiagReporter : public UninitVariablesHandler { Sema &S; - typedef llvm::SmallVector UsesVec; + typedef llvm::SmallVector UsesVec; typedef llvm::DenseMap UsesMap; UsesMap *uses; @@ -385,7 +385,7 @@ public: flushDiagnostics(); } - void handleUseOfUninitVariable(const DeclRefExpr *dr, const VarDecl *vd) { + void handleUseOfUninitVariable(const Expr *ex, const VarDecl *vd) { if (!uses) uses = new UsesMap(); @@ -393,7 +393,7 @@ public: if (!vec) vec = new UsesVec(); - vec->push_back(dr); + vec->push_back(ex); } void flushDiagnostics() { @@ -404,7 +404,7 @@ public: const VarDecl *vd = i->first; UsesVec *vec = i->second; - S.Diag(vd->getLocStart(), diag::warn_var_is_uninit) + S.Diag(vd->getLocStart(), diag::warn_uninit_var) << vd->getDeclName() << vd->getSourceRange(); // Sort the uses by their SourceLocations. While not strictly @@ -414,9 +414,15 @@ public: for (UsesVec::iterator vi = vec->begin(), ve = vec->end(); vi != ve; ++vi) { - const DeclRefExpr *dr = *vi; - S.Diag(dr->getLocStart(), diag::note_var_is_uninit) - << vd->getDeclName() << dr->getSourceRange(); + if (const DeclRefExpr *dr = dyn_cast(*vi)) { + S.Diag(dr->getLocStart(), diag::note_uninit_var) + << vd->getDeclName() << dr->getSourceRange(); + } + else { + const BlockExpr *be = cast(*vi); + S.Diag(be->getLocStart(), diag::note_uninit_var_captured_by_block) + << vd->getDeclName(); + } } // Suggest possible initialization (if any). @@ -514,11 +520,12 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (P.enableCheckUnreachable) CheckUnreachable(S, AC); - if (Diags.getDiagnosticLevel(diag::warn_var_is_uninit, D->getLocStart()) + if (Diags.getDiagnosticLevel(diag::warn_uninit_var, D->getLocStart()) != Diagnostic::Ignored) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); - runUninitializedVariablesAnalysis(*cast(D), *cfg, reporter); + runUninitializedVariablesAnalysis(*cast(D), *cfg, AC, + reporter); } } } diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c index faf94c024..200fc83b1 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 %s -verify +// RUN: %clang_cc1 -fsyntax-only -Wuninitialized-experimental -fsyntax-only -fblocks %s -verify int test1() { int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} @@ -192,3 +192,23 @@ int test28() { return sizeof(int[len]); // expected-note{{variable 'len' is possibly uninitialized when used here}} } +void test29() { + int x; // expected-warning{{use of uninitialized variable 'x'}} expected-note{{add initialization to silence this warning}} + (void) ^{ (void) x; }; // expected-note{{variable 'x' is possibly uninitialized when captured by block}} +} + +void test30() { + static int x; // no-warning + (void) ^{ (void) x; }; +} + +void test31() { + __block int x; // no-warning + (void) ^{ (void) x; }; +} + +int test32_x; +void test32() { + (void) ^{ (void) test32_x; }; // no-warning +} + -- 2.11.4.GIT