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
27namespace clang {
28namespace interp {
29class Context;
30class Function;
31class InterpStack;
32class InterpFrame;
33class SourceMapper;
34
35struct StdAllocatorCaller {
36 const Expr *Call = nullptr;
37 QualType AllocType;
38 explicit operator bool() { return Call; }
39};
40
41/// Interpreter context.
42class InterpState final : public State, public SourceMapper {
43public:
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
129private:
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
141public:
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
166class InterpStateCCOverride final {
167public:
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
180private:
181 bool Enabled;
182 InterpState &Ctx;
183 std::optional<bool> OldCC;
184};
185
186} // namespace interp
187} // namespace clang
188
189#endif
190

source code of clang/lib/AST/ByteCode/InterpState.h