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