xref: /llvm-project/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp (revision e53da3eab42e6efd448c1c60c14668e1eb3d907c)
1 //===-- DataflowEnvironment.cpp ---------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 //  This file defines an Environment class that is used by dataflow analyses
10 //  that run over Control-Flow Graphs (CFGs) to keep track of the state of the
11 //  program at given program points.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
16 #include "clang/AST/Decl.h"
17 #include "clang/AST/DeclCXX.h"
18 #include "clang/AST/Type.h"
19 #include "clang/Analysis/FlowSensitive/DataflowLattice.h"
20 #include "clang/Analysis/FlowSensitive/Value.h"
21 #include "llvm/ADT/DenseMap.h"
22 #include "llvm/ADT/DenseSet.h"
23 #include "llvm/ADT/STLExtras.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include <cassert>
27 #include <memory>
28 #include <utility>
29 
30 namespace clang {
31 namespace dataflow {
32 
33 // FIXME: convert these to parameters of the analysis or environment. Current
34 // settings have been experimentaly validated, but only for a particular
35 // analysis.
36 static constexpr int MaxCompositeValueDepth = 3;
37 static constexpr int MaxCompositeValueSize = 1000;
38 
39 /// Returns a map consisting of key-value entries that are present in both maps.
40 template <typename K, typename V>
41 llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
42                                         const llvm::DenseMap<K, V> &Map2) {
43   llvm::DenseMap<K, V> Result;
44   for (auto &Entry : Map1) {
45     auto It = Map2.find(Entry.first);
46     if (It != Map2.end() && Entry.second == It->second)
47       Result.insert({Entry.first, Entry.second});
48   }
49   return Result;
50 }
51 
52 static bool compareDistinctValues(QualType Type, Value &Val1,
53                                   const Environment &Env1, Value &Val2,
54                                   const Environment &Env2,
55                                   Environment::ValueModel &Model) {
56   // Note: Potentially costly, but, for booleans, we could check whether both
57   // can be proven equivalent in their respective environments.
58 
59   // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
60   // and implement separate, join/widen specific handling for
61   // reference/pointers.
62   switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
63   case ComparisonResult::Same:
64     return true;
65   case ComparisonResult::Different:
66     return false;
67   case ComparisonResult::Unknown:
68     switch (Val1.getKind()) {
69     case Value::Kind::Integer:
70     case Value::Kind::Reference:
71     case Value::Kind::Pointer:
72     case Value::Kind::Struct:
73       // FIXME: this choice intentionally introduces unsoundness to allow
74       // for convergence. Once we have widening support for the
75       // reference/pointer and struct built-in models, this should be
76       // `false`.
77       return true;
78     default:
79       return false;
80     }
81   }
82   llvm_unreachable("All cases covered in switch");
83 }
84 
85 /// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
86 /// respectively, of the same type `Type`. Merging generally produces a single
87 /// value that (soundly) approximates the two inputs, although the actual
88 /// meaning depends on `Model`.
89 static Value *mergeDistinctValues(QualType Type, Value &Val1,
90                                   const Environment &Env1, Value &Val2,
91                                   const Environment &Env2,
92                                   Environment &MergedEnv,
93                                   Environment::ValueModel &Model) {
94   // Join distinct boolean values preserving information about the constraints
95   // in the respective path conditions.
96   if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
97     // FIXME: Checking both values should be unnecessary, since they should have
98     // a consistent shape.  However, right now we can end up with BoolValue's in
99     // integer-typed variables due to our incorrect handling of
100     // boolean-to-integer casts (we just propagate the BoolValue to the result
101     // of the cast). So, a join can encounter an integer in one branch but a
102     // bool in the other.
103     // For example:
104     // ```
105     // std::optional<bool> o;
106     // int x;
107     // if (o.has_value())
108     //   x = o.value();
109     // ```
110     auto &Expr1 = cast<BoolValue>(Val1).formula();
111     auto &Expr2 = cast<BoolValue>(Val2).formula();
112     auto &A = MergedEnv.arena();
113     auto &MergedVal = A.makeAtomRef(A.makeAtom());
114     MergedEnv.addToFlowCondition(
115         A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
116                            A.makeEquals(MergedVal, Expr1)),
117                  A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
118                            A.makeEquals(MergedVal, Expr2))));
119     return &A.makeBoolValue(MergedVal);
120   }
121 
122   // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
123   // returns false to avoid storing unneeded values in `DACtx`.
124   // FIXME: Creating the value based on the type alone creates misshapen values
125   // for lvalues, since the type does not reflect the need for `ReferenceValue`.
126   // This issue will be resolved when `ReferenceValue` is eliminated as part
127   // of the ongoing migration to strict handling of value categories (see
128   // https://discourse.llvm.org/t/70086 for details).
129   if (Value *MergedVal = MergedEnv.createValue(Type))
130     if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
131       return MergedVal;
132 
133   return nullptr;
134 }
135 
136 // When widening does not change `Current`, return value will equal `&Prev`.
137 static Value &widenDistinctValues(QualType Type, Value &Prev,
138                                   const Environment &PrevEnv, Value &Current,
139                                   Environment &CurrentEnv,
140                                   Environment::ValueModel &Model) {
141   // Boolean-model widening.
142   if (isa<BoolValue>(&Prev)) {
143     assert(isa<BoolValue>(Current));
144     // Widen to Top, because we know they are different values. If previous was
145     // already Top, re-use that to (implicitly) indicate that no change occured.
146     if (isa<TopBoolValue>(Prev))
147       return Prev;
148     return CurrentEnv.makeTopBoolValue();
149   }
150 
151   // FIXME: Add other built-in model widening.
152 
153   // Custom-model widening.
154   if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
155     return *W;
156 
157   // Default of widening is a no-op: leave the current value unchanged.
158   return Current;
159 }
160 
161 /// Initializes a global storage value.
162 static void insertIfGlobal(const Decl &D,
163                            llvm::DenseSet<const VarDecl *> &Vars) {
164   if (auto *V = dyn_cast<VarDecl>(&D))
165     if (V->hasGlobalStorage())
166       Vars.insert(V);
167 }
168 
169 static void insertIfFunction(const Decl &D,
170                              llvm::DenseSet<const FunctionDecl *> &Funcs) {
171   if (auto *FD = dyn_cast<FunctionDecl>(&D))
172     Funcs.insert(FD);
173 }
174 
175 static void
176 getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields,
177                          llvm::DenseSet<const VarDecl *> &Vars,
178                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
179   insertIfGlobal(D, Vars);
180   insertIfFunction(D, Funcs);
181   if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
182     for (const auto *B : Decomp->bindings())
183       if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
184         // FIXME: should we be using `E->getFoundDecl()`?
185         if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
186           Fields.insert(FD);
187 }
188 
189 /// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
190 /// global variables and functions that are declared in or referenced from
191 /// sub-statements.
192 static void
193 getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
194                          llvm::DenseSet<const VarDecl *> &Vars,
195                          llvm::DenseSet<const FunctionDecl *> &Funcs) {
196   for (auto *Child : S.children())
197     if (Child != nullptr)
198       getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
199   if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
200     getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
201 
202   if (auto *DS = dyn_cast<DeclStmt>(&S)) {
203     if (DS->isSingleDecl())
204       getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
205     else
206       for (auto *D : DS->getDeclGroup())
207         getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
208   } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
209     insertIfGlobal(*E->getDecl(), Vars);
210     insertIfFunction(*E->getDecl(), Funcs);
211   } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
212     // FIXME: should we be using `E->getFoundDecl()`?
213     const ValueDecl *VD = E->getMemberDecl();
214     insertIfGlobal(*VD, Vars);
215     insertIfFunction(*VD, Funcs);
216     if (const auto *FD = dyn_cast<FieldDecl>(VD))
217       Fields.insert(FD);
218   }
219 }
220 
221 // FIXME: Add support for resetting globals after function calls to enable
222 // the implementation of sound analyses.
223 void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
224   assert(FuncDecl->getBody() != nullptr);
225 
226   FieldSet Fields;
227   llvm::DenseSet<const VarDecl *> Vars;
228   llvm::DenseSet<const FunctionDecl *> Funcs;
229 
230   // Look for global variable and field references in the
231   // constructor-initializers.
232   if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
233     for (const auto *Init : CtorDecl->inits()) {
234       if (Init->isMemberInitializer()) {
235         Fields.insert(Init->getMember());
236       } else if (Init->isIndirectMemberInitializer()) {
237         for (const auto *I : Init->getIndirectMember()->chain())
238           Fields.insert(cast<FieldDecl>(I));
239       }
240       const Expr *E = Init->getInit();
241       assert(E != nullptr);
242       getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
243     }
244     // Add all fields mentioned in default member initializers.
245     for (const FieldDecl *F : CtorDecl->getParent()->fields())
246       if (const auto *I = F->getInClassInitializer())
247           getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs);
248   }
249   getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs);
250 
251   // These have to be added before the lines that follow to ensure that
252   // `create*` work correctly for structs.
253   DACtx->addModeledFields(Fields);
254 
255   for (const VarDecl *D : Vars) {
256     if (getStorageLocation(*D) != nullptr)
257       continue;
258     auto &Loc = createStorageLocation(D->getType().getNonReferenceType());
259     setStorageLocation(*D, Loc);
260     if (auto *Val = createValue(D->getType().getNonReferenceType()))
261       setValue(Loc, *Val);
262   }
263 
264   for (const FunctionDecl *FD : Funcs) {
265     if (getStorageLocation(*FD) != nullptr)
266       continue;
267     auto &Loc = createStorageLocation(FD->getType());
268     setStorageLocation(*FD, Loc);
269   }
270 }
271 
272 Environment::Environment(DataflowAnalysisContext &DACtx)
273     : DACtx(&DACtx),
274       FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
275 
276 Environment Environment::fork() const {
277   Environment Copy(*this);
278   Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
279   return Copy;
280 }
281 
282 Environment::Environment(DataflowAnalysisContext &DACtx,
283                          const DeclContext &DeclCtx)
284     : Environment(DACtx) {
285   CallStack.push_back(&DeclCtx);
286 
287   if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
288     assert(FuncDecl->getBody() != nullptr);
289 
290     initFieldsGlobalsAndFuncs(FuncDecl);
291 
292     for (const auto *ParamDecl : FuncDecl->parameters()) {
293       assert(ParamDecl != nullptr);
294       // References aren't objects, so the reference itself doesn't have a
295       // storage location. Instead, the storage location for a reference refers
296       // directly to an object of the referenced type -- so strip off any
297       // reference from the type.
298       auto &ParamLoc =
299           createStorageLocation(ParamDecl->getType().getNonReferenceType());
300       setStorageLocation(*ParamDecl, ParamLoc);
301       if (Value *ParamVal =
302               createValue(ParamDecl->getType().getNonReferenceType()))
303           setValue(ParamLoc, *ParamVal);
304     }
305   }
306 
307   if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
308     auto *Parent = MethodDecl->getParent();
309     assert(Parent != nullptr);
310     if (Parent->isLambda())
311       MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
312 
313     // FIXME: Initialize the ThisPointeeLoc of lambdas too.
314     if (MethodDecl && !MethodDecl->isStatic()) {
315       QualType ThisPointeeType = MethodDecl->getThisObjectType();
316       ThisPointeeLoc = &cast<AggregateStorageLocation>(
317           createStorageLocation(ThisPointeeType));
318       if (Value *ThisPointeeVal = createValue(ThisPointeeType))
319         setValue(*ThisPointeeLoc, *ThisPointeeVal);
320     }
321   }
322 }
323 
324 bool Environment::canDescend(unsigned MaxDepth,
325                              const DeclContext *Callee) const {
326   return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
327 }
328 
329 Environment Environment::pushCall(const CallExpr *Call) const {
330   Environment Env(*this);
331 
332   if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
333     if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
334       if (!isa<CXXThisExpr>(Arg))
335         Env.ThisPointeeLoc = cast<AggregateStorageLocation>(
336             getStorageLocation(*Arg, SkipPast::Reference));
337       // Otherwise (when the argument is `this`), retain the current
338       // environment's `ThisPointeeLoc`.
339     }
340   }
341 
342   Env.pushCallInternal(Call->getDirectCallee(),
343                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
344 
345   return Env;
346 }
347 
348 Environment Environment::pushCall(const CXXConstructExpr *Call) const {
349   Environment Env(*this);
350 
351   Env.ThisPointeeLoc = &cast<AggregateStorageLocation>(
352       Env.createStorageLocation(Call->getType()));
353   if (Value *Val = Env.createValue(Call->getType()))
354     Env.setValue(*Env.ThisPointeeLoc, *Val);
355 
356   Env.pushCallInternal(Call->getConstructor(),
357                        llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
358 
359   return Env;
360 }
361 
362 void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
363                                    ArrayRef<const Expr *> Args) {
364   // Canonicalize to the definition of the function. This ensures that we're
365   // putting arguments into the same `ParamVarDecl`s` that the callee will later
366   // be retrieving them from.
367   assert(FuncDecl->getDefinition() != nullptr);
368   FuncDecl = FuncDecl->getDefinition();
369 
370   CallStack.push_back(FuncDecl);
371 
372   initFieldsGlobalsAndFuncs(FuncDecl);
373 
374   const auto *ParamIt = FuncDecl->param_begin();
375 
376   // FIXME: Parameters don't always map to arguments 1:1; examples include
377   // overloaded operators implemented as member functions, and parameter packs.
378   for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
379     assert(ParamIt != FuncDecl->param_end());
380 
381     const Expr *Arg = Args[ArgIndex];
382     auto *ArgLoc = getStorageLocation(*Arg, SkipPast::Reference);
383     if (ArgLoc == nullptr)
384       continue;
385 
386     const VarDecl *Param = *ParamIt;
387 
388     QualType ParamType = Param->getType();
389     if (ParamType->isReferenceType()) {
390       setStorageLocation(*Param, *ArgLoc);
391     } else {
392       auto &Loc = createStorageLocation(*Param);
393       setStorageLocation(*Param, Loc);
394 
395       if (auto *ArgVal = getValue(*ArgLoc)) {
396         setValue(Loc, *ArgVal);
397       } else if (Value *Val = createValue(ParamType)) {
398         setValue(Loc, *Val);
399       }
400     }
401   }
402 }
403 
404 void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
405   // We ignore `DACtx` because it's already the same in both. We don't want the
406   // callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or `ThisPointeeLoc`. We don't
407   // bring back `DeclToLoc` and `ExprToLoc` because we want to be able to later
408   // analyze the same callee in a different context, and `setStorageLocation`
409   // requires there to not already be a storage location assigned. Conceptually,
410   // these maps capture information from the local scope, so when popping that
411   // scope, we do not propagate the maps.
412   this->LocToVal = std::move(CalleeEnv.LocToVal);
413   this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
414   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
415 
416   if (Call->isGLValue()) {
417     if (CalleeEnv.ReturnLoc != nullptr)
418       setStorageLocationStrict(*Call, *CalleeEnv.ReturnLoc);
419   } else if (!Call->getType()->isVoidType()) {
420     if (CalleeEnv.ReturnVal != nullptr)
421       setValueStrict(*Call, *CalleeEnv.ReturnVal);
422   }
423 }
424 
425 void Environment::popCall(const CXXConstructExpr *Call,
426                           const Environment &CalleeEnv) {
427   // See also comment in `popCall(const CallExpr *, const Environment &)` above.
428   this->LocToVal = std::move(CalleeEnv.LocToVal);
429   this->MemberLocToStruct = std::move(CalleeEnv.MemberLocToStruct);
430   this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
431 
432   if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) {
433     setValueStrict(*Call, *Val);
434   }
435 }
436 
437 bool Environment::equivalentTo(const Environment &Other,
438                                Environment::ValueModel &Model) const {
439   assert(DACtx == Other.DACtx);
440 
441   if (ReturnVal != Other.ReturnVal)
442     return false;
443 
444   if (ReturnLoc != Other.ReturnLoc)
445     return false;
446 
447   if (ThisPointeeLoc != Other.ThisPointeeLoc)
448     return false;
449 
450   if (DeclToLoc != Other.DeclToLoc)
451     return false;
452 
453   if (ExprToLoc != Other.ExprToLoc)
454     return false;
455 
456   // Compare the contents for the intersection of their domains.
457   for (auto &Entry : LocToVal) {
458     const StorageLocation *Loc = Entry.first;
459     assert(Loc != nullptr);
460 
461     Value *Val = Entry.second;
462     assert(Val != nullptr);
463 
464     auto It = Other.LocToVal.find(Loc);
465     if (It == Other.LocToVal.end())
466       continue;
467     assert(It->second != nullptr);
468 
469     if (!areEquivalentValues(*Val, *It->second) &&
470         !compareDistinctValues(Loc->getType(), *Val, *this, *It->second, Other,
471                                Model))
472       return false;
473   }
474 
475   return true;
476 }
477 
478 LatticeJoinEffect Environment::widen(const Environment &PrevEnv,
479                                      Environment::ValueModel &Model) {
480   assert(DACtx == PrevEnv.DACtx);
481   assert(ReturnVal == PrevEnv.ReturnVal);
482   assert(ReturnLoc == PrevEnv.ReturnLoc);
483   assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
484   assert(CallStack == PrevEnv.CallStack);
485 
486   auto Effect = LatticeJoinEffect::Unchanged;
487 
488   // By the API, `PrevEnv` is a previous version of the environment for the same
489   // block, so we have some guarantees about its shape. In particular, it will
490   // be the result of a join or widen operation on previous values for this
491   // block. For `DeclToLoc` and `ExprToLoc`, join guarantees that these maps are
492   // subsets of the maps in `PrevEnv`. So, as long as we maintain this property
493   // here, we don't need change their current values to widen.
494   //
495   // FIXME: `MemberLocToStruct` does not share the above property, because
496   // `join` can cause the map size to increase (when we add fresh data in places
497   // of conflict). Once this issue with join is resolved, re-enable the
498   // assertion below or replace with something that captures the desired
499   // invariant.
500   assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
501   assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
502   // assert(MemberLocToStruct.size() <= PrevEnv.MemberLocToStruct.size());
503 
504   llvm::DenseMap<const StorageLocation *, Value *> WidenedLocToVal;
505   for (auto &Entry : LocToVal) {
506     const StorageLocation *Loc = Entry.first;
507     assert(Loc != nullptr);
508 
509     Value *Val = Entry.second;
510     assert(Val != nullptr);
511 
512     auto PrevIt = PrevEnv.LocToVal.find(Loc);
513     if (PrevIt == PrevEnv.LocToVal.end())
514       continue;
515     assert(PrevIt->second != nullptr);
516 
517     if (areEquivalentValues(*Val, *PrevIt->second)) {
518       WidenedLocToVal.insert({Loc, Val});
519       continue;
520     }
521 
522     Value &WidenedVal = widenDistinctValues(Loc->getType(), *PrevIt->second,
523                                             PrevEnv, *Val, *this, Model);
524     WidenedLocToVal.insert({Loc, &WidenedVal});
525     if (&WidenedVal != PrevIt->second)
526       Effect = LatticeJoinEffect::Changed;
527   }
528   LocToVal = std::move(WidenedLocToVal);
529   // FIXME: update the equivalence calculation for `MemberLocToStruct`, once we
530   // have a systematic way of soundly comparing this map.
531   if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
532       ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
533       LocToVal.size() != PrevEnv.LocToVal.size() ||
534       MemberLocToStruct.size() != PrevEnv.MemberLocToStruct.size())
535     Effect = LatticeJoinEffect::Changed;
536 
537   return Effect;
538 }
539 
540 Environment Environment::join(const Environment &EnvA, const Environment &EnvB,
541                               Environment::ValueModel &Model) {
542   assert(EnvA.DACtx == EnvB.DACtx);
543   assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
544   assert(EnvA.CallStack == EnvB.CallStack);
545 
546   Environment JoinedEnv(*EnvA.DACtx);
547 
548   JoinedEnv.CallStack = EnvA.CallStack;
549   JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
550 
551   if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) {
552     // `ReturnVal` might not always get set -- for example if we have a return
553     // statement of the form `return some_other_func()` and we decide not to
554     // analyze `some_other_func()`.
555     // In this case, we can't say anything about the joined return value -- we
556     // don't simply want to propagate the return value that we do have, because
557     // it might not be the correct one.
558     // This occurs for example in the test `ContextSensitiveMutualRecursion`.
559     JoinedEnv.ReturnVal = nullptr;
560   } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) {
561     JoinedEnv.ReturnVal = EnvA.ReturnVal;
562   } else {
563     assert(!EnvA.CallStack.empty());
564     // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
565     // cast.
566     auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
567     assert(Func != nullptr);
568     if (Value *MergedVal =
569             mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
570                                 *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
571       JoinedEnv.ReturnVal = MergedVal;
572   }
573 
574   if (EnvA.ReturnLoc == EnvB.ReturnLoc)
575     JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
576   else
577     JoinedEnv.ReturnLoc = nullptr;
578 
579   // FIXME: Once we're able to remove declarations from `DeclToLoc` when their
580   // lifetime ends, add an assertion that there aren't any entries in
581   // `DeclToLoc` and `Other.DeclToLoc` that map the same declaration to
582   // different storage locations.
583   JoinedEnv.DeclToLoc = intersectDenseMaps(EnvA.DeclToLoc, EnvB.DeclToLoc);
584 
585   JoinedEnv.ExprToLoc = intersectDenseMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
586 
587   JoinedEnv.MemberLocToStruct =
588       intersectDenseMaps(EnvA.MemberLocToStruct, EnvB.MemberLocToStruct);
589 
590   // FIXME: update join to detect backedges and simplify the flow condition
591   // accordingly.
592   JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
593       EnvA.FlowConditionToken, EnvB.FlowConditionToken);
594 
595   for (auto &Entry : EnvA.LocToVal) {
596     const StorageLocation *Loc = Entry.first;
597     assert(Loc != nullptr);
598 
599     Value *Val = Entry.second;
600     assert(Val != nullptr);
601 
602     auto It = EnvB.LocToVal.find(Loc);
603     if (It == EnvB.LocToVal.end())
604       continue;
605     assert(It->second != nullptr);
606 
607     if (areEquivalentValues(*Val, *It->second)) {
608       JoinedEnv.LocToVal.insert({Loc, Val});
609       continue;
610     }
611 
612     if (Value *MergedVal = mergeDistinctValues(
613             Loc->getType(), *Val, EnvA, *It->second, EnvB, JoinedEnv, Model)) {
614       JoinedEnv.LocToVal.insert({Loc, MergedVal});
615     }
616   }
617 
618   return JoinedEnv;
619 }
620 
621 StorageLocation &Environment::createStorageLocation(QualType Type) {
622   return DACtx->createStorageLocation(Type);
623 }
624 
625 StorageLocation &Environment::createStorageLocation(const VarDecl &D) {
626   // Evaluated declarations are always assigned the same storage locations to
627   // ensure that the environment stabilizes across loop iterations. Storage
628   // locations for evaluated declarations are stored in the analysis context.
629   return DACtx->getStableStorageLocation(D);
630 }
631 
632 StorageLocation &Environment::createStorageLocation(const Expr &E) {
633   // Evaluated expressions are always assigned the same storage locations to
634   // ensure that the environment stabilizes across loop iterations. Storage
635   // locations for evaluated expressions are stored in the analysis context.
636   return DACtx->getStableStorageLocation(E);
637 }
638 
639 void Environment::setStorageLocation(const ValueDecl &D, StorageLocation &Loc) {
640   assert(!DeclToLoc.contains(&D));
641   assert(!isa_and_nonnull<ReferenceValue>(getValue(Loc)));
642   DeclToLoc[&D] = &Loc;
643 }
644 
645 StorageLocation *Environment::getStorageLocation(const ValueDecl &D) const {
646   auto It = DeclToLoc.find(&D);
647   if (It == DeclToLoc.end())
648     return nullptr;
649 
650   StorageLocation *Loc = It->second;
651 
652   assert(!isa_and_nonnull<ReferenceValue>(getValue(*Loc)));
653 
654   return Loc;
655 }
656 
657 void Environment::setStorageLocation(const Expr &E, StorageLocation &Loc) {
658   const Expr &CanonE = ignoreCFGOmittedNodes(E);
659   assert(!ExprToLoc.contains(&CanonE));
660   ExprToLoc[&CanonE] = &Loc;
661 }
662 
663 void Environment::setStorageLocationStrict(const Expr &E,
664                                            StorageLocation &Loc) {
665   // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
666   // but we still want to be able to associate a `StorageLocation` with them,
667   // so allow these as an exception.
668   assert(E.isGLValue() ||
669          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
670   setStorageLocation(E, Loc);
671 }
672 
673 StorageLocation *Environment::getStorageLocation(const Expr &E,
674                                                  SkipPast SP) const {
675   // FIXME: Add a test with parens.
676   auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
677   return It == ExprToLoc.end() ? nullptr : &skip(*It->second, SP);
678 }
679 
680 StorageLocation *Environment::getStorageLocationStrict(const Expr &E) const {
681   // See comment in `setStorageLocationStrict()`.
682   assert(E.isGLValue() ||
683          E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
684   StorageLocation *Loc = getStorageLocation(E, SkipPast::None);
685 
686   if (Loc == nullptr)
687     return nullptr;
688 
689   if (auto *RefVal = dyn_cast_or_null<ReferenceValue>(getValue(*Loc)))
690     return &RefVal->getReferentLoc();
691 
692   return Loc;
693 }
694 
695 AggregateStorageLocation *Environment::getThisPointeeStorageLocation() const {
696   return ThisPointeeLoc;
697 }
698 
699 PointerValue &Environment::getOrCreateNullPointerValue(QualType PointeeType) {
700   return DACtx->getOrCreateNullPointerValue(PointeeType);
701 }
702 
703 void Environment::setValue(const StorageLocation &Loc, Value &Val) {
704   LocToVal[&Loc] = &Val;
705 
706   if (auto *StructVal = dyn_cast<StructValue>(&Val)) {
707     auto &AggregateLoc = *cast<AggregateStorageLocation>(&Loc);
708 
709     const QualType Type = AggregateLoc.getType();
710     assert(Type->isRecordType());
711 
712     for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
713       assert(Field != nullptr);
714       StorageLocation &FieldLoc = AggregateLoc.getChild(*Field);
715       MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field);
716       if (auto *FieldVal = StructVal->getChild(*Field))
717         setValue(FieldLoc, *FieldVal);
718     }
719   }
720 
721   auto It = MemberLocToStruct.find(&Loc);
722   if (It != MemberLocToStruct.end()) {
723     // `Loc` is the location of a struct member so we need to also update the
724     // value of the member in the corresponding `StructValue`.
725 
726     assert(It->second.first != nullptr);
727     StructValue &StructVal = *It->second.first;
728 
729     assert(It->second.second != nullptr);
730     const ValueDecl &Member = *It->second.second;
731 
732     StructVal.setChild(Member, Val);
733   }
734 }
735 
736 void Environment::clearValue(const StorageLocation &Loc) {
737   LocToVal.erase(&Loc);
738 
739   if (auto It = MemberLocToStruct.find(&Loc); It != MemberLocToStruct.end()) {
740     // `Loc` is the location of a struct member so we need to also clear the
741     // member in the corresponding `StructValue`.
742 
743     assert(It->second.first != nullptr);
744     StructValue &StructVal = *It->second.first;
745 
746     assert(It->second.second != nullptr);
747     const ValueDecl &Member = *It->second.second;
748 
749     StructVal.clearChild(Member);
750   }
751 }
752 
753 void Environment::setValueStrict(const Expr &E, Value &Val) {
754   assert(E.isPRValue());
755   assert(!isa<ReferenceValue>(Val));
756 
757   StorageLocation *Loc = getStorageLocation(E, SkipPast::None);
758   if (Loc == nullptr) {
759     Loc = &createStorageLocation(E);
760     setStorageLocation(E, *Loc);
761   }
762   setValue(*Loc, Val);
763 }
764 
765 Value *Environment::getValue(const StorageLocation &Loc) const {
766   return LocToVal.lookup(&Loc);
767 }
768 
769 Value *Environment::getValue(const ValueDecl &D) const {
770   auto *Loc = getStorageLocation(D);
771   if (Loc == nullptr)
772     return nullptr;
773   return getValue(*Loc);
774 }
775 
776 Value *Environment::getValue(const Expr &E, SkipPast SP) const {
777   auto *Loc = getStorageLocation(E, SP);
778   if (Loc == nullptr)
779     return nullptr;
780   return getValue(*Loc);
781 }
782 
783 Value *Environment::getValueStrict(const Expr &E) const {
784   assert(E.isPRValue());
785   Value *Val = getValue(E, SkipPast::None);
786 
787   assert(Val == nullptr || !isa<ReferenceValue>(Val));
788 
789   return Val;
790 }
791 
792 Value *Environment::createValue(QualType Type) {
793   llvm::DenseSet<QualType> Visited;
794   int CreatedValuesCount = 0;
795   Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
796                                                 CreatedValuesCount);
797   if (CreatedValuesCount > MaxCompositeValueSize) {
798     llvm::errs() << "Attempting to initialize a huge value of type: " << Type
799                  << '\n';
800   }
801   return Val;
802 }
803 
804 Value *Environment::createValueUnlessSelfReferential(
805     QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
806     int &CreatedValuesCount) {
807   assert(!Type.isNull());
808 
809   // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
810   if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
811       Depth > MaxCompositeValueDepth)
812     return nullptr;
813 
814   if (Type->isBooleanType()) {
815     CreatedValuesCount++;
816     return &makeAtomicBoolValue();
817   }
818 
819   if (Type->isIntegerType()) {
820     // FIXME: consider instead `return nullptr`, given that we do nothing useful
821     // with integers, and so distinguishing them serves no purpose, but could
822     // prevent convergence.
823     CreatedValuesCount++;
824     return &arena().create<IntegerValue>();
825   }
826 
827   if (Type->isReferenceType() || Type->isPointerType()) {
828     CreatedValuesCount++;
829     QualType PointeeType = Type->getPointeeType();
830     auto &PointeeLoc = createStorageLocation(PointeeType);
831 
832     if (Visited.insert(PointeeType.getCanonicalType()).second) {
833       Value *PointeeVal = createValueUnlessSelfReferential(
834           PointeeType, Visited, Depth, CreatedValuesCount);
835       Visited.erase(PointeeType.getCanonicalType());
836 
837       if (PointeeVal != nullptr)
838         setValue(PointeeLoc, *PointeeVal);
839     }
840 
841     if (Type->isReferenceType())
842       return &arena().create<ReferenceValue>(PointeeLoc);
843     else
844       return &arena().create<PointerValue>(PointeeLoc);
845   }
846 
847   if (Type->isRecordType()) {
848     CreatedValuesCount++;
849     llvm::DenseMap<const ValueDecl *, Value *> FieldValues;
850     for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
851       assert(Field != nullptr);
852 
853       QualType FieldType = Field->getType();
854       if (Visited.contains(FieldType.getCanonicalType()))
855         continue;
856 
857       Visited.insert(FieldType.getCanonicalType());
858       if (auto *FieldValue = createValueUnlessSelfReferential(
859               FieldType, Visited, Depth + 1, CreatedValuesCount))
860         FieldValues.insert({Field, FieldValue});
861       Visited.erase(FieldType.getCanonicalType());
862     }
863 
864     return &arena().create<StructValue>(std::move(FieldValues));
865   }
866 
867   return nullptr;
868 }
869 
870 StorageLocation &Environment::skip(StorageLocation &Loc, SkipPast SP) const {
871   switch (SP) {
872   case SkipPast::None:
873     return Loc;
874   case SkipPast::Reference:
875     // References cannot be chained so we only need to skip past one level of
876     // indirection.
877     if (auto *Val = dyn_cast_or_null<ReferenceValue>(getValue(Loc)))
878       return Val->getReferentLoc();
879     return Loc;
880   }
881   llvm_unreachable("bad SkipPast kind");
882 }
883 
884 const StorageLocation &Environment::skip(const StorageLocation &Loc,
885                                          SkipPast SP) const {
886   return skip(*const_cast<StorageLocation *>(&Loc), SP);
887 }
888 
889 void Environment::addToFlowCondition(const Formula &Val) {
890   DACtx->addFlowConditionConstraint(FlowConditionToken, Val);
891 }
892 void Environment::addToFlowCondition(BoolValue &Val) {
893   addToFlowCondition(Val.formula());
894 }
895 
896 bool Environment::flowConditionImplies(const Formula &Val) const {
897   return DACtx->flowConditionImplies(FlowConditionToken, Val);
898 }
899 bool Environment::flowConditionImplies(BoolValue &Val) const {
900   return flowConditionImplies(Val.formula());
901 }
902 
903 void Environment::dump(raw_ostream &OS) const {
904   // FIXME: add printing for remaining fields and allow caller to decide what
905   // fields are printed.
906   OS << "DeclToLoc:\n";
907   for (auto [D, L] : DeclToLoc)
908     OS << "  [" << D->getNameAsString() << ", " << L << "]\n";
909 
910   OS << "ExprToLoc:\n";
911   for (auto [E, L] : ExprToLoc)
912     OS << "  [" << E << ", " << L << "]\n";
913 
914   OS << "LocToVal:\n";
915   for (auto [L, V] : LocToVal) {
916     OS << "  [" << L << ", " << V << ": " << *V << "]\n";
917   }
918 
919   OS << "FlowConditionToken:\n";
920   DACtx->dumpFlowCondition(FlowConditionToken, OS);
921 }
922 
923 void Environment::dump() const {
924   dump(llvm::dbgs());
925 }
926 
927 AggregateStorageLocation *
928 getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
929                           const Environment &Env) {
930   Expr *ImplicitObject = MCE.getImplicitObjectArgument();
931   if (ImplicitObject == nullptr)
932     return nullptr;
933   StorageLocation *Loc =
934       Env.getStorageLocation(*ImplicitObject, SkipPast::Reference);
935   if (Loc == nullptr)
936     return nullptr;
937   if (ImplicitObject->getType()->isPointerType()) {
938     if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc)))
939       return &cast<AggregateStorageLocation>(Val->getPointeeLoc());
940     return nullptr;
941   }
942   return cast<AggregateStorageLocation>(Loc);
943 }
944 
945 AggregateStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
946                                                 const Environment &Env) {
947   Expr *Base = ME.getBase();
948   if (Base == nullptr)
949     return nullptr;
950   StorageLocation *Loc = Env.getStorageLocation(*Base, SkipPast::Reference);
951   if (Loc == nullptr)
952     return nullptr;
953   if (ME.isArrow()) {
954     if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Loc)))
955       return &cast<AggregateStorageLocation>(Val->getPointeeLoc());
956     return nullptr;
957   }
958   return cast<AggregateStorageLocation>(Loc);
959 }
960 
961 } // namespace dataflow
962 } // namespace clang
963