aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2011-01-25 19:13:48 +0000
committerTed Kremenek <kremenek@apple.com>2011-01-25 19:13:48 +0000
commita8c17a5babab35f2db26bf218e7571d1af4afedf (patch)
treeba2d1e33c9fbe93b088bf9fdf632e7537f38a215
parent937596fc25bba3ac7519e9ffff3e4fab2c97863e (diff)
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
-rw-r--r--include/clang/Analysis/Analyses/UninitializedValuesV2.h6
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--lib/Analysis/UninitializedValuesV2.cpp39
-rw-r--r--lib/Sema/AnalysisBasedWarnings.cpp27
-rw-r--r--test/Sema/uninit-variables.c22
5 files changed, 77 insertions, 23 deletions
diff --git a/include/clang/Analysis/Analyses/UninitializedValuesV2.h b/include/clang/Analysis/Analyses/UninitializedValuesV2.h
index 65390b644e..c1fe040793 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 e31842da4e..b18294eb3f 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<DiagGroup<"uninitialized">>;
-def warn_var_is_uninit : Warning<"use of uninitialized variable %0">,
+def warn_uninit_var : Warning<"use of uninitialized variable %0">,
InGroup<DiagGroup<"uninitialized-experimental">>, 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 4c54885413..4edc1a965b 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<TransferFunctions> {
CFGBlockValues &vals;
const CFG &cfg;
+ AnalysisContext &ac;
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<BlocksAttr>() || !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<CFGStmt>(&*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 38284f6627..4866c8fb3d 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<const DeclRefExpr *, 2> UsesVec;
+ typedef llvm::SmallVector<const Expr *, 2> UsesVec;
typedef llvm::DenseMap<const VarDecl *, UsesVec*> 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<DeclRefExpr>(*vi)) {
+ S.Diag(dr->getLocStart(), diag::note_uninit_var)
+ << vd->getDeclName() << dr->getSourceRange();
+ }
+ else {
+ const BlockExpr *be = cast<BlockExpr>(*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<DeclContext>(D), *cfg, reporter);
+ runUninitializedVariablesAnalysis(*cast<DeclContext>(D), *cfg, AC,
+ reporter);
}
}
}
diff --git a/test/Sema/uninit-variables.c b/test/Sema/uninit-variables.c
index faf94c024b..200fc83b10 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
+}
+