1616
1717#include < iterator>
1818#include < optional>
19- #include < type_traits>
2019#include < utility>
2120#include < vector>
2221
3736namespace clang {
3837namespace dataflow {
3938
40- // / Base class template for dataflow analyses built on a single lattice type.
41- // /
42- // / Requirements:
43- // /
44- // / `Derived` must be derived from a specialization of this class template and
45- // / must provide the following public members:
46- // / * `LatticeT initialElement()` - returns a lattice element that models the
47- // / initial state of a basic block;
48- // / * `void transfer(const CFGElement &, LatticeT &, Environment &)` - applies
49- // / the analysis transfer function for a given CFG element and lattice
50- // / element.
51- // /
52- // / `Derived` can optionally provide the following members:
53- // / * `void transferBranch(bool Branch, const Stmt *Stmt, TypeErasedLattice &E,
54- // / Environment &Env)` - applies the analysis transfer
55- // / function for a given edge from a CFG block of a conditional statement.
56- // /
57- // / `Derived` can optionally override the virtual functions in the
58- // / `Environment::ValueModel` interface (which is an indirect base class of
59- // / this class).
60- // /
61- // / `LatticeT` is a bounded join-semilattice that is used by `Derived` and must
62- // / provide the following public members:
63- // / * `LatticeJoinEffect join(const LatticeT &)` - joins the object and the
64- // / argument by computing their least upper bound, modifies the object if
65- // / necessary, and returns an effect indicating whether any changes were
66- // / made to it;
67- // / FIXME: make it `static LatticeT join(const LatticeT&, const LatticeT&)`
68- // / * `bool operator==(const LatticeT &) const` - returns true if and only if
69- // / the object is equal to the argument.
70- // /
71- // / `LatticeT` can optionally provide the following members:
72- // / * `LatticeJoinEffect widen(const LatticeT &Previous)` - replaces the
73- // / lattice element with an approximation that can reach a fixed point more
74- // / quickly than iterated application of the transfer function alone. The
75- // / previous value is provided to inform the choice of widened value. The
76- // / function must also serve as a comparison operation, by indicating whether
77- // / the widened value is equivalent to the previous value with the returned
78- // / `LatticeJoinEffect`.
79- template <typename Derived, typename LatticeT>
80- class DataflowAnalysis : public TypeErasedDataflowAnalysis {
81- public:
82- // / Bounded join-semilattice that is used in the analysis.
83- using Lattice = LatticeT;
84-
85- explicit DataflowAnalysis (ASTContext &Context) : Context(Context) {}
86-
87- explicit DataflowAnalysis (ASTContext &Context,
88- DataflowAnalysisOptions Options)
89- : TypeErasedDataflowAnalysis(Options), Context(Context) {}
90-
91- ASTContext &getASTContext () final { return Context; }
92-
93- TypeErasedLattice typeErasedInitialElement () final {
94- return {static_cast <Derived *>(this )->initialElement ()};
95- }
96-
97- TypeErasedLattice joinTypeErased (const TypeErasedLattice &E1 ,
98- const TypeErasedLattice &E2 ) final {
99- // FIXME: change the signature of join() to avoid copying here.
100- Lattice L1 = llvm::any_cast<const Lattice &>(E1 .Value );
101- const Lattice &L2 = llvm::any_cast<const Lattice &>(E2 .Value );
102- L1.join (L2);
103- return {std::move (L1)};
104- }
105-
106- LatticeJoinEffect widenTypeErased (TypeErasedLattice &Current,
107- const TypeErasedLattice &Previous) final {
108- Lattice &C = llvm::any_cast<Lattice &>(Current.Value );
109- const Lattice &P = llvm::any_cast<const Lattice &>(Previous.Value );
110- return widenInternal (Rank0{}, C, P);
111- }
112-
113- bool isEqualTypeErased (const TypeErasedLattice &E1 ,
114- const TypeErasedLattice &E2 ) final {
115- const Lattice &L1 = llvm::any_cast<const Lattice &>(E1 .Value );
116- const Lattice &L2 = llvm::any_cast<const Lattice &>(E2 .Value );
117- return L1 == L2;
118- }
119-
120- void transferTypeErased (const CFGElement &Element, TypeErasedLattice &E,
121- Environment &Env) final {
122- Lattice &L = llvm::any_cast<Lattice &>(E.Value );
123- static_cast <Derived *>(this )->transfer (Element, L, Env);
124- }
125-
126- void transferBranchTypeErased (bool Branch, const Stmt *Stmt,
127- TypeErasedLattice &E, Environment &Env) final {
128- transferBranchInternal (Rank0{}, *static_cast <Derived *>(this ), Branch, Stmt,
129- E, Env);
130- }
131-
132- private:
133- // These `Rank` structs are used for template metaprogramming to choose
134- // between overloads.
135- struct Rank1 {};
136- struct Rank0 : Rank1 {};
137-
138- // The first-choice implementation: use `widen` when it is available.
139- template <typename T>
140- static auto widenInternal (Rank0, T &Current, const T &Prev)
141- -> decltype(Current.widen(Prev)) {
142- return Current.widen (Prev);
143- }
144-
145- // The second-choice implementation: `widen` is unavailable. Widening is
146- // merged with equality checking, so when widening is unimplemented, we
147- // default to equality checking.
148- static LatticeJoinEffect widenInternal (Rank1, const Lattice &Current,
149- const Lattice &Prev) {
150- return Prev == Current ? LatticeJoinEffect::Unchanged
151- : LatticeJoinEffect::Changed;
152- }
153-
154- // The first-choice implementation: `transferBranch` is implemented.
155- template <typename Analysis>
156- static auto transferBranchInternal (Rank0, Analysis &A, bool Branch,
157- const Stmt *Stmt, TypeErasedLattice &L,
158- Environment &Env)
159- -> std::void_t<decltype(A.transferBranch(
160- Branch, Stmt, std::declval<LatticeT &>(), Env))> {
161- A.transferBranch (Branch, Stmt, llvm::any_cast<Lattice &>(L.Value ), Env);
162- }
163-
164- // The second-choice implementation: `transferBranch` is unimplemented. No-op.
165- template <typename Analysis>
166- static void transferBranchInternal (Rank1, Analysis &A, bool , const Stmt *,
167- TypeErasedLattice &, Environment &) {}
168-
169- ASTContext &Context;
170- };
171-
17239// Model of the program at a given program point.
17340template <typename LatticeT> struct DataflowAnalysisState {
17441 // Model of a program property.
@@ -241,7 +108,7 @@ runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis,
241108 [&PostAnalysisCallbacks](const CFGElement &Element,
242109 const TypeErasedDataflowAnalysisState &State) {
243110 auto *Lattice =
244- llvm::any_cast <typename AnalysisT::Lattice>(& State.Lattice .Value );
111+ llvm::cast <typename AnalysisT::Lattice>(State.Lattice .get () );
245112 // FIXME: we should not be copying the environment here!
246113 // Ultimately the `CFGEltCallback` only gets a const reference anyway.
247114 PostAnalysisCallbacks.Before (
@@ -254,7 +121,7 @@ runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis,
254121 [&PostAnalysisCallbacks](const CFGElement &Element,
255122 const TypeErasedDataflowAnalysisState &State) {
256123 auto *Lattice =
257- llvm::any_cast <typename AnalysisT::Lattice>(& State.Lattice .Value );
124+ llvm::cast <typename AnalysisT::Lattice>(State.Lattice .get () );
258125 // FIXME: we should not be copying the environment here!
259126 // Ultimately the `CFGEltCallback` only gets a const reference anyway.
260127 PostAnalysisCallbacks.After (
@@ -278,8 +145,8 @@ runDataflowAnalysis(const AdornedCFG &ACFG, AnalysisT &Analysis,
278145 return llvm::transformOptional (
279146 std::move (OptState), [](TypeErasedDataflowAnalysisState &&State) {
280147 return DataflowAnalysisState<typename AnalysisT::Lattice>{
281- llvm::any_cast <typename AnalysisT::Lattice>(
282- std::move ( State.Lattice .Value )),
148+ std::move (* llvm::cast <typename AnalysisT::Lattice>(
149+ State.Lattice .get () )),
283150 std::move (State.Env )};
284151 });
285152 });
@@ -341,8 +208,7 @@ diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
341208 auto EltDiagnostics = Diagnoser.Before (
342209 Elt, ASTCtx,
343210 TransferStateForDiagnostics<typename AnalysisT::Lattice>(
344- llvm::any_cast<const typename AnalysisT::Lattice &>(
345- State.Lattice .Value ),
211+ *llvm::cast<typename AnalysisT::Lattice>(State.Lattice .get ()),
346212 State.Env ));
347213 llvm::move (EltDiagnostics, std::back_inserter (Diagnostics));
348214 };
@@ -355,8 +221,7 @@ diagnoseFunction(const FunctionDecl &FuncDecl, ASTContext &ASTCtx,
355221 auto EltDiagnostics = Diagnoser.After (
356222 Elt, ASTCtx,
357223 TransferStateForDiagnostics<typename AnalysisT::Lattice>(
358- llvm::any_cast<const typename AnalysisT::Lattice &>(
359- State.Lattice .Value ),
224+ *llvm::cast<typename AnalysisT::Lattice>(State.Lattice .get ()),
360225 State.Env ));
361226 llvm::move (EltDiagnostics, std::back_inserter (Diagnostics));
362227 };
0 commit comments