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