1a7dea167SDimitry Andric //===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===// 2a7dea167SDimitry Andric // 3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6a7dea167SDimitry Andric // 7a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 8a7dea167SDimitry Andric // 9a7dea167SDimitry Andric // Definition of the interpreter state and entry point. 10a7dea167SDimitry Andric // 11a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 12a7dea167SDimitry Andric 13a7dea167SDimitry Andric #ifndef LLVM_CLANG_AST_INTERP_INTERP_H 14a7dea167SDimitry Andric #define LLVM_CLANG_AST_INTERP_INTERP_H 15a7dea167SDimitry Andric 160fca6ea1SDimitry Andric #include "../ExprConstShared.h" 17bdd1243dSDimitry Andric #include "Boolean.h" 180fca6ea1SDimitry Andric #include "DynamicAllocator.h" 1906c3fb27SDimitry Andric #include "Floating.h" 20a7dea167SDimitry Andric #include "Function.h" 2106c3fb27SDimitry Andric #include "FunctionPointer.h" 22a7dea167SDimitry Andric #include "InterpFrame.h" 23a7dea167SDimitry Andric #include "InterpStack.h" 24a7dea167SDimitry Andric #include "InterpState.h" 250fca6ea1SDimitry Andric #include "MemberPointer.h" 26a7dea167SDimitry Andric #include "Opcode.h" 27a7dea167SDimitry Andric #include "PrimType.h" 28a7dea167SDimitry Andric #include "Program.h" 29a7dea167SDimitry Andric #include "State.h" 30a7dea167SDimitry Andric #include "clang/AST/ASTContext.h" 31a7dea167SDimitry Andric #include "clang/AST/Expr.h" 32a7dea167SDimitry Andric #include "llvm/ADT/APFloat.h" 33a7dea167SDimitry Andric #include "llvm/ADT/APSInt.h" 34349cc55cSDimitry Andric #include <type_traits> 35a7dea167SDimitry Andric 36a7dea167SDimitry Andric namespace clang { 37a7dea167SDimitry Andric namespace interp { 38a7dea167SDimitry Andric 39a7dea167SDimitry Andric using APSInt = llvm::APSInt; 40a7dea167SDimitry Andric 41349cc55cSDimitry Andric /// Convert a value to an APValue. 420fca6ea1SDimitry Andric template <typename T> 430fca6ea1SDimitry Andric bool ReturnValue(const InterpState &S, const T &V, APValue &R) { 440fca6ea1SDimitry Andric R = V.toAPValue(S.getCtx()); 45a7dea167SDimitry Andric return true; 46a7dea167SDimitry Andric } 47a7dea167SDimitry Andric 48a7dea167SDimitry Andric /// Checks if the variable has externally defined storage. 49a7dea167SDimitry Andric bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 50a7dea167SDimitry Andric 51a7dea167SDimitry Andric /// Checks if the array is offsetable. 52a7dea167SDimitry Andric bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 53a7dea167SDimitry Andric 54349cc55cSDimitry Andric /// Checks if a pointer is live and accessible. 55a7dea167SDimitry Andric bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 56a7dea167SDimitry Andric AccessKinds AK); 575f757f3fSDimitry Andric 585f757f3fSDimitry Andric /// Checks if a pointer is a dummy pointer. 590fca6ea1SDimitry Andric bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 600fca6ea1SDimitry Andric AccessKinds AK); 615f757f3fSDimitry Andric 62a7dea167SDimitry Andric /// Checks if a pointer is null. 63a7dea167SDimitry Andric bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 64a7dea167SDimitry Andric CheckSubobjectKind CSK); 65a7dea167SDimitry Andric 66a7dea167SDimitry Andric /// Checks if a pointer is in range. 67a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 68a7dea167SDimitry Andric AccessKinds AK); 69a7dea167SDimitry Andric 70a7dea167SDimitry Andric /// Checks if a field from which a pointer is going to be derived is valid. 71a7dea167SDimitry Andric bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 72a7dea167SDimitry Andric CheckSubobjectKind CSK); 73a7dea167SDimitry Andric 745f757f3fSDimitry Andric /// Checks if Ptr is a one-past-the-end pointer. 755f757f3fSDimitry Andric bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 765f757f3fSDimitry Andric CheckSubobjectKind CSK); 775f757f3fSDimitry Andric 780fca6ea1SDimitry Andric /// Checks if the dowcast using the given offset is possible with the given 790fca6ea1SDimitry Andric /// pointer. 800fca6ea1SDimitry Andric bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 810fca6ea1SDimitry Andric uint32_t Offset); 820fca6ea1SDimitry Andric 83a7dea167SDimitry Andric /// Checks if a pointer points to const storage. 84a7dea167SDimitry Andric bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 85a7dea167SDimitry Andric 867a6dacacSDimitry Andric /// Checks if the Descriptor is of a constexpr or const global variable. 877a6dacacSDimitry Andric bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); 887a6dacacSDimitry Andric 89a7dea167SDimitry Andric /// Checks if a pointer points to a mutable field. 90a7dea167SDimitry Andric bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 91a7dea167SDimitry Andric 92a7dea167SDimitry Andric /// Checks if a value can be loaded from a block. 930fca6ea1SDimitry Andric bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 940fca6ea1SDimitry Andric AccessKinds AK = AK_Read); 95a7dea167SDimitry Andric 9606c3fb27SDimitry Andric bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 9706c3fb27SDimitry Andric AccessKinds AK); 980fca6ea1SDimitry Andric /// Check if a global variable is initialized. 990fca6ea1SDimitry Andric bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 10006c3fb27SDimitry Andric 101a7dea167SDimitry Andric /// Checks if a value can be stored in a block. 102a7dea167SDimitry Andric bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 103a7dea167SDimitry Andric 104a7dea167SDimitry Andric /// Checks if a method can be invoked on an object. 105a7dea167SDimitry Andric bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 106a7dea167SDimitry Andric 107a7dea167SDimitry Andric /// Checks if a value can be initialized. 108a7dea167SDimitry Andric bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 109a7dea167SDimitry Andric 110a7dea167SDimitry Andric /// Checks if a method can be called. 111bdd1243dSDimitry Andric bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F); 112a7dea167SDimitry Andric 11306c3fb27SDimitry Andric /// Checks if calling the currently active function would exceed 11406c3fb27SDimitry Andric /// the allowed call depth. 11506c3fb27SDimitry Andric bool CheckCallDepth(InterpState &S, CodePtr OpPC); 11606c3fb27SDimitry Andric 117a7dea167SDimitry Andric /// Checks the 'this' pointer. 118a7dea167SDimitry Andric bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 119a7dea167SDimitry Andric 120a7dea167SDimitry Andric /// Checks if a method is pure virtual. 121a7dea167SDimitry Andric bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 122a7dea167SDimitry Andric 1230fca6ea1SDimitry Andric /// Checks if all the arguments annotated as 'nonnull' are in fact not null. 1240fca6ea1SDimitry Andric bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F, 1250fca6ea1SDimitry Andric const CallExpr *CE, unsigned ArgSize); 1260fca6ea1SDimitry Andric 1270fca6ea1SDimitry Andric /// Checks if dynamic memory allocation is available in the current 1280fca6ea1SDimitry Andric /// language mode. 1290fca6ea1SDimitry Andric bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC); 1300fca6ea1SDimitry Andric 1310fca6ea1SDimitry Andric /// Diagnose mismatched new[]/delete or new/delete[] pairs. 1320fca6ea1SDimitry Andric bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray, 1330fca6ea1SDimitry Andric bool DeleteIsArray, const Descriptor *D, 1340fca6ea1SDimitry Andric const Expr *NewExpr); 1350fca6ea1SDimitry Andric 1360fca6ea1SDimitry Andric /// Check the source of the pointer passed to delete/delete[] has actually 1370fca6ea1SDimitry Andric /// been heap allocated by us. 1380fca6ea1SDimitry Andric bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source, 1395f757f3fSDimitry Andric const Pointer &Ptr); 1405f757f3fSDimitry Andric 1415f757f3fSDimitry Andric /// Sets the given integral value to the pointer, which is of 1425f757f3fSDimitry Andric /// a std::{weak,partial,strong}_ordering type. 1435f757f3fSDimitry Andric bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, 1445f757f3fSDimitry Andric const Pointer &Ptr, const APSInt &IntValue); 1455f757f3fSDimitry Andric 1460fca6ea1SDimitry Andric /// Copy the contents of Src into Dest. 1470fca6ea1SDimitry Andric bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest); 1480fca6ea1SDimitry Andric 149bdd1243dSDimitry Andric /// Checks if the shift operation is legal. 15006c3fb27SDimitry Andric template <typename LT, typename RT> 15106c3fb27SDimitry Andric bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, 15206c3fb27SDimitry Andric unsigned Bits) { 153bdd1243dSDimitry Andric if (RHS.isNegative()) { 154bdd1243dSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 155bdd1243dSDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 156*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 157bdd1243dSDimitry Andric return false; 158bdd1243dSDimitry Andric } 159bdd1243dSDimitry Andric 160bdd1243dSDimitry Andric // C++11 [expr.shift]p1: Shift width must be less than the bit width of 161bdd1243dSDimitry Andric // the shifted type. 162bdd1243dSDimitry Andric if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { 163bdd1243dSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 164bdd1243dSDimitry Andric const APSInt Val = RHS.toAPSInt(); 165bdd1243dSDimitry Andric QualType Ty = E->getType(); 166bdd1243dSDimitry Andric S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; 167*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 168*36b606aeSDimitry Andric return false; 169bdd1243dSDimitry Andric } 17006c3fb27SDimitry Andric 17106c3fb27SDimitry Andric if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) { 17206c3fb27SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 17306c3fb27SDimitry Andric // C++11 [expr.shift]p2: A signed left shift must have a non-negative 17406c3fb27SDimitry Andric // operand, and must not overflow the corresponding unsigned type. 175*36b606aeSDimitry Andric if (LHS.isNegative()) { 17606c3fb27SDimitry Andric S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); 177*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 178*36b606aeSDimitry Andric return false; 179*36b606aeSDimitry Andric } else if (LHS.toUnsigned().countLeadingZeros() < 180*36b606aeSDimitry Andric static_cast<unsigned>(RHS)) { 18106c3fb27SDimitry Andric S.CCEDiag(E, diag::note_constexpr_lshift_discards); 182*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 183*36b606aeSDimitry Andric return false; 184*36b606aeSDimitry Andric } 18506c3fb27SDimitry Andric } 18606c3fb27SDimitry Andric 18706c3fb27SDimitry Andric // C++2a [expr.shift]p2: [P0907R4]: 18806c3fb27SDimitry Andric // E1 << E2 is the unique value congruent to 18906c3fb27SDimitry Andric // E1 x 2^E2 module 2^N. 190bdd1243dSDimitry Andric return true; 191bdd1243dSDimitry Andric } 192bdd1243dSDimitry Andric 193bdd1243dSDimitry Andric /// Checks if Div/Rem operation on LHS and RHS is valid. 194bdd1243dSDimitry Andric template <typename T> 195bdd1243dSDimitry Andric bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { 196bdd1243dSDimitry Andric if (RHS.isZero()) { 1975f757f3fSDimitry Andric const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC)); 1980fca6ea1SDimitry Andric if constexpr (std::is_same_v<T, Floating>) { 1990fca6ea1SDimitry Andric S.CCEDiag(Op, diag::note_expr_divide_by_zero) 2000fca6ea1SDimitry Andric << Op->getRHS()->getSourceRange(); 2010fca6ea1SDimitry Andric return true; 2020fca6ea1SDimitry Andric } 2030fca6ea1SDimitry Andric 2045f757f3fSDimitry Andric S.FFDiag(Op, diag::note_expr_divide_by_zero) 2055f757f3fSDimitry Andric << Op->getRHS()->getSourceRange(); 206bdd1243dSDimitry Andric return false; 207bdd1243dSDimitry Andric } 208bdd1243dSDimitry Andric 209bdd1243dSDimitry Andric if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { 210bdd1243dSDimitry Andric APSInt LHSInt = LHS.toAPSInt(); 211bdd1243dSDimitry Andric SmallString<32> Trunc; 212bdd1243dSDimitry Andric (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); 213bdd1243dSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 214bdd1243dSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 215bdd1243dSDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); 216bdd1243dSDimitry Andric return false; 217bdd1243dSDimitry Andric } 218bdd1243dSDimitry Andric return true; 219bdd1243dSDimitry Andric } 220bdd1243dSDimitry Andric 2210fca6ea1SDimitry Andric template <typename SizeT> 2220fca6ea1SDimitry Andric bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements, 2230fca6ea1SDimitry Andric unsigned ElemSize, bool IsNoThrow) { 2240fca6ea1SDimitry Andric // FIXME: Both the SizeT::from() as well as the 2250fca6ea1SDimitry Andric // NumElements.toAPSInt() in this function are rather expensive. 2260fca6ea1SDimitry Andric 2270fca6ea1SDimitry Andric // FIXME: GH63562 2280fca6ea1SDimitry Andric // APValue stores array extents as unsigned, 2290fca6ea1SDimitry Andric // so anything that is greater that unsigned would overflow when 2300fca6ea1SDimitry Andric // constructing the array, we catch this here. 2310fca6ea1SDimitry Andric SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize); 2320fca6ea1SDimitry Andric if (NumElements->toAPSInt().getActiveBits() > 2330fca6ea1SDimitry Andric ConstantArrayType::getMaxSizeBits(S.getCtx()) || 2340fca6ea1SDimitry Andric *NumElements > MaxElements) { 2350fca6ea1SDimitry Andric if (!IsNoThrow) { 2360fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 2370fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_new_too_large) 2380fca6ea1SDimitry Andric << NumElements->toDiagnosticString(S.getCtx()); 2390fca6ea1SDimitry Andric } 2400fca6ea1SDimitry Andric return false; 2410fca6ea1SDimitry Andric } 2420fca6ea1SDimitry Andric return true; 2430fca6ea1SDimitry Andric } 2440fca6ea1SDimitry Andric 2455f757f3fSDimitry Andric /// Checks if the result of a floating-point operation is valid 24606c3fb27SDimitry Andric /// in the current context. 2475f757f3fSDimitry Andric bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, 2485f757f3fSDimitry Andric APFloat::opStatus Status); 2495f757f3fSDimitry Andric 2505f757f3fSDimitry Andric /// Checks why the given DeclRefExpr is invalid. 2515f757f3fSDimitry Andric bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR); 25206c3fb27SDimitry Andric 253bdd1243dSDimitry Andric /// Interpreter entry point. 254bdd1243dSDimitry Andric bool Interpret(InterpState &S, APValue &Result); 255a7dea167SDimitry Andric 25606c3fb27SDimitry Andric /// Interpret a builtin function. 2575f757f3fSDimitry Andric bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 2585f757f3fSDimitry Andric const CallExpr *Call); 2595f757f3fSDimitry Andric 2605f757f3fSDimitry Andric /// Interpret an offsetof operation. 2615f757f3fSDimitry Andric bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, 2625f757f3fSDimitry Andric llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result); 26306c3fb27SDimitry Andric 2640fca6ea1SDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC); 2650fca6ea1SDimitry Andric 26606c3fb27SDimitry Andric enum class ArithOp { Add, Sub }; 26706c3fb27SDimitry Andric 26806c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 26906c3fb27SDimitry Andric // Returning values 27006c3fb27SDimitry Andric //===----------------------------------------------------------------------===// 27106c3fb27SDimitry Andric 2725f757f3fSDimitry Andric void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC); 2735f757f3fSDimitry Andric 2745f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 27506c3fb27SDimitry Andric bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { 27606c3fb27SDimitry Andric const T &Ret = S.Stk.pop<T>(); 27706c3fb27SDimitry Andric 2785f757f3fSDimitry Andric // Make sure returned pointers are live. We might be trying to return a 2795f757f3fSDimitry Andric // pointer or reference to a local variable. 2805f757f3fSDimitry Andric // Just return false, since a diagnostic has already been emitted in Sema. 2815f757f3fSDimitry Andric if constexpr (std::is_same_v<T, Pointer>) { 2825f757f3fSDimitry Andric // FIXME: We could be calling isLive() here, but the emitted diagnostics 2835f757f3fSDimitry Andric // seem a little weird, at least if the returned expression is of 2845f757f3fSDimitry Andric // pointer type. 2855f757f3fSDimitry Andric // Null pointers are considered live here. 2865f757f3fSDimitry Andric if (!Ret.isZero() && !Ret.isLive()) 2875f757f3fSDimitry Andric return false; 2885f757f3fSDimitry Andric } 2895f757f3fSDimitry Andric 2905f757f3fSDimitry Andric assert(S.Current); 29106c3fb27SDimitry Andric assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 2925f757f3fSDimitry Andric if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 2935f757f3fSDimitry Andric cleanupAfterFunctionCall(S, PC); 29406c3fb27SDimitry Andric 29506c3fb27SDimitry Andric if (InterpFrame *Caller = S.Current->Caller) { 29606c3fb27SDimitry Andric PC = S.Current->getRetPC(); 29706c3fb27SDimitry Andric delete S.Current; 29806c3fb27SDimitry Andric S.Current = Caller; 29906c3fb27SDimitry Andric S.Stk.push<T>(Ret); 30006c3fb27SDimitry Andric } else { 30106c3fb27SDimitry Andric delete S.Current; 30206c3fb27SDimitry Andric S.Current = nullptr; 3030fca6ea1SDimitry Andric if (!ReturnValue<T>(S, Ret, Result)) 30406c3fb27SDimitry Andric return false; 30506c3fb27SDimitry Andric } 30606c3fb27SDimitry Andric return true; 30706c3fb27SDimitry Andric } 30806c3fb27SDimitry Andric 30906c3fb27SDimitry Andric inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { 31006c3fb27SDimitry Andric assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 3115f757f3fSDimitry Andric 3125f757f3fSDimitry Andric if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 3135f757f3fSDimitry Andric cleanupAfterFunctionCall(S, PC); 31406c3fb27SDimitry Andric 31506c3fb27SDimitry Andric if (InterpFrame *Caller = S.Current->Caller) { 31606c3fb27SDimitry Andric PC = S.Current->getRetPC(); 31706c3fb27SDimitry Andric delete S.Current; 31806c3fb27SDimitry Andric S.Current = Caller; 31906c3fb27SDimitry Andric } else { 32006c3fb27SDimitry Andric delete S.Current; 32106c3fb27SDimitry Andric S.Current = nullptr; 32206c3fb27SDimitry Andric } 32306c3fb27SDimitry Andric return true; 32406c3fb27SDimitry Andric } 32506c3fb27SDimitry Andric 326a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 327a7dea167SDimitry Andric // Add, Sub, Mul 328a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 329a7dea167SDimitry Andric 330a7dea167SDimitry Andric template <typename T, bool (*OpFW)(T, T, unsigned, T *), 331a7dea167SDimitry Andric template <typename U> class OpAP> 332a7dea167SDimitry Andric bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, 333a7dea167SDimitry Andric const T &RHS) { 334a7dea167SDimitry Andric // Fast path - add the numbers with fixed width. 335a7dea167SDimitry Andric T Result; 336a7dea167SDimitry Andric if (!OpFW(LHS, RHS, Bits, &Result)) { 337a7dea167SDimitry Andric S.Stk.push<T>(Result); 338a7dea167SDimitry Andric return true; 339a7dea167SDimitry Andric } 340a7dea167SDimitry Andric 341a7dea167SDimitry Andric // If for some reason evaluation continues, use the truncated results. 342a7dea167SDimitry Andric S.Stk.push<T>(Result); 343a7dea167SDimitry Andric 344a7dea167SDimitry Andric // Slow path - compute the result using another bit of precision. 345a7dea167SDimitry Andric APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); 346a7dea167SDimitry Andric 347a7dea167SDimitry Andric // Report undefined behaviour, stopping if required. 348a7dea167SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 349a7dea167SDimitry Andric QualType Type = E->getType(); 350a7dea167SDimitry Andric if (S.checkingForUndefinedBehavior()) { 351fe6060f1SDimitry Andric SmallString<32> Trunc; 3520fca6ea1SDimitry Andric Value.trunc(Result.bitWidth()) 3530fca6ea1SDimitry Andric .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 3540fca6ea1SDimitry Andric /*UpperCase=*/true, /*InsertSeparators=*/true); 355a7dea167SDimitry Andric auto Loc = E->getExprLoc(); 3565f757f3fSDimitry Andric S.report(Loc, diag::warn_integer_constant_overflow) 3575f757f3fSDimitry Andric << Trunc << Type << E->getSourceRange(); 3580fca6ea1SDimitry Andric } 3590fca6ea1SDimitry Andric 360a7dea167SDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 3610fca6ea1SDimitry Andric 3625f757f3fSDimitry Andric if (!S.noteUndefinedBehavior()) { 3635f757f3fSDimitry Andric S.Stk.pop<T>(); 3645f757f3fSDimitry Andric return false; 3655f757f3fSDimitry Andric } 3660fca6ea1SDimitry Andric 3675f757f3fSDimitry Andric return true; 368a7dea167SDimitry Andric } 369a7dea167SDimitry Andric 370a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 371a7dea167SDimitry Andric bool Add(InterpState &S, CodePtr OpPC) { 372a7dea167SDimitry Andric const T &RHS = S.Stk.pop<T>(); 373a7dea167SDimitry Andric const T &LHS = S.Stk.pop<T>(); 374a7dea167SDimitry Andric const unsigned Bits = RHS.bitWidth() + 1; 375a7dea167SDimitry Andric return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); 376a7dea167SDimitry Andric } 377a7dea167SDimitry Andric 37806c3fb27SDimitry Andric inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 37906c3fb27SDimitry Andric const Floating &RHS = S.Stk.pop<Floating>(); 38006c3fb27SDimitry Andric const Floating &LHS = S.Stk.pop<Floating>(); 38106c3fb27SDimitry Andric 38206c3fb27SDimitry Andric Floating Result; 38306c3fb27SDimitry Andric auto Status = Floating::add(LHS, RHS, RM, &Result); 38406c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 3855f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 38606c3fb27SDimitry Andric } 38706c3fb27SDimitry Andric 388a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 389a7dea167SDimitry Andric bool Sub(InterpState &S, CodePtr OpPC) { 390a7dea167SDimitry Andric const T &RHS = S.Stk.pop<T>(); 391a7dea167SDimitry Andric const T &LHS = S.Stk.pop<T>(); 392a7dea167SDimitry Andric const unsigned Bits = RHS.bitWidth() + 1; 393a7dea167SDimitry Andric return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); 394a7dea167SDimitry Andric } 395a7dea167SDimitry Andric 39606c3fb27SDimitry Andric inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 39706c3fb27SDimitry Andric const Floating &RHS = S.Stk.pop<Floating>(); 39806c3fb27SDimitry Andric const Floating &LHS = S.Stk.pop<Floating>(); 39906c3fb27SDimitry Andric 40006c3fb27SDimitry Andric Floating Result; 40106c3fb27SDimitry Andric auto Status = Floating::sub(LHS, RHS, RM, &Result); 40206c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 4035f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 40406c3fb27SDimitry Andric } 40506c3fb27SDimitry Andric 406a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 407a7dea167SDimitry Andric bool Mul(InterpState &S, CodePtr OpPC) { 408a7dea167SDimitry Andric const T &RHS = S.Stk.pop<T>(); 409a7dea167SDimitry Andric const T &LHS = S.Stk.pop<T>(); 410a7dea167SDimitry Andric const unsigned Bits = RHS.bitWidth() * 2; 411a7dea167SDimitry Andric return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); 412a7dea167SDimitry Andric } 413a7dea167SDimitry Andric 41406c3fb27SDimitry Andric inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 41506c3fb27SDimitry Andric const Floating &RHS = S.Stk.pop<Floating>(); 41606c3fb27SDimitry Andric const Floating &LHS = S.Stk.pop<Floating>(); 41706c3fb27SDimitry Andric 41806c3fb27SDimitry Andric Floating Result; 41906c3fb27SDimitry Andric auto Status = Floating::mul(LHS, RHS, RM, &Result); 42006c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 4215f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 42206c3fb27SDimitry Andric } 4230fca6ea1SDimitry Andric 4240fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 4250fca6ea1SDimitry Andric inline bool Mulc(InterpState &S, CodePtr OpPC) { 4260fca6ea1SDimitry Andric const Pointer &RHS = S.Stk.pop<Pointer>(); 4270fca6ea1SDimitry Andric const Pointer &LHS = S.Stk.pop<Pointer>(); 4280fca6ea1SDimitry Andric const Pointer &Result = S.Stk.peek<Pointer>(); 4290fca6ea1SDimitry Andric 4300fca6ea1SDimitry Andric if constexpr (std::is_same_v<T, Floating>) { 4310fca6ea1SDimitry Andric APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); 4320fca6ea1SDimitry Andric APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); 4330fca6ea1SDimitry Andric APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); 4340fca6ea1SDimitry Andric APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); 4350fca6ea1SDimitry Andric 4360fca6ea1SDimitry Andric APFloat ResR(A.getSemantics()); 4370fca6ea1SDimitry Andric APFloat ResI(A.getSemantics()); 4380fca6ea1SDimitry Andric HandleComplexComplexMul(A, B, C, D, ResR, ResI); 4390fca6ea1SDimitry Andric 4400fca6ea1SDimitry Andric // Copy into the result. 4410fca6ea1SDimitry Andric Result.atIndex(0).deref<Floating>() = Floating(ResR); 4420fca6ea1SDimitry Andric Result.atIndex(0).initialize(); 4430fca6ea1SDimitry Andric Result.atIndex(1).deref<Floating>() = Floating(ResI); 4440fca6ea1SDimitry Andric Result.atIndex(1).initialize(); 4450fca6ea1SDimitry Andric Result.initialize(); 4460fca6ea1SDimitry Andric } else { 4470fca6ea1SDimitry Andric // Integer element type. 4480fca6ea1SDimitry Andric const T &LHSR = LHS.atIndex(0).deref<T>(); 4490fca6ea1SDimitry Andric const T &LHSI = LHS.atIndex(1).deref<T>(); 4500fca6ea1SDimitry Andric const T &RHSR = RHS.atIndex(0).deref<T>(); 4510fca6ea1SDimitry Andric const T &RHSI = RHS.atIndex(1).deref<T>(); 4520fca6ea1SDimitry Andric unsigned Bits = LHSR.bitWidth(); 4530fca6ea1SDimitry Andric 4540fca6ea1SDimitry Andric // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS)) 4550fca6ea1SDimitry Andric T A; 4560fca6ea1SDimitry Andric if (T::mul(LHSR, RHSR, Bits, &A)) 4570fca6ea1SDimitry Andric return false; 4580fca6ea1SDimitry Andric T B; 4590fca6ea1SDimitry Andric if (T::mul(LHSI, RHSI, Bits, &B)) 4600fca6ea1SDimitry Andric return false; 4610fca6ea1SDimitry Andric if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>())) 4620fca6ea1SDimitry Andric return false; 4630fca6ea1SDimitry Andric Result.atIndex(0).initialize(); 4640fca6ea1SDimitry Andric 4650fca6ea1SDimitry Andric // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS)) 4660fca6ea1SDimitry Andric if (T::mul(LHSR, RHSI, Bits, &A)) 4670fca6ea1SDimitry Andric return false; 4680fca6ea1SDimitry Andric if (T::mul(LHSI, RHSR, Bits, &B)) 4690fca6ea1SDimitry Andric return false; 4700fca6ea1SDimitry Andric if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>())) 4710fca6ea1SDimitry Andric return false; 4720fca6ea1SDimitry Andric Result.atIndex(1).initialize(); 4730fca6ea1SDimitry Andric Result.initialize(); 4740fca6ea1SDimitry Andric } 4750fca6ea1SDimitry Andric 4760fca6ea1SDimitry Andric return true; 4770fca6ea1SDimitry Andric } 4780fca6ea1SDimitry Andric 4790fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 4800fca6ea1SDimitry Andric inline bool Divc(InterpState &S, CodePtr OpPC) { 4810fca6ea1SDimitry Andric const Pointer &RHS = S.Stk.pop<Pointer>(); 4820fca6ea1SDimitry Andric const Pointer &LHS = S.Stk.pop<Pointer>(); 4830fca6ea1SDimitry Andric const Pointer &Result = S.Stk.peek<Pointer>(); 4840fca6ea1SDimitry Andric 4850fca6ea1SDimitry Andric if constexpr (std::is_same_v<T, Floating>) { 4860fca6ea1SDimitry Andric APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat(); 4870fca6ea1SDimitry Andric APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat(); 4880fca6ea1SDimitry Andric APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat(); 4890fca6ea1SDimitry Andric APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat(); 4900fca6ea1SDimitry Andric 4910fca6ea1SDimitry Andric APFloat ResR(A.getSemantics()); 4920fca6ea1SDimitry Andric APFloat ResI(A.getSemantics()); 4930fca6ea1SDimitry Andric HandleComplexComplexDiv(A, B, C, D, ResR, ResI); 4940fca6ea1SDimitry Andric 4950fca6ea1SDimitry Andric // Copy into the result. 4960fca6ea1SDimitry Andric Result.atIndex(0).deref<Floating>() = Floating(ResR); 4970fca6ea1SDimitry Andric Result.atIndex(0).initialize(); 4980fca6ea1SDimitry Andric Result.atIndex(1).deref<Floating>() = Floating(ResI); 4990fca6ea1SDimitry Andric Result.atIndex(1).initialize(); 5000fca6ea1SDimitry Andric Result.initialize(); 5010fca6ea1SDimitry Andric } else { 5020fca6ea1SDimitry Andric // Integer element type. 5030fca6ea1SDimitry Andric const T &LHSR = LHS.atIndex(0).deref<T>(); 5040fca6ea1SDimitry Andric const T &LHSI = LHS.atIndex(1).deref<T>(); 5050fca6ea1SDimitry Andric const T &RHSR = RHS.atIndex(0).deref<T>(); 5060fca6ea1SDimitry Andric const T &RHSI = RHS.atIndex(1).deref<T>(); 5070fca6ea1SDimitry Andric unsigned Bits = LHSR.bitWidth(); 5080fca6ea1SDimitry Andric const T Zero = T::from(0, Bits); 5090fca6ea1SDimitry Andric 5100fca6ea1SDimitry Andric if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal && 5110fca6ea1SDimitry Andric Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) { 5120fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 5130fca6ea1SDimitry Andric S.FFDiag(E, diag::note_expr_divide_by_zero); 5140fca6ea1SDimitry Andric return false; 5150fca6ea1SDimitry Andric } 5160fca6ea1SDimitry Andric 5170fca6ea1SDimitry Andric // Den = real(RHS)² + imag(RHS)² 5180fca6ea1SDimitry Andric T A, B; 5190fca6ea1SDimitry Andric if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) 5200fca6ea1SDimitry Andric return false; 5210fca6ea1SDimitry Andric T Den; 5220fca6ea1SDimitry Andric if (T::add(A, B, Bits, &Den)) 5230fca6ea1SDimitry Andric return false; 5240fca6ea1SDimitry Andric 5250fca6ea1SDimitry Andric // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den 5260fca6ea1SDimitry Andric T &ResultR = Result.atIndex(0).deref<T>(); 5270fca6ea1SDimitry Andric T &ResultI = Result.atIndex(1).deref<T>(); 5280fca6ea1SDimitry Andric 5290fca6ea1SDimitry Andric if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B)) 5300fca6ea1SDimitry Andric return false; 5310fca6ea1SDimitry Andric if (T::add(A, B, Bits, &ResultR)) 5320fca6ea1SDimitry Andric return false; 5330fca6ea1SDimitry Andric if (T::div(ResultR, Den, Bits, &ResultR)) 5340fca6ea1SDimitry Andric return false; 5350fca6ea1SDimitry Andric Result.atIndex(0).initialize(); 5360fca6ea1SDimitry Andric 5370fca6ea1SDimitry Andric // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den 5380fca6ea1SDimitry Andric if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B)) 5390fca6ea1SDimitry Andric return false; 5400fca6ea1SDimitry Andric if (T::sub(A, B, Bits, &ResultI)) 5410fca6ea1SDimitry Andric return false; 5420fca6ea1SDimitry Andric if (T::div(ResultI, Den, Bits, &ResultI)) 5430fca6ea1SDimitry Andric return false; 5440fca6ea1SDimitry Andric Result.atIndex(1).initialize(); 5450fca6ea1SDimitry Andric Result.initialize(); 5460fca6ea1SDimitry Andric } 5470fca6ea1SDimitry Andric 5480fca6ea1SDimitry Andric return true; 5490fca6ea1SDimitry Andric } 5500fca6ea1SDimitry Andric 551bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack. 552bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack. 553bdd1243dSDimitry Andric /// 3) Pushes 'LHS & RHS' on the stack 554bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 555bdd1243dSDimitry Andric bool BitAnd(InterpState &S, CodePtr OpPC) { 556bdd1243dSDimitry Andric const T &RHS = S.Stk.pop<T>(); 557bdd1243dSDimitry Andric const T &LHS = S.Stk.pop<T>(); 558bdd1243dSDimitry Andric 559bdd1243dSDimitry Andric unsigned Bits = RHS.bitWidth(); 560bdd1243dSDimitry Andric T Result; 561bdd1243dSDimitry Andric if (!T::bitAnd(LHS, RHS, Bits, &Result)) { 562bdd1243dSDimitry Andric S.Stk.push<T>(Result); 563bdd1243dSDimitry Andric return true; 564bdd1243dSDimitry Andric } 565bdd1243dSDimitry Andric return false; 566bdd1243dSDimitry Andric } 567bdd1243dSDimitry Andric 568bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack. 569bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack. 570bdd1243dSDimitry Andric /// 3) Pushes 'LHS | RHS' on the stack 571bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 572bdd1243dSDimitry Andric bool BitOr(InterpState &S, CodePtr OpPC) { 573bdd1243dSDimitry Andric const T &RHS = S.Stk.pop<T>(); 574bdd1243dSDimitry Andric const T &LHS = S.Stk.pop<T>(); 575bdd1243dSDimitry Andric 576bdd1243dSDimitry Andric unsigned Bits = RHS.bitWidth(); 577bdd1243dSDimitry Andric T Result; 578bdd1243dSDimitry Andric if (!T::bitOr(LHS, RHS, Bits, &Result)) { 579bdd1243dSDimitry Andric S.Stk.push<T>(Result); 580bdd1243dSDimitry Andric return true; 581bdd1243dSDimitry Andric } 582bdd1243dSDimitry Andric return false; 583bdd1243dSDimitry Andric } 584bdd1243dSDimitry Andric 585bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack. 586bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack. 587bdd1243dSDimitry Andric /// 3) Pushes 'LHS ^ RHS' on the stack 588bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 589bdd1243dSDimitry Andric bool BitXor(InterpState &S, CodePtr OpPC) { 590bdd1243dSDimitry Andric const T &RHS = S.Stk.pop<T>(); 591bdd1243dSDimitry Andric const T &LHS = S.Stk.pop<T>(); 592bdd1243dSDimitry Andric 593bdd1243dSDimitry Andric unsigned Bits = RHS.bitWidth(); 594bdd1243dSDimitry Andric T Result; 595bdd1243dSDimitry Andric if (!T::bitXor(LHS, RHS, Bits, &Result)) { 596bdd1243dSDimitry Andric S.Stk.push<T>(Result); 597bdd1243dSDimitry Andric return true; 598bdd1243dSDimitry Andric } 599bdd1243dSDimitry Andric return false; 600bdd1243dSDimitry Andric } 601bdd1243dSDimitry Andric 602bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack. 603bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack. 604bdd1243dSDimitry Andric /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS). 605bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 606bdd1243dSDimitry Andric bool Rem(InterpState &S, CodePtr OpPC) { 607bdd1243dSDimitry Andric const T &RHS = S.Stk.pop<T>(); 608bdd1243dSDimitry Andric const T &LHS = S.Stk.pop<T>(); 609bdd1243dSDimitry Andric 610bdd1243dSDimitry Andric if (!CheckDivRem(S, OpPC, LHS, RHS)) 611bdd1243dSDimitry Andric return false; 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric const unsigned Bits = RHS.bitWidth() * 2; 614bdd1243dSDimitry Andric T Result; 615bdd1243dSDimitry Andric if (!T::rem(LHS, RHS, Bits, &Result)) { 616bdd1243dSDimitry Andric S.Stk.push<T>(Result); 617bdd1243dSDimitry Andric return true; 618bdd1243dSDimitry Andric } 619bdd1243dSDimitry Andric return false; 620bdd1243dSDimitry Andric } 621bdd1243dSDimitry Andric 622bdd1243dSDimitry Andric /// 1) Pops the RHS from the stack. 623bdd1243dSDimitry Andric /// 2) Pops the LHS from the stack. 624bdd1243dSDimitry Andric /// 3) Pushes 'LHS / RHS' on the stack 625bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 626bdd1243dSDimitry Andric bool Div(InterpState &S, CodePtr OpPC) { 627bdd1243dSDimitry Andric const T &RHS = S.Stk.pop<T>(); 628bdd1243dSDimitry Andric const T &LHS = S.Stk.pop<T>(); 629bdd1243dSDimitry Andric 630bdd1243dSDimitry Andric if (!CheckDivRem(S, OpPC, LHS, RHS)) 631bdd1243dSDimitry Andric return false; 632bdd1243dSDimitry Andric 633bdd1243dSDimitry Andric const unsigned Bits = RHS.bitWidth() * 2; 634bdd1243dSDimitry Andric T Result; 635bdd1243dSDimitry Andric if (!T::div(LHS, RHS, Bits, &Result)) { 636bdd1243dSDimitry Andric S.Stk.push<T>(Result); 637bdd1243dSDimitry Andric return true; 638bdd1243dSDimitry Andric } 639bdd1243dSDimitry Andric return false; 640bdd1243dSDimitry Andric } 641bdd1243dSDimitry Andric 64206c3fb27SDimitry Andric inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 64306c3fb27SDimitry Andric const Floating &RHS = S.Stk.pop<Floating>(); 64406c3fb27SDimitry Andric const Floating &LHS = S.Stk.pop<Floating>(); 64506c3fb27SDimitry Andric 64606c3fb27SDimitry Andric if (!CheckDivRem(S, OpPC, LHS, RHS)) 64706c3fb27SDimitry Andric return false; 64806c3fb27SDimitry Andric 64906c3fb27SDimitry Andric Floating Result; 65006c3fb27SDimitry Andric auto Status = Floating::div(LHS, RHS, RM, &Result); 65106c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 6525f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 65306c3fb27SDimitry Andric } 65406c3fb27SDimitry Andric 655bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 656bdd1243dSDimitry Andric // Inv 657bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 658bdd1243dSDimitry Andric 659bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 660bdd1243dSDimitry Andric bool Inv(InterpState &S, CodePtr OpPC) { 661bdd1243dSDimitry Andric using BoolT = PrimConv<PT_Bool>::T; 662bdd1243dSDimitry Andric const T &Val = S.Stk.pop<T>(); 663bdd1243dSDimitry Andric const unsigned Bits = Val.bitWidth(); 664bdd1243dSDimitry Andric Boolean R; 665bdd1243dSDimitry Andric Boolean::inv(BoolT::from(Val, Bits), &R); 666bdd1243dSDimitry Andric 667bdd1243dSDimitry Andric S.Stk.push<BoolT>(R); 668bdd1243dSDimitry Andric return true; 669bdd1243dSDimitry Andric } 670bdd1243dSDimitry Andric 671bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 672bdd1243dSDimitry Andric // Neg 673bdd1243dSDimitry Andric //===----------------------------------------------------------------------===// 674bdd1243dSDimitry Andric 675bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 676bdd1243dSDimitry Andric bool Neg(InterpState &S, CodePtr OpPC) { 67706c3fb27SDimitry Andric const T &Value = S.Stk.pop<T>(); 678bdd1243dSDimitry Andric T Result; 679bdd1243dSDimitry Andric 68006c3fb27SDimitry Andric if (!T::neg(Value, &Result)) { 681bdd1243dSDimitry Andric S.Stk.push<T>(Result); 682bdd1243dSDimitry Andric return true; 683bdd1243dSDimitry Andric } 684bdd1243dSDimitry Andric 68506c3fb27SDimitry Andric assert(isIntegralType(Name) && 68606c3fb27SDimitry Andric "don't expect other types to fail at constexpr negation"); 68706c3fb27SDimitry Andric S.Stk.push<T>(Result); 68806c3fb27SDimitry Andric 68906c3fb27SDimitry Andric APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); 69006c3fb27SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 69106c3fb27SDimitry Andric QualType Type = E->getType(); 69206c3fb27SDimitry Andric 69306c3fb27SDimitry Andric if (S.checkingForUndefinedBehavior()) { 69406c3fb27SDimitry Andric SmallString<32> Trunc; 6950fca6ea1SDimitry Andric NegatedValue.trunc(Result.bitWidth()) 6960fca6ea1SDimitry Andric .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 6970fca6ea1SDimitry Andric /*UpperCase=*/true, /*InsertSeparators=*/true); 69806c3fb27SDimitry Andric auto Loc = E->getExprLoc(); 6995f757f3fSDimitry Andric S.report(Loc, diag::warn_integer_constant_overflow) 7005f757f3fSDimitry Andric << Trunc << Type << E->getSourceRange(); 70106c3fb27SDimitry Andric return true; 70206c3fb27SDimitry Andric } 70306c3fb27SDimitry Andric 70406c3fb27SDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type; 70506c3fb27SDimitry Andric return S.noteUndefinedBehavior(); 70606c3fb27SDimitry Andric } 70706c3fb27SDimitry Andric 708bdd1243dSDimitry Andric enum class PushVal : bool { 709bdd1243dSDimitry Andric No, 710bdd1243dSDimitry Andric Yes, 711bdd1243dSDimitry Andric }; 712bdd1243dSDimitry Andric enum class IncDecOp { 713bdd1243dSDimitry Andric Inc, 714bdd1243dSDimitry Andric Dec, 715bdd1243dSDimitry Andric }; 716bdd1243dSDimitry Andric 717bdd1243dSDimitry Andric template <typename T, IncDecOp Op, PushVal DoPush> 718bdd1243dSDimitry Andric bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 7190fca6ea1SDimitry Andric assert(!Ptr.isDummy()); 7200fca6ea1SDimitry Andric 7210fca6ea1SDimitry Andric if constexpr (std::is_same_v<T, Boolean>) { 7220fca6ea1SDimitry Andric if (!S.getLangOpts().CPlusPlus14) 7230fca6ea1SDimitry Andric return Invalid(S, OpPC); 7240fca6ea1SDimitry Andric } 7250fca6ea1SDimitry Andric 7265f757f3fSDimitry Andric const T &Value = Ptr.deref<T>(); 727bdd1243dSDimitry Andric T Result; 728bdd1243dSDimitry Andric 729bdd1243dSDimitry Andric if constexpr (DoPush == PushVal::Yes) 73006c3fb27SDimitry Andric S.Stk.push<T>(Value); 731bdd1243dSDimitry Andric 732bdd1243dSDimitry Andric if constexpr (Op == IncDecOp::Inc) { 733bdd1243dSDimitry Andric if (!T::increment(Value, &Result)) { 734bdd1243dSDimitry Andric Ptr.deref<T>() = Result; 735bdd1243dSDimitry Andric return true; 736bdd1243dSDimitry Andric } 737bdd1243dSDimitry Andric } else { 738bdd1243dSDimitry Andric if (!T::decrement(Value, &Result)) { 739bdd1243dSDimitry Andric Ptr.deref<T>() = Result; 740bdd1243dSDimitry Andric return true; 741bdd1243dSDimitry Andric } 742bdd1243dSDimitry Andric } 743bdd1243dSDimitry Andric 744bdd1243dSDimitry Andric // Something went wrong with the previous operation. Compute the 745bdd1243dSDimitry Andric // result with another bit of precision. 746bdd1243dSDimitry Andric unsigned Bits = Value.bitWidth() + 1; 747bdd1243dSDimitry Andric APSInt APResult; 748bdd1243dSDimitry Andric if constexpr (Op == IncDecOp::Inc) 749bdd1243dSDimitry Andric APResult = ++Value.toAPSInt(Bits); 750bdd1243dSDimitry Andric else 751bdd1243dSDimitry Andric APResult = --Value.toAPSInt(Bits); 752bdd1243dSDimitry Andric 753bdd1243dSDimitry Andric // Report undefined behaviour, stopping if required. 754bdd1243dSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 755bdd1243dSDimitry Andric QualType Type = E->getType(); 756bdd1243dSDimitry Andric if (S.checkingForUndefinedBehavior()) { 757bdd1243dSDimitry Andric SmallString<32> Trunc; 7580fca6ea1SDimitry Andric APResult.trunc(Result.bitWidth()) 7590fca6ea1SDimitry Andric .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false, 7600fca6ea1SDimitry Andric /*UpperCase=*/true, /*InsertSeparators=*/true); 761bdd1243dSDimitry Andric auto Loc = E->getExprLoc(); 7625f757f3fSDimitry Andric S.report(Loc, diag::warn_integer_constant_overflow) 7635f757f3fSDimitry Andric << Trunc << Type << E->getSourceRange(); 764bdd1243dSDimitry Andric return true; 765bdd1243dSDimitry Andric } 766bdd1243dSDimitry Andric 767bdd1243dSDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type; 768bdd1243dSDimitry Andric return S.noteUndefinedBehavior(); 769bdd1243dSDimitry Andric } 770bdd1243dSDimitry Andric 771bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack 772bdd1243dSDimitry Andric /// 2) Load the value from the pointer 773bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer 774bdd1243dSDimitry Andric /// 4) Pushes the original (pre-inc) value on the stack. 775bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 776bdd1243dSDimitry Andric bool Inc(InterpState &S, CodePtr OpPC) { 777bdd1243dSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 7780fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 77906c3fb27SDimitry Andric return false; 78006c3fb27SDimitry Andric 781bdd1243dSDimitry Andric return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr); 782bdd1243dSDimitry Andric } 783bdd1243dSDimitry Andric 784bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack 785bdd1243dSDimitry Andric /// 2) Load the value from the pointer 786bdd1243dSDimitry Andric /// 3) Writes the value increased by one back to the pointer 787bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 788bdd1243dSDimitry Andric bool IncPop(InterpState &S, CodePtr OpPC) { 789bdd1243dSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 7900fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 79106c3fb27SDimitry Andric return false; 79206c3fb27SDimitry Andric 793bdd1243dSDimitry Andric return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr); 794bdd1243dSDimitry Andric } 795bdd1243dSDimitry Andric 796bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack 797bdd1243dSDimitry Andric /// 2) Load the value from the pointer 798bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer 799bdd1243dSDimitry Andric /// 4) Pushes the original (pre-dec) value on the stack. 800bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 801bdd1243dSDimitry Andric bool Dec(InterpState &S, CodePtr OpPC) { 802bdd1243dSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8030fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 80406c3fb27SDimitry Andric return false; 80506c3fb27SDimitry Andric 806bdd1243dSDimitry Andric return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr); 807bdd1243dSDimitry Andric } 808bdd1243dSDimitry Andric 809bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack 810bdd1243dSDimitry Andric /// 2) Load the value from the pointer 811bdd1243dSDimitry Andric /// 3) Writes the value decreased by one back to the pointer 812bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 813bdd1243dSDimitry Andric bool DecPop(InterpState &S, CodePtr OpPC) { 814bdd1243dSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8150fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 81606c3fb27SDimitry Andric return false; 81706c3fb27SDimitry Andric 818bdd1243dSDimitry Andric return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr); 819bdd1243dSDimitry Andric } 820bdd1243dSDimitry Andric 82106c3fb27SDimitry Andric template <IncDecOp Op, PushVal DoPush> 82206c3fb27SDimitry Andric bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 82306c3fb27SDimitry Andric llvm::RoundingMode RM) { 82406c3fb27SDimitry Andric Floating Value = Ptr.deref<Floating>(); 82506c3fb27SDimitry Andric Floating Result; 82606c3fb27SDimitry Andric 82706c3fb27SDimitry Andric if constexpr (DoPush == PushVal::Yes) 82806c3fb27SDimitry Andric S.Stk.push<Floating>(Value); 82906c3fb27SDimitry Andric 83006c3fb27SDimitry Andric llvm::APFloat::opStatus Status; 83106c3fb27SDimitry Andric if constexpr (Op == IncDecOp::Inc) 83206c3fb27SDimitry Andric Status = Floating::increment(Value, RM, &Result); 83306c3fb27SDimitry Andric else 83406c3fb27SDimitry Andric Status = Floating::decrement(Value, RM, &Result); 83506c3fb27SDimitry Andric 83606c3fb27SDimitry Andric Ptr.deref<Floating>() = Result; 83706c3fb27SDimitry Andric 8385f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 83906c3fb27SDimitry Andric } 84006c3fb27SDimitry Andric 84106c3fb27SDimitry Andric inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 84206c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8430fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 84406c3fb27SDimitry Andric return false; 84506c3fb27SDimitry Andric 84606c3fb27SDimitry Andric return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM); 84706c3fb27SDimitry Andric } 84806c3fb27SDimitry Andric 84906c3fb27SDimitry Andric inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 85006c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8510fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Increment)) 85206c3fb27SDimitry Andric return false; 85306c3fb27SDimitry Andric 85406c3fb27SDimitry Andric return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM); 85506c3fb27SDimitry Andric } 85606c3fb27SDimitry Andric 85706c3fb27SDimitry Andric inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 85806c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8590fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 86006c3fb27SDimitry Andric return false; 86106c3fb27SDimitry Andric 86206c3fb27SDimitry Andric return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM); 86306c3fb27SDimitry Andric } 86406c3fb27SDimitry Andric 86506c3fb27SDimitry Andric inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 86606c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 8670fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr, AK_Decrement)) 86806c3fb27SDimitry Andric return false; 86906c3fb27SDimitry Andric 87006c3fb27SDimitry Andric return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM); 87106c3fb27SDimitry Andric } 87206c3fb27SDimitry Andric 873bdd1243dSDimitry Andric /// 1) Pops the value from the stack. 874bdd1243dSDimitry Andric /// 2) Pushes the bitwise complemented value on the stack (~V). 875bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 876bdd1243dSDimitry Andric bool Comp(InterpState &S, CodePtr OpPC) { 877bdd1243dSDimitry Andric const T &Val = S.Stk.pop<T>(); 878bdd1243dSDimitry Andric T Result; 879bdd1243dSDimitry Andric if (!T::comp(Val, &Result)) { 880bdd1243dSDimitry Andric S.Stk.push<T>(Result); 881bdd1243dSDimitry Andric return true; 882bdd1243dSDimitry Andric } 883bdd1243dSDimitry Andric 884bdd1243dSDimitry Andric return false; 885bdd1243dSDimitry Andric } 886bdd1243dSDimitry Andric 887a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 888a7dea167SDimitry Andric // EQ, NE, GT, GE, LT, LE 889a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 890a7dea167SDimitry Andric 891a7dea167SDimitry Andric using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; 892a7dea167SDimitry Andric 893a7dea167SDimitry Andric template <typename T> 894a7dea167SDimitry Andric bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { 8950fca6ea1SDimitry Andric assert((!std::is_same_v<T, MemberPointer>) && 8960fca6ea1SDimitry Andric "Non-equality comparisons on member pointer types should already be " 8970fca6ea1SDimitry Andric "rejected in Sema."); 898a7dea167SDimitry Andric using BoolT = PrimConv<PT_Bool>::T; 899a7dea167SDimitry Andric const T &RHS = S.Stk.pop<T>(); 900a7dea167SDimitry Andric const T &LHS = S.Stk.pop<T>(); 901a7dea167SDimitry Andric S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); 902a7dea167SDimitry Andric return true; 903a7dea167SDimitry Andric } 904a7dea167SDimitry Andric 905a7dea167SDimitry Andric template <typename T> 906a7dea167SDimitry Andric bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { 907a7dea167SDimitry Andric return CmpHelper<T>(S, OpPC, Fn); 908a7dea167SDimitry Andric } 909a7dea167SDimitry Andric 91006c3fb27SDimitry Andric /// Function pointers cannot be compared in an ordered way. 91106c3fb27SDimitry Andric template <> 91206c3fb27SDimitry Andric inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC, 91306c3fb27SDimitry Andric CompareFn Fn) { 91406c3fb27SDimitry Andric const auto &RHS = S.Stk.pop<FunctionPointer>(); 91506c3fb27SDimitry Andric const auto &LHS = S.Stk.pop<FunctionPointer>(); 91606c3fb27SDimitry Andric 91706c3fb27SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 91806c3fb27SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 91906c3fb27SDimitry Andric << LHS.toDiagnosticString(S.getCtx()) 92006c3fb27SDimitry Andric << RHS.toDiagnosticString(S.getCtx()); 92106c3fb27SDimitry Andric return false; 92206c3fb27SDimitry Andric } 92306c3fb27SDimitry Andric 92406c3fb27SDimitry Andric template <> 92506c3fb27SDimitry Andric inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC, 92606c3fb27SDimitry Andric CompareFn Fn) { 92706c3fb27SDimitry Andric const auto &RHS = S.Stk.pop<FunctionPointer>(); 92806c3fb27SDimitry Andric const auto &LHS = S.Stk.pop<FunctionPointer>(); 9290fca6ea1SDimitry Andric 9300fca6ea1SDimitry Andric // We cannot compare against weak declarations at compile time. 9310fca6ea1SDimitry Andric for (const auto &FP : {LHS, RHS}) { 9320fca6ea1SDimitry Andric if (FP.isWeak()) { 9330fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 9340fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) 9350fca6ea1SDimitry Andric << FP.toDiagnosticString(S.getCtx()); 9360fca6ea1SDimitry Andric return false; 9370fca6ea1SDimitry Andric } 9380fca6ea1SDimitry Andric } 9390fca6ea1SDimitry Andric 94006c3fb27SDimitry Andric S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); 94106c3fb27SDimitry Andric return true; 94206c3fb27SDimitry Andric } 94306c3fb27SDimitry Andric 944a7dea167SDimitry Andric template <> 945a7dea167SDimitry Andric inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 946a7dea167SDimitry Andric using BoolT = PrimConv<PT_Bool>::T; 947a7dea167SDimitry Andric const Pointer &RHS = S.Stk.pop<Pointer>(); 948a7dea167SDimitry Andric const Pointer &LHS = S.Stk.pop<Pointer>(); 949a7dea167SDimitry Andric 950a7dea167SDimitry Andric if (!Pointer::hasSameBase(LHS, RHS)) { 951a7dea167SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 9525f757f3fSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 9535f757f3fSDimitry Andric << LHS.toDiagnosticString(S.getCtx()) 9545f757f3fSDimitry Andric << RHS.toDiagnosticString(S.getCtx()); 955a7dea167SDimitry Andric return false; 956a7dea167SDimitry Andric } else { 957a7dea167SDimitry Andric unsigned VL = LHS.getByteOffset(); 958a7dea167SDimitry Andric unsigned VR = RHS.getByteOffset(); 959a7dea167SDimitry Andric S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 960a7dea167SDimitry Andric return true; 961a7dea167SDimitry Andric } 962a7dea167SDimitry Andric } 963a7dea167SDimitry Andric 964a7dea167SDimitry Andric template <> 965a7dea167SDimitry Andric inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 966a7dea167SDimitry Andric using BoolT = PrimConv<PT_Bool>::T; 967a7dea167SDimitry Andric const Pointer &RHS = S.Stk.pop<Pointer>(); 968a7dea167SDimitry Andric const Pointer &LHS = S.Stk.pop<Pointer>(); 969a7dea167SDimitry Andric 970480093f4SDimitry Andric if (LHS.isZero() && RHS.isZero()) { 971a7dea167SDimitry Andric S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); 972a7dea167SDimitry Andric return true; 973a7dea167SDimitry Andric } 974a7dea167SDimitry Andric 9750fca6ea1SDimitry Andric // Reject comparisons to weak pointers. 9760fca6ea1SDimitry Andric for (const auto &P : {LHS, RHS}) { 9770fca6ea1SDimitry Andric if (P.isZero()) 9780fca6ea1SDimitry Andric continue; 9790fca6ea1SDimitry Andric if (P.isWeak()) { 9800fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 9810fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison) 9820fca6ea1SDimitry Andric << P.toDiagnosticString(S.getCtx()); 9830fca6ea1SDimitry Andric return false; 9840fca6ea1SDimitry Andric } 9850fca6ea1SDimitry Andric } 9860fca6ea1SDimitry Andric 987a7dea167SDimitry Andric if (!Pointer::hasSameBase(LHS, RHS)) { 9880fca6ea1SDimitry Andric if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() && 9890fca6ea1SDimitry Andric RHS.getOffset() == 0) { 9900fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 9910fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) 9920fca6ea1SDimitry Andric << LHS.toDiagnosticString(S.getCtx()); 9930fca6ea1SDimitry Andric return false; 9940fca6ea1SDimitry Andric } else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() && 9950fca6ea1SDimitry Andric LHS.getOffset() == 0) { 9960fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 9970fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end) 9980fca6ea1SDimitry Andric << RHS.toDiagnosticString(S.getCtx()); 9990fca6ea1SDimitry Andric return false; 10000fca6ea1SDimitry Andric } 10010fca6ea1SDimitry Andric 1002a7dea167SDimitry Andric S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); 1003a7dea167SDimitry Andric return true; 1004a7dea167SDimitry Andric } else { 1005a7dea167SDimitry Andric unsigned VL = LHS.getByteOffset(); 1006a7dea167SDimitry Andric unsigned VR = RHS.getByteOffset(); 1007bdd1243dSDimitry Andric 1008bdd1243dSDimitry Andric // In our Pointer class, a pointer to an array and a pointer to the first 1009bdd1243dSDimitry Andric // element in the same array are NOT equal. They have the same Base value, 1010bdd1243dSDimitry Andric // but a different Offset. This is a pretty rare case, so we fix this here 1011bdd1243dSDimitry Andric // by comparing pointers to the first elements. 10120fca6ea1SDimitry Andric if (!LHS.isZero() && LHS.isArrayRoot()) 1013bdd1243dSDimitry Andric VL = LHS.atIndex(0).getByteOffset(); 10140fca6ea1SDimitry Andric if (!RHS.isZero() && RHS.isArrayRoot()) 1015bdd1243dSDimitry Andric VR = RHS.atIndex(0).getByteOffset(); 1016bdd1243dSDimitry Andric 1017a7dea167SDimitry Andric S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 1018a7dea167SDimitry Andric return true; 1019a7dea167SDimitry Andric } 1020a7dea167SDimitry Andric } 1021a7dea167SDimitry Andric 10220fca6ea1SDimitry Andric template <> 10230fca6ea1SDimitry Andric inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC, 10240fca6ea1SDimitry Andric CompareFn Fn) { 10250fca6ea1SDimitry Andric const auto &RHS = S.Stk.pop<MemberPointer>(); 10260fca6ea1SDimitry Andric const auto &LHS = S.Stk.pop<MemberPointer>(); 10270fca6ea1SDimitry Andric 10280fca6ea1SDimitry Andric // If either operand is a pointer to a weak function, the comparison is not 10290fca6ea1SDimitry Andric // constant. 10300fca6ea1SDimitry Andric for (const auto &MP : {LHS, RHS}) { 10310fca6ea1SDimitry Andric if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) { 10320fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 10330fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD; 10340fca6ea1SDimitry Andric return false; 10350fca6ea1SDimitry Andric } 10360fca6ea1SDimitry Andric } 10370fca6ea1SDimitry Andric 10380fca6ea1SDimitry Andric // C++11 [expr.eq]p2: 10390fca6ea1SDimitry Andric // If both operands are null, they compare equal. Otherwise if only one is 10400fca6ea1SDimitry Andric // null, they compare unequal. 10410fca6ea1SDimitry Andric if (LHS.isZero() && RHS.isZero()) { 10420fca6ea1SDimitry Andric S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal)); 10430fca6ea1SDimitry Andric return true; 10440fca6ea1SDimitry Andric } 10450fca6ea1SDimitry Andric if (LHS.isZero() || RHS.isZero()) { 10460fca6ea1SDimitry Andric S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered)); 10470fca6ea1SDimitry Andric return true; 10480fca6ea1SDimitry Andric } 10490fca6ea1SDimitry Andric 10500fca6ea1SDimitry Andric // We cannot compare against virtual declarations at compile time. 10510fca6ea1SDimitry Andric for (const auto &MP : {LHS, RHS}) { 10520fca6ea1SDimitry Andric if (const CXXMethodDecl *MD = MP.getMemberFunction(); 10530fca6ea1SDimitry Andric MD && MD->isVirtual()) { 10540fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 10550fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD; 10560fca6ea1SDimitry Andric } 10570fca6ea1SDimitry Andric } 10580fca6ea1SDimitry Andric 10590fca6ea1SDimitry Andric S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); 10600fca6ea1SDimitry Andric return true; 10610fca6ea1SDimitry Andric } 10620fca6ea1SDimitry Andric 1063a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1064a7dea167SDimitry Andric bool EQ(InterpState &S, CodePtr OpPC) { 1065a7dea167SDimitry Andric return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 1066a7dea167SDimitry Andric return R == ComparisonCategoryResult::Equal; 1067a7dea167SDimitry Andric }); 1068a7dea167SDimitry Andric } 1069a7dea167SDimitry Andric 1070a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 10715f757f3fSDimitry Andric bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) { 10725f757f3fSDimitry Andric const T &RHS = S.Stk.pop<T>(); 10735f757f3fSDimitry Andric const T &LHS = S.Stk.pop<T>(); 10745f757f3fSDimitry Andric const Pointer &P = S.Stk.peek<Pointer>(); 10755f757f3fSDimitry Andric 10765f757f3fSDimitry Andric ComparisonCategoryResult CmpResult = LHS.compare(RHS); 10775f757f3fSDimitry Andric if (CmpResult == ComparisonCategoryResult::Unordered) { 10785f757f3fSDimitry Andric // This should only happen with pointers. 10795f757f3fSDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 10805f757f3fSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 10815f757f3fSDimitry Andric << LHS.toDiagnosticString(S.getCtx()) 10825f757f3fSDimitry Andric << RHS.toDiagnosticString(S.getCtx()); 10835f757f3fSDimitry Andric return false; 10845f757f3fSDimitry Andric } 10855f757f3fSDimitry Andric 10865f757f3fSDimitry Andric assert(CmpInfo); 10870fca6ea1SDimitry Andric const auto *CmpValueInfo = 10880fca6ea1SDimitry Andric CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult)); 10895f757f3fSDimitry Andric assert(CmpValueInfo); 10905f757f3fSDimitry Andric assert(CmpValueInfo->hasValidIntValue()); 10910fca6ea1SDimitry Andric return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue()); 10925f757f3fSDimitry Andric } 10935f757f3fSDimitry Andric 10945f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1095a7dea167SDimitry Andric bool NE(InterpState &S, CodePtr OpPC) { 1096a7dea167SDimitry Andric return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 1097a7dea167SDimitry Andric return R != ComparisonCategoryResult::Equal; 1098a7dea167SDimitry Andric }); 1099a7dea167SDimitry Andric } 1100a7dea167SDimitry Andric 1101a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1102a7dea167SDimitry Andric bool LT(InterpState &S, CodePtr OpPC) { 1103a7dea167SDimitry Andric return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1104a7dea167SDimitry Andric return R == ComparisonCategoryResult::Less; 1105a7dea167SDimitry Andric }); 1106a7dea167SDimitry Andric } 1107a7dea167SDimitry Andric 1108a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1109a7dea167SDimitry Andric bool LE(InterpState &S, CodePtr OpPC) { 1110a7dea167SDimitry Andric return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1111a7dea167SDimitry Andric return R == ComparisonCategoryResult::Less || 1112a7dea167SDimitry Andric R == ComparisonCategoryResult::Equal; 1113a7dea167SDimitry Andric }); 1114a7dea167SDimitry Andric } 1115a7dea167SDimitry Andric 1116a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1117a7dea167SDimitry Andric bool GT(InterpState &S, CodePtr OpPC) { 1118a7dea167SDimitry Andric return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1119a7dea167SDimitry Andric return R == ComparisonCategoryResult::Greater; 1120a7dea167SDimitry Andric }); 1121a7dea167SDimitry Andric } 1122a7dea167SDimitry Andric 1123a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1124a7dea167SDimitry Andric bool GE(InterpState &S, CodePtr OpPC) { 1125a7dea167SDimitry Andric return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 1126a7dea167SDimitry Andric return R == ComparisonCategoryResult::Greater || 1127a7dea167SDimitry Andric R == ComparisonCategoryResult::Equal; 1128a7dea167SDimitry Andric }); 1129a7dea167SDimitry Andric } 1130a7dea167SDimitry Andric 1131a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1132a7dea167SDimitry Andric // InRange 1133a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1134a7dea167SDimitry Andric 1135a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1136a7dea167SDimitry Andric bool InRange(InterpState &S, CodePtr OpPC) { 1137a7dea167SDimitry Andric const T RHS = S.Stk.pop<T>(); 1138a7dea167SDimitry Andric const T LHS = S.Stk.pop<T>(); 1139a7dea167SDimitry Andric const T Value = S.Stk.pop<T>(); 1140a7dea167SDimitry Andric 1141a7dea167SDimitry Andric S.Stk.push<bool>(LHS <= Value && Value <= RHS); 1142a7dea167SDimitry Andric return true; 1143a7dea167SDimitry Andric } 1144a7dea167SDimitry Andric 1145a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1146a7dea167SDimitry Andric // Dup, Pop, Test 1147a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1148a7dea167SDimitry Andric 1149a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1150a7dea167SDimitry Andric bool Dup(InterpState &S, CodePtr OpPC) { 1151a7dea167SDimitry Andric S.Stk.push<T>(S.Stk.peek<T>()); 1152a7dea167SDimitry Andric return true; 1153a7dea167SDimitry Andric } 1154a7dea167SDimitry Andric 1155a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1156a7dea167SDimitry Andric bool Pop(InterpState &S, CodePtr OpPC) { 1157a7dea167SDimitry Andric S.Stk.pop<T>(); 1158a7dea167SDimitry Andric return true; 1159a7dea167SDimitry Andric } 1160a7dea167SDimitry Andric 1161a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1162a7dea167SDimitry Andric // Const 1163a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1164a7dea167SDimitry Andric 1165a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1166a7dea167SDimitry Andric bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { 1167a7dea167SDimitry Andric S.Stk.push<T>(Arg); 1168a7dea167SDimitry Andric return true; 1169a7dea167SDimitry Andric } 1170a7dea167SDimitry Andric 1171a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1172a7dea167SDimitry Andric // Get/Set Local/Param/Global/This 1173a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1174a7dea167SDimitry Andric 1175a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1176a7dea167SDimitry Andric bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1177bdd1243dSDimitry Andric const Pointer &Ptr = S.Current->getLocalPointer(I); 1178bdd1243dSDimitry Andric if (!CheckLoad(S, OpPC, Ptr)) 1179bdd1243dSDimitry Andric return false; 1180bdd1243dSDimitry Andric S.Stk.push<T>(Ptr.deref<T>()); 1181a7dea167SDimitry Andric return true; 1182a7dea167SDimitry Andric } 1183a7dea167SDimitry Andric 118406c3fb27SDimitry Andric /// 1) Pops the value from the stack. 118506c3fb27SDimitry Andric /// 2) Writes the value to the local variable with the 118606c3fb27SDimitry Andric /// given offset. 1187a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1188a7dea167SDimitry Andric bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1189a7dea167SDimitry Andric S.Current->setLocal<T>(I, S.Stk.pop<T>()); 1190a7dea167SDimitry Andric return true; 1191a7dea167SDimitry Andric } 1192a7dea167SDimitry Andric 1193a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1194a7dea167SDimitry Andric bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1195a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) { 1196a7dea167SDimitry Andric return false; 1197a7dea167SDimitry Andric } 1198a7dea167SDimitry Andric S.Stk.push<T>(S.Current->getParam<T>(I)); 1199a7dea167SDimitry Andric return true; 1200a7dea167SDimitry Andric } 1201a7dea167SDimitry Andric 1202a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1203a7dea167SDimitry Andric bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1204a7dea167SDimitry Andric S.Current->setParam<T>(I, S.Stk.pop<T>()); 1205a7dea167SDimitry Andric return true; 1206a7dea167SDimitry Andric } 1207a7dea167SDimitry Andric 1208bdd1243dSDimitry Andric /// 1) Peeks a pointer on the stack 1209bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack 1210a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1211a7dea167SDimitry Andric bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { 1212a7dea167SDimitry Andric const Pointer &Obj = S.Stk.peek<Pointer>(); 1213a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1214a7dea167SDimitry Andric return false; 1215a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1216a7dea167SDimitry Andric return false; 1217a7dea167SDimitry Andric const Pointer &Field = Obj.atField(I); 1218a7dea167SDimitry Andric if (!CheckLoad(S, OpPC, Field)) 1219a7dea167SDimitry Andric return false; 1220a7dea167SDimitry Andric S.Stk.push<T>(Field.deref<T>()); 1221a7dea167SDimitry Andric return true; 1222a7dea167SDimitry Andric } 1223a7dea167SDimitry Andric 1224a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1225a7dea167SDimitry Andric bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { 1226a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1227a7dea167SDimitry Andric const Pointer &Obj = S.Stk.peek<Pointer>(); 1228a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1229a7dea167SDimitry Andric return false; 1230a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1231a7dea167SDimitry Andric return false; 1232a7dea167SDimitry Andric const Pointer &Field = Obj.atField(I); 1233a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Field)) 1234a7dea167SDimitry Andric return false; 123506c3fb27SDimitry Andric Field.initialize(); 1236a7dea167SDimitry Andric Field.deref<T>() = Value; 1237a7dea167SDimitry Andric return true; 1238a7dea167SDimitry Andric } 1239a7dea167SDimitry Andric 1240bdd1243dSDimitry Andric /// 1) Pops a pointer from the stack 1241bdd1243dSDimitry Andric /// 2) Pushes the value of the pointer's field on the stack 1242a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1243a7dea167SDimitry Andric bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { 1244a7dea167SDimitry Andric const Pointer &Obj = S.Stk.pop<Pointer>(); 1245a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Obj, CSK_Field)) 1246a7dea167SDimitry Andric return false; 1247a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Obj, CSK_Field)) 1248a7dea167SDimitry Andric return false; 1249a7dea167SDimitry Andric const Pointer &Field = Obj.atField(I); 1250a7dea167SDimitry Andric if (!CheckLoad(S, OpPC, Field)) 1251a7dea167SDimitry Andric return false; 1252a7dea167SDimitry Andric S.Stk.push<T>(Field.deref<T>()); 1253a7dea167SDimitry Andric return true; 1254a7dea167SDimitry Andric } 1255a7dea167SDimitry Andric 1256a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1257a7dea167SDimitry Andric bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1258a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1259a7dea167SDimitry Andric return false; 1260a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1261a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1262a7dea167SDimitry Andric return false; 1263a7dea167SDimitry Andric const Pointer &Field = This.atField(I); 1264a7dea167SDimitry Andric if (!CheckLoad(S, OpPC, Field)) 1265a7dea167SDimitry Andric return false; 1266a7dea167SDimitry Andric S.Stk.push<T>(Field.deref<T>()); 1267a7dea167SDimitry Andric return true; 1268a7dea167SDimitry Andric } 1269a7dea167SDimitry Andric 1270a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1271a7dea167SDimitry Andric bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1272a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1273a7dea167SDimitry Andric return false; 1274a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1275a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1276a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1277a7dea167SDimitry Andric return false; 1278a7dea167SDimitry Andric const Pointer &Field = This.atField(I); 1279a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Field)) 1280a7dea167SDimitry Andric return false; 1281a7dea167SDimitry Andric Field.deref<T>() = Value; 1282a7dea167SDimitry Andric return true; 1283a7dea167SDimitry Andric } 1284a7dea167SDimitry Andric 1285a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1286a7dea167SDimitry Andric bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 12870fca6ea1SDimitry Andric const Pointer &Ptr = S.P.getPtrGlobal(I); 12880fca6ea1SDimitry Andric if (!CheckConstant(S, OpPC, Ptr.getFieldDesc())) 12890fca6ea1SDimitry Andric return false; 12900fca6ea1SDimitry Andric if (Ptr.isExtern()) 12910fca6ea1SDimitry Andric return false; 12927a6dacacSDimitry Andric 12930fca6ea1SDimitry Andric // If a global variable is uninitialized, that means the initializer we've 12940fca6ea1SDimitry Andric // compiled for it wasn't a constant expression. Diagnose that. 12950fca6ea1SDimitry Andric if (!CheckGlobalInitialized(S, OpPC, Ptr)) 12967a6dacacSDimitry Andric return false; 12970fca6ea1SDimitry Andric 12980fca6ea1SDimitry Andric S.Stk.push<T>(Ptr.deref<T>()); 1299a7dea167SDimitry Andric return true; 1300a7dea167SDimitry Andric } 1301a7dea167SDimitry Andric 13027a6dacacSDimitry Andric /// Same as GetGlobal, but without the checks. 13037a6dacacSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 13047a6dacacSDimitry Andric bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { 13050fca6ea1SDimitry Andric const Pointer &Ptr = S.P.getPtrGlobal(I); 13060fca6ea1SDimitry Andric if (!Ptr.isInitialized()) 13070fca6ea1SDimitry Andric return false; 13080fca6ea1SDimitry Andric S.Stk.push<T>(Ptr.deref<T>()); 13097a6dacacSDimitry Andric return true; 13107a6dacacSDimitry Andric } 13117a6dacacSDimitry Andric 1312a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1313a7dea167SDimitry Andric bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1314a7dea167SDimitry Andric // TODO: emit warning. 1315a7dea167SDimitry Andric return false; 1316a7dea167SDimitry Andric } 1317a7dea167SDimitry Andric 1318a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1319a7dea167SDimitry Andric bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 13200fca6ea1SDimitry Andric const Pointer &P = S.P.getGlobal(I); 13210fca6ea1SDimitry Andric P.deref<T>() = S.Stk.pop<T>(); 13220fca6ea1SDimitry Andric P.initialize(); 1323a7dea167SDimitry Andric return true; 1324a7dea167SDimitry Andric } 1325a7dea167SDimitry Andric 132606c3fb27SDimitry Andric /// 1) Converts the value on top of the stack to an APValue 132706c3fb27SDimitry Andric /// 2) Sets that APValue on \Temp 13280fca6ea1SDimitry Andric /// 3) Initializes global with index \I with that 132906c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 133006c3fb27SDimitry Andric bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, 133106c3fb27SDimitry Andric const LifetimeExtendedTemporaryDecl *Temp) { 13320fca6ea1SDimitry Andric const Pointer &Ptr = S.P.getGlobal(I); 13330fca6ea1SDimitry Andric 133406c3fb27SDimitry Andric const T Value = S.Stk.peek<T>(); 13350fca6ea1SDimitry Andric APValue APV = Value.toAPValue(S.getCtx()); 133606c3fb27SDimitry Andric APValue *Cached = Temp->getOrCreateValue(true); 133706c3fb27SDimitry Andric *Cached = APV; 133806c3fb27SDimitry Andric 13390fca6ea1SDimitry Andric assert(Ptr.getDeclDesc()->asExpr()); 13400fca6ea1SDimitry Andric 13410fca6ea1SDimitry Andric S.SeenGlobalTemporaries.push_back( 13420fca6ea1SDimitry Andric std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp)); 13430fca6ea1SDimitry Andric 13440fca6ea1SDimitry Andric Ptr.deref<T>() = S.Stk.pop<T>(); 13450fca6ea1SDimitry Andric Ptr.initialize(); 134606c3fb27SDimitry Andric return true; 134706c3fb27SDimitry Andric } 134806c3fb27SDimitry Andric 13495f757f3fSDimitry Andric /// 1) Converts the value on top of the stack to an APValue 13505f757f3fSDimitry Andric /// 2) Sets that APValue on \Temp 13515f757f3fSDimitry Andric /// 3) Initialized global with index \I with that 13525f757f3fSDimitry Andric inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, 13535f757f3fSDimitry Andric const LifetimeExtendedTemporaryDecl *Temp) { 13545f757f3fSDimitry Andric assert(Temp); 13555f757f3fSDimitry Andric const Pointer &P = S.Stk.peek<Pointer>(); 13565f757f3fSDimitry Andric APValue *Cached = Temp->getOrCreateValue(true); 13575f757f3fSDimitry Andric 13580fca6ea1SDimitry Andric S.SeenGlobalTemporaries.push_back( 13590fca6ea1SDimitry Andric std::make_pair(P.getDeclDesc()->asExpr(), Temp)); 13600fca6ea1SDimitry Andric 13610fca6ea1SDimitry Andric if (std::optional<APValue> APV = 13620fca6ea1SDimitry Andric P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) { 13637a6dacacSDimitry Andric *Cached = *APV; 13645f757f3fSDimitry Andric return true; 13655f757f3fSDimitry Andric } 13665f757f3fSDimitry Andric 13677a6dacacSDimitry Andric return false; 13687a6dacacSDimitry Andric } 13697a6dacacSDimitry Andric 1370a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1371a7dea167SDimitry Andric bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1372a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1373a7dea167SDimitry Andric return false; 1374a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1375a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1376a7dea167SDimitry Andric return false; 1377a7dea167SDimitry Andric const Pointer &Field = This.atField(I); 1378a7dea167SDimitry Andric Field.deref<T>() = S.Stk.pop<T>(); 1379a7dea167SDimitry Andric Field.initialize(); 1380a7dea167SDimitry Andric return true; 1381a7dea167SDimitry Andric } 1382a7dea167SDimitry Andric 13837a6dacacSDimitry Andric // FIXME: The Field pointer here is too much IMO and we could instead just 13847a6dacacSDimitry Andric // pass an Offset + BitWidth pair. 1385a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 13867a6dacacSDimitry Andric bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, 13877a6dacacSDimitry Andric uint32_t FieldOffset) { 13885f757f3fSDimitry Andric assert(F->isBitField()); 1389a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1390a7dea167SDimitry Andric return false; 1391a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1392a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1393a7dea167SDimitry Andric return false; 13947a6dacacSDimitry Andric const Pointer &Field = This.atField(FieldOffset); 1395a7dea167SDimitry Andric const auto &Value = S.Stk.pop<T>(); 1396a7dea167SDimitry Andric Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1397a7dea167SDimitry Andric Field.initialize(); 1398a7dea167SDimitry Andric return true; 1399a7dea167SDimitry Andric } 1400a7dea167SDimitry Andric 1401a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1402a7dea167SDimitry Andric bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1403a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1404a7dea167SDimitry Andric return false; 1405a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1406a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1407a7dea167SDimitry Andric return false; 1408a7dea167SDimitry Andric const Pointer &Field = This.atField(I); 1409a7dea167SDimitry Andric Field.deref<T>() = S.Stk.pop<T>(); 1410a7dea167SDimitry Andric Field.activate(); 1411a7dea167SDimitry Andric Field.initialize(); 1412a7dea167SDimitry Andric return true; 1413a7dea167SDimitry Andric } 1414a7dea167SDimitry Andric 1415bdd1243dSDimitry Andric /// 1) Pops the value from the stack 1416bdd1243dSDimitry Andric /// 2) Peeks a pointer from the stack 1417bdd1243dSDimitry Andric /// 3) Pushes the value to field I of the pointer on the stack 1418a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1419a7dea167SDimitry Andric bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 1420a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1421bdd1243dSDimitry Andric const Pointer &Field = S.Stk.peek<Pointer>().atField(I); 1422a7dea167SDimitry Andric Field.deref<T>() = Value; 1423a7dea167SDimitry Andric Field.activate(); 1424a7dea167SDimitry Andric Field.initialize(); 1425a7dea167SDimitry Andric return true; 1426a7dea167SDimitry Andric } 1427a7dea167SDimitry Andric 1428a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1429a7dea167SDimitry Andric bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 14305f757f3fSDimitry Andric assert(F->isBitField()); 1431a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 14325f757f3fSDimitry Andric const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); 1433a7dea167SDimitry Andric Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1434a7dea167SDimitry Andric Field.activate(); 1435a7dea167SDimitry Andric Field.initialize(); 1436a7dea167SDimitry Andric return true; 1437a7dea167SDimitry Andric } 1438a7dea167SDimitry Andric 1439a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1440a7dea167SDimitry Andric bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1441a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1442a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1443a7dea167SDimitry Andric const Pointer &Field = Ptr.atField(I); 1444a7dea167SDimitry Andric Field.deref<T>() = Value; 1445a7dea167SDimitry Andric Field.activate(); 1446a7dea167SDimitry Andric Field.initialize(); 1447a7dea167SDimitry Andric return true; 1448a7dea167SDimitry Andric } 1449a7dea167SDimitry Andric 1450a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1451a7dea167SDimitry Andric // GetPtr Local/Param/Global/Field/This 1452a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1453a7dea167SDimitry Andric 1454a7dea167SDimitry Andric inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1455a7dea167SDimitry Andric S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 1456a7dea167SDimitry Andric return true; 1457a7dea167SDimitry Andric } 1458a7dea167SDimitry Andric 1459a7dea167SDimitry Andric inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1460a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) { 1461a7dea167SDimitry Andric return false; 1462a7dea167SDimitry Andric } 1463a7dea167SDimitry Andric S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 1464a7dea167SDimitry Andric return true; 1465a7dea167SDimitry Andric } 1466a7dea167SDimitry Andric 1467a7dea167SDimitry Andric inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1468a7dea167SDimitry Andric S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 1469a7dea167SDimitry Andric return true; 1470a7dea167SDimitry Andric } 1471a7dea167SDimitry Andric 14720fca6ea1SDimitry Andric /// 1) Peeks a Pointer 1473bdd1243dSDimitry Andric /// 2) Pushes Pointer.atField(Off) on the stack 1474a7dea167SDimitry Andric inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { 14750fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 14760fca6ea1SDimitry Andric 14770fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus && S.inConstantContext() && 14780fca6ea1SDimitry Andric !CheckNull(S, OpPC, Ptr, CSK_Field)) 1479a7dea167SDimitry Andric return false; 14800fca6ea1SDimitry Andric 1481a7dea167SDimitry Andric if (!CheckExtern(S, OpPC, Ptr)) 1482a7dea167SDimitry Andric return false; 1483a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1484a7dea167SDimitry Andric return false; 14850fca6ea1SDimitry Andric if (!CheckArray(S, OpPC, Ptr)) 14860fca6ea1SDimitry Andric return false; 14875f757f3fSDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) 14885f757f3fSDimitry Andric return false; 14895f757f3fSDimitry Andric 14900fca6ea1SDimitry Andric if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) 14910fca6ea1SDimitry Andric return false; 14920fca6ea1SDimitry Andric S.Stk.push<Pointer>(Ptr.atField(Off)); 14930fca6ea1SDimitry Andric return true; 14940fca6ea1SDimitry Andric } 14950fca6ea1SDimitry Andric 14960fca6ea1SDimitry Andric inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) { 14970fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 14980fca6ea1SDimitry Andric 14990fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus && S.inConstantContext() && 15000fca6ea1SDimitry Andric !CheckNull(S, OpPC, Ptr, CSK_Field)) 15010fca6ea1SDimitry Andric return false; 15020fca6ea1SDimitry Andric 15030fca6ea1SDimitry Andric if (!CheckExtern(S, OpPC, Ptr)) 15040fca6ea1SDimitry Andric return false; 15050fca6ea1SDimitry Andric if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 15060fca6ea1SDimitry Andric return false; 15070fca6ea1SDimitry Andric if (!CheckArray(S, OpPC, Ptr)) 15080fca6ea1SDimitry Andric return false; 15090fca6ea1SDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) 15100fca6ea1SDimitry Andric return false; 15110fca6ea1SDimitry Andric 15120fca6ea1SDimitry Andric if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize()) 15130fca6ea1SDimitry Andric return false; 15140fca6ea1SDimitry Andric 1515a7dea167SDimitry Andric S.Stk.push<Pointer>(Ptr.atField(Off)); 1516a7dea167SDimitry Andric return true; 1517a7dea167SDimitry Andric } 1518a7dea167SDimitry Andric 1519a7dea167SDimitry Andric inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1520a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1521a7dea167SDimitry Andric return false; 1522a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1523a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1524a7dea167SDimitry Andric return false; 1525a7dea167SDimitry Andric S.Stk.push<Pointer>(This.atField(Off)); 1526a7dea167SDimitry Andric return true; 1527a7dea167SDimitry Andric } 1528a7dea167SDimitry Andric 1529a7dea167SDimitry Andric inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1530a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1531a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 1532a7dea167SDimitry Andric return false; 1533a7dea167SDimitry Andric if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1534a7dea167SDimitry Andric return false; 1535a7dea167SDimitry Andric Pointer Field = Ptr.atField(Off); 1536a7dea167SDimitry Andric Ptr.deactivate(); 1537a7dea167SDimitry Andric Field.activate(); 1538a7dea167SDimitry Andric S.Stk.push<Pointer>(std::move(Field)); 1539a7dea167SDimitry Andric return true; 1540a7dea167SDimitry Andric } 1541a7dea167SDimitry Andric 1542a7dea167SDimitry Andric inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1543a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1544a7dea167SDimitry Andric return false; 1545a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1546a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1547a7dea167SDimitry Andric return false; 1548a7dea167SDimitry Andric Pointer Field = This.atField(Off); 1549a7dea167SDimitry Andric This.deactivate(); 1550a7dea167SDimitry Andric Field.activate(); 1551a7dea167SDimitry Andric S.Stk.push<Pointer>(std::move(Field)); 1552a7dea167SDimitry Andric return true; 1553a7dea167SDimitry Andric } 1554a7dea167SDimitry Andric 15555f757f3fSDimitry Andric inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) { 15565f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 15575f757f3fSDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_Derived)) 15585f757f3fSDimitry Andric return false; 15595f757f3fSDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived)) 15605f757f3fSDimitry Andric return false; 15610fca6ea1SDimitry Andric if (!CheckDowncast(S, OpPC, Ptr, Off)) 15620fca6ea1SDimitry Andric return false; 15630fca6ea1SDimitry Andric 15645f757f3fSDimitry Andric S.Stk.push<Pointer>(Ptr.atFieldSub(Off)); 15655f757f3fSDimitry Andric return true; 15665f757f3fSDimitry Andric } 15675f757f3fSDimitry Andric 1568a7dea167SDimitry Andric inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 156906c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 157006c3fb27SDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 157106c3fb27SDimitry Andric return false; 15725f757f3fSDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 15735f757f3fSDimitry Andric return false; 157406c3fb27SDimitry Andric S.Stk.push<Pointer>(Ptr.atField(Off)); 157506c3fb27SDimitry Andric return true; 157606c3fb27SDimitry Andric } 157706c3fb27SDimitry Andric 157806c3fb27SDimitry Andric inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1579a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1580a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1581a7dea167SDimitry Andric return false; 15825f757f3fSDimitry Andric if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 15835f757f3fSDimitry Andric return false; 1584a7dea167SDimitry Andric S.Stk.push<Pointer>(Ptr.atField(Off)); 1585a7dea167SDimitry Andric return true; 1586a7dea167SDimitry Andric } 1587a7dea167SDimitry Andric 15880fca6ea1SDimitry Andric inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) { 15890fca6ea1SDimitry Andric const auto &Ptr = S.Stk.pop<MemberPointer>(); 15900fca6ea1SDimitry Andric S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off)); 15910fca6ea1SDimitry Andric return true; 15920fca6ea1SDimitry Andric } 15930fca6ea1SDimitry Andric 1594a7dea167SDimitry Andric inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1595a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1596a7dea167SDimitry Andric return false; 1597a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1598a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1599a7dea167SDimitry Andric return false; 1600a7dea167SDimitry Andric S.Stk.push<Pointer>(This.atField(Off)); 1601a7dea167SDimitry Andric return true; 1602a7dea167SDimitry Andric } 1603a7dea167SDimitry Andric 16040fca6ea1SDimitry Andric inline bool FinishInitPop(InterpState &S, CodePtr OpPC) { 16055f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 16060fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) { 16075f757f3fSDimitry Andric Ptr.initialize(); 16080fca6ea1SDimitry Andric Ptr.activate(); 16090fca6ea1SDimitry Andric } 16100fca6ea1SDimitry Andric return true; 16110fca6ea1SDimitry Andric } 16120fca6ea1SDimitry Andric 16130fca6ea1SDimitry Andric inline bool FinishInit(InterpState &S, CodePtr OpPC) { 16140fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 16150fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) { 16160fca6ea1SDimitry Andric Ptr.initialize(); 16170fca6ea1SDimitry Andric Ptr.activate(); 16180fca6ea1SDimitry Andric } 16190fca6ea1SDimitry Andric return true; 16200fca6ea1SDimitry Andric } 16210fca6ea1SDimitry Andric 16220fca6ea1SDimitry Andric inline bool Dump(InterpState &S, CodePtr OpPC) { 16230fca6ea1SDimitry Andric S.Stk.dump(); 16245f757f3fSDimitry Andric return true; 16255f757f3fSDimitry Andric } 16265f757f3fSDimitry Andric 1627a7dea167SDimitry Andric inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 1628a7dea167SDimitry Andric const Pointer &Ptr) { 1629a7dea167SDimitry Andric Pointer Base = Ptr; 1630a7dea167SDimitry Andric while (Base.isBaseClass()) 1631a7dea167SDimitry Andric Base = Base.getBase(); 1632a7dea167SDimitry Andric 16330fca6ea1SDimitry Andric const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl); 16340fca6ea1SDimitry Andric S.Stk.push<Pointer>(Base.atField(VirtBase->Offset)); 1635a7dea167SDimitry Andric return true; 1636a7dea167SDimitry Andric } 1637a7dea167SDimitry Andric 16380fca6ea1SDimitry Andric inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC, 16390fca6ea1SDimitry Andric const RecordDecl *D) { 16400fca6ea1SDimitry Andric assert(D); 1641a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1642a7dea167SDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1643a7dea167SDimitry Andric return false; 1644a7dea167SDimitry Andric return VirtBaseHelper(S, OpPC, D, Ptr); 1645a7dea167SDimitry Andric } 1646a7dea167SDimitry Andric 1647a7dea167SDimitry Andric inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 1648a7dea167SDimitry Andric const RecordDecl *D) { 16490fca6ea1SDimitry Andric assert(D); 1650a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) 1651a7dea167SDimitry Andric return false; 1652a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 1653a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 1654a7dea167SDimitry Andric return false; 1655a7dea167SDimitry Andric return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 1656a7dea167SDimitry Andric } 1657a7dea167SDimitry Andric 1658a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1659a7dea167SDimitry Andric // Load, Store, Init 1660a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1661a7dea167SDimitry Andric 1662a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1663a7dea167SDimitry Andric bool Load(InterpState &S, CodePtr OpPC) { 1664a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 1665a7dea167SDimitry Andric if (!CheckLoad(S, OpPC, Ptr)) 1666a7dea167SDimitry Andric return false; 16670fca6ea1SDimitry Andric if (!Ptr.isBlockPointer()) 16680fca6ea1SDimitry Andric return false; 1669a7dea167SDimitry Andric S.Stk.push<T>(Ptr.deref<T>()); 1670a7dea167SDimitry Andric return true; 1671a7dea167SDimitry Andric } 1672a7dea167SDimitry Andric 1673a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1674a7dea167SDimitry Andric bool LoadPop(InterpState &S, CodePtr OpPC) { 1675a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1676a7dea167SDimitry Andric if (!CheckLoad(S, OpPC, Ptr)) 1677a7dea167SDimitry Andric return false; 16780fca6ea1SDimitry Andric if (!Ptr.isBlockPointer()) 16790fca6ea1SDimitry Andric return false; 1680a7dea167SDimitry Andric S.Stk.push<T>(Ptr.deref<T>()); 1681a7dea167SDimitry Andric return true; 1682a7dea167SDimitry Andric } 1683a7dea167SDimitry Andric 1684a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1685a7dea167SDimitry Andric bool Store(InterpState &S, CodePtr OpPC) { 1686a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1687a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 1688a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Ptr)) 1689a7dea167SDimitry Andric return false; 16900fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) 1691bdd1243dSDimitry Andric Ptr.initialize(); 1692a7dea167SDimitry Andric Ptr.deref<T>() = Value; 1693a7dea167SDimitry Andric return true; 1694a7dea167SDimitry Andric } 1695a7dea167SDimitry Andric 1696a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1697a7dea167SDimitry Andric bool StorePop(InterpState &S, CodePtr OpPC) { 1698a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1699a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1700a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Ptr)) 1701a7dea167SDimitry Andric return false; 17020fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) 1703bdd1243dSDimitry Andric Ptr.initialize(); 1704a7dea167SDimitry Andric Ptr.deref<T>() = Value; 1705a7dea167SDimitry Andric return true; 1706a7dea167SDimitry Andric } 1707a7dea167SDimitry Andric 1708a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1709a7dea167SDimitry Andric bool StoreBitField(InterpState &S, CodePtr OpPC) { 1710a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1711a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 1712a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Ptr)) 1713a7dea167SDimitry Andric return false; 17140fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) 1715bdd1243dSDimitry Andric Ptr.initialize(); 17165f757f3fSDimitry Andric if (const auto *FD = Ptr.getField()) 1717a7dea167SDimitry Andric Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 17185f757f3fSDimitry Andric else 1719a7dea167SDimitry Andric Ptr.deref<T>() = Value; 1720a7dea167SDimitry Andric return true; 1721a7dea167SDimitry Andric } 1722a7dea167SDimitry Andric 1723a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1724a7dea167SDimitry Andric bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 1725a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1726a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1727a7dea167SDimitry Andric if (!CheckStore(S, OpPC, Ptr)) 1728a7dea167SDimitry Andric return false; 17290fca6ea1SDimitry Andric if (Ptr.canBeInitialized()) 1730bdd1243dSDimitry Andric Ptr.initialize(); 17315f757f3fSDimitry Andric if (const auto *FD = Ptr.getField()) 1732a7dea167SDimitry Andric Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 17335f757f3fSDimitry Andric else 1734a7dea167SDimitry Andric Ptr.deref<T>() = Value; 1735a7dea167SDimitry Andric return true; 1736a7dea167SDimitry Andric } 1737a7dea167SDimitry Andric 1738a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 17390fca6ea1SDimitry Andric bool Init(InterpState &S, CodePtr OpPC) { 17400fca6ea1SDimitry Andric const T &Value = S.Stk.pop<T>(); 17410fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 17420fca6ea1SDimitry Andric if (!CheckInit(S, OpPC, Ptr)) { 17430fca6ea1SDimitry Andric assert(false); 17440fca6ea1SDimitry Andric return false; 17450fca6ea1SDimitry Andric } 17460fca6ea1SDimitry Andric Ptr.initialize(); 17470fca6ea1SDimitry Andric new (&Ptr.deref<T>()) T(Value); 17480fca6ea1SDimitry Andric return true; 17490fca6ea1SDimitry Andric } 17500fca6ea1SDimitry Andric 17510fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1752a7dea167SDimitry Andric bool InitPop(InterpState &S, CodePtr OpPC) { 1753a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1754a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 1755a7dea167SDimitry Andric if (!CheckInit(S, OpPC, Ptr)) 1756a7dea167SDimitry Andric return false; 1757a7dea167SDimitry Andric Ptr.initialize(); 1758a7dea167SDimitry Andric new (&Ptr.deref<T>()) T(Value); 1759a7dea167SDimitry Andric return true; 1760a7dea167SDimitry Andric } 1761a7dea167SDimitry Andric 1762bdd1243dSDimitry Andric /// 1) Pops the value from the stack 1763bdd1243dSDimitry Andric /// 2) Peeks a pointer and gets its index \Idx 1764bdd1243dSDimitry Andric /// 3) Sets the value on the pointer, leaving the pointer on the stack. 1765a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1766a7dea167SDimitry Andric bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1767a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1768a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx); 17690fca6ea1SDimitry Andric if (Ptr.isUnknownSizeArray()) 17700fca6ea1SDimitry Andric return false; 1771a7dea167SDimitry Andric if (!CheckInit(S, OpPC, Ptr)) 1772a7dea167SDimitry Andric return false; 1773a7dea167SDimitry Andric Ptr.initialize(); 1774a7dea167SDimitry Andric new (&Ptr.deref<T>()) T(Value); 1775a7dea167SDimitry Andric return true; 1776a7dea167SDimitry Andric } 1777a7dea167SDimitry Andric 1778bdd1243dSDimitry Andric /// The same as InitElem, but pops the pointer as well. 1779a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1780a7dea167SDimitry Andric bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1781a7dea167SDimitry Andric const T &Value = S.Stk.pop<T>(); 1782a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx); 17830fca6ea1SDimitry Andric if (Ptr.isUnknownSizeArray()) 17840fca6ea1SDimitry Andric return false; 1785a7dea167SDimitry Andric if (!CheckInit(S, OpPC, Ptr)) 1786a7dea167SDimitry Andric return false; 1787a7dea167SDimitry Andric Ptr.initialize(); 1788a7dea167SDimitry Andric new (&Ptr.deref<T>()) T(Value); 1789a7dea167SDimitry Andric return true; 1790a7dea167SDimitry Andric } 1791a7dea167SDimitry Andric 17920fca6ea1SDimitry Andric inline bool Memcpy(InterpState &S, CodePtr OpPC) { 17930fca6ea1SDimitry Andric const Pointer &Src = S.Stk.pop<Pointer>(); 17940fca6ea1SDimitry Andric Pointer &Dest = S.Stk.peek<Pointer>(); 17950fca6ea1SDimitry Andric 17960fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Src)) 17970fca6ea1SDimitry Andric return false; 17980fca6ea1SDimitry Andric 17990fca6ea1SDimitry Andric return DoMemcpy(S, OpPC, Src, Dest); 18000fca6ea1SDimitry Andric } 18010fca6ea1SDimitry Andric 18020fca6ea1SDimitry Andric inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) { 18030fca6ea1SDimitry Andric const auto &Member = S.Stk.pop<MemberPointer>(); 18040fca6ea1SDimitry Andric const auto &Base = S.Stk.pop<Pointer>(); 18050fca6ea1SDimitry Andric 18060fca6ea1SDimitry Andric S.Stk.push<MemberPointer>(Member.takeInstance(Base)); 18070fca6ea1SDimitry Andric return true; 18080fca6ea1SDimitry Andric } 18090fca6ea1SDimitry Andric 18100fca6ea1SDimitry Andric inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) { 18110fca6ea1SDimitry Andric const auto &MP = S.Stk.pop<MemberPointer>(); 18120fca6ea1SDimitry Andric 18130fca6ea1SDimitry Andric if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) { 18140fca6ea1SDimitry Andric S.Stk.push<Pointer>(*Ptr); 18150fca6ea1SDimitry Andric return true; 18160fca6ea1SDimitry Andric } 18170fca6ea1SDimitry Andric return false; 18180fca6ea1SDimitry Andric } 18190fca6ea1SDimitry Andric 1820a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1821a7dea167SDimitry Andric // AddOffset, SubOffset 1822a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 1823a7dea167SDimitry Andric 182406c3fb27SDimitry Andric template <class T, ArithOp Op> 182506c3fb27SDimitry Andric bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, 182606c3fb27SDimitry Andric const Pointer &Ptr) { 1827bdd1243dSDimitry Andric // A zero offset does not change the pointer. 1828a7dea167SDimitry Andric if (Offset.isZero()) { 1829bdd1243dSDimitry Andric S.Stk.push<Pointer>(Ptr); 1830a7dea167SDimitry Andric return true; 1831a7dea167SDimitry Andric } 1832bdd1243dSDimitry Andric 18330fca6ea1SDimitry Andric if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) { 18340fca6ea1SDimitry Andric // The CheckNull will have emitted a note already, but we only 18350fca6ea1SDimitry Andric // abort in C++, since this is fine in C. 18360fca6ea1SDimitry Andric if (S.getLangOpts().CPlusPlus) 1837bdd1243dSDimitry Andric return false; 18380fca6ea1SDimitry Andric } 1839bdd1243dSDimitry Andric 1840a7dea167SDimitry Andric // Arrays of unknown bounds cannot have pointers into them. 1841a7dea167SDimitry Andric if (!CheckArray(S, OpPC, Ptr)) 1842a7dea167SDimitry Andric return false; 1843a7dea167SDimitry Andric 18440fca6ea1SDimitry Andric uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems()); 18450fca6ea1SDimitry Andric uint64_t Index; 18460fca6ea1SDimitry Andric if (Ptr.isOnePastEnd()) 18470fca6ea1SDimitry Andric Index = MaxIndex; 18480fca6ea1SDimitry Andric else 18490fca6ea1SDimitry Andric Index = Ptr.getIndex(); 1850a7dea167SDimitry Andric 18515f757f3fSDimitry Andric bool Invalid = false; 1852a7dea167SDimitry Andric // Helper to report an invalid offset, computed as APSInt. 18535f757f3fSDimitry Andric auto DiagInvalidOffset = [&]() -> void { 1854a7dea167SDimitry Andric const unsigned Bits = Offset.bitWidth(); 18550fca6ea1SDimitry Andric APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false); 18560fca6ea1SDimitry Andric APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true), 18570fca6ea1SDimitry Andric /*IsUnsigned=*/false); 185806c3fb27SDimitry Andric APSInt NewIndex = 185906c3fb27SDimitry Andric (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset); 1860a7dea167SDimitry Andric S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 18610fca6ea1SDimitry Andric << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex; 18625f757f3fSDimitry Andric Invalid = true; 1863a7dea167SDimitry Andric }; 1864a7dea167SDimitry Andric 18650fca6ea1SDimitry Andric if (Ptr.isBlockPointer()) { 18660fca6ea1SDimitry Andric uint64_t IOffset = static_cast<uint64_t>(Offset); 18670fca6ea1SDimitry Andric uint64_t MaxOffset = MaxIndex - Index; 18680fca6ea1SDimitry Andric 186906c3fb27SDimitry Andric if constexpr (Op == ArithOp::Add) { 1870a7dea167SDimitry Andric // If the new offset would be negative, bail out. 18710fca6ea1SDimitry Andric if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index)) 18725f757f3fSDimitry Andric DiagInvalidOffset(); 1873a7dea167SDimitry Andric 1874a7dea167SDimitry Andric // If the new offset would be out of bounds, bail out. 18750fca6ea1SDimitry Andric if (Offset.isPositive() && IOffset > MaxOffset) 18765f757f3fSDimitry Andric DiagInvalidOffset(); 1877bdd1243dSDimitry Andric } else { 1878bdd1243dSDimitry Andric // If the new offset would be negative, bail out. 18790fca6ea1SDimitry Andric if (Offset.isPositive() && Index < IOffset) 18805f757f3fSDimitry Andric DiagInvalidOffset(); 1881a7dea167SDimitry Andric 1882bdd1243dSDimitry Andric // If the new offset would be out of bounds, bail out. 18830fca6ea1SDimitry Andric if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset)) 18845f757f3fSDimitry Andric DiagInvalidOffset(); 1885bdd1243dSDimitry Andric } 18860fca6ea1SDimitry Andric } 1887bdd1243dSDimitry Andric 18880fca6ea1SDimitry Andric if (Invalid && S.getLangOpts().CPlusPlus) 18895f757f3fSDimitry Andric return false; 18905f757f3fSDimitry Andric 1891a7dea167SDimitry Andric // Offset is valid - compute it on unsigned. 1892a7dea167SDimitry Andric int64_t WideIndex = static_cast<int64_t>(Index); 1893a7dea167SDimitry Andric int64_t WideOffset = static_cast<int64_t>(Offset); 1894bdd1243dSDimitry Andric int64_t Result; 189506c3fb27SDimitry Andric if constexpr (Op == ArithOp::Add) 1896bdd1243dSDimitry Andric Result = WideIndex + WideOffset; 1897bdd1243dSDimitry Andric else 1898bdd1243dSDimitry Andric Result = WideIndex - WideOffset; 1899bdd1243dSDimitry Andric 19000fca6ea1SDimitry Andric // When the pointer is one-past-end, going back to index 0 is the only 19010fca6ea1SDimitry Andric // useful thing we can do. Any other index has been diagnosed before and 19020fca6ea1SDimitry Andric // we don't get here. 19030fca6ea1SDimitry Andric if (Result == 0 && Ptr.isOnePastEnd()) { 19040fca6ea1SDimitry Andric S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee, 19050fca6ea1SDimitry Andric Ptr.asBlockPointer().Base); 19060fca6ea1SDimitry Andric return true; 19070fca6ea1SDimitry Andric } 19080fca6ea1SDimitry Andric 19090fca6ea1SDimitry Andric S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result))); 1910a7dea167SDimitry Andric return true; 1911a7dea167SDimitry Andric } 1912a7dea167SDimitry Andric 1913a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1914a7dea167SDimitry Andric bool AddOffset(InterpState &S, CodePtr OpPC) { 191506c3fb27SDimitry Andric const T &Offset = S.Stk.pop<T>(); 191606c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 191706c3fb27SDimitry Andric return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr); 1918a7dea167SDimitry Andric } 1919a7dea167SDimitry Andric 1920a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1921a7dea167SDimitry Andric bool SubOffset(InterpState &S, CodePtr OpPC) { 192206c3fb27SDimitry Andric const T &Offset = S.Stk.pop<T>(); 192306c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 192406c3fb27SDimitry Andric return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr); 192506c3fb27SDimitry Andric } 192606c3fb27SDimitry Andric 192706c3fb27SDimitry Andric template <ArithOp Op> 19285f757f3fSDimitry Andric static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, 19295f757f3fSDimitry Andric const Pointer &Ptr) { 19300fca6ea1SDimitry Andric if (Ptr.isDummy()) 19310fca6ea1SDimitry Andric return false; 19320fca6ea1SDimitry Andric 193306c3fb27SDimitry Andric using OneT = Integral<8, false>; 19345f757f3fSDimitry Andric 19355f757f3fSDimitry Andric const Pointer &P = Ptr.deref<Pointer>(); 19365f757f3fSDimitry Andric if (!CheckNull(S, OpPC, P, CSK_ArrayIndex)) 19375f757f3fSDimitry Andric return false; 193806c3fb27SDimitry Andric 193906c3fb27SDimitry Andric // Get the current value on the stack. 19405f757f3fSDimitry Andric S.Stk.push<Pointer>(P); 194106c3fb27SDimitry Andric 194206c3fb27SDimitry Andric // Now the current Ptr again and a constant 1. 194306c3fb27SDimitry Andric OneT One = OneT::from(1); 194406c3fb27SDimitry Andric if (!OffsetHelper<OneT, Op>(S, OpPC, One, P)) 194506c3fb27SDimitry Andric return false; 194606c3fb27SDimitry Andric 194706c3fb27SDimitry Andric // Store the new value. 194806c3fb27SDimitry Andric Ptr.deref<Pointer>() = S.Stk.pop<Pointer>(); 194906c3fb27SDimitry Andric return true; 195006c3fb27SDimitry Andric } 195106c3fb27SDimitry Andric 195206c3fb27SDimitry Andric static inline bool IncPtr(InterpState &S, CodePtr OpPC) { 19535f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 19545f757f3fSDimitry Andric 19555f757f3fSDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 19565f757f3fSDimitry Andric return false; 19575f757f3fSDimitry Andric 19585f757f3fSDimitry Andric return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); 195906c3fb27SDimitry Andric } 196006c3fb27SDimitry Andric 196106c3fb27SDimitry Andric static inline bool DecPtr(InterpState &S, CodePtr OpPC) { 19625f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 19635f757f3fSDimitry Andric 19645f757f3fSDimitry Andric if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 19655f757f3fSDimitry Andric return false; 19665f757f3fSDimitry Andric 19675f757f3fSDimitry Andric return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); 1968a7dea167SDimitry Andric } 1969a7dea167SDimitry Andric 1970bdd1243dSDimitry Andric /// 1) Pops a Pointer from the stack. 1971bdd1243dSDimitry Andric /// 2) Pops another Pointer from the stack. 1972bdd1243dSDimitry Andric /// 3) Pushes the different of the indices of the two pointers on the stack. 1973bdd1243dSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 1974bdd1243dSDimitry Andric inline bool SubPtr(InterpState &S, CodePtr OpPC) { 1975bdd1243dSDimitry Andric const Pointer &LHS = S.Stk.pop<Pointer>(); 1976bdd1243dSDimitry Andric const Pointer &RHS = S.Stk.pop<Pointer>(); 1977bdd1243dSDimitry Andric 19780fca6ea1SDimitry Andric if (RHS.isZero()) { 19790fca6ea1SDimitry Andric S.Stk.push<T>(T::from(LHS.getIndex())); 19800fca6ea1SDimitry Andric return true; 19810fca6ea1SDimitry Andric } 19820fca6ea1SDimitry Andric 19835f757f3fSDimitry Andric if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { 1984bdd1243dSDimitry Andric // TODO: Diagnose. 1985bdd1243dSDimitry Andric return false; 1986bdd1243dSDimitry Andric } 1987bdd1243dSDimitry Andric 19880fca6ea1SDimitry Andric if (LHS.isZero() && RHS.isZero()) { 19890fca6ea1SDimitry Andric S.Stk.push<T>(); 19900fca6ea1SDimitry Andric return true; 19910fca6ea1SDimitry Andric } 19920fca6ea1SDimitry Andric 19930fca6ea1SDimitry Andric T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems()) 19940fca6ea1SDimitry Andric : T::from(LHS.getIndex()); 19950fca6ea1SDimitry Andric T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems()) 19960fca6ea1SDimitry Andric : T::from(RHS.getIndex()); 1997bdd1243dSDimitry Andric return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B); 1998bdd1243dSDimitry Andric } 1999a7dea167SDimitry Andric 2000a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2001a7dea167SDimitry Andric // Destroy 2002a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2003a7dea167SDimitry Andric 2004a7dea167SDimitry Andric inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 2005a7dea167SDimitry Andric S.Current->destroy(I); 2006a7dea167SDimitry Andric return true; 2007a7dea167SDimitry Andric } 2008a7dea167SDimitry Andric 2009a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2010a7dea167SDimitry Andric // Cast, CastFP 2011a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2012a7dea167SDimitry Andric 2013a7dea167SDimitry Andric template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 2014a7dea167SDimitry Andric using T = typename PrimConv<TIn>::T; 2015a7dea167SDimitry Andric using U = typename PrimConv<TOut>::T; 2016a7dea167SDimitry Andric S.Stk.push<U>(U::from(S.Stk.pop<T>())); 2017a7dea167SDimitry Andric return true; 2018a7dea167SDimitry Andric } 2019a7dea167SDimitry Andric 202006c3fb27SDimitry Andric /// 1) Pops a Floating from the stack. 202106c3fb27SDimitry Andric /// 2) Pushes a new floating on the stack that uses the given semantics. 202206c3fb27SDimitry Andric inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, 202306c3fb27SDimitry Andric llvm::RoundingMode RM) { 202406c3fb27SDimitry Andric Floating F = S.Stk.pop<Floating>(); 202506c3fb27SDimitry Andric Floating Result = F.toSemantics(Sem, RM); 202606c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 202706c3fb27SDimitry Andric return true; 202806c3fb27SDimitry Andric } 202906c3fb27SDimitry Andric 20305f757f3fSDimitry Andric /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need 20315f757f3fSDimitry Andric /// to know what bitwidth the result should be. 20325f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 20335f757f3fSDimitry Andric bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 20345f757f3fSDimitry Andric S.Stk.push<IntegralAP<false>>( 20355f757f3fSDimitry Andric IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth)); 20365f757f3fSDimitry Andric return true; 20375f757f3fSDimitry Andric } 20385f757f3fSDimitry Andric 20395f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 20405f757f3fSDimitry Andric bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 20415f757f3fSDimitry Andric S.Stk.push<IntegralAP<true>>( 20425f757f3fSDimitry Andric IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth)); 20435f757f3fSDimitry Andric return true; 20445f757f3fSDimitry Andric } 20455f757f3fSDimitry Andric 204606c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 204706c3fb27SDimitry Andric bool CastIntegralFloating(InterpState &S, CodePtr OpPC, 204806c3fb27SDimitry Andric const llvm::fltSemantics *Sem, 204906c3fb27SDimitry Andric llvm::RoundingMode RM) { 205006c3fb27SDimitry Andric const T &From = S.Stk.pop<T>(); 205106c3fb27SDimitry Andric APSInt FromAP = From.toAPSInt(); 205206c3fb27SDimitry Andric Floating Result; 205306c3fb27SDimitry Andric 205406c3fb27SDimitry Andric auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result); 205506c3fb27SDimitry Andric S.Stk.push<Floating>(Result); 205606c3fb27SDimitry Andric 20575f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, Result, Status); 205806c3fb27SDimitry Andric } 205906c3fb27SDimitry Andric 206006c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 206106c3fb27SDimitry Andric bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) { 206206c3fb27SDimitry Andric const Floating &F = S.Stk.pop<Floating>(); 206306c3fb27SDimitry Andric 206406c3fb27SDimitry Andric if constexpr (std::is_same_v<T, Boolean>) { 206506c3fb27SDimitry Andric S.Stk.push<T>(T(F.isNonZero())); 206606c3fb27SDimitry Andric return true; 206706c3fb27SDimitry Andric } else { 20685f757f3fSDimitry Andric APSInt Result(std::max(8u, T::bitWidth()), 206906c3fb27SDimitry Andric /*IsUnsigned=*/!T::isSigned()); 207006c3fb27SDimitry Andric auto Status = F.convertToInteger(Result); 207106c3fb27SDimitry Andric 207206c3fb27SDimitry Andric // Float-to-Integral overflow check. 20730fca6ea1SDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp)) { 207406c3fb27SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 207506c3fb27SDimitry Andric QualType Type = E->getType(); 207606c3fb27SDimitry Andric 207706c3fb27SDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 20785f757f3fSDimitry Andric if (S.noteUndefinedBehavior()) { 20795f757f3fSDimitry Andric S.Stk.push<T>(T(Result)); 20805f757f3fSDimitry Andric return true; 20815f757f3fSDimitry Andric } 20825f757f3fSDimitry Andric return false; 20835f757f3fSDimitry Andric } 20845f757f3fSDimitry Andric 20855f757f3fSDimitry Andric S.Stk.push<T>(T(Result)); 20865f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, F, Status); 20875f757f3fSDimitry Andric } 20885f757f3fSDimitry Andric } 20895f757f3fSDimitry Andric 20905f757f3fSDimitry Andric static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, 20915f757f3fSDimitry Andric uint32_t BitWidth) { 20925f757f3fSDimitry Andric const Floating &F = S.Stk.pop<Floating>(); 20935f757f3fSDimitry Andric 20945f757f3fSDimitry Andric APSInt Result(BitWidth, /*IsUnsigned=*/true); 20955f757f3fSDimitry Andric auto Status = F.convertToInteger(Result); 20965f757f3fSDimitry Andric 20975f757f3fSDimitry Andric // Float-to-Integral overflow check. 20985f757f3fSDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 20995f757f3fSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 21005f757f3fSDimitry Andric QualType Type = E->getType(); 21015f757f3fSDimitry Andric 21025f757f3fSDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 210306c3fb27SDimitry Andric return S.noteUndefinedBehavior(); 210406c3fb27SDimitry Andric } 210506c3fb27SDimitry Andric 21065f757f3fSDimitry Andric S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 21075f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, F, Status); 210806c3fb27SDimitry Andric } 21095f757f3fSDimitry Andric 21105f757f3fSDimitry Andric static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, 21115f757f3fSDimitry Andric uint32_t BitWidth) { 21125f757f3fSDimitry Andric const Floating &F = S.Stk.pop<Floating>(); 21135f757f3fSDimitry Andric 21145f757f3fSDimitry Andric APSInt Result(BitWidth, /*IsUnsigned=*/false); 21155f757f3fSDimitry Andric auto Status = F.convertToInteger(Result); 21165f757f3fSDimitry Andric 21175f757f3fSDimitry Andric // Float-to-Integral overflow check. 21185f757f3fSDimitry Andric if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 21195f757f3fSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 21205f757f3fSDimitry Andric QualType Type = E->getType(); 21215f757f3fSDimitry Andric 21225f757f3fSDimitry Andric S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 21235f757f3fSDimitry Andric return S.noteUndefinedBehavior(); 21245f757f3fSDimitry Andric } 21255f757f3fSDimitry Andric 21265f757f3fSDimitry Andric S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 21275f757f3fSDimitry Andric return CheckFloatResult(S, OpPC, F, Status); 21285f757f3fSDimitry Andric } 21295f757f3fSDimitry Andric 21305f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 21315f757f3fSDimitry Andric bool CastPointerIntegral(InterpState &S, CodePtr OpPC) { 21325f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 21335f757f3fSDimitry Andric 21340fca6ea1SDimitry Andric if (Ptr.isDummy()) 21355f757f3fSDimitry Andric return false; 21365f757f3fSDimitry Andric 21370fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 21380fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast) 21390fca6ea1SDimitry Andric << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 21400fca6ea1SDimitry Andric 21415f757f3fSDimitry Andric S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation())); 21425f757f3fSDimitry Andric return true; 214306c3fb27SDimitry Andric } 214406c3fb27SDimitry Andric 21450fca6ea1SDimitry Andric static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, 21460fca6ea1SDimitry Andric uint32_t BitWidth) { 21470fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 21480fca6ea1SDimitry Andric 21490fca6ea1SDimitry Andric if (Ptr.isDummy()) 21500fca6ea1SDimitry Andric return false; 21510fca6ea1SDimitry Andric 21520fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 21530fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast) 21540fca6ea1SDimitry Andric << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 21550fca6ea1SDimitry Andric 21560fca6ea1SDimitry Andric S.Stk.push<IntegralAP<false>>( 21570fca6ea1SDimitry Andric IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth)); 21580fca6ea1SDimitry Andric return true; 21590fca6ea1SDimitry Andric } 21600fca6ea1SDimitry Andric 21610fca6ea1SDimitry Andric static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, 21620fca6ea1SDimitry Andric uint32_t BitWidth) { 21630fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 21640fca6ea1SDimitry Andric 21650fca6ea1SDimitry Andric if (Ptr.isDummy()) 21660fca6ea1SDimitry Andric return false; 21670fca6ea1SDimitry Andric 21680fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 21690fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast) 21700fca6ea1SDimitry Andric << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 21710fca6ea1SDimitry Andric 21720fca6ea1SDimitry Andric S.Stk.push<IntegralAP<true>>( 21730fca6ea1SDimitry Andric IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth)); 21740fca6ea1SDimitry Andric return true; 21750fca6ea1SDimitry Andric } 21760fca6ea1SDimitry Andric 21770fca6ea1SDimitry Andric static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) { 21780fca6ea1SDimitry Andric const auto &Ptr = S.Stk.peek<Pointer>(); 21790fca6ea1SDimitry Andric 21800fca6ea1SDimitry Andric if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) { 21810fca6ea1SDimitry Andric bool HasValidResult = !Ptr.isZero(); 21820fca6ea1SDimitry Andric 21830fca6ea1SDimitry Andric if (HasValidResult) { 21840fca6ea1SDimitry Andric // FIXME: note_constexpr_invalid_void_star_cast 21850fca6ea1SDimitry Andric } else if (!S.getLangOpts().CPlusPlus26) { 21860fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 21870fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast) 21880fca6ea1SDimitry Andric << 3 << "'void *'" << S.Current->getRange(OpPC); 21890fca6ea1SDimitry Andric } 21900fca6ea1SDimitry Andric } else { 21910fca6ea1SDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 21920fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_invalid_cast) 21930fca6ea1SDimitry Andric << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 21940fca6ea1SDimitry Andric } 21950fca6ea1SDimitry Andric 21960fca6ea1SDimitry Andric return true; 21970fca6ea1SDimitry Andric } 21980fca6ea1SDimitry Andric 2199a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2200a7dea167SDimitry Andric // Zero, Nullptr 2201a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2202a7dea167SDimitry Andric 2203a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 2204a7dea167SDimitry Andric bool Zero(InterpState &S, CodePtr OpPC) { 2205a7dea167SDimitry Andric S.Stk.push<T>(T::zero()); 2206a7dea167SDimitry Andric return true; 2207a7dea167SDimitry Andric } 2208a7dea167SDimitry Andric 22095f757f3fSDimitry Andric static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 22105f757f3fSDimitry Andric S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth)); 22115f757f3fSDimitry Andric return true; 22125f757f3fSDimitry Andric } 22135f757f3fSDimitry Andric 22145f757f3fSDimitry Andric static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 22155f757f3fSDimitry Andric S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth)); 22165f757f3fSDimitry Andric return true; 22175f757f3fSDimitry Andric } 22185f757f3fSDimitry Andric 2219a7dea167SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 22200fca6ea1SDimitry Andric inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 22210fca6ea1SDimitry Andric // Note: Desc can be null. 22220fca6ea1SDimitry Andric S.Stk.push<T>(0, Desc); 2223a7dea167SDimitry Andric return true; 2224a7dea167SDimitry Andric } 2225a7dea167SDimitry Andric 2226a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2227a7dea167SDimitry Andric // This, ImplicitThis 2228a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2229a7dea167SDimitry Andric 2230a7dea167SDimitry Andric inline bool This(InterpState &S, CodePtr OpPC) { 2231a7dea167SDimitry Andric // Cannot read 'this' in this mode. 2232a7dea167SDimitry Andric if (S.checkingPotentialConstantExpression()) { 2233a7dea167SDimitry Andric return false; 2234a7dea167SDimitry Andric } 2235a7dea167SDimitry Andric 2236a7dea167SDimitry Andric const Pointer &This = S.Current->getThis(); 2237a7dea167SDimitry Andric if (!CheckThis(S, OpPC, This)) 2238a7dea167SDimitry Andric return false; 2239a7dea167SDimitry Andric 22400fca6ea1SDimitry Andric // Ensure the This pointer has been cast to the correct base. 22410fca6ea1SDimitry Andric if (!This.isDummy()) { 22420fca6ea1SDimitry Andric assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl())); 22430fca6ea1SDimitry Andric assert(This.getRecord()); 22440fca6ea1SDimitry Andric assert( 22450fca6ea1SDimitry Andric This.getRecord()->getDecl() == 22460fca6ea1SDimitry Andric cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent()); 22470fca6ea1SDimitry Andric } 22480fca6ea1SDimitry Andric 2249a7dea167SDimitry Andric S.Stk.push<Pointer>(This); 2250a7dea167SDimitry Andric return true; 2251a7dea167SDimitry Andric } 2252a7dea167SDimitry Andric 2253bdd1243dSDimitry Andric inline bool RVOPtr(InterpState &S, CodePtr OpPC) { 2254bdd1243dSDimitry Andric assert(S.Current->getFunction()->hasRVO()); 225506c3fb27SDimitry Andric if (S.checkingPotentialConstantExpression()) 225606c3fb27SDimitry Andric return false; 2257bdd1243dSDimitry Andric S.Stk.push<Pointer>(S.Current->getRVOPtr()); 2258bdd1243dSDimitry Andric return true; 2259bdd1243dSDimitry Andric } 2260bdd1243dSDimitry Andric 2261a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2262a7dea167SDimitry Andric // Shr, Shl 2263a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 22640fca6ea1SDimitry Andric enum class ShiftDir { Left, Right }; 22650fca6ea1SDimitry Andric 22660fca6ea1SDimitry Andric template <class LT, class RT, ShiftDir Dir> 22670fca6ea1SDimitry Andric inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { 22680fca6ea1SDimitry Andric const unsigned Bits = LHS.bitWidth(); 22690fca6ea1SDimitry Andric 22700fca6ea1SDimitry Andric // OpenCL 6.3j: shift values are effectively % word size of LHS. 22710fca6ea1SDimitry Andric if (S.getLangOpts().OpenCL) 22720fca6ea1SDimitry Andric RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()), 22730fca6ea1SDimitry Andric RHS.bitWidth(), &RHS); 22740fca6ea1SDimitry Andric 22750fca6ea1SDimitry Andric if (RHS.isNegative()) { 22760fca6ea1SDimitry Andric // During constant-folding, a negative shift is an opposite shift. Such a 22770fca6ea1SDimitry Andric // shift is not a constant expression. 22780fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 22790fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 2280*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 22810fca6ea1SDimitry Andric return false; 22820fca6ea1SDimitry Andric RHS = -RHS; 22830fca6ea1SDimitry Andric return DoShift < LT, RT, 22840fca6ea1SDimitry Andric Dir == ShiftDir::Left ? ShiftDir::Right 22850fca6ea1SDimitry Andric : ShiftDir::Left > (S, OpPC, LHS, RHS); 22860fca6ea1SDimitry Andric } 22870fca6ea1SDimitry Andric 22880fca6ea1SDimitry Andric if constexpr (Dir == ShiftDir::Left) { 22890fca6ea1SDimitry Andric if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) { 22900fca6ea1SDimitry Andric // C++11 [expr.shift]p2: A signed left shift must have a non-negative 22910fca6ea1SDimitry Andric // operand, and must not overflow the corresponding unsigned type. 22920fca6ea1SDimitry Andric // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to 22930fca6ea1SDimitry Andric // E1 x 2^E2 module 2^N. 22940fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 22950fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); 2296*36b606aeSDimitry Andric if (!S.noteUndefinedBehavior()) 22970fca6ea1SDimitry Andric return false; 22980fca6ea1SDimitry Andric } 22990fca6ea1SDimitry Andric } 23000fca6ea1SDimitry Andric 23010fca6ea1SDimitry Andric if (!CheckShift(S, OpPC, LHS, RHS, Bits)) 23020fca6ea1SDimitry Andric return false; 23030fca6ea1SDimitry Andric 23040fca6ea1SDimitry Andric // Limit the shift amount to Bits - 1. If this happened, 23050fca6ea1SDimitry Andric // it has already been diagnosed by CheckShift() above, 23060fca6ea1SDimitry Andric // but we still need to handle it. 23070fca6ea1SDimitry Andric typename LT::AsUnsigned R; 23080fca6ea1SDimitry Andric if constexpr (Dir == ShiftDir::Left) { 23090fca6ea1SDimitry Andric if (RHS > RT::from(Bits - 1, RHS.bitWidth())) 23100fca6ea1SDimitry Andric LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 23110fca6ea1SDimitry Andric LT::AsUnsigned::from(Bits - 1), Bits, &R); 23120fca6ea1SDimitry Andric else 23130fca6ea1SDimitry Andric LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 23140fca6ea1SDimitry Andric LT::AsUnsigned::from(RHS, Bits), Bits, &R); 23150fca6ea1SDimitry Andric } else { 23160fca6ea1SDimitry Andric if (RHS > RT::from(Bits - 1, RHS.bitWidth())) 23170fca6ea1SDimitry Andric LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), 23180fca6ea1SDimitry Andric LT::AsUnsigned::from(Bits - 1), Bits, &R); 23190fca6ea1SDimitry Andric else 23200fca6ea1SDimitry Andric LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), 23210fca6ea1SDimitry Andric LT::AsUnsigned::from(RHS, Bits), Bits, &R); 23220fca6ea1SDimitry Andric } 23230fca6ea1SDimitry Andric 23240fca6ea1SDimitry Andric S.Stk.push<LT>(LT::from(R)); 23250fca6ea1SDimitry Andric return true; 23260fca6ea1SDimitry Andric } 2327a7dea167SDimitry Andric 2328bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR> 2329a7dea167SDimitry Andric inline bool Shr(InterpState &S, CodePtr OpPC) { 2330bdd1243dSDimitry Andric using LT = typename PrimConv<NameL>::T; 2331bdd1243dSDimitry Andric using RT = typename PrimConv<NameR>::T; 23320fca6ea1SDimitry Andric auto RHS = S.Stk.pop<RT>(); 23330fca6ea1SDimitry Andric auto LHS = S.Stk.pop<LT>(); 2334a7dea167SDimitry Andric 23350fca6ea1SDimitry Andric return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS); 2336a7dea167SDimitry Andric } 2337a7dea167SDimitry Andric 2338bdd1243dSDimitry Andric template <PrimType NameL, PrimType NameR> 2339a7dea167SDimitry Andric inline bool Shl(InterpState &S, CodePtr OpPC) { 2340bdd1243dSDimitry Andric using LT = typename PrimConv<NameL>::T; 2341bdd1243dSDimitry Andric using RT = typename PrimConv<NameR>::T; 23420fca6ea1SDimitry Andric auto RHS = S.Stk.pop<RT>(); 23430fca6ea1SDimitry Andric auto LHS = S.Stk.pop<LT>(); 2344a7dea167SDimitry Andric 23450fca6ea1SDimitry Andric return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS); 2346a7dea167SDimitry Andric } 2347a7dea167SDimitry Andric 2348a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2349a7dea167SDimitry Andric // NoRet 2350a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2351a7dea167SDimitry Andric 2352a7dea167SDimitry Andric inline bool NoRet(InterpState &S, CodePtr OpPC) { 2353a7dea167SDimitry Andric SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 2354a7dea167SDimitry Andric S.FFDiag(EndLoc, diag::note_constexpr_no_return); 2355a7dea167SDimitry Andric return false; 2356a7dea167SDimitry Andric } 2357a7dea167SDimitry Andric 2358a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2359a7dea167SDimitry Andric // NarrowPtr, ExpandPtr 2360a7dea167SDimitry Andric //===----------------------------------------------------------------------===// 2361a7dea167SDimitry Andric 2362a7dea167SDimitry Andric inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 2363a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 2364a7dea167SDimitry Andric S.Stk.push<Pointer>(Ptr.narrow()); 2365a7dea167SDimitry Andric return true; 2366a7dea167SDimitry Andric } 2367a7dea167SDimitry Andric 2368a7dea167SDimitry Andric inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 2369a7dea167SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 2370a7dea167SDimitry Andric S.Stk.push<Pointer>(Ptr.expand()); 2371a7dea167SDimitry Andric return true; 2372a7dea167SDimitry Andric } 2373a7dea167SDimitry Andric 237406c3fb27SDimitry Andric // 1) Pops an integral value from the stack 237506c3fb27SDimitry Andric // 2) Peeks a pointer 237606c3fb27SDimitry Andric // 3) Pushes a new pointer that's a narrowed array 237706c3fb27SDimitry Andric // element of the peeked pointer with the value 237806c3fb27SDimitry Andric // from 1) added as offset. 237906c3fb27SDimitry Andric // 238006c3fb27SDimitry Andric // This leaves the original pointer on the stack and pushes a new one 238106c3fb27SDimitry Andric // with the offset applied and narrowed. 238206c3fb27SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 238306c3fb27SDimitry Andric inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { 238406c3fb27SDimitry Andric const T &Offset = S.Stk.pop<T>(); 238506c3fb27SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 238606c3fb27SDimitry Andric 23870fca6ea1SDimitry Andric if (!Ptr.isZero()) { 23880fca6ea1SDimitry Andric if (!CheckArray(S, OpPC, Ptr)) 23890fca6ea1SDimitry Andric return false; 23900fca6ea1SDimitry Andric } 23910fca6ea1SDimitry Andric 239206c3fb27SDimitry Andric if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 239306c3fb27SDimitry Andric return false; 239406c3fb27SDimitry Andric 239506c3fb27SDimitry Andric return NarrowPtr(S, OpPC); 239606c3fb27SDimitry Andric } 239706c3fb27SDimitry Andric 23980fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 23990fca6ea1SDimitry Andric inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { 24000fca6ea1SDimitry Andric const T &Offset = S.Stk.pop<T>(); 24010fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 24020fca6ea1SDimitry Andric 24030fca6ea1SDimitry Andric if (!Ptr.isZero()) { 24040fca6ea1SDimitry Andric if (!CheckArray(S, OpPC, Ptr)) 24050fca6ea1SDimitry Andric return false; 24060fca6ea1SDimitry Andric } 24070fca6ea1SDimitry Andric 24080fca6ea1SDimitry Andric if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 24090fca6ea1SDimitry Andric return false; 24100fca6ea1SDimitry Andric 24110fca6ea1SDimitry Andric return NarrowPtr(S, OpPC); 24120fca6ea1SDimitry Andric } 24130fca6ea1SDimitry Andric 24140fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 24150fca6ea1SDimitry Andric inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) { 24160fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.peek<Pointer>(); 24170fca6ea1SDimitry Andric 24180fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr)) 24190fca6ea1SDimitry Andric return false; 24200fca6ea1SDimitry Andric 24210fca6ea1SDimitry Andric S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); 24220fca6ea1SDimitry Andric return true; 24230fca6ea1SDimitry Andric } 24240fca6ea1SDimitry Andric 24250fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 24260fca6ea1SDimitry Andric inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { 24270fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 24280fca6ea1SDimitry Andric 24290fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, Ptr)) 24300fca6ea1SDimitry Andric return false; 24310fca6ea1SDimitry Andric 24320fca6ea1SDimitry Andric S.Stk.push<T>(Ptr.atIndex(Index).deref<T>()); 24330fca6ea1SDimitry Andric return true; 24340fca6ea1SDimitry Andric } 24350fca6ea1SDimitry Andric 24360fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 24370fca6ea1SDimitry Andric inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) { 24380fca6ea1SDimitry Andric const auto &SrcPtr = S.Stk.pop<Pointer>(); 24390fca6ea1SDimitry Andric const auto &DestPtr = S.Stk.peek<Pointer>(); 24400fca6ea1SDimitry Andric 24410fca6ea1SDimitry Andric for (uint32_t I = 0; I != Size; ++I) { 24420fca6ea1SDimitry Andric const Pointer &SP = SrcPtr.atIndex(SrcIndex + I); 24430fca6ea1SDimitry Andric 24440fca6ea1SDimitry Andric if (!CheckLoad(S, OpPC, SP)) 24450fca6ea1SDimitry Andric return false; 24460fca6ea1SDimitry Andric 24470fca6ea1SDimitry Andric const Pointer &DP = DestPtr.atIndex(DestIndex + I); 24480fca6ea1SDimitry Andric DP.deref<T>() = SP.deref<T>(); 24490fca6ea1SDimitry Andric DP.initialize(); 24500fca6ea1SDimitry Andric } 24510fca6ea1SDimitry Andric return true; 24520fca6ea1SDimitry Andric } 24530fca6ea1SDimitry Andric 24540fca6ea1SDimitry Andric /// Just takes a pointer and checks if it's an incomplete 24555f757f3fSDimitry Andric /// array type. 24565f757f3fSDimitry Andric inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { 24575f757f3fSDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 24585f757f3fSDimitry Andric 24590fca6ea1SDimitry Andric if (Ptr.isZero()) { 24600fca6ea1SDimitry Andric S.Stk.push<Pointer>(Ptr); 24610fca6ea1SDimitry Andric return true; 24620fca6ea1SDimitry Andric } 24630fca6ea1SDimitry Andric 24640fca6ea1SDimitry Andric if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 24650fca6ea1SDimitry Andric return false; 24660fca6ea1SDimitry Andric 24670fca6ea1SDimitry Andric if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) { 24685f757f3fSDimitry Andric S.Stk.push<Pointer>(Ptr.atIndex(0)); 24695f757f3fSDimitry Andric return true; 24705f757f3fSDimitry Andric } 24715f757f3fSDimitry Andric 24725f757f3fSDimitry Andric const SourceInfo &E = S.Current->getSource(OpPC); 24735f757f3fSDimitry Andric S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array); 24745f757f3fSDimitry Andric 24755f757f3fSDimitry Andric return false; 24765f757f3fSDimitry Andric } 24775f757f3fSDimitry Andric 24780fca6ea1SDimitry Andric inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func, 24790fca6ea1SDimitry Andric uint32_t VarArgSize) { 2480bdd1243dSDimitry Andric if (Func->hasThisPointer()) { 24810fca6ea1SDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize; 24820fca6ea1SDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 248306c3fb27SDimitry Andric const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 248406c3fb27SDimitry Andric 24855f757f3fSDimitry Andric // If the current function is a lambda static invoker and 24865f757f3fSDimitry Andric // the function we're about to call is a lambda call operator, 24875f757f3fSDimitry Andric // skip the CheckInvoke, since the ThisPtr is a null pointer 24885f757f3fSDimitry Andric // anyway. 24895f757f3fSDimitry Andric if (!(S.Current->getFunction() && 24905f757f3fSDimitry Andric S.Current->getFunction()->isLambdaStaticInvoker() && 24915f757f3fSDimitry Andric Func->isLambdaCallOperator())) { 249206c3fb27SDimitry Andric if (!CheckInvoke(S, OpPC, ThisPtr)) 2493bdd1243dSDimitry Andric return false; 24945f757f3fSDimitry Andric } 2495bdd1243dSDimitry Andric 249606c3fb27SDimitry Andric if (S.checkingPotentialConstantExpression()) 249706c3fb27SDimitry Andric return false; 249806c3fb27SDimitry Andric } 249906c3fb27SDimitry Andric 250006c3fb27SDimitry Andric if (!CheckCallable(S, OpPC, Func)) 250106c3fb27SDimitry Andric return false; 250206c3fb27SDimitry Andric 250306c3fb27SDimitry Andric if (!CheckCallDepth(S, OpPC)) 250406c3fb27SDimitry Andric return false; 250506c3fb27SDimitry Andric 25060fca6ea1SDimitry Andric auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize); 25070fca6ea1SDimitry Andric InterpFrame *FrameBefore = S.Current; 25080fca6ea1SDimitry Andric S.Current = NewFrame.get(); 25090fca6ea1SDimitry Andric 25100fca6ea1SDimitry Andric APValue CallResult; 25110fca6ea1SDimitry Andric // Note that we cannot assert(CallResult.hasValue()) here since 25120fca6ea1SDimitry Andric // Ret() above only sets the APValue if the curent frame doesn't 25130fca6ea1SDimitry Andric // have a caller set. 25140fca6ea1SDimitry Andric if (Interpret(S, CallResult)) { 25150fca6ea1SDimitry Andric NewFrame.release(); // Frame was delete'd already. 25160fca6ea1SDimitry Andric assert(S.Current == FrameBefore); 25170fca6ea1SDimitry Andric return true; 25180fca6ea1SDimitry Andric } 25190fca6ea1SDimitry Andric 25200fca6ea1SDimitry Andric // Interpreting the function failed somehow. Reset to 25210fca6ea1SDimitry Andric // previous state. 25220fca6ea1SDimitry Andric S.Current = FrameBefore; 25230fca6ea1SDimitry Andric return false; 25240fca6ea1SDimitry Andric 25250fca6ea1SDimitry Andric return false; 25260fca6ea1SDimitry Andric } 25270fca6ea1SDimitry Andric 25280fca6ea1SDimitry Andric inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func, 25290fca6ea1SDimitry Andric uint32_t VarArgSize) { 25300fca6ea1SDimitry Andric if (Func->hasThisPointer()) { 25310fca6ea1SDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize; 25320fca6ea1SDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 25330fca6ea1SDimitry Andric 25340fca6ea1SDimitry Andric const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 25350fca6ea1SDimitry Andric 25360fca6ea1SDimitry Andric // If the current function is a lambda static invoker and 25370fca6ea1SDimitry Andric // the function we're about to call is a lambda call operator, 25380fca6ea1SDimitry Andric // skip the CheckInvoke, since the ThisPtr is a null pointer 25390fca6ea1SDimitry Andric // anyway. 25400fca6ea1SDimitry Andric if (!(S.Current->getFunction() && 25410fca6ea1SDimitry Andric S.Current->getFunction()->isLambdaStaticInvoker() && 25420fca6ea1SDimitry Andric Func->isLambdaCallOperator())) { 25430fca6ea1SDimitry Andric if (!CheckInvoke(S, OpPC, ThisPtr)) 25440fca6ea1SDimitry Andric return false; 25450fca6ea1SDimitry Andric } 25460fca6ea1SDimitry Andric } 25470fca6ea1SDimitry Andric 25480fca6ea1SDimitry Andric if (!CheckCallable(S, OpPC, Func)) 25490fca6ea1SDimitry Andric return false; 25500fca6ea1SDimitry Andric 25510fca6ea1SDimitry Andric if (Func->hasThisPointer() && S.checkingPotentialConstantExpression()) 25520fca6ea1SDimitry Andric return false; 25530fca6ea1SDimitry Andric 25540fca6ea1SDimitry Andric if (!CheckCallDepth(S, OpPC)) 25550fca6ea1SDimitry Andric return false; 25560fca6ea1SDimitry Andric 25570fca6ea1SDimitry Andric auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize); 2558bdd1243dSDimitry Andric InterpFrame *FrameBefore = S.Current; 2559bdd1243dSDimitry Andric S.Current = NewFrame.get(); 2560bdd1243dSDimitry Andric 2561bdd1243dSDimitry Andric APValue CallResult; 2562bdd1243dSDimitry Andric // Note that we cannot assert(CallResult.hasValue()) here since 2563bdd1243dSDimitry Andric // Ret() above only sets the APValue if the curent frame doesn't 2564bdd1243dSDimitry Andric // have a caller set. 2565bdd1243dSDimitry Andric if (Interpret(S, CallResult)) { 2566bdd1243dSDimitry Andric NewFrame.release(); // Frame was delete'd already. 2567bdd1243dSDimitry Andric assert(S.Current == FrameBefore); 2568bdd1243dSDimitry Andric return true; 2569bdd1243dSDimitry Andric } 2570bdd1243dSDimitry Andric 2571bdd1243dSDimitry Andric // Interpreting the function failed somehow. Reset to 2572bdd1243dSDimitry Andric // previous state. 2573bdd1243dSDimitry Andric S.Current = FrameBefore; 2574bdd1243dSDimitry Andric return false; 2575bdd1243dSDimitry Andric } 2576bdd1243dSDimitry Andric 25770fca6ea1SDimitry Andric inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func, 25780fca6ea1SDimitry Andric uint32_t VarArgSize) { 257906c3fb27SDimitry Andric assert(Func->hasThisPointer()); 258006c3fb27SDimitry Andric assert(Func->isVirtual()); 25810fca6ea1SDimitry Andric size_t ArgSize = Func->getArgSize() + VarArgSize; 25820fca6ea1SDimitry Andric size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 258306c3fb27SDimitry Andric Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 258406c3fb27SDimitry Andric 25850fca6ea1SDimitry Andric QualType DynamicType = ThisPtr.getDeclDesc()->getType(); 25860fca6ea1SDimitry Andric const CXXRecordDecl *DynamicDecl; 25870fca6ea1SDimitry Andric if (DynamicType->isPointerType() || DynamicType->isReferenceType()) 25880fca6ea1SDimitry Andric DynamicDecl = DynamicType->getPointeeCXXRecordDecl(); 25890fca6ea1SDimitry Andric else 25900fca6ea1SDimitry Andric DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl(); 259106c3fb27SDimitry Andric const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl()); 259206c3fb27SDimitry Andric const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl()); 259306c3fb27SDimitry Andric const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( 259406c3fb27SDimitry Andric DynamicDecl, StaticDecl, InitialFunction); 259506c3fb27SDimitry Andric 259606c3fb27SDimitry Andric if (Overrider != InitialFunction) { 25975f757f3fSDimitry Andric // DR1872: An instantiated virtual constexpr function can't be called in a 25985f757f3fSDimitry Andric // constant expression (prior to C++20). We can still constant-fold such a 25995f757f3fSDimitry Andric // call. 26005f757f3fSDimitry Andric if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) { 26015f757f3fSDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 26025f757f3fSDimitry Andric S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange(); 26035f757f3fSDimitry Andric } 26045f757f3fSDimitry Andric 26055f757f3fSDimitry Andric Func = S.getContext().getOrCreateFunction(Overrider); 260606c3fb27SDimitry Andric 260706c3fb27SDimitry Andric const CXXRecordDecl *ThisFieldDecl = 260806c3fb27SDimitry Andric ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl(); 260906c3fb27SDimitry Andric if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) { 261006c3fb27SDimitry Andric // If the function we call is further DOWN the hierarchy than the 261106c3fb27SDimitry Andric // FieldDesc of our pointer, just get the DeclDesc instead, which 261206c3fb27SDimitry Andric // is the furthest we might go up in the hierarchy. 261306c3fb27SDimitry Andric ThisPtr = ThisPtr.getDeclPtr(); 261406c3fb27SDimitry Andric } 261506c3fb27SDimitry Andric } 261606c3fb27SDimitry Andric 26170fca6ea1SDimitry Andric return Call(S, OpPC, Func, VarArgSize); 261806c3fb27SDimitry Andric } 261906c3fb27SDimitry Andric 26205f757f3fSDimitry Andric inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, 26215f757f3fSDimitry Andric const CallExpr *CE) { 262206c3fb27SDimitry Andric auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC); 262306c3fb27SDimitry Andric 262406c3fb27SDimitry Andric InterpFrame *FrameBefore = S.Current; 262506c3fb27SDimitry Andric S.Current = NewFrame.get(); 262606c3fb27SDimitry Andric 26275f757f3fSDimitry Andric if (InterpretBuiltin(S, PC, Func, CE)) { 262806c3fb27SDimitry Andric NewFrame.release(); 262906c3fb27SDimitry Andric return true; 263006c3fb27SDimitry Andric } 263106c3fb27SDimitry Andric S.Current = FrameBefore; 263206c3fb27SDimitry Andric return false; 263306c3fb27SDimitry Andric } 263406c3fb27SDimitry Andric 26350fca6ea1SDimitry Andric inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, 26360fca6ea1SDimitry Andric const CallExpr *CE) { 263706c3fb27SDimitry Andric const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>(); 263806c3fb27SDimitry Andric 263906c3fb27SDimitry Andric const Function *F = FuncPtr.getFunction(); 26400fca6ea1SDimitry Andric if (!F) { 26410fca6ea1SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 26420fca6ea1SDimitry Andric S.FFDiag(E, diag::note_constexpr_null_callee) 26430fca6ea1SDimitry Andric << const_cast<Expr *>(E) << E->getSourceRange(); 26440fca6ea1SDimitry Andric return false; 26450fca6ea1SDimitry Andric } 26460fca6ea1SDimitry Andric 26470fca6ea1SDimitry Andric if (!FuncPtr.isValid()) 264806c3fb27SDimitry Andric return false; 264906c3fb27SDimitry Andric 26500fca6ea1SDimitry Andric assert(F); 26515f757f3fSDimitry Andric 26520fca6ea1SDimitry Andric // This happens when the call expression has been cast to 26530fca6ea1SDimitry Andric // something else, but we don't support that. 26540fca6ea1SDimitry Andric if (S.Ctx.classify(F->getDecl()->getReturnType()) != 26550fca6ea1SDimitry Andric S.Ctx.classify(CE->getType())) 26560fca6ea1SDimitry Andric return false; 26570fca6ea1SDimitry Andric 26580fca6ea1SDimitry Andric // Check argument nullability state. 26590fca6ea1SDimitry Andric if (F->hasNonNullAttr()) { 26600fca6ea1SDimitry Andric if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize)) 26610fca6ea1SDimitry Andric return false; 26620fca6ea1SDimitry Andric } 26630fca6ea1SDimitry Andric 26640fca6ea1SDimitry Andric assert(ArgSize >= F->getWrittenArgSize()); 26650fca6ea1SDimitry Andric uint32_t VarArgSize = ArgSize - F->getWrittenArgSize(); 26660fca6ea1SDimitry Andric 26670fca6ea1SDimitry Andric // We need to do this explicitly here since we don't have the necessary 26680fca6ea1SDimitry Andric // information to do it automatically. 26690fca6ea1SDimitry Andric if (F->isThisPointerExplicit()) 26700fca6ea1SDimitry Andric VarArgSize -= align(primSize(PT_Ptr)); 26710fca6ea1SDimitry Andric 26720fca6ea1SDimitry Andric if (F->isVirtual()) 26730fca6ea1SDimitry Andric return CallVirt(S, OpPC, F, VarArgSize); 26740fca6ea1SDimitry Andric 26750fca6ea1SDimitry Andric return Call(S, OpPC, F, VarArgSize); 267606c3fb27SDimitry Andric } 267706c3fb27SDimitry Andric 267806c3fb27SDimitry Andric inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { 267906c3fb27SDimitry Andric assert(Func); 268006c3fb27SDimitry Andric S.Stk.push<FunctionPointer>(Func); 268106c3fb27SDimitry Andric return true; 268206c3fb27SDimitry Andric } 268306c3fb27SDimitry Andric 26840fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 26850fca6ea1SDimitry Andric inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 26860fca6ea1SDimitry Andric const T &IntVal = S.Stk.pop<T>(); 26870fca6ea1SDimitry Andric 26880fca6ea1SDimitry Andric S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc); 26890fca6ea1SDimitry Andric return true; 26900fca6ea1SDimitry Andric } 26910fca6ea1SDimitry Andric 26920fca6ea1SDimitry Andric inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) { 26930fca6ea1SDimitry Andric S.Stk.push<MemberPointer>(D); 26940fca6ea1SDimitry Andric return true; 26950fca6ea1SDimitry Andric } 26960fca6ea1SDimitry Andric 26970fca6ea1SDimitry Andric inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) { 26980fca6ea1SDimitry Andric const auto &MP = S.Stk.pop<MemberPointer>(); 26990fca6ea1SDimitry Andric 27000fca6ea1SDimitry Andric S.Stk.push<Pointer>(MP.getBase()); 27010fca6ea1SDimitry Andric return true; 27020fca6ea1SDimitry Andric } 27030fca6ea1SDimitry Andric 27040fca6ea1SDimitry Andric inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) { 27050fca6ea1SDimitry Andric const auto &MP = S.Stk.pop<MemberPointer>(); 27060fca6ea1SDimitry Andric 27070fca6ea1SDimitry Andric const auto *FD = cast<FunctionDecl>(MP.getDecl()); 27080fca6ea1SDimitry Andric const auto *Func = S.getContext().getOrCreateFunction(FD); 27090fca6ea1SDimitry Andric 27100fca6ea1SDimitry Andric S.Stk.push<FunctionPointer>(Func); 27110fca6ea1SDimitry Andric return true; 27120fca6ea1SDimitry Andric } 27130fca6ea1SDimitry Andric 27145f757f3fSDimitry Andric /// Just emit a diagnostic. The expression that caused emission of this 27155f757f3fSDimitry Andric /// op is not valid in a constant context. 27165f757f3fSDimitry Andric inline bool Invalid(InterpState &S, CodePtr OpPC) { 27175f757f3fSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 27185f757f3fSDimitry Andric S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) 27195f757f3fSDimitry Andric << S.Current->getRange(OpPC); 27205f757f3fSDimitry Andric return false; 27215f757f3fSDimitry Andric } 27225f757f3fSDimitry Andric 27230fca6ea1SDimitry Andric inline bool Unsupported(InterpState &S, CodePtr OpPC) { 27240fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 27250fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported) 27260fca6ea1SDimitry Andric << S.Current->getRange(OpPC); 27270fca6ea1SDimitry Andric return false; 27280fca6ea1SDimitry Andric } 27290fca6ea1SDimitry Andric 27300fca6ea1SDimitry Andric /// Do nothing and just abort execution. 27310fca6ea1SDimitry Andric inline bool Error(InterpState &S, CodePtr OpPC) { return false; } 27320fca6ea1SDimitry Andric 27335f757f3fSDimitry Andric /// Same here, but only for casts. 27345f757f3fSDimitry Andric inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) { 27355f757f3fSDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 27360fca6ea1SDimitry Andric 27370fca6ea1SDimitry Andric // FIXME: Support diagnosing other invalid cast kinds. 27380fca6ea1SDimitry Andric if (Kind == CastKind::Reinterpret) 27395f757f3fSDimitry Andric S.FFDiag(Loc, diag::note_constexpr_invalid_cast) 27405f757f3fSDimitry Andric << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC); 27415f757f3fSDimitry Andric return false; 27425f757f3fSDimitry Andric } 27435f757f3fSDimitry Andric 27445f757f3fSDimitry Andric inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, 27455f757f3fSDimitry Andric const DeclRefExpr *DR) { 27465f757f3fSDimitry Andric assert(DR); 27475f757f3fSDimitry Andric return CheckDeclRef(S, OpPC, DR); 27485f757f3fSDimitry Andric } 27495f757f3fSDimitry Andric 27500fca6ea1SDimitry Andric inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) { 27510fca6ea1SDimitry Andric if (S.inConstantContext()) { 27520fca6ea1SDimitry Andric const SourceRange &ArgRange = S.Current->getRange(OpPC); 27530fca6ea1SDimitry Andric const Expr *E = S.Current->getExpr(OpPC); 27540fca6ea1SDimitry Andric S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange; 27550fca6ea1SDimitry Andric } 27560fca6ea1SDimitry Andric return false; 27570fca6ea1SDimitry Andric } 27580fca6ea1SDimitry Andric 27590fca6ea1SDimitry Andric inline bool Assume(InterpState &S, CodePtr OpPC) { 27600fca6ea1SDimitry Andric const auto Val = S.Stk.pop<Boolean>(); 27610fca6ea1SDimitry Andric 27620fca6ea1SDimitry Andric if (Val) 27630fca6ea1SDimitry Andric return true; 27640fca6ea1SDimitry Andric 27650fca6ea1SDimitry Andric // Else, diagnose. 27660fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 27670fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_constexpr_assumption_failed); 27680fca6ea1SDimitry Andric return false; 27690fca6ea1SDimitry Andric } 27700fca6ea1SDimitry Andric 27715f757f3fSDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 27725f757f3fSDimitry Andric inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) { 27735f757f3fSDimitry Andric llvm::SmallVector<int64_t> ArrayIndices; 27745f757f3fSDimitry Andric for (size_t I = 0; I != E->getNumExpressions(); ++I) 27755f757f3fSDimitry Andric ArrayIndices.emplace_back(S.Stk.pop<int64_t>()); 27765f757f3fSDimitry Andric 27775f757f3fSDimitry Andric int64_t Result; 27785f757f3fSDimitry Andric if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result)) 27795f757f3fSDimitry Andric return false; 27805f757f3fSDimitry Andric 27815f757f3fSDimitry Andric S.Stk.push<T>(T::from(Result)); 27825f757f3fSDimitry Andric 27835f757f3fSDimitry Andric return true; 27845f757f3fSDimitry Andric } 27855f757f3fSDimitry Andric 27860fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 27870fca6ea1SDimitry Andric inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) { 27880fca6ea1SDimitry Andric const T &Arg = S.Stk.peek<T>(); 27890fca6ea1SDimitry Andric if (!Arg.isZero()) 27900fca6ea1SDimitry Andric return true; 27910fca6ea1SDimitry Andric 27920fca6ea1SDimitry Andric const SourceLocation &Loc = S.Current->getLocation(OpPC); 27930fca6ea1SDimitry Andric S.CCEDiag(Loc, diag::note_non_null_attribute_failed); 27940fca6ea1SDimitry Andric 27950fca6ea1SDimitry Andric return false; 27960fca6ea1SDimitry Andric } 27970fca6ea1SDimitry Andric 27980fca6ea1SDimitry Andric void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED, 27990fca6ea1SDimitry Andric const APSInt &Value); 28000fca6ea1SDimitry Andric 28010fca6ea1SDimitry Andric template <PrimType Name, class T = typename PrimConv<Name>::T> 28020fca6ea1SDimitry Andric inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) { 28030fca6ea1SDimitry Andric assert(ED); 28040fca6ea1SDimitry Andric assert(!ED->isFixed()); 28050fca6ea1SDimitry Andric const APSInt Val = S.Stk.peek<T>().toAPSInt(); 28060fca6ea1SDimitry Andric 28070fca6ea1SDimitry Andric if (S.inConstantContext()) 28080fca6ea1SDimitry Andric diagnoseEnumValue(S, OpPC, ED, Val); 28090fca6ea1SDimitry Andric return true; 28100fca6ea1SDimitry Andric } 28110fca6ea1SDimitry Andric 28120fca6ea1SDimitry Andric /// OldPtr -> Integer -> NewPtr. 28130fca6ea1SDimitry Andric template <PrimType TIn, PrimType TOut> 28140fca6ea1SDimitry Andric inline bool DecayPtr(InterpState &S, CodePtr OpPC) { 28150fca6ea1SDimitry Andric static_assert(isPtrType(TIn) && isPtrType(TOut)); 28160fca6ea1SDimitry Andric using FromT = typename PrimConv<TIn>::T; 28170fca6ea1SDimitry Andric using ToT = typename PrimConv<TOut>::T; 28180fca6ea1SDimitry Andric 28190fca6ea1SDimitry Andric const FromT &OldPtr = S.Stk.pop<FromT>(); 28200fca6ea1SDimitry Andric S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr)); 28210fca6ea1SDimitry Andric return true; 28220fca6ea1SDimitry Andric } 28230fca6ea1SDimitry Andric 28240fca6ea1SDimitry Andric inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) { 28250fca6ea1SDimitry Andric // An expression E is a core constant expression unless the evaluation of E 28260fca6ea1SDimitry Andric // would evaluate one of the following: [C++23] - a control flow that passes 28270fca6ea1SDimitry Andric // through a declaration of a variable with static or thread storage duration 28280fca6ea1SDimitry Andric // unless that variable is usable in constant expressions. 28290fca6ea1SDimitry Andric assert(VD->isLocalVarDecl() && 28300fca6ea1SDimitry Andric VD->isStaticLocal()); // Checked before emitting this. 28310fca6ea1SDimitry Andric 28320fca6ea1SDimitry Andric if (VD == S.EvaluatingDecl) 28330fca6ea1SDimitry Andric return true; 28340fca6ea1SDimitry Andric 28350fca6ea1SDimitry Andric if (!VD->isUsableInConstantExpressions(S.getCtx())) { 28360fca6ea1SDimitry Andric S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local) 28370fca6ea1SDimitry Andric << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD; 28380fca6ea1SDimitry Andric return false; 28390fca6ea1SDimitry Andric } 28400fca6ea1SDimitry Andric return true; 28410fca6ea1SDimitry Andric } 28420fca6ea1SDimitry Andric 28430fca6ea1SDimitry Andric inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) { 28440fca6ea1SDimitry Andric assert(Desc); 28450fca6ea1SDimitry Andric 28460fca6ea1SDimitry Andric if (!CheckDynamicMemoryAllocation(S, OpPC)) 28470fca6ea1SDimitry Andric return false; 28480fca6ea1SDimitry Andric 28490fca6ea1SDimitry Andric DynamicAllocator &Allocator = S.getAllocator(); 28500fca6ea1SDimitry Andric Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID()); 28510fca6ea1SDimitry Andric assert(B); 28520fca6ea1SDimitry Andric 28530fca6ea1SDimitry Andric S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 28540fca6ea1SDimitry Andric 28550fca6ea1SDimitry Andric return true; 28560fca6ea1SDimitry Andric } 28570fca6ea1SDimitry Andric 28580fca6ea1SDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T> 28590fca6ea1SDimitry Andric inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source, 28600fca6ea1SDimitry Andric bool IsNoThrow) { 28610fca6ea1SDimitry Andric if (!CheckDynamicMemoryAllocation(S, OpPC)) 28620fca6ea1SDimitry Andric return false; 28630fca6ea1SDimitry Andric 28640fca6ea1SDimitry Andric SizeT NumElements = S.Stk.pop<SizeT>(); 28650fca6ea1SDimitry Andric if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) { 28660fca6ea1SDimitry Andric if (!IsNoThrow) 28670fca6ea1SDimitry Andric return false; 28680fca6ea1SDimitry Andric 28690fca6ea1SDimitry Andric // If this failed and is nothrow, just return a null ptr. 28700fca6ea1SDimitry Andric S.Stk.push<Pointer>(0, nullptr); 28710fca6ea1SDimitry Andric return true; 28720fca6ea1SDimitry Andric } 28730fca6ea1SDimitry Andric 28740fca6ea1SDimitry Andric DynamicAllocator &Allocator = S.getAllocator(); 28750fca6ea1SDimitry Andric Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements), 28760fca6ea1SDimitry Andric S.Ctx.getEvalID()); 28770fca6ea1SDimitry Andric assert(B); 28780fca6ea1SDimitry Andric S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 28790fca6ea1SDimitry Andric 28800fca6ea1SDimitry Andric return true; 28810fca6ea1SDimitry Andric } 28820fca6ea1SDimitry Andric 28830fca6ea1SDimitry Andric template <PrimType Name, class SizeT = typename PrimConv<Name>::T> 28840fca6ea1SDimitry Andric inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc, 28850fca6ea1SDimitry Andric bool IsNoThrow) { 28860fca6ea1SDimitry Andric if (!CheckDynamicMemoryAllocation(S, OpPC)) 28870fca6ea1SDimitry Andric return false; 28880fca6ea1SDimitry Andric 28890fca6ea1SDimitry Andric SizeT NumElements = S.Stk.pop<SizeT>(); 28900fca6ea1SDimitry Andric if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(), 28910fca6ea1SDimitry Andric IsNoThrow)) { 28920fca6ea1SDimitry Andric if (!IsNoThrow) 28930fca6ea1SDimitry Andric return false; 28940fca6ea1SDimitry Andric 28950fca6ea1SDimitry Andric // If this failed and is nothrow, just return a null ptr. 28960fca6ea1SDimitry Andric S.Stk.push<Pointer>(0, ElementDesc); 28970fca6ea1SDimitry Andric return true; 28980fca6ea1SDimitry Andric } 28990fca6ea1SDimitry Andric 29000fca6ea1SDimitry Andric DynamicAllocator &Allocator = S.getAllocator(); 29010fca6ea1SDimitry Andric Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements), 29020fca6ea1SDimitry Andric S.Ctx.getEvalID()); 29030fca6ea1SDimitry Andric assert(B); 29040fca6ea1SDimitry Andric 29050fca6ea1SDimitry Andric S.Stk.push<Pointer>(B, sizeof(InlineDescriptor)); 29060fca6ea1SDimitry Andric 29070fca6ea1SDimitry Andric return true; 29080fca6ea1SDimitry Andric } 29090fca6ea1SDimitry Andric 29100fca6ea1SDimitry Andric bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B); 29110fca6ea1SDimitry Andric static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) { 29120fca6ea1SDimitry Andric if (!CheckDynamicMemoryAllocation(S, OpPC)) 29130fca6ea1SDimitry Andric return false; 29140fca6ea1SDimitry Andric 29150fca6ea1SDimitry Andric const Expr *Source = nullptr; 29160fca6ea1SDimitry Andric const Block *BlockToDelete = nullptr; 29170fca6ea1SDimitry Andric { 29180fca6ea1SDimitry Andric // Extra scope for this so the block doesn't have this pointer 29190fca6ea1SDimitry Andric // pointing to it when we destroy it. 29200fca6ea1SDimitry Andric const Pointer &Ptr = S.Stk.pop<Pointer>(); 29210fca6ea1SDimitry Andric 29220fca6ea1SDimitry Andric // Deleteing nullptr is always fine. 29230fca6ea1SDimitry Andric if (Ptr.isZero()) 29240fca6ea1SDimitry Andric return true; 29250fca6ea1SDimitry Andric 29260fca6ea1SDimitry Andric if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) { 29270fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 29280fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_delete_subobject) 29290fca6ea1SDimitry Andric << Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd(); 29300fca6ea1SDimitry Andric return false; 29310fca6ea1SDimitry Andric } 29320fca6ea1SDimitry Andric 29330fca6ea1SDimitry Andric Source = Ptr.getDeclDesc()->asExpr(); 29340fca6ea1SDimitry Andric BlockToDelete = Ptr.block(); 29350fca6ea1SDimitry Andric 29360fca6ea1SDimitry Andric if (!CheckDeleteSource(S, OpPC, Source, Ptr)) 29370fca6ea1SDimitry Andric return false; 29380fca6ea1SDimitry Andric } 29390fca6ea1SDimitry Andric assert(Source); 29400fca6ea1SDimitry Andric assert(BlockToDelete); 29410fca6ea1SDimitry Andric 29420fca6ea1SDimitry Andric // Invoke destructors before deallocating the memory. 29430fca6ea1SDimitry Andric if (!RunDestructors(S, OpPC, BlockToDelete)) 29440fca6ea1SDimitry Andric return false; 29450fca6ea1SDimitry Andric 29460fca6ea1SDimitry Andric DynamicAllocator &Allocator = S.getAllocator(); 29470fca6ea1SDimitry Andric bool WasArrayAlloc = Allocator.isArrayAllocation(Source); 29480fca6ea1SDimitry Andric const Descriptor *BlockDesc = BlockToDelete->getDescriptor(); 29490fca6ea1SDimitry Andric 29500fca6ea1SDimitry Andric if (!Allocator.deallocate(Source, BlockToDelete, S)) { 29510fca6ea1SDimitry Andric // Nothing has been deallocated, this must be a double-delete. 29520fca6ea1SDimitry Andric const SourceInfo &Loc = S.Current->getSource(OpPC); 29530fca6ea1SDimitry Andric S.FFDiag(Loc, diag::note_constexpr_double_delete); 29540fca6ea1SDimitry Andric return false; 29550fca6ea1SDimitry Andric } 29560fca6ea1SDimitry Andric return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm, 29570fca6ea1SDimitry Andric BlockDesc, Source); 29580fca6ea1SDimitry Andric } 29590fca6ea1SDimitry Andric 2960349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 2961349cc55cSDimitry Andric // Read opcode arguments 2962349cc55cSDimitry Andric //===----------------------------------------------------------------------===// 2963349cc55cSDimitry Andric 2964bdd1243dSDimitry Andric template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { 2965bdd1243dSDimitry Andric if constexpr (std::is_pointer<T>::value) { 2966349cc55cSDimitry Andric uint32_t ID = OpPC.read<uint32_t>(); 2967349cc55cSDimitry Andric return reinterpret_cast<T>(S.P.getNativePointer(ID)); 2968bdd1243dSDimitry Andric } else { 2969bdd1243dSDimitry Andric return OpPC.read<T>(); 2970349cc55cSDimitry Andric } 2971bdd1243dSDimitry Andric } 2972a7dea167SDimitry Andric 29735f757f3fSDimitry Andric template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { 29745f757f3fSDimitry Andric Floating F = Floating::deserialize(*OpPC); 29755f757f3fSDimitry Andric OpPC += align(F.bytesToSerialize()); 29765f757f3fSDimitry Andric return F; 29775f757f3fSDimitry Andric } 29785f757f3fSDimitry Andric 29790fca6ea1SDimitry Andric template <> 29800fca6ea1SDimitry Andric inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S, 29810fca6ea1SDimitry Andric CodePtr &OpPC) { 29820fca6ea1SDimitry Andric IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC); 29830fca6ea1SDimitry Andric OpPC += align(I.bytesToSerialize()); 29840fca6ea1SDimitry Andric return I; 29850fca6ea1SDimitry Andric } 29860fca6ea1SDimitry Andric 29870fca6ea1SDimitry Andric template <> 29880fca6ea1SDimitry Andric inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S, 29890fca6ea1SDimitry Andric CodePtr &OpPC) { 29900fca6ea1SDimitry Andric IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC); 29910fca6ea1SDimitry Andric OpPC += align(I.bytesToSerialize()); 29920fca6ea1SDimitry Andric return I; 29930fca6ea1SDimitry Andric } 29940fca6ea1SDimitry Andric 2995a7dea167SDimitry Andric } // namespace interp 2996a7dea167SDimitry Andric } // namespace clang 2997a7dea167SDimitry Andric 2998a7dea167SDimitry Andric #endif 2999