xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/Consumed.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //===- Consumed.cpp -------------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // A intra-procedural analysis for checking consumed properties.  This is based,
100b57cec5SDimitry Andric // in part, on research on linear types.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "clang/Analysis/Analyses/Consumed.h"
150b57cec5SDimitry Andric #include "clang/AST/Attr.h"
160b57cec5SDimitry Andric #include "clang/AST/Decl.h"
170b57cec5SDimitry Andric #include "clang/AST/DeclCXX.h"
180b57cec5SDimitry Andric #include "clang/AST/Expr.h"
190b57cec5SDimitry Andric #include "clang/AST/ExprCXX.h"
200b57cec5SDimitry Andric #include "clang/AST/Stmt.h"
210b57cec5SDimitry Andric #include "clang/AST/StmtVisitor.h"
220b57cec5SDimitry Andric #include "clang/AST/Type.h"
230b57cec5SDimitry Andric #include "clang/Analysis/Analyses/PostOrderCFGView.h"
240b57cec5SDimitry Andric #include "clang/Analysis/AnalysisDeclContext.h"
250b57cec5SDimitry Andric #include "clang/Analysis/CFG.h"
260b57cec5SDimitry Andric #include "clang/Basic/LLVM.h"
270b57cec5SDimitry Andric #include "clang/Basic/OperatorKinds.h"
280b57cec5SDimitry Andric #include "clang/Basic/SourceLocation.h"
290b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
300b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
310b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
320b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
330b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
340b57cec5SDimitry Andric #include <cassert>
350b57cec5SDimitry Andric #include <memory>
36bdd1243dSDimitry Andric #include <optional>
370b57cec5SDimitry Andric #include <utility>
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric // TODO: Adjust states of args to constructors in the same way that arguments to
400b57cec5SDimitry Andric //       function calls are handled.
410b57cec5SDimitry Andric // TODO: Use information from tests in for- and while-loop conditional.
420b57cec5SDimitry Andric // TODO: Add notes about the actual and expected state for
430b57cec5SDimitry Andric // TODO: Correctly identify unreachable blocks when chaining boolean operators.
440b57cec5SDimitry Andric // TODO: Adjust the parser and AttributesList class to support lists of
450b57cec5SDimitry Andric //       identifiers.
460b57cec5SDimitry Andric // TODO: Warn about unreachable code.
470b57cec5SDimitry Andric // TODO: Switch to using a bitmap to track unreachable blocks.
480b57cec5SDimitry Andric // TODO: Handle variable definitions, e.g. bool valid = x.isValid();
490b57cec5SDimitry Andric //       if (valid) ...; (Deferred)
500b57cec5SDimitry Andric // TODO: Take notes on state transitions to provide better warning messages.
510b57cec5SDimitry Andric //       (Deferred)
520b57cec5SDimitry Andric // TODO: Test nested conditionals: A) Checking the same value multiple times,
530b57cec5SDimitry Andric //       and 2) Checking different values. (Deferred)
540b57cec5SDimitry Andric 
550b57cec5SDimitry Andric using namespace clang;
560b57cec5SDimitry Andric using namespace consumed;
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric // Key method definition
590b57cec5SDimitry Andric ConsumedWarningsHandlerBase::~ConsumedWarningsHandlerBase() = default;
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric static SourceLocation getFirstStmtLoc(const CFGBlock *Block) {
620b57cec5SDimitry Andric   // Find the source location of the first statement in the block, if the block
630b57cec5SDimitry Andric   // is not empty.
640b57cec5SDimitry Andric   for (const auto &B : *Block)
65bdd1243dSDimitry Andric     if (std::optional<CFGStmt> CS = B.getAs<CFGStmt>())
660b57cec5SDimitry Andric       return CS->getStmt()->getBeginLoc();
670b57cec5SDimitry Andric 
680b57cec5SDimitry Andric   // Block is empty.
690b57cec5SDimitry Andric   // If we have one successor, return the first statement in that block
700b57cec5SDimitry Andric   if (Block->succ_size() == 1 && *Block->succ_begin())
710b57cec5SDimitry Andric     return getFirstStmtLoc(*Block->succ_begin());
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   return {};
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric static SourceLocation getLastStmtLoc(const CFGBlock *Block) {
770b57cec5SDimitry Andric   // Find the source location of the last statement in the block, if the block
780b57cec5SDimitry Andric   // is not empty.
790b57cec5SDimitry Andric   if (const Stmt *StmtNode = Block->getTerminatorStmt()) {
800b57cec5SDimitry Andric     return StmtNode->getBeginLoc();
810b57cec5SDimitry Andric   } else {
820b57cec5SDimitry Andric     for (CFGBlock::const_reverse_iterator BI = Block->rbegin(),
830b57cec5SDimitry Andric          BE = Block->rend(); BI != BE; ++BI) {
84bdd1243dSDimitry Andric       if (std::optional<CFGStmt> CS = BI->getAs<CFGStmt>())
850b57cec5SDimitry Andric         return CS->getStmt()->getBeginLoc();
860b57cec5SDimitry Andric     }
870b57cec5SDimitry Andric   }
880b57cec5SDimitry Andric 
890b57cec5SDimitry Andric   // If we have one successor, return the first statement in that block
900b57cec5SDimitry Andric   SourceLocation Loc;
910b57cec5SDimitry Andric   if (Block->succ_size() == 1 && *Block->succ_begin())
920b57cec5SDimitry Andric     Loc = getFirstStmtLoc(*Block->succ_begin());
930b57cec5SDimitry Andric   if (Loc.isValid())
940b57cec5SDimitry Andric     return Loc;
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric   // If we have one predecessor, return the last statement in that block
970b57cec5SDimitry Andric   if (Block->pred_size() == 1 && *Block->pred_begin())
980b57cec5SDimitry Andric     return getLastStmtLoc(*Block->pred_begin());
990b57cec5SDimitry Andric 
1000b57cec5SDimitry Andric   return Loc;
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric 
1030b57cec5SDimitry Andric static ConsumedState invertConsumedUnconsumed(ConsumedState State) {
1040b57cec5SDimitry Andric   switch (State) {
1050b57cec5SDimitry Andric   case CS_Unconsumed:
1060b57cec5SDimitry Andric     return CS_Consumed;
1070b57cec5SDimitry Andric   case CS_Consumed:
1080b57cec5SDimitry Andric     return CS_Unconsumed;
1090b57cec5SDimitry Andric   case CS_None:
1100b57cec5SDimitry Andric     return CS_None;
1110b57cec5SDimitry Andric   case CS_Unknown:
1120b57cec5SDimitry Andric     return CS_Unknown;
1130b57cec5SDimitry Andric   }
1140b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric static bool isCallableInState(const CallableWhenAttr *CWAttr,
1180b57cec5SDimitry Andric                               ConsumedState State) {
1190b57cec5SDimitry Andric   for (const auto &S : CWAttr->callableStates()) {
1200b57cec5SDimitry Andric     ConsumedState MappedAttrState = CS_None;
1210b57cec5SDimitry Andric 
1220b57cec5SDimitry Andric     switch (S) {
1230b57cec5SDimitry Andric     case CallableWhenAttr::Unknown:
1240b57cec5SDimitry Andric       MappedAttrState = CS_Unknown;
1250b57cec5SDimitry Andric       break;
1260b57cec5SDimitry Andric 
1270b57cec5SDimitry Andric     case CallableWhenAttr::Unconsumed:
1280b57cec5SDimitry Andric       MappedAttrState = CS_Unconsumed;
1290b57cec5SDimitry Andric       break;
1300b57cec5SDimitry Andric 
1310b57cec5SDimitry Andric     case CallableWhenAttr::Consumed:
1320b57cec5SDimitry Andric       MappedAttrState = CS_Consumed;
1330b57cec5SDimitry Andric       break;
1340b57cec5SDimitry Andric     }
1350b57cec5SDimitry Andric 
1360b57cec5SDimitry Andric     if (MappedAttrState == State)
1370b57cec5SDimitry Andric       return true;
1380b57cec5SDimitry Andric   }
1390b57cec5SDimitry Andric 
1400b57cec5SDimitry Andric   return false;
1410b57cec5SDimitry Andric }
1420b57cec5SDimitry Andric 
1430b57cec5SDimitry Andric static bool isConsumableType(const QualType &QT) {
1440b57cec5SDimitry Andric   if (QT->isPointerType() || QT->isReferenceType())
1450b57cec5SDimitry Andric     return false;
1460b57cec5SDimitry Andric 
1470b57cec5SDimitry Andric   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
1480b57cec5SDimitry Andric     return RD->hasAttr<ConsumableAttr>();
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   return false;
1510b57cec5SDimitry Andric }
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric static bool isAutoCastType(const QualType &QT) {
1540b57cec5SDimitry Andric   if (QT->isPointerType() || QT->isReferenceType())
1550b57cec5SDimitry Andric     return false;
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   if (const CXXRecordDecl *RD = QT->getAsCXXRecordDecl())
1580b57cec5SDimitry Andric     return RD->hasAttr<ConsumableAutoCastAttr>();
1590b57cec5SDimitry Andric 
1600b57cec5SDimitry Andric   return false;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric static bool isSetOnReadPtrType(const QualType &QT) {
1640b57cec5SDimitry Andric   if (const CXXRecordDecl *RD = QT->getPointeeCXXRecordDecl())
1650b57cec5SDimitry Andric     return RD->hasAttr<ConsumableSetOnReadAttr>();
1660b57cec5SDimitry Andric   return false;
1670b57cec5SDimitry Andric }
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric static bool isKnownState(ConsumedState State) {
1700b57cec5SDimitry Andric   switch (State) {
1710b57cec5SDimitry Andric   case CS_Unconsumed:
1720b57cec5SDimitry Andric   case CS_Consumed:
1730b57cec5SDimitry Andric     return true;
1740b57cec5SDimitry Andric   case CS_None:
1750b57cec5SDimitry Andric   case CS_Unknown:
1760b57cec5SDimitry Andric     return false;
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
1790b57cec5SDimitry Andric }
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric static bool isRValueRef(QualType ParamType) {
1820b57cec5SDimitry Andric   return ParamType->isRValueReferenceType();
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric static bool isTestingFunction(const FunctionDecl *FunDecl) {
1860b57cec5SDimitry Andric   return FunDecl->hasAttr<TestTypestateAttr>();
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric static bool isPointerOrRef(QualType ParamType) {
1900b57cec5SDimitry Andric   return ParamType->isPointerType() || ParamType->isReferenceType();
1910b57cec5SDimitry Andric }
1920b57cec5SDimitry Andric 
1930b57cec5SDimitry Andric static ConsumedState mapConsumableAttrState(const QualType QT) {
1940b57cec5SDimitry Andric   assert(isConsumableType(QT));
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   const ConsumableAttr *CAttr =
1970b57cec5SDimitry Andric       QT->getAsCXXRecordDecl()->getAttr<ConsumableAttr>();
1980b57cec5SDimitry Andric 
1990b57cec5SDimitry Andric   switch (CAttr->getDefaultState()) {
2000b57cec5SDimitry Andric   case ConsumableAttr::Unknown:
2010b57cec5SDimitry Andric     return CS_Unknown;
2020b57cec5SDimitry Andric   case ConsumableAttr::Unconsumed:
2030b57cec5SDimitry Andric     return CS_Unconsumed;
2040b57cec5SDimitry Andric   case ConsumableAttr::Consumed:
2050b57cec5SDimitry Andric     return CS_Consumed;
2060b57cec5SDimitry Andric   }
2070b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric static ConsumedState
2110b57cec5SDimitry Andric mapParamTypestateAttrState(const ParamTypestateAttr *PTAttr) {
2120b57cec5SDimitry Andric   switch (PTAttr->getParamState()) {
2130b57cec5SDimitry Andric   case ParamTypestateAttr::Unknown:
2140b57cec5SDimitry Andric     return CS_Unknown;
2150b57cec5SDimitry Andric   case ParamTypestateAttr::Unconsumed:
2160b57cec5SDimitry Andric     return CS_Unconsumed;
2170b57cec5SDimitry Andric   case ParamTypestateAttr::Consumed:
2180b57cec5SDimitry Andric     return CS_Consumed;
2190b57cec5SDimitry Andric   }
2200b57cec5SDimitry Andric   llvm_unreachable("invalid_enum");
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
2230b57cec5SDimitry Andric static ConsumedState
2240b57cec5SDimitry Andric mapReturnTypestateAttrState(const ReturnTypestateAttr *RTSAttr) {
2250b57cec5SDimitry Andric   switch (RTSAttr->getState()) {
2260b57cec5SDimitry Andric   case ReturnTypestateAttr::Unknown:
2270b57cec5SDimitry Andric     return CS_Unknown;
2280b57cec5SDimitry Andric   case ReturnTypestateAttr::Unconsumed:
2290b57cec5SDimitry Andric     return CS_Unconsumed;
2300b57cec5SDimitry Andric   case ReturnTypestateAttr::Consumed:
2310b57cec5SDimitry Andric     return CS_Consumed;
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
2340b57cec5SDimitry Andric }
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric static ConsumedState mapSetTypestateAttrState(const SetTypestateAttr *STAttr) {
2370b57cec5SDimitry Andric   switch (STAttr->getNewState()) {
2380b57cec5SDimitry Andric   case SetTypestateAttr::Unknown:
2390b57cec5SDimitry Andric     return CS_Unknown;
2400b57cec5SDimitry Andric   case SetTypestateAttr::Unconsumed:
2410b57cec5SDimitry Andric     return CS_Unconsumed;
2420b57cec5SDimitry Andric   case SetTypestateAttr::Consumed:
2430b57cec5SDimitry Andric     return CS_Consumed;
2440b57cec5SDimitry Andric   }
2450b57cec5SDimitry Andric   llvm_unreachable("invalid_enum");
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
2480b57cec5SDimitry Andric static StringRef stateToString(ConsumedState State) {
2490b57cec5SDimitry Andric   switch (State) {
2500b57cec5SDimitry Andric   case consumed::CS_None:
2510b57cec5SDimitry Andric     return "none";
2520b57cec5SDimitry Andric 
2530b57cec5SDimitry Andric   case consumed::CS_Unknown:
2540b57cec5SDimitry Andric     return "unknown";
2550b57cec5SDimitry Andric 
2560b57cec5SDimitry Andric   case consumed::CS_Unconsumed:
2570b57cec5SDimitry Andric     return "unconsumed";
2580b57cec5SDimitry Andric 
2590b57cec5SDimitry Andric   case consumed::CS_Consumed:
2600b57cec5SDimitry Andric     return "consumed";
2610b57cec5SDimitry Andric   }
2620b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric 
2650b57cec5SDimitry Andric static ConsumedState testsFor(const FunctionDecl *FunDecl) {
2660b57cec5SDimitry Andric   assert(isTestingFunction(FunDecl));
2670b57cec5SDimitry Andric   switch (FunDecl->getAttr<TestTypestateAttr>()->getTestState()) {
2680b57cec5SDimitry Andric   case TestTypestateAttr::Unconsumed:
2690b57cec5SDimitry Andric     return CS_Unconsumed;
2700b57cec5SDimitry Andric   case TestTypestateAttr::Consumed:
2710b57cec5SDimitry Andric     return CS_Consumed;
2720b57cec5SDimitry Andric   }
2730b57cec5SDimitry Andric   llvm_unreachable("invalid enum");
2740b57cec5SDimitry Andric }
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric namespace {
2770b57cec5SDimitry Andric 
2780b57cec5SDimitry Andric struct VarTestResult {
2790b57cec5SDimitry Andric   const VarDecl *Var;
2800b57cec5SDimitry Andric   ConsumedState TestsFor;
2810b57cec5SDimitry Andric };
2820b57cec5SDimitry Andric 
2830b57cec5SDimitry Andric } // namespace
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric namespace clang {
2860b57cec5SDimitry Andric namespace consumed {
2870b57cec5SDimitry Andric 
2880b57cec5SDimitry Andric enum EffectiveOp {
2890b57cec5SDimitry Andric   EO_And,
2900b57cec5SDimitry Andric   EO_Or
2910b57cec5SDimitry Andric };
2920b57cec5SDimitry Andric 
2930b57cec5SDimitry Andric class PropagationInfo {
2940b57cec5SDimitry Andric   enum {
2950b57cec5SDimitry Andric     IT_None,
2960b57cec5SDimitry Andric     IT_State,
2970b57cec5SDimitry Andric     IT_VarTest,
2980b57cec5SDimitry Andric     IT_BinTest,
2990b57cec5SDimitry Andric     IT_Var,
3000b57cec5SDimitry Andric     IT_Tmp
3010b57cec5SDimitry Andric   } InfoType = IT_None;
3020b57cec5SDimitry Andric 
3030b57cec5SDimitry Andric   struct BinTestTy {
3040b57cec5SDimitry Andric     const BinaryOperator *Source;
3050b57cec5SDimitry Andric     EffectiveOp EOp;
3060b57cec5SDimitry Andric     VarTestResult LTest;
3070b57cec5SDimitry Andric     VarTestResult RTest;
3080b57cec5SDimitry Andric   };
3090b57cec5SDimitry Andric 
3100b57cec5SDimitry Andric   union {
3110b57cec5SDimitry Andric     ConsumedState State;
3120b57cec5SDimitry Andric     VarTestResult VarTest;
3130b57cec5SDimitry Andric     const VarDecl *Var;
3140b57cec5SDimitry Andric     const CXXBindTemporaryExpr *Tmp;
3150b57cec5SDimitry Andric     BinTestTy BinTest;
3160b57cec5SDimitry Andric   };
3170b57cec5SDimitry Andric 
3180b57cec5SDimitry Andric public:
3190b57cec5SDimitry Andric   PropagationInfo() = default;
3200b57cec5SDimitry Andric   PropagationInfo(const VarTestResult &VarTest)
3210b57cec5SDimitry Andric       : InfoType(IT_VarTest), VarTest(VarTest) {}
3220b57cec5SDimitry Andric 
3230b57cec5SDimitry Andric   PropagationInfo(const VarDecl *Var, ConsumedState TestsFor)
3240b57cec5SDimitry Andric       : InfoType(IT_VarTest) {
3250b57cec5SDimitry Andric     VarTest.Var      = Var;
3260b57cec5SDimitry Andric     VarTest.TestsFor = TestsFor;
3270b57cec5SDimitry Andric   }
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
3300b57cec5SDimitry Andric                   const VarTestResult &LTest, const VarTestResult &RTest)
3310b57cec5SDimitry Andric       : InfoType(IT_BinTest) {
3320b57cec5SDimitry Andric     BinTest.Source  = Source;
3330b57cec5SDimitry Andric     BinTest.EOp     = EOp;
3340b57cec5SDimitry Andric     BinTest.LTest   = LTest;
3350b57cec5SDimitry Andric     BinTest.RTest   = RTest;
3360b57cec5SDimitry Andric   }
3370b57cec5SDimitry Andric 
3380b57cec5SDimitry Andric   PropagationInfo(const BinaryOperator *Source, EffectiveOp EOp,
3390b57cec5SDimitry Andric                   const VarDecl *LVar, ConsumedState LTestsFor,
3400b57cec5SDimitry Andric                   const VarDecl *RVar, ConsumedState RTestsFor)
3410b57cec5SDimitry Andric       : InfoType(IT_BinTest) {
3420b57cec5SDimitry Andric     BinTest.Source         = Source;
3430b57cec5SDimitry Andric     BinTest.EOp            = EOp;
3440b57cec5SDimitry Andric     BinTest.LTest.Var      = LVar;
3450b57cec5SDimitry Andric     BinTest.LTest.TestsFor = LTestsFor;
3460b57cec5SDimitry Andric     BinTest.RTest.Var      = RVar;
3470b57cec5SDimitry Andric     BinTest.RTest.TestsFor = RTestsFor;
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   PropagationInfo(ConsumedState State)
3510b57cec5SDimitry Andric       : InfoType(IT_State), State(State) {}
3520b57cec5SDimitry Andric   PropagationInfo(const VarDecl *Var) : InfoType(IT_Var), Var(Var) {}
3530b57cec5SDimitry Andric   PropagationInfo(const CXXBindTemporaryExpr *Tmp)
3540b57cec5SDimitry Andric       : InfoType(IT_Tmp), Tmp(Tmp) {}
3550b57cec5SDimitry Andric 
3560b57cec5SDimitry Andric   const ConsumedState &getState() const {
3570b57cec5SDimitry Andric     assert(InfoType == IT_State);
3580b57cec5SDimitry Andric     return State;
3590b57cec5SDimitry Andric   }
3600b57cec5SDimitry Andric 
3610b57cec5SDimitry Andric   const VarTestResult &getVarTest() const {
3620b57cec5SDimitry Andric     assert(InfoType == IT_VarTest);
3630b57cec5SDimitry Andric     return VarTest;
3640b57cec5SDimitry Andric   }
3650b57cec5SDimitry Andric 
3660b57cec5SDimitry Andric   const VarTestResult &getLTest() const {
3670b57cec5SDimitry Andric     assert(InfoType == IT_BinTest);
3680b57cec5SDimitry Andric     return BinTest.LTest;
3690b57cec5SDimitry Andric   }
3700b57cec5SDimitry Andric 
3710b57cec5SDimitry Andric   const VarTestResult &getRTest() const {
3720b57cec5SDimitry Andric     assert(InfoType == IT_BinTest);
3730b57cec5SDimitry Andric     return BinTest.RTest;
3740b57cec5SDimitry Andric   }
3750b57cec5SDimitry Andric 
3760b57cec5SDimitry Andric   const VarDecl *getVar() const {
3770b57cec5SDimitry Andric     assert(InfoType == IT_Var);
3780b57cec5SDimitry Andric     return Var;
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric 
3810b57cec5SDimitry Andric   const CXXBindTemporaryExpr *getTmp() const {
3820b57cec5SDimitry Andric     assert(InfoType == IT_Tmp);
3830b57cec5SDimitry Andric     return Tmp;
3840b57cec5SDimitry Andric   }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric   ConsumedState getAsState(const ConsumedStateMap *StateMap) const {
3870b57cec5SDimitry Andric     assert(isVar() || isTmp() || isState());
3880b57cec5SDimitry Andric 
3890b57cec5SDimitry Andric     if (isVar())
3900b57cec5SDimitry Andric       return StateMap->getState(Var);
3910b57cec5SDimitry Andric     else if (isTmp())
3920b57cec5SDimitry Andric       return StateMap->getState(Tmp);
3930b57cec5SDimitry Andric     else if (isState())
3940b57cec5SDimitry Andric       return State;
3950b57cec5SDimitry Andric     else
3960b57cec5SDimitry Andric       return CS_None;
3970b57cec5SDimitry Andric   }
3980b57cec5SDimitry Andric 
3990b57cec5SDimitry Andric   EffectiveOp testEffectiveOp() const {
4000b57cec5SDimitry Andric     assert(InfoType == IT_BinTest);
4010b57cec5SDimitry Andric     return BinTest.EOp;
4020b57cec5SDimitry Andric   }
4030b57cec5SDimitry Andric 
4040b57cec5SDimitry Andric   const BinaryOperator * testSourceNode() const {
4050b57cec5SDimitry Andric     assert(InfoType == IT_BinTest);
4060b57cec5SDimitry Andric     return BinTest.Source;
4070b57cec5SDimitry Andric   }
4080b57cec5SDimitry Andric 
4090b57cec5SDimitry Andric   bool isValid() const { return InfoType != IT_None; }
4100b57cec5SDimitry Andric   bool isState() const { return InfoType == IT_State; }
4110b57cec5SDimitry Andric   bool isVarTest() const { return InfoType == IT_VarTest; }
4120b57cec5SDimitry Andric   bool isBinTest() const { return InfoType == IT_BinTest; }
4130b57cec5SDimitry Andric   bool isVar() const { return InfoType == IT_Var; }
4140b57cec5SDimitry Andric   bool isTmp() const { return InfoType == IT_Tmp; }
4150b57cec5SDimitry Andric 
4160b57cec5SDimitry Andric   bool isTest() const {
4170b57cec5SDimitry Andric     return InfoType == IT_VarTest || InfoType == IT_BinTest;
4180b57cec5SDimitry Andric   }
4190b57cec5SDimitry Andric 
4200b57cec5SDimitry Andric   bool isPointerToValue() const {
4210b57cec5SDimitry Andric     return InfoType == IT_Var || InfoType == IT_Tmp;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric 
4240b57cec5SDimitry Andric   PropagationInfo invertTest() const {
4250b57cec5SDimitry Andric     assert(InfoType == IT_VarTest || InfoType == IT_BinTest);
4260b57cec5SDimitry Andric 
4270b57cec5SDimitry Andric     if (InfoType == IT_VarTest) {
4280b57cec5SDimitry Andric       return PropagationInfo(VarTest.Var,
4290b57cec5SDimitry Andric                              invertConsumedUnconsumed(VarTest.TestsFor));
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric     } else if (InfoType == IT_BinTest) {
4320b57cec5SDimitry Andric       return PropagationInfo(BinTest.Source,
4330b57cec5SDimitry Andric         BinTest.EOp == EO_And ? EO_Or : EO_And,
4340b57cec5SDimitry Andric         BinTest.LTest.Var, invertConsumedUnconsumed(BinTest.LTest.TestsFor),
4350b57cec5SDimitry Andric         BinTest.RTest.Var, invertConsumedUnconsumed(BinTest.RTest.TestsFor));
4360b57cec5SDimitry Andric     } else {
4370b57cec5SDimitry Andric       return {};
4380b57cec5SDimitry Andric     }
4390b57cec5SDimitry Andric   }
4400b57cec5SDimitry Andric };
4410b57cec5SDimitry Andric 
4420b57cec5SDimitry Andric } // namespace consumed
4430b57cec5SDimitry Andric } // namespace clang
4440b57cec5SDimitry Andric 
4450b57cec5SDimitry Andric static void
4460b57cec5SDimitry Andric setStateForVarOrTmp(ConsumedStateMap *StateMap, const PropagationInfo &PInfo,
4470b57cec5SDimitry Andric                     ConsumedState State) {
4480b57cec5SDimitry Andric   assert(PInfo.isVar() || PInfo.isTmp());
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric   if (PInfo.isVar())
4510b57cec5SDimitry Andric     StateMap->setState(PInfo.getVar(), State);
4520b57cec5SDimitry Andric   else
4530b57cec5SDimitry Andric     StateMap->setState(PInfo.getTmp(), State);
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric namespace clang {
4570b57cec5SDimitry Andric namespace consumed {
4580b57cec5SDimitry Andric 
4590b57cec5SDimitry Andric class ConsumedStmtVisitor : public ConstStmtVisitor<ConsumedStmtVisitor> {
4600b57cec5SDimitry Andric   using MapType = llvm::DenseMap<const Stmt *, PropagationInfo>;
4610b57cec5SDimitry Andric   using PairType= std::pair<const Stmt *, PropagationInfo>;
4620b57cec5SDimitry Andric   using InfoEntry = MapType::iterator;
4630b57cec5SDimitry Andric   using ConstInfoEntry = MapType::const_iterator;
4640b57cec5SDimitry Andric 
4650b57cec5SDimitry Andric   ConsumedAnalyzer &Analyzer;
4660b57cec5SDimitry Andric   ConsumedStateMap *StateMap;
4670b57cec5SDimitry Andric   MapType PropagationMap;
4680b57cec5SDimitry Andric 
4690b57cec5SDimitry Andric   InfoEntry findInfo(const Expr *E) {
4700b57cec5SDimitry Andric     if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
4710b57cec5SDimitry Andric       if (!Cleanups->cleanupsHaveSideEffects())
4720b57cec5SDimitry Andric         E = Cleanups->getSubExpr();
4730b57cec5SDimitry Andric     return PropagationMap.find(E->IgnoreParens());
4740b57cec5SDimitry Andric   }
4750b57cec5SDimitry Andric 
4760b57cec5SDimitry Andric   ConstInfoEntry findInfo(const Expr *E) const {
4770b57cec5SDimitry Andric     if (const auto Cleanups = dyn_cast<ExprWithCleanups>(E))
4780b57cec5SDimitry Andric       if (!Cleanups->cleanupsHaveSideEffects())
4790b57cec5SDimitry Andric         E = Cleanups->getSubExpr();
4800b57cec5SDimitry Andric     return PropagationMap.find(E->IgnoreParens());
4810b57cec5SDimitry Andric   }
4820b57cec5SDimitry Andric 
4830b57cec5SDimitry Andric   void insertInfo(const Expr *E, const PropagationInfo &PI) {
4840b57cec5SDimitry Andric     PropagationMap.insert(PairType(E->IgnoreParens(), PI));
4850b57cec5SDimitry Andric   }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   void forwardInfo(const Expr *From, const Expr *To);
4880b57cec5SDimitry Andric   void copyInfo(const Expr *From, const Expr *To, ConsumedState CS);
4890b57cec5SDimitry Andric   ConsumedState getInfo(const Expr *From);
4900b57cec5SDimitry Andric   void setInfo(const Expr *To, ConsumedState NS);
4910b57cec5SDimitry Andric   void propagateReturnType(const Expr *Call, const FunctionDecl *Fun);
4920b57cec5SDimitry Andric 
4930b57cec5SDimitry Andric public:
4940b57cec5SDimitry Andric   void checkCallability(const PropagationInfo &PInfo,
4950b57cec5SDimitry Andric                         const FunctionDecl *FunDecl,
4960b57cec5SDimitry Andric                         SourceLocation BlameLoc);
4970b57cec5SDimitry Andric   bool handleCall(const CallExpr *Call, const Expr *ObjArg,
4980b57cec5SDimitry Andric                   const FunctionDecl *FunD);
4990b57cec5SDimitry Andric 
5000b57cec5SDimitry Andric   void VisitBinaryOperator(const BinaryOperator *BinOp);
5010b57cec5SDimitry Andric   void VisitCallExpr(const CallExpr *Call);
5020b57cec5SDimitry Andric   void VisitCastExpr(const CastExpr *Cast);
5030b57cec5SDimitry Andric   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *Temp);
5040b57cec5SDimitry Andric   void VisitCXXConstructExpr(const CXXConstructExpr *Call);
5050b57cec5SDimitry Andric   void VisitCXXMemberCallExpr(const CXXMemberCallExpr *Call);
5060b57cec5SDimitry Andric   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *Call);
5070b57cec5SDimitry Andric   void VisitDeclRefExpr(const DeclRefExpr *DeclRef);
5080b57cec5SDimitry Andric   void VisitDeclStmt(const DeclStmt *DelcS);
5090b57cec5SDimitry Andric   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *Temp);
5100b57cec5SDimitry Andric   void VisitMemberExpr(const MemberExpr *MExpr);
5110b57cec5SDimitry Andric   void VisitParmVarDecl(const ParmVarDecl *Param);
5120b57cec5SDimitry Andric   void VisitReturnStmt(const ReturnStmt *Ret);
5130b57cec5SDimitry Andric   void VisitUnaryOperator(const UnaryOperator *UOp);
5140b57cec5SDimitry Andric   void VisitVarDecl(const VarDecl *Var);
5150b57cec5SDimitry Andric 
5160b57cec5SDimitry Andric   ConsumedStmtVisitor(ConsumedAnalyzer &Analyzer, ConsumedStateMap *StateMap)
5170b57cec5SDimitry Andric       : Analyzer(Analyzer), StateMap(StateMap) {}
5180b57cec5SDimitry Andric 
5190b57cec5SDimitry Andric   PropagationInfo getInfo(const Expr *StmtNode) const {
5200b57cec5SDimitry Andric     ConstInfoEntry Entry = findInfo(StmtNode);
5210b57cec5SDimitry Andric 
5220b57cec5SDimitry Andric     if (Entry != PropagationMap.end())
5230b57cec5SDimitry Andric       return Entry->second;
5240b57cec5SDimitry Andric     else
5250b57cec5SDimitry Andric       return {};
5260b57cec5SDimitry Andric   }
5270b57cec5SDimitry Andric 
5280b57cec5SDimitry Andric   void reset(ConsumedStateMap *NewStateMap) {
5290b57cec5SDimitry Andric     StateMap = NewStateMap;
5300b57cec5SDimitry Andric   }
5310b57cec5SDimitry Andric };
5320b57cec5SDimitry Andric 
5330b57cec5SDimitry Andric } // namespace consumed
5340b57cec5SDimitry Andric } // namespace clang
5350b57cec5SDimitry Andric 
5360b57cec5SDimitry Andric void ConsumedStmtVisitor::forwardInfo(const Expr *From, const Expr *To) {
5370b57cec5SDimitry Andric   InfoEntry Entry = findInfo(From);
5380b57cec5SDimitry Andric   if (Entry != PropagationMap.end())
5390b57cec5SDimitry Andric     insertInfo(To, Entry->second);
5400b57cec5SDimitry Andric }
5410b57cec5SDimitry Andric 
5420b57cec5SDimitry Andric // Create a new state for To, which is initialized to the state of From.
5430b57cec5SDimitry Andric // If NS is not CS_None, sets the state of From to NS.
5440b57cec5SDimitry Andric void ConsumedStmtVisitor::copyInfo(const Expr *From, const Expr *To,
5450b57cec5SDimitry Andric                                    ConsumedState NS) {
5460b57cec5SDimitry Andric   InfoEntry Entry = findInfo(From);
5470b57cec5SDimitry Andric   if (Entry != PropagationMap.end()) {
5480b57cec5SDimitry Andric     PropagationInfo& PInfo = Entry->second;
5490b57cec5SDimitry Andric     ConsumedState CS = PInfo.getAsState(StateMap);
5500b57cec5SDimitry Andric     if (CS != CS_None)
5510b57cec5SDimitry Andric       insertInfo(To, PropagationInfo(CS));
5520b57cec5SDimitry Andric     if (NS != CS_None && PInfo.isPointerToValue())
5530b57cec5SDimitry Andric       setStateForVarOrTmp(StateMap, PInfo, NS);
5540b57cec5SDimitry Andric   }
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric 
5570b57cec5SDimitry Andric // Get the ConsumedState for From
5580b57cec5SDimitry Andric ConsumedState ConsumedStmtVisitor::getInfo(const Expr *From) {
5590b57cec5SDimitry Andric   InfoEntry Entry = findInfo(From);
5600b57cec5SDimitry Andric   if (Entry != PropagationMap.end()) {
5610b57cec5SDimitry Andric     PropagationInfo& PInfo = Entry->second;
5620b57cec5SDimitry Andric     return PInfo.getAsState(StateMap);
5630b57cec5SDimitry Andric   }
5640b57cec5SDimitry Andric   return CS_None;
5650b57cec5SDimitry Andric }
5660b57cec5SDimitry Andric 
5670b57cec5SDimitry Andric // If we already have info for To then update it, otherwise create a new entry.
5680b57cec5SDimitry Andric void ConsumedStmtVisitor::setInfo(const Expr *To, ConsumedState NS) {
5690b57cec5SDimitry Andric   InfoEntry Entry = findInfo(To);
5700b57cec5SDimitry Andric   if (Entry != PropagationMap.end()) {
5710b57cec5SDimitry Andric     PropagationInfo& PInfo = Entry->second;
5720b57cec5SDimitry Andric     if (PInfo.isPointerToValue())
5730b57cec5SDimitry Andric       setStateForVarOrTmp(StateMap, PInfo, NS);
5740b57cec5SDimitry Andric   } else if (NS != CS_None) {
5750b57cec5SDimitry Andric      insertInfo(To, PropagationInfo(NS));
5760b57cec5SDimitry Andric   }
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric 
5790b57cec5SDimitry Andric void ConsumedStmtVisitor::checkCallability(const PropagationInfo &PInfo,
5800b57cec5SDimitry Andric                                            const FunctionDecl *FunDecl,
5810b57cec5SDimitry Andric                                            SourceLocation BlameLoc) {
5820b57cec5SDimitry Andric   assert(!PInfo.isTest());
5830b57cec5SDimitry Andric 
5840b57cec5SDimitry Andric   const CallableWhenAttr *CWAttr = FunDecl->getAttr<CallableWhenAttr>();
5850b57cec5SDimitry Andric   if (!CWAttr)
5860b57cec5SDimitry Andric     return;
5870b57cec5SDimitry Andric 
5880b57cec5SDimitry Andric   if (PInfo.isVar()) {
5890b57cec5SDimitry Andric     ConsumedState VarState = StateMap->getState(PInfo.getVar());
5900b57cec5SDimitry Andric 
5910b57cec5SDimitry Andric     if (VarState == CS_None || isCallableInState(CWAttr, VarState))
5920b57cec5SDimitry Andric       return;
5930b57cec5SDimitry Andric 
5940b57cec5SDimitry Andric     Analyzer.WarningsHandler.warnUseInInvalidState(
5950b57cec5SDimitry Andric       FunDecl->getNameAsString(), PInfo.getVar()->getNameAsString(),
5960b57cec5SDimitry Andric       stateToString(VarState), BlameLoc);
5970b57cec5SDimitry Andric   } else {
5980b57cec5SDimitry Andric     ConsumedState TmpState = PInfo.getAsState(StateMap);
5990b57cec5SDimitry Andric 
6000b57cec5SDimitry Andric     if (TmpState == CS_None || isCallableInState(CWAttr, TmpState))
6010b57cec5SDimitry Andric       return;
6020b57cec5SDimitry Andric 
6030b57cec5SDimitry Andric     Analyzer.WarningsHandler.warnUseOfTempInInvalidState(
6040b57cec5SDimitry Andric       FunDecl->getNameAsString(), stateToString(TmpState), BlameLoc);
6050b57cec5SDimitry Andric   }
6060b57cec5SDimitry Andric }
6070b57cec5SDimitry Andric 
6080b57cec5SDimitry Andric // Factors out common behavior for function, method, and operator calls.
6090b57cec5SDimitry Andric // Check parameters and set parameter state if necessary.
6100b57cec5SDimitry Andric // Returns true if the state of ObjArg is set, or false otherwise.
6110b57cec5SDimitry Andric bool ConsumedStmtVisitor::handleCall(const CallExpr *Call, const Expr *ObjArg,
6120b57cec5SDimitry Andric                                      const FunctionDecl *FunD) {
6130b57cec5SDimitry Andric   unsigned Offset = 0;
6140b57cec5SDimitry Andric   if (isa<CXXOperatorCallExpr>(Call) && isa<CXXMethodDecl>(FunD))
6150b57cec5SDimitry Andric     Offset = 1;  // first argument is 'this'
6160b57cec5SDimitry Andric 
6170b57cec5SDimitry Andric   // check explicit parameters
6180b57cec5SDimitry Andric   for (unsigned Index = Offset; Index < Call->getNumArgs(); ++Index) {
6190b57cec5SDimitry Andric     // Skip variable argument lists.
6200b57cec5SDimitry Andric     if (Index - Offset >= FunD->getNumParams())
6210b57cec5SDimitry Andric       break;
6220b57cec5SDimitry Andric 
6230b57cec5SDimitry Andric     const ParmVarDecl *Param = FunD->getParamDecl(Index - Offset);
6240b57cec5SDimitry Andric     QualType ParamType = Param->getType();
6250b57cec5SDimitry Andric 
6260b57cec5SDimitry Andric     InfoEntry Entry = findInfo(Call->getArg(Index));
6270b57cec5SDimitry Andric 
6280b57cec5SDimitry Andric     if (Entry == PropagationMap.end() || Entry->second.isTest())
6290b57cec5SDimitry Andric       continue;
6300b57cec5SDimitry Andric     PropagationInfo PInfo = Entry->second;
6310b57cec5SDimitry Andric 
6320b57cec5SDimitry Andric     // Check that the parameter is in the correct state.
6330b57cec5SDimitry Andric     if (ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>()) {
6340b57cec5SDimitry Andric       ConsumedState ParamState = PInfo.getAsState(StateMap);
6350b57cec5SDimitry Andric       ConsumedState ExpectedState = mapParamTypestateAttrState(PTA);
6360b57cec5SDimitry Andric 
6370b57cec5SDimitry Andric       if (ParamState != ExpectedState)
6380b57cec5SDimitry Andric         Analyzer.WarningsHandler.warnParamTypestateMismatch(
6390b57cec5SDimitry Andric           Call->getArg(Index)->getExprLoc(),
6400b57cec5SDimitry Andric           stateToString(ExpectedState), stateToString(ParamState));
6410b57cec5SDimitry Andric     }
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric     if (!(Entry->second.isVar() || Entry->second.isTmp()))
6440b57cec5SDimitry Andric       continue;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric     // Adjust state on the caller side.
647a7dea167SDimitry Andric     if (ReturnTypestateAttr *RT = Param->getAttr<ReturnTypestateAttr>())
6480b57cec5SDimitry Andric       setStateForVarOrTmp(StateMap, PInfo, mapReturnTypestateAttrState(RT));
649a7dea167SDimitry Andric     else if (isRValueRef(ParamType) || isConsumableType(ParamType))
650a7dea167SDimitry Andric       setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Consumed);
6510b57cec5SDimitry Andric     else if (isPointerOrRef(ParamType) &&
6520b57cec5SDimitry Andric              (!ParamType->getPointeeType().isConstQualified() ||
6530b57cec5SDimitry Andric               isSetOnReadPtrType(ParamType)))
6540b57cec5SDimitry Andric       setStateForVarOrTmp(StateMap, PInfo, consumed::CS_Unknown);
6550b57cec5SDimitry Andric   }
6560b57cec5SDimitry Andric 
6570b57cec5SDimitry Andric   if (!ObjArg)
6580b57cec5SDimitry Andric     return false;
6590b57cec5SDimitry Andric 
6600b57cec5SDimitry Andric   // check implicit 'self' parameter, if present
6610b57cec5SDimitry Andric   InfoEntry Entry = findInfo(ObjArg);
6620b57cec5SDimitry Andric   if (Entry != PropagationMap.end()) {
6630b57cec5SDimitry Andric     PropagationInfo PInfo = Entry->second;
6640b57cec5SDimitry Andric     checkCallability(PInfo, FunD, Call->getExprLoc());
6650b57cec5SDimitry Andric 
6660b57cec5SDimitry Andric     if (SetTypestateAttr *STA = FunD->getAttr<SetTypestateAttr>()) {
6670b57cec5SDimitry Andric       if (PInfo.isVar()) {
6680b57cec5SDimitry Andric         StateMap->setState(PInfo.getVar(), mapSetTypestateAttrState(STA));
6690b57cec5SDimitry Andric         return true;
6700b57cec5SDimitry Andric       }
6710b57cec5SDimitry Andric       else if (PInfo.isTmp()) {
6720b57cec5SDimitry Andric         StateMap->setState(PInfo.getTmp(), mapSetTypestateAttrState(STA));
6730b57cec5SDimitry Andric         return true;
6740b57cec5SDimitry Andric       }
6750b57cec5SDimitry Andric     }
6760b57cec5SDimitry Andric     else if (isTestingFunction(FunD) && PInfo.isVar()) {
6770b57cec5SDimitry Andric       PropagationMap.insert(PairType(Call,
6780b57cec5SDimitry Andric         PropagationInfo(PInfo.getVar(), testsFor(FunD))));
6790b57cec5SDimitry Andric     }
6800b57cec5SDimitry Andric   }
6810b57cec5SDimitry Andric   return false;
6820b57cec5SDimitry Andric }
6830b57cec5SDimitry Andric 
6840b57cec5SDimitry Andric void ConsumedStmtVisitor::propagateReturnType(const Expr *Call,
6850b57cec5SDimitry Andric                                               const FunctionDecl *Fun) {
6860b57cec5SDimitry Andric   QualType RetType = Fun->getCallResultType();
6870b57cec5SDimitry Andric   if (RetType->isReferenceType())
6880b57cec5SDimitry Andric     RetType = RetType->getPointeeType();
6890b57cec5SDimitry Andric 
6900b57cec5SDimitry Andric   if (isConsumableType(RetType)) {
6910b57cec5SDimitry Andric     ConsumedState ReturnState;
6920b57cec5SDimitry Andric     if (ReturnTypestateAttr *RTA = Fun->getAttr<ReturnTypestateAttr>())
6930b57cec5SDimitry Andric       ReturnState = mapReturnTypestateAttrState(RTA);
6940b57cec5SDimitry Andric     else
6950b57cec5SDimitry Andric       ReturnState = mapConsumableAttrState(RetType);
6960b57cec5SDimitry Andric 
6970b57cec5SDimitry Andric     PropagationMap.insert(PairType(Call, PropagationInfo(ReturnState)));
6980b57cec5SDimitry Andric   }
6990b57cec5SDimitry Andric }
7000b57cec5SDimitry Andric 
7010b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitBinaryOperator(const BinaryOperator *BinOp) {
7020b57cec5SDimitry Andric   switch (BinOp->getOpcode()) {
7030b57cec5SDimitry Andric   case BO_LAnd:
7040b57cec5SDimitry Andric   case BO_LOr : {
7050b57cec5SDimitry Andric     InfoEntry LEntry = findInfo(BinOp->getLHS()),
7060b57cec5SDimitry Andric               REntry = findInfo(BinOp->getRHS());
7070b57cec5SDimitry Andric 
7080b57cec5SDimitry Andric     VarTestResult LTest, RTest;
7090b57cec5SDimitry Andric 
7100b57cec5SDimitry Andric     if (LEntry != PropagationMap.end() && LEntry->second.isVarTest()) {
7110b57cec5SDimitry Andric       LTest = LEntry->second.getVarTest();
7120b57cec5SDimitry Andric     } else {
7130b57cec5SDimitry Andric       LTest.Var      = nullptr;
7140b57cec5SDimitry Andric       LTest.TestsFor = CS_None;
7150b57cec5SDimitry Andric     }
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric     if (REntry != PropagationMap.end() && REntry->second.isVarTest()) {
7180b57cec5SDimitry Andric       RTest = REntry->second.getVarTest();
7190b57cec5SDimitry Andric     } else {
7200b57cec5SDimitry Andric       RTest.Var      = nullptr;
7210b57cec5SDimitry Andric       RTest.TestsFor = CS_None;
7220b57cec5SDimitry Andric     }
7230b57cec5SDimitry Andric 
7240b57cec5SDimitry Andric     if (!(LTest.Var == nullptr && RTest.Var == nullptr))
7250b57cec5SDimitry Andric       PropagationMap.insert(PairType(BinOp, PropagationInfo(BinOp,
7260b57cec5SDimitry Andric         static_cast<EffectiveOp>(BinOp->getOpcode() == BO_LOr), LTest, RTest)));
7270b57cec5SDimitry Andric     break;
7280b57cec5SDimitry Andric   }
7290b57cec5SDimitry Andric 
7300b57cec5SDimitry Andric   case BO_PtrMemD:
7310b57cec5SDimitry Andric   case BO_PtrMemI:
7320b57cec5SDimitry Andric     forwardInfo(BinOp->getLHS(), BinOp);
7330b57cec5SDimitry Andric     break;
7340b57cec5SDimitry Andric 
7350b57cec5SDimitry Andric   default:
7360b57cec5SDimitry Andric     break;
7370b57cec5SDimitry Andric   }
7380b57cec5SDimitry Andric }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCallExpr(const CallExpr *Call) {
7410b57cec5SDimitry Andric   const FunctionDecl *FunDecl = Call->getDirectCallee();
7420b57cec5SDimitry Andric   if (!FunDecl)
7430b57cec5SDimitry Andric     return;
7440b57cec5SDimitry Andric 
7450b57cec5SDimitry Andric   // Special case for the std::move function.
7460b57cec5SDimitry Andric   // TODO: Make this more specific. (Deferred)
7470b57cec5SDimitry Andric   if (Call->isCallToStdMove()) {
7480b57cec5SDimitry Andric     copyInfo(Call->getArg(0), Call, CS_Consumed);
7490b57cec5SDimitry Andric     return;
7500b57cec5SDimitry Andric   }
7510b57cec5SDimitry Andric 
7520b57cec5SDimitry Andric   handleCall(Call, nullptr, FunDecl);
7530b57cec5SDimitry Andric   propagateReturnType(Call, FunDecl);
7540b57cec5SDimitry Andric }
7550b57cec5SDimitry Andric 
7560b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCastExpr(const CastExpr *Cast) {
7570b57cec5SDimitry Andric   forwardInfo(Cast->getSubExpr(), Cast);
7580b57cec5SDimitry Andric }
7590b57cec5SDimitry Andric 
7600b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXBindTemporaryExpr(
7610b57cec5SDimitry Andric   const CXXBindTemporaryExpr *Temp) {
7620b57cec5SDimitry Andric 
7630b57cec5SDimitry Andric   InfoEntry Entry = findInfo(Temp->getSubExpr());
7640b57cec5SDimitry Andric 
7650b57cec5SDimitry Andric   if (Entry != PropagationMap.end() && !Entry->second.isTest()) {
7660b57cec5SDimitry Andric     StateMap->setState(Temp, Entry->second.getAsState(StateMap));
7670b57cec5SDimitry Andric     PropagationMap.insert(PairType(Temp, PropagationInfo(Temp)));
7680b57cec5SDimitry Andric   }
7690b57cec5SDimitry Andric }
7700b57cec5SDimitry Andric 
7710b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXConstructExpr(const CXXConstructExpr *Call) {
7720b57cec5SDimitry Andric   CXXConstructorDecl *Constructor = Call->getConstructor();
7730b57cec5SDimitry Andric 
774*5f757f3fSDimitry Andric   QualType ThisType = Constructor->getFunctionObjectParameterType();
7750b57cec5SDimitry Andric 
7760b57cec5SDimitry Andric   if (!isConsumableType(ThisType))
7770b57cec5SDimitry Andric     return;
7780b57cec5SDimitry Andric 
7790b57cec5SDimitry Andric   // FIXME: What should happen if someone annotates the move constructor?
7800b57cec5SDimitry Andric   if (ReturnTypestateAttr *RTA = Constructor->getAttr<ReturnTypestateAttr>()) {
7810b57cec5SDimitry Andric     // TODO: Adjust state of args appropriately.
7820b57cec5SDimitry Andric     ConsumedState RetState = mapReturnTypestateAttrState(RTA);
7830b57cec5SDimitry Andric     PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
7840b57cec5SDimitry Andric   } else if (Constructor->isDefaultConstructor()) {
7850b57cec5SDimitry Andric     PropagationMap.insert(PairType(Call,
7860b57cec5SDimitry Andric       PropagationInfo(consumed::CS_Consumed)));
7870b57cec5SDimitry Andric   } else if (Constructor->isMoveConstructor()) {
7880b57cec5SDimitry Andric     copyInfo(Call->getArg(0), Call, CS_Consumed);
7890b57cec5SDimitry Andric   } else if (Constructor->isCopyConstructor()) {
7900b57cec5SDimitry Andric     // Copy state from arg.  If setStateOnRead then set arg to CS_Unknown.
7910b57cec5SDimitry Andric     ConsumedState NS =
7920b57cec5SDimitry Andric       isSetOnReadPtrType(Constructor->getThisType()) ?
7930b57cec5SDimitry Andric       CS_Unknown : CS_None;
7940b57cec5SDimitry Andric     copyInfo(Call->getArg(0), Call, NS);
7950b57cec5SDimitry Andric   } else {
7960b57cec5SDimitry Andric     // TODO: Adjust state of args appropriately.
7970b57cec5SDimitry Andric     ConsumedState RetState = mapConsumableAttrState(ThisType);
7980b57cec5SDimitry Andric     PropagationMap.insert(PairType(Call, PropagationInfo(RetState)));
7990b57cec5SDimitry Andric   }
8000b57cec5SDimitry Andric }
8010b57cec5SDimitry Andric 
8020b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXMemberCallExpr(
8030b57cec5SDimitry Andric     const CXXMemberCallExpr *Call) {
8040b57cec5SDimitry Andric   CXXMethodDecl* MD = Call->getMethodDecl();
8050b57cec5SDimitry Andric   if (!MD)
8060b57cec5SDimitry Andric     return;
8070b57cec5SDimitry Andric 
8080b57cec5SDimitry Andric   handleCall(Call, Call->getImplicitObjectArgument(), MD);
8090b57cec5SDimitry Andric   propagateReturnType(Call, MD);
8100b57cec5SDimitry Andric }
8110b57cec5SDimitry Andric 
8120b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitCXXOperatorCallExpr(
8130b57cec5SDimitry Andric     const CXXOperatorCallExpr *Call) {
8140b57cec5SDimitry Andric   const auto *FunDecl = dyn_cast_or_null<FunctionDecl>(Call->getDirectCallee());
8150b57cec5SDimitry Andric   if (!FunDecl) return;
8160b57cec5SDimitry Andric 
8170b57cec5SDimitry Andric   if (Call->getOperator() == OO_Equal) {
8180b57cec5SDimitry Andric     ConsumedState CS = getInfo(Call->getArg(1));
8190b57cec5SDimitry Andric     if (!handleCall(Call, Call->getArg(0), FunDecl))
8200b57cec5SDimitry Andric       setInfo(Call->getArg(0), CS);
8210b57cec5SDimitry Andric     return;
8220b57cec5SDimitry Andric   }
8230b57cec5SDimitry Andric 
8240b57cec5SDimitry Andric   if (const auto *MCall = dyn_cast<CXXMemberCallExpr>(Call))
8250b57cec5SDimitry Andric     handleCall(MCall, MCall->getImplicitObjectArgument(), FunDecl);
8260b57cec5SDimitry Andric   else
8270b57cec5SDimitry Andric     handleCall(Call, Call->getArg(0), FunDecl);
8280b57cec5SDimitry Andric 
8290b57cec5SDimitry Andric   propagateReturnType(Call, FunDecl);
8300b57cec5SDimitry Andric }
8310b57cec5SDimitry Andric 
8320b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitDeclRefExpr(const DeclRefExpr *DeclRef) {
8330b57cec5SDimitry Andric   if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclRef->getDecl()))
8340b57cec5SDimitry Andric     if (StateMap->getState(Var) != consumed::CS_None)
8350b57cec5SDimitry Andric       PropagationMap.insert(PairType(DeclRef, PropagationInfo(Var)));
8360b57cec5SDimitry Andric }
8370b57cec5SDimitry Andric 
8380b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitDeclStmt(const DeclStmt *DeclS) {
8390b57cec5SDimitry Andric   for (const auto *DI : DeclS->decls())
8400b57cec5SDimitry Andric     if (isa<VarDecl>(DI))
8410b57cec5SDimitry Andric       VisitVarDecl(cast<VarDecl>(DI));
8420b57cec5SDimitry Andric 
8430b57cec5SDimitry Andric   if (DeclS->isSingleDecl())
8440b57cec5SDimitry Andric     if (const auto *Var = dyn_cast_or_null<VarDecl>(DeclS->getSingleDecl()))
8450b57cec5SDimitry Andric       PropagationMap.insert(PairType(DeclS, PropagationInfo(Var)));
8460b57cec5SDimitry Andric }
8470b57cec5SDimitry Andric 
8480b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitMaterializeTemporaryExpr(
8490b57cec5SDimitry Andric   const MaterializeTemporaryExpr *Temp) {
850480093f4SDimitry Andric   forwardInfo(Temp->getSubExpr(), Temp);
8510b57cec5SDimitry Andric }
8520b57cec5SDimitry Andric 
8530b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitMemberExpr(const MemberExpr *MExpr) {
8540b57cec5SDimitry Andric   forwardInfo(MExpr->getBase(), MExpr);
8550b57cec5SDimitry Andric }
8560b57cec5SDimitry Andric 
8570b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitParmVarDecl(const ParmVarDecl *Param) {
8580b57cec5SDimitry Andric   QualType ParamType = Param->getType();
8590b57cec5SDimitry Andric   ConsumedState ParamState = consumed::CS_None;
8600b57cec5SDimitry Andric 
8610b57cec5SDimitry Andric   if (const ParamTypestateAttr *PTA = Param->getAttr<ParamTypestateAttr>())
8620b57cec5SDimitry Andric     ParamState = mapParamTypestateAttrState(PTA);
8630b57cec5SDimitry Andric   else if (isConsumableType(ParamType))
8640b57cec5SDimitry Andric     ParamState = mapConsumableAttrState(ParamType);
8650b57cec5SDimitry Andric   else if (isRValueRef(ParamType) &&
8660b57cec5SDimitry Andric            isConsumableType(ParamType->getPointeeType()))
8670b57cec5SDimitry Andric     ParamState = mapConsumableAttrState(ParamType->getPointeeType());
8680b57cec5SDimitry Andric   else if (ParamType->isReferenceType() &&
8690b57cec5SDimitry Andric            isConsumableType(ParamType->getPointeeType()))
8700b57cec5SDimitry Andric     ParamState = consumed::CS_Unknown;
8710b57cec5SDimitry Andric 
8720b57cec5SDimitry Andric   if (ParamState != CS_None)
8730b57cec5SDimitry Andric     StateMap->setState(Param, ParamState);
8740b57cec5SDimitry Andric }
8750b57cec5SDimitry Andric 
8760b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitReturnStmt(const ReturnStmt *Ret) {
8770b57cec5SDimitry Andric   ConsumedState ExpectedState = Analyzer.getExpectedReturnState();
8780b57cec5SDimitry Andric 
8790b57cec5SDimitry Andric   if (ExpectedState != CS_None) {
8800b57cec5SDimitry Andric     InfoEntry Entry = findInfo(Ret->getRetValue());
8810b57cec5SDimitry Andric 
8820b57cec5SDimitry Andric     if (Entry != PropagationMap.end()) {
8830b57cec5SDimitry Andric       ConsumedState RetState = Entry->second.getAsState(StateMap);
8840b57cec5SDimitry Andric 
8850b57cec5SDimitry Andric       if (RetState != ExpectedState)
8860b57cec5SDimitry Andric         Analyzer.WarningsHandler.warnReturnTypestateMismatch(
8870b57cec5SDimitry Andric           Ret->getReturnLoc(), stateToString(ExpectedState),
8880b57cec5SDimitry Andric           stateToString(RetState));
8890b57cec5SDimitry Andric     }
8900b57cec5SDimitry Andric   }
8910b57cec5SDimitry Andric 
8920b57cec5SDimitry Andric   StateMap->checkParamsForReturnTypestate(Ret->getBeginLoc(),
8930b57cec5SDimitry Andric                                           Analyzer.WarningsHandler);
8940b57cec5SDimitry Andric }
8950b57cec5SDimitry Andric 
8960b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitUnaryOperator(const UnaryOperator *UOp) {
8970b57cec5SDimitry Andric   InfoEntry Entry = findInfo(UOp->getSubExpr());
8980b57cec5SDimitry Andric   if (Entry == PropagationMap.end()) return;
8990b57cec5SDimitry Andric 
9000b57cec5SDimitry Andric   switch (UOp->getOpcode()) {
9010b57cec5SDimitry Andric   case UO_AddrOf:
9020b57cec5SDimitry Andric     PropagationMap.insert(PairType(UOp, Entry->second));
9030b57cec5SDimitry Andric     break;
9040b57cec5SDimitry Andric 
9050b57cec5SDimitry Andric   case UO_LNot:
9060b57cec5SDimitry Andric     if (Entry->second.isTest())
9070b57cec5SDimitry Andric       PropagationMap.insert(PairType(UOp, Entry->second.invertTest()));
9080b57cec5SDimitry Andric     break;
9090b57cec5SDimitry Andric 
9100b57cec5SDimitry Andric   default:
9110b57cec5SDimitry Andric     break;
9120b57cec5SDimitry Andric   }
9130b57cec5SDimitry Andric }
9140b57cec5SDimitry Andric 
9150b57cec5SDimitry Andric // TODO: See if I need to check for reference types here.
9160b57cec5SDimitry Andric void ConsumedStmtVisitor::VisitVarDecl(const VarDecl *Var) {
9170b57cec5SDimitry Andric   if (isConsumableType(Var->getType())) {
9180b57cec5SDimitry Andric     if (Var->hasInit()) {
9190b57cec5SDimitry Andric       MapType::iterator VIT = findInfo(Var->getInit()->IgnoreImplicit());
9200b57cec5SDimitry Andric       if (VIT != PropagationMap.end()) {
9210b57cec5SDimitry Andric         PropagationInfo PInfo = VIT->second;
9220b57cec5SDimitry Andric         ConsumedState St = PInfo.getAsState(StateMap);
9230b57cec5SDimitry Andric 
9240b57cec5SDimitry Andric         if (St != consumed::CS_None) {
9250b57cec5SDimitry Andric           StateMap->setState(Var, St);
9260b57cec5SDimitry Andric           return;
9270b57cec5SDimitry Andric         }
9280b57cec5SDimitry Andric       }
9290b57cec5SDimitry Andric     }
9300b57cec5SDimitry Andric     // Otherwise
9310b57cec5SDimitry Andric     StateMap->setState(Var, consumed::CS_Unknown);
9320b57cec5SDimitry Andric   }
9330b57cec5SDimitry Andric }
9340b57cec5SDimitry Andric 
9350b57cec5SDimitry Andric static void splitVarStateForIf(const IfStmt *IfNode, const VarTestResult &Test,
9360b57cec5SDimitry Andric                                ConsumedStateMap *ThenStates,
9370b57cec5SDimitry Andric                                ConsumedStateMap *ElseStates) {
9380b57cec5SDimitry Andric   ConsumedState VarState = ThenStates->getState(Test.Var);
9390b57cec5SDimitry Andric 
9400b57cec5SDimitry Andric   if (VarState == CS_Unknown) {
9410b57cec5SDimitry Andric     ThenStates->setState(Test.Var, Test.TestsFor);
9420b57cec5SDimitry Andric     ElseStates->setState(Test.Var, invertConsumedUnconsumed(Test.TestsFor));
9430b57cec5SDimitry Andric   } else if (VarState == invertConsumedUnconsumed(Test.TestsFor)) {
9440b57cec5SDimitry Andric     ThenStates->markUnreachable();
9450b57cec5SDimitry Andric   } else if (VarState == Test.TestsFor) {
9460b57cec5SDimitry Andric     ElseStates->markUnreachable();
9470b57cec5SDimitry Andric   }
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric 
9500b57cec5SDimitry Andric static void splitVarStateForIfBinOp(const PropagationInfo &PInfo,
9510b57cec5SDimitry Andric                                     ConsumedStateMap *ThenStates,
9520b57cec5SDimitry Andric                                     ConsumedStateMap *ElseStates) {
9530b57cec5SDimitry Andric   const VarTestResult &LTest = PInfo.getLTest(),
9540b57cec5SDimitry Andric                       &RTest = PInfo.getRTest();
9550b57cec5SDimitry Andric 
9560b57cec5SDimitry Andric   ConsumedState LState = LTest.Var ? ThenStates->getState(LTest.Var) : CS_None,
9570b57cec5SDimitry Andric                 RState = RTest.Var ? ThenStates->getState(RTest.Var) : CS_None;
9580b57cec5SDimitry Andric 
9590b57cec5SDimitry Andric   if (LTest.Var) {
9600b57cec5SDimitry Andric     if (PInfo.testEffectiveOp() == EO_And) {
9610b57cec5SDimitry Andric       if (LState == CS_Unknown) {
9620b57cec5SDimitry Andric         ThenStates->setState(LTest.Var, LTest.TestsFor);
9630b57cec5SDimitry Andric       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor)) {
9640b57cec5SDimitry Andric         ThenStates->markUnreachable();
9650b57cec5SDimitry Andric       } else if (LState == LTest.TestsFor && isKnownState(RState)) {
9660b57cec5SDimitry Andric         if (RState == RTest.TestsFor)
9670b57cec5SDimitry Andric           ElseStates->markUnreachable();
9680b57cec5SDimitry Andric         else
9690b57cec5SDimitry Andric           ThenStates->markUnreachable();
9700b57cec5SDimitry Andric       }
9710b57cec5SDimitry Andric     } else {
9720b57cec5SDimitry Andric       if (LState == CS_Unknown) {
9730b57cec5SDimitry Andric         ElseStates->setState(LTest.Var,
9740b57cec5SDimitry Andric                              invertConsumedUnconsumed(LTest.TestsFor));
9750b57cec5SDimitry Andric       } else if (LState == LTest.TestsFor) {
9760b57cec5SDimitry Andric         ElseStates->markUnreachable();
9770b57cec5SDimitry Andric       } else if (LState == invertConsumedUnconsumed(LTest.TestsFor) &&
9780b57cec5SDimitry Andric                  isKnownState(RState)) {
9790b57cec5SDimitry Andric         if (RState == RTest.TestsFor)
9800b57cec5SDimitry Andric           ElseStates->markUnreachable();
9810b57cec5SDimitry Andric         else
9820b57cec5SDimitry Andric           ThenStates->markUnreachable();
9830b57cec5SDimitry Andric       }
9840b57cec5SDimitry Andric     }
9850b57cec5SDimitry Andric   }
9860b57cec5SDimitry Andric 
9870b57cec5SDimitry Andric   if (RTest.Var) {
9880b57cec5SDimitry Andric     if (PInfo.testEffectiveOp() == EO_And) {
9890b57cec5SDimitry Andric       if (RState == CS_Unknown)
9900b57cec5SDimitry Andric         ThenStates->setState(RTest.Var, RTest.TestsFor);
9910b57cec5SDimitry Andric       else if (RState == invertConsumedUnconsumed(RTest.TestsFor))
9920b57cec5SDimitry Andric         ThenStates->markUnreachable();
9930b57cec5SDimitry Andric     } else {
9940b57cec5SDimitry Andric       if (RState == CS_Unknown)
9950b57cec5SDimitry Andric         ElseStates->setState(RTest.Var,
9960b57cec5SDimitry Andric                              invertConsumedUnconsumed(RTest.TestsFor));
9970b57cec5SDimitry Andric       else if (RState == RTest.TestsFor)
9980b57cec5SDimitry Andric         ElseStates->markUnreachable();
9990b57cec5SDimitry Andric     }
10000b57cec5SDimitry Andric   }
10010b57cec5SDimitry Andric }
10020b57cec5SDimitry Andric 
10030b57cec5SDimitry Andric bool ConsumedBlockInfo::allBackEdgesVisited(const CFGBlock *CurrBlock,
10040b57cec5SDimitry Andric                                             const CFGBlock *TargetBlock) {
10050b57cec5SDimitry Andric   assert(CurrBlock && "Block pointer must not be NULL");
10060b57cec5SDimitry Andric   assert(TargetBlock && "TargetBlock pointer must not be NULL");
10070b57cec5SDimitry Andric 
10080b57cec5SDimitry Andric   unsigned int CurrBlockOrder = VisitOrder[CurrBlock->getBlockID()];
10090b57cec5SDimitry Andric   for (CFGBlock::const_pred_iterator PI = TargetBlock->pred_begin(),
10100b57cec5SDimitry Andric        PE = TargetBlock->pred_end(); PI != PE; ++PI) {
10110b57cec5SDimitry Andric     if (*PI && CurrBlockOrder < VisitOrder[(*PI)->getBlockID()] )
10120b57cec5SDimitry Andric       return false;
10130b57cec5SDimitry Andric   }
10140b57cec5SDimitry Andric   return true;
10150b57cec5SDimitry Andric }
10160b57cec5SDimitry Andric 
10170b57cec5SDimitry Andric void ConsumedBlockInfo::addInfo(
10180b57cec5SDimitry Andric     const CFGBlock *Block, ConsumedStateMap *StateMap,
10190b57cec5SDimitry Andric     std::unique_ptr<ConsumedStateMap> &OwnedStateMap) {
10200b57cec5SDimitry Andric   assert(Block && "Block pointer must not be NULL");
10210b57cec5SDimitry Andric 
10220b57cec5SDimitry Andric   auto &Entry = StateMapsArray[Block->getBlockID()];
10230b57cec5SDimitry Andric 
10240b57cec5SDimitry Andric   if (Entry) {
10250b57cec5SDimitry Andric     Entry->intersect(*StateMap);
10260b57cec5SDimitry Andric   } else if (OwnedStateMap)
10270b57cec5SDimitry Andric     Entry = std::move(OwnedStateMap);
10280b57cec5SDimitry Andric   else
1029a7dea167SDimitry Andric     Entry = std::make_unique<ConsumedStateMap>(*StateMap);
10300b57cec5SDimitry Andric }
10310b57cec5SDimitry Andric 
10320b57cec5SDimitry Andric void ConsumedBlockInfo::addInfo(const CFGBlock *Block,
10330b57cec5SDimitry Andric                                 std::unique_ptr<ConsumedStateMap> StateMap) {
10340b57cec5SDimitry Andric   assert(Block && "Block pointer must not be NULL");
10350b57cec5SDimitry Andric 
10360b57cec5SDimitry Andric   auto &Entry = StateMapsArray[Block->getBlockID()];
10370b57cec5SDimitry Andric 
10380b57cec5SDimitry Andric   if (Entry) {
10390b57cec5SDimitry Andric     Entry->intersect(*StateMap);
10400b57cec5SDimitry Andric   } else {
10410b57cec5SDimitry Andric     Entry = std::move(StateMap);
10420b57cec5SDimitry Andric   }
10430b57cec5SDimitry Andric }
10440b57cec5SDimitry Andric 
10450b57cec5SDimitry Andric ConsumedStateMap* ConsumedBlockInfo::borrowInfo(const CFGBlock *Block) {
10460b57cec5SDimitry Andric   assert(Block && "Block pointer must not be NULL");
10470b57cec5SDimitry Andric   assert(StateMapsArray[Block->getBlockID()] && "Block has no block info");
10480b57cec5SDimitry Andric 
10490b57cec5SDimitry Andric   return StateMapsArray[Block->getBlockID()].get();
10500b57cec5SDimitry Andric }
10510b57cec5SDimitry Andric 
10520b57cec5SDimitry Andric void ConsumedBlockInfo::discardInfo(const CFGBlock *Block) {
10530b57cec5SDimitry Andric   StateMapsArray[Block->getBlockID()] = nullptr;
10540b57cec5SDimitry Andric }
10550b57cec5SDimitry Andric 
10560b57cec5SDimitry Andric std::unique_ptr<ConsumedStateMap>
10570b57cec5SDimitry Andric ConsumedBlockInfo::getInfo(const CFGBlock *Block) {
10580b57cec5SDimitry Andric   assert(Block && "Block pointer must not be NULL");
10590b57cec5SDimitry Andric 
10600b57cec5SDimitry Andric   auto &Entry = StateMapsArray[Block->getBlockID()];
1061a7dea167SDimitry Andric   return isBackEdgeTarget(Block) ? std::make_unique<ConsumedStateMap>(*Entry)
10620b57cec5SDimitry Andric                                  : std::move(Entry);
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric 
10650b57cec5SDimitry Andric bool ConsumedBlockInfo::isBackEdge(const CFGBlock *From, const CFGBlock *To) {
10660b57cec5SDimitry Andric   assert(From && "From block must not be NULL");
10670b57cec5SDimitry Andric   assert(To   && "From block must not be NULL");
10680b57cec5SDimitry Andric 
10690b57cec5SDimitry Andric   return VisitOrder[From->getBlockID()] > VisitOrder[To->getBlockID()];
10700b57cec5SDimitry Andric }
10710b57cec5SDimitry Andric 
10720b57cec5SDimitry Andric bool ConsumedBlockInfo::isBackEdgeTarget(const CFGBlock *Block) {
10730b57cec5SDimitry Andric   assert(Block && "Block pointer must not be NULL");
10740b57cec5SDimitry Andric 
10750b57cec5SDimitry Andric   // Anything with less than two predecessors can't be the target of a back
10760b57cec5SDimitry Andric   // edge.
10770b57cec5SDimitry Andric   if (Block->pred_size() < 2)
10780b57cec5SDimitry Andric     return false;
10790b57cec5SDimitry Andric 
10800b57cec5SDimitry Andric   unsigned int BlockVisitOrder = VisitOrder[Block->getBlockID()];
10810b57cec5SDimitry Andric   for (CFGBlock::const_pred_iterator PI = Block->pred_begin(),
10820b57cec5SDimitry Andric        PE = Block->pred_end(); PI != PE; ++PI) {
10830b57cec5SDimitry Andric     if (*PI && BlockVisitOrder < VisitOrder[(*PI)->getBlockID()])
10840b57cec5SDimitry Andric       return true;
10850b57cec5SDimitry Andric   }
10860b57cec5SDimitry Andric   return false;
10870b57cec5SDimitry Andric }
10880b57cec5SDimitry Andric 
10890b57cec5SDimitry Andric void ConsumedStateMap::checkParamsForReturnTypestate(SourceLocation BlameLoc,
10900b57cec5SDimitry Andric   ConsumedWarningsHandlerBase &WarningsHandler) const {
10910b57cec5SDimitry Andric 
10920b57cec5SDimitry Andric   for (const auto &DM : VarMap) {
10930b57cec5SDimitry Andric     if (isa<ParmVarDecl>(DM.first)) {
10940b57cec5SDimitry Andric       const auto *Param = cast<ParmVarDecl>(DM.first);
10950b57cec5SDimitry Andric       const ReturnTypestateAttr *RTA = Param->getAttr<ReturnTypestateAttr>();
10960b57cec5SDimitry Andric 
10970b57cec5SDimitry Andric       if (!RTA)
10980b57cec5SDimitry Andric         continue;
10990b57cec5SDimitry Andric 
11000b57cec5SDimitry Andric       ConsumedState ExpectedState = mapReturnTypestateAttrState(RTA);
11010b57cec5SDimitry Andric       if (DM.second != ExpectedState)
11020b57cec5SDimitry Andric         WarningsHandler.warnParamReturnTypestateMismatch(BlameLoc,
11030b57cec5SDimitry Andric           Param->getNameAsString(), stateToString(ExpectedState),
11040b57cec5SDimitry Andric           stateToString(DM.second));
11050b57cec5SDimitry Andric     }
11060b57cec5SDimitry Andric   }
11070b57cec5SDimitry Andric }
11080b57cec5SDimitry Andric 
11090b57cec5SDimitry Andric void ConsumedStateMap::clearTemporaries() {
11100b57cec5SDimitry Andric   TmpMap.clear();
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric 
11130b57cec5SDimitry Andric ConsumedState ConsumedStateMap::getState(const VarDecl *Var) const {
11140b57cec5SDimitry Andric   VarMapType::const_iterator Entry = VarMap.find(Var);
11150b57cec5SDimitry Andric 
11160b57cec5SDimitry Andric   if (Entry != VarMap.end())
11170b57cec5SDimitry Andric     return Entry->second;
11180b57cec5SDimitry Andric 
11190b57cec5SDimitry Andric   return CS_None;
11200b57cec5SDimitry Andric }
11210b57cec5SDimitry Andric 
11220b57cec5SDimitry Andric ConsumedState
11230b57cec5SDimitry Andric ConsumedStateMap::getState(const CXXBindTemporaryExpr *Tmp) const {
11240b57cec5SDimitry Andric   TmpMapType::const_iterator Entry = TmpMap.find(Tmp);
11250b57cec5SDimitry Andric 
11260b57cec5SDimitry Andric   if (Entry != TmpMap.end())
11270b57cec5SDimitry Andric     return Entry->second;
11280b57cec5SDimitry Andric 
11290b57cec5SDimitry Andric   return CS_None;
11300b57cec5SDimitry Andric }
11310b57cec5SDimitry Andric 
11320b57cec5SDimitry Andric void ConsumedStateMap::intersect(const ConsumedStateMap &Other) {
11330b57cec5SDimitry Andric   ConsumedState LocalState;
11340b57cec5SDimitry Andric 
11350b57cec5SDimitry Andric   if (this->From && this->From == Other.From && !Other.Reachable) {
11360b57cec5SDimitry Andric     this->markUnreachable();
11370b57cec5SDimitry Andric     return;
11380b57cec5SDimitry Andric   }
11390b57cec5SDimitry Andric 
11400b57cec5SDimitry Andric   for (const auto &DM : Other.VarMap) {
11410b57cec5SDimitry Andric     LocalState = this->getState(DM.first);
11420b57cec5SDimitry Andric 
11430b57cec5SDimitry Andric     if (LocalState == CS_None)
11440b57cec5SDimitry Andric       continue;
11450b57cec5SDimitry Andric 
11460b57cec5SDimitry Andric     if (LocalState != DM.second)
11470b57cec5SDimitry Andric      VarMap[DM.first] = CS_Unknown;
11480b57cec5SDimitry Andric   }
11490b57cec5SDimitry Andric }
11500b57cec5SDimitry Andric 
11510b57cec5SDimitry Andric void ConsumedStateMap::intersectAtLoopHead(const CFGBlock *LoopHead,
11520b57cec5SDimitry Andric   const CFGBlock *LoopBack, const ConsumedStateMap *LoopBackStates,
11530b57cec5SDimitry Andric   ConsumedWarningsHandlerBase &WarningsHandler) {
11540b57cec5SDimitry Andric 
11550b57cec5SDimitry Andric   ConsumedState LocalState;
11560b57cec5SDimitry Andric   SourceLocation BlameLoc = getLastStmtLoc(LoopBack);
11570b57cec5SDimitry Andric 
11580b57cec5SDimitry Andric   for (const auto &DM : LoopBackStates->VarMap) {
11590b57cec5SDimitry Andric     LocalState = this->getState(DM.first);
11600b57cec5SDimitry Andric 
11610b57cec5SDimitry Andric     if (LocalState == CS_None)
11620b57cec5SDimitry Andric       continue;
11630b57cec5SDimitry Andric 
11640b57cec5SDimitry Andric     if (LocalState != DM.second) {
11650b57cec5SDimitry Andric       VarMap[DM.first] = CS_Unknown;
11660b57cec5SDimitry Andric       WarningsHandler.warnLoopStateMismatch(BlameLoc,
11670b57cec5SDimitry Andric                                             DM.first->getNameAsString());
11680b57cec5SDimitry Andric     }
11690b57cec5SDimitry Andric   }
11700b57cec5SDimitry Andric }
11710b57cec5SDimitry Andric 
11720b57cec5SDimitry Andric void ConsumedStateMap::markUnreachable() {
11730b57cec5SDimitry Andric   this->Reachable = false;
11740b57cec5SDimitry Andric   VarMap.clear();
11750b57cec5SDimitry Andric   TmpMap.clear();
11760b57cec5SDimitry Andric }
11770b57cec5SDimitry Andric 
11780b57cec5SDimitry Andric void ConsumedStateMap::setState(const VarDecl *Var, ConsumedState State) {
11790b57cec5SDimitry Andric   VarMap[Var] = State;
11800b57cec5SDimitry Andric }
11810b57cec5SDimitry Andric 
11820b57cec5SDimitry Andric void ConsumedStateMap::setState(const CXXBindTemporaryExpr *Tmp,
11830b57cec5SDimitry Andric                                 ConsumedState State) {
11840b57cec5SDimitry Andric   TmpMap[Tmp] = State;
11850b57cec5SDimitry Andric }
11860b57cec5SDimitry Andric 
11870b57cec5SDimitry Andric void ConsumedStateMap::remove(const CXXBindTemporaryExpr *Tmp) {
11880b57cec5SDimitry Andric   TmpMap.erase(Tmp);
11890b57cec5SDimitry Andric }
11900b57cec5SDimitry Andric 
11910b57cec5SDimitry Andric bool ConsumedStateMap::operator!=(const ConsumedStateMap *Other) const {
11920b57cec5SDimitry Andric   for (const auto &DM : Other->VarMap)
11930b57cec5SDimitry Andric     if (this->getState(DM.first) != DM.second)
11940b57cec5SDimitry Andric       return true;
11950b57cec5SDimitry Andric   return false;
11960b57cec5SDimitry Andric }
11970b57cec5SDimitry Andric 
11980b57cec5SDimitry Andric void ConsumedAnalyzer::determineExpectedReturnState(AnalysisDeclContext &AC,
11990b57cec5SDimitry Andric                                                     const FunctionDecl *D) {
12000b57cec5SDimitry Andric   QualType ReturnType;
12010b57cec5SDimitry Andric   if (const auto *Constructor = dyn_cast<CXXConstructorDecl>(D)) {
1202*5f757f3fSDimitry Andric     ReturnType = Constructor->getFunctionObjectParameterType();
12030b57cec5SDimitry Andric   } else
12040b57cec5SDimitry Andric     ReturnType = D->getCallResultType();
12050b57cec5SDimitry Andric 
12060b57cec5SDimitry Andric   if (const ReturnTypestateAttr *RTSAttr = D->getAttr<ReturnTypestateAttr>()) {
12070b57cec5SDimitry Andric     const CXXRecordDecl *RD = ReturnType->getAsCXXRecordDecl();
12080b57cec5SDimitry Andric     if (!RD || !RD->hasAttr<ConsumableAttr>()) {
12090b57cec5SDimitry Andric       // FIXME: This should be removed when template instantiation propagates
12100b57cec5SDimitry Andric       //        attributes at template specialization definition, not
12110b57cec5SDimitry Andric       //        declaration. When it is removed the test needs to be enabled
12120b57cec5SDimitry Andric       //        in SemaDeclAttr.cpp.
12130b57cec5SDimitry Andric       WarningsHandler.warnReturnTypestateForUnconsumableType(
12140b57cec5SDimitry Andric           RTSAttr->getLocation(), ReturnType.getAsString());
12150b57cec5SDimitry Andric       ExpectedReturnState = CS_None;
12160b57cec5SDimitry Andric     } else
12170b57cec5SDimitry Andric       ExpectedReturnState = mapReturnTypestateAttrState(RTSAttr);
12180b57cec5SDimitry Andric   } else if (isConsumableType(ReturnType)) {
12190b57cec5SDimitry Andric     if (isAutoCastType(ReturnType))   // We can auto-cast the state to the
12200b57cec5SDimitry Andric       ExpectedReturnState = CS_None;  // expected state.
12210b57cec5SDimitry Andric     else
12220b57cec5SDimitry Andric       ExpectedReturnState = mapConsumableAttrState(ReturnType);
12230b57cec5SDimitry Andric   }
12240b57cec5SDimitry Andric   else
12250b57cec5SDimitry Andric     ExpectedReturnState = CS_None;
12260b57cec5SDimitry Andric }
12270b57cec5SDimitry Andric 
12280b57cec5SDimitry Andric bool ConsumedAnalyzer::splitState(const CFGBlock *CurrBlock,
12290b57cec5SDimitry Andric                                   const ConsumedStmtVisitor &Visitor) {
12300b57cec5SDimitry Andric   std::unique_ptr<ConsumedStateMap> FalseStates(
12310b57cec5SDimitry Andric       new ConsumedStateMap(*CurrStates));
12320b57cec5SDimitry Andric   PropagationInfo PInfo;
12330b57cec5SDimitry Andric 
12340b57cec5SDimitry Andric   if (const auto *IfNode =
12350b57cec5SDimitry Andric           dyn_cast_or_null<IfStmt>(CurrBlock->getTerminator().getStmt())) {
12360b57cec5SDimitry Andric     const Expr *Cond = IfNode->getCond();
12370b57cec5SDimitry Andric 
12380b57cec5SDimitry Andric     PInfo = Visitor.getInfo(Cond);
12390b57cec5SDimitry Andric     if (!PInfo.isValid() && isa<BinaryOperator>(Cond))
12400b57cec5SDimitry Andric       PInfo = Visitor.getInfo(cast<BinaryOperator>(Cond)->getRHS());
12410b57cec5SDimitry Andric 
12420b57cec5SDimitry Andric     if (PInfo.isVarTest()) {
12430b57cec5SDimitry Andric       CurrStates->setSource(Cond);
12440b57cec5SDimitry Andric       FalseStates->setSource(Cond);
12450b57cec5SDimitry Andric       splitVarStateForIf(IfNode, PInfo.getVarTest(), CurrStates.get(),
12460b57cec5SDimitry Andric                          FalseStates.get());
12470b57cec5SDimitry Andric     } else if (PInfo.isBinTest()) {
12480b57cec5SDimitry Andric       CurrStates->setSource(PInfo.testSourceNode());
12490b57cec5SDimitry Andric       FalseStates->setSource(PInfo.testSourceNode());
12500b57cec5SDimitry Andric       splitVarStateForIfBinOp(PInfo, CurrStates.get(), FalseStates.get());
12510b57cec5SDimitry Andric     } else {
12520b57cec5SDimitry Andric       return false;
12530b57cec5SDimitry Andric     }
12540b57cec5SDimitry Andric   } else if (const auto *BinOp =
12550b57cec5SDimitry Andric        dyn_cast_or_null<BinaryOperator>(CurrBlock->getTerminator().getStmt())) {
12560b57cec5SDimitry Andric     PInfo = Visitor.getInfo(BinOp->getLHS());
12570b57cec5SDimitry Andric     if (!PInfo.isVarTest()) {
12580b57cec5SDimitry Andric       if ((BinOp = dyn_cast_or_null<BinaryOperator>(BinOp->getLHS()))) {
12590b57cec5SDimitry Andric         PInfo = Visitor.getInfo(BinOp->getRHS());
12600b57cec5SDimitry Andric 
12610b57cec5SDimitry Andric         if (!PInfo.isVarTest())
12620b57cec5SDimitry Andric           return false;
12630b57cec5SDimitry Andric       } else {
12640b57cec5SDimitry Andric         return false;
12650b57cec5SDimitry Andric       }
12660b57cec5SDimitry Andric     }
12670b57cec5SDimitry Andric 
12680b57cec5SDimitry Andric     CurrStates->setSource(BinOp);
12690b57cec5SDimitry Andric     FalseStates->setSource(BinOp);
12700b57cec5SDimitry Andric 
12710b57cec5SDimitry Andric     const VarTestResult &Test = PInfo.getVarTest();
12720b57cec5SDimitry Andric     ConsumedState VarState = CurrStates->getState(Test.Var);
12730b57cec5SDimitry Andric 
12740b57cec5SDimitry Andric     if (BinOp->getOpcode() == BO_LAnd) {
12750b57cec5SDimitry Andric       if (VarState == CS_Unknown)
12760b57cec5SDimitry Andric         CurrStates->setState(Test.Var, Test.TestsFor);
12770b57cec5SDimitry Andric       else if (VarState == invertConsumedUnconsumed(Test.TestsFor))
12780b57cec5SDimitry Andric         CurrStates->markUnreachable();
12790b57cec5SDimitry Andric 
12800b57cec5SDimitry Andric     } else if (BinOp->getOpcode() == BO_LOr) {
12810b57cec5SDimitry Andric       if (VarState == CS_Unknown)
12820b57cec5SDimitry Andric         FalseStates->setState(Test.Var,
12830b57cec5SDimitry Andric                               invertConsumedUnconsumed(Test.TestsFor));
12840b57cec5SDimitry Andric       else if (VarState == Test.TestsFor)
12850b57cec5SDimitry Andric         FalseStates->markUnreachable();
12860b57cec5SDimitry Andric     }
12870b57cec5SDimitry Andric   } else {
12880b57cec5SDimitry Andric     return false;
12890b57cec5SDimitry Andric   }
12900b57cec5SDimitry Andric 
12910b57cec5SDimitry Andric   CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin();
12920b57cec5SDimitry Andric 
12930b57cec5SDimitry Andric   if (*SI)
12940b57cec5SDimitry Andric     BlockInfo.addInfo(*SI, std::move(CurrStates));
12950b57cec5SDimitry Andric   else
12960b57cec5SDimitry Andric     CurrStates = nullptr;
12970b57cec5SDimitry Andric 
12980b57cec5SDimitry Andric   if (*++SI)
12990b57cec5SDimitry Andric     BlockInfo.addInfo(*SI, std::move(FalseStates));
13000b57cec5SDimitry Andric 
13010b57cec5SDimitry Andric   return true;
13020b57cec5SDimitry Andric }
13030b57cec5SDimitry Andric 
13040b57cec5SDimitry Andric void ConsumedAnalyzer::run(AnalysisDeclContext &AC) {
13050b57cec5SDimitry Andric   const auto *D = dyn_cast_or_null<FunctionDecl>(AC.getDecl());
13060b57cec5SDimitry Andric   if (!D)
13070b57cec5SDimitry Andric     return;
13080b57cec5SDimitry Andric 
13090b57cec5SDimitry Andric   CFG *CFGraph = AC.getCFG();
13100b57cec5SDimitry Andric   if (!CFGraph)
13110b57cec5SDimitry Andric     return;
13120b57cec5SDimitry Andric 
13130b57cec5SDimitry Andric   determineExpectedReturnState(AC, D);
13140b57cec5SDimitry Andric 
13150b57cec5SDimitry Andric   PostOrderCFGView *SortedGraph = AC.getAnalysis<PostOrderCFGView>();
13160b57cec5SDimitry Andric   // AC.getCFG()->viewCFG(LangOptions());
13170b57cec5SDimitry Andric 
13180b57cec5SDimitry Andric   BlockInfo = ConsumedBlockInfo(CFGraph->getNumBlockIDs(), SortedGraph);
13190b57cec5SDimitry Andric 
1320a7dea167SDimitry Andric   CurrStates = std::make_unique<ConsumedStateMap>();
13210b57cec5SDimitry Andric   ConsumedStmtVisitor Visitor(*this, CurrStates.get());
13220b57cec5SDimitry Andric 
13230b57cec5SDimitry Andric   // Add all trackable parameters to the state map.
13240b57cec5SDimitry Andric   for (const auto *PI : D->parameters())
13250b57cec5SDimitry Andric     Visitor.VisitParmVarDecl(PI);
13260b57cec5SDimitry Andric 
13270b57cec5SDimitry Andric   // Visit all of the function's basic blocks.
13280b57cec5SDimitry Andric   for (const auto *CurrBlock : *SortedGraph) {
13290b57cec5SDimitry Andric     if (!CurrStates)
13300b57cec5SDimitry Andric       CurrStates = BlockInfo.getInfo(CurrBlock);
13310b57cec5SDimitry Andric 
13320b57cec5SDimitry Andric     if (!CurrStates) {
13330b57cec5SDimitry Andric       continue;
13340b57cec5SDimitry Andric     } else if (!CurrStates->isReachable()) {
13350b57cec5SDimitry Andric       CurrStates = nullptr;
13360b57cec5SDimitry Andric       continue;
13370b57cec5SDimitry Andric     }
13380b57cec5SDimitry Andric 
13390b57cec5SDimitry Andric     Visitor.reset(CurrStates.get());
13400b57cec5SDimitry Andric 
13410b57cec5SDimitry Andric     // Visit all of the basic block's statements.
13420b57cec5SDimitry Andric     for (const auto &B : *CurrBlock) {
13430b57cec5SDimitry Andric       switch (B.getKind()) {
13440b57cec5SDimitry Andric       case CFGElement::Statement:
13450b57cec5SDimitry Andric         Visitor.Visit(B.castAs<CFGStmt>().getStmt());
13460b57cec5SDimitry Andric         break;
13470b57cec5SDimitry Andric 
13480b57cec5SDimitry Andric       case CFGElement::TemporaryDtor: {
13490b57cec5SDimitry Andric         const CFGTemporaryDtor &DTor = B.castAs<CFGTemporaryDtor>();
13500b57cec5SDimitry Andric         const CXXBindTemporaryExpr *BTE = DTor.getBindTemporaryExpr();
13510b57cec5SDimitry Andric 
13520b57cec5SDimitry Andric         Visitor.checkCallability(PropagationInfo(BTE),
13530b57cec5SDimitry Andric                                  DTor.getDestructorDecl(AC.getASTContext()),
13540b57cec5SDimitry Andric                                  BTE->getExprLoc());
13550b57cec5SDimitry Andric         CurrStates->remove(BTE);
13560b57cec5SDimitry Andric         break;
13570b57cec5SDimitry Andric       }
13580b57cec5SDimitry Andric 
13590b57cec5SDimitry Andric       case CFGElement::AutomaticObjectDtor: {
13600b57cec5SDimitry Andric         const CFGAutomaticObjDtor &DTor = B.castAs<CFGAutomaticObjDtor>();
13610b57cec5SDimitry Andric         SourceLocation Loc = DTor.getTriggerStmt()->getEndLoc();
13620b57cec5SDimitry Andric         const VarDecl *Var = DTor.getVarDecl();
13630b57cec5SDimitry Andric 
13640b57cec5SDimitry Andric         Visitor.checkCallability(PropagationInfo(Var),
13650b57cec5SDimitry Andric                                  DTor.getDestructorDecl(AC.getASTContext()),
13660b57cec5SDimitry Andric                                  Loc);
13670b57cec5SDimitry Andric         break;
13680b57cec5SDimitry Andric       }
13690b57cec5SDimitry Andric 
13700b57cec5SDimitry Andric       default:
13710b57cec5SDimitry Andric         break;
13720b57cec5SDimitry Andric       }
13730b57cec5SDimitry Andric     }
13740b57cec5SDimitry Andric 
13750b57cec5SDimitry Andric     // TODO: Handle other forms of branching with precision, including while-
13760b57cec5SDimitry Andric     //       and for-loops. (Deferred)
13770b57cec5SDimitry Andric     if (!splitState(CurrBlock, Visitor)) {
13780b57cec5SDimitry Andric       CurrStates->setSource(nullptr);
13790b57cec5SDimitry Andric 
13800b57cec5SDimitry Andric       if (CurrBlock->succ_size() > 1 ||
13810b57cec5SDimitry Andric           (CurrBlock->succ_size() == 1 &&
13820b57cec5SDimitry Andric            (*CurrBlock->succ_begin())->pred_size() > 1)) {
13830b57cec5SDimitry Andric 
13840b57cec5SDimitry Andric         auto *RawState = CurrStates.get();
13850b57cec5SDimitry Andric 
13860b57cec5SDimitry Andric         for (CFGBlock::const_succ_iterator SI = CurrBlock->succ_begin(),
13870b57cec5SDimitry Andric              SE = CurrBlock->succ_end(); SI != SE; ++SI) {
13880b57cec5SDimitry Andric           if (*SI == nullptr) continue;
13890b57cec5SDimitry Andric 
13900b57cec5SDimitry Andric           if (BlockInfo.isBackEdge(CurrBlock, *SI)) {
13910b57cec5SDimitry Andric             BlockInfo.borrowInfo(*SI)->intersectAtLoopHead(
13920b57cec5SDimitry Andric                 *SI, CurrBlock, RawState, WarningsHandler);
13930b57cec5SDimitry Andric 
13940b57cec5SDimitry Andric             if (BlockInfo.allBackEdgesVisited(CurrBlock, *SI))
13950b57cec5SDimitry Andric               BlockInfo.discardInfo(*SI);
13960b57cec5SDimitry Andric           } else {
13970b57cec5SDimitry Andric             BlockInfo.addInfo(*SI, RawState, CurrStates);
13980b57cec5SDimitry Andric           }
13990b57cec5SDimitry Andric         }
14000b57cec5SDimitry Andric 
14010b57cec5SDimitry Andric         CurrStates = nullptr;
14020b57cec5SDimitry Andric       }
14030b57cec5SDimitry Andric     }
14040b57cec5SDimitry Andric 
14050b57cec5SDimitry Andric     if (CurrBlock == &AC.getCFG()->getExit() &&
14060b57cec5SDimitry Andric         D->getCallResultType()->isVoidType())
14070b57cec5SDimitry Andric       CurrStates->checkParamsForReturnTypestate(D->getLocation(),
14080b57cec5SDimitry Andric                                                 WarningsHandler);
14090b57cec5SDimitry Andric   } // End of block iterator.
14100b57cec5SDimitry Andric 
14110b57cec5SDimitry Andric   // Delete the last existing state map.
14120b57cec5SDimitry Andric   CurrStates = nullptr;
14130b57cec5SDimitry Andric 
14140b57cec5SDimitry Andric   WarningsHandler.emitDiagnostics();
14150b57cec5SDimitry Andric }
1416