104eeddc0SDimitry Andric //===-- DataflowEnvironment.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 an Environment class that is used by dataflow analyses 1004eeddc0SDimitry Andric // that run over Control-Flow Graphs (CFGs) to keep track of the state of the 1104eeddc0SDimitry Andric // program at given program points. 1204eeddc0SDimitry Andric // 1304eeddc0SDimitry Andric //===----------------------------------------------------------------------===// 1404eeddc0SDimitry Andric 1504eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" 1604eeddc0SDimitry Andric #include "clang/AST/Decl.h" 1704eeddc0SDimitry Andric #include "clang/AST/DeclCXX.h" 1804eeddc0SDimitry Andric #include "clang/AST/Type.h" 1904eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/DataflowLattice.h" 2004eeddc0SDimitry Andric #include "clang/Analysis/FlowSensitive/Value.h" 2104eeddc0SDimitry Andric #include "llvm/ADT/DenseMap.h" 2204eeddc0SDimitry Andric #include "llvm/ADT/DenseSet.h" 23*06c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h" 24bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 2581ad6265SDimitry Andric #include "llvm/Support/Casting.h" 2604eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2781ad6265SDimitry Andric #include <cassert> 2804eeddc0SDimitry Andric #include <memory> 2904eeddc0SDimitry Andric #include <utility> 3004eeddc0SDimitry Andric 3104eeddc0SDimitry Andric namespace clang { 3204eeddc0SDimitry Andric namespace dataflow { 3304eeddc0SDimitry Andric 3481ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 3581ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 3681ad6265SDimitry Andric // analysis. 3781ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 3881ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 3981ad6265SDimitry Andric 4004eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 4104eeddc0SDimitry Andric template <typename K, typename V> 4204eeddc0SDimitry Andric llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1, 4304eeddc0SDimitry Andric const llvm::DenseMap<K, V> &Map2) { 4404eeddc0SDimitry Andric llvm::DenseMap<K, V> Result; 4504eeddc0SDimitry Andric for (auto &Entry : Map1) { 4604eeddc0SDimitry Andric auto It = Map2.find(Entry.first); 4704eeddc0SDimitry Andric if (It != Map2.end() && Entry.second == It->second) 4804eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 4904eeddc0SDimitry Andric } 5004eeddc0SDimitry Andric return Result; 5104eeddc0SDimitry Andric } 5204eeddc0SDimitry Andric 53bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1, 54bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 5581ad6265SDimitry Andric const Environment &Env2, 5681ad6265SDimitry Andric Environment::ValueModel &Model) { 57bdd1243dSDimitry Andric // Note: Potentially costly, but, for booleans, we could check whether both 58bdd1243dSDimitry Andric // can be proven equivalent in their respective environments. 59bdd1243dSDimitry Andric 60bdd1243dSDimitry Andric // FIXME: move the reference/pointers logic from `areEquivalentValues` to here 61bdd1243dSDimitry Andric // and implement separate, join/widen specific handling for 62bdd1243dSDimitry Andric // reference/pointers. 63bdd1243dSDimitry Andric switch (Model.compare(Type, Val1, Env1, Val2, Env2)) { 64bdd1243dSDimitry Andric case ComparisonResult::Same: 65bdd1243dSDimitry Andric return true; 66bdd1243dSDimitry Andric case ComparisonResult::Different: 67bdd1243dSDimitry Andric return false; 68bdd1243dSDimitry Andric case ComparisonResult::Unknown: 69bdd1243dSDimitry Andric switch (Val1.getKind()) { 70bdd1243dSDimitry Andric case Value::Kind::Integer: 71bdd1243dSDimitry Andric case Value::Kind::Reference: 72bdd1243dSDimitry Andric case Value::Kind::Pointer: 73bdd1243dSDimitry Andric case Value::Kind::Struct: 74bdd1243dSDimitry Andric // FIXME: this choice intentionally introduces unsoundness to allow 75bdd1243dSDimitry Andric // for convergence. Once we have widening support for the 76bdd1243dSDimitry Andric // reference/pointer and struct built-in models, this should be 77bdd1243dSDimitry Andric // `false`. 78bdd1243dSDimitry Andric return true; 79bdd1243dSDimitry Andric default: 80bdd1243dSDimitry Andric return false; 81bdd1243dSDimitry Andric } 82bdd1243dSDimitry Andric } 83bdd1243dSDimitry Andric llvm_unreachable("All cases covered in switch"); 8481ad6265SDimitry Andric } 8581ad6265SDimitry Andric 8681ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, 8781ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single 8881ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 8981ad6265SDimitry Andric /// meaning depends on `Model`. 90bdd1243dSDimitry Andric static Value *mergeDistinctValues(QualType Type, Value &Val1, 91bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 9281ad6265SDimitry Andric const Environment &Env2, 9381ad6265SDimitry Andric Environment &MergedEnv, 9481ad6265SDimitry Andric Environment::ValueModel &Model) { 9581ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 9681ad6265SDimitry Andric // in the respective path conditions. 97bdd1243dSDimitry Andric if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) { 98bdd1243dSDimitry Andric // FIXME: Checking both values should be unnecessary, since they should have 99bdd1243dSDimitry Andric // a consistent shape. However, right now we can end up with BoolValue's in 100bdd1243dSDimitry Andric // integer-typed variables due to our incorrect handling of 101bdd1243dSDimitry Andric // boolean-to-integer casts (we just propagate the BoolValue to the result 102bdd1243dSDimitry Andric // of the cast). So, a join can encounter an integer in one branch but a 103bdd1243dSDimitry Andric // bool in the other. 104bdd1243dSDimitry Andric // For example: 105bdd1243dSDimitry Andric // ``` 106bdd1243dSDimitry Andric // std::optional<bool> o; 107bdd1243dSDimitry Andric // int x; 108bdd1243dSDimitry Andric // if (o.has_value()) 109bdd1243dSDimitry Andric // x = o.value(); 110bdd1243dSDimitry Andric // ``` 111*06c3fb27SDimitry Andric auto &Expr1 = cast<BoolValue>(Val1).formula(); 112*06c3fb27SDimitry Andric auto &Expr2 = cast<BoolValue>(Val2).formula(); 113*06c3fb27SDimitry Andric auto &A = MergedEnv.arena(); 114*06c3fb27SDimitry Andric auto &MergedVal = A.makeAtomRef(A.makeAtom()); 115*06c3fb27SDimitry Andric MergedEnv.addToFlowCondition( 116*06c3fb27SDimitry Andric A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()), 117*06c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr1)), 118*06c3fb27SDimitry Andric A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()), 119*06c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr2)))); 120*06c3fb27SDimitry Andric return &A.makeBoolValue(MergedVal); 121*06c3fb27SDimitry Andric } 122*06c3fb27SDimitry Andric 123*06c3fb27SDimitry Andric Value *MergedVal = nullptr; 124*06c3fb27SDimitry Andric if (auto *StructVal1 = dyn_cast<StructValue>(&Val1)) { 125*06c3fb27SDimitry Andric [[maybe_unused]] auto *StructVal2 = cast<StructValue>(&Val2); 126*06c3fb27SDimitry Andric 127*06c3fb27SDimitry Andric // Values to be merged are always associated with the same location in 128*06c3fb27SDimitry Andric // `LocToVal`. The location stored in `StructVal` should therefore also 129*06c3fb27SDimitry Andric // be the same. 130*06c3fb27SDimitry Andric assert(&StructVal1->getAggregateLoc() == &StructVal2->getAggregateLoc()); 131*06c3fb27SDimitry Andric 132*06c3fb27SDimitry Andric // `StructVal1` and `StructVal2` may have different properties associated 133*06c3fb27SDimitry Andric // with them. Create a new `StructValue` without any properties so that we 134*06c3fb27SDimitry Andric // soundly approximate both values. If a particular analysis needs to merge 135*06c3fb27SDimitry Andric // properties, it should do so in `DataflowAnalysis::merge()`. 136*06c3fb27SDimitry Andric MergedVal = &MergedEnv.create<StructValue>(StructVal1->getAggregateLoc()); 137*06c3fb27SDimitry Andric } else { 138*06c3fb27SDimitry Andric MergedVal = MergedEnv.createValue(Type); 13981ad6265SDimitry Andric } 14081ad6265SDimitry Andric 14181ad6265SDimitry Andric // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` 14281ad6265SDimitry Andric // returns false to avoid storing unneeded values in `DACtx`. 143bdd1243dSDimitry Andric // FIXME: Creating the value based on the type alone creates misshapen values 144bdd1243dSDimitry Andric // for lvalues, since the type does not reflect the need for `ReferenceValue`. 145*06c3fb27SDimitry Andric // This issue will be resolved when `ReferenceValue` is eliminated as part 146*06c3fb27SDimitry Andric // of the ongoing migration to strict handling of value categories (see 147*06c3fb27SDimitry Andric // https://discourse.llvm.org/t/70086 for details). 148*06c3fb27SDimitry Andric if (MergedVal) 149bdd1243dSDimitry Andric if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv)) 15081ad6265SDimitry Andric return MergedVal; 15181ad6265SDimitry Andric 15281ad6265SDimitry Andric return nullptr; 15381ad6265SDimitry Andric } 15481ad6265SDimitry Andric 155bdd1243dSDimitry Andric // When widening does not change `Current`, return value will equal `&Prev`. 156bdd1243dSDimitry Andric static Value &widenDistinctValues(QualType Type, Value &Prev, 157bdd1243dSDimitry Andric const Environment &PrevEnv, Value &Current, 158bdd1243dSDimitry Andric Environment &CurrentEnv, 159bdd1243dSDimitry Andric Environment::ValueModel &Model) { 160bdd1243dSDimitry Andric // Boolean-model widening. 161bdd1243dSDimitry Andric if (isa<BoolValue>(&Prev)) { 162bdd1243dSDimitry Andric assert(isa<BoolValue>(Current)); 163bdd1243dSDimitry Andric // Widen to Top, because we know they are different values. If previous was 164bdd1243dSDimitry Andric // already Top, re-use that to (implicitly) indicate that no change occured. 165bdd1243dSDimitry Andric if (isa<TopBoolValue>(Prev)) 166bdd1243dSDimitry Andric return Prev; 167bdd1243dSDimitry Andric return CurrentEnv.makeTopBoolValue(); 168bdd1243dSDimitry Andric } 16981ad6265SDimitry Andric 170bdd1243dSDimitry Andric // FIXME: Add other built-in model widening. 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric // Custom-model widening. 173bdd1243dSDimitry Andric if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) 174bdd1243dSDimitry Andric return *W; 175bdd1243dSDimitry Andric 176bdd1243dSDimitry Andric // Default of widening is a no-op: leave the current value unchanged. 177bdd1243dSDimitry Andric return Current; 17881ad6265SDimitry Andric } 17981ad6265SDimitry Andric 18081ad6265SDimitry Andric /// Initializes a global storage value. 181bdd1243dSDimitry Andric static void insertIfGlobal(const Decl &D, 182bdd1243dSDimitry Andric llvm::DenseSet<const VarDecl *> &Vars) { 18381ad6265SDimitry Andric if (auto *V = dyn_cast<VarDecl>(&D)) 184bdd1243dSDimitry Andric if (V->hasGlobalStorage()) 185bdd1243dSDimitry Andric Vars.insert(V); 18681ad6265SDimitry Andric } 18781ad6265SDimitry Andric 188*06c3fb27SDimitry Andric static void insertIfFunction(const Decl &D, 189*06c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 190*06c3fb27SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(&D)) 191*06c3fb27SDimitry Andric Funcs.insert(FD); 192*06c3fb27SDimitry Andric } 193*06c3fb27SDimitry Andric 194*06c3fb27SDimitry Andric static void 195*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields, 196*06c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 197*06c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 198*06c3fb27SDimitry Andric insertIfGlobal(D, Vars); 199*06c3fb27SDimitry Andric insertIfFunction(D, Funcs); 200bdd1243dSDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) 201bdd1243dSDimitry Andric for (const auto *B : Decomp->bindings()) 202bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) 203bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 204bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) 205bdd1243dSDimitry Andric Fields.insert(FD); 20681ad6265SDimitry Andric } 20781ad6265SDimitry Andric 208*06c3fb27SDimitry Andric /// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields, 209*06c3fb27SDimitry Andric /// global variables and functions that are declared in or referenced from 210*06c3fb27SDimitry Andric /// sub-statements. 211*06c3fb27SDimitry Andric static void 212*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, 213*06c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 214*06c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 215bdd1243dSDimitry Andric for (auto *Child : S.children()) 216bdd1243dSDimitry Andric if (Child != nullptr) 217*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); 218*06c3fb27SDimitry Andric if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S)) 219*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); 220bdd1243dSDimitry Andric 22181ad6265SDimitry Andric if (auto *DS = dyn_cast<DeclStmt>(&S)) { 222bdd1243dSDimitry Andric if (DS->isSingleDecl()) 223*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs); 224bdd1243dSDimitry Andric else 22581ad6265SDimitry Andric for (auto *D : DS->getDeclGroup()) 226*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs); 22781ad6265SDimitry Andric } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 228*06c3fb27SDimitry Andric insertIfGlobal(*E->getDecl(), Vars); 229*06c3fb27SDimitry Andric insertIfFunction(*E->getDecl(), Funcs); 23081ad6265SDimitry Andric } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 231bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 232bdd1243dSDimitry Andric const ValueDecl *VD = E->getMemberDecl(); 233*06c3fb27SDimitry Andric insertIfGlobal(*VD, Vars); 234*06c3fb27SDimitry Andric insertIfFunction(*VD, Funcs); 235bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(VD)) 236bdd1243dSDimitry Andric Fields.insert(FD); 237*06c3fb27SDimitry Andric } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) { 238*06c3fb27SDimitry Andric if (RecordDecl *RD = InitList->getType()->getAsRecordDecl()) 239*06c3fb27SDimitry Andric for (const auto *FD : getFieldsForInitListExpr(RD)) 240*06c3fb27SDimitry Andric Fields.insert(FD); 241bdd1243dSDimitry Andric } 242bdd1243dSDimitry Andric } 243bdd1243dSDimitry Andric 244bdd1243dSDimitry Andric // FIXME: Add support for resetting globals after function calls to enable 245bdd1243dSDimitry Andric // the implementation of sound analyses. 246*06c3fb27SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { 247*06c3fb27SDimitry Andric assert(FuncDecl->getBody() != nullptr); 248*06c3fb27SDimitry Andric 249*06c3fb27SDimitry Andric FieldSet Fields; 250*06c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> Vars; 251*06c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> Funcs; 252*06c3fb27SDimitry Andric 253*06c3fb27SDimitry Andric // Look for global variable and field references in the 254*06c3fb27SDimitry Andric // constructor-initializers. 255*06c3fb27SDimitry Andric if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) { 256*06c3fb27SDimitry Andric for (const auto *Init : CtorDecl->inits()) { 257*06c3fb27SDimitry Andric if (Init->isMemberInitializer()) { 258*06c3fb27SDimitry Andric Fields.insert(Init->getMember()); 259*06c3fb27SDimitry Andric } else if (Init->isIndirectMemberInitializer()) { 260*06c3fb27SDimitry Andric for (const auto *I : Init->getIndirectMember()->chain()) 261*06c3fb27SDimitry Andric Fields.insert(cast<FieldDecl>(I)); 262*06c3fb27SDimitry Andric } 263*06c3fb27SDimitry Andric const Expr *E = Init->getInit(); 264*06c3fb27SDimitry Andric assert(E != nullptr); 265*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); 266*06c3fb27SDimitry Andric } 267*06c3fb27SDimitry Andric // Add all fields mentioned in default member initializers. 268*06c3fb27SDimitry Andric for (const FieldDecl *F : CtorDecl->getParent()->fields()) 269*06c3fb27SDimitry Andric if (const auto *I = F->getInClassInitializer()) 270*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs); 271*06c3fb27SDimitry Andric } 272*06c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs); 273*06c3fb27SDimitry Andric 274*06c3fb27SDimitry Andric // These have to be added before the lines that follow to ensure that 275*06c3fb27SDimitry Andric // `create*` work correctly for structs. 276*06c3fb27SDimitry Andric DACtx->addModeledFields(Fields); 277*06c3fb27SDimitry Andric 278bdd1243dSDimitry Andric for (const VarDecl *D : Vars) { 279*06c3fb27SDimitry Andric if (getStorageLocation(*D) != nullptr) 280bdd1243dSDimitry Andric continue; 281*06c3fb27SDimitry Andric 282*06c3fb27SDimitry Andric setStorageLocation(*D, createObject(*D)); 283*06c3fb27SDimitry Andric } 284*06c3fb27SDimitry Andric 285*06c3fb27SDimitry Andric for (const FunctionDecl *FD : Funcs) { 286*06c3fb27SDimitry Andric if (getStorageLocation(*FD) != nullptr) 287*06c3fb27SDimitry Andric continue; 288*06c3fb27SDimitry Andric auto &Loc = createStorageLocation(FD->getType()); 289*06c3fb27SDimitry Andric setStorageLocation(*FD, Loc); 29081ad6265SDimitry Andric } 29181ad6265SDimitry Andric } 29281ad6265SDimitry Andric 29381ad6265SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx) 294*06c3fb27SDimitry Andric : DACtx(&DACtx), 295*06c3fb27SDimitry Andric FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} 29681ad6265SDimitry Andric 297*06c3fb27SDimitry Andric Environment Environment::fork() const { 298*06c3fb27SDimitry Andric Environment Copy(*this); 299*06c3fb27SDimitry Andric Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken); 300*06c3fb27SDimitry Andric return Copy; 3011fd87a68SDimitry Andric } 3021fd87a68SDimitry Andric 30304eeddc0SDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx, 30404eeddc0SDimitry Andric const DeclContext &DeclCtx) 30504eeddc0SDimitry Andric : Environment(DACtx) { 306bdd1243dSDimitry Andric CallStack.push_back(&DeclCtx); 307bdd1243dSDimitry Andric 30804eeddc0SDimitry Andric if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) { 30981ad6265SDimitry Andric assert(FuncDecl->getBody() != nullptr); 310bdd1243dSDimitry Andric 311*06c3fb27SDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 312bdd1243dSDimitry Andric 31304eeddc0SDimitry Andric for (const auto *ParamDecl : FuncDecl->parameters()) { 31404eeddc0SDimitry Andric assert(ParamDecl != nullptr); 315*06c3fb27SDimitry Andric setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); 31604eeddc0SDimitry Andric } 31704eeddc0SDimitry Andric } 31804eeddc0SDimitry Andric 31904eeddc0SDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) { 32081ad6265SDimitry Andric auto *Parent = MethodDecl->getParent(); 32181ad6265SDimitry Andric assert(Parent != nullptr); 32281ad6265SDimitry Andric if (Parent->isLambda()) 32381ad6265SDimitry Andric MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext()); 32481ad6265SDimitry Andric 325bdd1243dSDimitry Andric // FIXME: Initialize the ThisPointeeLoc of lambdas too. 32681ad6265SDimitry Andric if (MethodDecl && !MethodDecl->isStatic()) { 32704eeddc0SDimitry Andric QualType ThisPointeeType = MethodDecl->getThisObjectType(); 328*06c3fb27SDimitry Andric ThisPointeeLoc = 329*06c3fb27SDimitry Andric &cast<StructValue>(createValue(ThisPointeeType))->getAggregateLoc(); 33004eeddc0SDimitry Andric } 33104eeddc0SDimitry Andric } 33204eeddc0SDimitry Andric } 333bdd1243dSDimitry Andric 334bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth, 335bdd1243dSDimitry Andric const DeclContext *Callee) const { 336bdd1243dSDimitry Andric return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee); 33704eeddc0SDimitry Andric } 33804eeddc0SDimitry Andric 339972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const { 340972a253aSDimitry Andric Environment Env(*this); 341972a253aSDimitry Andric 342bdd1243dSDimitry Andric if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) { 343bdd1243dSDimitry Andric if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { 344bdd1243dSDimitry Andric if (!isa<CXXThisExpr>(Arg)) 345*06c3fb27SDimitry Andric Env.ThisPointeeLoc = cast<AggregateStorageLocation>( 346*06c3fb27SDimitry Andric getStorageLocation(*Arg, SkipPast::Reference)); 347bdd1243dSDimitry Andric // Otherwise (when the argument is `this`), retain the current 348bdd1243dSDimitry Andric // environment's `ThisPointeeLoc`. 349bdd1243dSDimitry Andric } 350bdd1243dSDimitry Andric } 351972a253aSDimitry Andric 352bdd1243dSDimitry Andric Env.pushCallInternal(Call->getDirectCallee(), 353bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 354bdd1243dSDimitry Andric 355bdd1243dSDimitry Andric return Env; 356bdd1243dSDimitry Andric } 357bdd1243dSDimitry Andric 358bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const { 359bdd1243dSDimitry Andric Environment Env(*this); 360bdd1243dSDimitry Andric 361*06c3fb27SDimitry Andric Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); 362bdd1243dSDimitry Andric 363bdd1243dSDimitry Andric Env.pushCallInternal(Call->getConstructor(), 364bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 365bdd1243dSDimitry Andric 366bdd1243dSDimitry Andric return Env; 367bdd1243dSDimitry Andric } 368bdd1243dSDimitry Andric 369bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl, 370bdd1243dSDimitry Andric ArrayRef<const Expr *> Args) { 371*06c3fb27SDimitry Andric // Canonicalize to the definition of the function. This ensures that we're 372*06c3fb27SDimitry Andric // putting arguments into the same `ParamVarDecl`s` that the callee will later 373*06c3fb27SDimitry Andric // be retrieving them from. 374*06c3fb27SDimitry Andric assert(FuncDecl->getDefinition() != nullptr); 375*06c3fb27SDimitry Andric FuncDecl = FuncDecl->getDefinition(); 376*06c3fb27SDimitry Andric 377bdd1243dSDimitry Andric CallStack.push_back(FuncDecl); 378bdd1243dSDimitry Andric 379*06c3fb27SDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 380bdd1243dSDimitry Andric 381bdd1243dSDimitry Andric const auto *ParamIt = FuncDecl->param_begin(); 382972a253aSDimitry Andric 383972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include 384972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs. 385bdd1243dSDimitry Andric for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) { 386972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end()); 387972a253aSDimitry Andric const VarDecl *Param = *ParamIt; 388*06c3fb27SDimitry Andric setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); 389bdd1243dSDimitry Andric } 390972a253aSDimitry Andric } 391972a253aSDimitry Andric 392*06c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { 393bdd1243dSDimitry Andric // We ignore `DACtx` because it's already the same in both. We don't want the 394*06c3fb27SDimitry Andric // callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or `ThisPointeeLoc`. We don't 395*06c3fb27SDimitry Andric // bring back `DeclToLoc` and `ExprToLoc` because we want to be able to later 396*06c3fb27SDimitry Andric // analyze the same callee in a different context, and `setStorageLocation` 397*06c3fb27SDimitry Andric // requires there to not already be a storage location assigned. Conceptually, 398*06c3fb27SDimitry Andric // these maps capture information from the local scope, so when popping that 399*06c3fb27SDimitry Andric // scope, we do not propagate the maps. 400bdd1243dSDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 401bdd1243dSDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 402*06c3fb27SDimitry Andric 403*06c3fb27SDimitry Andric if (Call->isGLValue()) { 404*06c3fb27SDimitry Andric if (CalleeEnv.ReturnLoc != nullptr) 405*06c3fb27SDimitry Andric setStorageLocationStrict(*Call, *CalleeEnv.ReturnLoc); 406*06c3fb27SDimitry Andric } else if (!Call->getType()->isVoidType()) { 407*06c3fb27SDimitry Andric if (CalleeEnv.ReturnVal != nullptr) 408*06c3fb27SDimitry Andric setValueStrict(*Call, *CalleeEnv.ReturnVal); 409*06c3fb27SDimitry Andric } 410*06c3fb27SDimitry Andric } 411*06c3fb27SDimitry Andric 412*06c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call, 413*06c3fb27SDimitry Andric const Environment &CalleeEnv) { 414*06c3fb27SDimitry Andric // See also comment in `popCall(const CallExpr *, const Environment &)` above. 415*06c3fb27SDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 416*06c3fb27SDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 417*06c3fb27SDimitry Andric 418*06c3fb27SDimitry Andric if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) { 419*06c3fb27SDimitry Andric setValueStrict(*Call, *Val); 420*06c3fb27SDimitry Andric } 421972a253aSDimitry Andric } 422972a253aSDimitry Andric 4231fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 4241fd87a68SDimitry Andric Environment::ValueModel &Model) const { 42504eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 4261fd87a68SDimitry Andric 427*06c3fb27SDimitry Andric if (ReturnVal != Other.ReturnVal) 428*06c3fb27SDimitry Andric return false; 429*06c3fb27SDimitry Andric 430bdd1243dSDimitry Andric if (ReturnLoc != Other.ReturnLoc) 431bdd1243dSDimitry Andric return false; 432bdd1243dSDimitry Andric 433bdd1243dSDimitry Andric if (ThisPointeeLoc != Other.ThisPointeeLoc) 434bdd1243dSDimitry Andric return false; 435bdd1243dSDimitry Andric 4361fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 4371fd87a68SDimitry Andric return false; 4381fd87a68SDimitry Andric 4391fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 4401fd87a68SDimitry Andric return false; 4411fd87a68SDimitry Andric 44281ad6265SDimitry Andric // Compare the contents for the intersection of their domains. 4431fd87a68SDimitry Andric for (auto &Entry : LocToVal) { 4441fd87a68SDimitry Andric const StorageLocation *Loc = Entry.first; 4451fd87a68SDimitry Andric assert(Loc != nullptr); 4461fd87a68SDimitry Andric 4471fd87a68SDimitry Andric Value *Val = Entry.second; 4481fd87a68SDimitry Andric assert(Val != nullptr); 4491fd87a68SDimitry Andric 4501fd87a68SDimitry Andric auto It = Other.LocToVal.find(Loc); 4511fd87a68SDimitry Andric if (It == Other.LocToVal.end()) 45281ad6265SDimitry Andric continue; 4531fd87a68SDimitry Andric assert(It->second != nullptr); 4541fd87a68SDimitry Andric 455bdd1243dSDimitry Andric if (!areEquivalentValues(*Val, *It->second) && 456bdd1243dSDimitry Andric !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other, 457bdd1243dSDimitry Andric Model)) 4581fd87a68SDimitry Andric return false; 4591fd87a68SDimitry Andric } 4601fd87a68SDimitry Andric 4611fd87a68SDimitry Andric return true; 46204eeddc0SDimitry Andric } 46304eeddc0SDimitry Andric 464bdd1243dSDimitry Andric LatticeJoinEffect Environment::widen(const Environment &PrevEnv, 465bdd1243dSDimitry Andric Environment::ValueModel &Model) { 466bdd1243dSDimitry Andric assert(DACtx == PrevEnv.DACtx); 467*06c3fb27SDimitry Andric assert(ReturnVal == PrevEnv.ReturnVal); 468bdd1243dSDimitry Andric assert(ReturnLoc == PrevEnv.ReturnLoc); 469bdd1243dSDimitry Andric assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); 470bdd1243dSDimitry Andric assert(CallStack == PrevEnv.CallStack); 471bdd1243dSDimitry Andric 472bdd1243dSDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 473bdd1243dSDimitry Andric 474bdd1243dSDimitry Andric // By the API, `PrevEnv` is a previous version of the environment for the same 475bdd1243dSDimitry Andric // block, so we have some guarantees about its shape. In particular, it will 476bdd1243dSDimitry Andric // be the result of a join or widen operation on previous values for this 477bdd1243dSDimitry Andric // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are 478bdd1243dSDimitry Andric // subsets of the maps in `PrevEnv`. So, as long as we maintain this property 479bdd1243dSDimitry Andric // here, we don't need change their current values to widen. 480bdd1243dSDimitry Andric assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size()); 481bdd1243dSDimitry Andric assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size()); 482bdd1243dSDimitry Andric 483*06c3fb27SDimitry Andric llvm::MapVector<const StorageLocation *, Value *> WidenedLocToVal; 484bdd1243dSDimitry Andric for (auto &Entry : LocToVal) { 485bdd1243dSDimitry Andric const StorageLocation *Loc = Entry.first; 486bdd1243dSDimitry Andric assert(Loc != nullptr); 487bdd1243dSDimitry Andric 488bdd1243dSDimitry Andric Value *Val = Entry.second; 489bdd1243dSDimitry Andric assert(Val != nullptr); 490bdd1243dSDimitry Andric 491bdd1243dSDimitry Andric auto PrevIt = PrevEnv.LocToVal.find(Loc); 492bdd1243dSDimitry Andric if (PrevIt == PrevEnv.LocToVal.end()) 493bdd1243dSDimitry Andric continue; 494bdd1243dSDimitry Andric assert(PrevIt->second != nullptr); 495bdd1243dSDimitry Andric 496bdd1243dSDimitry Andric if (areEquivalentValues(*Val, *PrevIt->second)) { 497bdd1243dSDimitry Andric WidenedLocToVal.insert({Loc, Val}); 498bdd1243dSDimitry Andric continue; 499bdd1243dSDimitry Andric } 500bdd1243dSDimitry Andric 501bdd1243dSDimitry Andric Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second, 502bdd1243dSDimitry Andric PrevEnv, *Val, *this, Model); 503bdd1243dSDimitry Andric WidenedLocToVal.insert({Loc, &WidenedVal}); 504bdd1243dSDimitry Andric if (&WidenedVal != PrevIt->second) 505bdd1243dSDimitry Andric Effect = LatticeJoinEffect::Changed; 506bdd1243dSDimitry Andric } 507bdd1243dSDimitry Andric LocToVal = std::move(WidenedLocToVal); 508bdd1243dSDimitry Andric if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() || 509bdd1243dSDimitry Andric ExprToLoc.size() != PrevEnv.ExprToLoc.size() || 510*06c3fb27SDimitry Andric LocToVal.size() != PrevEnv.LocToVal.size()) 511bdd1243dSDimitry Andric Effect = LatticeJoinEffect::Changed; 512bdd1243dSDimitry Andric 513bdd1243dSDimitry Andric return Effect; 514bdd1243dSDimitry Andric } 515bdd1243dSDimitry Andric 516*06c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB, 5171fd87a68SDimitry Andric Environment::ValueModel &Model) { 518*06c3fb27SDimitry Andric assert(EnvA.DACtx == EnvB.DACtx); 519*06c3fb27SDimitry Andric assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); 520*06c3fb27SDimitry Andric assert(EnvA.CallStack == EnvB.CallStack); 52104eeddc0SDimitry Andric 522*06c3fb27SDimitry Andric Environment JoinedEnv(*EnvA.DACtx); 52304eeddc0SDimitry Andric 524*06c3fb27SDimitry Andric JoinedEnv.CallStack = EnvA.CallStack; 525*06c3fb27SDimitry Andric JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; 52681ad6265SDimitry Andric 527*06c3fb27SDimitry Andric if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) { 528*06c3fb27SDimitry Andric // `ReturnVal` might not always get set -- for example if we have a return 529*06c3fb27SDimitry Andric // statement of the form `return some_other_func()` and we decide not to 530*06c3fb27SDimitry Andric // analyze `some_other_func()`. 531*06c3fb27SDimitry Andric // In this case, we can't say anything about the joined return value -- we 532*06c3fb27SDimitry Andric // don't simply want to propagate the return value that we do have, because 533*06c3fb27SDimitry Andric // it might not be the correct one. 534*06c3fb27SDimitry Andric // This occurs for example in the test `ContextSensitiveMutualRecursion`. 535*06c3fb27SDimitry Andric JoinedEnv.ReturnVal = nullptr; 536*06c3fb27SDimitry Andric } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) { 537*06c3fb27SDimitry Andric JoinedEnv.ReturnVal = EnvA.ReturnVal; 538*06c3fb27SDimitry Andric } else { 539*06c3fb27SDimitry Andric assert(!EnvA.CallStack.empty()); 540*06c3fb27SDimitry Andric // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this 541*06c3fb27SDimitry Andric // cast. 542*06c3fb27SDimitry Andric auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back()); 543*06c3fb27SDimitry Andric assert(Func != nullptr); 544*06c3fb27SDimitry Andric if (Value *MergedVal = 545*06c3fb27SDimitry Andric mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA, 546*06c3fb27SDimitry Andric *EnvB.ReturnVal, EnvB, JoinedEnv, Model)) 547*06c3fb27SDimitry Andric JoinedEnv.ReturnVal = MergedVal; 548*06c3fb27SDimitry Andric } 549bdd1243dSDimitry Andric 550*06c3fb27SDimitry Andric if (EnvA.ReturnLoc == EnvB.ReturnLoc) 551*06c3fb27SDimitry Andric JoinedEnv.ReturnLoc = EnvA.ReturnLoc; 552*06c3fb27SDimitry Andric else 553*06c3fb27SDimitry Andric JoinedEnv.ReturnLoc = nullptr; 55404eeddc0SDimitry Andric 555*06c3fb27SDimitry Andric // FIXME: Once we're able to remove declarations from `DeclToLoc` when their 556*06c3fb27SDimitry Andric // lifetime ends, add an assertion that there aren't any entries in 557*06c3fb27SDimitry Andric // `DeclToLoc` and `Other.DeclToLoc` that map the same declaration to 558*06c3fb27SDimitry Andric // different storage locations. 559*06c3fb27SDimitry Andric JoinedEnv.DeclToLoc = intersectDenseMaps(EnvA.DeclToLoc, EnvB.DeclToLoc); 56004eeddc0SDimitry Andric 561*06c3fb27SDimitry Andric JoinedEnv.ExprToLoc = intersectDenseMaps(EnvA.ExprToLoc, EnvB.ExprToLoc); 56281ad6265SDimitry Andric 563bdd1243dSDimitry Andric // FIXME: update join to detect backedges and simplify the flow condition 564bdd1243dSDimitry Andric // accordingly. 565*06c3fb27SDimitry Andric JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions( 566*06c3fb27SDimitry Andric EnvA.FlowConditionToken, EnvB.FlowConditionToken); 56781ad6265SDimitry Andric 568*06c3fb27SDimitry Andric for (auto &Entry : EnvA.LocToVal) { 56904eeddc0SDimitry Andric const StorageLocation *Loc = Entry.first; 57004eeddc0SDimitry Andric assert(Loc != nullptr); 57104eeddc0SDimitry Andric 57204eeddc0SDimitry Andric Value *Val = Entry.second; 57304eeddc0SDimitry Andric assert(Val != nullptr); 57404eeddc0SDimitry Andric 575*06c3fb27SDimitry Andric auto It = EnvB.LocToVal.find(Loc); 576*06c3fb27SDimitry Andric if (It == EnvB.LocToVal.end()) 57704eeddc0SDimitry Andric continue; 57804eeddc0SDimitry Andric assert(It->second != nullptr); 57904eeddc0SDimitry Andric 580bdd1243dSDimitry Andric if (areEquivalentValues(*Val, *It->second)) { 58181ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, Val}); 58204eeddc0SDimitry Andric continue; 58304eeddc0SDimitry Andric } 58404eeddc0SDimitry Andric 585*06c3fb27SDimitry Andric if (Value *MergedVal = mergeDistinctValues( 586*06c3fb27SDimitry Andric Loc->getType(), *Val, EnvA, *It->second, EnvB, JoinedEnv, Model)) { 58781ad6265SDimitry Andric JoinedEnv.LocToVal.insert({Loc, MergedVal}); 588bdd1243dSDimitry Andric } 58904eeddc0SDimitry Andric } 59004eeddc0SDimitry Andric 591*06c3fb27SDimitry Andric return JoinedEnv; 59204eeddc0SDimitry Andric } 59304eeddc0SDimitry Andric 59404eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 595bdd1243dSDimitry Andric return DACtx->createStorageLocation(Type); 59604eeddc0SDimitry Andric } 59704eeddc0SDimitry Andric 59804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const VarDecl &D) { 59904eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 60004eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 60104eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 60281ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 60304eeddc0SDimitry Andric } 60404eeddc0SDimitry Andric 60504eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 60604eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 60704eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 60804eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 60981ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 61004eeddc0SDimitry Andric } 61104eeddc0SDimitry Andric 61204eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 613*06c3fb27SDimitry Andric assert(!DeclToLoc.contains(&D)); 614*06c3fb27SDimitry Andric assert(!isa_and_nonnull<ReferenceValue>(getValue(Loc))); 61504eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 61604eeddc0SDimitry Andric } 61704eeddc0SDimitry Andric 618*06c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 61904eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 620*06c3fb27SDimitry Andric if (It == DeclToLoc.end()) 621*06c3fb27SDimitry Andric return nullptr; 622*06c3fb27SDimitry Andric 623*06c3fb27SDimitry Andric StorageLocation *Loc = It->second; 624*06c3fb27SDimitry Andric 625*06c3fb27SDimitry Andric assert(!isa_and_nonnull<ReferenceValue>(getValue(*Loc))); 626*06c3fb27SDimitry Andric 627*06c3fb27SDimitry Andric return Loc; 62804eeddc0SDimitry Andric } 62904eeddc0SDimitry Andric 63004eeddc0SDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 63181ad6265SDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 632*06c3fb27SDimitry Andric assert(!ExprToLoc.contains(&CanonE)); 63381ad6265SDimitry Andric ExprToLoc[&CanonE] = &Loc; 63404eeddc0SDimitry Andric } 63504eeddc0SDimitry Andric 636*06c3fb27SDimitry Andric void Environment::setStorageLocationStrict(const Expr &E, 637*06c3fb27SDimitry Andric StorageLocation &Loc) { 638*06c3fb27SDimitry Andric // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason, 639*06c3fb27SDimitry Andric // but we still want to be able to associate a `StorageLocation` with them, 640*06c3fb27SDimitry Andric // so allow these as an exception. 641*06c3fb27SDimitry Andric assert(E.isGLValue() || 642*06c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 643*06c3fb27SDimitry Andric setStorageLocation(E, Loc); 644*06c3fb27SDimitry Andric } 645*06c3fb27SDimitry Andric 64604eeddc0SDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E, 64704eeddc0SDimitry Andric SkipPast SP) const { 64881ad6265SDimitry Andric // FIXME: Add a test with parens. 64981ad6265SDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 65004eeddc0SDimitry Andric return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP); 65104eeddc0SDimitry Andric } 65204eeddc0SDimitry Andric 653*06c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocationStrict(const Expr &E) const { 654*06c3fb27SDimitry Andric // See comment in `setStorageLocationStrict()`. 655*06c3fb27SDimitry Andric assert(E.isGLValue() || 656*06c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 657*06c3fb27SDimitry Andric StorageLocation *Loc = getStorageLocation(E, SkipPast::None); 658*06c3fb27SDimitry Andric 659*06c3fb27SDimitry Andric if (Loc == nullptr) 660*06c3fb27SDimitry Andric return nullptr; 661*06c3fb27SDimitry Andric 662*06c3fb27SDimitry Andric if (auto *RefVal = dyn_cast_or_null<ReferenceValue>(getValue(*Loc))) 663*06c3fb27SDimitry Andric return &RefVal->getReferentLoc(); 664*06c3fb27SDimitry Andric 665*06c3fb27SDimitry Andric return Loc; 666*06c3fb27SDimitry Andric } 667*06c3fb27SDimitry Andric 668*06c3fb27SDimitry Andric AggregateStorageLocation *Environment::getThisPointeeStorageLocation() const { 669bdd1243dSDimitry Andric return ThisPointeeLoc; 670bdd1243dSDimitry Andric } 671bdd1243dSDimitry Andric 672*06c3fb27SDimitry Andric AggregateStorageLocation & 673*06c3fb27SDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) { 674*06c3fb27SDimitry Andric assert(RecordPRValue.getType()->isRecordType()); 675*06c3fb27SDimitry Andric assert(RecordPRValue.isPRValue()); 676*06c3fb27SDimitry Andric 677*06c3fb27SDimitry Andric if (StorageLocation *ExistingLoc = 678*06c3fb27SDimitry Andric getStorageLocation(RecordPRValue, SkipPast::None)) 679*06c3fb27SDimitry Andric return *cast<AggregateStorageLocation>(ExistingLoc); 680*06c3fb27SDimitry Andric auto &Loc = cast<AggregateStorageLocation>( 681*06c3fb27SDimitry Andric DACtx->getStableStorageLocation(RecordPRValue)); 682*06c3fb27SDimitry Andric setStorageLocation(RecordPRValue, Loc); 683*06c3fb27SDimitry Andric return Loc; 68404eeddc0SDimitry Andric } 68504eeddc0SDimitry Andric 68681ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 68781ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 68881ad6265SDimitry Andric } 68981ad6265SDimitry Andric 69004eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 691*06c3fb27SDimitry Andric assert(!isa<StructValue>(&Val) || 692*06c3fb27SDimitry Andric &cast<StructValue>(&Val)->getAggregateLoc() == &Loc); 693*06c3fb27SDimitry Andric 69404eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 695*06c3fb27SDimitry Andric } 696*06c3fb27SDimitry Andric 697*06c3fb27SDimitry Andric void Environment::setValueStrict(const Expr &E, Value &Val) { 698*06c3fb27SDimitry Andric assert(E.isPRValue()); 699*06c3fb27SDimitry Andric assert(!isa<ReferenceValue>(Val)); 70004eeddc0SDimitry Andric 70104eeddc0SDimitry Andric if (auto *StructVal = dyn_cast<StructValue>(&Val)) { 702*06c3fb27SDimitry Andric if (auto *ExistingVal = cast_or_null<StructValue>(getValueStrict(E))) 703*06c3fb27SDimitry Andric assert(&ExistingVal->getAggregateLoc() == &StructVal->getAggregateLoc()); 704*06c3fb27SDimitry Andric if (StorageLocation *ExistingLoc = getStorageLocation(E, SkipPast::None)) 705*06c3fb27SDimitry Andric assert(ExistingLoc == &StructVal->getAggregateLoc()); 706*06c3fb27SDimitry Andric else 707*06c3fb27SDimitry Andric setStorageLocation(E, StructVal->getAggregateLoc()); 708*06c3fb27SDimitry Andric setValue(StructVal->getAggregateLoc(), Val); 709*06c3fb27SDimitry Andric return; 71004eeddc0SDimitry Andric } 71181ad6265SDimitry Andric 712*06c3fb27SDimitry Andric StorageLocation *Loc = getStorageLocation(E, SkipPast::None); 713*06c3fb27SDimitry Andric if (Loc == nullptr) { 714*06c3fb27SDimitry Andric Loc = &createStorageLocation(E); 715*06c3fb27SDimitry Andric setStorageLocation(E, *Loc); 71681ad6265SDimitry Andric } 717*06c3fb27SDimitry Andric setValue(*Loc, Val); 71804eeddc0SDimitry Andric } 71904eeddc0SDimitry Andric 72004eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 721*06c3fb27SDimitry Andric return LocToVal.lookup(&Loc); 72204eeddc0SDimitry Andric } 72304eeddc0SDimitry Andric 724*06c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const { 725*06c3fb27SDimitry Andric auto *Loc = getStorageLocation(D); 72604eeddc0SDimitry Andric if (Loc == nullptr) 72704eeddc0SDimitry Andric return nullptr; 72804eeddc0SDimitry Andric return getValue(*Loc); 72904eeddc0SDimitry Andric } 73004eeddc0SDimitry Andric 73104eeddc0SDimitry Andric Value *Environment::getValue(const Expr &E, SkipPast SP) const { 73204eeddc0SDimitry Andric auto *Loc = getStorageLocation(E, SP); 73304eeddc0SDimitry Andric if (Loc == nullptr) 73404eeddc0SDimitry Andric return nullptr; 73504eeddc0SDimitry Andric return getValue(*Loc); 73604eeddc0SDimitry Andric } 73704eeddc0SDimitry Andric 738*06c3fb27SDimitry Andric Value *Environment::getValueStrict(const Expr &E) const { 739*06c3fb27SDimitry Andric assert(E.isPRValue()); 740*06c3fb27SDimitry Andric Value *Val = getValue(E, SkipPast::None); 741*06c3fb27SDimitry Andric 742*06c3fb27SDimitry Andric assert(Val == nullptr || !isa<ReferenceValue>(Val)); 743*06c3fb27SDimitry Andric 744*06c3fb27SDimitry Andric return Val; 745*06c3fb27SDimitry Andric } 746*06c3fb27SDimitry Andric 74704eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 74804eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 74981ad6265SDimitry Andric int CreatedValuesCount = 0; 75081ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 75181ad6265SDimitry Andric CreatedValuesCount); 75281ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 75381ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 75481ad6265SDimitry Andric << '\n'; 75581ad6265SDimitry Andric } 75681ad6265SDimitry Andric return Val; 75704eeddc0SDimitry Andric } 75804eeddc0SDimitry Andric 75904eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 76081ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 76181ad6265SDimitry Andric int &CreatedValuesCount) { 76204eeddc0SDimitry Andric assert(!Type.isNull()); 76304eeddc0SDimitry Andric 76481ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 76581ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 76681ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 76781ad6265SDimitry Andric return nullptr; 76881ad6265SDimitry Andric 76981ad6265SDimitry Andric if (Type->isBooleanType()) { 77081ad6265SDimitry Andric CreatedValuesCount++; 77181ad6265SDimitry Andric return &makeAtomicBoolValue(); 77281ad6265SDimitry Andric } 77381ad6265SDimitry Andric 77404eeddc0SDimitry Andric if (Type->isIntegerType()) { 775bdd1243dSDimitry Andric // FIXME: consider instead `return nullptr`, given that we do nothing useful 776bdd1243dSDimitry Andric // with integers, and so distinguishing them serves no purpose, but could 777bdd1243dSDimitry Andric // prevent convergence. 77881ad6265SDimitry Andric CreatedValuesCount++; 779*06c3fb27SDimitry Andric return &arena().create<IntegerValue>(); 78004eeddc0SDimitry Andric } 78104eeddc0SDimitry Andric 782*06c3fb27SDimitry Andric if (Type->isReferenceType() || Type->isPointerType()) { 78381ad6265SDimitry Andric CreatedValuesCount++; 784*06c3fb27SDimitry Andric QualType PointeeType = Type->getPointeeType(); 785*06c3fb27SDimitry Andric StorageLocation &PointeeLoc = 786*06c3fb27SDimitry Andric createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); 78704eeddc0SDimitry Andric 788*06c3fb27SDimitry Andric if (Type->isReferenceType()) 789*06c3fb27SDimitry Andric return &arena().create<ReferenceValue>(PointeeLoc); 790*06c3fb27SDimitry Andric else 791*06c3fb27SDimitry Andric return &arena().create<PointerValue>(PointeeLoc); 79204eeddc0SDimitry Andric } 79304eeddc0SDimitry Andric 794*06c3fb27SDimitry Andric if (Type->isRecordType()) { 79581ad6265SDimitry Andric CreatedValuesCount++; 796*06c3fb27SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 797*06c3fb27SDimitry Andric for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { 79804eeddc0SDimitry Andric assert(Field != nullptr); 79904eeddc0SDimitry Andric 80004eeddc0SDimitry Andric QualType FieldType = Field->getType(); 80104eeddc0SDimitry Andric 802*06c3fb27SDimitry Andric FieldLocs.insert( 803*06c3fb27SDimitry Andric {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, 804*06c3fb27SDimitry Andric CreatedValuesCount)}); 80504eeddc0SDimitry Andric } 80604eeddc0SDimitry Andric 807*06c3fb27SDimitry Andric AggregateStorageLocation &Loc = 808*06c3fb27SDimitry Andric arena().create<AggregateStorageLocation>(Type, std::move(FieldLocs)); 809*06c3fb27SDimitry Andric StructValue &StructVal = create<StructValue>(Loc); 810*06c3fb27SDimitry Andric 811*06c3fb27SDimitry Andric // As we already have a storage location for the `StructValue`, we can and 812*06c3fb27SDimitry Andric // should associate them in the environment. 813*06c3fb27SDimitry Andric setValue(Loc, StructVal); 814*06c3fb27SDimitry Andric 815*06c3fb27SDimitry Andric return &StructVal; 81604eeddc0SDimitry Andric } 81704eeddc0SDimitry Andric 81804eeddc0SDimitry Andric return nullptr; 81904eeddc0SDimitry Andric } 82004eeddc0SDimitry Andric 821*06c3fb27SDimitry Andric StorageLocation & 822*06c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty, 823*06c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited, 824*06c3fb27SDimitry Andric int Depth, int &CreatedValuesCount) { 825*06c3fb27SDimitry Andric if (!Visited.insert(Ty.getCanonicalType()).second) 826*06c3fb27SDimitry Andric return createStorageLocation(Ty.getNonReferenceType()); 827*06c3fb27SDimitry Andric Value *Val = createValueUnlessSelfReferential( 828*06c3fb27SDimitry Andric Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount); 829*06c3fb27SDimitry Andric Visited.erase(Ty.getCanonicalType()); 830*06c3fb27SDimitry Andric 831*06c3fb27SDimitry Andric Ty = Ty.getNonReferenceType(); 832*06c3fb27SDimitry Andric 833*06c3fb27SDimitry Andric if (Val == nullptr) 834*06c3fb27SDimitry Andric return createStorageLocation(Ty); 835*06c3fb27SDimitry Andric 836*06c3fb27SDimitry Andric if (Ty->isRecordType()) 837*06c3fb27SDimitry Andric return cast<StructValue>(Val)->getAggregateLoc(); 838*06c3fb27SDimitry Andric 839*06c3fb27SDimitry Andric StorageLocation &Loc = createStorageLocation(Ty); 840*06c3fb27SDimitry Andric setValue(Loc, *Val); 841*06c3fb27SDimitry Andric return Loc; 842*06c3fb27SDimitry Andric } 843*06c3fb27SDimitry Andric 844*06c3fb27SDimitry Andric StorageLocation &Environment::createObjectInternal(const VarDecl *D, 845*06c3fb27SDimitry Andric QualType Ty, 846*06c3fb27SDimitry Andric const Expr *InitExpr) { 847*06c3fb27SDimitry Andric if (Ty->isReferenceType()) { 848*06c3fb27SDimitry Andric // Although variables of reference type always need to be initialized, it 849*06c3fb27SDimitry Andric // can happen that we can't see the initializer, so `InitExpr` may still 850*06c3fb27SDimitry Andric // be null. 851*06c3fb27SDimitry Andric if (InitExpr) { 852*06c3fb27SDimitry Andric if (auto *InitExprLoc = 853*06c3fb27SDimitry Andric getStorageLocation(*InitExpr, SkipPast::Reference)) 854*06c3fb27SDimitry Andric return *InitExprLoc; 855*06c3fb27SDimitry Andric } 856*06c3fb27SDimitry Andric 857*06c3fb27SDimitry Andric // Even though we have an initializer, we might not get an 858*06c3fb27SDimitry Andric // InitExprLoc, for example if the InitExpr is a CallExpr for which we 859*06c3fb27SDimitry Andric // don't have a function body. In this case, we just invent a storage 860*06c3fb27SDimitry Andric // location and value -- it's the best we can do. 861*06c3fb27SDimitry Andric return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); 862*06c3fb27SDimitry Andric } 863*06c3fb27SDimitry Andric 864*06c3fb27SDimitry Andric Value *Val = nullptr; 865*06c3fb27SDimitry Andric if (InitExpr) 866*06c3fb27SDimitry Andric // In the (few) cases where an expression is intentionally 867*06c3fb27SDimitry Andric // "uninterpreted", `InitExpr` is not associated with a value. There are 868*06c3fb27SDimitry Andric // two ways to handle this situation: propagate the status, so that 869*06c3fb27SDimitry Andric // uninterpreted initializers result in uninterpreted variables, or 870*06c3fb27SDimitry Andric // provide a default value. We choose the latter so that later refinements 871*06c3fb27SDimitry Andric // of the variable can be used for reasoning about the surrounding code. 872*06c3fb27SDimitry Andric // For this reason, we let this case be handled by the `createValue()` 873*06c3fb27SDimitry Andric // call below. 874*06c3fb27SDimitry Andric // 875*06c3fb27SDimitry Andric // FIXME. If and when we interpret all language cases, change this to 876*06c3fb27SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a 877*06c3fb27SDimitry Andric // default value (assuming we don't update the environment API to return 878*06c3fb27SDimitry Andric // references). 879*06c3fb27SDimitry Andric Val = getValueStrict(*InitExpr); 880*06c3fb27SDimitry Andric if (!Val) 881*06c3fb27SDimitry Andric Val = createValue(Ty); 882*06c3fb27SDimitry Andric 883*06c3fb27SDimitry Andric if (Ty->isRecordType()) 884*06c3fb27SDimitry Andric return cast<StructValue>(Val)->getAggregateLoc(); 885*06c3fb27SDimitry Andric 886*06c3fb27SDimitry Andric StorageLocation &Loc = 887*06c3fb27SDimitry Andric D ? createStorageLocation(*D) : createStorageLocation(Ty); 888*06c3fb27SDimitry Andric 889*06c3fb27SDimitry Andric if (Val) 890*06c3fb27SDimitry Andric setValue(Loc, *Val); 891*06c3fb27SDimitry Andric 892*06c3fb27SDimitry Andric return Loc; 893*06c3fb27SDimitry Andric } 894*06c3fb27SDimitry Andric 89504eeddc0SDimitry Andric StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const { 89604eeddc0SDimitry Andric switch (SP) { 89704eeddc0SDimitry Andric case SkipPast::None: 89804eeddc0SDimitry Andric return Loc; 89904eeddc0SDimitry Andric case SkipPast::Reference: 90004eeddc0SDimitry Andric // References cannot be chained so we only need to skip past one level of 90104eeddc0SDimitry Andric // indirection. 90204eeddc0SDimitry Andric if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc))) 90381ad6265SDimitry Andric return Val->getReferentLoc(); 90404eeddc0SDimitry Andric return Loc; 90504eeddc0SDimitry Andric } 90604eeddc0SDimitry Andric llvm_unreachable("bad SkipPast kind"); 90704eeddc0SDimitry Andric } 90804eeddc0SDimitry Andric 90904eeddc0SDimitry Andric const StorageLocation &Environment::skip(const StorageLocation &Loc, 91004eeddc0SDimitry Andric SkipPast SP) const { 91104eeddc0SDimitry Andric return skip(*const_cast<StorageLocation *>(&Loc), SP); 91204eeddc0SDimitry Andric } 91304eeddc0SDimitry Andric 914*06c3fb27SDimitry Andric void Environment::addToFlowCondition(const Formula &Val) { 915*06c3fb27SDimitry Andric DACtx->addFlowConditionConstraint(FlowConditionToken, Val); 91681ad6265SDimitry Andric } 91781ad6265SDimitry Andric 918*06c3fb27SDimitry Andric bool Environment::flowConditionImplies(const Formula &Val) const { 919*06c3fb27SDimitry Andric return DACtx->flowConditionImplies(FlowConditionToken, Val); 92081ad6265SDimitry Andric } 92181ad6265SDimitry Andric 922bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const { 923bdd1243dSDimitry Andric // FIXME: add printing for remaining fields and allow caller to decide what 924bdd1243dSDimitry Andric // fields are printed. 925bdd1243dSDimitry Andric OS << "DeclToLoc:\n"; 926bdd1243dSDimitry Andric for (auto [D, L] : DeclToLoc) 927*06c3fb27SDimitry Andric OS << " [" << D->getNameAsString() << ", " << L << "]\n"; 928bdd1243dSDimitry Andric 929bdd1243dSDimitry Andric OS << "ExprToLoc:\n"; 930bdd1243dSDimitry Andric for (auto [E, L] : ExprToLoc) 931bdd1243dSDimitry Andric OS << " [" << E << ", " << L << "]\n"; 932bdd1243dSDimitry Andric 933bdd1243dSDimitry Andric OS << "LocToVal:\n"; 934bdd1243dSDimitry Andric for (auto [L, V] : LocToVal) { 935bdd1243dSDimitry Andric OS << " [" << L << ", " << V << ": " << *V << "]\n"; 936bdd1243dSDimitry Andric } 937bdd1243dSDimitry Andric 938bdd1243dSDimitry Andric OS << "FlowConditionToken:\n"; 939*06c3fb27SDimitry Andric DACtx->dumpFlowCondition(FlowConditionToken, OS); 940fcaf7f86SDimitry Andric } 941fcaf7f86SDimitry Andric 942bdd1243dSDimitry Andric void Environment::dump() const { 943bdd1243dSDimitry Andric dump(llvm::dbgs()); 944bdd1243dSDimitry Andric } 945bdd1243dSDimitry Andric 946*06c3fb27SDimitry Andric AggregateStorageLocation * 947*06c3fb27SDimitry Andric getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 948*06c3fb27SDimitry Andric const Environment &Env) { 949*06c3fb27SDimitry Andric Expr *ImplicitObject = MCE.getImplicitObjectArgument(); 950*06c3fb27SDimitry Andric if (ImplicitObject == nullptr) 951*06c3fb27SDimitry Andric return nullptr; 952*06c3fb27SDimitry Andric StorageLocation *Loc = 953*06c3fb27SDimitry Andric Env.getStorageLocation(*ImplicitObject, SkipPast::Reference); 954*06c3fb27SDimitry Andric if (Loc == nullptr) 955*06c3fb27SDimitry Andric return nullptr; 956*06c3fb27SDimitry Andric if (ImplicitObject->getType()->isPointerType()) { 957*06c3fb27SDimitry Andric if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc))) 958*06c3fb27SDimitry Andric return &cast<AggregateStorageLocation>(Val->getPointeeLoc()); 959*06c3fb27SDimitry Andric return nullptr; 960*06c3fb27SDimitry Andric } 961*06c3fb27SDimitry Andric return cast<AggregateStorageLocation>(Loc); 962*06c3fb27SDimitry Andric } 963*06c3fb27SDimitry Andric 964*06c3fb27SDimitry Andric AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 965*06c3fb27SDimitry Andric const Environment &Env) { 966*06c3fb27SDimitry Andric Expr *Base = ME.getBase(); 967*06c3fb27SDimitry Andric if (Base == nullptr) 968*06c3fb27SDimitry Andric return nullptr; 969*06c3fb27SDimitry Andric StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference); 970*06c3fb27SDimitry Andric if (Loc == nullptr) 971*06c3fb27SDimitry Andric return nullptr; 972*06c3fb27SDimitry Andric if (ME.isArrow()) { 973*06c3fb27SDimitry Andric if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc))) 974*06c3fb27SDimitry Andric return &cast<AggregateStorageLocation>(Val->getPointeeLoc()); 975*06c3fb27SDimitry Andric return nullptr; 976*06c3fb27SDimitry Andric } 977*06c3fb27SDimitry Andric return cast<AggregateStorageLocation>(Loc); 978*06c3fb27SDimitry Andric } 979*06c3fb27SDimitry Andric 980*06c3fb27SDimitry Andric std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) { 981*06c3fb27SDimitry Andric // Unnamed bitfields are only used for padding and do not appear in 982*06c3fb27SDimitry Andric // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s 983*06c3fb27SDimitry Andric // field list, and we thus need to remove them before mapping inits to 984*06c3fb27SDimitry Andric // fields to avoid mapping inits to the wrongs fields. 985*06c3fb27SDimitry Andric std::vector<FieldDecl *> Fields; 986*06c3fb27SDimitry Andric llvm::copy_if( 987*06c3fb27SDimitry Andric RD->fields(), std::back_inserter(Fields), 988*06c3fb27SDimitry Andric [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); 989*06c3fb27SDimitry Andric return Fields; 990*06c3fb27SDimitry Andric } 991*06c3fb27SDimitry Andric 992*06c3fb27SDimitry Andric StructValue &refreshStructValue(AggregateStorageLocation &Loc, 993*06c3fb27SDimitry Andric Environment &Env) { 994*06c3fb27SDimitry Andric auto &NewVal = Env.create<StructValue>(Loc); 995*06c3fb27SDimitry Andric Env.setValue(Loc, NewVal); 996*06c3fb27SDimitry Andric return NewVal; 997*06c3fb27SDimitry Andric } 998*06c3fb27SDimitry Andric 999*06c3fb27SDimitry Andric StructValue &refreshStructValue(const Expr &Expr, Environment &Env) { 1000*06c3fb27SDimitry Andric assert(Expr.getType()->isRecordType()); 1001*06c3fb27SDimitry Andric 1002*06c3fb27SDimitry Andric if (Expr.isPRValue()) { 1003*06c3fb27SDimitry Andric if (auto *ExistingVal = 1004*06c3fb27SDimitry Andric cast_or_null<StructValue>(Env.getValueStrict(Expr))) { 1005*06c3fb27SDimitry Andric auto &NewVal = Env.create<StructValue>(ExistingVal->getAggregateLoc()); 1006*06c3fb27SDimitry Andric Env.setValueStrict(Expr, NewVal); 1007*06c3fb27SDimitry Andric return NewVal; 1008*06c3fb27SDimitry Andric } 1009*06c3fb27SDimitry Andric 1010*06c3fb27SDimitry Andric auto &NewVal = *cast<StructValue>(Env.createValue(Expr.getType())); 1011*06c3fb27SDimitry Andric Env.setValueStrict(Expr, NewVal); 1012*06c3fb27SDimitry Andric return NewVal; 1013*06c3fb27SDimitry Andric } 1014*06c3fb27SDimitry Andric 1015*06c3fb27SDimitry Andric if (auto *Loc = cast_or_null<AggregateStorageLocation>( 1016*06c3fb27SDimitry Andric Env.getStorageLocationStrict(Expr))) { 1017*06c3fb27SDimitry Andric auto &NewVal = Env.create<StructValue>(*Loc); 1018*06c3fb27SDimitry Andric Env.setValue(*Loc, NewVal); 1019*06c3fb27SDimitry Andric return NewVal; 1020*06c3fb27SDimitry Andric } 1021*06c3fb27SDimitry Andric 1022*06c3fb27SDimitry Andric auto &NewVal = *cast<StructValue>(Env.createValue(Expr.getType())); 1023*06c3fb27SDimitry Andric Env.setStorageLocationStrict(Expr, NewVal.getAggregateLoc()); 1024*06c3fb27SDimitry Andric return NewVal; 1025*06c3fb27SDimitry Andric } 1026*06c3fb27SDimitry Andric 102704eeddc0SDimitry Andric } // namespace dataflow 102804eeddc0SDimitry Andric } // namespace clang 1029