clang 18.0.0git
DataflowEnvironment.cpp
Go to the documentation of this file.
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
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/Type.h"
21#include "llvm/ADT/DenseMap.h"
22#include "llvm/ADT/DenseSet.h"
23#include "llvm/ADT/MapVector.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/Support/ErrorHandling.h"
26#include <cassert>
27#include <utility>
28
29namespace clang {
30namespace dataflow {
31
32// FIXME: convert these to parameters of the analysis or environment. Current
33// settings have been experimentaly validated, but only for a particular
34// analysis.
35static constexpr int MaxCompositeValueDepth = 3;
36static constexpr int MaxCompositeValueSize = 1000;
37
38/// Returns whether all declarations that `DeclToLoc1` and `DeclToLoc2` have in
39/// common map to the same storage location in both maps.
41 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc1,
42 const llvm::DenseMap<const ValueDecl *, StorageLocation *> &DeclToLoc2) {
43 for (auto &Entry : DeclToLoc1) {
44 auto It = DeclToLoc2.find(Entry.first);
45 if (It != DeclToLoc2.end() && Entry.second != It->second)
46 return false;
47 }
48
49 return true;
50}
51
52/// Returns a map consisting of key-value entries that are present in both maps.
53template <typename K, typename V>
54llvm::DenseMap<K, V> intersectDenseMaps(const llvm::DenseMap<K, V> &Map1,
55 const llvm::DenseMap<K, V> &Map2) {
56 llvm::DenseMap<K, V> Result;
57 for (auto &Entry : Map1) {
58 auto It = Map2.find(Entry.first);
59 if (It != Map2.end() && Entry.second == It->second)
60 Result.insert({Entry.first, Entry.second});
61 }
62 return Result;
63}
64
65// Whether to consider equivalent two values with an unknown relation.
66//
67// FIXME: this function is a hack enabling unsoundness to support
68// convergence. Once we have widening support for the reference/pointer and
69// struct built-in models, this should be unconditionally `false` (and inlined
70// as such at its call sites).
72 switch (K) {
76 return true;
77 default:
78 return false;
79 }
80}
81
83 const Environment &Env1, Value &Val2,
84 const Environment &Env2,
86 // Note: Potentially costly, but, for booleans, we could check whether both
87 // can be proven equivalent in their respective environments.
88
89 // FIXME: move the reference/pointers logic from `areEquivalentValues` to here
90 // and implement separate, join/widen specific handling for
91 // reference/pointers.
92 switch (Model.compare(Type, Val1, Env1, Val2, Env2)) {
94 return true;
96 return false;
98 return equateUnknownValues(Val1.getKind());
99 }
100 llvm_unreachable("All cases covered in switch");
101}
102
103/// Attempts to merge distinct values `Val1` and `Val2` in `Env1` and `Env2`,
104/// respectively, of the same type `Type`. Merging generally produces a single
105/// value that (soundly) approximates the two inputs, although the actual
106/// meaning depends on `Model`.
108 const Environment &Env1, Value &Val2,
109 const Environment &Env2,
110 Environment &MergedEnv,
112 // Join distinct boolean values preserving information about the constraints
113 // in the respective path conditions.
114 if (isa<BoolValue>(&Val1) && isa<BoolValue>(&Val2)) {
115 // FIXME: Checking both values should be unnecessary, since they should have
116 // a consistent shape. However, right now we can end up with BoolValue's in
117 // integer-typed variables due to our incorrect handling of
118 // boolean-to-integer casts (we just propagate the BoolValue to the result
119 // of the cast). So, a join can encounter an integer in one branch but a
120 // bool in the other.
121 // For example:
122 // ```
123 // std::optional<bool> o;
124 // int x;
125 // if (o.has_value())
126 // x = o.value();
127 // ```
128 auto &Expr1 = cast<BoolValue>(Val1).formula();
129 auto &Expr2 = cast<BoolValue>(Val2).formula();
130 auto &A = MergedEnv.arena();
131 auto &MergedVal = A.makeAtomRef(A.makeAtom());
132 MergedEnv.addToFlowCondition(
133 A.makeOr(A.makeAnd(A.makeAtomRef(Env1.getFlowConditionToken()),
134 A.makeEquals(MergedVal, Expr1)),
135 A.makeAnd(A.makeAtomRef(Env2.getFlowConditionToken()),
136 A.makeEquals(MergedVal, Expr2))));
137 return &A.makeBoolValue(MergedVal);
138 }
139
140 Value *MergedVal = nullptr;
141 if (auto *RecordVal1 = dyn_cast<RecordValue>(&Val1)) {
142 auto *RecordVal2 = cast<RecordValue>(&Val2);
143
144 if (&RecordVal1->getLoc() == &RecordVal2->getLoc())
145 // `RecordVal1` and `RecordVal2` may have different properties associated
146 // with them. Create a new `RecordValue` with the same location but
147 // without any properties so that we soundly approximate both values. If a
148 // particular analysis needs to merge properties, it should do so in
149 // `DataflowAnalysis::merge()`.
150 MergedVal = &MergedEnv.create<RecordValue>(RecordVal1->getLoc());
151 else
152 // If the locations for the two records are different, need to create a
153 // completely new value.
154 MergedVal = MergedEnv.createValue(Type);
155 } else {
156 MergedVal = MergedEnv.createValue(Type);
157 }
158
159 // FIXME: Consider destroying `MergedValue` immediately if `ValueModel::merge`
160 // returns false to avoid storing unneeded values in `DACtx`.
161 if (MergedVal)
162 if (Model.merge(Type, Val1, Env1, Val2, Env2, *MergedVal, MergedEnv))
163 return MergedVal;
164
165 return nullptr;
166}
167
168// When widening does not change `Current`, return value will equal `&Prev`.
170 const Environment &PrevEnv, Value &Current,
171 Environment &CurrentEnv,
173 // Boolean-model widening.
174 if (isa<BoolValue>(&Prev)) {
175 assert(isa<BoolValue>(Current));
176 // Widen to Top, because we know they are different values. If previous was
177 // already Top, re-use that to (implicitly) indicate that no change occured.
178 if (isa<TopBoolValue>(Prev))
179 return Prev;
180 return CurrentEnv.makeTopBoolValue();
181 }
182
183 // FIXME: Add other built-in model widening.
184
185 // Custom-model widening.
186 if (auto *W = Model.widen(Type, Prev, PrevEnv, Current, CurrentEnv))
187 return *W;
188
189 return equateUnknownValues(Prev.getKind()) ? Prev : Current;
190}
191
192// Returns whether the values in `Map1` and `Map2` compare equal for those
193// keys that `Map1` and `Map2` have in common.
194template <typename Key>
195bool compareKeyToValueMaps(const llvm::MapVector<Key, Value *> &Map1,
196 const llvm::MapVector<Key, Value *> &Map2,
197 const Environment &Env1, const Environment &Env2,
199 for (auto &Entry : Map1) {
200 Key K = Entry.first;
201 assert(K != nullptr);
202
203 Value *Val = Entry.second;
204 assert(Val != nullptr);
205
206 auto It = Map2.find(K);
207 if (It == Map2.end())
208 continue;
209 assert(It->second != nullptr);
210
211 if (!areEquivalentValues(*Val, *It->second) &&
212 !compareDistinctValues(K->getType(), *Val, Env1, *It->second, Env2,
213 Model))
214 return false;
215 }
216
217 return true;
218}
219
220// Perform a join on either `LocToVal` or `ExprToVal`. `Key` must be either
221// `const StorageLocation *` or `const Expr *`.
222template <typename Key>
223llvm::MapVector<Key, Value *>
224joinKeyToValueMap(const llvm::MapVector<Key, Value *> &Map1,
225 const llvm::MapVector<Key, Value *> &Map2,
226 const Environment &Env1, const Environment &Env2,
227 Environment &JoinedEnv, Environment::ValueModel &Model) {
228 llvm::MapVector<Key, Value *> MergedMap;
229 for (auto &Entry : Map1) {
230 Key K = Entry.first;
231 assert(K != nullptr);
232
233 Value *Val = Entry.second;
234 assert(Val != nullptr);
235
236 auto It = Map2.find(K);
237 if (It == Map2.end())
238 continue;
239 assert(It->second != nullptr);
240
241 if (areEquivalentValues(*Val, *It->second)) {
242 MergedMap.insert({K, Val});
243 continue;
244 }
245
246 if (Value *MergedVal = mergeDistinctValues(
247 K->getType(), *Val, Env1, *It->second, Env2, JoinedEnv, Model)) {
248 MergedMap.insert({K, MergedVal});
249 }
250 }
251
252 return MergedMap;
253}
254
255// Perform widening on either `LocToVal` or `ExprToVal`. `Key` must be either
256// `const StorageLocation *` or `const Expr *`.
257template <typename Key>
258llvm::MapVector<Key, Value *>
259widenKeyToValueMap(const llvm::MapVector<Key, Value *> &CurMap,
260 const llvm::MapVector<Key, Value *> &PrevMap,
261 Environment &CurEnv, const Environment &PrevEnv,
263 llvm::MapVector<Key, Value *> WidenedMap;
264 for (auto &Entry : CurMap) {
265 Key K = Entry.first;
266 assert(K != nullptr);
267
268 Value *Val = Entry.second;
269 assert(Val != nullptr);
270
271 auto PrevIt = PrevMap.find(K);
272 if (PrevIt == PrevMap.end())
273 continue;
274 assert(PrevIt->second != nullptr);
275
276 if (areEquivalentValues(*Val, *PrevIt->second)) {
277 WidenedMap.insert({K, Val});
278 continue;
279 }
280
281 Value &WidenedVal = widenDistinctValues(K->getType(), *PrevIt->second,
282 PrevEnv, *Val, CurEnv, Model);
283 WidenedMap.insert({K, &WidenedVal});
284 if (&WidenedVal != PrevIt->second)
286 }
287
288 return WidenedMap;
289}
290
291/// Initializes a global storage value.
292static void insertIfGlobal(const Decl &D,
294 if (auto *V = dyn_cast<VarDecl>(&D))
295 if (V->hasGlobalStorage())
296 Vars.insert(V);
297}
298
299static void insertIfFunction(const Decl &D,
301 if (auto *FD = dyn_cast<FunctionDecl>(&D))
302 Funcs.insert(FD);
303}
304
306 if (!C.getMethodDecl())
307 return nullptr;
308 auto *Body = dyn_cast_or_null<CompoundStmt>(C.getMethodDecl()->getBody());
309 if (!Body || Body->size() != 1)
310 return nullptr;
311 if (auto *RS = dyn_cast<ReturnStmt>(*Body->body_begin()))
312 if (auto *Return = RS->getRetValue())
313 return dyn_cast<MemberExpr>(Return->IgnoreParenImpCasts());
314 return nullptr;
315}
316
317static void
321 insertIfGlobal(D, Vars);
322 insertIfFunction(D, Funcs);
323 if (const auto *Decomp = dyn_cast<DecompositionDecl>(&D))
324 for (const auto *B : Decomp->bindings())
325 if (auto *ME = dyn_cast_or_null<MemberExpr>(B->getBinding()))
326 // FIXME: should we be using `E->getFoundDecl()`?
327 if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()))
328 Fields.insert(FD);
329}
330
331/// Traverses `S` and inserts into `Fields`, `Vars` and `Funcs` any fields,
332/// global variables and functions that are declared in or referenced from
333/// sub-statements.
334static void
338 for (auto *Child : S.children())
339 if (Child != nullptr)
340 getFieldsGlobalsAndFuncs(*Child, Fields, Vars, Funcs);
341 if (const auto *DefaultInit = dyn_cast<CXXDefaultInitExpr>(&S))
342 getFieldsGlobalsAndFuncs(*DefaultInit->getExpr(), Fields, Vars, Funcs);
343
344 if (auto *DS = dyn_cast<DeclStmt>(&S)) {
345 if (DS->isSingleDecl())
346 getFieldsGlobalsAndFuncs(*DS->getSingleDecl(), Fields, Vars, Funcs);
347 else
348 for (auto *D : DS->getDeclGroup())
349 getFieldsGlobalsAndFuncs(*D, Fields, Vars, Funcs);
350 } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
351 insertIfGlobal(*E->getDecl(), Vars);
352 insertIfFunction(*E->getDecl(), Funcs);
353 } else if (const auto *C = dyn_cast<CXXMemberCallExpr>(&S)) {
354 // If this is a method that returns a member variable but does nothing else,
355 // model the field of the return value.
357 if (const auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()))
358 Fields.insert(FD);
359 } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
360 // FIXME: should we be using `E->getFoundDecl()`?
361 const ValueDecl *VD = E->getMemberDecl();
362 insertIfGlobal(*VD, Vars);
363 insertIfFunction(*VD, Funcs);
364 if (const auto *FD = dyn_cast<FieldDecl>(VD))
365 Fields.insert(FD);
366 } else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
367 if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
368 for (const auto *FD : getFieldsForInitListExpr(RD))
369 Fields.insert(FD);
370 }
371}
372
373// FIXME: Add support for resetting globals after function calls to enable
374// the implementation of sound analyses.
375void Environment::initFieldsGlobalsAndFuncs(const FunctionDecl *FuncDecl) {
376 assert(FuncDecl->getBody() != nullptr);
377
378 FieldSet Fields;
381
382 // Look for global variable and field references in the
383 // constructor-initializers.
384 if (const auto *CtorDecl = dyn_cast<CXXConstructorDecl>(FuncDecl)) {
385 for (const auto *Init : CtorDecl->inits()) {
386 if (Init->isMemberInitializer()) {
387 Fields.insert(Init->getMember());
388 } else if (Init->isIndirectMemberInitializer()) {
389 for (const auto *I : Init->getIndirectMember()->chain())
390 Fields.insert(cast<FieldDecl>(I));
391 }
392 const Expr *E = Init->getInit();
393 assert(E != nullptr);
394 getFieldsGlobalsAndFuncs(*E, Fields, Vars, Funcs);
395 }
396 // Add all fields mentioned in default member initializers.
397 for (const FieldDecl *F : CtorDecl->getParent()->fields())
398 if (const auto *I = F->getInClassInitializer())
399 getFieldsGlobalsAndFuncs(*I, Fields, Vars, Funcs);
400 }
401 getFieldsGlobalsAndFuncs(*FuncDecl->getBody(), Fields, Vars, Funcs);
402
403 // These have to be added before the lines that follow to ensure that
404 // `create*` work correctly for structs.
405 DACtx->addModeledFields(Fields);
406
407 for (const VarDecl *D : Vars) {
408 if (getStorageLocation(*D) != nullptr)
409 continue;
410
412 }
413
414 for (const FunctionDecl *FD : Funcs) {
415 if (getStorageLocation(*FD) != nullptr)
416 continue;
417 auto &Loc = createStorageLocation(FD->getType());
418 setStorageLocation(*FD, Loc);
419 }
420}
421
423 : DACtx(&DACtx),
424 FlowConditionToken(DACtx.arena().makeFlowConditionToken()) {}
425
427 Environment Copy(*this);
428 Copy.FlowConditionToken = DACtx->forkFlowCondition(FlowConditionToken);
429 return Copy;
430}
431
433 const DeclContext &DeclCtx)
434 : Environment(DACtx) {
435 CallStack.push_back(&DeclCtx);
436
437 if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
438 assert(FuncDecl->getBody() != nullptr);
439
440 initFieldsGlobalsAndFuncs(FuncDecl);
441
442 for (const auto *ParamDecl : FuncDecl->parameters()) {
443 assert(ParamDecl != nullptr);
444 setStorageLocation(*ParamDecl, createObject(*ParamDecl, nullptr));
445 }
446 }
447
448 if (const auto *MethodDecl = dyn_cast<CXXMethodDecl>(&DeclCtx)) {
449 auto *Parent = MethodDecl->getParent();
450 assert(Parent != nullptr);
451 if (Parent->isLambda())
452 MethodDecl = dyn_cast<CXXMethodDecl>(Parent->getDeclContext());
453
454 // FIXME: Initialize the ThisPointeeLoc of lambdas too.
455 if (MethodDecl && !MethodDecl->isStatic()) {
456 QualType ThisPointeeType = MethodDecl->getThisObjectType();
457 ThisPointeeLoc =
458 &cast<RecordValue>(createValue(ThisPointeeType))->getLoc();
459 }
460 }
461}
462
463bool Environment::canDescend(unsigned MaxDepth,
464 const DeclContext *Callee) const {
465 return CallStack.size() <= MaxDepth && !llvm::is_contained(CallStack, Callee);
466}
467
469 Environment Env(*this);
470
471 if (const auto *MethodCall = dyn_cast<CXXMemberCallExpr>(Call)) {
472 if (const Expr *Arg = MethodCall->getImplicitObjectArgument()) {
473 if (!isa<CXXThisExpr>(Arg))
474 Env.ThisPointeeLoc =
475 cast<RecordStorageLocation>(getStorageLocation(*Arg));
476 // Otherwise (when the argument is `this`), retain the current
477 // environment's `ThisPointeeLoc`.
478 }
479 }
480
481 Env.pushCallInternal(Call->getDirectCallee(),
482 llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
483
484 return Env;
485}
486
488 Environment Env(*this);
489
490 Env.ThisPointeeLoc = &Env.getResultObjectLocation(*Call);
491
492 Env.pushCallInternal(Call->getConstructor(),
493 llvm::ArrayRef(Call->getArgs(), Call->getNumArgs()));
494
495 return Env;
496}
497
498void Environment::pushCallInternal(const FunctionDecl *FuncDecl,
500 // Canonicalize to the definition of the function. This ensures that we're
501 // putting arguments into the same `ParamVarDecl`s` that the callee will later
502 // be retrieving them from.
503 assert(FuncDecl->getDefinition() != nullptr);
504 FuncDecl = FuncDecl->getDefinition();
505
506 CallStack.push_back(FuncDecl);
507
508 initFieldsGlobalsAndFuncs(FuncDecl);
509
510 const auto *ParamIt = FuncDecl->param_begin();
511
512 // FIXME: Parameters don't always map to arguments 1:1; examples include
513 // overloaded operators implemented as member functions, and parameter packs.
514 for (unsigned ArgIndex = 0; ArgIndex < Args.size(); ++ParamIt, ++ArgIndex) {
515 assert(ParamIt != FuncDecl->param_end());
516 const VarDecl *Param = *ParamIt;
517 setStorageLocation(*Param, createObject(*Param, Args[ArgIndex]));
518 }
519}
520
521void Environment::popCall(const CallExpr *Call, const Environment &CalleeEnv) {
522 // We ignore some entries of `CalleeEnv`:
523 // - `DACtx` because is already the same in both
524 // - We don't want the callee's `DeclCtx`, `ReturnVal`, `ReturnLoc` or
525 // `ThisPointeeLoc` because they don't apply to us.
526 // - `DeclToLoc`, `ExprToLoc`, and `ExprToVal` capture information from the
527 // callee's local scope, so when popping that scope, we do not propagate
528 // the maps.
529 this->LocToVal = std::move(CalleeEnv.LocToVal);
530 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
531
532 if (Call->isGLValue()) {
533 if (CalleeEnv.ReturnLoc != nullptr)
534 setStorageLocation(*Call, *CalleeEnv.ReturnLoc);
535 } else if (!Call->getType()->isVoidType()) {
536 if (CalleeEnv.ReturnVal != nullptr)
537 setValue(*Call, *CalleeEnv.ReturnVal);
538 }
539}
540
542 const Environment &CalleeEnv) {
543 // See also comment in `popCall(const CallExpr *, const Environment &)` above.
544 this->LocToVal = std::move(CalleeEnv.LocToVal);
545 this->FlowConditionToken = std::move(CalleeEnv.FlowConditionToken);
546
547 if (Value *Val = CalleeEnv.getValue(*CalleeEnv.ThisPointeeLoc)) {
548 setValue(*Call, *Val);
549 }
550}
551
553 Environment::ValueModel &Model) const {
554 assert(DACtx == Other.DACtx);
555
556 if (ReturnVal != Other.ReturnVal)
557 return false;
558
559 if (ReturnLoc != Other.ReturnLoc)
560 return false;
561
562 if (ThisPointeeLoc != Other.ThisPointeeLoc)
563 return false;
564
565 if (DeclToLoc != Other.DeclToLoc)
566 return false;
567
568 if (ExprToLoc != Other.ExprToLoc)
569 return false;
570
571 if (!compareKeyToValueMaps(ExprToVal, Other.ExprToVal, *this, Other, Model))
572 return false;
573
574 if (!compareKeyToValueMaps(LocToVal, Other.LocToVal, *this, Other, Model))
575 return false;
576
577 return true;
578}
579
582 assert(DACtx == PrevEnv.DACtx);
583 assert(ReturnVal == PrevEnv.ReturnVal);
584 assert(ReturnLoc == PrevEnv.ReturnLoc);
585 assert(ThisPointeeLoc == PrevEnv.ThisPointeeLoc);
586 assert(CallStack == PrevEnv.CallStack);
587
588 auto Effect = LatticeJoinEffect::Unchanged;
589
590 // By the API, `PrevEnv` is a previous version of the environment for the same
591 // block, so we have some guarantees about its shape. In particular, it will
592 // be the result of a join or widen operation on previous values for this
593 // block. For `DeclToLoc`, `ExprToVal`, and `ExprToLoc`, join guarantees that
594 // these maps are subsets of the maps in `PrevEnv`. So, as long as we maintain
595 // this property here, we don't need change their current values to widen.
596 assert(DeclToLoc.size() <= PrevEnv.DeclToLoc.size());
597 assert(ExprToVal.size() <= PrevEnv.ExprToVal.size());
598 assert(ExprToLoc.size() <= PrevEnv.ExprToLoc.size());
599
600 ExprToVal = widenKeyToValueMap(ExprToVal, PrevEnv.ExprToVal, *this, PrevEnv,
601 Model, Effect);
602
603 LocToVal = widenKeyToValueMap(LocToVal, PrevEnv.LocToVal, *this, PrevEnv,
604 Model, Effect);
605 if (DeclToLoc.size() != PrevEnv.DeclToLoc.size() ||
606 ExprToLoc.size() != PrevEnv.ExprToLoc.size() ||
607 ExprToVal.size() != PrevEnv.ExprToVal.size() ||
608 LocToVal.size() != PrevEnv.LocToVal.size())
610
611 return Effect;
612}
613
616 assert(EnvA.DACtx == EnvB.DACtx);
617 assert(EnvA.ThisPointeeLoc == EnvB.ThisPointeeLoc);
618 assert(EnvA.CallStack == EnvB.CallStack);
619
620 Environment JoinedEnv(*EnvA.DACtx);
621
622 JoinedEnv.CallStack = EnvA.CallStack;
623 JoinedEnv.ThisPointeeLoc = EnvA.ThisPointeeLoc;
624
625 if (EnvA.ReturnVal == nullptr || EnvB.ReturnVal == nullptr) {
626 // `ReturnVal` might not always get set -- for example if we have a return
627 // statement of the form `return some_other_func()` and we decide not to
628 // analyze `some_other_func()`.
629 // In this case, we can't say anything about the joined return value -- we
630 // don't simply want to propagate the return value that we do have, because
631 // it might not be the correct one.
632 // This occurs for example in the test `ContextSensitiveMutualRecursion`.
633 JoinedEnv.ReturnVal = nullptr;
634 } else if (areEquivalentValues(*EnvA.ReturnVal, *EnvB.ReturnVal)) {
635 JoinedEnv.ReturnVal = EnvA.ReturnVal;
636 } else {
637 assert(!EnvA.CallStack.empty());
638 // FIXME: Make `CallStack` a vector of `FunctionDecl` so we don't need this
639 // cast.
640 auto *Func = dyn_cast<FunctionDecl>(EnvA.CallStack.back());
641 assert(Func != nullptr);
642 if (Value *MergedVal =
643 mergeDistinctValues(Func->getReturnType(), *EnvA.ReturnVal, EnvA,
644 *EnvB.ReturnVal, EnvB, JoinedEnv, Model))
645 JoinedEnv.ReturnVal = MergedVal;
646 }
647
648 if (EnvA.ReturnLoc == EnvB.ReturnLoc)
649 JoinedEnv.ReturnLoc = EnvA.ReturnLoc;
650 else
651 JoinedEnv.ReturnLoc = nullptr;
652
653 assert(declToLocConsistent(EnvA.DeclToLoc, EnvB.DeclToLoc));
654 JoinedEnv.DeclToLoc = intersectDenseMaps(EnvA.DeclToLoc, EnvB.DeclToLoc);
655
656 JoinedEnv.ExprToLoc = intersectDenseMaps(EnvA.ExprToLoc, EnvB.ExprToLoc);
657
658 // FIXME: update join to detect backedges and simplify the flow condition
659 // accordingly.
660 JoinedEnv.FlowConditionToken = EnvA.DACtx->joinFlowConditions(
661 EnvA.FlowConditionToken, EnvB.FlowConditionToken);
662
663 JoinedEnv.ExprToVal = joinKeyToValueMap(EnvA.ExprToVal, EnvB.ExprToVal, EnvA,
664 EnvB, JoinedEnv, Model);
665
666 JoinedEnv.LocToVal = joinKeyToValueMap(EnvA.LocToVal, EnvB.LocToVal, EnvA,
667 EnvB, JoinedEnv, Model);
668
669 return JoinedEnv;
670}
671
673 return DACtx->createStorageLocation(Type);
674}
675
677 // Evaluated declarations are always assigned the same storage locations to
678 // ensure that the environment stabilizes across loop iterations. Storage
679 // locations for evaluated declarations are stored in the analysis context.
680 return DACtx->getStableStorageLocation(D);
681}
682
684 // Evaluated expressions are always assigned the same storage locations to
685 // ensure that the environment stabilizes across loop iterations. Storage
686 // locations for evaluated expressions are stored in the analysis context.
687 return DACtx->getStableStorageLocation(E);
688}
689
691 assert(!DeclToLoc.contains(&D));
692 DeclToLoc[&D] = &Loc;
693}
694
696 auto It = DeclToLoc.find(&D);
697 if (It == DeclToLoc.end())
698 return nullptr;
699
700 StorageLocation *Loc = It->second;
701
702 return Loc;
703}
704
706 assert(DeclToLoc.contains(&D));
707 DeclToLoc.erase(&D);
708}
709
711 // `DeclRefExpr`s to builtin function types aren't glvalues, for some reason,
712 // but we still want to be able to associate a `StorageLocation` with them,
713 // so allow these as an exception.
714 assert(E.isGLValue() ||
715 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
716 setStorageLocationInternal(E, Loc);
717}
718
720 // See comment in `setStorageLocation()`.
721 assert(E.isGLValue() ||
722 E.getType()->isSpecificBuiltinType(BuiltinType::BuiltinFn));
723 return getStorageLocationInternal(E);
724}
725
727 return ThisPointeeLoc;
728}
729
732 assert(RecordPRValue.getType()->isRecordType());
733 assert(RecordPRValue.isPRValue());
734
735 if (StorageLocation *ExistingLoc = getStorageLocationInternal(RecordPRValue))
736 return *cast<RecordStorageLocation>(ExistingLoc);
737 auto &Loc = cast<RecordStorageLocation>(
738 DACtx->getStableStorageLocation(RecordPRValue));
739 setStorageLocationInternal(RecordPRValue, Loc);
740 return Loc;
741}
742
744 return DACtx->getOrCreateNullPointerValue(PointeeType);
745}
746
748 assert(!isa<RecordValue>(&Val) || &cast<RecordValue>(&Val)->getLoc() == &Loc);
749
750 LocToVal[&Loc] = &Val;
751}
752
753void Environment::setValue(const Expr &E, Value &Val) {
754 assert(E.isPRValue());
755 ExprToVal[&E] = &Val;
756}
757
759 return LocToVal.lookup(&Loc);
760}
761
763 auto *Loc = getStorageLocation(D);
764 if (Loc == nullptr)
765 return nullptr;
766 return getValue(*Loc);
767}
768
770 if (E.isPRValue()) {
771 auto It = ExprToVal.find(&ignoreCFGOmittedNodes(E));
772 return It == ExprToVal.end() ? nullptr : It->second;
773 }
774
775 auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
776 if (It == ExprToLoc.end())
777 return nullptr;
778 return getValue(*It->second);
779}
780
783 int CreatedValuesCount = 0;
784 Value *Val = createValueUnlessSelfReferential(Type, Visited, /*Depth=*/0,
785 CreatedValuesCount);
786 if (CreatedValuesCount > MaxCompositeValueSize) {
787 llvm::errs() << "Attempting to initialize a huge value of type: " << Type
788 << '\n';
789 }
790 return Val;
791}
792
793void Environment::setStorageLocationInternal(const Expr &E,
794 StorageLocation &Loc) {
795 const Expr &CanonE = ignoreCFGOmittedNodes(E);
796 assert(!ExprToLoc.contains(&CanonE));
797 ExprToLoc[&CanonE] = &Loc;
798}
799
800StorageLocation *Environment::getStorageLocationInternal(const Expr &E) const {
801 auto It = ExprToLoc.find(&ignoreCFGOmittedNodes(E));
802 return It == ExprToLoc.end() ? nullptr : &*It->second;
803}
804
805Value *Environment::createValueUnlessSelfReferential(
806 QualType Type, llvm::DenseSet<QualType> &Visited, int Depth,
807 int &CreatedValuesCount) {
808 assert(!Type.isNull());
809 assert(!Type->isReferenceType());
810
811 // Allow unlimited fields at depth 1; only cap at deeper nesting levels.
812 if ((Depth > 1 && CreatedValuesCount > MaxCompositeValueSize) ||
814 return nullptr;
815
816 if (Type->isBooleanType()) {
817 CreatedValuesCount++;
818 return &makeAtomicBoolValue();
819 }
820
821 if (Type->isIntegerType()) {
822 // FIXME: consider instead `return nullptr`, given that we do nothing useful
823 // with integers, and so distinguishing them serves no purpose, but could
824 // prevent convergence.
825 CreatedValuesCount++;
826 return &arena().create<IntegerValue>();
827 }
828
829 if (Type->isPointerType()) {
830 CreatedValuesCount++;
831 QualType PointeeType = Type->getPointeeType();
832 StorageLocation &PointeeLoc =
833 createLocAndMaybeValue(PointeeType, Visited, Depth, CreatedValuesCount);
834
835 return &arena().create<PointerValue>(PointeeLoc);
836 }
837
838 if (Type->isRecordType()) {
839 CreatedValuesCount++;
840 llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
841 for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
842 assert(Field != nullptr);
843
844 QualType FieldType = Field->getType();
845
846 FieldLocs.insert(
847 {Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
848 CreatedValuesCount)});
849 }
850
851 RecordStorageLocation &Loc =
852 arena().create<RecordStorageLocation>(Type, std::move(FieldLocs));
853 RecordValue &RecordVal = create<RecordValue>(Loc);
854
855 // As we already have a storage location for the `RecordValue`, we can and
856 // should associate them in the environment.
857 setValue(Loc, RecordVal);
858
859 return &RecordVal;
860 }
861
862 return nullptr;
863}
864
865StorageLocation &
866Environment::createLocAndMaybeValue(QualType Ty,
868 int Depth, int &CreatedValuesCount) {
869 if (!Visited.insert(Ty.getCanonicalType()).second)
870 return createStorageLocation(Ty.getNonReferenceType());
871 Value *Val = createValueUnlessSelfReferential(
872 Ty.getNonReferenceType(), Visited, Depth, CreatedValuesCount);
873 Visited.erase(Ty.getCanonicalType());
874
875 Ty = Ty.getNonReferenceType();
876
877 if (Val == nullptr)
878 return createStorageLocation(Ty);
879
880 if (Ty->isRecordType())
881 return cast<RecordValue>(Val)->getLoc();
882
883 StorageLocation &Loc = createStorageLocation(Ty);
884 setValue(Loc, *Val);
885 return Loc;
886}
887
888StorageLocation &Environment::createObjectInternal(const VarDecl *D,
889 QualType Ty,
890 const Expr *InitExpr) {
891 if (Ty->isReferenceType()) {
892 // Although variables of reference type always need to be initialized, it
893 // can happen that we can't see the initializer, so `InitExpr` may still
894 // be null.
895 if (InitExpr) {
896 if (auto *InitExprLoc = getStorageLocation(*InitExpr))
897 return *InitExprLoc;
898 }
899
900 // Even though we have an initializer, we might not get an
901 // InitExprLoc, for example if the InitExpr is a CallExpr for which we
902 // don't have a function body. In this case, we just invent a storage
903 // location and value -- it's the best we can do.
904 return createObjectInternal(D, Ty.getNonReferenceType(), nullptr);
905 }
906
907 Value *Val = nullptr;
908 if (InitExpr)
909 // In the (few) cases where an expression is intentionally
910 // "uninterpreted", `InitExpr` is not associated with a value. There are
911 // two ways to handle this situation: propagate the status, so that
912 // uninterpreted initializers result in uninterpreted variables, or
913 // provide a default value. We choose the latter so that later refinements
914 // of the variable can be used for reasoning about the surrounding code.
915 // For this reason, we let this case be handled by the `createValue()`
916 // call below.
917 //
918 // FIXME. If and when we interpret all language cases, change this to
919 // assert that `InitExpr` is interpreted, rather than supplying a
920 // default value (assuming we don't update the environment API to return
921 // references).
922 Val = getValue(*InitExpr);
923 if (!Val)
924 Val = createValue(Ty);
925
926 if (Ty->isRecordType())
927 return cast<RecordValue>(Val)->getLoc();
928
929 StorageLocation &Loc =
931
932 if (Val)
933 setValue(Loc, *Val);
934
935 return Loc;
936}
937
939 DACtx->addFlowConditionConstraint(FlowConditionToken, Val);
940}
941
943 return DACtx->flowConditionImplies(FlowConditionToken, Val);
944}
945
946void Environment::dump(raw_ostream &OS) const {
947 // FIXME: add printing for remaining fields and allow caller to decide what
948 // fields are printed.
949 OS << "DeclToLoc:\n";
950 for (auto [D, L] : DeclToLoc)
951 OS << " [" << D->getNameAsString() << ", " << L << "]\n";
952
953 OS << "ExprToLoc:\n";
954 for (auto [E, L] : ExprToLoc)
955 OS << " [" << E << ", " << L << "]\n";
956
957 OS << "ExprToVal:\n";
958 for (auto [E, V] : ExprToVal)
959 OS << " [" << E << ", " << V << ": " << *V << "]\n";
960
961 OS << "LocToVal:\n";
962 for (auto [L, V] : LocToVal) {
963 OS << " [" << L << ", " << V << ": " << *V << "]\n";
964 }
965
966 OS << "FlowConditionToken:\n";
967 DACtx->dumpFlowCondition(FlowConditionToken, OS);
968}
969
970void Environment::dump() const {
971 dump(llvm::dbgs());
972}
973
975 const Environment &Env) {
976 Expr *ImplicitObject = MCE.getImplicitObjectArgument();
977 if (ImplicitObject == nullptr)
978 return nullptr;
979 if (ImplicitObject->getType()->isPointerType()) {
980 if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*ImplicitObject)))
981 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
982 return nullptr;
983 }
984 return cast_or_null<RecordStorageLocation>(
985 Env.getStorageLocation(*ImplicitObject));
986}
987
989 const Environment &Env) {
990 Expr *Base = ME.getBase();
991 if (Base == nullptr)
992 return nullptr;
993 if (ME.isArrow()) {
994 if (auto *Val = cast_or_null<PointerValue>(Env.getValue(*Base)))
995 return &cast<RecordStorageLocation>(Val->getPointeeLoc());
996 return nullptr;
997 }
998 return cast_or_null<RecordStorageLocation>(Env.getStorageLocation(*Base));
999}
1000
1001std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
1002 // Unnamed bitfields are only used for padding and do not appear in
1003 // `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
1004 // field list, and we thus need to remove them before mapping inits to
1005 // fields to avoid mapping inits to the wrongs fields.
1006 std::vector<FieldDecl *> Fields;
1007 llvm::copy_if(
1008 RD->fields(), std::back_inserter(Fields),
1009 [](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
1010 return Fields;
1011}
1012
1014 auto &NewVal = Env.create<RecordValue>(Loc);
1015 Env.setValue(Loc, NewVal);
1016 return NewVal;
1017}
1018
1020 assert(Expr.getType()->isRecordType());
1021
1022 if (Expr.isPRValue()) {
1023 if (auto *ExistingVal = cast_or_null<RecordValue>(Env.getValue(Expr))) {
1024 auto &NewVal = Env.create<RecordValue>(ExistingVal->getLoc());
1025 Env.setValue(Expr, NewVal);
1026 return NewVal;
1027 }
1028
1029 auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType()));
1030 Env.setValue(Expr, NewVal);
1031 return NewVal;
1032 }
1033
1034 if (auto *Loc =
1035 cast_or_null<RecordStorageLocation>(Env.getStorageLocation(Expr))) {
1036 auto &NewVal = Env.create<RecordValue>(*Loc);
1037 Env.setValue(*Loc, NewVal);
1038 return NewVal;
1039 }
1040
1041 auto &NewVal = *cast<RecordValue>(Env.createValue(Expr.getType()));
1042 Env.setStorageLocation(Expr, NewVal.getLoc());
1043 return NewVal;
1044}
1045
1046} // namespace dataflow
1047} // namespace clang
#define V(N, I)
Definition: ASTContext.h:3233
NodeId Parent
Definition: ASTDiff.cpp:191
MatchType Type
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
const Environment & Env
Definition: HTMLLogger.cpp:145
llvm::DenseSet< const void * > Visited
Definition: HTMLLogger.cpp:143
C Language Family Type Representation.
Represents a call to a C++ constructor.
Definition: ExprCXX.h:1523
Represents a call to a member function that may be written either with member call syntax (e....
Definition: ExprCXX.h:176
Expr * getImplicitObjectArgument() const
Retrieve the implicit object argument for the member call.
Definition: ExprCXX.cpp:653
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2832
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition: DeclBase.h:1409
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:83
This represents one expression.
Definition: Expr.h:110
bool isGLValue() const
Definition: Expr.h:274
bool isPRValue() const
Definition: Expr.h:272
QualType getType() const
Definition: Expr.h:142
Represents a member of a struct/union/class.
Definition: Decl.h:2962
Represents a function declaration or definition.
Definition: Decl.h:1919
Stmt * getBody(const FunctionDecl *&Definition) const
Retrieve the body (definition) of the function.
Definition: Decl.cpp:3174
param_iterator param_end()
Definition: Decl.h:2616
ArrayRef< ParmVarDecl * > parameters() const
Definition: Decl.h:2603
param_iterator param_begin()
Definition: Decl.h:2615
FunctionDecl * getDefinition()
Get the definition for this declaration.
Definition: Decl.h:2186
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:3195
Expr * getBase() const
Definition: Expr.h:3268
bool isArrow() const
Definition: Expr.h:3375
A (possibly-)qualified type.
Definition: Type.h:736
Represents a struct/union/class.
Definition: Decl.h:4036
field_range fields() const
Definition: Decl.h:4263
Stmt - This represents one statement.
Definition: Stmt.h:72
The base class of the type hierarchy.
Definition: Type.h:1597
bool isPointerType() const
Definition: Type.h:6999
bool isSpecificBuiltinType(unsigned K) const
Test for a particular builtin type.
Definition: Type.h:7286
bool isRecordType() const
Definition: Type.h:7089
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:703
Represents a variable declaration or definition.
Definition: Decl.h:915
const Formula & makeAtomRef(Atom A)
Returns a formula for the variable A.
Definition: Arena.cpp:25
std::enable_if_t< std::is_base_of< StorageLocation, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of StorageLocation), forwarding args to the constructor,...
Definition: Arena.h:34
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
StorageLocation & getStableStorageLocation(const VarDecl &D)
Returns a stable storage location for D.
Atom joinFlowConditions(Atom FirstToken, Atom SecondToken)
Creates a new flow condition that represents the disjunction of the flow conditions identified by Fir...
void addFlowConditionConstraint(Atom Token, const Formula &Constraint)
Adds Constraint to the flow condition identified by Token.
Atom forkFlowCondition(Atom Token)
Creates a new flow condition with the same constraints as the flow condition identified by Token and ...
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
bool flowConditionImplies(Atom Token, const Formula &)
Returns true if and only if the constraints of the flow condition identified by Token imply that Val ...
StorageLocation & createStorageLocation(QualType Type)
Returns a new storage location appropriate for Type.
FieldSet getModeledFields(QualType Type)
Returns the fields of Type, limited to the set of fields modeled by this context.
LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token, llvm::raw_ostream &OS=llvm::dbgs())
Supplements Environment with non-standard comparison and join operations.
virtual ComparisonResult compare(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2)
Returns: Same: Val1 is equivalent to Val2, according to the model.
virtual Value * widen(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv)
This function may widen the current value – replace it with an approximation that can reach a fixed p...
virtual bool merge(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &MergedVal, Environment &MergedEnv)
Modifies MergedVal to approximate both Val1 and Val2.
Holds the state of the program (store and heap) at a given program point.
static Environment join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model)
Joins two environments by taking the intersection of storage locations and values that are stored in ...
void addToFlowCondition(const Formula &)
Record a fact that must be true if this point in the program is reached.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
LatticeJoinEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
RecordStorageLocation * getThisPointeeStorageLocation() const
Returns the storage location assigned to the this pointee in the environment or null if the this poin...
Environment pushCall(const CallExpr *Call) const
Creates and returns an environment to use for an inline analysis of the callee.
StorageLocation * getStorageLocation(const ValueDecl &D) const
Returns the storage location assigned to D in the environment, or null if D isn't assigned a storage ...
LLVM_DUMP_METHOD void dump() const
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Environment fork() const
Returns a new environment that is a copy of this one.
void popCall(const CallExpr *Call, const Environment &CalleeEnv)
Moves gathered information back into this from a CalleeEnv created via pushCall.
Environment(DataflowAnalysisContext &DACtx)
Creates an environment that uses DACtx to store objects that encompass the state of a program.
bool equivalentTo(const Environment &Other, Environment::ValueModel &Model) const
Returns true if and only if the environment is equivalent to Other, i.e the two environments:
BoolValue & makeAtomicBoolValue() const
Returns an atomic boolean value.
Value * getValue(const StorageLocation &Loc) const
Returns the value assigned to Loc in the environment or null if Loc isn't assigned a value in the env...
bool canDescend(unsigned MaxDepth, const DeclContext *Callee) const
Returns whether this Environment can be extended to analyze the given Callee (i.e.
StorageLocation & createObject(QualType Ty, const Expr *InitExpr=nullptr)
Creates an object (i.e.
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue)
Returns the location of the result object for a record-type prvalue.
void setStorageLocation(const ValueDecl &D, StorageLocation &Loc)
Assigns Loc as the storage location of D in the environment.
void removeDecl(const ValueDecl &D)
Removes the location assigned to D in the environment.
Value * createValue(QualType Type)
Creates a value appropriate for Type, if Type is supported, otherwise returns null.
void setValue(const StorageLocation &Loc, Value &Val)
Assigns Val as the value of Loc in the environment.
Atom getFlowConditionToken() const
Returns a boolean variable that identifies the flow condition (FC).
bool flowConditionImplies(const Formula &) const
Returns true if the formula is always true when this point is reached.
std::enable_if_t< std::is_base_of< Value, T >::value, T & > create(Args &&...args)
Creates a T (some subclass of Value), forwarding args to the constructor, and returns a reference to ...
Models a symbolic pointer. Specifically, any value of type T*.
Definition: Value.h:168
A storage location for a record (struct, class, or union).
Models a value of struct or class type.
Definition: Value.h:216
Base class for elements of the local variable store and of the heap.
Base class for all values computed by abstract interpretation.
Definition: Value.h:33
Kind getKind() const
Definition: Value.h:56
llvm::MapVector< Key, Value * > joinKeyToValueMap(const llvm::MapVector< Key, Value * > &Map1, const llvm::MapVector< Key, Value * > &Map2, const Environment &Env1, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
static Value & widenDistinctValues(QualType Type, Value &Prev, const Environment &PrevEnv, Value &Current, Environment &CurrentEnv, Environment::ValueModel &Model)
llvm::DenseMap< K, V > intersectDenseMaps(const llvm::DenseMap< K, V > &Map1, const llvm::DenseMap< K, V > &Map2)
Returns a map consisting of key-value entries that are present in both maps.
bool declToLocConsistent(const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc1, const llvm::DenseMap< const ValueDecl *, StorageLocation * > &DeclToLoc2)
Returns whether all declarations that DeclToLoc1 and DeclToLoc2 have in common map to the same storag...
static void getFieldsGlobalsAndFuncs(const Decl &D, FieldSet &Fields, llvm::DenseSet< const VarDecl * > &Vars, llvm::DenseSet< const FunctionDecl * > &Funcs)
bool compareKeyToValueMaps(const llvm::MapVector< Key, Value * > &Map1, const llvm::MapVector< Key, Value * > &Map2, const Environment &Env1, const Environment &Env2, Environment::ValueModel &Model)
static bool equateUnknownValues(Value::Kind K)
bool areEquivalentValues(const Value &Val1, const Value &Val2)
An equivalence relation for values.
Definition: Value.cpp:29
static constexpr int MaxCompositeValueDepth
LatticeJoinEffect
Effect indicating whether a lattice join operation resulted in a new value.
static Value * mergeDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment &MergedEnv, Environment::ValueModel &Model)
Attempts to merge distinct values Val1 and Val2 in Env1 and Env2, respectively, of the same type Type...
llvm::SmallSetVector< const FieldDecl *, 4 > FieldSet
A set of FieldDecl *.
static constexpr int MaxCompositeValueSize
static void insertIfFunction(const Decl &D, llvm::DenseSet< const FunctionDecl * > &Funcs)
static MemberExpr * getMemberForAccessor(const CXXMemberCallExpr &C)
llvm::MapVector< Key, Value * > widenKeyToValueMap(const llvm::MapVector< Key, Value * > &CurMap, const llvm::MapVector< Key, Value * > &PrevMap, Environment &CurEnv, const Environment &PrevEnv, Environment::ValueModel &Model, LatticeJoinEffect &Effect)
RecordStorageLocation * getImplicitObjectLocation(const CXXMemberCallExpr &MCE, const Environment &Env)
Returns the storage location for the implicit object of a CXXMemberCallExpr, or null if none is defin...
const Expr & ignoreCFGOmittedNodes(const Expr &E)
Skip past nodes that the CFG does not emit.
std::vector< FieldDecl * > getFieldsForInitListExpr(const RecordDecl *RD)
Returns the fields of RD that are initialized by an InitListExpr, in the order in which they appear i...
static bool compareDistinctValues(QualType Type, Value &Val1, const Environment &Env1, Value &Val2, const Environment &Env2, Environment::ValueModel &Model)
RecordStorageLocation * getBaseObjectLocation(const MemberExpr &ME, const Environment &Env)
Returns the storage location for the base object of a MemberExpr, or null if none is defined in the e...
static void insertIfGlobal(const Decl &D, llvm::DenseSet< const VarDecl * > &Vars)
Initializes a global storage value.
RecordValue & refreshRecordValue(RecordStorageLocation &Loc, Environment &Env)
Associates a new RecordValue with Loc and returns the new value.
@ C
Languages that the frontend can parse and compile.
@ Result
The result type of a method or function.