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