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