1*67e74705SXin Li //==- DeadStoresChecker.cpp - Check for stores to dead variables -*- C++ -*-==//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li //
10*67e74705SXin Li // This file defines a DeadStores, a flow-sensitive checker that looks for
11*67e74705SXin Li // stores to variables that are no longer live.
12*67e74705SXin Li //
13*67e74705SXin Li //===----------------------------------------------------------------------===//
14*67e74705SXin Li
15*67e74705SXin Li #include "ClangSACheckers.h"
16*67e74705SXin Li #include "clang/AST/ASTContext.h"
17*67e74705SXin Li #include "clang/AST/Attr.h"
18*67e74705SXin Li #include "clang/AST/ParentMap.h"
19*67e74705SXin Li #include "clang/AST/RecursiveASTVisitor.h"
20*67e74705SXin Li #include "clang/Analysis/Analyses/LiveVariables.h"
21*67e74705SXin Li #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22*67e74705SXin Li #include "clang/StaticAnalyzer/Core/Checker.h"
23*67e74705SXin Li #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
24*67e74705SXin Li #include "llvm/ADT/BitVector.h"
25*67e74705SXin Li #include "llvm/ADT/SmallString.h"
26*67e74705SXin Li #include "llvm/Support/SaveAndRestore.h"
27*67e74705SXin Li
28*67e74705SXin Li using namespace clang;
29*67e74705SXin Li using namespace ento;
30*67e74705SXin Li
31*67e74705SXin Li namespace {
32*67e74705SXin Li
33*67e74705SXin Li /// A simple visitor to record what VarDecls occur in EH-handling code.
34*67e74705SXin Li class EHCodeVisitor : public RecursiveASTVisitor<EHCodeVisitor> {
35*67e74705SXin Li public:
36*67e74705SXin Li bool inEH;
37*67e74705SXin Li llvm::DenseSet<const VarDecl *> &S;
38*67e74705SXin Li
TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt * S)39*67e74705SXin Li bool TraverseObjCAtFinallyStmt(ObjCAtFinallyStmt *S) {
40*67e74705SXin Li SaveAndRestore<bool> inFinally(inEH, true);
41*67e74705SXin Li return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtFinallyStmt(S);
42*67e74705SXin Li }
43*67e74705SXin Li
TraverseObjCAtCatchStmt(ObjCAtCatchStmt * S)44*67e74705SXin Li bool TraverseObjCAtCatchStmt(ObjCAtCatchStmt *S) {
45*67e74705SXin Li SaveAndRestore<bool> inCatch(inEH, true);
46*67e74705SXin Li return ::RecursiveASTVisitor<EHCodeVisitor>::TraverseObjCAtCatchStmt(S);
47*67e74705SXin Li }
48*67e74705SXin Li
TraverseCXXCatchStmt(CXXCatchStmt * S)49*67e74705SXin Li bool TraverseCXXCatchStmt(CXXCatchStmt *S) {
50*67e74705SXin Li SaveAndRestore<bool> inCatch(inEH, true);
51*67e74705SXin Li return TraverseStmt(S->getHandlerBlock());
52*67e74705SXin Li }
53*67e74705SXin Li
VisitDeclRefExpr(DeclRefExpr * DR)54*67e74705SXin Li bool VisitDeclRefExpr(DeclRefExpr *DR) {
55*67e74705SXin Li if (inEH)
56*67e74705SXin Li if (const VarDecl *D = dyn_cast<VarDecl>(DR->getDecl()))
57*67e74705SXin Li S.insert(D);
58*67e74705SXin Li return true;
59*67e74705SXin Li }
60*67e74705SXin Li
EHCodeVisitor(llvm::DenseSet<const VarDecl * > & S)61*67e74705SXin Li EHCodeVisitor(llvm::DenseSet<const VarDecl *> &S) :
62*67e74705SXin Li inEH(false), S(S) {}
63*67e74705SXin Li };
64*67e74705SXin Li
65*67e74705SXin Li // FIXME: Eventually migrate into its own file, and have it managed by
66*67e74705SXin Li // AnalysisManager.
67*67e74705SXin Li class ReachableCode {
68*67e74705SXin Li const CFG &cfg;
69*67e74705SXin Li llvm::BitVector reachable;
70*67e74705SXin Li public:
ReachableCode(const CFG & cfg)71*67e74705SXin Li ReachableCode(const CFG &cfg)
72*67e74705SXin Li : cfg(cfg), reachable(cfg.getNumBlockIDs(), false) {}
73*67e74705SXin Li
74*67e74705SXin Li void computeReachableBlocks();
75*67e74705SXin Li
isReachable(const CFGBlock * block) const76*67e74705SXin Li bool isReachable(const CFGBlock *block) const {
77*67e74705SXin Li return reachable[block->getBlockID()];
78*67e74705SXin Li }
79*67e74705SXin Li };
80*67e74705SXin Li }
81*67e74705SXin Li
computeReachableBlocks()82*67e74705SXin Li void ReachableCode::computeReachableBlocks() {
83*67e74705SXin Li if (!cfg.getNumBlockIDs())
84*67e74705SXin Li return;
85*67e74705SXin Li
86*67e74705SXin Li SmallVector<const CFGBlock*, 10> worklist;
87*67e74705SXin Li worklist.push_back(&cfg.getEntry());
88*67e74705SXin Li
89*67e74705SXin Li while (!worklist.empty()) {
90*67e74705SXin Li const CFGBlock *block = worklist.pop_back_val();
91*67e74705SXin Li llvm::BitVector::reference isReachable = reachable[block->getBlockID()];
92*67e74705SXin Li if (isReachable)
93*67e74705SXin Li continue;
94*67e74705SXin Li isReachable = true;
95*67e74705SXin Li for (CFGBlock::const_succ_iterator i = block->succ_begin(),
96*67e74705SXin Li e = block->succ_end(); i != e; ++i)
97*67e74705SXin Li if (const CFGBlock *succ = *i)
98*67e74705SXin Li worklist.push_back(succ);
99*67e74705SXin Li }
100*67e74705SXin Li }
101*67e74705SXin Li
102*67e74705SXin Li static const Expr *
LookThroughTransitiveAssignmentsAndCommaOperators(const Expr * Ex)103*67e74705SXin Li LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
104*67e74705SXin Li while (Ex) {
105*67e74705SXin Li const BinaryOperator *BO =
106*67e74705SXin Li dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
107*67e74705SXin Li if (!BO)
108*67e74705SXin Li break;
109*67e74705SXin Li if (BO->getOpcode() == BO_Assign) {
110*67e74705SXin Li Ex = BO->getRHS();
111*67e74705SXin Li continue;
112*67e74705SXin Li }
113*67e74705SXin Li if (BO->getOpcode() == BO_Comma) {
114*67e74705SXin Li Ex = BO->getRHS();
115*67e74705SXin Li continue;
116*67e74705SXin Li }
117*67e74705SXin Li break;
118*67e74705SXin Li }
119*67e74705SXin Li return Ex;
120*67e74705SXin Li }
121*67e74705SXin Li
122*67e74705SXin Li namespace {
123*67e74705SXin Li class DeadStoreObs : public LiveVariables::Observer {
124*67e74705SXin Li const CFG &cfg;
125*67e74705SXin Li ASTContext &Ctx;
126*67e74705SXin Li BugReporter& BR;
127*67e74705SXin Li const CheckerBase *Checker;
128*67e74705SXin Li AnalysisDeclContext* AC;
129*67e74705SXin Li ParentMap& Parents;
130*67e74705SXin Li llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
131*67e74705SXin Li std::unique_ptr<ReachableCode> reachableCode;
132*67e74705SXin Li const CFGBlock *currentBlock;
133*67e74705SXin Li std::unique_ptr<llvm::DenseSet<const VarDecl *>> InEH;
134*67e74705SXin Li
135*67e74705SXin Li enum DeadStoreKind { Standard, Enclosing, DeadIncrement, DeadInit };
136*67e74705SXin Li
137*67e74705SXin Li public:
DeadStoreObs(const CFG & cfg,ASTContext & ctx,BugReporter & br,const CheckerBase * checker,AnalysisDeclContext * ac,ParentMap & parents,llvm::SmallPtrSet<const VarDecl *,20> & escaped)138*67e74705SXin Li DeadStoreObs(const CFG &cfg, ASTContext &ctx, BugReporter &br,
139*67e74705SXin Li const CheckerBase *checker, AnalysisDeclContext *ac,
140*67e74705SXin Li ParentMap &parents,
141*67e74705SXin Li llvm::SmallPtrSet<const VarDecl *, 20> &escaped)
142*67e74705SXin Li : cfg(cfg), Ctx(ctx), BR(br), Checker(checker), AC(ac), Parents(parents),
143*67e74705SXin Li Escaped(escaped), currentBlock(nullptr) {}
144*67e74705SXin Li
~DeadStoreObs()145*67e74705SXin Li ~DeadStoreObs() override {}
146*67e74705SXin Li
isLive(const LiveVariables::LivenessValues & Live,const VarDecl * D)147*67e74705SXin Li bool isLive(const LiveVariables::LivenessValues &Live, const VarDecl *D) {
148*67e74705SXin Li if (Live.isLive(D))
149*67e74705SXin Li return true;
150*67e74705SXin Li // Lazily construct the set that records which VarDecls are in
151*67e74705SXin Li // EH code.
152*67e74705SXin Li if (!InEH.get()) {
153*67e74705SXin Li InEH.reset(new llvm::DenseSet<const VarDecl *>());
154*67e74705SXin Li EHCodeVisitor V(*InEH.get());
155*67e74705SXin Li V.TraverseStmt(AC->getBody());
156*67e74705SXin Li }
157*67e74705SXin Li // Treat all VarDecls that occur in EH code as being "always live"
158*67e74705SXin Li // when considering to suppress dead stores. Frequently stores
159*67e74705SXin Li // are followed by reads in EH code, but we don't have the ability
160*67e74705SXin Li // to analyze that yet.
161*67e74705SXin Li return InEH->count(D);
162*67e74705SXin Li }
163*67e74705SXin Li
Report(const VarDecl * V,DeadStoreKind dsk,PathDiagnosticLocation L,SourceRange R)164*67e74705SXin Li void Report(const VarDecl *V, DeadStoreKind dsk,
165*67e74705SXin Li PathDiagnosticLocation L, SourceRange R) {
166*67e74705SXin Li if (Escaped.count(V))
167*67e74705SXin Li return;
168*67e74705SXin Li
169*67e74705SXin Li // Compute reachable blocks within the CFG for trivial cases
170*67e74705SXin Li // where a bogus dead store can be reported because itself is unreachable.
171*67e74705SXin Li if (!reachableCode.get()) {
172*67e74705SXin Li reachableCode.reset(new ReachableCode(cfg));
173*67e74705SXin Li reachableCode->computeReachableBlocks();
174*67e74705SXin Li }
175*67e74705SXin Li
176*67e74705SXin Li if (!reachableCode->isReachable(currentBlock))
177*67e74705SXin Li return;
178*67e74705SXin Li
179*67e74705SXin Li SmallString<64> buf;
180*67e74705SXin Li llvm::raw_svector_ostream os(buf);
181*67e74705SXin Li const char *BugType = nullptr;
182*67e74705SXin Li
183*67e74705SXin Li switch (dsk) {
184*67e74705SXin Li case DeadInit:
185*67e74705SXin Li BugType = "Dead initialization";
186*67e74705SXin Li os << "Value stored to '" << *V
187*67e74705SXin Li << "' during its initialization is never read";
188*67e74705SXin Li break;
189*67e74705SXin Li
190*67e74705SXin Li case DeadIncrement:
191*67e74705SXin Li BugType = "Dead increment";
192*67e74705SXin Li case Standard:
193*67e74705SXin Li if (!BugType) BugType = "Dead assignment";
194*67e74705SXin Li os << "Value stored to '" << *V << "' is never read";
195*67e74705SXin Li break;
196*67e74705SXin Li
197*67e74705SXin Li case Enclosing:
198*67e74705SXin Li // Don't report issues in this case, e.g.: "if (x = foo())",
199*67e74705SXin Li // where 'x' is unused later. We have yet to see a case where
200*67e74705SXin Li // this is a real bug.
201*67e74705SXin Li return;
202*67e74705SXin Li }
203*67e74705SXin Li
204*67e74705SXin Li BR.EmitBasicReport(AC->getDecl(), Checker, BugType, "Dead store", os.str(),
205*67e74705SXin Li L, R);
206*67e74705SXin Li }
207*67e74705SXin Li
CheckVarDecl(const VarDecl * VD,const Expr * Ex,const Expr * Val,DeadStoreKind dsk,const LiveVariables::LivenessValues & Live)208*67e74705SXin Li void CheckVarDecl(const VarDecl *VD, const Expr *Ex, const Expr *Val,
209*67e74705SXin Li DeadStoreKind dsk,
210*67e74705SXin Li const LiveVariables::LivenessValues &Live) {
211*67e74705SXin Li
212*67e74705SXin Li if (!VD->hasLocalStorage())
213*67e74705SXin Li return;
214*67e74705SXin Li // Reference types confuse the dead stores checker. Skip them
215*67e74705SXin Li // for now.
216*67e74705SXin Li if (VD->getType()->getAs<ReferenceType>())
217*67e74705SXin Li return;
218*67e74705SXin Li
219*67e74705SXin Li if (!isLive(Live, VD) &&
220*67e74705SXin Li !(VD->hasAttr<UnusedAttr>() || VD->hasAttr<BlocksAttr>() ||
221*67e74705SXin Li VD->hasAttr<ObjCPreciseLifetimeAttr>())) {
222*67e74705SXin Li
223*67e74705SXin Li PathDiagnosticLocation ExLoc =
224*67e74705SXin Li PathDiagnosticLocation::createBegin(Ex, BR.getSourceManager(), AC);
225*67e74705SXin Li Report(VD, dsk, ExLoc, Val->getSourceRange());
226*67e74705SXin Li }
227*67e74705SXin Li }
228*67e74705SXin Li
CheckDeclRef(const DeclRefExpr * DR,const Expr * Val,DeadStoreKind dsk,const LiveVariables::LivenessValues & Live)229*67e74705SXin Li void CheckDeclRef(const DeclRefExpr *DR, const Expr *Val, DeadStoreKind dsk,
230*67e74705SXin Li const LiveVariables::LivenessValues& Live) {
231*67e74705SXin Li if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
232*67e74705SXin Li CheckVarDecl(VD, DR, Val, dsk, Live);
233*67e74705SXin Li }
234*67e74705SXin Li
isIncrement(VarDecl * VD,const BinaryOperator * B)235*67e74705SXin Li bool isIncrement(VarDecl *VD, const BinaryOperator* B) {
236*67e74705SXin Li if (B->isCompoundAssignmentOp())
237*67e74705SXin Li return true;
238*67e74705SXin Li
239*67e74705SXin Li const Expr *RHS = B->getRHS()->IgnoreParenCasts();
240*67e74705SXin Li const BinaryOperator* BRHS = dyn_cast<BinaryOperator>(RHS);
241*67e74705SXin Li
242*67e74705SXin Li if (!BRHS)
243*67e74705SXin Li return false;
244*67e74705SXin Li
245*67e74705SXin Li const DeclRefExpr *DR;
246*67e74705SXin Li
247*67e74705SXin Li if ((DR = dyn_cast<DeclRefExpr>(BRHS->getLHS()->IgnoreParenCasts())))
248*67e74705SXin Li if (DR->getDecl() == VD)
249*67e74705SXin Li return true;
250*67e74705SXin Li
251*67e74705SXin Li if ((DR = dyn_cast<DeclRefExpr>(BRHS->getRHS()->IgnoreParenCasts())))
252*67e74705SXin Li if (DR->getDecl() == VD)
253*67e74705SXin Li return true;
254*67e74705SXin Li
255*67e74705SXin Li return false;
256*67e74705SXin Li }
257*67e74705SXin Li
observeStmt(const Stmt * S,const CFGBlock * block,const LiveVariables::LivenessValues & Live)258*67e74705SXin Li void observeStmt(const Stmt *S, const CFGBlock *block,
259*67e74705SXin Li const LiveVariables::LivenessValues &Live) override {
260*67e74705SXin Li
261*67e74705SXin Li currentBlock = block;
262*67e74705SXin Li
263*67e74705SXin Li // Skip statements in macros.
264*67e74705SXin Li if (S->getLocStart().isMacroID())
265*67e74705SXin Li return;
266*67e74705SXin Li
267*67e74705SXin Li // Only cover dead stores from regular assignments. ++/-- dead stores
268*67e74705SXin Li // have never flagged a real bug.
269*67e74705SXin Li if (const BinaryOperator* B = dyn_cast<BinaryOperator>(S)) {
270*67e74705SXin Li if (!B->isAssignmentOp()) return; // Skip non-assignments.
271*67e74705SXin Li
272*67e74705SXin Li if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(B->getLHS()))
273*67e74705SXin Li if (VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
274*67e74705SXin Li // Special case: check for assigning null to a pointer.
275*67e74705SXin Li // This is a common form of defensive programming.
276*67e74705SXin Li const Expr *RHS =
277*67e74705SXin Li LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
278*67e74705SXin Li RHS = RHS->IgnoreParenCasts();
279*67e74705SXin Li
280*67e74705SXin Li QualType T = VD->getType();
281*67e74705SXin Li if (T.isVolatileQualified())
282*67e74705SXin Li return;
283*67e74705SXin Li if (T->isPointerType() || T->isObjCObjectPointerType()) {
284*67e74705SXin Li if (RHS->isNullPointerConstant(Ctx, Expr::NPC_ValueDependentIsNull))
285*67e74705SXin Li return;
286*67e74705SXin Li }
287*67e74705SXin Li
288*67e74705SXin Li // Special case: self-assignments. These are often used to shut up
289*67e74705SXin Li // "unused variable" compiler warnings.
290*67e74705SXin Li if (const DeclRefExpr *RhsDR = dyn_cast<DeclRefExpr>(RHS))
291*67e74705SXin Li if (VD == dyn_cast<VarDecl>(RhsDR->getDecl()))
292*67e74705SXin Li return;
293*67e74705SXin Li
294*67e74705SXin Li // Otherwise, issue a warning.
295*67e74705SXin Li DeadStoreKind dsk = Parents.isConsumedExpr(B)
296*67e74705SXin Li ? Enclosing
297*67e74705SXin Li : (isIncrement(VD,B) ? DeadIncrement : Standard);
298*67e74705SXin Li
299*67e74705SXin Li CheckVarDecl(VD, DR, B->getRHS(), dsk, Live);
300*67e74705SXin Li }
301*67e74705SXin Li }
302*67e74705SXin Li else if (const UnaryOperator* U = dyn_cast<UnaryOperator>(S)) {
303*67e74705SXin Li if (!U->isIncrementOp() || U->isPrefix())
304*67e74705SXin Li return;
305*67e74705SXin Li
306*67e74705SXin Li const Stmt *parent = Parents.getParentIgnoreParenCasts(U);
307*67e74705SXin Li if (!parent || !isa<ReturnStmt>(parent))
308*67e74705SXin Li return;
309*67e74705SXin Li
310*67e74705SXin Li const Expr *Ex = U->getSubExpr()->IgnoreParenCasts();
311*67e74705SXin Li
312*67e74705SXin Li if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Ex))
313*67e74705SXin Li CheckDeclRef(DR, U, DeadIncrement, Live);
314*67e74705SXin Li }
315*67e74705SXin Li else if (const DeclStmt *DS = dyn_cast<DeclStmt>(S))
316*67e74705SXin Li // Iterate through the decls. Warn if any initializers are complex
317*67e74705SXin Li // expressions that are not live (never used).
318*67e74705SXin Li for (const auto *DI : DS->decls()) {
319*67e74705SXin Li const auto *V = dyn_cast<VarDecl>(DI);
320*67e74705SXin Li
321*67e74705SXin Li if (!V)
322*67e74705SXin Li continue;
323*67e74705SXin Li
324*67e74705SXin Li if (V->hasLocalStorage()) {
325*67e74705SXin Li // Reference types confuse the dead stores checker. Skip them
326*67e74705SXin Li // for now.
327*67e74705SXin Li if (V->getType()->getAs<ReferenceType>())
328*67e74705SXin Li return;
329*67e74705SXin Li
330*67e74705SXin Li if (const Expr *E = V->getInit()) {
331*67e74705SXin Li while (const ExprWithCleanups *exprClean =
332*67e74705SXin Li dyn_cast<ExprWithCleanups>(E))
333*67e74705SXin Li E = exprClean->getSubExpr();
334*67e74705SXin Li
335*67e74705SXin Li // Look through transitive assignments, e.g.:
336*67e74705SXin Li // int x = y = 0;
337*67e74705SXin Li E = LookThroughTransitiveAssignmentsAndCommaOperators(E);
338*67e74705SXin Li
339*67e74705SXin Li // Don't warn on C++ objects (yet) until we can show that their
340*67e74705SXin Li // constructors/destructors don't have side effects.
341*67e74705SXin Li if (isa<CXXConstructExpr>(E))
342*67e74705SXin Li return;
343*67e74705SXin Li
344*67e74705SXin Li // A dead initialization is a variable that is dead after it
345*67e74705SXin Li // is initialized. We don't flag warnings for those variables
346*67e74705SXin Li // marked 'unused' or 'objc_precise_lifetime'.
347*67e74705SXin Li if (!isLive(Live, V) &&
348*67e74705SXin Li !V->hasAttr<UnusedAttr>() &&
349*67e74705SXin Li !V->hasAttr<ObjCPreciseLifetimeAttr>()) {
350*67e74705SXin Li // Special case: check for initializations with constants.
351*67e74705SXin Li //
352*67e74705SXin Li // e.g. : int x = 0;
353*67e74705SXin Li //
354*67e74705SXin Li // If x is EVER assigned a new value later, don't issue
355*67e74705SXin Li // a warning. This is because such initialization can be
356*67e74705SXin Li // due to defensive programming.
357*67e74705SXin Li if (E->isEvaluatable(Ctx))
358*67e74705SXin Li return;
359*67e74705SXin Li
360*67e74705SXin Li if (const DeclRefExpr *DRE =
361*67e74705SXin Li dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
362*67e74705SXin Li if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
363*67e74705SXin Li // Special case: check for initialization from constant
364*67e74705SXin Li // variables.
365*67e74705SXin Li //
366*67e74705SXin Li // e.g. extern const int MyConstant;
367*67e74705SXin Li // int x = MyConstant;
368*67e74705SXin Li //
369*67e74705SXin Li if (VD->hasGlobalStorage() &&
370*67e74705SXin Li VD->getType().isConstQualified())
371*67e74705SXin Li return;
372*67e74705SXin Li // Special case: check for initialization from scalar
373*67e74705SXin Li // parameters. This is often a form of defensive
374*67e74705SXin Li // programming. Non-scalars are still an error since
375*67e74705SXin Li // because it more likely represents an actual algorithmic
376*67e74705SXin Li // bug.
377*67e74705SXin Li if (isa<ParmVarDecl>(VD) && VD->getType()->isScalarType())
378*67e74705SXin Li return;
379*67e74705SXin Li }
380*67e74705SXin Li
381*67e74705SXin Li PathDiagnosticLocation Loc =
382*67e74705SXin Li PathDiagnosticLocation::create(V, BR.getSourceManager());
383*67e74705SXin Li Report(V, DeadInit, Loc, E->getSourceRange());
384*67e74705SXin Li }
385*67e74705SXin Li }
386*67e74705SXin Li }
387*67e74705SXin Li }
388*67e74705SXin Li }
389*67e74705SXin Li };
390*67e74705SXin Li
391*67e74705SXin Li } // end anonymous namespace
392*67e74705SXin Li
393*67e74705SXin Li //===----------------------------------------------------------------------===//
394*67e74705SXin Li // Driver function to invoke the Dead-Stores checker on a CFG.
395*67e74705SXin Li //===----------------------------------------------------------------------===//
396*67e74705SXin Li
397*67e74705SXin Li namespace {
398*67e74705SXin Li class FindEscaped {
399*67e74705SXin Li public:
400*67e74705SXin Li llvm::SmallPtrSet<const VarDecl*, 20> Escaped;
401*67e74705SXin Li
operator ()(const Stmt * S)402*67e74705SXin Li void operator()(const Stmt *S) {
403*67e74705SXin Li // Check for '&'. Any VarDecl whose address has been taken we treat as
404*67e74705SXin Li // escaped.
405*67e74705SXin Li // FIXME: What about references?
406*67e74705SXin Li if (auto *LE = dyn_cast<LambdaExpr>(S)) {
407*67e74705SXin Li findLambdaReferenceCaptures(LE);
408*67e74705SXin Li return;
409*67e74705SXin Li }
410*67e74705SXin Li
411*67e74705SXin Li const UnaryOperator *U = dyn_cast<UnaryOperator>(S);
412*67e74705SXin Li if (!U)
413*67e74705SXin Li return;
414*67e74705SXin Li if (U->getOpcode() != UO_AddrOf)
415*67e74705SXin Li return;
416*67e74705SXin Li
417*67e74705SXin Li const Expr *E = U->getSubExpr()->IgnoreParenCasts();
418*67e74705SXin Li if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E))
419*67e74705SXin Li if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl()))
420*67e74705SXin Li Escaped.insert(VD);
421*67e74705SXin Li }
422*67e74705SXin Li
423*67e74705SXin Li // Treat local variables captured by reference in C++ lambdas as escaped.
findLambdaReferenceCaptures(const LambdaExpr * LE)424*67e74705SXin Li void findLambdaReferenceCaptures(const LambdaExpr *LE) {
425*67e74705SXin Li const CXXRecordDecl *LambdaClass = LE->getLambdaClass();
426*67e74705SXin Li llvm::DenseMap<const VarDecl *, FieldDecl *> CaptureFields;
427*67e74705SXin Li FieldDecl *ThisCaptureField;
428*67e74705SXin Li LambdaClass->getCaptureFields(CaptureFields, ThisCaptureField);
429*67e74705SXin Li
430*67e74705SXin Li for (const LambdaCapture &C : LE->captures()) {
431*67e74705SXin Li if (!C.capturesVariable())
432*67e74705SXin Li continue;
433*67e74705SXin Li
434*67e74705SXin Li VarDecl *VD = C.getCapturedVar();
435*67e74705SXin Li const FieldDecl *FD = CaptureFields[VD];
436*67e74705SXin Li if (!FD)
437*67e74705SXin Li continue;
438*67e74705SXin Li
439*67e74705SXin Li // If the capture field is a reference type, it is capture-by-reference.
440*67e74705SXin Li if (FD->getType()->isReferenceType())
441*67e74705SXin Li Escaped.insert(VD);
442*67e74705SXin Li }
443*67e74705SXin Li }
444*67e74705SXin Li };
445*67e74705SXin Li } // end anonymous namespace
446*67e74705SXin Li
447*67e74705SXin Li
448*67e74705SXin Li //===----------------------------------------------------------------------===//
449*67e74705SXin Li // DeadStoresChecker
450*67e74705SXin Li //===----------------------------------------------------------------------===//
451*67e74705SXin Li
452*67e74705SXin Li namespace {
453*67e74705SXin Li class DeadStoresChecker : public Checker<check::ASTCodeBody> {
454*67e74705SXin Li public:
checkASTCodeBody(const Decl * D,AnalysisManager & mgr,BugReporter & BR) const455*67e74705SXin Li void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
456*67e74705SXin Li BugReporter &BR) const {
457*67e74705SXin Li
458*67e74705SXin Li // Don't do anything for template instantiations.
459*67e74705SXin Li // Proving that code in a template instantiation is "dead"
460*67e74705SXin Li // means proving that it is dead in all instantiations.
461*67e74705SXin Li // This same problem exists with -Wunreachable-code.
462*67e74705SXin Li if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
463*67e74705SXin Li if (FD->isTemplateInstantiation())
464*67e74705SXin Li return;
465*67e74705SXin Li
466*67e74705SXin Li if (LiveVariables *L = mgr.getAnalysis<LiveVariables>(D)) {
467*67e74705SXin Li CFG &cfg = *mgr.getCFG(D);
468*67e74705SXin Li AnalysisDeclContext *AC = mgr.getAnalysisDeclContext(D);
469*67e74705SXin Li ParentMap &pmap = mgr.getParentMap(D);
470*67e74705SXin Li FindEscaped FS;
471*67e74705SXin Li cfg.VisitBlockStmts(FS);
472*67e74705SXin Li DeadStoreObs A(cfg, BR.getContext(), BR, this, AC, pmap, FS.Escaped);
473*67e74705SXin Li L->runOnAllBlocks(A);
474*67e74705SXin Li }
475*67e74705SXin Li }
476*67e74705SXin Li };
477*67e74705SXin Li }
478*67e74705SXin Li
registerDeadStoresChecker(CheckerManager & mgr)479*67e74705SXin Li void ento::registerDeadStoresChecker(CheckerManager &mgr) {
480*67e74705SXin Li mgr.registerChecker<DeadStoresChecker>();
481*67e74705SXin Li }
482