104eeddc0SDimitry Andric //===-- Transfer.cpp --------------------------------------------*- C++ -*-===// 204eeddc0SDimitry Andric // 304eeddc0SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 404eeddc0SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 504eeddc0SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 604eeddc0SDimitry Andric // 704eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 804eeddc0SDimitry Andric // 904eeddc0SDimitry Andric // This file defines transfer functions that evaluate program statements and 1004eeddc0SDimitry Andric // update an environment accordingly. 1104eeddc0SDimitry Andric // 1204eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1304eeddc0SDimitry Andric 1404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Transfer.h" 1504eeddc0SDimitry Andric #include "clang/AST/Decl.h" 1604eeddc0SDimitry Andric #include "clang/AST/DeclBase.h" 1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h" 1804eeddc0SDimitry Andric #include "clang/AST/Expr.h" 1904eeddc0SDimitry Andric #include "clang/AST/ExprCXX.h" 2004eeddc0SDimitry Andric #include "clang/AST/OperationKinds.h" 2104eeddc0SDimitry Andric #include "clang/AST/Stmt.h" 2204eeddc0SDimitry Andric #include "clang/AST/StmtVisitor.h" 23*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/ASTOps.h" 24*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/AdornedCFG.h" 25*0fca6ea1SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" 2604eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 27972a253aSDimitry Andric #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" 2806c3fb27SDimitry Andric #include "clang/Analysis/FlowSensitive/RecordOps.h" 2981ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 3081ad6265SDimitry Andric #include "clang/Basic/Builtins.h" 3104eeddc0SDimitry Andric #include "clang/Basic/OperatorKinds.h" 3204eeddc0SDimitry Andric #include "llvm/Support/Casting.h" 335f757f3fSDimitry Andric #include "llvm/Support/Debug.h" 345f757f3fSDimitry Andric #include <assert.h> 3504eeddc0SDimitry Andric #include <cassert> 365f757f3fSDimitry Andric 375f757f3fSDimitry Andric #define DEBUG_TYPE "dataflow" 3804eeddc0SDimitry Andric 3904eeddc0SDimitry Andric namespace clang { 4004eeddc0SDimitry Andric namespace dataflow { 4104eeddc0SDimitry Andric 4206c3fb27SDimitry Andric const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { 43*0fca6ea1SDimitry Andric auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); 44*0fca6ea1SDimitry Andric if (BlockIt == ACFG.getStmtToBlock().end()) { 45*0fca6ea1SDimitry Andric assert(false); 46*0fca6ea1SDimitry Andric // Return null to avoid dereferencing the end iterator in non-assert builds. 47*0fca6ea1SDimitry Andric return nullptr; 48*0fca6ea1SDimitry Andric } 49*0fca6ea1SDimitry Andric if (!ACFG.isBlockReachable(*BlockIt->getSecond())) 5006c3fb27SDimitry Andric return nullptr; 517a6dacacSDimitry Andric if (BlockIt->getSecond()->getBlockID() == CurBlockID) 527a6dacacSDimitry Andric return &CurState.Env; 5306c3fb27SDimitry Andric const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; 545f757f3fSDimitry Andric if (!(State)) 555f757f3fSDimitry Andric return nullptr; 5606c3fb27SDimitry Andric return &State->Env; 5704eeddc0SDimitry Andric } 5804eeddc0SDimitry Andric 5906c3fb27SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, 6006c3fb27SDimitry Andric Environment &Env) { 615f757f3fSDimitry Andric Value *LHSValue = Env.getValue(LHS); 625f757f3fSDimitry Andric Value *RHSValue = Env.getValue(RHS); 63bdd1243dSDimitry Andric 6406c3fb27SDimitry Andric if (LHSValue == RHSValue) 6506c3fb27SDimitry Andric return Env.getBoolLiteralValue(true); 66bdd1243dSDimitry Andric 6706c3fb27SDimitry Andric if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue)) 6806c3fb27SDimitry Andric if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue)) 6906c3fb27SDimitry Andric return Env.makeIff(*LHSBool, *RHSBool); 70bdd1243dSDimitry Andric 71*0fca6ea1SDimitry Andric if (auto *LHSPtr = dyn_cast_or_null<PointerValue>(LHSValue)) 72*0fca6ea1SDimitry Andric if (auto *RHSPtr = dyn_cast_or_null<PointerValue>(RHSValue)) 73*0fca6ea1SDimitry Andric // If the storage locations are the same, the pointers definitely compare 74*0fca6ea1SDimitry Andric // the same. If the storage locations are different, they may still alias, 75*0fca6ea1SDimitry Andric // so we fall through to the case below that returns an atom. 76*0fca6ea1SDimitry Andric if (&LHSPtr->getPointeeLoc() == &RHSPtr->getPointeeLoc()) 77*0fca6ea1SDimitry Andric return Env.getBoolLiteralValue(true); 78*0fca6ea1SDimitry Andric 7906c3fb27SDimitry Andric return Env.makeAtomicBoolValue(); 80bdd1243dSDimitry Andric } 81bdd1243dSDimitry Andric 82bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) { 8306c3fb27SDimitry Andric if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) { 8406c3fb27SDimitry Andric auto &A = Env.getDataflowAnalysisContext().arena(); 8506c3fb27SDimitry Andric return A.makeBoolValue(A.makeAtomRef(Top->getAtom())); 86bdd1243dSDimitry Andric } 8706c3fb27SDimitry Andric return V; 88bdd1243dSDimitry Andric } 89bdd1243dSDimitry Andric 90bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new 9106c3fb27SDimitry Andric // value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion, 9206c3fb27SDimitry Andric // by skipping past the reference. 93bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) { 945f757f3fSDimitry Andric auto *Loc = Env.getStorageLocation(E); 95bdd1243dSDimitry Andric if (Loc == nullptr) 96bdd1243dSDimitry Andric return nullptr; 97bdd1243dSDimitry Andric auto *Val = Env.getValue(*Loc); 98bdd1243dSDimitry Andric 99bdd1243dSDimitry Andric auto *B = dyn_cast_or_null<BoolValue>(Val); 100bdd1243dSDimitry Andric if (B == nullptr) 101bdd1243dSDimitry Andric return Val; 102bdd1243dSDimitry Andric 103bdd1243dSDimitry Andric auto &UnpackedVal = unpackValue(*B, Env); 104bdd1243dSDimitry Andric if (&UnpackedVal == Val) 105bdd1243dSDimitry Andric return Val; 106bdd1243dSDimitry Andric Env.setValue(*Loc, UnpackedVal); 107bdd1243dSDimitry Andric return &UnpackedVal; 108bdd1243dSDimitry Andric } 109bdd1243dSDimitry Andric 11006c3fb27SDimitry Andric static void propagateValue(const Expr &From, const Expr &To, Environment &Env) { 111*0fca6ea1SDimitry Andric if (From.getType()->isRecordType()) 112*0fca6ea1SDimitry Andric return; 1135f757f3fSDimitry Andric if (auto *Val = Env.getValue(From)) 1145f757f3fSDimitry Andric Env.setValue(To, *Val); 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric 11706c3fb27SDimitry Andric static void propagateStorageLocation(const Expr &From, const Expr &To, 11806c3fb27SDimitry Andric Environment &Env) { 1195f757f3fSDimitry Andric if (auto *Loc = Env.getStorageLocation(From)) 1205f757f3fSDimitry Andric Env.setStorageLocation(To, *Loc); 12106c3fb27SDimitry Andric } 12206c3fb27SDimitry Andric 12306c3fb27SDimitry Andric // Propagates the value or storage location of `From` to `To` in cases where 12406c3fb27SDimitry Andric // `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff 12506c3fb27SDimitry Andric // `From` is a glvalue. 12606c3fb27SDimitry Andric static void propagateValueOrStorageLocation(const Expr &From, const Expr &To, 12706c3fb27SDimitry Andric Environment &Env) { 12806c3fb27SDimitry Andric assert(From.isGLValue() == To.isGLValue()); 12906c3fb27SDimitry Andric if (From.isGLValue()) 13006c3fb27SDimitry Andric propagateStorageLocation(From, To, Env); 13106c3fb27SDimitry Andric else 13206c3fb27SDimitry Andric propagateValue(From, To, Env); 13306c3fb27SDimitry Andric } 13406c3fb27SDimitry Andric 13506c3fb27SDimitry Andric namespace { 13606c3fb27SDimitry Andric 13704eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { 13804eeddc0SDimitry Andric public: 139*0fca6ea1SDimitry Andric TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env, 140*0fca6ea1SDimitry Andric Environment::ValueModel &Model) 141*0fca6ea1SDimitry Andric : StmtToEnv(StmtToEnv), Env(Env), Model(Model) {} 14204eeddc0SDimitry Andric 14304eeddc0SDimitry Andric void VisitBinaryOperator(const BinaryOperator *S) { 14481ad6265SDimitry Andric const Expr *LHS = S->getLHS(); 14504eeddc0SDimitry Andric assert(LHS != nullptr); 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric const Expr *RHS = S->getRHS(); 14881ad6265SDimitry Andric assert(RHS != nullptr); 14981ad6265SDimitry Andric 150*0fca6ea1SDimitry Andric // Do compound assignments up-front, as there are so many of them and we 151*0fca6ea1SDimitry Andric // don't want to list all of them in the switch statement below. 152*0fca6ea1SDimitry Andric // To avoid generating unnecessary values, we don't create a new value but 153*0fca6ea1SDimitry Andric // instead leave it to the specific analysis to do this if desired. 154*0fca6ea1SDimitry Andric if (S->isCompoundAssignmentOp()) 155*0fca6ea1SDimitry Andric propagateStorageLocation(*S->getLHS(), *S, Env); 156*0fca6ea1SDimitry Andric 15781ad6265SDimitry Andric switch (S->getOpcode()) { 15881ad6265SDimitry Andric case BO_Assign: { 1595f757f3fSDimitry Andric auto *LHSLoc = Env.getStorageLocation(*LHS); 16004eeddc0SDimitry Andric if (LHSLoc == nullptr) 16181ad6265SDimitry Andric break; 16204eeddc0SDimitry Andric 1635f757f3fSDimitry Andric auto *RHSVal = Env.getValue(*RHS); 16404eeddc0SDimitry Andric if (RHSVal == nullptr) 16581ad6265SDimitry Andric break; 16604eeddc0SDimitry Andric 16704eeddc0SDimitry Andric // Assign a value to the storage location of the left-hand side. 16804eeddc0SDimitry Andric Env.setValue(*LHSLoc, *RHSVal); 16904eeddc0SDimitry Andric 17004eeddc0SDimitry Andric // Assign a storage location for the whole expression. 17104eeddc0SDimitry Andric Env.setStorageLocation(*S, *LHSLoc); 17281ad6265SDimitry Andric break; 17304eeddc0SDimitry Andric } 17481ad6265SDimitry Andric case BO_LAnd: 17581ad6265SDimitry Andric case BO_LOr: { 17681ad6265SDimitry Andric BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS); 17781ad6265SDimitry Andric BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS); 17881ad6265SDimitry Andric 17981ad6265SDimitry Andric if (S->getOpcode() == BO_LAnd) 1805f757f3fSDimitry Andric Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal)); 18181ad6265SDimitry Andric else 1825f757f3fSDimitry Andric Env.setValue(*S, Env.makeOr(LHSVal, RHSVal)); 18381ad6265SDimitry Andric break; 18481ad6265SDimitry Andric } 18581ad6265SDimitry Andric case BO_NE: 18681ad6265SDimitry Andric case BO_EQ: { 18781ad6265SDimitry Andric auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env); 1885f757f3fSDimitry Andric Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue 18981ad6265SDimitry Andric : Env.makeNot(LHSEqRHSValue)); 19081ad6265SDimitry Andric break; 19181ad6265SDimitry Andric } 19281ad6265SDimitry Andric case BO_Comma: { 19306c3fb27SDimitry Andric propagateValueOrStorageLocation(*RHS, *S, Env); 19481ad6265SDimitry Andric break; 19581ad6265SDimitry Andric } 19681ad6265SDimitry Andric default: 19781ad6265SDimitry Andric break; 19881ad6265SDimitry Andric } 19904eeddc0SDimitry Andric } 20004eeddc0SDimitry Andric 20104eeddc0SDimitry Andric void VisitDeclRefExpr(const DeclRefExpr *S) { 202bdd1243dSDimitry Andric const ValueDecl *VD = S->getDecl(); 203bdd1243dSDimitry Andric assert(VD != nullptr); 20406c3fb27SDimitry Andric 2055f757f3fSDimitry Andric // Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a 2065f757f3fSDimitry Andric // `StorageLocation`, and there's also no sensible `Value` that we can 2075f757f3fSDimitry Andric // assign to them. Examples: 2085f757f3fSDimitry Andric // - Non-static member variables 2095f757f3fSDimitry Andric // - Non static member functions 2105f757f3fSDimitry Andric // Note: Member operators are an exception to this, but apparently only 2115f757f3fSDimitry Andric // if the `DeclRefExpr` is used within the callee of a 2125f757f3fSDimitry Andric // `CXXOperatorCallExpr`. In other cases, for example when applying the 2135f757f3fSDimitry Andric // address-of operator, the `DeclRefExpr` is a prvalue. 2145f757f3fSDimitry Andric if (!S->isGLValue()) 21506c3fb27SDimitry Andric return; 21606c3fb27SDimitry Andric 21706c3fb27SDimitry Andric auto *DeclLoc = Env.getStorageLocation(*VD); 21804eeddc0SDimitry Andric if (DeclLoc == nullptr) 21904eeddc0SDimitry Andric return; 22004eeddc0SDimitry Andric 2215f757f3fSDimitry Andric Env.setStorageLocation(*S, *DeclLoc); 22204eeddc0SDimitry Andric } 22304eeddc0SDimitry Andric 22404eeddc0SDimitry Andric void VisitDeclStmt(const DeclStmt *S) { 22504eeddc0SDimitry Andric // Group decls are converted into single decls in the CFG so the cast below 22604eeddc0SDimitry Andric // is safe. 22704eeddc0SDimitry Andric const auto &D = *cast<VarDecl>(S->getSingleDecl()); 22881ad6265SDimitry Andric 22906c3fb27SDimitry Andric ProcessVarDecl(D); 23006c3fb27SDimitry Andric } 23106c3fb27SDimitry Andric 23206c3fb27SDimitry Andric void ProcessVarDecl(const VarDecl &D) { 23381ad6265SDimitry Andric // Static local vars are already initialized in `Environment`. 23481ad6265SDimitry Andric if (D.hasGlobalStorage()) 23581ad6265SDimitry Andric return; 23681ad6265SDimitry Andric 23706c3fb27SDimitry Andric // If this is the holding variable for a `BindingDecl`, we may already 23806c3fb27SDimitry Andric // have a storage location set up -- so check. (See also explanation below 23906c3fb27SDimitry Andric // where we process the `BindingDecl`.) 24006c3fb27SDimitry Andric if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr) 24104eeddc0SDimitry Andric return; 24204eeddc0SDimitry Andric 24306c3fb27SDimitry Andric assert(Env.getStorageLocation(D) == nullptr); 24404eeddc0SDimitry Andric 24506c3fb27SDimitry Andric Env.setStorageLocation(D, Env.createObject(D)); 24681ad6265SDimitry Andric 24706c3fb27SDimitry Andric // `DecompositionDecl` must be handled after we've interpreted the loc 24806c3fb27SDimitry Andric // itself, because the binding expression refers back to the 24906c3fb27SDimitry Andric // `DecompositionDecl` (even though it has no written name). 25081ad6265SDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) { 25181ad6265SDimitry Andric // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This 25281ad6265SDimitry Andric // needs to be evaluated after initializing the values in the storage for 25381ad6265SDimitry Andric // VarDecl, as the bindings refer to them. 25481ad6265SDimitry Andric // FIXME: Add support for ArraySubscriptExpr. 255bdd1243dSDimitry Andric // FIXME: Consider adding AST nodes used in BindingDecls to the CFG. 25681ad6265SDimitry Andric for (const auto *B : Decomp->bindings()) { 257bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) { 25881ad6265SDimitry Andric auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase()); 25981ad6265SDimitry Andric if (DE == nullptr) 26081ad6265SDimitry Andric continue; 26181ad6265SDimitry Andric 262bdd1243dSDimitry Andric // ME and its base haven't been visited because they aren't included 263bdd1243dSDimitry Andric // in the statements of the CFG basic block. 26481ad6265SDimitry Andric VisitDeclRefExpr(DE); 26581ad6265SDimitry Andric VisitMemberExpr(ME); 26681ad6265SDimitry Andric 2675f757f3fSDimitry Andric if (auto *Loc = Env.getStorageLocation(*ME)) 26881ad6265SDimitry Andric Env.setStorageLocation(*B, *Loc); 269bdd1243dSDimitry Andric } else if (auto *VD = B->getHoldingVar()) { 27006c3fb27SDimitry Andric // Holding vars are used to back the `BindingDecl`s of tuple-like 27106c3fb27SDimitry Andric // types. The holding var declarations appear after the 27206c3fb27SDimitry Andric // `DecompositionDecl`, so we have to explicitly process them here 27306c3fb27SDimitry Andric // to know their storage location. They will be processed a second 27406c3fb27SDimitry Andric // time when we visit their `VarDecl`s, so we have code that protects 27506c3fb27SDimitry Andric // against this above. 27606c3fb27SDimitry Andric ProcessVarDecl(*VD); 27706c3fb27SDimitry Andric auto *VDLoc = Env.getStorageLocation(*VD); 27806c3fb27SDimitry Andric assert(VDLoc != nullptr); 27906c3fb27SDimitry Andric Env.setStorageLocation(*B, *VDLoc); 280bdd1243dSDimitry Andric } 28181ad6265SDimitry Andric } 28204eeddc0SDimitry Andric } 28304eeddc0SDimitry Andric } 28404eeddc0SDimitry Andric 28504eeddc0SDimitry Andric void VisitImplicitCastExpr(const ImplicitCastExpr *S) { 28681ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 28704eeddc0SDimitry Andric assert(SubExpr != nullptr); 28804eeddc0SDimitry Andric 28904eeddc0SDimitry Andric switch (S->getCastKind()) { 29081ad6265SDimitry Andric case CK_IntegralToBoolean: { 29181ad6265SDimitry Andric // This cast creates a new, boolean value from the integral value. We 29281ad6265SDimitry Andric // model that with a fresh value in the environment, unless it's already a 29381ad6265SDimitry Andric // boolean. 29406c3fb27SDimitry Andric if (auto *SubExprVal = 2955f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr))) 2965f757f3fSDimitry Andric Env.setValue(*S, *SubExprVal); 29781ad6265SDimitry Andric else 29881ad6265SDimitry Andric // FIXME: If integer modeling is added, then update this code to create 29981ad6265SDimitry Andric // the boolean based on the integer model. 3005f757f3fSDimitry Andric Env.setValue(*S, Env.makeAtomicBoolValue()); 30181ad6265SDimitry Andric break; 30281ad6265SDimitry Andric } 30381ad6265SDimitry Andric 30404eeddc0SDimitry Andric case CK_LValueToRValue: { 305bdd1243dSDimitry Andric // When an L-value is used as an R-value, it may result in sharing, so we 3065f757f3fSDimitry Andric // need to unpack any nested `Top`s. 307bdd1243dSDimitry Andric auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env); 30804eeddc0SDimitry Andric if (SubExprVal == nullptr) 30904eeddc0SDimitry Andric break; 31004eeddc0SDimitry Andric 3115f757f3fSDimitry Andric Env.setValue(*S, *SubExprVal); 31204eeddc0SDimitry Andric break; 31304eeddc0SDimitry Andric } 31481ad6265SDimitry Andric 31581ad6265SDimitry Andric case CK_IntegralCast: 31681ad6265SDimitry Andric // FIXME: This cast creates a new integral value from the 31781ad6265SDimitry Andric // subexpression. But, because we don't model integers, we don't 31881ad6265SDimitry Andric // distinguish between this new value and the underlying one. If integer 31981ad6265SDimitry Andric // modeling is added, then update this code to create a fresh location and 32081ad6265SDimitry Andric // value. 32181ad6265SDimitry Andric case CK_UncheckedDerivedToBase: 32281ad6265SDimitry Andric case CK_ConstructorConversion: 32381ad6265SDimitry Andric case CK_UserDefinedConversion: 32481ad6265SDimitry Andric // FIXME: Add tests that excercise CK_UncheckedDerivedToBase, 32581ad6265SDimitry Andric // CK_ConstructorConversion, and CK_UserDefinedConversion. 32604eeddc0SDimitry Andric case CK_NoOp: { 32704eeddc0SDimitry Andric // FIXME: Consider making `Environment::getStorageLocation` skip noop 32806c3fb27SDimitry Andric // expressions (this and other similar expressions in the file) instead 32906c3fb27SDimitry Andric // of assigning them storage locations. 33006c3fb27SDimitry Andric propagateValueOrStorageLocation(*SubExpr, *S, Env); 33104eeddc0SDimitry Andric break; 33204eeddc0SDimitry Andric } 33306c3fb27SDimitry Andric case CK_NullToPointer: { 33481ad6265SDimitry Andric auto &NullPointerVal = 33581ad6265SDimitry Andric Env.getOrCreateNullPointerValue(S->getType()->getPointeeType()); 3365f757f3fSDimitry Andric Env.setValue(*S, NullPointerVal); 33781ad6265SDimitry Andric break; 33881ad6265SDimitry Andric } 33906c3fb27SDimitry Andric case CK_NullToMemberPointer: 34006c3fb27SDimitry Andric // FIXME: Implement pointers to members. For now, don't associate a value 34106c3fb27SDimitry Andric // with this expression. 34206c3fb27SDimitry Andric break; 34306c3fb27SDimitry Andric case CK_FunctionToPointerDecay: { 3445f757f3fSDimitry Andric StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr); 34506c3fb27SDimitry Andric if (PointeeLoc == nullptr) 34606c3fb27SDimitry Andric break; 34706c3fb27SDimitry Andric 3485f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 34906c3fb27SDimitry Andric break; 35006c3fb27SDimitry Andric } 35106c3fb27SDimitry Andric case CK_BuiltinFnToFnPtr: 35206c3fb27SDimitry Andric // Despite its name, the result type of `BuiltinFnToFnPtr` is a function, 35306c3fb27SDimitry Andric // not a function pointer. In addition, builtin functions can only be 35406c3fb27SDimitry Andric // called directly; it is not legal to take their address. We therefore 35506c3fb27SDimitry Andric // don't need to create a value or storage location for them. 35606c3fb27SDimitry Andric break; 35704eeddc0SDimitry Andric default: 35804eeddc0SDimitry Andric break; 35904eeddc0SDimitry Andric } 36004eeddc0SDimitry Andric } 36104eeddc0SDimitry Andric 36204eeddc0SDimitry Andric void VisitUnaryOperator(const UnaryOperator *S) { 36381ad6265SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 36404eeddc0SDimitry Andric assert(SubExpr != nullptr); 36504eeddc0SDimitry Andric 36604eeddc0SDimitry Andric switch (S->getOpcode()) { 36704eeddc0SDimitry Andric case UO_Deref: { 368cb14a3feSDimitry Andric const auto *SubExprVal = Env.get<PointerValue>(*SubExpr); 36904eeddc0SDimitry Andric if (SubExprVal == nullptr) 37004eeddc0SDimitry Andric break; 37104eeddc0SDimitry Andric 3725f757f3fSDimitry Andric Env.setStorageLocation(*S, SubExprVal->getPointeeLoc()); 37304eeddc0SDimitry Andric break; 37404eeddc0SDimitry Andric } 37504eeddc0SDimitry Andric case UO_AddrOf: { 37606c3fb27SDimitry Andric // FIXME: Model pointers to members. 37706c3fb27SDimitry Andric if (S->getType()->isMemberPointerType()) 37804eeddc0SDimitry Andric break; 37904eeddc0SDimitry Andric 3805f757f3fSDimitry Andric if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr)) 3815f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc)); 38204eeddc0SDimitry Andric break; 38304eeddc0SDimitry Andric } 38481ad6265SDimitry Andric case UO_LNot: { 3855f757f3fSDimitry Andric auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)); 38681ad6265SDimitry Andric if (SubExprVal == nullptr) 38781ad6265SDimitry Andric break; 38881ad6265SDimitry Andric 3895f757f3fSDimitry Andric Env.setValue(*S, Env.makeNot(*SubExprVal)); 39081ad6265SDimitry Andric break; 39181ad6265SDimitry Andric } 392*0fca6ea1SDimitry Andric case UO_PreInc: 393*0fca6ea1SDimitry Andric case UO_PreDec: 394*0fca6ea1SDimitry Andric // Propagate the storage location and clear out any value associated with 395*0fca6ea1SDimitry Andric // it (to represent the fact that the value has definitely changed). 396*0fca6ea1SDimitry Andric // To avoid generating unnecessary values, we leave it to the specific 397*0fca6ea1SDimitry Andric // analysis to create a new value if desired. 398*0fca6ea1SDimitry Andric propagateStorageLocation(*S->getSubExpr(), *S, Env); 399*0fca6ea1SDimitry Andric if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) 400*0fca6ea1SDimitry Andric Env.clearValue(*Loc); 401*0fca6ea1SDimitry Andric break; 402*0fca6ea1SDimitry Andric case UO_PostInc: 403*0fca6ea1SDimitry Andric case UO_PostDec: 404*0fca6ea1SDimitry Andric // Propagate the old value, then clear out any value associated with the 405*0fca6ea1SDimitry Andric // storage location (to represent the fact that the value has definitely 406*0fca6ea1SDimitry Andric // changed). See above for rationale. 407*0fca6ea1SDimitry Andric propagateValue(*S->getSubExpr(), *S, Env); 408*0fca6ea1SDimitry Andric if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr())) 409*0fca6ea1SDimitry Andric Env.clearValue(*Loc); 410*0fca6ea1SDimitry Andric break; 41104eeddc0SDimitry Andric default: 41204eeddc0SDimitry Andric break; 41304eeddc0SDimitry Andric } 41404eeddc0SDimitry Andric } 41504eeddc0SDimitry Andric 41604eeddc0SDimitry Andric void VisitCXXThisExpr(const CXXThisExpr *S) { 41704eeddc0SDimitry Andric auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation(); 41881ad6265SDimitry Andric if (ThisPointeeLoc == nullptr) 41981ad6265SDimitry Andric // Unions are not supported yet, and will not have a location for the 42081ad6265SDimitry Andric // `this` expression's pointee. 42181ad6265SDimitry Andric return; 42204eeddc0SDimitry Andric 4235f757f3fSDimitry Andric Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc)); 42406c3fb27SDimitry Andric } 42506c3fb27SDimitry Andric 42606c3fb27SDimitry Andric void VisitCXXNewExpr(const CXXNewExpr *S) { 42706c3fb27SDimitry Andric if (Value *Val = Env.createValue(S->getType())) 4285f757f3fSDimitry Andric Env.setValue(*S, *Val); 42906c3fb27SDimitry Andric } 43006c3fb27SDimitry Andric 43106c3fb27SDimitry Andric void VisitCXXDeleteExpr(const CXXDeleteExpr *S) { 43206c3fb27SDimitry Andric // Empty method. 43306c3fb27SDimitry Andric // We consciously don't do anything on deletes. Diagnosing double deletes 43406c3fb27SDimitry Andric // (for example) should be done by a specific analysis, not by the 43506c3fb27SDimitry Andric // framework. 43604eeddc0SDimitry Andric } 43704eeddc0SDimitry Andric 438bdd1243dSDimitry Andric void VisitReturnStmt(const ReturnStmt *S) { 43906c3fb27SDimitry Andric if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts) 440bdd1243dSDimitry Andric return; 441bdd1243dSDimitry Andric 442bdd1243dSDimitry Andric auto *Ret = S->getRetValue(); 443bdd1243dSDimitry Andric if (Ret == nullptr) 444bdd1243dSDimitry Andric return; 445bdd1243dSDimitry Andric 44606c3fb27SDimitry Andric if (Ret->isPRValue()) { 447*0fca6ea1SDimitry Andric if (Ret->getType()->isRecordType()) 448*0fca6ea1SDimitry Andric return; 449*0fca6ea1SDimitry Andric 4505f757f3fSDimitry Andric auto *Val = Env.getValue(*Ret); 451bdd1243dSDimitry Andric if (Val == nullptr) 452bdd1243dSDimitry Andric return; 453bdd1243dSDimitry Andric 45406c3fb27SDimitry Andric // FIXME: Model NRVO. 45506c3fb27SDimitry Andric Env.setReturnValue(Val); 45606c3fb27SDimitry Andric } else { 4575f757f3fSDimitry Andric auto *Loc = Env.getStorageLocation(*Ret); 45806c3fb27SDimitry Andric if (Loc == nullptr) 459bdd1243dSDimitry Andric return; 460bdd1243dSDimitry Andric 461bdd1243dSDimitry Andric // FIXME: Model NRVO. 46206c3fb27SDimitry Andric Env.setReturnStorageLocation(Loc); 46306c3fb27SDimitry Andric } 464bdd1243dSDimitry Andric } 465bdd1243dSDimitry Andric 46604eeddc0SDimitry Andric void VisitMemberExpr(const MemberExpr *S) { 46704eeddc0SDimitry Andric ValueDecl *Member = S->getMemberDecl(); 46804eeddc0SDimitry Andric assert(Member != nullptr); 46904eeddc0SDimitry Andric 47004eeddc0SDimitry Andric // FIXME: Consider assigning pointer values to function member expressions. 47104eeddc0SDimitry Andric if (Member->isFunctionOrFunctionTemplate()) 47204eeddc0SDimitry Andric return; 47304eeddc0SDimitry Andric 474bdd1243dSDimitry Andric // FIXME: if/when we add support for modeling enums, use that support here. 475bdd1243dSDimitry Andric if (isa<EnumConstantDecl>(Member)) 476bdd1243dSDimitry Andric return; 477bdd1243dSDimitry Andric 47881ad6265SDimitry Andric if (auto *D = dyn_cast<VarDecl>(Member)) { 47981ad6265SDimitry Andric if (D->hasGlobalStorage()) { 48006c3fb27SDimitry Andric auto *VarDeclLoc = Env.getStorageLocation(*D); 48181ad6265SDimitry Andric if (VarDeclLoc == nullptr) 48281ad6265SDimitry Andric return; 48381ad6265SDimitry Andric 48481ad6265SDimitry Andric Env.setStorageLocation(*S, *VarDeclLoc); 48581ad6265SDimitry Andric return; 48681ad6265SDimitry Andric } 48781ad6265SDimitry Andric } 48881ad6265SDimitry Andric 4895f757f3fSDimitry Andric RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env); 49004eeddc0SDimitry Andric if (BaseLoc == nullptr) 49104eeddc0SDimitry Andric return; 49204eeddc0SDimitry Andric 49306c3fb27SDimitry Andric auto *MemberLoc = BaseLoc->getChild(*Member); 49406c3fb27SDimitry Andric if (MemberLoc == nullptr) 49506c3fb27SDimitry Andric return; 4965f757f3fSDimitry Andric Env.setStorageLocation(*S, *MemberLoc); 49704eeddc0SDimitry Andric } 49804eeddc0SDimitry Andric 499*0fca6ea1SDimitry Andric void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) { 500*0fca6ea1SDimitry Andric const Expr *ArgExpr = S->getExpr(); 501*0fca6ea1SDimitry Andric assert(ArgExpr != nullptr); 502*0fca6ea1SDimitry Andric propagateValueOrStorageLocation(*ArgExpr, *S, Env); 503*0fca6ea1SDimitry Andric 504*0fca6ea1SDimitry Andric if (S->isPRValue() && S->getType()->isRecordType()) { 505*0fca6ea1SDimitry Andric auto &Loc = Env.getResultObjectLocation(*S); 506*0fca6ea1SDimitry Andric Env.initializeFieldsWithValues(Loc); 507*0fca6ea1SDimitry Andric } 508*0fca6ea1SDimitry Andric } 509*0fca6ea1SDimitry Andric 51004eeddc0SDimitry Andric void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) { 51104eeddc0SDimitry Andric const Expr *InitExpr = S->getExpr(); 51204eeddc0SDimitry Andric assert(InitExpr != nullptr); 513*0fca6ea1SDimitry Andric 514*0fca6ea1SDimitry Andric // If this is a prvalue of record type, the handler for `*InitExpr` (if one 515*0fca6ea1SDimitry Andric // exists) will initialize the result object; there is no value to propgate 516*0fca6ea1SDimitry Andric // here. 517*0fca6ea1SDimitry Andric if (S->getType()->isRecordType() && S->isPRValue()) 518*0fca6ea1SDimitry Andric return; 519*0fca6ea1SDimitry Andric 52006c3fb27SDimitry Andric propagateValueOrStorageLocation(*InitExpr, *S, Env); 52104eeddc0SDimitry Andric } 52204eeddc0SDimitry Andric 52304eeddc0SDimitry Andric void VisitCXXConstructExpr(const CXXConstructExpr *S) { 52404eeddc0SDimitry Andric const CXXConstructorDecl *ConstructorDecl = S->getConstructor(); 52504eeddc0SDimitry Andric assert(ConstructorDecl != nullptr); 52604eeddc0SDimitry Andric 527*0fca6ea1SDimitry Andric // `CXXConstructExpr` can have array type if default-initializing an array 528*0fca6ea1SDimitry Andric // of records. We don't handle this specifically beyond potentially inlining 529*0fca6ea1SDimitry Andric // the call. 530*0fca6ea1SDimitry Andric if (!S->getType()->isRecordType()) { 531*0fca6ea1SDimitry Andric transferInlineCall(S, ConstructorDecl); 532*0fca6ea1SDimitry Andric return; 533*0fca6ea1SDimitry Andric } 534*0fca6ea1SDimitry Andric 535*0fca6ea1SDimitry Andric RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 536*0fca6ea1SDimitry Andric 53704eeddc0SDimitry Andric if (ConstructorDecl->isCopyOrMoveConstructor()) { 53806c3fb27SDimitry Andric // It is permissible for a copy/move constructor to have additional 53906c3fb27SDimitry Andric // parameters as long as they have default arguments defined for them. 54006c3fb27SDimitry Andric assert(S->getNumArgs() != 0); 54104eeddc0SDimitry Andric 54204eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 54304eeddc0SDimitry Andric assert(Arg != nullptr); 54404eeddc0SDimitry Andric 545cb14a3feSDimitry Andric auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg); 54604eeddc0SDimitry Andric if (ArgLoc == nullptr) 54704eeddc0SDimitry Andric return; 54804eeddc0SDimitry Andric 549*0fca6ea1SDimitry Andric // Even if the copy/move constructor call is elidable, we choose to copy 550*0fca6ea1SDimitry Andric // the record in all cases (which isn't wrong, just potentially not 551*0fca6ea1SDimitry Andric // optimal). 552*0fca6ea1SDimitry Andric copyRecord(*ArgLoc, Loc, Env); 55304eeddc0SDimitry Andric return; 55404eeddc0SDimitry Andric } 55504eeddc0SDimitry Andric 556*0fca6ea1SDimitry Andric Env.initializeFieldsWithValues(Loc, S->getType()); 557bdd1243dSDimitry Andric 558bdd1243dSDimitry Andric transferInlineCall(S, ConstructorDecl); 55904eeddc0SDimitry Andric } 56004eeddc0SDimitry Andric 56104eeddc0SDimitry Andric void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) { 56204eeddc0SDimitry Andric if (S->getOperator() == OO_Equal) { 56304eeddc0SDimitry Andric assert(S->getNumArgs() == 2); 56404eeddc0SDimitry Andric 56504eeddc0SDimitry Andric const Expr *Arg0 = S->getArg(0); 56604eeddc0SDimitry Andric assert(Arg0 != nullptr); 56704eeddc0SDimitry Andric 56804eeddc0SDimitry Andric const Expr *Arg1 = S->getArg(1); 56904eeddc0SDimitry Andric assert(Arg1 != nullptr); 57004eeddc0SDimitry Andric 57104eeddc0SDimitry Andric // Evaluate only copy and move assignment operators. 57206c3fb27SDimitry Andric const auto *Method = 57306c3fb27SDimitry Andric dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee()); 57406c3fb27SDimitry Andric if (!Method) 57506c3fb27SDimitry Andric return; 57606c3fb27SDimitry Andric if (!Method->isCopyAssignmentOperator() && 57706c3fb27SDimitry Andric !Method->isMoveAssignmentOperator()) 57804eeddc0SDimitry Andric return; 57904eeddc0SDimitry Andric 5805f757f3fSDimitry Andric RecordStorageLocation *LocSrc = nullptr; 5815f757f3fSDimitry Andric if (Arg1->isPRValue()) { 582*0fca6ea1SDimitry Andric LocSrc = &Env.getResultObjectLocation(*Arg1); 5835f757f3fSDimitry Andric } else { 584cb14a3feSDimitry Andric LocSrc = Env.get<RecordStorageLocation>(*Arg1); 58506c3fb27SDimitry Andric } 586cb14a3feSDimitry Andric auto *LocDst = Env.get<RecordStorageLocation>(*Arg0); 5875f757f3fSDimitry Andric 5885f757f3fSDimitry Andric if (LocSrc == nullptr || LocDst == nullptr) 5895f757f3fSDimitry Andric return; 5905f757f3fSDimitry Andric 5915f757f3fSDimitry Andric copyRecord(*LocSrc, *LocDst, Env); 592*0fca6ea1SDimitry Andric 593*0fca6ea1SDimitry Andric // The assignment operator can have an arbitrary return type. We model the 594*0fca6ea1SDimitry Andric // return value only if the return type is the same as or a base class of 595*0fca6ea1SDimitry Andric // the destination type. 596*0fca6ea1SDimitry Andric if (S->getType().getCanonicalType().getUnqualifiedType() != 597*0fca6ea1SDimitry Andric LocDst->getType().getCanonicalType().getUnqualifiedType()) { 598*0fca6ea1SDimitry Andric auto ReturnDecl = S->getType()->getAsCXXRecordDecl(); 599*0fca6ea1SDimitry Andric auto DstDecl = LocDst->getType()->getAsCXXRecordDecl(); 600*0fca6ea1SDimitry Andric if (ReturnDecl == nullptr || DstDecl == nullptr) 601*0fca6ea1SDimitry Andric return; 602*0fca6ea1SDimitry Andric if (!DstDecl->isDerivedFrom(ReturnDecl)) 603*0fca6ea1SDimitry Andric return; 604*0fca6ea1SDimitry Andric } 605*0fca6ea1SDimitry Andric 606*0fca6ea1SDimitry Andric if (S->isGLValue()) 6075f757f3fSDimitry Andric Env.setStorageLocation(*S, *LocDst); 608*0fca6ea1SDimitry Andric else 609*0fca6ea1SDimitry Andric copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env); 610*0fca6ea1SDimitry Andric 611*0fca6ea1SDimitry Andric return; 61204eeddc0SDimitry Andric } 61304eeddc0SDimitry Andric 614*0fca6ea1SDimitry Andric // `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to 615*0fca6ea1SDimitry Andric // initialize the prvalue's fields with values. 616*0fca6ea1SDimitry Andric VisitCallExpr(S); 61704eeddc0SDimitry Andric } 61804eeddc0SDimitry Andric 619*0fca6ea1SDimitry Andric void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) { 620*0fca6ea1SDimitry Andric propagateValue(*RBO->getSemanticForm(), *RBO, Env); 62104eeddc0SDimitry Andric } 62204eeddc0SDimitry Andric 62304eeddc0SDimitry Andric void VisitCallExpr(const CallExpr *S) { 62481ad6265SDimitry Andric // Of clang's builtins, only `__builtin_expect` is handled explicitly, since 62581ad6265SDimitry Andric // others (like trap, debugtrap, and unreachable) are handled by CFG 62681ad6265SDimitry Andric // construction. 62704eeddc0SDimitry Andric if (S->isCallToStdMove()) { 62804eeddc0SDimitry Andric assert(S->getNumArgs() == 1); 62904eeddc0SDimitry Andric 63004eeddc0SDimitry Andric const Expr *Arg = S->getArg(0); 63104eeddc0SDimitry Andric assert(Arg != nullptr); 63204eeddc0SDimitry Andric 6335f757f3fSDimitry Andric auto *ArgLoc = Env.getStorageLocation(*Arg); 63404eeddc0SDimitry Andric if (ArgLoc == nullptr) 63504eeddc0SDimitry Andric return; 63604eeddc0SDimitry Andric 63704eeddc0SDimitry Andric Env.setStorageLocation(*S, *ArgLoc); 63881ad6265SDimitry Andric } else if (S->getDirectCallee() != nullptr && 63981ad6265SDimitry Andric S->getDirectCallee()->getBuiltinID() == 64081ad6265SDimitry Andric Builtin::BI__builtin_expect) { 64181ad6265SDimitry Andric assert(S->getNumArgs() > 0); 64281ad6265SDimitry Andric assert(S->getArg(0) != nullptr); 6435f757f3fSDimitry Andric auto *ArgVal = Env.getValue(*S->getArg(0)); 6445f757f3fSDimitry Andric if (ArgVal == nullptr) 64581ad6265SDimitry Andric return; 6465f757f3fSDimitry Andric Env.setValue(*S, *ArgVal); 647972a253aSDimitry Andric } else if (const FunctionDecl *F = S->getDirectCallee()) { 648bdd1243dSDimitry Andric transferInlineCall(S, F); 649cb14a3feSDimitry Andric 650*0fca6ea1SDimitry Andric // If this call produces a prvalue of record type, initialize its fields 651*0fca6ea1SDimitry Andric // with values. 652*0fca6ea1SDimitry Andric if (S->getType()->isRecordType() && S->isPRValue()) { 653*0fca6ea1SDimitry Andric RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 654*0fca6ea1SDimitry Andric Env.initializeFieldsWithValues(Loc); 655*0fca6ea1SDimitry Andric } 65604eeddc0SDimitry Andric } 65704eeddc0SDimitry Andric } 65804eeddc0SDimitry Andric 65904eeddc0SDimitry Andric void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) { 66004eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 66104eeddc0SDimitry Andric assert(SubExpr != nullptr); 66204eeddc0SDimitry Andric 66306c3fb27SDimitry Andric StorageLocation &Loc = Env.createStorageLocation(*S); 66406c3fb27SDimitry Andric Env.setStorageLocation(*S, Loc); 665*0fca6ea1SDimitry Andric 666*0fca6ea1SDimitry Andric if (SubExpr->getType()->isRecordType()) 667*0fca6ea1SDimitry Andric // Nothing else left to do -- we initialized the record when transferring 668*0fca6ea1SDimitry Andric // `SubExpr`. 669*0fca6ea1SDimitry Andric return; 670*0fca6ea1SDimitry Andric 671*0fca6ea1SDimitry Andric if (Value *SubExprVal = Env.getValue(*SubExpr)) 672*0fca6ea1SDimitry Andric Env.setValue(Loc, *SubExprVal); 67304eeddc0SDimitry Andric } 67404eeddc0SDimitry Andric 67504eeddc0SDimitry Andric void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) { 67604eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 67704eeddc0SDimitry Andric assert(SubExpr != nullptr); 67804eeddc0SDimitry Andric 67906c3fb27SDimitry Andric propagateValue(*SubExpr, *S, Env); 68004eeddc0SDimitry Andric } 68104eeddc0SDimitry Andric 68204eeddc0SDimitry Andric void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) { 68304eeddc0SDimitry Andric if (S->getCastKind() == CK_NoOp) { 68404eeddc0SDimitry Andric const Expr *SubExpr = S->getSubExpr(); 68504eeddc0SDimitry Andric assert(SubExpr != nullptr); 68604eeddc0SDimitry Andric 68706c3fb27SDimitry Andric propagateValueOrStorageLocation(*SubExpr, *S, Env); 68804eeddc0SDimitry Andric } 68904eeddc0SDimitry Andric } 69004eeddc0SDimitry Andric 69104eeddc0SDimitry Andric void VisitConditionalOperator(const ConditionalOperator *S) { 692*0fca6ea1SDimitry Andric const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr()); 693*0fca6ea1SDimitry Andric const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr()); 694*0fca6ea1SDimitry Andric 695*0fca6ea1SDimitry Andric if (TrueEnv == nullptr || FalseEnv == nullptr) { 696*0fca6ea1SDimitry Andric // If the true or false branch is dead, we may not have an environment for 697*0fca6ea1SDimitry Andric // it. We could handle this specifically by forwarding the value or 698*0fca6ea1SDimitry Andric // location of the live branch, but this case is rare enough that this 699*0fca6ea1SDimitry Andric // probably isn't worth the additional complexity. 700*0fca6ea1SDimitry Andric return; 701*0fca6ea1SDimitry Andric } 702*0fca6ea1SDimitry Andric 703*0fca6ea1SDimitry Andric if (S->isGLValue()) { 704*0fca6ea1SDimitry Andric StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr()); 705*0fca6ea1SDimitry Andric StorageLocation *FalseLoc = 706*0fca6ea1SDimitry Andric FalseEnv->getStorageLocation(*S->getFalseExpr()); 707*0fca6ea1SDimitry Andric if (TrueLoc == FalseLoc && TrueLoc != nullptr) 708*0fca6ea1SDimitry Andric Env.setStorageLocation(*S, *TrueLoc); 709*0fca6ea1SDimitry Andric } else if (!S->getType()->isRecordType()) { 710*0fca6ea1SDimitry Andric // The conditional operator can evaluate to either of the values of the 711*0fca6ea1SDimitry Andric // two branches. To model this, join these two values together to yield 712*0fca6ea1SDimitry Andric // the result of the conditional operator. 713*0fca6ea1SDimitry Andric // Note: Most joins happen in `computeBlockInputState()`, but this case is 714*0fca6ea1SDimitry Andric // different: 715*0fca6ea1SDimitry Andric // - `computeBlockInputState()` (which in turn calls `Environment::join()` 716*0fca6ea1SDimitry Andric // joins values associated with the _same_ expression or storage 717*0fca6ea1SDimitry Andric // location, then associates the joined value with that expression or 718*0fca6ea1SDimitry Andric // storage location. This join has nothing to do with transfer -- 719*0fca6ea1SDimitry Andric // instead, it joins together the results of performing transfer on two 720*0fca6ea1SDimitry Andric // different blocks. 721*0fca6ea1SDimitry Andric // - Here, we join values associated with _different_ expressions (the 722*0fca6ea1SDimitry Andric // true and false branch), then associate the joined value with a third 723*0fca6ea1SDimitry Andric // expression (the conditional operator itself). This join is what it 724*0fca6ea1SDimitry Andric // means to perform transfer on the conditional operator. 725*0fca6ea1SDimitry Andric if (Value *Val = Environment::joinValues( 726*0fca6ea1SDimitry Andric S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv, 727*0fca6ea1SDimitry Andric FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model)) 7285f757f3fSDimitry Andric Env.setValue(*S, *Val); 72904eeddc0SDimitry Andric } 730*0fca6ea1SDimitry Andric } 73104eeddc0SDimitry Andric 73204eeddc0SDimitry Andric void VisitInitListExpr(const InitListExpr *S) { 73304eeddc0SDimitry Andric QualType Type = S->getType(); 73404eeddc0SDimitry Andric 735*0fca6ea1SDimitry Andric if (!Type->isRecordType()) { 736*0fca6ea1SDimitry Andric // Until array initialization is implemented, we skip arrays and don't 737*0fca6ea1SDimitry Andric // need to care about cases where `getNumInits() > 1`. 738*0fca6ea1SDimitry Andric if (!Type->isArrayType() && S->getNumInits() == 1) 739*0fca6ea1SDimitry Andric propagateValueOrStorageLocation(*S->getInit(0), *S, Env); 74004eeddc0SDimitry Andric return; 74106c3fb27SDimitry Andric } 74204eeddc0SDimitry Andric 743*0fca6ea1SDimitry Andric // If the initializer list is transparent, there's nothing to do. 744*0fca6ea1SDimitry Andric if (S->isSemanticForm() && S->isTransparent()) 7455f757f3fSDimitry Andric return; 74606c3fb27SDimitry Andric 747*0fca6ea1SDimitry Andric RecordStorageLocation &Loc = Env.getResultObjectLocation(*S); 74806c3fb27SDimitry Andric 749*0fca6ea1SDimitry Andric // Initialization of base classes and fields of record type happens when we 750*0fca6ea1SDimitry Andric // visit the nested `CXXConstructExpr` or `InitListExpr` for that base class 751*0fca6ea1SDimitry Andric // or field. We therefore only need to deal with fields of non-record type 752*0fca6ea1SDimitry Andric // here. 75306c3fb27SDimitry Andric 754*0fca6ea1SDimitry Andric RecordInitListHelper InitListHelper(S); 7555f757f3fSDimitry Andric 756*0fca6ea1SDimitry Andric for (auto [Field, Init] : InitListHelper.field_inits()) { 757*0fca6ea1SDimitry Andric if (Field->getType()->isRecordType()) 758*0fca6ea1SDimitry Andric continue; 759*0fca6ea1SDimitry Andric if (Field->getType()->isReferenceType()) { 760*0fca6ea1SDimitry Andric assert(Field->getType().getCanonicalType()->getPointeeType() == 7615f757f3fSDimitry Andric Init->getType().getCanonicalType()); 762*0fca6ea1SDimitry Andric Loc.setChild(*Field, &Env.createObject(Field->getType(), Init)); 763*0fca6ea1SDimitry Andric continue; 7645f757f3fSDimitry Andric } 765*0fca6ea1SDimitry Andric assert(Field->getType().getCanonicalType().getUnqualifiedType() == 766*0fca6ea1SDimitry Andric Init->getType().getCanonicalType().getUnqualifiedType()); 767*0fca6ea1SDimitry Andric StorageLocation *FieldLoc = Loc.getChild(*Field); 768*0fca6ea1SDimitry Andric // Locations for non-reference fields must always be non-null. 769*0fca6ea1SDimitry Andric assert(FieldLoc != nullptr); 770*0fca6ea1SDimitry Andric Value *Val = Env.getValue(*Init); 771*0fca6ea1SDimitry Andric if (Val == nullptr && isa<ImplicitValueInitExpr>(Init) && 772*0fca6ea1SDimitry Andric Init->getType()->isPointerType()) 773*0fca6ea1SDimitry Andric Val = 774*0fca6ea1SDimitry Andric &Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType()); 775*0fca6ea1SDimitry Andric if (Val == nullptr) 776*0fca6ea1SDimitry Andric Val = Env.createValue(Field->getType()); 777*0fca6ea1SDimitry Andric if (Val != nullptr) 778*0fca6ea1SDimitry Andric Env.setValue(*FieldLoc, *Val); 7795f757f3fSDimitry Andric } 7805f757f3fSDimitry Andric 781*0fca6ea1SDimitry Andric for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) { 782*0fca6ea1SDimitry Andric QualType FieldType = FieldLoc->getType(); 783*0fca6ea1SDimitry Andric if (FieldType->isRecordType()) { 784*0fca6ea1SDimitry Andric Env.initializeFieldsWithValues(*cast<RecordStorageLocation>(FieldLoc)); 785*0fca6ea1SDimitry Andric } else { 786*0fca6ea1SDimitry Andric if (Value *Val = Env.createValue(FieldType)) 787*0fca6ea1SDimitry Andric Env.setValue(*FieldLoc, *Val); 7885f757f3fSDimitry Andric } 7895f757f3fSDimitry Andric } 7905f757f3fSDimitry Andric 79104eeddc0SDimitry Andric // FIXME: Implement array initialization. 79204eeddc0SDimitry Andric } 79304eeddc0SDimitry Andric 79404eeddc0SDimitry Andric void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) { 7955f757f3fSDimitry Andric Env.setValue(*S, Env.getBoolLiteralValue(S->getValue())); 79606c3fb27SDimitry Andric } 79706c3fb27SDimitry Andric 79806c3fb27SDimitry Andric void VisitIntegerLiteral(const IntegerLiteral *S) { 7995f757f3fSDimitry Andric Env.setValue(*S, Env.getIntLiteralValue(S->getValue())); 80004eeddc0SDimitry Andric } 80104eeddc0SDimitry Andric 80281ad6265SDimitry Andric void VisitParenExpr(const ParenExpr *S) { 80381ad6265SDimitry Andric // The CFG does not contain `ParenExpr` as top-level statements in basic 80481ad6265SDimitry Andric // blocks, however manual traversal to sub-expressions may encounter them. 80581ad6265SDimitry Andric // Redirect to the sub-expression. 80681ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 80781ad6265SDimitry Andric assert(SubExpr != nullptr); 80881ad6265SDimitry Andric Visit(SubExpr); 80981ad6265SDimitry Andric } 81081ad6265SDimitry Andric 81181ad6265SDimitry Andric void VisitExprWithCleanups(const ExprWithCleanups *S) { 81281ad6265SDimitry Andric // The CFG does not contain `ExprWithCleanups` as top-level statements in 81381ad6265SDimitry Andric // basic blocks, however manual traversal to sub-expressions may encounter 81481ad6265SDimitry Andric // them. Redirect to the sub-expression. 81581ad6265SDimitry Andric auto *SubExpr = S->getSubExpr(); 81681ad6265SDimitry Andric assert(SubExpr != nullptr); 81781ad6265SDimitry Andric Visit(SubExpr); 81881ad6265SDimitry Andric } 81981ad6265SDimitry Andric 82004eeddc0SDimitry Andric private: 82106c3fb27SDimitry Andric /// Returns the value for the sub-expression `SubExpr` of a logic operator. 82281ad6265SDimitry Andric BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) { 82381ad6265SDimitry Andric // `SubExpr` and its parent logic operator might be part of different basic 82481ad6265SDimitry Andric // blocks. We try to access the value that is assigned to `SubExpr` in the 82581ad6265SDimitry Andric // corresponding environment. 82606c3fb27SDimitry Andric if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) 82706c3fb27SDimitry Andric if (auto *Val = 8285f757f3fSDimitry Andric dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr))) 82981ad6265SDimitry Andric return *Val; 83081ad6265SDimitry Andric 83106c3fb27SDimitry Andric // The sub-expression may lie within a basic block that isn't reachable, 83206c3fb27SDimitry Andric // even if we need it to evaluate the current (reachable) expression 83306c3fb27SDimitry Andric // (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr` 83406c3fb27SDimitry Andric // within the current environment and then try to get the value that gets 83506c3fb27SDimitry Andric // assigned to it. 8365f757f3fSDimitry Andric if (Env.getValue(SubExpr) == nullptr) 83781ad6265SDimitry Andric Visit(&SubExpr); 8385f757f3fSDimitry Andric if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr))) 83981ad6265SDimitry Andric return *Val; 84081ad6265SDimitry Andric 84181ad6265SDimitry Andric // If the value of `SubExpr` is still unknown, we create a fresh symbolic 84281ad6265SDimitry Andric // boolean value for it. 84381ad6265SDimitry Andric return Env.makeAtomicBoolValue(); 84481ad6265SDimitry Andric } 84581ad6265SDimitry Andric 846bdd1243dSDimitry Andric // If context sensitivity is enabled, try to analyze the body of the callee 847bdd1243dSDimitry Andric // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`. 848bdd1243dSDimitry Andric template <typename E> 849bdd1243dSDimitry Andric void transferInlineCall(const E *S, const FunctionDecl *F) { 85006c3fb27SDimitry Andric const auto &Options = Env.getDataflowAnalysisContext().getOptions(); 851bdd1243dSDimitry Andric if (!(Options.ContextSensitiveOpts && 852bdd1243dSDimitry Andric Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) 853bdd1243dSDimitry Andric return; 854bdd1243dSDimitry Andric 855*0fca6ea1SDimitry Andric const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F); 856*0fca6ea1SDimitry Andric if (!ACFG) 857bdd1243dSDimitry Andric return; 858bdd1243dSDimitry Andric 859bdd1243dSDimitry Andric // FIXME: We don't support context-sensitive analysis of recursion, so 860bdd1243dSDimitry Andric // we should return early here if `F` is the same as the `FunctionDecl` 861bdd1243dSDimitry Andric // holding `S` itself. 862bdd1243dSDimitry Andric 863*0fca6ea1SDimitry Andric auto ExitBlock = ACFG->getCFG().getExit().getBlockID(); 864bdd1243dSDimitry Andric 865bdd1243dSDimitry Andric auto CalleeEnv = Env.pushCall(S); 866bdd1243dSDimitry Andric 867bdd1243dSDimitry Andric // FIXME: Use the same analysis as the caller for the callee. Note, 868bdd1243dSDimitry Andric // though, that doing so would require support for changing the analysis's 869bdd1243dSDimitry Andric // ASTContext. 870*0fca6ea1SDimitry Andric auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(), 871bdd1243dSDimitry Andric DataflowAnalysisOptions{Options}); 872bdd1243dSDimitry Andric 873bdd1243dSDimitry Andric auto BlockToOutputState = 874*0fca6ea1SDimitry Andric dataflow::runDataflowAnalysis(*ACFG, Analysis, CalleeEnv); 875bdd1243dSDimitry Andric assert(BlockToOutputState); 876bdd1243dSDimitry Andric assert(ExitBlock < BlockToOutputState->size()); 877bdd1243dSDimitry Andric 87806c3fb27SDimitry Andric auto &ExitState = (*BlockToOutputState)[ExitBlock]; 879bdd1243dSDimitry Andric assert(ExitState); 880bdd1243dSDimitry Andric 88106c3fb27SDimitry Andric Env.popCall(S, ExitState->Env); 882bdd1243dSDimitry Andric } 883bdd1243dSDimitry Andric 88481ad6265SDimitry Andric const StmtToEnvMap &StmtToEnv; 88504eeddc0SDimitry Andric Environment &Env; 886*0fca6ea1SDimitry Andric Environment::ValueModel &Model; 88704eeddc0SDimitry Andric }; 88804eeddc0SDimitry Andric 88906c3fb27SDimitry Andric } // namespace 89006c3fb27SDimitry Andric 891*0fca6ea1SDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env, 892*0fca6ea1SDimitry Andric Environment::ValueModel &Model) { 893*0fca6ea1SDimitry Andric TransferVisitor(StmtToEnv, Env, Model).Visit(&S); 89404eeddc0SDimitry Andric } 89504eeddc0SDimitry Andric 89604eeddc0SDimitry Andric } // namespace dataflow 89704eeddc0SDimitry Andric } // namespace clang 898