Teach -Wuninitialized-experimental to also warn
about uninitialized variables captured by blocks. llvm-svn: 124213
This commit is contained in:
parent
7fd987de23
commit
bcf848f70a
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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">;
|
||||
|
|
|
@ -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 ∾
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue