1a07aba5dSTimm Baeder //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===// 2a07aba5dSTimm Baeder // 3a07aba5dSTimm Baeder // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a07aba5dSTimm Baeder // See https://llvm.org/LICENSE.txt for license information. 5a07aba5dSTimm Baeder // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a07aba5dSTimm Baeder // 7a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 8a07aba5dSTimm Baeder // 9a07aba5dSTimm Baeder // Definition of the interpreter state and entry point. 10a07aba5dSTimm Baeder // 11a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 12a07aba5dSTimm Baeder 13a07aba5dSTimm Baeder #ifndef LLVM_CLANG_AST_INTERP_INTERP_H 14a07aba5dSTimm Baeder #define LLVM_CLANG_AST_INTERP_INTERP_H 15a07aba5dSTimm Baeder 16a07aba5dSTimm Baeder #include "../ExprConstShared.h" 171fbbf4c4STimm Baeder #include "BitcastBuffer.h" 18a07aba5dSTimm Baeder #include "Boolean.h" 19a07aba5dSTimm Baeder #include "DynamicAllocator.h" 20048bc672STimm Baeder #include "FixedPoint.h" 21a07aba5dSTimm Baeder #include "Floating.h" 22a07aba5dSTimm Baeder #include "Function.h" 23a07aba5dSTimm Baeder #include "FunctionPointer.h" 24ef2a104cSTimm Baeder #include "InterpBuiltinBitCast.h" 25a07aba5dSTimm Baeder #include "InterpFrame.h" 26a07aba5dSTimm Baeder #include "InterpStack.h" 27a07aba5dSTimm Baeder #include "InterpState.h" 28a07aba5dSTimm Baeder #include "MemberPointer.h" 29a07aba5dSTimm Baeder #include "Opcode.h" 30a07aba5dSTimm Baeder #include "PrimType.h" 31a07aba5dSTimm Baeder #include "Program.h" 32a07aba5dSTimm Baeder #include "State.h" 33a07aba5dSTimm Baeder #include "clang/AST/ASTContext.h" 34a07aba5dSTimm Baeder #include "clang/AST/Expr.h" 35a07aba5dSTimm Baeder #include "llvm/ADT/APFloat.h" 36a07aba5dSTimm Baeder #include "llvm/ADT/APSInt.h" 37a07aba5dSTimm Baeder #include <type_traits> 38a07aba5dSTimm Baeder 39a07aba5dSTimm Baeder namespace clang { 40a07aba5dSTimm Baeder namespace interp { 41a07aba5dSTimm Baeder 42a07aba5dSTimm Baeder using APSInt = llvm::APSInt; 43641b4d53STimm Baeder using FixedPointSemantics = llvm::FixedPointSemantics; 44a07aba5dSTimm Baeder 45a07aba5dSTimm Baeder /// Checks if the variable has externally defined storage. 46a07aba5dSTimm Baeder bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 47a07aba5dSTimm Baeder 48a07aba5dSTimm Baeder /// Checks if the array is offsetable. 49a07aba5dSTimm Baeder bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 50a07aba5dSTimm Baeder 51a07aba5dSTimm Baeder /// Checks if a pointer is live and accessible. 52a07aba5dSTimm Baeder bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 53a07aba5dSTimm Baeder AccessKinds AK); 54a07aba5dSTimm Baeder 55a07aba5dSTimm Baeder /// Checks if a pointer is a dummy pointer. 56a07aba5dSTimm Baeder bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 57a07aba5dSTimm Baeder AccessKinds AK); 58a07aba5dSTimm Baeder 59a07aba5dSTimm Baeder /// Checks if a pointer is null. 60a07aba5dSTimm Baeder bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 61a07aba5dSTimm Baeder CheckSubobjectKind CSK); 62a07aba5dSTimm Baeder 63a07aba5dSTimm Baeder /// Checks if a pointer is in range. 64a07aba5dSTimm Baeder bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 65a07aba5dSTimm Baeder AccessKinds AK); 66a07aba5dSTimm Baeder 67a07aba5dSTimm Baeder /// Checks if a field from which a pointer is going to be derived is valid. 68a07aba5dSTimm Baeder bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 69a07aba5dSTimm Baeder CheckSubobjectKind CSK); 70a07aba5dSTimm Baeder 71a07aba5dSTimm Baeder /// Checks if Ptr is a one-past-the-end pointer. 72a07aba5dSTimm Baeder bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 73a07aba5dSTimm Baeder CheckSubobjectKind CSK); 74a07aba5dSTimm Baeder 75a07aba5dSTimm Baeder /// Checks if the dowcast using the given offset is possible with the given 76a07aba5dSTimm Baeder /// pointer. 77a07aba5dSTimm Baeder bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 78a07aba5dSTimm Baeder uint32_t Offset); 79a07aba5dSTimm Baeder 80a07aba5dSTimm Baeder /// Checks if a pointer points to const storage. 81a07aba5dSTimm Baeder bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 82a07aba5dSTimm Baeder 83a07aba5dSTimm Baeder /// Checks if the Descriptor is of a constexpr or const global variable. 84a07aba5dSTimm Baeder bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); 85a07aba5dSTimm Baeder 86a07aba5dSTimm Baeder /// Checks if a pointer points to a mutable field. 87a07aba5dSTimm Baeder bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 88a07aba5dSTimm Baeder 89a07aba5dSTimm Baeder /// Checks if a value can be loaded from a block. 90a07aba5dSTimm Baeder bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 91a07aba5dSTimm Baeder AccessKinds AK = AK_Read); 92a14c7309STimm Baeder bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 93a07aba5dSTimm Baeder 94a07aba5dSTimm Baeder bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 95a07aba5dSTimm Baeder AccessKinds AK); 96a07aba5dSTimm Baeder /// Check if a global variable is initialized. 97a07aba5dSTimm Baeder bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 98a07aba5dSTimm Baeder 99a07aba5dSTimm Baeder /// Checks if a value can be stored in a block. 100a07aba5dSTimm Baeder bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 101a07aba5dSTimm Baeder 102a07aba5dSTimm Baeder /// Checks if a method can be invoked on an object. 103a07aba5dSTimm Baeder bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 104a07aba5dSTimm Baeder 105a07aba5dSTimm Baeder /// Checks if a value can be initialized. 106a07aba5dSTimm Baeder bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 107a07aba5dSTimm Baeder 108a07aba5dSTimm Baeder /// Checks if a method can be called. 109a07aba5dSTimm Baeder bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F); 110a07aba5dSTimm Baeder 111a07aba5dSTimm Baeder /// Checks if calling the currently active function would exceed 112a07aba5dSTimm Baeder /// the allowed call depth. 113a07aba5dSTimm Baeder bool CheckCallDepth(InterpState &S, CodePtr OpPC); 114a07aba5dSTimm Baeder 115a07aba5dSTimm Baeder /// Checks the 'this' pointer. 116a07aba5dSTimm Baeder bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 117a07aba5dSTimm Baeder 118a07aba5dSTimm Baeder /// Checks if a method is pure virtual. 119a07aba5dSTimm Baeder bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 120a07aba5dSTimm Baeder 121a07aba5dSTimm Baeder /// Checks if all the arguments annotated as 'nonnull' are in fact not null. 122a07aba5dSTimm Baeder bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, 123a07aba5dSTimm Baeder const CallExpr *CE, unsigned ArgSize); 124a07aba5dSTimm Baeder 125a07aba5dSTimm Baeder /// Checks if dynamic memory allocation is available in the current 126a07aba5dSTimm Baeder /// language mode. 127a07aba5dSTimm Baeder bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC); 128a07aba5dSTimm Baeder 129a07aba5dSTimm Baeder /// Diagnose mismatched new[]/delete or new/delete[] pairs. 130610b8539STimm Baeder bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, 131610b8539STimm Baeder DynamicAllocator::Form AllocForm, 132610b8539STimm Baeder DynamicAllocator::Form DeleteForm, const Descriptor *D, 133a07aba5dSTimm Baeder const Expr *NewExpr); 134a07aba5dSTimm Baeder 135a07aba5dSTimm Baeder /// Check the source of the pointer passed to delete/delete[] has actually 136a07aba5dSTimm Baeder /// been heap allocated by us. 137a07aba5dSTimm Baeder bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, 138a07aba5dSTimm Baeder const Pointer &Ptr); 139a07aba5dSTimm Baeder 140a07aba5dSTimm Baeder /// Sets the given integral value to the pointer, which is of 141a07aba5dSTimm Baeder /// a std::{weak,partial,strong}_ordering type. 142a07aba5dSTimm Baeder bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, 143a07aba5dSTimm Baeder const Pointer &Ptr, const APSInt &IntValue); 144a07aba5dSTimm Baeder 145a07aba5dSTimm Baeder /// Copy the contents of Src into Dest. 146a07aba5dSTimm Baeder bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); 147a07aba5dSTimm Baeder 148f70ccdaeSTimm Baeder bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, 149f70ccdaeSTimm Baeder uint32_t VarArgSize); 150f70ccdaeSTimm Baeder bool Call(InterpState &S, CodePtr OpPC, const Function *Func, 151f70ccdaeSTimm Baeder uint32_t VarArgSize); 152f70ccdaeSTimm Baeder bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, 153f70ccdaeSTimm Baeder uint32_t VarArgSize); 15446870175STimm Bäder bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, 15578cf9b83STimm Baeder const CallExpr *CE, uint32_t BuiltinID); 156f70ccdaeSTimm Baeder bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, 157f70ccdaeSTimm Baeder const CallExpr *CE); 158f86050deSTimm Baeder bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T); 159fed8695bSTimm Baeder bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index); 160ef2a104cSTimm Baeder bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits, 161ef2a104cSTimm Baeder bool TargetIsUCharOrByte); 162f70ccdaeSTimm Baeder 16395ce78b7STimm Baeder template <typename T> 16495ce78b7STimm Baeder static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) { 16595ce78b7STimm Baeder const Expr *E = S.Current->getExpr(OpPC); 16695ce78b7STimm Baeder S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType(); 16795ce78b7STimm Baeder return S.noteUndefinedBehavior(); 16895ce78b7STimm Baeder } 16995ce78b7STimm Baeder bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC, 17095ce78b7STimm Baeder const FixedPoint &FP); 17195ce78b7STimm Baeder 1720050503bSTimm Baeder enum class ShiftDir { Left, Right }; 1730050503bSTimm Baeder 174a07aba5dSTimm Baeder /// Checks if the shift operation is legal. 1750050503bSTimm Baeder template <ShiftDir Dir, typename LT, typename RT> 176a07aba5dSTimm Baeder bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, 177a07aba5dSTimm Baeder unsigned Bits) { 178a07aba5dSTimm Baeder if (RHS.isNegative()) { 179a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 180a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 181a07aba5dSTimm Baeder if (!S.noteUndefinedBehavior()) 182a07aba5dSTimm Baeder return false; 183a07aba5dSTimm Baeder } 184a07aba5dSTimm Baeder 185a07aba5dSTimm Baeder // C++11 [expr.shift]p1: Shift width must be less than the bit width of 186a07aba5dSTimm Baeder // the shifted type. 187a07aba5dSTimm Baeder if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { 188a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 189a07aba5dSTimm Baeder const APSInt Val = RHS.toAPSInt(); 190a07aba5dSTimm Baeder QualType Ty = E->getType(); 191a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; 192a07aba5dSTimm Baeder if (!S.noteUndefinedBehavior()) 193a07aba5dSTimm Baeder return false; 194a07aba5dSTimm Baeder } 195a07aba5dSTimm Baeder 1960050503bSTimm Baeder if constexpr (Dir == ShiftDir::Left) { 197a07aba5dSTimm Baeder if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) { 198a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 199a07aba5dSTimm Baeder // C++11 [expr.shift]p2: A signed left shift must have a non-negative 200a07aba5dSTimm Baeder // operand, and must not overflow the corresponding unsigned type. 201a07aba5dSTimm Baeder if (LHS.isNegative()) { 202a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); 203a07aba5dSTimm Baeder if (!S.noteUndefinedBehavior()) 204a07aba5dSTimm Baeder return false; 205a07aba5dSTimm Baeder } else if (LHS.toUnsigned().countLeadingZeros() < 206a07aba5dSTimm Baeder static_cast<unsigned>(RHS)) { 207a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_lshift_discards); 208a07aba5dSTimm Baeder if (!S.noteUndefinedBehavior()) 209a07aba5dSTimm Baeder return false; 210a07aba5dSTimm Baeder } 211a07aba5dSTimm Baeder } 2120050503bSTimm Baeder } 213a07aba5dSTimm Baeder 214a07aba5dSTimm Baeder // C++2a [expr.shift]p2: [P0907R4]: 215a07aba5dSTimm Baeder // E1 << E2 is the unique value congruent to 216a07aba5dSTimm Baeder // E1 x 2^E2 module 2^N. 217a07aba5dSTimm Baeder return true; 218a07aba5dSTimm Baeder } 219a07aba5dSTimm Baeder 220a07aba5dSTimm Baeder /// Checks if Div/Rem operation on LHS and RHS is valid. 221a07aba5dSTimm Baeder template <typename T> 222a07aba5dSTimm Baeder bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { 223a07aba5dSTimm Baeder if (RHS.isZero()) { 224a07aba5dSTimm Baeder const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC)); 225a07aba5dSTimm Baeder if constexpr (std::is_same_v<T, Floating>) { 226a07aba5dSTimm Baeder S.CCEDiag(Op, diag::note_expr_divide_by_zero) 227a07aba5dSTimm Baeder << Op->getRHS()->getSourceRange(); 228a07aba5dSTimm Baeder return true; 229a07aba5dSTimm Baeder } 230a07aba5dSTimm Baeder 231a07aba5dSTimm Baeder S.FFDiag(Op, diag::note_expr_divide_by_zero) 232a07aba5dSTimm Baeder << Op->getRHS()->getSourceRange(); 233a07aba5dSTimm Baeder return false; 234a07aba5dSTimm Baeder } 235a07aba5dSTimm Baeder 23679382eb9STimm Baeder if constexpr (!std::is_same_v<T, FixedPoint>) { 237a07aba5dSTimm Baeder if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { 238a07aba5dSTimm Baeder APSInt LHSInt = LHS.toAPSInt(); 239a07aba5dSTimm Baeder SmallString<32> Trunc; 240a07aba5dSTimm Baeder (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); 241a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 242a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 243a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); 244a07aba5dSTimm Baeder return false; 245a07aba5dSTimm Baeder } 24679382eb9STimm Baeder } 247a07aba5dSTimm Baeder return true; 248a07aba5dSTimm Baeder } 249a07aba5dSTimm Baeder 250a07aba5dSTimm Baeder template <typename SizeT> 251a07aba5dSTimm Baeder bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, 252a07aba5dSTimm Baeder unsigned ElemSize, bool IsNoThrow) { 253a07aba5dSTimm Baeder // FIXME: Both the SizeT::from() as well as the 254a07aba5dSTimm Baeder // NumElements.toAPSInt() in this function are rather expensive. 255a07aba5dSTimm Baeder 2569a32f283STimm Baeder // Can't be too many elements if the bitwidth of NumElements is lower than 2579a32f283STimm Baeder // that of Descriptor::MaxArrayElemBytes. 2589a32f283STimm Baeder if ((NumElements->bitWidth() - NumElements->isSigned()) < 2599a32f283STimm Baeder (sizeof(Descriptor::MaxArrayElemBytes) * 8)) 2609a32f283STimm Baeder return true; 2619a32f283STimm Baeder 262a07aba5dSTimm Baeder // FIXME: GH63562 263a07aba5dSTimm Baeder // APValue stores array extents as unsigned, 264a07aba5dSTimm Baeder // so anything that is greater that unsigned would overflow when 265a07aba5dSTimm Baeder // constructing the array, we catch this here. 266a07aba5dSTimm Baeder SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); 2679a32f283STimm Baeder assert(MaxElements.isPositive()); 268a07aba5dSTimm Baeder if (NumElements->toAPSInt().getActiveBits() > 269d9e72860Syronglin ConstantArrayType::getMaxSizeBits(S.getASTContext()) || 270a07aba5dSTimm Baeder *NumElements > MaxElements) { 271a07aba5dSTimm Baeder if (!IsNoThrow) { 272a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 273ccb7cc31STimm Baeder 274ccb7cc31STimm Baeder if (NumElements->isSigned() && NumElements->isNegative()) { 275ccb7cc31STimm Baeder S.FFDiag(Loc, diag::note_constexpr_new_negative) 276ccb7cc31STimm Baeder << NumElements->toDiagnosticString(S.getASTContext()); 277ccb7cc31STimm Baeder } else { 278a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_new_too_large) 279d9e72860Syronglin << NumElements->toDiagnosticString(S.getASTContext()); 280a07aba5dSTimm Baeder } 281ccb7cc31STimm Baeder } 282a07aba5dSTimm Baeder return false; 283a07aba5dSTimm Baeder } 284a07aba5dSTimm Baeder return true; 285a07aba5dSTimm Baeder } 286a07aba5dSTimm Baeder 287a07aba5dSTimm Baeder /// Checks if the result of a floating-point operation is valid 288a07aba5dSTimm Baeder /// in the current context. 289a07aba5dSTimm Baeder bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, 2900f5f440fSTimm Baeder APFloat::opStatus Status, FPOptions FPO); 291a07aba5dSTimm Baeder 292a07aba5dSTimm Baeder /// Checks why the given DeclRefExpr is invalid. 293a07aba5dSTimm Baeder bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR); 294a07aba5dSTimm Baeder 295a07aba5dSTimm Baeder /// Interpreter entry point. 29682ed9c03STimm Baeder bool Interpret(InterpState &S); 297a07aba5dSTimm Baeder 298a07aba5dSTimm Baeder /// Interpret a builtin function. 299a07aba5dSTimm Baeder bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 30078cf9b83STimm Baeder const CallExpr *Call, uint32_t BuiltinID); 301a07aba5dSTimm Baeder 302a07aba5dSTimm Baeder /// Interpret an offsetof operation. 303a07aba5dSTimm Baeder bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, 304a07aba5dSTimm Baeder llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result); 305a07aba5dSTimm Baeder 306a07aba5dSTimm Baeder inline bool Invalid(InterpState &S, CodePtr OpPC); 307a07aba5dSTimm Baeder 308a07aba5dSTimm Baeder enum class ArithOp { Add, Sub }; 309a07aba5dSTimm Baeder 310a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 311a07aba5dSTimm Baeder // Returning values 312a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 313a07aba5dSTimm Baeder 31483fea8b8STimm Baeder void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC, 31583fea8b8STimm Baeder const Function *Func); 316a07aba5dSTimm Baeder 317a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 31882ed9c03STimm Baeder bool Ret(InterpState &S, CodePtr &PC) { 319a07aba5dSTimm Baeder const T &Ret = S.Stk.pop<T>(); 320a07aba5dSTimm Baeder 321a07aba5dSTimm Baeder assert(S.Current); 322a07aba5dSTimm Baeder assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 323a07aba5dSTimm Baeder if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 32483fea8b8STimm Baeder cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); 325a07aba5dSTimm Baeder 326a07aba5dSTimm Baeder if (InterpFrame *Caller = S.Current->Caller) { 327a07aba5dSTimm Baeder PC = S.Current->getRetPC(); 328a07aba5dSTimm Baeder delete S.Current; 329a07aba5dSTimm Baeder S.Current = Caller; 330a07aba5dSTimm Baeder S.Stk.push<T>(Ret); 331a07aba5dSTimm Baeder } else { 332a07aba5dSTimm Baeder delete S.Current; 333a07aba5dSTimm Baeder S.Current = nullptr; 33482ed9c03STimm Baeder // The topmost frame should come from an EvalEmitter, 33582ed9c03STimm Baeder // which has its own implementation of the Ret<> instruction. 336a07aba5dSTimm Baeder } 337a07aba5dSTimm Baeder return true; 338a07aba5dSTimm Baeder } 339a07aba5dSTimm Baeder 34082ed9c03STimm Baeder inline bool RetVoid(InterpState &S, CodePtr &PC) { 341a07aba5dSTimm Baeder assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 342a07aba5dSTimm Baeder 343a07aba5dSTimm Baeder if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 34483fea8b8STimm Baeder cleanupAfterFunctionCall(S, PC, S.Current->getFunction()); 345a07aba5dSTimm Baeder 346a07aba5dSTimm Baeder if (InterpFrame *Caller = S.Current->Caller) { 347a07aba5dSTimm Baeder PC = S.Current->getRetPC(); 348a07aba5dSTimm Baeder delete S.Current; 349a07aba5dSTimm Baeder S.Current = Caller; 350a07aba5dSTimm Baeder } else { 351a07aba5dSTimm Baeder delete S.Current; 352a07aba5dSTimm Baeder S.Current = nullptr; 353a07aba5dSTimm Baeder } 354a07aba5dSTimm Baeder return true; 355a07aba5dSTimm Baeder } 356a07aba5dSTimm Baeder 357a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 358a07aba5dSTimm Baeder // Add, Sub, Mul 359a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 360a07aba5dSTimm Baeder 361a07aba5dSTimm Baeder template <typename T, bool (*OpFW)(T, T, unsigned, T *), 362a07aba5dSTimm Baeder template <typename U> class OpAP> 363a07aba5dSTimm Baeder bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, 364a07aba5dSTimm Baeder const T &RHS) { 365a07aba5dSTimm Baeder // Fast path - add the numbers with fixed width. 366a07aba5dSTimm Baeder T Result; 367a07aba5dSTimm Baeder if (!OpFW(LHS, RHS, Bits, &Result)) { 368a07aba5dSTimm Baeder S.Stk.push<T>(Result); 369a07aba5dSTimm Baeder return true; 370a07aba5dSTimm Baeder } 371a07aba5dSTimm Baeder // If for some reason evaluation continues, use the truncated results. 372a07aba5dSTimm Baeder S.Stk.push<T>(Result); 373a07aba5dSTimm Baeder 3745c811cccSTimm Baeder // Short-circuit fixed-points here since the error handling is easier. 3755c811cccSTimm Baeder if constexpr (std::is_same_v<T, FixedPoint>) 3765c811cccSTimm Baeder return handleFixedPointOverflow(S, OpPC, Result); 3775c811cccSTimm Baeder 378a07aba5dSTimm Baeder // Slow path - compute the result using another bit of precision. 379a07aba5dSTimm Baeder APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); 380a07aba5dSTimm Baeder 381a07aba5dSTimm Baeder // Report undefined behaviour, stopping if required. 382a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 383a07aba5dSTimm Baeder QualType Type = E->getType(); 384a07aba5dSTimm Baeder if (S.checkingForUndefinedBehavior()) { 385a07aba5dSTimm Baeder SmallString<32> Trunc; 386a07aba5dSTimm Baeder Value.trunc(Result.bitWidth()) 387a07aba5dSTimm Baeder .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 388a07aba5dSTimm Baeder /*UpperCase=*/true, /*InsertSeparators=*/true); 389a07aba5dSTimm Baeder auto Loc = E->getExprLoc(); 390a07aba5dSTimm Baeder S.report(Loc, diag::warn_integer_constant_overflow) 391a07aba5dSTimm Baeder << Trunc << Type << E->getSourceRange(); 392a07aba5dSTimm Baeder } 393a07aba5dSTimm Baeder 39495ce78b7STimm Baeder if (!handleOverflow(S, OpPC, Value)) { 395a07aba5dSTimm Baeder S.Stk.pop<T>(); 396a07aba5dSTimm Baeder return false; 397a07aba5dSTimm Baeder } 398a07aba5dSTimm Baeder return true; 399a07aba5dSTimm Baeder } 400a07aba5dSTimm Baeder 401a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 402a07aba5dSTimm Baeder bool Add(InterpState &S, CodePtr OpPC) { 403a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 404a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 405a07aba5dSTimm Baeder const unsigned Bits = RHS.bitWidth() + 1; 406a07aba5dSTimm Baeder return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); 407a07aba5dSTimm Baeder } 408a07aba5dSTimm Baeder 4090f5f440fSTimm Baeder static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) { 4100f5f440fSTimm Baeder auto RM = FPO.getRoundingMode(); 4110f5f440fSTimm Baeder if (RM == llvm::RoundingMode::Dynamic) 4120f5f440fSTimm Baeder return llvm::RoundingMode::NearestTiesToEven; 4130f5f440fSTimm Baeder return RM; 4140f5f440fSTimm Baeder } 4150f5f440fSTimm Baeder 4160f5f440fSTimm Baeder inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 417a07aba5dSTimm Baeder const Floating &RHS = S.Stk.pop<Floating>(); 418a07aba5dSTimm Baeder const Floating &LHS = S.Stk.pop<Floating>(); 419a07aba5dSTimm Baeder 4200f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 421a07aba5dSTimm Baeder Floating Result; 4220f5f440fSTimm Baeder auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result); 423a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 4240f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 425a07aba5dSTimm Baeder } 426a07aba5dSTimm Baeder 427a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 428a07aba5dSTimm Baeder bool Sub(InterpState &S, CodePtr OpPC) { 429a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 430a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 431a07aba5dSTimm Baeder const unsigned Bits = RHS.bitWidth() + 1; 432a07aba5dSTimm Baeder return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); 433a07aba5dSTimm Baeder } 434a07aba5dSTimm Baeder 4350f5f440fSTimm Baeder inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 436a07aba5dSTimm Baeder const Floating &RHS = S.Stk.pop<Floating>(); 437a07aba5dSTimm Baeder const Floating &LHS = S.Stk.pop<Floating>(); 438a07aba5dSTimm Baeder 4390f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 440a07aba5dSTimm Baeder Floating Result; 4410f5f440fSTimm Baeder auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result); 442a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 4430f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 444a07aba5dSTimm Baeder } 445a07aba5dSTimm Baeder 446a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 447a07aba5dSTimm Baeder bool Mul(InterpState &S, CodePtr OpPC) { 448a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 449a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 450a07aba5dSTimm Baeder const unsigned Bits = RHS.bitWidth() * 2; 451a07aba5dSTimm Baeder return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); 452a07aba5dSTimm Baeder } 453a07aba5dSTimm Baeder 4540f5f440fSTimm Baeder inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 455a07aba5dSTimm Baeder const Floating &RHS = S.Stk.pop<Floating>(); 456a07aba5dSTimm Baeder const Floating &LHS = S.Stk.pop<Floating>(); 457a07aba5dSTimm Baeder 4580f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 459a07aba5dSTimm Baeder Floating Result; 4600f5f440fSTimm Baeder auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result); 461a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 4620f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 463a07aba5dSTimm Baeder } 464a07aba5dSTimm Baeder 465a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 466a07aba5dSTimm Baeder inline bool Mulc(InterpState &S, CodePtr OpPC) { 467a07aba5dSTimm Baeder const Pointer &RHS = S.Stk.pop<Pointer>(); 468a07aba5dSTimm Baeder const Pointer &LHS = S.Stk.pop<Pointer>(); 469a07aba5dSTimm Baeder const Pointer &Result = S.Stk.peek<Pointer>(); 470a07aba5dSTimm Baeder 471a07aba5dSTimm Baeder if constexpr (std::is_same_v<T, Floating>) { 472a07aba5dSTimm Baeder APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); 473a07aba5dSTimm Baeder APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); 474a07aba5dSTimm Baeder APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); 475a07aba5dSTimm Baeder APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); 476a07aba5dSTimm Baeder 477a07aba5dSTimm Baeder APFloat ResR(A.getSemantics()); 478a07aba5dSTimm Baeder APFloat ResI(A.getSemantics()); 479a07aba5dSTimm Baeder HandleComplexComplexMul(A, B, C, D, ResR, ResI); 480a07aba5dSTimm Baeder 481a07aba5dSTimm Baeder // Copy into the result. 482a07aba5dSTimm Baeder Result.atIndex(0).deref<Floating>() = Floating(ResR); 483a07aba5dSTimm Baeder Result.atIndex(0).initialize(); 484a07aba5dSTimm Baeder Result.atIndex(1).deref<Floating>() = Floating(ResI); 485a07aba5dSTimm Baeder Result.atIndex(1).initialize(); 486a07aba5dSTimm Baeder Result.initialize(); 487a07aba5dSTimm Baeder } else { 488a07aba5dSTimm Baeder // Integer element type. 489a07aba5dSTimm Baeder const T &LHSR = LHS.atIndex(0).deref<T>(); 490a07aba5dSTimm Baeder const T &LHSI = LHS.atIndex(1).deref<T>(); 491a07aba5dSTimm Baeder const T &RHSR = RHS.atIndex(0).deref<T>(); 492a07aba5dSTimm Baeder const T &RHSI = RHS.atIndex(1).deref<T>(); 493a07aba5dSTimm Baeder unsigned Bits = LHSR.bitWidth(); 494a07aba5dSTimm Baeder 495a07aba5dSTimm Baeder // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS)) 496a07aba5dSTimm Baeder T A; 497a07aba5dSTimm Baeder if (T::mul(LHSR, RHSR, Bits, &A)) 498a07aba5dSTimm Baeder return false; 499a07aba5dSTimm Baeder T B; 500a07aba5dSTimm Baeder if (T::mul(LHSI, RHSI, Bits, &B)) 501a07aba5dSTimm Baeder return false; 502a07aba5dSTimm Baeder if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>())) 503a07aba5dSTimm Baeder return false; 504a07aba5dSTimm Baeder Result.atIndex(0).initialize(); 505a07aba5dSTimm Baeder 506a07aba5dSTimm Baeder // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS)) 507a07aba5dSTimm Baeder if (T::mul(LHSR, RHSI, Bits, &A)) 508a07aba5dSTimm Baeder return false; 509a07aba5dSTimm Baeder if (T::mul(LHSI, RHSR, Bits, &B)) 510a07aba5dSTimm Baeder return false; 511a07aba5dSTimm Baeder if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>())) 512a07aba5dSTimm Baeder return false; 513a07aba5dSTimm Baeder Result.atIndex(1).initialize(); 514a07aba5dSTimm Baeder Result.initialize(); 515a07aba5dSTimm Baeder } 516a07aba5dSTimm Baeder 517a07aba5dSTimm Baeder return true; 518a07aba5dSTimm Baeder } 519a07aba5dSTimm Baeder 520a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 521a07aba5dSTimm Baeder inline bool Divc(InterpState &S, CodePtr OpPC) { 522a07aba5dSTimm Baeder const Pointer &RHS = S.Stk.pop<Pointer>(); 523a07aba5dSTimm Baeder const Pointer &LHS = S.Stk.pop<Pointer>(); 524a07aba5dSTimm Baeder const Pointer &Result = S.Stk.peek<Pointer>(); 525a07aba5dSTimm Baeder 526a07aba5dSTimm Baeder if constexpr (std::is_same_v<T, Floating>) { 527a07aba5dSTimm Baeder APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); 528a07aba5dSTimm Baeder APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); 529a07aba5dSTimm Baeder APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); 530a07aba5dSTimm Baeder APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); 531a07aba5dSTimm Baeder 532a07aba5dSTimm Baeder APFloat ResR(A.getSemantics()); 533a07aba5dSTimm Baeder APFloat ResI(A.getSemantics()); 534a07aba5dSTimm Baeder HandleComplexComplexDiv(A, B, C, D, ResR, ResI); 535a07aba5dSTimm Baeder 536a07aba5dSTimm Baeder // Copy into the result. 537a07aba5dSTimm Baeder Result.atIndex(0).deref<Floating>() = Floating(ResR); 538a07aba5dSTimm Baeder Result.atIndex(0).initialize(); 539a07aba5dSTimm Baeder Result.atIndex(1).deref<Floating>() = Floating(ResI); 540a07aba5dSTimm Baeder Result.atIndex(1).initialize(); 541a07aba5dSTimm Baeder Result.initialize(); 542a07aba5dSTimm Baeder } else { 543a07aba5dSTimm Baeder // Integer element type. 544a07aba5dSTimm Baeder const T &LHSR = LHS.atIndex(0).deref<T>(); 545a07aba5dSTimm Baeder const T &LHSI = LHS.atIndex(1).deref<T>(); 546a07aba5dSTimm Baeder const T &RHSR = RHS.atIndex(0).deref<T>(); 547a07aba5dSTimm Baeder const T &RHSI = RHS.atIndex(1).deref<T>(); 548a07aba5dSTimm Baeder unsigned Bits = LHSR.bitWidth(); 549a07aba5dSTimm Baeder const T Zero = T::from(0, Bits); 550a07aba5dSTimm Baeder 551a07aba5dSTimm Baeder if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal && 552a07aba5dSTimm Baeder Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) { 553a07aba5dSTimm Baeder const SourceInfo &E = S.Current->getSource(OpPC); 554a07aba5dSTimm Baeder S.FFDiag(E, diag::note_expr_divide_by_zero); 555a07aba5dSTimm Baeder return false; 556a07aba5dSTimm Baeder } 557a07aba5dSTimm Baeder 558a07aba5dSTimm Baeder // Den = real(RHS)² + imag(RHS)² 559a07aba5dSTimm Baeder T A, B; 56040db2615STimm Baeder if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) { 56140db2615STimm Baeder // Ignore overflow here, because that's what the current interpeter does. 56240db2615STimm Baeder } 563a07aba5dSTimm Baeder T Den; 564a07aba5dSTimm Baeder if (T::add(A, B, Bits, &Den)) 565a07aba5dSTimm Baeder return false; 566a07aba5dSTimm Baeder 56740db2615STimm Baeder if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) { 56840db2615STimm Baeder const SourceInfo &E = S.Current->getSource(OpPC); 56940db2615STimm Baeder S.FFDiag(E, diag::note_expr_divide_by_zero); 57040db2615STimm Baeder return false; 57140db2615STimm Baeder } 57240db2615STimm Baeder 573a07aba5dSTimm Baeder // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den 574a07aba5dSTimm Baeder T &ResultR = Result.atIndex(0).deref<T>(); 575a07aba5dSTimm Baeder T &ResultI = Result.atIndex(1).deref<T>(); 576a07aba5dSTimm Baeder 577a07aba5dSTimm Baeder if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B)) 578a07aba5dSTimm Baeder return false; 579a07aba5dSTimm Baeder if (T::add(A, B, Bits, &ResultR)) 580a07aba5dSTimm Baeder return false; 581a07aba5dSTimm Baeder if (T::div(ResultR, Den, Bits, &ResultR)) 582a07aba5dSTimm Baeder return false; 583a07aba5dSTimm Baeder Result.atIndex(0).initialize(); 584a07aba5dSTimm Baeder 585a07aba5dSTimm Baeder // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den 586a07aba5dSTimm Baeder if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B)) 587a07aba5dSTimm Baeder return false; 588a07aba5dSTimm Baeder if (T::sub(A, B, Bits, &ResultI)) 589a07aba5dSTimm Baeder return false; 590a07aba5dSTimm Baeder if (T::div(ResultI, Den, Bits, &ResultI)) 591a07aba5dSTimm Baeder return false; 592a07aba5dSTimm Baeder Result.atIndex(1).initialize(); 593a07aba5dSTimm Baeder Result.initialize(); 594a07aba5dSTimm Baeder } 595a07aba5dSTimm Baeder 596a07aba5dSTimm Baeder return true; 597a07aba5dSTimm Baeder } 598a07aba5dSTimm Baeder 599a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack. 600a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack. 601a07aba5dSTimm Baeder /// 3) Pushes 'LHS & RHS' on the stack 602a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 603a07aba5dSTimm Baeder bool BitAnd(InterpState &S, CodePtr OpPC) { 604a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 605a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 606a07aba5dSTimm Baeder 607a07aba5dSTimm Baeder unsigned Bits = RHS.bitWidth(); 608a07aba5dSTimm Baeder T Result; 609a07aba5dSTimm Baeder if (!T::bitAnd(LHS, RHS, Bits, &Result)) { 610a07aba5dSTimm Baeder S.Stk.push<T>(Result); 611a07aba5dSTimm Baeder return true; 612a07aba5dSTimm Baeder } 613a07aba5dSTimm Baeder return false; 614a07aba5dSTimm Baeder } 615a07aba5dSTimm Baeder 616a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack. 617a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack. 618a07aba5dSTimm Baeder /// 3) Pushes 'LHS | RHS' on the stack 619a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 620a07aba5dSTimm Baeder bool BitOr(InterpState &S, CodePtr OpPC) { 621a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 622a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 623a07aba5dSTimm Baeder 624a07aba5dSTimm Baeder unsigned Bits = RHS.bitWidth(); 625a07aba5dSTimm Baeder T Result; 626a07aba5dSTimm Baeder if (!T::bitOr(LHS, RHS, Bits, &Result)) { 627a07aba5dSTimm Baeder S.Stk.push<T>(Result); 628a07aba5dSTimm Baeder return true; 629a07aba5dSTimm Baeder } 630a07aba5dSTimm Baeder return false; 631a07aba5dSTimm Baeder } 632a07aba5dSTimm Baeder 633a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack. 634a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack. 635a07aba5dSTimm Baeder /// 3) Pushes 'LHS ^ RHS' on the stack 636a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 637a07aba5dSTimm Baeder bool BitXor(InterpState &S, CodePtr OpPC) { 638a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 639a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 640a07aba5dSTimm Baeder 641a07aba5dSTimm Baeder unsigned Bits = RHS.bitWidth(); 642a07aba5dSTimm Baeder T Result; 643a07aba5dSTimm Baeder if (!T::bitXor(LHS, RHS, Bits, &Result)) { 644a07aba5dSTimm Baeder S.Stk.push<T>(Result); 645a07aba5dSTimm Baeder return true; 646a07aba5dSTimm Baeder } 647a07aba5dSTimm Baeder return false; 648a07aba5dSTimm Baeder } 649a07aba5dSTimm Baeder 650a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack. 651a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack. 652a07aba5dSTimm Baeder /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS). 653a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 654a07aba5dSTimm Baeder bool Rem(InterpState &S, CodePtr OpPC) { 655a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 656a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 657a07aba5dSTimm Baeder 658a07aba5dSTimm Baeder if (!CheckDivRem(S, OpPC, LHS, RHS)) 659a07aba5dSTimm Baeder return false; 660a07aba5dSTimm Baeder 661a07aba5dSTimm Baeder const unsigned Bits = RHS.bitWidth() * 2; 662a07aba5dSTimm Baeder T Result; 663a07aba5dSTimm Baeder if (!T::rem(LHS, RHS, Bits, &Result)) { 664a07aba5dSTimm Baeder S.Stk.push<T>(Result); 665a07aba5dSTimm Baeder return true; 666a07aba5dSTimm Baeder } 667a07aba5dSTimm Baeder return false; 668a07aba5dSTimm Baeder } 669a07aba5dSTimm Baeder 670a07aba5dSTimm Baeder /// 1) Pops the RHS from the stack. 671a07aba5dSTimm Baeder /// 2) Pops the LHS from the stack. 672a07aba5dSTimm Baeder /// 3) Pushes 'LHS / RHS' on the stack 673a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 674a07aba5dSTimm Baeder bool Div(InterpState &S, CodePtr OpPC) { 675a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 676a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 677a07aba5dSTimm Baeder 678a07aba5dSTimm Baeder if (!CheckDivRem(S, OpPC, LHS, RHS)) 679a07aba5dSTimm Baeder return false; 680a07aba5dSTimm Baeder 681a07aba5dSTimm Baeder const unsigned Bits = RHS.bitWidth() * 2; 682a07aba5dSTimm Baeder T Result; 683a07aba5dSTimm Baeder if (!T::div(LHS, RHS, Bits, &Result)) { 684a07aba5dSTimm Baeder S.Stk.push<T>(Result); 685a07aba5dSTimm Baeder return true; 686a07aba5dSTimm Baeder } 6875c811cccSTimm Baeder 6885c811cccSTimm Baeder if constexpr (std::is_same_v<T, FixedPoint>) { 6895c811cccSTimm Baeder if (handleFixedPointOverflow(S, OpPC, Result)) { 6905c811cccSTimm Baeder S.Stk.push<T>(Result); 6915c811cccSTimm Baeder return true; 6925c811cccSTimm Baeder } 6935c811cccSTimm Baeder } 694a07aba5dSTimm Baeder return false; 695a07aba5dSTimm Baeder } 696a07aba5dSTimm Baeder 6970f5f440fSTimm Baeder inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 698a07aba5dSTimm Baeder const Floating &RHS = S.Stk.pop<Floating>(); 699a07aba5dSTimm Baeder const Floating &LHS = S.Stk.pop<Floating>(); 700a07aba5dSTimm Baeder 701a07aba5dSTimm Baeder if (!CheckDivRem(S, OpPC, LHS, RHS)) 702a07aba5dSTimm Baeder return false; 703a07aba5dSTimm Baeder 7040f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 705a07aba5dSTimm Baeder Floating Result; 7060f5f440fSTimm Baeder auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result); 707a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 7080f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 709a07aba5dSTimm Baeder } 710a07aba5dSTimm Baeder 711a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 712a07aba5dSTimm Baeder // Inv 713a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 714a07aba5dSTimm Baeder 715d082f1f3STimm Bäder inline bool Inv(InterpState &S, CodePtr OpPC) { 716d082f1f3STimm Bäder const auto &Val = S.Stk.pop<Boolean>(); 717d082f1f3STimm Bäder S.Stk.push<Boolean>(!Val); 718a07aba5dSTimm Baeder return true; 719a07aba5dSTimm Baeder } 720a07aba5dSTimm Baeder 721a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 722a07aba5dSTimm Baeder // Neg 723a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 724a07aba5dSTimm Baeder 725a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 726a07aba5dSTimm Baeder bool Neg(InterpState &S, CodePtr OpPC) { 727a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 728a07aba5dSTimm Baeder T Result; 729a07aba5dSTimm Baeder 730a07aba5dSTimm Baeder if (!T::neg(Value, &Result)) { 731a07aba5dSTimm Baeder S.Stk.push<T>(Result); 732a07aba5dSTimm Baeder return true; 733a07aba5dSTimm Baeder } 734a07aba5dSTimm Baeder 735a07aba5dSTimm Baeder assert(isIntegralType(Name) && 736a07aba5dSTimm Baeder "don't expect other types to fail at constexpr negation"); 737a07aba5dSTimm Baeder S.Stk.push<T>(Result); 738a07aba5dSTimm Baeder 739a07aba5dSTimm Baeder APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); 740a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 741a07aba5dSTimm Baeder QualType Type = E->getType(); 742a07aba5dSTimm Baeder 743a07aba5dSTimm Baeder if (S.checkingForUndefinedBehavior()) { 744a07aba5dSTimm Baeder SmallString<32> Trunc; 745a07aba5dSTimm Baeder NegatedValue.trunc(Result.bitWidth()) 746a07aba5dSTimm Baeder .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 747a07aba5dSTimm Baeder /*UpperCase=*/true, /*InsertSeparators=*/true); 748a07aba5dSTimm Baeder auto Loc = E->getExprLoc(); 749a07aba5dSTimm Baeder S.report(Loc, diag::warn_integer_constant_overflow) 750a07aba5dSTimm Baeder << Trunc << Type << E->getSourceRange(); 751a07aba5dSTimm Baeder return true; 752a07aba5dSTimm Baeder } 753a07aba5dSTimm Baeder 75495ce78b7STimm Baeder return handleOverflow(S, OpPC, NegatedValue); 755a07aba5dSTimm Baeder } 756a07aba5dSTimm Baeder 757a07aba5dSTimm Baeder enum class PushVal : bool { 758a07aba5dSTimm Baeder No, 759a07aba5dSTimm Baeder Yes, 760a07aba5dSTimm Baeder }; 761a07aba5dSTimm Baeder enum class IncDecOp { 762a07aba5dSTimm Baeder Inc, 763a07aba5dSTimm Baeder Dec, 764a07aba5dSTimm Baeder }; 765a07aba5dSTimm Baeder 766a07aba5dSTimm Baeder template <typename T, IncDecOp Op, PushVal DoPush> 767a07aba5dSTimm Baeder bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 768a07aba5dSTimm Baeder assert(!Ptr.isDummy()); 769a07aba5dSTimm Baeder 770a07aba5dSTimm Baeder if constexpr (std::is_same_v<T, Boolean>) { 771a07aba5dSTimm Baeder if (!S.getLangOpts().CPlusPlus14) 772a07aba5dSTimm Baeder return Invalid(S, OpPC); 773a07aba5dSTimm Baeder } 774a07aba5dSTimm Baeder 775a07aba5dSTimm Baeder const T &Value = Ptr.deref<T>(); 776a07aba5dSTimm Baeder T Result; 777a07aba5dSTimm Baeder 778a07aba5dSTimm Baeder if constexpr (DoPush == PushVal::Yes) 779a07aba5dSTimm Baeder S.Stk.push<T>(Value); 780a07aba5dSTimm Baeder 781a07aba5dSTimm Baeder if constexpr (Op == IncDecOp::Inc) { 782a07aba5dSTimm Baeder if (!T::increment(Value, &Result)) { 783a07aba5dSTimm Baeder Ptr.deref<T>() = Result; 784a07aba5dSTimm Baeder return true; 785a07aba5dSTimm Baeder } 786a07aba5dSTimm Baeder } else { 787a07aba5dSTimm Baeder if (!T::decrement(Value, &Result)) { 788a07aba5dSTimm Baeder Ptr.deref<T>() = Result; 789a07aba5dSTimm Baeder return true; 790a07aba5dSTimm Baeder } 791a07aba5dSTimm Baeder } 792a07aba5dSTimm Baeder 793a07aba5dSTimm Baeder // Something went wrong with the previous operation. Compute the 794a07aba5dSTimm Baeder // result with another bit of precision. 795a07aba5dSTimm Baeder unsigned Bits = Value.bitWidth() + 1; 796a07aba5dSTimm Baeder APSInt APResult; 797a07aba5dSTimm Baeder if constexpr (Op == IncDecOp::Inc) 798a07aba5dSTimm Baeder APResult = ++Value.toAPSInt(Bits); 799a07aba5dSTimm Baeder else 800a07aba5dSTimm Baeder APResult = --Value.toAPSInt(Bits); 801a07aba5dSTimm Baeder 802a07aba5dSTimm Baeder // Report undefined behaviour, stopping if required. 803a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 804a07aba5dSTimm Baeder QualType Type = E->getType(); 805a07aba5dSTimm Baeder if (S.checkingForUndefinedBehavior()) { 806a07aba5dSTimm Baeder SmallString<32> Trunc; 807a07aba5dSTimm Baeder APResult.trunc(Result.bitWidth()) 808a07aba5dSTimm Baeder .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 809a07aba5dSTimm Baeder /*UpperCase=*/true, /*InsertSeparators=*/true); 810a07aba5dSTimm Baeder auto Loc = E->getExprLoc(); 811a07aba5dSTimm Baeder S.report(Loc, diag::warn_integer_constant_overflow) 812a07aba5dSTimm Baeder << Trunc << Type << E->getSourceRange(); 813a07aba5dSTimm Baeder return true; 814a07aba5dSTimm Baeder } 815a07aba5dSTimm Baeder 81695ce78b7STimm Baeder return handleOverflow(S, OpPC, APResult); 817a07aba5dSTimm Baeder } 818a07aba5dSTimm Baeder 819a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack 820a07aba5dSTimm Baeder /// 2) Load the value from the pointer 821a07aba5dSTimm Baeder /// 3) Writes the value increased by one back to the pointer 822a07aba5dSTimm Baeder /// 4) Pushes the original (pre-inc) value on the stack. 823a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 824a07aba5dSTimm Baeder bool Inc(InterpState &S, CodePtr OpPC) { 825a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 826a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 827a07aba5dSTimm Baeder return false; 828a07aba5dSTimm Baeder 829a07aba5dSTimm Baeder return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr); 830a07aba5dSTimm Baeder } 831a07aba5dSTimm Baeder 832a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack 833a07aba5dSTimm Baeder /// 2) Load the value from the pointer 834a07aba5dSTimm Baeder /// 3) Writes the value increased by one back to the pointer 835a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 836a07aba5dSTimm Baeder bool IncPop(InterpState &S, CodePtr OpPC) { 837a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 838a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 839a07aba5dSTimm Baeder return false; 840a07aba5dSTimm Baeder 841a07aba5dSTimm Baeder return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr); 842a07aba5dSTimm Baeder } 843a07aba5dSTimm Baeder 844a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack 845a07aba5dSTimm Baeder /// 2) Load the value from the pointer 846a07aba5dSTimm Baeder /// 3) Writes the value decreased by one back to the pointer 847a07aba5dSTimm Baeder /// 4) Pushes the original (pre-dec) value on the stack. 848a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 849a07aba5dSTimm Baeder bool Dec(InterpState &S, CodePtr OpPC) { 850a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 851a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 852a07aba5dSTimm Baeder return false; 853a07aba5dSTimm Baeder 854a07aba5dSTimm Baeder return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr); 855a07aba5dSTimm Baeder } 856a07aba5dSTimm Baeder 857a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack 858a07aba5dSTimm Baeder /// 2) Load the value from the pointer 859a07aba5dSTimm Baeder /// 3) Writes the value decreased by one back to the pointer 860a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 861a07aba5dSTimm Baeder bool DecPop(InterpState &S, CodePtr OpPC) { 862a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 863a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 864a07aba5dSTimm Baeder return false; 865a07aba5dSTimm Baeder 866a07aba5dSTimm Baeder return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr); 867a07aba5dSTimm Baeder } 868a07aba5dSTimm Baeder 869a07aba5dSTimm Baeder template <IncDecOp Op, PushVal DoPush> 870a07aba5dSTimm Baeder bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 8710f5f440fSTimm Baeder uint32_t FPOI) { 872a07aba5dSTimm Baeder Floating Value = Ptr.deref<Floating>(); 873a07aba5dSTimm Baeder Floating Result; 874a07aba5dSTimm Baeder 875a07aba5dSTimm Baeder if constexpr (DoPush == PushVal::Yes) 876a07aba5dSTimm Baeder S.Stk.push<Floating>(Value); 877a07aba5dSTimm Baeder 8780f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 879a07aba5dSTimm Baeder llvm::APFloat::opStatus Status; 880a07aba5dSTimm Baeder if constexpr (Op == IncDecOp::Inc) 8810f5f440fSTimm Baeder Status = Floating::increment(Value, getRoundingMode(FPO), &Result); 882a07aba5dSTimm Baeder else 8830f5f440fSTimm Baeder Status = Floating::decrement(Value, getRoundingMode(FPO), &Result); 884a07aba5dSTimm Baeder 885a07aba5dSTimm Baeder Ptr.deref<Floating>() = Result; 886a07aba5dSTimm Baeder 8870f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 888a07aba5dSTimm Baeder } 889a07aba5dSTimm Baeder 8900f5f440fSTimm Baeder inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 891a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 892a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 893a07aba5dSTimm Baeder return false; 894a07aba5dSTimm Baeder 8950f5f440fSTimm Baeder return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI); 896a07aba5dSTimm Baeder } 897a07aba5dSTimm Baeder 8980f5f440fSTimm Baeder inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 899a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 900a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 901a07aba5dSTimm Baeder return false; 902a07aba5dSTimm Baeder 9030f5f440fSTimm Baeder return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI); 904a07aba5dSTimm Baeder } 905a07aba5dSTimm Baeder 9060f5f440fSTimm Baeder inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 907a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 908a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 909a07aba5dSTimm Baeder return false; 910a07aba5dSTimm Baeder 9110f5f440fSTimm Baeder return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI); 912a07aba5dSTimm Baeder } 913a07aba5dSTimm Baeder 9140f5f440fSTimm Baeder inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 915a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 916a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 917a07aba5dSTimm Baeder return false; 918a07aba5dSTimm Baeder 9190f5f440fSTimm Baeder return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI); 920a07aba5dSTimm Baeder } 921a07aba5dSTimm Baeder 922a07aba5dSTimm Baeder /// 1) Pops the value from the stack. 923a07aba5dSTimm Baeder /// 2) Pushes the bitwise complemented value on the stack (~V). 924a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 925a07aba5dSTimm Baeder bool Comp(InterpState &S, CodePtr OpPC) { 926a07aba5dSTimm Baeder const T &Val = S.Stk.pop<T>(); 927a07aba5dSTimm Baeder T Result; 928a07aba5dSTimm Baeder if (!T::comp(Val, &Result)) { 929a07aba5dSTimm Baeder S.Stk.push<T>(Result); 930a07aba5dSTimm Baeder return true; 931a07aba5dSTimm Baeder } 932a07aba5dSTimm Baeder 933a07aba5dSTimm Baeder return false; 934a07aba5dSTimm Baeder } 935a07aba5dSTimm Baeder 936a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 937a07aba5dSTimm Baeder // EQ, NE, GT, GE, LT, LE 938a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 939a07aba5dSTimm Baeder 940a07aba5dSTimm Baeder using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; 941a07aba5dSTimm Baeder 942a07aba5dSTimm Baeder template <typename T> 943a07aba5dSTimm Baeder bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { 944a07aba5dSTimm Baeder assert((!std::is_same_v<T, MemberPointer>) && 945a07aba5dSTimm Baeder "Non-equality comparisons on member pointer types should already be " 946a07aba5dSTimm Baeder "rejected in Sema."); 947a07aba5dSTimm Baeder using BoolT = PrimConv<PT_Bool>::T; 948a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 949a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 950a07aba5dSTimm Baeder S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); 951a07aba5dSTimm Baeder return true; 952a07aba5dSTimm Baeder } 953a07aba5dSTimm Baeder 954a07aba5dSTimm Baeder template <typename T> 955a07aba5dSTimm Baeder bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { 956a07aba5dSTimm Baeder return CmpHelper<T>(S, OpPC, Fn); 957a07aba5dSTimm Baeder } 958a07aba5dSTimm Baeder 959a07aba5dSTimm Baeder /// Function pointers cannot be compared in an ordered way. 960a07aba5dSTimm Baeder template <> 961a07aba5dSTimm Baeder inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC, 962a07aba5dSTimm Baeder CompareFn Fn) { 963a07aba5dSTimm Baeder const auto &RHS = S.Stk.pop<FunctionPointer>(); 964a07aba5dSTimm Baeder const auto &LHS = S.Stk.pop<FunctionPointer>(); 965a07aba5dSTimm Baeder 966a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 967a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 968d9e72860Syronglin << LHS.toDiagnosticString(S.getASTContext()) 969d9e72860Syronglin << RHS.toDiagnosticString(S.getASTContext()); 970a07aba5dSTimm Baeder return false; 971a07aba5dSTimm Baeder } 972a07aba5dSTimm Baeder 973a07aba5dSTimm Baeder template <> 974a07aba5dSTimm Baeder inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC, 975a07aba5dSTimm Baeder CompareFn Fn) { 976a07aba5dSTimm Baeder const auto &RHS = S.Stk.pop<FunctionPointer>(); 977a07aba5dSTimm Baeder const auto &LHS = S.Stk.pop<FunctionPointer>(); 978a07aba5dSTimm Baeder 979a07aba5dSTimm Baeder // We cannot compare against weak declarations at compile time. 980a07aba5dSTimm Baeder for (const auto &FP : {LHS, RHS}) { 981a07aba5dSTimm Baeder if (FP.isWeak()) { 982a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 983a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) 984d9e72860Syronglin << FP.toDiagnosticString(S.getASTContext()); 985a07aba5dSTimm Baeder return false; 986a07aba5dSTimm Baeder } 987a07aba5dSTimm Baeder } 988a07aba5dSTimm Baeder 989a07aba5dSTimm Baeder S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); 990a07aba5dSTimm Baeder return true; 991a07aba5dSTimm Baeder } 992a07aba5dSTimm Baeder 993a07aba5dSTimm Baeder template <> 994a07aba5dSTimm Baeder inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 995a07aba5dSTimm Baeder using BoolT = PrimConv<PT_Bool>::T; 996a07aba5dSTimm Baeder const Pointer &RHS = S.Stk.pop<Pointer>(); 997a07aba5dSTimm Baeder const Pointer &LHS = S.Stk.pop<Pointer>(); 998a07aba5dSTimm Baeder 999a07aba5dSTimm Baeder if (!Pointer::hasSameBase(LHS, RHS)) { 1000a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1001a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 1002d9e72860Syronglin << LHS.toDiagnosticString(S.getASTContext()) 1003d9e72860Syronglin << RHS.toDiagnosticString(S.getASTContext()); 1004a07aba5dSTimm Baeder return false; 1005a07aba5dSTimm Baeder } else { 1006a07aba5dSTimm Baeder unsigned VL = LHS.getByteOffset(); 1007a07aba5dSTimm Baeder unsigned VR = RHS.getByteOffset(); 1008a07aba5dSTimm Baeder S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 1009a07aba5dSTimm Baeder return true; 1010a07aba5dSTimm Baeder } 1011a07aba5dSTimm Baeder } 1012a07aba5dSTimm Baeder 1013a07aba5dSTimm Baeder template <> 1014a07aba5dSTimm Baeder inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 1015a07aba5dSTimm Baeder using BoolT = PrimConv<PT_Bool>::T; 1016a07aba5dSTimm Baeder const Pointer &RHS = S.Stk.pop<Pointer>(); 1017a07aba5dSTimm Baeder const Pointer &LHS = S.Stk.pop<Pointer>(); 1018a07aba5dSTimm Baeder 1019a07aba5dSTimm Baeder if (LHS.isZero() && RHS.isZero()) { 1020a07aba5dSTimm Baeder S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); 1021a07aba5dSTimm Baeder return true; 1022a07aba5dSTimm Baeder } 1023a07aba5dSTimm Baeder 1024a07aba5dSTimm Baeder // Reject comparisons to weak pointers. 1025a07aba5dSTimm Baeder for (const auto &P : {LHS, RHS}) { 1026a07aba5dSTimm Baeder if (P.isZero()) 1027a07aba5dSTimm Baeder continue; 1028a07aba5dSTimm Baeder if (P.isWeak()) { 1029a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1030a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) 1031d9e72860Syronglin << P.toDiagnosticString(S.getASTContext()); 1032a07aba5dSTimm Baeder return false; 1033a07aba5dSTimm Baeder } 1034a07aba5dSTimm Baeder } 1035a07aba5dSTimm Baeder 1036360e4abfSTimm Baeder if (Pointer::hasSameBase(LHS, RHS)) { 1037a07aba5dSTimm Baeder unsigned VL = LHS.getByteOffset(); 1038a07aba5dSTimm Baeder unsigned VR = RHS.getByteOffset(); 1039a07aba5dSTimm Baeder 1040a07aba5dSTimm Baeder // In our Pointer class, a pointer to an array and a pointer to the first 1041a07aba5dSTimm Baeder // element in the same array are NOT equal. They have the same Base value, 1042a07aba5dSTimm Baeder // but a different Offset. This is a pretty rare case, so we fix this here 1043a07aba5dSTimm Baeder // by comparing pointers to the first elements. 1044a07aba5dSTimm Baeder if (!LHS.isZero() && LHS.isArrayRoot()) 1045a07aba5dSTimm Baeder VL = LHS.atIndex(0).getByteOffset(); 1046a07aba5dSTimm Baeder if (!RHS.isZero() && RHS.isArrayRoot()) 1047a07aba5dSTimm Baeder VR = RHS.atIndex(0).getByteOffset(); 1048a07aba5dSTimm Baeder 1049a07aba5dSTimm Baeder S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 1050a07aba5dSTimm Baeder return true; 1051a07aba5dSTimm Baeder } 1052360e4abfSTimm Baeder // Otherwise we need to do a bunch of extra checks before returning Unordered. 1053360e4abfSTimm Baeder if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && 1054360e4abfSTimm Baeder RHS.getOffset() == 0) { 1055360e4abfSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1056360e4abfSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) 1057360e4abfSTimm Baeder << LHS.toDiagnosticString(S.getASTContext()); 1058360e4abfSTimm Baeder return false; 1059360e4abfSTimm Baeder } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && 1060360e4abfSTimm Baeder LHS.getOffset() == 0) { 1061360e4abfSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1062360e4abfSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) 1063360e4abfSTimm Baeder << RHS.toDiagnosticString(S.getASTContext()); 1064360e4abfSTimm Baeder return false; 1065360e4abfSTimm Baeder } 1066360e4abfSTimm Baeder 1067360e4abfSTimm Baeder bool BothNonNull = !LHS.isZero() && !RHS.isZero(); 1068360e4abfSTimm Baeder // Reject comparisons to literals. 1069360e4abfSTimm Baeder for (const auto &P : {LHS, RHS}) { 1070360e4abfSTimm Baeder if (P.isZero()) 1071360e4abfSTimm Baeder continue; 1072360e4abfSTimm Baeder if (BothNonNull && P.pointsToLiteral()) { 1073360e4abfSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1074360e4abfSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_literal_comparison); 1075360e4abfSTimm Baeder return false; 1076360e4abfSTimm Baeder } 1077360e4abfSTimm Baeder } 1078360e4abfSTimm Baeder 1079360e4abfSTimm Baeder S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); 1080360e4abfSTimm Baeder return true; 1081a07aba5dSTimm Baeder } 1082a07aba5dSTimm Baeder 1083a07aba5dSTimm Baeder template <> 1084a07aba5dSTimm Baeder inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC, 1085a07aba5dSTimm Baeder CompareFn Fn) { 1086a07aba5dSTimm Baeder const auto &RHS = S.Stk.pop<MemberPointer>(); 1087a07aba5dSTimm Baeder const auto &LHS = S.Stk.pop<MemberPointer>(); 1088a07aba5dSTimm Baeder 1089a07aba5dSTimm Baeder // If either operand is a pointer to a weak function, the comparison is not 1090a07aba5dSTimm Baeder // constant. 1091a07aba5dSTimm Baeder for (const auto &MP : {LHS, RHS}) { 1092360e4abfSTimm Baeder if (MP.isWeak()) { 1093a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1094360e4abfSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) 1095360e4abfSTimm Baeder << MP.getMemberFunction(); 1096a07aba5dSTimm Baeder return false; 1097a07aba5dSTimm Baeder } 1098a07aba5dSTimm Baeder } 1099a07aba5dSTimm Baeder 1100a07aba5dSTimm Baeder // C++11 [expr.eq]p2: 1101a07aba5dSTimm Baeder // If both operands are null, they compare equal. Otherwise if only one is 1102a07aba5dSTimm Baeder // null, they compare unequal. 1103a07aba5dSTimm Baeder if (LHS.isZero() && RHS.isZero()) { 1104a07aba5dSTimm Baeder S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal)); 1105a07aba5dSTimm Baeder return true; 1106a07aba5dSTimm Baeder } 1107a07aba5dSTimm Baeder if (LHS.isZero() || RHS.isZero()) { 1108a07aba5dSTimm Baeder S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered)); 1109a07aba5dSTimm Baeder return true; 1110a07aba5dSTimm Baeder } 1111a07aba5dSTimm Baeder 1112a07aba5dSTimm Baeder // We cannot compare against virtual declarations at compile time. 1113a07aba5dSTimm Baeder for (const auto &MP : {LHS, RHS}) { 1114a07aba5dSTimm Baeder if (const CXXMethodDecl *MD = MP.getMemberFunction(); 1115a07aba5dSTimm Baeder MD && MD->isVirtual()) { 1116a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1117a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD; 1118a07aba5dSTimm Baeder } 1119a07aba5dSTimm Baeder } 1120a07aba5dSTimm Baeder 1121a07aba5dSTimm Baeder S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); 1122a07aba5dSTimm Baeder return true; 1123a07aba5dSTimm Baeder } 1124a07aba5dSTimm Baeder 1125a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1126a07aba5dSTimm Baeder bool EQ(InterpState &S, CodePtr OpPC) { 1127a07aba5dSTimm Baeder return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 1128a07aba5dSTimm Baeder return R == ComparisonCategoryResult::Equal; 1129a07aba5dSTimm Baeder }); 1130a07aba5dSTimm Baeder } 1131a07aba5dSTimm Baeder 1132a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1133a07aba5dSTimm Baeder bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) { 1134a07aba5dSTimm Baeder const T &RHS = S.Stk.pop<T>(); 1135a07aba5dSTimm Baeder const T &LHS = S.Stk.pop<T>(); 1136a07aba5dSTimm Baeder const Pointer &P = S.Stk.peek<Pointer>(); 1137a07aba5dSTimm Baeder 1138a07aba5dSTimm Baeder ComparisonCategoryResult CmpResult = LHS.compare(RHS); 1139a07aba5dSTimm Baeder if (CmpResult == ComparisonCategoryResult::Unordered) { 1140a07aba5dSTimm Baeder // This should only happen with pointers. 1141a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 1142a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 1143d9e72860Syronglin << LHS.toDiagnosticString(S.getASTContext()) 1144d9e72860Syronglin << RHS.toDiagnosticString(S.getASTContext()); 1145a07aba5dSTimm Baeder return false; 1146a07aba5dSTimm Baeder } 1147a07aba5dSTimm Baeder 1148a07aba5dSTimm Baeder assert(CmpInfo); 1149a07aba5dSTimm Baeder const auto *CmpValueInfo = 1150a07aba5dSTimm Baeder CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult)); 1151a07aba5dSTimm Baeder assert(CmpValueInfo); 1152a07aba5dSTimm Baeder assert(CmpValueInfo->hasValidIntValue()); 1153a07aba5dSTimm Baeder return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue()); 1154a07aba5dSTimm Baeder } 1155a07aba5dSTimm Baeder 1156a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1157a07aba5dSTimm Baeder bool NE(InterpState &S, CodePtr OpPC) { 1158a07aba5dSTimm Baeder return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 1159a07aba5dSTimm Baeder return R != ComparisonCategoryResult::Equal; 1160a07aba5dSTimm Baeder }); 1161a07aba5dSTimm Baeder } 1162a07aba5dSTimm Baeder 1163a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1164a07aba5dSTimm Baeder bool LT(InterpState &S, CodePtr OpPC) { 1165a07aba5dSTimm Baeder return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1166a07aba5dSTimm Baeder return R == ComparisonCategoryResult::Less; 1167a07aba5dSTimm Baeder }); 1168a07aba5dSTimm Baeder } 1169a07aba5dSTimm Baeder 1170a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1171a07aba5dSTimm Baeder bool LE(InterpState &S, CodePtr OpPC) { 1172a07aba5dSTimm Baeder return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1173a07aba5dSTimm Baeder return R == ComparisonCategoryResult::Less || 1174a07aba5dSTimm Baeder R == ComparisonCategoryResult::Equal; 1175a07aba5dSTimm Baeder }); 1176a07aba5dSTimm Baeder } 1177a07aba5dSTimm Baeder 1178a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1179a07aba5dSTimm Baeder bool GT(InterpState &S, CodePtr OpPC) { 1180a07aba5dSTimm Baeder return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1181a07aba5dSTimm Baeder return R == ComparisonCategoryResult::Greater; 1182a07aba5dSTimm Baeder }); 1183a07aba5dSTimm Baeder } 1184a07aba5dSTimm Baeder 1185a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1186a07aba5dSTimm Baeder bool GE(InterpState &S, CodePtr OpPC) { 1187a07aba5dSTimm Baeder return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1188a07aba5dSTimm Baeder return R == ComparisonCategoryResult::Greater || 1189a07aba5dSTimm Baeder R == ComparisonCategoryResult::Equal; 1190a07aba5dSTimm Baeder }); 1191a07aba5dSTimm Baeder } 1192a07aba5dSTimm Baeder 1193a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1194a07aba5dSTimm Baeder // InRange 1195a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1196a07aba5dSTimm Baeder 1197a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1198a07aba5dSTimm Baeder bool InRange(InterpState &S, CodePtr OpPC) { 1199a07aba5dSTimm Baeder const T RHS = S.Stk.pop<T>(); 1200a07aba5dSTimm Baeder const T LHS = S.Stk.pop<T>(); 1201a07aba5dSTimm Baeder const T Value = S.Stk.pop<T>(); 1202a07aba5dSTimm Baeder 1203a07aba5dSTimm Baeder S.Stk.push<bool>(LHS <= Value && Value <= RHS); 1204a07aba5dSTimm Baeder return true; 1205a07aba5dSTimm Baeder } 1206a07aba5dSTimm Baeder 1207a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1208a07aba5dSTimm Baeder // Dup, Pop, Test 1209a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1210a07aba5dSTimm Baeder 1211a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1212a07aba5dSTimm Baeder bool Dup(InterpState &S, CodePtr OpPC) { 1213a07aba5dSTimm Baeder S.Stk.push<T>(S.Stk.peek<T>()); 1214a07aba5dSTimm Baeder return true; 1215a07aba5dSTimm Baeder } 1216a07aba5dSTimm Baeder 1217a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1218a07aba5dSTimm Baeder bool Pop(InterpState &S, CodePtr OpPC) { 1219a07aba5dSTimm Baeder S.Stk.pop<T>(); 1220a07aba5dSTimm Baeder return true; 1221a07aba5dSTimm Baeder } 1222a07aba5dSTimm Baeder 1223a07aba5dSTimm Baeder /// [Value1, Value2] -> [Value2, Value1] 1224a07aba5dSTimm Baeder template <PrimType TopName, PrimType BottomName> 1225a07aba5dSTimm Baeder bool Flip(InterpState &S, CodePtr OpPC) { 1226a07aba5dSTimm Baeder using TopT = typename PrimConv<TopName>::T; 1227a07aba5dSTimm Baeder using BottomT = typename PrimConv<BottomName>::T; 1228a07aba5dSTimm Baeder 1229a07aba5dSTimm Baeder const auto &Top = S.Stk.pop<TopT>(); 1230a07aba5dSTimm Baeder const auto &Bottom = S.Stk.pop<BottomT>(); 1231a07aba5dSTimm Baeder 1232a07aba5dSTimm Baeder S.Stk.push<TopT>(Top); 1233a07aba5dSTimm Baeder S.Stk.push<BottomT>(Bottom); 1234a07aba5dSTimm Baeder 1235a07aba5dSTimm Baeder return true; 1236a07aba5dSTimm Baeder } 1237a07aba5dSTimm Baeder 1238a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1239a07aba5dSTimm Baeder // Const 1240a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1241a07aba5dSTimm Baeder 1242a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1243a07aba5dSTimm Baeder bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { 1244a07aba5dSTimm Baeder S.Stk.push<T>(Arg); 1245a07aba5dSTimm Baeder return true; 1246a07aba5dSTimm Baeder } 1247a07aba5dSTimm Baeder 1248a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1249a07aba5dSTimm Baeder // Get/Set Local/Param/Global/This 1250a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1251a07aba5dSTimm Baeder 1252a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1253a07aba5dSTimm Baeder bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1254a07aba5dSTimm Baeder const Pointer &Ptr = S.Current->getLocalPointer(I); 1255a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr)) 1256a07aba5dSTimm Baeder return false; 1257a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.deref<T>()); 1258a07aba5dSTimm Baeder return true; 1259a07aba5dSTimm Baeder } 1260a07aba5dSTimm Baeder 1261a07aba5dSTimm Baeder /// 1) Pops the value from the stack. 1262a07aba5dSTimm Baeder /// 2) Writes the value to the local variable with the 1263a07aba5dSTimm Baeder /// given offset. 1264a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1265a07aba5dSTimm Baeder bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1266a07aba5dSTimm Baeder S.Current->setLocal<T>(I, S.Stk.pop<T>()); 1267a07aba5dSTimm Baeder return true; 1268a07aba5dSTimm Baeder } 1269a07aba5dSTimm Baeder 1270a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1271a07aba5dSTimm Baeder bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1272a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) { 1273a07aba5dSTimm Baeder return false; 1274a07aba5dSTimm Baeder } 1275a07aba5dSTimm Baeder S.Stk.push<T>(S.Current->getParam<T>(I)); 1276a07aba5dSTimm Baeder return true; 1277a07aba5dSTimm Baeder } 1278a07aba5dSTimm Baeder 1279a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1280a07aba5dSTimm Baeder bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1281a07aba5dSTimm Baeder S.Current->setParam<T>(I, S.Stk.pop<T>()); 1282a07aba5dSTimm Baeder return true; 1283a07aba5dSTimm Baeder } 1284a07aba5dSTimm Baeder 1285a07aba5dSTimm Baeder /// 1) Peeks a pointer on the stack 1286a07aba5dSTimm Baeder /// 2) Pushes the value of the pointer's field on the stack 1287a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1288a07aba5dSTimm Baeder bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { 1289a07aba5dSTimm Baeder const Pointer &Obj = S.Stk.peek<Pointer>(); 1290a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1291a07aba5dSTimm Baeder return false; 1292a07aba5dSTimm Baeder if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1293a07aba5dSTimm Baeder return false; 1294a07aba5dSTimm Baeder const Pointer &Field = Obj.atField(I); 1295a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Field)) 1296a07aba5dSTimm Baeder return false; 1297a07aba5dSTimm Baeder S.Stk.push<T>(Field.deref<T>()); 1298a07aba5dSTimm Baeder return true; 1299a07aba5dSTimm Baeder } 1300a07aba5dSTimm Baeder 1301a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1302a07aba5dSTimm Baeder bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { 1303a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1304a07aba5dSTimm Baeder const Pointer &Obj = S.Stk.peek<Pointer>(); 1305a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1306a07aba5dSTimm Baeder return false; 1307a07aba5dSTimm Baeder if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1308a07aba5dSTimm Baeder return false; 1309a07aba5dSTimm Baeder const Pointer &Field = Obj.atField(I); 1310a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Field)) 1311a07aba5dSTimm Baeder return false; 1312a07aba5dSTimm Baeder Field.initialize(); 1313a07aba5dSTimm Baeder Field.deref<T>() = Value; 1314a07aba5dSTimm Baeder return true; 1315a07aba5dSTimm Baeder } 1316a07aba5dSTimm Baeder 1317a07aba5dSTimm Baeder /// 1) Pops a pointer from the stack 1318a07aba5dSTimm Baeder /// 2) Pushes the value of the pointer's field on the stack 1319a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1320a07aba5dSTimm Baeder bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { 1321a07aba5dSTimm Baeder const Pointer &Obj = S.Stk.pop<Pointer>(); 1322a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1323a07aba5dSTimm Baeder return false; 1324a07aba5dSTimm Baeder if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1325a07aba5dSTimm Baeder return false; 1326a07aba5dSTimm Baeder const Pointer &Field = Obj.atField(I); 1327a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Field)) 1328a07aba5dSTimm Baeder return false; 1329a07aba5dSTimm Baeder S.Stk.push<T>(Field.deref<T>()); 1330a07aba5dSTimm Baeder return true; 1331a07aba5dSTimm Baeder } 1332a07aba5dSTimm Baeder 1333a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1334a07aba5dSTimm Baeder bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1335a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1336a07aba5dSTimm Baeder return false; 1337a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1338a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1339a07aba5dSTimm Baeder return false; 1340a07aba5dSTimm Baeder const Pointer &Field = This.atField(I); 1341a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Field)) 1342a07aba5dSTimm Baeder return false; 1343a07aba5dSTimm Baeder S.Stk.push<T>(Field.deref<T>()); 1344a07aba5dSTimm Baeder return true; 1345a07aba5dSTimm Baeder } 1346a07aba5dSTimm Baeder 1347a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1348a07aba5dSTimm Baeder bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1349a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1350a07aba5dSTimm Baeder return false; 1351a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1352a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1353a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1354a07aba5dSTimm Baeder return false; 1355a07aba5dSTimm Baeder const Pointer &Field = This.atField(I); 1356a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Field)) 1357a07aba5dSTimm Baeder return false; 1358a07aba5dSTimm Baeder Field.deref<T>() = Value; 1359a07aba5dSTimm Baeder return true; 1360a07aba5dSTimm Baeder } 1361a07aba5dSTimm Baeder 1362a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1363a07aba5dSTimm Baeder bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1364a07aba5dSTimm Baeder const Pointer &Ptr = S.P.getPtrGlobal(I); 1365a07aba5dSTimm Baeder if (!CheckConstant(S, OpPC, Ptr.getFieldDesc())) 1366a07aba5dSTimm Baeder return false; 1367a07aba5dSTimm Baeder if (Ptr.isExtern()) 1368a07aba5dSTimm Baeder return false; 1369a07aba5dSTimm Baeder 1370a07aba5dSTimm Baeder // If a global variable is uninitialized, that means the initializer we've 1371a07aba5dSTimm Baeder // compiled for it wasn't a constant expression. Diagnose that. 1372a07aba5dSTimm Baeder if (!CheckGlobalInitialized(S, OpPC, Ptr)) 1373a07aba5dSTimm Baeder return false; 1374a07aba5dSTimm Baeder 1375a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.deref<T>()); 1376a07aba5dSTimm Baeder return true; 1377a07aba5dSTimm Baeder } 1378a07aba5dSTimm Baeder 1379a07aba5dSTimm Baeder /// Same as GetGlobal, but without the checks. 1380a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1381a07aba5dSTimm Baeder bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { 1382a07aba5dSTimm Baeder const Pointer &Ptr = S.P.getPtrGlobal(I); 1383a07aba5dSTimm Baeder if (!Ptr.isInitialized()) 1384a07aba5dSTimm Baeder return false; 1385a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.deref<T>()); 1386a07aba5dSTimm Baeder return true; 1387a07aba5dSTimm Baeder } 1388a07aba5dSTimm Baeder 1389a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1390a07aba5dSTimm Baeder bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1391a07aba5dSTimm Baeder // TODO: emit warning. 1392a07aba5dSTimm Baeder return false; 1393a07aba5dSTimm Baeder } 1394a07aba5dSTimm Baeder 1395a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1396a07aba5dSTimm Baeder bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1397a07aba5dSTimm Baeder const Pointer &P = S.P.getGlobal(I); 1398a07aba5dSTimm Baeder P.deref<T>() = S.Stk.pop<T>(); 1399a07aba5dSTimm Baeder P.initialize(); 1400a07aba5dSTimm Baeder return true; 1401a07aba5dSTimm Baeder } 1402a07aba5dSTimm Baeder 1403a07aba5dSTimm Baeder /// 1) Converts the value on top of the stack to an APValue 1404a07aba5dSTimm Baeder /// 2) Sets that APValue on \Temp 1405a07aba5dSTimm Baeder /// 3) Initializes global with index \I with that 1406a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1407a07aba5dSTimm Baeder bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, 1408a07aba5dSTimm Baeder const LifetimeExtendedTemporaryDecl *Temp) { 1409a07aba5dSTimm Baeder const Pointer &Ptr = S.P.getGlobal(I); 1410a07aba5dSTimm Baeder 1411a07aba5dSTimm Baeder const T Value = S.Stk.peek<T>(); 1412d9e72860Syronglin APValue APV = Value.toAPValue(S.getASTContext()); 1413a07aba5dSTimm Baeder APValue *Cached = Temp->getOrCreateValue(true); 1414a07aba5dSTimm Baeder *Cached = APV; 1415a07aba5dSTimm Baeder 1416a07aba5dSTimm Baeder assert(Ptr.getDeclDesc()->asExpr()); 1417a07aba5dSTimm Baeder 1418a07aba5dSTimm Baeder S.SeenGlobalTemporaries.push_back( 1419a07aba5dSTimm Baeder std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp)); 1420a07aba5dSTimm Baeder 1421a07aba5dSTimm Baeder Ptr.deref<T>() = S.Stk.pop<T>(); 1422a07aba5dSTimm Baeder Ptr.initialize(); 1423a07aba5dSTimm Baeder return true; 1424a07aba5dSTimm Baeder } 1425a07aba5dSTimm Baeder 1426a07aba5dSTimm Baeder /// 1) Converts the value on top of the stack to an APValue 1427a07aba5dSTimm Baeder /// 2) Sets that APValue on \Temp 1428a07aba5dSTimm Baeder /// 3) Initialized global with index \I with that 1429a07aba5dSTimm Baeder inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, 1430a07aba5dSTimm Baeder const LifetimeExtendedTemporaryDecl *Temp) { 1431a07aba5dSTimm Baeder assert(Temp); 1432a07aba5dSTimm Baeder const Pointer &P = S.Stk.peek<Pointer>(); 1433a07aba5dSTimm Baeder APValue *Cached = Temp->getOrCreateValue(true); 1434a07aba5dSTimm Baeder 1435a07aba5dSTimm Baeder S.SeenGlobalTemporaries.push_back( 1436a07aba5dSTimm Baeder std::make_pair(P.getDeclDesc()->asExpr(), Temp)); 1437a07aba5dSTimm Baeder 1438a07aba5dSTimm Baeder if (std::optional<APValue> APV = 1439d9e72860Syronglin P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) { 1440a07aba5dSTimm Baeder *Cached = *APV; 1441a07aba5dSTimm Baeder return true; 1442a07aba5dSTimm Baeder } 1443a07aba5dSTimm Baeder 1444a07aba5dSTimm Baeder return false; 1445a07aba5dSTimm Baeder } 1446a07aba5dSTimm Baeder 1447a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1448a07aba5dSTimm Baeder bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1449a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1450a07aba5dSTimm Baeder return false; 1451a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1452a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1453a07aba5dSTimm Baeder return false; 1454a07aba5dSTimm Baeder const Pointer &Field = This.atField(I); 1455a07aba5dSTimm Baeder Field.deref<T>() = S.Stk.pop<T>(); 1456a07aba5dSTimm Baeder Field.activate(); 1457a07aba5dSTimm Baeder Field.initialize(); 1458a07aba5dSTimm Baeder return true; 1459a07aba5dSTimm Baeder } 1460a07aba5dSTimm Baeder 1461a07aba5dSTimm Baeder // FIXME: The Field pointer here is too much IMO and we could instead just 1462a07aba5dSTimm Baeder // pass an Offset + BitWidth pair. 1463a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1464a07aba5dSTimm Baeder bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, 1465a07aba5dSTimm Baeder uint32_t FieldOffset) { 1466a07aba5dSTimm Baeder assert(F->isBitField()); 1467a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1468a07aba5dSTimm Baeder return false; 1469a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1470a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1471a07aba5dSTimm Baeder return false; 1472a07aba5dSTimm Baeder const Pointer &Field = This.atField(FieldOffset); 1473a07aba5dSTimm Baeder const auto &Value = S.Stk.pop<T>(); 1474cfe26358STimm Baeder Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); 1475a07aba5dSTimm Baeder Field.initialize(); 1476a07aba5dSTimm Baeder return true; 1477a07aba5dSTimm Baeder } 1478a07aba5dSTimm Baeder 1479a07aba5dSTimm Baeder /// 1) Pops the value from the stack 1480a07aba5dSTimm Baeder /// 2) Peeks a pointer from the stack 1481a07aba5dSTimm Baeder /// 3) Pushes the value to field I of the pointer on the stack 1482a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1483a07aba5dSTimm Baeder bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 1484a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1485a07aba5dSTimm Baeder const Pointer &Field = S.Stk.peek<Pointer>().atField(I); 1486a07aba5dSTimm Baeder Field.deref<T>() = Value; 1487a07aba5dSTimm Baeder Field.activate(); 1488a07aba5dSTimm Baeder Field.initialize(); 1489a07aba5dSTimm Baeder return true; 1490a07aba5dSTimm Baeder } 1491a07aba5dSTimm Baeder 1492a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1493a07aba5dSTimm Baeder bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 1494a07aba5dSTimm Baeder assert(F->isBitField()); 1495a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1496a07aba5dSTimm Baeder const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); 1497cfe26358STimm Baeder Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue()); 1498a07aba5dSTimm Baeder Field.activate(); 1499a07aba5dSTimm Baeder Field.initialize(); 1500a07aba5dSTimm Baeder return true; 1501a07aba5dSTimm Baeder } 1502a07aba5dSTimm Baeder 1503a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1504a07aba5dSTimm Baeder // GetPtr Local/Param/Global/Field/This 1505a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1506a07aba5dSTimm Baeder 1507a07aba5dSTimm Baeder inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1508a07aba5dSTimm Baeder S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 1509a07aba5dSTimm Baeder return true; 1510a07aba5dSTimm Baeder } 1511a07aba5dSTimm Baeder 1512a07aba5dSTimm Baeder inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1513a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) { 1514a07aba5dSTimm Baeder return false; 1515a07aba5dSTimm Baeder } 1516a07aba5dSTimm Baeder S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 1517a07aba5dSTimm Baeder return true; 1518a07aba5dSTimm Baeder } 1519a07aba5dSTimm Baeder 1520a07aba5dSTimm Baeder inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1521a07aba5dSTimm Baeder S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 1522a07aba5dSTimm Baeder return true; 1523a07aba5dSTimm Baeder } 1524a07aba5dSTimm Baeder 1525a07aba5dSTimm Baeder /// 1) Peeks a Pointer 1526a07aba5dSTimm Baeder /// 2) Pushes Pointer.atField(Off) on the stack 1527e86b68ffSTimm Baeder bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off); 1528e86b68ffSTimm Baeder bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off); 1529a07aba5dSTimm Baeder 1530a07aba5dSTimm Baeder inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1531a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1532a07aba5dSTimm Baeder return false; 1533a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1534a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1535a07aba5dSTimm Baeder return false; 1536a07aba5dSTimm Baeder S.Stk.push<Pointer>(This.atField(Off)); 1537a07aba5dSTimm Baeder return true; 1538a07aba5dSTimm Baeder } 1539a07aba5dSTimm Baeder 1540a07aba5dSTimm Baeder inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1541a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1542a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 1543a07aba5dSTimm Baeder return false; 1544a07aba5dSTimm Baeder if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1545a07aba5dSTimm Baeder return false; 1546a07aba5dSTimm Baeder Pointer Field = Ptr.atField(Off); 1547a07aba5dSTimm Baeder Ptr.deactivate(); 1548a07aba5dSTimm Baeder Field.activate(); 1549a07aba5dSTimm Baeder S.Stk.push<Pointer>(std::move(Field)); 1550a07aba5dSTimm Baeder return true; 1551a07aba5dSTimm Baeder } 1552a07aba5dSTimm Baeder 1553a07aba5dSTimm Baeder inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1554a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1555a07aba5dSTimm Baeder return false; 1556a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1557a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1558a07aba5dSTimm Baeder return false; 1559a07aba5dSTimm Baeder Pointer Field = This.atField(Off); 1560a07aba5dSTimm Baeder This.deactivate(); 1561a07aba5dSTimm Baeder Field.activate(); 1562a07aba5dSTimm Baeder S.Stk.push<Pointer>(std::move(Field)); 1563a07aba5dSTimm Baeder return true; 1564a07aba5dSTimm Baeder } 1565a07aba5dSTimm Baeder 1566a07aba5dSTimm Baeder inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1567a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1568a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Ptr, CSK_Derived)) 1569a07aba5dSTimm Baeder return false; 1570a07aba5dSTimm Baeder if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived)) 1571a07aba5dSTimm Baeder return false; 1572a07aba5dSTimm Baeder if (!CheckDowncast(S, OpPC, Ptr, Off)) 1573a07aba5dSTimm Baeder return false; 1574a07aba5dSTimm Baeder 1575a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.atFieldSub(Off)); 1576a07aba5dSTimm Baeder return true; 1577a07aba5dSTimm Baeder } 1578a07aba5dSTimm Baeder 1579a07aba5dSTimm Baeder inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1580a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 158155c70f6dSTimm Baeder if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 158255c70f6dSTimm Baeder return false; 158343fd2c40STimm Baeder 158443fd2c40STimm Baeder if (!Ptr.isBlockPointer()) { 158543fd2c40STimm Baeder S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); 158643fd2c40STimm Baeder return true; 158743fd2c40STimm Baeder } 158843fd2c40STimm Baeder 1589a07aba5dSTimm Baeder if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1590a07aba5dSTimm Baeder return false; 1591a07aba5dSTimm Baeder const Pointer &Result = Ptr.atField(Off); 1592ba7dadf0STimm Baeder if (Result.isPastEnd() || !Result.isBaseClass()) 1593a07aba5dSTimm Baeder return false; 1594a07aba5dSTimm Baeder S.Stk.push<Pointer>(Result); 1595a07aba5dSTimm Baeder return true; 1596a07aba5dSTimm Baeder } 1597a07aba5dSTimm Baeder 1598a07aba5dSTimm Baeder inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1599a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 160043fd2c40STimm Baeder 160155c70f6dSTimm Baeder if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 160255c70f6dSTimm Baeder return false; 160355c70f6dSTimm Baeder 160443fd2c40STimm Baeder if (!Ptr.isBlockPointer()) { 160543fd2c40STimm Baeder S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off)); 160643fd2c40STimm Baeder return true; 160743fd2c40STimm Baeder } 160843fd2c40STimm Baeder 1609a07aba5dSTimm Baeder if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1610a07aba5dSTimm Baeder return false; 1611a07aba5dSTimm Baeder const Pointer &Result = Ptr.atField(Off); 1612ba7dadf0STimm Baeder if (Result.isPastEnd() || !Result.isBaseClass()) 1613a07aba5dSTimm Baeder return false; 1614a07aba5dSTimm Baeder S.Stk.push<Pointer>(Result); 1615a07aba5dSTimm Baeder return true; 1616a07aba5dSTimm Baeder } 1617a07aba5dSTimm Baeder 1618a07aba5dSTimm Baeder inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) { 1619a07aba5dSTimm Baeder const auto &Ptr = S.Stk.pop<MemberPointer>(); 1620a07aba5dSTimm Baeder S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off)); 1621a07aba5dSTimm Baeder return true; 1622a07aba5dSTimm Baeder } 1623a07aba5dSTimm Baeder 1624a07aba5dSTimm Baeder inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1625a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1626a07aba5dSTimm Baeder return false; 1627a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1628a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1629a07aba5dSTimm Baeder return false; 1630a07aba5dSTimm Baeder S.Stk.push<Pointer>(This.atField(Off)); 1631a07aba5dSTimm Baeder return true; 1632a07aba5dSTimm Baeder } 1633a07aba5dSTimm Baeder 1634a07aba5dSTimm Baeder inline bool FinishInitPop(InterpState &S, CodePtr OpPC) { 1635a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1636a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) { 1637a07aba5dSTimm Baeder Ptr.initialize(); 1638a07aba5dSTimm Baeder Ptr.activate(); 1639a07aba5dSTimm Baeder } 1640a07aba5dSTimm Baeder return true; 1641a07aba5dSTimm Baeder } 1642a07aba5dSTimm Baeder 1643a07aba5dSTimm Baeder inline bool FinishInit(InterpState &S, CodePtr OpPC) { 1644a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 1645a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) { 1646a07aba5dSTimm Baeder Ptr.initialize(); 1647a07aba5dSTimm Baeder Ptr.activate(); 1648a07aba5dSTimm Baeder } 1649a07aba5dSTimm Baeder return true; 1650a07aba5dSTimm Baeder } 1651a07aba5dSTimm Baeder 1652a07aba5dSTimm Baeder inline bool Dump(InterpState &S, CodePtr OpPC) { 1653a07aba5dSTimm Baeder S.Stk.dump(); 1654a07aba5dSTimm Baeder return true; 1655a07aba5dSTimm Baeder } 1656a07aba5dSTimm Baeder 1657a07aba5dSTimm Baeder inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 1658a07aba5dSTimm Baeder const Pointer &Ptr) { 1659a07aba5dSTimm Baeder Pointer Base = Ptr; 1660a07aba5dSTimm Baeder while (Base.isBaseClass()) 1661a07aba5dSTimm Baeder Base = Base.getBase(); 1662a07aba5dSTimm Baeder 1663a07aba5dSTimm Baeder const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl); 1664a07aba5dSTimm Baeder S.Stk.push<Pointer>(Base.atField(VirtBase->Offset)); 1665a07aba5dSTimm Baeder return true; 1666a07aba5dSTimm Baeder } 1667a07aba5dSTimm Baeder 1668a07aba5dSTimm Baeder inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, 1669a07aba5dSTimm Baeder const RecordDecl *D) { 1670a07aba5dSTimm Baeder assert(D); 1671a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1672a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1673a07aba5dSTimm Baeder return false; 1674a07aba5dSTimm Baeder return VirtBaseHelper(S, OpPC, D, Ptr); 1675a07aba5dSTimm Baeder } 1676a07aba5dSTimm Baeder 1677a07aba5dSTimm Baeder inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 1678a07aba5dSTimm Baeder const RecordDecl *D) { 1679a07aba5dSTimm Baeder assert(D); 1680a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 1681a07aba5dSTimm Baeder return false; 1682a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 1683a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 1684a07aba5dSTimm Baeder return false; 1685a07aba5dSTimm Baeder return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 1686a07aba5dSTimm Baeder } 1687a07aba5dSTimm Baeder 1688a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1689a07aba5dSTimm Baeder // Load, Store, Init 1690a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1691a07aba5dSTimm Baeder 1692a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1693a07aba5dSTimm Baeder bool Load(InterpState &S, CodePtr OpPC) { 1694a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 1695a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr)) 1696a07aba5dSTimm Baeder return false; 1697a07aba5dSTimm Baeder if (!Ptr.isBlockPointer()) 1698a07aba5dSTimm Baeder return false; 1699a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.deref<T>()); 1700a07aba5dSTimm Baeder return true; 1701a07aba5dSTimm Baeder } 1702a07aba5dSTimm Baeder 1703a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1704a07aba5dSTimm Baeder bool LoadPop(InterpState &S, CodePtr OpPC) { 1705a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1706a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr)) 1707a07aba5dSTimm Baeder return false; 1708a07aba5dSTimm Baeder if (!Ptr.isBlockPointer()) 1709a07aba5dSTimm Baeder return false; 1710a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.deref<T>()); 1711a07aba5dSTimm Baeder return true; 1712a07aba5dSTimm Baeder } 1713a07aba5dSTimm Baeder 1714a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1715a07aba5dSTimm Baeder bool Store(InterpState &S, CodePtr OpPC) { 1716a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1717a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 1718a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Ptr)) 1719a07aba5dSTimm Baeder return false; 1720a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) { 1721a07aba5dSTimm Baeder Ptr.initialize(); 1722a07aba5dSTimm Baeder Ptr.activate(); 1723a07aba5dSTimm Baeder } 1724a07aba5dSTimm Baeder Ptr.deref<T>() = Value; 1725a07aba5dSTimm Baeder return true; 1726a07aba5dSTimm Baeder } 1727a07aba5dSTimm Baeder 1728a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1729a07aba5dSTimm Baeder bool StorePop(InterpState &S, CodePtr OpPC) { 1730a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1731a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1732a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Ptr)) 1733a07aba5dSTimm Baeder return false; 1734a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) { 1735a07aba5dSTimm Baeder Ptr.initialize(); 1736a07aba5dSTimm Baeder Ptr.activate(); 1737a07aba5dSTimm Baeder } 1738a07aba5dSTimm Baeder Ptr.deref<T>() = Value; 1739a07aba5dSTimm Baeder return true; 1740a07aba5dSTimm Baeder } 1741a07aba5dSTimm Baeder 1742a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1743a07aba5dSTimm Baeder bool StoreBitField(InterpState &S, CodePtr OpPC) { 1744a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1745a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 1746a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Ptr)) 1747a07aba5dSTimm Baeder return false; 1748a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) 1749a07aba5dSTimm Baeder Ptr.initialize(); 1750a07aba5dSTimm Baeder if (const auto *FD = Ptr.getField()) 1751cfe26358STimm Baeder Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue()); 1752a07aba5dSTimm Baeder else 1753a07aba5dSTimm Baeder Ptr.deref<T>() = Value; 1754a07aba5dSTimm Baeder return true; 1755a07aba5dSTimm Baeder } 1756a07aba5dSTimm Baeder 1757a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1758a07aba5dSTimm Baeder bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 1759a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1760a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1761a07aba5dSTimm Baeder if (!CheckStore(S, OpPC, Ptr)) 1762a07aba5dSTimm Baeder return false; 1763a07aba5dSTimm Baeder if (Ptr.canBeInitialized()) 1764a07aba5dSTimm Baeder Ptr.initialize(); 1765a07aba5dSTimm Baeder if (const auto *FD = Ptr.getField()) 1766cfe26358STimm Baeder Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue()); 1767a07aba5dSTimm Baeder else 1768a07aba5dSTimm Baeder Ptr.deref<T>() = Value; 1769a07aba5dSTimm Baeder return true; 1770a07aba5dSTimm Baeder } 1771a07aba5dSTimm Baeder 1772a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1773a07aba5dSTimm Baeder bool Init(InterpState &S, CodePtr OpPC) { 1774a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1775a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 1776a07aba5dSTimm Baeder if (!CheckInit(S, OpPC, Ptr)) { 1777a07aba5dSTimm Baeder assert(false); 1778a07aba5dSTimm Baeder return false; 1779a07aba5dSTimm Baeder } 17805d086253STimm Baeder Ptr.activate(); 1781a07aba5dSTimm Baeder Ptr.initialize(); 1782a07aba5dSTimm Baeder new (&Ptr.deref<T>()) T(Value); 1783a07aba5dSTimm Baeder return true; 1784a07aba5dSTimm Baeder } 1785a07aba5dSTimm Baeder 1786a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1787a07aba5dSTimm Baeder bool InitPop(InterpState &S, CodePtr OpPC) { 1788a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 1789a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1790a07aba5dSTimm Baeder if (!CheckInit(S, OpPC, Ptr)) 1791a07aba5dSTimm Baeder return false; 17925d086253STimm Baeder Ptr.activate(); 1793a07aba5dSTimm Baeder Ptr.initialize(); 1794a07aba5dSTimm Baeder new (&Ptr.deref<T>()) T(Value); 1795a07aba5dSTimm Baeder return true; 1796a07aba5dSTimm Baeder } 1797a07aba5dSTimm Baeder 1798a07aba5dSTimm Baeder /// 1) Pops the value from the stack 1799a07aba5dSTimm Baeder /// 2) Peeks a pointer and gets its index \Idx 1800a07aba5dSTimm Baeder /// 3) Sets the value on the pointer, leaving the pointer on the stack. 1801a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1802a07aba5dSTimm Baeder bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1803a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 180403888a90STimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 180503888a90STimm Baeder 1806a07aba5dSTimm Baeder if (Ptr.isUnknownSizeArray()) 1807a07aba5dSTimm Baeder return false; 180803888a90STimm Baeder 180903888a90STimm Baeder // In the unlikely event that we're initializing the first item of 181003888a90STimm Baeder // a non-array, skip the atIndex(). 181103888a90STimm Baeder if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) { 1812a07aba5dSTimm Baeder Ptr.initialize(); 1813a07aba5dSTimm Baeder new (&Ptr.deref<T>()) T(Value); 1814a07aba5dSTimm Baeder return true; 1815a07aba5dSTimm Baeder } 1816a07aba5dSTimm Baeder 181703888a90STimm Baeder const Pointer &ElemPtr = Ptr.atIndex(Idx); 181803888a90STimm Baeder if (!CheckInit(S, OpPC, ElemPtr)) 181903888a90STimm Baeder return false; 182003888a90STimm Baeder ElemPtr.initialize(); 182103888a90STimm Baeder new (&ElemPtr.deref<T>()) T(Value); 182203888a90STimm Baeder return true; 182303888a90STimm Baeder } 182403888a90STimm Baeder 1825a07aba5dSTimm Baeder /// The same as InitElem, but pops the pointer as well. 1826a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1827a07aba5dSTimm Baeder bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1828a07aba5dSTimm Baeder const T &Value = S.Stk.pop<T>(); 182903888a90STimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 1830a07aba5dSTimm Baeder if (Ptr.isUnknownSizeArray()) 1831a07aba5dSTimm Baeder return false; 183203888a90STimm Baeder 183303888a90STimm Baeder // In the unlikely event that we're initializing the first item of 183403888a90STimm Baeder // a non-array, skip the atIndex(). 183503888a90STimm Baeder if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) { 1836a07aba5dSTimm Baeder Ptr.initialize(); 1837a07aba5dSTimm Baeder new (&Ptr.deref<T>()) T(Value); 1838a07aba5dSTimm Baeder return true; 1839a07aba5dSTimm Baeder } 1840a07aba5dSTimm Baeder 184103888a90STimm Baeder const Pointer &ElemPtr = Ptr.atIndex(Idx); 184203888a90STimm Baeder if (!CheckInit(S, OpPC, ElemPtr)) 184303888a90STimm Baeder return false; 184403888a90STimm Baeder ElemPtr.initialize(); 184503888a90STimm Baeder new (&ElemPtr.deref<T>()) T(Value); 184603888a90STimm Baeder return true; 184703888a90STimm Baeder } 184803888a90STimm Baeder 1849a07aba5dSTimm Baeder inline bool Memcpy(InterpState &S, CodePtr OpPC) { 1850a07aba5dSTimm Baeder const Pointer &Src = S.Stk.pop<Pointer>(); 1851a07aba5dSTimm Baeder Pointer &Dest = S.Stk.peek<Pointer>(); 1852a07aba5dSTimm Baeder 1853a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Src)) 1854a07aba5dSTimm Baeder return false; 1855a07aba5dSTimm Baeder 1856a07aba5dSTimm Baeder return DoMemcpy(S, OpPC, Src, Dest); 1857a07aba5dSTimm Baeder } 1858a07aba5dSTimm Baeder 1859a07aba5dSTimm Baeder inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) { 1860a07aba5dSTimm Baeder const auto &Member = S.Stk.pop<MemberPointer>(); 1861a07aba5dSTimm Baeder const auto &Base = S.Stk.pop<Pointer>(); 1862a07aba5dSTimm Baeder 1863a07aba5dSTimm Baeder S.Stk.push<MemberPointer>(Member.takeInstance(Base)); 1864a07aba5dSTimm Baeder return true; 1865a07aba5dSTimm Baeder } 1866a07aba5dSTimm Baeder 1867a07aba5dSTimm Baeder inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) { 1868a07aba5dSTimm Baeder const auto &MP = S.Stk.pop<MemberPointer>(); 1869a07aba5dSTimm Baeder 1870a07aba5dSTimm Baeder if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) { 1871a07aba5dSTimm Baeder S.Stk.push<Pointer>(*Ptr); 1872a07aba5dSTimm Baeder return true; 1873a07aba5dSTimm Baeder } 1874a07aba5dSTimm Baeder return false; 1875a07aba5dSTimm Baeder } 1876a07aba5dSTimm Baeder 1877a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1878a07aba5dSTimm Baeder // AddOffset, SubOffset 1879a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 1880a07aba5dSTimm Baeder 1881a07aba5dSTimm Baeder template <class T, ArithOp Op> 1882a07aba5dSTimm Baeder bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, 1883923b8eeaSTimm Baeder const Pointer &Ptr, bool IsPointerArith = false) { 1884a07aba5dSTimm Baeder // A zero offset does not change the pointer. 1885a07aba5dSTimm Baeder if (Offset.isZero()) { 1886a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr); 1887a07aba5dSTimm Baeder return true; 1888a07aba5dSTimm Baeder } 1889a07aba5dSTimm Baeder 1890923b8eeaSTimm Baeder if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) { 1891a07aba5dSTimm Baeder // The CheckNull will have emitted a note already, but we only 1892a07aba5dSTimm Baeder // abort in C++, since this is fine in C. 1893a07aba5dSTimm Baeder if (S.getLangOpts().CPlusPlus) 1894a07aba5dSTimm Baeder return false; 1895a07aba5dSTimm Baeder } 1896a07aba5dSTimm Baeder 1897a07aba5dSTimm Baeder // Arrays of unknown bounds cannot have pointers into them. 1898a07aba5dSTimm Baeder if (!CheckArray(S, OpPC, Ptr)) 1899a07aba5dSTimm Baeder return false; 1900a07aba5dSTimm Baeder 1901dac18299STimm Baeder // This is much simpler for integral pointers, so handle them first. 1902dac18299STimm Baeder if (Ptr.isIntegralPointer()) { 1903dac18299STimm Baeder uint64_t V = Ptr.getIntegerRepresentation(); 1904dac18299STimm Baeder uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize(); 1905dac18299STimm Baeder if constexpr (Op == ArithOp::Add) 1906dac18299STimm Baeder S.Stk.push<Pointer>(V + O, Ptr.asIntPointer().Desc); 1907dac18299STimm Baeder else 1908dac18299STimm Baeder S.Stk.push<Pointer>(V - O, Ptr.asIntPointer().Desc); 1909dac18299STimm Baeder return true; 1910db94852bSTimm Baeder } else if (Ptr.isFunctionPointer()) { 1911db94852bSTimm Baeder uint64_t O = static_cast<uint64_t>(Offset); 1912db94852bSTimm Baeder uint64_t N; 1913db94852bSTimm Baeder if constexpr (Op == ArithOp::Add) 1914db94852bSTimm Baeder N = Ptr.getByteOffset() + O; 1915db94852bSTimm Baeder else 1916db94852bSTimm Baeder N = Ptr.getByteOffset() - O; 1917db94852bSTimm Baeder 1918db94852bSTimm Baeder if (N > 1) 1919db94852bSTimm Baeder S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 1920db94852bSTimm Baeder << N << /*non-array*/ true << 0; 1921db94852bSTimm Baeder S.Stk.push<Pointer>(Ptr.asFunctionPointer().getFunction(), N); 1922db94852bSTimm Baeder return true; 1923dac18299STimm Baeder } 1924dac18299STimm Baeder 1925db94852bSTimm Baeder assert(Ptr.isBlockPointer()); 1926db94852bSTimm Baeder 1927a07aba5dSTimm Baeder uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems()); 1928a07aba5dSTimm Baeder uint64_t Index; 1929a07aba5dSTimm Baeder if (Ptr.isOnePastEnd()) 1930a07aba5dSTimm Baeder Index = MaxIndex; 1931a07aba5dSTimm Baeder else 1932a07aba5dSTimm Baeder Index = Ptr.getIndex(); 1933a07aba5dSTimm Baeder 1934a07aba5dSTimm Baeder bool Invalid = false; 1935a07aba5dSTimm Baeder // Helper to report an invalid offset, computed as APSInt. 1936a07aba5dSTimm Baeder auto DiagInvalidOffset = [&]() -> void { 1937a07aba5dSTimm Baeder const unsigned Bits = Offset.bitWidth(); 1938a07aba5dSTimm Baeder APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false); 1939a07aba5dSTimm Baeder APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true), 1940a07aba5dSTimm Baeder /*IsUnsigned=*/false); 1941a07aba5dSTimm Baeder APSInt NewIndex = 1942a07aba5dSTimm Baeder (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset); 1943a07aba5dSTimm Baeder S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 1944a07aba5dSTimm Baeder << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex; 1945a07aba5dSTimm Baeder Invalid = true; 1946a07aba5dSTimm Baeder }; 1947a07aba5dSTimm Baeder 1948a07aba5dSTimm Baeder if (Ptr.isBlockPointer()) { 1949a07aba5dSTimm Baeder uint64_t IOffset = static_cast<uint64_t>(Offset); 1950a07aba5dSTimm Baeder uint64_t MaxOffset = MaxIndex - Index; 1951a07aba5dSTimm Baeder 1952a07aba5dSTimm Baeder if constexpr (Op == ArithOp::Add) { 1953a07aba5dSTimm Baeder // If the new offset would be negative, bail out. 1954a07aba5dSTimm Baeder if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index)) 1955a07aba5dSTimm Baeder DiagInvalidOffset(); 1956a07aba5dSTimm Baeder 1957a07aba5dSTimm Baeder // If the new offset would be out of bounds, bail out. 1958a07aba5dSTimm Baeder if (Offset.isPositive() && IOffset > MaxOffset) 1959a07aba5dSTimm Baeder DiagInvalidOffset(); 1960a07aba5dSTimm Baeder } else { 1961a07aba5dSTimm Baeder // If the new offset would be negative, bail out. 1962a07aba5dSTimm Baeder if (Offset.isPositive() && Index < IOffset) 1963a07aba5dSTimm Baeder DiagInvalidOffset(); 1964a07aba5dSTimm Baeder 1965a07aba5dSTimm Baeder // If the new offset would be out of bounds, bail out. 1966a07aba5dSTimm Baeder if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset)) 1967a07aba5dSTimm Baeder DiagInvalidOffset(); 1968a07aba5dSTimm Baeder } 1969a07aba5dSTimm Baeder } 1970a07aba5dSTimm Baeder 1971a07aba5dSTimm Baeder if (Invalid && S.getLangOpts().CPlusPlus) 1972a07aba5dSTimm Baeder return false; 1973a07aba5dSTimm Baeder 1974a07aba5dSTimm Baeder // Offset is valid - compute it on unsigned. 1975a07aba5dSTimm Baeder int64_t WideIndex = static_cast<int64_t>(Index); 1976a07aba5dSTimm Baeder int64_t WideOffset = static_cast<int64_t>(Offset); 1977a07aba5dSTimm Baeder int64_t Result; 1978a07aba5dSTimm Baeder if constexpr (Op == ArithOp::Add) 1979a07aba5dSTimm Baeder Result = WideIndex + WideOffset; 1980a07aba5dSTimm Baeder else 1981a07aba5dSTimm Baeder Result = WideIndex - WideOffset; 1982a07aba5dSTimm Baeder 1983a07aba5dSTimm Baeder // When the pointer is one-past-end, going back to index 0 is the only 1984a07aba5dSTimm Baeder // useful thing we can do. Any other index has been diagnosed before and 1985a07aba5dSTimm Baeder // we don't get here. 1986a07aba5dSTimm Baeder if (Result == 0 && Ptr.isOnePastEnd()) { 1987a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee, 1988a07aba5dSTimm Baeder Ptr.asBlockPointer().Base); 1989a07aba5dSTimm Baeder return true; 1990a07aba5dSTimm Baeder } 1991a07aba5dSTimm Baeder 1992a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result))); 1993a07aba5dSTimm Baeder return true; 1994a07aba5dSTimm Baeder } 1995a07aba5dSTimm Baeder 1996a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 1997a07aba5dSTimm Baeder bool AddOffset(InterpState &S, CodePtr OpPC) { 1998a07aba5dSTimm Baeder const T &Offset = S.Stk.pop<T>(); 1999d6d60707STimm Baeder Pointer Ptr = S.Stk.pop<Pointer>(); 2000d6d60707STimm Baeder if (Ptr.isBlockPointer()) 2001d6d60707STimm Baeder Ptr = Ptr.expand(); 2002923b8eeaSTimm Baeder return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr, 2003923b8eeaSTimm Baeder /*IsPointerArith=*/true); 2004a07aba5dSTimm Baeder } 2005a07aba5dSTimm Baeder 2006a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2007a07aba5dSTimm Baeder bool SubOffset(InterpState &S, CodePtr OpPC) { 2008a07aba5dSTimm Baeder const T &Offset = S.Stk.pop<T>(); 2009a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2010923b8eeaSTimm Baeder return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr, 2011923b8eeaSTimm Baeder /*IsPointerArith=*/true); 2012a07aba5dSTimm Baeder } 2013a07aba5dSTimm Baeder 2014a07aba5dSTimm Baeder template <ArithOp Op> 2015a07aba5dSTimm Baeder static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, 2016a07aba5dSTimm Baeder const Pointer &Ptr) { 2017a07aba5dSTimm Baeder if (Ptr.isDummy()) 2018a07aba5dSTimm Baeder return false; 2019a07aba5dSTimm Baeder 2020a07aba5dSTimm Baeder using OneT = Integral<8, false>; 2021a07aba5dSTimm Baeder 2022a07aba5dSTimm Baeder const Pointer &P = Ptr.deref<Pointer>(); 2023a07aba5dSTimm Baeder if (!CheckNull(S, OpPC, P, CSK_ArrayIndex)) 2024a07aba5dSTimm Baeder return false; 2025a07aba5dSTimm Baeder 2026a07aba5dSTimm Baeder // Get the current value on the stack. 2027a07aba5dSTimm Baeder S.Stk.push<Pointer>(P); 2028a07aba5dSTimm Baeder 2029a07aba5dSTimm Baeder // Now the current Ptr again and a constant 1. 2030a07aba5dSTimm Baeder OneT One = OneT::from(1); 2031923b8eeaSTimm Baeder if (!OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) 2032a07aba5dSTimm Baeder return false; 2033a07aba5dSTimm Baeder 2034a07aba5dSTimm Baeder // Store the new value. 2035a07aba5dSTimm Baeder Ptr.deref<Pointer>() = S.Stk.pop<Pointer>(); 2036a07aba5dSTimm Baeder return true; 2037a07aba5dSTimm Baeder } 2038a07aba5dSTimm Baeder 2039a07aba5dSTimm Baeder static inline bool IncPtr(InterpState &S, CodePtr OpPC) { 2040a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2041a07aba5dSTimm Baeder 2042a07aba5dSTimm Baeder if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 2043a07aba5dSTimm Baeder return false; 2044a07aba5dSTimm Baeder 2045a07aba5dSTimm Baeder return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); 2046a07aba5dSTimm Baeder } 2047a07aba5dSTimm Baeder 2048a07aba5dSTimm Baeder static inline bool DecPtr(InterpState &S, CodePtr OpPC) { 2049a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2050a07aba5dSTimm Baeder 2051a07aba5dSTimm Baeder if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 2052a07aba5dSTimm Baeder return false; 2053a07aba5dSTimm Baeder 2054a07aba5dSTimm Baeder return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); 2055a07aba5dSTimm Baeder } 2056a07aba5dSTimm Baeder 2057a07aba5dSTimm Baeder /// 1) Pops a Pointer from the stack. 2058a07aba5dSTimm Baeder /// 2) Pops another Pointer from the stack. 2059a07aba5dSTimm Baeder /// 3) Pushes the different of the indices of the two pointers on the stack. 2060a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2061a07aba5dSTimm Baeder inline bool SubPtr(InterpState &S, CodePtr OpPC) { 2062a07aba5dSTimm Baeder const Pointer &LHS = S.Stk.pop<Pointer>(); 2063a07aba5dSTimm Baeder const Pointer &RHS = S.Stk.pop<Pointer>(); 2064a07aba5dSTimm Baeder 2065a07aba5dSTimm Baeder for (const Pointer &P : {LHS, RHS}) { 2066a07aba5dSTimm Baeder if (P.isZeroSizeArray()) { 2067a07aba5dSTimm Baeder QualType PtrT = P.getType(); 2068a07aba5dSTimm Baeder while (auto *AT = dyn_cast<ArrayType>(PtrT)) 2069a07aba5dSTimm Baeder PtrT = AT->getElementType(); 2070a07aba5dSTimm Baeder 2071d9e72860Syronglin QualType ArrayTy = S.getASTContext().getConstantArrayType( 2072a07aba5dSTimm Baeder PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0); 2073a07aba5dSTimm Baeder S.FFDiag(S.Current->getSource(OpPC), 2074a07aba5dSTimm Baeder diag::note_constexpr_pointer_subtraction_zero_size) 2075a07aba5dSTimm Baeder << ArrayTy; 2076a07aba5dSTimm Baeder 2077a07aba5dSTimm Baeder return false; 2078a07aba5dSTimm Baeder } 2079a07aba5dSTimm Baeder } 2080a07aba5dSTimm Baeder 2081a07aba5dSTimm Baeder if (RHS.isZero()) { 2082a07aba5dSTimm Baeder S.Stk.push<T>(T::from(LHS.getIndex())); 2083a07aba5dSTimm Baeder return true; 2084a07aba5dSTimm Baeder } 2085a07aba5dSTimm Baeder 2086a07aba5dSTimm Baeder if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { 2087a07aba5dSTimm Baeder // TODO: Diagnose. 2088a07aba5dSTimm Baeder return false; 2089a07aba5dSTimm Baeder } 2090a07aba5dSTimm Baeder 2091a07aba5dSTimm Baeder if (LHS.isZero() && RHS.isZero()) { 2092a07aba5dSTimm Baeder S.Stk.push<T>(); 2093a07aba5dSTimm Baeder return true; 2094a07aba5dSTimm Baeder } 2095a07aba5dSTimm Baeder 2096db94852bSTimm Baeder T A = LHS.isBlockPointer() 2097db94852bSTimm Baeder ? (LHS.isElementPastEnd() ? T::from(LHS.getNumElems()) 2098db94852bSTimm Baeder : T::from(LHS.getIndex())) 2099db94852bSTimm Baeder : T::from(LHS.getIntegerRepresentation()); 2100db94852bSTimm Baeder T B = RHS.isBlockPointer() 2101db94852bSTimm Baeder ? (RHS.isElementPastEnd() ? T::from(RHS.getNumElems()) 2102db94852bSTimm Baeder : T::from(RHS.getIndex())) 2103db94852bSTimm Baeder : T::from(RHS.getIntegerRepresentation()); 2104db94852bSTimm Baeder 2105a07aba5dSTimm Baeder return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B); 2106a07aba5dSTimm Baeder } 2107a07aba5dSTimm Baeder 2108a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2109a07aba5dSTimm Baeder // Destroy 2110a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2111a07aba5dSTimm Baeder 2112a07aba5dSTimm Baeder inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 2113a07aba5dSTimm Baeder S.Current->destroy(I); 2114a07aba5dSTimm Baeder return true; 2115a07aba5dSTimm Baeder } 2116a07aba5dSTimm Baeder 2117a07aba5dSTimm Baeder inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) { 2118a07aba5dSTimm Baeder S.Current->initScope(I); 2119a07aba5dSTimm Baeder return true; 2120a07aba5dSTimm Baeder } 2121a07aba5dSTimm Baeder 2122a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2123a07aba5dSTimm Baeder // Cast, CastFP 2124a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2125a07aba5dSTimm Baeder 2126a07aba5dSTimm Baeder template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 2127a07aba5dSTimm Baeder using T = typename PrimConv<TIn>::T; 2128a07aba5dSTimm Baeder using U = typename PrimConv<TOut>::T; 2129a07aba5dSTimm Baeder S.Stk.push<U>(U::from(S.Stk.pop<T>())); 2130a07aba5dSTimm Baeder return true; 2131a07aba5dSTimm Baeder } 2132a07aba5dSTimm Baeder 2133a07aba5dSTimm Baeder /// 1) Pops a Floating from the stack. 2134a07aba5dSTimm Baeder /// 2) Pushes a new floating on the stack that uses the given semantics. 2135a07aba5dSTimm Baeder inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, 2136a07aba5dSTimm Baeder llvm::RoundingMode RM) { 2137a07aba5dSTimm Baeder Floating F = S.Stk.pop<Floating>(); 2138a07aba5dSTimm Baeder Floating Result = F.toSemantics(Sem, RM); 2139a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 2140a07aba5dSTimm Baeder return true; 2141a07aba5dSTimm Baeder } 2142a07aba5dSTimm Baeder 2143c2a37e41STimm Baeder inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) { 2144046b064dSTimm Baeder FixedPointSemantics TargetSemantics = 2145046b064dSTimm Baeder FixedPointSemantics::getFromOpaqueInt(FPS); 2146c2a37e41STimm Baeder const auto &Source = S.Stk.pop<FixedPoint>(); 2147c2a37e41STimm Baeder 2148c2a37e41STimm Baeder bool Overflow; 2149c2a37e41STimm Baeder FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow); 2150c2a37e41STimm Baeder 215195ce78b7STimm Baeder if (Overflow && !handleFixedPointOverflow(S, OpPC, Result)) 2152c2a37e41STimm Baeder return false; 2153c2a37e41STimm Baeder 2154c2a37e41STimm Baeder S.Stk.push<FixedPoint>(Result); 2155c2a37e41STimm Baeder return true; 2156c2a37e41STimm Baeder } 2157c2a37e41STimm Baeder 2158a07aba5dSTimm Baeder /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need 2159a07aba5dSTimm Baeder /// to know what bitwidth the result should be. 2160a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2161a07aba5dSTimm Baeder bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 2162a07aba5dSTimm Baeder S.Stk.push<IntegralAP<false>>( 2163a07aba5dSTimm Baeder IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth)); 2164a07aba5dSTimm Baeder return true; 2165a07aba5dSTimm Baeder } 2166a07aba5dSTimm Baeder 2167a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2168a07aba5dSTimm Baeder bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 2169a07aba5dSTimm Baeder S.Stk.push<IntegralAP<true>>( 2170a07aba5dSTimm Baeder IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth)); 2171a07aba5dSTimm Baeder return true; 2172a07aba5dSTimm Baeder } 2173a07aba5dSTimm Baeder 2174a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2175a07aba5dSTimm Baeder bool CastIntegralFloating(InterpState &S, CodePtr OpPC, 21760f5f440fSTimm Baeder const llvm::fltSemantics *Sem, uint32_t FPOI) { 2177a07aba5dSTimm Baeder const T &From = S.Stk.pop<T>(); 2178a07aba5dSTimm Baeder APSInt FromAP = From.toAPSInt(); 2179a07aba5dSTimm Baeder Floating Result; 2180a07aba5dSTimm Baeder 21810f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 21820f5f440fSTimm Baeder auto Status = 21830f5f440fSTimm Baeder Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), Result); 2184a07aba5dSTimm Baeder S.Stk.push<Floating>(Result); 2185a07aba5dSTimm Baeder 21860f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, Result, Status, FPO); 2187a07aba5dSTimm Baeder } 2188a07aba5dSTimm Baeder 2189a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 21900f5f440fSTimm Baeder bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) { 2191a07aba5dSTimm Baeder const Floating &F = S.Stk.pop<Floating>(); 2192a07aba5dSTimm Baeder 2193a07aba5dSTimm Baeder if constexpr (std::is_same_v<T, Boolean>) { 2194a07aba5dSTimm Baeder S.Stk.push<T>(T(F.isNonZero())); 2195a07aba5dSTimm Baeder return true; 2196a07aba5dSTimm Baeder } else { 2197a07aba5dSTimm Baeder APSInt Result(std::max(8u, T::bitWidth()), 2198a07aba5dSTimm Baeder /*IsUnsigned=*/!T::isSigned()); 2199a07aba5dSTimm Baeder auto Status = F.convertToInteger(Result); 2200a07aba5dSTimm Baeder 2201a07aba5dSTimm Baeder // Float-to-Integral overflow check. 2202a07aba5dSTimm Baeder if ((Status & APFloat::opStatus::opInvalidOp)) { 2203a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 2204a07aba5dSTimm Baeder QualType Type = E->getType(); 2205a07aba5dSTimm Baeder 2206a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 2207a07aba5dSTimm Baeder if (S.noteUndefinedBehavior()) { 2208a07aba5dSTimm Baeder S.Stk.push<T>(T(Result)); 2209a07aba5dSTimm Baeder return true; 2210a07aba5dSTimm Baeder } 2211a07aba5dSTimm Baeder return false; 2212a07aba5dSTimm Baeder } 2213a07aba5dSTimm Baeder 22140f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 2215a07aba5dSTimm Baeder S.Stk.push<T>(T(Result)); 22160f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, F, Status, FPO); 2217a07aba5dSTimm Baeder } 2218a07aba5dSTimm Baeder } 2219a07aba5dSTimm Baeder 2220a07aba5dSTimm Baeder static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, 22210f5f440fSTimm Baeder uint32_t BitWidth, uint32_t FPOI) { 2222a07aba5dSTimm Baeder const Floating &F = S.Stk.pop<Floating>(); 2223a07aba5dSTimm Baeder 2224a07aba5dSTimm Baeder APSInt Result(BitWidth, /*IsUnsigned=*/true); 2225a07aba5dSTimm Baeder auto Status = F.convertToInteger(Result); 2226a07aba5dSTimm Baeder 2227a07aba5dSTimm Baeder // Float-to-Integral overflow check. 222895ce78b7STimm Baeder if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) 222995ce78b7STimm Baeder return handleOverflow(S, OpPC, F.getAPFloat()); 2230a07aba5dSTimm Baeder 22310f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 2232a07aba5dSTimm Baeder S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 22330f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, F, Status, FPO); 2234a07aba5dSTimm Baeder } 2235a07aba5dSTimm Baeder 2236a07aba5dSTimm Baeder static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, 22370f5f440fSTimm Baeder uint32_t BitWidth, uint32_t FPOI) { 2238a07aba5dSTimm Baeder const Floating &F = S.Stk.pop<Floating>(); 2239a07aba5dSTimm Baeder 2240a07aba5dSTimm Baeder APSInt Result(BitWidth, /*IsUnsigned=*/false); 2241a07aba5dSTimm Baeder auto Status = F.convertToInteger(Result); 2242a07aba5dSTimm Baeder 2243a07aba5dSTimm Baeder // Float-to-Integral overflow check. 224495ce78b7STimm Baeder if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) 224595ce78b7STimm Baeder return handleOverflow(S, OpPC, F.getAPFloat()); 2246a07aba5dSTimm Baeder 22470f5f440fSTimm Baeder FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI); 2248a07aba5dSTimm Baeder S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 22490f5f440fSTimm Baeder return CheckFloatResult(S, OpPC, F, Status, FPO); 2250a07aba5dSTimm Baeder } 2251a07aba5dSTimm Baeder 2252e637a5c9STimm Baeder bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC, 2253e637a5c9STimm Baeder const Pointer &Ptr, unsigned BitWidth); 2254e637a5c9STimm Baeder bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth); 2255e637a5c9STimm Baeder bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth); 2256e637a5c9STimm Baeder 2257a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2258a07aba5dSTimm Baeder bool CastPointerIntegral(InterpState &S, CodePtr OpPC) { 2259a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2260a07aba5dSTimm Baeder 2261e637a5c9STimm Baeder if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth())) 2262a07aba5dSTimm Baeder return false; 2263a07aba5dSTimm Baeder 2264a07aba5dSTimm Baeder S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation())); 2265a07aba5dSTimm Baeder return true; 2266a07aba5dSTimm Baeder } 2267a07aba5dSTimm Baeder 2268641b4d53STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2269641b4d53STimm Baeder static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC, 2270641b4d53STimm Baeder uint32_t FPS) { 2271641b4d53STimm Baeder const T &Int = S.Stk.pop<T>(); 2272641b4d53STimm Baeder 2273046b064dSTimm Baeder FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS); 2274641b4d53STimm Baeder 2275641b4d53STimm Baeder bool Overflow; 227695ce78b7STimm Baeder FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow); 2277641b4d53STimm Baeder 227895ce78b7STimm Baeder if (Overflow && !handleFixedPointOverflow(S, OpPC, Result)) 2279641b4d53STimm Baeder return false; 2280641b4d53STimm Baeder 22816cbd8a30STimm Baeder S.Stk.push<FixedPoint>(Result); 22826cbd8a30STimm Baeder return true; 22836cbd8a30STimm Baeder } 22846cbd8a30STimm Baeder 22856cbd8a30STimm Baeder static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC, 22866cbd8a30STimm Baeder uint32_t FPS) { 22876cbd8a30STimm Baeder const auto &Float = S.Stk.pop<Floating>(); 22886cbd8a30STimm Baeder 2289046b064dSTimm Baeder FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS); 22906cbd8a30STimm Baeder 22916cbd8a30STimm Baeder bool Overflow; 229295ce78b7STimm Baeder FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow); 22936cbd8a30STimm Baeder 229495ce78b7STimm Baeder if (Overflow && !handleFixedPointOverflow(S, OpPC, Result)) 22956cbd8a30STimm Baeder return false; 22966cbd8a30STimm Baeder 22976cbd8a30STimm Baeder S.Stk.push<FixedPoint>(Result); 2298641b4d53STimm Baeder return true; 2299641b4d53STimm Baeder } 2300641b4d53STimm Baeder 23013a5b9da1STimm Baeder static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC, 23023a5b9da1STimm Baeder const llvm::fltSemantics *Sem) { 23033a5b9da1STimm Baeder const auto &Fixed = S.Stk.pop<FixedPoint>(); 23043a5b9da1STimm Baeder 23053a5b9da1STimm Baeder S.Stk.push<Floating>(Fixed.toFloat(Sem)); 23063a5b9da1STimm Baeder return true; 23073a5b9da1STimm Baeder } 23083a5b9da1STimm Baeder 230995ce78b7STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 231095ce78b7STimm Baeder static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) { 231195ce78b7STimm Baeder const auto &Fixed = S.Stk.pop<FixedPoint>(); 231295ce78b7STimm Baeder 231395ce78b7STimm Baeder bool Overflow; 231495ce78b7STimm Baeder APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow); 231595ce78b7STimm Baeder 231695ce78b7STimm Baeder if (Overflow && !handleOverflow(S, OpPC, Int)) 231795ce78b7STimm Baeder return false; 231895ce78b7STimm Baeder 231995ce78b7STimm Baeder S.Stk.push<T>(Int); 232095ce78b7STimm Baeder return true; 232195ce78b7STimm Baeder } 232295ce78b7STimm Baeder 2323a07aba5dSTimm Baeder static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) { 2324a07aba5dSTimm Baeder const auto &Ptr = S.Stk.peek<Pointer>(); 2325a07aba5dSTimm Baeder 2326a07aba5dSTimm Baeder if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) { 2327a07aba5dSTimm Baeder bool HasValidResult = !Ptr.isZero(); 2328a07aba5dSTimm Baeder 2329a07aba5dSTimm Baeder if (HasValidResult) { 2330a07aba5dSTimm Baeder // FIXME: note_constexpr_invalid_void_star_cast 2331a07aba5dSTimm Baeder } else if (!S.getLangOpts().CPlusPlus26) { 2332a07aba5dSTimm Baeder const SourceInfo &E = S.Current->getSource(OpPC); 2333a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_invalid_cast) 2334a07aba5dSTimm Baeder << 3 << "'void *'" << S.Current->getRange(OpPC); 2335a07aba5dSTimm Baeder } 2336a07aba5dSTimm Baeder } else { 2337a07aba5dSTimm Baeder const SourceInfo &E = S.Current->getSource(OpPC); 2338a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_invalid_cast) 2339a07aba5dSTimm Baeder << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 2340a07aba5dSTimm Baeder } 2341a07aba5dSTimm Baeder 2342a07aba5dSTimm Baeder return true; 2343a07aba5dSTimm Baeder } 2344a07aba5dSTimm Baeder 2345a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2346a07aba5dSTimm Baeder // Zero, Nullptr 2347a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2348a07aba5dSTimm Baeder 2349a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2350a07aba5dSTimm Baeder bool Zero(InterpState &S, CodePtr OpPC) { 2351a07aba5dSTimm Baeder S.Stk.push<T>(T::zero()); 2352a07aba5dSTimm Baeder return true; 2353a07aba5dSTimm Baeder } 2354a07aba5dSTimm Baeder 2355a07aba5dSTimm Baeder static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 2356a07aba5dSTimm Baeder S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth)); 2357a07aba5dSTimm Baeder return true; 2358a07aba5dSTimm Baeder } 2359a07aba5dSTimm Baeder 2360a07aba5dSTimm Baeder static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 2361a07aba5dSTimm Baeder S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth)); 2362a07aba5dSTimm Baeder return true; 2363a07aba5dSTimm Baeder } 2364a07aba5dSTimm Baeder 2365a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 236644be7946STimm Baeder inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value, 236744be7946STimm Baeder const Descriptor *Desc) { 236844be7946STimm Baeder // FIXME(perf): This is a somewhat often-used function and the value of a 236944be7946STimm Baeder // null pointer is almost always 0. 237044be7946STimm Baeder S.Stk.push<T>(Value, Desc); 2371a07aba5dSTimm Baeder return true; 2372a07aba5dSTimm Baeder } 2373a07aba5dSTimm Baeder 2374360e4abfSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2375360e4abfSTimm Baeder inline bool IsNonNull(InterpState &S, CodePtr OpPC) { 2376360e4abfSTimm Baeder const auto &P = S.Stk.pop<T>(); 2377360e4abfSTimm Baeder if (P.isWeak()) 2378360e4abfSTimm Baeder return false; 2379360e4abfSTimm Baeder S.Stk.push<Boolean>(Boolean::from(!P.isZero())); 2380360e4abfSTimm Baeder return true; 2381360e4abfSTimm Baeder } 2382360e4abfSTimm Baeder 2383a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2384a07aba5dSTimm Baeder // This, ImplicitThis 2385a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2386a07aba5dSTimm Baeder 2387a07aba5dSTimm Baeder inline bool This(InterpState &S, CodePtr OpPC) { 2388a07aba5dSTimm Baeder // Cannot read 'this' in this mode. 2389a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) { 2390a07aba5dSTimm Baeder return false; 2391a07aba5dSTimm Baeder } 2392a07aba5dSTimm Baeder 2393a07aba5dSTimm Baeder const Pointer &This = S.Current->getThis(); 2394a07aba5dSTimm Baeder if (!CheckThis(S, OpPC, This)) 2395a07aba5dSTimm Baeder return false; 2396a07aba5dSTimm Baeder 2397a07aba5dSTimm Baeder // Ensure the This pointer has been cast to the correct base. 2398a07aba5dSTimm Baeder if (!This.isDummy()) { 2399a07aba5dSTimm Baeder assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl())); 2400a07aba5dSTimm Baeder assert(This.getRecord()); 2401a07aba5dSTimm Baeder assert( 2402a07aba5dSTimm Baeder This.getRecord()->getDecl() == 2403a07aba5dSTimm Baeder cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent()); 2404a07aba5dSTimm Baeder } 2405a07aba5dSTimm Baeder 2406a07aba5dSTimm Baeder S.Stk.push<Pointer>(This); 2407a07aba5dSTimm Baeder return true; 2408a07aba5dSTimm Baeder } 2409a07aba5dSTimm Baeder 2410a07aba5dSTimm Baeder inline bool RVOPtr(InterpState &S, CodePtr OpPC) { 2411a07aba5dSTimm Baeder assert(S.Current->getFunction()->hasRVO()); 2412a07aba5dSTimm Baeder if (S.checkingPotentialConstantExpression()) 2413a07aba5dSTimm Baeder return false; 2414a07aba5dSTimm Baeder S.Stk.push<Pointer>(S.Current->getRVOPtr()); 2415a07aba5dSTimm Baeder return true; 2416a07aba5dSTimm Baeder } 2417a07aba5dSTimm Baeder 2418a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2419a07aba5dSTimm Baeder // Shr, Shl 2420a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2421a07aba5dSTimm Baeder 2422a07aba5dSTimm Baeder template <class LT, class RT, ShiftDir Dir> 2423a07aba5dSTimm Baeder inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { 2424a07aba5dSTimm Baeder const unsigned Bits = LHS.bitWidth(); 2425a07aba5dSTimm Baeder 2426a07aba5dSTimm Baeder // OpenCL 6.3j: shift values are effectively % word size of LHS. 2427a07aba5dSTimm Baeder if (S.getLangOpts().OpenCL) 2428a07aba5dSTimm Baeder RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), 2429a07aba5dSTimm Baeder RHS.bitWidth(), &RHS); 2430a07aba5dSTimm Baeder 2431a07aba5dSTimm Baeder if (RHS.isNegative()) { 2432a07aba5dSTimm Baeder // During constant-folding, a negative shift is an opposite shift. Such a 2433a07aba5dSTimm Baeder // shift is not a constant expression. 2434a07aba5dSTimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 2435a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 2436a07aba5dSTimm Baeder if (!S.noteUndefinedBehavior()) 2437a07aba5dSTimm Baeder return false; 2438a07aba5dSTimm Baeder RHS = -RHS; 2439a07aba5dSTimm Baeder return DoShift<LT, RT, 2440a07aba5dSTimm Baeder Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>( 2441a07aba5dSTimm Baeder S, OpPC, LHS, RHS); 2442a07aba5dSTimm Baeder } 2443a07aba5dSTimm Baeder 24440050503bSTimm Baeder if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits)) 2445a07aba5dSTimm Baeder return false; 2446a07aba5dSTimm Baeder 2447a07aba5dSTimm Baeder // Limit the shift amount to Bits - 1. If this happened, 2448a07aba5dSTimm Baeder // it has already been diagnosed by CheckShift() above, 2449a07aba5dSTimm Baeder // but we still need to handle it. 24502503a665STimm Bäder // Note that we have to be extra careful here since we're doing the shift in 24512503a665STimm Bäder // any case, but we need to adjust the shift amount or the way we do the shift 24522503a665STimm Bäder // for the potential error cases. 2453a07aba5dSTimm Baeder typename LT::AsUnsigned R; 24542503a665STimm Bäder unsigned MaxShiftAmount = LHS.bitWidth() - 1; 2455a07aba5dSTimm Baeder if constexpr (Dir == ShiftDir::Left) { 24562503a665STimm Bäder if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) == 24572503a665STimm Bäder ComparisonCategoryResult::Greater) { 24582503a665STimm Bäder if (LHS.isNegative()) 24592503a665STimm Bäder R = LT::AsUnsigned::zero(LHS.bitWidth()); 24602503a665STimm Bäder else { 24612503a665STimm Bäder RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth()); 2462a6636ce4STimm Bäder LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 246349c2207fSTimm Baeder LT::AsUnsigned::from(RHS, Bits), Bits, &R); 246449c2207fSTimm Baeder } 24652503a665STimm Bäder } else if (LHS.isNegative()) { 24662503a665STimm Bäder if (LHS.isMin()) { 24672503a665STimm Bäder R = LT::AsUnsigned::zero(LHS.bitWidth()); 24682503a665STimm Bäder } else { 24692503a665STimm Bäder // If the LHS is negative, perform the cast and invert the result. 24702503a665STimm Bäder typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS); 24712503a665STimm Bäder LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits, 24722503a665STimm Bäder &R); 24732503a665STimm Bäder R = -R; 24742503a665STimm Bäder } 24752503a665STimm Bäder } else { 24762503a665STimm Bäder // The good case, a simple left shift. 24772503a665STimm Bäder LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 24782503a665STimm Bäder LT::AsUnsigned::from(RHS, Bits), Bits, &R); 24792503a665STimm Bäder } 24802503a665STimm Bäder } else { 24812503a665STimm Bäder // Right shift. 24822503a665STimm Bäder if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) == 24832503a665STimm Bäder ComparisonCategoryResult::Greater) { 24842503a665STimm Bäder R = LT::AsUnsigned::from(-1); 24852503a665STimm Bäder } else { 24862503a665STimm Bäder // Do the shift on potentially signed LT, then convert to unsigned type. 24872503a665STimm Bäder LT A; 24882503a665STimm Bäder LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A); 24892503a665STimm Bäder R = LT::AsUnsigned::from(A); 2490555399d5STimm Baeder } 2491555399d5STimm Baeder } 2492555399d5STimm Baeder 2493a07aba5dSTimm Baeder S.Stk.push<LT>(LT::from(R)); 2494a07aba5dSTimm Baeder return true; 2495a07aba5dSTimm Baeder } 2496a07aba5dSTimm Baeder 2497a07aba5dSTimm Baeder template <PrimType NameL, PrimType NameR> 2498a07aba5dSTimm Baeder inline bool Shr(InterpState &S, CodePtr OpPC) { 2499a07aba5dSTimm Baeder using LT = typename PrimConv<NameL>::T; 2500a07aba5dSTimm Baeder using RT = typename PrimConv<NameR>::T; 2501a07aba5dSTimm Baeder auto RHS = S.Stk.pop<RT>(); 2502a07aba5dSTimm Baeder auto LHS = S.Stk.pop<LT>(); 2503a07aba5dSTimm Baeder 2504a07aba5dSTimm Baeder return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS); 2505a07aba5dSTimm Baeder } 2506a07aba5dSTimm Baeder 2507a07aba5dSTimm Baeder template <PrimType NameL, PrimType NameR> 2508a07aba5dSTimm Baeder inline bool Shl(InterpState &S, CodePtr OpPC) { 2509a07aba5dSTimm Baeder using LT = typename PrimConv<NameL>::T; 2510a07aba5dSTimm Baeder using RT = typename PrimConv<NameR>::T; 2511a07aba5dSTimm Baeder auto RHS = S.Stk.pop<RT>(); 2512a07aba5dSTimm Baeder auto LHS = S.Stk.pop<LT>(); 2513a07aba5dSTimm Baeder 2514a07aba5dSTimm Baeder return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS); 2515a07aba5dSTimm Baeder } 2516a07aba5dSTimm Baeder 25176f04e65cSTimm Baeder static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) { 25186f04e65cSTimm Baeder const auto &RHS = S.Stk.pop<FixedPoint>(); 25196f04e65cSTimm Baeder const auto &LHS = S.Stk.pop<FixedPoint>(); 25206f04e65cSTimm Baeder llvm::FixedPointSemantics LHSSema = LHS.getSemantics(); 25216f04e65cSTimm Baeder 25226f04e65cSTimm Baeder unsigned ShiftBitWidth = 25236f04e65cSTimm Baeder LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1; 25246f04e65cSTimm Baeder 25256f04e65cSTimm Baeder // Embedded-C 4.1.6.2.2: 25266f04e65cSTimm Baeder // The right operand must be nonnegative and less than the total number 25276f04e65cSTimm Baeder // of (nonpadding) bits of the fixed-point operand ... 25286f04e65cSTimm Baeder if (RHS.isNegative()) { 25296f04e65cSTimm Baeder S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift) 25306f04e65cSTimm Baeder << RHS.toAPSInt(); 25316f04e65cSTimm Baeder } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue( 25326f04e65cSTimm Baeder ShiftBitWidth)) != RHS.toAPSInt()) { 25336f04e65cSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 25346f04e65cSTimm Baeder S.CCEDiag(E, diag::note_constexpr_large_shift) 25356f04e65cSTimm Baeder << RHS.toAPSInt() << E->getType() << ShiftBitWidth; 25366f04e65cSTimm Baeder } 25376f04e65cSTimm Baeder 25386f04e65cSTimm Baeder FixedPoint Result; 25396f04e65cSTimm Baeder if (Left) { 25406f04e65cSTimm Baeder if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) && 25416f04e65cSTimm Baeder !handleFixedPointOverflow(S, OpPC, Result)) 25426f04e65cSTimm Baeder return false; 25436f04e65cSTimm Baeder } else { 25446f04e65cSTimm Baeder if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) && 25456f04e65cSTimm Baeder !handleFixedPointOverflow(S, OpPC, Result)) 25466f04e65cSTimm Baeder return false; 25476f04e65cSTimm Baeder } 25486f04e65cSTimm Baeder 25496f04e65cSTimm Baeder S.Stk.push<FixedPoint>(Result); 25506f04e65cSTimm Baeder return true; 25516f04e65cSTimm Baeder } 25526f04e65cSTimm Baeder 2553a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2554a07aba5dSTimm Baeder // NoRet 2555a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2556a07aba5dSTimm Baeder 2557a07aba5dSTimm Baeder inline bool NoRet(InterpState &S, CodePtr OpPC) { 2558a07aba5dSTimm Baeder SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 2559a07aba5dSTimm Baeder S.FFDiag(EndLoc, diag::note_constexpr_no_return); 2560a07aba5dSTimm Baeder return false; 2561a07aba5dSTimm Baeder } 2562a07aba5dSTimm Baeder 2563a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2564a07aba5dSTimm Baeder // NarrowPtr, ExpandPtr 2565a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 2566a07aba5dSTimm Baeder 2567a07aba5dSTimm Baeder inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 2568a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2569a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.narrow()); 2570a07aba5dSTimm Baeder return true; 2571a07aba5dSTimm Baeder } 2572a07aba5dSTimm Baeder 2573a07aba5dSTimm Baeder inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 2574a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2575a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.expand()); 2576a07aba5dSTimm Baeder return true; 2577a07aba5dSTimm Baeder } 2578a07aba5dSTimm Baeder 2579a07aba5dSTimm Baeder // 1) Pops an integral value from the stack 2580a07aba5dSTimm Baeder // 2) Peeks a pointer 2581a07aba5dSTimm Baeder // 3) Pushes a new pointer that's a narrowed array 2582a07aba5dSTimm Baeder // element of the peeked pointer with the value 2583a07aba5dSTimm Baeder // from 1) added as offset. 2584a07aba5dSTimm Baeder // 2585a07aba5dSTimm Baeder // This leaves the original pointer on the stack and pushes a new one 2586a07aba5dSTimm Baeder // with the offset applied and narrowed. 2587a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2588a07aba5dSTimm Baeder inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { 2589a07aba5dSTimm Baeder const T &Offset = S.Stk.pop<T>(); 2590a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 2591a07aba5dSTimm Baeder 2592a07aba5dSTimm Baeder if (!Ptr.isZero() && !Offset.isZero()) { 2593a07aba5dSTimm Baeder if (!CheckArray(S, OpPC, Ptr)) 2594a07aba5dSTimm Baeder return false; 2595a07aba5dSTimm Baeder } 2596a07aba5dSTimm Baeder 2597a07aba5dSTimm Baeder if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 2598a07aba5dSTimm Baeder return false; 2599a07aba5dSTimm Baeder 2600a07aba5dSTimm Baeder return NarrowPtr(S, OpPC); 2601a07aba5dSTimm Baeder } 2602a07aba5dSTimm Baeder 2603a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2604a07aba5dSTimm Baeder inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { 2605a07aba5dSTimm Baeder const T &Offset = S.Stk.pop<T>(); 2606a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2607a07aba5dSTimm Baeder 2608a07aba5dSTimm Baeder if (!Ptr.isZero() && !Offset.isZero()) { 2609a07aba5dSTimm Baeder if (!CheckArray(S, OpPC, Ptr)) 2610a07aba5dSTimm Baeder return false; 2611a07aba5dSTimm Baeder } 2612a07aba5dSTimm Baeder 2613a07aba5dSTimm Baeder if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 2614a07aba5dSTimm Baeder return false; 2615a07aba5dSTimm Baeder 2616a07aba5dSTimm Baeder return NarrowPtr(S, OpPC); 2617a07aba5dSTimm Baeder } 2618a07aba5dSTimm Baeder 2619a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2620a07aba5dSTimm Baeder inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) { 2621a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.peek<Pointer>(); 2622a07aba5dSTimm Baeder 2623a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr)) 2624a07aba5dSTimm Baeder return false; 2625a07aba5dSTimm Baeder 2626e1365ce2STimm Baeder assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name); 2627a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); 2628a07aba5dSTimm Baeder return true; 2629a07aba5dSTimm Baeder } 2630a07aba5dSTimm Baeder 2631a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2632a07aba5dSTimm Baeder inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { 2633a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2634a07aba5dSTimm Baeder 2635a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, Ptr)) 2636a07aba5dSTimm Baeder return false; 2637a07aba5dSTimm Baeder 2638e1365ce2STimm Baeder assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name); 2639a07aba5dSTimm Baeder S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); 2640a07aba5dSTimm Baeder return true; 2641a07aba5dSTimm Baeder } 2642a07aba5dSTimm Baeder 2643a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2644a07aba5dSTimm Baeder inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, 2645a07aba5dSTimm Baeder uint32_t DestIndex, uint32_t Size) { 2646a07aba5dSTimm Baeder const auto &SrcPtr = S.Stk.pop<Pointer>(); 2647a07aba5dSTimm Baeder const auto &DestPtr = S.Stk.peek<Pointer>(); 2648a07aba5dSTimm Baeder 2649a07aba5dSTimm Baeder for (uint32_t I = 0; I != Size; ++I) { 2650a07aba5dSTimm Baeder const Pointer &SP = SrcPtr.atIndex(SrcIndex + I); 2651a07aba5dSTimm Baeder 2652a07aba5dSTimm Baeder if (!CheckLoad(S, OpPC, SP)) 2653a07aba5dSTimm Baeder return false; 2654a07aba5dSTimm Baeder 2655a07aba5dSTimm Baeder const Pointer &DP = DestPtr.atIndex(DestIndex + I); 2656a07aba5dSTimm Baeder DP.deref<T>() = SP.deref<T>(); 2657a07aba5dSTimm Baeder DP.initialize(); 2658a07aba5dSTimm Baeder } 2659a07aba5dSTimm Baeder return true; 2660a07aba5dSTimm Baeder } 2661a07aba5dSTimm Baeder 2662a07aba5dSTimm Baeder /// Just takes a pointer and checks if it's an incomplete 2663a07aba5dSTimm Baeder /// array type. 2664a07aba5dSTimm Baeder inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { 2665a07aba5dSTimm Baeder const Pointer &Ptr = S.Stk.pop<Pointer>(); 2666a07aba5dSTimm Baeder 2667a07aba5dSTimm Baeder if (Ptr.isZero()) { 2668a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr); 2669a07aba5dSTimm Baeder return true; 2670a07aba5dSTimm Baeder } 2671a07aba5dSTimm Baeder 2672a07aba5dSTimm Baeder if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 2673a07aba5dSTimm Baeder return false; 2674a07aba5dSTimm Baeder 2675f7a74eceSTimm Baeder if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) { 2676a07aba5dSTimm Baeder S.Stk.push<Pointer>(Ptr.atIndex(0)); 2677a07aba5dSTimm Baeder return true; 2678a07aba5dSTimm Baeder } 2679a07aba5dSTimm Baeder 2680a07aba5dSTimm Baeder const SourceInfo &E = S.Current->getSource(OpPC); 2681a07aba5dSTimm Baeder S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array); 2682a07aba5dSTimm Baeder 2683a07aba5dSTimm Baeder return false; 2684a07aba5dSTimm Baeder } 2685a07aba5dSTimm Baeder 2686a07aba5dSTimm Baeder inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { 2687a07aba5dSTimm Baeder assert(Func); 2688a07aba5dSTimm Baeder S.Stk.push<FunctionPointer>(Func); 2689a07aba5dSTimm Baeder return true; 2690a07aba5dSTimm Baeder } 2691a07aba5dSTimm Baeder 2692a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2693a07aba5dSTimm Baeder inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 2694a07aba5dSTimm Baeder const T &IntVal = S.Stk.pop<T>(); 2695a07aba5dSTimm Baeder 2696*e8674af6STimm Baeder if (Desc) 2697*e8674af6STimm Baeder S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast) 2698*e8674af6STimm Baeder << 2 << S.getLangOpts().CPlusPlus; 2699*e8674af6STimm Baeder 2700a07aba5dSTimm Baeder S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc); 2701a07aba5dSTimm Baeder return true; 2702a07aba5dSTimm Baeder } 2703a07aba5dSTimm Baeder 27046f81c878STimm Baeder inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) { 2705a07aba5dSTimm Baeder S.Stk.push<MemberPointer>(D); 2706a07aba5dSTimm Baeder return true; 2707a07aba5dSTimm Baeder } 2708a07aba5dSTimm Baeder 2709a07aba5dSTimm Baeder inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) { 2710a07aba5dSTimm Baeder const auto &MP = S.Stk.pop<MemberPointer>(); 2711a07aba5dSTimm Baeder 2712a07aba5dSTimm Baeder S.Stk.push<Pointer>(MP.getBase()); 2713a07aba5dSTimm Baeder return true; 2714a07aba5dSTimm Baeder } 2715a07aba5dSTimm Baeder 2716a07aba5dSTimm Baeder inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) { 2717a07aba5dSTimm Baeder const auto &MP = S.Stk.pop<MemberPointer>(); 2718a07aba5dSTimm Baeder 2719a07aba5dSTimm Baeder const auto *FD = cast<FunctionDecl>(MP.getDecl()); 2720a07aba5dSTimm Baeder const auto *Func = S.getContext().getOrCreateFunction(FD); 2721a07aba5dSTimm Baeder 2722a07aba5dSTimm Baeder S.Stk.push<FunctionPointer>(Func); 2723a07aba5dSTimm Baeder return true; 2724a07aba5dSTimm Baeder } 2725a07aba5dSTimm Baeder 2726a07aba5dSTimm Baeder /// Just emit a diagnostic. The expression that caused emission of this 2727a07aba5dSTimm Baeder /// op is not valid in a constant context. 2728a07aba5dSTimm Baeder inline bool Invalid(InterpState &S, CodePtr OpPC) { 2729a07aba5dSTimm Baeder const SourceLocation &Loc = S.Current->getLocation(OpPC); 2730a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) 2731a07aba5dSTimm Baeder << S.Current->getRange(OpPC); 2732a07aba5dSTimm Baeder return false; 2733a07aba5dSTimm Baeder } 2734a07aba5dSTimm Baeder 2735a07aba5dSTimm Baeder inline bool Unsupported(InterpState &S, CodePtr OpPC) { 2736a07aba5dSTimm Baeder const SourceLocation &Loc = S.Current->getLocation(OpPC); 2737a07aba5dSTimm Baeder S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported) 2738a07aba5dSTimm Baeder << S.Current->getRange(OpPC); 2739a07aba5dSTimm Baeder return false; 2740a07aba5dSTimm Baeder } 2741a07aba5dSTimm Baeder 2742a07aba5dSTimm Baeder /// Do nothing and just abort execution. 2743a07aba5dSTimm Baeder inline bool Error(InterpState &S, CodePtr OpPC) { return false; } 274483fea8b8STimm Baeder inline bool SideEffect(InterpState &S, CodePtr OpPC) { 274583fea8b8STimm Baeder return S.noteSideEffect(); 274683fea8b8STimm Baeder } 2747a07aba5dSTimm Baeder 2748a07aba5dSTimm Baeder /// Same here, but only for casts. 2749a07aba5dSTimm Baeder inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind, 2750a07aba5dSTimm Baeder bool Fatal) { 2751a07aba5dSTimm Baeder const SourceLocation &Loc = S.Current->getLocation(OpPC); 2752a07aba5dSTimm Baeder 2753a07aba5dSTimm Baeder // FIXME: Support diagnosing other invalid cast kinds. 2754a07aba5dSTimm Baeder if (Kind == CastKind::Reinterpret) { 2755a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_invalid_cast) 2756a07aba5dSTimm Baeder << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC); 2757a07aba5dSTimm Baeder return !Fatal; 2758a07aba5dSTimm Baeder } 2759a07aba5dSTimm Baeder return false; 2760a07aba5dSTimm Baeder } 2761a07aba5dSTimm Baeder 2762159f2530STimm Baeder inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR, 2763159f2530STimm Baeder bool InitializerFailed) { 2764a07aba5dSTimm Baeder assert(DR); 2765159f2530STimm Baeder 2766159f2530STimm Baeder if (InitializerFailed) { 2767159f2530STimm Baeder const SourceInfo &Loc = S.Current->getSource(OpPC); 2768159f2530STimm Baeder const auto *VD = cast<VarDecl>(DR->getDecl()); 2769159f2530STimm Baeder S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD; 2770159f2530STimm Baeder S.Note(VD->getLocation(), diag::note_declared_at); 2771159f2530STimm Baeder return false; 2772159f2530STimm Baeder } 2773159f2530STimm Baeder 2774a07aba5dSTimm Baeder return CheckDeclRef(S, OpPC, DR); 2775a07aba5dSTimm Baeder } 2776a07aba5dSTimm Baeder 2777a07aba5dSTimm Baeder inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) { 2778a07aba5dSTimm Baeder if (S.inConstantContext()) { 2779a07aba5dSTimm Baeder const SourceRange &ArgRange = S.Current->getRange(OpPC); 2780a07aba5dSTimm Baeder const Expr *E = S.Current->getExpr(OpPC); 2781a07aba5dSTimm Baeder S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange; 2782a07aba5dSTimm Baeder } 2783a07aba5dSTimm Baeder return false; 2784a07aba5dSTimm Baeder } 2785a07aba5dSTimm Baeder 2786a07aba5dSTimm Baeder inline bool Assume(InterpState &S, CodePtr OpPC) { 2787a07aba5dSTimm Baeder const auto Val = S.Stk.pop<Boolean>(); 2788a07aba5dSTimm Baeder 2789a07aba5dSTimm Baeder if (Val) 2790a07aba5dSTimm Baeder return true; 2791a07aba5dSTimm Baeder 2792a07aba5dSTimm Baeder // Else, diagnose. 2793a07aba5dSTimm Baeder const SourceLocation &Loc = S.Current->getLocation(OpPC); 2794a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_constexpr_assumption_failed); 2795a07aba5dSTimm Baeder return false; 2796a07aba5dSTimm Baeder } 2797a07aba5dSTimm Baeder 2798a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2799a07aba5dSTimm Baeder inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) { 2800a07aba5dSTimm Baeder llvm::SmallVector<int64_t> ArrayIndices; 2801a07aba5dSTimm Baeder for (size_t I = 0; I != E->getNumExpressions(); ++I) 2802a07aba5dSTimm Baeder ArrayIndices.emplace_back(S.Stk.pop<int64_t>()); 2803a07aba5dSTimm Baeder 2804a07aba5dSTimm Baeder int64_t Result; 2805a07aba5dSTimm Baeder if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result)) 2806a07aba5dSTimm Baeder return false; 2807a07aba5dSTimm Baeder 2808a07aba5dSTimm Baeder S.Stk.push<T>(T::from(Result)); 2809a07aba5dSTimm Baeder 2810a07aba5dSTimm Baeder return true; 2811a07aba5dSTimm Baeder } 2812a07aba5dSTimm Baeder 2813a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2814a07aba5dSTimm Baeder inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) { 2815a07aba5dSTimm Baeder const T &Arg = S.Stk.peek<T>(); 2816a07aba5dSTimm Baeder if (!Arg.isZero()) 2817a07aba5dSTimm Baeder return true; 2818a07aba5dSTimm Baeder 2819a07aba5dSTimm Baeder const SourceLocation &Loc = S.Current->getLocation(OpPC); 2820a07aba5dSTimm Baeder S.CCEDiag(Loc, diag::note_non_null_attribute_failed); 2821a07aba5dSTimm Baeder 2822a07aba5dSTimm Baeder return false; 2823a07aba5dSTimm Baeder } 2824a07aba5dSTimm Baeder 2825a07aba5dSTimm Baeder void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, 2826a07aba5dSTimm Baeder const APSInt &Value); 2827a07aba5dSTimm Baeder 2828a07aba5dSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2829a07aba5dSTimm Baeder inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) { 2830a07aba5dSTimm Baeder assert(ED); 2831a07aba5dSTimm Baeder assert(!ED->isFixed()); 2832a07aba5dSTimm Baeder const APSInt Val = S.Stk.peek<T>().toAPSInt(); 2833a07aba5dSTimm Baeder 2834a07aba5dSTimm Baeder if (S.inConstantContext()) 2835a07aba5dSTimm Baeder diagnoseEnumValue(S, OpPC, ED, Val); 2836a07aba5dSTimm Baeder return true; 2837a07aba5dSTimm Baeder } 2838a07aba5dSTimm Baeder 2839a07aba5dSTimm Baeder /// OldPtr -> Integer -> NewPtr. 2840a07aba5dSTimm Baeder template <PrimType TIn, PrimType TOut> 2841a07aba5dSTimm Baeder inline bool DecayPtr(InterpState &S, CodePtr OpPC) { 2842a07aba5dSTimm Baeder static_assert(isPtrType(TIn) && isPtrType(TOut)); 2843a07aba5dSTimm Baeder using FromT = typename PrimConv<TIn>::T; 2844a07aba5dSTimm Baeder using ToT = typename PrimConv<TOut>::T; 2845a07aba5dSTimm Baeder 2846a07aba5dSTimm Baeder const FromT &OldPtr = S.Stk.pop<FromT>(); 2847a07aba5dSTimm Baeder 2848a07aba5dSTimm Baeder if constexpr (std::is_same_v<FromT, FunctionPointer> && 2849a07aba5dSTimm Baeder std::is_same_v<ToT, Pointer>) { 2850db94852bSTimm Baeder S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset()); 2851a07aba5dSTimm Baeder return true; 2852db94852bSTimm Baeder } else if constexpr (std::is_same_v<FromT, Pointer> && 2853db94852bSTimm Baeder std::is_same_v<ToT, FunctionPointer>) { 2854db94852bSTimm Baeder if (OldPtr.isFunctionPointer()) { 2855db94852bSTimm Baeder S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(), 2856db94852bSTimm Baeder OldPtr.getByteOffset()); 2857db94852bSTimm Baeder return true; 2858db94852bSTimm Baeder } 2859a07aba5dSTimm Baeder } 2860a07aba5dSTimm Baeder 2861a07aba5dSTimm Baeder S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr)); 2862a07aba5dSTimm Baeder return true; 2863a07aba5dSTimm Baeder } 2864a07aba5dSTimm Baeder 2865a07aba5dSTimm Baeder inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) { 2866a07aba5dSTimm Baeder // An expression E is a core constant expression unless the evaluation of E 2867a07aba5dSTimm Baeder // would evaluate one of the following: [C++23] - a control flow that passes 2868a07aba5dSTimm Baeder // through a declaration of a variable with static or thread storage duration 2869a07aba5dSTimm Baeder // unless that variable is usable in constant expressions. 2870a07aba5dSTimm Baeder assert(VD->isLocalVarDecl() && 2871a07aba5dSTimm Baeder VD->isStaticLocal()); // Checked before emitting this. 2872a07aba5dSTimm Baeder 2873a07aba5dSTimm Baeder if (VD == S.EvaluatingDecl) 2874a07aba5dSTimm Baeder return true; 2875a07aba5dSTimm Baeder 2876d9e72860Syronglin if (!VD->isUsableInConstantExpressions(S.getASTContext())) { 2877a07aba5dSTimm Baeder S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local) 2878a07aba5dSTimm Baeder << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD; 2879a07aba5dSTimm Baeder return false; 2880a07aba5dSTimm Baeder } 2881a07aba5dSTimm Baeder return true; 2882a07aba5dSTimm Baeder } 2883a07aba5dSTimm Baeder 2884a07aba5dSTimm Baeder inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 2885a07aba5dSTimm Baeder assert(Desc); 2886a07aba5dSTimm Baeder 2887a07aba5dSTimm Baeder if (!CheckDynamicMemoryAllocation(S, OpPC)) 2888a07aba5dSTimm Baeder return false; 2889a07aba5dSTimm Baeder 2890a07aba5dSTimm Baeder DynamicAllocator &Allocator = S.getAllocator(); 2891610b8539STimm Baeder Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(), 2892610b8539STimm Baeder DynamicAllocator::Form::NonArray); 2893a07aba5dSTimm Baeder assert(B); 2894a07aba5dSTimm Baeder 2895610b8539STimm Baeder S.Stk.push<Pointer>(B); 2896a07aba5dSTimm Baeder 2897a07aba5dSTimm Baeder return true; 2898a07aba5dSTimm Baeder } 2899a07aba5dSTimm Baeder 2900a07aba5dSTimm Baeder template <PrimType Name, class SizeT = typename PrimConv<Name>::T> 2901a07aba5dSTimm Baeder inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, 2902a07aba5dSTimm Baeder bool IsNoThrow) { 2903a07aba5dSTimm Baeder if (!CheckDynamicMemoryAllocation(S, OpPC)) 2904a07aba5dSTimm Baeder return false; 2905a07aba5dSTimm Baeder 2906a07aba5dSTimm Baeder SizeT NumElements = S.Stk.pop<SizeT>(); 2907a07aba5dSTimm Baeder if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) { 2908a07aba5dSTimm Baeder if (!IsNoThrow) 2909a07aba5dSTimm Baeder return false; 2910a07aba5dSTimm Baeder 2911a07aba5dSTimm Baeder // If this failed and is nothrow, just return a null ptr. 2912a07aba5dSTimm Baeder S.Stk.push<Pointer>(0, nullptr); 2913a07aba5dSTimm Baeder return true; 2914a07aba5dSTimm Baeder } 2915a07aba5dSTimm Baeder 2916a07aba5dSTimm Baeder DynamicAllocator &Allocator = S.getAllocator(); 2917610b8539STimm Baeder Block *B = 2918610b8539STimm Baeder Allocator.allocate(Source, T, static_cast<size_t>(NumElements), 2919610b8539STimm Baeder S.Ctx.getEvalID(), DynamicAllocator::Form::Array); 2920a07aba5dSTimm Baeder assert(B); 2921a07aba5dSTimm Baeder S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 2922a07aba5dSTimm Baeder 2923a07aba5dSTimm Baeder return true; 2924a07aba5dSTimm Baeder } 2925a07aba5dSTimm Baeder 2926a07aba5dSTimm Baeder template <PrimType Name, class SizeT = typename PrimConv<Name>::T> 2927a07aba5dSTimm Baeder inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, 2928a07aba5dSTimm Baeder bool IsNoThrow) { 2929a07aba5dSTimm Baeder if (!CheckDynamicMemoryAllocation(S, OpPC)) 2930a07aba5dSTimm Baeder return false; 2931a07aba5dSTimm Baeder 2932a07aba5dSTimm Baeder SizeT NumElements = S.Stk.pop<SizeT>(); 2933a07aba5dSTimm Baeder if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(), 2934a07aba5dSTimm Baeder IsNoThrow)) { 2935a07aba5dSTimm Baeder if (!IsNoThrow) 2936a07aba5dSTimm Baeder return false; 2937a07aba5dSTimm Baeder 2938a07aba5dSTimm Baeder // If this failed and is nothrow, just return a null ptr. 2939a07aba5dSTimm Baeder S.Stk.push<Pointer>(0, ElementDesc); 2940a07aba5dSTimm Baeder return true; 2941a07aba5dSTimm Baeder } 2942a07aba5dSTimm Baeder 2943a07aba5dSTimm Baeder DynamicAllocator &Allocator = S.getAllocator(); 2944610b8539STimm Baeder Block *B = 2945610b8539STimm Baeder Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements), 2946610b8539STimm Baeder S.Ctx.getEvalID(), DynamicAllocator::Form::Array); 2947a07aba5dSTimm Baeder assert(B); 2948a07aba5dSTimm Baeder 2949a07aba5dSTimm Baeder S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 2950a07aba5dSTimm Baeder 2951a07aba5dSTimm Baeder return true; 2952a07aba5dSTimm Baeder } 2953a07aba5dSTimm Baeder 2954f93258e4STimm Baeder bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm, 2955f93258e4STimm Baeder bool IsGlobalDelete); 2956a07aba5dSTimm Baeder 2957b9c4c4ccSTimm Baeder static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) { 2958b9c4c4ccSTimm Baeder S.Stk.push<Boolean>(Boolean::from(S.inConstantContext())); 2959b9c4c4ccSTimm Baeder return true; 2960b9c4c4ccSTimm Baeder } 2961b9c4c4ccSTimm Baeder 29623eaf4a9dSTimm Baeder static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) { 29633eaf4a9dSTimm Baeder return S.maybeDiagnoseDanglingAllocations(); 29643eaf4a9dSTimm Baeder } 29653eaf4a9dSTimm Baeder 2966c712ab82STimm Baeder /// Check if the initializer and storage types of a placement-new expression 2967c712ab82STimm Baeder /// match. 2968c712ab82STimm Baeder bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E, 2969c712ab82STimm Baeder std::optional<uint64_t> ArraySize = std::nullopt); 2970c712ab82STimm Baeder 2971c712ab82STimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 2972c712ab82STimm Baeder bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) { 2973c712ab82STimm Baeder const auto &Size = S.Stk.pop<T>(); 2974c712ab82STimm Baeder return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size)); 2975c712ab82STimm Baeder } 2976c712ab82STimm Baeder bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E); 2977ef2a104cSTimm Baeder 2978ef2a104cSTimm Baeder template <PrimType Name, class T = typename PrimConv<Name>::T> 297956fd46edSTimm Baeder inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte, 298056fd46edSTimm Baeder uint32_t ResultBitWidth, 298156fd46edSTimm Baeder const llvm::fltSemantics *Sem) { 2982ef2a104cSTimm Baeder const Pointer &FromPtr = S.Stk.pop<Pointer>(); 2983ef2a104cSTimm Baeder 2984ef2a104cSTimm Baeder if (!CheckLoad(S, OpPC, FromPtr)) 2985ef2a104cSTimm Baeder return false; 2986ef2a104cSTimm Baeder 298756fd46edSTimm Baeder if constexpr (std::is_same_v<T, Pointer>) { 298856fd46edSTimm Baeder // The only pointer type we can validly bitcast to is nullptr_t. 298956fd46edSTimm Baeder S.Stk.push<Pointer>(); 299056fd46edSTimm Baeder return true; 299156fd46edSTimm Baeder } else { 299256fd46edSTimm Baeder 2993ef2a104cSTimm Baeder size_t BuffSize = ResultBitWidth / 8; 2994ef2a104cSTimm Baeder llvm::SmallVector<std::byte> Buff(BuffSize); 2995ef2a104cSTimm Baeder bool HasIndeterminateBits = false; 2996ef2a104cSTimm Baeder 29971fbbf4c4STimm Baeder Bits FullBitWidth(ResultBitWidth); 29981fbbf4c4STimm Baeder Bits BitWidth = FullBitWidth; 29991fbbf4c4STimm Baeder 30001fbbf4c4STimm Baeder if constexpr (std::is_same_v<T, Floating>) { 30011fbbf4c4STimm Baeder assert(Sem); 30021fbbf4c4STimm Baeder BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem)); 30031fbbf4c4STimm Baeder } 30041fbbf4c4STimm Baeder 30051fbbf4c4STimm Baeder if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth, 30061fbbf4c4STimm Baeder HasIndeterminateBits)) 3007ef2a104cSTimm Baeder return false; 3008ef2a104cSTimm Baeder 3009ef2a104cSTimm Baeder if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte)) 3010ef2a104cSTimm Baeder return false; 3011ef2a104cSTimm Baeder 3012ef2a104cSTimm Baeder if constexpr (std::is_same_v<T, Floating>) { 30135b32c595STimm Baeder assert(Sem); 30141fbbf4c4STimm Baeder S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem)); 3015ef2a104cSTimm Baeder } else { 3016ef2a104cSTimm Baeder assert(!Sem); 3017ef2a104cSTimm Baeder S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth)); 3018ef2a104cSTimm Baeder } 3019ef2a104cSTimm Baeder return true; 3020ef2a104cSTimm Baeder } 302156fd46edSTimm Baeder } 3022ef2a104cSTimm Baeder 302356fd46edSTimm Baeder inline bool BitCast(InterpState &S, CodePtr OpPC) { 30242588b8beSTimm Baeder const Pointer &FromPtr = S.Stk.pop<Pointer>(); 30252588b8beSTimm Baeder Pointer &ToPtr = S.Stk.peek<Pointer>(); 30262588b8beSTimm Baeder 30271425fa91STimm Baeder if (!CheckLoad(S, OpPC, FromPtr)) 30281425fa91STimm Baeder return false; 30291425fa91STimm Baeder 30302588b8beSTimm Baeder if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr)) 30312588b8beSTimm Baeder return false; 30322588b8beSTimm Baeder 30332588b8beSTimm Baeder return true; 30342588b8beSTimm Baeder } 30352588b8beSTimm Baeder 3036e86b68ffSTimm Baeder /// Typeid support. 3037e86b68ffSTimm Baeder bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr, 3038e86b68ffSTimm Baeder const Type *TypeInfoType); 3039e86b68ffSTimm Baeder bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType); 3040e86b68ffSTimm Baeder bool DiagTypeid(InterpState &S, CodePtr OpPC); 3041e86b68ffSTimm Baeder 3042a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 3043a07aba5dSTimm Baeder // Read opcode arguments 3044a07aba5dSTimm Baeder //===----------------------------------------------------------------------===// 3045a07aba5dSTimm Baeder 3046a07aba5dSTimm Baeder template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { 3047a07aba5dSTimm Baeder if constexpr (std::is_pointer<T>::value) { 3048a07aba5dSTimm Baeder uint32_t ID = OpPC.read<uint32_t>(); 3049a07aba5dSTimm Baeder return reinterpret_cast<T>(S.P.getNativePointer(ID)); 3050a07aba5dSTimm Baeder } else { 3051a07aba5dSTimm Baeder return OpPC.read<T>(); 3052a07aba5dSTimm Baeder } 3053a07aba5dSTimm Baeder } 3054a07aba5dSTimm Baeder 3055a07aba5dSTimm Baeder template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { 3056a07aba5dSTimm Baeder Floating F = Floating::deserialize(*OpPC); 3057a07aba5dSTimm Baeder OpPC += align(F.bytesToSerialize()); 3058a07aba5dSTimm Baeder return F; 3059a07aba5dSTimm Baeder } 3060a07aba5dSTimm Baeder 3061a07aba5dSTimm Baeder template <> 3062a07aba5dSTimm Baeder inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S, 3063a07aba5dSTimm Baeder CodePtr &OpPC) { 3064a07aba5dSTimm Baeder IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC); 3065a07aba5dSTimm Baeder OpPC += align(I.bytesToSerialize()); 3066a07aba5dSTimm Baeder return I; 3067a07aba5dSTimm Baeder } 3068a07aba5dSTimm Baeder 3069a07aba5dSTimm Baeder template <> 3070a07aba5dSTimm Baeder inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S, 3071a07aba5dSTimm Baeder CodePtr &OpPC) { 3072a07aba5dSTimm Baeder IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC); 3073a07aba5dSTimm Baeder OpPC += align(I.bytesToSerialize()); 3074a07aba5dSTimm Baeder return I; 3075a07aba5dSTimm Baeder } 3076a07aba5dSTimm Baeder 3077b5c9cba3STimm Baeder template <> 3078b5c9cba3STimm Baeder inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) { 3079b5c9cba3STimm Baeder FixedPoint FP = FixedPoint::deserialize(*OpPC); 3080b5c9cba3STimm Baeder OpPC += align(FP.bytesToSerialize()); 3081b5c9cba3STimm Baeder return FP; 3082b5c9cba3STimm Baeder } 3083b5c9cba3STimm Baeder 3084a07aba5dSTimm Baeder } // namespace interp 3085a07aba5dSTimm Baeder } // namespace clang 3086a07aba5dSTimm Baeder 3087a07aba5dSTimm Baeder #endif 3088