xref: /freebsd/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
23972a253aSDimitry Andric #include "clang/Analysis/FlowSensitive/ControlFlowContext.h"
2404eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
25972a253aSDimitry Andric #include "clang/Analysis/FlowSensitive/NoopAnalysis.h"
2681ad6265SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h"
2781ad6265SDimitry Andric #include "clang/Basic/Builtins.h"
2804eeddc0SDimitry Andric #include "clang/Basic/OperatorKinds.h"
2904eeddc0SDimitry Andric #include "llvm/ADT/STLExtras.h"
3004eeddc0SDimitry Andric #include "llvm/Support/Casting.h"
31*bdd1243dSDimitry Andric #include "llvm/Support/ErrorHandling.h"
3204eeddc0SDimitry Andric #include <cassert>
3304eeddc0SDimitry Andric #include <memory>
3404eeddc0SDimitry Andric #include <tuple>
3504eeddc0SDimitry Andric 
3604eeddc0SDimitry Andric namespace clang {
3704eeddc0SDimitry Andric namespace dataflow {
3804eeddc0SDimitry Andric 
3981ad6265SDimitry Andric static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,
4081ad6265SDimitry Andric                                           Environment &Env) {
4181ad6265SDimitry Andric   if (auto *LHSValue =
4281ad6265SDimitry Andric           dyn_cast_or_null<BoolValue>(Env.getValue(LHS, SkipPast::Reference)))
4381ad6265SDimitry Andric     if (auto *RHSValue =
4481ad6265SDimitry Andric             dyn_cast_or_null<BoolValue>(Env.getValue(RHS, SkipPast::Reference)))
4581ad6265SDimitry Andric       return Env.makeIff(*LHSValue, *RHSValue);
4681ad6265SDimitry Andric 
4781ad6265SDimitry Andric   return Env.makeAtomicBoolValue();
4804eeddc0SDimitry Andric }
4904eeddc0SDimitry Andric 
50*bdd1243dSDimitry Andric // Functionally updates `V` such that any instances of `TopBool` are replaced
51*bdd1243dSDimitry Andric // with fresh atomic bools. Note: This implementation assumes that `B` is a
52*bdd1243dSDimitry Andric // tree; if `B` is a DAG, it will lose any sharing between subvalues that was
53*bdd1243dSDimitry Andric // present in the original .
54*bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env);
55*bdd1243dSDimitry Andric 
56*bdd1243dSDimitry Andric template <typename Derived, typename M>
57*bdd1243dSDimitry Andric BoolValue &unpackBinaryBoolValue(Environment &Env, BoolValue &B, M build) {
58*bdd1243dSDimitry Andric   auto &V = *cast<Derived>(&B);
59*bdd1243dSDimitry Andric   BoolValue &Left = V.getLeftSubValue();
60*bdd1243dSDimitry Andric   BoolValue &Right = V.getRightSubValue();
61*bdd1243dSDimitry Andric   BoolValue &ULeft = unpackValue(Left, Env);
62*bdd1243dSDimitry Andric   BoolValue &URight = unpackValue(Right, Env);
63*bdd1243dSDimitry Andric 
64*bdd1243dSDimitry Andric   if (&ULeft == &Left && &URight == &Right)
65*bdd1243dSDimitry Andric     return V;
66*bdd1243dSDimitry Andric 
67*bdd1243dSDimitry Andric   return (Env.*build)(ULeft, URight);
68*bdd1243dSDimitry Andric }
69*bdd1243dSDimitry Andric 
70*bdd1243dSDimitry Andric static BoolValue &unpackValue(BoolValue &V, Environment &Env) {
71*bdd1243dSDimitry Andric   switch (V.getKind()) {
72*bdd1243dSDimitry Andric   case Value::Kind::Integer:
73*bdd1243dSDimitry Andric   case Value::Kind::Reference:
74*bdd1243dSDimitry Andric   case Value::Kind::Pointer:
75*bdd1243dSDimitry Andric   case Value::Kind::Struct:
76*bdd1243dSDimitry Andric     llvm_unreachable("BoolValue cannot have any of these kinds.");
77*bdd1243dSDimitry Andric 
78*bdd1243dSDimitry Andric   case Value::Kind::AtomicBool:
79*bdd1243dSDimitry Andric     return V;
80*bdd1243dSDimitry Andric 
81*bdd1243dSDimitry Andric   case Value::Kind::TopBool:
82*bdd1243dSDimitry Andric     // Unpack `TopBool` into a fresh atomic bool.
83*bdd1243dSDimitry Andric     return Env.makeAtomicBoolValue();
84*bdd1243dSDimitry Andric 
85*bdd1243dSDimitry Andric   case Value::Kind::Negation: {
86*bdd1243dSDimitry Andric     auto &N = *cast<NegationValue>(&V);
87*bdd1243dSDimitry Andric     BoolValue &Sub = N.getSubVal();
88*bdd1243dSDimitry Andric     BoolValue &USub = unpackValue(Sub, Env);
89*bdd1243dSDimitry Andric 
90*bdd1243dSDimitry Andric     if (&USub == &Sub)
91*bdd1243dSDimitry Andric       return V;
92*bdd1243dSDimitry Andric     return Env.makeNot(USub);
93*bdd1243dSDimitry Andric   }
94*bdd1243dSDimitry Andric   case Value::Kind::Conjunction:
95*bdd1243dSDimitry Andric     return unpackBinaryBoolValue<ConjunctionValue>(Env, V,
96*bdd1243dSDimitry Andric                                                    &Environment::makeAnd);
97*bdd1243dSDimitry Andric   case Value::Kind::Disjunction:
98*bdd1243dSDimitry Andric     return unpackBinaryBoolValue<DisjunctionValue>(Env, V,
99*bdd1243dSDimitry Andric                                                    &Environment::makeOr);
100*bdd1243dSDimitry Andric   case Value::Kind::Implication:
101*bdd1243dSDimitry Andric     return unpackBinaryBoolValue<ImplicationValue>(
102*bdd1243dSDimitry Andric         Env, V, &Environment::makeImplication);
103*bdd1243dSDimitry Andric   case Value::Kind::Biconditional:
104*bdd1243dSDimitry Andric     return unpackBinaryBoolValue<BiconditionalValue>(Env, V,
105*bdd1243dSDimitry Andric                                                      &Environment::makeIff);
106*bdd1243dSDimitry Andric   }
107*bdd1243dSDimitry Andric   llvm_unreachable("All reachable cases in switch return");
108*bdd1243dSDimitry Andric }
109*bdd1243dSDimitry Andric 
110*bdd1243dSDimitry Andric // Unpacks the value (if any) associated with `E` and updates `E` to the new
111*bdd1243dSDimitry Andric // value, if any unpacking occured.
112*bdd1243dSDimitry Andric static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {
113*bdd1243dSDimitry Andric   // FIXME: this is too flexible: it _allows_ a reference, while it should
114*bdd1243dSDimitry Andric   // _require_ one, since lvalues should always be wrapped in `ReferenceValue`.
115*bdd1243dSDimitry Andric   auto *Loc = Env.getStorageLocation(E, SkipPast::Reference);
116*bdd1243dSDimitry Andric   if (Loc == nullptr)
117*bdd1243dSDimitry Andric     return nullptr;
118*bdd1243dSDimitry Andric   auto *Val = Env.getValue(*Loc);
119*bdd1243dSDimitry Andric 
120*bdd1243dSDimitry Andric   auto *B = dyn_cast_or_null<BoolValue>(Val);
121*bdd1243dSDimitry Andric   if (B == nullptr)
122*bdd1243dSDimitry Andric     return Val;
123*bdd1243dSDimitry Andric 
124*bdd1243dSDimitry Andric   auto &UnpackedVal = unpackValue(*B, Env);
125*bdd1243dSDimitry Andric   if (&UnpackedVal == Val)
126*bdd1243dSDimitry Andric     return Val;
127*bdd1243dSDimitry Andric   Env.setValue(*Loc, UnpackedVal);
128*bdd1243dSDimitry Andric   return &UnpackedVal;
129*bdd1243dSDimitry Andric }
130*bdd1243dSDimitry Andric 
13104eeddc0SDimitry Andric class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
13204eeddc0SDimitry Andric public:
133*bdd1243dSDimitry Andric   TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env)
134*bdd1243dSDimitry Andric       : StmtToEnv(StmtToEnv), Env(Env) {}
13504eeddc0SDimitry Andric 
13604eeddc0SDimitry Andric   void VisitBinaryOperator(const BinaryOperator *S) {
13781ad6265SDimitry Andric     const Expr *LHS = S->getLHS();
13804eeddc0SDimitry Andric     assert(LHS != nullptr);
13981ad6265SDimitry Andric 
14081ad6265SDimitry Andric     const Expr *RHS = S->getRHS();
14181ad6265SDimitry Andric     assert(RHS != nullptr);
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric     switch (S->getOpcode()) {
14481ad6265SDimitry Andric     case BO_Assign: {
14504eeddc0SDimitry Andric       auto *LHSLoc = Env.getStorageLocation(*LHS, SkipPast::Reference);
14604eeddc0SDimitry Andric       if (LHSLoc == nullptr)
14781ad6265SDimitry Andric         break;
14804eeddc0SDimitry Andric 
14981ad6265SDimitry Andric       auto *RHSVal = Env.getValue(*RHS, SkipPast::Reference);
15004eeddc0SDimitry Andric       if (RHSVal == nullptr)
15181ad6265SDimitry Andric         break;
15204eeddc0SDimitry Andric 
15304eeddc0SDimitry Andric       // Assign a value to the storage location of the left-hand side.
15404eeddc0SDimitry Andric       Env.setValue(*LHSLoc, *RHSVal);
15504eeddc0SDimitry Andric 
15604eeddc0SDimitry Andric       // Assign a storage location for the whole expression.
15704eeddc0SDimitry Andric       Env.setStorageLocation(*S, *LHSLoc);
15881ad6265SDimitry Andric       break;
15904eeddc0SDimitry Andric     }
16081ad6265SDimitry Andric     case BO_LAnd:
16181ad6265SDimitry Andric     case BO_LOr: {
16281ad6265SDimitry Andric       BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);
16381ad6265SDimitry Andric       BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);
16481ad6265SDimitry Andric 
16581ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
16681ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
16781ad6265SDimitry Andric       if (S->getOpcode() == BO_LAnd)
16881ad6265SDimitry Andric         Env.setValue(Loc, Env.makeAnd(LHSVal, RHSVal));
16981ad6265SDimitry Andric       else
17081ad6265SDimitry Andric         Env.setValue(Loc, Env.makeOr(LHSVal, RHSVal));
17181ad6265SDimitry Andric       break;
17281ad6265SDimitry Andric     }
17381ad6265SDimitry Andric     case BO_NE:
17481ad6265SDimitry Andric     case BO_EQ: {
17581ad6265SDimitry Andric       auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);
17681ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
17781ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
17881ad6265SDimitry Andric       Env.setValue(Loc, S->getOpcode() == BO_EQ ? LHSEqRHSValue
17981ad6265SDimitry Andric                                                 : Env.makeNot(LHSEqRHSValue));
18081ad6265SDimitry Andric       break;
18181ad6265SDimitry Andric     }
18281ad6265SDimitry Andric     case BO_Comma: {
18381ad6265SDimitry Andric       if (auto *Loc = Env.getStorageLocation(*RHS, SkipPast::None))
18481ad6265SDimitry Andric         Env.setStorageLocation(*S, *Loc);
18581ad6265SDimitry Andric       break;
18681ad6265SDimitry Andric     }
18781ad6265SDimitry Andric     default:
18881ad6265SDimitry Andric       break;
18981ad6265SDimitry Andric     }
19004eeddc0SDimitry Andric   }
19104eeddc0SDimitry Andric 
19204eeddc0SDimitry Andric   void VisitDeclRefExpr(const DeclRefExpr *S) {
193*bdd1243dSDimitry Andric     const ValueDecl *VD = S->getDecl();
194*bdd1243dSDimitry Andric     assert(VD != nullptr);
195*bdd1243dSDimitry Andric     auto *DeclLoc = Env.getStorageLocation(*VD, SkipPast::None);
19604eeddc0SDimitry Andric     if (DeclLoc == nullptr)
19704eeddc0SDimitry Andric       return;
19804eeddc0SDimitry Andric 
199*bdd1243dSDimitry Andric     if (VD->getType()->isReferenceType()) {
200*bdd1243dSDimitry Andric       assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*DeclLoc))) &&
201*bdd1243dSDimitry Andric              "reference-typed declarations map to `ReferenceValue`s");
20204eeddc0SDimitry Andric       Env.setStorageLocation(*S, *DeclLoc);
20304eeddc0SDimitry Andric     } else {
20404eeddc0SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
20504eeddc0SDimitry Andric       auto &Val = Env.takeOwnership(std::make_unique<ReferenceValue>(*DeclLoc));
20604eeddc0SDimitry Andric       Env.setStorageLocation(*S, Loc);
20704eeddc0SDimitry Andric       Env.setValue(Loc, Val);
20804eeddc0SDimitry Andric     }
20904eeddc0SDimitry Andric   }
21004eeddc0SDimitry Andric 
21104eeddc0SDimitry Andric   void VisitDeclStmt(const DeclStmt *S) {
21204eeddc0SDimitry Andric     // Group decls are converted into single decls in the CFG so the cast below
21304eeddc0SDimitry Andric     // is safe.
21404eeddc0SDimitry Andric     const auto &D = *cast<VarDecl>(S->getSingleDecl());
21581ad6265SDimitry Andric 
21681ad6265SDimitry Andric     // Static local vars are already initialized in `Environment`.
21781ad6265SDimitry Andric     if (D.hasGlobalStorage())
21881ad6265SDimitry Andric       return;
21981ad6265SDimitry Andric 
220*bdd1243dSDimitry Andric     // The storage location for `D` could have been created earlier, before the
221*bdd1243dSDimitry Andric     // variable's declaration statement (for example, in the case of
222*bdd1243dSDimitry Andric     // BindingDecls).
223*bdd1243dSDimitry Andric     auto *MaybeLoc = Env.getStorageLocation(D, SkipPast::None);
224*bdd1243dSDimitry Andric     if (MaybeLoc == nullptr) {
225*bdd1243dSDimitry Andric       MaybeLoc = &Env.createStorageLocation(D);
226*bdd1243dSDimitry Andric       Env.setStorageLocation(D, *MaybeLoc);
227*bdd1243dSDimitry Andric     }
228*bdd1243dSDimitry Andric     auto &Loc = *MaybeLoc;
22904eeddc0SDimitry Andric 
23004eeddc0SDimitry Andric     const Expr *InitExpr = D.getInit();
23104eeddc0SDimitry Andric     if (InitExpr == nullptr) {
23204eeddc0SDimitry Andric       // No initializer expression - associate `Loc` with a new value.
23304eeddc0SDimitry Andric       if (Value *Val = Env.createValue(D.getType()))
23404eeddc0SDimitry Andric         Env.setValue(Loc, *Val);
23504eeddc0SDimitry Andric       return;
23604eeddc0SDimitry Andric     }
23704eeddc0SDimitry Andric 
23804eeddc0SDimitry Andric     if (D.getType()->isReferenceType()) {
23904eeddc0SDimitry Andric       // Initializing a reference variable - do not create a reference to
24004eeddc0SDimitry Andric       // reference.
24104eeddc0SDimitry Andric       if (auto *InitExprLoc =
24204eeddc0SDimitry Andric               Env.getStorageLocation(*InitExpr, SkipPast::Reference)) {
24304eeddc0SDimitry Andric         auto &Val =
24404eeddc0SDimitry Andric             Env.takeOwnership(std::make_unique<ReferenceValue>(*InitExprLoc));
24504eeddc0SDimitry Andric         Env.setValue(Loc, Val);
24604eeddc0SDimitry Andric       }
24781ad6265SDimitry Andric     } else if (auto *InitExprVal = Env.getValue(*InitExpr, SkipPast::None)) {
24881ad6265SDimitry Andric       Env.setValue(Loc, *InitExprVal);
24904eeddc0SDimitry Andric     }
25004eeddc0SDimitry Andric 
25181ad6265SDimitry Andric     if (Env.getValue(Loc) == nullptr) {
25281ad6265SDimitry Andric       // We arrive here in (the few) cases where an expression is intentionally
25381ad6265SDimitry Andric       // "uninterpreted". There are two ways to handle this situation: propagate
25481ad6265SDimitry Andric       // the status, so that uninterpreted initializers result in uninterpreted
25581ad6265SDimitry Andric       // variables, or provide a default value. We choose the latter so that
25681ad6265SDimitry Andric       // later refinements of the variable can be used for reasoning about the
25781ad6265SDimitry Andric       // surrounding code.
25881ad6265SDimitry Andric       //
25981ad6265SDimitry Andric       // FIXME. If and when we interpret all language cases, change this to
26081ad6265SDimitry Andric       // assert that `InitExpr` is interpreted, rather than supplying a default
26181ad6265SDimitry Andric       // value (assuming we don't update the environment API to return
26281ad6265SDimitry Andric       // references).
26304eeddc0SDimitry Andric       if (Value *Val = Env.createValue(D.getType()))
26404eeddc0SDimitry Andric         Env.setValue(Loc, *Val);
26581ad6265SDimitry Andric     }
26681ad6265SDimitry Andric 
26781ad6265SDimitry Andric     if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {
26881ad6265SDimitry Andric       // If VarDecl is a DecompositionDecl, evaluate each of its bindings. This
26981ad6265SDimitry Andric       // needs to be evaluated after initializing the values in the storage for
27081ad6265SDimitry Andric       // VarDecl, as the bindings refer to them.
27181ad6265SDimitry Andric       // FIXME: Add support for ArraySubscriptExpr.
272*bdd1243dSDimitry Andric       // FIXME: Consider adding AST nodes used in BindingDecls to the CFG.
27381ad6265SDimitry Andric       for (const auto *B : Decomp->bindings()) {
274*bdd1243dSDimitry Andric         if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {
27581ad6265SDimitry Andric           auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());
27681ad6265SDimitry Andric           if (DE == nullptr)
27781ad6265SDimitry Andric             continue;
27881ad6265SDimitry Andric 
279*bdd1243dSDimitry Andric           // ME and its base haven't been visited because they aren't included
280*bdd1243dSDimitry Andric           // in the statements of the CFG basic block.
28181ad6265SDimitry Andric           VisitDeclRefExpr(DE);
28281ad6265SDimitry Andric           VisitMemberExpr(ME);
28381ad6265SDimitry Andric 
28481ad6265SDimitry Andric           if (auto *Loc = Env.getStorageLocation(*ME, SkipPast::Reference))
28581ad6265SDimitry Andric             Env.setStorageLocation(*B, *Loc);
286*bdd1243dSDimitry Andric         } else if (auto *VD = B->getHoldingVar()) {
287*bdd1243dSDimitry Andric           // Holding vars are used to back the BindingDecls of tuple-like
288*bdd1243dSDimitry Andric           // types. The holding var declarations appear *after* this statement,
289*bdd1243dSDimitry Andric           // so we have to create a location for them here to share with `B`. We
290*bdd1243dSDimitry Andric           // don't visit the binding, because we know it will be a DeclRefExpr
291*bdd1243dSDimitry Andric           // to `VD`.
292*bdd1243dSDimitry Andric           auto &VDLoc = Env.createStorageLocation(*VD);
293*bdd1243dSDimitry Andric           Env.setStorageLocation(*VD, VDLoc);
294*bdd1243dSDimitry Andric           Env.setStorageLocation(*B, VDLoc);
295*bdd1243dSDimitry Andric         }
29681ad6265SDimitry Andric       }
29704eeddc0SDimitry Andric     }
29804eeddc0SDimitry Andric   }
29904eeddc0SDimitry Andric 
30004eeddc0SDimitry Andric   void VisitImplicitCastExpr(const ImplicitCastExpr *S) {
30181ad6265SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
30204eeddc0SDimitry Andric     assert(SubExpr != nullptr);
30304eeddc0SDimitry Andric 
30404eeddc0SDimitry Andric     switch (S->getCastKind()) {
30581ad6265SDimitry Andric     case CK_IntegralToBoolean: {
30681ad6265SDimitry Andric       // This cast creates a new, boolean value from the integral value. We
30781ad6265SDimitry Andric       // model that with a fresh value in the environment, unless it's already a
30881ad6265SDimitry Andric       // boolean.
30981ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
31081ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
31181ad6265SDimitry Andric       if (auto *SubExprVal = dyn_cast_or_null<BoolValue>(
31281ad6265SDimitry Andric               Env.getValue(*SubExpr, SkipPast::Reference)))
31381ad6265SDimitry Andric         Env.setValue(Loc, *SubExprVal);
31481ad6265SDimitry Andric       else
31581ad6265SDimitry Andric         // FIXME: If integer modeling is added, then update this code to create
31681ad6265SDimitry Andric         // the boolean based on the integer model.
31781ad6265SDimitry Andric         Env.setValue(Loc, Env.makeAtomicBoolValue());
31881ad6265SDimitry Andric       break;
31981ad6265SDimitry Andric     }
32081ad6265SDimitry Andric 
32104eeddc0SDimitry Andric     case CK_LValueToRValue: {
322*bdd1243dSDimitry Andric       // When an L-value is used as an R-value, it may result in sharing, so we
323*bdd1243dSDimitry Andric       // need to unpack any nested `Top`s.
324*bdd1243dSDimitry Andric       auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);
32504eeddc0SDimitry Andric       if (SubExprVal == nullptr)
32604eeddc0SDimitry Andric         break;
32704eeddc0SDimitry Andric 
32804eeddc0SDimitry Andric       auto &ExprLoc = Env.createStorageLocation(*S);
32904eeddc0SDimitry Andric       Env.setStorageLocation(*S, ExprLoc);
33004eeddc0SDimitry Andric       Env.setValue(ExprLoc, *SubExprVal);
33104eeddc0SDimitry Andric       break;
33204eeddc0SDimitry Andric     }
33381ad6265SDimitry Andric 
33481ad6265SDimitry Andric     case CK_IntegralCast:
33581ad6265SDimitry Andric       // FIXME: This cast creates a new integral value from the
33681ad6265SDimitry Andric       // subexpression. But, because we don't model integers, we don't
33781ad6265SDimitry Andric       // distinguish between this new value and the underlying one. If integer
33881ad6265SDimitry Andric       // modeling is added, then update this code to create a fresh location and
33981ad6265SDimitry Andric       // value.
34081ad6265SDimitry Andric     case CK_UncheckedDerivedToBase:
34181ad6265SDimitry Andric     case CK_ConstructorConversion:
34281ad6265SDimitry Andric     case CK_UserDefinedConversion:
34381ad6265SDimitry Andric       // FIXME: Add tests that excercise CK_UncheckedDerivedToBase,
34481ad6265SDimitry Andric       // CK_ConstructorConversion, and CK_UserDefinedConversion.
34504eeddc0SDimitry Andric     case CK_NoOp: {
34604eeddc0SDimitry Andric       // FIXME: Consider making `Environment::getStorageLocation` skip noop
34704eeddc0SDimitry Andric       // expressions (this and other similar expressions in the file) instead of
34804eeddc0SDimitry Andric       // assigning them storage locations.
34904eeddc0SDimitry Andric       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
35004eeddc0SDimitry Andric       if (SubExprLoc == nullptr)
35104eeddc0SDimitry Andric         break;
35204eeddc0SDimitry Andric 
35304eeddc0SDimitry Andric       Env.setStorageLocation(*S, *SubExprLoc);
35404eeddc0SDimitry Andric       break;
35504eeddc0SDimitry Andric     }
35681ad6265SDimitry Andric     case CK_NullToPointer:
35781ad6265SDimitry Andric     case CK_NullToMemberPointer: {
35881ad6265SDimitry Andric       auto &Loc = Env.createStorageLocation(S->getType());
35981ad6265SDimitry Andric       Env.setStorageLocation(*S, Loc);
36081ad6265SDimitry Andric 
36181ad6265SDimitry Andric       auto &NullPointerVal =
36281ad6265SDimitry Andric           Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());
36381ad6265SDimitry Andric       Env.setValue(Loc, NullPointerVal);
36481ad6265SDimitry Andric       break;
36581ad6265SDimitry Andric     }
36604eeddc0SDimitry Andric     default:
36704eeddc0SDimitry Andric       break;
36804eeddc0SDimitry Andric     }
36904eeddc0SDimitry Andric   }
37004eeddc0SDimitry Andric 
37104eeddc0SDimitry Andric   void VisitUnaryOperator(const UnaryOperator *S) {
37281ad6265SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
37304eeddc0SDimitry Andric     assert(SubExpr != nullptr);
37404eeddc0SDimitry Andric 
37504eeddc0SDimitry Andric     switch (S->getOpcode()) {
37604eeddc0SDimitry Andric     case UO_Deref: {
37704eeddc0SDimitry Andric       // Skip past a reference to handle dereference of a dependent pointer.
37804eeddc0SDimitry Andric       const auto *SubExprVal = cast_or_null<PointerValue>(
37904eeddc0SDimitry Andric           Env.getValue(*SubExpr, SkipPast::Reference));
38004eeddc0SDimitry Andric       if (SubExprVal == nullptr)
38104eeddc0SDimitry Andric         break;
38204eeddc0SDimitry Andric 
38304eeddc0SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
38404eeddc0SDimitry Andric       Env.setStorageLocation(*S, Loc);
38504eeddc0SDimitry Andric       Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
38604eeddc0SDimitry Andric                             SubExprVal->getPointeeLoc())));
38704eeddc0SDimitry Andric       break;
38804eeddc0SDimitry Andric     }
38904eeddc0SDimitry Andric     case UO_AddrOf: {
39004eeddc0SDimitry Andric       // Do not form a pointer to a reference. If `SubExpr` is assigned a
39104eeddc0SDimitry Andric       // `ReferenceValue` then form a value that points to the location of its
39204eeddc0SDimitry Andric       // pointee.
39304eeddc0SDimitry Andric       StorageLocation *PointeeLoc =
39404eeddc0SDimitry Andric           Env.getStorageLocation(*SubExpr, SkipPast::Reference);
39504eeddc0SDimitry Andric       if (PointeeLoc == nullptr)
39604eeddc0SDimitry Andric         break;
39704eeddc0SDimitry Andric 
39804eeddc0SDimitry Andric       auto &PointerLoc = Env.createStorageLocation(*S);
39904eeddc0SDimitry Andric       auto &PointerVal =
40004eeddc0SDimitry Andric           Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
40104eeddc0SDimitry Andric       Env.setStorageLocation(*S, PointerLoc);
40204eeddc0SDimitry Andric       Env.setValue(PointerLoc, PointerVal);
40304eeddc0SDimitry Andric       break;
40404eeddc0SDimitry Andric     }
40581ad6265SDimitry Andric     case UO_LNot: {
40681ad6265SDimitry Andric       auto *SubExprVal =
40781ad6265SDimitry Andric           dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr, SkipPast::None));
40881ad6265SDimitry Andric       if (SubExprVal == nullptr)
40981ad6265SDimitry Andric         break;
41081ad6265SDimitry Andric 
41181ad6265SDimitry Andric       auto &ExprLoc = Env.createStorageLocation(*S);
41281ad6265SDimitry Andric       Env.setStorageLocation(*S, ExprLoc);
41381ad6265SDimitry Andric       Env.setValue(ExprLoc, Env.makeNot(*SubExprVal));
41481ad6265SDimitry Andric       break;
41581ad6265SDimitry Andric     }
41604eeddc0SDimitry Andric     default:
41704eeddc0SDimitry Andric       break;
41804eeddc0SDimitry Andric     }
41904eeddc0SDimitry Andric   }
42004eeddc0SDimitry Andric 
42104eeddc0SDimitry Andric   void VisitCXXThisExpr(const CXXThisExpr *S) {
42204eeddc0SDimitry Andric     auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();
42381ad6265SDimitry Andric     if (ThisPointeeLoc == nullptr)
42481ad6265SDimitry Andric       // Unions are not supported yet, and will not have a location for the
42581ad6265SDimitry Andric       // `this` expression's pointee.
42681ad6265SDimitry Andric       return;
42704eeddc0SDimitry Andric 
42804eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
42904eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
43004eeddc0SDimitry Andric     Env.setValue(Loc, Env.takeOwnership(
43104eeddc0SDimitry Andric                           std::make_unique<PointerValue>(*ThisPointeeLoc)));
43204eeddc0SDimitry Andric   }
43304eeddc0SDimitry Andric 
434*bdd1243dSDimitry Andric   void VisitReturnStmt(const ReturnStmt *S) {
435*bdd1243dSDimitry Andric     if (!Env.getAnalysisOptions().ContextSensitiveOpts)
436*bdd1243dSDimitry Andric       return;
437*bdd1243dSDimitry Andric 
438*bdd1243dSDimitry Andric     auto *Ret = S->getRetValue();
439*bdd1243dSDimitry Andric     if (Ret == nullptr)
440*bdd1243dSDimitry Andric       return;
441*bdd1243dSDimitry Andric 
442*bdd1243dSDimitry Andric     auto *Val = Env.getValue(*Ret, SkipPast::None);
443*bdd1243dSDimitry Andric     if (Val == nullptr)
444*bdd1243dSDimitry Andric       return;
445*bdd1243dSDimitry Andric 
446*bdd1243dSDimitry Andric     // FIXME: Support reference-type returns.
447*bdd1243dSDimitry Andric     if (Val->getKind() == Value::Kind::Reference)
448*bdd1243dSDimitry Andric       return;
449*bdd1243dSDimitry Andric 
450*bdd1243dSDimitry Andric     auto *Loc = Env.getReturnStorageLocation();
451*bdd1243dSDimitry Andric     assert(Loc != nullptr);
452*bdd1243dSDimitry Andric     // FIXME: Support reference-type returns.
453*bdd1243dSDimitry Andric     if (Loc->getType()->isReferenceType())
454*bdd1243dSDimitry Andric       return;
455*bdd1243dSDimitry Andric 
456*bdd1243dSDimitry Andric     // FIXME: Model NRVO.
457*bdd1243dSDimitry Andric     Env.setValue(*Loc, *Val);
458*bdd1243dSDimitry Andric   }
459*bdd1243dSDimitry Andric 
46004eeddc0SDimitry Andric   void VisitMemberExpr(const MemberExpr *S) {
46104eeddc0SDimitry Andric     ValueDecl *Member = S->getMemberDecl();
46204eeddc0SDimitry Andric     assert(Member != nullptr);
46304eeddc0SDimitry Andric 
46404eeddc0SDimitry Andric     // FIXME: Consider assigning pointer values to function member expressions.
46504eeddc0SDimitry Andric     if (Member->isFunctionOrFunctionTemplate())
46604eeddc0SDimitry Andric       return;
46704eeddc0SDimitry Andric 
468*bdd1243dSDimitry Andric     // FIXME: if/when we add support for modeling enums, use that support here.
469*bdd1243dSDimitry Andric     if (isa<EnumConstantDecl>(Member))
470*bdd1243dSDimitry Andric       return;
471*bdd1243dSDimitry Andric 
47281ad6265SDimitry Andric     if (auto *D = dyn_cast<VarDecl>(Member)) {
47381ad6265SDimitry Andric       if (D->hasGlobalStorage()) {
47481ad6265SDimitry Andric         auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
47581ad6265SDimitry Andric         if (VarDeclLoc == nullptr)
47681ad6265SDimitry Andric           return;
47781ad6265SDimitry Andric 
47881ad6265SDimitry Andric         if (VarDeclLoc->getType()->isReferenceType()) {
479*bdd1243dSDimitry Andric           assert(isa_and_nonnull<ReferenceValue>(Env.getValue((*VarDeclLoc))) &&
480*bdd1243dSDimitry Andric                  "reference-typed declarations map to `ReferenceValue`s");
48181ad6265SDimitry Andric           Env.setStorageLocation(*S, *VarDeclLoc);
48281ad6265SDimitry Andric         } else {
48381ad6265SDimitry Andric           auto &Loc = Env.createStorageLocation(*S);
48481ad6265SDimitry Andric           Env.setStorageLocation(*S, Loc);
48581ad6265SDimitry Andric           Env.setValue(Loc, Env.takeOwnership(
48681ad6265SDimitry Andric                                 std::make_unique<ReferenceValue>(*VarDeclLoc)));
48781ad6265SDimitry Andric         }
48881ad6265SDimitry Andric         return;
48981ad6265SDimitry Andric       }
49081ad6265SDimitry Andric     }
49181ad6265SDimitry Andric 
49204eeddc0SDimitry Andric     // The receiver can be either a value or a pointer to a value. Skip past the
49304eeddc0SDimitry Andric     // indirection to handle both cases.
49404eeddc0SDimitry Andric     auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
49504eeddc0SDimitry Andric         Env.getStorageLocation(*S->getBase(), SkipPast::ReferenceThenPointer));
49604eeddc0SDimitry Andric     if (BaseLoc == nullptr)
49704eeddc0SDimitry Andric       return;
49804eeddc0SDimitry Andric 
49904eeddc0SDimitry Andric     auto &MemberLoc = BaseLoc->getChild(*Member);
50004eeddc0SDimitry Andric     if (MemberLoc.getType()->isReferenceType()) {
501*bdd1243dSDimitry Andric       // Based on its type, `MemberLoc` must be mapped either to nothing or to a
502*bdd1243dSDimitry Andric       // `ReferenceValue`. For the former, we won't set a storage location for
503*bdd1243dSDimitry Andric       // this expression, so as to maintain an invariant lvalue expressions;
504*bdd1243dSDimitry Andric       // namely, that their location maps to a `ReferenceValue`.  In this,
505*bdd1243dSDimitry Andric       // lvalues are unlike other expressions, where it is valid for their
506*bdd1243dSDimitry Andric       // location to map to nothing (because they are not modeled).
507*bdd1243dSDimitry Andric       //
508*bdd1243dSDimitry Andric       // Note: we need this invariant for lvalues so that, when accessing a
509*bdd1243dSDimitry Andric       // value, we can distinguish an rvalue from an lvalue. An alternative
510*bdd1243dSDimitry Andric       // design, which takes the expression's value category into account, would
511*bdd1243dSDimitry Andric       // avoid the need for this invariant.
512*bdd1243dSDimitry Andric       if (auto *V = Env.getValue(MemberLoc)) {
513*bdd1243dSDimitry Andric         assert(isa<ReferenceValue>(V) &&
514*bdd1243dSDimitry Andric                "reference-typed declarations map to `ReferenceValue`s");
51504eeddc0SDimitry Andric         Env.setStorageLocation(*S, MemberLoc);
516*bdd1243dSDimitry Andric       }
51704eeddc0SDimitry Andric     } else {
51804eeddc0SDimitry Andric       auto &Loc = Env.createStorageLocation(*S);
51904eeddc0SDimitry Andric       Env.setStorageLocation(*S, Loc);
52004eeddc0SDimitry Andric       Env.setValue(
52104eeddc0SDimitry Andric           Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(MemberLoc)));
52204eeddc0SDimitry Andric     }
52304eeddc0SDimitry Andric   }
52404eeddc0SDimitry Andric 
52504eeddc0SDimitry Andric   void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {
52604eeddc0SDimitry Andric     const Expr *InitExpr = S->getExpr();
52704eeddc0SDimitry Andric     assert(InitExpr != nullptr);
52804eeddc0SDimitry Andric 
52904eeddc0SDimitry Andric     Value *InitExprVal = Env.getValue(*InitExpr, SkipPast::None);
53004eeddc0SDimitry Andric     if (InitExprVal == nullptr)
53104eeddc0SDimitry Andric       return;
53204eeddc0SDimitry Andric 
53304eeddc0SDimitry Andric     const FieldDecl *Field = S->getField();
53404eeddc0SDimitry Andric     assert(Field != nullptr);
53504eeddc0SDimitry Andric 
53604eeddc0SDimitry Andric     auto &ThisLoc =
53704eeddc0SDimitry Andric         *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation());
53804eeddc0SDimitry Andric     auto &FieldLoc = ThisLoc.getChild(*Field);
53904eeddc0SDimitry Andric     Env.setValue(FieldLoc, *InitExprVal);
54004eeddc0SDimitry Andric   }
54104eeddc0SDimitry Andric 
54204eeddc0SDimitry Andric   void VisitCXXConstructExpr(const CXXConstructExpr *S) {
54304eeddc0SDimitry Andric     const CXXConstructorDecl *ConstructorDecl = S->getConstructor();
54404eeddc0SDimitry Andric     assert(ConstructorDecl != nullptr);
54504eeddc0SDimitry Andric 
54604eeddc0SDimitry Andric     if (ConstructorDecl->isCopyOrMoveConstructor()) {
54704eeddc0SDimitry Andric       assert(S->getNumArgs() == 1);
54804eeddc0SDimitry Andric 
54904eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
55004eeddc0SDimitry Andric       assert(Arg != nullptr);
55104eeddc0SDimitry Andric 
55204eeddc0SDimitry Andric       if (S->isElidable()) {
55304eeddc0SDimitry Andric         auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::Reference);
55404eeddc0SDimitry Andric         if (ArgLoc == nullptr)
55504eeddc0SDimitry Andric           return;
55604eeddc0SDimitry Andric 
55704eeddc0SDimitry Andric         Env.setStorageLocation(*S, *ArgLoc);
55804eeddc0SDimitry Andric       } else if (auto *ArgVal = Env.getValue(*Arg, SkipPast::Reference)) {
55904eeddc0SDimitry Andric         auto &Loc = Env.createStorageLocation(*S);
56004eeddc0SDimitry Andric         Env.setStorageLocation(*S, Loc);
56104eeddc0SDimitry Andric         Env.setValue(Loc, *ArgVal);
56204eeddc0SDimitry Andric       }
56304eeddc0SDimitry Andric       return;
56404eeddc0SDimitry Andric     }
56504eeddc0SDimitry Andric 
56604eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
56704eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
56804eeddc0SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
56904eeddc0SDimitry Andric       Env.setValue(Loc, *Val);
570*bdd1243dSDimitry Andric 
571*bdd1243dSDimitry Andric     transferInlineCall(S, ConstructorDecl);
57204eeddc0SDimitry Andric   }
57304eeddc0SDimitry Andric 
57404eeddc0SDimitry Andric   void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {
57504eeddc0SDimitry Andric     if (S->getOperator() == OO_Equal) {
57604eeddc0SDimitry Andric       assert(S->getNumArgs() == 2);
57704eeddc0SDimitry Andric 
57804eeddc0SDimitry Andric       const Expr *Arg0 = S->getArg(0);
57904eeddc0SDimitry Andric       assert(Arg0 != nullptr);
58004eeddc0SDimitry Andric 
58104eeddc0SDimitry Andric       const Expr *Arg1 = S->getArg(1);
58204eeddc0SDimitry Andric       assert(Arg1 != nullptr);
58304eeddc0SDimitry Andric 
58404eeddc0SDimitry Andric       // Evaluate only copy and move assignment operators.
58504eeddc0SDimitry Andric       auto *Arg0Type = Arg0->getType()->getUnqualifiedDesugaredType();
58604eeddc0SDimitry Andric       auto *Arg1Type = Arg1->getType()->getUnqualifiedDesugaredType();
58704eeddc0SDimitry Andric       if (Arg0Type != Arg1Type)
58804eeddc0SDimitry Andric         return;
58904eeddc0SDimitry Andric 
59004eeddc0SDimitry Andric       auto *ObjectLoc = Env.getStorageLocation(*Arg0, SkipPast::Reference);
59104eeddc0SDimitry Andric       if (ObjectLoc == nullptr)
59204eeddc0SDimitry Andric         return;
59304eeddc0SDimitry Andric 
59404eeddc0SDimitry Andric       auto *Val = Env.getValue(*Arg1, SkipPast::Reference);
59504eeddc0SDimitry Andric       if (Val == nullptr)
59604eeddc0SDimitry Andric         return;
59704eeddc0SDimitry Andric 
59881ad6265SDimitry Andric       // Assign a value to the storage location of the object.
59904eeddc0SDimitry Andric       Env.setValue(*ObjectLoc, *Val);
60081ad6265SDimitry Andric 
60181ad6265SDimitry Andric       // FIXME: Add a test for the value of the whole expression.
60281ad6265SDimitry Andric       // Assign a storage location for the whole expression.
60381ad6265SDimitry Andric       Env.setStorageLocation(*S, *ObjectLoc);
60404eeddc0SDimitry Andric     }
60504eeddc0SDimitry Andric   }
60604eeddc0SDimitry Andric 
60704eeddc0SDimitry Andric   void VisitCXXFunctionalCastExpr(const CXXFunctionalCastExpr *S) {
60804eeddc0SDimitry Andric     if (S->getCastKind() == CK_ConstructorConversion) {
60904eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
61004eeddc0SDimitry Andric       assert(SubExpr != nullptr);
61104eeddc0SDimitry Andric 
61204eeddc0SDimitry Andric       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
61304eeddc0SDimitry Andric       if (SubExprLoc == nullptr)
61404eeddc0SDimitry Andric         return;
61504eeddc0SDimitry Andric 
61604eeddc0SDimitry Andric       Env.setStorageLocation(*S, *SubExprLoc);
61704eeddc0SDimitry Andric     }
61804eeddc0SDimitry Andric   }
61904eeddc0SDimitry Andric 
62004eeddc0SDimitry Andric   void VisitCXXTemporaryObjectExpr(const CXXTemporaryObjectExpr *S) {
62104eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
62204eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
62304eeddc0SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
62404eeddc0SDimitry Andric       Env.setValue(Loc, *Val);
62504eeddc0SDimitry Andric   }
62604eeddc0SDimitry Andric 
62704eeddc0SDimitry Andric   void VisitCallExpr(const CallExpr *S) {
62881ad6265SDimitry Andric     // Of clang's builtins, only `__builtin_expect` is handled explicitly, since
62981ad6265SDimitry Andric     // others (like trap, debugtrap, and unreachable) are handled by CFG
63081ad6265SDimitry Andric     // construction.
63104eeddc0SDimitry Andric     if (S->isCallToStdMove()) {
63204eeddc0SDimitry Andric       assert(S->getNumArgs() == 1);
63304eeddc0SDimitry Andric 
63404eeddc0SDimitry Andric       const Expr *Arg = S->getArg(0);
63504eeddc0SDimitry Andric       assert(Arg != nullptr);
63604eeddc0SDimitry Andric 
63704eeddc0SDimitry Andric       auto *ArgLoc = Env.getStorageLocation(*Arg, SkipPast::None);
63804eeddc0SDimitry Andric       if (ArgLoc == nullptr)
63904eeddc0SDimitry Andric         return;
64004eeddc0SDimitry Andric 
64104eeddc0SDimitry Andric       Env.setStorageLocation(*S, *ArgLoc);
64281ad6265SDimitry Andric     } else if (S->getDirectCallee() != nullptr &&
64381ad6265SDimitry Andric                S->getDirectCallee()->getBuiltinID() ==
64481ad6265SDimitry Andric                    Builtin::BI__builtin_expect) {
64581ad6265SDimitry Andric       assert(S->getNumArgs() > 0);
64681ad6265SDimitry Andric       assert(S->getArg(0) != nullptr);
64781ad6265SDimitry Andric       // `__builtin_expect` returns by-value, so strip away any potential
64881ad6265SDimitry Andric       // references in the argument.
64981ad6265SDimitry Andric       auto *ArgLoc = Env.getStorageLocation(*S->getArg(0), SkipPast::Reference);
65081ad6265SDimitry Andric       if (ArgLoc == nullptr)
65181ad6265SDimitry Andric         return;
65281ad6265SDimitry Andric       Env.setStorageLocation(*S, *ArgLoc);
653972a253aSDimitry Andric     } else if (const FunctionDecl *F = S->getDirectCallee()) {
654*bdd1243dSDimitry Andric       transferInlineCall(S, F);
65504eeddc0SDimitry Andric     }
65604eeddc0SDimitry Andric   }
65704eeddc0SDimitry Andric 
65804eeddc0SDimitry Andric   void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {
65904eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
66004eeddc0SDimitry Andric     assert(SubExpr != nullptr);
66104eeddc0SDimitry Andric 
66204eeddc0SDimitry Andric     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
66304eeddc0SDimitry Andric     if (SubExprLoc == nullptr)
66404eeddc0SDimitry Andric       return;
66504eeddc0SDimitry Andric 
66604eeddc0SDimitry Andric     Env.setStorageLocation(*S, *SubExprLoc);
66704eeddc0SDimitry Andric   }
66804eeddc0SDimitry Andric 
66904eeddc0SDimitry Andric   void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {
67004eeddc0SDimitry Andric     const Expr *SubExpr = S->getSubExpr();
67104eeddc0SDimitry Andric     assert(SubExpr != nullptr);
67204eeddc0SDimitry Andric 
67304eeddc0SDimitry Andric     auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
67404eeddc0SDimitry Andric     if (SubExprLoc == nullptr)
67504eeddc0SDimitry Andric       return;
67604eeddc0SDimitry Andric 
67704eeddc0SDimitry Andric     Env.setStorageLocation(*S, *SubExprLoc);
67804eeddc0SDimitry Andric   }
67904eeddc0SDimitry Andric 
68004eeddc0SDimitry Andric   void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {
68104eeddc0SDimitry Andric     if (S->getCastKind() == CK_NoOp) {
68204eeddc0SDimitry Andric       const Expr *SubExpr = S->getSubExpr();
68304eeddc0SDimitry Andric       assert(SubExpr != nullptr);
68404eeddc0SDimitry Andric 
68504eeddc0SDimitry Andric       auto *SubExprLoc = Env.getStorageLocation(*SubExpr, SkipPast::None);
68604eeddc0SDimitry Andric       if (SubExprLoc == nullptr)
68704eeddc0SDimitry Andric         return;
68804eeddc0SDimitry Andric 
68904eeddc0SDimitry Andric       Env.setStorageLocation(*S, *SubExprLoc);
69004eeddc0SDimitry Andric     }
69104eeddc0SDimitry Andric   }
69204eeddc0SDimitry Andric 
69304eeddc0SDimitry Andric   void VisitConditionalOperator(const ConditionalOperator *S) {
69404eeddc0SDimitry Andric     // FIXME: Revisit this once flow conditions are added to the framework. For
69504eeddc0SDimitry Andric     // `a = b ? c : d` we can add `b => a == c && !b => a == d` to the flow
69604eeddc0SDimitry Andric     // condition.
69704eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
69804eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
69904eeddc0SDimitry Andric     if (Value *Val = Env.createValue(S->getType()))
70004eeddc0SDimitry Andric       Env.setValue(Loc, *Val);
70104eeddc0SDimitry Andric   }
70204eeddc0SDimitry Andric 
70304eeddc0SDimitry Andric   void VisitInitListExpr(const InitListExpr *S) {
70404eeddc0SDimitry Andric     QualType Type = S->getType();
70504eeddc0SDimitry Andric 
70604eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
70704eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
70804eeddc0SDimitry Andric 
70904eeddc0SDimitry Andric     auto *Val = Env.createValue(Type);
71004eeddc0SDimitry Andric     if (Val == nullptr)
71104eeddc0SDimitry Andric       return;
71204eeddc0SDimitry Andric 
71304eeddc0SDimitry Andric     Env.setValue(Loc, *Val);
71404eeddc0SDimitry Andric 
71504eeddc0SDimitry Andric     if (Type->isStructureOrClassType()) {
716972a253aSDimitry Andric       for (auto It : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
717972a253aSDimitry Andric         const FieldDecl *Field = std::get<0>(It);
71804eeddc0SDimitry Andric         assert(Field != nullptr);
71904eeddc0SDimitry Andric 
720972a253aSDimitry Andric         const Expr *Init = std::get<1>(It);
72104eeddc0SDimitry Andric         assert(Init != nullptr);
72204eeddc0SDimitry Andric 
72304eeddc0SDimitry Andric         if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
72404eeddc0SDimitry Andric           cast<StructValue>(Val)->setChild(*Field, *InitVal);
72504eeddc0SDimitry Andric       }
72604eeddc0SDimitry Andric     }
72704eeddc0SDimitry Andric     // FIXME: Implement array initialization.
72804eeddc0SDimitry Andric   }
72904eeddc0SDimitry Andric 
73004eeddc0SDimitry Andric   void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
73104eeddc0SDimitry Andric     auto &Loc = Env.createStorageLocation(*S);
73204eeddc0SDimitry Andric     Env.setStorageLocation(*S, Loc);
73304eeddc0SDimitry Andric     Env.setValue(Loc, Env.getBoolLiteralValue(S->getValue()));
73404eeddc0SDimitry Andric   }
73504eeddc0SDimitry Andric 
73681ad6265SDimitry Andric   void VisitParenExpr(const ParenExpr *S) {
73781ad6265SDimitry Andric     // The CFG does not contain `ParenExpr` as top-level statements in basic
73881ad6265SDimitry Andric     // blocks, however manual traversal to sub-expressions may encounter them.
73981ad6265SDimitry Andric     // Redirect to the sub-expression.
74081ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
74181ad6265SDimitry Andric     assert(SubExpr != nullptr);
74281ad6265SDimitry Andric     Visit(SubExpr);
74381ad6265SDimitry Andric   }
74481ad6265SDimitry Andric 
74581ad6265SDimitry Andric   void VisitExprWithCleanups(const ExprWithCleanups *S) {
74681ad6265SDimitry Andric     // The CFG does not contain `ExprWithCleanups` as top-level statements in
74781ad6265SDimitry Andric     // basic blocks, however manual traversal to sub-expressions may encounter
74881ad6265SDimitry Andric     // them. Redirect to the sub-expression.
74981ad6265SDimitry Andric     auto *SubExpr = S->getSubExpr();
75081ad6265SDimitry Andric     assert(SubExpr != nullptr);
75181ad6265SDimitry Andric     Visit(SubExpr);
75281ad6265SDimitry Andric   }
75381ad6265SDimitry Andric 
75404eeddc0SDimitry Andric private:
75581ad6265SDimitry Andric   BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {
75681ad6265SDimitry Andric     // `SubExpr` and its parent logic operator might be part of different basic
75781ad6265SDimitry Andric     // blocks. We try to access the value that is assigned to `SubExpr` in the
75881ad6265SDimitry Andric     // corresponding environment.
75981ad6265SDimitry Andric     if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) {
76081ad6265SDimitry Andric       if (auto *Val = dyn_cast_or_null<BoolValue>(
76181ad6265SDimitry Andric               SubExprEnv->getValue(SubExpr, SkipPast::Reference)))
76281ad6265SDimitry Andric         return *Val;
76381ad6265SDimitry Andric     }
76481ad6265SDimitry Andric 
76581ad6265SDimitry Andric     if (Env.getStorageLocation(SubExpr, SkipPast::None) == nullptr) {
76681ad6265SDimitry Andric       // Sub-expressions that are logic operators are not added in basic blocks
76781ad6265SDimitry Andric       // (e.g. see CFG for `bool d = a && (b || c);`). If `SubExpr` is a logic
76881ad6265SDimitry Andric       // operator, it may not have been evaluated and assigned a value yet. In
76981ad6265SDimitry Andric       // that case, we need to first visit `SubExpr` and then try to get the
77081ad6265SDimitry Andric       // value that gets assigned to it.
77181ad6265SDimitry Andric       Visit(&SubExpr);
77281ad6265SDimitry Andric     }
77381ad6265SDimitry Andric 
77481ad6265SDimitry Andric     if (auto *Val = dyn_cast_or_null<BoolValue>(
77581ad6265SDimitry Andric             Env.getValue(SubExpr, SkipPast::Reference)))
77681ad6265SDimitry Andric       return *Val;
77781ad6265SDimitry Andric 
77881ad6265SDimitry Andric     // If the value of `SubExpr` is still unknown, we create a fresh symbolic
77981ad6265SDimitry Andric     // boolean value for it.
78081ad6265SDimitry Andric     return Env.makeAtomicBoolValue();
78181ad6265SDimitry Andric   }
78281ad6265SDimitry Andric 
783*bdd1243dSDimitry Andric   // If context sensitivity is enabled, try to analyze the body of the callee
784*bdd1243dSDimitry Andric   // `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.
785*bdd1243dSDimitry Andric   template <typename E>
786*bdd1243dSDimitry Andric   void transferInlineCall(const E *S, const FunctionDecl *F) {
787*bdd1243dSDimitry Andric     const auto &Options = Env.getAnalysisOptions();
788*bdd1243dSDimitry Andric     if (!(Options.ContextSensitiveOpts &&
789*bdd1243dSDimitry Andric           Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))
790*bdd1243dSDimitry Andric       return;
791*bdd1243dSDimitry Andric 
792*bdd1243dSDimitry Andric     const ControlFlowContext *CFCtx = Env.getControlFlowContext(F);
793*bdd1243dSDimitry Andric     if (!CFCtx)
794*bdd1243dSDimitry Andric       return;
795*bdd1243dSDimitry Andric 
796*bdd1243dSDimitry Andric     // FIXME: We don't support context-sensitive analysis of recursion, so
797*bdd1243dSDimitry Andric     // we should return early here if `F` is the same as the `FunctionDecl`
798*bdd1243dSDimitry Andric     // holding `S` itself.
799*bdd1243dSDimitry Andric 
800*bdd1243dSDimitry Andric     auto ExitBlock = CFCtx->getCFG().getExit().getBlockID();
801*bdd1243dSDimitry Andric 
802*bdd1243dSDimitry Andric     if (const auto *NonConstructExpr = dyn_cast<CallExpr>(S)) {
803*bdd1243dSDimitry Andric       // Note that it is important for the storage location of `S` to be set
804*bdd1243dSDimitry Andric       // before `pushCall`, because the latter uses it to set the storage
805*bdd1243dSDimitry Andric       // location for `return`.
806*bdd1243dSDimitry Andric       auto &ReturnLoc = Env.createStorageLocation(*S);
807*bdd1243dSDimitry Andric       Env.setStorageLocation(*S, ReturnLoc);
808*bdd1243dSDimitry Andric     }
809*bdd1243dSDimitry Andric     auto CalleeEnv = Env.pushCall(S);
810*bdd1243dSDimitry Andric 
811*bdd1243dSDimitry Andric     // FIXME: Use the same analysis as the caller for the callee. Note,
812*bdd1243dSDimitry Andric     // though, that doing so would require support for changing the analysis's
813*bdd1243dSDimitry Andric     // ASTContext.
814*bdd1243dSDimitry Andric     assert(CFCtx->getDecl() != nullptr &&
815*bdd1243dSDimitry Andric            "ControlFlowContexts in the environment should always carry a decl");
816*bdd1243dSDimitry Andric     auto Analysis = NoopAnalysis(CFCtx->getDecl()->getASTContext(),
817*bdd1243dSDimitry Andric                                  DataflowAnalysisOptions{Options});
818*bdd1243dSDimitry Andric 
819*bdd1243dSDimitry Andric     auto BlockToOutputState =
820*bdd1243dSDimitry Andric         dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv);
821*bdd1243dSDimitry Andric     assert(BlockToOutputState);
822*bdd1243dSDimitry Andric     assert(ExitBlock < BlockToOutputState->size());
823*bdd1243dSDimitry Andric 
824*bdd1243dSDimitry Andric     auto ExitState = (*BlockToOutputState)[ExitBlock];
825*bdd1243dSDimitry Andric     assert(ExitState);
826*bdd1243dSDimitry Andric 
827*bdd1243dSDimitry Andric     Env.popCall(ExitState->Env);
828*bdd1243dSDimitry Andric   }
829*bdd1243dSDimitry Andric 
83081ad6265SDimitry Andric   const StmtToEnvMap &StmtToEnv;
83104eeddc0SDimitry Andric   Environment &Env;
83204eeddc0SDimitry Andric };
83304eeddc0SDimitry Andric 
834*bdd1243dSDimitry Andric void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) {
835*bdd1243dSDimitry Andric   TransferVisitor(StmtToEnv, Env).Visit(&S);
83604eeddc0SDimitry Andric }
83704eeddc0SDimitry Andric 
83804eeddc0SDimitry Andric } // namespace dataflow
83904eeddc0SDimitry Andric } // namespace clang
840