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