1af7bc39bSStanislav Gatev //===-- Transfer.cpp --------------------------------------------*- C++ -*-===// 2af7bc39bSStanislav Gatev // 3af7bc39bSStanislav Gatev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4af7bc39bSStanislav Gatev // See https://llvm.org/LICENSE.txt for license information. 5af7bc39bSStanislav Gatev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6af7bc39bSStanislav Gatev // 7af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===// 8af7bc39bSStanislav Gatev // 9af7bc39bSStanislav Gatev // This file defines transfer functions that evaluate program statements and 10af7bc39bSStanislav Gatev // update an environment accordingly. 11af7bc39bSStanislav Gatev // 12af7bc39bSStanislav Gatev //===----------------------------------------------------------------------===// 13af7bc39bSStanislav Gatev 14af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/Transfer.h" 15af7bc39bSStanislav Gatev #include "clang/AST/Decl.h" 16af7bc39bSStanislav Gatev #include "clang/AST/DeclBase.h" 177d941d6dSStanislav Gatev #include "clang/AST/DeclCXX.h" 18af7bc39bSStanislav Gatev #include "clang/AST/Expr.h" 1999f7d55eSStanislav Gatev #include "clang/AST/ExprCXX.h" 20e7481f6eSStanislav Gatev #include "clang/AST/OperationKinds.h" 21af7bc39bSStanislav Gatev #include "clang/AST/Stmt.h" 22af7bc39bSStanislav Gatev #include "clang/AST/StmtVisitor.h" 239ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/ASTOps.h" 2459ff3adcSmartinboehme #include "clang/Analysis/FlowSensitive/AdornedCFG.h" 259ec8c961SSamira Bazuzi #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 26af7bc39bSStanislav Gatev #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 27300fbf56SSam Estep #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" 28f2123af1SMartin Braenne #include "clang/Analysis/FlowSensitive/RecordOps.h" 29ef1e1b31SYitzhak Mandelbaum #include "clang/Analysis/FlowSensitive/Value.h" 30506ec85bSYitzhak Mandelbaum #include "clang/Basic/Builtins.h" 31e7481f6eSStanislav Gatev #include "clang/Basic/OperatorKinds.h" 32af7bc39bSStanislav Gatev #include "llvm/Support/Casting.h" 33f9026cfbSKinuko Yasuda #include "llvm/Support/Debug.h" 34f9026cfbSKinuko Yasuda #include <assert.h> 35af7bc39bSStanislav Gatev #include <cassert> 36f9026cfbSKinuko Yasuda 37f9026cfbSKinuko Yasuda #define DEBUG_TYPE "dataflow" 38af7bc39bSStanislav Gatev 39af7bc39bSStanislav Gatev namespace clang { 40af7bc39bSStanislav Gatev namespace dataflow { 41af7bc39bSStanislav Gatev 420608541aSMartin Braenne const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { 43*0362a299Smartinboehme const CFGBlock *Block = ACFG.blockForStmt(S); 44*0362a299Smartinboehme if (Block == nullptr) { 45c70f0583Smartinboehme assert(false); 46c70f0583Smartinboehme return nullptr; 47c70f0583Smartinboehme } 48*0362a299Smartinboehme if (!ACFG.isBlockReachable(*Block)) 490608541aSMartin Braenne return nullptr; 50*0362a299Smartinboehme if (Block->getBlockID() == CurBlockID) 51ccf1e322Smartinboehme return &CurState.Env; 52*0362a299Smartinboehme const auto &State = BlockToState[Block->getBlockID()]; 53977289e4Smartinboehme if (!(State)) 548e1d2f2fSKinuko Yasuda return nullptr; 550608541aSMartin Braenne return &State->Env; 560608541aSMartin Braenne } 570608541aSMartin Braenne 58ef1e1b31SYitzhak Mandelbaum static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 59ef1e1b31SYitzhak Mandelbaum Environment &Env) { 60e95134b9SMartin Braenne Value *LHSValue = Env.getValue(LHS); 61e95134b9SMartin Braenne Value *RHSValue = Env.getValue(RHS); 62762cb1d3SMartin Braenne 63762cb1d3SMartin Braenne if (LHSValue == RHSValue) 64762cb1d3SMartin Braenne return Env.getBoolLiteralValue(true); 65762cb1d3SMartin Braenne 66762cb1d3SMartin Braenne if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue)) 67762cb1d3SMartin Braenne if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue)) 68762cb1d3SMartin Braenne return Env.makeIff(*LHSBool, *RHSBool); 69ef1e1b31SYitzhak Mandelbaum 70f3fbd21fSmartinboehme if (auto *LHSPtr = dyn_cast_or_null<PointerValue>(LHSValue)) 71f3fbd21fSmartinboehme if (auto *RHSPtr = dyn_cast_or_null<PointerValue>(RHSValue)) 72f3fbd21fSmartinboehme // If the storage locations are the same, the pointers definitely compare 73f3fbd21fSmartinboehme // the same. If the storage locations are different, they may still alias, 74f3fbd21fSmartinboehme // so we fall through to the case below that returns an atom. 75f3fbd21fSmartinboehme if (&LHSPtr->getPointeeLoc() == &RHSPtr->getPointeeLoc()) 76f3fbd21fSmartinboehme return Env.getBoolLiteralValue(true); 77f3fbd21fSmartinboehme 78ef1e1b31SYitzhak Mandelbaum return Env.makeAtomicBoolValue(); 79ef1e1b31SYitzhak Mandelbaum } 80ef1e1b31SYitzhak Mandelbaum 812d8cd195SSam McCall static BoolValue &unpackValue(BoolValue &V, Environment &Env) { 82fc9821a8SSam McCall if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) { 83fc9821a8SSam McCall auto &A = Env.getDataflowAnalysisContext().arena(); 84fc9821a8SSam McCall return A.makeBoolValue(A.makeAtomRef(Top->getAtom())); 852d8cd195SSam McCall } 86fc9821a8SSam McCall return V; 8739b9d4f1SYitzhak Mandelbaum } 8839b9d4f1SYitzhak Mandelbaum 8939b9d4f1SYitzhak Mandelbaum // Unpacks the value (if any) associated with `E` and updates `E` to the new 9002562804SYitzhak Mandelbaum // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion, 9102562804SYitzhak Mandelbaum // by skipping past the reference. 9239b9d4f1SYitzhak Mandelbaum static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { 93b244b6aeSMartin Braenne auto *Loc = Env.getStorageLocation(E); 9439b9d4f1SYitzhak Mandelbaum if (Loc == nullptr) 9539b9d4f1SYitzhak Mandelbaum return nullptr; 9639b9d4f1SYitzhak Mandelbaum auto *Val = Env.getValue(*Loc); 9739b9d4f1SYitzhak Mandelbaum 9839b9d4f1SYitzhak Mandelbaum auto *B = dyn_cast_or_null<BoolValue>(Val); 9939b9d4f1SYitzhak Mandelbaum if (B == nullptr) 10039b9d4f1SYitzhak Mandelbaum return Val; 10139b9d4f1SYitzhak Mandelbaum 10239b9d4f1SYitzhak Mandelbaum auto &UnpackedVal = unpackValue(*B, Env); 10339b9d4f1SYitzhak Mandelbaum if (&UnpackedVal == Val) 10439b9d4f1SYitzhak Mandelbaum return Val; 10539b9d4f1SYitzhak Mandelbaum Env.setValue(*Loc, UnpackedVal); 10639b9d4f1SYitzhak Mandelbaum return &UnpackedVal; 10739b9d4f1SYitzhak Mandelbaum } 10839b9d4f1SYitzhak Mandelbaum 1095a16665eSMartin Braenne static void propagateValue(const Expr &From, const Expr &To, Environment &Env) { 110e8fce958Smartinboehme if (From.getType()->isRecordType()) 111e8fce958Smartinboehme return; 112e95134b9SMartin Braenne if (auto *Val = Env.getValue(From)) 113b244b6aeSMartin Braenne Env.setValue(To, *Val); 1145a16665eSMartin Braenne } 1155a16665eSMartin Braenne 1165a16665eSMartin Braenne static void propagateStorageLocation(const Expr &From, const Expr &To, 1175a16665eSMartin Braenne Environment &Env) { 118b244b6aeSMartin Braenne if (auto *Loc = Env.getStorageLocation(From)) 119b244b6aeSMartin Braenne Env.setStorageLocation(To, *Loc); 1205a16665eSMartin Braenne } 1215a16665eSMartin Braenne 122d3632486SMartin Braenne // Propagates the value or storage location of `From` to `To` in cases where 1235a16665eSMartin Braenne // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff 1245a16665eSMartin Braenne // `From` is a glvalue. 1255a16665eSMartin Braenne static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, 1265a16665eSMartin Braenne Environment &Env) { 1275a16665eSMartin Braenne assert(From.isGLValue() == To.isGLValue()); 1285a16665eSMartin Braenne if (From.isGLValue()) 1295a16665eSMartin Braenne propagateStorageLocation(From, To, Env); 1305a16665eSMartin Braenne else 1315a16665eSMartin Braenne propagateValue(From, To, Env); 1325a16665eSMartin Braenne } 1335a16665eSMartin Braenne 1341bc2d43eSMartin Braenne namespace { 1351bc2d43eSMartin Braenne 136af7bc39bSStanislav Gatev class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 137af7bc39bSStanislav Gatev public: 1389ba6961cSmartinboehme TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env, 1399ba6961cSmartinboehme Environment::ValueModel &Model) 1409ba6961cSmartinboehme : StmtToEnv(StmtToEnv), Env(Env), Model(Model) {} 141af7bc39bSStanislav Gatev 142e7481f6eSStanislav Gatev void VisitBinaryOperator(const BinaryOperator *S) { 14345643cfcSEric Li const Expr *LHS = S->getLHS(); 144e7481f6eSStanislav Gatev assert(LHS != nullptr); 145cf63e9d4SStanislav Gatev 14645643cfcSEric Li const Expr *RHS = S->getRHS(); 147cf63e9d4SStanislav Gatev assert(RHS != nullptr); 148cf63e9d4SStanislav Gatev 14949241727Smartinboehme // Do compound assignments up-front, as there are so many of them and we 15049241727Smartinboehme // don't want to list all of them in the switch statement below. 15149241727Smartinboehme // To avoid generating unnecessary values, we don't create a new value but 15249241727Smartinboehme // instead leave it to the specific analysis to do this if desired. 15349241727Smartinboehme if (S->isCompoundAssignmentOp()) 15449241727Smartinboehme propagateStorageLocation(*S->getLHS(), *S, Env); 15549241727Smartinboehme 156cf63e9d4SStanislav Gatev switch (S->getOpcode()) { 157cf63e9d4SStanislav Gatev case BO_Assign: { 158b244b6aeSMartin Braenne auto *LHSLoc = Env.getStorageLocation(*LHS); 159e7481f6eSStanislav Gatev if (LHSLoc == nullptr) 160dd4dde8dSStanislav Gatev break; 161e7481f6eSStanislav Gatev 162e95134b9SMartin Braenne auto *RHSVal = Env.getValue(*RHS); 163e7481f6eSStanislav Gatev if (RHSVal == nullptr) 164dd4dde8dSStanislav Gatev break; 165e7481f6eSStanislav Gatev 166e7481f6eSStanislav Gatev // Assign a value to the storage location of the left-hand side. 167e7481f6eSStanislav Gatev Env.setValue(*LHSLoc, *RHSVal); 168e7481f6eSStanislav Gatev 169e7481f6eSStanislav Gatev // Assign a storage location for the whole expression. 170b244b6aeSMartin Braenne Env.setStorageLocation(*S, *LHSLoc); 171dd4dde8dSStanislav Gatev break; 172e7481f6eSStanislav Gatev } 173dd4dde8dSStanislav Gatev case BO_LAnd: 174dd4dde8dSStanislav Gatev case BO_LOr: { 1757f6c3a90SMartin Braenne BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 1767f6c3a90SMartin Braenne BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 1775acd29ebSMartin Braenne 178dd4dde8dSStanislav Gatev if (S->getOpcode() == BO_LAnd) 179b244b6aeSMartin Braenne Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal)); 180dd4dde8dSStanislav Gatev else 181b244b6aeSMartin Braenne Env.setValue(*S, Env.makeOr(LHSVal, RHSVal)); 182dd4dde8dSStanislav Gatev break; 183dd4dde8dSStanislav Gatev } 184ef1e1b31SYitzhak Mandelbaum case BO_NE: 185ef1e1b31SYitzhak Mandelbaum case BO_EQ: { 186ef1e1b31SYitzhak Mandelbaum auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 187b244b6aeSMartin Braenne Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue 188ef1e1b31SYitzhak Mandelbaum : Env.makeNot(LHSEqRHSValue)); 189ef1e1b31SYitzhak Mandelbaum break; 190ef1e1b31SYitzhak Mandelbaum } 191ba53906cSStanislav Gatev case BO_Comma: { 19268baaca6SMartin Braenne propagateValueOrStorageLocation(*RHS, *S, Env); 193ba53906cSStanislav Gatev break; 194ba53906cSStanislav Gatev } 195dd4dde8dSStanislav Gatev default: 196dd4dde8dSStanislav Gatev break; 197dd4dde8dSStanislav Gatev } 198e7481f6eSStanislav Gatev } 199e7481f6eSStanislav Gatev 200e7481f6eSStanislav Gatev void VisitDeclRefExpr(const DeclRefExpr *S) { 201ef463545SYitzhak Mandelbaum const ValueDecl *VD = S->getDecl(); 202ef463545SYitzhak Mandelbaum assert(VD != nullptr); 2031d7f9ce6SMartin Braenne 2044866a6e1SMartin Braenne // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a 2054866a6e1SMartin Braenne // `StorageLocation`, and there's also no sensible `Value` that we can 2064866a6e1SMartin Braenne // assign to them. Examples: 2074866a6e1SMartin Braenne // - Non-static member variables 2084866a6e1SMartin Braenne // - Non static member functions 2094866a6e1SMartin Braenne // Note: Member operators are an exception to this, but apparently only 2104866a6e1SMartin Braenne // if the `DeclRefExpr` is used within the callee of a 2114866a6e1SMartin Braenne // `CXXOperatorCallExpr`. In other cases, for example when applying the 2124866a6e1SMartin Braenne // address-of operator, the `DeclRefExpr` is a prvalue. 2134866a6e1SMartin Braenne if (!S->isGLValue()) 2141d7f9ce6SMartin Braenne return; 2151d7f9ce6SMartin Braenne 2169940fac7SMartin Braenne auto *DeclLoc = Env.getStorageLocation(*VD); 217e7481f6eSStanislav Gatev if (DeclLoc == nullptr) 218e7481f6eSStanislav Gatev return; 219e7481f6eSStanislav Gatev 220b244b6aeSMartin Braenne Env.setStorageLocation(*S, *DeclLoc); 221e7481f6eSStanislav Gatev } 222e7481f6eSStanislav Gatev 223af7bc39bSStanislav Gatev void VisitDeclStmt(const DeclStmt *S) { 22437e6496cSStanislav Gatev // Group decls are converted into single decls in the CFG so the cast below 22537e6496cSStanislav Gatev // is safe. 22637e6496cSStanislav Gatev const auto &D = *cast<VarDecl>(S->getSingleDecl()); 22703dff121SStanislav Gatev 228bfbe1378SMartin Braenne ProcessVarDecl(D); 229bfbe1378SMartin Braenne } 230bfbe1378SMartin Braenne 231bfbe1378SMartin Braenne void ProcessVarDecl(const VarDecl &D) { 23203dff121SStanislav Gatev // Static local vars are already initialized in `Environment`. 23303dff121SStanislav Gatev if (D.hasGlobalStorage()) 23403dff121SStanislav Gatev return; 23503dff121SStanislav Gatev 236bfbe1378SMartin Braenne // If this is the holding variable for a `BindingDecl`, we may already 237bfbe1378SMartin Braenne // have a storage location set up -- so check. (See also explanation below 238bfbe1378SMartin Braenne // where we process the `BindingDecl`.) 2396d768548SMartin Braenne if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr) 2406d768548SMartin Braenne return; 241bfbe1378SMartin Braenne 242bfbe1378SMartin Braenne assert(Env.getStorageLocation(D) == nullptr); 24337e6496cSStanislav Gatev 2446d768548SMartin Braenne Env.setStorageLocation(D, Env.createObject(D)); 245af7bc39bSStanislav Gatev 24602562804SYitzhak Mandelbaum // `DecompositionDecl` must be handled after we've interpreted the loc 24702562804SYitzhak Mandelbaum // itself, because the binding expression refers back to the 24802562804SYitzhak Mandelbaum // `DecompositionDecl` (even though it has no written name). 2490e286b77SStanislav Gatev if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 2500e286b77SStanislav Gatev // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 2510e286b77SStanislav Gatev // needs to be evaluated after initializing the values in the storage for 2520e286b77SStanislav Gatev // VarDecl, as the bindings refer to them. 2530e286b77SStanislav Gatev // FIXME: Add support for ArraySubscriptExpr. 254ef463545SYitzhak Mandelbaum // FIXME: Consider adding AST nodes used in BindingDecls to the CFG. 2550e286b77SStanislav Gatev for (const auto *B : Decomp->bindings()) { 256ef463545SYitzhak Mandelbaum if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) { 2570e286b77SStanislav Gatev auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 2580e286b77SStanislav Gatev if (DE == nullptr) 2590e286b77SStanislav Gatev continue; 2600e286b77SStanislav Gatev 261ef463545SYitzhak Mandelbaum // ME and its base haven't been visited because they aren't included 262ef463545SYitzhak Mandelbaum // in the statements of the CFG basic block. 2630e286b77SStanislav Gatev VisitDeclRefExpr(DE); 2640e286b77SStanislav Gatev VisitMemberExpr(ME); 2650e286b77SStanislav Gatev 266b244b6aeSMartin Braenne if (auto *Loc = Env.getStorageLocation(*ME)) 2670e286b77SStanislav Gatev Env.setStorageLocation(*B, *Loc); 268ef463545SYitzhak Mandelbaum } else if (auto *VD = B->getHoldingVar()) { 269bfbe1378SMartin Braenne // Holding vars are used to back the `BindingDecl`s of tuple-like 270bfbe1378SMartin Braenne // types. The holding var declarations appear after the 271bfbe1378SMartin Braenne // `DecompositionDecl`, so we have to explicitly process them here 272bfbe1378SMartin Braenne // to know their storage location. They will be processed a second 273bfbe1378SMartin Braenne // time when we visit their `VarDecl`s, so we have code that protects 274bfbe1378SMartin Braenne // against this above. 275bfbe1378SMartin Braenne ProcessVarDecl(*VD); 276bfbe1378SMartin Braenne auto *VDLoc = Env.getStorageLocation(*VD); 277bfbe1378SMartin Braenne assert(VDLoc != nullptr); 278bfbe1378SMartin Braenne Env.setStorageLocation(*B, *VDLoc); 279ef463545SYitzhak Mandelbaum } 2800e286b77SStanislav Gatev } 2810e286b77SStanislav Gatev } 2820e286b77SStanislav Gatev } 2830e286b77SStanislav Gatev 284e7481f6eSStanislav Gatev void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 28562b2a47aSEric Li const Expr *SubExpr = S->getSubExpr(); 286e7481f6eSStanislav Gatev assert(SubExpr != nullptr); 2877d941d6dSStanislav Gatev 2887d941d6dSStanislav Gatev switch (S->getCastKind()) { 289d002495bSYitzhak Mandelbaum case CK_IntegralToBoolean: { 290d002495bSYitzhak Mandelbaum // This cast creates a new, boolean value from the integral value. We 291d002495bSYitzhak Mandelbaum // model that with a fresh value in the environment, unless it's already a 292d002495bSYitzhak Mandelbaum // boolean. 293080ee850SMartin Braenne if (auto *SubExprVal = 294e95134b9SMartin Braenne dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr))) 295b244b6aeSMartin Braenne Env.setValue(*S, *SubExprVal); 296d002495bSYitzhak Mandelbaum else 297d002495bSYitzhak Mandelbaum // FIXME: If integer modeling is added, then update this code to create 298d002495bSYitzhak Mandelbaum // the boolean based on the integer model. 299b244b6aeSMartin Braenne Env.setValue(*S, Env.makeAtomicBoolValue()); 300d002495bSYitzhak Mandelbaum break; 301d002495bSYitzhak Mandelbaum } 302d002495bSYitzhak Mandelbaum 3037d941d6dSStanislav Gatev case CK_LValueToRValue: { 30439b9d4f1SYitzhak Mandelbaum // When an L-value is used as an R-value, it may result in sharing, so we 3056eb1b237SMartin Braenne // need to unpack any nested `Top`s. 30639b9d4f1SYitzhak Mandelbaum auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); 307e7481f6eSStanislav Gatev if (SubExprVal == nullptr) 3087d941d6dSStanislav Gatev break; 309e7481f6eSStanislav Gatev 310b244b6aeSMartin Braenne Env.setValue(*S, *SubExprVal); 3117d941d6dSStanislav Gatev break; 312e7481f6eSStanislav Gatev } 313d002495bSYitzhak Mandelbaum 314d002495bSYitzhak Mandelbaum case CK_IntegralCast: 315d002495bSYitzhak Mandelbaum // FIXME: This cast creates a new integral value from the 316d002495bSYitzhak Mandelbaum // subexpression. But, because we don't model integers, we don't 317d002495bSYitzhak Mandelbaum // distinguish between this new value and the underlying one. If integer 318d002495bSYitzhak Mandelbaum // modeling is added, then update this code to create a fresh location and 319d002495bSYitzhak Mandelbaum // value. 320092a530cSStanislav Gatev case CK_UncheckedDerivedToBase: 321092a530cSStanislav Gatev case CK_ConstructorConversion: 322092a530cSStanislav Gatev case CK_UserDefinedConversion: 323092a530cSStanislav Gatev // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 324092a530cSStanislav Gatev // CK_ConstructorConversion, and CK_UserDefinedConversion. 3257d941d6dSStanislav Gatev case CK_NoOp: { 3267d941d6dSStanislav Gatev // FIXME: Consider making `Environment::getStorageLocation` skip noop 32768baaca6SMartin Braenne // expressions (this and other similar expressions in the file) instead 32868baaca6SMartin Braenne // of assigning them storage locations. 32968baaca6SMartin Braenne propagateValueOrStorageLocation(*SubExpr, *S, Env); 3307d941d6dSStanislav Gatev break; 3317d941d6dSStanislav Gatev } 3321d7f9ce6SMartin Braenne case CK_NullToPointer: { 333b611376eSWei Yi Tee auto &NullPointerVal = 334b611376eSWei Yi Tee Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 335b244b6aeSMartin Braenne Env.setValue(*S, NullPointerVal); 336b611376eSWei Yi Tee break; 337b611376eSWei Yi Tee } 3381d7f9ce6SMartin Braenne case CK_NullToMemberPointer: 3391d7f9ce6SMartin Braenne // FIXME: Implement pointers to members. For now, don't associate a value 3401d7f9ce6SMartin Braenne // with this expression. 3411d7f9ce6SMartin Braenne break; 342ca01be54SMartin Braenne case CK_FunctionToPointerDecay: { 343b244b6aeSMartin Braenne StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr); 344d9e71733SMartin Braenne if (PointeeLoc == nullptr) 345d9e71733SMartin Braenne break; 346d9e71733SMartin Braenne 347b244b6aeSMartin Braenne Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 348d9e71733SMartin Braenne break; 349d9e71733SMartin Braenne } 350ca01be54SMartin Braenne case CK_BuiltinFnToFnPtr: 351ca01be54SMartin Braenne // Despite its name, the result type of `BuiltinFnToFnPtr` is a function, 352ca01be54SMartin Braenne // not a function pointer. In addition, builtin functions can only be 353ca01be54SMartin Braenne // called directly; it is not legal to take their address. We therefore 354ca01be54SMartin Braenne // don't need to create a value or storage location for them. 355ca01be54SMartin Braenne break; 3567d941d6dSStanislav Gatev default: 3577d941d6dSStanislav Gatev break; 3587d941d6dSStanislav Gatev } 359e7481f6eSStanislav Gatev } 360e7481f6eSStanislav Gatev 361e7481f6eSStanislav Gatev void VisitUnaryOperator(const UnaryOperator *S) { 36262b2a47aSEric Li const Expr *SubExpr = S->getSubExpr(); 36359e031ffSStanislav Gatev assert(SubExpr != nullptr); 36459e031ffSStanislav Gatev 36559e031ffSStanislav Gatev switch (S->getOpcode()) { 36659e031ffSStanislav Gatev case UO_Deref: { 3672ee396b0Smartinboehme const auto *SubExprVal = Env.get<PointerValue>(*SubExpr); 368e7481f6eSStanislav Gatev if (SubExprVal == nullptr) 36959e031ffSStanislav Gatev break; 370e7481f6eSStanislav Gatev 371b244b6aeSMartin Braenne Env.setStorageLocation(*S, SubExprVal->getPointeeLoc()); 37259e031ffSStanislav Gatev break; 373e7481f6eSStanislav Gatev } 37459e031ffSStanislav Gatev case UO_AddrOf: { 3751d7f9ce6SMartin Braenne // FIXME: Model pointers to members. 3761d7f9ce6SMartin Braenne if (S->getType()->isMemberPointerType()) 37759e031ffSStanislav Gatev break; 37859e031ffSStanislav Gatev 379b244b6aeSMartin Braenne if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr)) 380b244b6aeSMartin Braenne Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 38159e031ffSStanislav Gatev break; 38259e031ffSStanislav Gatev } 383dd4dde8dSStanislav Gatev case UO_LNot: { 384e95134b9SMartin Braenne auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)); 385dd4dde8dSStanislav Gatev if (SubExprVal == nullptr) 386a4808415SStanislav Gatev break; 387dd4dde8dSStanislav Gatev 388b244b6aeSMartin Braenne Env.setValue(*S, Env.makeNot(*SubExprVal)); 389a4808415SStanislav Gatev break; 390dd4dde8dSStanislav Gatev } 39168761a9eSmartinboehme case UO_PreInc: 39268761a9eSmartinboehme case UO_PreDec: 39385f47fddSmartinboehme // Propagate the storage location and clear out any value associated with 39485f47fddSmartinboehme // it (to represent the fact that the value has definitely changed). 39585f47fddSmartinboehme // To avoid generating unnecessary values, we leave it to the specific 39685f47fddSmartinboehme // analysis to create a new value if desired. 39768761a9eSmartinboehme propagateStorageLocation(*S->getSubExpr(), *S, Env); 39885f47fddSmartinboehme if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) 39985f47fddSmartinboehme Env.clearValue(*Loc); 40068761a9eSmartinboehme break; 40168761a9eSmartinboehme case UO_PostInc: 40268761a9eSmartinboehme case UO_PostDec: 40385f47fddSmartinboehme // Propagate the old value, then clear out any value associated with the 40485f47fddSmartinboehme // storage location (to represent the fact that the value has definitely 40585f47fddSmartinboehme // changed). See above for rationale. 40668761a9eSmartinboehme propagateValue(*S->getSubExpr(), *S, Env); 40785f47fddSmartinboehme if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) 40885f47fddSmartinboehme Env.clearValue(*Loc); 40968761a9eSmartinboehme break; 41059e031ffSStanislav Gatev default: 41159e031ffSStanislav Gatev break; 41259e031ffSStanislav Gatev } 413e7481f6eSStanislav Gatev } 414e7481f6eSStanislav Gatev 41599f7d55eSStanislav Gatev void VisitCXXThisExpr(const CXXThisExpr *S) { 41699f7d55eSStanislav Gatev auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 41733b598a8SEric Li if (ThisPointeeLoc == nullptr) 41833b598a8SEric Li // Unions are not supported yet, and will not have a location for the 41933b598a8SEric Li // `this` expression's pointee. 42033b598a8SEric Li return; 42199f7d55eSStanislav Gatev 422b244b6aeSMartin Braenne Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc)); 42399f7d55eSStanislav Gatev } 42499f7d55eSStanislav Gatev 4256ab900f8SMartin Braenne void VisitCXXNewExpr(const CXXNewExpr *S) { 4266ab900f8SMartin Braenne if (Value *Val = Env.createValue(S->getType())) 427b244b6aeSMartin Braenne Env.setValue(*S, *Val); 4286ab900f8SMartin Braenne } 4296ab900f8SMartin Braenne 4306ab900f8SMartin Braenne void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { 4316ab900f8SMartin Braenne // Empty method. 4326ab900f8SMartin Braenne // We consciously don't do anything on deletes. Diagnosing double deletes 4336ab900f8SMartin Braenne // (for example) should be done by a specific analysis, not by the 4346ab900f8SMartin Braenne // framework. 4356ab900f8SMartin Braenne } 4366ab900f8SMartin Braenne 4370eaecbbcSSam Estep void VisitReturnStmt(const ReturnStmt *S) { 4382cdb6b84SSamira Bazuzi if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts) 43938404df9SYitzhak Mandelbaum return; 44038404df9SYitzhak Mandelbaum 4410eaecbbcSSam Estep auto *Ret = S->getRetValue(); 4420eaecbbcSSam Estep if (Ret == nullptr) 4430eaecbbcSSam Estep return; 4440eaecbbcSSam Estep 44564413584SMartin Braenne if (Ret->isPRValue()) { 446e8fce958Smartinboehme if (Ret->getType()->isRecordType()) 447e8fce958Smartinboehme return; 448e8fce958Smartinboehme 449e95134b9SMartin Braenne auto *Val = Env.getValue(*Ret); 4500eaecbbcSSam Estep if (Val == nullptr) 4510eaecbbcSSam Estep return; 4520eaecbbcSSam Estep 45364413584SMartin Braenne // FIXME: Model NRVO. 45464413584SMartin Braenne Env.setReturnValue(Val); 45564413584SMartin Braenne } else { 456b244b6aeSMartin Braenne auto *Loc = Env.getStorageLocation(*Ret); 45764413584SMartin Braenne if (Loc == nullptr) 45838404df9SYitzhak Mandelbaum return; 45938404df9SYitzhak Mandelbaum 4600eaecbbcSSam Estep // FIXME: Model NRVO. 46164413584SMartin Braenne Env.setReturnStorageLocation(Loc); 46264413584SMartin Braenne } 4630eaecbbcSSam Estep } 4640eaecbbcSSam Estep 46599f7d55eSStanislav Gatev void VisitMemberExpr(const MemberExpr *S) { 46699f7d55eSStanislav Gatev ValueDecl *Member = S->getMemberDecl(); 46799f7d55eSStanislav Gatev assert(Member != nullptr); 46899f7d55eSStanislav Gatev 46999f7d55eSStanislav Gatev // FIXME: Consider assigning pointer values to function member expressions. 47099f7d55eSStanislav Gatev if (Member->isFunctionOrFunctionTemplate()) 47199f7d55eSStanislav Gatev return; 47299f7d55eSStanislav Gatev 4733ce03c42SYitzhak Mandelbaum // FIXME: if/when we add support for modeling enums, use that support here. 4743ce03c42SYitzhak Mandelbaum if (isa<EnumConstantDecl>(Member)) 4753ce03c42SYitzhak Mandelbaum return; 4763ce03c42SYitzhak Mandelbaum 47703dff121SStanislav Gatev if (auto *D = dyn_cast<VarDecl>(Member)) { 47803dff121SStanislav Gatev if (D->hasGlobalStorage()) { 4799940fac7SMartin Braenne auto *VarDeclLoc = Env.getStorageLocation(*D); 48003dff121SStanislav Gatev if (VarDeclLoc == nullptr) 48103dff121SStanislav Gatev return; 48203dff121SStanislav Gatev 483b244b6aeSMartin Braenne Env.setStorageLocation(*S, *VarDeclLoc); 48403dff121SStanislav Gatev return; 48503dff121SStanislav Gatev } 48603dff121SStanislav Gatev } 48703dff121SStanislav Gatev 4889ecdbe38SMartin Braenne RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); 48999f7d55eSStanislav Gatev if (BaseLoc == nullptr) 49099f7d55eSStanislav Gatev return; 49199f7d55eSStanislav Gatev 49244f98d01SMartin Braenne auto *MemberLoc = BaseLoc->getChild(*Member); 49344f98d01SMartin Braenne if (MemberLoc == nullptr) 49444f98d01SMartin Braenne return; 495b244b6aeSMartin Braenne Env.setStorageLocation(*S, *MemberLoc); 49699f7d55eSStanislav Gatev } 49799f7d55eSStanislav Gatev 49827d50499Smartinboehme void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { 49927d50499Smartinboehme const Expr *ArgExpr = S->getExpr(); 50027d50499Smartinboehme assert(ArgExpr != nullptr); 50127d50499Smartinboehme propagateValueOrStorageLocation(*ArgExpr, *S, Env); 50227d50499Smartinboehme 50327d50499Smartinboehme if (S->isPRValue() && S->getType()->isRecordType()) { 50471f1932bSmartinboehme auto &Loc = Env.getResultObjectLocation(*S); 50571f1932bSmartinboehme Env.initializeFieldsWithValues(Loc); 50627d50499Smartinboehme } 50727d50499Smartinboehme } 50827d50499Smartinboehme 509963f4005SStanislav Gatev void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 510963f4005SStanislav Gatev const Expr *InitExpr = S->getExpr(); 511963f4005SStanislav Gatev assert(InitExpr != nullptr); 51271f1932bSmartinboehme 51371f1932bSmartinboehme // If this is a prvalue of record type, the handler for `*InitExpr` (if one 51471f1932bSmartinboehme // exists) will initialize the result object; there is no value to propgate 51571f1932bSmartinboehme // here. 51671f1932bSmartinboehme if (S->getType()->isRecordType() && S->isPRValue()) 51771f1932bSmartinboehme return; 51871f1932bSmartinboehme 519d3632486SMartin Braenne propagateValueOrStorageLocation(*InitExpr, *S, Env); 520963f4005SStanislav Gatev } 521963f4005SStanislav Gatev 5227d941d6dSStanislav Gatev void VisitCXXConstructExpr(const CXXConstructExpr *S) { 5237d941d6dSStanislav Gatev const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 5247d941d6dSStanislav Gatev assert(ConstructorDecl != nullptr); 5257d941d6dSStanislav Gatev 52671f1932bSmartinboehme // `CXXConstructExpr` can have array type if default-initializing an array 52771f1932bSmartinboehme // of records. We don't handle this specifically beyond potentially inlining 52871f1932bSmartinboehme // the call. 52971f1932bSmartinboehme if (!S->getType()->isRecordType()) { 53071f1932bSmartinboehme transferInlineCall(S, ConstructorDecl); 53171f1932bSmartinboehme return; 53271f1932bSmartinboehme } 53371f1932bSmartinboehme 53471f1932bSmartinboehme RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 53571f1932bSmartinboehme 5367d941d6dSStanislav Gatev if (ConstructorDecl->isCopyOrMoveConstructor()) { 537e6e753d1SPaul Semel // It is permissible for a copy/move constructor to have additional 538e6e753d1SPaul Semel // parameters as long as they have default arguments defined for them. 539e6e753d1SPaul Semel assert(S->getNumArgs() != 0); 5407d941d6dSStanislav Gatev 5417d941d6dSStanislav Gatev const Expr *Arg = S->getArg(0); 5427d941d6dSStanislav Gatev assert(Arg != nullptr); 5437d941d6dSStanislav Gatev 5442ee396b0Smartinboehme auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg); 5457d941d6dSStanislav Gatev if (ArgLoc == nullptr) 5467d941d6dSStanislav Gatev return; 5477d941d6dSStanislav Gatev 54871f1932bSmartinboehme // Even if the copy/move constructor call is elidable, we choose to copy 54971f1932bSmartinboehme // the record in all cases (which isn't wrong, just potentially not 55071f1932bSmartinboehme // optimal). 55171f1932bSmartinboehme copyRecord(*ArgLoc, Loc, Env); 5527d941d6dSStanislav Gatev return; 5537d941d6dSStanislav Gatev } 5547d941d6dSStanislav Gatev 55571f1932bSmartinboehme Env.initializeFieldsWithValues(Loc, S->getType()); 556eb91fd5cSSam Estep 557eb91fd5cSSam Estep transferInlineCall(S, ConstructorDecl); 5587d941d6dSStanislav Gatev } 5597d941d6dSStanislav Gatev 5607d941d6dSStanislav Gatev void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 5617d941d6dSStanislav Gatev if (S->getOperator() == OO_Equal) { 5627d941d6dSStanislav Gatev assert(S->getNumArgs() == 2); 5637d941d6dSStanislav Gatev 5647d941d6dSStanislav Gatev const Expr *Arg0 = S->getArg(0); 5657d941d6dSStanislav Gatev assert(Arg0 != nullptr); 5667d941d6dSStanislav Gatev 5677d941d6dSStanislav Gatev const Expr *Arg1 = S->getArg(1); 5687d941d6dSStanislav Gatev assert(Arg1 != nullptr); 5697d941d6dSStanislav Gatev 5707d941d6dSStanislav Gatev // Evaluate only copy and move assignment operators. 5716b85cc18SMartin Braenne const auto *Method = 5726b85cc18SMartin Braenne dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee()); 5736b85cc18SMartin Braenne if (!Method) 5746b85cc18SMartin Braenne return; 5756b85cc18SMartin Braenne if (!Method->isCopyAssignmentOperator() && 5766b85cc18SMartin Braenne !Method->isMoveAssignmentOperator()) 5777d941d6dSStanislav Gatev return; 5787d941d6dSStanislav Gatev 5796b573f46Smartinboehme RecordStorageLocation *LocSrc = nullptr; 5806b573f46Smartinboehme if (Arg1->isPRValue()) { 581e8fce958Smartinboehme LocSrc = &Env.getResultObjectLocation(*Arg1); 5826b573f46Smartinboehme } else { 5832ee396b0Smartinboehme LocSrc = Env.get<RecordStorageLocation>(*Arg1); 5846b573f46Smartinboehme } 5852ee396b0Smartinboehme auto *LocDst = Env.get<RecordStorageLocation>(*Arg0); 5867d941d6dSStanislav Gatev 587a93e76ddSmartinboehme if (LocSrc == nullptr || LocDst == nullptr) 588a93e76ddSmartinboehme return; 589a93e76ddSmartinboehme 59044f98d01SMartin Braenne copyRecord(*LocSrc, *LocDst, Env); 591a8fb0dccSPaul Semel 5920348e718Smartinboehme // The assignment operator can have an arbitrary return type. We model the 5930348e718Smartinboehme // return value only if the return type is the same as or a base class of 5940348e718Smartinboehme // the destination type. 5950348e718Smartinboehme if (S->getType().getCanonicalType().getUnqualifiedType() != 5960348e718Smartinboehme LocDst->getType().getCanonicalType().getUnqualifiedType()) { 5970348e718Smartinboehme auto ReturnDecl = S->getType()->getAsCXXRecordDecl(); 5980348e718Smartinboehme auto DstDecl = LocDst->getType()->getAsCXXRecordDecl(); 5990348e718Smartinboehme if (ReturnDecl == nullptr || DstDecl == nullptr) 6000348e718Smartinboehme return; 6010348e718Smartinboehme if (!DstDecl->isDerivedFrom(ReturnDecl)) 6020348e718Smartinboehme return; 603a8fb0dccSPaul Semel } 604a8fb0dccSPaul Semel 6050348e718Smartinboehme if (S->isGLValue()) 6060348e718Smartinboehme Env.setStorageLocation(*S, *LocDst); 6070348e718Smartinboehme else 6080348e718Smartinboehme copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env); 6090348e718Smartinboehme 6105c2da289SPaul Semel return; 61144f98d01SMartin Braenne } 6125c2da289SPaul Semel 61371f1932bSmartinboehme // `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to 61471f1932bSmartinboehme // initialize the prvalue's fields with values. 6155c2da289SPaul Semel VisitCallExpr(S); 6167d941d6dSStanislav Gatev } 6177d941d6dSStanislav Gatev 618a446c9bfSmartinboehme void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) { 619a446c9bfSmartinboehme propagateValue(*RBO->getSemanticForm(), *RBO, Env); 620a446c9bfSmartinboehme } 621a446c9bfSmartinboehme 6227d941d6dSStanislav Gatev void VisitCallExpr(const CallExpr *S) { 623506ec85bSYitzhak Mandelbaum // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 624506ec85bSYitzhak Mandelbaum // others (like trap, debugtrap, and unreachable) are handled by CFG 625506ec85bSYitzhak Mandelbaum // construction. 6267d941d6dSStanislav Gatev if (S->isCallToStdMove()) { 6277d941d6dSStanislav Gatev assert(S->getNumArgs() == 1); 6287d941d6dSStanislav Gatev 6297d941d6dSStanislav Gatev const Expr *Arg = S->getArg(0); 6307d941d6dSStanislav Gatev assert(Arg != nullptr); 6317d941d6dSStanislav Gatev 632b244b6aeSMartin Braenne auto *ArgLoc = Env.getStorageLocation(*Arg); 6337d941d6dSStanislav Gatev if (ArgLoc == nullptr) 6347d941d6dSStanislav Gatev return; 6357d941d6dSStanislav Gatev 636b244b6aeSMartin Braenne Env.setStorageLocation(*S, *ArgLoc); 637506ec85bSYitzhak Mandelbaum } else if (S->getDirectCallee() != nullptr && 638506ec85bSYitzhak Mandelbaum S->getDirectCallee()->getBuiltinID() == 639506ec85bSYitzhak Mandelbaum Builtin::BI__builtin_expect) { 640506ec85bSYitzhak Mandelbaum assert(S->getNumArgs() > 0); 641506ec85bSYitzhak Mandelbaum assert(S->getArg(0) != nullptr); 642f76f6674SMartin Braenne auto *ArgVal = Env.getValue(*S->getArg(0)); 643f76f6674SMartin Braenne if (ArgVal == nullptr) 644506ec85bSYitzhak Mandelbaum return; 645b244b6aeSMartin Braenne Env.setValue(*S, *ArgVal); 646300fbf56SSam Estep } else if (const FunctionDecl *F = S->getDirectCallee()) { 647eb91fd5cSSam Estep transferInlineCall(S, F); 648ca103434Smartinboehme 64971f1932bSmartinboehme // If this call produces a prvalue of record type, initialize its fields 65071f1932bSmartinboehme // with values. 651e8fce958Smartinboehme if (S->getType()->isRecordType() && S->isPRValue()) { 65271f1932bSmartinboehme RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 65371f1932bSmartinboehme Env.initializeFieldsWithValues(Loc); 65471f1932bSmartinboehme } 6557d941d6dSStanislav Gatev } 6567d941d6dSStanislav Gatev } 6577d941d6dSStanislav Gatev 6587d941d6dSStanislav Gatev void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 6597d941d6dSStanislav Gatev const Expr *SubExpr = S->getSubExpr(); 6607d941d6dSStanislav Gatev assert(SubExpr != nullptr); 6617d941d6dSStanislav Gatev 66244f98d01SMartin Braenne StorageLocation &Loc = Env.createStorageLocation(*S); 663b244b6aeSMartin Braenne Env.setStorageLocation(*S, Loc); 664e8fce958Smartinboehme 665e8fce958Smartinboehme if (SubExpr->getType()->isRecordType()) 666e8fce958Smartinboehme // Nothing else left to do -- we initialized the record when transferring 667e8fce958Smartinboehme // `SubExpr`. 668e8fce958Smartinboehme return; 669e8fce958Smartinboehme 670e8fce958Smartinboehme if (Value *SubExprVal = Env.getValue(*SubExpr)) 671e8fce958Smartinboehme Env.setValue(Loc, *SubExprVal); 6727d941d6dSStanislav Gatev } 6737d941d6dSStanislav Gatev 67437e6496cSStanislav Gatev void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 67537e6496cSStanislav Gatev const Expr *SubExpr = S->getSubExpr(); 67637e6496cSStanislav Gatev assert(SubExpr != nullptr); 67737e6496cSStanislav Gatev 6785a16665eSMartin Braenne propagateValue(*SubExpr, *S, Env); 67937e6496cSStanislav Gatev } 68037e6496cSStanislav Gatev 68137e6496cSStanislav Gatev void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 68237e6496cSStanislav Gatev if (S->getCastKind() == CK_NoOp) { 68337e6496cSStanislav Gatev const Expr *SubExpr = S->getSubExpr(); 68437e6496cSStanislav Gatev assert(SubExpr != nullptr); 68537e6496cSStanislav Gatev 6865a16665eSMartin Braenne propagateValueOrStorageLocation(*SubExpr, *S, Env); 68737e6496cSStanislav Gatev } 68837e6496cSStanislav Gatev } 68937e6496cSStanislav Gatev 6908e53ae3dSStanislav Gatev void VisitConditionalOperator(const ConditionalOperator *S) { 6919ba6961cSmartinboehme const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr()); 6929ba6961cSmartinboehme const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr()); 6939ba6961cSmartinboehme 6949ba6961cSmartinboehme if (TrueEnv == nullptr || FalseEnv == nullptr) { 6959ba6961cSmartinboehme // If the true or false branch is dead, we may not have an environment for 6969ba6961cSmartinboehme // it. We could handle this specifically by forwarding the value or 6979ba6961cSmartinboehme // location of the live branch, but this case is rare enough that this 6989ba6961cSmartinboehme // probably isn't worth the additional complexity. 6999ba6961cSmartinboehme return; 7009ba6961cSmartinboehme } 7019ba6961cSmartinboehme 7029ba6961cSmartinboehme if (S->isGLValue()) { 7039ba6961cSmartinboehme StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr()); 7049ba6961cSmartinboehme StorageLocation *FalseLoc = 7059ba6961cSmartinboehme FalseEnv->getStorageLocation(*S->getFalseExpr()); 7069ba6961cSmartinboehme if (TrueLoc == FalseLoc && TrueLoc != nullptr) 7079ba6961cSmartinboehme Env.setStorageLocation(*S, *TrueLoc); 7089ba6961cSmartinboehme } else if (!S->getType()->isRecordType()) { 7099ba6961cSmartinboehme // The conditional operator can evaluate to either of the values of the 7109ba6961cSmartinboehme // two branches. To model this, join these two values together to yield 7119ba6961cSmartinboehme // the result of the conditional operator. 7129ba6961cSmartinboehme // Note: Most joins happen in `computeBlockInputState()`, but this case is 7139ba6961cSmartinboehme // different: 7149ba6961cSmartinboehme // - `computeBlockInputState()` (which in turn calls `Environment::join()` 7159ba6961cSmartinboehme // joins values associated with the _same_ expression or storage 7169ba6961cSmartinboehme // location, then associates the joined value with that expression or 7179ba6961cSmartinboehme // storage location. This join has nothing to do with transfer -- 7189ba6961cSmartinboehme // instead, it joins together the results of performing transfer on two 7199ba6961cSmartinboehme // different blocks. 7209ba6961cSmartinboehme // - Here, we join values associated with _different_ expressions (the 7219ba6961cSmartinboehme // true and false branch), then associate the joined value with a third 7229ba6961cSmartinboehme // expression (the conditional operator itself). This join is what it 7239ba6961cSmartinboehme // means to perform transfer on the conditional operator. 7249ba6961cSmartinboehme if (Value *Val = Environment::joinValues( 7259ba6961cSmartinboehme S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv, 7269ba6961cSmartinboehme FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model)) 727b244b6aeSMartin Braenne Env.setValue(*S, *Val); 7285a16665eSMartin Braenne } 72971f1932bSmartinboehme } 7308e53ae3dSStanislav Gatev 73164ba462bSStanislav Gatev void VisitInitListExpr(const InitListExpr *S) { 73264ba462bSStanislav Gatev QualType Type = S->getType(); 73364ba462bSStanislav Gatev 734128780b0Smartinboehme if (!Type->isRecordType()) { 7352730a5c6SSamira Bazuzi // Until array initialization is implemented, we skip arrays and don't 7362730a5c6SSamira Bazuzi // need to care about cases where `getNumInits() > 1`. 7372730a5c6SSamira Bazuzi if (!Type->isArrayType() && S->getNumInits() == 1) 738ba279934SPaul Semel propagateValueOrStorageLocation(*S->getInit(0), *S, Env); 73964ba462bSStanislav Gatev return; 74044f98d01SMartin Braenne } 74164ba462bSStanislav Gatev 742e8fce958Smartinboehme // If the initializer list is transparent, there's nothing to do. 743e8fce958Smartinboehme if (S->isSemanticForm() && S->isTransparent()) 744bc378934SPaul Semel return; 745bc378934SPaul Semel 74671f1932bSmartinboehme RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 74771f1932bSmartinboehme 74871f1932bSmartinboehme // Initialization of base classes and fields of record type happens when we 74971f1932bSmartinboehme // visit the nested `CXXConstructExpr` or `InitListExpr` for that base class 75071f1932bSmartinboehme // or field. We therefore only need to deal with fields of non-record type 75171f1932bSmartinboehme // here. 75271f1932bSmartinboehme 7538d77d362Smartinboehme RecordInitListHelper InitListHelper(S); 75444f98d01SMartin Braenne 7557549b458Smartinboehme for (auto [Field, Init] : InitListHelper.field_inits()) { 75671f1932bSmartinboehme if (Field->getType()->isRecordType()) 75771f1932bSmartinboehme continue; 75871f1932bSmartinboehme if (Field->getType()->isReferenceType()) { 75971f1932bSmartinboehme assert(Field->getType().getCanonicalType()->getPointeeType() == 76071f1932bSmartinboehme Init->getType().getCanonicalType()); 76171f1932bSmartinboehme Loc.setChild(*Field, &Env.createObject(Field->getType(), Init)); 76271f1932bSmartinboehme continue; 76371f1932bSmartinboehme } 76471f1932bSmartinboehme assert(Field->getType().getCanonicalType().getUnqualifiedType() == 76571f1932bSmartinboehme Init->getType().getCanonicalType().getUnqualifiedType()); 76671f1932bSmartinboehme StorageLocation *FieldLoc = Loc.getChild(*Field); 76771f1932bSmartinboehme // Locations for non-reference fields must always be non-null. 76871f1932bSmartinboehme assert(FieldLoc != nullptr); 76971f1932bSmartinboehme Value *Val = Env.getValue(*Init); 77071f1932bSmartinboehme if (Val == nullptr && isa<ImplicitValueInitExpr>(Init) && 77171f1932bSmartinboehme Init->getType()->isPointerType()) 77271f1932bSmartinboehme Val = 77371f1932bSmartinboehme &Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType()); 77471f1932bSmartinboehme if (Val == nullptr) 77571f1932bSmartinboehme Val = Env.createValue(Field->getType()); 77671f1932bSmartinboehme if (Val != nullptr) 77771f1932bSmartinboehme Env.setValue(*FieldLoc, *Val); 7787549b458Smartinboehme } 7797549b458Smartinboehme 78071f1932bSmartinboehme for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { 78171f1932bSmartinboehme QualType FieldType = FieldLoc->getType(); 78271f1932bSmartinboehme if (FieldType->isRecordType()) { 78371f1932bSmartinboehme Env.initializeFieldsWithValues(*cast<RecordStorageLocation>(FieldLoc)); 78471f1932bSmartinboehme } else { 78571f1932bSmartinboehme if (Value *Val = Env.createValue(FieldType)) 78671f1932bSmartinboehme Env.setValue(*FieldLoc, *Val); 787128780b0Smartinboehme } 788128780b0Smartinboehme } 789128780b0Smartinboehme 79064ba462bSStanislav Gatev // FIXME: Implement array initialization. 79164ba462bSStanislav Gatev } 79264ba462bSStanislav Gatev 79375c22b38SStanislav Gatev void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 794b244b6aeSMartin Braenne Env.setValue(*S, Env.getBoolLiteralValue(S->getValue())); 79575c22b38SStanislav Gatev } 796af7bc39bSStanislav Gatev 797762cb1d3SMartin Braenne void VisitIntegerLiteral(const IntegerLiteral *S) { 798b244b6aeSMartin Braenne Env.setValue(*S, Env.getIntLiteralValue(S->getValue())); 799762cb1d3SMartin Braenne } 800762cb1d3SMartin Braenne 80145643cfcSEric Li void VisitParenExpr(const ParenExpr *S) { 80245643cfcSEric Li // The CFG does not contain `ParenExpr` as top-level statements in basic 80345643cfcSEric Li // blocks, however manual traversal to sub-expressions may encounter them. 80445643cfcSEric Li // Redirect to the sub-expression. 80545643cfcSEric Li auto *SubExpr = S->getSubExpr(); 80645643cfcSEric Li assert(SubExpr != nullptr); 80745643cfcSEric Li Visit(SubExpr); 80845643cfcSEric Li } 80945643cfcSEric Li 81045643cfcSEric Li void VisitExprWithCleanups(const ExprWithCleanups *S) { 81145643cfcSEric Li // The CFG does not contain `ExprWithCleanups` as top-level statements in 81245643cfcSEric Li // basic blocks, however manual traversal to sub-expressions may encounter 81345643cfcSEric Li // them. Redirect to the sub-expression. 81445643cfcSEric Li auto *SubExpr = S->getSubExpr(); 81545643cfcSEric Li assert(SubExpr != nullptr); 81645643cfcSEric Li Visit(SubExpr); 81745643cfcSEric Li } 81845643cfcSEric Li 819af7bc39bSStanislav Gatev private: 8207f6c3a90SMartin Braenne /// Returns the value for the sub-expression `SubExpr` of a logic operator. 8217f6c3a90SMartin Braenne BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 822cf63e9d4SStanislav Gatev // `SubExpr` and its parent logic operator might be part of different basic 823cf63e9d4SStanislav Gatev // blocks. We try to access the value that is assigned to `SubExpr` in the 824cf63e9d4SStanislav Gatev // corresponding environment. 8257f6c3a90SMartin Braenne if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) 8265a16665eSMartin Braenne if (auto *Val = 827e95134b9SMartin Braenne dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr))) 8287f6c3a90SMartin Braenne return *Val; 829cf63e9d4SStanislav Gatev 8307f6c3a90SMartin Braenne // The sub-expression may lie within a basic block that isn't reachable, 8317f6c3a90SMartin Braenne // even if we need it to evaluate the current (reachable) expression 8327f6c3a90SMartin Braenne // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` 8337f6c3a90SMartin Braenne // within the current environment and then try to get the value that gets 8347f6c3a90SMartin Braenne // assigned to it. 835e95134b9SMartin Braenne if (Env.getValue(SubExpr) == nullptr) 836cf63e9d4SStanislav Gatev Visit(&SubExpr); 837e95134b9SMartin Braenne if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr))) 8387f6c3a90SMartin Braenne return *Val; 839cf63e9d4SStanislav Gatev 840cf63e9d4SStanislav Gatev // If the value of `SubExpr` is still unknown, we create a fresh symbolic 841cf63e9d4SStanislav Gatev // boolean value for it. 8427f6c3a90SMartin Braenne return Env.makeAtomicBoolValue(); 843cf63e9d4SStanislav Gatev } 844cf63e9d4SStanislav Gatev 845eb91fd5cSSam Estep // If context sensitivity is enabled, try to analyze the body of the callee 846eb91fd5cSSam Estep // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 847eb91fd5cSSam Estep template <typename E> 848eb91fd5cSSam Estep void transferInlineCall(const E *S, const FunctionDecl *F) { 8492cdb6b84SSamira Bazuzi const auto &Options = Env.getDataflowAnalysisContext().getOptions(); 8502efc8f8dSSam Estep if (!(Options.ContextSensitiveOpts && 8512efc8f8dSSam Estep Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 852eb91fd5cSSam Estep return; 853eb91fd5cSSam Estep 85459ff3adcSmartinboehme const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F); 85559ff3adcSmartinboehme if (!ACFG) 856eb91fd5cSSam Estep return; 857eb91fd5cSSam Estep 858eb91fd5cSSam Estep // FIXME: We don't support context-sensitive analysis of recursion, so 859eb91fd5cSSam Estep // we should return early here if `F` is the same as the `FunctionDecl` 860eb91fd5cSSam Estep // holding `S` itself. 861eb91fd5cSSam Estep 86259ff3adcSmartinboehme auto ExitBlock = ACFG->getCFG().getExit().getBlockID(); 863eb91fd5cSSam Estep 864eb91fd5cSSam Estep auto CalleeEnv = Env.pushCall(S); 865eb91fd5cSSam Estep 866eb91fd5cSSam Estep // FIXME: Use the same analysis as the caller for the callee. Note, 867eb91fd5cSSam Estep // though, that doing so would require support for changing the analysis's 868eb91fd5cSSam Estep // ASTContext. 86959ff3adcSmartinboehme auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(), 8702efc8f8dSSam Estep DataflowAnalysisOptions{Options}); 871eb91fd5cSSam Estep 872eb91fd5cSSam Estep auto BlockToOutputState = 87359ff3adcSmartinboehme dataflow::runDataflowAnalysis(*ACFG, Analysis, CalleeEnv); 874eb91fd5cSSam Estep assert(BlockToOutputState); 875eb91fd5cSSam Estep assert(ExitBlock < BlockToOutputState->size()); 876eb91fd5cSSam Estep 877c2bb6807SSam McCall auto &ExitState = (*BlockToOutputState)[ExitBlock]; 878eb91fd5cSSam Estep assert(ExitState); 879eb91fd5cSSam Estep 88064413584SMartin Braenne Env.popCall(S, ExitState->Env); 881eb91fd5cSSam Estep } 882eb91fd5cSSam Estep 883dd4dde8dSStanislav Gatev const StmtToEnvMap &StmtToEnv; 884af7bc39bSStanislav Gatev Environment &Env; 8859ba6961cSmartinboehme Environment::ValueModel &Model; 886af7bc39bSStanislav Gatev }; 887af7bc39bSStanislav Gatev 8881bc2d43eSMartin Braenne } // namespace 8891bc2d43eSMartin Braenne 8909ba6961cSmartinboehme void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, 8919ba6961cSmartinboehme Environment::ValueModel &Model) { 8929ba6961cSmartinboehme TransferVisitor(StmtToEnv, Env, Model).Visit(&S); 893af7bc39bSStanislav Gatev } 894af7bc39bSStanislav Gatev 895af7bc39bSStanislav Gatev } // namespace dataflow 896af7bc39bSStanislav Gatev } // namespace clang 897