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