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