Path: blob/main/contrib/llvm-project/clang/lib/AST/ByteCode/Interp.h
213799 views
//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// Definition of the interpreter state and entry point.9//10//===----------------------------------------------------------------------===//1112#ifndef LLVM_CLANG_AST_INTERP_INTERP_H13#define LLVM_CLANG_AST_INTERP_INTERP_H1415#include "../ExprConstShared.h"16#include "BitcastBuffer.h"17#include "Boolean.h"18#include "DynamicAllocator.h"19#include "FixedPoint.h"20#include "Floating.h"21#include "Function.h"22#include "InterpBuiltinBitCast.h"23#include "InterpFrame.h"24#include "InterpStack.h"25#include "InterpState.h"26#include "MemberPointer.h"27#include "Opcode.h"28#include "PrimType.h"29#include "Program.h"30#include "State.h"31#include "clang/AST/ASTContext.h"32#include "clang/AST/Expr.h"33#include "llvm/ADT/APFloat.h"34#include "llvm/ADT/APSInt.h"35#include <type_traits>3637namespace clang {38namespace interp {3940using APSInt = llvm::APSInt;41using FixedPointSemantics = llvm::FixedPointSemantics;4243/// Checks if the variable has externally defined storage.44bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);4546/// Checks if the array is offsetable.47bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);4849/// Checks if a pointer is live and accessible.50bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,51AccessKinds AK);5253/// Checks if a pointer is a dummy pointer.54bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,55AccessKinds AK);5657/// Checks if a pointer is null.58bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,59CheckSubobjectKind CSK);6061/// Checks if a pointer is in range.62bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,63AccessKinds AK);6465/// Checks if a field from which a pointer is going to be derived is valid.66bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,67CheckSubobjectKind CSK);6869/// Checks if Ptr is a one-past-the-end pointer.70bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,71CheckSubobjectKind CSK);7273/// Checks if the dowcast using the given offset is possible with the given74/// pointer.75bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,76uint32_t Offset);7778/// Checks if a pointer points to const storage.79bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);8081/// Checks if the Descriptor is of a constexpr or const global variable.82bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);8384/// Checks if a pointer points to a mutable field.85bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);8687/// Checks if a value can be loaded from a block.88bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,89AccessKinds AK = AK_Read);90bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);9192bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,93AccessKinds AK);94/// Check if a global variable is initialized.95bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);9697/// Checks if a value can be stored in a block.98bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);99100/// Checks if a method can be invoked on an object.101bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);102103/// Checks if a value can be initialized.104bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);105106/// Checks if a method can be called.107bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);108109/// Checks if calling the currently active function would exceed110/// the allowed call depth.111bool CheckCallDepth(InterpState &S, CodePtr OpPC);112113/// Checks the 'this' pointer.114bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);115116/// Checks if all the arguments annotated as 'nonnull' are in fact not null.117bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,118const CallExpr *CE, unsigned ArgSize);119120/// Checks if dynamic memory allocation is available in the current121/// language mode.122bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);123124/// Diagnose mismatched new[]/delete or new/delete[] pairs.125bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC,126DynamicAllocator::Form AllocForm,127DynamicAllocator::Form DeleteForm, const Descriptor *D,128const Expr *NewExpr);129130/// Check the source of the pointer passed to delete/delete[] has actually131/// been heap allocated by us.132bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,133const Pointer &Ptr);134135bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,136AccessKinds AK);137138/// Sets the given integral value to the pointer, which is of139/// a std::{weak,partial,strong}_ordering type.140bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,141const Pointer &Ptr, const APSInt &IntValue);142143/// Copy the contents of Src into Dest.144bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);145146bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,147uint32_t VarArgSize);148bool Call(InterpState &S, CodePtr OpPC, const Function *Func,149uint32_t VarArgSize);150bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,151uint32_t VarArgSize);152bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,153uint32_t BuiltinID);154bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,155const CallExpr *CE);156bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);157bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);158bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,159bool TargetIsUCharOrByte);160bool CheckBCPResult(InterpState &S, const Pointer &Ptr);161bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);162163template <typename T>164static bool handleOverflow(InterpState &S, CodePtr OpPC, const T &SrcValue) {165const Expr *E = S.Current->getExpr(OpPC);166S.CCEDiag(E, diag::note_constexpr_overflow) << SrcValue << E->getType();167return S.noteUndefinedBehavior();168}169bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,170const FixedPoint &FP);171172bool isConstexprUnknown(const Pointer &P);173174inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems);175176enum class ShiftDir { Left, Right };177178/// Checks if the shift operation is legal.179template <ShiftDir Dir, typename LT, typename RT>180bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,181unsigned Bits) {182if (RHS.isNegative()) {183const SourceInfo &Loc = S.Current->getSource(OpPC);184S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();185if (!S.noteUndefinedBehavior())186return false;187}188189// C++11 [expr.shift]p1: Shift width must be less than the bit width of190// the shifted type.191if (Bits > 1 && RHS >= Bits) {192const Expr *E = S.Current->getExpr(OpPC);193const APSInt Val = RHS.toAPSInt();194QualType Ty = E->getType();195S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;196if (!S.noteUndefinedBehavior())197return false;198}199200if constexpr (Dir == ShiftDir::Left) {201if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {202// C++11 [expr.shift]p2: A signed left shift must have a non-negative203// operand, and must not overflow the corresponding unsigned type.204if (LHS.isNegative()) {205const Expr *E = S.Current->getExpr(OpPC);206S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();207if (!S.noteUndefinedBehavior())208return false;209} else if (LHS.toUnsigned().countLeadingZeros() <210static_cast<unsigned>(RHS)) {211const Expr *E = S.Current->getExpr(OpPC);212S.CCEDiag(E, diag::note_constexpr_lshift_discards);213if (!S.noteUndefinedBehavior())214return false;215}216}217}218219// C++2a [expr.shift]p2: [P0907R4]:220// E1 << E2 is the unique value congruent to221// E1 x 2^E2 module 2^N.222return true;223}224225/// Checks if Div/Rem operation on LHS and RHS is valid.226template <typename T>227bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {228if (RHS.isZero()) {229const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));230if constexpr (std::is_same_v<T, Floating>) {231S.CCEDiag(Op, diag::note_expr_divide_by_zero)232<< Op->getRHS()->getSourceRange();233return true;234}235236S.FFDiag(Op, diag::note_expr_divide_by_zero)237<< Op->getRHS()->getSourceRange();238return false;239}240241if constexpr (!std::is_same_v<T, FixedPoint>) {242if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {243APSInt LHSInt = LHS.toAPSInt();244SmallString<32> Trunc;245(-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);246const SourceInfo &Loc = S.Current->getSource(OpPC);247const Expr *E = S.Current->getExpr(OpPC);248S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();249return false;250}251}252return true;253}254255template <typename SizeT>256bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,257unsigned ElemSize, bool IsNoThrow) {258// FIXME: Both the SizeT::from() as well as the259// NumElements.toAPSInt() in this function are rather expensive.260261// Can't be too many elements if the bitwidth of NumElements is lower than262// that of Descriptor::MaxArrayElemBytes.263if ((NumElements->bitWidth() - NumElements->isSigned()) <264(sizeof(Descriptor::MaxArrayElemBytes) * 8))265return true;266267// FIXME: GH63562268// APValue stores array extents as unsigned,269// so anything that is greater that unsigned would overflow when270// constructing the array, we catch this here.271SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);272assert(MaxElements.isPositive());273if (NumElements->toAPSInt().getActiveBits() >274ConstantArrayType::getMaxSizeBits(S.getASTContext()) ||275*NumElements > MaxElements) {276if (!IsNoThrow) {277const SourceInfo &Loc = S.Current->getSource(OpPC);278279if (NumElements->isSigned() && NumElements->isNegative()) {280S.FFDiag(Loc, diag::note_constexpr_new_negative)281<< NumElements->toDiagnosticString(S.getASTContext());282} else {283S.FFDiag(Loc, diag::note_constexpr_new_too_large)284<< NumElements->toDiagnosticString(S.getASTContext());285}286}287return false;288}289return true;290}291292/// Checks if the result of a floating-point operation is valid293/// in the current context.294bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,295APFloat::opStatus Status, FPOptions FPO);296297/// Checks why the given DeclRefExpr is invalid.298bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);299300/// Interpreter entry point.301bool Interpret(InterpState &S);302303/// Interpret a builtin function.304bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,305uint32_t BuiltinID);306307/// Interpret an offsetof operation.308bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,309ArrayRef<int64_t> ArrayIndices, int64_t &Result);310311inline bool Invalid(InterpState &S, CodePtr OpPC);312313enum class ArithOp { Add, Sub };314315//===----------------------------------------------------------------------===//316// Returning values317//===----------------------------------------------------------------------===//318319void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,320const Function *Func);321322template <PrimType Name, class T = typename PrimConv<Name>::T>323bool Ret(InterpState &S, CodePtr &PC) {324const T &Ret = S.Stk.pop<T>();325326assert(S.Current);327assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");328if (!S.checkingPotentialConstantExpression() || S.Current->Caller)329cleanupAfterFunctionCall(S, PC, S.Current->getFunction());330331if (InterpFrame *Caller = S.Current->Caller) {332PC = S.Current->getRetPC();333InterpFrame::free(S.Current);334S.Current = Caller;335S.Stk.push<T>(Ret);336} else {337InterpFrame::free(S.Current);338S.Current = nullptr;339// The topmost frame should come from an EvalEmitter,340// which has its own implementation of the Ret<> instruction.341}342return true;343}344345inline bool RetVoid(InterpState &S, CodePtr &PC) {346assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");347348if (!S.checkingPotentialConstantExpression() || S.Current->Caller)349cleanupAfterFunctionCall(S, PC, S.Current->getFunction());350351if (InterpFrame *Caller = S.Current->Caller) {352PC = S.Current->getRetPC();353InterpFrame::free(S.Current);354S.Current = Caller;355} else {356InterpFrame::free(S.Current);357S.Current = nullptr;358}359return true;360}361362//===----------------------------------------------------------------------===//363// Add, Sub, Mul364//===----------------------------------------------------------------------===//365366template <typename T, bool (*OpFW)(T, T, unsigned, T *),367template <typename U> class OpAP>368bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,369const T &RHS) {370// Fast path - add the numbers with fixed width.371T Result;372if constexpr (needsAlloc<T>())373Result = S.allocAP<T>(LHS.bitWidth());374375if (!OpFW(LHS, RHS, Bits, &Result)) {376S.Stk.push<T>(Result);377return true;378}379// If for some reason evaluation continues, use the truncated results.380S.Stk.push<T>(Result);381382// Short-circuit fixed-points here since the error handling is easier.383if constexpr (std::is_same_v<T, FixedPoint>)384return handleFixedPointOverflow(S, OpPC, Result);385386// Slow path - compute the result using another bit of precision.387APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));388389// Report undefined behaviour, stopping if required.390if (S.checkingForUndefinedBehavior()) {391const Expr *E = S.Current->getExpr(OpPC);392QualType Type = E->getType();393SmallString<32> Trunc;394Value.trunc(Result.bitWidth())395.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,396/*UpperCase=*/true, /*InsertSeparators=*/true);397S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)398<< Trunc << Type << E->getSourceRange();399}400401if (!handleOverflow(S, OpPC, Value)) {402S.Stk.pop<T>();403return false;404}405return true;406}407408template <PrimType Name, class T = typename PrimConv<Name>::T>409bool Add(InterpState &S, CodePtr OpPC) {410const T &RHS = S.Stk.pop<T>();411const T &LHS = S.Stk.pop<T>();412const unsigned Bits = RHS.bitWidth() + 1;413414return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);415}416417static inline llvm::RoundingMode getRoundingMode(FPOptions FPO) {418auto RM = FPO.getRoundingMode();419if (RM == llvm::RoundingMode::Dynamic)420return llvm::RoundingMode::NearestTiesToEven;421return RM;422}423424inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {425const Floating &RHS = S.Stk.pop<Floating>();426const Floating &LHS = S.Stk.pop<Floating>();427428FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);429Floating Result = S.allocFloat(LHS.getSemantics());430auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);431S.Stk.push<Floating>(Result);432return CheckFloatResult(S, OpPC, Result, Status, FPO);433}434435template <PrimType Name, class T = typename PrimConv<Name>::T>436bool Sub(InterpState &S, CodePtr OpPC) {437const T &RHS = S.Stk.pop<T>();438const T &LHS = S.Stk.pop<T>();439const unsigned Bits = RHS.bitWidth() + 1;440441return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);442}443444inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {445const Floating &RHS = S.Stk.pop<Floating>();446const Floating &LHS = S.Stk.pop<Floating>();447448FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);449Floating Result = S.allocFloat(LHS.getSemantics());450auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);451S.Stk.push<Floating>(Result);452return CheckFloatResult(S, OpPC, Result, Status, FPO);453}454455template <PrimType Name, class T = typename PrimConv<Name>::T>456bool Mul(InterpState &S, CodePtr OpPC) {457const T &RHS = S.Stk.pop<T>();458const T &LHS = S.Stk.pop<T>();459const unsigned Bits = RHS.bitWidth() * 2;460461return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);462}463464inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {465const Floating &RHS = S.Stk.pop<Floating>();466const Floating &LHS = S.Stk.pop<Floating>();467468FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);469Floating Result = S.allocFloat(LHS.getSemantics());470471auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);472473S.Stk.push<Floating>(Result);474return CheckFloatResult(S, OpPC, Result, Status, FPO);475}476477template <PrimType Name, class T = typename PrimConv<Name>::T>478inline bool Mulc(InterpState &S, CodePtr OpPC) {479const Pointer &RHS = S.Stk.pop<Pointer>();480const Pointer &LHS = S.Stk.pop<Pointer>();481const Pointer &Result = S.Stk.peek<Pointer>();482483if constexpr (std::is_same_v<T, Floating>) {484APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();485APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();486APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();487APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();488489APFloat ResR(A.getSemantics());490APFloat ResI(A.getSemantics());491HandleComplexComplexMul(A, B, C, D, ResR, ResI);492493// Copy into the result.494Floating RA = S.allocFloat(A.getSemantics());495RA.copy(ResR);496Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);497Result.atIndex(0).initialize();498499Floating RI = S.allocFloat(A.getSemantics());500RI.copy(ResI);501Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);502Result.atIndex(1).initialize();503Result.initialize();504} else {505// Integer element type.506const T &LHSR = LHS.atIndex(0).deref<T>();507const T &LHSI = LHS.atIndex(1).deref<T>();508const T &RHSR = RHS.atIndex(0).deref<T>();509const T &RHSI = RHS.atIndex(1).deref<T>();510unsigned Bits = LHSR.bitWidth();511512// real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))513T A;514if (T::mul(LHSR, RHSR, Bits, &A))515return false;516T B;517if (T::mul(LHSI, RHSI, Bits, &B))518return false;519if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))520return false;521Result.atIndex(0).initialize();522523// imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))524if (T::mul(LHSR, RHSI, Bits, &A))525return false;526if (T::mul(LHSI, RHSR, Bits, &B))527return false;528if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))529return false;530Result.atIndex(1).initialize();531Result.initialize();532}533534return true;535}536537template <PrimType Name, class T = typename PrimConv<Name>::T>538inline bool Divc(InterpState &S, CodePtr OpPC) {539const Pointer &RHS = S.Stk.pop<Pointer>();540const Pointer &LHS = S.Stk.pop<Pointer>();541const Pointer &Result = S.Stk.peek<Pointer>();542543if constexpr (std::is_same_v<T, Floating>) {544APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();545APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();546APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();547APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();548549APFloat ResR(A.getSemantics());550APFloat ResI(A.getSemantics());551HandleComplexComplexDiv(A, B, C, D, ResR, ResI);552553// Copy into the result.554Floating RA = S.allocFloat(A.getSemantics());555RA.copy(ResR);556Result.atIndex(0).deref<Floating>() = RA; // Floating(ResR);557Result.atIndex(0).initialize();558559Floating RI = S.allocFloat(A.getSemantics());560RI.copy(ResI);561Result.atIndex(1).deref<Floating>() = RI; // Floating(ResI);562Result.atIndex(1).initialize();563564Result.initialize();565} else {566// Integer element type.567const T &LHSR = LHS.atIndex(0).deref<T>();568const T &LHSI = LHS.atIndex(1).deref<T>();569const T &RHSR = RHS.atIndex(0).deref<T>();570const T &RHSI = RHS.atIndex(1).deref<T>();571unsigned Bits = LHSR.bitWidth();572const T Zero = T::from(0, Bits);573574if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&575Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {576const SourceInfo &E = S.Current->getSource(OpPC);577S.FFDiag(E, diag::note_expr_divide_by_zero);578return false;579}580581// Den = real(RHS)² + imag(RHS)²582T A, B;583if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {584// Ignore overflow here, because that's what the current interpeter does.585}586T Den;587if (T::add(A, B, Bits, &Den))588return false;589590if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) {591const SourceInfo &E = S.Current->getSource(OpPC);592S.FFDiag(E, diag::note_expr_divide_by_zero);593return false;594}595596// real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den597T &ResultR = Result.atIndex(0).deref<T>();598T &ResultI = Result.atIndex(1).deref<T>();599600if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))601return false;602if (T::add(A, B, Bits, &ResultR))603return false;604if (T::div(ResultR, Den, Bits, &ResultR))605return false;606Result.atIndex(0).initialize();607608// imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den609if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))610return false;611if (T::sub(A, B, Bits, &ResultI))612return false;613if (T::div(ResultI, Den, Bits, &ResultI))614return false;615Result.atIndex(1).initialize();616Result.initialize();617}618619return true;620}621622/// 1) Pops the RHS from the stack.623/// 2) Pops the LHS from the stack.624/// 3) Pushes 'LHS & RHS' on the stack625template <PrimType Name, class T = typename PrimConv<Name>::T>626bool BitAnd(InterpState &S, CodePtr OpPC) {627const T &RHS = S.Stk.pop<T>();628const T &LHS = S.Stk.pop<T>();629unsigned Bits = RHS.bitWidth();630631T Result;632if constexpr (needsAlloc<T>())633Result = S.allocAP<T>(Bits);634635if (!T::bitAnd(LHS, RHS, Bits, &Result)) {636S.Stk.push<T>(Result);637return true;638}639return false;640}641642/// 1) Pops the RHS from the stack.643/// 2) Pops the LHS from the stack.644/// 3) Pushes 'LHS | RHS' on the stack645template <PrimType Name, class T = typename PrimConv<Name>::T>646bool BitOr(InterpState &S, CodePtr OpPC) {647const T &RHS = S.Stk.pop<T>();648const T &LHS = S.Stk.pop<T>();649unsigned Bits = RHS.bitWidth();650651T Result;652if constexpr (needsAlloc<T>())653Result = S.allocAP<T>(Bits);654655if (!T::bitOr(LHS, RHS, Bits, &Result)) {656S.Stk.push<T>(Result);657return true;658}659return false;660}661662/// 1) Pops the RHS from the stack.663/// 2) Pops the LHS from the stack.664/// 3) Pushes 'LHS ^ RHS' on the stack665template <PrimType Name, class T = typename PrimConv<Name>::T>666bool BitXor(InterpState &S, CodePtr OpPC) {667const T &RHS = S.Stk.pop<T>();668const T &LHS = S.Stk.pop<T>();669670unsigned Bits = RHS.bitWidth();671672T Result;673if constexpr (needsAlloc<T>())674Result = S.allocAP<T>(Bits);675676if (!T::bitXor(LHS, RHS, Bits, &Result)) {677S.Stk.push<T>(Result);678return true;679}680return false;681}682683/// 1) Pops the RHS from the stack.684/// 2) Pops the LHS from the stack.685/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).686template <PrimType Name, class T = typename PrimConv<Name>::T>687bool Rem(InterpState &S, CodePtr OpPC) {688const T &RHS = S.Stk.pop<T>();689const T &LHS = S.Stk.pop<T>();690const unsigned Bits = RHS.bitWidth() * 2;691692if (!CheckDivRem(S, OpPC, LHS, RHS))693return false;694695T Result;696if constexpr (needsAlloc<T>())697Result = S.allocAP<T>(LHS.bitWidth());698699if (!T::rem(LHS, RHS, Bits, &Result)) {700S.Stk.push<T>(Result);701return true;702}703return false;704}705706/// 1) Pops the RHS from the stack.707/// 2) Pops the LHS from the stack.708/// 3) Pushes 'LHS / RHS' on the stack709template <PrimType Name, class T = typename PrimConv<Name>::T>710bool Div(InterpState &S, CodePtr OpPC) {711const T &RHS = S.Stk.pop<T>();712const T &LHS = S.Stk.pop<T>();713const unsigned Bits = RHS.bitWidth() * 2;714715if (!CheckDivRem(S, OpPC, LHS, RHS))716return false;717718T Result;719if constexpr (needsAlloc<T>())720Result = S.allocAP<T>(LHS.bitWidth());721722if (!T::div(LHS, RHS, Bits, &Result)) {723S.Stk.push<T>(Result);724return true;725}726727if constexpr (std::is_same_v<T, FixedPoint>) {728if (handleFixedPointOverflow(S, OpPC, Result)) {729S.Stk.push<T>(Result);730return true;731}732}733return false;734}735736inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {737const Floating &RHS = S.Stk.pop<Floating>();738const Floating &LHS = S.Stk.pop<Floating>();739740if (!CheckDivRem(S, OpPC, LHS, RHS))741return false;742743FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);744745Floating Result = S.allocFloat(LHS.getSemantics());746auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);747748S.Stk.push<Floating>(Result);749return CheckFloatResult(S, OpPC, Result, Status, FPO);750}751752//===----------------------------------------------------------------------===//753// Inv754//===----------------------------------------------------------------------===//755756inline bool Inv(InterpState &S, CodePtr OpPC) {757const auto &Val = S.Stk.pop<Boolean>();758S.Stk.push<Boolean>(!Val);759return true;760}761762//===----------------------------------------------------------------------===//763// Neg764//===----------------------------------------------------------------------===//765766template <PrimType Name, class T = typename PrimConv<Name>::T>767bool Neg(InterpState &S, CodePtr OpPC) {768const T &Value = S.Stk.pop<T>();769770if constexpr (std::is_same_v<T, Floating>) {771T Result = S.allocFloat(Value.getSemantics());772773if (!T::neg(Value, &Result)) {774S.Stk.push<T>(Result);775return true;776}777return false;778} else {779T Result;780if constexpr (needsAlloc<T>())781Result = S.allocAP<T>(Value.bitWidth());782783if (!T::neg(Value, &Result)) {784S.Stk.push<T>(Result);785return true;786}787788assert(isIntegralType(Name) &&789"don't expect other types to fail at constexpr negation");790S.Stk.push<T>(Result);791792APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);793if (S.checkingForUndefinedBehavior()) {794const Expr *E = S.Current->getExpr(OpPC);795QualType Type = E->getType();796SmallString<32> Trunc;797NegatedValue.trunc(Result.bitWidth())798.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,799/*UpperCase=*/true, /*InsertSeparators=*/true);800S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)801<< Trunc << Type << E->getSourceRange();802return true;803}804805return handleOverflow(S, OpPC, NegatedValue);806}807}808809enum class PushVal : bool {810No,811Yes,812};813enum class IncDecOp {814Inc,815Dec,816};817818template <typename T, IncDecOp Op, PushVal DoPush>819bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,820bool CanOverflow) {821assert(!Ptr.isDummy());822823if (!S.inConstantContext()) {824if (isConstexprUnknown(Ptr))825return false;826}827828if constexpr (std::is_same_v<T, Boolean>) {829if (!S.getLangOpts().CPlusPlus14)830return Invalid(S, OpPC);831}832833const T &Value = Ptr.deref<T>();834T Result;835if constexpr (needsAlloc<T>())836Result = S.allocAP<T>(Value.bitWidth());837838if constexpr (DoPush == PushVal::Yes)839S.Stk.push<T>(Value);840841if constexpr (Op == IncDecOp::Inc) {842if (!T::increment(Value, &Result) || !CanOverflow) {843Ptr.deref<T>() = Result;844return true;845}846} else {847if (!T::decrement(Value, &Result) || !CanOverflow) {848Ptr.deref<T>() = Result;849return true;850}851}852assert(CanOverflow);853854// Something went wrong with the previous operation. Compute the855// result with another bit of precision.856unsigned Bits = Value.bitWidth() + 1;857APSInt APResult;858if constexpr (Op == IncDecOp::Inc)859APResult = ++Value.toAPSInt(Bits);860else861APResult = --Value.toAPSInt(Bits);862863// Report undefined behaviour, stopping if required.864if (S.checkingForUndefinedBehavior()) {865const Expr *E = S.Current->getExpr(OpPC);866QualType Type = E->getType();867SmallString<32> Trunc;868APResult.trunc(Result.bitWidth())869.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,870/*UpperCase=*/true, /*InsertSeparators=*/true);871S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)872<< Trunc << Type << E->getSourceRange();873return true;874}875return handleOverflow(S, OpPC, APResult);876}877878/// 1) Pops a pointer from the stack879/// 2) Load the value from the pointer880/// 3) Writes the value increased by one back to the pointer881/// 4) Pushes the original (pre-inc) value on the stack.882template <PrimType Name, class T = typename PrimConv<Name>::T>883bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {884const Pointer &Ptr = S.Stk.pop<Pointer>();885if (!CheckLoad(S, OpPC, Ptr, AK_Increment))886return false;887888return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,889CanOverflow);890}891892/// 1) Pops a pointer from the stack893/// 2) Load the value from the pointer894/// 3) Writes the value increased by one back to the pointer895template <PrimType Name, class T = typename PrimConv<Name>::T>896bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {897const Pointer &Ptr = S.Stk.pop<Pointer>();898if (!CheckLoad(S, OpPC, Ptr, AK_Increment))899return false;900901return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);902}903904template <PrimType Name, class T = typename PrimConv<Name>::T>905bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {906const Pointer &Ptr = S.Stk.peek<Pointer>();907if (!CheckLoad(S, OpPC, Ptr, AK_Increment))908return false;909910return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);911}912913/// 1) Pops a pointer from the stack914/// 2) Load the value from the pointer915/// 3) Writes the value decreased by one back to the pointer916/// 4) Pushes the original (pre-dec) value on the stack.917template <PrimType Name, class T = typename PrimConv<Name>::T>918bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {919const Pointer &Ptr = S.Stk.pop<Pointer>();920if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))921return false;922923return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,924CanOverflow);925}926927/// 1) Pops a pointer from the stack928/// 2) Load the value from the pointer929/// 3) Writes the value decreased by one back to the pointer930template <PrimType Name, class T = typename PrimConv<Name>::T>931bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {932const Pointer &Ptr = S.Stk.pop<Pointer>();933if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))934return false;935936return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);937}938939template <PrimType Name, class T = typename PrimConv<Name>::T>940bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {941const Pointer &Ptr = S.Stk.peek<Pointer>();942if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))943return false;944return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);945}946947template <IncDecOp Op, PushVal DoPush>948bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,949uint32_t FPOI) {950Floating Value = Ptr.deref<Floating>();951Floating Result = S.allocFloat(Value.getSemantics());952953if constexpr (DoPush == PushVal::Yes)954S.Stk.push<Floating>(Value);955956FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);957llvm::APFloat::opStatus Status;958if constexpr (Op == IncDecOp::Inc)959Status = Floating::increment(Value, getRoundingMode(FPO), &Result);960else961Status = Floating::decrement(Value, getRoundingMode(FPO), &Result);962963Ptr.deref<Floating>() = Result;964965return CheckFloatResult(S, OpPC, Result, Status, FPO);966}967968inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {969const Pointer &Ptr = S.Stk.pop<Pointer>();970if (!CheckLoad(S, OpPC, Ptr, AK_Increment))971return false;972973return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);974}975976inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {977const Pointer &Ptr = S.Stk.pop<Pointer>();978if (!CheckLoad(S, OpPC, Ptr, AK_Increment))979return false;980981return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);982}983984inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {985const Pointer &Ptr = S.Stk.pop<Pointer>();986if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))987return false;988989return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);990}991992inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {993const Pointer &Ptr = S.Stk.pop<Pointer>();994if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))995return false;996997return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);998}9991000/// 1) Pops the value from the stack.1001/// 2) Pushes the bitwise complemented value on the stack (~V).1002template <PrimType Name, class T = typename PrimConv<Name>::T>1003bool Comp(InterpState &S, CodePtr OpPC) {1004const T &Val = S.Stk.pop<T>();10051006T Result;1007if constexpr (needsAlloc<T>())1008Result = S.allocAP<T>(Val.bitWidth());10091010if (!T::comp(Val, &Result)) {1011S.Stk.push<T>(Result);1012return true;1013}1014return false;1015}10161017//===----------------------------------------------------------------------===//1018// EQ, NE, GT, GE, LT, LE1019//===----------------------------------------------------------------------===//10201021using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;10221023template <typename T>1024bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {1025assert((!std::is_same_v<T, MemberPointer>) &&1026"Non-equality comparisons on member pointer types should already be "1027"rejected in Sema.");1028using BoolT = PrimConv<PT_Bool>::T;1029const T &RHS = S.Stk.pop<T>();1030const T &LHS = S.Stk.pop<T>();1031S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));1032return true;1033}10341035template <typename T>1036bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {1037return CmpHelper<T>(S, OpPC, Fn);1038}10391040template <>1041inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {1042using BoolT = PrimConv<PT_Bool>::T;1043const Pointer &RHS = S.Stk.pop<Pointer>();1044const Pointer &LHS = S.Stk.pop<Pointer>();10451046// Function pointers cannot be compared in an ordered way.1047if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||1048LHS.isTypeidPointer() || RHS.isTypeidPointer()) {1049const SourceInfo &Loc = S.Current->getSource(OpPC);1050S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1051<< LHS.toDiagnosticString(S.getASTContext())1052<< RHS.toDiagnosticString(S.getASTContext());1053return false;1054}10551056if (!Pointer::hasSameBase(LHS, RHS)) {1057const SourceInfo &Loc = S.Current->getSource(OpPC);1058S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1059<< LHS.toDiagnosticString(S.getASTContext())1060<< RHS.toDiagnosticString(S.getASTContext());1061return false;1062}10631064// Diagnose comparisons between fields with different access specifiers.1065if (std::optional<std::pair<Pointer, Pointer>> Split =1066Pointer::computeSplitPoint(LHS, RHS)) {1067const FieldDecl *LF = Split->first.getField();1068const FieldDecl *RF = Split->second.getField();1069if (LF && RF && !LF->getParent()->isUnion() &&1070LF->getAccess() != RF->getAccess()) {1071S.CCEDiag(S.Current->getSource(OpPC),1072diag::note_constexpr_pointer_comparison_differing_access)1073<< LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();1074}1075}10761077unsigned VL = LHS.getByteOffset();1078unsigned VR = RHS.getByteOffset();1079S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));1080return true;1081}10821083static inline bool IsOpaqueConstantCall(const CallExpr *E) {1084unsigned Builtin = E->getBuiltinCallee();1085return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||1086Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||1087Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||1088Builtin == Builtin::BI__builtin_function_start);1089}10901091bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,1092const Pointer &RHS);10931094template <>1095inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {1096using BoolT = PrimConv<PT_Bool>::T;1097const Pointer &RHS = S.Stk.pop<Pointer>();1098const Pointer &LHS = S.Stk.pop<Pointer>();10991100if (LHS.isZero() && RHS.isZero()) {1101S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));1102return true;1103}11041105// Reject comparisons to weak pointers.1106for (const auto &P : {LHS, RHS}) {1107if (P.isZero())1108continue;1109if (P.isWeak()) {1110const SourceInfo &Loc = S.Current->getSource(OpPC);1111S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)1112<< P.toDiagnosticString(S.getASTContext());1113return false;1114}1115}11161117if (!S.inConstantContext()) {1118if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))1119return false;1120}11211122if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {1123S.Stk.push<BoolT>(BoolT::from(Fn(Compare(LHS.getIntegerRepresentation(),1124RHS.getIntegerRepresentation()))));1125return true;1126}11271128// FIXME: The source check here isn't entirely correct.1129if (LHS.pointsToStringLiteral() && RHS.pointsToStringLiteral() &&1130LHS.getFieldDesc()->asExpr() != RHS.getFieldDesc()->asExpr()) {1131if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {1132const SourceInfo &Loc = S.Current->getSource(OpPC);1133S.FFDiag(Loc, diag::note_constexpr_literal_comparison)1134<< LHS.toDiagnosticString(S.getASTContext())1135<< RHS.toDiagnosticString(S.getASTContext());1136return false;1137}1138}11391140if (Pointer::hasSameBase(LHS, RHS)) {1141size_t A = LHS.computeOffsetForComparison();1142size_t B = RHS.computeOffsetForComparison();1143S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));1144return true;1145}11461147// Otherwise we need to do a bunch of extra checks before returning Unordered.1148if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&1149RHS.getOffset() == 0) {1150const SourceInfo &Loc = S.Current->getSource(OpPC);1151S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)1152<< LHS.toDiagnosticString(S.getASTContext());1153return false;1154} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&1155LHS.getOffset() == 0) {1156const SourceInfo &Loc = S.Current->getSource(OpPC);1157S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)1158<< RHS.toDiagnosticString(S.getASTContext());1159return false;1160}11611162bool BothNonNull = !LHS.isZero() && !RHS.isZero();1163// Reject comparisons to literals.1164for (const auto &P : {LHS, RHS}) {1165if (P.isZero())1166continue;1167if (BothNonNull && P.pointsToLiteral()) {1168const Expr *E = P.getDeclDesc()->asExpr();1169if (isa<StringLiteral>(E)) {1170const SourceInfo &Loc = S.Current->getSource(OpPC);1171S.FFDiag(Loc, diag::note_constexpr_literal_comparison);1172return false;1173} else if (const auto *CE = dyn_cast<CallExpr>(E);1174CE && IsOpaqueConstantCall(CE)) {1175const SourceInfo &Loc = S.Current->getSource(OpPC);1176S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)1177<< P.toDiagnosticString(S.getASTContext());1178return false;1179}1180} else if (BothNonNull && P.isIntegralPointer()) {1181const SourceInfo &Loc = S.Current->getSource(OpPC);1182S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)1183<< LHS.toDiagnosticString(S.getASTContext())1184<< RHS.toDiagnosticString(S.getASTContext());1185return false;1186}1187}11881189if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {1190const SourceInfo &Loc = S.Current->getSource(OpPC);1191S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)1192<< LHS.toDiagnosticString(S.getASTContext())1193<< RHS.toDiagnosticString(S.getASTContext());1194return false;1195}11961197S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));1198return true;1199}12001201template <>1202inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,1203CompareFn Fn) {1204const auto &RHS = S.Stk.pop<MemberPointer>();1205const auto &LHS = S.Stk.pop<MemberPointer>();12061207// If either operand is a pointer to a weak function, the comparison is not1208// constant.1209for (const auto &MP : {LHS, RHS}) {1210if (MP.isWeak()) {1211const SourceInfo &Loc = S.Current->getSource(OpPC);1212S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)1213<< MP.getMemberFunction();1214return false;1215}1216}12171218// C++11 [expr.eq]p2:1219// If both operands are null, they compare equal. Otherwise if only one is1220// null, they compare unequal.1221if (LHS.isZero() && RHS.isZero()) {1222S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));1223return true;1224}1225if (LHS.isZero() || RHS.isZero()) {1226S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));1227return true;1228}12291230// We cannot compare against virtual declarations at compile time.1231for (const auto &MP : {LHS, RHS}) {1232if (const CXXMethodDecl *MD = MP.getMemberFunction();1233MD && MD->isVirtual()) {1234const SourceInfo &Loc = S.Current->getSource(OpPC);1235S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;1236}1237}12381239S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));1240return true;1241}12421243template <PrimType Name, class T = typename PrimConv<Name>::T>1244bool EQ(InterpState &S, CodePtr OpPC) {1245return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1246return R == ComparisonCategoryResult::Equal;1247});1248}12491250template <PrimType Name, class T = typename PrimConv<Name>::T>1251bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {1252const T &RHS = S.Stk.pop<T>();1253const T &LHS = S.Stk.pop<T>();1254const Pointer &P = S.Stk.peek<Pointer>();12551256ComparisonCategoryResult CmpResult = LHS.compare(RHS);1257if constexpr (std::is_same_v<T, Pointer>) {1258if (CmpResult == ComparisonCategoryResult::Unordered) {1259const SourceInfo &Loc = S.Current->getSource(OpPC);1260S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1261<< LHS.toDiagnosticString(S.getASTContext())1262<< RHS.toDiagnosticString(S.getASTContext());1263return false;1264}1265}12661267assert(CmpInfo);1268const auto *CmpValueInfo =1269CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));1270assert(CmpValueInfo);1271assert(CmpValueInfo->hasValidIntValue());1272return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());1273}12741275template <PrimType Name, class T = typename PrimConv<Name>::T>1276bool NE(InterpState &S, CodePtr OpPC) {1277return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1278return R != ComparisonCategoryResult::Equal;1279});1280}12811282template <PrimType Name, class T = typename PrimConv<Name>::T>1283bool LT(InterpState &S, CodePtr OpPC) {1284return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1285return R == ComparisonCategoryResult::Less;1286});1287}12881289template <PrimType Name, class T = typename PrimConv<Name>::T>1290bool LE(InterpState &S, CodePtr OpPC) {1291return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1292return R == ComparisonCategoryResult::Less ||1293R == ComparisonCategoryResult::Equal;1294});1295}12961297template <PrimType Name, class T = typename PrimConv<Name>::T>1298bool GT(InterpState &S, CodePtr OpPC) {1299return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1300return R == ComparisonCategoryResult::Greater;1301});1302}13031304template <PrimType Name, class T = typename PrimConv<Name>::T>1305bool GE(InterpState &S, CodePtr OpPC) {1306return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1307return R == ComparisonCategoryResult::Greater ||1308R == ComparisonCategoryResult::Equal;1309});1310}13111312//===----------------------------------------------------------------------===//1313// Dup, Pop, Test1314//===----------------------------------------------------------------------===//13151316template <PrimType Name, class T = typename PrimConv<Name>::T>1317bool Dup(InterpState &S, CodePtr OpPC) {1318S.Stk.push<T>(S.Stk.peek<T>());1319return true;1320}13211322template <PrimType Name, class T = typename PrimConv<Name>::T>1323bool Pop(InterpState &S, CodePtr OpPC) {1324S.Stk.pop<T>();1325return true;1326}13271328/// [Value1, Value2] -> [Value2, Value1]1329template <PrimType TopName, PrimType BottomName>1330bool Flip(InterpState &S, CodePtr OpPC) {1331using TopT = typename PrimConv<TopName>::T;1332using BottomT = typename PrimConv<BottomName>::T;13331334const auto &Top = S.Stk.pop<TopT>();1335const auto &Bottom = S.Stk.pop<BottomT>();13361337S.Stk.push<TopT>(Top);1338S.Stk.push<BottomT>(Bottom);13391340return true;1341}13421343//===----------------------------------------------------------------------===//1344// Const1345//===----------------------------------------------------------------------===//13461347template <PrimType Name, class T = typename PrimConv<Name>::T>1348bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {1349if constexpr (needsAlloc<T>()) {1350T Result = S.allocAP<T>(Arg.bitWidth());1351Result.copy(Arg.toAPSInt());1352S.Stk.push<T>(Result);1353return true;1354}1355S.Stk.push<T>(Arg);1356return true;1357}13581359inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {1360Floating Result = S.allocFloat(F.getSemantics());1361Result.copy(F.getAPFloat());1362S.Stk.push<Floating>(Result);1363return true;1364}13651366//===----------------------------------------------------------------------===//1367// Get/Set Local/Param/Global/This1368//===----------------------------------------------------------------------===//13691370template <PrimType Name, class T = typename PrimConv<Name>::T>1371bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1372const Pointer &Ptr = S.Current->getLocalPointer(I);1373if (!CheckLoad(S, OpPC, Ptr))1374return false;1375S.Stk.push<T>(Ptr.deref<T>());1376return true;1377}13781379bool EndLifetime(InterpState &S, CodePtr OpPC);1380bool EndLifetimePop(InterpState &S, CodePtr OpPC);1381bool StartLifetime(InterpState &S, CodePtr OpPC);13821383/// 1) Pops the value from the stack.1384/// 2) Writes the value to the local variable with the1385/// given offset.1386template <PrimType Name, class T = typename PrimConv<Name>::T>1387bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1388S.Current->setLocal<T>(I, S.Stk.pop<T>());1389return true;1390}13911392template <PrimType Name, class T = typename PrimConv<Name>::T>1393bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1394if (S.checkingPotentialConstantExpression()) {1395return false;1396}1397S.Stk.push<T>(S.Current->getParam<T>(I));1398return true;1399}14001401template <PrimType Name, class T = typename PrimConv<Name>::T>1402bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1403S.Current->setParam<T>(I, S.Stk.pop<T>());1404return true;1405}14061407/// 1) Peeks a pointer on the stack1408/// 2) Pushes the value of the pointer's field on the stack1409template <PrimType Name, class T = typename PrimConv<Name>::T>1410bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {1411const Pointer &Obj = S.Stk.peek<Pointer>();1412if (!CheckNull(S, OpPC, Obj, CSK_Field))1413return false;1414if (!CheckRange(S, OpPC, Obj, CSK_Field))1415return false;1416const Pointer &Field = Obj.atField(I);1417if (!CheckLoad(S, OpPC, Field))1418return false;1419S.Stk.push<T>(Field.deref<T>());1420return true;1421}14221423template <PrimType Name, class T = typename PrimConv<Name>::T>1424bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {1425const T &Value = S.Stk.pop<T>();1426const Pointer &Obj = S.Stk.peek<Pointer>();1427if (!CheckNull(S, OpPC, Obj, CSK_Field))1428return false;1429if (!CheckRange(S, OpPC, Obj, CSK_Field))1430return false;1431const Pointer &Field = Obj.atField(I);1432if (!CheckStore(S, OpPC, Field))1433return false;1434Field.initialize();1435Field.deref<T>() = Value;1436return true;1437}14381439/// 1) Pops a pointer from the stack1440/// 2) Pushes the value of the pointer's field on the stack1441template <PrimType Name, class T = typename PrimConv<Name>::T>1442bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {1443const Pointer &Obj = S.Stk.pop<Pointer>();1444if (!CheckNull(S, OpPC, Obj, CSK_Field))1445return false;1446if (!CheckRange(S, OpPC, Obj, CSK_Field))1447return false;1448const Pointer &Field = Obj.atField(I);1449if (!CheckLoad(S, OpPC, Field))1450return false;1451S.Stk.push<T>(Field.deref<T>());1452return true;1453}14541455template <PrimType Name, class T = typename PrimConv<Name>::T>1456bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1457if (S.checkingPotentialConstantExpression())1458return false;1459const Pointer &This = S.Current->getThis();1460if (!CheckThis(S, OpPC, This))1461return false;1462const Pointer &Field = This.atField(I);1463if (!CheckLoad(S, OpPC, Field))1464return false;1465S.Stk.push<T>(Field.deref<T>());1466return true;1467}14681469template <PrimType Name, class T = typename PrimConv<Name>::T>1470bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1471if (S.checkingPotentialConstantExpression())1472return false;1473const T &Value = S.Stk.pop<T>();1474const Pointer &This = S.Current->getThis();1475if (!CheckThis(S, OpPC, This))1476return false;1477const Pointer &Field = This.atField(I);1478if (!CheckStore(S, OpPC, Field))1479return false;1480Field.deref<T>() = Value;1481return true;1482}14831484template <PrimType Name, class T = typename PrimConv<Name>::T>1485bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1486const Pointer &Ptr = S.P.getPtrGlobal(I);1487if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))1488return false;1489if (Ptr.isExtern())1490return false;14911492// If a global variable is uninitialized, that means the initializer we've1493// compiled for it wasn't a constant expression. Diagnose that.1494if (!CheckGlobalInitialized(S, OpPC, Ptr))1495return false;14961497S.Stk.push<T>(Ptr.deref<T>());1498return true;1499}15001501/// Same as GetGlobal, but without the checks.1502template <PrimType Name, class T = typename PrimConv<Name>::T>1503bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {1504const Pointer &Ptr = S.P.getPtrGlobal(I);1505if (!CheckInitialized(S, OpPC, Ptr, AK_Read))1506return false;1507S.Stk.push<T>(Ptr.deref<T>());1508return true;1509}15101511template <PrimType Name, class T = typename PrimConv<Name>::T>1512bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1513// TODO: emit warning.1514return false;1515}15161517template <PrimType Name, class T = typename PrimConv<Name>::T>1518bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1519const Pointer &P = S.P.getGlobal(I);15201521P.deref<T>() = S.Stk.pop<T>();15221523if constexpr (std::is_same_v<T, Floating>) {1524auto &Val = P.deref<Floating>();1525if (!Val.singleWord()) {1526uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];1527Val.take(NewMemory);1528}15291530} else if constexpr (needsAlloc<T>()) {1531auto &Val = P.deref<T>();1532if (!Val.singleWord()) {1533uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];1534Val.take(NewMemory);1535}1536}15371538P.initialize();1539return true;1540}15411542/// 1) Converts the value on top of the stack to an APValue1543/// 2) Sets that APValue on \Temp1544/// 3) Initializes global with index \I with that1545template <PrimType Name, class T = typename PrimConv<Name>::T>1546bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,1547const LifetimeExtendedTemporaryDecl *Temp) {1548const Pointer &Ptr = S.P.getGlobal(I);15491550const T Value = S.Stk.peek<T>();1551APValue APV = Value.toAPValue(S.getASTContext());1552APValue *Cached = Temp->getOrCreateValue(true);1553*Cached = APV;15541555assert(Ptr.getDeclDesc()->asExpr());15561557S.SeenGlobalTemporaries.push_back(1558std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));15591560Ptr.deref<T>() = S.Stk.pop<T>();1561Ptr.initialize();1562return true;1563}15641565/// 1) Converts the value on top of the stack to an APValue1566/// 2) Sets that APValue on \Temp1567/// 3) Initialized global with index \I with that1568inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,1569const LifetimeExtendedTemporaryDecl *Temp) {1570assert(Temp);1571const Pointer &P = S.Stk.peek<Pointer>();1572APValue *Cached = Temp->getOrCreateValue(true);15731574S.SeenGlobalTemporaries.push_back(1575std::make_pair(P.getDeclDesc()->asExpr(), Temp));15761577if (std::optional<APValue> APV =1578P.toRValue(S.getASTContext(), Temp->getTemporaryExpr()->getType())) {1579*Cached = *APV;1580return true;1581}15821583return false;1584}15851586template <PrimType Name, class T = typename PrimConv<Name>::T>1587bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1588if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1589return false;1590const Pointer &This = S.Current->getThis();1591if (!CheckThis(S, OpPC, This))1592return false;1593const Pointer &Field = This.atField(I);1594Field.deref<T>() = S.Stk.pop<T>();1595Field.activate();1596Field.initialize();1597return true;1598}15991600// FIXME: The Field pointer here is too much IMO and we could instead just1601// pass an Offset + BitWidth pair.1602template <PrimType Name, class T = typename PrimConv<Name>::T>1603bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,1604uint32_t FieldOffset) {1605assert(F->isBitField());1606if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1607return false;1608const Pointer &This = S.Current->getThis();1609if (!CheckThis(S, OpPC, This))1610return false;1611const Pointer &Field = This.atField(FieldOffset);1612const auto &Value = S.Stk.pop<T>();1613Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1614Field.initialize();1615return true;1616}16171618/// 1) Pops the value from the stack1619/// 2) Peeks a pointer from the stack1620/// 3) Pushes the value to field I of the pointer on the stack1621template <PrimType Name, class T = typename PrimConv<Name>::T>1622bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {1623const T &Value = S.Stk.pop<T>();1624const Pointer &Ptr = S.Stk.peek<Pointer>();1625if (!CheckRange(S, OpPC, Ptr, CSK_Field))1626return false;1627const Pointer &Field = Ptr.atField(I);1628Field.deref<T>() = Value;1629Field.activate();1630Field.initialize();1631return true;1632}16331634template <PrimType Name, class T = typename PrimConv<Name>::T>1635bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {1636assert(F->isBitField());1637const T &Value = S.Stk.pop<T>();1638const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);16391640if constexpr (needsAlloc<T>()) {1641T Result = S.allocAP<T>(Value.bitWidth());1642if (T::isSigned())1643Result.copy(Value.toAPSInt()1644.trunc(F->Decl->getBitWidthValue())1645.sextOrTrunc(Value.bitWidth()));1646else1647Result.copy(Value.toAPSInt()1648.trunc(F->Decl->getBitWidthValue())1649.zextOrTrunc(Value.bitWidth()));16501651Field.deref<T>() = Result;1652} else {1653Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1654}1655Field.activate();1656Field.initialize();1657return true;1658}16591660//===----------------------------------------------------------------------===//1661// GetPtr Local/Param/Global/Field/This1662//===----------------------------------------------------------------------===//16631664inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1665S.Stk.push<Pointer>(S.Current->getLocalPointer(I));1666return true;1667}16681669inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {1670if (S.checkingPotentialConstantExpression()) {1671return false;1672}1673S.Stk.push<Pointer>(S.Current->getParamPointer(I));1674return true;1675}16761677inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1678S.Stk.push<Pointer>(S.P.getPtrGlobal(I));1679return true;1680}16811682/// 1) Peeks a Pointer1683/// 2) Pushes Pointer.atField(Off) on the stack1684bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);1685bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);16861687inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {1688if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1689return false;1690const Pointer &This = S.Current->getThis();1691if (!CheckThis(S, OpPC, This))1692return false;1693S.Stk.push<Pointer>(This.atField(Off));1694return true;1695}16961697inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {1698const Pointer &Ptr = S.Stk.pop<Pointer>();1699if (!CheckNull(S, OpPC, Ptr, CSK_Field))1700return false;1701if (!CheckRange(S, OpPC, Ptr, CSK_Field))1702return false;1703Pointer Field = Ptr.atField(Off);1704Ptr.deactivate();1705Field.activate();1706S.Stk.push<Pointer>(std::move(Field));1707return true;1708}17091710inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {1711if (S.checkingPotentialConstantExpression())1712return false;1713const Pointer &This = S.Current->getThis();1714if (!CheckThis(S, OpPC, This))1715return false;1716Pointer Field = This.atField(Off);1717This.deactivate();1718Field.activate();1719S.Stk.push<Pointer>(std::move(Field));1720return true;1721}17221723inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,1724bool NullOK, const Type *TargetType) {1725const Pointer &Ptr = S.Stk.pop<Pointer>();1726if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))1727return false;17281729if (!Ptr.isBlockPointer()) {1730// FIXME: We don't have the necessary information in integral pointers.1731// The Descriptor only has a record, but that does of course not include1732// the potential derived classes of said record.1733S.Stk.push<Pointer>(Ptr);1734return true;1735}17361737if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))1738return false;1739if (!CheckDowncast(S, OpPC, Ptr, Off))1740return false;17411742const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();1743assert(TargetRecord);17441745if (TargetRecord->getDecl()1746->getTypeForDecl()1747->getAsCXXRecordDecl()1748->getCanonicalDecl() !=1749TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {1750QualType MostDerivedType = Ptr.getDeclDesc()->getType();1751S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)1752<< MostDerivedType << QualType(TargetType, 0);1753return false;1754}17551756S.Stk.push<Pointer>(Ptr.atFieldSub(Off));1757return true;1758}17591760inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1761const Pointer &Ptr = S.Stk.peek<Pointer>();1762if (!CheckNull(S, OpPC, Ptr, CSK_Base))1763return false;17641765if (!Ptr.isBlockPointer()) {1766S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));1767return true;1768}17691770if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1771return false;1772const Pointer &Result = Ptr.atField(Off);1773if (Result.isPastEnd() || !Result.isBaseClass())1774return false;1775S.Stk.push<Pointer>(Result);1776return true;1777}17781779inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,1780bool NullOK) {1781const Pointer &Ptr = S.Stk.pop<Pointer>();17821783if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))1784return false;17851786if (!Ptr.isBlockPointer()) {1787S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));1788return true;1789}17901791if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1792return false;1793const Pointer &Result = Ptr.atField(Off);1794if (Result.isPastEnd() || !Result.isBaseClass())1795return false;1796S.Stk.push<Pointer>(Result);1797return true;1798}17991800inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {1801const auto &Ptr = S.Stk.pop<MemberPointer>();1802S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));1803return true;1804}18051806inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1807if (S.checkingPotentialConstantExpression())1808return false;1809const Pointer &This = S.Current->getThis();1810if (!CheckThis(S, OpPC, This))1811return false;1812S.Stk.push<Pointer>(This.atField(Off));1813return true;1814}18151816inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {1817const Pointer &Ptr = S.Stk.pop<Pointer>();1818if (Ptr.canBeInitialized()) {1819Ptr.initialize();1820Ptr.activate();1821}1822return true;1823}18241825inline bool FinishInit(InterpState &S, CodePtr OpPC) {1826const Pointer &Ptr = S.Stk.peek<Pointer>();1827if (Ptr.canBeInitialized()) {1828Ptr.initialize();1829Ptr.activate();1830}1831return true;1832}18331834bool FinishInitGlobal(InterpState &S, CodePtr OpPC);18351836inline bool Dump(InterpState &S, CodePtr OpPC) {1837S.Stk.dump();1838return true;1839}18401841inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,1842const Pointer &Ptr) {1843Pointer Base = Ptr;1844while (Base.isBaseClass())1845Base = Base.getBase();18461847const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);1848S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));1849return true;1850}18511852inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,1853const RecordDecl *D) {1854assert(D);1855const Pointer &Ptr = S.Stk.pop<Pointer>();1856if (!CheckNull(S, OpPC, Ptr, CSK_Base))1857return false;1858return VirtBaseHelper(S, OpPC, D, Ptr);1859}18601861inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,1862const RecordDecl *D) {1863assert(D);1864if (S.checkingPotentialConstantExpression())1865return false;1866const Pointer &This = S.Current->getThis();1867if (!CheckThis(S, OpPC, This))1868return false;1869return VirtBaseHelper(S, OpPC, D, S.Current->getThis());1870}18711872//===----------------------------------------------------------------------===//1873// Load, Store, Init1874//===----------------------------------------------------------------------===//18751876template <PrimType Name, class T = typename PrimConv<Name>::T>1877bool Load(InterpState &S, CodePtr OpPC) {1878const Pointer &Ptr = S.Stk.peek<Pointer>();1879if (!CheckLoad(S, OpPC, Ptr))1880return false;1881if (!Ptr.isBlockPointer())1882return false;1883S.Stk.push<T>(Ptr.deref<T>());1884return true;1885}18861887template <PrimType Name, class T = typename PrimConv<Name>::T>1888bool LoadPop(InterpState &S, CodePtr OpPC) {1889const Pointer &Ptr = S.Stk.pop<Pointer>();1890if (!CheckLoad(S, OpPC, Ptr))1891return false;1892if (!Ptr.isBlockPointer())1893return false;1894S.Stk.push<T>(Ptr.deref<T>());1895return true;1896}18971898template <PrimType Name, class T = typename PrimConv<Name>::T>1899bool Store(InterpState &S, CodePtr OpPC) {1900const T &Value = S.Stk.pop<T>();1901const Pointer &Ptr = S.Stk.peek<Pointer>();1902if (!CheckStore(S, OpPC, Ptr))1903return false;1904if (Ptr.canBeInitialized()) {1905Ptr.initialize();1906Ptr.activate();1907}1908Ptr.deref<T>() = Value;1909return true;1910}19111912template <PrimType Name, class T = typename PrimConv<Name>::T>1913bool StorePop(InterpState &S, CodePtr OpPC) {1914const T &Value = S.Stk.pop<T>();1915const Pointer &Ptr = S.Stk.pop<Pointer>();1916if (!CheckStore(S, OpPC, Ptr))1917return false;1918if (Ptr.canBeInitialized()) {1919Ptr.initialize();1920Ptr.activate();1921}1922Ptr.deref<T>() = Value;1923return true;1924}19251926template <PrimType Name, class T = typename PrimConv<Name>::T>1927bool StoreBitField(InterpState &S, CodePtr OpPC) {1928const T &Value = S.Stk.pop<T>();1929const Pointer &Ptr = S.Stk.peek<Pointer>();1930if (!CheckStore(S, OpPC, Ptr))1931return false;1932if (Ptr.canBeInitialized()) {1933Ptr.initialize();1934Ptr.activate();1935}1936if (const auto *FD = Ptr.getField())1937Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());1938else1939Ptr.deref<T>() = Value;1940return true;1941}19421943template <PrimType Name, class T = typename PrimConv<Name>::T>1944bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {1945const T &Value = S.Stk.pop<T>();1946const Pointer &Ptr = S.Stk.pop<Pointer>();1947if (!CheckStore(S, OpPC, Ptr))1948return false;1949if (Ptr.canBeInitialized()) {1950Ptr.initialize();1951Ptr.activate();1952}1953if (const auto *FD = Ptr.getField())1954Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());1955else1956Ptr.deref<T>() = Value;1957return true;1958}19591960template <PrimType Name, class T = typename PrimConv<Name>::T>1961bool Init(InterpState &S, CodePtr OpPC) {1962const T &Value = S.Stk.pop<T>();1963const Pointer &Ptr = S.Stk.peek<Pointer>();1964if (!CheckInit(S, OpPC, Ptr))1965return false;1966Ptr.activate();1967Ptr.initialize();1968new (&Ptr.deref<T>()) T(Value);1969return true;1970}19711972template <PrimType Name, class T = typename PrimConv<Name>::T>1973bool InitPop(InterpState &S, CodePtr OpPC) {1974const T &Value = S.Stk.pop<T>();1975const Pointer &Ptr = S.Stk.pop<Pointer>();1976if (!CheckInit(S, OpPC, Ptr))1977return false;1978Ptr.activate();1979Ptr.initialize();1980new (&Ptr.deref<T>()) T(Value);1981return true;1982}19831984/// 1) Pops the value from the stack1985/// 2) Peeks a pointer and gets its index \Idx1986/// 3) Sets the value on the pointer, leaving the pointer on the stack.1987template <PrimType Name, class T = typename PrimConv<Name>::T>1988bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {1989const T &Value = S.Stk.pop<T>();1990const Pointer &Ptr = S.Stk.peek<Pointer>();19911992if (Ptr.isUnknownSizeArray())1993return false;19941995// In the unlikely event that we're initializing the first item of1996// a non-array, skip the atIndex().1997if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {1998Ptr.initialize();1999new (&Ptr.deref<T>()) T(Value);2000return true;2001}20022003const Pointer &ElemPtr = Ptr.atIndex(Idx);2004if (!CheckInit(S, OpPC, ElemPtr))2005return false;2006ElemPtr.initialize();2007new (&ElemPtr.deref<T>()) T(Value);2008return true;2009}20102011/// The same as InitElem, but pops the pointer as well.2012template <PrimType Name, class T = typename PrimConv<Name>::T>2013bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {2014const T &Value = S.Stk.pop<T>();2015const Pointer &Ptr = S.Stk.pop<Pointer>();2016if (Ptr.isUnknownSizeArray())2017return false;20182019// In the unlikely event that we're initializing the first item of2020// a non-array, skip the atIndex().2021if (Idx == 0 && !Ptr.getFieldDesc()->isArray()) {2022Ptr.initialize();2023new (&Ptr.deref<T>()) T(Value);2024return true;2025}20262027const Pointer &ElemPtr = Ptr.atIndex(Idx);2028if (!CheckInit(S, OpPC, ElemPtr))2029return false;2030ElemPtr.initialize();2031new (&ElemPtr.deref<T>()) T(Value);2032return true;2033}20342035inline bool Memcpy(InterpState &S, CodePtr OpPC) {2036const Pointer &Src = S.Stk.pop<Pointer>();2037Pointer &Dest = S.Stk.peek<Pointer>();20382039if (!CheckLoad(S, OpPC, Src))2040return false;20412042return DoMemcpy(S, OpPC, Src, Dest);2043}20442045inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {2046const auto &Member = S.Stk.pop<MemberPointer>();2047const auto &Base = S.Stk.pop<Pointer>();20482049S.Stk.push<MemberPointer>(Member.takeInstance(Base));2050return true;2051}20522053inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {2054const auto &MP = S.Stk.pop<MemberPointer>();20552056if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {2057S.Stk.push<Pointer>(*Ptr);2058return true;2059}2060return Invalid(S, OpPC);2061}20622063//===----------------------------------------------------------------------===//2064// AddOffset, SubOffset2065//===----------------------------------------------------------------------===//20662067template <class T, ArithOp Op>2068std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,2069const T &Offset, const Pointer &Ptr,2070bool IsPointerArith = false) {2071// A zero offset does not change the pointer.2072if (Offset.isZero())2073return Ptr;20742075if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {2076// The CheckNull will have emitted a note already, but we only2077// abort in C++, since this is fine in C.2078if (S.getLangOpts().CPlusPlus)2079return std::nullopt;2080}20812082// Arrays of unknown bounds cannot have pointers into them.2083if (!CheckArray(S, OpPC, Ptr))2084return std::nullopt;20852086// This is much simpler for integral pointers, so handle them first.2087if (Ptr.isIntegralPointer()) {2088uint64_t V = Ptr.getIntegerRepresentation();2089uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();2090if constexpr (Op == ArithOp::Add)2091return Pointer(V + O, Ptr.asIntPointer().Desc);2092else2093return Pointer(V - O, Ptr.asIntPointer().Desc);2094} else if (Ptr.isFunctionPointer()) {2095uint64_t O = static_cast<uint64_t>(Offset);2096uint64_t N;2097if constexpr (Op == ArithOp::Add)2098N = Ptr.getByteOffset() + O;2099else2100N = Ptr.getByteOffset() - O;21012102if (N > 1)2103S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)2104<< N << /*non-array*/ true << 0;2105return Pointer(Ptr.asFunctionPointer().getFunction(), N);2106}21072108assert(Ptr.isBlockPointer());21092110uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());2111uint64_t Index;2112if (Ptr.isOnePastEnd())2113Index = MaxIndex;2114else2115Index = Ptr.getIndex();21162117bool Invalid = false;2118// Helper to report an invalid offset, computed as APSInt.2119auto DiagInvalidOffset = [&]() -> void {2120const unsigned Bits = Offset.bitWidth();2121APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);2122APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),2123/*IsUnsigned=*/false);2124APSInt NewIndex =2125(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);2126S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)2127<< NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;2128Invalid = true;2129};21302131if (Ptr.isBlockPointer()) {2132uint64_t IOffset = static_cast<uint64_t>(Offset);2133uint64_t MaxOffset = MaxIndex - Index;21342135if constexpr (Op == ArithOp::Add) {2136// If the new offset would be negative, bail out.2137if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))2138DiagInvalidOffset();21392140// If the new offset would be out of bounds, bail out.2141if (Offset.isPositive() && IOffset > MaxOffset)2142DiagInvalidOffset();2143} else {2144// If the new offset would be negative, bail out.2145if (Offset.isPositive() && Index < IOffset)2146DiagInvalidOffset();21472148// If the new offset would be out of bounds, bail out.2149if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))2150DiagInvalidOffset();2151}2152}21532154if (Invalid && S.getLangOpts().CPlusPlus)2155return std::nullopt;21562157// Offset is valid - compute it on unsigned.2158int64_t WideIndex = static_cast<int64_t>(Index);2159int64_t WideOffset = static_cast<int64_t>(Offset);2160int64_t Result;2161if constexpr (Op == ArithOp::Add)2162Result = WideIndex + WideOffset;2163else2164Result = WideIndex - WideOffset;21652166// When the pointer is one-past-end, going back to index 0 is the only2167// useful thing we can do. Any other index has been diagnosed before and2168// we don't get here.2169if (Result == 0 && Ptr.isOnePastEnd()) {2170if (Ptr.getFieldDesc()->isArray())2171return Ptr.atIndex(0);2172return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);2173}21742175return Ptr.atIndex(static_cast<uint64_t>(Result));2176}21772178template <PrimType Name, class T = typename PrimConv<Name>::T>2179bool AddOffset(InterpState &S, CodePtr OpPC) {2180const T &Offset = S.Stk.pop<T>();2181Pointer Ptr = S.Stk.pop<Pointer>();2182if (Ptr.isBlockPointer())2183Ptr = Ptr.expand();21842185if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(2186S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {2187S.Stk.push<Pointer>(*Result);2188return true;2189}2190return false;2191}21922193template <PrimType Name, class T = typename PrimConv<Name>::T>2194bool SubOffset(InterpState &S, CodePtr OpPC) {2195const T &Offset = S.Stk.pop<T>();2196const Pointer &Ptr = S.Stk.pop<Pointer>();21972198if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(2199S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {2200S.Stk.push<Pointer>(*Result);2201return true;2202}2203return false;2204}22052206template <ArithOp Op>2207static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,2208const Pointer &Ptr) {2209if (Ptr.isDummy())2210return false;22112212using OneT = Integral<8, false>;22132214const Pointer &P = Ptr.deref<Pointer>();2215if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))2216return false;22172218// Get the current value on the stack.2219S.Stk.push<Pointer>(P);22202221// Now the current Ptr again and a constant 1.2222OneT One = OneT::from(1);2223if (std::optional<Pointer> Result =2224OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {2225// Store the new value.2226Ptr.deref<Pointer>() = *Result;2227return true;2228}2229return false;2230}22312232static inline bool IncPtr(InterpState &S, CodePtr OpPC) {2233const Pointer &Ptr = S.Stk.pop<Pointer>();22342235if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))2236return false;22372238return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);2239}22402241static inline bool DecPtr(InterpState &S, CodePtr OpPC) {2242const Pointer &Ptr = S.Stk.pop<Pointer>();22432244if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))2245return false;22462247return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);2248}22492250/// 1) Pops a Pointer from the stack.2251/// 2) Pops another Pointer from the stack.2252/// 3) Pushes the difference of the indices of the two pointers on the stack.2253template <PrimType Name, class T = typename PrimConv<Name>::T>2254inline bool SubPtr(InterpState &S, CodePtr OpPC) {2255const Pointer &LHS = S.Stk.pop<Pointer>();2256const Pointer &RHS = S.Stk.pop<Pointer>();22572258if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {2259S.FFDiag(S.Current->getSource(OpPC),2260diag::note_constexpr_pointer_arith_unspecified)2261<< LHS.toDiagnosticString(S.getASTContext())2262<< RHS.toDiagnosticString(S.getASTContext());2263return false;2264}22652266if (LHS == RHS) {2267S.Stk.push<T>();2268return true;2269}22702271for (const Pointer &P : {LHS, RHS}) {2272if (P.isZeroSizeArray()) {2273QualType PtrT = P.getType();2274while (auto *AT = dyn_cast<ArrayType>(PtrT))2275PtrT = AT->getElementType();22762277QualType ArrayTy = S.getASTContext().getConstantArrayType(2278PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);2279S.FFDiag(S.Current->getSource(OpPC),2280diag::note_constexpr_pointer_subtraction_zero_size)2281<< ArrayTy;22822283return false;2284}2285}22862287int64_t A64 =2288LHS.isBlockPointer()2289? (LHS.isElementPastEnd() ? LHS.getNumElems() : LHS.getIndex())2290: LHS.getIntegerRepresentation();22912292int64_t B64 =2293RHS.isBlockPointer()2294? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())2295: RHS.getIntegerRepresentation();22962297int64_t R64 = A64 - B64;2298if (static_cast<int64_t>(T::from(R64)) != R64)2299return handleOverflow(S, OpPC, R64);23002301S.Stk.push<T>(T::from(R64));2302return true;2303}23042305//===----------------------------------------------------------------------===//2306// Destroy2307//===----------------------------------------------------------------------===//23082309inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {2310assert(S.Current->getFunction());23112312// FIXME: We iterate the scope once here and then again in the destroy() call2313// below.2314for (auto &Local : S.Current->getFunction()->getScope(I).locals_reverse()) {2315const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);23162317if (Ptr.getLifetime() == Lifetime::Ended) {2318auto *D = cast<NamedDecl>(Ptr.getFieldDesc()->asDecl());2319S.FFDiag(D->getLocation(), diag::note_constexpr_destroy_out_of_lifetime)2320<< D->getNameAsString();2321return false;2322}2323}23242325S.Current->destroy(I);2326return true;2327}23282329inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {2330S.Current->initScope(I);2331return true;2332}23332334//===----------------------------------------------------------------------===//2335// Cast, CastFP2336//===----------------------------------------------------------------------===//23372338template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {2339using T = typename PrimConv<TIn>::T;2340using U = typename PrimConv<TOut>::T;2341S.Stk.push<U>(U::from(S.Stk.pop<T>()));2342return true;2343}23442345/// 1) Pops a Floating from the stack.2346/// 2) Pushes a new floating on the stack that uses the given semantics.2347inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,2348llvm::RoundingMode RM) {2349Floating F = S.Stk.pop<Floating>();2350Floating Result = S.allocFloat(*Sem);2351F.toSemantics(Sem, RM, &Result);2352S.Stk.push<Floating>(Result);2353return true;2354}23552356inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {2357FixedPointSemantics TargetSemantics =2358FixedPointSemantics::getFromOpaqueInt(FPS);2359const auto &Source = S.Stk.pop<FixedPoint>();23602361bool Overflow;2362FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);23632364if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2365return false;23662367S.Stk.push<FixedPoint>(Result);2368return true;2369}23702371/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need2372/// to know what bitwidth the result should be.2373template <PrimType Name, class T = typename PrimConv<Name>::T>2374bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2375auto Result = S.allocAP<IntegralAP<false>>(BitWidth);2376// Copy data.2377{2378APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);2379Result.copy(Source);2380}2381S.Stk.push<IntegralAP<false>>(Result);2382return true;2383}23842385template <PrimType Name, class T = typename PrimConv<Name>::T>2386bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2387auto Result = S.allocAP<IntegralAP<true>>(BitWidth);2388// Copy data.2389{2390APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);2391Result.copy(Source);2392}2393S.Stk.push<IntegralAP<true>>(Result);2394return true;2395}23962397template <PrimType Name, class T = typename PrimConv<Name>::T>2398bool CastIntegralFloating(InterpState &S, CodePtr OpPC,2399const llvm::fltSemantics *Sem, uint32_t FPOI) {2400const T &From = S.Stk.pop<T>();2401APSInt FromAP = From.toAPSInt();24022403FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2404Floating Result = S.allocFloat(*Sem);2405auto Status =2406Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result);2407S.Stk.push<Floating>(Result);24082409return CheckFloatResult(S, OpPC, Result, Status, FPO);2410}24112412template <PrimType Name, class T = typename PrimConv<Name>::T>2413bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {2414const Floating &F = S.Stk.pop<Floating>();24152416if constexpr (std::is_same_v<T, Boolean>) {2417S.Stk.push<T>(T(F.isNonZero()));2418return true;2419} else {2420APSInt Result(std::max(8u, T::bitWidth()),2421/*IsUnsigned=*/!T::isSigned());2422auto Status = F.convertToInteger(Result);24232424// Float-to-Integral overflow check.2425if ((Status & APFloat::opStatus::opInvalidOp)) {2426const Expr *E = S.Current->getExpr(OpPC);2427QualType Type = E->getType();24282429S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;2430if (S.noteUndefinedBehavior()) {2431S.Stk.push<T>(T(Result));2432return true;2433}2434return false;2435}24362437FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2438S.Stk.push<T>(T(Result));2439return CheckFloatResult(S, OpPC, F, Status, FPO);2440}2441}24422443static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,2444uint32_t BitWidth, uint32_t FPOI) {2445const Floating &F = S.Stk.pop<Floating>();24462447APSInt Result(BitWidth, /*IsUnsigned=*/true);2448auto Status = F.convertToInteger(Result);24492450// Float-to-Integral overflow check.2451if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())2452return handleOverflow(S, OpPC, F.getAPFloat());24532454FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);24552456auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);2457ResultAP.copy(Result);24582459S.Stk.push<IntegralAP<false>>(ResultAP);24602461return CheckFloatResult(S, OpPC, F, Status, FPO);2462}24632464static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,2465uint32_t BitWidth, uint32_t FPOI) {2466const Floating &F = S.Stk.pop<Floating>();24672468APSInt Result(BitWidth, /*IsUnsigned=*/false);2469auto Status = F.convertToInteger(Result);24702471// Float-to-Integral overflow check.2472if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())2473return handleOverflow(S, OpPC, F.getAPFloat());24742475FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);24762477auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);2478ResultAP.copy(Result);24792480S.Stk.push<IntegralAP<true>>(ResultAP);24812482return CheckFloatResult(S, OpPC, F, Status, FPO);2483}24842485bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,2486const Pointer &Ptr, unsigned BitWidth);2487bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);2488bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);24892490template <PrimType Name, class T = typename PrimConv<Name>::T>2491bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {2492const Pointer &Ptr = S.Stk.pop<Pointer>();24932494S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)2495<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret2496<< S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);24972498if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))2499return Invalid(S, OpPC);25002501S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));2502return true;2503}25042505template <PrimType Name, class T = typename PrimConv<Name>::T>2506static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,2507uint32_t FPS) {2508const T &Int = S.Stk.pop<T>();25092510FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);25112512bool Overflow;2513FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);25142515if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2516return false;25172518S.Stk.push<FixedPoint>(Result);2519return true;2520}25212522static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,2523uint32_t FPS) {2524const auto &Float = S.Stk.pop<Floating>();25252526FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);25272528bool Overflow;2529FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);25302531if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2532return false;25332534S.Stk.push<FixedPoint>(Result);2535return true;2536}25372538static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,2539const llvm::fltSemantics *Sem) {2540const auto &Fixed = S.Stk.pop<FixedPoint>();2541Floating Result = S.allocFloat(*Sem);2542Result.copy(Fixed.toFloat(Sem));2543S.Stk.push<Floating>(Result);2544return true;2545}25462547template <PrimType Name, class T = typename PrimConv<Name>::T>2548static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {2549const auto &Fixed = S.Stk.pop<FixedPoint>();25502551bool Overflow;2552APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);25532554if (Overflow && !handleOverflow(S, OpPC, Int))2555return false;25562557S.Stk.push<T>(Int);2558return true;2559}25602561static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {2562const auto &Ptr = S.Stk.peek<Pointer>();25632564if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {2565bool HasValidResult = !Ptr.isZero();25662567if (HasValidResult) {2568if (S.getStdAllocatorCaller("allocate"))2569return true;25702571const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));2572if (S.getLangOpts().CPlusPlus26 &&2573S.getASTContext().hasSimilarType(Ptr.getType(),2574E->getType()->getPointeeType()))2575return true;25762577S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)2578<< E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus262579<< Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();2580} else if (!S.getLangOpts().CPlusPlus26) {2581const SourceInfo &E = S.Current->getSource(OpPC);2582S.CCEDiag(E, diag::note_constexpr_invalid_cast)2583<< diag::ConstexprInvalidCastKind::CastFrom << "'void *'"2584<< S.Current->getRange(OpPC);2585}2586} else {2587const SourceInfo &E = S.Current->getSource(OpPC);2588S.CCEDiag(E, diag::note_constexpr_invalid_cast)2589<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret2590<< S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);2591}25922593return true;2594}25952596//===----------------------------------------------------------------------===//2597// Zero, Nullptr2598//===----------------------------------------------------------------------===//25992600template <PrimType Name, class T = typename PrimConv<Name>::T>2601bool Zero(InterpState &S, CodePtr OpPC) {2602S.Stk.push<T>(T::zero());2603return true;2604}26052606static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2607auto Result = S.allocAP<IntegralAP<false>>(BitWidth);2608if (!Result.singleWord())2609std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));2610S.Stk.push<IntegralAP<false>>(Result);2611return true;2612}26132614static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2615auto Result = S.allocAP<IntegralAP<true>>(BitWidth);2616if (!Result.singleWord())2617std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));2618S.Stk.push<IntegralAP<true>>(Result);2619return true;2620}26212622template <PrimType Name, class T = typename PrimConv<Name>::T>2623inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,2624const Descriptor *Desc) {2625// FIXME(perf): This is a somewhat often-used function and the value of a2626// null pointer is almost always 0.2627S.Stk.push<T>(Value, Desc);2628return true;2629}26302631template <PrimType Name, class T = typename PrimConv<Name>::T>2632inline bool IsNonNull(InterpState &S, CodePtr OpPC) {2633const auto &P = S.Stk.pop<T>();2634if (P.isWeak())2635return false;2636S.Stk.push<Boolean>(Boolean::from(!P.isZero()));2637return true;2638}26392640//===----------------------------------------------------------------------===//2641// This, ImplicitThis2642//===----------------------------------------------------------------------===//26432644inline bool This(InterpState &S, CodePtr OpPC) {2645// Cannot read 'this' in this mode.2646if (S.checkingPotentialConstantExpression()) {2647return false;2648}26492650const Pointer &This = S.Current->getThis();2651if (!CheckThis(S, OpPC, This))2652return false;26532654// Ensure the This pointer has been cast to the correct base.2655if (!This.isDummy()) {2656assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));2657if (!This.isTypeidPointer()) {2658[[maybe_unused]] const Record *R = This.getRecord();2659if (!R)2660R = This.narrow().getRecord();2661assert(R);2662assert(R->getDecl() ==2663cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())2664->getParent());2665}2666}26672668S.Stk.push<Pointer>(This);2669return true;2670}26712672inline bool RVOPtr(InterpState &S, CodePtr OpPC) {2673assert(S.Current->getFunction()->hasRVO());2674if (S.checkingPotentialConstantExpression())2675return false;2676S.Stk.push<Pointer>(S.Current->getRVOPtr());2677return true;2678}26792680//===----------------------------------------------------------------------===//2681// Shr, Shl2682//===----------------------------------------------------------------------===//26832684template <class LT, class RT, ShiftDir Dir>2685inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,2686LT *Result) {2687static_assert(!needsAlloc<LT>());2688const unsigned Bits = LHS.bitWidth();26892690// OpenCL 6.3j: shift values are effectively % word size of LHS.2691if (S.getLangOpts().OpenCL)2692RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),2693RHS.bitWidth(), &RHS);26942695if (RHS.isNegative()) {2696// During constant-folding, a negative shift is an opposite shift. Such a2697// shift is not a constant expression.2698const SourceInfo &Loc = S.Current->getSource(OpPC);2699S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();2700if (!S.noteUndefinedBehavior())2701return false;2702RHS = -RHS;2703return DoShift<LT, RT,2704Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(2705S, OpPC, LHS, RHS, Result);2706}27072708if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))2709return false;27102711// Limit the shift amount to Bits - 1. If this happened,2712// it has already been diagnosed by CheckShift() above,2713// but we still need to handle it.2714// Note that we have to be extra careful here since we're doing the shift in2715// any case, but we need to adjust the shift amount or the way we do the shift2716// for the potential error cases.2717typename LT::AsUnsigned R;2718unsigned MaxShiftAmount = LHS.bitWidth() - 1;2719if constexpr (Dir == ShiftDir::Left) {2720if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==2721ComparisonCategoryResult::Greater) {2722if (LHS.isNegative())2723R = LT::AsUnsigned::zero(LHS.bitWidth());2724else {2725RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());2726LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2727LT::AsUnsigned::from(RHS, Bits), Bits, &R);2728}2729} else if (LHS.isNegative()) {2730if (LHS.isMin()) {2731R = LT::AsUnsigned::zero(LHS.bitWidth());2732} else {2733// If the LHS is negative, perform the cast and invert the result.2734typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);2735LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,2736&R);2737R = -R;2738}2739} else {2740// The good case, a simple left shift.2741LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2742LT::AsUnsigned::from(RHS, Bits), Bits, &R);2743}2744S.Stk.push<LT>(LT::from(R));2745return true;2746}27472748// Right shift.2749if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==2750ComparisonCategoryResult::Greater) {2751R = LT::AsUnsigned::from(-1);2752} else {2753// Do the shift on potentially signed LT, then convert to unsigned type.2754LT A;2755LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);2756R = LT::AsUnsigned::from(A);2757}27582759S.Stk.push<LT>(LT::from(R));2760return true;2761}27622763/// A version of DoShift that works on IntegralAP.2764template <class LT, class RT, ShiftDir Dir>2765inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,2766APSInt RHS, LT *Result) {2767const unsigned Bits = LHS.getBitWidth();27682769// OpenCL 6.3j: shift values are effectively % word size of LHS.2770if (S.getLangOpts().OpenCL)2771RHS &=2772APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),2773RHS.isUnsigned());27742775if (RHS.isNegative()) {2776// During constant-folding, a negative shift is an opposite shift. Such a2777// shift is not a constant expression.2778const SourceInfo &Loc = S.Current->getSource(OpPC);2779S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();2780if (!S.noteUndefinedBehavior())2781return false;2782return DoShiftAP<LT, RT,2783Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(2784S, OpPC, LHS, -RHS, Result);2785}27862787if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),2788Bits))2789return false;27902791unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1);2792if constexpr (Dir == ShiftDir::Left) {2793if constexpr (needsAlloc<LT>())2794Result->copy(LHS << SA);2795else2796*Result = LT(LHS << SA);2797} else {2798if constexpr (needsAlloc<LT>())2799Result->copy(LHS >> SA);2800else2801*Result = LT(LHS >> SA);2802}28032804S.Stk.push<LT>(*Result);2805return true;2806}28072808template <PrimType NameL, PrimType NameR>2809inline bool Shr(InterpState &S, CodePtr OpPC) {2810using LT = typename PrimConv<NameL>::T;2811using RT = typename PrimConv<NameR>::T;2812auto RHS = S.Stk.pop<RT>();2813auto LHS = S.Stk.pop<LT>();28142815if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {2816LT Result;2817if constexpr (needsAlloc<LT>())2818Result = S.allocAP<LT>(LHS.bitWidth());2819return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),2820RHS.toAPSInt(), &Result);2821} else {2822LT Result;2823return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);2824}2825}28262827template <PrimType NameL, PrimType NameR>2828inline bool Shl(InterpState &S, CodePtr OpPC) {2829using LT = typename PrimConv<NameL>::T;2830using RT = typename PrimConv<NameR>::T;2831auto RHS = S.Stk.pop<RT>();2832auto LHS = S.Stk.pop<LT>();28332834if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {2835LT Result;2836if constexpr (needsAlloc<LT>())2837Result = S.allocAP<LT>(LHS.bitWidth());2838return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),2839RHS.toAPSInt(), &Result);2840} else {2841LT Result;2842return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);2843}2844}28452846static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {2847const auto &RHS = S.Stk.pop<FixedPoint>();2848const auto &LHS = S.Stk.pop<FixedPoint>();2849llvm::FixedPointSemantics LHSSema = LHS.getSemantics();28502851unsigned ShiftBitWidth =2852LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;28532854// Embedded-C 4.1.6.2.2:2855// The right operand must be nonnegative and less than the total number2856// of (nonpadding) bits of the fixed-point operand ...2857if (RHS.isNegative()) {2858S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)2859<< RHS.toAPSInt();2860} else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(2861ShiftBitWidth)) != RHS.toAPSInt()) {2862const Expr *E = S.Current->getExpr(OpPC);2863S.CCEDiag(E, diag::note_constexpr_large_shift)2864<< RHS.toAPSInt() << E->getType() << ShiftBitWidth;2865}28662867FixedPoint Result;2868if (Left) {2869if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&2870!handleFixedPointOverflow(S, OpPC, Result))2871return false;2872} else {2873if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&2874!handleFixedPointOverflow(S, OpPC, Result))2875return false;2876}28772878S.Stk.push<FixedPoint>(Result);2879return true;2880}28812882//===----------------------------------------------------------------------===//2883// NoRet2884//===----------------------------------------------------------------------===//28852886inline bool NoRet(InterpState &S, CodePtr OpPC) {2887SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();2888S.FFDiag(EndLoc, diag::note_constexpr_no_return);2889return false;2890}28912892//===----------------------------------------------------------------------===//2893// NarrowPtr, ExpandPtr2894//===----------------------------------------------------------------------===//28952896inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {2897const Pointer &Ptr = S.Stk.pop<Pointer>();2898S.Stk.push<Pointer>(Ptr.narrow());2899return true;2900}29012902inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {2903const Pointer &Ptr = S.Stk.pop<Pointer>();2904if (Ptr.isBlockPointer())2905S.Stk.push<Pointer>(Ptr.expand());2906else2907S.Stk.push<Pointer>(Ptr);2908return true;2909}29102911// 1) Pops an integral value from the stack2912// 2) Peeks a pointer2913// 3) Pushes a new pointer that's a narrowed array2914// element of the peeked pointer with the value2915// from 1) added as offset.2916//2917// This leaves the original pointer on the stack and pushes a new one2918// with the offset applied and narrowed.2919template <PrimType Name, class T = typename PrimConv<Name>::T>2920inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {2921const T &Offset = S.Stk.pop<T>();2922const Pointer &Ptr = S.Stk.peek<Pointer>();29232924if (!Ptr.isZero() && !Offset.isZero()) {2925if (!CheckArray(S, OpPC, Ptr))2926return false;2927}29282929if (Offset.isZero()) {2930if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {2931S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());2932return true;2933}2934S.Stk.push<Pointer>(Ptr);2935return true;2936}29372938assert(!Offset.isZero());29392940if (std::optional<Pointer> Result =2941OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {2942S.Stk.push<Pointer>(Result->narrow());2943return true;2944}29452946return false;2947}29482949template <PrimType Name, class T = typename PrimConv<Name>::T>2950inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {2951const T &Offset = S.Stk.pop<T>();2952const Pointer &Ptr = S.Stk.pop<Pointer>();29532954if (!Ptr.isZero() && !Offset.isZero()) {2955if (!CheckArray(S, OpPC, Ptr))2956return false;2957}29582959if (Offset.isZero()) {2960if (Ptr.getFieldDesc()->isArray() && Ptr.getIndex() == 0) {2961S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());2962return true;2963}2964S.Stk.push<Pointer>(Ptr);2965return true;2966}29672968assert(!Offset.isZero());29692970if (std::optional<Pointer> Result =2971OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {2972S.Stk.push<Pointer>(Result->narrow());2973return true;2974}2975return false;2976}29772978template <PrimType Name, class T = typename PrimConv<Name>::T>2979inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {2980const Pointer &Ptr = S.Stk.peek<Pointer>();29812982if (!CheckLoad(S, OpPC, Ptr))2983return false;29842985assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);2986S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());2987return true;2988}29892990template <PrimType Name, class T = typename PrimConv<Name>::T>2991inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {2992const Pointer &Ptr = S.Stk.pop<Pointer>();29932994if (!CheckLoad(S, OpPC, Ptr))2995return false;29962997assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);2998S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());2999return true;3000}30013002template <PrimType Name, class T = typename PrimConv<Name>::T>3003inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,3004uint32_t DestIndex, uint32_t Size) {3005const auto &SrcPtr = S.Stk.pop<Pointer>();3006const auto &DestPtr = S.Stk.peek<Pointer>();30073008for (uint32_t I = 0; I != Size; ++I) {3009const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);30103011if (!CheckLoad(S, OpPC, SP))3012return false;30133014const Pointer &DP = DestPtr.atIndex(DestIndex + I);3015DP.deref<T>() = SP.deref<T>();3016DP.initialize();3017}3018return true;3019}30203021/// Just takes a pointer and checks if it's an incomplete3022/// array type.3023inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {3024const Pointer &Ptr = S.Stk.pop<Pointer>();30253026if (Ptr.isZero()) {3027S.Stk.push<Pointer>(Ptr);3028return true;3029}30303031if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))3032return false;30333034if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {3035S.Stk.push<Pointer>(Ptr.atIndex(0));3036return true;3037}30383039const SourceInfo &E = S.Current->getSource(OpPC);3040S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);30413042return false;3043}30443045inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {3046assert(Func);3047S.Stk.push<Pointer>(Func);3048return true;3049}30503051template <PrimType Name, class T = typename PrimConv<Name>::T>3052inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {3053const T &IntVal = S.Stk.pop<T>();30543055S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)3056<< diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret3057<< S.getLangOpts().CPlusPlus;30583059S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);3060return true;3061}30623063inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {3064S.Stk.push<MemberPointer>(D);3065return true;3066}30673068inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {3069const auto &MP = S.Stk.pop<MemberPointer>();30703071S.Stk.push<Pointer>(MP.getBase());3072return true;3073}30743075inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {3076const auto &MP = S.Stk.pop<MemberPointer>();30773078const auto *FD = cast<FunctionDecl>(MP.getDecl());3079const auto *Func = S.getContext().getOrCreateFunction(FD);30803081S.Stk.push<Pointer>(Func);3082return true;3083}30843085/// Just emit a diagnostic. The expression that caused emission of this3086/// op is not valid in a constant context.3087inline bool Invalid(InterpState &S, CodePtr OpPC) {3088const SourceLocation &Loc = S.Current->getLocation(OpPC);3089S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)3090<< S.Current->getRange(OpPC);3091return false;3092}30933094inline bool Unsupported(InterpState &S, CodePtr OpPC) {3095const SourceLocation &Loc = S.Current->getLocation(OpPC);3096S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)3097<< S.Current->getRange(OpPC);3098return false;3099}31003101inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {3102++S.SpeculationDepth;3103if (S.SpeculationDepth != 1)3104return true;31053106assert(S.PrevDiags == nullptr);3107S.PrevDiags = S.getEvalStatus().Diag;3108S.getEvalStatus().Diag = nullptr;3109return true;3110}3111inline bool EndSpeculation(InterpState &S, CodePtr OpPC) {3112assert(S.SpeculationDepth != 0);3113--S.SpeculationDepth;3114if (S.SpeculationDepth == 0) {3115S.getEvalStatus().Diag = S.PrevDiags;3116S.PrevDiags = nullptr;3117}3118return true;3119}31203121inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {3122S.ConstantContextOverride = Value;3123return true;3124}3125inline bool PopCC(InterpState &S, CodePtr OpPC) {3126S.ConstantContextOverride = std::nullopt;3127return true;3128}31293130/// Do nothing and just abort execution.3131inline bool Error(InterpState &S, CodePtr OpPC) { return false; }31323133inline bool SideEffect(InterpState &S, CodePtr OpPC) {3134return S.noteSideEffect();3135}31363137/// Same here, but only for casts.3138inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,3139bool Fatal) {3140const SourceLocation &Loc = S.Current->getLocation(OpPC);31413142if (Kind == CastKind::Reinterpret) {3143S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)3144<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);3145return !Fatal;3146} else if (Kind == CastKind::Volatile) {3147if (!S.checkingPotentialConstantExpression()) {3148const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));3149if (S.getLangOpts().CPlusPlus)3150S.FFDiag(E, diag::note_constexpr_access_volatile_type)3151<< AK_Read << E->getSubExpr()->getType();3152else3153S.FFDiag(E);3154}31553156return false;3157} else if (Kind == CastKind::Dynamic) {3158assert(!S.getLangOpts().CPlusPlus20);3159S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)3160<< diag::ConstexprInvalidCastKind::Dynamic;3161return true;3162}31633164return false;3165}31663167inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,3168bool InitializerFailed) {3169assert(DR);31703171if (InitializerFailed) {3172const SourceInfo &Loc = S.Current->getSource(OpPC);3173const auto *VD = cast<VarDecl>(DR->getDecl());3174S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;3175S.Note(VD->getLocation(), diag::note_declared_at);3176return false;3177}31783179return CheckDeclRef(S, OpPC, DR);3180}31813182inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {3183if (S.inConstantContext()) {3184const SourceRange &ArgRange = S.Current->getRange(OpPC);3185const Expr *E = S.Current->getExpr(OpPC);3186S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;3187}3188return false;3189}31903191inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {3192if (!S.getLangOpts().CPlusPlus20)3193S.CCEDiag(S.Current->getSource(OpPC),3194diag::note_constexpr_pseudo_destructor);3195return true;3196}31973198inline bool Assume(InterpState &S, CodePtr OpPC) {3199const auto Val = S.Stk.pop<Boolean>();32003201if (Val)3202return true;32033204// Else, diagnose.3205const SourceLocation &Loc = S.Current->getLocation(OpPC);3206S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);3207return false;3208}32093210template <PrimType Name, class T = typename PrimConv<Name>::T>3211inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {3212llvm::SmallVector<int64_t> ArrayIndices;3213for (size_t I = 0; I != E->getNumExpressions(); ++I)3214ArrayIndices.emplace_back(S.Stk.pop<int64_t>());32153216int64_t Result;3217if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))3218return false;32193220S.Stk.push<T>(T::from(Result));32213222return true;3223}32243225template <PrimType Name, class T = typename PrimConv<Name>::T>3226inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {3227const T &Arg = S.Stk.peek<T>();3228if (!Arg.isZero())3229return true;32303231const SourceLocation &Loc = S.Current->getLocation(OpPC);3232S.CCEDiag(Loc, diag::note_non_null_attribute_failed);32333234return false;3235}32363237void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,3238const APSInt &Value);32393240template <PrimType Name, class T = typename PrimConv<Name>::T>3241inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {3242assert(ED);3243assert(!ED->isFixed());32443245if (S.inConstantContext()) {3246const APSInt Val = S.Stk.peek<T>().toAPSInt();3247diagnoseEnumValue(S, OpPC, ED, Val);3248}3249return true;3250}32513252/// OldPtr -> Integer -> NewPtr.3253template <PrimType TIn, PrimType TOut>3254inline bool DecayPtr(InterpState &S, CodePtr OpPC) {3255static_assert(isPtrType(TIn) && isPtrType(TOut));3256using FromT = typename PrimConv<TIn>::T;3257using ToT = typename PrimConv<TOut>::T;32583259const FromT &OldPtr = S.Stk.pop<FromT>();32603261if constexpr (std::is_same_v<FromT, FunctionPointer> &&3262std::is_same_v<ToT, Pointer>) {3263S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());3264return true;3265} else if constexpr (std::is_same_v<FromT, Pointer> &&3266std::is_same_v<ToT, FunctionPointer>) {3267if (OldPtr.isFunctionPointer()) {3268S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),3269OldPtr.getByteOffset());3270return true;3271}3272}32733274S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));3275return true;3276}32773278inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {3279// An expression E is a core constant expression unless the evaluation of E3280// would evaluate one of the following: [C++23] - a control flow that passes3281// through a declaration of a variable with static or thread storage duration3282// unless that variable is usable in constant expressions.3283assert(VD->isLocalVarDecl() &&3284VD->isStaticLocal()); // Checked before emitting this.32853286if (VD == S.EvaluatingDecl)3287return true;32883289if (!VD->isUsableInConstantExpressions(S.getASTContext())) {3290S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)3291<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;3292return false;3293}3294return true;3295}32963297inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {3298assert(Desc);32993300if (!CheckDynamicMemoryAllocation(S, OpPC))3301return false;33023303DynamicAllocator &Allocator = S.getAllocator();3304Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),3305DynamicAllocator::Form::NonArray);3306assert(B);3307S.Stk.push<Pointer>(B);3308return true;3309}33103311template <PrimType Name, class SizeT = typename PrimConv<Name>::T>3312inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,3313bool IsNoThrow) {3314if (!CheckDynamicMemoryAllocation(S, OpPC))3315return false;33163317SizeT NumElements = S.Stk.pop<SizeT>();3318if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {3319if (!IsNoThrow)3320return false;33213322// If this failed and is nothrow, just return a null ptr.3323S.Stk.push<Pointer>(0, nullptr);3324return true;3325}3326assert(NumElements.isPositive());33273328if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))3329return false;33303331DynamicAllocator &Allocator = S.getAllocator();3332Block *B =3333Allocator.allocate(Source, T, static_cast<size_t>(NumElements),3334S.Ctx.getEvalID(), DynamicAllocator::Form::Array);3335assert(B);3336if (NumElements.isZero())3337S.Stk.push<Pointer>(B);3338else3339S.Stk.push<Pointer>(Pointer(B).atIndex(0));3340return true;3341}33423343template <PrimType Name, class SizeT = typename PrimConv<Name>::T>3344inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,3345bool IsNoThrow) {3346if (!CheckDynamicMemoryAllocation(S, OpPC))3347return false;33483349SizeT NumElements = S.Stk.pop<SizeT>();3350if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),3351IsNoThrow)) {3352if (!IsNoThrow)3353return false;33543355// If this failed and is nothrow, just return a null ptr.3356S.Stk.push<Pointer>(0, ElementDesc);3357return true;3358}3359assert(NumElements.isPositive());33603361if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))3362return false;33633364DynamicAllocator &Allocator = S.getAllocator();3365Block *B =3366Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),3367S.Ctx.getEvalID(), DynamicAllocator::Form::Array);3368assert(B);3369if (NumElements.isZero())3370S.Stk.push<Pointer>(B);3371else3372S.Stk.push<Pointer>(Pointer(B).atIndex(0));33733374return true;3375}33763377bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,3378bool IsGlobalDelete);33793380static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {3381S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));3382return true;3383}33843385static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {3386return S.maybeDiagnoseDanglingAllocations();3387}33883389/// Check if the initializer and storage types of a placement-new expression3390/// match.3391bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,3392std::optional<uint64_t> ArraySize = std::nullopt);33933394template <PrimType Name, class T = typename PrimConv<Name>::T>3395bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {3396const auto &Size = S.Stk.pop<T>();3397return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));3398}3399bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);34003401template <PrimType Name, class T = typename PrimConv<Name>::T>3402inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,3403uint32_t ResultBitWidth,3404const llvm::fltSemantics *Sem) {3405const Pointer &FromPtr = S.Stk.pop<Pointer>();34063407if (!CheckLoad(S, OpPC, FromPtr))3408return false;34093410if constexpr (std::is_same_v<T, Pointer>) {3411// The only pointer type we can validly bitcast to is nullptr_t.3412S.Stk.push<Pointer>();3413return true;3414} else {34153416size_t BuffSize = ResultBitWidth / 8;3417llvm::SmallVector<std::byte> Buff(BuffSize);3418bool HasIndeterminateBits = false;34193420Bits FullBitWidth(ResultBitWidth);3421Bits BitWidth = FullBitWidth;34223423if constexpr (std::is_same_v<T, Floating>) {3424assert(Sem);3425BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));3426}34273428if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,3429HasIndeterminateBits))3430return false;34313432if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))3433return false;34343435if constexpr (std::is_same_v<T, Floating>) {3436assert(Sem);3437Floating Result = S.allocFloat(*Sem);3438Floating::bitcastFromMemory(Buff.data(), *Sem, &Result);3439S.Stk.push<Floating>(Result);34403441// S.Stk.push<Floating>(T::bitcastFromMemory(Buff.data(), *Sem));3442} else if constexpr (needsAlloc<T>()) {3443T Result = S.allocAP<T>(ResultBitWidth);3444T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);3445S.Stk.push<T>(Result);3446} else {3447assert(!Sem);3448S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));3449}3450return true;3451}3452}34533454inline bool BitCast(InterpState &S, CodePtr OpPC) {3455const Pointer &FromPtr = S.Stk.pop<Pointer>();3456Pointer &ToPtr = S.Stk.peek<Pointer>();34573458if (!CheckLoad(S, OpPC, FromPtr))3459return false;34603461if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))3462return false;34633464return true;3465}34663467/// Typeid support.3468bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,3469const Type *TypeInfoType);3470bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);3471bool DiagTypeid(InterpState &S, CodePtr OpPC);34723473inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {3474const auto &Ptr = S.Stk.peek<Pointer>();3475return CheckDestructor(S, OpPC, Ptr);3476}34773478inline bool CheckArraySize(InterpState &S, CodePtr OpPC, uint64_t NumElems) {3479uint64_t Limit = S.getLangOpts().ConstexprStepLimit;3480if (NumElems > Limit) {3481S.FFDiag(S.Current->getSource(OpPC),3482diag::note_constexpr_new_exceeds_limits)3483<< NumElems << Limit;3484return false;3485}3486return true;3487}34883489//===----------------------------------------------------------------------===//3490// Read opcode arguments3491//===----------------------------------------------------------------------===//34923493template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {3494if constexpr (std::is_pointer<T>::value) {3495uint32_t ID = OpPC.read<uint32_t>();3496return reinterpret_cast<T>(S.P.getNativePointer(ID));3497} else {3498return OpPC.read<T>();3499}3500}35013502template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {3503auto &Semantics =3504llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC));35053506auto F = S.allocFloat(Semantics);3507Floating::deserialize(*OpPC, &F);3508OpPC += align(F.bytesToSerialize());3509return F;3510}35113512template <>3513inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,3514CodePtr &OpPC) {3515uint32_t BitWidth = IntegralAP<false>::deserializeSize(*OpPC);3516auto Result = S.allocAP<IntegralAP<false>>(BitWidth);3517assert(Result.bitWidth() == BitWidth);35183519IntegralAP<false>::deserialize(*OpPC, &Result);3520OpPC += align(Result.bytesToSerialize());3521return Result;3522}35233524template <>3525inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,3526CodePtr &OpPC) {3527uint32_t BitWidth = IntegralAP<true>::deserializeSize(*OpPC);3528auto Result = S.allocAP<IntegralAP<true>>(BitWidth);3529assert(Result.bitWidth() == BitWidth);35303531IntegralAP<true>::deserialize(*OpPC, &Result);3532OpPC += align(Result.bytesToSerialize());3533return Result;3534}35353536template <>3537inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {3538FixedPoint FP = FixedPoint::deserialize(*OpPC);3539OpPC += align(FP.bytesToSerialize());3540return FP;3541}35423543} // namespace interp3544} // namespace clang35453546#endif354735483549