xref: /openbsd-src/gnu/llvm/clang/lib/AST/Interp/Interp.h (revision 12c855180aad702bbcca06e0398d774beeafb155)
1e5dd7070Spatrick //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Definition of the interpreter state and entry point.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
14e5dd7070Spatrick #define LLVM_CLANG_AST_INTERP_INTERP_H
15e5dd7070Spatrick 
16*12c85518Srobert #include "Boolean.h"
17e5dd7070Spatrick #include "Function.h"
18e5dd7070Spatrick #include "InterpFrame.h"
19e5dd7070Spatrick #include "InterpStack.h"
20e5dd7070Spatrick #include "InterpState.h"
21e5dd7070Spatrick #include "Opcode.h"
22e5dd7070Spatrick #include "PrimType.h"
23e5dd7070Spatrick #include "Program.h"
24e5dd7070Spatrick #include "State.h"
25e5dd7070Spatrick #include "clang/AST/ASTContext.h"
26e5dd7070Spatrick #include "clang/AST/ASTDiagnostic.h"
27e5dd7070Spatrick #include "clang/AST/CXXInheritance.h"
28e5dd7070Spatrick #include "clang/AST/Expr.h"
29e5dd7070Spatrick #include "llvm/ADT/APFloat.h"
30e5dd7070Spatrick #include "llvm/ADT/APSInt.h"
31e5dd7070Spatrick #include "llvm/Support/Endian.h"
32*12c85518Srobert #include <limits>
33*12c85518Srobert #include <type_traits>
34e5dd7070Spatrick 
35e5dd7070Spatrick namespace clang {
36e5dd7070Spatrick namespace interp {
37e5dd7070Spatrick 
38e5dd7070Spatrick using APInt = llvm::APInt;
39e5dd7070Spatrick using APSInt = llvm::APSInt;
40e5dd7070Spatrick 
41*12c85518Srobert /// Convert a value to an APValue.
ReturnValue(const T & V,APValue & R)42e5dd7070Spatrick template <typename T> bool ReturnValue(const T &V, APValue &R) {
43e5dd7070Spatrick   R = V.toAPValue();
44e5dd7070Spatrick   return true;
45e5dd7070Spatrick }
46e5dd7070Spatrick 
47e5dd7070Spatrick /// Checks if the variable has externally defined storage.
48e5dd7070Spatrick bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
49e5dd7070Spatrick 
50e5dd7070Spatrick /// Checks if the array is offsetable.
51e5dd7070Spatrick bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
52e5dd7070Spatrick 
53*12c85518Srobert /// Checks if a pointer is live and accessible.
54e5dd7070Spatrick bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
55e5dd7070Spatrick                AccessKinds AK);
56e5dd7070Spatrick /// Checks if a pointer is null.
57e5dd7070Spatrick bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
58e5dd7070Spatrick                CheckSubobjectKind CSK);
59e5dd7070Spatrick 
60e5dd7070Spatrick /// Checks if a pointer is in range.
61e5dd7070Spatrick bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
62e5dd7070Spatrick                 AccessKinds AK);
63e5dd7070Spatrick 
64e5dd7070Spatrick /// Checks if a field from which a pointer is going to be derived is valid.
65e5dd7070Spatrick bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
66e5dd7070Spatrick                 CheckSubobjectKind CSK);
67e5dd7070Spatrick 
68e5dd7070Spatrick /// Checks if a pointer points to const storage.
69e5dd7070Spatrick bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
70e5dd7070Spatrick 
71e5dd7070Spatrick /// Checks if a pointer points to a mutable field.
72e5dd7070Spatrick bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
73e5dd7070Spatrick 
74e5dd7070Spatrick /// Checks if a value can be loaded from a block.
75e5dd7070Spatrick bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
76e5dd7070Spatrick 
77e5dd7070Spatrick /// Checks if a value can be stored in a block.
78e5dd7070Spatrick bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
79e5dd7070Spatrick 
80e5dd7070Spatrick /// Checks if a method can be invoked on an object.
81e5dd7070Spatrick bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
82e5dd7070Spatrick 
83e5dd7070Spatrick /// Checks if a value can be initialized.
84e5dd7070Spatrick bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
85e5dd7070Spatrick 
86e5dd7070Spatrick /// Checks if a method can be called.
87*12c85518Srobert bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);
88e5dd7070Spatrick 
89e5dd7070Spatrick /// Checks the 'this' pointer.
90e5dd7070Spatrick bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
91e5dd7070Spatrick 
92e5dd7070Spatrick /// Checks if a method is pure virtual.
93e5dd7070Spatrick bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
94e5dd7070Spatrick 
95*12c85518Srobert /// Checks that all fields are initialized after a constructor call.
96*12c85518Srobert bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This);
97*12c85518Srobert 
98*12c85518Srobert /// Checks if the shift operation is legal.
99*12c85518Srobert template <typename RT>
CheckShift(InterpState & S,CodePtr OpPC,const RT & RHS,unsigned Bits)100*12c85518Srobert bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) {
101*12c85518Srobert   if (RHS.isNegative()) {
102*12c85518Srobert     const SourceInfo &Loc = S.Current->getSource(OpPC);
103*12c85518Srobert     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
104*12c85518Srobert     return false;
105*12c85518Srobert   }
106*12c85518Srobert 
107*12c85518Srobert   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
108*12c85518Srobert   // the shifted type.
109*12c85518Srobert   if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {
110*12c85518Srobert     const Expr *E = S.Current->getExpr(OpPC);
111*12c85518Srobert     const APSInt Val = RHS.toAPSInt();
112*12c85518Srobert     QualType Ty = E->getType();
113*12c85518Srobert     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
114*12c85518Srobert     return false;
115*12c85518Srobert   }
116*12c85518Srobert   return true;
117*12c85518Srobert }
118*12c85518Srobert 
119*12c85518Srobert /// Checks if Div/Rem operation on LHS and RHS is valid.
120*12c85518Srobert template <typename T>
CheckDivRem(InterpState & S,CodePtr OpPC,const T & LHS,const T & RHS)121*12c85518Srobert bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {
122*12c85518Srobert   if (RHS.isZero()) {
123*12c85518Srobert     const SourceInfo &Loc = S.Current->getSource(OpPC);
124*12c85518Srobert     S.FFDiag(Loc, diag::note_expr_divide_by_zero);
125*12c85518Srobert     return false;
126*12c85518Srobert   }
127*12c85518Srobert 
128*12c85518Srobert   if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {
129*12c85518Srobert     APSInt LHSInt = LHS.toAPSInt();
130*12c85518Srobert     SmallString<32> Trunc;
131*12c85518Srobert     (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);
132*12c85518Srobert     const SourceInfo &Loc = S.Current->getSource(OpPC);
133*12c85518Srobert     const Expr *E = S.Current->getExpr(OpPC);
134*12c85518Srobert     S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();
135*12c85518Srobert     return false;
136*12c85518Srobert   }
137*12c85518Srobert   return true;
138*12c85518Srobert }
139*12c85518Srobert 
140*12c85518Srobert /// Interpreter entry point.
141*12c85518Srobert bool Interpret(InterpState &S, APValue &Result);
142e5dd7070Spatrick 
143e5dd7070Spatrick //===----------------------------------------------------------------------===//
144e5dd7070Spatrick // Add, Sub, Mul
145e5dd7070Spatrick //===----------------------------------------------------------------------===//
146e5dd7070Spatrick 
147e5dd7070Spatrick template <typename T, bool (*OpFW)(T, T, unsigned, T *),
148e5dd7070Spatrick           template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)149e5dd7070Spatrick bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
150e5dd7070Spatrick                      const T &RHS) {
151e5dd7070Spatrick   // Fast path - add the numbers with fixed width.
152e5dd7070Spatrick   T Result;
153e5dd7070Spatrick   if (!OpFW(LHS, RHS, Bits, &Result)) {
154e5dd7070Spatrick     S.Stk.push<T>(Result);
155e5dd7070Spatrick     return true;
156e5dd7070Spatrick   }
157e5dd7070Spatrick 
158e5dd7070Spatrick   // If for some reason evaluation continues, use the truncated results.
159e5dd7070Spatrick   S.Stk.push<T>(Result);
160e5dd7070Spatrick 
161e5dd7070Spatrick   // Slow path - compute the result using another bit of precision.
162e5dd7070Spatrick   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
163e5dd7070Spatrick 
164e5dd7070Spatrick   // Report undefined behaviour, stopping if required.
165e5dd7070Spatrick   const Expr *E = S.Current->getExpr(OpPC);
166e5dd7070Spatrick   QualType Type = E->getType();
167e5dd7070Spatrick   if (S.checkingForUndefinedBehavior()) {
168a9ac8606Spatrick     SmallString<32> Trunc;
169a9ac8606Spatrick     Value.trunc(Result.bitWidth()).toString(Trunc, 10);
170e5dd7070Spatrick     auto Loc = E->getExprLoc();
171e5dd7070Spatrick     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
172e5dd7070Spatrick     return true;
173e5dd7070Spatrick   } else {
174e5dd7070Spatrick     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
175e5dd7070Spatrick     return S.noteUndefinedBehavior();
176e5dd7070Spatrick   }
177e5dd7070Spatrick }
178e5dd7070Spatrick 
179e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)180e5dd7070Spatrick bool Add(InterpState &S, CodePtr OpPC) {
181e5dd7070Spatrick   const T &RHS = S.Stk.pop<T>();
182e5dd7070Spatrick   const T &LHS = S.Stk.pop<T>();
183e5dd7070Spatrick   const unsigned Bits = RHS.bitWidth() + 1;
184e5dd7070Spatrick   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
185e5dd7070Spatrick }
186e5dd7070Spatrick 
187e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)188e5dd7070Spatrick bool Sub(InterpState &S, CodePtr OpPC) {
189e5dd7070Spatrick   const T &RHS = S.Stk.pop<T>();
190e5dd7070Spatrick   const T &LHS = S.Stk.pop<T>();
191e5dd7070Spatrick   const unsigned Bits = RHS.bitWidth() + 1;
192e5dd7070Spatrick   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
193e5dd7070Spatrick }
194e5dd7070Spatrick 
195e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)196e5dd7070Spatrick bool Mul(InterpState &S, CodePtr OpPC) {
197e5dd7070Spatrick   const T &RHS = S.Stk.pop<T>();
198e5dd7070Spatrick   const T &LHS = S.Stk.pop<T>();
199e5dd7070Spatrick   const unsigned Bits = RHS.bitWidth() * 2;
200e5dd7070Spatrick   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
201e5dd7070Spatrick }
202e5dd7070Spatrick 
203*12c85518Srobert /// 1) Pops the RHS from the stack.
204*12c85518Srobert /// 2) Pops the LHS from the stack.
205*12c85518Srobert /// 3) Pushes 'LHS & RHS' on the stack
206*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitAnd(InterpState & S,CodePtr OpPC)207*12c85518Srobert bool BitAnd(InterpState &S, CodePtr OpPC) {
208*12c85518Srobert   const T &RHS = S.Stk.pop<T>();
209*12c85518Srobert   const T &LHS = S.Stk.pop<T>();
210*12c85518Srobert 
211*12c85518Srobert   unsigned Bits = RHS.bitWidth();
212*12c85518Srobert   T Result;
213*12c85518Srobert   if (!T::bitAnd(LHS, RHS, Bits, &Result)) {
214*12c85518Srobert     S.Stk.push<T>(Result);
215*12c85518Srobert     return true;
216*12c85518Srobert   }
217*12c85518Srobert   return false;
218*12c85518Srobert }
219*12c85518Srobert 
220*12c85518Srobert /// 1) Pops the RHS from the stack.
221*12c85518Srobert /// 2) Pops the LHS from the stack.
222*12c85518Srobert /// 3) Pushes 'LHS | RHS' on the stack
223*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitOr(InterpState & S,CodePtr OpPC)224*12c85518Srobert bool BitOr(InterpState &S, CodePtr OpPC) {
225*12c85518Srobert   const T &RHS = S.Stk.pop<T>();
226*12c85518Srobert   const T &LHS = S.Stk.pop<T>();
227*12c85518Srobert 
228*12c85518Srobert   unsigned Bits = RHS.bitWidth();
229*12c85518Srobert   T Result;
230*12c85518Srobert   if (!T::bitOr(LHS, RHS, Bits, &Result)) {
231*12c85518Srobert     S.Stk.push<T>(Result);
232*12c85518Srobert     return true;
233*12c85518Srobert   }
234*12c85518Srobert   return false;
235*12c85518Srobert }
236*12c85518Srobert 
237*12c85518Srobert /// 1) Pops the RHS from the stack.
238*12c85518Srobert /// 2) Pops the LHS from the stack.
239*12c85518Srobert /// 3) Pushes 'LHS ^ RHS' on the stack
240*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
BitXor(InterpState & S,CodePtr OpPC)241*12c85518Srobert bool BitXor(InterpState &S, CodePtr OpPC) {
242*12c85518Srobert   const T &RHS = S.Stk.pop<T>();
243*12c85518Srobert   const T &LHS = S.Stk.pop<T>();
244*12c85518Srobert 
245*12c85518Srobert   unsigned Bits = RHS.bitWidth();
246*12c85518Srobert   T Result;
247*12c85518Srobert   if (!T::bitXor(LHS, RHS, Bits, &Result)) {
248*12c85518Srobert     S.Stk.push<T>(Result);
249*12c85518Srobert     return true;
250*12c85518Srobert   }
251*12c85518Srobert   return false;
252*12c85518Srobert }
253*12c85518Srobert 
254*12c85518Srobert /// 1) Pops the RHS from the stack.
255*12c85518Srobert /// 2) Pops the LHS from the stack.
256*12c85518Srobert /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).
257*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Rem(InterpState & S,CodePtr OpPC)258*12c85518Srobert bool Rem(InterpState &S, CodePtr OpPC) {
259*12c85518Srobert   const T &RHS = S.Stk.pop<T>();
260*12c85518Srobert   const T &LHS = S.Stk.pop<T>();
261*12c85518Srobert 
262*12c85518Srobert   if (!CheckDivRem(S, OpPC, LHS, RHS))
263*12c85518Srobert     return false;
264*12c85518Srobert 
265*12c85518Srobert   const unsigned Bits = RHS.bitWidth() * 2;
266*12c85518Srobert   T Result;
267*12c85518Srobert   if (!T::rem(LHS, RHS, Bits, &Result)) {
268*12c85518Srobert     S.Stk.push<T>(Result);
269*12c85518Srobert     return true;
270*12c85518Srobert   }
271*12c85518Srobert   return false;
272*12c85518Srobert }
273*12c85518Srobert 
274*12c85518Srobert /// 1) Pops the RHS from the stack.
275*12c85518Srobert /// 2) Pops the LHS from the stack.
276*12c85518Srobert /// 3) Pushes 'LHS / RHS' on the stack
277*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Div(InterpState & S,CodePtr OpPC)278*12c85518Srobert bool Div(InterpState &S, CodePtr OpPC) {
279*12c85518Srobert   const T &RHS = S.Stk.pop<T>();
280*12c85518Srobert   const T &LHS = S.Stk.pop<T>();
281*12c85518Srobert 
282*12c85518Srobert   if (!CheckDivRem(S, OpPC, LHS, RHS))
283*12c85518Srobert     return false;
284*12c85518Srobert 
285*12c85518Srobert   const unsigned Bits = RHS.bitWidth() * 2;
286*12c85518Srobert   T Result;
287*12c85518Srobert   if (!T::div(LHS, RHS, Bits, &Result)) {
288*12c85518Srobert     S.Stk.push<T>(Result);
289*12c85518Srobert     return true;
290*12c85518Srobert   }
291*12c85518Srobert   return false;
292*12c85518Srobert }
293*12c85518Srobert 
294*12c85518Srobert //===----------------------------------------------------------------------===//
295*12c85518Srobert // Inv
296*12c85518Srobert //===----------------------------------------------------------------------===//
297*12c85518Srobert 
298*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Inv(InterpState & S,CodePtr OpPC)299*12c85518Srobert bool Inv(InterpState &S, CodePtr OpPC) {
300*12c85518Srobert   using BoolT = PrimConv<PT_Bool>::T;
301*12c85518Srobert   const T &Val = S.Stk.pop<T>();
302*12c85518Srobert   const unsigned Bits = Val.bitWidth();
303*12c85518Srobert   Boolean R;
304*12c85518Srobert   Boolean::inv(BoolT::from(Val, Bits), &R);
305*12c85518Srobert 
306*12c85518Srobert   S.Stk.push<BoolT>(R);
307*12c85518Srobert   return true;
308*12c85518Srobert }
309*12c85518Srobert 
310*12c85518Srobert //===----------------------------------------------------------------------===//
311*12c85518Srobert // Neg
312*12c85518Srobert //===----------------------------------------------------------------------===//
313*12c85518Srobert 
314*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Neg(InterpState & S,CodePtr OpPC)315*12c85518Srobert bool Neg(InterpState &S, CodePtr OpPC) {
316*12c85518Srobert   const T &Val = S.Stk.pop<T>();
317*12c85518Srobert   T Result;
318*12c85518Srobert   T::neg(Val, &Result);
319*12c85518Srobert 
320*12c85518Srobert   S.Stk.push<T>(Result);
321*12c85518Srobert   return true;
322*12c85518Srobert }
323*12c85518Srobert 
324*12c85518Srobert enum class PushVal : bool {
325*12c85518Srobert   No,
326*12c85518Srobert   Yes,
327*12c85518Srobert };
328*12c85518Srobert enum class IncDecOp {
329*12c85518Srobert   Inc,
330*12c85518Srobert   Dec,
331*12c85518Srobert };
332*12c85518Srobert 
333*12c85518Srobert template <typename T, IncDecOp Op, PushVal DoPush>
IncDecHelper(InterpState & S,CodePtr OpPC,const Pointer & Ptr)334*12c85518Srobert bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
335*12c85518Srobert   T Value = Ptr.deref<T>();
336*12c85518Srobert   T Result;
337*12c85518Srobert 
338*12c85518Srobert   if constexpr (DoPush == PushVal::Yes)
339*12c85518Srobert     S.Stk.push<T>(Result);
340*12c85518Srobert 
341*12c85518Srobert   if constexpr (Op == IncDecOp::Inc) {
342*12c85518Srobert     if (!T::increment(Value, &Result)) {
343*12c85518Srobert       Ptr.deref<T>() = Result;
344*12c85518Srobert       return true;
345*12c85518Srobert     }
346*12c85518Srobert   } else {
347*12c85518Srobert     if (!T::decrement(Value, &Result)) {
348*12c85518Srobert       Ptr.deref<T>() = Result;
349*12c85518Srobert       return true;
350*12c85518Srobert     }
351*12c85518Srobert   }
352*12c85518Srobert 
353*12c85518Srobert   // Something went wrong with the previous operation. Compute the
354*12c85518Srobert   // result with another bit of precision.
355*12c85518Srobert   unsigned Bits = Value.bitWidth() + 1;
356*12c85518Srobert   APSInt APResult;
357*12c85518Srobert   if constexpr (Op == IncDecOp::Inc)
358*12c85518Srobert     APResult = ++Value.toAPSInt(Bits);
359*12c85518Srobert   else
360*12c85518Srobert     APResult = --Value.toAPSInt(Bits);
361*12c85518Srobert 
362*12c85518Srobert   // Report undefined behaviour, stopping if required.
363*12c85518Srobert   const Expr *E = S.Current->getExpr(OpPC);
364*12c85518Srobert   QualType Type = E->getType();
365*12c85518Srobert   if (S.checkingForUndefinedBehavior()) {
366*12c85518Srobert     SmallString<32> Trunc;
367*12c85518Srobert     APResult.trunc(Result.bitWidth()).toString(Trunc, 10);
368*12c85518Srobert     auto Loc = E->getExprLoc();
369*12c85518Srobert     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
370*12c85518Srobert     return true;
371*12c85518Srobert   }
372*12c85518Srobert 
373*12c85518Srobert   S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;
374*12c85518Srobert   return S.noteUndefinedBehavior();
375*12c85518Srobert }
376*12c85518Srobert 
377*12c85518Srobert /// 1) Pops a pointer from the stack
378*12c85518Srobert /// 2) Load the value from the pointer
379*12c85518Srobert /// 3) Writes the value increased by one back to the pointer
380*12c85518Srobert /// 4) Pushes the original (pre-inc) value on the stack.
381*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Inc(InterpState & S,CodePtr OpPC)382*12c85518Srobert bool Inc(InterpState &S, CodePtr OpPC) {
383*12c85518Srobert   // FIXME: Check initialization of Ptr
384*12c85518Srobert   const Pointer &Ptr = S.Stk.pop<Pointer>();
385*12c85518Srobert 
386*12c85518Srobert   return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);
387*12c85518Srobert }
388*12c85518Srobert 
389*12c85518Srobert /// 1) Pops a pointer from the stack
390*12c85518Srobert /// 2) Load the value from the pointer
391*12c85518Srobert /// 3) Writes the value increased by one back to the pointer
392*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
IncPop(InterpState & S,CodePtr OpPC)393*12c85518Srobert bool IncPop(InterpState &S, CodePtr OpPC) {
394*12c85518Srobert   // FIXME: Check initialization of Ptr
395*12c85518Srobert   const Pointer &Ptr = S.Stk.pop<Pointer>();
396*12c85518Srobert 
397*12c85518Srobert   return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);
398*12c85518Srobert }
399*12c85518Srobert 
400*12c85518Srobert /// 1) Pops a pointer from the stack
401*12c85518Srobert /// 2) Load the value from the pointer
402*12c85518Srobert /// 3) Writes the value decreased by one back to the pointer
403*12c85518Srobert /// 4) Pushes the original (pre-dec) value on the stack.
404*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Dec(InterpState & S,CodePtr OpPC)405*12c85518Srobert bool Dec(InterpState &S, CodePtr OpPC) {
406*12c85518Srobert   // FIXME: Check initialization of Ptr
407*12c85518Srobert   const Pointer &Ptr = S.Stk.pop<Pointer>();
408*12c85518Srobert 
409*12c85518Srobert   return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);
410*12c85518Srobert }
411*12c85518Srobert 
412*12c85518Srobert /// 1) Pops a pointer from the stack
413*12c85518Srobert /// 2) Load the value from the pointer
414*12c85518Srobert /// 3) Writes the value decreased by one back to the pointer
415*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
DecPop(InterpState & S,CodePtr OpPC)416*12c85518Srobert bool DecPop(InterpState &S, CodePtr OpPC) {
417*12c85518Srobert   // FIXME: Check initialization of Ptr
418*12c85518Srobert   const Pointer &Ptr = S.Stk.pop<Pointer>();
419*12c85518Srobert 
420*12c85518Srobert   return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);
421*12c85518Srobert }
422*12c85518Srobert 
423*12c85518Srobert /// 1) Pops the value from the stack.
424*12c85518Srobert /// 2) Pushes the bitwise complemented value on the stack (~V).
425*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
Comp(InterpState & S,CodePtr OpPC)426*12c85518Srobert bool Comp(InterpState &S, CodePtr OpPC) {
427*12c85518Srobert   const T &Val = S.Stk.pop<T>();
428*12c85518Srobert   T Result;
429*12c85518Srobert   if (!T::comp(Val, &Result)) {
430*12c85518Srobert     S.Stk.push<T>(Result);
431*12c85518Srobert     return true;
432*12c85518Srobert   }
433*12c85518Srobert 
434*12c85518Srobert   return false;
435*12c85518Srobert }
436*12c85518Srobert 
437e5dd7070Spatrick //===----------------------------------------------------------------------===//
438e5dd7070Spatrick // EQ, NE, GT, GE, LT, LE
439e5dd7070Spatrick //===----------------------------------------------------------------------===//
440e5dd7070Spatrick 
441e5dd7070Spatrick using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
442e5dd7070Spatrick 
443e5dd7070Spatrick template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)444e5dd7070Spatrick bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
445e5dd7070Spatrick   using BoolT = PrimConv<PT_Bool>::T;
446e5dd7070Spatrick   const T &RHS = S.Stk.pop<T>();
447e5dd7070Spatrick   const T &LHS = S.Stk.pop<T>();
448e5dd7070Spatrick   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
449e5dd7070Spatrick   return true;
450e5dd7070Spatrick }
451e5dd7070Spatrick 
452e5dd7070Spatrick template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)453e5dd7070Spatrick bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
454e5dd7070Spatrick   return CmpHelper<T>(S, OpPC, Fn);
455e5dd7070Spatrick }
456e5dd7070Spatrick 
457e5dd7070Spatrick template <>
458e5dd7070Spatrick inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
459e5dd7070Spatrick   using BoolT = PrimConv<PT_Bool>::T;
460e5dd7070Spatrick   const Pointer &RHS = S.Stk.pop<Pointer>();
461e5dd7070Spatrick   const Pointer &LHS = S.Stk.pop<Pointer>();
462e5dd7070Spatrick 
463e5dd7070Spatrick   if (!Pointer::hasSameBase(LHS, RHS)) {
464e5dd7070Spatrick     const SourceInfo &Loc = S.Current->getSource(OpPC);
465e5dd7070Spatrick     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
466e5dd7070Spatrick     return false;
467e5dd7070Spatrick   } else {
468e5dd7070Spatrick     unsigned VL = LHS.getByteOffset();
469e5dd7070Spatrick     unsigned VR = RHS.getByteOffset();
470e5dd7070Spatrick     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
471e5dd7070Spatrick     return true;
472e5dd7070Spatrick   }
473e5dd7070Spatrick }
474e5dd7070Spatrick 
475e5dd7070Spatrick template <>
476e5dd7070Spatrick inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
477e5dd7070Spatrick   using BoolT = PrimConv<PT_Bool>::T;
478e5dd7070Spatrick   const Pointer &RHS = S.Stk.pop<Pointer>();
479e5dd7070Spatrick   const Pointer &LHS = S.Stk.pop<Pointer>();
480e5dd7070Spatrick 
481e5dd7070Spatrick   if (LHS.isZero() && RHS.isZero()) {
482e5dd7070Spatrick     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
483e5dd7070Spatrick     return true;
484e5dd7070Spatrick   }
485e5dd7070Spatrick 
486e5dd7070Spatrick   if (!Pointer::hasSameBase(LHS, RHS)) {
487e5dd7070Spatrick     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
488e5dd7070Spatrick     return true;
489e5dd7070Spatrick   } else {
490e5dd7070Spatrick     unsigned VL = LHS.getByteOffset();
491e5dd7070Spatrick     unsigned VR = RHS.getByteOffset();
492*12c85518Srobert 
493*12c85518Srobert     // In our Pointer class, a pointer to an array and a pointer to the first
494*12c85518Srobert     // element in the same array are NOT equal. They have the same Base value,
495*12c85518Srobert     // but a different Offset. This is a pretty rare case, so we fix this here
496*12c85518Srobert     // by comparing pointers to the first elements.
497*12c85518Srobert     if (LHS.inArray() && LHS.isRoot())
498*12c85518Srobert       VL = LHS.atIndex(0).getByteOffset();
499*12c85518Srobert     if (RHS.inArray() && RHS.isRoot())
500*12c85518Srobert       VR = RHS.atIndex(0).getByteOffset();
501*12c85518Srobert 
502e5dd7070Spatrick     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
503e5dd7070Spatrick     return true;
504e5dd7070Spatrick   }
505e5dd7070Spatrick }
506e5dd7070Spatrick 
507e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)508e5dd7070Spatrick bool EQ(InterpState &S, CodePtr OpPC) {
509e5dd7070Spatrick   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
510e5dd7070Spatrick     return R == ComparisonCategoryResult::Equal;
511e5dd7070Spatrick   });
512e5dd7070Spatrick }
513e5dd7070Spatrick 
514e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)515e5dd7070Spatrick bool NE(InterpState &S, CodePtr OpPC) {
516e5dd7070Spatrick   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
517e5dd7070Spatrick     return R != ComparisonCategoryResult::Equal;
518e5dd7070Spatrick   });
519e5dd7070Spatrick }
520e5dd7070Spatrick 
521e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)522e5dd7070Spatrick bool LT(InterpState &S, CodePtr OpPC) {
523e5dd7070Spatrick   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
524e5dd7070Spatrick     return R == ComparisonCategoryResult::Less;
525e5dd7070Spatrick   });
526e5dd7070Spatrick }
527e5dd7070Spatrick 
528e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)529e5dd7070Spatrick bool LE(InterpState &S, CodePtr OpPC) {
530e5dd7070Spatrick   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
531e5dd7070Spatrick     return R == ComparisonCategoryResult::Less ||
532e5dd7070Spatrick            R == ComparisonCategoryResult::Equal;
533e5dd7070Spatrick   });
534e5dd7070Spatrick }
535e5dd7070Spatrick 
536e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)537e5dd7070Spatrick bool GT(InterpState &S, CodePtr OpPC) {
538e5dd7070Spatrick   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
539e5dd7070Spatrick     return R == ComparisonCategoryResult::Greater;
540e5dd7070Spatrick   });
541e5dd7070Spatrick }
542e5dd7070Spatrick 
543e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)544e5dd7070Spatrick bool GE(InterpState &S, CodePtr OpPC) {
545e5dd7070Spatrick   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
546e5dd7070Spatrick     return R == ComparisonCategoryResult::Greater ||
547e5dd7070Spatrick            R == ComparisonCategoryResult::Equal;
548e5dd7070Spatrick   });
549e5dd7070Spatrick }
550e5dd7070Spatrick 
551e5dd7070Spatrick //===----------------------------------------------------------------------===//
552e5dd7070Spatrick // InRange
553e5dd7070Spatrick //===----------------------------------------------------------------------===//
554e5dd7070Spatrick 
555e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)556e5dd7070Spatrick bool InRange(InterpState &S, CodePtr OpPC) {
557e5dd7070Spatrick   const T RHS = S.Stk.pop<T>();
558e5dd7070Spatrick   const T LHS = S.Stk.pop<T>();
559e5dd7070Spatrick   const T Value = S.Stk.pop<T>();
560e5dd7070Spatrick 
561e5dd7070Spatrick   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
562e5dd7070Spatrick   return true;
563e5dd7070Spatrick }
564e5dd7070Spatrick 
565e5dd7070Spatrick //===----------------------------------------------------------------------===//
566e5dd7070Spatrick // Dup, Pop, Test
567e5dd7070Spatrick //===----------------------------------------------------------------------===//
568e5dd7070Spatrick 
569e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)570e5dd7070Spatrick bool Dup(InterpState &S, CodePtr OpPC) {
571e5dd7070Spatrick   S.Stk.push<T>(S.Stk.peek<T>());
572e5dd7070Spatrick   return true;
573e5dd7070Spatrick }
574e5dd7070Spatrick 
575e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)576e5dd7070Spatrick bool Pop(InterpState &S, CodePtr OpPC) {
577e5dd7070Spatrick   S.Stk.pop<T>();
578e5dd7070Spatrick   return true;
579e5dd7070Spatrick }
580e5dd7070Spatrick 
581e5dd7070Spatrick //===----------------------------------------------------------------------===//
582e5dd7070Spatrick // Const
583e5dd7070Spatrick //===----------------------------------------------------------------------===//
584e5dd7070Spatrick 
585e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)586e5dd7070Spatrick bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
587e5dd7070Spatrick   S.Stk.push<T>(Arg);
588e5dd7070Spatrick   return true;
589e5dd7070Spatrick }
590e5dd7070Spatrick 
591e5dd7070Spatrick //===----------------------------------------------------------------------===//
592e5dd7070Spatrick // Get/Set Local/Param/Global/This
593e5dd7070Spatrick //===----------------------------------------------------------------------===//
594e5dd7070Spatrick 
595e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)596e5dd7070Spatrick bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
597*12c85518Srobert   const Pointer &Ptr = S.Current->getLocalPointer(I);
598*12c85518Srobert   if (!CheckLoad(S, OpPC, Ptr))
599*12c85518Srobert     return false;
600*12c85518Srobert   S.Stk.push<T>(Ptr.deref<T>());
601e5dd7070Spatrick   return true;
602e5dd7070Spatrick }
603e5dd7070Spatrick 
604e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)605e5dd7070Spatrick bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
606e5dd7070Spatrick   S.Current->setLocal<T>(I, S.Stk.pop<T>());
607e5dd7070Spatrick   return true;
608e5dd7070Spatrick }
609e5dd7070Spatrick 
610e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)611e5dd7070Spatrick bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
612e5dd7070Spatrick   if (S.checkingPotentialConstantExpression()) {
613e5dd7070Spatrick     return false;
614e5dd7070Spatrick   }
615e5dd7070Spatrick   S.Stk.push<T>(S.Current->getParam<T>(I));
616e5dd7070Spatrick   return true;
617e5dd7070Spatrick }
618e5dd7070Spatrick 
619e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)620e5dd7070Spatrick bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
621e5dd7070Spatrick   S.Current->setParam<T>(I, S.Stk.pop<T>());
622e5dd7070Spatrick   return true;
623e5dd7070Spatrick }
624e5dd7070Spatrick 
625*12c85518Srobert /// 1) Peeks a pointer on the stack
626*12c85518Srobert /// 2) Pushes the value of the pointer's field on the stack
627e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)628e5dd7070Spatrick bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
629e5dd7070Spatrick   const Pointer &Obj = S.Stk.peek<Pointer>();
630e5dd7070Spatrick   if (!CheckNull(S, OpPC, Obj, CSK_Field))
631e5dd7070Spatrick       return false;
632e5dd7070Spatrick   if (!CheckRange(S, OpPC, Obj, CSK_Field))
633e5dd7070Spatrick     return false;
634e5dd7070Spatrick   const Pointer &Field = Obj.atField(I);
635e5dd7070Spatrick   if (!CheckLoad(S, OpPC, Field))
636e5dd7070Spatrick     return false;
637e5dd7070Spatrick   S.Stk.push<T>(Field.deref<T>());
638e5dd7070Spatrick   return true;
639e5dd7070Spatrick }
640e5dd7070Spatrick 
641e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)642e5dd7070Spatrick bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
643e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
644e5dd7070Spatrick   const Pointer &Obj = S.Stk.peek<Pointer>();
645e5dd7070Spatrick   if (!CheckNull(S, OpPC, Obj, CSK_Field))
646e5dd7070Spatrick     return false;
647e5dd7070Spatrick   if (!CheckRange(S, OpPC, Obj, CSK_Field))
648e5dd7070Spatrick     return false;
649e5dd7070Spatrick   const Pointer &Field = Obj.atField(I);
650e5dd7070Spatrick   if (!CheckStore(S, OpPC, Field))
651e5dd7070Spatrick     return false;
652e5dd7070Spatrick   Field.deref<T>() = Value;
653e5dd7070Spatrick   return true;
654e5dd7070Spatrick }
655e5dd7070Spatrick 
656*12c85518Srobert /// 1) Pops a pointer from the stack
657*12c85518Srobert /// 2) Pushes the value of the pointer's field on the stack
658e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)659e5dd7070Spatrick bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
660e5dd7070Spatrick   const Pointer &Obj = S.Stk.pop<Pointer>();
661e5dd7070Spatrick   if (!CheckNull(S, OpPC, Obj, CSK_Field))
662e5dd7070Spatrick     return false;
663e5dd7070Spatrick   if (!CheckRange(S, OpPC, Obj, CSK_Field))
664e5dd7070Spatrick     return false;
665e5dd7070Spatrick   const Pointer &Field = Obj.atField(I);
666e5dd7070Spatrick   if (!CheckLoad(S, OpPC, Field))
667e5dd7070Spatrick     return false;
668e5dd7070Spatrick   S.Stk.push<T>(Field.deref<T>());
669e5dd7070Spatrick   return true;
670e5dd7070Spatrick }
671e5dd7070Spatrick 
672e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)673e5dd7070Spatrick bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
674e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
675e5dd7070Spatrick     return false;
676e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
677e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
678e5dd7070Spatrick     return false;
679e5dd7070Spatrick   const Pointer &Field = This.atField(I);
680e5dd7070Spatrick   if (!CheckLoad(S, OpPC, Field))
681e5dd7070Spatrick     return false;
682e5dd7070Spatrick   S.Stk.push<T>(Field.deref<T>());
683e5dd7070Spatrick   return true;
684e5dd7070Spatrick }
685e5dd7070Spatrick 
686e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)687e5dd7070Spatrick bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
688e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
689e5dd7070Spatrick     return false;
690e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
691e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
692e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
693e5dd7070Spatrick     return false;
694e5dd7070Spatrick   const Pointer &Field = This.atField(I);
695e5dd7070Spatrick   if (!CheckStore(S, OpPC, Field))
696e5dd7070Spatrick     return false;
697e5dd7070Spatrick   Field.deref<T>() = Value;
698e5dd7070Spatrick   return true;
699e5dd7070Spatrick }
700e5dd7070Spatrick 
701e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)702e5dd7070Spatrick bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
703e5dd7070Spatrick   auto *B = S.P.getGlobal(I);
704e5dd7070Spatrick   if (B->isExtern())
705e5dd7070Spatrick     return false;
706e5dd7070Spatrick   S.Stk.push<T>(B->deref<T>());
707e5dd7070Spatrick   return true;
708e5dd7070Spatrick }
709e5dd7070Spatrick 
710e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)711e5dd7070Spatrick bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
712e5dd7070Spatrick   // TODO: emit warning.
713e5dd7070Spatrick   return false;
714e5dd7070Spatrick }
715e5dd7070Spatrick 
716e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)717e5dd7070Spatrick bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
718e5dd7070Spatrick   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
719e5dd7070Spatrick   return true;
720e5dd7070Spatrick }
721e5dd7070Spatrick 
722e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)723e5dd7070Spatrick bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
724e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
725e5dd7070Spatrick     return false;
726e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
727e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
728e5dd7070Spatrick     return false;
729e5dd7070Spatrick   const Pointer &Field = This.atField(I);
730e5dd7070Spatrick   Field.deref<T>() = S.Stk.pop<T>();
731e5dd7070Spatrick   Field.initialize();
732e5dd7070Spatrick   return true;
733e5dd7070Spatrick }
734e5dd7070Spatrick 
735e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)736e5dd7070Spatrick bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
737e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
738e5dd7070Spatrick     return false;
739e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
740e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
741e5dd7070Spatrick     return false;
742e5dd7070Spatrick   const Pointer &Field = This.atField(F->Offset);
743e5dd7070Spatrick   const auto &Value = S.Stk.pop<T>();
744e5dd7070Spatrick   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
745e5dd7070Spatrick   Field.initialize();
746e5dd7070Spatrick   return true;
747e5dd7070Spatrick }
748e5dd7070Spatrick 
749e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)750e5dd7070Spatrick bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
751e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
752e5dd7070Spatrick     return false;
753e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
754e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
755e5dd7070Spatrick     return false;
756e5dd7070Spatrick   const Pointer &Field = This.atField(I);
757e5dd7070Spatrick   Field.deref<T>() = S.Stk.pop<T>();
758e5dd7070Spatrick   Field.activate();
759e5dd7070Spatrick   Field.initialize();
760e5dd7070Spatrick   return true;
761e5dd7070Spatrick }
762e5dd7070Spatrick 
763*12c85518Srobert /// 1) Pops the value from the stack
764*12c85518Srobert /// 2) Peeks a pointer from the stack
765*12c85518Srobert /// 3) Pushes the value to field I of the pointer on the stack
766e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)767e5dd7070Spatrick bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
768e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
769*12c85518Srobert   const Pointer &Field = S.Stk.peek<Pointer>().atField(I);
770e5dd7070Spatrick   Field.deref<T>() = Value;
771e5dd7070Spatrick   Field.activate();
772e5dd7070Spatrick   Field.initialize();
773e5dd7070Spatrick   return true;
774e5dd7070Spatrick }
775e5dd7070Spatrick 
776e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)777e5dd7070Spatrick bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
778e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
779e5dd7070Spatrick   const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
780e5dd7070Spatrick   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
781e5dd7070Spatrick   Field.activate();
782e5dd7070Spatrick   Field.initialize();
783e5dd7070Spatrick   return true;
784e5dd7070Spatrick }
785e5dd7070Spatrick 
786e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)787e5dd7070Spatrick bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
788e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
789e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
790e5dd7070Spatrick   const Pointer &Field = Ptr.atField(I);
791e5dd7070Spatrick   Field.deref<T>() = Value;
792e5dd7070Spatrick   Field.activate();
793e5dd7070Spatrick   Field.initialize();
794e5dd7070Spatrick   return true;
795e5dd7070Spatrick }
796e5dd7070Spatrick 
797e5dd7070Spatrick //===----------------------------------------------------------------------===//
798e5dd7070Spatrick // GetPtr Local/Param/Global/Field/This
799e5dd7070Spatrick //===----------------------------------------------------------------------===//
800e5dd7070Spatrick 
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)801e5dd7070Spatrick inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
802e5dd7070Spatrick   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
803e5dd7070Spatrick   return true;
804e5dd7070Spatrick }
805e5dd7070Spatrick 
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)806e5dd7070Spatrick inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
807e5dd7070Spatrick   if (S.checkingPotentialConstantExpression()) {
808e5dd7070Spatrick     return false;
809e5dd7070Spatrick   }
810e5dd7070Spatrick   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
811e5dd7070Spatrick   return true;
812e5dd7070Spatrick }
813e5dd7070Spatrick 
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)814e5dd7070Spatrick inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
815e5dd7070Spatrick   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
816e5dd7070Spatrick   return true;
817e5dd7070Spatrick }
818e5dd7070Spatrick 
819*12c85518Srobert /// 1) Pops a Pointer from the stack
820*12c85518Srobert /// 2) Pushes Pointer.atField(Off) on the stack
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)821e5dd7070Spatrick inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
822e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
823e5dd7070Spatrick   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
824e5dd7070Spatrick     return false;
825e5dd7070Spatrick   if (!CheckExtern(S, OpPC, Ptr))
826e5dd7070Spatrick     return false;
827e5dd7070Spatrick   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
828e5dd7070Spatrick     return false;
829e5dd7070Spatrick   S.Stk.push<Pointer>(Ptr.atField(Off));
830e5dd7070Spatrick   return true;
831e5dd7070Spatrick }
832e5dd7070Spatrick 
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)833e5dd7070Spatrick inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
834e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
835e5dd7070Spatrick     return false;
836e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
837e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
838e5dd7070Spatrick     return false;
839e5dd7070Spatrick   S.Stk.push<Pointer>(This.atField(Off));
840e5dd7070Spatrick   return true;
841e5dd7070Spatrick }
842e5dd7070Spatrick 
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)843e5dd7070Spatrick inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
844e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
845e5dd7070Spatrick   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
846e5dd7070Spatrick     return false;
847e5dd7070Spatrick   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
848e5dd7070Spatrick     return false;
849e5dd7070Spatrick   Pointer Field = Ptr.atField(Off);
850e5dd7070Spatrick   Ptr.deactivate();
851e5dd7070Spatrick   Field.activate();
852e5dd7070Spatrick   S.Stk.push<Pointer>(std::move(Field));
853e5dd7070Spatrick   return true;
854e5dd7070Spatrick }
855e5dd7070Spatrick 
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)856e5dd7070Spatrick inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
857e5dd7070Spatrick  if (S.checkingPotentialConstantExpression())
858e5dd7070Spatrick     return false;
859e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
860e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
861e5dd7070Spatrick     return false;
862e5dd7070Spatrick   Pointer Field = This.atField(Off);
863e5dd7070Spatrick   This.deactivate();
864e5dd7070Spatrick   Field.activate();
865e5dd7070Spatrick   S.Stk.push<Pointer>(std::move(Field));
866e5dd7070Spatrick   return true;
867e5dd7070Spatrick }
868e5dd7070Spatrick 
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)869e5dd7070Spatrick inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
870e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
871e5dd7070Spatrick   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
872e5dd7070Spatrick     return false;
873e5dd7070Spatrick   S.Stk.push<Pointer>(Ptr.atField(Off));
874e5dd7070Spatrick   return true;
875e5dd7070Spatrick }
876e5dd7070Spatrick 
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)877e5dd7070Spatrick inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
878e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
879e5dd7070Spatrick     return false;
880e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
881e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
882e5dd7070Spatrick     return false;
883e5dd7070Spatrick   S.Stk.push<Pointer>(This.atField(Off));
884e5dd7070Spatrick   return true;
885e5dd7070Spatrick }
886e5dd7070Spatrick 
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)887e5dd7070Spatrick inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
888e5dd7070Spatrick                            const Pointer &Ptr) {
889e5dd7070Spatrick   Pointer Base = Ptr;
890e5dd7070Spatrick   while (Base.isBaseClass())
891e5dd7070Spatrick     Base = Base.getBase();
892e5dd7070Spatrick 
893e5dd7070Spatrick   auto *Field = Base.getRecord()->getVirtualBase(Decl);
894e5dd7070Spatrick   S.Stk.push<Pointer>(Base.atField(Field->Offset));
895e5dd7070Spatrick   return true;
896e5dd7070Spatrick }
897e5dd7070Spatrick 
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)898e5dd7070Spatrick inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
899e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
900e5dd7070Spatrick   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
901e5dd7070Spatrick     return false;
902e5dd7070Spatrick   return VirtBaseHelper(S, OpPC, D, Ptr);
903e5dd7070Spatrick }
904e5dd7070Spatrick 
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)905e5dd7070Spatrick inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
906e5dd7070Spatrick                                const RecordDecl *D) {
907e5dd7070Spatrick   if (S.checkingPotentialConstantExpression())
908e5dd7070Spatrick     return false;
909e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
910e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
911e5dd7070Spatrick     return false;
912e5dd7070Spatrick   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
913e5dd7070Spatrick }
914e5dd7070Spatrick 
915e5dd7070Spatrick //===----------------------------------------------------------------------===//
916e5dd7070Spatrick // Load, Store, Init
917e5dd7070Spatrick //===----------------------------------------------------------------------===//
918e5dd7070Spatrick 
919e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)920e5dd7070Spatrick bool Load(InterpState &S, CodePtr OpPC) {
921e5dd7070Spatrick   const Pointer &Ptr = S.Stk.peek<Pointer>();
922e5dd7070Spatrick   if (!CheckLoad(S, OpPC, Ptr))
923e5dd7070Spatrick     return false;
924e5dd7070Spatrick   S.Stk.push<T>(Ptr.deref<T>());
925e5dd7070Spatrick   return true;
926e5dd7070Spatrick }
927e5dd7070Spatrick 
928e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)929e5dd7070Spatrick bool LoadPop(InterpState &S, CodePtr OpPC) {
930e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
931e5dd7070Spatrick   if (!CheckLoad(S, OpPC, Ptr))
932e5dd7070Spatrick     return false;
933e5dd7070Spatrick   S.Stk.push<T>(Ptr.deref<T>());
934e5dd7070Spatrick   return true;
935e5dd7070Spatrick }
936e5dd7070Spatrick 
937e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)938e5dd7070Spatrick bool Store(InterpState &S, CodePtr OpPC) {
939e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
940e5dd7070Spatrick   const Pointer &Ptr = S.Stk.peek<Pointer>();
941e5dd7070Spatrick   if (!CheckStore(S, OpPC, Ptr))
942e5dd7070Spatrick     return false;
943*12c85518Srobert   if (!Ptr.isRoot())
944*12c85518Srobert     Ptr.initialize();
945e5dd7070Spatrick   Ptr.deref<T>() = Value;
946e5dd7070Spatrick   return true;
947e5dd7070Spatrick }
948e5dd7070Spatrick 
949e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)950e5dd7070Spatrick bool StorePop(InterpState &S, CodePtr OpPC) {
951e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
952e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
953e5dd7070Spatrick   if (!CheckStore(S, OpPC, Ptr))
954e5dd7070Spatrick     return false;
955*12c85518Srobert   if (!Ptr.isRoot())
956*12c85518Srobert     Ptr.initialize();
957e5dd7070Spatrick   Ptr.deref<T>() = Value;
958e5dd7070Spatrick   return true;
959e5dd7070Spatrick }
960e5dd7070Spatrick 
961e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)962e5dd7070Spatrick bool StoreBitField(InterpState &S, CodePtr OpPC) {
963e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
964e5dd7070Spatrick   const Pointer &Ptr = S.Stk.peek<Pointer>();
965e5dd7070Spatrick   if (!CheckStore(S, OpPC, Ptr))
966e5dd7070Spatrick     return false;
967*12c85518Srobert   if (!Ptr.isRoot())
968*12c85518Srobert     Ptr.initialize();
969e5dd7070Spatrick   if (auto *FD = Ptr.getField()) {
970e5dd7070Spatrick     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
971e5dd7070Spatrick   } else {
972e5dd7070Spatrick     Ptr.deref<T>() = Value;
973e5dd7070Spatrick   }
974e5dd7070Spatrick   return true;
975e5dd7070Spatrick }
976e5dd7070Spatrick 
977e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)978e5dd7070Spatrick bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
979e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
980e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
981e5dd7070Spatrick   if (!CheckStore(S, OpPC, Ptr))
982e5dd7070Spatrick     return false;
983*12c85518Srobert   if (!Ptr.isRoot())
984*12c85518Srobert     Ptr.initialize();
985e5dd7070Spatrick   if (auto *FD = Ptr.getField()) {
986e5dd7070Spatrick     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
987e5dd7070Spatrick   } else {
988e5dd7070Spatrick     Ptr.deref<T>() = Value;
989e5dd7070Spatrick   }
990e5dd7070Spatrick   return true;
991e5dd7070Spatrick }
992e5dd7070Spatrick 
993e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)994e5dd7070Spatrick bool InitPop(InterpState &S, CodePtr OpPC) {
995e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
996e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
997e5dd7070Spatrick   if (!CheckInit(S, OpPC, Ptr))
998e5dd7070Spatrick     return false;
999e5dd7070Spatrick   Ptr.initialize();
1000e5dd7070Spatrick   new (&Ptr.deref<T>()) T(Value);
1001e5dd7070Spatrick   return true;
1002e5dd7070Spatrick }
1003e5dd7070Spatrick 
1004*12c85518Srobert /// 1) Pops the value from the stack
1005*12c85518Srobert /// 2) Peeks a pointer and gets its index \Idx
1006*12c85518Srobert /// 3) Sets the value on the pointer, leaving the pointer on the stack.
1007e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)1008e5dd7070Spatrick bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1009e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
1010e5dd7070Spatrick   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
1011e5dd7070Spatrick   if (!CheckInit(S, OpPC, Ptr))
1012e5dd7070Spatrick     return false;
1013e5dd7070Spatrick   Ptr.initialize();
1014e5dd7070Spatrick   new (&Ptr.deref<T>()) T(Value);
1015e5dd7070Spatrick   return true;
1016e5dd7070Spatrick }
1017e5dd7070Spatrick 
1018*12c85518Srobert /// The same as InitElem, but pops the pointer as well.
1019e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)1020e5dd7070Spatrick bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
1021e5dd7070Spatrick   const T &Value = S.Stk.pop<T>();
1022e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
1023e5dd7070Spatrick   if (!CheckInit(S, OpPC, Ptr))
1024e5dd7070Spatrick     return false;
1025e5dd7070Spatrick   Ptr.initialize();
1026e5dd7070Spatrick   new (&Ptr.deref<T>()) T(Value);
1027e5dd7070Spatrick   return true;
1028e5dd7070Spatrick }
1029e5dd7070Spatrick 
1030e5dd7070Spatrick //===----------------------------------------------------------------------===//
1031e5dd7070Spatrick // AddOffset, SubOffset
1032e5dd7070Spatrick //===----------------------------------------------------------------------===//
1033e5dd7070Spatrick 
OffsetHelper(InterpState & S,CodePtr OpPC)1034e5dd7070Spatrick template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
1035e5dd7070Spatrick   // Fetch the pointer and the offset.
1036e5dd7070Spatrick   const T &Offset = S.Stk.pop<T>();
1037e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
1038*12c85518Srobert 
1039e5dd7070Spatrick   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
1040e5dd7070Spatrick     return false;
1041e5dd7070Spatrick 
1042*12c85518Srobert   // A zero offset does not change the pointer.
1043e5dd7070Spatrick   if (Offset.isZero()) {
1044*12c85518Srobert     S.Stk.push<Pointer>(Ptr);
1045e5dd7070Spatrick     return true;
1046e5dd7070Spatrick   }
1047*12c85518Srobert 
1048*12c85518Srobert   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
1049*12c85518Srobert     return false;
1050*12c85518Srobert 
1051e5dd7070Spatrick   // Arrays of unknown bounds cannot have pointers into them.
1052e5dd7070Spatrick   if (!CheckArray(S, OpPC, Ptr))
1053e5dd7070Spatrick     return false;
1054e5dd7070Spatrick 
1055*12c85518Srobert   // Get a version of the index comparable to the type.
1056*12c85518Srobert   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
1057e5dd7070Spatrick   // Compute the largest index into the array.
1058e5dd7070Spatrick   unsigned MaxIndex = Ptr.getNumElems();
1059e5dd7070Spatrick 
1060e5dd7070Spatrick   // Helper to report an invalid offset, computed as APSInt.
1061e5dd7070Spatrick   auto InvalidOffset = [&]() {
1062e5dd7070Spatrick     const unsigned Bits = Offset.bitWidth();
1063e5dd7070Spatrick     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
1064e5dd7070Spatrick     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
1065e5dd7070Spatrick     APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
1066e5dd7070Spatrick     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
1067e5dd7070Spatrick         << NewIndex
1068e5dd7070Spatrick         << /*array*/ static_cast<int>(!Ptr.inArray())
1069e5dd7070Spatrick         << static_cast<unsigned>(MaxIndex);
1070e5dd7070Spatrick     return false;
1071e5dd7070Spatrick   };
1072e5dd7070Spatrick 
1073*12c85518Srobert   unsigned MaxOffset = MaxIndex - Ptr.getIndex();
1074*12c85518Srobert   if constexpr (Add) {
1075e5dd7070Spatrick     // If the new offset would be negative, bail out.
1076*12c85518Srobert     if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
1077e5dd7070Spatrick       return InvalidOffset();
1078e5dd7070Spatrick 
1079e5dd7070Spatrick     // If the new offset would be out of bounds, bail out.
1080*12c85518Srobert     if (Offset.isPositive() && Offset > MaxOffset)
1081e5dd7070Spatrick       return InvalidOffset();
1082*12c85518Srobert   } else {
1083*12c85518Srobert     // If the new offset would be negative, bail out.
1084*12c85518Srobert     if (Offset.isPositive() && Index < Offset)
1085e5dd7070Spatrick       return InvalidOffset();
1086e5dd7070Spatrick 
1087*12c85518Srobert     // If the new offset would be out of bounds, bail out.
1088*12c85518Srobert     if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
1089*12c85518Srobert       return InvalidOffset();
1090*12c85518Srobert   }
1091*12c85518Srobert 
1092e5dd7070Spatrick   // Offset is valid - compute it on unsigned.
1093e5dd7070Spatrick   int64_t WideIndex = static_cast<int64_t>(Index);
1094e5dd7070Spatrick   int64_t WideOffset = static_cast<int64_t>(Offset);
1095*12c85518Srobert   int64_t Result;
1096*12c85518Srobert   if constexpr (Add)
1097*12c85518Srobert     Result = WideIndex + WideOffset;
1098*12c85518Srobert   else
1099*12c85518Srobert     Result = WideIndex - WideOffset;
1100*12c85518Srobert 
1101e5dd7070Spatrick   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
1102e5dd7070Spatrick   return true;
1103e5dd7070Spatrick }
1104e5dd7070Spatrick 
1105e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)1106e5dd7070Spatrick bool AddOffset(InterpState &S, CodePtr OpPC) {
1107e5dd7070Spatrick   return OffsetHelper<T, true>(S, OpPC);
1108e5dd7070Spatrick }
1109e5dd7070Spatrick 
1110e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)1111e5dd7070Spatrick bool SubOffset(InterpState &S, CodePtr OpPC) {
1112e5dd7070Spatrick   return OffsetHelper<T, false>(S, OpPC);
1113e5dd7070Spatrick }
1114e5dd7070Spatrick 
1115*12c85518Srobert /// 1) Pops a Pointer from the stack.
1116*12c85518Srobert /// 2) Pops another Pointer from the stack.
1117*12c85518Srobert /// 3) Pushes the different of the indices of the two pointers on the stack.
1118*12c85518Srobert template <PrimType Name, class T = typename PrimConv<Name>::T>
SubPtr(InterpState & S,CodePtr OpPC)1119*12c85518Srobert inline bool SubPtr(InterpState &S, CodePtr OpPC) {
1120*12c85518Srobert   const Pointer &LHS = S.Stk.pop<Pointer>();
1121*12c85518Srobert   const Pointer &RHS = S.Stk.pop<Pointer>();
1122*12c85518Srobert 
1123*12c85518Srobert   if (!Pointer::hasSameArray(LHS, RHS)) {
1124*12c85518Srobert     // TODO: Diagnose.
1125*12c85518Srobert     return false;
1126*12c85518Srobert   }
1127*12c85518Srobert 
1128*12c85518Srobert   T A = T::from(LHS.getIndex());
1129*12c85518Srobert   T B = T::from(RHS.getIndex());
1130*12c85518Srobert   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);
1131*12c85518Srobert }
1132e5dd7070Spatrick 
1133e5dd7070Spatrick //===----------------------------------------------------------------------===//
1134e5dd7070Spatrick // Destroy
1135e5dd7070Spatrick //===----------------------------------------------------------------------===//
1136e5dd7070Spatrick 
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)1137e5dd7070Spatrick inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
1138e5dd7070Spatrick   S.Current->destroy(I);
1139e5dd7070Spatrick   return true;
1140e5dd7070Spatrick }
1141e5dd7070Spatrick 
1142e5dd7070Spatrick //===----------------------------------------------------------------------===//
1143e5dd7070Spatrick // Cast, CastFP
1144e5dd7070Spatrick //===----------------------------------------------------------------------===//
1145e5dd7070Spatrick 
Cast(InterpState & S,CodePtr OpPC)1146e5dd7070Spatrick template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
1147e5dd7070Spatrick   using T = typename PrimConv<TIn>::T;
1148e5dd7070Spatrick   using U = typename PrimConv<TOut>::T;
1149e5dd7070Spatrick   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
1150e5dd7070Spatrick   return true;
1151e5dd7070Spatrick }
1152e5dd7070Spatrick 
1153e5dd7070Spatrick //===----------------------------------------------------------------------===//
1154e5dd7070Spatrick // Zero, Nullptr
1155e5dd7070Spatrick //===----------------------------------------------------------------------===//
1156e5dd7070Spatrick 
1157e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)1158e5dd7070Spatrick bool Zero(InterpState &S, CodePtr OpPC) {
1159e5dd7070Spatrick   S.Stk.push<T>(T::zero());
1160e5dd7070Spatrick   return true;
1161e5dd7070Spatrick }
1162e5dd7070Spatrick 
1163e5dd7070Spatrick template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)1164e5dd7070Spatrick inline bool Null(InterpState &S, CodePtr OpPC) {
1165e5dd7070Spatrick   S.Stk.push<T>();
1166e5dd7070Spatrick   return true;
1167e5dd7070Spatrick }
1168e5dd7070Spatrick 
1169e5dd7070Spatrick //===----------------------------------------------------------------------===//
1170e5dd7070Spatrick // This, ImplicitThis
1171e5dd7070Spatrick //===----------------------------------------------------------------------===//
1172e5dd7070Spatrick 
This(InterpState & S,CodePtr OpPC)1173e5dd7070Spatrick inline bool This(InterpState &S, CodePtr OpPC) {
1174e5dd7070Spatrick   // Cannot read 'this' in this mode.
1175e5dd7070Spatrick   if (S.checkingPotentialConstantExpression()) {
1176e5dd7070Spatrick     return false;
1177e5dd7070Spatrick   }
1178e5dd7070Spatrick 
1179e5dd7070Spatrick   const Pointer &This = S.Current->getThis();
1180e5dd7070Spatrick   if (!CheckThis(S, OpPC, This))
1181e5dd7070Spatrick     return false;
1182e5dd7070Spatrick 
1183e5dd7070Spatrick   S.Stk.push<Pointer>(This);
1184e5dd7070Spatrick   return true;
1185e5dd7070Spatrick }
1186e5dd7070Spatrick 
RVOPtr(InterpState & S,CodePtr OpPC)1187*12c85518Srobert inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
1188*12c85518Srobert   assert(S.Current->getFunction()->hasRVO());
1189*12c85518Srobert   S.Stk.push<Pointer>(S.Current->getRVOPtr());
1190*12c85518Srobert   return true;
1191*12c85518Srobert }
1192*12c85518Srobert 
1193e5dd7070Spatrick //===----------------------------------------------------------------------===//
1194e5dd7070Spatrick // Shr, Shl
1195e5dd7070Spatrick //===----------------------------------------------------------------------===//
1196e5dd7070Spatrick 
1197*12c85518Srobert template <PrimType NameL, PrimType NameR>
Shr(InterpState & S,CodePtr OpPC)1198e5dd7070Spatrick inline bool Shr(InterpState &S, CodePtr OpPC) {
1199*12c85518Srobert   using LT = typename PrimConv<NameL>::T;
1200*12c85518Srobert   using RT = typename PrimConv<NameR>::T;
1201*12c85518Srobert   const auto &RHS = S.Stk.pop<RT>();
1202*12c85518Srobert   const auto &LHS = S.Stk.pop<LT>();
1203e5dd7070Spatrick   const unsigned Bits = LHS.bitWidth();
1204e5dd7070Spatrick 
1205*12c85518Srobert   if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1206*12c85518Srobert     return false;
1207*12c85518Srobert 
1208*12c85518Srobert   unsigned URHS = static_cast<unsigned>(RHS);
1209*12c85518Srobert   S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
1210*12c85518Srobert   return true;
1211e5dd7070Spatrick }
1212e5dd7070Spatrick 
1213*12c85518Srobert template <PrimType NameL, PrimType NameR>
Shl(InterpState & S,CodePtr OpPC)1214e5dd7070Spatrick inline bool Shl(InterpState &S, CodePtr OpPC) {
1215*12c85518Srobert   using LT = typename PrimConv<NameL>::T;
1216*12c85518Srobert   using RT = typename PrimConv<NameR>::T;
1217*12c85518Srobert   const auto &RHS = S.Stk.pop<RT>();
1218*12c85518Srobert   const auto &LHS = S.Stk.pop<LT>();
1219e5dd7070Spatrick   const unsigned Bits = LHS.bitWidth();
1220e5dd7070Spatrick 
1221*12c85518Srobert   if (!CheckShift<RT>(S, OpPC, RHS, Bits))
1222*12c85518Srobert     return false;
1223*12c85518Srobert 
1224*12c85518Srobert   unsigned URHS = static_cast<unsigned>(RHS);
1225*12c85518Srobert   S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
1226*12c85518Srobert 
1227*12c85518Srobert   return true;
1228e5dd7070Spatrick }
1229e5dd7070Spatrick 
1230e5dd7070Spatrick //===----------------------------------------------------------------------===//
1231e5dd7070Spatrick // NoRet
1232e5dd7070Spatrick //===----------------------------------------------------------------------===//
1233e5dd7070Spatrick 
NoRet(InterpState & S,CodePtr OpPC)1234e5dd7070Spatrick inline bool NoRet(InterpState &S, CodePtr OpPC) {
1235e5dd7070Spatrick   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
1236e5dd7070Spatrick   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
1237e5dd7070Spatrick   return false;
1238e5dd7070Spatrick }
1239e5dd7070Spatrick 
1240e5dd7070Spatrick //===----------------------------------------------------------------------===//
1241e5dd7070Spatrick // NarrowPtr, ExpandPtr
1242e5dd7070Spatrick //===----------------------------------------------------------------------===//
1243e5dd7070Spatrick 
NarrowPtr(InterpState & S,CodePtr OpPC)1244e5dd7070Spatrick inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
1245e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
1246e5dd7070Spatrick   S.Stk.push<Pointer>(Ptr.narrow());
1247e5dd7070Spatrick   return true;
1248e5dd7070Spatrick }
1249e5dd7070Spatrick 
ExpandPtr(InterpState & S,CodePtr OpPC)1250e5dd7070Spatrick inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
1251e5dd7070Spatrick   const Pointer &Ptr = S.Stk.pop<Pointer>();
1252e5dd7070Spatrick   S.Stk.push<Pointer>(Ptr.expand());
1253e5dd7070Spatrick   return true;
1254e5dd7070Spatrick }
1255e5dd7070Spatrick 
Call(InterpState & S,CodePtr & PC,const Function * Func)1256*12c85518Srobert inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) {
1257*12c85518Srobert   auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);
1258*12c85518Srobert   Pointer ThisPtr;
1259*12c85518Srobert   if (Func->hasThisPointer()) {
1260*12c85518Srobert     ThisPtr = NewFrame->getThis();
1261*12c85518Srobert     if (!CheckInvoke(S, PC, ThisPtr)) {
1262*12c85518Srobert       return false;
1263*12c85518Srobert     }
1264*12c85518Srobert   }
1265*12c85518Srobert 
1266*12c85518Srobert   if (!CheckCallable(S, PC, Func))
1267*12c85518Srobert     return false;
1268*12c85518Srobert 
1269*12c85518Srobert   InterpFrame *FrameBefore = S.Current;
1270*12c85518Srobert   S.Current = NewFrame.get();
1271*12c85518Srobert 
1272*12c85518Srobert   APValue CallResult;
1273*12c85518Srobert   // Note that we cannot assert(CallResult.hasValue()) here since
1274*12c85518Srobert   // Ret() above only sets the APValue if the curent frame doesn't
1275*12c85518Srobert   // have a caller set.
1276*12c85518Srobert   if (Interpret(S, CallResult)) {
1277*12c85518Srobert     NewFrame.release(); // Frame was delete'd already.
1278*12c85518Srobert     assert(S.Current == FrameBefore);
1279*12c85518Srobert 
1280*12c85518Srobert     // For constructors, check that all fields have been initialized.
1281*12c85518Srobert     if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr))
1282*12c85518Srobert       return false;
1283*12c85518Srobert 
1284*12c85518Srobert     return true;
1285*12c85518Srobert   }
1286*12c85518Srobert 
1287*12c85518Srobert   // Interpreting the function failed somehow. Reset to
1288*12c85518Srobert   // previous state.
1289*12c85518Srobert   S.Current = FrameBefore;
1290*12c85518Srobert   return false;
1291*12c85518Srobert }
1292*12c85518Srobert 
1293*12c85518Srobert //===----------------------------------------------------------------------===//
1294*12c85518Srobert // Read opcode arguments
1295*12c85518Srobert //===----------------------------------------------------------------------===//
1296*12c85518Srobert 
ReadArg(InterpState & S,CodePtr & OpPC)1297*12c85518Srobert template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {
1298*12c85518Srobert   if constexpr (std::is_pointer<T>::value) {
1299*12c85518Srobert     uint32_t ID = OpPC.read<uint32_t>();
1300*12c85518Srobert     return reinterpret_cast<T>(S.P.getNativePointer(ID));
1301*12c85518Srobert   } else {
1302*12c85518Srobert     return OpPC.read<T>();
1303*12c85518Srobert   }
1304*12c85518Srobert }
1305e5dd7070Spatrick 
1306e5dd7070Spatrick } // namespace interp
1307e5dd7070Spatrick } // namespace clang
1308e5dd7070Spatrick 
1309e5dd7070Spatrick #endif
1310