1 //===- Consumed.cpp --------------------------------------------*- 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 // A intra-procedural analysis for checking consumed properties. This is based, 11 // in part, on research on linear types. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "clang/AST/ASTContext.h" 16 #include "clang/AST/Attr.h" 17 #include "clang/AST/DeclCXX.h" 18 #include "clang/AST/ExprCXX.h" 19 #include "clang/AST/RecursiveASTVisitor.h" 20 #include "clang/AST/StmtVisitor.h" 21 #include "clang/AST/StmtCXX.h" 22 #include "clang/AST/Type.h" 23 #include "clang/Analysis/Analyses/PostOrderCFGView.h" 24 #include "clang/Analysis/AnalysisContext.h" 25 #include "clang/Analysis/CFG.h" 26 #include "clang/Analysis/Analyses/Consumed.h" 27 #include "clang/Basic/OperatorKinds.h" 28 #include "clang/Basic/SourceLocation.h" 29 #include "llvm/ADT/DenseMap.h" 30 #include "llvm/ADT/SmallVector.h" 31 #include "llvm/Support/Compiler.h" 32 #include "llvm/Support/raw_ostream.h" 33 34 // TODO: Use information from tests in while-loop conditional. 35 // TODO: Add notes about the actual and expected state for 36 // TODO: Correctly identify unreachable blocks when chaining boolean operators. 37 // TODO: Adjust the parser and AttributesList class to support lists of 38 // identifiers. 39 // TODO: Warn about unreachable code. 40 // TODO: Switch to using a bitmap to track unreachable blocks. 41 // TODO: Handle variable definitions, e.g. bool valid = x.isValid(); 42 // if (valid) ...; (Deferred) 43 // TODO: Take notes on state transitions to provide better warning messages. 44 // (Deferred) 45 // TODO: Test nested conditionals: A) Checking the same value multiple times, 46 // and 2) Checking different values. (Deferred) 47 48 using namespace clang; 49 using namespace consumed; 50 51 // Key method definition 52 ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() {} 53 54 static SourceLocation getLastStmtLoc(const CFGBlock *Block) { 55 // Find the source location of the last statement in the block, if the block 56 // is not empty. 57 if (const Stmt *StmtNode = Block->getTerminator()) { 58 return StmtNode->getLocStart(); 59 } else { 60 for (CFGBlock::const_reverse_iterator BI = Block->rbegin(), 61 BE = Block->rend(); BI != BE; ++BI) { 62 // FIXME: Handle other CFGElement kinds. 63 if (Optional<CFGStmt> CS = BI->getAs<CFGStmt>()) 64 return CS->getStmt()->getLocStart(); 65 } 66 } 67 68 // The block is empty, and has a single predecessor. Use its exit location. 69 assert(Block->pred_size() == 1 && *Block->pred_begin() && 70 Block->succ_size() != 0); 71 72 return getLastStmtLoc(*Block->pred_begin()); 73 } 74 75 static ConsumedState invertConsumedUnconsumed(ConsumedState State) { 76 switch (State) { 77 case CS_Unconsumed: 78 return CS_Consumed; 79 case CS_Consumed: 80 return CS_Unconsumed; 81 case CS_None: 82 return CS_None; 83 case CS_Unknown: 84 return CS_Unknown; 85 } 86 llvm_unreachable("invalid enum"); 87 } 88 89 static bool isCallableInState(const CallableWhenAttr *CWAttr, 90 ConsumedState State) { 91 92 CallableWhenAttr::callableState_iterator I = CWAttr->callableState_begin(), 93 E = CWAttr->callableState_end(); 94 95 for (; I != E; ++I) { 96 97 ConsumedState MappedAttrState = CS_None; 98 99 switch (*I) { 100 case CallableWhenAttr::Unknown: 101 MappedAttrState = CS_Unknown; 102 break; 103 104 case CallableWhenAttr::Unconsumed: 105 MappedAttrState = CS_Unconsumed; 106 break; 107 108 case CallableWhenAttr::Consumed: 109 MappedAttrState = CS_Consumed; 110 break; 111 } 112 113 if (MappedAttrState == State) 114 return true; 115 } 116 117 return false; 118 } 119 120 static bool isConsumableType(const QualType &QT) { 121 if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl()) 122 return RD->hasAttr<ConsumableAttr>(); 123 else 124 return false; 125 } 126 127 static bool isKnownState(ConsumedState State) { 128 switch (State) { 129 case CS_Unconsumed: 130 case CS_Consumed: 131 return true; 132 case CS_None: 133 case CS_Unknown: 134 return false; 135 } 136 llvm_unreachable("invalid enum"); 137 } 138 139 static bool isTestingFunction(const FunctionDecl *FunDecl) { 140 return FunDecl->hasAttr<TestsTypestateAttr>(); 141 } 142 143 static ConsumedState mapConsumableAttrState(const QualType QT) { 144 assert(isConsumableType(QT)); 145 146 const ConsumableAttr *CAttr = 147 QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>(); 148 149 switch (CAttr->getDefaultState()) { 150 case ConsumableAttr::Unknown: 151 return CS_Unknown; 152 case ConsumableAttr::Unconsumed: 153 return CS_Unconsumed; 154 case ConsumableAttr::Consumed: 155 return CS_Consumed; 156 } 157 llvm_unreachable("invalid enum"); 158 } 159 160 static ConsumedState 161 mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) { 162 switch (RTSAttr->getState()) { 163 case ReturnTypestateAttr::Unknown: 164 return CS_Unknown; 165 case ReturnTypestateAttr::Unconsumed: 166 return CS_Unconsumed; 167 case ReturnTypestateAttr::Consumed: 168 return CS_Consumed; 169 } 170 llvm_unreachable("invalid enum"); 171 } 172 173 static StringRef stateToString(ConsumedState State) { 174 switch (State) { 175 case consumed::CS_None: 176 return "none"; 177 178 case consumed::CS_Unknown: 179 return "unknown"; 180 181 case consumed::CS_Unconsumed: 182 return "unconsumed"; 183 184 case consumed::CS_Consumed: 185 return "consumed"; 186 } 187 llvm_unreachable("invalid enum"); 188 } 189 190 static ConsumedState testsFor(const FunctionDecl *FunDecl) { 191 assert(isTestingFunction(FunDecl)); 192 switch (FunDecl->getAttr<TestsTypestateAttr>()->getTestState()) { 193 case TestsTypestateAttr::Unconsumed: 194 return CS_Unconsumed; 195 case TestsTypestateAttr::Consumed: 196 return CS_Consumed; 197 } 198 llvm_unreachable("invalid enum"); 199 } 200 201 namespace { 202 struct VarTestResult { 203 const VarDecl *Var; 204 ConsumedState TestsFor; 205 }; 206 } // end anonymous::VarTestResult 207 208 namespace clang { 209 namespace consumed { 210 211 enum EffectiveOp { 212 EO_And, 213 EO_Or 214 }; 215 216 class PropagationInfo { 217 enum { 218 IT_None, 219 IT_State, 220 IT_Test, 221 IT_BinTest, 222 IT_Var 223 } InfoType; 224 225 struct BinTestTy { 226 const BinaryOperator *Source; 227 EffectiveOp EOp; 228 VarTestResult LTest; 229 VarTestResult RTest; 230 }; 231 232 union { 233 ConsumedState State; 234 VarTestResult Test; 235 const VarDecl *Var; 236 BinTestTy BinTest; 237 }; 238 239 QualType TempType; 240 241 public: 242 PropagationInfo() : InfoType(IT_None) {} 243 244 PropagationInfo(const VarTestResult &Test) : InfoType(IT_Test), Test(Test) {} 245 PropagationInfo(const VarDecl *Var, ConsumedState TestsFor) 246 : InfoType(IT_Test) { 247 248 Test.Var = Var; 249 Test.TestsFor = TestsFor; 250 } 251 252 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 253 const VarTestResult <est, const VarTestResult &RTest) 254 : InfoType(IT_BinTest) { 255 256 BinTest.Source = Source; 257 BinTest.EOp = EOp; 258 BinTest.LTest = LTest; 259 BinTest.RTest = RTest; 260 } 261 262 PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp, 263 const VarDecl *LVar, ConsumedState LTestsFor, 264 const VarDecl *RVar, ConsumedState RTestsFor) 265 : InfoType(IT_BinTest) { 266 267 BinTest.Source = Source; 268 BinTest.EOp = EOp; 269 BinTest.LTest.Var = LVar; 270 BinTest.LTest.TestsFor = LTestsFor; 271 BinTest.RTest.Var = RVar; 272 BinTest.RTest.TestsFor = RTestsFor; 273 } 274 275 PropagationInfo(ConsumedState State, QualType TempType) 276 : InfoType(IT_State), State(State), TempType(TempType) {} 277 278 PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {} 279 280 const ConsumedState & getState() const { 281 assert(InfoType == IT_State); 282 return State; 283 } 284 285 const QualType & getTempType() const { 286 assert(InfoType == IT_State); 287 return TempType; 288 } 289 290 const VarTestResult & getTest() const { 291 assert(InfoType == IT_Test); 292 return Test; 293 } 294 295 const VarTestResult & getLTest() const { 296 assert(InfoType == IT_BinTest); 297 return BinTest.LTest; 298 } 299 300 const VarTestResult & getRTest() const { 301 assert(InfoType == IT_BinTest); 302 return BinTest.RTest; 303 } 304 305 const VarDecl * getVar() const { 306 assert(InfoType == IT_Var); 307 return Var; 308 } 309 310 EffectiveOp testEffectiveOp() const { 311 assert(InfoType == IT_BinTest); 312 return BinTest.EOp; 313 } 314 315 const BinaryOperator * testSourceNode() const { 316 assert(InfoType == IT_BinTest); 317 return BinTest.Source; 318 } 319 320 bool isValid() const { return InfoType != IT_None; } 321 bool isState() const { return InfoType == IT_State; } 322 bool isTest() const { return InfoType == IT_Test; } 323 bool isBinTest() const { return InfoType == IT_BinTest; } 324 bool isVar() const { return InfoType == IT_Var; } 325 326 PropagationInfo invertTest() const { 327 assert(InfoType == IT_Test || InfoType == IT_BinTest); 328 329 if (InfoType == IT_Test) { 330 return PropagationInfo(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 331 332 } else if (InfoType == IT_BinTest) { 333 return PropagationInfo(BinTest.Source, 334 BinTest.EOp == EO_And ? EO_Or : EO_And, 335 BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor), 336 BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor)); 337 } else { 338 return PropagationInfo(); 339 } 340 } 341 }; 342 343 class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> { 344 345 typedef llvm::DenseMap<const Stmt *, PropagationInfo> MapType; 346 typedef std::pair<const Stmt *, PropagationInfo> PairType; 347 typedef MapType::iterator InfoEntry; 348 typedef MapType::const_iterator ConstInfoEntry; 349 350 AnalysisDeclContext &AC; 351 ConsumedAnalyzer &Analyzer; 352 ConsumedStateMap *StateMap; 353 MapType PropagationMap; 354 void forwardInfo(const Stmt *From, const Stmt *To); 355 bool isLikeMoveAssignment(const CXXMethodDecl *MethodDecl); 356 void propagateReturnType(const Stmt *Call, const FunctionDecl *Fun, 357 QualType ReturnType); 358 359 public: 360 void checkCallability(const PropagationInfo &PInfo, 361 const FunctionDecl *FunDecl, 362 SourceLocation BlameLoc); 363 364 void Visit(const Stmt *StmtNode); 365 366 void VisitBinaryOperator(const BinaryOperator *BinOp); 367 void VisitCallExpr(const CallExpr *Call); 368 void VisitCastExpr(const CastExpr *Cast); 369 void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp); 370 void VisitCXXConstructExpr(const CXXConstructExpr *Call); 371 void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call); 372 void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call); 373 void VisitDeclRefExpr(const DeclRefExpr *DeclRef); 374 void VisitDeclStmt(const DeclStmt *DelcS); 375 void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp); 376 void VisitMemberExpr(const MemberExpr *MExpr); 377 void VisitParmVarDecl(const ParmVarDecl *Param); 378 void VisitReturnStmt(const ReturnStmt *Ret); 379 void VisitUnaryOperator(const UnaryOperator *UOp); 380 void VisitVarDecl(const VarDecl *Var); 381 382 ConsumedStmtVisitor(AnalysisDeclContext &AC, ConsumedAnalyzer &Analyzer, 383 ConsumedStateMap *StateMap) 384 : AC(AC), Analyzer(Analyzer), StateMap(StateMap) {} 385 386 PropagationInfo getInfo(const Stmt *StmtNode) const { 387 ConstInfoEntry Entry = PropagationMap.find(StmtNode); 388 389 if (Entry != PropagationMap.end()) 390 return Entry->second; 391 else 392 return PropagationInfo(); 393 } 394 395 void reset(ConsumedStateMap *NewStateMap) { 396 StateMap = NewStateMap; 397 } 398 }; 399 400 void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo, 401 const FunctionDecl *FunDecl, 402 SourceLocation BlameLoc) { 403 404 if (!FunDecl->hasAttr<CallableWhenAttr>()) 405 return; 406 407 const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>(); 408 409 if (PInfo.isVar()) { 410 const VarDecl *Var = PInfo.getVar(); 411 ConsumedState VarState = StateMap->getState(Var); 412 413 assert(VarState != CS_None && "Invalid state"); 414 415 if (isCallableInState(CWAttr, VarState)) 416 return; 417 418 Analyzer.WarningsHandler.warnUseInInvalidState( 419 FunDecl->getNameAsString(), Var->getNameAsString(), 420 stateToString(VarState), BlameLoc); 421 422 } else if (PInfo.isState()) { 423 424 assert(PInfo.getState() != CS_None && "Invalid state"); 425 426 if (isCallableInState(CWAttr, PInfo.getState())) 427 return; 428 429 Analyzer.WarningsHandler.warnUseOfTempInInvalidState( 430 FunDecl->getNameAsString(), stateToString(PInfo.getState()), BlameLoc); 431 } 432 } 433 434 void ConsumedStmtVisitor::forwardInfo(const Stmt *From, const Stmt *To) { 435 InfoEntry Entry = PropagationMap.find(From); 436 437 if (Entry != PropagationMap.end()) 438 PropagationMap.insert(PairType(To, Entry->second)); 439 } 440 441 bool ConsumedStmtVisitor::isLikeMoveAssignment( 442 const CXXMethodDecl *MethodDecl) { 443 444 return MethodDecl->isMoveAssignmentOperator() || 445 (MethodDecl->getOverloadedOperator() == OO_Equal && 446 MethodDecl->getNumParams() == 1 && 447 MethodDecl->getParamDecl(0)->getType()->isRValueReferenceType()); 448 } 449 450 void ConsumedStmtVisitor::propagateReturnType(const Stmt *Call, 451 const FunctionDecl *Fun, 452 QualType ReturnType) { 453 if (isConsumableType(ReturnType)) { 454 455 ConsumedState ReturnState; 456 457 if (Fun->hasAttr<ReturnTypestateAttr>()) 458 ReturnState = mapReturnTypestateAttrState( 459 Fun->getAttr<ReturnTypestateAttr>()); 460 else 461 ReturnState = mapConsumableAttrState(ReturnType); 462 463 PropagationMap.insert(PairType(Call, 464 PropagationInfo(ReturnState, ReturnType))); 465 } 466 } 467 468 void ConsumedStmtVisitor::Visit(const Stmt *StmtNode) { 469 470 ConstStmtVisitor<ConsumedStmtVisitor>::Visit(StmtNode); 471 472 for (Stmt::const_child_iterator CI = StmtNode->child_begin(), 473 CE = StmtNode->child_end(); CI != CE; ++CI) { 474 475 PropagationMap.erase(*CI); 476 } 477 } 478 479 void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) { 480 switch (BinOp->getOpcode()) { 481 case BO_LAnd: 482 case BO_LOr : { 483 InfoEntry LEntry = PropagationMap.find(BinOp->getLHS()), 484 REntry = PropagationMap.find(BinOp->getRHS()); 485 486 VarTestResult LTest, RTest; 487 488 if (LEntry != PropagationMap.end() && LEntry->second.isTest()) { 489 LTest = LEntry->second.getTest(); 490 491 } else { 492 LTest.Var = NULL; 493 LTest.TestsFor = CS_None; 494 } 495 496 if (REntry != PropagationMap.end() && REntry->second.isTest()) { 497 RTest = REntry->second.getTest(); 498 499 } else { 500 RTest.Var = NULL; 501 RTest.TestsFor = CS_None; 502 } 503 504 if (!(LTest.Var == NULL && RTest.Var == NULL)) 505 PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp, 506 static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest))); 507 508 break; 509 } 510 511 case BO_PtrMemD: 512 case BO_PtrMemI: 513 forwardInfo(BinOp->getLHS(), BinOp); 514 break; 515 516 default: 517 break; 518 } 519 } 520 521 void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) { 522 if (const FunctionDecl *FunDecl = 523 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee())) { 524 525 // Special case for the std::move function. 526 // TODO: Make this more specific. (Deferred) 527 if (FunDecl->getNameAsString() == "move") { 528 InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 529 530 if (Entry != PropagationMap.end()) { 531 PropagationMap.insert(PairType(Call, Entry->second)); 532 } 533 534 return; 535 } 536 537 unsigned Offset = Call->getNumArgs() - FunDecl->getNumParams(); 538 539 for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) { 540 QualType ParamType = FunDecl->getParamDecl(Index - Offset)->getType(); 541 542 InfoEntry Entry = PropagationMap.find(Call->getArg(Index)); 543 544 if (Entry == PropagationMap.end() || !Entry->second.isVar()) { 545 continue; 546 } 547 548 PropagationInfo PInfo = Entry->second; 549 550 if (ParamType->isRValueReferenceType() || 551 (ParamType->isLValueReferenceType() && 552 !cast<LValueReferenceType>(*ParamType).isSpelledAsLValue())) { 553 554 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); 555 556 } else if (!(ParamType.isConstQualified() || 557 ((ParamType->isReferenceType() || 558 ParamType->isPointerType()) && 559 ParamType->getPointeeType().isConstQualified()))) { 560 561 StateMap->setState(PInfo.getVar(), consumed::CS_Unknown); 562 } 563 } 564 565 QualType RetType = FunDecl->getCallResultType(); 566 if (RetType->isReferenceType()) 567 RetType = RetType->getPointeeType(); 568 569 propagateReturnType(Call, FunDecl, RetType); 570 } 571 } 572 573 void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) { 574 forwardInfo(Cast->getSubExpr(), Cast); 575 } 576 577 void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr( 578 const CXXBindTemporaryExpr *Temp) { 579 580 forwardInfo(Temp->getSubExpr(), Temp); 581 } 582 583 void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) { 584 CXXConstructorDecl *Constructor = Call->getConstructor(); 585 586 ASTContext &CurrContext = AC.getASTContext(); 587 QualType ThisType = Constructor->getThisType(CurrContext)->getPointeeType(); 588 589 if (isConsumableType(ThisType)) { 590 if (Constructor->isDefaultConstructor()) { 591 592 PropagationMap.insert(PairType(Call, 593 PropagationInfo(consumed::CS_Consumed, ThisType))); 594 595 } else if (Constructor->isMoveConstructor()) { 596 597 PropagationInfo PInfo = 598 PropagationMap.find(Call->getArg(0))->second; 599 600 if (PInfo.isVar()) { 601 const VarDecl* Var = PInfo.getVar(); 602 603 PropagationMap.insert(PairType(Call, 604 PropagationInfo(StateMap->getState(Var), ThisType))); 605 606 StateMap->setState(Var, consumed::CS_Consumed); 607 608 } else { 609 PropagationMap.insert(PairType(Call, PInfo)); 610 } 611 612 } else if (Constructor->isCopyConstructor()) { 613 MapType::iterator Entry = PropagationMap.find(Call->getArg(0)); 614 615 if (Entry != PropagationMap.end()) 616 PropagationMap.insert(PairType(Call, Entry->second)); 617 618 } else { 619 propagateReturnType(Call, Constructor, ThisType); 620 } 621 } 622 } 623 624 625 void ConsumedStmtVisitor::VisitCXXMemberCallExpr( 626 const CXXMemberCallExpr *Call) { 627 628 VisitCallExpr(Call); 629 630 InfoEntry Entry = PropagationMap.find(Call->getCallee()->IgnoreParens()); 631 632 if (Entry != PropagationMap.end()) { 633 PropagationInfo PInfo = Entry->second; 634 const CXXMethodDecl *MethodDecl = Call->getMethodDecl(); 635 636 checkCallability(PInfo, MethodDecl, Call->getExprLoc()); 637 638 if (PInfo.isVar()) { 639 if (isTestingFunction(MethodDecl)) 640 PropagationMap.insert(PairType(Call, 641 PropagationInfo(PInfo.getVar(), testsFor(MethodDecl)))); 642 else if (MethodDecl->hasAttr<ConsumesAttr>()) 643 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); 644 } 645 } 646 } 647 648 void ConsumedStmtVisitor::VisitCXXOperatorCallExpr( 649 const CXXOperatorCallExpr *Call) { 650 651 const FunctionDecl *FunDecl = 652 dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee()); 653 654 if (!FunDecl) return; 655 656 if (isa<CXXMethodDecl>(FunDecl) && 657 isLikeMoveAssignment(cast<CXXMethodDecl>(FunDecl))) { 658 659 InfoEntry LEntry = PropagationMap.find(Call->getArg(0)); 660 InfoEntry REntry = PropagationMap.find(Call->getArg(1)); 661 662 PropagationInfo LPInfo, RPInfo; 663 664 if (LEntry != PropagationMap.end() && 665 REntry != PropagationMap.end()) { 666 667 LPInfo = LEntry->second; 668 RPInfo = REntry->second; 669 670 if (LPInfo.isVar() && RPInfo.isVar()) { 671 StateMap->setState(LPInfo.getVar(), 672 StateMap->getState(RPInfo.getVar())); 673 674 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 675 676 PropagationMap.insert(PairType(Call, LPInfo)); 677 678 } else if (LPInfo.isVar() && !RPInfo.isVar()) { 679 StateMap->setState(LPInfo.getVar(), RPInfo.getState()); 680 681 PropagationMap.insert(PairType(Call, LPInfo)); 682 683 } else if (!LPInfo.isVar() && RPInfo.isVar()) { 684 PropagationMap.insert(PairType(Call, 685 PropagationInfo(StateMap->getState(RPInfo.getVar()), 686 LPInfo.getTempType()))); 687 688 StateMap->setState(RPInfo.getVar(), consumed::CS_Consumed); 689 690 } else { 691 PropagationMap.insert(PairType(Call, RPInfo)); 692 } 693 694 } else if (LEntry != PropagationMap.end() && 695 REntry == PropagationMap.end()) { 696 697 LPInfo = LEntry->second; 698 699 if (LPInfo.isVar()) { 700 StateMap->setState(LPInfo.getVar(), consumed::CS_Unknown); 701 702 PropagationMap.insert(PairType(Call, LPInfo)); 703 704 } else if (LPInfo.isState()) { 705 PropagationMap.insert(PairType(Call, 706 PropagationInfo(consumed::CS_Unknown, LPInfo.getTempType()))); 707 } 708 709 } else if (LEntry == PropagationMap.end() && 710 REntry != PropagationMap.end()) { 711 712 if (REntry->second.isVar()) 713 StateMap->setState(REntry->second.getVar(), consumed::CS_Consumed); 714 } 715 716 } else { 717 718 VisitCallExpr(Call); 719 720 InfoEntry Entry = PropagationMap.find(Call->getArg(0)); 721 722 if (Entry != PropagationMap.end()) { 723 PropagationInfo PInfo = Entry->second; 724 725 checkCallability(PInfo, FunDecl, Call->getExprLoc()); 726 727 if (PInfo.isVar()) { 728 if (isTestingFunction(FunDecl)) 729 PropagationMap.insert(PairType(Call, 730 PropagationInfo(PInfo.getVar(), testsFor(FunDecl)))); 731 else if (FunDecl->hasAttr<ConsumesAttr>()) 732 StateMap->setState(PInfo.getVar(), consumed::CS_Consumed); 733 } 734 } 735 } 736 } 737 738 void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) { 739 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl())) 740 if (StateMap->getState(Var) != consumed::CS_None) 741 PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var))); 742 } 743 744 void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) { 745 for (DeclStmt::const_decl_iterator DI = DeclS->decl_begin(), 746 DE = DeclS->decl_end(); DI != DE; ++DI) { 747 748 if (isa<VarDecl>(*DI)) VisitVarDecl(cast<VarDecl>(*DI)); 749 } 750 751 if (DeclS->isSingleDecl()) 752 if (const VarDecl *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl())) 753 PropagationMap.insert(PairType(DeclS, PropagationInfo(Var))); 754 } 755 756 void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr( 757 const MaterializeTemporaryExpr *Temp) { 758 759 InfoEntry Entry = PropagationMap.find(Temp->GetTemporaryExpr()); 760 761 if (Entry != PropagationMap.end()) 762 PropagationMap.insert(PairType(Temp, Entry->second)); 763 } 764 765 void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) { 766 forwardInfo(MExpr->getBase(), MExpr); 767 } 768 769 770 void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) { 771 QualType ParamType = Param->getType(); 772 ConsumedState ParamState = consumed::CS_None; 773 774 if (!(ParamType->isPointerType() || ParamType->isReferenceType()) && 775 isConsumableType(ParamType)) 776 ParamState = mapConsumableAttrState(ParamType); 777 else if (ParamType->isReferenceType() && 778 isConsumableType(ParamType->getPointeeType())) 779 ParamState = consumed::CS_Unknown; 780 781 if (ParamState) 782 StateMap->setState(Param, ParamState); 783 } 784 785 void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) { 786 if (ConsumedState ExpectedState = Analyzer.getExpectedReturnState()) { 787 InfoEntry Entry = PropagationMap.find(Ret->getRetValue()); 788 789 if (Entry != PropagationMap.end()) { 790 assert(Entry->second.isState() || Entry->second.isVar()); 791 792 ConsumedState RetState = Entry->second.isState() ? 793 Entry->second.getState() : StateMap->getState(Entry->second.getVar()); 794 795 if (RetState != ExpectedState) 796 Analyzer.WarningsHandler.warnReturnTypestateMismatch( 797 Ret->getReturnLoc(), stateToString(ExpectedState), 798 stateToString(RetState)); 799 } 800 } 801 } 802 803 void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) { 804 InfoEntry Entry = PropagationMap.find(UOp->getSubExpr()->IgnoreParens()); 805 if (Entry == PropagationMap.end()) return; 806 807 switch (UOp->getOpcode()) { 808 case UO_AddrOf: 809 PropagationMap.insert(PairType(UOp, Entry->second)); 810 break; 811 812 case UO_LNot: 813 if (Entry->second.isTest() || Entry->second.isBinTest()) 814 PropagationMap.insert(PairType(UOp, Entry->second.invertTest())); 815 break; 816 817 default: 818 break; 819 } 820 } 821 822 // TODO: See if I need to check for reference types here. 823 void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) { 824 if (isConsumableType(Var->getType())) { 825 if (Var->hasInit()) { 826 PropagationInfo PInfo = 827 PropagationMap.find(Var->getInit())->second; 828 829 StateMap->setState(Var, PInfo.isVar() ? 830 StateMap->getState(PInfo.getVar()) : PInfo.getState()); 831 832 } else { 833 StateMap->setState(Var, consumed::CS_Unknown); 834 } 835 } 836 } 837 }} // end clang::consumed::ConsumedStmtVisitor 838 839 namespace clang { 840 namespace consumed { 841 842 void splitVarStateForIf(const IfStmt * IfNode, const VarTestResult &Test, 843 ConsumedStateMap *ThenStates, 844 ConsumedStateMap *ElseStates) { 845 846 ConsumedState VarState = ThenStates->getState(Test.Var); 847 848 if (VarState == CS_Unknown) { 849 ThenStates->setState(Test.Var, Test.TestsFor); 850 ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor)); 851 852 } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) { 853 ThenStates->markUnreachable(); 854 855 } else if (VarState == Test.TestsFor) { 856 ElseStates->markUnreachable(); 857 } 858 } 859 860 void splitVarStateForIfBinOp(const PropagationInfo &PInfo, 861 ConsumedStateMap *ThenStates, ConsumedStateMap *ElseStates) { 862 863 const VarTestResult <est = PInfo.getLTest(), 864 &RTest = PInfo.getRTest(); 865 866 ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None, 867 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None; 868 869 if (LTest.Var) { 870 if (PInfo.testEffectiveOp() == EO_And) { 871 if (LState == CS_Unknown) { 872 ThenStates->setState(LTest.Var, LTest.TestsFor); 873 874 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) { 875 ThenStates->markUnreachable(); 876 877 } else if (LState == LTest.TestsFor && isKnownState(RState)) { 878 if (RState == RTest.TestsFor) 879 ElseStates->markUnreachable(); 880 else 881 ThenStates->markUnreachable(); 882 } 883 884 } else { 885 if (LState == CS_Unknown) { 886 ElseStates->setState(LTest.Var, 887 invertConsumedUnconsumed(LTest.TestsFor)); 888 889 } else if (LState == LTest.TestsFor) { 890 ElseStates->markUnreachable(); 891 892 } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) && 893 isKnownState(RState)) { 894 895 if (RState == RTest.TestsFor) 896 ElseStates->markUnreachable(); 897 else 898 ThenStates->markUnreachable(); 899 } 900 } 901 } 902 903 if (RTest.Var) { 904 if (PInfo.testEffectiveOp() == EO_And) { 905 if (RState == CS_Unknown) 906 ThenStates->setState(RTest.Var, RTest.TestsFor); 907 else if (RState == invertConsumedUnconsumed(RTest.TestsFor)) 908 ThenStates->markUnreachable(); 909 910 } else { 911 if (RState == CS_Unknown) 912 ElseStates->setState(RTest.Var, 913 invertConsumedUnconsumed(RTest.TestsFor)); 914 else if (RState == RTest.TestsFor) 915 ElseStates->markUnreachable(); 916 } 917 } 918 } 919 920 bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock, 921 const CFGBlock *TargetBlock) { 922 923 assert(CurrBlock && "Block pointer must not be NULL"); 924 assert(TargetBlock && "TargetBlock pointer must not be NULL"); 925 926 unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()]; 927 for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(), 928 PE = TargetBlock->pred_end(); PI != PE; ++PI) { 929 if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] ) 930 return false; 931 } 932 return true; 933 } 934 935 void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 936 ConsumedStateMap *StateMap, 937 bool &AlreadyOwned) { 938 939 assert(Block && "Block pointer must not be NULL"); 940 941 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 942 943 if (Entry) { 944 Entry->intersect(StateMap); 945 946 } else if (AlreadyOwned) { 947 StateMapsArray[Block->getBlockID()] = new ConsumedStateMap(*StateMap); 948 949 } else { 950 StateMapsArray[Block->getBlockID()] = StateMap; 951 AlreadyOwned = true; 952 } 953 } 954 955 void ConsumedBlockInfo::addInfo(const CFGBlock *Block, 956 ConsumedStateMap *StateMap) { 957 958 assert(Block != NULL && "Block pointer must not be NULL"); 959 960 ConsumedStateMap *Entry = StateMapsArray[Block->getBlockID()]; 961 962 if (Entry) { 963 Entry->intersect(StateMap); 964 delete StateMap; 965 966 } else { 967 StateMapsArray[Block->getBlockID()] = StateMap; 968 } 969 } 970 971 ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) { 972 assert(Block && "Block pointer must not be NULL"); 973 assert(StateMapsArray[Block->getBlockID()] && "Block has no block info"); 974 975 return StateMapsArray[Block->getBlockID()]; 976 } 977 978 void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) { 979 unsigned int BlockID = Block->getBlockID(); 980 delete StateMapsArray[BlockID]; 981 StateMapsArray[BlockID] = NULL; 982 } 983 984 ConsumedStateMap* ConsumedBlockInfo::getInfo(const CFGBlock *Block) { 985 assert(Block && "Block pointer must not be NULL"); 986 987 ConsumedStateMap *StateMap = StateMapsArray[Block->getBlockID()]; 988 if (isBackEdgeTarget(Block)) { 989 return new ConsumedStateMap(*StateMap); 990 } else { 991 StateMapsArray[Block->getBlockID()] = NULL; 992 return StateMap; 993 } 994 } 995 996 bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) { 997 assert(From && "From block must not be NULL"); 998 assert(To && "From block must not be NULL"); 999 1000 return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()]; 1001 } 1002 1003 bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) { 1004 assert(Block != NULL && "Block pointer must not be NULL"); 1005 1006 // Anything with less than two predecessors can't be the target of a back 1007 // edge. 1008 if (Block->pred_size() < 2) 1009 return false; 1010 1011 unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()]; 1012 for (CFGBlock::const_pred_iterator PI = Block->pred_begin(), 1013 PE = Block->pred_end(); PI != PE; ++PI) { 1014 if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()]) 1015 return true; 1016 } 1017 return false; 1018 } 1019 1020 ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const { 1021 MapType::const_iterator Entry = Map.find(Var); 1022 1023 if (Entry != Map.end()) { 1024 return Entry->second; 1025 1026 } else { 1027 return CS_None; 1028 } 1029 } 1030 1031 void ConsumedStateMap::intersect(const ConsumedStateMap *Other) { 1032 ConsumedState LocalState; 1033 1034 if (this->From && this->From == Other->From && !Other->Reachable) { 1035 this->markUnreachable(); 1036 return; 1037 } 1038 1039 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1040 DMI != DME; ++DMI) { 1041 1042 LocalState = this->getState(DMI->first); 1043 1044 if (LocalState == CS_None) 1045 continue; 1046 1047 if (LocalState != DMI->second) 1048 Map[DMI->first] = CS_Unknown; 1049 } 1050 } 1051 1052 void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead, 1053 const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates, 1054 ConsumedWarningsHandlerBase &WarningsHandler) { 1055 1056 ConsumedState LocalState; 1057 SourceLocation BlameLoc = getLastStmtLoc(LoopBack); 1058 1059 for (MapType::const_iterator DMI = LoopBackStates->Map.begin(), 1060 DME = LoopBackStates->Map.end(); DMI != DME; ++DMI) { 1061 1062 LocalState = this->getState(DMI->first); 1063 1064 if (LocalState == CS_None) 1065 continue; 1066 1067 if (LocalState != DMI->second) { 1068 Map[DMI->first] = CS_Unknown; 1069 WarningsHandler.warnLoopStateMismatch( 1070 BlameLoc, DMI->first->getNameAsString()); 1071 } 1072 } 1073 } 1074 1075 void ConsumedStateMap::markUnreachable() { 1076 this->Reachable = false; 1077 Map.clear(); 1078 } 1079 1080 void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) { 1081 Map[Var] = State; 1082 } 1083 1084 void ConsumedStateMap::remove(const VarDecl *Var) { 1085 Map.erase(Var); 1086 } 1087 1088 bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const { 1089 for (MapType::const_iterator DMI = Other->Map.begin(), DME = Other->Map.end(); 1090 DMI != DME; ++DMI) { 1091 1092 if (this->getState(DMI->first) != DMI->second) 1093 return true; 1094 } 1095 1096 return false; 1097 } 1098 1099 void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC, 1100 const FunctionDecl *D) { 1101 QualType ReturnType; 1102 if (const CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(D)) { 1103 ASTContext &CurrContext = AC.getASTContext(); 1104 ReturnType = Constructor->getThisType(CurrContext)->getPointeeType(); 1105 } else 1106 ReturnType = D->getCallResultType(); 1107 1108 if (D->hasAttr<ReturnTypestateAttr>()) { 1109 const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>(); 1110 1111 const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl(); 1112 if (!RD || !RD->hasAttr<ConsumableAttr>()) { 1113 // FIXME: This should be removed when template instantiation propagates 1114 // attributes at template specialization definition, not 1115 // declaration. When it is removed the test needs to be enabled 1116 // in SemaDeclAttr.cpp. 1117 WarningsHandler.warnReturnTypestateForUnconsumableType( 1118 RTSAttr->getLocation(), ReturnType.getAsString()); 1119 ExpectedReturnState = CS_None; 1120 } else 1121 ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr); 1122 } else if (isConsumableType(ReturnType)) 1123 ExpectedReturnState = mapConsumableAttrState(ReturnType); 1124 else 1125 ExpectedReturnState = CS_None; 1126 } 1127 1128 bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock, 1129 const ConsumedStmtVisitor &Visitor) { 1130 1131 ConsumedStateMap *FalseStates = new ConsumedStateMap(*CurrStates); 1132 PropagationInfo PInfo; 1133 1134 if (const IfStmt *IfNode = 1135 dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) { 1136 1137 const Stmt *Cond = IfNode->getCond(); 1138 1139 PInfo = Visitor.getInfo(Cond); 1140 if (!PInfo.isValid() && isa<BinaryOperator>(Cond)) 1141 PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS()); 1142 1143 if (PInfo.isTest()) { 1144 CurrStates->setSource(Cond); 1145 FalseStates->setSource(Cond); 1146 splitVarStateForIf(IfNode, PInfo.getTest(), CurrStates, FalseStates); 1147 1148 } else if (PInfo.isBinTest()) { 1149 CurrStates->setSource(PInfo.testSourceNode()); 1150 FalseStates->setSource(PInfo.testSourceNode()); 1151 splitVarStateForIfBinOp(PInfo, CurrStates, FalseStates); 1152 1153 } else { 1154 delete FalseStates; 1155 return false; 1156 } 1157 1158 } else if (const BinaryOperator *BinOp = 1159 dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) { 1160 1161 PInfo = Visitor.getInfo(BinOp->getLHS()); 1162 if (!PInfo.isTest()) { 1163 if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) { 1164 PInfo = Visitor.getInfo(BinOp->getRHS()); 1165 1166 if (!PInfo.isTest()) { 1167 delete FalseStates; 1168 return false; 1169 } 1170 1171 } else { 1172 delete FalseStates; 1173 return false; 1174 } 1175 } 1176 1177 CurrStates->setSource(BinOp); 1178 FalseStates->setSource(BinOp); 1179 1180 const VarTestResult &Test = PInfo.getTest(); 1181 ConsumedState VarState = CurrStates->getState(Test.Var); 1182 1183 if (BinOp->getOpcode() == BO_LAnd) { 1184 if (VarState == CS_Unknown) 1185 CurrStates->setState(Test.Var, Test.TestsFor); 1186 else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) 1187 CurrStates->markUnreachable(); 1188 1189 } else if (BinOp->getOpcode() == BO_LOr) { 1190 if (VarState == CS_Unknown) 1191 FalseStates->setState(Test.Var, 1192 invertConsumedUnconsumed(Test.TestsFor)); 1193 else if (VarState == Test.TestsFor) 1194 FalseStates->markUnreachable(); 1195 } 1196 1197 } else { 1198 delete FalseStates; 1199 return false; 1200 } 1201 1202 CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(); 1203 1204 if (*SI) 1205 BlockInfo.addInfo(*SI, CurrStates); 1206 else 1207 delete CurrStates; 1208 1209 if (*++SI) 1210 BlockInfo.addInfo(*SI, FalseStates); 1211 else 1212 delete FalseStates; 1213 1214 CurrStates = NULL; 1215 return true; 1216 } 1217 1218 void ConsumedAnalyzer::run(AnalysisDeclContext &AC) { 1219 const FunctionDecl *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl()); 1220 if (!D) 1221 return; 1222 1223 CFG *CFGraph = AC.getCFG(); 1224 if (!CFGraph) 1225 return; 1226 1227 determineExpectedReturnState(AC, D); 1228 1229 PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>(); 1230 // AC.getCFG()->viewCFG(LangOptions()); 1231 1232 BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph); 1233 1234 CurrStates = new ConsumedStateMap(); 1235 ConsumedStmtVisitor Visitor(AC, *this, CurrStates); 1236 1237 // Add all trackable parameters to the state map. 1238 for (FunctionDecl::param_const_iterator PI = D->param_begin(), 1239 PE = D->param_end(); PI != PE; ++PI) { 1240 Visitor.VisitParmVarDecl(*PI); 1241 } 1242 1243 // Visit all of the function's basic blocks. 1244 for (PostOrderCFGView::iterator I = SortedGraph->begin(), 1245 E = SortedGraph->end(); I != E; ++I) { 1246 1247 const CFGBlock *CurrBlock = *I; 1248 1249 if (CurrStates == NULL) 1250 CurrStates = BlockInfo.getInfo(CurrBlock); 1251 1252 if (!CurrStates) { 1253 continue; 1254 1255 } else if (!CurrStates->isReachable()) { 1256 delete CurrStates; 1257 CurrStates = NULL; 1258 continue; 1259 } 1260 1261 Visitor.reset(CurrStates); 1262 1263 // Visit all of the basic block's statements. 1264 for (CFGBlock::const_iterator BI = CurrBlock->begin(), 1265 BE = CurrBlock->end(); BI != BE; ++BI) { 1266 1267 switch (BI->getKind()) { 1268 case CFGElement::Statement: 1269 Visitor.Visit(BI->castAs<CFGStmt>().getStmt()); 1270 break; 1271 1272 case CFGElement::TemporaryDtor: { 1273 const CFGTemporaryDtor DTor = BI->castAs<CFGTemporaryDtor>(); 1274 const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr(); 1275 PropagationInfo PInfo = Visitor.getInfo(BTE); 1276 1277 if (PInfo.isValid()) 1278 Visitor.checkCallability(PInfo, 1279 DTor.getDestructorDecl(AC.getASTContext()), 1280 BTE->getExprLoc()); 1281 break; 1282 } 1283 1284 case CFGElement::AutomaticObjectDtor: { 1285 const CFGAutomaticObjDtor DTor = BI->castAs<CFGAutomaticObjDtor>(); 1286 1287 const VarDecl *Var = DTor.getVarDecl(); 1288 ConsumedState VarState = CurrStates->getState(Var); 1289 1290 if (VarState != CS_None) { 1291 PropagationInfo PInfo(Var); 1292 1293 Visitor.checkCallability(PInfo, 1294 DTor.getDestructorDecl(AC.getASTContext()), 1295 getLastStmtLoc(CurrBlock)); 1296 1297 CurrStates->remove(Var); 1298 } 1299 break; 1300 } 1301 1302 default: 1303 break; 1304 } 1305 } 1306 1307 // TODO: Handle other forms of branching with precision, including while- 1308 // and for-loops. (Deferred) 1309 if (!splitState(CurrBlock, Visitor)) { 1310 CurrStates->setSource(NULL); 1311 1312 if (CurrBlock->succ_size() > 1 || 1313 (CurrBlock->succ_size() == 1 && 1314 (*CurrBlock->succ_begin())->pred_size() > 1)) { 1315 1316 bool OwnershipTaken = false; 1317 1318 for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(), 1319 SE = CurrBlock->succ_end(); SI != SE; ++SI) { 1320 1321 if (*SI == NULL) continue; 1322 1323 if (BlockInfo.isBackEdge(CurrBlock, *SI)) { 1324 BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(*SI, CurrBlock, 1325 CurrStates, 1326 WarningsHandler); 1327 1328 if (BlockInfo.allBackEdgesVisited(*SI, CurrBlock)) 1329 BlockInfo.discardInfo(*SI); 1330 } else { 1331 BlockInfo.addInfo(*SI, CurrStates, OwnershipTaken); 1332 } 1333 } 1334 1335 if (!OwnershipTaken) 1336 delete CurrStates; 1337 1338 CurrStates = NULL; 1339 } 1340 } 1341 } // End of block iterator. 1342 1343 // Delete the last existing state map. 1344 delete CurrStates; 1345 1346 WarningsHandler.emitDiagnostics(); 1347 } 1348 }} // end namespace clang::consumed 1349