diff --git a/clang/lib/Analysis/AnalysisContext.cpp b/clang/lib/Analysis/AnalysisContext.cpp index 0c64610bea40..ccd5088f2ec7 100644 --- a/clang/lib/Analysis/AnalysisContext.cpp +++ b/clang/lib/Analysis/AnalysisContext.cpp @@ -194,6 +194,7 @@ namespace { class FindBlockDeclRefExprsVals : public StmtVisitor{ BumpVector &BEVals; BumpVectorContext &BC; + llvm::DenseMap Visited; public: FindBlockDeclRefExprsVals(BumpVector &bevals, BumpVectorContext &bc) @@ -204,10 +205,27 @@ public: if (Stmt *child = *I) Visit(child); } + + void VisitDeclRefExpr(const DeclRefExpr *DR) { + // Non-local variables are also directly modified. + if (const VarDecl *VD = dyn_cast(DR->getDecl())) + if (!VD->hasLocalStorage()) { + unsigned &flag = Visited[VD]; + if (!flag) { + flag = 1; + BEVals.push_back(VD, BC); + } + } + } void VisitBlockDeclRefExpr(BlockDeclRefExpr *DR) { - if (const VarDecl *VD = dyn_cast(DR->getDecl())) - BEVals.push_back(VD, BC); + if (const VarDecl *VD = dyn_cast(DR->getDecl())) { + unsigned &flag = Visited[VD]; + if (!flag) { + flag = 1; + BEVals.push_back(VD, BC); + } + } } }; } // end anonymous namespace diff --git a/clang/lib/Checker/MemRegion.cpp b/clang/lib/Checker/MemRegion.cpp index 1e82883a68aa..cfa855e195c0 100644 --- a/clang/lib/Checker/MemRegion.cpp +++ b/clang/lib/Checker/MemRegion.cpp @@ -759,7 +759,7 @@ void BlockDataRegion::LazyInitializeReferencedVars() { const VarDecl *VD = *I; const VarRegion *VR = 0; - if (!VD->getAttr()) + if (!VD->getAttr() && VD->hasLocalStorage()) VR = MemMgr.getVarRegion(VD, this); else { if (LC) diff --git a/clang/lib/Checker/RegionStore.cpp b/clang/lib/Checker/RegionStore.cpp index 528419f0a886..341bfe7a7212 100644 --- a/clang/lib/Checker/RegionStore.cpp +++ b/clang/lib/Checker/RegionStore.cpp @@ -606,10 +606,11 @@ Store InvalidateRegionsWorker::InvalidateRegions(RegionStoreManager &RM, // by reference. if (const BlockDataRegion *BR = dyn_cast(baseR)) { for (BlockDataRegion::referenced_vars_iterator - I = BR->referenced_vars_begin(), E = BR->referenced_vars_end() ; - I != E; ++I) { - const VarRegion *VR = *I; - if (VR->getDecl()->getAttr()) + BI = BR->referenced_vars_begin(), BE = BR->referenced_vars_end() ; + BI != BE; ++BI) { + const VarRegion *VR = *BI; + const VarDecl *VD = VR->getDecl(); + if (VD->getAttr() || !VD->hasLocalStorage()) AddToWorkList(VR); } continue; diff --git a/clang/test/Analysis/misc-ps-region-store.m b/clang/test/Analysis/misc-ps-region-store.m index 6666dae2ed8b..46a8720c19a7 100644 --- a/clang/test/Analysis/misc-ps-region-store.m +++ b/clang/test/Analysis/misc-ps-region-store.m @@ -595,14 +595,50 @@ int blocks_2(int *p, int z) { typedef void (^RDar7582031CB)(void); @interface RDar7582031 - rdar7582031:RDar7582031CB; +- rdar7582031_b:RDar7582031CB; @end +// Test with one block. unsigned rdar7582031(RDar7582031 *o) { __block unsigned x; [o rdar7582031:^{ x = 1; }]; return x; // no-warning } +// Test with two blocks. +unsigned long rdar7582031_b(RDar7582031 *o) { + __block unsigned y; + __block unsigned long x; + [o rdar7582031:^{ y = 1; }]; + [o rdar7582031_b:^{ x = 1LL; }]; + return x + (unsigned long) y; // no-warning +} + +// Show we get an error when 'o' is null because the message +// expression has no effect. +unsigned long rdar7582031_b2(RDar7582031 *o) { + __block unsigned y; + __block unsigned long x; + if (o) + return 1; + [o rdar7582031:^{ y = 1; }]; + [o rdar7582031_b:^{ x = 1LL; }]; + return x + (unsigned long) y; // expected-warning{{The left operand of '+' is a garbage value}} +} + +// Show that we handle static variables also getting invalidated. +void rdar7582031_aux(void (^)(void)); +RDar7582031 *rdar7582031_aux_2(); + +unsigned rdar7582031_static() { + static RDar7582031 *o = 0; + rdar7582031_aux(^{ o = rdar7582031_aux_2(); }); + + __block unsigned x; + [o rdar7582031:^{ x = 1; }]; + return x; // no-warning +} + //===----------------------------------------------------------------------===// // - Test that variables passed using __blocks // are not treated as being uninitialized.