Path: blob/main/contrib/llvm-project/clang/lib/Analysis/FlowSensitive/Transfer.cpp
35266 views
//===-- Transfer.cpp --------------------------------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines transfer functions that evaluate program statements and9// update an environment accordingly.10//11//===----------------------------------------------------------------------===//1213#include "clang/Analysis/FlowSensitive/Transfer.h"14#include "clang/AST/Decl.h"15#include "clang/AST/DeclBase.h"16#include "clang/AST/DeclCXX.h"17#include "clang/AST/Expr.h"18#include "clang/AST/ExprCXX.h"19#include "clang/AST/OperationKinds.h"20#include "clang/AST/Stmt.h"21#include "clang/AST/StmtVisitor.h"22#include "clang/Analysis/FlowSensitive/ASTOps.h"23#include "clang/Analysis/FlowSensitive/AdornedCFG.h"24#include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h"25#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"26#include "clang/Analysis/FlowSensitive/NoopAnalysis.h"27#include "clang/Analysis/FlowSensitive/RecordOps.h"28#include "clang/Analysis/FlowSensitive/Value.h"29#include "clang/Basic/Builtins.h"30#include "clang/Basic/OperatorKinds.h"31#include "llvm/Support/Casting.h"32#include "llvm/Support/Debug.h"33#include <assert.h>34#include <cassert>3536#define DEBUG_TYPE "dataflow"3738namespace clang {39namespace dataflow {4041const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const {42auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S));43if (BlockIt == ACFG.getStmtToBlock().end()) {44assert(false);45// Return null to avoid dereferencing the end iterator in non-assert builds.46return nullptr;47}48if (!ACFG.isBlockReachable(*BlockIt->getSecond()))49return nullptr;50if (BlockIt->getSecond()->getBlockID() == CurBlockID)51return &CurState.Env;52const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()];53if (!(State))54return nullptr;55return &State->Env;56}5758static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS,59Environment &Env) {60Value *LHSValue = Env.getValue(LHS);61Value *RHSValue = Env.getValue(RHS);6263if (LHSValue == RHSValue)64return Env.getBoolLiteralValue(true);6566if (auto *LHSBool = dyn_cast_or_null<BoolValue>(LHSValue))67if (auto *RHSBool = dyn_cast_or_null<BoolValue>(RHSValue))68return Env.makeIff(*LHSBool, *RHSBool);6970if (auto *LHSPtr = dyn_cast_or_null<PointerValue>(LHSValue))71if (auto *RHSPtr = dyn_cast_or_null<PointerValue>(RHSValue))72// If the storage locations are the same, the pointers definitely compare73// the same. If the storage locations are different, they may still alias,74// so we fall through to the case below that returns an atom.75if (&LHSPtr->getPointeeLoc() == &RHSPtr->getPointeeLoc())76return Env.getBoolLiteralValue(true);7778return Env.makeAtomicBoolValue();79}8081static BoolValue &unpackValue(BoolValue &V, Environment &Env) {82if (auto *Top = llvm::dyn_cast<TopBoolValue>(&V)) {83auto &A = Env.getDataflowAnalysisContext().arena();84return A.makeBoolValue(A.makeAtomRef(Top->getAtom()));85}86return V;87}8889// Unpacks the value (if any) associated with `E` and updates `E` to the new90// value, if any unpacking occured. Also, does the lvalue-to-rvalue conversion,91// by skipping past the reference.92static Value *maybeUnpackLValueExpr(const Expr &E, Environment &Env) {93auto *Loc = Env.getStorageLocation(E);94if (Loc == nullptr)95return nullptr;96auto *Val = Env.getValue(*Loc);9798auto *B = dyn_cast_or_null<BoolValue>(Val);99if (B == nullptr)100return Val;101102auto &UnpackedVal = unpackValue(*B, Env);103if (&UnpackedVal == Val)104return Val;105Env.setValue(*Loc, UnpackedVal);106return &UnpackedVal;107}108109static void propagateValue(const Expr &From, const Expr &To, Environment &Env) {110if (From.getType()->isRecordType())111return;112if (auto *Val = Env.getValue(From))113Env.setValue(To, *Val);114}115116static void propagateStorageLocation(const Expr &From, const Expr &To,117Environment &Env) {118if (auto *Loc = Env.getStorageLocation(From))119Env.setStorageLocation(To, *Loc);120}121122// Propagates the value or storage location of `From` to `To` in cases where123// `From` may be either a glvalue or a prvalue. `To` must be a glvalue iff124// `From` is a glvalue.125static void propagateValueOrStorageLocation(const Expr &From, const Expr &To,126Environment &Env) {127assert(From.isGLValue() == To.isGLValue());128if (From.isGLValue())129propagateStorageLocation(From, To, Env);130else131propagateValue(From, To, Env);132}133134namespace {135136class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {137public:138TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env,139Environment::ValueModel &Model)140: StmtToEnv(StmtToEnv), Env(Env), Model(Model) {}141142void VisitBinaryOperator(const BinaryOperator *S) {143const Expr *LHS = S->getLHS();144assert(LHS != nullptr);145146const Expr *RHS = S->getRHS();147assert(RHS != nullptr);148149// Do compound assignments up-front, as there are so many of them and we150// don't want to list all of them in the switch statement below.151// To avoid generating unnecessary values, we don't create a new value but152// instead leave it to the specific analysis to do this if desired.153if (S->isCompoundAssignmentOp())154propagateStorageLocation(*S->getLHS(), *S, Env);155156switch (S->getOpcode()) {157case BO_Assign: {158auto *LHSLoc = Env.getStorageLocation(*LHS);159if (LHSLoc == nullptr)160break;161162auto *RHSVal = Env.getValue(*RHS);163if (RHSVal == nullptr)164break;165166// Assign a value to the storage location of the left-hand side.167Env.setValue(*LHSLoc, *RHSVal);168169// Assign a storage location for the whole expression.170Env.setStorageLocation(*S, *LHSLoc);171break;172}173case BO_LAnd:174case BO_LOr: {175BoolValue &LHSVal = getLogicOperatorSubExprValue(*LHS);176BoolValue &RHSVal = getLogicOperatorSubExprValue(*RHS);177178if (S->getOpcode() == BO_LAnd)179Env.setValue(*S, Env.makeAnd(LHSVal, RHSVal));180else181Env.setValue(*S, Env.makeOr(LHSVal, RHSVal));182break;183}184case BO_NE:185case BO_EQ: {186auto &LHSEqRHSValue = evaluateBooleanEquality(*LHS, *RHS, Env);187Env.setValue(*S, S->getOpcode() == BO_EQ ? LHSEqRHSValue188: Env.makeNot(LHSEqRHSValue));189break;190}191case BO_Comma: {192propagateValueOrStorageLocation(*RHS, *S, Env);193break;194}195default:196break;197}198}199200void VisitDeclRefExpr(const DeclRefExpr *S) {201const ValueDecl *VD = S->getDecl();202assert(VD != nullptr);203204// Some `DeclRefExpr`s aren't glvalues, so we can't associate them with a205// `StorageLocation`, and there's also no sensible `Value` that we can206// assign to them. Examples:207// - Non-static member variables208// - Non static member functions209// Note: Member operators are an exception to this, but apparently only210// if the `DeclRefExpr` is used within the callee of a211// `CXXOperatorCallExpr`. In other cases, for example when applying the212// address-of operator, the `DeclRefExpr` is a prvalue.213if (!S->isGLValue())214return;215216auto *DeclLoc = Env.getStorageLocation(*VD);217if (DeclLoc == nullptr)218return;219220Env.setStorageLocation(*S, *DeclLoc);221}222223void VisitDeclStmt(const DeclStmt *S) {224// Group decls are converted into single decls in the CFG so the cast below225// is safe.226const auto &D = *cast<VarDecl>(S->getSingleDecl());227228ProcessVarDecl(D);229}230231void ProcessVarDecl(const VarDecl &D) {232// Static local vars are already initialized in `Environment`.233if (D.hasGlobalStorage())234return;235236// If this is the holding variable for a `BindingDecl`, we may already237// have a storage location set up -- so check. (See also explanation below238// where we process the `BindingDecl`.)239if (D.getType()->isReferenceType() && Env.getStorageLocation(D) != nullptr)240return;241242assert(Env.getStorageLocation(D) == nullptr);243244Env.setStorageLocation(D, Env.createObject(D));245246// `DecompositionDecl` must be handled after we've interpreted the loc247// itself, because the binding expression refers back to the248// `DecompositionDecl` (even though it has no written name).249if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) {250// If VarDecl is a DecompositionDecl, evaluate each of its bindings. This251// needs to be evaluated after initializing the values in the storage for252// VarDecl, as the bindings refer to them.253// FIXME: Add support for ArraySubscriptExpr.254// FIXME: Consider adding AST nodes used in BindingDecls to the CFG.255for (const auto *B : Decomp->bindings()) {256if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) {257auto *DE = dyn_cast_or_null<DeclRefExpr>(ME->getBase());258if (DE == nullptr)259continue;260261// ME and its base haven't been visited because they aren't included262// in the statements of the CFG basic block.263VisitDeclRefExpr(DE);264VisitMemberExpr(ME);265266if (auto *Loc = Env.getStorageLocation(*ME))267Env.setStorageLocation(*B, *Loc);268} else if (auto *VD = B->getHoldingVar()) {269// Holding vars are used to back the `BindingDecl`s of tuple-like270// types. The holding var declarations appear after the271// `DecompositionDecl`, so we have to explicitly process them here272// to know their storage location. They will be processed a second273// time when we visit their `VarDecl`s, so we have code that protects274// against this above.275ProcessVarDecl(*VD);276auto *VDLoc = Env.getStorageLocation(*VD);277assert(VDLoc != nullptr);278Env.setStorageLocation(*B, *VDLoc);279}280}281}282}283284void VisitImplicitCastExpr(const ImplicitCastExpr *S) {285const Expr *SubExpr = S->getSubExpr();286assert(SubExpr != nullptr);287288switch (S->getCastKind()) {289case CK_IntegralToBoolean: {290// This cast creates a new, boolean value from the integral value. We291// model that with a fresh value in the environment, unless it's already a292// boolean.293if (auto *SubExprVal =294dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr)))295Env.setValue(*S, *SubExprVal);296else297// FIXME: If integer modeling is added, then update this code to create298// the boolean based on the integer model.299Env.setValue(*S, Env.makeAtomicBoolValue());300break;301}302303case CK_LValueToRValue: {304// When an L-value is used as an R-value, it may result in sharing, so we305// need to unpack any nested `Top`s.306auto *SubExprVal = maybeUnpackLValueExpr(*SubExpr, Env);307if (SubExprVal == nullptr)308break;309310Env.setValue(*S, *SubExprVal);311break;312}313314case CK_IntegralCast:315// FIXME: This cast creates a new integral value from the316// subexpression. But, because we don't model integers, we don't317// distinguish between this new value and the underlying one. If integer318// modeling is added, then update this code to create a fresh location and319// value.320case CK_UncheckedDerivedToBase:321case CK_ConstructorConversion:322case CK_UserDefinedConversion:323// FIXME: Add tests that excercise CK_UncheckedDerivedToBase,324// CK_ConstructorConversion, and CK_UserDefinedConversion.325case CK_NoOp: {326// FIXME: Consider making `Environment::getStorageLocation` skip noop327// expressions (this and other similar expressions in the file) instead328// of assigning them storage locations.329propagateValueOrStorageLocation(*SubExpr, *S, Env);330break;331}332case CK_NullToPointer: {333auto &NullPointerVal =334Env.getOrCreateNullPointerValue(S->getType()->getPointeeType());335Env.setValue(*S, NullPointerVal);336break;337}338case CK_NullToMemberPointer:339// FIXME: Implement pointers to members. For now, don't associate a value340// with this expression.341break;342case CK_FunctionToPointerDecay: {343StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr);344if (PointeeLoc == nullptr)345break;346347Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));348break;349}350case CK_BuiltinFnToFnPtr:351// Despite its name, the result type of `BuiltinFnToFnPtr` is a function,352// not a function pointer. In addition, builtin functions can only be353// called directly; it is not legal to take their address. We therefore354// don't need to create a value or storage location for them.355break;356default:357break;358}359}360361void VisitUnaryOperator(const UnaryOperator *S) {362const Expr *SubExpr = S->getSubExpr();363assert(SubExpr != nullptr);364365switch (S->getOpcode()) {366case UO_Deref: {367const auto *SubExprVal = Env.get<PointerValue>(*SubExpr);368if (SubExprVal == nullptr)369break;370371Env.setStorageLocation(*S, SubExprVal->getPointeeLoc());372break;373}374case UO_AddrOf: {375// FIXME: Model pointers to members.376if (S->getType()->isMemberPointerType())377break;378379if (StorageLocation *PointeeLoc = Env.getStorageLocation(*SubExpr))380Env.setValue(*S, Env.create<PointerValue>(*PointeeLoc));381break;382}383case UO_LNot: {384auto *SubExprVal = dyn_cast_or_null<BoolValue>(Env.getValue(*SubExpr));385if (SubExprVal == nullptr)386break;387388Env.setValue(*S, Env.makeNot(*SubExprVal));389break;390}391case UO_PreInc:392case UO_PreDec:393// Propagate the storage location and clear out any value associated with394// it (to represent the fact that the value has definitely changed).395// To avoid generating unnecessary values, we leave it to the specific396// analysis to create a new value if desired.397propagateStorageLocation(*S->getSubExpr(), *S, Env);398if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))399Env.clearValue(*Loc);400break;401case UO_PostInc:402case UO_PostDec:403// Propagate the old value, then clear out any value associated with the404// storage location (to represent the fact that the value has definitely405// changed). See above for rationale.406propagateValue(*S->getSubExpr(), *S, Env);407if (StorageLocation *Loc = Env.getStorageLocation(*S->getSubExpr()))408Env.clearValue(*Loc);409break;410default:411break;412}413}414415void VisitCXXThisExpr(const CXXThisExpr *S) {416auto *ThisPointeeLoc = Env.getThisPointeeStorageLocation();417if (ThisPointeeLoc == nullptr)418// Unions are not supported yet, and will not have a location for the419// `this` expression's pointee.420return;421422Env.setValue(*S, Env.create<PointerValue>(*ThisPointeeLoc));423}424425void VisitCXXNewExpr(const CXXNewExpr *S) {426if (Value *Val = Env.createValue(S->getType()))427Env.setValue(*S, *Val);428}429430void VisitCXXDeleteExpr(const CXXDeleteExpr *S) {431// Empty method.432// We consciously don't do anything on deletes. Diagnosing double deletes433// (for example) should be done by a specific analysis, not by the434// framework.435}436437void VisitReturnStmt(const ReturnStmt *S) {438if (!Env.getDataflowAnalysisContext().getOptions().ContextSensitiveOpts)439return;440441auto *Ret = S->getRetValue();442if (Ret == nullptr)443return;444445if (Ret->isPRValue()) {446if (Ret->getType()->isRecordType())447return;448449auto *Val = Env.getValue(*Ret);450if (Val == nullptr)451return;452453// FIXME: Model NRVO.454Env.setReturnValue(Val);455} else {456auto *Loc = Env.getStorageLocation(*Ret);457if (Loc == nullptr)458return;459460// FIXME: Model NRVO.461Env.setReturnStorageLocation(Loc);462}463}464465void VisitMemberExpr(const MemberExpr *S) {466ValueDecl *Member = S->getMemberDecl();467assert(Member != nullptr);468469// FIXME: Consider assigning pointer values to function member expressions.470if (Member->isFunctionOrFunctionTemplate())471return;472473// FIXME: if/when we add support for modeling enums, use that support here.474if (isa<EnumConstantDecl>(Member))475return;476477if (auto *D = dyn_cast<VarDecl>(Member)) {478if (D->hasGlobalStorage()) {479auto *VarDeclLoc = Env.getStorageLocation(*D);480if (VarDeclLoc == nullptr)481return;482483Env.setStorageLocation(*S, *VarDeclLoc);484return;485}486}487488RecordStorageLocation *BaseLoc = getBaseObjectLocation(*S, Env);489if (BaseLoc == nullptr)490return;491492auto *MemberLoc = BaseLoc->getChild(*Member);493if (MemberLoc == nullptr)494return;495Env.setStorageLocation(*S, *MemberLoc);496}497498void VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *S) {499const Expr *ArgExpr = S->getExpr();500assert(ArgExpr != nullptr);501propagateValueOrStorageLocation(*ArgExpr, *S, Env);502503if (S->isPRValue() && S->getType()->isRecordType()) {504auto &Loc = Env.getResultObjectLocation(*S);505Env.initializeFieldsWithValues(Loc);506}507}508509void VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *S) {510const Expr *InitExpr = S->getExpr();511assert(InitExpr != nullptr);512513// If this is a prvalue of record type, the handler for `*InitExpr` (if one514// exists) will initialize the result object; there is no value to propgate515// here.516if (S->getType()->isRecordType() && S->isPRValue())517return;518519propagateValueOrStorageLocation(*InitExpr, *S, Env);520}521522void VisitCXXConstructExpr(const CXXConstructExpr *S) {523const CXXConstructorDecl *ConstructorDecl = S->getConstructor();524assert(ConstructorDecl != nullptr);525526// `CXXConstructExpr` can have array type if default-initializing an array527// of records. We don't handle this specifically beyond potentially inlining528// the call.529if (!S->getType()->isRecordType()) {530transferInlineCall(S, ConstructorDecl);531return;532}533534RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);535536if (ConstructorDecl->isCopyOrMoveConstructor()) {537// It is permissible for a copy/move constructor to have additional538// parameters as long as they have default arguments defined for them.539assert(S->getNumArgs() != 0);540541const Expr *Arg = S->getArg(0);542assert(Arg != nullptr);543544auto *ArgLoc = Env.get<RecordStorageLocation>(*Arg);545if (ArgLoc == nullptr)546return;547548// Even if the copy/move constructor call is elidable, we choose to copy549// the record in all cases (which isn't wrong, just potentially not550// optimal).551copyRecord(*ArgLoc, Loc, Env);552return;553}554555Env.initializeFieldsWithValues(Loc, S->getType());556557transferInlineCall(S, ConstructorDecl);558}559560void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *S) {561if (S->getOperator() == OO_Equal) {562assert(S->getNumArgs() == 2);563564const Expr *Arg0 = S->getArg(0);565assert(Arg0 != nullptr);566567const Expr *Arg1 = S->getArg(1);568assert(Arg1 != nullptr);569570// Evaluate only copy and move assignment operators.571const auto *Method =572dyn_cast_or_null<CXXMethodDecl>(S->getDirectCallee());573if (!Method)574return;575if (!Method->isCopyAssignmentOperator() &&576!Method->isMoveAssignmentOperator())577return;578579RecordStorageLocation *LocSrc = nullptr;580if (Arg1->isPRValue()) {581LocSrc = &Env.getResultObjectLocation(*Arg1);582} else {583LocSrc = Env.get<RecordStorageLocation>(*Arg1);584}585auto *LocDst = Env.get<RecordStorageLocation>(*Arg0);586587if (LocSrc == nullptr || LocDst == nullptr)588return;589590copyRecord(*LocSrc, *LocDst, Env);591592// The assignment operator can have an arbitrary return type. We model the593// return value only if the return type is the same as or a base class of594// the destination type.595if (S->getType().getCanonicalType().getUnqualifiedType() !=596LocDst->getType().getCanonicalType().getUnqualifiedType()) {597auto ReturnDecl = S->getType()->getAsCXXRecordDecl();598auto DstDecl = LocDst->getType()->getAsCXXRecordDecl();599if (ReturnDecl == nullptr || DstDecl == nullptr)600return;601if (!DstDecl->isDerivedFrom(ReturnDecl))602return;603}604605if (S->isGLValue())606Env.setStorageLocation(*S, *LocDst);607else608copyRecord(*LocDst, Env.getResultObjectLocation(*S), Env);609610return;611}612613// `CXXOperatorCallExpr` can be a prvalue. Call `VisitCallExpr`() to614// initialize the prvalue's fields with values.615VisitCallExpr(S);616}617618void VisitCXXRewrittenBinaryOperator(const CXXRewrittenBinaryOperator *RBO) {619propagateValue(*RBO->getSemanticForm(), *RBO, Env);620}621622void VisitCallExpr(const CallExpr *S) {623// Of clang's builtins, only `__builtin_expect` is handled explicitly, since624// others (like trap, debugtrap, and unreachable) are handled by CFG625// construction.626if (S->isCallToStdMove()) {627assert(S->getNumArgs() == 1);628629const Expr *Arg = S->getArg(0);630assert(Arg != nullptr);631632auto *ArgLoc = Env.getStorageLocation(*Arg);633if (ArgLoc == nullptr)634return;635636Env.setStorageLocation(*S, *ArgLoc);637} else if (S->getDirectCallee() != nullptr &&638S->getDirectCallee()->getBuiltinID() ==639Builtin::BI__builtin_expect) {640assert(S->getNumArgs() > 0);641assert(S->getArg(0) != nullptr);642auto *ArgVal = Env.getValue(*S->getArg(0));643if (ArgVal == nullptr)644return;645Env.setValue(*S, *ArgVal);646} else if (const FunctionDecl *F = S->getDirectCallee()) {647transferInlineCall(S, F);648649// If this call produces a prvalue of record type, initialize its fields650// with values.651if (S->getType()->isRecordType() && S->isPRValue()) {652RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);653Env.initializeFieldsWithValues(Loc);654}655}656}657658void VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *S) {659const Expr *SubExpr = S->getSubExpr();660assert(SubExpr != nullptr);661662StorageLocation &Loc = Env.createStorageLocation(*S);663Env.setStorageLocation(*S, Loc);664665if (SubExpr->getType()->isRecordType())666// Nothing else left to do -- we initialized the record when transferring667// `SubExpr`.668return;669670if (Value *SubExprVal = Env.getValue(*SubExpr))671Env.setValue(Loc, *SubExprVal);672}673674void VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *S) {675const Expr *SubExpr = S->getSubExpr();676assert(SubExpr != nullptr);677678propagateValue(*SubExpr, *S, Env);679}680681void VisitCXXStaticCastExpr(const CXXStaticCastExpr *S) {682if (S->getCastKind() == CK_NoOp) {683const Expr *SubExpr = S->getSubExpr();684assert(SubExpr != nullptr);685686propagateValueOrStorageLocation(*SubExpr, *S, Env);687}688}689690void VisitConditionalOperator(const ConditionalOperator *S) {691const Environment *TrueEnv = StmtToEnv.getEnvironment(*S->getTrueExpr());692const Environment *FalseEnv = StmtToEnv.getEnvironment(*S->getFalseExpr());693694if (TrueEnv == nullptr || FalseEnv == nullptr) {695// If the true or false branch is dead, we may not have an environment for696// it. We could handle this specifically by forwarding the value or697// location of the live branch, but this case is rare enough that this698// probably isn't worth the additional complexity.699return;700}701702if (S->isGLValue()) {703StorageLocation *TrueLoc = TrueEnv->getStorageLocation(*S->getTrueExpr());704StorageLocation *FalseLoc =705FalseEnv->getStorageLocation(*S->getFalseExpr());706if (TrueLoc == FalseLoc && TrueLoc != nullptr)707Env.setStorageLocation(*S, *TrueLoc);708} else if (!S->getType()->isRecordType()) {709// The conditional operator can evaluate to either of the values of the710// two branches. To model this, join these two values together to yield711// the result of the conditional operator.712// Note: Most joins happen in `computeBlockInputState()`, but this case is713// different:714// - `computeBlockInputState()` (which in turn calls `Environment::join()`715// joins values associated with the _same_ expression or storage716// location, then associates the joined value with that expression or717// storage location. This join has nothing to do with transfer --718// instead, it joins together the results of performing transfer on two719// different blocks.720// - Here, we join values associated with _different_ expressions (the721// true and false branch), then associate the joined value with a third722// expression (the conditional operator itself). This join is what it723// means to perform transfer on the conditional operator.724if (Value *Val = Environment::joinValues(725S->getType(), TrueEnv->getValue(*S->getTrueExpr()), *TrueEnv,726FalseEnv->getValue(*S->getFalseExpr()), *FalseEnv, Env, Model))727Env.setValue(*S, *Val);728}729}730731void VisitInitListExpr(const InitListExpr *S) {732QualType Type = S->getType();733734if (!Type->isRecordType()) {735// Until array initialization is implemented, we skip arrays and don't736// need to care about cases where `getNumInits() > 1`.737if (!Type->isArrayType() && S->getNumInits() == 1)738propagateValueOrStorageLocation(*S->getInit(0), *S, Env);739return;740}741742// If the initializer list is transparent, there's nothing to do.743if (S->isSemanticForm() && S->isTransparent())744return;745746RecordStorageLocation &Loc = Env.getResultObjectLocation(*S);747748// Initialization of base classes and fields of record type happens when we749// visit the nested `CXXConstructExpr` or `InitListExpr` for that base class750// or field. We therefore only need to deal with fields of non-record type751// here.752753RecordInitListHelper InitListHelper(S);754755for (auto [Field, Init] : InitListHelper.field_inits()) {756if (Field->getType()->isRecordType())757continue;758if (Field->getType()->isReferenceType()) {759assert(Field->getType().getCanonicalType()->getPointeeType() ==760Init->getType().getCanonicalType());761Loc.setChild(*Field, &Env.createObject(Field->getType(), Init));762continue;763}764assert(Field->getType().getCanonicalType().getUnqualifiedType() ==765Init->getType().getCanonicalType().getUnqualifiedType());766StorageLocation *FieldLoc = Loc.getChild(*Field);767// Locations for non-reference fields must always be non-null.768assert(FieldLoc != nullptr);769Value *Val = Env.getValue(*Init);770if (Val == nullptr && isa<ImplicitValueInitExpr>(Init) &&771Init->getType()->isPointerType())772Val =773&Env.getOrCreateNullPointerValue(Init->getType()->getPointeeType());774if (Val == nullptr)775Val = Env.createValue(Field->getType());776if (Val != nullptr)777Env.setValue(*FieldLoc, *Val);778}779780for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {781QualType FieldType = FieldLoc->getType();782if (FieldType->isRecordType()) {783Env.initializeFieldsWithValues(*cast<RecordStorageLocation>(FieldLoc));784} else {785if (Value *Val = Env.createValue(FieldType))786Env.setValue(*FieldLoc, *Val);787}788}789790// FIXME: Implement array initialization.791}792793void VisitCXXBoolLiteralExpr(const CXXBoolLiteralExpr *S) {794Env.setValue(*S, Env.getBoolLiteralValue(S->getValue()));795}796797void VisitIntegerLiteral(const IntegerLiteral *S) {798Env.setValue(*S, Env.getIntLiteralValue(S->getValue()));799}800801void VisitParenExpr(const ParenExpr *S) {802// The CFG does not contain `ParenExpr` as top-level statements in basic803// blocks, however manual traversal to sub-expressions may encounter them.804// Redirect to the sub-expression.805auto *SubExpr = S->getSubExpr();806assert(SubExpr != nullptr);807Visit(SubExpr);808}809810void VisitExprWithCleanups(const ExprWithCleanups *S) {811// The CFG does not contain `ExprWithCleanups` as top-level statements in812// basic blocks, however manual traversal to sub-expressions may encounter813// them. Redirect to the sub-expression.814auto *SubExpr = S->getSubExpr();815assert(SubExpr != nullptr);816Visit(SubExpr);817}818819private:820/// Returns the value for the sub-expression `SubExpr` of a logic operator.821BoolValue &getLogicOperatorSubExprValue(const Expr &SubExpr) {822// `SubExpr` and its parent logic operator might be part of different basic823// blocks. We try to access the value that is assigned to `SubExpr` in the824// corresponding environment.825if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr))826if (auto *Val =827dyn_cast_or_null<BoolValue>(SubExprEnv->getValue(SubExpr)))828return *Val;829830// The sub-expression may lie within a basic block that isn't reachable,831// even if we need it to evaluate the current (reachable) expression832// (see https://discourse.llvm.org/t/70775). In this case, visit `SubExpr`833// within the current environment and then try to get the value that gets834// assigned to it.835if (Env.getValue(SubExpr) == nullptr)836Visit(&SubExpr);837if (auto *Val = dyn_cast_or_null<BoolValue>(Env.getValue(SubExpr)))838return *Val;839840// If the value of `SubExpr` is still unknown, we create a fresh symbolic841// boolean value for it.842return Env.makeAtomicBoolValue();843}844845// If context sensitivity is enabled, try to analyze the body of the callee846// `F` of `S`. The type `E` must be either `CallExpr` or `CXXConstructExpr`.847template <typename E>848void transferInlineCall(const E *S, const FunctionDecl *F) {849const auto &Options = Env.getDataflowAnalysisContext().getOptions();850if (!(Options.ContextSensitiveOpts &&851Env.canDescend(Options.ContextSensitiveOpts->Depth, F)))852return;853854const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F);855if (!ACFG)856return;857858// FIXME: We don't support context-sensitive analysis of recursion, so859// we should return early here if `F` is the same as the `FunctionDecl`860// holding `S` itself.861862auto ExitBlock = ACFG->getCFG().getExit().getBlockID();863864auto CalleeEnv = Env.pushCall(S);865866// FIXME: Use the same analysis as the caller for the callee. Note,867// though, that doing so would require support for changing the analysis's868// ASTContext.869auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(),870DataflowAnalysisOptions{Options});871872auto BlockToOutputState =873dataflow::runDataflowAnalysis(*ACFG, Analysis, CalleeEnv);874assert(BlockToOutputState);875assert(ExitBlock < BlockToOutputState->size());876877auto &ExitState = (*BlockToOutputState)[ExitBlock];878assert(ExitState);879880Env.popCall(S, ExitState->Env);881}882883const StmtToEnvMap &StmtToEnv;884Environment &Env;885Environment::ValueModel &Model;886};887888} // namespace889890void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env,891Environment::ValueModel &Model) {892TransferVisitor(StmtToEnv, Env, Model).Visit(&S);893}894895} // namespace dataflow896} // namespace clang897898899