xref: /llvm-project/clang/lib/AST/ByteCode/InterpState.h (revision a024a0ceedae886c254b496c9321f9ef253cd7f8)
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 /// Interpreter context.
36 class InterpState final : public State, public SourceMapper {
37 public:
38   InterpState(State &Parent, Program &P, InterpStack &Stk, Context &Ctx,
39               SourceMapper *M = nullptr);
40 
41   ~InterpState();
42 
43   void cleanup();
44 
45   InterpState(const InterpState &) = delete;
46   InterpState &operator=(const InterpState &) = delete;
47 
48   // Stack frame accessors.
49   Frame *getSplitFrame() { return Parent.getCurrentFrame(); }
50   Frame *getCurrentFrame() override;
51   unsigned getCallStackDepth() override {
52     return Current ? (Current->getDepth() + 1) : 1;
53   }
54   const Frame *getBottomFrame() const override {
55     return Parent.getBottomFrame();
56   }
57 
58   // Access objects from the walker context.
59   Expr::EvalStatus &getEvalStatus() const override {
60     return Parent.getEvalStatus();
61   }
62   ASTContext &getASTContext() const override { return Parent.getASTContext(); }
63 
64   // Forward status checks and updates to the walker.
65   bool checkingForUndefinedBehavior() const override {
66     return Parent.checkingForUndefinedBehavior();
67   }
68   bool keepEvaluatingAfterFailure() const override {
69     return Parent.keepEvaluatingAfterFailure();
70   }
71   bool keepEvaluatingAfterSideEffect() const override {
72     return Parent.keepEvaluatingAfterSideEffect();
73   }
74   bool checkingPotentialConstantExpression() const override {
75     return Parent.checkingPotentialConstantExpression();
76   }
77   bool noteUndefinedBehavior() override {
78     return Parent.noteUndefinedBehavior();
79   }
80   bool inConstantContext() const;
81   bool hasActiveDiagnostic() override { return Parent.hasActiveDiagnostic(); }
82   void setActiveDiagnostic(bool Flag) override {
83     Parent.setActiveDiagnostic(Flag);
84   }
85   void setFoldFailureDiagnostic(bool Flag) override {
86     Parent.setFoldFailureDiagnostic(Flag);
87   }
88   bool hasPriorDiagnostic() override { return Parent.hasPriorDiagnostic(); }
89   bool noteSideEffect() override { return Parent.noteSideEffect(); }
90 
91   /// Reports overflow and return true if evaluation should continue.
92   bool reportOverflow(const Expr *E, const llvm::APSInt &Value);
93 
94   /// Deallocates a pointer.
95   void deallocate(Block *B);
96 
97   /// Delegates source mapping to the mapper.
98   SourceInfo getSource(const Function *F, CodePtr PC) const override {
99     if (M)
100       return M->getSource(F, PC);
101 
102     assert(F && "Function cannot be null");
103     return F->getSource(PC);
104   }
105 
106   Context &getContext() const { return Ctx; }
107 
108   void setEvalLocation(SourceLocation SL) { this->EvalLocation = SL; }
109 
110   DynamicAllocator &getAllocator() { return Alloc; }
111 
112   /// Diagnose any dynamic allocations that haven't been freed yet.
113   /// Will return \c false if there were any allocations to diagnose,
114   /// \c true otherwise.
115   bool maybeDiagnoseDanglingAllocations();
116 
117 private:
118   friend class EvaluationResult;
119   friend class InterpStateCCOverride;
120   /// AST Walker state.
121   State &Parent;
122   /// Dead block chain.
123   DeadBlock *DeadBlocks = nullptr;
124   /// Reference to the offset-source mapping.
125   SourceMapper *M;
126   /// Allocator used for dynamic allocations performed via the program.
127   DynamicAllocator Alloc;
128   std::optional<bool> ConstantContextOverride;
129 
130 public:
131   /// Reference to the module containing all bytecode.
132   Program &P;
133   /// Temporary stack.
134   InterpStack &Stk;
135   /// Interpreter Context.
136   Context &Ctx;
137   /// The current frame.
138   InterpFrame *Current = nullptr;
139   /// Source location of the evaluating expression
140   SourceLocation EvalLocation;
141   /// Declaration we're initializing/evaluting, if any.
142   const VarDecl *EvaluatingDecl = nullptr;
143 
144   llvm::SmallVector<
145       std::pair<const Expr *, const LifetimeExtendedTemporaryDecl *>>
146       SeenGlobalTemporaries;
147 };
148 
149 class InterpStateCCOverride final {
150 public:
151   InterpStateCCOverride(InterpState &Ctx, bool Value)
152       : Ctx(Ctx), OldCC(Ctx.ConstantContextOverride) {
153     // We only override this if the new value is true.
154     Enabled = Value;
155     if (Enabled)
156       Ctx.ConstantContextOverride = Value;
157   }
158   ~InterpStateCCOverride() {
159     if (Enabled)
160       Ctx.ConstantContextOverride = OldCC;
161   }
162 
163 private:
164   bool Enabled;
165   InterpState &Ctx;
166   std::optional<bool> OldCC;
167 };
168 
169 } // namespace interp
170 } // namespace clang
171 
172 #endif
173