UninitializedValues.cpp revision f7bafc77ba12bb1beb665243a0334cd81e024728
1//==- UninitializedValues.cpp - Find Uninitialized Values -------*- C++ --*-==//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements uninitialized values analysis for source-level CFGs.
11//
12//===----------------------------------------------------------------------===//
13
14#include <utility>
15#include "llvm/ADT/Optional.h"
16#include "llvm/ADT/SmallVector.h"
17#include "llvm/ADT/BitVector.h"
18#include "llvm/ADT/DenseMap.h"
19#include "clang/AST/Decl.h"
20#include "clang/Analysis/CFG.h"
21#include "clang/Analysis/AnalysisContext.h"
22#include "clang/Analysis/Visitors/CFGRecStmtDeclVisitor.h"
23#include "clang/Analysis/Analyses/UninitializedValues.h"
24#include "clang/Analysis/Support/SaveAndRestore.h"
25
26using namespace clang;
27
28static bool isTrackedVar(const VarDecl *vd, const DeclContext *dc) {
29  return vd->isLocalVarDecl() && !vd->hasGlobalStorage() &&
30         vd->getType()->isScalarType() &&
31         vd->getDeclContext() == dc;
32}
33
34//------------------------------------------------------------------------====//
35// DeclToIndex: a mapping from Decls we track to value indices.
36//====------------------------------------------------------------------------//
37
38namespace {
39class DeclToIndex {
40  llvm::DenseMap<const VarDecl *, unsigned> map;
41public:
42  DeclToIndex() {}
43
44  /// Compute the actual mapping from declarations to bits.
45  void computeMap(const DeclContext &dc);
46
47  /// Return the number of declarations in the map.
48  unsigned size() const { return map.size(); }
49
50  /// Returns the bit vector index for a given declaration.
51  llvm::Optional<unsigned> getValueIndex(const VarDecl *d);
52};
53}
54
55void DeclToIndex::computeMap(const DeclContext &dc) {
56  unsigned count = 0;
57  DeclContext::specific_decl_iterator<VarDecl> I(dc.decls_begin()),
58                                               E(dc.decls_end());
59  for ( ; I != E; ++I) {
60    const VarDecl *vd = *I;
61    if (isTrackedVar(vd, &dc))
62      map[vd] = count++;
63  }
64}
65
66llvm::Optional<unsigned> DeclToIndex::getValueIndex(const VarDecl *d) {
67  llvm::DenseMap<const VarDecl *, unsigned>::iterator I = map.find(d);
68  if (I == map.end())
69    return llvm::Optional<unsigned>();
70  return I->second;
71}
72
73//------------------------------------------------------------------------====//
74// CFGBlockValues: dataflow values for CFG blocks.
75//====------------------------------------------------------------------------//
76
77// These values are defined in such a way that a merge can be done using
78// a bitwise OR.
79enum Value { Unknown = 0x0,         /* 00 */
80             Initialized = 0x1,     /* 01 */
81             Uninitialized = 0x2,   /* 10 */
82             MayUninitialized = 0x3 /* 11 */ };
83
84static bool isUninitialized(const Value v) {
85  return v >= Uninitialized;
86}
87static bool isAlwaysUninit(const Value v) {
88  return v == Uninitialized;
89}
90
91class ValueVector {
92  llvm::BitVector vec;
93public:
94  ValueVector() {}
95  ValueVector(unsigned size) : vec(size << 1) {}
96  void resize(unsigned n) { vec.resize(n << 1); }
97  void merge(const ValueVector &rhs) { vec |= rhs.vec; }
98  bool operator!=(const ValueVector &rhs) const { return vec != rhs.vec; }
99  void reset() { vec.reset(); }
100
101  class reference {
102    ValueVector &vv;
103    const unsigned idx;
104
105    reference();  // Undefined
106  public:
107    reference(ValueVector &vv, unsigned idx) : vv(vv), idx(idx) {}
108    ~reference() {}
109
110    reference &operator=(Value v) {
111      vv.vec[idx << 1] = (((unsigned) v) & 0x1) ? true : false;
112      vv.vec[(idx << 1) | 1] = (((unsigned) v) & 0x2) ? true : false;
113      return *this;
114    }
115    operator Value() {
116      unsigned x = (vv.vec[idx << 1] ? 1 : 0) | (vv.vec[(idx << 1) | 1] ? 2 :0);
117      return (Value) x;
118    }
119
120    bool operator==(Value v) {
121      return v = operator Value();
122    }
123  };
124
125  reference operator[](unsigned idx) { return reference(*this, idx); }
126};
127
128typedef std::pair<ValueVector *, ValueVector *> BVPair;
129
130namespace {
131class CFGBlockValues {
132  const CFG &cfg;
133  BVPair *vals;
134  ValueVector scratch;
135  DeclToIndex DeclToIndex;
136
137  ValueVector &lazyCreate(ValueVector *&bv);
138public:
139  CFGBlockValues(const CFG &cfg);
140  ~CFGBlockValues();
141
142  void computeSetOfDeclarations(const DeclContext &dc);
143  ValueVector &getValueVector(const CFGBlock *block,
144                                const CFGBlock *dstBlock);
145
146  BVPair &getValueVectors(const CFGBlock *block, bool shouldLazyCreate);
147
148  void mergeIntoScratch(ValueVector const &source, bool isFirst);
149  bool updateValueVectorWithScratch(const CFGBlock *block);
150  bool updateValueVectors(const CFGBlock *block, const BVPair &newVals);
151
152  bool hasNoDeclarations() const {
153    return DeclToIndex.size() == 0;
154  }
155
156  void resetScratch();
157  ValueVector &getScratch() { return scratch; }
158
159  ValueVector::reference operator[](const VarDecl *vd);
160};
161}
162
163CFGBlockValues::CFGBlockValues(const CFG &c) : cfg(c), vals(0) {
164  unsigned n = cfg.getNumBlockIDs();
165  if (!n)
166    return;
167  vals = new std::pair<ValueVector*, ValueVector*>[n];
168  memset(vals, 0, sizeof(*vals) * n);
169}
170
171CFGBlockValues::~CFGBlockValues() {
172  unsigned n = cfg.getNumBlockIDs();
173  if (n == 0)
174    return;
175  for (unsigned i = 0; i < n; ++i) {
176    delete vals[i].first;
177    delete vals[i].second;
178  }
179  delete [] vals;
180}
181
182void CFGBlockValues::computeSetOfDeclarations(const DeclContext &dc) {
183  DeclToIndex.computeMap(dc);
184  scratch.resize(DeclToIndex.size());
185}
186
187ValueVector &CFGBlockValues::lazyCreate(ValueVector *&bv) {
188  if (!bv)
189    bv = new ValueVector(DeclToIndex.size());
190  return *bv;
191}
192
193/// This function pattern matches for a '&&' or '||' that appears at
194/// the beginning of a CFGBlock that also (1) has a terminator and
195/// (2) has no other elements.  If such an expression is found, it is returned.
196static BinaryOperator *getLogicalOperatorInChain(const CFGBlock *block) {
197  if (block->empty())
198    return 0;
199
200  const CFGStmt *cstmt = block->front().getAs<CFGStmt>();
201  BinaryOperator *b = llvm::dyn_cast_or_null<BinaryOperator>(cstmt->getStmt());
202
203  if (!b || !b->isLogicalOp())
204    return 0;
205
206  if (block->pred_size() == 2 &&
207      ((block->succ_size() == 2 && block->getTerminatorCondition() == b) ||
208       block->size() == 1))
209    return b;
210
211  return 0;
212}
213
214ValueVector &CFGBlockValues::getValueVector(const CFGBlock *block,
215                                            const CFGBlock *dstBlock) {
216  unsigned idx = block->getBlockID();
217  if (dstBlock && getLogicalOperatorInChain(block)) {
218    if (*block->succ_begin() == dstBlock)
219      return lazyCreate(vals[idx].first);
220    assert(*(block->succ_begin()+1) == dstBlock);
221    return lazyCreate(vals[idx].second);
222  }
223
224  assert(vals[idx].second == 0);
225  return lazyCreate(vals[idx].first);
226}
227
228BVPair &CFGBlockValues::getValueVectors(const clang::CFGBlock *block,
229                                        bool shouldLazyCreate) {
230  unsigned idx = block->getBlockID();
231  lazyCreate(vals[idx].first);
232  if (shouldLazyCreate)
233    lazyCreate(vals[idx].second);
234  return vals[idx];
235}
236
237void CFGBlockValues::mergeIntoScratch(ValueVector const &source,
238                                      bool isFirst) {
239  if (isFirst)
240    scratch = source;
241  else
242    scratch.merge(source);
243}
244#if 0
245static void printVector(const CFGBlock *block, ValueVector &bv,
246                        unsigned num) {
247
248  llvm::errs() << block->getBlockID() << " :";
249  for (unsigned i = 0; i < bv.size(); ++i) {
250    llvm::errs() << ' ' << bv[i];
251  }
252  llvm::errs() << " : " << num << '\n';
253}
254#endif
255
256bool CFGBlockValues::updateValueVectorWithScratch(const CFGBlock *block) {
257  ValueVector &dst = getValueVector(block, 0);
258  bool changed = (dst != scratch);
259  if (changed)
260    dst = scratch;
261#if 0
262  printVector(block, scratch, 0);
263#endif
264  return changed;
265}
266
267bool CFGBlockValues::updateValueVectors(const CFGBlock *block,
268                                      const BVPair &newVals) {
269  BVPair &vals = getValueVectors(block, true);
270  bool changed = *newVals.first != *vals.first ||
271                 *newVals.second != *vals.second;
272  *vals.first = *newVals.first;
273  *vals.second = *newVals.second;
274#if 0
275  printVector(block, *vals.first, 1);
276  printVector(block, *vals.second, 2);
277#endif
278  return changed;
279}
280
281void CFGBlockValues::resetScratch() {
282  scratch.reset();
283}
284
285ValueVector::reference CFGBlockValues::operator[](const VarDecl *vd) {
286  const llvm::Optional<unsigned> &idx = DeclToIndex.getValueIndex(vd);
287  assert(idx.hasValue());
288  return scratch[idx.getValue()];
289}
290
291//------------------------------------------------------------------------====//
292// Worklist: worklist for dataflow analysis.
293//====------------------------------------------------------------------------//
294
295namespace {
296class DataflowWorklist {
297  llvm::SmallVector<const CFGBlock *, 20> worklist;
298  llvm::BitVector enqueuedBlocks;
299public:
300  DataflowWorklist(const CFG &cfg) : enqueuedBlocks(cfg.getNumBlockIDs()) {}
301
302  void enqueue(const CFGBlock *block);
303  void enqueueSuccessors(const CFGBlock *block);
304  const CFGBlock *dequeue();
305
306};
307}
308
309void DataflowWorklist::enqueue(const CFGBlock *block) {
310  if (!block)
311    return;
312  unsigned idx = block->getBlockID();
313  if (enqueuedBlocks[idx])
314    return;
315  worklist.push_back(block);
316  enqueuedBlocks[idx] = true;
317}
318
319void DataflowWorklist::enqueueSuccessors(const clang::CFGBlock *block) {
320  for (CFGBlock::const_succ_iterator I = block->succ_begin(),
321       E = block->succ_end(); I != E; ++I) {
322    enqueue(*I);
323  }
324}
325
326const CFGBlock *DataflowWorklist::dequeue() {
327  if (worklist.empty())
328    return 0;
329  const CFGBlock *b = worklist.back();
330  worklist.pop_back();
331  enqueuedBlocks[b->getBlockID()] = false;
332  return b;
333}
334
335//------------------------------------------------------------------------====//
336// Transfer function for uninitialized values analysis.
337//====------------------------------------------------------------------------//
338
339namespace {
340class FindVarResult {
341  const VarDecl *vd;
342  const DeclRefExpr *dr;
343public:
344  FindVarResult(VarDecl *vd, DeclRefExpr *dr) : vd(vd), dr(dr) {}
345
346  const DeclRefExpr *getDeclRefExpr() const { return dr; }
347  const VarDecl *getDecl() const { return vd; }
348};
349
350class TransferFunctions : public CFGRecStmtVisitor<TransferFunctions> {
351  CFGBlockValues &vals;
352  const CFG &cfg;
353  AnalysisContext &ac;
354  UninitVariablesHandler *handler;
355  const DeclRefExpr *currentDR;
356  const Expr *currentVoidCast;
357  const bool flagBlockUses;
358public:
359  TransferFunctions(CFGBlockValues &vals, const CFG &cfg,
360                    AnalysisContext &ac,
361                    UninitVariablesHandler *handler,
362                    bool flagBlockUses)
363    : vals(vals), cfg(cfg), ac(ac), handler(handler), currentDR(0),
364      currentVoidCast(0), flagBlockUses(flagBlockUses) {}
365
366  const CFG &getCFG() { return cfg; }
367  void reportUninit(const DeclRefExpr *ex, const VarDecl *vd,
368                    bool isAlwaysUninit);
369
370  void VisitBlockExpr(BlockExpr *be);
371  void VisitDeclStmt(DeclStmt *ds);
372  void VisitDeclRefExpr(DeclRefExpr *dr);
373  void VisitUnaryOperator(UnaryOperator *uo);
374  void VisitBinaryOperator(BinaryOperator *bo);
375  void VisitCastExpr(CastExpr *ce);
376  void VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *se);
377  void BlockStmt_VisitObjCForCollectionStmt(ObjCForCollectionStmt *fs);
378
379  bool isTrackedVar(const VarDecl *vd) {
380    return ::isTrackedVar(vd, cast<DeclContext>(ac.getDecl()));
381  }
382
383  FindVarResult findBlockVarDecl(Expr *ex);
384};
385}
386
387void TransferFunctions::reportUninit(const DeclRefExpr *ex,
388                                     const VarDecl *vd, bool isAlwaysUnit) {
389  if (handler) handler->handleUseOfUninitVariable(ex, vd, isAlwaysUnit);
390}
391
392FindVarResult TransferFunctions::findBlockVarDecl(Expr* ex) {
393  if (DeclRefExpr* dr = dyn_cast<DeclRefExpr>(ex->IgnoreParenCasts()))
394    if (VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
395      if (isTrackedVar(vd))
396        return FindVarResult(vd, dr);
397  return FindVarResult(0, 0);
398}
399
400void TransferFunctions::BlockStmt_VisitObjCForCollectionStmt(
401    ObjCForCollectionStmt *fs) {
402
403  Visit(fs->getCollection());
404
405  // This represents an initialization of the 'element' value.
406  Stmt *element = fs->getElement();
407  const VarDecl* vd = 0;
408
409  if (DeclStmt* ds = dyn_cast<DeclStmt>(element)) {
410    vd = cast<VarDecl>(ds->getSingleDecl());
411    if (!isTrackedVar(vd))
412      vd = 0;
413  }
414  else {
415    // Initialize the value of the reference variable.
416    const FindVarResult &res = findBlockVarDecl(cast<Expr>(element));
417    vd = res.getDecl();
418    if (!vd) {
419      Visit(element);
420      return;
421    }
422  }
423
424  if (vd)
425    vals[vd] = Initialized;
426}
427
428void TransferFunctions::VisitBlockExpr(BlockExpr *be) {
429  if (!flagBlockUses || !handler)
430    return;
431  AnalysisContext::referenced_decls_iterator i, e;
432  llvm::tie(i, e) = ac.getReferencedBlockVars(be->getBlockDecl());
433  for ( ; i != e; ++i) {
434    const VarDecl *vd = *i;
435    if (vd->getAttr<BlocksAttr>() || !vd->hasLocalStorage() ||
436        !isTrackedVar(vd))
437      continue;
438    Value v = vals[vd];
439    if (isUninitialized(v))
440      handler->handleUseOfUninitVariable(be, vd, isAlwaysUninit(v));
441  }
442}
443
444void TransferFunctions::VisitDeclStmt(DeclStmt *ds) {
445  for (DeclStmt::decl_iterator DI = ds->decl_begin(), DE = ds->decl_end();
446       DI != DE; ++DI) {
447    if (VarDecl *vd = dyn_cast<VarDecl>(*DI)) {
448      if (isTrackedVar(vd)) {
449        vals[vd] = Uninitialized;
450        if (Stmt *init = vd->getInit()) {
451          Visit(init);
452          vals[vd] = Initialized;
453        }
454      }
455      else if (Stmt *init = vd->getInit()) {
456        Visit(init);
457      }
458    }
459  }
460}
461
462void TransferFunctions::VisitDeclRefExpr(DeclRefExpr *dr) {
463  // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
464  // cannot be block-level expressions.  Therefore, we determine if
465  // a DeclRefExpr is involved in a "load" by comparing it to the current
466  // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
467  // If a DeclRefExpr is not involved in a load, we are essentially computing
468  // its address, either for assignment to a reference or via the '&' operator.
469  // In such cases, treat the variable as being initialized, since this
470  // analysis isn't powerful enough to do alias tracking.
471  if (dr != currentDR)
472    if (const VarDecl *vd = dyn_cast<VarDecl>(dr->getDecl()))
473      if (isTrackedVar(vd))
474        vals[vd] = Initialized;
475}
476
477void TransferFunctions::VisitBinaryOperator(clang::BinaryOperator *bo) {
478  if (bo->isAssignmentOp()) {
479    const FindVarResult &res = findBlockVarDecl(bo->getLHS());
480    if (const VarDecl* vd = res.getDecl()) {
481      // We assume that DeclRefExprs wrapped in a BinaryOperator "assignment"
482      // cannot be block-level expressions.  Therefore, we determine if
483      // a DeclRefExpr is involved in a "load" by comparing it to the current
484      // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
485      SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
486                                                res.getDeclRefExpr());
487      Visit(bo->getRHS());
488      Visit(bo->getLHS());
489
490      ValueVector::reference val = vals[vd];
491      if (isUninitialized(val)) {
492        if (bo->getOpcode() != BO_Assign)
493          reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
494        val = Initialized;
495      }
496      return;
497    }
498  }
499  Visit(bo->getRHS());
500  Visit(bo->getLHS());
501}
502
503void TransferFunctions::VisitUnaryOperator(clang::UnaryOperator *uo) {
504  switch (uo->getOpcode()) {
505    case clang::UO_PostDec:
506    case clang::UO_PostInc:
507    case clang::UO_PreDec:
508    case clang::UO_PreInc: {
509      const FindVarResult &res = findBlockVarDecl(uo->getSubExpr());
510      if (const VarDecl *vd = res.getDecl()) {
511        // We assume that DeclRefExprs wrapped in a unary operator ++/--
512        // cannot be block-level expressions.  Therefore, we determine if
513        // a DeclRefExpr is involved in a "load" by comparing it to the current
514        // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
515        SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
516                                                  res.getDeclRefExpr());
517        Visit(uo->getSubExpr());
518
519        ValueVector::reference val = vals[vd];
520        if (isUninitialized(val)) {
521          reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
522          // Don't cascade warnings.
523          val = Initialized;
524        }
525        return;
526      }
527      break;
528    }
529    default:
530      break;
531  }
532  Visit(uo->getSubExpr());
533}
534
535void TransferFunctions::VisitCastExpr(clang::CastExpr *ce) {
536  if (ce->getCastKind() == CK_LValueToRValue) {
537    const FindVarResult &res = findBlockVarDecl(ce->getSubExpr());
538    if (const VarDecl *vd = res.getDecl()) {
539      // We assume that DeclRefExprs wrapped in an lvalue-to-rvalue cast
540      // cannot be block-level expressions.  Therefore, we determine if
541      // a DeclRefExpr is involved in a "load" by comparing it to the current
542      // DeclRefExpr found when analyzing the last lvalue-to-rvalue CastExpr.
543      // Here we update 'currentDR' to be the one associated with this
544      // lvalue-to-rvalue cast.  Then, when we analyze the DeclRefExpr, we
545      // will know that we are not computing its lvalue for other purposes
546      // than to perform a load.
547      SaveAndRestore<const DeclRefExpr*> lastDR(currentDR,
548                                                res.getDeclRefExpr());
549      Visit(ce->getSubExpr());
550      if (currentVoidCast != ce) {
551        Value val = vals[vd];
552        if (isUninitialized(val)) {
553          reportUninit(res.getDeclRefExpr(), vd, isAlwaysUninit(val));
554          // Don't cascade warnings.
555          vals[vd] = Initialized;
556        }
557      }
558      return;
559    }
560  }
561  else if (CStyleCastExpr *cse = dyn_cast<CStyleCastExpr>(ce)) {
562    if (cse->getType()->isVoidType()) {
563      // e.g. (void) x;
564      SaveAndRestore<const Expr *>
565        lastVoidCast(currentVoidCast, cse->getSubExpr()->IgnoreParens());
566      Visit(cse->getSubExpr());
567      return;
568    }
569  }
570  Visit(ce->getSubExpr());
571}
572
573void TransferFunctions::VisitUnaryExprOrTypeTraitExpr(
574                                          UnaryExprOrTypeTraitExpr *se) {
575  if (se->getKind() == UETT_SizeOf) {
576    if (se->getType()->isConstantSizeType())
577      return;
578    // Handle VLAs.
579    Visit(se->getArgumentExpr());
580  }
581}
582
583//------------------------------------------------------------------------====//
584// High-level "driver" logic for uninitialized values analysis.
585//====------------------------------------------------------------------------//
586
587static bool runOnBlock(const CFGBlock *block, const CFG &cfg,
588                       AnalysisContext &ac, CFGBlockValues &vals,
589                       UninitVariablesHandler *handler = 0,
590                       bool flagBlockUses = false) {
591
592  if (const BinaryOperator *b = getLogicalOperatorInChain(block)) {
593    CFGBlock::const_pred_iterator itr = block->pred_begin();
594    BVPair vA = vals.getValueVectors(*itr, false);
595    ++itr;
596    BVPair vB = vals.getValueVectors(*itr, false);
597
598    BVPair valsAB;
599
600    if (b->getOpcode() == BO_LAnd) {
601      // Merge the 'F' bits from the first and second.
602      vals.mergeIntoScratch(*(vA.second ? vA.second : vA.first), true);
603      vals.mergeIntoScratch(*(vB.second ? vB.second : vB.first), false);
604      valsAB.first = vA.first;
605      valsAB.second = &vals.getScratch();
606    }
607    else {
608      // Merge the 'T' bits from the first and second.
609      assert(b->getOpcode() == BO_LOr);
610      vals.mergeIntoScratch(*vA.first, true);
611      vals.mergeIntoScratch(*vB.first, false);
612      valsAB.first = &vals.getScratch();
613      valsAB.second = vA.second ? vA.second : vA.first;
614    }
615    return vals.updateValueVectors(block, valsAB);
616  }
617
618  // Default behavior: merge in values of predecessor blocks.
619  vals.resetScratch();
620  bool isFirst = true;
621  for (CFGBlock::const_pred_iterator I = block->pred_begin(),
622       E = block->pred_end(); I != E; ++I) {
623    vals.mergeIntoScratch(vals.getValueVector(*I, block), isFirst);
624    isFirst = false;
625  }
626  // Apply the transfer function.
627  TransferFunctions tf(vals, cfg, ac, handler, flagBlockUses);
628  for (CFGBlock::const_iterator I = block->begin(), E = block->end();
629       I != E; ++I) {
630    if (const CFGStmt *cs = dyn_cast<CFGStmt>(&*I)) {
631      tf.BlockStmt_Visit(cs->getStmt());
632    }
633  }
634  return vals.updateValueVectorWithScratch(block);
635}
636
637void clang::runUninitializedVariablesAnalysis(const DeclContext &dc,
638                                              const CFG &cfg,
639                                              AnalysisContext &ac,
640                                              UninitVariablesHandler &handler) {
641  CFGBlockValues vals(cfg);
642  vals.computeSetOfDeclarations(dc);
643  if (vals.hasNoDeclarations())
644    return;
645  DataflowWorklist worklist(cfg);
646  llvm::BitVector previouslyVisited(cfg.getNumBlockIDs());
647
648  worklist.enqueueSuccessors(&cfg.getEntry());
649
650  while (const CFGBlock *block = worklist.dequeue()) {
651    // Did the block change?
652    bool changed = runOnBlock(block, cfg, ac, vals);
653    if (changed || !previouslyVisited[block->getBlockID()])
654      worklist.enqueueSuccessors(block);
655    previouslyVisited[block->getBlockID()] = true;
656  }
657
658  // Run through the blocks one more time, and report uninitialized variabes.
659  for (CFG::const_iterator BI = cfg.begin(), BE = cfg.end(); BI != BE; ++BI) {
660    runOnBlock(*BI, cfg, ac, vals, &handler, /* flagBlockUses */ true);
661  }
662}
663
664UninitVariablesHandler::~UninitVariablesHandler() {}
665
666