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
getEnvironment(const Stmt & S) const4206c3fb27SDimitry 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
evaluateBooleanEquality(const Expr & LHS,const Expr & RHS,Environment & Env)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
unpackValue(BoolValue & V,Environment & Env)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.
maybeUnpackLValueExpr(const Expr & E,Environment & Env)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
propagateValue(const Expr & From,const Expr & To,Environment & Env)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
propagateStorageLocation(const Expr & From,const Expr & To,Environment & Env)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.
propagateValueOrStorageLocation(const Expr & From,const Expr & To,Environment & Env)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:
TransferVisitor(const StmtToEnvMap & StmtToEnv,Environment & Env,Environment::ValueModel & Model)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
VisitBinaryOperator(const BinaryOperator * S)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
VisitDeclRefExpr(const DeclRefExpr * S)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
VisitDeclStmt(const DeclStmt * S)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
ProcessVarDecl(const VarDecl & D)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
VisitImplicitCastExpr(const ImplicitCastExpr * S)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
VisitUnaryOperator(const UnaryOperator * S)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
VisitCXXThisExpr(const CXXThisExpr * S)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
VisitCXXNewExpr(const CXXNewExpr * S)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
VisitCXXDeleteExpr(const CXXDeleteExpr * S)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
VisitReturnStmt(const ReturnStmt * S)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
VisitMemberExpr(const MemberExpr * S)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
VisitCXXDefaultArgExpr(const CXXDefaultArgExpr * S)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
VisitCXXDefaultInitExpr(const CXXDefaultInitExpr * S)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
VisitCXXConstructExpr(const CXXConstructExpr * S)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
VisitCXXOperatorCallExpr(const CXXOperatorCallExpr * S)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
VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator * RBO)619*0fca6ea1SDimitry Andric void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) {
620*0fca6ea1SDimitry Andric propagateValue(*RBO->getSemanticForm(), *RBO, Env);
62104eeddc0SDimitry Andric }
62204eeddc0SDimitry Andric
VisitCallExpr(const CallExpr * S)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
VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr * S)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
VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr * S)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
VisitCXXStaticCastExpr(const CXXStaticCastExpr * S)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
VisitConditionalOperator(const ConditionalOperator * S)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
VisitInitListExpr(const InitListExpr * S)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
VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr * S)79404eeddc0SDimitry Andric void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {
7955f757f3fSDimitry Andric Env.setValue(*S, Env.getBoolLiteralValue(S->getValue()));
79606c3fb27SDimitry Andric }
79706c3fb27SDimitry Andric
VisitIntegerLiteral(const IntegerLiteral * S)79806c3fb27SDimitry Andric void VisitIntegerLiteral(const IntegerLiteral *S) {
7995f757f3fSDimitry Andric Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));
80004eeddc0SDimitry Andric }
80104eeddc0SDimitry Andric
VisitParenExpr(const ParenExpr * S)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
VisitExprWithCleanups(const ExprWithCleanups * S)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.
getLogicOperatorSubExprValue(const Expr & SubExpr)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>
transferInlineCall(const E * S,const FunctionDecl * F)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
transfer(const StmtToEnvMap & StmtToEnv,const Stmt & S,Environment & Env,Environment::ValueModel & Model)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