1a7dea167SDimitry Andric //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Definition of the interpreter state and entry point.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERP_H
15a7dea167SDimitry Andric 
16a7dea167SDimitry Andric #include <limits>
17a7dea167SDimitry Andric #include <vector>
18a7dea167SDimitry Andric #include "Function.h"
19a7dea167SDimitry Andric #include "InterpFrame.h"
20a7dea167SDimitry Andric #include "InterpStack.h"
21a7dea167SDimitry Andric #include "InterpState.h"
22a7dea167SDimitry Andric #include "Opcode.h"
23a7dea167SDimitry Andric #include "PrimType.h"
24a7dea167SDimitry Andric #include "Program.h"
25a7dea167SDimitry Andric #include "State.h"
26a7dea167SDimitry Andric #include "clang/AST/ASTContext.h"
27a7dea167SDimitry Andric #include "clang/AST/ASTDiagnostic.h"
28a7dea167SDimitry Andric #include "clang/AST/CXXInheritance.h"
29a7dea167SDimitry Andric #include "clang/AST/Expr.h"
30a7dea167SDimitry Andric #include "llvm/ADT/APFloat.h"
31a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h"
32a7dea167SDimitry Andric #include "llvm/Support/Endian.h"
33a7dea167SDimitry Andric 
34a7dea167SDimitry Andric namespace clang {
35a7dea167SDimitry Andric namespace interp {
36a7dea167SDimitry Andric 
37a7dea167SDimitry Andric using APInt = llvm::APInt;
38a7dea167SDimitry Andric using APSInt = llvm::APSInt;
39a7dea167SDimitry Andric 
40a7dea167SDimitry Andric /// Convers a value to an APValue.
41a7dea167SDimitry Andric template <typename T> bool ReturnValue(const T &V, APValue &R) {
42a7dea167SDimitry Andric   R = V.toAPValue();
43a7dea167SDimitry Andric   return true;
44a7dea167SDimitry Andric }
45a7dea167SDimitry Andric 
46a7dea167SDimitry Andric /// Checks if the variable has externally defined storage.
47a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
48a7dea167SDimitry Andric 
49a7dea167SDimitry Andric /// Checks if the array is offsetable.
50a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
51a7dea167SDimitry Andric 
52a7dea167SDimitry Andric /// Checks if a pointer is live and accesible.
53a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
54a7dea167SDimitry Andric                AccessKinds AK);
55a7dea167SDimitry Andric /// Checks if a pointer is null.
56a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
57a7dea167SDimitry Andric                CheckSubobjectKind CSK);
58a7dea167SDimitry Andric 
59a7dea167SDimitry Andric /// Checks if a pointer is in range.
60a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
61a7dea167SDimitry Andric                 AccessKinds AK);
62a7dea167SDimitry Andric 
63a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid.
64a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
65a7dea167SDimitry Andric                 CheckSubobjectKind CSK);
66a7dea167SDimitry Andric 
67a7dea167SDimitry Andric /// Checks if a pointer points to const storage.
68a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
69a7dea167SDimitry Andric 
70a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field.
71a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
72a7dea167SDimitry Andric 
73a7dea167SDimitry Andric /// Checks if a value can be loaded from a block.
74a7dea167SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
75a7dea167SDimitry Andric 
76a7dea167SDimitry Andric /// Checks if a value can be stored in a block.
77a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
78a7dea167SDimitry Andric 
79a7dea167SDimitry Andric /// Checks if a method can be invoked on an object.
80a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
81a7dea167SDimitry Andric 
82a7dea167SDimitry Andric /// Checks if a value can be initialized.
83a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
84a7dea167SDimitry Andric 
85a7dea167SDimitry Andric /// Checks if a method can be called.
86a7dea167SDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
87a7dea167SDimitry Andric 
88a7dea167SDimitry Andric /// Checks the 'this' pointer.
89a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
90a7dea167SDimitry Andric 
91a7dea167SDimitry Andric /// Checks if a method is pure virtual.
92a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
93a7dea167SDimitry Andric 
94a7dea167SDimitry Andric template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
95a7dea167SDimitry Andric 
96a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
97a7dea167SDimitry Andric // Add, Sub, Mul
98a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
99a7dea167SDimitry Andric 
100a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *),
101a7dea167SDimitry Andric           template <typename U> class OpAP>
102a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
103a7dea167SDimitry Andric                      const T &RHS) {
104a7dea167SDimitry Andric   // Fast path - add the numbers with fixed width.
105a7dea167SDimitry Andric   T Result;
106a7dea167SDimitry Andric   if (!OpFW(LHS, RHS, Bits, &Result)) {
107a7dea167SDimitry Andric     S.Stk.push<T>(Result);
108a7dea167SDimitry Andric     return true;
109a7dea167SDimitry Andric   }
110a7dea167SDimitry Andric 
111a7dea167SDimitry Andric   // If for some reason evaluation continues, use the truncated results.
112a7dea167SDimitry Andric   S.Stk.push<T>(Result);
113a7dea167SDimitry Andric 
114a7dea167SDimitry Andric   // Slow path - compute the result using another bit of precision.
115a7dea167SDimitry Andric   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
116a7dea167SDimitry Andric 
117a7dea167SDimitry Andric   // Report undefined behaviour, stopping if required.
118a7dea167SDimitry Andric   const Expr *E = S.Current->getExpr(OpPC);
119a7dea167SDimitry Andric   QualType Type = E->getType();
120a7dea167SDimitry Andric   if (S.checkingForUndefinedBehavior()) {
121*fe6060f1SDimitry Andric     SmallString<32> Trunc;
122*fe6060f1SDimitry Andric     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
123a7dea167SDimitry Andric     auto Loc = E->getExprLoc();
124a7dea167SDimitry Andric     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
125a7dea167SDimitry Andric     return true;
126a7dea167SDimitry Andric   } else {
127a7dea167SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
128a7dea167SDimitry Andric     return S.noteUndefinedBehavior();
129a7dea167SDimitry Andric   }
130a7dea167SDimitry Andric }
131a7dea167SDimitry Andric 
132a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
133a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) {
134a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
135a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
136a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
137a7dea167SDimitry Andric   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
138a7dea167SDimitry Andric }
139a7dea167SDimitry Andric 
140a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
141a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) {
142a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
143a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
144a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() + 1;
145a7dea167SDimitry Andric   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
146a7dea167SDimitry Andric }
147a7dea167SDimitry Andric 
148a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
149a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) {
150a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
151a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
152a7dea167SDimitry Andric   const unsigned Bits = RHS.bitWidth() * 2;
153a7dea167SDimitry Andric   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
154a7dea167SDimitry Andric }
155a7dea167SDimitry Andric 
156a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
157a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE
158a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
159a7dea167SDimitry Andric 
160a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
161a7dea167SDimitry Andric 
162a7dea167SDimitry Andric template <typename T>
163a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
164a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
165a7dea167SDimitry Andric   const T &RHS = S.Stk.pop<T>();
166a7dea167SDimitry Andric   const T &LHS = S.Stk.pop<T>();
167a7dea167SDimitry Andric   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
168a7dea167SDimitry Andric   return true;
169a7dea167SDimitry Andric }
170a7dea167SDimitry Andric 
171a7dea167SDimitry Andric template <typename T>
172a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
173a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, Fn);
174a7dea167SDimitry Andric }
175a7dea167SDimitry Andric 
176a7dea167SDimitry Andric template <>
177a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
178a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
179a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
180a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
181a7dea167SDimitry Andric 
182a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
183a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
184a7dea167SDimitry Andric     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
185a7dea167SDimitry Andric     return false;
186a7dea167SDimitry Andric   } else {
187a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
188a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
189a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
190a7dea167SDimitry Andric     return true;
191a7dea167SDimitry Andric   }
192a7dea167SDimitry Andric }
193a7dea167SDimitry Andric 
194a7dea167SDimitry Andric template <>
195a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
196a7dea167SDimitry Andric   using BoolT = PrimConv<PT_Bool>::T;
197a7dea167SDimitry Andric   const Pointer &RHS = S.Stk.pop<Pointer>();
198a7dea167SDimitry Andric   const Pointer &LHS = S.Stk.pop<Pointer>();
199a7dea167SDimitry Andric 
200480093f4SDimitry Andric   if (LHS.isZero() && RHS.isZero()) {
201a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
202a7dea167SDimitry Andric     return true;
203a7dea167SDimitry Andric   }
204a7dea167SDimitry Andric 
205a7dea167SDimitry Andric   if (!Pointer::hasSameBase(LHS, RHS)) {
206a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
207a7dea167SDimitry Andric     return true;
208a7dea167SDimitry Andric   } else {
209a7dea167SDimitry Andric     unsigned VL = LHS.getByteOffset();
210a7dea167SDimitry Andric     unsigned VR = RHS.getByteOffset();
211a7dea167SDimitry Andric     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
212a7dea167SDimitry Andric     return true;
213a7dea167SDimitry Andric   }
214a7dea167SDimitry Andric }
215a7dea167SDimitry Andric 
216a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
217a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) {
218a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
219a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Equal;
220a7dea167SDimitry Andric   });
221a7dea167SDimitry Andric }
222a7dea167SDimitry Andric 
223a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
224a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) {
225a7dea167SDimitry Andric   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
226a7dea167SDimitry Andric     return R != ComparisonCategoryResult::Equal;
227a7dea167SDimitry Andric   });
228a7dea167SDimitry Andric }
229a7dea167SDimitry Andric 
230a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
231a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) {
232a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
233a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less;
234a7dea167SDimitry Andric   });
235a7dea167SDimitry Andric }
236a7dea167SDimitry Andric 
237a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
238a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) {
239a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
240a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Less ||
241a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
242a7dea167SDimitry Andric   });
243a7dea167SDimitry Andric }
244a7dea167SDimitry Andric 
245a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
246a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) {
247a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
248a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater;
249a7dea167SDimitry Andric   });
250a7dea167SDimitry Andric }
251a7dea167SDimitry Andric 
252a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
253a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) {
254a7dea167SDimitry Andric   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
255a7dea167SDimitry Andric     return R == ComparisonCategoryResult::Greater ||
256a7dea167SDimitry Andric            R == ComparisonCategoryResult::Equal;
257a7dea167SDimitry Andric   });
258a7dea167SDimitry Andric }
259a7dea167SDimitry Andric 
260a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
261a7dea167SDimitry Andric // InRange
262a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
263a7dea167SDimitry Andric 
264a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
265a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) {
266a7dea167SDimitry Andric   const T RHS = S.Stk.pop<T>();
267a7dea167SDimitry Andric   const T LHS = S.Stk.pop<T>();
268a7dea167SDimitry Andric   const T Value = S.Stk.pop<T>();
269a7dea167SDimitry Andric 
270a7dea167SDimitry Andric   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
271a7dea167SDimitry Andric   return true;
272a7dea167SDimitry Andric }
273a7dea167SDimitry Andric 
274a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
275a7dea167SDimitry Andric // Dup, Pop, Test
276a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
277a7dea167SDimitry Andric 
278a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
279a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) {
280a7dea167SDimitry Andric   S.Stk.push<T>(S.Stk.peek<T>());
281a7dea167SDimitry Andric   return true;
282a7dea167SDimitry Andric }
283a7dea167SDimitry Andric 
284a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
285a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) {
286a7dea167SDimitry Andric   S.Stk.pop<T>();
287a7dea167SDimitry Andric   return true;
288a7dea167SDimitry Andric }
289a7dea167SDimitry Andric 
290a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
291a7dea167SDimitry Andric // Const
292a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
293a7dea167SDimitry Andric 
294a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
295a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
296a7dea167SDimitry Andric   S.Stk.push<T>(Arg);
297a7dea167SDimitry Andric   return true;
298a7dea167SDimitry Andric }
299a7dea167SDimitry Andric 
300a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
301a7dea167SDimitry Andric // Get/Set Local/Param/Global/This
302a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
303a7dea167SDimitry Andric 
304a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
305a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
306a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getLocal<T>(I));
307a7dea167SDimitry Andric   return true;
308a7dea167SDimitry Andric }
309a7dea167SDimitry Andric 
310a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
311a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
312a7dea167SDimitry Andric   S.Current->setLocal<T>(I, S.Stk.pop<T>());
313a7dea167SDimitry Andric   return true;
314a7dea167SDimitry Andric }
315a7dea167SDimitry Andric 
316a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
317a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
318a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
319a7dea167SDimitry Andric     return false;
320a7dea167SDimitry Andric   }
321a7dea167SDimitry Andric   S.Stk.push<T>(S.Current->getParam<T>(I));
322a7dea167SDimitry Andric   return true;
323a7dea167SDimitry Andric }
324a7dea167SDimitry Andric 
325a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
326a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
327a7dea167SDimitry Andric   S.Current->setParam<T>(I, S.Stk.pop<T>());
328a7dea167SDimitry Andric   return true;
329a7dea167SDimitry Andric }
330a7dea167SDimitry Andric 
331a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
332a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
333a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
334a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
335a7dea167SDimitry Andric       return false;
336a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
337a7dea167SDimitry Andric     return false;
338a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
339a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
340a7dea167SDimitry Andric     return false;
341a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
342a7dea167SDimitry Andric   return true;
343a7dea167SDimitry Andric }
344a7dea167SDimitry Andric 
345a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
346a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
347a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
348a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.peek<Pointer>();
349a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
350a7dea167SDimitry Andric     return false;
351a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
352a7dea167SDimitry Andric     return false;
353a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
354a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
355a7dea167SDimitry Andric     return false;
356a7dea167SDimitry Andric   Field.deref<T>() = Value;
357a7dea167SDimitry Andric   return true;
358a7dea167SDimitry Andric }
359a7dea167SDimitry Andric 
360a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
361a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
362a7dea167SDimitry Andric   const Pointer &Obj = S.Stk.pop<Pointer>();
363a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Obj, CSK_Field))
364a7dea167SDimitry Andric     return false;
365a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Obj, CSK_Field))
366a7dea167SDimitry Andric     return false;
367a7dea167SDimitry Andric   const Pointer &Field = Obj.atField(I);
368a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
369a7dea167SDimitry Andric     return false;
370a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
371a7dea167SDimitry Andric   return true;
372a7dea167SDimitry Andric }
373a7dea167SDimitry Andric 
374a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
375a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
376a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
377a7dea167SDimitry Andric     return false;
378a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
379a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
380a7dea167SDimitry Andric     return false;
381a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
382a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Field))
383a7dea167SDimitry Andric     return false;
384a7dea167SDimitry Andric   S.Stk.push<T>(Field.deref<T>());
385a7dea167SDimitry Andric   return true;
386a7dea167SDimitry Andric }
387a7dea167SDimitry Andric 
388a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
389a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
390a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
391a7dea167SDimitry Andric     return false;
392a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
393a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
394a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
395a7dea167SDimitry Andric     return false;
396a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
397a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Field))
398a7dea167SDimitry Andric     return false;
399a7dea167SDimitry Andric   Field.deref<T>() = Value;
400a7dea167SDimitry Andric   return true;
401a7dea167SDimitry Andric }
402a7dea167SDimitry Andric 
403a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
404a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
405a7dea167SDimitry Andric   auto *B = S.P.getGlobal(I);
406a7dea167SDimitry Andric   if (B->isExtern())
407a7dea167SDimitry Andric     return false;
408a7dea167SDimitry Andric   S.Stk.push<T>(B->deref<T>());
409a7dea167SDimitry Andric   return true;
410a7dea167SDimitry Andric }
411a7dea167SDimitry Andric 
412a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
413a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
414a7dea167SDimitry Andric   // TODO: emit warning.
415a7dea167SDimitry Andric   return false;
416a7dea167SDimitry Andric }
417a7dea167SDimitry Andric 
418a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
419a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
420a7dea167SDimitry Andric   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
421a7dea167SDimitry Andric   return true;
422a7dea167SDimitry Andric }
423a7dea167SDimitry Andric 
424a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
425a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
426a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
427a7dea167SDimitry Andric     return false;
428a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
429a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
430a7dea167SDimitry Andric     return false;
431a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
432a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
433a7dea167SDimitry Andric   Field.initialize();
434a7dea167SDimitry Andric   return true;
435a7dea167SDimitry Andric }
436a7dea167SDimitry Andric 
437a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
438a7dea167SDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
439a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
440a7dea167SDimitry Andric     return false;
441a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
442a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
443a7dea167SDimitry Andric     return false;
444a7dea167SDimitry Andric   const Pointer &Field = This.atField(F->Offset);
445a7dea167SDimitry Andric   const auto &Value = S.Stk.pop<T>();
446a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
447a7dea167SDimitry Andric   Field.initialize();
448a7dea167SDimitry Andric   return true;
449a7dea167SDimitry Andric }
450a7dea167SDimitry Andric 
451a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
452a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
453a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
454a7dea167SDimitry Andric     return false;
455a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
456a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
457a7dea167SDimitry Andric     return false;
458a7dea167SDimitry Andric   const Pointer &Field = This.atField(I);
459a7dea167SDimitry Andric   Field.deref<T>() = S.Stk.pop<T>();
460a7dea167SDimitry Andric   Field.activate();
461a7dea167SDimitry Andric   Field.initialize();
462a7dea167SDimitry Andric   return true;
463a7dea167SDimitry Andric }
464a7dea167SDimitry Andric 
465a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
466a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
467a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
468a7dea167SDimitry Andric   const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
469a7dea167SDimitry Andric   Field.deref<T>() = Value;
470a7dea167SDimitry Andric   Field.activate();
471a7dea167SDimitry Andric   Field.initialize();
472a7dea167SDimitry Andric   return true;
473a7dea167SDimitry Andric }
474a7dea167SDimitry Andric 
475a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
476a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
477a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
478a7dea167SDimitry Andric   const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
479a7dea167SDimitry Andric   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
480a7dea167SDimitry Andric   Field.activate();
481a7dea167SDimitry Andric   Field.initialize();
482a7dea167SDimitry Andric   return true;
483a7dea167SDimitry Andric }
484a7dea167SDimitry Andric 
485a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
486a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
487a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
488a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
489a7dea167SDimitry Andric   const Pointer &Field = Ptr.atField(I);
490a7dea167SDimitry Andric   Field.deref<T>() = Value;
491a7dea167SDimitry Andric   Field.activate();
492a7dea167SDimitry Andric   Field.initialize();
493a7dea167SDimitry Andric   return true;
494a7dea167SDimitry Andric }
495a7dea167SDimitry Andric 
496a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
497a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This
498a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
499a7dea167SDimitry Andric 
500a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
501a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
502a7dea167SDimitry Andric   return true;
503a7dea167SDimitry Andric }
504a7dea167SDimitry Andric 
505a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
506a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
507a7dea167SDimitry Andric     return false;
508a7dea167SDimitry Andric   }
509a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
510a7dea167SDimitry Andric   return true;
511a7dea167SDimitry Andric }
512a7dea167SDimitry Andric 
513a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
514a7dea167SDimitry Andric   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
515a7dea167SDimitry Andric   return true;
516a7dea167SDimitry Andric }
517a7dea167SDimitry Andric 
518a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
519a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
520a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
521a7dea167SDimitry Andric     return false;
522a7dea167SDimitry Andric   if (!CheckExtern(S, OpPC, Ptr))
523a7dea167SDimitry Andric     return false;
524a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
525a7dea167SDimitry Andric     return false;
526a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
527a7dea167SDimitry Andric   return true;
528a7dea167SDimitry Andric }
529a7dea167SDimitry Andric 
530a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
531a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
532a7dea167SDimitry Andric     return false;
533a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
534a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
535a7dea167SDimitry Andric     return false;
536a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
537a7dea167SDimitry Andric   return true;
538a7dea167SDimitry Andric }
539a7dea167SDimitry Andric 
540a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
541a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
542a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
543a7dea167SDimitry Andric     return false;
544a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
545a7dea167SDimitry Andric     return false;
546a7dea167SDimitry Andric   Pointer Field = Ptr.atField(Off);
547a7dea167SDimitry Andric   Ptr.deactivate();
548a7dea167SDimitry Andric   Field.activate();
549a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
550a7dea167SDimitry Andric   return true;
551a7dea167SDimitry Andric }
552a7dea167SDimitry Andric 
553a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
554a7dea167SDimitry Andric  if (S.checkingPotentialConstantExpression())
555a7dea167SDimitry Andric     return false;
556a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
557a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
558a7dea167SDimitry Andric     return false;
559a7dea167SDimitry Andric   Pointer Field = This.atField(Off);
560a7dea167SDimitry Andric   This.deactivate();
561a7dea167SDimitry Andric   Field.activate();
562a7dea167SDimitry Andric   S.Stk.push<Pointer>(std::move(Field));
563a7dea167SDimitry Andric   return true;
564a7dea167SDimitry Andric }
565a7dea167SDimitry Andric 
566a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
567a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
568a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
569a7dea167SDimitry Andric     return false;
570a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atField(Off));
571a7dea167SDimitry Andric   return true;
572a7dea167SDimitry Andric }
573a7dea167SDimitry Andric 
574a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
575a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
576a7dea167SDimitry Andric     return false;
577a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
578a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
579a7dea167SDimitry Andric     return false;
580a7dea167SDimitry Andric   S.Stk.push<Pointer>(This.atField(Off));
581a7dea167SDimitry Andric   return true;
582a7dea167SDimitry Andric }
583a7dea167SDimitry Andric 
584a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
585a7dea167SDimitry Andric                            const Pointer &Ptr) {
586a7dea167SDimitry Andric   Pointer Base = Ptr;
587a7dea167SDimitry Andric   while (Base.isBaseClass())
588a7dea167SDimitry Andric     Base = Base.getBase();
589a7dea167SDimitry Andric 
590a7dea167SDimitry Andric   auto *Field = Base.getRecord()->getVirtualBase(Decl);
591a7dea167SDimitry Andric   S.Stk.push<Pointer>(Base.atField(Field->Offset));
592a7dea167SDimitry Andric   return true;
593a7dea167SDimitry Andric }
594a7dea167SDimitry Andric 
595a7dea167SDimitry Andric inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
596a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
597a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
598a7dea167SDimitry Andric     return false;
599a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, Ptr);
600a7dea167SDimitry Andric }
601a7dea167SDimitry Andric 
602a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
603a7dea167SDimitry Andric                                const RecordDecl *D) {
604a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression())
605a7dea167SDimitry Andric     return false;
606a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
607a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
608a7dea167SDimitry Andric     return false;
609a7dea167SDimitry Andric   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
610a7dea167SDimitry Andric }
611a7dea167SDimitry Andric 
612a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
613a7dea167SDimitry Andric // Load, Store, Init
614a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
615a7dea167SDimitry Andric 
616a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
617a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) {
618a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
619a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
620a7dea167SDimitry Andric     return false;
621a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
622a7dea167SDimitry Andric   return true;
623a7dea167SDimitry Andric }
624a7dea167SDimitry Andric 
625a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
626a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) {
627a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
628a7dea167SDimitry Andric   if (!CheckLoad(S, OpPC, Ptr))
629a7dea167SDimitry Andric     return false;
630a7dea167SDimitry Andric   S.Stk.push<T>(Ptr.deref<T>());
631a7dea167SDimitry Andric   return true;
632a7dea167SDimitry Andric }
633a7dea167SDimitry Andric 
634a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
635a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) {
636a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
637a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
638a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
639a7dea167SDimitry Andric     return false;
640a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
641a7dea167SDimitry Andric   return true;
642a7dea167SDimitry Andric }
643a7dea167SDimitry Andric 
644a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
645a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) {
646a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
647a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
648a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
649a7dea167SDimitry Andric     return false;
650a7dea167SDimitry Andric   Ptr.deref<T>() = Value;
651a7dea167SDimitry Andric   return true;
652a7dea167SDimitry Andric }
653a7dea167SDimitry Andric 
654a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
655a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) {
656a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
657a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>();
658a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
659a7dea167SDimitry Andric     return false;
660a7dea167SDimitry Andric   if (auto *FD = Ptr.getField()) {
661a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
662a7dea167SDimitry Andric   } else {
663a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
664a7dea167SDimitry Andric   }
665a7dea167SDimitry Andric   return true;
666a7dea167SDimitry Andric }
667a7dea167SDimitry Andric 
668a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
669a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
670a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
671a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
672a7dea167SDimitry Andric   if (!CheckStore(S, OpPC, Ptr))
673a7dea167SDimitry Andric     return false;
674a7dea167SDimitry Andric   if (auto *FD = Ptr.getField()) {
675a7dea167SDimitry Andric     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
676a7dea167SDimitry Andric   } else {
677a7dea167SDimitry Andric     Ptr.deref<T>() = Value;
678a7dea167SDimitry Andric   }
679a7dea167SDimitry Andric   return true;
680a7dea167SDimitry Andric }
681a7dea167SDimitry Andric 
682a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
683a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) {
684a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
685a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
686a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
687a7dea167SDimitry Andric     return false;
688a7dea167SDimitry Andric   Ptr.initialize();
689a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
690a7dea167SDimitry Andric   return true;
691a7dea167SDimitry Andric }
692a7dea167SDimitry Andric 
693a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
694a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
695a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
696a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
697a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
698a7dea167SDimitry Andric     return false;
699a7dea167SDimitry Andric   Ptr.initialize();
700a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
701a7dea167SDimitry Andric   return true;
702a7dea167SDimitry Andric }
703a7dea167SDimitry Andric 
704a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
705a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
706a7dea167SDimitry Andric   const T &Value = S.Stk.pop<T>();
707a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
708a7dea167SDimitry Andric   if (!CheckInit(S, OpPC, Ptr))
709a7dea167SDimitry Andric     return false;
710a7dea167SDimitry Andric   Ptr.initialize();
711a7dea167SDimitry Andric   new (&Ptr.deref<T>()) T(Value);
712a7dea167SDimitry Andric   return true;
713a7dea167SDimitry Andric }
714a7dea167SDimitry Andric 
715a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
716a7dea167SDimitry Andric // AddOffset, SubOffset
717a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
718a7dea167SDimitry Andric 
719a7dea167SDimitry Andric template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
720a7dea167SDimitry Andric   // Fetch the pointer and the offset.
721a7dea167SDimitry Andric   const T &Offset = S.Stk.pop<T>();
722a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
723a7dea167SDimitry Andric   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
724a7dea167SDimitry Andric     return false;
725a7dea167SDimitry Andric   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
726a7dea167SDimitry Andric     return false;
727a7dea167SDimitry Andric 
728a7dea167SDimitry Andric   // Get a version of the index comparable to the type.
729a7dea167SDimitry Andric   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
730a7dea167SDimitry Andric   // A zero offset does not change the pointer, but in the case of an array
731a7dea167SDimitry Andric   // it has to be adjusted to point to the first element instead of the array.
732a7dea167SDimitry Andric   if (Offset.isZero()) {
733a7dea167SDimitry Andric     S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
734a7dea167SDimitry Andric     return true;
735a7dea167SDimitry Andric   }
736a7dea167SDimitry Andric   // Arrays of unknown bounds cannot have pointers into them.
737a7dea167SDimitry Andric   if (!CheckArray(S, OpPC, Ptr))
738a7dea167SDimitry Andric     return false;
739a7dea167SDimitry Andric 
740a7dea167SDimitry Andric   // Compute the largest index into the array.
741a7dea167SDimitry Andric   unsigned MaxIndex = Ptr.getNumElems();
742a7dea167SDimitry Andric 
743a7dea167SDimitry Andric   // Helper to report an invalid offset, computed as APSInt.
744a7dea167SDimitry Andric   auto InvalidOffset = [&]() {
745a7dea167SDimitry Andric     const unsigned Bits = Offset.bitWidth();
746a7dea167SDimitry Andric     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
747a7dea167SDimitry Andric     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
748a7dea167SDimitry Andric     APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
749a7dea167SDimitry Andric     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
750a7dea167SDimitry Andric         << NewIndex
751a7dea167SDimitry Andric         << /*array*/ static_cast<int>(!Ptr.inArray())
752a7dea167SDimitry Andric         << static_cast<unsigned>(MaxIndex);
753a7dea167SDimitry Andric     return false;
754a7dea167SDimitry Andric   };
755a7dea167SDimitry Andric 
756a7dea167SDimitry Andric   // If the new offset would be negative, bail out.
757a7dea167SDimitry Andric   if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
758a7dea167SDimitry Andric     return InvalidOffset();
759a7dea167SDimitry Andric   if (!Add && Offset.isPositive() && Index < Offset)
760a7dea167SDimitry Andric     return InvalidOffset();
761a7dea167SDimitry Andric 
762a7dea167SDimitry Andric   // If the new offset would be out of bounds, bail out.
763a7dea167SDimitry Andric   unsigned MaxOffset = MaxIndex - Ptr.getIndex();
764a7dea167SDimitry Andric   if (Add && Offset.isPositive() && Offset > MaxOffset)
765a7dea167SDimitry Andric     return InvalidOffset();
766a7dea167SDimitry Andric   if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
767a7dea167SDimitry Andric     return InvalidOffset();
768a7dea167SDimitry Andric 
769a7dea167SDimitry Andric   // Offset is valid - compute it on unsigned.
770a7dea167SDimitry Andric   int64_t WideIndex = static_cast<int64_t>(Index);
771a7dea167SDimitry Andric   int64_t WideOffset = static_cast<int64_t>(Offset);
772a7dea167SDimitry Andric   int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
773a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
774a7dea167SDimitry Andric   return true;
775a7dea167SDimitry Andric }
776a7dea167SDimitry Andric 
777a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
778a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) {
779a7dea167SDimitry Andric   return OffsetHelper<T, true>(S, OpPC);
780a7dea167SDimitry Andric }
781a7dea167SDimitry Andric 
782a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
783a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) {
784a7dea167SDimitry Andric   return OffsetHelper<T, false>(S, OpPC);
785a7dea167SDimitry Andric }
786a7dea167SDimitry Andric 
787a7dea167SDimitry Andric 
788a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
789a7dea167SDimitry Andric // Destroy
790a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
791a7dea167SDimitry Andric 
792a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
793a7dea167SDimitry Andric   S.Current->destroy(I);
794a7dea167SDimitry Andric   return true;
795a7dea167SDimitry Andric }
796a7dea167SDimitry Andric 
797a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
798a7dea167SDimitry Andric // Cast, CastFP
799a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
800a7dea167SDimitry Andric 
801a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
802a7dea167SDimitry Andric   using T = typename PrimConv<TIn>::T;
803a7dea167SDimitry Andric   using U = typename PrimConv<TOut>::T;
804a7dea167SDimitry Andric   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
805a7dea167SDimitry Andric   return true;
806a7dea167SDimitry Andric }
807a7dea167SDimitry Andric 
808a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
809a7dea167SDimitry Andric // Zero, Nullptr
810a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
811a7dea167SDimitry Andric 
812a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
813a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) {
814a7dea167SDimitry Andric   S.Stk.push<T>(T::zero());
815a7dea167SDimitry Andric   return true;
816a7dea167SDimitry Andric }
817a7dea167SDimitry Andric 
818a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T>
819a7dea167SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC) {
820a7dea167SDimitry Andric   S.Stk.push<T>();
821a7dea167SDimitry Andric   return true;
822a7dea167SDimitry Andric }
823a7dea167SDimitry Andric 
824a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
825a7dea167SDimitry Andric // This, ImplicitThis
826a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
827a7dea167SDimitry Andric 
828a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) {
829a7dea167SDimitry Andric   // Cannot read 'this' in this mode.
830a7dea167SDimitry Andric   if (S.checkingPotentialConstantExpression()) {
831a7dea167SDimitry Andric     return false;
832a7dea167SDimitry Andric   }
833a7dea167SDimitry Andric 
834a7dea167SDimitry Andric   const Pointer &This = S.Current->getThis();
835a7dea167SDimitry Andric   if (!CheckThis(S, OpPC, This))
836a7dea167SDimitry Andric     return false;
837a7dea167SDimitry Andric 
838a7dea167SDimitry Andric   S.Stk.push<Pointer>(This);
839a7dea167SDimitry Andric   return true;
840a7dea167SDimitry Andric }
841a7dea167SDimitry Andric 
842a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
843a7dea167SDimitry Andric // Shr, Shl
844a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
845a7dea167SDimitry Andric 
846a7dea167SDimitry Andric template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
847a7dea167SDimitry Andric unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
848a7dea167SDimitry Andric   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
849a7dea167SDimitry Andric   // the shifted type.
850a7dea167SDimitry Andric   if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
851a7dea167SDimitry Andric     const Expr *E = S.Current->getExpr(OpPC);
852a7dea167SDimitry Andric     const APSInt Val = V.toAPSInt();
853a7dea167SDimitry Andric     QualType Ty = E->getType();
854a7dea167SDimitry Andric     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
855a7dea167SDimitry Andric     return Bits;
856a7dea167SDimitry Andric   } else {
857a7dea167SDimitry Andric     return static_cast<unsigned>(V);
858a7dea167SDimitry Andric   }
859a7dea167SDimitry Andric }
860a7dea167SDimitry Andric 
861a7dea167SDimitry Andric template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
862a7dea167SDimitry Andric inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
863a7dea167SDimitry Andric   if (RHS >= V.bitWidth()) {
864a7dea167SDimitry Andric     S.Stk.push<T>(T::from(0, V.bitWidth()));
865a7dea167SDimitry Andric   } else {
866a7dea167SDimitry Andric     S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
867a7dea167SDimitry Andric   }
868a7dea167SDimitry Andric   return true;
869a7dea167SDimitry Andric }
870a7dea167SDimitry Andric 
871a7dea167SDimitry Andric template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
872a7dea167SDimitry Andric inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
8735ffd83dbSDimitry Andric   if (V.isSigned() && !S.getLangOpts().CPlusPlus20) {
874a7dea167SDimitry Andric     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
875a7dea167SDimitry Andric     // operand, and must not overflow the corresponding unsigned type.
876a7dea167SDimitry Andric     // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
877a7dea167SDimitry Andric     // E1 x 2^E2 module 2^N.
878a7dea167SDimitry Andric     if (V.isNegative()) {
879a7dea167SDimitry Andric       const Expr *E = S.Current->getExpr(OpPC);
880a7dea167SDimitry Andric       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
881a7dea167SDimitry Andric     } else if (V.countLeadingZeros() < RHS) {
882a7dea167SDimitry Andric       S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
883a7dea167SDimitry Andric     }
884a7dea167SDimitry Andric   }
885a7dea167SDimitry Andric 
886a7dea167SDimitry Andric   if (V.bitWidth() == 1) {
887a7dea167SDimitry Andric     S.Stk.push<T>(V);
888a7dea167SDimitry Andric   } else if (RHS >= V.bitWidth()) {
889a7dea167SDimitry Andric     S.Stk.push<T>(T::from(0, V.bitWidth()));
890a7dea167SDimitry Andric   } else {
891a7dea167SDimitry Andric     S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
892a7dea167SDimitry Andric   }
893a7dea167SDimitry Andric   return true;
894a7dea167SDimitry Andric }
895a7dea167SDimitry Andric 
896a7dea167SDimitry Andric template <PrimType TL, PrimType TR>
897a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) {
898a7dea167SDimitry Andric   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
899a7dea167SDimitry Andric   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
900a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
901a7dea167SDimitry Andric 
902a7dea167SDimitry Andric   if (RHS.isSigned() && RHS.isNegative()) {
903a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
904a7dea167SDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
905a7dea167SDimitry Andric     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
906a7dea167SDimitry Andric   } else {
907a7dea167SDimitry Andric     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
908a7dea167SDimitry Andric   }
909a7dea167SDimitry Andric }
910a7dea167SDimitry Andric 
911a7dea167SDimitry Andric template <PrimType TL, PrimType TR>
912a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) {
913a7dea167SDimitry Andric   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
914a7dea167SDimitry Andric   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
915a7dea167SDimitry Andric   const unsigned Bits = LHS.bitWidth();
916a7dea167SDimitry Andric 
917a7dea167SDimitry Andric   if (RHS.isSigned() && RHS.isNegative()) {
918a7dea167SDimitry Andric     const SourceInfo &Loc = S.Current->getSource(OpPC);
919a7dea167SDimitry Andric     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
920a7dea167SDimitry Andric     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
921a7dea167SDimitry Andric   } else {
922a7dea167SDimitry Andric     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
923a7dea167SDimitry Andric   }
924a7dea167SDimitry Andric }
925a7dea167SDimitry Andric 
926a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
927a7dea167SDimitry Andric // NoRet
928a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
929a7dea167SDimitry Andric 
930a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) {
931a7dea167SDimitry Andric   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
932a7dea167SDimitry Andric   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
933a7dea167SDimitry Andric   return false;
934a7dea167SDimitry Andric }
935a7dea167SDimitry Andric 
936a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
937a7dea167SDimitry Andric // NarrowPtr, ExpandPtr
938a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
939a7dea167SDimitry Andric 
940a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
941a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
942a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.narrow());
943a7dea167SDimitry Andric   return true;
944a7dea167SDimitry Andric }
945a7dea167SDimitry Andric 
946a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
947a7dea167SDimitry Andric   const Pointer &Ptr = S.Stk.pop<Pointer>();
948a7dea167SDimitry Andric   S.Stk.push<Pointer>(Ptr.expand());
949a7dea167SDimitry Andric   return true;
950a7dea167SDimitry Andric }
951a7dea167SDimitry Andric 
952a7dea167SDimitry Andric /// Interpreter entry point.
953a7dea167SDimitry Andric bool Interpret(InterpState &S, APValue &Result);
954a7dea167SDimitry Andric 
955a7dea167SDimitry Andric } // namespace interp
956a7dea167SDimitry Andric } // namespace clang
957a7dea167SDimitry Andric 
958a7dea167SDimitry Andric #endif
959