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" 2306c3fb27SDimitry Andric #include "llvm/ADT/MapVector.h" 24bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 2504eeddc0SDimitry Andric #include "llvm/Support/ErrorHandling.h" 2681ad6265SDimitry Andric #include <cassert> 2704eeddc0SDimitry Andric #include <utility> 2804eeddc0SDimitry Andric 2904eeddc0SDimitry Andric namespace clang { 3004eeddc0SDimitry Andric namespace dataflow { 3104eeddc0SDimitry Andric 3281ad6265SDimitry Andric // FIXME: convert these to parameters of the analysis or environment. Current 3381ad6265SDimitry Andric // settings have been experimentaly validated, but only for a particular 3481ad6265SDimitry Andric // analysis. 3581ad6265SDimitry Andric static constexpr int MaxCompositeValueDepth = 3; 3681ad6265SDimitry Andric static constexpr int MaxCompositeValueSize = 1000; 3781ad6265SDimitry Andric 3804eeddc0SDimitry Andric /// Returns a map consisting of key-value entries that are present in both maps. 395f757f3fSDimitry Andric static llvm::DenseMap<const ValueDecl *, StorageLocation *> intersectDeclToLoc( 405f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1, 415f757f3fSDimitry Andric const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) { 425f757f3fSDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> Result; 435f757f3fSDimitry Andric for (auto &Entry : DeclToLoc1) { 445f757f3fSDimitry Andric auto It = DeclToLoc2.find(Entry.first); 455f757f3fSDimitry Andric if (It != DeclToLoc2.end() && Entry.second == It->second) 4604eeddc0SDimitry Andric Result.insert({Entry.first, Entry.second}); 4704eeddc0SDimitry Andric } 4804eeddc0SDimitry Andric return Result; 4904eeddc0SDimitry Andric } 5004eeddc0SDimitry Andric 515f757f3fSDimitry Andric // Whether to consider equivalent two values with an unknown relation. 525f757f3fSDimitry Andric // 535f757f3fSDimitry Andric // FIXME: this function is a hack enabling unsoundness to support 545f757f3fSDimitry Andric // convergence. Once we have widening support for the reference/pointer and 555f757f3fSDimitry Andric // struct built-in models, this should be unconditionally `false` (and inlined 565f757f3fSDimitry Andric // as such at its call sites). 575f757f3fSDimitry Andric static bool equateUnknownValues(Value::Kind K) { 585f757f3fSDimitry Andric switch (K) { 595f757f3fSDimitry Andric case Value::Kind::Integer: 605f757f3fSDimitry Andric case Value::Kind::Pointer: 615f757f3fSDimitry Andric case Value::Kind::Record: 625f757f3fSDimitry Andric return true; 635f757f3fSDimitry Andric default: 645f757f3fSDimitry Andric return false; 655f757f3fSDimitry Andric } 665f757f3fSDimitry Andric } 675f757f3fSDimitry Andric 68bdd1243dSDimitry Andric static bool compareDistinctValues(QualType Type, Value &Val1, 69bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 7081ad6265SDimitry Andric const Environment &Env2, 7181ad6265SDimitry Andric Environment::ValueModel &Model) { 72bdd1243dSDimitry Andric // Note: Potentially costly, but, for booleans, we could check whether both 73bdd1243dSDimitry Andric // can be proven equivalent in their respective environments. 74bdd1243dSDimitry Andric 75bdd1243dSDimitry Andric // FIXME: move the reference/pointers logic from `areEquivalentValues` to here 76bdd1243dSDimitry Andric // and implement separate, join/widen specific handling for 77bdd1243dSDimitry Andric // reference/pointers. 78bdd1243dSDimitry Andric switch (Model.compare(Type, Val1, Env1, Val2, Env2)) { 79bdd1243dSDimitry Andric case ComparisonResult::Same: 80bdd1243dSDimitry Andric return true; 81bdd1243dSDimitry Andric case ComparisonResult::Different: 82bdd1243dSDimitry Andric return false; 83bdd1243dSDimitry Andric case ComparisonResult::Unknown: 845f757f3fSDimitry Andric return equateUnknownValues(Val1.getKind()); 85bdd1243dSDimitry Andric } 86bdd1243dSDimitry Andric llvm_unreachable("All cases covered in switch"); 8781ad6265SDimitry Andric } 8881ad6265SDimitry Andric 8981ad6265SDimitry Andric /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`, 9081ad6265SDimitry Andric /// respectively, of the same type `Type`. Merging generally produces a single 9181ad6265SDimitry Andric /// value that (soundly) approximates the two inputs, although the actual 9281ad6265SDimitry Andric /// meaning depends on `Model`. 93bdd1243dSDimitry Andric static Value *mergeDistinctValues(QualType Type, Value &Val1, 94bdd1243dSDimitry Andric const Environment &Env1, Value &Val2, 9581ad6265SDimitry Andric const Environment &Env2, 9681ad6265SDimitry Andric Environment &MergedEnv, 9781ad6265SDimitry Andric Environment::ValueModel &Model) { 9881ad6265SDimitry Andric // Join distinct boolean values preserving information about the constraints 9981ad6265SDimitry Andric // in the respective path conditions. 100bdd1243dSDimitry Andric if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) { 101bdd1243dSDimitry Andric // FIXME: Checking both values should be unnecessary, since they should have 102bdd1243dSDimitry Andric // a consistent shape. However, right now we can end up with BoolValue's in 103bdd1243dSDimitry Andric // integer-typed variables due to our incorrect handling of 104bdd1243dSDimitry Andric // boolean-to-integer casts (we just propagate the BoolValue to the result 105bdd1243dSDimitry Andric // of the cast). So, a join can encounter an integer in one branch but a 106bdd1243dSDimitry Andric // bool in the other. 107bdd1243dSDimitry Andric // For example: 108bdd1243dSDimitry Andric // ``` 109bdd1243dSDimitry Andric // std::optional<bool> o; 110bdd1243dSDimitry Andric // int x; 111bdd1243dSDimitry Andric // if (o.has_value()) 112bdd1243dSDimitry Andric // x = o.value(); 113bdd1243dSDimitry Andric // ``` 11406c3fb27SDimitry Andric auto &Expr1 = cast<BoolValue>(Val1).formula(); 11506c3fb27SDimitry Andric auto &Expr2 = cast<BoolValue>(Val2).formula(); 11606c3fb27SDimitry Andric auto &A = MergedEnv.arena(); 11706c3fb27SDimitry Andric auto &MergedVal = A.makeAtomRef(A.makeAtom()); 1185f757f3fSDimitry Andric MergedEnv.assume( 11906c3fb27SDimitry Andric A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()), 12006c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr1)), 12106c3fb27SDimitry Andric A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()), 12206c3fb27SDimitry Andric A.makeEquals(MergedVal, Expr2)))); 12306c3fb27SDimitry Andric return &A.makeBoolValue(MergedVal); 12406c3fb27SDimitry Andric } 12506c3fb27SDimitry Andric 12606c3fb27SDimitry Andric Value *MergedVal = nullptr; 1275f757f3fSDimitry Andric if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) { 1285f757f3fSDimitry Andric auto *RecordVal2 = cast<RecordValue>(&Val2); 12906c3fb27SDimitry Andric 1305f757f3fSDimitry Andric if (&RecordVal1->getLoc() == &RecordVal2->getLoc()) 1315f757f3fSDimitry Andric // `RecordVal1` and `RecordVal2` may have different properties associated 1325f757f3fSDimitry Andric // with them. Create a new `RecordValue` with the same location but 1335f757f3fSDimitry Andric // without any properties so that we soundly approximate both values. If a 1345f757f3fSDimitry Andric // particular analysis needs to merge properties, it should do so in 1355f757f3fSDimitry Andric // `DataflowAnalysis::merge()`. 1365f757f3fSDimitry Andric MergedVal = &MergedEnv.create<RecordValue>(RecordVal1->getLoc()); 1375f757f3fSDimitry Andric else 1385f757f3fSDimitry Andric // If the locations for the two records are different, need to create a 1395f757f3fSDimitry Andric // completely new value. 1405f757f3fSDimitry Andric MergedVal = MergedEnv.createValue(Type); 14106c3fb27SDimitry Andric } else { 14206c3fb27SDimitry Andric MergedVal = MergedEnv.createValue(Type); 14381ad6265SDimitry Andric } 14481ad6265SDimitry Andric 14581ad6265SDimitry Andric // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge` 14681ad6265SDimitry Andric // returns false to avoid storing unneeded values in `DACtx`. 14706c3fb27SDimitry Andric if (MergedVal) 148bdd1243dSDimitry Andric if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv)) 14981ad6265SDimitry Andric return MergedVal; 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric return nullptr; 15281ad6265SDimitry Andric } 15381ad6265SDimitry Andric 154bdd1243dSDimitry Andric // When widening does not change `Current`, return value will equal `&Prev`. 155bdd1243dSDimitry Andric static Value &widenDistinctValues(QualType Type, Value &Prev, 156bdd1243dSDimitry Andric const Environment &PrevEnv, Value &Current, 157bdd1243dSDimitry Andric Environment &CurrentEnv, 158bdd1243dSDimitry Andric Environment::ValueModel &Model) { 159bdd1243dSDimitry Andric // Boolean-model widening. 1605f757f3fSDimitry Andric if (auto *PrevBool = dyn_cast<BoolValue>(&Prev)) { 1615f757f3fSDimitry Andric // If previous value was already Top, re-use that to (implicitly) indicate 1625f757f3fSDimitry Andric // that no change occurred. 163bdd1243dSDimitry Andric if (isa<TopBoolValue>(Prev)) 164bdd1243dSDimitry Andric return Prev; 1655f757f3fSDimitry Andric 1665f757f3fSDimitry Andric // We may need to widen to Top, but before we do so, check whether both 1675f757f3fSDimitry Andric // values are implied to be either true or false in the current environment. 1685f757f3fSDimitry Andric // In that case, we can simply return a literal instead. 1695f757f3fSDimitry Andric auto &CurBool = cast<BoolValue>(Current); 1705f757f3fSDimitry Andric bool TruePrev = PrevEnv.proves(PrevBool->formula()); 1715f757f3fSDimitry Andric bool TrueCur = CurrentEnv.proves(CurBool.formula()); 1725f757f3fSDimitry Andric if (TruePrev && TrueCur) 1735f757f3fSDimitry Andric return CurrentEnv.getBoolLiteralValue(true); 1745f757f3fSDimitry Andric if (!TruePrev && !TrueCur && 1755f757f3fSDimitry Andric PrevEnv.proves(PrevEnv.arena().makeNot(PrevBool->formula())) && 1765f757f3fSDimitry Andric CurrentEnv.proves(CurrentEnv.arena().makeNot(CurBool.formula()))) 1775f757f3fSDimitry Andric return CurrentEnv.getBoolLiteralValue(false); 1785f757f3fSDimitry Andric 179bdd1243dSDimitry Andric return CurrentEnv.makeTopBoolValue(); 180bdd1243dSDimitry Andric } 18181ad6265SDimitry Andric 182bdd1243dSDimitry Andric // FIXME: Add other built-in model widening. 183bdd1243dSDimitry Andric 184bdd1243dSDimitry Andric // Custom-model widening. 185bdd1243dSDimitry Andric if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv)) 186bdd1243dSDimitry Andric return *W; 187bdd1243dSDimitry Andric 1885f757f3fSDimitry Andric return equateUnknownValues(Prev.getKind()) ? Prev : Current; 1895f757f3fSDimitry Andric } 1905f757f3fSDimitry Andric 1915f757f3fSDimitry Andric // Returns whether the values in `Map1` and `Map2` compare equal for those 1925f757f3fSDimitry Andric // keys that `Map1` and `Map2` have in common. 1935f757f3fSDimitry Andric template <typename Key> 1945f757f3fSDimitry Andric bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1, 1955f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &Map2, 1965f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 1975f757f3fSDimitry Andric Environment::ValueModel &Model) { 1985f757f3fSDimitry Andric for (auto &Entry : Map1) { 1995f757f3fSDimitry Andric Key K = Entry.first; 2005f757f3fSDimitry Andric assert(K != nullptr); 2015f757f3fSDimitry Andric 2025f757f3fSDimitry Andric Value *Val = Entry.second; 2035f757f3fSDimitry Andric assert(Val != nullptr); 2045f757f3fSDimitry Andric 2055f757f3fSDimitry Andric auto It = Map2.find(K); 2065f757f3fSDimitry Andric if (It == Map2.end()) 2075f757f3fSDimitry Andric continue; 2085f757f3fSDimitry Andric assert(It->second != nullptr); 2095f757f3fSDimitry Andric 2105f757f3fSDimitry Andric if (!areEquivalentValues(*Val, *It->second) && 2115f757f3fSDimitry Andric !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2, 2125f757f3fSDimitry Andric Model)) 2135f757f3fSDimitry Andric return false; 2145f757f3fSDimitry Andric } 2155f757f3fSDimitry Andric 2165f757f3fSDimitry Andric return true; 2175f757f3fSDimitry Andric } 2185f757f3fSDimitry Andric 2195f757f3fSDimitry Andric // Perform a join on two `LocToVal` maps. 2205f757f3fSDimitry Andric static llvm::MapVector<const StorageLocation *, Value *> 2215f757f3fSDimitry Andric joinLocToVal(const llvm::MapVector<const StorageLocation *, Value *> &LocToVal, 2225f757f3fSDimitry Andric const llvm::MapVector<const StorageLocation *, Value *> &LocToVal2, 2235f757f3fSDimitry Andric const Environment &Env1, const Environment &Env2, 2245f757f3fSDimitry Andric Environment &JoinedEnv, Environment::ValueModel &Model) { 2255f757f3fSDimitry Andric llvm::MapVector<const StorageLocation *, Value *> Result; 2265f757f3fSDimitry Andric for (auto &Entry : LocToVal) { 2275f757f3fSDimitry Andric const StorageLocation *Loc = Entry.first; 2285f757f3fSDimitry Andric assert(Loc != nullptr); 2295f757f3fSDimitry Andric 2305f757f3fSDimitry Andric Value *Val = Entry.second; 2315f757f3fSDimitry Andric assert(Val != nullptr); 2325f757f3fSDimitry Andric 2335f757f3fSDimitry Andric auto It = LocToVal2.find(Loc); 2345f757f3fSDimitry Andric if (It == LocToVal2.end()) 2355f757f3fSDimitry Andric continue; 2365f757f3fSDimitry Andric assert(It->second != nullptr); 2375f757f3fSDimitry Andric 2385f757f3fSDimitry Andric if (areEquivalentValues(*Val, *It->second)) { 2395f757f3fSDimitry Andric Result.insert({Loc, Val}); 2405f757f3fSDimitry Andric continue; 2415f757f3fSDimitry Andric } 2425f757f3fSDimitry Andric 2435f757f3fSDimitry Andric if (Value *MergedVal = mergeDistinctValues( 2445f757f3fSDimitry Andric Loc->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) { 2455f757f3fSDimitry Andric Result.insert({Loc, MergedVal}); 2465f757f3fSDimitry Andric } 2475f757f3fSDimitry Andric } 2485f757f3fSDimitry Andric 2495f757f3fSDimitry Andric return Result; 2505f757f3fSDimitry Andric } 2515f757f3fSDimitry Andric 2525f757f3fSDimitry Andric // Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either 2535f757f3fSDimitry Andric // `const StorageLocation *` or `const Expr *`. 2545f757f3fSDimitry Andric template <typename Key> 2555f757f3fSDimitry Andric llvm::MapVector<Key, Value *> 2565f757f3fSDimitry Andric widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap, 2575f757f3fSDimitry Andric const llvm::MapVector<Key, Value *> &PrevMap, 2585f757f3fSDimitry Andric Environment &CurEnv, const Environment &PrevEnv, 2595f757f3fSDimitry Andric Environment::ValueModel &Model, LatticeJoinEffect &Effect) { 2605f757f3fSDimitry Andric llvm::MapVector<Key, Value *> WidenedMap; 2615f757f3fSDimitry Andric for (auto &Entry : CurMap) { 2625f757f3fSDimitry Andric Key K = Entry.first; 2635f757f3fSDimitry Andric assert(K != nullptr); 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric Value *Val = Entry.second; 2665f757f3fSDimitry Andric assert(Val != nullptr); 2675f757f3fSDimitry Andric 2685f757f3fSDimitry Andric auto PrevIt = PrevMap.find(K); 2695f757f3fSDimitry Andric if (PrevIt == PrevMap.end()) 2705f757f3fSDimitry Andric continue; 2715f757f3fSDimitry Andric assert(PrevIt->second != nullptr); 2725f757f3fSDimitry Andric 2735f757f3fSDimitry Andric if (areEquivalentValues(*Val, *PrevIt->second)) { 2745f757f3fSDimitry Andric WidenedMap.insert({K, Val}); 2755f757f3fSDimitry Andric continue; 2765f757f3fSDimitry Andric } 2775f757f3fSDimitry Andric 2785f757f3fSDimitry Andric Value &WidenedVal = widenDistinctValues(K->getType(), *PrevIt->second, 2795f757f3fSDimitry Andric PrevEnv, *Val, CurEnv, Model); 2805f757f3fSDimitry Andric WidenedMap.insert({K, &WidenedVal}); 2815f757f3fSDimitry Andric if (&WidenedVal != PrevIt->second) 2825f757f3fSDimitry Andric Effect = LatticeJoinEffect::Changed; 2835f757f3fSDimitry Andric } 2845f757f3fSDimitry Andric 2855f757f3fSDimitry Andric return WidenedMap; 28681ad6265SDimitry Andric } 28781ad6265SDimitry Andric 28881ad6265SDimitry Andric /// Initializes a global storage value. 289bdd1243dSDimitry Andric static void insertIfGlobal(const Decl &D, 290bdd1243dSDimitry Andric llvm::DenseSet<const VarDecl *> &Vars) { 29181ad6265SDimitry Andric if (auto *V = dyn_cast<VarDecl>(&D)) 292bdd1243dSDimitry Andric if (V->hasGlobalStorage()) 293bdd1243dSDimitry Andric Vars.insert(V); 29481ad6265SDimitry Andric } 29581ad6265SDimitry Andric 29606c3fb27SDimitry Andric static void insertIfFunction(const Decl &D, 29706c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 29806c3fb27SDimitry Andric if (auto *FD = dyn_cast<FunctionDecl>(&D)) 29906c3fb27SDimitry Andric Funcs.insert(FD); 30006c3fb27SDimitry Andric } 30106c3fb27SDimitry Andric 3025f757f3fSDimitry Andric static MemberExpr *getMemberForAccessor(const CXXMemberCallExpr &C) { 3035f757f3fSDimitry Andric // Use getCalleeDecl instead of getMethodDecl in order to handle 3045f757f3fSDimitry Andric // pointer-to-member calls. 3055f757f3fSDimitry Andric const auto *MethodDecl = dyn_cast_or_null<CXXMethodDecl>(C.getCalleeDecl()); 3065f757f3fSDimitry Andric if (!MethodDecl) 3075f757f3fSDimitry Andric return nullptr; 3085f757f3fSDimitry Andric auto *Body = dyn_cast_or_null<CompoundStmt>(MethodDecl->getBody()); 3095f757f3fSDimitry Andric if (!Body || Body->size() != 1) 3105f757f3fSDimitry Andric return nullptr; 3115f757f3fSDimitry Andric if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin())) 3125f757f3fSDimitry Andric if (auto *Return = RS->getRetValue()) 3135f757f3fSDimitry Andric return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts()); 3145f757f3fSDimitry Andric return nullptr; 3155f757f3fSDimitry Andric } 3165f757f3fSDimitry Andric 31706c3fb27SDimitry Andric static void 31806c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields, 31906c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 32006c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 32106c3fb27SDimitry Andric insertIfGlobal(D, Vars); 32206c3fb27SDimitry Andric insertIfFunction(D, Funcs); 323bdd1243dSDimitry Andric if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D)) 324bdd1243dSDimitry Andric for (const auto *B : Decomp->bindings()) 325bdd1243dSDimitry Andric if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding())) 326bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 327bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl())) 328bdd1243dSDimitry Andric Fields.insert(FD); 32981ad6265SDimitry Andric } 33081ad6265SDimitry Andric 33106c3fb27SDimitry Andric /// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields, 33206c3fb27SDimitry Andric /// global variables and functions that are declared in or referenced from 33306c3fb27SDimitry Andric /// sub-statements. 33406c3fb27SDimitry Andric static void 33506c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields, 33606c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> &Vars, 33706c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> &Funcs) { 338bdd1243dSDimitry Andric for (auto *Child : S.children()) 339bdd1243dSDimitry Andric if (Child != nullptr) 34006c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs); 34106c3fb27SDimitry Andric if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S)) 34206c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs); 343bdd1243dSDimitry Andric 34481ad6265SDimitry Andric if (auto *DS = dyn_cast<DeclStmt>(&S)) { 345bdd1243dSDimitry Andric if (DS->isSingleDecl()) 34606c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs); 347bdd1243dSDimitry Andric else 34881ad6265SDimitry Andric for (auto *D : DS->getDeclGroup()) 34906c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs); 35081ad6265SDimitry Andric } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) { 35106c3fb27SDimitry Andric insertIfGlobal(*E->getDecl(), Vars); 35206c3fb27SDimitry Andric insertIfFunction(*E->getDecl(), Funcs); 3535f757f3fSDimitry Andric } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) { 3545f757f3fSDimitry Andric // If this is a method that returns a member variable but does nothing else, 3555f757f3fSDimitry Andric // model the field of the return value. 3565f757f3fSDimitry Andric if (MemberExpr *E = getMemberForAccessor(*C)) 3575f757f3fSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) 3585f757f3fSDimitry Andric Fields.insert(FD); 35981ad6265SDimitry Andric } else if (auto *E = dyn_cast<MemberExpr>(&S)) { 360bdd1243dSDimitry Andric // FIXME: should we be using `E->getFoundDecl()`? 361bdd1243dSDimitry Andric const ValueDecl *VD = E->getMemberDecl(); 36206c3fb27SDimitry Andric insertIfGlobal(*VD, Vars); 36306c3fb27SDimitry Andric insertIfFunction(*VD, Funcs); 364bdd1243dSDimitry Andric if (const auto *FD = dyn_cast<FieldDecl>(VD)) 365bdd1243dSDimitry Andric Fields.insert(FD); 36606c3fb27SDimitry Andric } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) { 36706c3fb27SDimitry Andric if (RecordDecl *RD = InitList->getType()->getAsRecordDecl()) 36806c3fb27SDimitry Andric for (const auto *FD : getFieldsForInitListExpr(RD)) 36906c3fb27SDimitry Andric Fields.insert(FD); 370bdd1243dSDimitry Andric } 371bdd1243dSDimitry Andric } 372bdd1243dSDimitry Andric 3735f757f3fSDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx) 3745f757f3fSDimitry Andric : DACtx(&DACtx), 3755f757f3fSDimitry Andric FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {} 3765f757f3fSDimitry Andric 3775f757f3fSDimitry Andric Environment::Environment(DataflowAnalysisContext &DACtx, 3785f757f3fSDimitry Andric const DeclContext &DeclCtx) 3795f757f3fSDimitry Andric : Environment(DACtx) { 3805f757f3fSDimitry Andric CallStack.push_back(&DeclCtx); 3815f757f3fSDimitry Andric } 3825f757f3fSDimitry Andric 3835f757f3fSDimitry Andric void Environment::initialize() { 3845f757f3fSDimitry Andric const DeclContext *DeclCtx = getDeclCtx(); 3855f757f3fSDimitry Andric if (DeclCtx == nullptr) 3865f757f3fSDimitry Andric return; 3875f757f3fSDimitry Andric 3885f757f3fSDimitry Andric if (const auto *FuncDecl = dyn_cast<FunctionDecl>(DeclCtx)) { 3895f757f3fSDimitry Andric assert(FuncDecl->getBody() != nullptr); 3905f757f3fSDimitry Andric 3915f757f3fSDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 3925f757f3fSDimitry Andric 3935f757f3fSDimitry Andric for (const auto *ParamDecl : FuncDecl->parameters()) { 3945f757f3fSDimitry Andric assert(ParamDecl != nullptr); 3955f757f3fSDimitry Andric setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr)); 3965f757f3fSDimitry Andric } 3975f757f3fSDimitry Andric } 3985f757f3fSDimitry Andric 3995f757f3fSDimitry Andric if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(DeclCtx)) { 4005f757f3fSDimitry Andric auto *Parent = MethodDecl->getParent(); 4015f757f3fSDimitry Andric assert(Parent != nullptr); 4025f757f3fSDimitry Andric 4035f757f3fSDimitry Andric if (Parent->isLambda()) { 4045f757f3fSDimitry Andric for (auto Capture : Parent->captures()) { 4055f757f3fSDimitry Andric if (Capture.capturesVariable()) { 4065f757f3fSDimitry Andric const auto *VarDecl = Capture.getCapturedVar(); 4075f757f3fSDimitry Andric assert(VarDecl != nullptr); 4085f757f3fSDimitry Andric setStorageLocation(*VarDecl, createObject(*VarDecl, nullptr)); 4095f757f3fSDimitry Andric } else if (Capture.capturesThis()) { 4105f757f3fSDimitry Andric const auto *SurroundingMethodDecl = 4115f757f3fSDimitry Andric cast<CXXMethodDecl>(DeclCtx->getNonClosureAncestor()); 4125f757f3fSDimitry Andric QualType ThisPointeeType = 4135f757f3fSDimitry Andric SurroundingMethodDecl->getFunctionObjectParameterType(); 4145f757f3fSDimitry Andric setThisPointeeStorageLocation( 4155f757f3fSDimitry Andric cast<RecordValue>(createValue(ThisPointeeType))->getLoc()); 4165f757f3fSDimitry Andric } 4175f757f3fSDimitry Andric } 4185f757f3fSDimitry Andric } else if (MethodDecl->isImplicitObjectMemberFunction()) { 4195f757f3fSDimitry Andric QualType ThisPointeeType = MethodDecl->getFunctionObjectParameterType(); 4205f757f3fSDimitry Andric setThisPointeeStorageLocation( 4215f757f3fSDimitry Andric cast<RecordValue>(createValue(ThisPointeeType))->getLoc()); 4225f757f3fSDimitry Andric } 4235f757f3fSDimitry Andric } 4245f757f3fSDimitry Andric } 4255f757f3fSDimitry Andric 426bdd1243dSDimitry Andric // FIXME: Add support for resetting globals after function calls to enable 427bdd1243dSDimitry Andric // the implementation of sound analyses. 42806c3fb27SDimitry Andric void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) { 42906c3fb27SDimitry Andric assert(FuncDecl->getBody() != nullptr); 43006c3fb27SDimitry Andric 43106c3fb27SDimitry Andric FieldSet Fields; 43206c3fb27SDimitry Andric llvm::DenseSet<const VarDecl *> Vars; 43306c3fb27SDimitry Andric llvm::DenseSet<const FunctionDecl *> Funcs; 43406c3fb27SDimitry Andric 43506c3fb27SDimitry Andric // Look for global variable and field references in the 43606c3fb27SDimitry Andric // constructor-initializers. 43706c3fb27SDimitry Andric if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) { 43806c3fb27SDimitry Andric for (const auto *Init : CtorDecl->inits()) { 43906c3fb27SDimitry Andric if (Init->isMemberInitializer()) { 44006c3fb27SDimitry Andric Fields.insert(Init->getMember()); 44106c3fb27SDimitry Andric } else if (Init->isIndirectMemberInitializer()) { 44206c3fb27SDimitry Andric for (const auto *I : Init->getIndirectMember()->chain()) 44306c3fb27SDimitry Andric Fields.insert(cast<FieldDecl>(I)); 44406c3fb27SDimitry Andric } 44506c3fb27SDimitry Andric const Expr *E = Init->getInit(); 44606c3fb27SDimitry Andric assert(E != nullptr); 44706c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs); 44806c3fb27SDimitry Andric } 44906c3fb27SDimitry Andric // Add all fields mentioned in default member initializers. 45006c3fb27SDimitry Andric for (const FieldDecl *F : CtorDecl->getParent()->fields()) 45106c3fb27SDimitry Andric if (const auto *I = F->getInClassInitializer()) 45206c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs); 45306c3fb27SDimitry Andric } 45406c3fb27SDimitry Andric getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs); 45506c3fb27SDimitry Andric 45606c3fb27SDimitry Andric // These have to be added before the lines that follow to ensure that 45706c3fb27SDimitry Andric // `create*` work correctly for structs. 45806c3fb27SDimitry Andric DACtx->addModeledFields(Fields); 45906c3fb27SDimitry Andric 460bdd1243dSDimitry Andric for (const VarDecl *D : Vars) { 46106c3fb27SDimitry Andric if (getStorageLocation(*D) != nullptr) 462bdd1243dSDimitry Andric continue; 46306c3fb27SDimitry Andric 46406c3fb27SDimitry Andric setStorageLocation(*D, createObject(*D)); 46506c3fb27SDimitry Andric } 46606c3fb27SDimitry Andric 46706c3fb27SDimitry Andric for (const FunctionDecl *FD : Funcs) { 46806c3fb27SDimitry Andric if (getStorageLocation(*FD) != nullptr) 46906c3fb27SDimitry Andric continue; 47006c3fb27SDimitry Andric auto &Loc = createStorageLocation(FD->getType()); 47106c3fb27SDimitry Andric setStorageLocation(*FD, Loc); 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric } 47481ad6265SDimitry Andric 47506c3fb27SDimitry Andric Environment Environment::fork() const { 47606c3fb27SDimitry Andric Environment Copy(*this); 47706c3fb27SDimitry Andric Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken); 47806c3fb27SDimitry Andric return Copy; 4791fd87a68SDimitry Andric } 4801fd87a68SDimitry Andric 481bdd1243dSDimitry Andric bool Environment::canDescend(unsigned MaxDepth, 482bdd1243dSDimitry Andric const DeclContext *Callee) const { 483bdd1243dSDimitry Andric return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee); 48404eeddc0SDimitry Andric } 48504eeddc0SDimitry Andric 486972a253aSDimitry Andric Environment Environment::pushCall(const CallExpr *Call) const { 487972a253aSDimitry Andric Environment Env(*this); 488972a253aSDimitry Andric 489bdd1243dSDimitry Andric if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) { 490bdd1243dSDimitry Andric if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) { 491bdd1243dSDimitry Andric if (!isa<CXXThisExpr>(Arg)) 4925f757f3fSDimitry Andric Env.ThisPointeeLoc = 4935f757f3fSDimitry Andric cast<RecordStorageLocation>(getStorageLocation(*Arg)); 494bdd1243dSDimitry Andric // Otherwise (when the argument is `this`), retain the current 495bdd1243dSDimitry Andric // environment's `ThisPointeeLoc`. 496bdd1243dSDimitry Andric } 497bdd1243dSDimitry Andric } 498972a253aSDimitry Andric 499bdd1243dSDimitry Andric Env.pushCallInternal(Call->getDirectCallee(), 500bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 501bdd1243dSDimitry Andric 502bdd1243dSDimitry Andric return Env; 503bdd1243dSDimitry Andric } 504bdd1243dSDimitry Andric 505bdd1243dSDimitry Andric Environment Environment::pushCall(const CXXConstructExpr *Call) const { 506bdd1243dSDimitry Andric Environment Env(*this); 507bdd1243dSDimitry Andric 50806c3fb27SDimitry Andric Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call); 509bdd1243dSDimitry Andric 510bdd1243dSDimitry Andric Env.pushCallInternal(Call->getConstructor(), 511bdd1243dSDimitry Andric llvm::ArrayRef(Call->getArgs(), Call->getNumArgs())); 512bdd1243dSDimitry Andric 513bdd1243dSDimitry Andric return Env; 514bdd1243dSDimitry Andric } 515bdd1243dSDimitry Andric 516bdd1243dSDimitry Andric void Environment::pushCallInternal(const FunctionDecl *FuncDecl, 517bdd1243dSDimitry Andric ArrayRef<const Expr *> Args) { 51806c3fb27SDimitry Andric // Canonicalize to the definition of the function. This ensures that we're 51906c3fb27SDimitry Andric // putting arguments into the same `ParamVarDecl`s` that the callee will later 52006c3fb27SDimitry Andric // be retrieving them from. 52106c3fb27SDimitry Andric assert(FuncDecl->getDefinition() != nullptr); 52206c3fb27SDimitry Andric FuncDecl = FuncDecl->getDefinition(); 52306c3fb27SDimitry Andric 524bdd1243dSDimitry Andric CallStack.push_back(FuncDecl); 525bdd1243dSDimitry Andric 52606c3fb27SDimitry Andric initFieldsGlobalsAndFuncs(FuncDecl); 527bdd1243dSDimitry Andric 528bdd1243dSDimitry Andric const auto *ParamIt = FuncDecl->param_begin(); 529972a253aSDimitry Andric 530972a253aSDimitry Andric // FIXME: Parameters don't always map to arguments 1:1; examples include 531972a253aSDimitry Andric // overloaded operators implemented as member functions, and parameter packs. 532bdd1243dSDimitry Andric for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) { 533972a253aSDimitry Andric assert(ParamIt != FuncDecl->param_end()); 534972a253aSDimitry Andric const VarDecl *Param = *ParamIt; 53506c3fb27SDimitry Andric setStorageLocation(*Param, createObject(*Param, Args[ArgIndex])); 536bdd1243dSDimitry Andric } 537972a253aSDimitry Andric } 538972a253aSDimitry Andric 53906c3fb27SDimitry Andric void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) { 5405f757f3fSDimitry Andric // We ignore some entries of `CalleeEnv`: 5415f757f3fSDimitry Andric // - `DACtx` because is already the same in both 5425f757f3fSDimitry Andric // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or 5435f757f3fSDimitry Andric // `ThisPointeeLoc` because they don't apply to us. 5445f757f3fSDimitry Andric // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the 5455f757f3fSDimitry Andric // callee's local scope, so when popping that scope, we do not propagate 5465f757f3fSDimitry Andric // the maps. 547bdd1243dSDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 548bdd1243dSDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 54906c3fb27SDimitry Andric 55006c3fb27SDimitry Andric if (Call->isGLValue()) { 55106c3fb27SDimitry Andric if (CalleeEnv.ReturnLoc != nullptr) 5525f757f3fSDimitry Andric setStorageLocation(*Call, *CalleeEnv.ReturnLoc); 55306c3fb27SDimitry Andric } else if (!Call->getType()->isVoidType()) { 55406c3fb27SDimitry Andric if (CalleeEnv.ReturnVal != nullptr) 5555f757f3fSDimitry Andric setValue(*Call, *CalleeEnv.ReturnVal); 55606c3fb27SDimitry Andric } 55706c3fb27SDimitry Andric } 55806c3fb27SDimitry Andric 55906c3fb27SDimitry Andric void Environment::popCall(const CXXConstructExpr *Call, 56006c3fb27SDimitry Andric const Environment &CalleeEnv) { 56106c3fb27SDimitry Andric // See also comment in `popCall(const CallExpr *, const Environment &)` above. 56206c3fb27SDimitry Andric this->LocToVal = std::move(CalleeEnv.LocToVal); 56306c3fb27SDimitry Andric this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken); 56406c3fb27SDimitry Andric 56506c3fb27SDimitry Andric if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) { 5665f757f3fSDimitry Andric setValue(*Call, *Val); 56706c3fb27SDimitry Andric } 568972a253aSDimitry Andric } 569972a253aSDimitry Andric 5701fd87a68SDimitry Andric bool Environment::equivalentTo(const Environment &Other, 5711fd87a68SDimitry Andric Environment::ValueModel &Model) const { 57204eeddc0SDimitry Andric assert(DACtx == Other.DACtx); 5731fd87a68SDimitry Andric 57406c3fb27SDimitry Andric if (ReturnVal != Other.ReturnVal) 57506c3fb27SDimitry Andric return false; 57606c3fb27SDimitry Andric 577bdd1243dSDimitry Andric if (ReturnLoc != Other.ReturnLoc) 578bdd1243dSDimitry Andric return false; 579bdd1243dSDimitry Andric 580bdd1243dSDimitry Andric if (ThisPointeeLoc != Other.ThisPointeeLoc) 581bdd1243dSDimitry Andric return false; 582bdd1243dSDimitry Andric 5831fd87a68SDimitry Andric if (DeclToLoc != Other.DeclToLoc) 5841fd87a68SDimitry Andric return false; 5851fd87a68SDimitry Andric 5861fd87a68SDimitry Andric if (ExprToLoc != Other.ExprToLoc) 5871fd87a68SDimitry Andric return false; 5881fd87a68SDimitry Andric 5895f757f3fSDimitry Andric if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model)) 5901fd87a68SDimitry Andric return false; 5915f757f3fSDimitry Andric 5925f757f3fSDimitry Andric if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model)) 5935f757f3fSDimitry Andric return false; 5941fd87a68SDimitry Andric 5951fd87a68SDimitry Andric return true; 59604eeddc0SDimitry Andric } 59704eeddc0SDimitry Andric 598bdd1243dSDimitry Andric LatticeJoinEffect Environment::widen(const Environment &PrevEnv, 599bdd1243dSDimitry Andric Environment::ValueModel &Model) { 600bdd1243dSDimitry Andric assert(DACtx == PrevEnv.DACtx); 60106c3fb27SDimitry Andric assert(ReturnVal == PrevEnv.ReturnVal); 602bdd1243dSDimitry Andric assert(ReturnLoc == PrevEnv.ReturnLoc); 603bdd1243dSDimitry Andric assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc); 604bdd1243dSDimitry Andric assert(CallStack == PrevEnv.CallStack); 605bdd1243dSDimitry Andric 606bdd1243dSDimitry Andric auto Effect = LatticeJoinEffect::Unchanged; 607bdd1243dSDimitry Andric 608bdd1243dSDimitry Andric // By the API, `PrevEnv` is a previous version of the environment for the same 609bdd1243dSDimitry Andric // block, so we have some guarantees about its shape. In particular, it will 610bdd1243dSDimitry Andric // be the result of a join or widen operation on previous values for this 6115f757f3fSDimitry Andric // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that 6125f757f3fSDimitry Andric // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain 6135f757f3fSDimitry Andric // this property here, we don't need change their current values to widen. 614bdd1243dSDimitry Andric assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size()); 6155f757f3fSDimitry Andric assert(ExprToVal.size() <= PrevEnv.ExprToVal.size()); 616bdd1243dSDimitry Andric assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size()); 617bdd1243dSDimitry Andric 6185f757f3fSDimitry Andric ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv, 6195f757f3fSDimitry Andric Model, Effect); 620bdd1243dSDimitry Andric 6215f757f3fSDimitry Andric LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv, 6225f757f3fSDimitry Andric Model, Effect); 623bdd1243dSDimitry Andric if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() || 624bdd1243dSDimitry Andric ExprToLoc.size() != PrevEnv.ExprToLoc.size() || 6255f757f3fSDimitry Andric ExprToVal.size() != PrevEnv.ExprToVal.size() || 62606c3fb27SDimitry Andric LocToVal.size() != PrevEnv.LocToVal.size()) 627bdd1243dSDimitry Andric Effect = LatticeJoinEffect::Changed; 628bdd1243dSDimitry Andric 629bdd1243dSDimitry Andric return Effect; 630bdd1243dSDimitry Andric } 631bdd1243dSDimitry Andric 63206c3fb27SDimitry Andric Environment Environment::join(const Environment &EnvA, const Environment &EnvB, 6331fd87a68SDimitry Andric Environment::ValueModel &Model) { 63406c3fb27SDimitry Andric assert(EnvA.DACtx == EnvB.DACtx); 63506c3fb27SDimitry Andric assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc); 63606c3fb27SDimitry Andric assert(EnvA.CallStack == EnvB.CallStack); 63704eeddc0SDimitry Andric 63806c3fb27SDimitry Andric Environment JoinedEnv(*EnvA.DACtx); 63904eeddc0SDimitry Andric 64006c3fb27SDimitry Andric JoinedEnv.CallStack = EnvA.CallStack; 64106c3fb27SDimitry Andric JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc; 64281ad6265SDimitry Andric 64306c3fb27SDimitry Andric if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) { 64406c3fb27SDimitry Andric // `ReturnVal` might not always get set -- for example if we have a return 64506c3fb27SDimitry Andric // statement of the form `return some_other_func()` and we decide not to 64606c3fb27SDimitry Andric // analyze `some_other_func()`. 64706c3fb27SDimitry Andric // In this case, we can't say anything about the joined return value -- we 64806c3fb27SDimitry Andric // don't simply want to propagate the return value that we do have, because 64906c3fb27SDimitry Andric // it might not be the correct one. 65006c3fb27SDimitry Andric // This occurs for example in the test `ContextSensitiveMutualRecursion`. 65106c3fb27SDimitry Andric JoinedEnv.ReturnVal = nullptr; 65206c3fb27SDimitry Andric } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) { 65306c3fb27SDimitry Andric JoinedEnv.ReturnVal = EnvA.ReturnVal; 65406c3fb27SDimitry Andric } else { 65506c3fb27SDimitry Andric assert(!EnvA.CallStack.empty()); 65606c3fb27SDimitry Andric // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this 65706c3fb27SDimitry Andric // cast. 65806c3fb27SDimitry Andric auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back()); 65906c3fb27SDimitry Andric assert(Func != nullptr); 66006c3fb27SDimitry Andric if (Value *MergedVal = 66106c3fb27SDimitry Andric mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA, 66206c3fb27SDimitry Andric *EnvB.ReturnVal, EnvB, JoinedEnv, Model)) 66306c3fb27SDimitry Andric JoinedEnv.ReturnVal = MergedVal; 66406c3fb27SDimitry Andric } 665bdd1243dSDimitry Andric 66606c3fb27SDimitry Andric if (EnvA.ReturnLoc == EnvB.ReturnLoc) 66706c3fb27SDimitry Andric JoinedEnv.ReturnLoc = EnvA.ReturnLoc; 66806c3fb27SDimitry Andric else 66906c3fb27SDimitry Andric JoinedEnv.ReturnLoc = nullptr; 67004eeddc0SDimitry Andric 6715f757f3fSDimitry Andric JoinedEnv.DeclToLoc = intersectDeclToLoc(EnvA.DeclToLoc, EnvB.DeclToLoc); 67281ad6265SDimitry Andric 673bdd1243dSDimitry Andric // FIXME: update join to detect backedges and simplify the flow condition 674bdd1243dSDimitry Andric // accordingly. 67506c3fb27SDimitry Andric JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions( 67606c3fb27SDimitry Andric EnvA.FlowConditionToken, EnvB.FlowConditionToken); 67781ad6265SDimitry Andric 6785f757f3fSDimitry Andric JoinedEnv.LocToVal = 6795f757f3fSDimitry Andric joinLocToVal(EnvA.LocToVal, EnvB.LocToVal, EnvA, EnvB, JoinedEnv, Model); 68004eeddc0SDimitry Andric 6815f757f3fSDimitry Andric // We intentionally leave `JoinedEnv.ExprToLoc` and `JoinedEnv.ExprToVal` 6825f757f3fSDimitry Andric // empty, as we never need to access entries in these maps outside of the 6835f757f3fSDimitry Andric // basic block that sets them. 68404eeddc0SDimitry Andric 68506c3fb27SDimitry Andric return JoinedEnv; 68604eeddc0SDimitry Andric } 68704eeddc0SDimitry Andric 68804eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(QualType Type) { 689bdd1243dSDimitry Andric return DACtx->createStorageLocation(Type); 69004eeddc0SDimitry Andric } 69104eeddc0SDimitry Andric 6925f757f3fSDimitry Andric StorageLocation &Environment::createStorageLocation(const ValueDecl &D) { 69304eeddc0SDimitry Andric // Evaluated declarations are always assigned the same storage locations to 69404eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 69504eeddc0SDimitry Andric // locations for evaluated declarations are stored in the analysis context. 69681ad6265SDimitry Andric return DACtx->getStableStorageLocation(D); 69704eeddc0SDimitry Andric } 69804eeddc0SDimitry Andric 69904eeddc0SDimitry Andric StorageLocation &Environment::createStorageLocation(const Expr &E) { 70004eeddc0SDimitry Andric // Evaluated expressions are always assigned the same storage locations to 70104eeddc0SDimitry Andric // ensure that the environment stabilizes across loop iterations. Storage 70204eeddc0SDimitry Andric // locations for evaluated expressions are stored in the analysis context. 70381ad6265SDimitry Andric return DACtx->getStableStorageLocation(E); 70404eeddc0SDimitry Andric } 70504eeddc0SDimitry Andric 70604eeddc0SDimitry Andric void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) { 70706c3fb27SDimitry Andric assert(!DeclToLoc.contains(&D)); 70804eeddc0SDimitry Andric DeclToLoc[&D] = &Loc; 70904eeddc0SDimitry Andric } 71004eeddc0SDimitry Andric 71106c3fb27SDimitry Andric StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const { 71204eeddc0SDimitry Andric auto It = DeclToLoc.find(&D); 71306c3fb27SDimitry Andric if (It == DeclToLoc.end()) 71406c3fb27SDimitry Andric return nullptr; 71506c3fb27SDimitry Andric 71606c3fb27SDimitry Andric StorageLocation *Loc = It->second; 71706c3fb27SDimitry Andric 71806c3fb27SDimitry Andric return Loc; 71904eeddc0SDimitry Andric } 72004eeddc0SDimitry Andric 7215f757f3fSDimitry Andric void Environment::removeDecl(const ValueDecl &D) { DeclToLoc.erase(&D); } 72204eeddc0SDimitry Andric 7235f757f3fSDimitry Andric void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) { 72406c3fb27SDimitry Andric // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason, 72506c3fb27SDimitry Andric // but we still want to be able to associate a `StorageLocation` with them, 72606c3fb27SDimitry Andric // so allow these as an exception. 72706c3fb27SDimitry Andric assert(E.isGLValue() || 72806c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 729*cb14a3feSDimitry Andric const Expr &CanonE = ignoreCFGOmittedNodes(E); 730*cb14a3feSDimitry Andric assert(!ExprToLoc.contains(&CanonE)); 731*cb14a3feSDimitry Andric ExprToLoc[&CanonE] = &Loc; 73206c3fb27SDimitry Andric } 73306c3fb27SDimitry Andric 7345f757f3fSDimitry Andric StorageLocation *Environment::getStorageLocation(const Expr &E) const { 7355f757f3fSDimitry Andric // See comment in `setStorageLocation()`. 73606c3fb27SDimitry Andric assert(E.isGLValue() || 73706c3fb27SDimitry Andric E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn)); 738*cb14a3feSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 739*cb14a3feSDimitry Andric return It == ExprToLoc.end() ? nullptr : &*It->second; 740*cb14a3feSDimitry Andric } 741*cb14a3feSDimitry Andric 742*cb14a3feSDimitry Andric // Returns whether a prvalue of record type is the one that originally 743*cb14a3feSDimitry Andric // constructs the object (i.e. it doesn't propagate it from one of its 744*cb14a3feSDimitry Andric // children). 745*cb14a3feSDimitry Andric static bool isOriginalRecordConstructor(const Expr &RecordPRValue) { 746*cb14a3feSDimitry Andric if (auto *Init = dyn_cast<InitListExpr>(&RecordPRValue)) 747*cb14a3feSDimitry Andric return !Init->isSemanticForm() || !Init->isTransparent(); 748*cb14a3feSDimitry Andric return isa<CXXConstructExpr>(RecordPRValue) || isa<CallExpr>(RecordPRValue) || 749*cb14a3feSDimitry Andric isa<LambdaExpr>(RecordPRValue) || 750*cb14a3feSDimitry Andric // The framework currently does not propagate the objects created in 751*cb14a3feSDimitry Andric // the two branches of a `ConditionalOperator` because there is no way 752*cb14a3feSDimitry Andric // to reconcile their storage locations, which are different. We 753*cb14a3feSDimitry Andric // therefore claim that the `ConditionalOperator` is the expression 754*cb14a3feSDimitry Andric // that originally constructs the object. 755*cb14a3feSDimitry Andric // Ultimately, this will be fixed by propagating locations down from 756*cb14a3feSDimitry Andric // the result object, rather than up from the original constructor as 757*cb14a3feSDimitry Andric // we do now (see also the FIXME in the documentation for 758*cb14a3feSDimitry Andric // `getResultObjectLocation()`). 759*cb14a3feSDimitry Andric isa<ConditionalOperator>(RecordPRValue); 76006c3fb27SDimitry Andric } 76106c3fb27SDimitry Andric 7625f757f3fSDimitry Andric RecordStorageLocation & 763*cb14a3feSDimitry Andric Environment::getResultObjectLocation(const Expr &RecordPRValue) const { 76406c3fb27SDimitry Andric assert(RecordPRValue.getType()->isRecordType()); 76506c3fb27SDimitry Andric assert(RecordPRValue.isPRValue()); 76606c3fb27SDimitry Andric 767*cb14a3feSDimitry Andric // Returns a storage location that we can use if assertions fail. 768*cb14a3feSDimitry Andric auto FallbackForAssertFailure = 769*cb14a3feSDimitry Andric [this, &RecordPRValue]() -> RecordStorageLocation & { 770*cb14a3feSDimitry Andric return cast<RecordStorageLocation>( 77106c3fb27SDimitry Andric DACtx->getStableStorageLocation(RecordPRValue)); 772*cb14a3feSDimitry Andric }; 773*cb14a3feSDimitry Andric 774*cb14a3feSDimitry Andric if (isOriginalRecordConstructor(RecordPRValue)) { 775*cb14a3feSDimitry Andric auto *Val = cast_or_null<RecordValue>(getValue(RecordPRValue)); 776*cb14a3feSDimitry Andric // The builtin transfer function should have created a `RecordValue` for all 777*cb14a3feSDimitry Andric // original record constructors. 778*cb14a3feSDimitry Andric assert(Val); 779*cb14a3feSDimitry Andric if (!Val) 780*cb14a3feSDimitry Andric return FallbackForAssertFailure(); 781*cb14a3feSDimitry Andric return Val->getLoc(); 782*cb14a3feSDimitry Andric } 783*cb14a3feSDimitry Andric 784*cb14a3feSDimitry Andric // Expression nodes that propagate a record prvalue should have exactly one 785*cb14a3feSDimitry Andric // child. 786*cb14a3feSDimitry Andric llvm::SmallVector<const Stmt *> children(RecordPRValue.child_begin(), 787*cb14a3feSDimitry Andric RecordPRValue.child_end()); 788*cb14a3feSDimitry Andric assert(children.size() == 1); 789*cb14a3feSDimitry Andric if (children.empty()) 790*cb14a3feSDimitry Andric return FallbackForAssertFailure(); 791*cb14a3feSDimitry Andric 792*cb14a3feSDimitry Andric return getResultObjectLocation(*cast<Expr>(children[0])); 79304eeddc0SDimitry Andric } 79404eeddc0SDimitry Andric 79581ad6265SDimitry Andric PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) { 79681ad6265SDimitry Andric return DACtx->getOrCreateNullPointerValue(PointeeType); 79781ad6265SDimitry Andric } 79881ad6265SDimitry Andric 79904eeddc0SDimitry Andric void Environment::setValue(const StorageLocation &Loc, Value &Val) { 8005f757f3fSDimitry Andric assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc); 80106c3fb27SDimitry Andric 80204eeddc0SDimitry Andric LocToVal[&Loc] = &Val; 80306c3fb27SDimitry Andric } 80406c3fb27SDimitry Andric 8055f757f3fSDimitry Andric void Environment::setValue(const Expr &E, Value &Val) { 806*cb14a3feSDimitry Andric if (auto *RecordVal = dyn_cast<RecordValue>(&Val)) { 807*cb14a3feSDimitry Andric assert(isOriginalRecordConstructor(E) || 808*cb14a3feSDimitry Andric &RecordVal->getLoc() == &getResultObjectLocation(E)); 809*cb14a3feSDimitry Andric } 810*cb14a3feSDimitry Andric 81106c3fb27SDimitry Andric assert(E.isPRValue()); 8125f757f3fSDimitry Andric ExprToVal[&E] = &Val; 81304eeddc0SDimitry Andric } 81404eeddc0SDimitry Andric 81504eeddc0SDimitry Andric Value *Environment::getValue(const StorageLocation &Loc) const { 81606c3fb27SDimitry Andric return LocToVal.lookup(&Loc); 81704eeddc0SDimitry Andric } 81804eeddc0SDimitry Andric 81906c3fb27SDimitry Andric Value *Environment::getValue(const ValueDecl &D) const { 82006c3fb27SDimitry Andric auto *Loc = getStorageLocation(D); 82104eeddc0SDimitry Andric if (Loc == nullptr) 82204eeddc0SDimitry Andric return nullptr; 82304eeddc0SDimitry Andric return getValue(*Loc); 82404eeddc0SDimitry Andric } 82504eeddc0SDimitry Andric 8265f757f3fSDimitry Andric Value *Environment::getValue(const Expr &E) const { 8275f757f3fSDimitry Andric if (E.isPRValue()) { 8285f757f3fSDimitry Andric auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E)); 8295f757f3fSDimitry Andric return It == ExprToVal.end() ? nullptr : It->second; 83004eeddc0SDimitry Andric } 83104eeddc0SDimitry Andric 8325f757f3fSDimitry Andric auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E)); 8335f757f3fSDimitry Andric if (It == ExprToLoc.end()) 8345f757f3fSDimitry Andric return nullptr; 8355f757f3fSDimitry Andric return getValue(*It->second); 83606c3fb27SDimitry Andric } 83706c3fb27SDimitry Andric 83804eeddc0SDimitry Andric Value *Environment::createValue(QualType Type) { 83904eeddc0SDimitry Andric llvm::DenseSet<QualType> Visited; 84081ad6265SDimitry Andric int CreatedValuesCount = 0; 84181ad6265SDimitry Andric Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0, 84281ad6265SDimitry Andric CreatedValuesCount); 84381ad6265SDimitry Andric if (CreatedValuesCount > MaxCompositeValueSize) { 84481ad6265SDimitry Andric llvm::errs() << "Attempting to initialize a huge value of type: " << Type 84581ad6265SDimitry Andric << '\n'; 84681ad6265SDimitry Andric } 84781ad6265SDimitry Andric return Val; 84804eeddc0SDimitry Andric } 84904eeddc0SDimitry Andric 85004eeddc0SDimitry Andric Value *Environment::createValueUnlessSelfReferential( 85181ad6265SDimitry Andric QualType Type, llvm::DenseSet<QualType> &Visited, int Depth, 85281ad6265SDimitry Andric int &CreatedValuesCount) { 85304eeddc0SDimitry Andric assert(!Type.isNull()); 8545f757f3fSDimitry Andric assert(!Type->isReferenceType()); 85504eeddc0SDimitry Andric 85681ad6265SDimitry Andric // Allow unlimited fields at depth 1; only cap at deeper nesting levels. 85781ad6265SDimitry Andric if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) || 85881ad6265SDimitry Andric Depth > MaxCompositeValueDepth) 85981ad6265SDimitry Andric return nullptr; 86081ad6265SDimitry Andric 86181ad6265SDimitry Andric if (Type->isBooleanType()) { 86281ad6265SDimitry Andric CreatedValuesCount++; 86381ad6265SDimitry Andric return &makeAtomicBoolValue(); 86481ad6265SDimitry Andric } 86581ad6265SDimitry Andric 86604eeddc0SDimitry Andric if (Type->isIntegerType()) { 867bdd1243dSDimitry Andric // FIXME: consider instead `return nullptr`, given that we do nothing useful 868bdd1243dSDimitry Andric // with integers, and so distinguishing them serves no purpose, but could 869bdd1243dSDimitry Andric // prevent convergence. 87081ad6265SDimitry Andric CreatedValuesCount++; 87106c3fb27SDimitry Andric return &arena().create<IntegerValue>(); 87204eeddc0SDimitry Andric } 87304eeddc0SDimitry Andric 8745f757f3fSDimitry Andric if (Type->isPointerType()) { 87581ad6265SDimitry Andric CreatedValuesCount++; 87606c3fb27SDimitry Andric QualType PointeeType = Type->getPointeeType(); 87706c3fb27SDimitry Andric StorageLocation &PointeeLoc = 87806c3fb27SDimitry Andric createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount); 87904eeddc0SDimitry Andric 88006c3fb27SDimitry Andric return &arena().create<PointerValue>(PointeeLoc); 88104eeddc0SDimitry Andric } 88204eeddc0SDimitry Andric 88306c3fb27SDimitry Andric if (Type->isRecordType()) { 88481ad6265SDimitry Andric CreatedValuesCount++; 88506c3fb27SDimitry Andric llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs; 88606c3fb27SDimitry Andric for (const FieldDecl *Field : DACtx->getModeledFields(Type)) { 88704eeddc0SDimitry Andric assert(Field != nullptr); 88804eeddc0SDimitry Andric 88904eeddc0SDimitry Andric QualType FieldType = Field->getType(); 89004eeddc0SDimitry Andric 89106c3fb27SDimitry Andric FieldLocs.insert( 89206c3fb27SDimitry Andric {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1, 89306c3fb27SDimitry Andric CreatedValuesCount)}); 89404eeddc0SDimitry Andric } 89504eeddc0SDimitry Andric 8965f757f3fSDimitry Andric RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs; 8975f757f3fSDimitry Andric for (const auto &Entry : DACtx->getSyntheticFields(Type)) { 8985f757f3fSDimitry Andric SyntheticFieldLocs.insert( 8995f757f3fSDimitry Andric {Entry.getKey(), 9005f757f3fSDimitry Andric &createLocAndMaybeValue(Entry.getValue(), Visited, Depth + 1, 9015f757f3fSDimitry Andric CreatedValuesCount)}); 9025f757f3fSDimitry Andric } 90306c3fb27SDimitry Andric 9045f757f3fSDimitry Andric RecordStorageLocation &Loc = DACtx->createRecordStorageLocation( 9055f757f3fSDimitry Andric Type, std::move(FieldLocs), std::move(SyntheticFieldLocs)); 9065f757f3fSDimitry Andric RecordValue &RecordVal = create<RecordValue>(Loc); 9075f757f3fSDimitry Andric 9085f757f3fSDimitry Andric // As we already have a storage location for the `RecordValue`, we can and 90906c3fb27SDimitry Andric // should associate them in the environment. 9105f757f3fSDimitry Andric setValue(Loc, RecordVal); 91106c3fb27SDimitry Andric 9125f757f3fSDimitry Andric return &RecordVal; 91304eeddc0SDimitry Andric } 91404eeddc0SDimitry Andric 91504eeddc0SDimitry Andric return nullptr; 91604eeddc0SDimitry Andric } 91704eeddc0SDimitry Andric 91806c3fb27SDimitry Andric StorageLocation & 91906c3fb27SDimitry Andric Environment::createLocAndMaybeValue(QualType Ty, 92006c3fb27SDimitry Andric llvm::DenseSet<QualType> &Visited, 92106c3fb27SDimitry Andric int Depth, int &CreatedValuesCount) { 92206c3fb27SDimitry Andric if (!Visited.insert(Ty.getCanonicalType()).second) 92306c3fb27SDimitry Andric return createStorageLocation(Ty.getNonReferenceType()); 92406c3fb27SDimitry Andric Value *Val = createValueUnlessSelfReferential( 92506c3fb27SDimitry Andric Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount); 92606c3fb27SDimitry Andric Visited.erase(Ty.getCanonicalType()); 92706c3fb27SDimitry Andric 92806c3fb27SDimitry Andric Ty = Ty.getNonReferenceType(); 92906c3fb27SDimitry Andric 93006c3fb27SDimitry Andric if (Val == nullptr) 93106c3fb27SDimitry Andric return createStorageLocation(Ty); 93206c3fb27SDimitry Andric 93306c3fb27SDimitry Andric if (Ty->isRecordType()) 9345f757f3fSDimitry Andric return cast<RecordValue>(Val)->getLoc(); 93506c3fb27SDimitry Andric 93606c3fb27SDimitry Andric StorageLocation &Loc = createStorageLocation(Ty); 93706c3fb27SDimitry Andric setValue(Loc, *Val); 93806c3fb27SDimitry Andric return Loc; 93906c3fb27SDimitry Andric } 94006c3fb27SDimitry Andric 9415f757f3fSDimitry Andric StorageLocation &Environment::createObjectInternal(const ValueDecl *D, 94206c3fb27SDimitry Andric QualType Ty, 94306c3fb27SDimitry Andric const Expr *InitExpr) { 94406c3fb27SDimitry Andric if (Ty->isReferenceType()) { 94506c3fb27SDimitry Andric // Although variables of reference type always need to be initialized, it 94606c3fb27SDimitry Andric // can happen that we can't see the initializer, so `InitExpr` may still 94706c3fb27SDimitry Andric // be null. 94806c3fb27SDimitry Andric if (InitExpr) { 9495f757f3fSDimitry Andric if (auto *InitExprLoc = getStorageLocation(*InitExpr)) 95006c3fb27SDimitry Andric return *InitExprLoc; 95106c3fb27SDimitry Andric } 95206c3fb27SDimitry Andric 95306c3fb27SDimitry Andric // Even though we have an initializer, we might not get an 95406c3fb27SDimitry Andric // InitExprLoc, for example if the InitExpr is a CallExpr for which we 95506c3fb27SDimitry Andric // don't have a function body. In this case, we just invent a storage 95606c3fb27SDimitry Andric // location and value -- it's the best we can do. 95706c3fb27SDimitry Andric return createObjectInternal(D, Ty.getNonReferenceType(), nullptr); 95806c3fb27SDimitry Andric } 95906c3fb27SDimitry Andric 96006c3fb27SDimitry Andric Value *Val = nullptr; 96106c3fb27SDimitry Andric if (InitExpr) 96206c3fb27SDimitry Andric // In the (few) cases where an expression is intentionally 96306c3fb27SDimitry Andric // "uninterpreted", `InitExpr` is not associated with a value. There are 96406c3fb27SDimitry Andric // two ways to handle this situation: propagate the status, so that 96506c3fb27SDimitry Andric // uninterpreted initializers result in uninterpreted variables, or 96606c3fb27SDimitry Andric // provide a default value. We choose the latter so that later refinements 96706c3fb27SDimitry Andric // of the variable can be used for reasoning about the surrounding code. 96806c3fb27SDimitry Andric // For this reason, we let this case be handled by the `createValue()` 96906c3fb27SDimitry Andric // call below. 97006c3fb27SDimitry Andric // 97106c3fb27SDimitry Andric // FIXME. If and when we interpret all language cases, change this to 97206c3fb27SDimitry Andric // assert that `InitExpr` is interpreted, rather than supplying a 97306c3fb27SDimitry Andric // default value (assuming we don't update the environment API to return 97406c3fb27SDimitry Andric // references). 9755f757f3fSDimitry Andric Val = getValue(*InitExpr); 97606c3fb27SDimitry Andric if (!Val) 97706c3fb27SDimitry Andric Val = createValue(Ty); 97806c3fb27SDimitry Andric 97906c3fb27SDimitry Andric if (Ty->isRecordType()) 9805f757f3fSDimitry Andric return cast<RecordValue>(Val)->getLoc(); 98106c3fb27SDimitry Andric 98206c3fb27SDimitry Andric StorageLocation &Loc = 98306c3fb27SDimitry Andric D ? createStorageLocation(*D) : createStorageLocation(Ty); 98406c3fb27SDimitry Andric 98506c3fb27SDimitry Andric if (Val) 98606c3fb27SDimitry Andric setValue(Loc, *Val); 98706c3fb27SDimitry Andric 98806c3fb27SDimitry Andric return Loc; 98906c3fb27SDimitry Andric } 99006c3fb27SDimitry Andric 9915f757f3fSDimitry Andric void Environment::assume(const Formula &F) { 9925f757f3fSDimitry Andric DACtx->addFlowConditionConstraint(FlowConditionToken, F); 99304eeddc0SDimitry Andric } 99404eeddc0SDimitry Andric 9955f757f3fSDimitry Andric bool Environment::proves(const Formula &F) const { 9965f757f3fSDimitry Andric return DACtx->flowConditionImplies(FlowConditionToken, F); 99704eeddc0SDimitry Andric } 99804eeddc0SDimitry Andric 9995f757f3fSDimitry Andric bool Environment::allows(const Formula &F) const { 10005f757f3fSDimitry Andric return DACtx->flowConditionAllows(FlowConditionToken, F); 100181ad6265SDimitry Andric } 100281ad6265SDimitry Andric 1003bdd1243dSDimitry Andric void Environment::dump(raw_ostream &OS) const { 1004bdd1243dSDimitry Andric // FIXME: add printing for remaining fields and allow caller to decide what 1005bdd1243dSDimitry Andric // fields are printed. 1006bdd1243dSDimitry Andric OS << "DeclToLoc:\n"; 1007bdd1243dSDimitry Andric for (auto [D, L] : DeclToLoc) 100806c3fb27SDimitry Andric OS << " [" << D->getNameAsString() << ", " << L << "]\n"; 1009bdd1243dSDimitry Andric 1010bdd1243dSDimitry Andric OS << "ExprToLoc:\n"; 1011bdd1243dSDimitry Andric for (auto [E, L] : ExprToLoc) 1012bdd1243dSDimitry Andric OS << " [" << E << ", " << L << "]\n"; 1013bdd1243dSDimitry Andric 10145f757f3fSDimitry Andric OS << "ExprToVal:\n"; 10155f757f3fSDimitry Andric for (auto [E, V] : ExprToVal) 10165f757f3fSDimitry Andric OS << " [" << E << ", " << V << ": " << *V << "]\n"; 10175f757f3fSDimitry Andric 1018bdd1243dSDimitry Andric OS << "LocToVal:\n"; 1019bdd1243dSDimitry Andric for (auto [L, V] : LocToVal) { 1020bdd1243dSDimitry Andric OS << " [" << L << ", " << V << ": " << *V << "]\n"; 1021bdd1243dSDimitry Andric } 1022bdd1243dSDimitry Andric 10235f757f3fSDimitry Andric OS << "\n"; 102406c3fb27SDimitry Andric DACtx->dumpFlowCondition(FlowConditionToken, OS); 1025fcaf7f86SDimitry Andric } 1026fcaf7f86SDimitry Andric 1027bdd1243dSDimitry Andric void Environment::dump() const { 1028bdd1243dSDimitry Andric dump(llvm::dbgs()); 1029bdd1243dSDimitry Andric } 1030bdd1243dSDimitry Andric 10315f757f3fSDimitry Andric RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE, 103206c3fb27SDimitry Andric const Environment &Env) { 103306c3fb27SDimitry Andric Expr *ImplicitObject = MCE.getImplicitObjectArgument(); 103406c3fb27SDimitry Andric if (ImplicitObject == nullptr) 103506c3fb27SDimitry Andric return nullptr; 103606c3fb27SDimitry Andric if (ImplicitObject->getType()->isPointerType()) { 1037*cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*ImplicitObject)) 10385f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 103906c3fb27SDimitry Andric return nullptr; 104006c3fb27SDimitry Andric } 10415f757f3fSDimitry Andric return cast_or_null<RecordStorageLocation>( 10425f757f3fSDimitry Andric Env.getStorageLocation(*ImplicitObject)); 104306c3fb27SDimitry Andric } 104406c3fb27SDimitry Andric 10455f757f3fSDimitry Andric RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME, 104606c3fb27SDimitry Andric const Environment &Env) { 104706c3fb27SDimitry Andric Expr *Base = ME.getBase(); 104806c3fb27SDimitry Andric if (Base == nullptr) 104906c3fb27SDimitry Andric return nullptr; 105006c3fb27SDimitry Andric if (ME.isArrow()) { 1051*cb14a3feSDimitry Andric if (auto *Val = Env.get<PointerValue>(*Base)) 10525f757f3fSDimitry Andric return &cast<RecordStorageLocation>(Val->getPointeeLoc()); 105306c3fb27SDimitry Andric return nullptr; 105406c3fb27SDimitry Andric } 1055*cb14a3feSDimitry Andric return Env.get<RecordStorageLocation>(*Base); 105606c3fb27SDimitry Andric } 105706c3fb27SDimitry Andric 105806c3fb27SDimitry Andric std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) { 105906c3fb27SDimitry Andric // Unnamed bitfields are only used for padding and do not appear in 106006c3fb27SDimitry Andric // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s 106106c3fb27SDimitry Andric // field list, and we thus need to remove them before mapping inits to 106206c3fb27SDimitry Andric // fields to avoid mapping inits to the wrongs fields. 106306c3fb27SDimitry Andric std::vector<FieldDecl *> Fields; 106406c3fb27SDimitry Andric llvm::copy_if( 106506c3fb27SDimitry Andric RD->fields(), std::back_inserter(Fields), 106606c3fb27SDimitry Andric [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); }); 106706c3fb27SDimitry Andric return Fields; 106806c3fb27SDimitry Andric } 106906c3fb27SDimitry Andric 10705f757f3fSDimitry Andric RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env) { 10715f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(Loc); 107206c3fb27SDimitry Andric Env.setValue(Loc, NewVal); 107306c3fb27SDimitry Andric return NewVal; 107406c3fb27SDimitry Andric } 107506c3fb27SDimitry Andric 10765f757f3fSDimitry Andric RecordValue &refreshRecordValue(const Expr &Expr, Environment &Env) { 107706c3fb27SDimitry Andric assert(Expr.getType()->isRecordType()); 107806c3fb27SDimitry Andric 107906c3fb27SDimitry Andric if (Expr.isPRValue()) { 1080*cb14a3feSDimitry Andric if (auto *ExistingVal = Env.get<RecordValue>(Expr)) { 10815f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(ExistingVal->getLoc()); 10825f757f3fSDimitry Andric Env.setValue(Expr, NewVal); 1083*cb14a3feSDimitry Andric Env.setValue(NewVal.getLoc(), NewVal); 108406c3fb27SDimitry Andric return NewVal; 108506c3fb27SDimitry Andric } 108606c3fb27SDimitry Andric 10875f757f3fSDimitry Andric auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType())); 10885f757f3fSDimitry Andric Env.setValue(Expr, NewVal); 108906c3fb27SDimitry Andric return NewVal; 109006c3fb27SDimitry Andric } 109106c3fb27SDimitry Andric 1092*cb14a3feSDimitry Andric if (auto *Loc = Env.get<RecordStorageLocation>(Expr)) { 10935f757f3fSDimitry Andric auto &NewVal = Env.create<RecordValue>(*Loc); 109406c3fb27SDimitry Andric Env.setValue(*Loc, NewVal); 109506c3fb27SDimitry Andric return NewVal; 109606c3fb27SDimitry Andric } 109706c3fb27SDimitry Andric 10985f757f3fSDimitry Andric auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType())); 10995f757f3fSDimitry Andric Env.setStorageLocation(Expr, NewVal.getLoc()); 110006c3fb27SDimitry Andric return NewVal; 110106c3fb27SDimitry Andric } 110206c3fb27SDimitry Andric 110304eeddc0SDimitry Andric } // namespace dataflow 110404eeddc0SDimitry Andric } // namespace clang 1105