106f32e7eSjoerg //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg //
906f32e7eSjoerg // Definition of the interpreter state and entry point.
1006f32e7eSjoerg //
1106f32e7eSjoerg //===----------------------------------------------------------------------===//
1206f32e7eSjoerg 
1306f32e7eSjoerg #ifndef LLVM_CLANG_AST_INTERP_INTERP_H
1406f32e7eSjoerg #define LLVM_CLANG_AST_INTERP_INTERP_H
1506f32e7eSjoerg 
1606f32e7eSjoerg #include <limits>
1706f32e7eSjoerg #include <vector>
1806f32e7eSjoerg #include "Function.h"
1906f32e7eSjoerg #include "InterpFrame.h"
2006f32e7eSjoerg #include "InterpStack.h"
2106f32e7eSjoerg #include "InterpState.h"
2206f32e7eSjoerg #include "Opcode.h"
2306f32e7eSjoerg #include "PrimType.h"
2406f32e7eSjoerg #include "Program.h"
2506f32e7eSjoerg #include "State.h"
2606f32e7eSjoerg #include "clang/AST/ASTContext.h"
2706f32e7eSjoerg #include "clang/AST/ASTDiagnostic.h"
2806f32e7eSjoerg #include "clang/AST/CXXInheritance.h"
2906f32e7eSjoerg #include "clang/AST/Expr.h"
3006f32e7eSjoerg #include "llvm/ADT/APFloat.h"
3106f32e7eSjoerg #include "llvm/ADT/APSInt.h"
3206f32e7eSjoerg #include "llvm/Support/Endian.h"
3306f32e7eSjoerg 
3406f32e7eSjoerg namespace clang {
3506f32e7eSjoerg namespace interp {
3606f32e7eSjoerg 
3706f32e7eSjoerg using APInt = llvm::APInt;
3806f32e7eSjoerg using APSInt = llvm::APSInt;
3906f32e7eSjoerg 
4006f32e7eSjoerg /// Convers a value to an APValue.
ReturnValue(const T & V,APValue & R)4106f32e7eSjoerg template <typename T> bool ReturnValue(const T &V, APValue &R) {
4206f32e7eSjoerg   R = V.toAPValue();
4306f32e7eSjoerg   return true;
4406f32e7eSjoerg }
4506f32e7eSjoerg 
4606f32e7eSjoerg /// Checks if the variable has externally defined storage.
4706f32e7eSjoerg bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
4806f32e7eSjoerg 
4906f32e7eSjoerg /// Checks if the array is offsetable.
5006f32e7eSjoerg bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
5106f32e7eSjoerg 
5206f32e7eSjoerg /// Checks if a pointer is live and accesible.
5306f32e7eSjoerg bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
5406f32e7eSjoerg                AccessKinds AK);
5506f32e7eSjoerg /// Checks if a pointer is null.
5606f32e7eSjoerg bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
5706f32e7eSjoerg                CheckSubobjectKind CSK);
5806f32e7eSjoerg 
5906f32e7eSjoerg /// Checks if a pointer is in range.
6006f32e7eSjoerg bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
6106f32e7eSjoerg                 AccessKinds AK);
6206f32e7eSjoerg 
6306f32e7eSjoerg /// Checks if a field from which a pointer is going to be derived is valid.
6406f32e7eSjoerg bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
6506f32e7eSjoerg                 CheckSubobjectKind CSK);
6606f32e7eSjoerg 
6706f32e7eSjoerg /// Checks if a pointer points to const storage.
6806f32e7eSjoerg bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
6906f32e7eSjoerg 
7006f32e7eSjoerg /// Checks if a pointer points to a mutable field.
7106f32e7eSjoerg bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
7206f32e7eSjoerg 
7306f32e7eSjoerg /// Checks if a value can be loaded from a block.
7406f32e7eSjoerg bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
7506f32e7eSjoerg 
7606f32e7eSjoerg /// Checks if a value can be stored in a block.
7706f32e7eSjoerg bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
7806f32e7eSjoerg 
7906f32e7eSjoerg /// Checks if a method can be invoked on an object.
8006f32e7eSjoerg bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
8106f32e7eSjoerg 
8206f32e7eSjoerg /// Checks if a value can be initialized.
8306f32e7eSjoerg bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);
8406f32e7eSjoerg 
8506f32e7eSjoerg /// Checks if a method can be called.
8606f32e7eSjoerg bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F);
8706f32e7eSjoerg 
8806f32e7eSjoerg /// Checks the 'this' pointer.
8906f32e7eSjoerg bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
9006f32e7eSjoerg 
9106f32e7eSjoerg /// Checks if a method is pure virtual.
9206f32e7eSjoerg bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);
9306f32e7eSjoerg 
IsTrue(const T & V)9406f32e7eSjoerg template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); }
9506f32e7eSjoerg 
9606f32e7eSjoerg //===----------------------------------------------------------------------===//
9706f32e7eSjoerg // Add, Sub, Mul
9806f32e7eSjoerg //===----------------------------------------------------------------------===//
9906f32e7eSjoerg 
10006f32e7eSjoerg template <typename T, bool (*OpFW)(T, T, unsigned, T *),
10106f32e7eSjoerg           template <typename U> class OpAP>
AddSubMulHelper(InterpState & S,CodePtr OpPC,unsigned Bits,const T & LHS,const T & RHS)10206f32e7eSjoerg bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,
10306f32e7eSjoerg                      const T &RHS) {
10406f32e7eSjoerg   // Fast path - add the numbers with fixed width.
10506f32e7eSjoerg   T Result;
10606f32e7eSjoerg   if (!OpFW(LHS, RHS, Bits, &Result)) {
10706f32e7eSjoerg     S.Stk.push<T>(Result);
10806f32e7eSjoerg     return true;
10906f32e7eSjoerg   }
11006f32e7eSjoerg 
11106f32e7eSjoerg   // If for some reason evaluation continues, use the truncated results.
11206f32e7eSjoerg   S.Stk.push<T>(Result);
11306f32e7eSjoerg 
11406f32e7eSjoerg   // Slow path - compute the result using another bit of precision.
11506f32e7eSjoerg   APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));
11606f32e7eSjoerg 
11706f32e7eSjoerg   // Report undefined behaviour, stopping if required.
11806f32e7eSjoerg   const Expr *E = S.Current->getExpr(OpPC);
11906f32e7eSjoerg   QualType Type = E->getType();
12006f32e7eSjoerg   if (S.checkingForUndefinedBehavior()) {
12106f32e7eSjoerg     auto Trunc = Value.trunc(Result.bitWidth()).toString(10);
12206f32e7eSjoerg     auto Loc = E->getExprLoc();
12306f32e7eSjoerg     S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type;
12406f32e7eSjoerg     return true;
12506f32e7eSjoerg   } else {
12606f32e7eSjoerg     S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;
12706f32e7eSjoerg     return S.noteUndefinedBehavior();
12806f32e7eSjoerg   }
12906f32e7eSjoerg }
13006f32e7eSjoerg 
13106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Add(InterpState & S,CodePtr OpPC)13206f32e7eSjoerg bool Add(InterpState &S, CodePtr OpPC) {
13306f32e7eSjoerg   const T &RHS = S.Stk.pop<T>();
13406f32e7eSjoerg   const T &LHS = S.Stk.pop<T>();
13506f32e7eSjoerg   const unsigned Bits = RHS.bitWidth() + 1;
13606f32e7eSjoerg   return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);
13706f32e7eSjoerg }
13806f32e7eSjoerg 
13906f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Sub(InterpState & S,CodePtr OpPC)14006f32e7eSjoerg bool Sub(InterpState &S, CodePtr OpPC) {
14106f32e7eSjoerg   const T &RHS = S.Stk.pop<T>();
14206f32e7eSjoerg   const T &LHS = S.Stk.pop<T>();
14306f32e7eSjoerg   const unsigned Bits = RHS.bitWidth() + 1;
14406f32e7eSjoerg   return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);
14506f32e7eSjoerg }
14606f32e7eSjoerg 
14706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Mul(InterpState & S,CodePtr OpPC)14806f32e7eSjoerg bool Mul(InterpState &S, CodePtr OpPC) {
14906f32e7eSjoerg   const T &RHS = S.Stk.pop<T>();
15006f32e7eSjoerg   const T &LHS = S.Stk.pop<T>();
15106f32e7eSjoerg   const unsigned Bits = RHS.bitWidth() * 2;
15206f32e7eSjoerg   return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);
15306f32e7eSjoerg }
15406f32e7eSjoerg 
15506f32e7eSjoerg //===----------------------------------------------------------------------===//
15606f32e7eSjoerg // EQ, NE, GT, GE, LT, LE
15706f32e7eSjoerg //===----------------------------------------------------------------------===//
15806f32e7eSjoerg 
15906f32e7eSjoerg using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;
16006f32e7eSjoerg 
16106f32e7eSjoerg template <typename T>
CmpHelper(InterpState & S,CodePtr OpPC,CompareFn Fn)16206f32e7eSjoerg bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {
16306f32e7eSjoerg   using BoolT = PrimConv<PT_Bool>::T;
16406f32e7eSjoerg   const T &RHS = S.Stk.pop<T>();
16506f32e7eSjoerg   const T &LHS = S.Stk.pop<T>();
16606f32e7eSjoerg   S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));
16706f32e7eSjoerg   return true;
16806f32e7eSjoerg }
16906f32e7eSjoerg 
17006f32e7eSjoerg template <typename T>
CmpHelperEQ(InterpState & S,CodePtr OpPC,CompareFn Fn)17106f32e7eSjoerg bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {
17206f32e7eSjoerg   return CmpHelper<T>(S, OpPC, Fn);
17306f32e7eSjoerg }
17406f32e7eSjoerg 
17506f32e7eSjoerg template <>
17606f32e7eSjoerg inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
17706f32e7eSjoerg   using BoolT = PrimConv<PT_Bool>::T;
17806f32e7eSjoerg   const Pointer &RHS = S.Stk.pop<Pointer>();
17906f32e7eSjoerg   const Pointer &LHS = S.Stk.pop<Pointer>();
18006f32e7eSjoerg 
18106f32e7eSjoerg   if (!Pointer::hasSameBase(LHS, RHS)) {
18206f32e7eSjoerg     const SourceInfo &Loc = S.Current->getSource(OpPC);
18306f32e7eSjoerg     S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
18406f32e7eSjoerg     return false;
18506f32e7eSjoerg   } else {
18606f32e7eSjoerg     unsigned VL = LHS.getByteOffset();
18706f32e7eSjoerg     unsigned VR = RHS.getByteOffset();
18806f32e7eSjoerg     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
18906f32e7eSjoerg     return true;
19006f32e7eSjoerg   }
19106f32e7eSjoerg }
19206f32e7eSjoerg 
19306f32e7eSjoerg template <>
19406f32e7eSjoerg inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
19506f32e7eSjoerg   using BoolT = PrimConv<PT_Bool>::T;
19606f32e7eSjoerg   const Pointer &RHS = S.Stk.pop<Pointer>();
19706f32e7eSjoerg   const Pointer &LHS = S.Stk.pop<Pointer>();
19806f32e7eSjoerg 
199*13fbcb42Sjoerg   if (LHS.isZero() && RHS.isZero()) {
20006f32e7eSjoerg     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));
20106f32e7eSjoerg     return true;
20206f32e7eSjoerg   }
20306f32e7eSjoerg 
20406f32e7eSjoerg   if (!Pointer::hasSameBase(LHS, RHS)) {
20506f32e7eSjoerg     S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));
20606f32e7eSjoerg     return true;
20706f32e7eSjoerg   } else {
20806f32e7eSjoerg     unsigned VL = LHS.getByteOffset();
20906f32e7eSjoerg     unsigned VR = RHS.getByteOffset();
21006f32e7eSjoerg     S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
21106f32e7eSjoerg     return true;
21206f32e7eSjoerg   }
21306f32e7eSjoerg }
21406f32e7eSjoerg 
21506f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
EQ(InterpState & S,CodePtr OpPC)21606f32e7eSjoerg bool EQ(InterpState &S, CodePtr OpPC) {
21706f32e7eSjoerg   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
21806f32e7eSjoerg     return R == ComparisonCategoryResult::Equal;
21906f32e7eSjoerg   });
22006f32e7eSjoerg }
22106f32e7eSjoerg 
22206f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
NE(InterpState & S,CodePtr OpPC)22306f32e7eSjoerg bool NE(InterpState &S, CodePtr OpPC) {
22406f32e7eSjoerg   return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {
22506f32e7eSjoerg     return R != ComparisonCategoryResult::Equal;
22606f32e7eSjoerg   });
22706f32e7eSjoerg }
22806f32e7eSjoerg 
22906f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
LT(InterpState & S,CodePtr OpPC)23006f32e7eSjoerg bool LT(InterpState &S, CodePtr OpPC) {
23106f32e7eSjoerg   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
23206f32e7eSjoerg     return R == ComparisonCategoryResult::Less;
23306f32e7eSjoerg   });
23406f32e7eSjoerg }
23506f32e7eSjoerg 
23606f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
LE(InterpState & S,CodePtr OpPC)23706f32e7eSjoerg bool LE(InterpState &S, CodePtr OpPC) {
23806f32e7eSjoerg   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
23906f32e7eSjoerg     return R == ComparisonCategoryResult::Less ||
24006f32e7eSjoerg            R == ComparisonCategoryResult::Equal;
24106f32e7eSjoerg   });
24206f32e7eSjoerg }
24306f32e7eSjoerg 
24406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GT(InterpState & S,CodePtr OpPC)24506f32e7eSjoerg bool GT(InterpState &S, CodePtr OpPC) {
24606f32e7eSjoerg   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
24706f32e7eSjoerg     return R == ComparisonCategoryResult::Greater;
24806f32e7eSjoerg   });
24906f32e7eSjoerg }
25006f32e7eSjoerg 
25106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GE(InterpState & S,CodePtr OpPC)25206f32e7eSjoerg bool GE(InterpState &S, CodePtr OpPC) {
25306f32e7eSjoerg   return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {
25406f32e7eSjoerg     return R == ComparisonCategoryResult::Greater ||
25506f32e7eSjoerg            R == ComparisonCategoryResult::Equal;
25606f32e7eSjoerg   });
25706f32e7eSjoerg }
25806f32e7eSjoerg 
25906f32e7eSjoerg //===----------------------------------------------------------------------===//
26006f32e7eSjoerg // InRange
26106f32e7eSjoerg //===----------------------------------------------------------------------===//
26206f32e7eSjoerg 
26306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InRange(InterpState & S,CodePtr OpPC)26406f32e7eSjoerg bool InRange(InterpState &S, CodePtr OpPC) {
26506f32e7eSjoerg   const T RHS = S.Stk.pop<T>();
26606f32e7eSjoerg   const T LHS = S.Stk.pop<T>();
26706f32e7eSjoerg   const T Value = S.Stk.pop<T>();
26806f32e7eSjoerg 
26906f32e7eSjoerg   S.Stk.push<bool>(LHS <= Value && Value <= RHS);
27006f32e7eSjoerg   return true;
27106f32e7eSjoerg }
27206f32e7eSjoerg 
27306f32e7eSjoerg //===----------------------------------------------------------------------===//
27406f32e7eSjoerg // Dup, Pop, Test
27506f32e7eSjoerg //===----------------------------------------------------------------------===//
27606f32e7eSjoerg 
27706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Dup(InterpState & S,CodePtr OpPC)27806f32e7eSjoerg bool Dup(InterpState &S, CodePtr OpPC) {
27906f32e7eSjoerg   S.Stk.push<T>(S.Stk.peek<T>());
28006f32e7eSjoerg   return true;
28106f32e7eSjoerg }
28206f32e7eSjoerg 
28306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Pop(InterpState & S,CodePtr OpPC)28406f32e7eSjoerg bool Pop(InterpState &S, CodePtr OpPC) {
28506f32e7eSjoerg   S.Stk.pop<T>();
28606f32e7eSjoerg   return true;
28706f32e7eSjoerg }
28806f32e7eSjoerg 
28906f32e7eSjoerg //===----------------------------------------------------------------------===//
29006f32e7eSjoerg // Const
29106f32e7eSjoerg //===----------------------------------------------------------------------===//
29206f32e7eSjoerg 
29306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Const(InterpState & S,CodePtr OpPC,const T & Arg)29406f32e7eSjoerg bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {
29506f32e7eSjoerg   S.Stk.push<T>(Arg);
29606f32e7eSjoerg   return true;
29706f32e7eSjoerg }
29806f32e7eSjoerg 
29906f32e7eSjoerg //===----------------------------------------------------------------------===//
30006f32e7eSjoerg // Get/Set Local/Param/Global/This
30106f32e7eSjoerg //===----------------------------------------------------------------------===//
30206f32e7eSjoerg 
30306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetLocal(InterpState & S,CodePtr OpPC,uint32_t I)30406f32e7eSjoerg bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
30506f32e7eSjoerg   S.Stk.push<T>(S.Current->getLocal<T>(I));
30606f32e7eSjoerg   return true;
30706f32e7eSjoerg }
30806f32e7eSjoerg 
30906f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SetLocal(InterpState & S,CodePtr OpPC,uint32_t I)31006f32e7eSjoerg bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
31106f32e7eSjoerg   S.Current->setLocal<T>(I, S.Stk.pop<T>());
31206f32e7eSjoerg   return true;
31306f32e7eSjoerg }
31406f32e7eSjoerg 
31506f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetParam(InterpState & S,CodePtr OpPC,uint32_t I)31606f32e7eSjoerg bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
31706f32e7eSjoerg   if (S.checkingPotentialConstantExpression()) {
31806f32e7eSjoerg     return false;
31906f32e7eSjoerg   }
32006f32e7eSjoerg   S.Stk.push<T>(S.Current->getParam<T>(I));
32106f32e7eSjoerg   return true;
32206f32e7eSjoerg }
32306f32e7eSjoerg 
32406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SetParam(InterpState & S,CodePtr OpPC,uint32_t I)32506f32e7eSjoerg bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {
32606f32e7eSjoerg   S.Current->setParam<T>(I, S.Stk.pop<T>());
32706f32e7eSjoerg   return true;
32806f32e7eSjoerg }
32906f32e7eSjoerg 
33006f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetField(InterpState & S,CodePtr OpPC,uint32_t I)33106f32e7eSjoerg bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {
33206f32e7eSjoerg   const Pointer &Obj = S.Stk.peek<Pointer>();
33306f32e7eSjoerg   if (!CheckNull(S, OpPC, Obj, CSK_Field))
33406f32e7eSjoerg       return false;
33506f32e7eSjoerg   if (!CheckRange(S, OpPC, Obj, CSK_Field))
33606f32e7eSjoerg     return false;
33706f32e7eSjoerg   const Pointer &Field = Obj.atField(I);
33806f32e7eSjoerg   if (!CheckLoad(S, OpPC, Field))
33906f32e7eSjoerg     return false;
34006f32e7eSjoerg   S.Stk.push<T>(Field.deref<T>());
34106f32e7eSjoerg   return true;
34206f32e7eSjoerg }
34306f32e7eSjoerg 
34406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SetField(InterpState & S,CodePtr OpPC,uint32_t I)34506f32e7eSjoerg bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {
34606f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
34706f32e7eSjoerg   const Pointer &Obj = S.Stk.peek<Pointer>();
34806f32e7eSjoerg   if (!CheckNull(S, OpPC, Obj, CSK_Field))
34906f32e7eSjoerg     return false;
35006f32e7eSjoerg   if (!CheckRange(S, OpPC, Obj, CSK_Field))
35106f32e7eSjoerg     return false;
35206f32e7eSjoerg   const Pointer &Field = Obj.atField(I);
35306f32e7eSjoerg   if (!CheckStore(S, OpPC, Field))
35406f32e7eSjoerg     return false;
35506f32e7eSjoerg   Field.deref<T>() = Value;
35606f32e7eSjoerg   return true;
35706f32e7eSjoerg }
35806f32e7eSjoerg 
35906f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetFieldPop(InterpState & S,CodePtr OpPC,uint32_t I)36006f32e7eSjoerg bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {
36106f32e7eSjoerg   const Pointer &Obj = S.Stk.pop<Pointer>();
36206f32e7eSjoerg   if (!CheckNull(S, OpPC, Obj, CSK_Field))
36306f32e7eSjoerg     return false;
36406f32e7eSjoerg   if (!CheckRange(S, OpPC, Obj, CSK_Field))
36506f32e7eSjoerg     return false;
36606f32e7eSjoerg   const Pointer &Field = Obj.atField(I);
36706f32e7eSjoerg   if (!CheckLoad(S, OpPC, Field))
36806f32e7eSjoerg     return false;
36906f32e7eSjoerg   S.Stk.push<T>(Field.deref<T>());
37006f32e7eSjoerg   return true;
37106f32e7eSjoerg }
37206f32e7eSjoerg 
37306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetThisField(InterpState & S,CodePtr OpPC,uint32_t I)37406f32e7eSjoerg bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
37506f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
37606f32e7eSjoerg     return false;
37706f32e7eSjoerg   const Pointer &This = S.Current->getThis();
37806f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
37906f32e7eSjoerg     return false;
38006f32e7eSjoerg   const Pointer &Field = This.atField(I);
38106f32e7eSjoerg   if (!CheckLoad(S, OpPC, Field))
38206f32e7eSjoerg     return false;
38306f32e7eSjoerg   S.Stk.push<T>(Field.deref<T>());
38406f32e7eSjoerg   return true;
38506f32e7eSjoerg }
38606f32e7eSjoerg 
38706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SetThisField(InterpState & S,CodePtr OpPC,uint32_t I)38806f32e7eSjoerg bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
38906f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
39006f32e7eSjoerg     return false;
39106f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
39206f32e7eSjoerg   const Pointer &This = S.Current->getThis();
39306f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
39406f32e7eSjoerg     return false;
39506f32e7eSjoerg   const Pointer &Field = This.atField(I);
39606f32e7eSjoerg   if (!CheckStore(S, OpPC, Field))
39706f32e7eSjoerg     return false;
39806f32e7eSjoerg   Field.deref<T>() = Value;
39906f32e7eSjoerg   return true;
40006f32e7eSjoerg }
40106f32e7eSjoerg 
40206f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
GetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)40306f32e7eSjoerg bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
40406f32e7eSjoerg   auto *B = S.P.getGlobal(I);
40506f32e7eSjoerg   if (B->isExtern())
40606f32e7eSjoerg     return false;
40706f32e7eSjoerg   S.Stk.push<T>(B->deref<T>());
40806f32e7eSjoerg   return true;
40906f32e7eSjoerg }
41006f32e7eSjoerg 
41106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SetGlobal(InterpState & S,CodePtr OpPC,uint32_t I)41206f32e7eSjoerg bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
41306f32e7eSjoerg   // TODO: emit warning.
41406f32e7eSjoerg   return false;
41506f32e7eSjoerg }
41606f32e7eSjoerg 
41706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitGlobal(InterpState & S,CodePtr OpPC,uint32_t I)41806f32e7eSjoerg bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
41906f32e7eSjoerg   S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>();
42006f32e7eSjoerg   return true;
42106f32e7eSjoerg }
42206f32e7eSjoerg 
42306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisField(InterpState & S,CodePtr OpPC,uint32_t I)42406f32e7eSjoerg bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {
42506f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
42606f32e7eSjoerg     return false;
42706f32e7eSjoerg   const Pointer &This = S.Current->getThis();
42806f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
42906f32e7eSjoerg     return false;
43006f32e7eSjoerg   const Pointer &Field = This.atField(I);
43106f32e7eSjoerg   Field.deref<T>() = S.Stk.pop<T>();
43206f32e7eSjoerg   Field.initialize();
43306f32e7eSjoerg   return true;
43406f32e7eSjoerg }
43506f32e7eSjoerg 
43606f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)43706f32e7eSjoerg bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
43806f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
43906f32e7eSjoerg     return false;
44006f32e7eSjoerg   const Pointer &This = S.Current->getThis();
44106f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
44206f32e7eSjoerg     return false;
44306f32e7eSjoerg   const Pointer &Field = This.atField(F->Offset);
44406f32e7eSjoerg   const auto &Value = S.Stk.pop<T>();
44506f32e7eSjoerg   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
44606f32e7eSjoerg   Field.initialize();
44706f32e7eSjoerg   return true;
44806f32e7eSjoerg }
44906f32e7eSjoerg 
45006f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitThisFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)45106f32e7eSjoerg bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
45206f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
45306f32e7eSjoerg     return false;
45406f32e7eSjoerg   const Pointer &This = S.Current->getThis();
45506f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
45606f32e7eSjoerg     return false;
45706f32e7eSjoerg   const Pointer &Field = This.atField(I);
45806f32e7eSjoerg   Field.deref<T>() = S.Stk.pop<T>();
45906f32e7eSjoerg   Field.activate();
46006f32e7eSjoerg   Field.initialize();
46106f32e7eSjoerg   return true;
46206f32e7eSjoerg }
46306f32e7eSjoerg 
46406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitField(InterpState & S,CodePtr OpPC,uint32_t I)46506f32e7eSjoerg bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {
46606f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
46706f32e7eSjoerg   const Pointer &Field = S.Stk.pop<Pointer>().atField(I);
46806f32e7eSjoerg   Field.deref<T>() = Value;
46906f32e7eSjoerg   Field.activate();
47006f32e7eSjoerg   Field.initialize();
47106f32e7eSjoerg   return true;
47206f32e7eSjoerg }
47306f32e7eSjoerg 
47406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitBitField(InterpState & S,CodePtr OpPC,const Record::Field * F)47506f32e7eSjoerg bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {
47606f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
47706f32e7eSjoerg   const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset);
47806f32e7eSjoerg   Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));
47906f32e7eSjoerg   Field.activate();
48006f32e7eSjoerg   Field.initialize();
48106f32e7eSjoerg   return true;
48206f32e7eSjoerg }
48306f32e7eSjoerg 
48406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitFieldActive(InterpState & S,CodePtr OpPC,uint32_t I)48506f32e7eSjoerg bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {
48606f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
48706f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
48806f32e7eSjoerg   const Pointer &Field = Ptr.atField(I);
48906f32e7eSjoerg   Field.deref<T>() = Value;
49006f32e7eSjoerg   Field.activate();
49106f32e7eSjoerg   Field.initialize();
49206f32e7eSjoerg   return true;
49306f32e7eSjoerg }
49406f32e7eSjoerg 
49506f32e7eSjoerg //===----------------------------------------------------------------------===//
49606f32e7eSjoerg // GetPtr Local/Param/Global/Field/This
49706f32e7eSjoerg //===----------------------------------------------------------------------===//
49806f32e7eSjoerg 
GetPtrLocal(InterpState & S,CodePtr OpPC,uint32_t I)49906f32e7eSjoerg inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {
50006f32e7eSjoerg   S.Stk.push<Pointer>(S.Current->getLocalPointer(I));
50106f32e7eSjoerg   return true;
50206f32e7eSjoerg }
50306f32e7eSjoerg 
GetPtrParam(InterpState & S,CodePtr OpPC,uint32_t I)50406f32e7eSjoerg inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {
50506f32e7eSjoerg   if (S.checkingPotentialConstantExpression()) {
50606f32e7eSjoerg     return false;
50706f32e7eSjoerg   }
50806f32e7eSjoerg   S.Stk.push<Pointer>(S.Current->getParamPointer(I));
50906f32e7eSjoerg   return true;
51006f32e7eSjoerg }
51106f32e7eSjoerg 
GetPtrGlobal(InterpState & S,CodePtr OpPC,uint32_t I)51206f32e7eSjoerg inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {
51306f32e7eSjoerg   S.Stk.push<Pointer>(S.P.getPtrGlobal(I));
51406f32e7eSjoerg   return true;
51506f32e7eSjoerg }
51606f32e7eSjoerg 
GetPtrField(InterpState & S,CodePtr OpPC,uint32_t Off)51706f32e7eSjoerg inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {
51806f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
51906f32e7eSjoerg   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
52006f32e7eSjoerg     return false;
52106f32e7eSjoerg   if (!CheckExtern(S, OpPC, Ptr))
52206f32e7eSjoerg     return false;
52306f32e7eSjoerg   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
52406f32e7eSjoerg     return false;
52506f32e7eSjoerg   S.Stk.push<Pointer>(Ptr.atField(Off));
52606f32e7eSjoerg   return true;
52706f32e7eSjoerg }
52806f32e7eSjoerg 
GetPtrThisField(InterpState & S,CodePtr OpPC,uint32_t Off)52906f32e7eSjoerg inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
53006f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
53106f32e7eSjoerg     return false;
53206f32e7eSjoerg   const Pointer &This = S.Current->getThis();
53306f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
53406f32e7eSjoerg     return false;
53506f32e7eSjoerg   S.Stk.push<Pointer>(This.atField(Off));
53606f32e7eSjoerg   return true;
53706f32e7eSjoerg }
53806f32e7eSjoerg 
GetPtrActiveField(InterpState & S,CodePtr OpPC,uint32_t Off)53906f32e7eSjoerg inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {
54006f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
54106f32e7eSjoerg   if (!CheckNull(S, OpPC, Ptr, CSK_Field))
54206f32e7eSjoerg     return false;
54306f32e7eSjoerg   if (!CheckRange(S, OpPC, Ptr, CSK_Field))
54406f32e7eSjoerg     return false;
54506f32e7eSjoerg   Pointer Field = Ptr.atField(Off);
54606f32e7eSjoerg   Ptr.deactivate();
54706f32e7eSjoerg   Field.activate();
54806f32e7eSjoerg   S.Stk.push<Pointer>(std::move(Field));
54906f32e7eSjoerg   return true;
55006f32e7eSjoerg }
55106f32e7eSjoerg 
GetPtrActiveThisField(InterpState & S,CodePtr OpPC,uint32_t Off)55206f32e7eSjoerg inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {
55306f32e7eSjoerg  if (S.checkingPotentialConstantExpression())
55406f32e7eSjoerg     return false;
55506f32e7eSjoerg   const Pointer &This = S.Current->getThis();
55606f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
55706f32e7eSjoerg     return false;
55806f32e7eSjoerg   Pointer Field = This.atField(Off);
55906f32e7eSjoerg   This.deactivate();
56006f32e7eSjoerg   Field.activate();
56106f32e7eSjoerg   S.Stk.push<Pointer>(std::move(Field));
56206f32e7eSjoerg   return true;
56306f32e7eSjoerg }
56406f32e7eSjoerg 
GetPtrBase(InterpState & S,CodePtr OpPC,uint32_t Off)56506f32e7eSjoerg inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
56606f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
56706f32e7eSjoerg   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
56806f32e7eSjoerg     return false;
56906f32e7eSjoerg   S.Stk.push<Pointer>(Ptr.atField(Off));
57006f32e7eSjoerg   return true;
57106f32e7eSjoerg }
57206f32e7eSjoerg 
GetPtrThisBase(InterpState & S,CodePtr OpPC,uint32_t Off)57306f32e7eSjoerg inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {
57406f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
57506f32e7eSjoerg     return false;
57606f32e7eSjoerg   const Pointer &This = S.Current->getThis();
57706f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
57806f32e7eSjoerg     return false;
57906f32e7eSjoerg   S.Stk.push<Pointer>(This.atField(Off));
58006f32e7eSjoerg   return true;
58106f32e7eSjoerg }
58206f32e7eSjoerg 
VirtBaseHelper(InterpState & S,CodePtr OpPC,const RecordDecl * Decl,const Pointer & Ptr)58306f32e7eSjoerg inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,
58406f32e7eSjoerg                            const Pointer &Ptr) {
58506f32e7eSjoerg   Pointer Base = Ptr;
58606f32e7eSjoerg   while (Base.isBaseClass())
58706f32e7eSjoerg     Base = Base.getBase();
58806f32e7eSjoerg 
58906f32e7eSjoerg   auto *Field = Base.getRecord()->getVirtualBase(Decl);
59006f32e7eSjoerg   S.Stk.push<Pointer>(Base.atField(Field->Offset));
59106f32e7eSjoerg   return true;
59206f32e7eSjoerg }
59306f32e7eSjoerg 
GetPtrVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)59406f32e7eSjoerg inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) {
59506f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
59606f32e7eSjoerg   if (!CheckNull(S, OpPC, Ptr, CSK_Base))
59706f32e7eSjoerg     return false;
59806f32e7eSjoerg   return VirtBaseHelper(S, OpPC, D, Ptr);
59906f32e7eSjoerg }
60006f32e7eSjoerg 
GetPtrThisVirtBase(InterpState & S,CodePtr OpPC,const RecordDecl * D)60106f32e7eSjoerg inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,
60206f32e7eSjoerg                                const RecordDecl *D) {
60306f32e7eSjoerg   if (S.checkingPotentialConstantExpression())
60406f32e7eSjoerg     return false;
60506f32e7eSjoerg   const Pointer &This = S.Current->getThis();
60606f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
60706f32e7eSjoerg     return false;
60806f32e7eSjoerg   return VirtBaseHelper(S, OpPC, D, S.Current->getThis());
60906f32e7eSjoerg }
61006f32e7eSjoerg 
61106f32e7eSjoerg //===----------------------------------------------------------------------===//
61206f32e7eSjoerg // Load, Store, Init
61306f32e7eSjoerg //===----------------------------------------------------------------------===//
61406f32e7eSjoerg 
61506f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Load(InterpState & S,CodePtr OpPC)61606f32e7eSjoerg bool Load(InterpState &S, CodePtr OpPC) {
61706f32e7eSjoerg   const Pointer &Ptr = S.Stk.peek<Pointer>();
61806f32e7eSjoerg   if (!CheckLoad(S, OpPC, Ptr))
61906f32e7eSjoerg     return false;
62006f32e7eSjoerg   S.Stk.push<T>(Ptr.deref<T>());
62106f32e7eSjoerg   return true;
62206f32e7eSjoerg }
62306f32e7eSjoerg 
62406f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
LoadPop(InterpState & S,CodePtr OpPC)62506f32e7eSjoerg bool LoadPop(InterpState &S, CodePtr OpPC) {
62606f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
62706f32e7eSjoerg   if (!CheckLoad(S, OpPC, Ptr))
62806f32e7eSjoerg     return false;
62906f32e7eSjoerg   S.Stk.push<T>(Ptr.deref<T>());
63006f32e7eSjoerg   return true;
63106f32e7eSjoerg }
63206f32e7eSjoerg 
63306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Store(InterpState & S,CodePtr OpPC)63406f32e7eSjoerg bool Store(InterpState &S, CodePtr OpPC) {
63506f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
63606f32e7eSjoerg   const Pointer &Ptr = S.Stk.peek<Pointer>();
63706f32e7eSjoerg   if (!CheckStore(S, OpPC, Ptr))
63806f32e7eSjoerg     return false;
63906f32e7eSjoerg   Ptr.deref<T>() = Value;
64006f32e7eSjoerg   return true;
64106f32e7eSjoerg }
64206f32e7eSjoerg 
64306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
StorePop(InterpState & S,CodePtr OpPC)64406f32e7eSjoerg bool StorePop(InterpState &S, CodePtr OpPC) {
64506f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
64606f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
64706f32e7eSjoerg   if (!CheckStore(S, OpPC, Ptr))
64806f32e7eSjoerg     return false;
64906f32e7eSjoerg   Ptr.deref<T>() = Value;
65006f32e7eSjoerg   return true;
65106f32e7eSjoerg }
65206f32e7eSjoerg 
65306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitField(InterpState & S,CodePtr OpPC)65406f32e7eSjoerg bool StoreBitField(InterpState &S, CodePtr OpPC) {
65506f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
65606f32e7eSjoerg   const Pointer &Ptr = S.Stk.peek<Pointer>();
65706f32e7eSjoerg   if (!CheckStore(S, OpPC, Ptr))
65806f32e7eSjoerg     return false;
65906f32e7eSjoerg   if (auto *FD = Ptr.getField()) {
66006f32e7eSjoerg     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
66106f32e7eSjoerg   } else {
66206f32e7eSjoerg     Ptr.deref<T>() = Value;
66306f32e7eSjoerg   }
66406f32e7eSjoerg   return true;
66506f32e7eSjoerg }
66606f32e7eSjoerg 
66706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
StoreBitFieldPop(InterpState & S,CodePtr OpPC)66806f32e7eSjoerg bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {
66906f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
67006f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
67106f32e7eSjoerg   if (!CheckStore(S, OpPC, Ptr))
67206f32e7eSjoerg     return false;
67306f32e7eSjoerg   if (auto *FD = Ptr.getField()) {
67406f32e7eSjoerg     Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));
67506f32e7eSjoerg   } else {
67606f32e7eSjoerg     Ptr.deref<T>() = Value;
67706f32e7eSjoerg   }
67806f32e7eSjoerg   return true;
67906f32e7eSjoerg }
68006f32e7eSjoerg 
68106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitPop(InterpState & S,CodePtr OpPC)68206f32e7eSjoerg bool InitPop(InterpState &S, CodePtr OpPC) {
68306f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
68406f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
68506f32e7eSjoerg   if (!CheckInit(S, OpPC, Ptr))
68606f32e7eSjoerg     return false;
68706f32e7eSjoerg   Ptr.initialize();
68806f32e7eSjoerg   new (&Ptr.deref<T>()) T(Value);
68906f32e7eSjoerg   return true;
69006f32e7eSjoerg }
69106f32e7eSjoerg 
69206f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElem(InterpState & S,CodePtr OpPC,uint32_t Idx)69306f32e7eSjoerg bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {
69406f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
69506f32e7eSjoerg   const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);
69606f32e7eSjoerg   if (!CheckInit(S, OpPC, Ptr))
69706f32e7eSjoerg     return false;
69806f32e7eSjoerg   Ptr.initialize();
69906f32e7eSjoerg   new (&Ptr.deref<T>()) T(Value);
70006f32e7eSjoerg   return true;
70106f32e7eSjoerg }
70206f32e7eSjoerg 
70306f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
InitElemPop(InterpState & S,CodePtr OpPC,uint32_t Idx)70406f32e7eSjoerg bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {
70506f32e7eSjoerg   const T &Value = S.Stk.pop<T>();
70606f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);
70706f32e7eSjoerg   if (!CheckInit(S, OpPC, Ptr))
70806f32e7eSjoerg     return false;
70906f32e7eSjoerg   Ptr.initialize();
71006f32e7eSjoerg   new (&Ptr.deref<T>()) T(Value);
71106f32e7eSjoerg   return true;
71206f32e7eSjoerg }
71306f32e7eSjoerg 
71406f32e7eSjoerg //===----------------------------------------------------------------------===//
71506f32e7eSjoerg // AddOffset, SubOffset
71606f32e7eSjoerg //===----------------------------------------------------------------------===//
71706f32e7eSjoerg 
OffsetHelper(InterpState & S,CodePtr OpPC)71806f32e7eSjoerg template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) {
71906f32e7eSjoerg   // Fetch the pointer and the offset.
72006f32e7eSjoerg   const T &Offset = S.Stk.pop<T>();
72106f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
72206f32e7eSjoerg   if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
72306f32e7eSjoerg     return false;
72406f32e7eSjoerg   if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))
72506f32e7eSjoerg     return false;
72606f32e7eSjoerg 
72706f32e7eSjoerg   // Get a version of the index comparable to the type.
72806f32e7eSjoerg   T Index = T::from(Ptr.getIndex(), Offset.bitWidth());
72906f32e7eSjoerg   // A zero offset does not change the pointer, but in the case of an array
73006f32e7eSjoerg   // it has to be adjusted to point to the first element instead of the array.
73106f32e7eSjoerg   if (Offset.isZero()) {
73206f32e7eSjoerg     S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr);
73306f32e7eSjoerg     return true;
73406f32e7eSjoerg   }
73506f32e7eSjoerg   // Arrays of unknown bounds cannot have pointers into them.
73606f32e7eSjoerg   if (!CheckArray(S, OpPC, Ptr))
73706f32e7eSjoerg     return false;
73806f32e7eSjoerg 
73906f32e7eSjoerg   // Compute the largest index into the array.
74006f32e7eSjoerg   unsigned MaxIndex = Ptr.getNumElems();
74106f32e7eSjoerg 
74206f32e7eSjoerg   // Helper to report an invalid offset, computed as APSInt.
74306f32e7eSjoerg   auto InvalidOffset = [&]() {
74406f32e7eSjoerg     const unsigned Bits = Offset.bitWidth();
74506f32e7eSjoerg     APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false);
74606f32e7eSjoerg     APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false);
74706f32e7eSjoerg     APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset);
74806f32e7eSjoerg     S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)
74906f32e7eSjoerg         << NewIndex
75006f32e7eSjoerg         << /*array*/ static_cast<int>(!Ptr.inArray())
75106f32e7eSjoerg         << static_cast<unsigned>(MaxIndex);
75206f32e7eSjoerg     return false;
75306f32e7eSjoerg   };
75406f32e7eSjoerg 
75506f32e7eSjoerg   // If the new offset would be negative, bail out.
75606f32e7eSjoerg   if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index))
75706f32e7eSjoerg     return InvalidOffset();
75806f32e7eSjoerg   if (!Add && Offset.isPositive() && Index < Offset)
75906f32e7eSjoerg     return InvalidOffset();
76006f32e7eSjoerg 
76106f32e7eSjoerg   // If the new offset would be out of bounds, bail out.
76206f32e7eSjoerg   unsigned MaxOffset = MaxIndex - Ptr.getIndex();
76306f32e7eSjoerg   if (Add && Offset.isPositive() && Offset > MaxOffset)
76406f32e7eSjoerg     return InvalidOffset();
76506f32e7eSjoerg   if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
76606f32e7eSjoerg     return InvalidOffset();
76706f32e7eSjoerg 
76806f32e7eSjoerg   // Offset is valid - compute it on unsigned.
76906f32e7eSjoerg   int64_t WideIndex = static_cast<int64_t>(Index);
77006f32e7eSjoerg   int64_t WideOffset = static_cast<int64_t>(Offset);
77106f32e7eSjoerg   int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset);
77206f32e7eSjoerg   S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result)));
77306f32e7eSjoerg   return true;
77406f32e7eSjoerg }
77506f32e7eSjoerg 
77606f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
AddOffset(InterpState & S,CodePtr OpPC)77706f32e7eSjoerg bool AddOffset(InterpState &S, CodePtr OpPC) {
77806f32e7eSjoerg   return OffsetHelper<T, true>(S, OpPC);
77906f32e7eSjoerg }
78006f32e7eSjoerg 
78106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
SubOffset(InterpState & S,CodePtr OpPC)78206f32e7eSjoerg bool SubOffset(InterpState &S, CodePtr OpPC) {
78306f32e7eSjoerg   return OffsetHelper<T, false>(S, OpPC);
78406f32e7eSjoerg }
78506f32e7eSjoerg 
78606f32e7eSjoerg 
78706f32e7eSjoerg //===----------------------------------------------------------------------===//
78806f32e7eSjoerg // Destroy
78906f32e7eSjoerg //===----------------------------------------------------------------------===//
79006f32e7eSjoerg 
Destroy(InterpState & S,CodePtr OpPC,uint32_t I)79106f32e7eSjoerg inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {
79206f32e7eSjoerg   S.Current->destroy(I);
79306f32e7eSjoerg   return true;
79406f32e7eSjoerg }
79506f32e7eSjoerg 
79606f32e7eSjoerg //===----------------------------------------------------------------------===//
79706f32e7eSjoerg // Cast, CastFP
79806f32e7eSjoerg //===----------------------------------------------------------------------===//
79906f32e7eSjoerg 
Cast(InterpState & S,CodePtr OpPC)80006f32e7eSjoerg template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {
80106f32e7eSjoerg   using T = typename PrimConv<TIn>::T;
80206f32e7eSjoerg   using U = typename PrimConv<TOut>::T;
80306f32e7eSjoerg   S.Stk.push<U>(U::from(S.Stk.pop<T>()));
80406f32e7eSjoerg   return true;
80506f32e7eSjoerg }
80606f32e7eSjoerg 
80706f32e7eSjoerg //===----------------------------------------------------------------------===//
80806f32e7eSjoerg // Zero, Nullptr
80906f32e7eSjoerg //===----------------------------------------------------------------------===//
81006f32e7eSjoerg 
81106f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Zero(InterpState & S,CodePtr OpPC)81206f32e7eSjoerg bool Zero(InterpState &S, CodePtr OpPC) {
81306f32e7eSjoerg   S.Stk.push<T>(T::zero());
81406f32e7eSjoerg   return true;
81506f32e7eSjoerg }
81606f32e7eSjoerg 
81706f32e7eSjoerg template <PrimType Name, class T = typename PrimConv<Name>::T>
Null(InterpState & S,CodePtr OpPC)81806f32e7eSjoerg inline bool Null(InterpState &S, CodePtr OpPC) {
81906f32e7eSjoerg   S.Stk.push<T>();
82006f32e7eSjoerg   return true;
82106f32e7eSjoerg }
82206f32e7eSjoerg 
82306f32e7eSjoerg //===----------------------------------------------------------------------===//
82406f32e7eSjoerg // This, ImplicitThis
82506f32e7eSjoerg //===----------------------------------------------------------------------===//
82606f32e7eSjoerg 
This(InterpState & S,CodePtr OpPC)82706f32e7eSjoerg inline bool This(InterpState &S, CodePtr OpPC) {
82806f32e7eSjoerg   // Cannot read 'this' in this mode.
82906f32e7eSjoerg   if (S.checkingPotentialConstantExpression()) {
83006f32e7eSjoerg     return false;
83106f32e7eSjoerg   }
83206f32e7eSjoerg 
83306f32e7eSjoerg   const Pointer &This = S.Current->getThis();
83406f32e7eSjoerg   if (!CheckThis(S, OpPC, This))
83506f32e7eSjoerg     return false;
83606f32e7eSjoerg 
83706f32e7eSjoerg   S.Stk.push<Pointer>(This);
83806f32e7eSjoerg   return true;
83906f32e7eSjoerg }
84006f32e7eSjoerg 
84106f32e7eSjoerg //===----------------------------------------------------------------------===//
84206f32e7eSjoerg // Shr, Shl
84306f32e7eSjoerg //===----------------------------------------------------------------------===//
84406f32e7eSjoerg 
84506f32e7eSjoerg template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T>
Trunc(InterpState & S,CodePtr OpPC,unsigned Bits,const T & V)84606f32e7eSjoerg unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) {
84706f32e7eSjoerg   // C++11 [expr.shift]p1: Shift width must be less than the bit width of
84806f32e7eSjoerg   // the shifted type.
84906f32e7eSjoerg   if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) {
85006f32e7eSjoerg     const Expr *E = S.Current->getExpr(OpPC);
85106f32e7eSjoerg     const APSInt Val = V.toAPSInt();
85206f32e7eSjoerg     QualType Ty = E->getType();
85306f32e7eSjoerg     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
85406f32e7eSjoerg     return Bits;
85506f32e7eSjoerg   } else {
85606f32e7eSjoerg     return static_cast<unsigned>(V);
85706f32e7eSjoerg   }
85806f32e7eSjoerg }
85906f32e7eSjoerg 
86006f32e7eSjoerg template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
ShiftRight(InterpState & S,CodePtr OpPC,const T & V,unsigned RHS)86106f32e7eSjoerg inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
86206f32e7eSjoerg   if (RHS >= V.bitWidth()) {
86306f32e7eSjoerg     S.Stk.push<T>(T::from(0, V.bitWidth()));
86406f32e7eSjoerg   } else {
86506f32e7eSjoerg     S.Stk.push<T>(T::from(V >> RHS, V.bitWidth()));
86606f32e7eSjoerg   }
86706f32e7eSjoerg   return true;
86806f32e7eSjoerg }
86906f32e7eSjoerg 
87006f32e7eSjoerg template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T>
ShiftLeft(InterpState & S,CodePtr OpPC,const T & V,unsigned RHS)87106f32e7eSjoerg inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) {
872*13fbcb42Sjoerg   if (V.isSigned() && !S.getLangOpts().CPlusPlus20) {
87306f32e7eSjoerg     // C++11 [expr.shift]p2: A signed left shift must have a non-negative
87406f32e7eSjoerg     // operand, and must not overflow the corresponding unsigned type.
87506f32e7eSjoerg     // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
87606f32e7eSjoerg     // E1 x 2^E2 module 2^N.
87706f32e7eSjoerg     if (V.isNegative()) {
87806f32e7eSjoerg       const Expr *E = S.Current->getExpr(OpPC);
87906f32e7eSjoerg       S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt();
88006f32e7eSjoerg     } else if (V.countLeadingZeros() < RHS) {
88106f32e7eSjoerg       S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards);
88206f32e7eSjoerg     }
88306f32e7eSjoerg   }
88406f32e7eSjoerg 
88506f32e7eSjoerg   if (V.bitWidth() == 1) {
88606f32e7eSjoerg     S.Stk.push<T>(V);
88706f32e7eSjoerg   } else if (RHS >= V.bitWidth()) {
88806f32e7eSjoerg     S.Stk.push<T>(T::from(0, V.bitWidth()));
88906f32e7eSjoerg   } else {
89006f32e7eSjoerg     S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth()));
89106f32e7eSjoerg   }
89206f32e7eSjoerg   return true;
89306f32e7eSjoerg }
89406f32e7eSjoerg 
89506f32e7eSjoerg template <PrimType TL, PrimType TR>
Shr(InterpState & S,CodePtr OpPC)89606f32e7eSjoerg inline bool Shr(InterpState &S, CodePtr OpPC) {
89706f32e7eSjoerg   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
89806f32e7eSjoerg   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
89906f32e7eSjoerg   const unsigned Bits = LHS.bitWidth();
90006f32e7eSjoerg 
90106f32e7eSjoerg   if (RHS.isSigned() && RHS.isNegative()) {
90206f32e7eSjoerg     const SourceInfo &Loc = S.Current->getSource(OpPC);
90306f32e7eSjoerg     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
90406f32e7eSjoerg     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
90506f32e7eSjoerg   } else {
90606f32e7eSjoerg     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
90706f32e7eSjoerg   }
90806f32e7eSjoerg }
90906f32e7eSjoerg 
91006f32e7eSjoerg template <PrimType TL, PrimType TR>
Shl(InterpState & S,CodePtr OpPC)91106f32e7eSjoerg inline bool Shl(InterpState &S, CodePtr OpPC) {
91206f32e7eSjoerg   const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>();
91306f32e7eSjoerg   const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>();
91406f32e7eSjoerg   const unsigned Bits = LHS.bitWidth();
91506f32e7eSjoerg 
91606f32e7eSjoerg   if (RHS.isSigned() && RHS.isNegative()) {
91706f32e7eSjoerg     const SourceInfo &Loc = S.Current->getSource(OpPC);
91806f32e7eSjoerg     S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();
91906f32e7eSjoerg     return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS));
92006f32e7eSjoerg   } else {
92106f32e7eSjoerg     return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS));
92206f32e7eSjoerg   }
92306f32e7eSjoerg }
92406f32e7eSjoerg 
92506f32e7eSjoerg //===----------------------------------------------------------------------===//
92606f32e7eSjoerg // NoRet
92706f32e7eSjoerg //===----------------------------------------------------------------------===//
92806f32e7eSjoerg 
NoRet(InterpState & S,CodePtr OpPC)92906f32e7eSjoerg inline bool NoRet(InterpState &S, CodePtr OpPC) {
93006f32e7eSjoerg   SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();
93106f32e7eSjoerg   S.FFDiag(EndLoc, diag::note_constexpr_no_return);
93206f32e7eSjoerg   return false;
93306f32e7eSjoerg }
93406f32e7eSjoerg 
93506f32e7eSjoerg //===----------------------------------------------------------------------===//
93606f32e7eSjoerg // NarrowPtr, ExpandPtr
93706f32e7eSjoerg //===----------------------------------------------------------------------===//
93806f32e7eSjoerg 
NarrowPtr(InterpState & S,CodePtr OpPC)93906f32e7eSjoerg inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {
94006f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
94106f32e7eSjoerg   S.Stk.push<Pointer>(Ptr.narrow());
94206f32e7eSjoerg   return true;
94306f32e7eSjoerg }
94406f32e7eSjoerg 
ExpandPtr(InterpState & S,CodePtr OpPC)94506f32e7eSjoerg inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {
94606f32e7eSjoerg   const Pointer &Ptr = S.Stk.pop<Pointer>();
94706f32e7eSjoerg   S.Stk.push<Pointer>(Ptr.expand());
94806f32e7eSjoerg   return true;
94906f32e7eSjoerg }
95006f32e7eSjoerg 
95106f32e7eSjoerg /// Interpreter entry point.
95206f32e7eSjoerg bool Interpret(InterpState &S, APValue &Result);
95306f32e7eSjoerg 
95406f32e7eSjoerg } // namespace interp
95506f32e7eSjoerg } // namespace clang
95606f32e7eSjoerg 
95706f32e7eSjoerg #endif
958