Path: blob/main/contrib/llvm-project/clang/lib/AST/Interp/Interp.h
35292 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 "Boolean.h"17#include "DynamicAllocator.h"18#include "Floating.h"19#include "Function.h"20#include "FunctionPointer.h"21#include "InterpFrame.h"22#include "InterpStack.h"23#include "InterpState.h"24#include "MemberPointer.h"25#include "Opcode.h"26#include "PrimType.h"27#include "Program.h"28#include "State.h"29#include "clang/AST/ASTContext.h"30#include "clang/AST/Expr.h"31#include "llvm/ADT/APFloat.h"32#include "llvm/ADT/APSInt.h"33#include <type_traits>3435namespace clang {36namespace interp {3738using APSInt = llvm::APSInt;3940/// Convert a value to an APValue.41template <typename T>42bool ReturnValue(const InterpState &S, const T &V, APValue &R) {43R = V.toAPValue(S.getCtx());44return true;45}4647/// Checks if the variable has externally defined storage.48bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);4950/// Checks if the array is offsetable.51bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr);5253/// Checks if a pointer is live and accessible.54bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,55AccessKinds AK);5657/// Checks if a pointer is a dummy pointer.58bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr,59AccessKinds AK);6061/// Checks if a pointer is null.62bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,63CheckSubobjectKind CSK);6465/// Checks if a pointer is in range.66bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,67AccessKinds AK);6869/// Checks if a field from which a pointer is going to be derived is valid.70bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr,71CheckSubobjectKind CSK);7273/// Checks if Ptr is a one-past-the-end pointer.74bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,75CheckSubobjectKind CSK);7677/// Checks if the dowcast using the given offset is possible with the given78/// pointer.79bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,80uint32_t Offset);8182/// Checks if a pointer points to const storage.83bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);8485/// Checks if the Descriptor is of a constexpr or const global variable.86bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);8788/// Checks if a pointer points to a mutable field.89bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr);9091/// Checks if a value can be loaded from a block.92bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr,93AccessKinds AK = AK_Read);9495bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,96AccessKinds AK);97/// Check if a global variable is initialized.98bool CheckGlobalInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr);99100/// Checks if a value can be stored in a block.101bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr);102103/// Checks if a method can be invoked on an object.104bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr);105106/// Checks if a value can be initialized.107bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);108109/// Checks if a method can be called.110bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F);111112/// Checks if calling the currently active function would exceed113/// the allowed call depth.114bool CheckCallDepth(InterpState &S, CodePtr OpPC);115116/// Checks the 'this' pointer.117bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);118119/// Checks if a method is pure virtual.120bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);121122/// Checks if all the arguments annotated as 'nonnull' are in fact not null.123bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,124const CallExpr *CE, unsigned ArgSize);125126/// Checks if dynamic memory allocation is available in the current127/// language mode.128bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);129130/// Diagnose mismatched new[]/delete or new/delete[] pairs.131bool CheckNewDeleteForms(InterpState &S, CodePtr OpPC, bool NewWasArray,132bool DeleteIsArray, const Descriptor *D,133const Expr *NewExpr);134135/// Check the source of the pointer passed to delete/delete[] has actually136/// been heap allocated by us.137bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,138const Pointer &Ptr);139140/// Sets the given integral value to the pointer, which is of141/// a std::{weak,partial,strong}_ordering type.142bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,143const Pointer &Ptr, const APSInt &IntValue);144145/// Copy the contents of Src into Dest.146bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest);147148/// Checks if the shift operation is legal.149template <typename LT, typename RT>150bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,151unsigned Bits) {152if (RHS.isNegative()) {153const SourceInfo &Loc = S.Current->getSource(OpPC);154S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();155if (!S.noteUndefinedBehavior())156return false;157}158159// C++11 [expr.shift]p1: Shift width must be less than the bit width of160// the shifted type.161if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) {162const Expr *E = S.Current->getExpr(OpPC);163const APSInt Val = RHS.toAPSInt();164QualType Ty = E->getType();165S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;166if (!S.noteUndefinedBehavior())167return false;168}169170if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {171const Expr *E = S.Current->getExpr(OpPC);172// C++11 [expr.shift]p2: A signed left shift must have a non-negative173// operand, and must not overflow the corresponding unsigned type.174if (LHS.isNegative()) {175S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();176if (!S.noteUndefinedBehavior())177return false;178} else if (LHS.toUnsigned().countLeadingZeros() <179static_cast<unsigned>(RHS)) {180S.CCEDiag(E, diag::note_constexpr_lshift_discards);181if (!S.noteUndefinedBehavior())182return false;183}184}185186// C++2a [expr.shift]p2: [P0907R4]:187// E1 << E2 is the unique value congruent to188// E1 x 2^E2 module 2^N.189return true;190}191192/// Checks if Div/Rem operation on LHS and RHS is valid.193template <typename T>194bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {195if (RHS.isZero()) {196const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));197if constexpr (std::is_same_v<T, Floating>) {198S.CCEDiag(Op, diag::note_expr_divide_by_zero)199<< Op->getRHS()->getSourceRange();200return true;201}202203S.FFDiag(Op, diag::note_expr_divide_by_zero)204<< Op->getRHS()->getSourceRange();205return false;206}207208if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {209APSInt LHSInt = LHS.toAPSInt();210SmallString<32> Trunc;211(-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);212const SourceInfo &Loc = S.Current->getSource(OpPC);213const Expr *E = S.Current->getExpr(OpPC);214S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();215return false;216}217return true;218}219220template <typename SizeT>221bool CheckArraySize(InterpState &S, CodePtr OpPC, SizeT *NumElements,222unsigned ElemSize, bool IsNoThrow) {223// FIXME: Both the SizeT::from() as well as the224// NumElements.toAPSInt() in this function are rather expensive.225226// FIXME: GH63562227// APValue stores array extents as unsigned,228// so anything that is greater that unsigned would overflow when229// constructing the array, we catch this here.230SizeT MaxElements = SizeT::from(Descriptor::MaxArrayElemBytes / ElemSize);231if (NumElements->toAPSInt().getActiveBits() >232ConstantArrayType::getMaxSizeBits(S.getCtx()) ||233*NumElements > MaxElements) {234if (!IsNoThrow) {235const SourceInfo &Loc = S.Current->getSource(OpPC);236S.FFDiag(Loc, diag::note_constexpr_new_too_large)237<< NumElements->toDiagnosticString(S.getCtx());238}239return false;240}241return true;242}243244/// Checks if the result of a floating-point operation is valid245/// in the current context.246bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,247APFloat::opStatus Status);248249/// Checks why the given DeclRefExpr is invalid.250bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);251252/// Interpreter entry point.253bool Interpret(InterpState &S, APValue &Result);254255/// Interpret a builtin function.256bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,257const CallExpr *Call);258259/// Interpret an offsetof operation.260bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E,261llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result);262263inline bool Invalid(InterpState &S, CodePtr OpPC);264265enum class ArithOp { Add, Sub };266267//===----------------------------------------------------------------------===//268// Returning values269//===----------------------------------------------------------------------===//270271void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC);272273template <PrimType Name, class T = typename PrimConv<Name>::T>274bool Ret(InterpState &S, CodePtr &PC, APValue &Result) {275const T &Ret = S.Stk.pop<T>();276277// Make sure returned pointers are live. We might be trying to return a278// pointer or reference to a local variable.279// Just return false, since a diagnostic has already been emitted in Sema.280if constexpr (std::is_same_v<T, Pointer>) {281// FIXME: We could be calling isLive() here, but the emitted diagnostics282// seem a little weird, at least if the returned expression is of283// pointer type.284// Null pointers are considered live here.285if (!Ret.isZero() && !Ret.isLive())286return false;287}288289assert(S.Current);290assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");291if (!S.checkingPotentialConstantExpression() || S.Current->Caller)292cleanupAfterFunctionCall(S, PC);293294if (InterpFrame *Caller = S.Current->Caller) {295PC = S.Current->getRetPC();296delete S.Current;297S.Current = Caller;298S.Stk.push<T>(Ret);299} else {300delete S.Current;301S.Current = nullptr;302if (!ReturnValue<T>(S, Ret, Result))303return false;304}305return true;306}307308inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) {309assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");310311if (!S.checkingPotentialConstantExpression() || S.Current->Caller)312cleanupAfterFunctionCall(S, PC);313314if (InterpFrame *Caller = S.Current->Caller) {315PC = S.Current->getRetPC();316delete S.Current;317S.Current = Caller;318} else {319delete S.Current;320S.Current = nullptr;321}322return true;323}324325//===----------------------------------------------------------------------===//326// Add, Sub, Mul327//===----------------------------------------------------------------------===//328329template <typename T, bool (*OpFW)(T, T, unsigned, T *),330template <typename U> class OpAP>331bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,332const T &RHS) {333// Fast path - add the numbers with fixed width.334T Result;335if (!OpFW(LHS, RHS, Bits, &Result)) {336S.Stk.push<T>(Result);337return true;338}339340// If for some reason evaluation continues, use the truncated results.341S.Stk.push<T>(Result);342343// Slow path - compute the result using another bit of precision.344APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));345346// Report undefined behaviour, stopping if required.347const Expr *E = S.Current->getExpr(OpPC);348QualType Type = E->getType();349if (S.checkingForUndefinedBehavior()) {350SmallString<32> Trunc;351Value.trunc(Result.bitWidth())352.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,353/*UpperCase=*/true, /*InsertSeparators=*/true);354auto Loc = E->getExprLoc();355S.report(Loc, diag::warn_integer_constant_overflow)356<< Trunc << Type << E->getSourceRange();357}358359S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type;360361if (!S.noteUndefinedBehavior()) {362S.Stk.pop<T>();363return false;364}365366return true;367}368369template <PrimType Name, class T = typename PrimConv<Name>::T>370bool Add(InterpState &S, CodePtr OpPC) {371const T &RHS = S.Stk.pop<T>();372const T &LHS = S.Stk.pop<T>();373const unsigned Bits = RHS.bitWidth() + 1;374return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);375}376377inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {378const Floating &RHS = S.Stk.pop<Floating>();379const Floating &LHS = S.Stk.pop<Floating>();380381Floating Result;382auto Status = Floating::add(LHS, RHS, RM, &Result);383S.Stk.push<Floating>(Result);384return CheckFloatResult(S, OpPC, Result, Status);385}386387template <PrimType Name, class T = typename PrimConv<Name>::T>388bool Sub(InterpState &S, CodePtr OpPC) {389const T &RHS = S.Stk.pop<T>();390const T &LHS = S.Stk.pop<T>();391const unsigned Bits = RHS.bitWidth() + 1;392return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);393}394395inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {396const Floating &RHS = S.Stk.pop<Floating>();397const Floating &LHS = S.Stk.pop<Floating>();398399Floating Result;400auto Status = Floating::sub(LHS, RHS, RM, &Result);401S.Stk.push<Floating>(Result);402return CheckFloatResult(S, OpPC, Result, Status);403}404405template <PrimType Name, class T = typename PrimConv<Name>::T>406bool Mul(InterpState &S, CodePtr OpPC) {407const T &RHS = S.Stk.pop<T>();408const T &LHS = S.Stk.pop<T>();409const unsigned Bits = RHS.bitWidth() * 2;410return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);411}412413inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {414const Floating &RHS = S.Stk.pop<Floating>();415const Floating &LHS = S.Stk.pop<Floating>();416417Floating Result;418auto Status = Floating::mul(LHS, RHS, RM, &Result);419S.Stk.push<Floating>(Result);420return CheckFloatResult(S, OpPC, Result, Status);421}422423template <PrimType Name, class T = typename PrimConv<Name>::T>424inline bool Mulc(InterpState &S, CodePtr OpPC) {425const Pointer &RHS = S.Stk.pop<Pointer>();426const Pointer &LHS = S.Stk.pop<Pointer>();427const Pointer &Result = S.Stk.peek<Pointer>();428429if constexpr (std::is_same_v<T, Floating>) {430APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();431APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();432APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();433APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();434435APFloat ResR(A.getSemantics());436APFloat ResI(A.getSemantics());437HandleComplexComplexMul(A, B, C, D, ResR, ResI);438439// Copy into the result.440Result.atIndex(0).deref<Floating>() = Floating(ResR);441Result.atIndex(0).initialize();442Result.atIndex(1).deref<Floating>() = Floating(ResI);443Result.atIndex(1).initialize();444Result.initialize();445} else {446// Integer element type.447const T &LHSR = LHS.atIndex(0).deref<T>();448const T &LHSI = LHS.atIndex(1).deref<T>();449const T &RHSR = RHS.atIndex(0).deref<T>();450const T &RHSI = RHS.atIndex(1).deref<T>();451unsigned Bits = LHSR.bitWidth();452453// real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))454T A;455if (T::mul(LHSR, RHSR, Bits, &A))456return false;457T B;458if (T::mul(LHSI, RHSI, Bits, &B))459return false;460if (T::sub(A, B, Bits, &Result.atIndex(0).deref<T>()))461return false;462Result.atIndex(0).initialize();463464// imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))465if (T::mul(LHSR, RHSI, Bits, &A))466return false;467if (T::mul(LHSI, RHSR, Bits, &B))468return false;469if (T::add(A, B, Bits, &Result.atIndex(1).deref<T>()))470return false;471Result.atIndex(1).initialize();472Result.initialize();473}474475return true;476}477478template <PrimType Name, class T = typename PrimConv<Name>::T>479inline bool Divc(InterpState &S, CodePtr OpPC) {480const Pointer &RHS = S.Stk.pop<Pointer>();481const Pointer &LHS = S.Stk.pop<Pointer>();482const Pointer &Result = S.Stk.peek<Pointer>();483484if constexpr (std::is_same_v<T, Floating>) {485APFloat A = LHS.atIndex(0).deref<Floating>().getAPFloat();486APFloat B = LHS.atIndex(1).deref<Floating>().getAPFloat();487APFloat C = RHS.atIndex(0).deref<Floating>().getAPFloat();488APFloat D = RHS.atIndex(1).deref<Floating>().getAPFloat();489490APFloat ResR(A.getSemantics());491APFloat ResI(A.getSemantics());492HandleComplexComplexDiv(A, B, C, D, ResR, ResI);493494// Copy into the result.495Result.atIndex(0).deref<Floating>() = Floating(ResR);496Result.atIndex(0).initialize();497Result.atIndex(1).deref<Floating>() = Floating(ResI);498Result.atIndex(1).initialize();499Result.initialize();500} else {501// Integer element type.502const T &LHSR = LHS.atIndex(0).deref<T>();503const T &LHSI = LHS.atIndex(1).deref<T>();504const T &RHSR = RHS.atIndex(0).deref<T>();505const T &RHSI = RHS.atIndex(1).deref<T>();506unsigned Bits = LHSR.bitWidth();507const T Zero = T::from(0, Bits);508509if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&510Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {511const SourceInfo &E = S.Current->getSource(OpPC);512S.FFDiag(E, diag::note_expr_divide_by_zero);513return false;514}515516// Den = real(RHS)² + imag(RHS)²517T A, B;518if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B))519return false;520T Den;521if (T::add(A, B, Bits, &Den))522return false;523524// real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den525T &ResultR = Result.atIndex(0).deref<T>();526T &ResultI = Result.atIndex(1).deref<T>();527528if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))529return false;530if (T::add(A, B, Bits, &ResultR))531return false;532if (T::div(ResultR, Den, Bits, &ResultR))533return false;534Result.atIndex(0).initialize();535536// imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den537if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))538return false;539if (T::sub(A, B, Bits, &ResultI))540return false;541if (T::div(ResultI, Den, Bits, &ResultI))542return false;543Result.atIndex(1).initialize();544Result.initialize();545}546547return true;548}549550/// 1) Pops the RHS from the stack.551/// 2) Pops the LHS from the stack.552/// 3) Pushes 'LHS & RHS' on the stack553template <PrimType Name, class T = typename PrimConv<Name>::T>554bool BitAnd(InterpState &S, CodePtr OpPC) {555const T &RHS = S.Stk.pop<T>();556const T &LHS = S.Stk.pop<T>();557558unsigned Bits = RHS.bitWidth();559T Result;560if (!T::bitAnd(LHS, RHS, Bits, &Result)) {561S.Stk.push<T>(Result);562return true;563}564return false;565}566567/// 1) Pops the RHS from the stack.568/// 2) Pops the LHS from the stack.569/// 3) Pushes 'LHS | RHS' on the stack570template <PrimType Name, class T = typename PrimConv<Name>::T>571bool BitOr(InterpState &S, CodePtr OpPC) {572const T &RHS = S.Stk.pop<T>();573const T &LHS = S.Stk.pop<T>();574575unsigned Bits = RHS.bitWidth();576T Result;577if (!T::bitOr(LHS, RHS, Bits, &Result)) {578S.Stk.push<T>(Result);579return true;580}581return false;582}583584/// 1) Pops the RHS from the stack.585/// 2) Pops the LHS from the stack.586/// 3) Pushes 'LHS ^ RHS' on the stack587template <PrimType Name, class T = typename PrimConv<Name>::T>588bool BitXor(InterpState &S, CodePtr OpPC) {589const T &RHS = S.Stk.pop<T>();590const T &LHS = S.Stk.pop<T>();591592unsigned Bits = RHS.bitWidth();593T Result;594if (!T::bitXor(LHS, RHS, Bits, &Result)) {595S.Stk.push<T>(Result);596return true;597}598return false;599}600601/// 1) Pops the RHS from the stack.602/// 2) Pops the LHS from the stack.603/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).604template <PrimType Name, class T = typename PrimConv<Name>::T>605bool Rem(InterpState &S, CodePtr OpPC) {606const T &RHS = S.Stk.pop<T>();607const T &LHS = S.Stk.pop<T>();608609if (!CheckDivRem(S, OpPC, LHS, RHS))610return false;611612const unsigned Bits = RHS.bitWidth() * 2;613T Result;614if (!T::rem(LHS, RHS, Bits, &Result)) {615S.Stk.push<T>(Result);616return true;617}618return false;619}620621/// 1) Pops the RHS from the stack.622/// 2) Pops the LHS from the stack.623/// 3) Pushes 'LHS / RHS' on the stack624template <PrimType Name, class T = typename PrimConv<Name>::T>625bool Div(InterpState &S, CodePtr OpPC) {626const T &RHS = S.Stk.pop<T>();627const T &LHS = S.Stk.pop<T>();628629if (!CheckDivRem(S, OpPC, LHS, RHS))630return false;631632const unsigned Bits = RHS.bitWidth() * 2;633T Result;634if (!T::div(LHS, RHS, Bits, &Result)) {635S.Stk.push<T>(Result);636return true;637}638return false;639}640641inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {642const Floating &RHS = S.Stk.pop<Floating>();643const Floating &LHS = S.Stk.pop<Floating>();644645if (!CheckDivRem(S, OpPC, LHS, RHS))646return false;647648Floating Result;649auto Status = Floating::div(LHS, RHS, RM, &Result);650S.Stk.push<Floating>(Result);651return CheckFloatResult(S, OpPC, Result, Status);652}653654//===----------------------------------------------------------------------===//655// Inv656//===----------------------------------------------------------------------===//657658template <PrimType Name, class T = typename PrimConv<Name>::T>659bool Inv(InterpState &S, CodePtr OpPC) {660using BoolT = PrimConv<PT_Bool>::T;661const T &Val = S.Stk.pop<T>();662const unsigned Bits = Val.bitWidth();663Boolean R;664Boolean::inv(BoolT::from(Val, Bits), &R);665666S.Stk.push<BoolT>(R);667return true;668}669670//===----------------------------------------------------------------------===//671// Neg672//===----------------------------------------------------------------------===//673674template <PrimType Name, class T = typename PrimConv<Name>::T>675bool Neg(InterpState &S, CodePtr OpPC) {676const T &Value = S.Stk.pop<T>();677T Result;678679if (!T::neg(Value, &Result)) {680S.Stk.push<T>(Result);681return true;682}683684assert(isIntegralType(Name) &&685"don't expect other types to fail at constexpr negation");686S.Stk.push<T>(Result);687688APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);689const Expr *E = S.Current->getExpr(OpPC);690QualType Type = E->getType();691692if (S.checkingForUndefinedBehavior()) {693SmallString<32> Trunc;694NegatedValue.trunc(Result.bitWidth())695.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,696/*UpperCase=*/true, /*InsertSeparators=*/true);697auto Loc = E->getExprLoc();698S.report(Loc, diag::warn_integer_constant_overflow)699<< Trunc << Type << E->getSourceRange();700return true;701}702703S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type;704return S.noteUndefinedBehavior();705}706707enum class PushVal : bool {708No,709Yes,710};711enum class IncDecOp {712Inc,713Dec,714};715716template <typename T, IncDecOp Op, PushVal DoPush>717bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {718assert(!Ptr.isDummy());719720if constexpr (std::is_same_v<T, Boolean>) {721if (!S.getLangOpts().CPlusPlus14)722return Invalid(S, OpPC);723}724725const T &Value = Ptr.deref<T>();726T Result;727728if constexpr (DoPush == PushVal::Yes)729S.Stk.push<T>(Value);730731if constexpr (Op == IncDecOp::Inc) {732if (!T::increment(Value, &Result)) {733Ptr.deref<T>() = Result;734return true;735}736} else {737if (!T::decrement(Value, &Result)) {738Ptr.deref<T>() = Result;739return true;740}741}742743// Something went wrong with the previous operation. Compute the744// result with another bit of precision.745unsigned Bits = Value.bitWidth() + 1;746APSInt APResult;747if constexpr (Op == IncDecOp::Inc)748APResult = ++Value.toAPSInt(Bits);749else750APResult = --Value.toAPSInt(Bits);751752// Report undefined behaviour, stopping if required.753const Expr *E = S.Current->getExpr(OpPC);754QualType Type = E->getType();755if (S.checkingForUndefinedBehavior()) {756SmallString<32> Trunc;757APResult.trunc(Result.bitWidth())758.toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,759/*UpperCase=*/true, /*InsertSeparators=*/true);760auto Loc = E->getExprLoc();761S.report(Loc, diag::warn_integer_constant_overflow)762<< Trunc << Type << E->getSourceRange();763return true;764}765766S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type;767return S.noteUndefinedBehavior();768}769770/// 1) Pops a pointer from the stack771/// 2) Load the value from the pointer772/// 3) Writes the value increased by one back to the pointer773/// 4) Pushes the original (pre-inc) value on the stack.774template <PrimType Name, class T = typename PrimConv<Name>::T>775bool Inc(InterpState &S, CodePtr OpPC) {776const Pointer &Ptr = S.Stk.pop<Pointer>();777if (!CheckLoad(S, OpPC, Ptr, AK_Increment))778return false;779780return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr);781}782783/// 1) Pops a pointer from the stack784/// 2) Load the value from the pointer785/// 3) Writes the value increased by one back to the pointer786template <PrimType Name, class T = typename PrimConv<Name>::T>787bool IncPop(InterpState &S, CodePtr OpPC) {788const Pointer &Ptr = S.Stk.pop<Pointer>();789if (!CheckLoad(S, OpPC, Ptr, AK_Increment))790return false;791792return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr);793}794795/// 1) Pops a pointer from the stack796/// 2) Load the value from the pointer797/// 3) Writes the value decreased by one back to the pointer798/// 4) Pushes the original (pre-dec) value on the stack.799template <PrimType Name, class T = typename PrimConv<Name>::T>800bool Dec(InterpState &S, CodePtr OpPC) {801const Pointer &Ptr = S.Stk.pop<Pointer>();802if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))803return false;804805return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr);806}807808/// 1) Pops a pointer from the stack809/// 2) Load the value from the pointer810/// 3) Writes the value decreased by one back to the pointer811template <PrimType Name, class T = typename PrimConv<Name>::T>812bool DecPop(InterpState &S, CodePtr OpPC) {813const Pointer &Ptr = S.Stk.pop<Pointer>();814if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))815return false;816817return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr);818}819820template <IncDecOp Op, PushVal DoPush>821bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,822llvm::RoundingMode RM) {823Floating Value = Ptr.deref<Floating>();824Floating Result;825826if constexpr (DoPush == PushVal::Yes)827S.Stk.push<Floating>(Value);828829llvm::APFloat::opStatus Status;830if constexpr (Op == IncDecOp::Inc)831Status = Floating::increment(Value, RM, &Result);832else833Status = Floating::decrement(Value, RM, &Result);834835Ptr.deref<Floating>() = Result;836837return CheckFloatResult(S, OpPC, Result, Status);838}839840inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {841const Pointer &Ptr = S.Stk.pop<Pointer>();842if (!CheckLoad(S, OpPC, Ptr, AK_Increment))843return false;844845return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM);846}847848inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {849const Pointer &Ptr = S.Stk.pop<Pointer>();850if (!CheckLoad(S, OpPC, Ptr, AK_Increment))851return false;852853return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM);854}855856inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {857const Pointer &Ptr = S.Stk.pop<Pointer>();858if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))859return false;860861return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM);862}863864inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) {865const Pointer &Ptr = S.Stk.pop<Pointer>();866if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))867return false;868869return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM);870}871872/// 1) Pops the value from the stack.873/// 2) Pushes the bitwise complemented value on the stack (~V).874template <PrimType Name, class T = typename PrimConv<Name>::T>875bool Comp(InterpState &S, CodePtr OpPC) {876const T &Val = S.Stk.pop<T>();877T Result;878if (!T::comp(Val, &Result)) {879S.Stk.push<T>(Result);880return true;881}882883return false;884}885886//===----------------------------------------------------------------------===//887// EQ, NE, GT, GE, LT, LE888//===----------------------------------------------------------------------===//889890using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;891892template <typename T>893bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {894assert((!std::is_same_v<T, MemberPointer>) &&895"Non-equality comparisons on member pointer types should already be "896"rejected in Sema.");897using BoolT = PrimConv<PT_Bool>::T;898const T &RHS = S.Stk.pop<T>();899const T &LHS = S.Stk.pop<T>();900S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));901return true;902}903904template <typename T>905bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {906return CmpHelper<T>(S, OpPC, Fn);907}908909/// Function pointers cannot be compared in an ordered way.910template <>911inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC,912CompareFn Fn) {913const auto &RHS = S.Stk.pop<FunctionPointer>();914const auto &LHS = S.Stk.pop<FunctionPointer>();915916const SourceInfo &Loc = S.Current->getSource(OpPC);917S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)918<< LHS.toDiagnosticString(S.getCtx())919<< RHS.toDiagnosticString(S.getCtx());920return false;921}922923template <>924inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC,925CompareFn Fn) {926const auto &RHS = S.Stk.pop<FunctionPointer>();927const auto &LHS = S.Stk.pop<FunctionPointer>();928929// We cannot compare against weak declarations at compile time.930for (const auto &FP : {LHS, RHS}) {931if (FP.isWeak()) {932const SourceInfo &Loc = S.Current->getSource(OpPC);933S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)934<< FP.toDiagnosticString(S.getCtx());935return false;936}937}938939S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));940return true;941}942943template <>944inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {945using BoolT = PrimConv<PT_Bool>::T;946const Pointer &RHS = S.Stk.pop<Pointer>();947const Pointer &LHS = S.Stk.pop<Pointer>();948949if (!Pointer::hasSameBase(LHS, RHS)) {950const SourceInfo &Loc = S.Current->getSource(OpPC);951S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)952<< LHS.toDiagnosticString(S.getCtx())953<< RHS.toDiagnosticString(S.getCtx());954return false;955} else {956unsigned VL = LHS.getByteOffset();957unsigned VR = RHS.getByteOffset();958S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));959return true;960}961}962963template <>964inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {965using BoolT = PrimConv<PT_Bool>::T;966const Pointer &RHS = S.Stk.pop<Pointer>();967const Pointer &LHS = S.Stk.pop<Pointer>();968969if (LHS.isZero() && RHS.isZero()) {970S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));971return true;972}973974// Reject comparisons to weak pointers.975for (const auto &P : {LHS, RHS}) {976if (P.isZero())977continue;978if (P.isWeak()) {979const SourceInfo &Loc = S.Current->getSource(OpPC);980S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)981<< P.toDiagnosticString(S.getCtx());982return false;983}984}985986if (!Pointer::hasSameBase(LHS, RHS)) {987if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&988RHS.getOffset() == 0) {989const SourceInfo &Loc = S.Current->getSource(OpPC);990S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)991<< LHS.toDiagnosticString(S.getCtx());992return false;993} else if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&994LHS.getOffset() == 0) {995const SourceInfo &Loc = S.Current->getSource(OpPC);996S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)997<< RHS.toDiagnosticString(S.getCtx());998return false;999}10001001S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));1002return true;1003} else {1004unsigned VL = LHS.getByteOffset();1005unsigned VR = RHS.getByteOffset();10061007// In our Pointer class, a pointer to an array and a pointer to the first1008// element in the same array are NOT equal. They have the same Base value,1009// but a different Offset. This is a pretty rare case, so we fix this here1010// by comparing pointers to the first elements.1011if (!LHS.isZero() && LHS.isArrayRoot())1012VL = LHS.atIndex(0).getByteOffset();1013if (!RHS.isZero() && RHS.isArrayRoot())1014VR = RHS.atIndex(0).getByteOffset();10151016S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));1017return true;1018}1019}10201021template <>1022inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,1023CompareFn Fn) {1024const auto &RHS = S.Stk.pop<MemberPointer>();1025const auto &LHS = S.Stk.pop<MemberPointer>();10261027// If either operand is a pointer to a weak function, the comparison is not1028// constant.1029for (const auto &MP : {LHS, RHS}) {1030if (const CXXMethodDecl *MD = MP.getMemberFunction(); MD && MD->isWeak()) {1031const SourceInfo &Loc = S.Current->getSource(OpPC);1032S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison) << MD;1033return false;1034}1035}10361037// C++11 [expr.eq]p2:1038// If both operands are null, they compare equal. Otherwise if only one is1039// null, they compare unequal.1040if (LHS.isZero() && RHS.isZero()) {1041S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));1042return true;1043}1044if (LHS.isZero() || RHS.isZero()) {1045S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));1046return true;1047}10481049// We cannot compare against virtual declarations at compile time.1050for (const auto &MP : {LHS, RHS}) {1051if (const CXXMethodDecl *MD = MP.getMemberFunction();1052MD && MD->isVirtual()) {1053const SourceInfo &Loc = S.Current->getSource(OpPC);1054S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;1055}1056}10571058S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));1059return true;1060}10611062template <PrimType Name, class T = typename PrimConv<Name>::T>1063bool EQ(InterpState &S, CodePtr OpPC) {1064return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1065return R == ComparisonCategoryResult::Equal;1066});1067}10681069template <PrimType Name, class T = typename PrimConv<Name>::T>1070bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {1071const T &RHS = S.Stk.pop<T>();1072const T &LHS = S.Stk.pop<T>();1073const Pointer &P = S.Stk.peek<Pointer>();10741075ComparisonCategoryResult CmpResult = LHS.compare(RHS);1076if (CmpResult == ComparisonCategoryResult::Unordered) {1077// This should only happen with pointers.1078const SourceInfo &Loc = S.Current->getSource(OpPC);1079S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1080<< LHS.toDiagnosticString(S.getCtx())1081<< RHS.toDiagnosticString(S.getCtx());1082return false;1083}10841085assert(CmpInfo);1086const auto *CmpValueInfo =1087CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));1088assert(CmpValueInfo);1089assert(CmpValueInfo->hasValidIntValue());1090return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());1091}10921093template <PrimType Name, class T = typename PrimConv<Name>::T>1094bool NE(InterpState &S, CodePtr OpPC) {1095return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1096return R != ComparisonCategoryResult::Equal;1097});1098}10991100template <PrimType Name, class T = typename PrimConv<Name>::T>1101bool LT(InterpState &S, CodePtr OpPC) {1102return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1103return R == ComparisonCategoryResult::Less;1104});1105}11061107template <PrimType Name, class T = typename PrimConv<Name>::T>1108bool LE(InterpState &S, CodePtr OpPC) {1109return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1110return R == ComparisonCategoryResult::Less ||1111R == ComparisonCategoryResult::Equal;1112});1113}11141115template <PrimType Name, class T = typename PrimConv<Name>::T>1116bool GT(InterpState &S, CodePtr OpPC) {1117return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1118return R == ComparisonCategoryResult::Greater;1119});1120}11211122template <PrimType Name, class T = typename PrimConv<Name>::T>1123bool GE(InterpState &S, CodePtr OpPC) {1124return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1125return R == ComparisonCategoryResult::Greater ||1126R == ComparisonCategoryResult::Equal;1127});1128}11291130//===----------------------------------------------------------------------===//1131// InRange1132//===----------------------------------------------------------------------===//11331134template <PrimType Name, class T = typename PrimConv<Name>::T>1135bool InRange(InterpState &S, CodePtr OpPC) {1136const T RHS = S.Stk.pop<T>();1137const T LHS = S.Stk.pop<T>();1138const T Value = S.Stk.pop<T>();11391140S.Stk.push<bool>(LHS <= Value && Value <= RHS);1141return true;1142}11431144//===----------------------------------------------------------------------===//1145// Dup, Pop, Test1146//===----------------------------------------------------------------------===//11471148template <PrimType Name, class T = typename PrimConv<Name>::T>1149bool Dup(InterpState &S, CodePtr OpPC) {1150S.Stk.push<T>(S.Stk.peek<T>());1151return true;1152}11531154template <PrimType Name, class T = typename PrimConv<Name>::T>1155bool Pop(InterpState &S, CodePtr OpPC) {1156S.Stk.pop<T>();1157return true;1158}11591160//===----------------------------------------------------------------------===//1161// Const1162//===----------------------------------------------------------------------===//11631164template <PrimType Name, class T = typename PrimConv<Name>::T>1165bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {1166S.Stk.push<T>(Arg);1167return true;1168}11691170//===----------------------------------------------------------------------===//1171// Get/Set Local/Param/Global/This1172//===----------------------------------------------------------------------===//11731174template <PrimType Name, class T = typename PrimConv<Name>::T>1175bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1176const Pointer &Ptr = S.Current->getLocalPointer(I);1177if (!CheckLoad(S, OpPC, Ptr))1178return false;1179S.Stk.push<T>(Ptr.deref<T>());1180return true;1181}11821183/// 1) Pops the value from the stack.1184/// 2) Writes the value to the local variable with the1185/// given offset.1186template <PrimType Name, class T = typename PrimConv<Name>::T>1187bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1188S.Current->setLocal<T>(I, S.Stk.pop<T>());1189return true;1190}11911192template <PrimType Name, class T = typename PrimConv<Name>::T>1193bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1194if (S.checkingPotentialConstantExpression()) {1195return false;1196}1197S.Stk.push<T>(S.Current->getParam<T>(I));1198return true;1199}12001201template <PrimType Name, class T = typename PrimConv<Name>::T>1202bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1203S.Current->setParam<T>(I, S.Stk.pop<T>());1204return true;1205}12061207/// 1) Peeks a pointer on the stack1208/// 2) Pushes the value of the pointer's field on the stack1209template <PrimType Name, class T = typename PrimConv<Name>::T>1210bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {1211const Pointer &Obj = S.Stk.peek<Pointer>();1212if (!CheckNull(S, OpPC, Obj, CSK_Field))1213return false;1214if (!CheckRange(S, OpPC, Obj, CSK_Field))1215return false;1216const Pointer &Field = Obj.atField(I);1217if (!CheckLoad(S, OpPC, Field))1218return false;1219S.Stk.push<T>(Field.deref<T>());1220return true;1221}12221223template <PrimType Name, class T = typename PrimConv<Name>::T>1224bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {1225const T &Value = S.Stk.pop<T>();1226const Pointer &Obj = S.Stk.peek<Pointer>();1227if (!CheckNull(S, OpPC, Obj, CSK_Field))1228return false;1229if (!CheckRange(S, OpPC, Obj, CSK_Field))1230return false;1231const Pointer &Field = Obj.atField(I);1232if (!CheckStore(S, OpPC, Field))1233return false;1234Field.initialize();1235Field.deref<T>() = Value;1236return true;1237}12381239/// 1) Pops a pointer from the stack1240/// 2) Pushes the value of the pointer's field on the stack1241template <PrimType Name, class T = typename PrimConv<Name>::T>1242bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {1243const Pointer &Obj = S.Stk.pop<Pointer>();1244if (!CheckNull(S, OpPC, Obj, CSK_Field))1245return false;1246if (!CheckRange(S, OpPC, Obj, CSK_Field))1247return false;1248const Pointer &Field = Obj.atField(I);1249if (!CheckLoad(S, OpPC, Field))1250return false;1251S.Stk.push<T>(Field.deref<T>());1252return true;1253}12541255template <PrimType Name, class T = typename PrimConv<Name>::T>1256bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1257if (S.checkingPotentialConstantExpression())1258return false;1259const Pointer &This = S.Current->getThis();1260if (!CheckThis(S, OpPC, This))1261return false;1262const Pointer &Field = This.atField(I);1263if (!CheckLoad(S, OpPC, Field))1264return false;1265S.Stk.push<T>(Field.deref<T>());1266return true;1267}12681269template <PrimType Name, class T = typename PrimConv<Name>::T>1270bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1271if (S.checkingPotentialConstantExpression())1272return false;1273const T &Value = S.Stk.pop<T>();1274const Pointer &This = S.Current->getThis();1275if (!CheckThis(S, OpPC, This))1276return false;1277const Pointer &Field = This.atField(I);1278if (!CheckStore(S, OpPC, Field))1279return false;1280Field.deref<T>() = Value;1281return true;1282}12831284template <PrimType Name, class T = typename PrimConv<Name>::T>1285bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1286const Pointer &Ptr = S.P.getPtrGlobal(I);1287if (!CheckConstant(S, OpPC, Ptr.getFieldDesc()))1288return false;1289if (Ptr.isExtern())1290return false;12911292// If a global variable is uninitialized, that means the initializer we've1293// compiled for it wasn't a constant expression. Diagnose that.1294if (!CheckGlobalInitialized(S, OpPC, Ptr))1295return false;12961297S.Stk.push<T>(Ptr.deref<T>());1298return true;1299}13001301/// Same as GetGlobal, but without the checks.1302template <PrimType Name, class T = typename PrimConv<Name>::T>1303bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {1304const Pointer &Ptr = S.P.getPtrGlobal(I);1305if (!Ptr.isInitialized())1306return false;1307S.Stk.push<T>(Ptr.deref<T>());1308return true;1309}13101311template <PrimType Name, class T = typename PrimConv<Name>::T>1312bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1313// TODO: emit warning.1314return false;1315}13161317template <PrimType Name, class T = typename PrimConv<Name>::T>1318bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1319const Pointer &P = S.P.getGlobal(I);1320P.deref<T>() = S.Stk.pop<T>();1321P.initialize();1322return true;1323}13241325/// 1) Converts the value on top of the stack to an APValue1326/// 2) Sets that APValue on \Temp1327/// 3) Initializes global with index \I with that1328template <PrimType Name, class T = typename PrimConv<Name>::T>1329bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,1330const LifetimeExtendedTemporaryDecl *Temp) {1331const Pointer &Ptr = S.P.getGlobal(I);13321333const T Value = S.Stk.peek<T>();1334APValue APV = Value.toAPValue(S.getCtx());1335APValue *Cached = Temp->getOrCreateValue(true);1336*Cached = APV;13371338assert(Ptr.getDeclDesc()->asExpr());13391340S.SeenGlobalTemporaries.push_back(1341std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));13421343Ptr.deref<T>() = S.Stk.pop<T>();1344Ptr.initialize();1345return true;1346}13471348/// 1) Converts the value on top of the stack to an APValue1349/// 2) Sets that APValue on \Temp1350/// 3) Initialized global with index \I with that1351inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,1352const LifetimeExtendedTemporaryDecl *Temp) {1353assert(Temp);1354const Pointer &P = S.Stk.peek<Pointer>();1355APValue *Cached = Temp->getOrCreateValue(true);13561357S.SeenGlobalTemporaries.push_back(1358std::make_pair(P.getDeclDesc()->asExpr(), Temp));13591360if (std::optional<APValue> APV =1361P.toRValue(S.getCtx(), Temp->getTemporaryExpr()->getType())) {1362*Cached = *APV;1363return true;1364}13651366return false;1367}13681369template <PrimType Name, class T = typename PrimConv<Name>::T>1370bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1371if (S.checkingPotentialConstantExpression())1372return false;1373const Pointer &This = S.Current->getThis();1374if (!CheckThis(S, OpPC, This))1375return false;1376const Pointer &Field = This.atField(I);1377Field.deref<T>() = S.Stk.pop<T>();1378Field.initialize();1379return true;1380}13811382// FIXME: The Field pointer here is too much IMO and we could instead just1383// pass an Offset + BitWidth pair.1384template <PrimType Name, class T = typename PrimConv<Name>::T>1385bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,1386uint32_t FieldOffset) {1387assert(F->isBitField());1388if (S.checkingPotentialConstantExpression())1389return false;1390const Pointer &This = S.Current->getThis();1391if (!CheckThis(S, OpPC, This))1392return false;1393const Pointer &Field = This.atField(FieldOffset);1394const auto &Value = S.Stk.pop<T>();1395Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));1396Field.initialize();1397return true;1398}13991400template <PrimType Name, class T = typename PrimConv<Name>::T>1401bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {1402if (S.checkingPotentialConstantExpression())1403return false;1404const Pointer &This = S.Current->getThis();1405if (!CheckThis(S, OpPC, This))1406return false;1407const Pointer &Field = This.atField(I);1408Field.deref<T>() = S.Stk.pop<T>();1409Field.activate();1410Field.initialize();1411return true;1412}14131414/// 1) Pops the value from the stack1415/// 2) Peeks a pointer from the stack1416/// 3) Pushes the value to field I of the pointer on the stack1417template <PrimType Name, class T = typename PrimConv<Name>::T>1418bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {1419const T &Value = S.Stk.pop<T>();1420const Pointer &Field = S.Stk.peek<Pointer>().atField(I);1421Field.deref<T>() = Value;1422Field.activate();1423Field.initialize();1424return true;1425}14261427template <PrimType Name, class T = typename PrimConv<Name>::T>1428bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {1429assert(F->isBitField());1430const T &Value = S.Stk.pop<T>();1431const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset);1432Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx()));1433Field.activate();1434Field.initialize();1435return true;1436}14371438template <PrimType Name, class T = typename PrimConv<Name>::T>1439bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) {1440const T &Value = S.Stk.pop<T>();1441const Pointer &Ptr = S.Stk.pop<Pointer>();1442const Pointer &Field = Ptr.atField(I);1443Field.deref<T>() = Value;1444Field.activate();1445Field.initialize();1446return true;1447}14481449//===----------------------------------------------------------------------===//1450// GetPtr Local/Param/Global/Field/This1451//===----------------------------------------------------------------------===//14521453inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1454S.Stk.push<Pointer>(S.Current->getLocalPointer(I));1455return true;1456}14571458inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {1459if (S.checkingPotentialConstantExpression()) {1460return false;1461}1462S.Stk.push<Pointer>(S.Current->getParamPointer(I));1463return true;1464}14651466inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1467S.Stk.push<Pointer>(S.P.getPtrGlobal(I));1468return true;1469}14701471/// 1) Peeks a Pointer1472/// 2) Pushes Pointer.atField(Off) on the stack1473inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) {1474const Pointer &Ptr = S.Stk.peek<Pointer>();14751476if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&1477!CheckNull(S, OpPC, Ptr, CSK_Field))1478return false;14791480if (!CheckExtern(S, OpPC, Ptr))1481return false;1482if (!CheckRange(S, OpPC, Ptr, CSK_Field))1483return false;1484if (!CheckArray(S, OpPC, Ptr))1485return false;1486if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))1487return false;14881489if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())1490return false;1491S.Stk.push<Pointer>(Ptr.atField(Off));1492return true;1493}14941495inline bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off) {1496const Pointer &Ptr = S.Stk.pop<Pointer>();14971498if (S.getLangOpts().CPlusPlus && S.inConstantContext() &&1499!CheckNull(S, OpPC, Ptr, CSK_Field))1500return false;15011502if (!CheckExtern(S, OpPC, Ptr))1503return false;1504if (!CheckRange(S, OpPC, Ptr, CSK_Field))1505return false;1506if (!CheckArray(S, OpPC, Ptr))1507return false;1508if (!CheckSubobject(S, OpPC, Ptr, CSK_Field))1509return false;15101511if (Ptr.isBlockPointer() && Off > Ptr.block()->getSize())1512return false;15131514S.Stk.push<Pointer>(Ptr.atField(Off));1515return true;1516}15171518inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {1519if (S.checkingPotentialConstantExpression())1520return false;1521const Pointer &This = S.Current->getThis();1522if (!CheckThis(S, OpPC, This))1523return false;1524S.Stk.push<Pointer>(This.atField(Off));1525return true;1526}15271528inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) {1529const Pointer &Ptr = S.Stk.pop<Pointer>();1530if (!CheckNull(S, OpPC, Ptr, CSK_Field))1531return false;1532if (!CheckRange(S, OpPC, Ptr, CSK_Field))1533return false;1534Pointer Field = Ptr.atField(Off);1535Ptr.deactivate();1536Field.activate();1537S.Stk.push<Pointer>(std::move(Field));1538return true;1539}15401541inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {1542if (S.checkingPotentialConstantExpression())1543return false;1544const Pointer &This = S.Current->getThis();1545if (!CheckThis(S, OpPC, This))1546return false;1547Pointer Field = This.atField(Off);1548This.deactivate();1549Field.activate();1550S.Stk.push<Pointer>(std::move(Field));1551return true;1552}15531554inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) {1555const Pointer &Ptr = S.Stk.pop<Pointer>();1556if (!CheckNull(S, OpPC, Ptr, CSK_Derived))1557return false;1558if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))1559return false;1560if (!CheckDowncast(S, OpPC, Ptr, Off))1561return false;15621563S.Stk.push<Pointer>(Ptr.atFieldSub(Off));1564return true;1565}15661567inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1568const Pointer &Ptr = S.Stk.peek<Pointer>();1569if (!CheckNull(S, OpPC, Ptr, CSK_Base))1570return false;1571if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1572return false;1573S.Stk.push<Pointer>(Ptr.atField(Off));1574return true;1575}15761577inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) {1578const Pointer &Ptr = S.Stk.pop<Pointer>();1579if (!CheckNull(S, OpPC, Ptr, CSK_Base))1580return false;1581if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1582return false;1583S.Stk.push<Pointer>(Ptr.atField(Off));1584return true;1585}15861587inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {1588const auto &Ptr = S.Stk.pop<MemberPointer>();1589S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));1590return true;1591}15921593inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1594if (S.checkingPotentialConstantExpression())1595return false;1596const Pointer &This = S.Current->getThis();1597if (!CheckThis(S, OpPC, This))1598return false;1599S.Stk.push<Pointer>(This.atField(Off));1600return true;1601}16021603inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {1604const Pointer &Ptr = S.Stk.pop<Pointer>();1605if (Ptr.canBeInitialized()) {1606Ptr.initialize();1607Ptr.activate();1608}1609return true;1610}16111612inline bool FinishInit(InterpState &S, CodePtr OpPC) {1613const Pointer &Ptr = S.Stk.peek<Pointer>();1614if (Ptr.canBeInitialized()) {1615Ptr.initialize();1616Ptr.activate();1617}1618return true;1619}16201621inline bool Dump(InterpState &S, CodePtr OpPC) {1622S.Stk.dump();1623return true;1624}16251626inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,1627const Pointer &Ptr) {1628Pointer Base = Ptr;1629while (Base.isBaseClass())1630Base = Base.getBase();16311632const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);1633S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));1634return true;1635}16361637inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,1638const RecordDecl *D) {1639assert(D);1640const Pointer &Ptr = S.Stk.pop<Pointer>();1641if (!CheckNull(S, OpPC, Ptr, CSK_Base))1642return false;1643return VirtBaseHelper(S, OpPC, D, Ptr);1644}16451646inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,1647const RecordDecl *D) {1648assert(D);1649if (S.checkingPotentialConstantExpression())1650return false;1651const Pointer &This = S.Current->getThis();1652if (!CheckThis(S, OpPC, This))1653return false;1654return VirtBaseHelper(S, OpPC, D, S.Current->getThis());1655}16561657//===----------------------------------------------------------------------===//1658// Load, Store, Init1659//===----------------------------------------------------------------------===//16601661template <PrimType Name, class T = typename PrimConv<Name>::T>1662bool Load(InterpState &S, CodePtr OpPC) {1663const Pointer &Ptr = S.Stk.peek<Pointer>();1664if (!CheckLoad(S, OpPC, Ptr))1665return false;1666if (!Ptr.isBlockPointer())1667return false;1668S.Stk.push<T>(Ptr.deref<T>());1669return true;1670}16711672template <PrimType Name, class T = typename PrimConv<Name>::T>1673bool LoadPop(InterpState &S, CodePtr OpPC) {1674const Pointer &Ptr = S.Stk.pop<Pointer>();1675if (!CheckLoad(S, OpPC, Ptr))1676return false;1677if (!Ptr.isBlockPointer())1678return false;1679S.Stk.push<T>(Ptr.deref<T>());1680return true;1681}16821683template <PrimType Name, class T = typename PrimConv<Name>::T>1684bool Store(InterpState &S, CodePtr OpPC) {1685const T &Value = S.Stk.pop<T>();1686const Pointer &Ptr = S.Stk.peek<Pointer>();1687if (!CheckStore(S, OpPC, Ptr))1688return false;1689if (Ptr.canBeInitialized())1690Ptr.initialize();1691Ptr.deref<T>() = Value;1692return true;1693}16941695template <PrimType Name, class T = typename PrimConv<Name>::T>1696bool StorePop(InterpState &S, CodePtr OpPC) {1697const T &Value = S.Stk.pop<T>();1698const Pointer &Ptr = S.Stk.pop<Pointer>();1699if (!CheckStore(S, OpPC, Ptr))1700return false;1701if (Ptr.canBeInitialized())1702Ptr.initialize();1703Ptr.deref<T>() = Value;1704return true;1705}17061707template <PrimType Name, class T = typename PrimConv<Name>::T>1708bool StoreBitField(InterpState &S, CodePtr OpPC) {1709const T &Value = S.Stk.pop<T>();1710const Pointer &Ptr = S.Stk.peek<Pointer>();1711if (!CheckStore(S, OpPC, Ptr))1712return false;1713if (Ptr.canBeInitialized())1714Ptr.initialize();1715if (const auto *FD = Ptr.getField())1716Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));1717else1718Ptr.deref<T>() = Value;1719return true;1720}17211722template <PrimType Name, class T = typename PrimConv<Name>::T>1723bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {1724const T &Value = S.Stk.pop<T>();1725const Pointer &Ptr = S.Stk.pop<Pointer>();1726if (!CheckStore(S, OpPC, Ptr))1727return false;1728if (Ptr.canBeInitialized())1729Ptr.initialize();1730if (const auto *FD = Ptr.getField())1731Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx()));1732else1733Ptr.deref<T>() = Value;1734return true;1735}17361737template <PrimType Name, class T = typename PrimConv<Name>::T>1738bool Init(InterpState &S, CodePtr OpPC) {1739const T &Value = S.Stk.pop<T>();1740const Pointer &Ptr = S.Stk.peek<Pointer>();1741if (!CheckInit(S, OpPC, Ptr)) {1742assert(false);1743return false;1744}1745Ptr.initialize();1746new (&Ptr.deref<T>()) T(Value);1747return true;1748}17491750template <PrimType Name, class T = typename PrimConv<Name>::T>1751bool InitPop(InterpState &S, CodePtr OpPC) {1752const T &Value = S.Stk.pop<T>();1753const Pointer &Ptr = S.Stk.pop<Pointer>();1754if (!CheckInit(S, OpPC, Ptr))1755return false;1756Ptr.initialize();1757new (&Ptr.deref<T>()) T(Value);1758return true;1759}17601761/// 1) Pops the value from the stack1762/// 2) Peeks a pointer and gets its index \Idx1763/// 3) Sets the value on the pointer, leaving the pointer on the stack.1764template <PrimType Name, class T = typename PrimConv<Name>::T>1765bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {1766const T &Value = S.Stk.pop<T>();1767const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx);1768if (Ptr.isUnknownSizeArray())1769return false;1770if (!CheckInit(S, OpPC, Ptr))1771return false;1772Ptr.initialize();1773new (&Ptr.deref<T>()) T(Value);1774return true;1775}17761777/// The same as InitElem, but pops the pointer as well.1778template <PrimType Name, class T = typename PrimConv<Name>::T>1779bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {1780const T &Value = S.Stk.pop<T>();1781const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx);1782if (Ptr.isUnknownSizeArray())1783return false;1784if (!CheckInit(S, OpPC, Ptr))1785return false;1786Ptr.initialize();1787new (&Ptr.deref<T>()) T(Value);1788return true;1789}17901791inline bool Memcpy(InterpState &S, CodePtr OpPC) {1792const Pointer &Src = S.Stk.pop<Pointer>();1793Pointer &Dest = S.Stk.peek<Pointer>();17941795if (!CheckLoad(S, OpPC, Src))1796return false;17971798return DoMemcpy(S, OpPC, Src, Dest);1799}18001801inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {1802const auto &Member = S.Stk.pop<MemberPointer>();1803const auto &Base = S.Stk.pop<Pointer>();18041805S.Stk.push<MemberPointer>(Member.takeInstance(Base));1806return true;1807}18081809inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {1810const auto &MP = S.Stk.pop<MemberPointer>();18111812if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {1813S.Stk.push<Pointer>(*Ptr);1814return true;1815}1816return false;1817}18181819//===----------------------------------------------------------------------===//1820// AddOffset, SubOffset1821//===----------------------------------------------------------------------===//18221823template <class T, ArithOp Op>1824bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,1825const Pointer &Ptr) {1826// A zero offset does not change the pointer.1827if (Offset.isZero()) {1828S.Stk.push<Pointer>(Ptr);1829return true;1830}18311832if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {1833// The CheckNull will have emitted a note already, but we only1834// abort in C++, since this is fine in C.1835if (S.getLangOpts().CPlusPlus)1836return false;1837}18381839// Arrays of unknown bounds cannot have pointers into them.1840if (!CheckArray(S, OpPC, Ptr))1841return false;18421843uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());1844uint64_t Index;1845if (Ptr.isOnePastEnd())1846Index = MaxIndex;1847else1848Index = Ptr.getIndex();18491850bool Invalid = false;1851// Helper to report an invalid offset, computed as APSInt.1852auto DiagInvalidOffset = [&]() -> void {1853const unsigned Bits = Offset.bitWidth();1854APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);1855APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),1856/*IsUnsigned=*/false);1857APSInt NewIndex =1858(Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);1859S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)1860<< NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;1861Invalid = true;1862};18631864if (Ptr.isBlockPointer()) {1865uint64_t IOffset = static_cast<uint64_t>(Offset);1866uint64_t MaxOffset = MaxIndex - Index;18671868if constexpr (Op == ArithOp::Add) {1869// If the new offset would be negative, bail out.1870if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))1871DiagInvalidOffset();18721873// If the new offset would be out of bounds, bail out.1874if (Offset.isPositive() && IOffset > MaxOffset)1875DiagInvalidOffset();1876} else {1877// If the new offset would be negative, bail out.1878if (Offset.isPositive() && Index < IOffset)1879DiagInvalidOffset();18801881// If the new offset would be out of bounds, bail out.1882if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))1883DiagInvalidOffset();1884}1885}18861887if (Invalid && S.getLangOpts().CPlusPlus)1888return false;18891890// Offset is valid - compute it on unsigned.1891int64_t WideIndex = static_cast<int64_t>(Index);1892int64_t WideOffset = static_cast<int64_t>(Offset);1893int64_t Result;1894if constexpr (Op == ArithOp::Add)1895Result = WideIndex + WideOffset;1896else1897Result = WideIndex - WideOffset;18981899// When the pointer is one-past-end, going back to index 0 is the only1900// useful thing we can do. Any other index has been diagnosed before and1901// we don't get here.1902if (Result == 0 && Ptr.isOnePastEnd()) {1903S.Stk.push<Pointer>(Ptr.asBlockPointer().Pointee,1904Ptr.asBlockPointer().Base);1905return true;1906}19071908S.Stk.push<Pointer>(Ptr.atIndex(static_cast<uint64_t>(Result)));1909return true;1910}19111912template <PrimType Name, class T = typename PrimConv<Name>::T>1913bool AddOffset(InterpState &S, CodePtr OpPC) {1914const T &Offset = S.Stk.pop<T>();1915const Pointer &Ptr = S.Stk.pop<Pointer>();1916return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr);1917}19181919template <PrimType Name, class T = typename PrimConv<Name>::T>1920bool SubOffset(InterpState &S, CodePtr OpPC) {1921const T &Offset = S.Stk.pop<T>();1922const Pointer &Ptr = S.Stk.pop<Pointer>();1923return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr);1924}19251926template <ArithOp Op>1927static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,1928const Pointer &Ptr) {1929if (Ptr.isDummy())1930return false;19311932using OneT = Integral<8, false>;19331934const Pointer &P = Ptr.deref<Pointer>();1935if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))1936return false;19371938// Get the current value on the stack.1939S.Stk.push<Pointer>(P);19401941// Now the current Ptr again and a constant 1.1942OneT One = OneT::from(1);1943if (!OffsetHelper<OneT, Op>(S, OpPC, One, P))1944return false;19451946// Store the new value.1947Ptr.deref<Pointer>() = S.Stk.pop<Pointer>();1948return true;1949}19501951static inline bool IncPtr(InterpState &S, CodePtr OpPC) {1952const Pointer &Ptr = S.Stk.pop<Pointer>();19531954if (!CheckInitialized(S, OpPC, Ptr, AK_Increment))1955return false;19561957return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);1958}19591960static inline bool DecPtr(InterpState &S, CodePtr OpPC) {1961const Pointer &Ptr = S.Stk.pop<Pointer>();19621963if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement))1964return false;19651966return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);1967}19681969/// 1) Pops a Pointer from the stack.1970/// 2) Pops another Pointer from the stack.1971/// 3) Pushes the different of the indices of the two pointers on the stack.1972template <PrimType Name, class T = typename PrimConv<Name>::T>1973inline bool SubPtr(InterpState &S, CodePtr OpPC) {1974const Pointer &LHS = S.Stk.pop<Pointer>();1975const Pointer &RHS = S.Stk.pop<Pointer>();19761977if (RHS.isZero()) {1978S.Stk.push<T>(T::from(LHS.getIndex()));1979return true;1980}19811982if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {1983// TODO: Diagnose.1984return false;1985}19861987if (LHS.isZero() && RHS.isZero()) {1988S.Stk.push<T>();1989return true;1990}19911992T A = LHS.isElementPastEnd() ? T::from(LHS.getNumElems())1993: T::from(LHS.getIndex());1994T B = RHS.isElementPastEnd() ? T::from(RHS.getNumElems())1995: T::from(RHS.getIndex());1996return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B);1997}19981999//===----------------------------------------------------------------------===//2000// Destroy2001//===----------------------------------------------------------------------===//20022003inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {2004S.Current->destroy(I);2005return true;2006}20072008//===----------------------------------------------------------------------===//2009// Cast, CastFP2010//===----------------------------------------------------------------------===//20112012template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {2013using T = typename PrimConv<TIn>::T;2014using U = typename PrimConv<TOut>::T;2015S.Stk.push<U>(U::from(S.Stk.pop<T>()));2016return true;2017}20182019/// 1) Pops a Floating from the stack.2020/// 2) Pushes a new floating on the stack that uses the given semantics.2021inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,2022llvm::RoundingMode RM) {2023Floating F = S.Stk.pop<Floating>();2024Floating Result = F.toSemantics(Sem, RM);2025S.Stk.push<Floating>(Result);2026return true;2027}20282029/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need2030/// to know what bitwidth the result should be.2031template <PrimType Name, class T = typename PrimConv<Name>::T>2032bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2033S.Stk.push<IntegralAP<false>>(2034IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth));2035return true;2036}20372038template <PrimType Name, class T = typename PrimConv<Name>::T>2039bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2040S.Stk.push<IntegralAP<true>>(2041IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth));2042return true;2043}20442045template <PrimType Name, class T = typename PrimConv<Name>::T>2046bool CastIntegralFloating(InterpState &S, CodePtr OpPC,2047const llvm::fltSemantics *Sem,2048llvm::RoundingMode RM) {2049const T &From = S.Stk.pop<T>();2050APSInt FromAP = From.toAPSInt();2051Floating Result;20522053auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result);2054S.Stk.push<Floating>(Result);20552056return CheckFloatResult(S, OpPC, Result, Status);2057}20582059template <PrimType Name, class T = typename PrimConv<Name>::T>2060bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) {2061const Floating &F = S.Stk.pop<Floating>();20622063if constexpr (std::is_same_v<T, Boolean>) {2064S.Stk.push<T>(T(F.isNonZero()));2065return true;2066} else {2067APSInt Result(std::max(8u, T::bitWidth()),2068/*IsUnsigned=*/!T::isSigned());2069auto Status = F.convertToInteger(Result);20702071// Float-to-Integral overflow check.2072if ((Status & APFloat::opStatus::opInvalidOp)) {2073const Expr *E = S.Current->getExpr(OpPC);2074QualType Type = E->getType();20752076S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;2077if (S.noteUndefinedBehavior()) {2078S.Stk.push<T>(T(Result));2079return true;2080}2081return false;2082}20832084S.Stk.push<T>(T(Result));2085return CheckFloatResult(S, OpPC, F, Status);2086}2087}20882089static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,2090uint32_t BitWidth) {2091const Floating &F = S.Stk.pop<Floating>();20922093APSInt Result(BitWidth, /*IsUnsigned=*/true);2094auto Status = F.convertToInteger(Result);20952096// Float-to-Integral overflow check.2097if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {2098const Expr *E = S.Current->getExpr(OpPC);2099QualType Type = E->getType();21002101S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;2102return S.noteUndefinedBehavior();2103}21042105S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));2106return CheckFloatResult(S, OpPC, F, Status);2107}21082109static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,2110uint32_t BitWidth) {2111const Floating &F = S.Stk.pop<Floating>();21122113APSInt Result(BitWidth, /*IsUnsigned=*/false);2114auto Status = F.convertToInteger(Result);21152116// Float-to-Integral overflow check.2117if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) {2118const Expr *E = S.Current->getExpr(OpPC);2119QualType Type = E->getType();21202121S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;2122return S.noteUndefinedBehavior();2123}21242125S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result));2126return CheckFloatResult(S, OpPC, F, Status);2127}21282129template <PrimType Name, class T = typename PrimConv<Name>::T>2130bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {2131const Pointer &Ptr = S.Stk.pop<Pointer>();21322133if (Ptr.isDummy())2134return false;21352136const SourceInfo &E = S.Current->getSource(OpPC);2137S.CCEDiag(E, diag::note_constexpr_invalid_cast)2138<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);21392140S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));2141return true;2142}21432144static inline bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC,2145uint32_t BitWidth) {2146const Pointer &Ptr = S.Stk.pop<Pointer>();21472148if (Ptr.isDummy())2149return false;21502151const SourceInfo &E = S.Current->getSource(OpPC);2152S.CCEDiag(E, diag::note_constexpr_invalid_cast)2153<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);21542155S.Stk.push<IntegralAP<false>>(2156IntegralAP<false>::from(Ptr.getIntegerRepresentation(), BitWidth));2157return true;2158}21592160static inline bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC,2161uint32_t BitWidth) {2162const Pointer &Ptr = S.Stk.pop<Pointer>();21632164if (Ptr.isDummy())2165return false;21662167const SourceInfo &E = S.Current->getSource(OpPC);2168S.CCEDiag(E, diag::note_constexpr_invalid_cast)2169<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);21702171S.Stk.push<IntegralAP<true>>(2172IntegralAP<true>::from(Ptr.getIntegerRepresentation(), BitWidth));2173return true;2174}21752176static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {2177const auto &Ptr = S.Stk.peek<Pointer>();21782179if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {2180bool HasValidResult = !Ptr.isZero();21812182if (HasValidResult) {2183// FIXME: note_constexpr_invalid_void_star_cast2184} else if (!S.getLangOpts().CPlusPlus26) {2185const SourceInfo &E = S.Current->getSource(OpPC);2186S.CCEDiag(E, diag::note_constexpr_invalid_cast)2187<< 3 << "'void *'" << S.Current->getRange(OpPC);2188}2189} else {2190const SourceInfo &E = S.Current->getSource(OpPC);2191S.CCEDiag(E, diag::note_constexpr_invalid_cast)2192<< 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);2193}21942195return true;2196}21972198//===----------------------------------------------------------------------===//2199// Zero, Nullptr2200//===----------------------------------------------------------------------===//22012202template <PrimType Name, class T = typename PrimConv<Name>::T>2203bool Zero(InterpState &S, CodePtr OpPC) {2204S.Stk.push<T>(T::zero());2205return true;2206}22072208static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2209S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth));2210return true;2211}22122213static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2214S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth));2215return true;2216}22172218template <PrimType Name, class T = typename PrimConv<Name>::T>2219inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {2220// Note: Desc can be null.2221S.Stk.push<T>(0, Desc);2222return true;2223}22242225//===----------------------------------------------------------------------===//2226// This, ImplicitThis2227//===----------------------------------------------------------------------===//22282229inline bool This(InterpState &S, CodePtr OpPC) {2230// Cannot read 'this' in this mode.2231if (S.checkingPotentialConstantExpression()) {2232return false;2233}22342235const Pointer &This = S.Current->getThis();2236if (!CheckThis(S, OpPC, This))2237return false;22382239// Ensure the This pointer has been cast to the correct base.2240if (!This.isDummy()) {2241assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));2242assert(This.getRecord());2243assert(2244This.getRecord()->getDecl() ==2245cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())->getParent());2246}22472248S.Stk.push<Pointer>(This);2249return true;2250}22512252inline bool RVOPtr(InterpState &S, CodePtr OpPC) {2253assert(S.Current->getFunction()->hasRVO());2254if (S.checkingPotentialConstantExpression())2255return false;2256S.Stk.push<Pointer>(S.Current->getRVOPtr());2257return true;2258}22592260//===----------------------------------------------------------------------===//2261// Shr, Shl2262//===----------------------------------------------------------------------===//2263enum class ShiftDir { Left, Right };22642265template <class LT, class RT, ShiftDir Dir>2266inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {2267const unsigned Bits = LHS.bitWidth();22682269// OpenCL 6.3j: shift values are effectively % word size of LHS.2270if (S.getLangOpts().OpenCL)2271RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),2272RHS.bitWidth(), &RHS);22732274if (RHS.isNegative()) {2275// During constant-folding, a negative shift is an opposite shift. Such a2276// shift is not a constant expression.2277const SourceInfo &Loc = S.Current->getSource(OpPC);2278S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();2279if (!S.noteUndefinedBehavior())2280return false;2281RHS = -RHS;2282return DoShift < LT, RT,2283Dir == ShiftDir::Left ? ShiftDir::Right2284: ShiftDir::Left > (S, OpPC, LHS, RHS);2285}22862287if constexpr (Dir == ShiftDir::Left) {2288if (LHS.isNegative() && !S.getLangOpts().CPlusPlus20) {2289// C++11 [expr.shift]p2: A signed left shift must have a non-negative2290// operand, and must not overflow the corresponding unsigned type.2291// C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to2292// E1 x 2^E2 module 2^N.2293const SourceInfo &Loc = S.Current->getSource(OpPC);2294S.CCEDiag(Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();2295if (!S.noteUndefinedBehavior())2296return false;2297}2298}22992300if (!CheckShift(S, OpPC, LHS, RHS, Bits))2301return false;23022303// Limit the shift amount to Bits - 1. If this happened,2304// it has already been diagnosed by CheckShift() above,2305// but we still need to handle it.2306typename LT::AsUnsigned R;2307if constexpr (Dir == ShiftDir::Left) {2308if (RHS > RT::from(Bits - 1, RHS.bitWidth()))2309LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2310LT::AsUnsigned::from(Bits - 1), Bits, &R);2311else2312LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2313LT::AsUnsigned::from(RHS, Bits), Bits, &R);2314} else {2315if (RHS > RT::from(Bits - 1, RHS.bitWidth()))2316LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),2317LT::AsUnsigned::from(Bits - 1), Bits, &R);2318else2319LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),2320LT::AsUnsigned::from(RHS, Bits), Bits, &R);2321}23222323S.Stk.push<LT>(LT::from(R));2324return true;2325}23262327template <PrimType NameL, PrimType NameR>2328inline bool Shr(InterpState &S, CodePtr OpPC) {2329using LT = typename PrimConv<NameL>::T;2330using RT = typename PrimConv<NameR>::T;2331auto RHS = S.Stk.pop<RT>();2332auto LHS = S.Stk.pop<LT>();23332334return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS);2335}23362337template <PrimType NameL, PrimType NameR>2338inline bool Shl(InterpState &S, CodePtr OpPC) {2339using LT = typename PrimConv<NameL>::T;2340using RT = typename PrimConv<NameR>::T;2341auto RHS = S.Stk.pop<RT>();2342auto LHS = S.Stk.pop<LT>();23432344return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS);2345}23462347//===----------------------------------------------------------------------===//2348// NoRet2349//===----------------------------------------------------------------------===//23502351inline bool NoRet(InterpState &S, CodePtr OpPC) {2352SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();2353S.FFDiag(EndLoc, diag::note_constexpr_no_return);2354return false;2355}23562357//===----------------------------------------------------------------------===//2358// NarrowPtr, ExpandPtr2359//===----------------------------------------------------------------------===//23602361inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {2362const Pointer &Ptr = S.Stk.pop<Pointer>();2363S.Stk.push<Pointer>(Ptr.narrow());2364return true;2365}23662367inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {2368const Pointer &Ptr = S.Stk.pop<Pointer>();2369S.Stk.push<Pointer>(Ptr.expand());2370return true;2371}23722373// 1) Pops an integral value from the stack2374// 2) Peeks a pointer2375// 3) Pushes a new pointer that's a narrowed array2376// element of the peeked pointer with the value2377// from 1) added as offset.2378//2379// This leaves the original pointer on the stack and pushes a new one2380// with the offset applied and narrowed.2381template <PrimType Name, class T = typename PrimConv<Name>::T>2382inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {2383const T &Offset = S.Stk.pop<T>();2384const Pointer &Ptr = S.Stk.peek<Pointer>();23852386if (!Ptr.isZero()) {2387if (!CheckArray(S, OpPC, Ptr))2388return false;2389}23902391if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))2392return false;23932394return NarrowPtr(S, OpPC);2395}23962397template <PrimType Name, class T = typename PrimConv<Name>::T>2398inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {2399const T &Offset = S.Stk.pop<T>();2400const Pointer &Ptr = S.Stk.pop<Pointer>();24012402if (!Ptr.isZero()) {2403if (!CheckArray(S, OpPC, Ptr))2404return false;2405}24062407if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))2408return false;24092410return NarrowPtr(S, OpPC);2411}24122413template <PrimType Name, class T = typename PrimConv<Name>::T>2414inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {2415const Pointer &Ptr = S.Stk.peek<Pointer>();24162417if (!CheckLoad(S, OpPC, Ptr))2418return false;24192420S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());2421return true;2422}24232424template <PrimType Name, class T = typename PrimConv<Name>::T>2425inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {2426const Pointer &Ptr = S.Stk.pop<Pointer>();24272428if (!CheckLoad(S, OpPC, Ptr))2429return false;24302431S.Stk.push<T>(Ptr.atIndex(Index).deref<T>());2432return true;2433}24342435template <PrimType Name, class T = typename PrimConv<Name>::T>2436inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex, uint32_t DestIndex, uint32_t Size) {2437const auto &SrcPtr = S.Stk.pop<Pointer>();2438const auto &DestPtr = S.Stk.peek<Pointer>();24392440for (uint32_t I = 0; I != Size; ++I) {2441const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);24422443if (!CheckLoad(S, OpPC, SP))2444return false;24452446const Pointer &DP = DestPtr.atIndex(DestIndex + I);2447DP.deref<T>() = SP.deref<T>();2448DP.initialize();2449}2450return true;2451}24522453/// Just takes a pointer and checks if it's an incomplete2454/// array type.2455inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {2456const Pointer &Ptr = S.Stk.pop<Pointer>();24572458if (Ptr.isZero()) {2459S.Stk.push<Pointer>(Ptr);2460return true;2461}24622463if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))2464return false;24652466if (Ptr.isRoot() || !Ptr.isUnknownSizeArray() || Ptr.isDummy()) {2467S.Stk.push<Pointer>(Ptr.atIndex(0));2468return true;2469}24702471const SourceInfo &E = S.Current->getSource(OpPC);2472S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);24732474return false;2475}24762477inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,2478uint32_t VarArgSize) {2479if (Func->hasThisPointer()) {2480size_t ArgSize = Func->getArgSize() + VarArgSize;2481size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);2482const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);24832484// If the current function is a lambda static invoker and2485// the function we're about to call is a lambda call operator,2486// skip the CheckInvoke, since the ThisPtr is a null pointer2487// anyway.2488if (!(S.Current->getFunction() &&2489S.Current->getFunction()->isLambdaStaticInvoker() &&2490Func->isLambdaCallOperator())) {2491if (!CheckInvoke(S, OpPC, ThisPtr))2492return false;2493}24942495if (S.checkingPotentialConstantExpression())2496return false;2497}24982499if (!CheckCallable(S, OpPC, Func))2500return false;25012502if (!CheckCallDepth(S, OpPC))2503return false;25042505auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);2506InterpFrame *FrameBefore = S.Current;2507S.Current = NewFrame.get();25082509APValue CallResult;2510// Note that we cannot assert(CallResult.hasValue()) here since2511// Ret() above only sets the APValue if the curent frame doesn't2512// have a caller set.2513if (Interpret(S, CallResult)) {2514NewFrame.release(); // Frame was delete'd already.2515assert(S.Current == FrameBefore);2516return true;2517}25182519// Interpreting the function failed somehow. Reset to2520// previous state.2521S.Current = FrameBefore;2522return false;25232524return false;2525}25262527inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,2528uint32_t VarArgSize) {2529if (Func->hasThisPointer()) {2530size_t ArgSize = Func->getArgSize() + VarArgSize;2531size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);25322533const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);25342535// If the current function is a lambda static invoker and2536// the function we're about to call is a lambda call operator,2537// skip the CheckInvoke, since the ThisPtr is a null pointer2538// anyway.2539if (!(S.Current->getFunction() &&2540S.Current->getFunction()->isLambdaStaticInvoker() &&2541Func->isLambdaCallOperator())) {2542if (!CheckInvoke(S, OpPC, ThisPtr))2543return false;2544}2545}25462547if (!CheckCallable(S, OpPC, Func))2548return false;25492550if (Func->hasThisPointer() && S.checkingPotentialConstantExpression())2551return false;25522553if (!CheckCallDepth(S, OpPC))2554return false;25552556auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);2557InterpFrame *FrameBefore = S.Current;2558S.Current = NewFrame.get();25592560APValue CallResult;2561// Note that we cannot assert(CallResult.hasValue()) here since2562// Ret() above only sets the APValue if the curent frame doesn't2563// have a caller set.2564if (Interpret(S, CallResult)) {2565NewFrame.release(); // Frame was delete'd already.2566assert(S.Current == FrameBefore);2567return true;2568}25692570// Interpreting the function failed somehow. Reset to2571// previous state.2572S.Current = FrameBefore;2573return false;2574}25752576inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,2577uint32_t VarArgSize) {2578assert(Func->hasThisPointer());2579assert(Func->isVirtual());2580size_t ArgSize = Func->getArgSize() + VarArgSize;2581size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);2582Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);25832584QualType DynamicType = ThisPtr.getDeclDesc()->getType();2585const CXXRecordDecl *DynamicDecl;2586if (DynamicType->isPointerType() || DynamicType->isReferenceType())2587DynamicDecl = DynamicType->getPointeeCXXRecordDecl();2588else2589DynamicDecl = ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl();2590const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl());2591const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl());2592const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction(2593DynamicDecl, StaticDecl, InitialFunction);25942595if (Overrider != InitialFunction) {2596// DR1872: An instantiated virtual constexpr function can't be called in a2597// constant expression (prior to C++20). We can still constant-fold such a2598// call.2599if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) {2600const Expr *E = S.Current->getExpr(OpPC);2601S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange();2602}26032604Func = S.getContext().getOrCreateFunction(Overrider);26052606const CXXRecordDecl *ThisFieldDecl =2607ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl();2608if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) {2609// If the function we call is further DOWN the hierarchy than the2610// FieldDesc of our pointer, just get the DeclDesc instead, which2611// is the furthest we might go up in the hierarchy.2612ThisPtr = ThisPtr.getDeclPtr();2613}2614}26152616return Call(S, OpPC, Func, VarArgSize);2617}26182619inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,2620const CallExpr *CE) {2621auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC);26222623InterpFrame *FrameBefore = S.Current;2624S.Current = NewFrame.get();26252626if (InterpretBuiltin(S, PC, Func, CE)) {2627NewFrame.release();2628return true;2629}2630S.Current = FrameBefore;2631return false;2632}26332634inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,2635const CallExpr *CE) {2636const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();26372638const Function *F = FuncPtr.getFunction();2639if (!F) {2640const Expr *E = S.Current->getExpr(OpPC);2641S.FFDiag(E, diag::note_constexpr_null_callee)2642<< const_cast<Expr *>(E) << E->getSourceRange();2643return false;2644}26452646if (!FuncPtr.isValid())2647return false;26482649assert(F);26502651// This happens when the call expression has been cast to2652// something else, but we don't support that.2653if (S.Ctx.classify(F->getDecl()->getReturnType()) !=2654S.Ctx.classify(CE->getType()))2655return false;26562657// Check argument nullability state.2658if (F->hasNonNullAttr()) {2659if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))2660return false;2661}26622663assert(ArgSize >= F->getWrittenArgSize());2664uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();26652666// We need to do this explicitly here since we don't have the necessary2667// information to do it automatically.2668if (F->isThisPointerExplicit())2669VarArgSize -= align(primSize(PT_Ptr));26702671if (F->isVirtual())2672return CallVirt(S, OpPC, F, VarArgSize);26732674return Call(S, OpPC, F, VarArgSize);2675}26762677inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {2678assert(Func);2679S.Stk.push<FunctionPointer>(Func);2680return true;2681}26822683template <PrimType Name, class T = typename PrimConv<Name>::T>2684inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {2685const T &IntVal = S.Stk.pop<T>();26862687S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);2688return true;2689}26902691inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const Decl *D) {2692S.Stk.push<MemberPointer>(D);2693return true;2694}26952696inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {2697const auto &MP = S.Stk.pop<MemberPointer>();26982699S.Stk.push<Pointer>(MP.getBase());2700return true;2701}27022703inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {2704const auto &MP = S.Stk.pop<MemberPointer>();27052706const auto *FD = cast<FunctionDecl>(MP.getDecl());2707const auto *Func = S.getContext().getOrCreateFunction(FD);27082709S.Stk.push<FunctionPointer>(Func);2710return true;2711}27122713/// Just emit a diagnostic. The expression that caused emission of this2714/// op is not valid in a constant context.2715inline bool Invalid(InterpState &S, CodePtr OpPC) {2716const SourceLocation &Loc = S.Current->getLocation(OpPC);2717S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr)2718<< S.Current->getRange(OpPC);2719return false;2720}27212722inline bool Unsupported(InterpState &S, CodePtr OpPC) {2723const SourceLocation &Loc = S.Current->getLocation(OpPC);2724S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)2725<< S.Current->getRange(OpPC);2726return false;2727}27282729/// Do nothing and just abort execution.2730inline bool Error(InterpState &S, CodePtr OpPC) { return false; }27312732/// Same here, but only for casts.2733inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) {2734const SourceLocation &Loc = S.Current->getLocation(OpPC);27352736// FIXME: Support diagnosing other invalid cast kinds.2737if (Kind == CastKind::Reinterpret)2738S.FFDiag(Loc, diag::note_constexpr_invalid_cast)2739<< static_cast<unsigned>(Kind) << S.Current->getRange(OpPC);2740return false;2741}27422743inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC,2744const DeclRefExpr *DR) {2745assert(DR);2746return CheckDeclRef(S, OpPC, DR);2747}27482749inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {2750if (S.inConstantContext()) {2751const SourceRange &ArgRange = S.Current->getRange(OpPC);2752const Expr *E = S.Current->getExpr(OpPC);2753S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;2754}2755return false;2756}27572758inline bool Assume(InterpState &S, CodePtr OpPC) {2759const auto Val = S.Stk.pop<Boolean>();27602761if (Val)2762return true;27632764// Else, diagnose.2765const SourceLocation &Loc = S.Current->getLocation(OpPC);2766S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);2767return false;2768}27692770template <PrimType Name, class T = typename PrimConv<Name>::T>2771inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {2772llvm::SmallVector<int64_t> ArrayIndices;2773for (size_t I = 0; I != E->getNumExpressions(); ++I)2774ArrayIndices.emplace_back(S.Stk.pop<int64_t>());27752776int64_t Result;2777if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))2778return false;27792780S.Stk.push<T>(T::from(Result));27812782return true;2783}27842785template <PrimType Name, class T = typename PrimConv<Name>::T>2786inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {2787const T &Arg = S.Stk.peek<T>();2788if (!Arg.isZero())2789return true;27902791const SourceLocation &Loc = S.Current->getLocation(OpPC);2792S.CCEDiag(Loc, diag::note_non_null_attribute_failed);27932794return false;2795}27962797void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,2798const APSInt &Value);27992800template <PrimType Name, class T = typename PrimConv<Name>::T>2801inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {2802assert(ED);2803assert(!ED->isFixed());2804const APSInt Val = S.Stk.peek<T>().toAPSInt();28052806if (S.inConstantContext())2807diagnoseEnumValue(S, OpPC, ED, Val);2808return true;2809}28102811/// OldPtr -> Integer -> NewPtr.2812template <PrimType TIn, PrimType TOut>2813inline bool DecayPtr(InterpState &S, CodePtr OpPC) {2814static_assert(isPtrType(TIn) && isPtrType(TOut));2815using FromT = typename PrimConv<TIn>::T;2816using ToT = typename PrimConv<TOut>::T;28172818const FromT &OldPtr = S.Stk.pop<FromT>();2819S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));2820return true;2821}28222823inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {2824// An expression E is a core constant expression unless the evaluation of E2825// would evaluate one of the following: [C++23] - a control flow that passes2826// through a declaration of a variable with static or thread storage duration2827// unless that variable is usable in constant expressions.2828assert(VD->isLocalVarDecl() &&2829VD->isStaticLocal()); // Checked before emitting this.28302831if (VD == S.EvaluatingDecl)2832return true;28332834if (!VD->isUsableInConstantExpressions(S.getCtx())) {2835S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)2836<< (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;2837return false;2838}2839return true;2840}28412842inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {2843assert(Desc);28442845if (!CheckDynamicMemoryAllocation(S, OpPC))2846return false;28472848DynamicAllocator &Allocator = S.getAllocator();2849Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID());2850assert(B);28512852S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));28532854return true;2855}28562857template <PrimType Name, class SizeT = typename PrimConv<Name>::T>2858inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,2859bool IsNoThrow) {2860if (!CheckDynamicMemoryAllocation(S, OpPC))2861return false;28622863SizeT NumElements = S.Stk.pop<SizeT>();2864if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {2865if (!IsNoThrow)2866return false;28672868// If this failed and is nothrow, just return a null ptr.2869S.Stk.push<Pointer>(0, nullptr);2870return true;2871}28722873DynamicAllocator &Allocator = S.getAllocator();2874Block *B = Allocator.allocate(Source, T, static_cast<size_t>(NumElements),2875S.Ctx.getEvalID());2876assert(B);2877S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));28782879return true;2880}28812882template <PrimType Name, class SizeT = typename PrimConv<Name>::T>2883inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,2884bool IsNoThrow) {2885if (!CheckDynamicMemoryAllocation(S, OpPC))2886return false;28872888SizeT NumElements = S.Stk.pop<SizeT>();2889if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),2890IsNoThrow)) {2891if (!IsNoThrow)2892return false;28932894// If this failed and is nothrow, just return a null ptr.2895S.Stk.push<Pointer>(0, ElementDesc);2896return true;2897}28982899DynamicAllocator &Allocator = S.getAllocator();2900Block *B = Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),2901S.Ctx.getEvalID());2902assert(B);29032904S.Stk.push<Pointer>(B, sizeof(InlineDescriptor));29052906return true;2907}29082909bool RunDestructors(InterpState &S, CodePtr OpPC, const Block *B);2910static inline bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm) {2911if (!CheckDynamicMemoryAllocation(S, OpPC))2912return false;29132914const Expr *Source = nullptr;2915const Block *BlockToDelete = nullptr;2916{2917// Extra scope for this so the block doesn't have this pointer2918// pointing to it when we destroy it.2919const Pointer &Ptr = S.Stk.pop<Pointer>();29202921// Deleteing nullptr is always fine.2922if (Ptr.isZero())2923return true;29242925if (!Ptr.isRoot() || Ptr.isOnePastEnd() || Ptr.isArrayElement()) {2926const SourceInfo &Loc = S.Current->getSource(OpPC);2927S.FFDiag(Loc, diag::note_constexpr_delete_subobject)2928<< Ptr.toDiagnosticString(S.getCtx()) << Ptr.isOnePastEnd();2929return false;2930}29312932Source = Ptr.getDeclDesc()->asExpr();2933BlockToDelete = Ptr.block();29342935if (!CheckDeleteSource(S, OpPC, Source, Ptr))2936return false;2937}2938assert(Source);2939assert(BlockToDelete);29402941// Invoke destructors before deallocating the memory.2942if (!RunDestructors(S, OpPC, BlockToDelete))2943return false;29442945DynamicAllocator &Allocator = S.getAllocator();2946bool WasArrayAlloc = Allocator.isArrayAllocation(Source);2947const Descriptor *BlockDesc = BlockToDelete->getDescriptor();29482949if (!Allocator.deallocate(Source, BlockToDelete, S)) {2950// Nothing has been deallocated, this must be a double-delete.2951const SourceInfo &Loc = S.Current->getSource(OpPC);2952S.FFDiag(Loc, diag::note_constexpr_double_delete);2953return false;2954}2955return CheckNewDeleteForms(S, OpPC, WasArrayAlloc, DeleteIsArrayForm,2956BlockDesc, Source);2957}29582959//===----------------------------------------------------------------------===//2960// Read opcode arguments2961//===----------------------------------------------------------------------===//29622963template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {2964if constexpr (std::is_pointer<T>::value) {2965uint32_t ID = OpPC.read<uint32_t>();2966return reinterpret_cast<T>(S.P.getNativePointer(ID));2967} else {2968return OpPC.read<T>();2969}2970}29712972template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {2973Floating F = Floating::deserialize(*OpPC);2974OpPC += align(F.bytesToSerialize());2975return F;2976}29772978template <>2979inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,2980CodePtr &OpPC) {2981IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);2982OpPC += align(I.bytesToSerialize());2983return I;2984}29852986template <>2987inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,2988CodePtr &OpPC) {2989IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);2990OpPC += align(I.bytesToSerialize());2991return I;2992}29932994} // namespace interp2995} // namespace clang29962997#endif299829993000