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