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