clang 24.0.0git
DataflowEnvironment.h
Go to the documentation of this file.
1//===-- DataflowEnvironment.h -----------------------------------*- 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#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
16#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
17
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclBase.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/ExprCXX.h"
22#include "clang/AST/Type.h"
30#include "llvm/ADT/DenseMap.h"
31#include "llvm/ADT/DenseSet.h"
32#include "llvm/ADT/MapVector.h"
33#include "llvm/Support/Compiler.h"
34#include "llvm/Support/ErrorHandling.h"
35#include <cassert>
36#include <memory>
37#include <optional>
38#include <type_traits>
39#include <utility>
40#include <vector>
41
42namespace clang {
43namespace dataflow {
44
45/// Indicates the result of a tentative comparison.
51
52/// The result of a `widen` operation.
54 /// Non-null pointer to a potentially widened version of the input value.
56 /// Whether `V` represents a "change" (that is, a different value) with
57 /// respect to the previous value in the sequence.
59};
60
61/// Holds the state of the program (store and heap) at a given program point.
62///
63/// WARNING: Symbolic values that are created by the environment for static
64/// local and global variables are not currently invalidated on function calls.
65/// This is unsound and should be taken into account when designing dataflow
66/// analyses.
68public:
69 /// Supplements `Environment` with non-standard comparison and join
70 /// operations.
71 class ValueModel {
72 public:
73 virtual ~ValueModel() = default;
74
75 /// Returns:
76 /// `Same`: `Val1` is equivalent to `Val2`, according to the model.
77 /// `Different`: `Val1` is distinct from `Val2`, according to the model.
78 /// `Unknown`: The model can't determine a relationship between `Val1` and
79 /// `Val2`.
80 ///
81 /// Requirements:
82 ///
83 /// `Val1` and `Val2` must be distinct.
84 ///
85 /// `Val1` and `Val2` must model values of type `Type`.
86 ///
87 /// `Val1` and `Val2` must be assigned to the same storage location in
88 /// `Env1` and `Env2` respectively.
90 const Environment &Env1, const Value &Val2,
91 const Environment &Env2) {
92 // FIXME: Consider adding `QualType` to `Value` and removing the `Type`
93 // argument here.
95 }
96
97 /// Modifies `JoinedVal` to approximate both `Val1` and `Val2`. This should
98 /// obey the properties of a lattice join.
99 ///
100 /// `Env1` and `Env2` can be used to query child values and path condition
101 /// implications of `Val1` and `Val2` respectively.
102 ///
103 /// Requirements:
104 ///
105 /// `Val1` and `Val2` must be distinct.
106 ///
107 /// `Val1`, `Val2`, and `JoinedVal` must model values of type `Type`.
108 ///
109 /// `Val1` and `Val2` must be assigned to the same storage location in
110 /// `Env1` and `Env2` respectively.
111 virtual void join(QualType Type, const Value &Val1, const Environment &Env1,
112 const Value &Val2, const Environment &Env2,
113 Value &JoinedVal, Environment &JoinedEnv) {}
114
115 /// This function may widen the current value -- replace it with an
116 /// approximation that can reach a fixed point more quickly than iterated
117 /// application of the transfer function alone. The previous value is
118 /// provided to inform the choice of widened value. The function must also
119 /// serve as a comparison operation, by indicating whether the widened value
120 /// is equivalent to the previous value.
121 ///
122 /// Returns one of the folowing:
123 /// * `std::nullopt`, if this value is not of interest to the
124 /// model.
125 /// * A `WidenResult` with:
126 /// * A non-null `Value *` that points either to `Current` or a widened
127 /// version of `Current`. This value must be consistent with
128 /// the flow condition of `CurrentEnv`. We particularly caution
129 /// against using `Prev`, which is rarely consistent.
130 /// * A `LatticeEffect` indicating whether the value should be
131 /// considered a new value (`Changed`) or one *equivalent* (if not
132 /// necessarily equal) to `Prev` (`Unchanged`).
133 ///
134 /// `PrevEnv` and `CurrentEnv` can be used to query child values and path
135 /// condition implications of `Prev` and `Current`, respectively.
136 ///
137 /// Requirements:
138 ///
139 /// `Prev` and `Current` must model values of type `Type`.
140 ///
141 /// `Prev` and `Current` must be assigned to the same storage location in
142 /// `PrevEnv` and `CurrentEnv`, respectively.
143 virtual std::optional<WidenResult> widen(QualType Type, Value &Prev,
144 const Environment &PrevEnv,
145 Value &Current,
146 Environment &CurrentEnv) {
147 // The default implementation reduces to just comparison, since comparison
148 // is required by the API, even if no widening is performed.
149 switch (compare(Type, Prev, PrevEnv, Current, CurrentEnv)) {
151 return std::nullopt;
153 return WidenResult{&Current, LatticeEffect::Unchanged};
155 return WidenResult{&Current, LatticeEffect::Changed};
156 }
157 llvm_unreachable("all cases in switch covered");
158 }
159 };
160
161 /// Abstract interface for modeling boolean formulas and path conditions in
162 /// an `Environment`.
163 class BoolModel {
164 public:
165 explicit BoolModel(BoolModelKind K) : K(K) {}
166 virtual ~BoolModel() = default;
167
168 BoolModelKind getKind() const { return K; }
169
170 /// Returns an exact copy of this model state.
171 virtual std::unique_ptr<BoolModel> clone() const = 0;
172
173 /// If this model state was cloned, updates this model state to be a fork
174 /// so that mutations to either model state will not affect the other.
175 virtual void onFork() = 0;
176
177 /// Records a fact that must be true if this point in the program is
178 /// reached.
179 virtual void assume(const Formula &F) = 0;
180
181 /// Returns true if `F` is always true when this point is reached.
182 /// Returns false if the formula may be false (or the flow condition isn't
183 /// sufficiently precise to prove that it is true).
184 /// See `Environment::proves` for more details.
185 virtual bool proves(const Formula &F) const = 0;
186
187 /// Returns true if `F` may be true when this point is reached.
188 /// Returns false if the formula is always false when this point is reached
189 /// (or the flow condition is overly constraining).
190 /// See `Environment::allows` for more details.
191 virtual bool allows(const Formula &F) const = 0;
192
193 /// Joins two distinct boolean values `Val1` (from `Model1`) and `Val2`
194 /// (from `Model2`) into `JoinedEnv`.
195 /// Requires `Model1` and `Model2` to have the same kind as `this`.
196 virtual BoolValue &joinBoolValues(BoolValue &Val1, const BoolModel &Model1,
197 BoolValue &Val2, const BoolModel &Model2,
198 Environment &JoinedEnv) = 0;
199
200 /// Populates `this` with the join of `ModelA` and `ModelB`.
201 ///
202 /// Requirements: `ModelA` and `ModelB` must have the same kind as `this`.
203 virtual void join(const BoolModel &ModelA, const BoolModel &ModelB) = 0;
204
205 /// Widens `this` with respect to `PrevModel` and returns whether the state
206 /// changed relative to `PrevModel`.
207 ///
208 /// Requirements: `PrevModel` must have the same kind as `this`.
209 virtual LatticeEffect widen(const BoolModel &PrevModel) = 0;
210
211 /// Returns whether this boolean model state is equivalent to `Other` for
212 /// convergence purposes.
213 /// Requirements: `Other` must have the same kind as `this`.
214 virtual bool isEquivalentTo(const BoolModel &Other) const = 0;
215
216 /// Returns the flow condition token (only meaningful for SAT-based models).
217 virtual Atom getFlowConditionToken() const = 0;
218
219 virtual void dump(raw_ostream &OS) const = 0;
220
221 private:
223 };
224
225 /// Creates an environment that uses `DACtx` to store objects that encompass
226 /// the state of a program. `FlowConditionToken` sets the flow condition
227 /// associated with the environment (requires `DACtx.getOptions().BoolModel ==
228 /// BoolModelKind::SAT`). Generally, new environments should be initialized
229 /// using one of the other constructors. This constructor is for specialized
230 /// use, such as deserialization.
231 Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken);
232
233 /// Creates an environment that uses `DACtx` to store objects that encompass
234 /// the state of a program. Initializes the boolean model configured in
235 /// `DACtx.getOptions().BoolModel`.
236 explicit Environment(DataflowAnalysisContext &DACtx);
237
238 /// Creates an environment that uses `DACtx` to store objects that encompass
239 /// the state of a program, with `S` as the statement to analyze.
241 InitialTargetStmt = &S;
242 }
243
244 /// Creates an environment that uses `DACtx` to store objects that encompass
245 /// the state of a program, with `FD` as the function to analyze.
246 ///
247 /// Requirements:
248 ///
249 /// The function must have a body, i.e.
250 /// `FunctionDecl::doesThisDecalarationHaveABody()` must be true.
252 : Environment(DACtx, *FD.getBody()) {
253 assert(FD.doesThisDeclarationHaveABody());
254 InitialTargetFunc = &FD;
255 }
256
257 // Copy-constructor is private, Environments should not be copied. See fork().
259
262
263 /// Assigns storage locations and values to all parameters, captures, global
264 /// variables, fields and functions referenced in the `Stmt` or `FunctionDecl`
265 /// passed to the constructor.
266 ///
267 /// If no `Stmt` or `FunctionDecl` was supplied, this function does nothing.
268 void initialize();
269
270 /// Returns a new environment that is a copy of this one.
271 ///
272 /// The state of the program is initially the same, but can be mutated without
273 /// affecting the original.
274 ///
275 /// However the original should not be further mutated, as this may interfere
276 /// with the fork. (In practice, values are stored independently, but the
277 /// forked flow condition references the original).
278 Environment fork() const;
279
280 /// Creates and returns an environment to use for an inline analysis of the
281 /// callee. Uses the storage location from each argument in the `Call` as the
282 /// storage location for the corresponding parameter in the callee.
283 ///
284 /// Requirements:
285 ///
286 /// The callee of `Call` must be a `FunctionDecl`.
287 ///
288 /// The body of the callee must not reference globals.
289 ///
290 /// The arguments of `Call` must map 1:1 to the callee's parameters.
291 Environment pushCall(const CallExpr *Call) const;
293
294 /// Moves gathered information back into `this` from a `CalleeEnv` created via
295 /// `pushCall`.
296 void popCall(const CallExpr *Call, const Environment &CalleeEnv);
297 void popCall(const CXXConstructExpr *Call, const Environment &CalleeEnv);
298
299 /// Returns true if and only if the environment is equivalent to `Other`, i.e
300 /// the two environments:
301 /// - have the same mappings from declarations to storage locations,
302 /// - have the same mappings from expressions to storage locations,
303 /// - have the same or equivalent (according to `Model`) values assigned to
304 /// the same storage locations.
305 ///
306 /// Requirements:
307 ///
308 /// `Other` and `this` must use the same `DataflowAnalysisContext`.
309 bool equivalentTo(const Environment &Other,
310 Environment::ValueModel &Model) const;
311
312 /// How to treat expression state (`ExprToLoc` and `ExprToVal`) in a join.
313 /// If the join happens within a full expression, expression state should be
314 /// kept; otherwise, we can discard it.
319
320 /// Joins two environments by taking the intersection of storage locations and
321 /// values that are stored in them. Distinct values that are assigned to the
322 /// same storage locations in `EnvA` and `EnvB` are merged using `Model`.
323 ///
324 /// Requirements:
325 ///
326 /// `EnvA` and `EnvB` must use the same `DataflowAnalysisContext`.
327 static Environment join(const Environment &EnvA, const Environment &EnvB,
329 ExprJoinBehavior ExprBehavior);
330
331 /// Returns a value that approximates both `Val1` and `Val2`, or null if no
332 /// such value can be produced.
333 ///
334 /// `Env1` and `Env2` can be used to query child values and path condition
335 /// implications of `Val1` and `Val2` respectively. The joined value will be
336 /// produced in `JoinedEnv`.
337 ///
338 /// Requirements:
339 ///
340 /// `Val1` and `Val2` must model values of type `Type`.
341 static Value *joinValues(QualType Ty, Value *Val1, const Environment &Env1,
342 Value *Val2, const Environment &Env2,
343 Environment &JoinedEnv,
345
346 /// Joins two distinct boolean values `Val1` (from `Env1`) and `Val2` (from
347 /// `Env2`) into this environment.
349 BoolValue &Val2, const Environment &Env2) {
350 return BoolState->joinBoolValues(Val1, *Env1.BoolState, Val2,
351 *Env2.BoolState, *this);
352 }
353
354 /// Widens the environment point-wise, using `PrevEnv` as needed to inform the
355 /// approximation.
356 ///
357 /// Requirements:
358 ///
359 /// `PrevEnv` must be the immediate previous version of the environment.
360 /// `PrevEnv` and `this` must use the same `DataflowAnalysisContext`.
361 LatticeEffect widen(const Environment &PrevEnv,
363
364 // FIXME: Rename `createOrGetStorageLocation` to `getOrCreateStorageLocation`,
365 // `getStableStorageLocation`, or something more appropriate.
366
367 /// Creates a storage location appropriate for `Type`. Does not assign a value
368 /// to the returned storage location in the environment.
369 ///
370 /// Requirements:
371 ///
372 /// `Type` must not be null.
374
375 /// Creates a storage location for `D`. Does not assign the returned storage
376 /// location to `D` in the environment. Does not assign a value to the
377 /// returned storage location in the environment.
379
380 /// Creates a storage location for `E`. Does not assign the returned storage
381 /// location to `E` in the environment. Does not assign a value to the
382 /// returned storage location in the environment.
384
385 /// Assigns `Loc` as the storage location of `D` in the environment.
386 ///
387 /// Requirements:
388 ///
389 /// `D` must not already have a storage location in the environment.
390 void setStorageLocation(const ValueDecl &D, StorageLocation &Loc);
391
392 /// Returns the storage location assigned to `D` in the environment, or null
393 /// if `D` isn't assigned a storage location in the environment.
395
396 /// Removes the location assigned to `D` in the environment (if any).
397 void removeDecl(const ValueDecl &D);
398
399 /// Assigns `Loc` as the storage location of the glvalue `E` in the
400 /// environment.
401 ///
402 /// Requirements:
403 ///
404 /// `E` must not be assigned a storage location in the environment.
405 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
406 void setStorageLocation(const Expr &E, StorageLocation &Loc);
407
408 /// Returns the storage location assigned to the glvalue `E` in the
409 /// environment, or null if `E` isn't assigned a storage location in the
410 /// environment.
411 ///
412 /// Requirements:
413 /// `E` must be a glvalue or a `BuiltinType::BuiltinFn`
414 StorageLocation *getStorageLocation(const Expr &E) const;
415
416 /// Returns the result of casting `getStorageLocation(...)` to a subclass of
417 /// `StorageLocation` (using `cast_or_null<T>`).
418 /// This assert-fails if the result of `getStorageLocation(...)` is not of
419 /// type `T *`; if the storage location is not guaranteed to have type `T *`,
420 /// consider using `dyn_cast_or_null<T>(getStorageLocation(...))` instead.
421 template <typename T>
422 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
423 get(const ValueDecl &D) const {
424 return cast_or_null<T>(getStorageLocation(D));
425 }
426 template <typename T>
427 std::enable_if_t<std::is_base_of_v<StorageLocation, T>, T *>
428 get(const Expr &E) const {
429 return cast_or_null<T>(getStorageLocation(E));
430 }
431
432 /// Returns the storage location assigned to the `this` pointee in the
433 /// environment or null if the `this` pointee has no assigned storage location
434 /// in the environment.
435 /// If you want to look up the storage location for a specific `CXXThisExpr`,
436 /// use the overload that takes a `CXXThisExpr`.
438 return ThisPointeeLoc;
439 }
440
441 /// Returns the storage location assigned to the `this` pointee in the
442 /// environment given a specific `CXXThisExpr`. Returns null if the `this`
443 /// pointee has no assigned storage location in the environment.
444 /// Note that `this` can be used in a non-member context, e.g.:
445 ///
446 /// \code
447 /// struct S {
448 /// int x;
449 /// int y = this->x;
450 /// };
451 /// int foo() {
452 /// return S{10}.y; // will have a `this` for initializing `S::y`.
453 /// }
454 /// \endcode
457 auto It = ThisExprOverrides->find(&ThisExpr);
458 if (It == ThisExprOverrides->end())
459 return ThisPointeeLoc;
460 return It->second;
461 }
462
463 /// Sets the storage location assigned to the `this` pointee in the
464 /// environment.
466 ThisPointeeLoc = &Loc;
467 }
468
469 /// Returns the location of the result object for a record-type prvalue.
470 ///
471 /// In C++, prvalues of record type serve only a limited purpose: They can
472 /// only be used to initialize a result object (e.g. a variable or a
473 /// temporary). This function returns the location of that result object.
474 ///
475 /// When creating a prvalue of record type, we already need the storage
476 /// location of the result object to pass in `this`, even though prvalues are
477 /// otherwise not associated with storage locations.
478 ///
479 /// Requirements:
480 /// `E` must be a prvalue of record type.
482 getResultObjectLocation(const Expr &RecordPRValue) const;
483
484 /// Returns the return value of the function currently being analyzed.
485 /// This can be null if:
486 /// - The function has a void return type
487 /// - No return value could be determined for the function, for example
488 /// because it calls a function without a body.
489 ///
490 /// Requirements:
491 /// The current analysis target must be a function and must have a
492 /// non-reference return type.
494 assert(getCurrentFunc() != nullptr &&
495 !getCurrentFunc()->getReturnType()->isReferenceType());
496 return ReturnVal;
497 }
498
499 /// Returns the storage location for the reference returned by the function
500 /// currently being analyzed. This can be null if the function doesn't return
501 /// a single consistent reference.
502 ///
503 /// Requirements:
504 /// The current analysis target must be a function and must have a reference
505 /// return type.
507 assert(getCurrentFunc() != nullptr &&
508 getCurrentFunc()->getReturnType()->isReferenceType());
509 return ReturnLoc;
510 }
511
512 /// Sets the return value of the function currently being analyzed.
513 ///
514 /// Requirements:
515 /// The current analysis target must be a function and must have a
516 /// non-reference return type.
518 assert(getCurrentFunc() != nullptr &&
519 !getCurrentFunc()->getReturnType()->isReferenceType());
520 ReturnVal = Val;
521 }
522
523 /// Sets the storage location for the reference returned by the function
524 /// currently being analyzed.
525 ///
526 /// Requirements:
527 /// The current analysis target must be a function and must have a reference
528 /// return type.
530 assert(getCurrentFunc() != nullptr &&
531 getCurrentFunc()->getReturnType()->isReferenceType());
532 ReturnLoc = Loc;
533 }
534
535 /// Returns a pointer value that represents a null pointer. Calls with
536 /// `PointeeType` that are canonically equivalent will return the same result.
538
539 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
540 /// returns null.
541 ///
542 /// If `Type` is a pointer or reference type, creates all the necessary
543 /// storage locations and values for indirections until it finds a
544 /// non-pointer/non-reference type.
545 ///
546 /// If `Type` is one of the following types, this function will always return
547 /// a non-null pointer:
548 /// - `bool`
549 /// - Any integer type
550 ///
551 /// Requirements:
552 ///
553 /// - `Type` must not be null.
554 /// - `Type` must not be a reference type or record type.
556
557 /// Creates an object (i.e. a storage location with an associated value) of
558 /// type `Ty`. If `InitExpr` is non-null and has a value associated with it,
559 /// initializes the object with this value. Otherwise, initializes the object
560 /// with a value created using `createValue()`.
561 StorageLocation &createObject(QualType Ty, const Expr *InitExpr = nullptr) {
562 return createObjectInternal(nullptr, Ty, InitExpr);
563 }
564
565 /// Creates an object for the variable declaration `D`. If `D` has an
566 /// initializer and this initializer is associated with a value, initializes
567 /// the object with this value. Otherwise, initializes the object with a
568 /// value created using `createValue()`. Uses the storage location returned by
569 /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
571 return createObjectInternal(&D, D.getType(), D.getInit());
572 }
573
574 /// Creates an object for the variable declaration `D`. If `InitExpr` is
575 /// non-null and has a value associated with it, initializes the object with
576 /// this value. Otherwise, initializes the object with a value created using
577 /// `createValue()`. Uses the storage location returned by
578 /// `DataflowAnalysisContext::getStableStorageLocation(D)`.
579 StorageLocation &createObject(const ValueDecl &D, const Expr *InitExpr) {
580 return createObjectInternal(&D, D.getType(), InitExpr);
581 }
582
583 /// Initializes the fields (including synthetic fields) of `Loc` with values,
584 /// unless values of the field type are not supported or we hit one of the
585 /// limits at which we stop producing values.
586 /// If a field already has a value, that value is preserved.
587 /// If `Type` is provided, initializes only those fields that are modeled for
588 /// `Type`; this is intended for use in cases where `Loc` is a derived type
589 /// and we only want to initialize the fields of a base type.
594
595 /// Assigns `Val` as the value of `Loc` in the environment.
596 ///
597 /// Requirements:
598 ///
599 /// `Loc` must not be a `RecordStorageLocation`.
600 void setValue(const StorageLocation &Loc, Value &Val);
601
602 /// Clears any association between `Loc` and a value in the environment.
603 void clearValue(const StorageLocation &Loc) { LocToVal.erase(&Loc); }
604
605 /// Assigns `Val` as the value of the prvalue `E` in the environment.
606 ///
607 /// Requirements:
608 ///
609 /// - `E` must be a prvalue.
610 /// - `E` must not have record type.
611 void setValue(const Expr &E, Value &Val);
612
613 /// Returns the value assigned to `Loc` in the environment or null if `Loc`
614 /// isn't assigned a value in the environment.
615 ///
616 /// Requirements:
617 ///
618 /// `Loc` must not be a `RecordStorageLocation`.
619 Value *getValue(const StorageLocation &Loc) const;
620
621 /// Equivalent to `getValue(getStorageLocation(D))` if `D` is assigned a
622 /// storage location in the environment, otherwise returns null.
623 ///
624 /// Requirements:
625 ///
626 /// `D` must not have record type.
627 Value *getValue(const ValueDecl &D) const;
628
629 /// Equivalent to `getValue(getStorageLocation(E, SP))` if `E` is assigned a
630 /// storage location in the environment, otherwise returns null.
631 Value *getValue(const Expr &E) const;
632
633 /// Returns the result of casting `getValue(...)` to a subclass of `Value`
634 /// (using `cast_or_null<T>`).
635 /// This assert-fails if the result of `getValue(...)` is not of type `T *`;
636 /// if the value is not guaranteed to have type `T *`, consider using
637 /// `dyn_cast_or_null<T>(getValue(...))` instead.
638 template <typename T>
639 std::enable_if_t<std::is_base_of_v<Value, T>, T *>
640 get(const StorageLocation &Loc) const {
641 return cast_or_null<T>(getValue(Loc));
642 }
643 template <typename T>
644 std::enable_if_t<std::is_base_of_v<Value, T>, T *>
645 get(const ValueDecl &D) const {
646 return cast_or_null<T>(getValue(D));
647 }
648 template <typename T>
649 std::enable_if_t<std::is_base_of_v<Value, T>, T *> get(const Expr &E) const {
650 return cast_or_null<T>(getValue(E));
651 }
652
653 // FIXME: should we deprecate the following & call arena().create() directly?
654
655 /// Creates a `T` (some subclass of `Value`), forwarding `args` to the
656 /// constructor, and returns a reference to it.
657 ///
658 /// The analysis context takes ownership of the created object. The object
659 /// will be destroyed when the analysis context is destroyed.
660 template <typename T, typename... Args>
661 std::enable_if_t<std::is_base_of<Value, T>::value, T &>
662 create(Args &&...args) {
663 return arena().create<T>(std::forward<Args>(args)...);
664 }
665
666 /// Returns a symbolic integer value that models an integer literal equal to
667 /// `Value`
669 return arena().makeIntLiteral(Value);
670 }
671
672 /// Returns a symbolic boolean value that models a boolean literal equal to
673 /// `Value`
675 return arena().makeBoolValue(arena().makeLiteral(Value));
676 }
677
678 /// Returns an atomic boolean value.
680 return arena().makeAtomValue();
681 }
682
683 /// Returns a unique instance of boolean Top.
685 return arena().makeTopValue();
686 }
687
688 /// Returns a boolean value that represents the conjunction of `LHS` and
689 /// `RHS`. Subsequent calls with the same arguments, regardless of their
690 /// order, will return the same result. If the given boolean values represent
691 /// the same value, the result will be the value itself.
693 return arena().makeBoolValue(
694 arena().makeAnd(LHS.formula(), RHS.formula()));
695 }
696
697 /// Returns a boolean value that represents the disjunction of `LHS` and
698 /// `RHS`. Subsequent calls with the same arguments, regardless of their
699 /// order, will return the same result. If the given boolean values represent
700 /// the same value, the result will be the value itself.
701 BoolValue &makeOr(BoolValue &LHS, BoolValue &RHS) const {
702 return arena().makeBoolValue(
703 arena().makeOr(LHS.formula(), RHS.formula()));
704 }
705
706 /// Returns a boolean value that represents the negation of `Val`. Subsequent
707 /// calls with the same argument will return the same result.
709 return arena().makeBoolValue(arena().makeNot(Val.formula()));
710 }
711
712 /// Returns a boolean value represents `LHS` => `RHS`. Subsequent calls with
713 /// the same arguments, will return the same result. If the given boolean
714 /// values represent the same value, the result will be a value that
715 /// represents the true boolean literal.
717 return arena().makeBoolValue(
718 arena().makeImplies(LHS.formula(), RHS.formula()));
719 }
720
721 /// Returns a boolean value represents `LHS` <=> `RHS`. Subsequent calls with
722 /// the same arguments, regardless of their order, will return the same
723 /// result. If the given boolean values represent the same value, the result
724 /// will be a value that represents the true boolean literal.
726 return arena().makeBoolValue(
727 arena().makeEquals(LHS.formula(), RHS.formula()));
728 }
729
730 /// Returns a boolean variable that identifies the flow condition (FC).
731 ///
732 /// The flow condition is a set of facts that are necessarily true when the
733 /// program reaches the current point, expressed as boolean formulas.
734 /// The flow condition token is equivalent to the AND of these facts.
735 ///
736 /// These may e.g. constrain the value of certain variables. A pointer
737 /// variable may have a consistent modeled PointerValue throughout, but at a
738 /// given point the Environment may tell us that the value must be non-null.
739 ///
740 /// The FC is necessary but not sufficient for this point to be reachable.
741 /// In particular, where the FC token appears in flow conditions of successor
742 /// environments, it means "point X may have been reached", not
743 /// "point X was reached".
745 return BoolState->getFlowConditionToken();
746 }
747
748 /// Record a fact that must be true if this point in the program is reached.
749 void assume(const Formula &);
750
751 /// Returns true if the formula is always true when this point is reached.
752 /// Returns false if the formula may be false (or the flow condition isn't
753 /// sufficiently precise to prove that it is true) or if the solver times out.
754 ///
755 /// Note that there is an asymmetry between this function and `allows()` in
756 /// that they both return false if the solver times out. The assumption is
757 /// that if `proves()` or `allows()` returns true, this will result in a
758 /// diagnostic, and we want to bias towards false negatives in the case where
759 /// the solver times out.
760 bool proves(const Formula &) const;
761
762 /// Returns true if the formula may be true when this point is reached.
763 /// Returns false if the formula is always false when this point is reached
764 /// (or the flow condition is overly constraining) or if the solver times out.
765 bool allows(const Formula &) const;
766
767 /// Returns the function currently being analyzed, or null if the code being
768 /// analyzed isn't part of a function.
770 return CallStack.empty() ? InitialTargetFunc : CallStack.back();
771 }
772
773 /// Returns the size of the call stack, not counting the initial analysis
774 /// target.
775 size_t callStackSize() const { return CallStack.size(); }
776
777 /// Returns whether this `Environment` can be extended to analyze the given
778 /// `Callee` (i.e. if `pushCall` can be used).
779 /// Recursion is not allowed. `MaxDepth` is the maximum size of the call stack
780 /// (i.e. the maximum value that `callStackSize()` may assume after the call).
781 bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const;
782
783 /// Returns the `DataflowAnalysisContext` used by the environment.
785
786 Arena &arena() const { return DACtx->arena(); }
787
788 LLVM_DUMP_METHOD void dump() const;
789 LLVM_DUMP_METHOD void dump(raw_ostream &OS) const;
790
791private:
792 using PrValueToResultObject =
793 llvm::DenseMap<const Expr *, RecordStorageLocation *>;
794 using ThisExprOverridesMap =
795 llvm::DenseMap<const CXXThisExpr *, RecordStorageLocation *>;
796
797 // The copy-constructor is for use in fork() and pushCall() only.
798 Environment(const Environment &);
799
800 /// Creates a value appropriate for `Type`, if `Type` is supported, otherwise
801 /// return null.
802 ///
803 /// Recursively initializes storage locations and values until it sees a
804 /// self-referential pointer or reference type. `Visited` is used to track
805 /// which types appeared in the reference/pointer chain in order to avoid
806 /// creating a cyclic dependency with self-referential pointers/references.
807 ///
808 /// Requirements:
809 ///
810 /// `Type` must not be null.
811 Value *createValueUnlessSelfReferential(QualType Type,
812 llvm::DenseSet<QualType> &Visited,
813 int Depth, int &CreatedValuesCount);
814
815 /// Creates a storage location for `Ty`. Also creates and associates a value
816 /// with the storage location, unless values of this type are not supported or
817 /// we hit one of the limits at which we stop producing values (controlled by
818 /// `Visited`, `Depth`, and `CreatedValuesCount`).
819 StorageLocation &createLocAndMaybeValue(QualType Ty,
820 llvm::DenseSet<QualType> &Visited,
821 int Depth, int &CreatedValuesCount);
822
823 /// Initializes the fields (including synthetic fields) of `Loc` with values,
824 /// unless values of the field type are not supported or we hit one of the
825 /// limits at which we stop producing values (controlled by `Visited`,
826 /// `Depth`, and `CreatedValuesCount`). If `Type` is different from
827 /// `Loc.getType()`, initializes only those fields that are modeled for
828 /// `Type`.
830 llvm::DenseSet<QualType> &Visited, int Depth,
831 int &CreatedValuesCount);
832
833 /// Shared implementation of `createObject()` overloads.
834 /// `D` and `InitExpr` may be null.
835 StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
836 const Expr *InitExpr);
837
838 /// Shared implementation of `pushCall` overloads. Note that unlike
839 /// `pushCall`, this member is invoked on the environment of the callee, not
840 /// of the caller.
841 void pushCallInternal(const FunctionDecl *FuncDecl,
843
844 /// Assigns storage locations and values to all global variables, fields
845 /// and functions in `Referenced`.
846 void initFieldsGlobalsAndFuncs(const ReferencedDecls &Referenced);
847
848 static PrValueToResultObject
849 buildResultObjectMap(DataflowAnalysisContext *DACtx,
850 const FunctionDecl *FuncDecl,
851 RecordStorageLocation *ThisPointeeLoc,
852 RecordStorageLocation *LocForRecordReturnVal);
853
854 static PrValueToResultObject
855 buildResultObjectMap(DataflowAnalysisContext *DACtx, Stmt *S,
856 RecordStorageLocation *ThisPointeeLoc,
857 RecordStorageLocation *LocForRecordReturnVal);
858
859 static ThisExprOverridesMap
860 buildThisExprOverridesMap(const FunctionDecl *FuncDecl,
861 RecordStorageLocation *ThisPointeeLoc,
862 const PrValueToResultObject &ResultObjectMap);
863
864 static ThisExprOverridesMap
865 buildThisExprOverridesMap(Stmt *S, RecordStorageLocation *ThisPointeeLoc,
866 const PrValueToResultObject &ResultObjectMap);
867
868 // `DACtx` is not null and not owned by this object.
870
871 // FIXME: move the fields `CallStack`, `ResultObjectMap`, `ReturnVal`,
872 // `ReturnLoc` and `ThisPointeeLoc` into a separate call-context object,
873 // shared between environments in the same call.
874 // https://github.com/llvm/llvm-project/issues/59005
875
876 // The stack of functions called from the initial analysis target.
877 std::vector<const FunctionDecl *> CallStack;
878
879 // Initial function to analyze, if a function was passed to the constructor.
880 // Null otherwise.
881 const FunctionDecl *InitialTargetFunc = nullptr;
882 // Top-level statement of the initial analysis target.
883 // If a function was passed to the constructor, this is its body.
884 // If a statement was passed to the constructor, this is that statement.
885 // Null if no analysis target was passed to the constructor.
886 Stmt *InitialTargetStmt = nullptr;
887
888 // Maps from prvalues of record type to their result objects. Shared between
889 // all environments for the same analysis target.
890 // FIXME: It's somewhat unsatisfactory that we have to use a `shared_ptr`
891 // here, though the cost is acceptable: The overhead of a `shared_ptr` is
892 // incurred when it is copied, and this happens only relatively rarely (when
893 // we fork the environment). The need for a `shared_ptr` will go away once we
894 // introduce a shared call-context object (see above).
895 std::shared_ptr<PrValueToResultObject> ResultObjectMap;
896
897 // The following three member variables handle various different types of
898 // return values when the current analysis target is a function.
899 // - If the return type is not a reference and not a record: Value returned
900 // by the function.
901 Value *ReturnVal = nullptr;
902 // - If the return type is a reference: Storage location of the reference
903 // returned by the function.
904 StorageLocation *ReturnLoc = nullptr;
905 // - If the return type is a record or the function being analyzed is a
906 // constructor: Storage location into which the return value should be
907 // constructed.
908 RecordStorageLocation *LocForRecordReturnVal = nullptr;
909
910 // The storage location of the `this` pointee. Should only be null if the
911 // analysis target is not a method.
912 RecordStorageLocation *ThisPointeeLoc = nullptr;
913
914 // Maps from `CXXThisExpr`s to their storage locations, if it should be
915 // different from `ThisPointeeLoc` (for example, CXXThisExpr that are
916 // under a CXXDefaultInitExpr under an InitListExpr).
917 std::shared_ptr<ThisExprOverridesMap> ThisExprOverrides;
918
919 // Maps from declarations and glvalue expression to storage locations that are
920 // assigned to them. Unlike the maps in `DataflowAnalysisContext`, these
921 // include only storage locations that are in scope for a particular basic
922 // block.
923 llvm::DenseMap<const ValueDecl *, StorageLocation *> DeclToLoc;
924 llvm::DenseMap<const Expr *, StorageLocation *> ExprToLoc;
925 // Maps from prvalue expressions and storage locations to the values that
926 // are assigned to them.
927 // We preserve insertion order so that join/widen process values in
928 // deterministic sequence. This in turn produces deterministic SAT formulas.
929 llvm::MapVector<const Expr *, Value *> ExprToVal;
930 llvm::MapVector<const StorageLocation *, Value *> LocToVal;
931
932 // The flow condition abstracted in a boolean model.
933 std::unique_ptr<BoolModel> BoolState;
934};
935
936/// Returns the storage location for the implicit object of a
937/// `CXXMemberCallExpr`, or null if none is defined in the environment.
938/// Dereferences the pointer if the member call expression was written using
939/// `->`.
940RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
941 const Environment &Env);
942
943/// Returns the storage location for the base object of a `MemberExpr`, or null
944/// if none is defined in the environment. Dereferences the pointer if the
945/// member expression was written using `->`.
946RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
947 const Environment &Env);
948
949} // namespace dataflow
950} // namespace clang
951
952#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_DATAFLOWENVIRONMENT_H
Defines the clang::Expr interface and subclasses for C++ expressions.
C Language Family Type Representation.
Represents a call to a C++ constructor.
Definition ExprCXX.h:1553
Represents a call to a member function that may be written either with member call syntax (e....
Definition ExprCXX.h:184
Represents the this expression in C++.
Definition ExprCXX.h:1159
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition Expr.h:3012
This represents one expression.
Definition Expr.h:114
Represents a function declaration or definition.
Definition Decl.h:2082
bool doesThisDeclarationHaveABody() const
Returns whether this specific declaration of the function has a body.
Definition Decl.h:2482
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3433
A (possibly-)qualified type.
Definition TypeBase.h:938
Stmt - This represents one statement.
Definition Stmt.h:85
The base class of the type hierarchy.
Definition TypeBase.h:1879
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition Decl.h:714
QualType getType() const
Definition Decl.h:725
Represents a variable declaration or definition.
Definition Decl.h:934
const Expr * getInit() const
Definition Decl.h:1393
The Arena owns the objects that model data within an analysis.
Definition Arena.h:21
IntegerValue & makeIntLiteral(llvm::APInt Value)
Returns a symbolic integer value that models an integer literal equal to Value.
Definition Arena.cpp:104
TopBoolValue & makeTopValue()
Creates a fresh Top boolean value.
Definition Arena.h:76
BoolValue & makeBoolValue(const Formula &)
Creates a BoolValue wrapping a particular formula.
Definition Arena.cpp:112
AtomicBoolValue & makeAtomValue()
Creates a fresh atom and wraps in in an AtomicBoolValue.
Definition Arena.h:71
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:36
Models a boolean.
Definition Value.h:94
const Formula & formula() const
Definition Value.h:107
Owns objects that encompass the state of a program and stores context that is used during dataflow an...
virtual void dump(raw_ostream &OS) const =0
virtual void join(const BoolModel &ModelA, const BoolModel &ModelB)=0
Populates this with the join of ModelA and ModelB.
virtual bool proves(const Formula &F) const =0
Returns true if F is always true when this point is reached.
virtual Atom getFlowConditionToken() const =0
Returns the flow condition token (only meaningful for SAT-based models).
virtual void onFork()=0
If this model state was cloned, updates this model state to be a fork so that mutations to either mod...
virtual bool isEquivalentTo(const BoolModel &Other) const =0
Returns whether this boolean model state is equivalent to Other for convergence purposes.
virtual std::unique_ptr< BoolModel > clone() const =0
Returns an exact copy of this model state.
virtual LatticeEffect widen(const BoolModel &PrevModel)=0
Widens this with respect to PrevModel and returns whether the state changed relative to PrevModel.
virtual void assume(const Formula &F)=0
Records a fact that must be true if this point in the program is reached.
virtual bool allows(const Formula &F) const =0
Returns true if F may be true when this point is reached.
virtual BoolValue & joinBoolValues(BoolValue &Val1, const BoolModel &Model1, BoolValue &Val2, const BoolModel &Model2, Environment &JoinedEnv)=0
Joins two distinct boolean values Val1 (from Model1) and Val2 (from Model2) into JoinedEnv.
Supplements Environment with non-standard comparison and join operations.
virtual std::optional< WidenResult > 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 void join(QualType Type, const Value &Val1, const Environment &Env1, const Value &Val2, const Environment &Env2, Value &JoinedVal, Environment &JoinedEnv)
Modifies JoinedVal to approximate both Val1 and Val2.
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.
Holds the state of the program (store and heap) at a given program point.
bool allows(const Formula &) const
Returns true if the formula may be true when this point is reached.
void initializeFieldsWithValues(RecordStorageLocation &Loc)
LatticeEffect widen(const Environment &PrevEnv, Environment::ValueModel &Model)
Widens the environment point-wise, using PrevEnv as needed to inform the approximation.
PointerValue & getOrCreateNullPointerValue(QualType PointeeType)
Returns a pointer value that represents a null pointer.
BoolValue & makeAnd(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value that represents the conjunction of LHS and RHS.
std::enable_if_t< std::is_base_of_v< Value, T >, T * > get(const StorageLocation &Loc) const
Returns the result of casting getValue(...) to a subclass of Value (using cast_or_null<T>).
RecordStorageLocation * getThisPointeeStorageLocation() const
Returns the storage location assigned to the this pointee in the environment or null if the this poin...
BoolValue & makeIff(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS <=> RHS.
Environment pushCall(const CallExpr *Call) const
Creates and returns an environment to use for an inline analysis of the callee.
void clearValue(const StorageLocation &Loc)
Clears any association between Loc and a value in the environment.
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
Environment(DataflowAnalysisContext &DACtx, Stmt &S)
Creates an environment that uses DACtx to store objects that encompass the state of a program,...
void setReturnValue(Value *Val)
Sets the return value of the function currently being analyzed.
Environment(Environment &&Other)=default
BoolValue & makeTopBoolValue() const
Returns a unique instance of boolean Top.
StorageLocation & createObject(const VarDecl &D)
Creates an object for the variable declaration D.
void initializeFieldsWithValues(RecordStorageLocation &Loc, QualType Type)
Initializes the fields (including synthetic fields) of Loc with values, unless values of the field ty...
StorageLocation & createStorageLocation(QualType Type)
Creates a storage location appropriate for Type.
Value * getReturnValue() const
Returns the return value of the function currently being analyzed.
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.
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.
std::enable_if_t< std::is_base_of_v< Value, T >, T * > get(const ValueDecl &D) const
bool proves(const Formula &) const
Returns true if the formula is always true when this point is reached.
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...
Environment & operator=(const Environment &Other)=delete
const FunctionDecl * getCurrentFunc() const
Returns the function currently being analyzed, or null if the code being analyzed isn't part of a fun...
BoolValue & getBoolLiteralValue(bool Value) const
Returns a symbolic boolean value that models a boolean literal equal to Value
StorageLocation & createObject(QualType Ty, const Expr *InitExpr=nullptr)
Creates an object (i.e.
void assume(const Formula &)
Record a fact that must be true if this point in the program is reached.
DataflowAnalysisContext & getDataflowAnalysisContext() const
Returns the DataflowAnalysisContext used by the environment.
BoolValue & joinBoolValues(BoolValue &Val1, const Environment &Env1, BoolValue &Val2, const Environment &Env2)
Joins two distinct boolean values Val1 (from Env1) and Val2 (from Env2) into this environment.
Environment(DataflowAnalysisContext &DACtx, Atom FlowConditionToken)
Creates an environment that uses DACtx to store objects that encompass the state of a program.
static Value * joinValues(QualType Ty, Value *Val1, const Environment &Env1, Value *Val2, const Environment &Env2, Environment &JoinedEnv, Environment::ValueModel &Model)
Returns a value that approximates both Val1 and Val2, or null if no such value can be produced.
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 (if any).
RecordStorageLocation & getResultObjectLocation(const Expr &RecordPRValue) const
Returns the location of the result object for a record-type prvalue.
std::enable_if_t< std::is_base_of_v< StorageLocation, T >, T * > get(const Expr &E) const
ExprJoinBehavior
How to treat expression state (ExprToLoc and ExprToVal) in a join.
static Environment join(const Environment &EnvA, const Environment &EnvB, Environment::ValueModel &Model, ExprJoinBehavior ExprBehavior)
Joins two environments by taking the intersection of storage locations and values that are stored in ...
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.
IntegerValue & getIntLiteralValue(llvm::APInt Value) const
Returns a symbolic integer value that models an integer literal equal to Value
Environment & operator=(Environment &&Other)=default
void setThisPointeeStorageLocation(RecordStorageLocation &Loc)
Sets the storage location assigned to the this pointee in the environment.
Atom getFlowConditionToken() const
Returns a boolean variable that identifies the flow condition (FC).
Environment(DataflowAnalysisContext &DACtx, const FunctionDecl &FD)
Creates an environment that uses DACtx to store objects that encompass the state of a program,...
RecordStorageLocation * getThisPointeeStorageLocation(const CXXThisExpr &ThisExpr) const
Returns the storage location assigned to the this pointee in the environment given a specific CXXThis...
StorageLocation & createObject(const ValueDecl &D, const Expr *InitExpr)
Creates an object for the variable declaration D.
BoolValue & makeNot(BoolValue &Val) const
Returns a boolean value that represents the negation of Val.
size_t callStackSize() const
Returns the size of the call stack, not counting the initial analysis target.
bool canDescend(unsigned MaxDepth, const FunctionDecl *Callee) const
Returns whether this Environment can be extended to analyze the given Callee (i.e.
std::enable_if_t< std::is_base_of_v< StorageLocation, T >, T * > get(const ValueDecl &D) const
Returns the result of casting getStorageLocation(...) to a subclass of StorageLocation (using cast_or...
void initialize()
Assigns storage locations and values to all parameters, captures, global variables,...
BoolValue & makeOr(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value that represents the disjunction of LHS and RHS.
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 ...
void setReturnStorageLocation(StorageLocation *Loc)
Sets the storage location for the reference returned by the function currently being analyzed.
StorageLocation * getReturnStorageLocation() const
Returns the storage location for the reference returned by the function currently being analyzed.
std::enable_if_t< std::is_base_of_v< Value, T >, T * > get(const Expr &E) const
BoolValue & makeImplication(BoolValue &LHS, BoolValue &RHS) const
Returns a boolean value represents LHS => RHS.
Models an integer.
Definition Value.h:160
Models a symbolic pointer. Specifically, any value of type T*.
Definition Value.h:170
A storage location for a record (struct, class, or union).
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
BoolModelKind
Selects the boolean model used to represent and reason about path conditions and boolean values in En...
Atom
Identifies an atomic boolean variable such as "V1".
Definition Formula.h:34
ComparisonResult
Indicates the result of a tentative comparison.
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...
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...
LatticeEffect
Effect indicating whether a lattice operation resulted in a new value.
Top level wrappers for InstallAPI frontend operations.
const FunctionProtoType * T
A collection of several types of declarations, all referenced from the same function.
Definition ASTOps.h:142
The result of a widen operation.
LatticeEffect Effect
Whether V represents a "change" (that is, a different value) with respect to the previous value in th...
Value * V
Non-null pointer to a potentially widened version of the input value.