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 <est, 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 <est = 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