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