1 | //===--- InterpState.h - Interpreter state for the constexpr VM -*- 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 | // Definition of the interpreter state and entry point. |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | |
13 | #ifndef LLVM_CLANG_AST_INTERP_INTERPSTATE_H |
14 | #define LLVM_CLANG_AST_INTERP_INTERPSTATE_H |
15 | |
16 | #include "Context.h" |
17 | #include "DynamicAllocator.h" |
18 | #include "Function.h" |
19 | #include "InterpFrame.h" |
20 | #include "InterpStack.h" |
21 | #include "State.h" |
22 | #include "clang/AST/APValue.h" |
23 | #include "clang/AST/ASTDiagnostic.h" |
24 | #include "clang/AST/Expr.h" |
25 | #include "clang/AST/OptionalDiagnostic.h" |
26 | |
27 | namespace clang { |
28 | namespace interp { |
29 | class Context; |
30 | class Function; |
31 | class InterpStack; |
32 | class InterpFrame; |
33 | class SourceMapper; |
34 | |
35 | struct StdAllocatorCaller { |
36 | const Expr *Call = nullptr; |
37 | QualType AllocType; |
38 | explicit operator bool() { return Call; } |
39 | }; |
40 | |
41 | /// Interpreter context. |
42 | class InterpState final : public State, public SourceMapper { |
43 | public: |
44 | InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx, |
45 | SourceMapper *M = nullptr); |
46 | InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx, |
47 | const Function *Func); |
48 | |
49 | ~InterpState(); |
50 | |
51 | void cleanup(); |
52 | |
53 | InterpState(const InterpState &) = delete; |
54 | InterpState &operator=(const InterpState &) = delete; |
55 | |
56 | bool diagnosing() const { return getEvalStatus().Diag != nullptr; } |
57 | |
58 | // Stack frame accessors. |
59 | Frame *getSplitFrame() { return Parent.getCurrentFrame(); } |
60 | Frame *getCurrentFrame() override; |
61 | unsigned getCallStackDepth() override { |
62 | return Current ? (Current->getDepth() + 1) : 1; |
63 | } |
64 | const Frame *getBottomFrame() const override { |
65 | return Parent.getBottomFrame(); |
66 | } |
67 | |
68 | // Access objects from the walker context. |
69 | Expr::EvalStatus &getEvalStatus() const override { |
70 | return Parent.getEvalStatus(); |
71 | } |
72 | ASTContext &getASTContext() const override { return Parent.getASTContext(); } |
73 | |
74 | // Forward status checks and updates to the walker. |
75 | bool checkingForUndefinedBehavior() const override { |
76 | return Parent.checkingForUndefinedBehavior(); |
77 | } |
78 | bool keepEvaluatingAfterFailure() const override { |
79 | return Parent.keepEvaluatingAfterFailure(); |
80 | } |
81 | bool keepEvaluatingAfterSideEffect() const override { |
82 | return Parent.keepEvaluatingAfterSideEffect(); |
83 | } |
84 | bool checkingPotentialConstantExpression() const override { |
85 | return Parent.checkingPotentialConstantExpression(); |
86 | } |
87 | bool noteUndefinedBehavior() override { |
88 | return Parent.noteUndefinedBehavior(); |
89 | } |
90 | bool inConstantContext() const; |
91 | bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); } |
92 | void setActiveDiagnostic(bool Flag) override { |
93 | Parent.setActiveDiagnostic(Flag); |
94 | } |
95 | void setFoldFailureDiagnostic(bool Flag) override { |
96 | Parent.setFoldFailureDiagnostic(Flag); |
97 | } |
98 | bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); } |
99 | bool noteSideEffect() override { return Parent.noteSideEffect(); } |
100 | |
101 | /// Reports overflow and return true if evaluation should continue. |
102 | bool reportOverflow(const Expr *E, const llvm::APSInt &Value); |
103 | |
104 | /// Deallocates a pointer. |
105 | void deallocate(Block *B); |
106 | |
107 | /// Delegates source mapping to the mapper. |
108 | SourceInfo getSource(const Function *F, CodePtr PC) const override { |
109 | if (M) |
110 | return M->getSource(F, PC); |
111 | |
112 | assert(F && "Function cannot be null" ); |
113 | return F->getSource(PC); |
114 | } |
115 | |
116 | Context &getContext() const { return Ctx; } |
117 | |
118 | void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; } |
119 | |
120 | DynamicAllocator &getAllocator() { return Alloc; } |
121 | |
122 | /// Diagnose any dynamic allocations that haven't been freed yet. |
123 | /// Will return \c false if there were any allocations to diagnose, |
124 | /// \c true otherwise. |
125 | bool maybeDiagnoseDanglingAllocations(); |
126 | |
127 | StdAllocatorCaller getStdAllocatorCaller(StringRef Name) const; |
128 | |
129 | private: |
130 | friend class EvaluationResult; |
131 | friend class InterpStateCCOverride; |
132 | /// AST Walker state. |
133 | State &Parent; |
134 | /// Dead block chain. |
135 | DeadBlock *DeadBlocks = nullptr; |
136 | /// Reference to the offset-source mapping. |
137 | SourceMapper *M; |
138 | /// Allocator used for dynamic allocations performed via the program. |
139 | DynamicAllocator Alloc; |
140 | |
141 | public: |
142 | /// Reference to the module containing all bytecode. |
143 | Program &P; |
144 | /// Temporary stack. |
145 | InterpStack &Stk; |
146 | /// Interpreter Context. |
147 | Context &Ctx; |
148 | /// Bottom function frame. |
149 | InterpFrame BottomFrame; |
150 | /// The current frame. |
151 | InterpFrame *Current = nullptr; |
152 | /// Source location of the evaluating expression |
153 | SourceLocation EvalLocation; |
154 | /// Declaration we're initializing/evaluting, if any. |
155 | const VarDecl *EvaluatingDecl = nullptr; |
156 | /// Things needed to do speculative execution. |
157 | SmallVectorImpl<PartialDiagnosticAt> *PrevDiags = nullptr; |
158 | unsigned SpeculationDepth = 0; |
159 | std::optional<bool> ConstantContextOverride; |
160 | |
161 | llvm::SmallVector< |
162 | std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>> |
163 | SeenGlobalTemporaries; |
164 | }; |
165 | |
166 | class InterpStateCCOverride final { |
167 | public: |
168 | InterpStateCCOverride(InterpState &Ctx, bool Value) |
169 | : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) { |
170 | // We only override this if the new value is true. |
171 | Enabled = Value; |
172 | if (Enabled) |
173 | Ctx.ConstantContextOverride = Value; |
174 | } |
175 | ~InterpStateCCOverride() { |
176 | if (Enabled) |
177 | Ctx.ConstantContextOverride = OldCC; |
178 | } |
179 | |
180 | private: |
181 | bool Enabled; |
182 | InterpState &Ctx; |
183 | std::optional<bool> OldCC; |
184 | }; |
185 | |
186 | } // namespace interp |
187 | } // namespace clang |
188 | |
189 | #endif |
190 | |