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 ∾ 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