brintos

brintos / llvm-project-archived public Read only

0
0
Text · 120.3 KiB · d8b8b20 Raw
3793 lines · c
1//===--- Interp.h - Interpreter for the constexpr VM ------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// Definition of the interpreter state and entry point.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_CLANG_AST_INTERP_INTERP_H14#define LLVM_CLANG_AST_INTERP_INTERP_H15 16#include "../ExprConstShared.h"17#include "BitcastBuffer.h"18#include "Boolean.h"19#include "DynamicAllocator.h"20#include "FixedPoint.h"21#include "Floating.h"22#include "Function.h"23#include "InterpBuiltinBitCast.h"24#include "InterpFrame.h"25#include "InterpHelpers.h"26#include "InterpStack.h"27#include "InterpState.h"28#include "MemberPointer.h"29#include "PrimType.h"30#include "Program.h"31#include "State.h"32#include "clang/AST/ASTContext.h"33#include "clang/AST/Expr.h"34#include "llvm/ADT/APFloat.h"35#include "llvm/ADT/APSInt.h"36#include <type_traits>37 38namespace clang {39namespace interp {40 41using APSInt = llvm::APSInt;42using FixedPointSemantics = llvm::FixedPointSemantics;43 44/// Checks if the variable has externally defined storage.45bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr);46 47/// Checks if a pointer is null.48bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr,49               CheckSubobjectKind CSK);50 51/// Checks if Ptr is a one-past-the-end pointer.52bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr,53                    CheckSubobjectKind CSK);54 55/// Checks if the dowcast using the given offset is possible with the given56/// pointer.57bool CheckDowncast(InterpState &S, CodePtr OpPC, const Pointer &Ptr,58                   uint32_t Offset);59 60/// Checks if a pointer points to const storage.61bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr);62 63/// Checks if the Descriptor is of a constexpr or const global variable.64bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc);65 66bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr);67 68bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,69                           AccessKinds AK);70bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,71                           const Descriptor *Desc, AccessKinds AK);72 73/// Checks a direct load of a primitive value from a global or local variable.74bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);75bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B);76 77/// Checks if a value can be stored in a block.78bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr,79                bool WillBeActivated = false);80 81/// Checks if a value can be initialized.82bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr);83 84/// Checks the 'this' pointer.85bool CheckThis(InterpState &S, CodePtr OpPC);86 87/// Checks if dynamic memory allocation is available in the current88/// language mode.89bool CheckDynamicMemoryAllocation(InterpState &S, CodePtr OpPC);90 91/// Check the source of the pointer passed to delete/delete[] has actually92/// been heap allocated by us.93bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const Expr *Source,94                       const Pointer &Ptr);95 96bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,97                 AccessKinds AK);98 99/// Sets the given integral value to the pointer, which is of100/// a std::{weak,partial,strong}_ordering type.101bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,102                                const Pointer &Ptr, const APSInt &IntValue);103 104bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,105             uint32_t VarArgSize);106bool Call(InterpState &S, CodePtr OpPC, const Function *Func,107          uint32_t VarArgSize);108bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,109              uint32_t VarArgSize);110bool CallBI(InterpState &S, CodePtr OpPC, const CallExpr *CE,111            uint32_t BuiltinID);112bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,113             const CallExpr *CE);114bool CheckLiteralType(InterpState &S, CodePtr OpPC, const Type *T);115bool InvalidShuffleVectorIndex(InterpState &S, CodePtr OpPC, uint32_t Index);116bool CheckBitCast(InterpState &S, CodePtr OpPC, bool HasIndeterminateBits,117                  bool TargetIsUCharOrByte);118bool CheckBCPResult(InterpState &S, const Pointer &Ptr);119bool CheckDestructor(InterpState &S, CodePtr OpPC, const Pointer &Ptr);120bool CheckFunctionDecl(InterpState &S, CodePtr OpPC, const FunctionDecl *FD);121 122bool handleFixedPointOverflow(InterpState &S, CodePtr OpPC,123                              const FixedPoint &FP);124 125bool isConstexprUnknown(const Pointer &P);126 127enum class ShiftDir { Left, Right };128 129/// Checks if the shift operation is legal.130template <ShiftDir Dir, typename LT, typename RT>131bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,132                unsigned Bits) {133  if (RHS.isNegative()) {134    const SourceInfo &Loc = S.Current->getSource(OpPC);135    S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();136    if (!S.noteUndefinedBehavior())137      return false;138  }139 140  // C++11 [expr.shift]p1: Shift width must be less than the bit width of141  // the shifted type.142  if (Bits > 1 && RHS >= Bits) {143    const Expr *E = S.Current->getExpr(OpPC);144    const APSInt Val = RHS.toAPSInt();145    QualType Ty = E->getType();146    S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;147    if (!S.noteUndefinedBehavior())148      return false;149  }150 151  if constexpr (Dir == ShiftDir::Left) {152    if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {153      // C++11 [expr.shift]p2: A signed left shift must have a non-negative154      // operand, and must not overflow the corresponding unsigned type.155      if (LHS.isNegative()) {156        const Expr *E = S.Current->getExpr(OpPC);157        S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();158        if (!S.noteUndefinedBehavior())159          return false;160      } else if (LHS.toUnsigned().countLeadingZeros() <161                 static_cast<unsigned>(RHS)) {162        const Expr *E = S.Current->getExpr(OpPC);163        S.CCEDiag(E, diag::note_constexpr_lshift_discards);164        if (!S.noteUndefinedBehavior())165          return false;166      }167    }168  }169 170  // C++2a [expr.shift]p2: [P0907R4]:171  //    E1 << E2 is the unique value congruent to172  //    E1 x 2^E2 module 2^N.173  return true;174}175 176/// Checks if Div/Rem operation on LHS and RHS is valid.177template <typename T>178bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) {179  if (RHS.isZero()) {180    const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC));181    if constexpr (std::is_same_v<T, Floating>) {182      S.CCEDiag(Op, diag::note_expr_divide_by_zero)183          << Op->getRHS()->getSourceRange();184      return true;185    }186 187    S.FFDiag(Op, diag::note_expr_divide_by_zero)188        << Op->getRHS()->getSourceRange();189    return false;190  }191 192  if constexpr (!std::is_same_v<T, FixedPoint>) {193    if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) {194      APSInt LHSInt = LHS.toAPSInt();195      SmallString<32> Trunc;196      (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10);197      const SourceInfo &Loc = S.Current->getSource(OpPC);198      const Expr *E = S.Current->getExpr(OpPC);199      S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType();200      return false;201    }202  }203  return true;204}205 206/// Checks if the result of a floating-point operation is valid207/// in the current context.208bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result,209                      APFloat::opStatus Status, FPOptions FPO);210 211/// Checks why the given DeclRefExpr is invalid.212bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR);213 214enum class ArithOp { Add, Sub };215 216//===----------------------------------------------------------------------===//217// Returning values218//===----------------------------------------------------------------------===//219 220void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC,221                              const Function *Func);222 223template <PrimType Name, class T = typename PrimConv<Name>::T>224bool Ret(InterpState &S, CodePtr &PC) {225  const T &Ret = S.Stk.pop<T>();226 227  assert(S.Current);228  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");229  if (!S.checkingPotentialConstantExpression() || S.Current->Caller)230    cleanupAfterFunctionCall(S, PC, S.Current->getFunction());231 232  if (InterpFrame *Caller = S.Current->Caller) {233    PC = S.Current->getRetPC();234    InterpFrame::free(S.Current);235    S.Current = Caller;236    S.Stk.push<T>(Ret);237  } else {238    InterpFrame::free(S.Current);239    S.Current = nullptr;240    // The topmost frame should come from an EvalEmitter,241    // which has its own implementation of the Ret<> instruction.242  }243  return true;244}245 246inline bool RetVoid(InterpState &S, CodePtr &PC) {247  assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame");248 249  if (!S.checkingPotentialConstantExpression() || S.Current->Caller)250    cleanupAfterFunctionCall(S, PC, S.Current->getFunction());251 252  if (InterpFrame *Caller = S.Current->Caller) {253    PC = S.Current->getRetPC();254    InterpFrame::free(S.Current);255    S.Current = Caller;256  } else {257    InterpFrame::free(S.Current);258    S.Current = nullptr;259  }260  return true;261}262 263//===----------------------------------------------------------------------===//264// Add, Sub, Mul265//===----------------------------------------------------------------------===//266 267template <typename T, bool (*OpFW)(T, T, unsigned, T *),268          template <typename U> class OpAP>269bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS,270                     const T &RHS) {271  // Fast path - add the numbers with fixed width.272  T Result;273  if constexpr (needsAlloc<T>())274    Result = S.allocAP<T>(LHS.bitWidth());275 276  if (!OpFW(LHS, RHS, Bits, &Result)) {277    S.Stk.push<T>(Result);278    return true;279  }280  // If for some reason evaluation continues, use the truncated results.281  S.Stk.push<T>(Result);282 283  // Short-circuit fixed-points here since the error handling is easier.284  if constexpr (std::is_same_v<T, FixedPoint>)285    return handleFixedPointOverflow(S, OpPC, Result);286 287  // Slow path - compute the result using another bit of precision.288  APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits));289 290  // Report undefined behaviour, stopping if required.291  if (S.checkingForUndefinedBehavior()) {292    const Expr *E = S.Current->getExpr(OpPC);293    QualType Type = E->getType();294    SmallString<32> Trunc;295    Value.trunc(Result.bitWidth())296        .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,297                  /*UpperCase=*/true, /*InsertSeparators=*/true);298    S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)299        << Trunc << Type << E->getSourceRange();300  }301 302  if (!handleOverflow(S, OpPC, Value)) {303    S.Stk.pop<T>();304    return false;305  }306  return true;307}308 309template <PrimType Name, class T = typename PrimConv<Name>::T>310bool Add(InterpState &S, CodePtr OpPC) {311  const T &RHS = S.Stk.pop<T>();312  const T &LHS = S.Stk.pop<T>();313  const unsigned Bits = RHS.bitWidth() + 1;314 315  return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS);316}317 318inline bool Addf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {319  const Floating &RHS = S.Stk.pop<Floating>();320  const Floating &LHS = S.Stk.pop<Floating>();321 322  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);323  Floating Result = S.allocFloat(LHS.getSemantics());324  auto Status = Floating::add(LHS, RHS, getRoundingMode(FPO), &Result);325  S.Stk.push<Floating>(Result);326  return CheckFloatResult(S, OpPC, Result, Status, FPO);327}328 329template <PrimType Name, class T = typename PrimConv<Name>::T>330bool Sub(InterpState &S, CodePtr OpPC) {331  const T &RHS = S.Stk.pop<T>();332  const T &LHS = S.Stk.pop<T>();333  const unsigned Bits = RHS.bitWidth() + 1;334 335  return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS);336}337 338inline bool Subf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {339  const Floating &RHS = S.Stk.pop<Floating>();340  const Floating &LHS = S.Stk.pop<Floating>();341 342  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);343  Floating Result = S.allocFloat(LHS.getSemantics());344  auto Status = Floating::sub(LHS, RHS, getRoundingMode(FPO), &Result);345  S.Stk.push<Floating>(Result);346  return CheckFloatResult(S, OpPC, Result, Status, FPO);347}348 349template <PrimType Name, class T = typename PrimConv<Name>::T>350bool Mul(InterpState &S, CodePtr OpPC) {351  const T &RHS = S.Stk.pop<T>();352  const T &LHS = S.Stk.pop<T>();353  const unsigned Bits = RHS.bitWidth() * 2;354 355  return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS);356}357 358inline bool Mulf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {359  const Floating &RHS = S.Stk.pop<Floating>();360  const Floating &LHS = S.Stk.pop<Floating>();361 362  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);363  Floating Result = S.allocFloat(LHS.getSemantics());364 365  auto Status = Floating::mul(LHS, RHS, getRoundingMode(FPO), &Result);366 367  S.Stk.push<Floating>(Result);368  return CheckFloatResult(S, OpPC, Result, Status, FPO);369}370 371template <PrimType Name, class T = typename PrimConv<Name>::T>372inline bool Mulc(InterpState &S, CodePtr OpPC) {373  const Pointer &RHS = S.Stk.pop<Pointer>();374  const Pointer &LHS = S.Stk.pop<Pointer>();375  const Pointer &Result = S.Stk.peek<Pointer>();376 377  if constexpr (std::is_same_v<T, Floating>) {378    APFloat A = LHS.elem<Floating>(0).getAPFloat();379    APFloat B = LHS.elem<Floating>(1).getAPFloat();380    APFloat C = RHS.elem<Floating>(0).getAPFloat();381    APFloat D = RHS.elem<Floating>(1).getAPFloat();382 383    APFloat ResR(A.getSemantics());384    APFloat ResI(A.getSemantics());385    HandleComplexComplexMul(A, B, C, D, ResR, ResI);386 387    // Copy into the result.388    Floating RA = S.allocFloat(A.getSemantics());389    RA.copy(ResR);390    Result.elem<Floating>(0) = RA; // Floating(ResR);391 392    Floating RI = S.allocFloat(A.getSemantics());393    RI.copy(ResI);394    Result.elem<Floating>(1) = RI; // Floating(ResI);395    Result.initializeAllElements();396  } else {397    // Integer element type.398    const T &LHSR = LHS.elem<T>(0);399    const T &LHSI = LHS.elem<T>(1);400    const T &RHSR = RHS.elem<T>(0);401    const T &RHSI = RHS.elem<T>(1);402    unsigned Bits = LHSR.bitWidth();403 404    // real(Result) = (real(LHS) * real(RHS)) - (imag(LHS) * imag(RHS))405    T A;406    if (T::mul(LHSR, RHSR, Bits, &A))407      return false;408    T B;409    if (T::mul(LHSI, RHSI, Bits, &B))410      return false;411    if (T::sub(A, B, Bits, &Result.elem<T>(0)))412      return false;413 414    // imag(Result) = (real(LHS) * imag(RHS)) + (imag(LHS) * real(RHS))415    if (T::mul(LHSR, RHSI, Bits, &A))416      return false;417    if (T::mul(LHSI, RHSR, Bits, &B))418      return false;419    if (T::add(A, B, Bits, &Result.elem<T>(1)))420      return false;421    Result.initialize();422    Result.initializeAllElements();423  }424 425  return true;426}427 428template <PrimType Name, class T = typename PrimConv<Name>::T>429inline bool Divc(InterpState &S, CodePtr OpPC) {430  const Pointer &RHS = S.Stk.pop<Pointer>();431  const Pointer &LHS = S.Stk.pop<Pointer>();432  const Pointer &Result = S.Stk.peek<Pointer>();433 434  if constexpr (std::is_same_v<T, Floating>) {435    APFloat A = LHS.elem<Floating>(0).getAPFloat();436    APFloat B = LHS.elem<Floating>(1).getAPFloat();437    APFloat C = RHS.elem<Floating>(0).getAPFloat();438    APFloat D = RHS.elem<Floating>(1).getAPFloat();439 440    APFloat ResR(A.getSemantics());441    APFloat ResI(A.getSemantics());442    HandleComplexComplexDiv(A, B, C, D, ResR, ResI);443 444    // Copy into the result.445    Floating RA = S.allocFloat(A.getSemantics());446    RA.copy(ResR);447    Result.elem<Floating>(0) = RA; // Floating(ResR);448 449    Floating RI = S.allocFloat(A.getSemantics());450    RI.copy(ResI);451    Result.elem<Floating>(1) = RI; // Floating(ResI);452 453    Result.initializeAllElements();454  } else {455    // Integer element type.456    const T &LHSR = LHS.elem<T>(0);457    const T &LHSI = LHS.elem<T>(1);458    const T &RHSR = RHS.elem<T>(0);459    const T &RHSI = RHS.elem<T>(1);460    unsigned Bits = LHSR.bitWidth();461    const T Zero = T::from(0, Bits);462 463    if (Compare(RHSR, Zero) == ComparisonCategoryResult::Equal &&464        Compare(RHSI, Zero) == ComparisonCategoryResult::Equal) {465      const SourceInfo &E = S.Current->getSource(OpPC);466      S.FFDiag(E, diag::note_expr_divide_by_zero);467      return false;468    }469 470    // Den = real(RHS)² + imag(RHS)²471    T A, B;472    if (T::mul(RHSR, RHSR, Bits, &A) || T::mul(RHSI, RHSI, Bits, &B)) {473      // Ignore overflow here, because that's what the current interpeter does.474    }475    T Den;476    if (T::add(A, B, Bits, &Den))477      return false;478 479    if (Compare(Den, Zero) == ComparisonCategoryResult::Equal) {480      const SourceInfo &E = S.Current->getSource(OpPC);481      S.FFDiag(E, diag::note_expr_divide_by_zero);482      return false;483    }484 485    // real(Result) = ((real(LHS) * real(RHS)) + (imag(LHS) * imag(RHS))) / Den486    T &ResultR = Result.elem<T>(0);487    T &ResultI = Result.elem<T>(1);488 489    if (T::mul(LHSR, RHSR, Bits, &A) || T::mul(LHSI, RHSI, Bits, &B))490      return false;491    if (T::add(A, B, Bits, &ResultR))492      return false;493    if (T::div(ResultR, Den, Bits, &ResultR))494      return false;495 496    // imag(Result) = ((imag(LHS) * real(RHS)) - (real(LHS) * imag(RHS))) / Den497    if (T::mul(LHSI, RHSR, Bits, &A) || T::mul(LHSR, RHSI, Bits, &B))498      return false;499    if (T::sub(A, B, Bits, &ResultI))500      return false;501    if (T::div(ResultI, Den, Bits, &ResultI))502      return false;503    Result.initializeAllElements();504  }505 506  return true;507}508 509/// 1) Pops the RHS from the stack.510/// 2) Pops the LHS from the stack.511/// 3) Pushes 'LHS & RHS' on the stack512template <PrimType Name, class T = typename PrimConv<Name>::T>513bool BitAnd(InterpState &S, CodePtr OpPC) {514  const T &RHS = S.Stk.pop<T>();515  const T &LHS = S.Stk.pop<T>();516  unsigned Bits = RHS.bitWidth();517 518  T Result;519  if constexpr (needsAlloc<T>())520    Result = S.allocAP<T>(Bits);521 522  if (!T::bitAnd(LHS, RHS, Bits, &Result)) {523    S.Stk.push<T>(Result);524    return true;525  }526  return false;527}528 529/// 1) Pops the RHS from the stack.530/// 2) Pops the LHS from the stack.531/// 3) Pushes 'LHS | RHS' on the stack532template <PrimType Name, class T = typename PrimConv<Name>::T>533bool BitOr(InterpState &S, CodePtr OpPC) {534  const T &RHS = S.Stk.pop<T>();535  const T &LHS = S.Stk.pop<T>();536  unsigned Bits = RHS.bitWidth();537 538  T Result;539  if constexpr (needsAlloc<T>())540    Result = S.allocAP<T>(Bits);541 542  if (!T::bitOr(LHS, RHS, Bits, &Result)) {543    S.Stk.push<T>(Result);544    return true;545  }546  return false;547}548 549/// 1) Pops the RHS from the stack.550/// 2) Pops the LHS from the stack.551/// 3) Pushes 'LHS ^ RHS' on the stack552template <PrimType Name, class T = typename PrimConv<Name>::T>553bool BitXor(InterpState &S, CodePtr OpPC) {554  const T &RHS = S.Stk.pop<T>();555  const T &LHS = S.Stk.pop<T>();556 557  unsigned Bits = RHS.bitWidth();558 559  T Result;560  if constexpr (needsAlloc<T>())561    Result = S.allocAP<T>(Bits);562 563  if (!T::bitXor(LHS, RHS, Bits, &Result)) {564    S.Stk.push<T>(Result);565    return true;566  }567  return false;568}569 570/// 1) Pops the RHS from the stack.571/// 2) Pops the LHS from the stack.572/// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS).573template <PrimType Name, class T = typename PrimConv<Name>::T>574bool Rem(InterpState &S, CodePtr OpPC) {575  const T &RHS = S.Stk.pop<T>();576  const T &LHS = S.Stk.pop<T>();577  const unsigned Bits = RHS.bitWidth() * 2;578 579  if (!CheckDivRem(S, OpPC, LHS, RHS))580    return false;581 582  T Result;583  if constexpr (needsAlloc<T>())584    Result = S.allocAP<T>(LHS.bitWidth());585 586  if (!T::rem(LHS, RHS, Bits, &Result)) {587    S.Stk.push<T>(Result);588    return true;589  }590  return false;591}592 593/// 1) Pops the RHS from the stack.594/// 2) Pops the LHS from the stack.595/// 3) Pushes 'LHS / RHS' on the stack596template <PrimType Name, class T = typename PrimConv<Name>::T>597bool Div(InterpState &S, CodePtr OpPC) {598  const T &RHS = S.Stk.pop<T>();599  const T &LHS = S.Stk.pop<T>();600  const unsigned Bits = RHS.bitWidth() * 2;601 602  if (!CheckDivRem(S, OpPC, LHS, RHS))603    return false;604 605  T Result;606  if constexpr (needsAlloc<T>())607    Result = S.allocAP<T>(LHS.bitWidth());608 609  if (!T::div(LHS, RHS, Bits, &Result)) {610    S.Stk.push<T>(Result);611    return true;612  }613 614  if constexpr (std::is_same_v<T, FixedPoint>) {615    if (handleFixedPointOverflow(S, OpPC, Result)) {616      S.Stk.push<T>(Result);617      return true;618    }619  }620  return false;621}622 623inline bool Divf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {624  const Floating &RHS = S.Stk.pop<Floating>();625  const Floating &LHS = S.Stk.pop<Floating>();626 627  if (!CheckDivRem(S, OpPC, LHS, RHS))628    return false;629 630  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);631 632  Floating Result = S.allocFloat(LHS.getSemantics());633  auto Status = Floating::div(LHS, RHS, getRoundingMode(FPO), &Result);634 635  S.Stk.push<Floating>(Result);636  return CheckFloatResult(S, OpPC, Result, Status, FPO);637}638 639//===----------------------------------------------------------------------===//640// Inv641//===----------------------------------------------------------------------===//642 643inline bool Inv(InterpState &S, CodePtr OpPC) {644  const auto &Val = S.Stk.pop<Boolean>();645  S.Stk.push<Boolean>(!Val);646  return true;647}648 649//===----------------------------------------------------------------------===//650// Neg651//===----------------------------------------------------------------------===//652 653template <PrimType Name, class T = typename PrimConv<Name>::T>654bool Neg(InterpState &S, CodePtr OpPC) {655  const T &Value = S.Stk.pop<T>();656 657  if constexpr (std::is_same_v<T, Floating>) {658    T Result = S.allocFloat(Value.getSemantics());659 660    if (!T::neg(Value, &Result)) {661      S.Stk.push<T>(Result);662      return true;663    }664    return false;665  } else {666    T Result;667    if constexpr (needsAlloc<T>())668      Result = S.allocAP<T>(Value.bitWidth());669 670    if (!T::neg(Value, &Result)) {671      S.Stk.push<T>(Result);672      return true;673    }674 675    assert(isIntegralType(Name) &&676           "don't expect other types to fail at constexpr negation");677    S.Stk.push<T>(Result);678 679    APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1);680    if (S.checkingForUndefinedBehavior()) {681      const Expr *E = S.Current->getExpr(OpPC);682      QualType Type = E->getType();683      SmallString<32> Trunc;684      NegatedValue.trunc(Result.bitWidth())685          .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,686                    /*UpperCase=*/true, /*InsertSeparators=*/true);687      S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)688          << Trunc << Type << E->getSourceRange();689      return true;690    }691 692    return handleOverflow(S, OpPC, NegatedValue);693  }694}695 696enum class PushVal : bool {697  No,698  Yes,699};700enum class IncDecOp {701  Inc,702  Dec,703};704 705template <typename T, IncDecOp Op, PushVal DoPush>706bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,707                  bool CanOverflow, UnsignedOrNone BitWidth = std::nullopt) {708  assert(!Ptr.isDummy());709 710  if (!S.inConstantContext()) {711    if (isConstexprUnknown(Ptr))712      return false;713  }714 715  if constexpr (std::is_same_v<T, Boolean>) {716    if (!S.getLangOpts().CPlusPlus14)717      return Invalid(S, OpPC);718  }719 720  const T &Value = Ptr.deref<T>();721  T Result;722  if constexpr (needsAlloc<T>())723    Result = S.allocAP<T>(Value.bitWidth());724 725  if constexpr (DoPush == PushVal::Yes)726    S.Stk.push<T>(Value);727 728  if constexpr (Op == IncDecOp::Inc) {729    if (!T::increment(Value, &Result) || !CanOverflow) {730      if (BitWidth)731        Ptr.deref<T>() = Result.truncate(*BitWidth);732      else733        Ptr.deref<T>() = Result;734      return true;735    }736  } else {737    if (!T::decrement(Value, &Result) || !CanOverflow) {738      if (BitWidth)739        Ptr.deref<T>() = Result.truncate(*BitWidth);740      else741        Ptr.deref<T>() = Result;742      return true;743    }744  }745  assert(CanOverflow);746 747  // Something went wrong with the previous operation. Compute the748  // result with another bit of precision.749  unsigned Bits = Value.bitWidth() + 1;750  APSInt APResult;751  if constexpr (Op == IncDecOp::Inc)752    APResult = ++Value.toAPSInt(Bits);753  else754    APResult = --Value.toAPSInt(Bits);755 756  // Report undefined behaviour, stopping if required.757  if (S.checkingForUndefinedBehavior()) {758    const Expr *E = S.Current->getExpr(OpPC);759    QualType Type = E->getType();760    SmallString<32> Trunc;761    APResult.trunc(Result.bitWidth())762        .toString(Trunc, 10, Result.isSigned(), /*formatAsCLiteral=*/false,763                  /*UpperCase=*/true, /*InsertSeparators=*/true);764    S.report(E->getExprLoc(), diag::warn_integer_constant_overflow)765        << Trunc << Type << E->getSourceRange();766    return true;767  }768  return handleOverflow(S, OpPC, APResult);769}770 771/// 1) Pops a pointer from the stack772/// 2) Load the value from the pointer773/// 3) Writes the value increased by one back to the pointer774/// 4) Pushes the original (pre-inc) value on the stack.775template <PrimType Name, class T = typename PrimConv<Name>::T>776bool Inc(InterpState &S, CodePtr OpPC, bool CanOverflow) {777  const Pointer &Ptr = S.Stk.pop<Pointer>();778  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))779    return false;780 781  return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr,782                                                      CanOverflow);783}784 785template <PrimType Name, class T = typename PrimConv<Name>::T>786bool IncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,787                 unsigned BitWidth) {788  const Pointer &Ptr = S.Stk.pop<Pointer>();789  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))790    return false;791 792  return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,793                                                      BitWidth);794}795 796/// 1) Pops a pointer from the stack797/// 2) Load the value from the pointer798/// 3) Writes the value increased by one back to the pointer799template <PrimType Name, class T = typename PrimConv<Name>::T>800bool IncPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {801  const Pointer &Ptr = S.Stk.pop<Pointer>();802  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))803    return false;804 805  return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);806}807 808template <PrimType Name, class T = typename PrimConv<Name>::T>809bool IncPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,810                    uint32_t BitWidth) {811  const Pointer &Ptr = S.Stk.pop<Pointer>();812  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))813    return false;814 815  return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,816                                                     BitWidth);817}818 819template <PrimType Name, class T = typename PrimConv<Name>::T>820bool PreInc(InterpState &S, CodePtr OpPC, bool CanOverflow) {821  const Pointer &Ptr = S.Stk.peek<Pointer>();822  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))823    return false;824 825  return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow);826}827 828template <PrimType Name, class T = typename PrimConv<Name>::T>829bool PreIncBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,830                    uint32_t BitWidth) {831  const Pointer &Ptr = S.Stk.peek<Pointer>();832  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))833    return false;834 835  return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, CanOverflow,836                                                     BitWidth);837}838 839/// 1) Pops a pointer from the stack840/// 2) Load the value from the pointer841/// 3) Writes the value decreased by one back to the pointer842/// 4) Pushes the original (pre-dec) value on the stack.843template <PrimType Name, class T = typename PrimConv<Name>::T>844bool Dec(InterpState &S, CodePtr OpPC, bool CanOverflow) {845  const Pointer &Ptr = S.Stk.pop<Pointer>();846  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))847    return false;848 849  return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr,850                                                      CanOverflow);851}852template <PrimType Name, class T = typename PrimConv<Name>::T>853bool DecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,854                 uint32_t BitWidth) {855  const Pointer &Ptr = S.Stk.pop<Pointer>();856  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))857    return false;858 859  return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, CanOverflow,860                                                      BitWidth);861}862 863/// 1) Pops a pointer from the stack864/// 2) Load the value from the pointer865/// 3) Writes the value decreased by one back to the pointer866template <PrimType Name, class T = typename PrimConv<Name>::T>867bool DecPop(InterpState &S, CodePtr OpPC, bool CanOverflow) {868  const Pointer &Ptr = S.Stk.pop<Pointer>();869  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))870    return false;871 872  return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);873}874 875template <PrimType Name, class T = typename PrimConv<Name>::T>876bool DecPopBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,877                    uint32_t BitWidth) {878  const Pointer &Ptr = S.Stk.pop<Pointer>();879  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))880    return false;881 882  return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,883                                                     BitWidth);884}885 886template <PrimType Name, class T = typename PrimConv<Name>::T>887bool PreDec(InterpState &S, CodePtr OpPC, bool CanOverflow) {888  const Pointer &Ptr = S.Stk.peek<Pointer>();889  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))890    return false;891  return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow);892}893 894template <PrimType Name, class T = typename PrimConv<Name>::T>895bool PreDecBitfield(InterpState &S, CodePtr OpPC, bool CanOverflow,896                    uint32_t BitWidth) {897  const Pointer &Ptr = S.Stk.peek<Pointer>();898  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))899    return false;900  return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, CanOverflow,901                                                     BitWidth);902}903 904template <IncDecOp Op, PushVal DoPush>905bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr,906                       uint32_t FPOI) {907  Floating Value = Ptr.deref<Floating>();908  Floating Result = S.allocFloat(Value.getSemantics());909 910  if constexpr (DoPush == PushVal::Yes)911    S.Stk.push<Floating>(Value);912 913  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);914  llvm::APFloat::opStatus Status;915  if constexpr (Op == IncDecOp::Inc)916    Status = Floating::increment(Value, getRoundingMode(FPO), &Result);917  else918    Status = Floating::decrement(Value, getRoundingMode(FPO), &Result);919 920  Ptr.deref<Floating>() = Result;921 922  return CheckFloatResult(S, OpPC, Result, Status, FPO);923}924 925inline bool Incf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {926  const Pointer &Ptr = S.Stk.pop<Pointer>();927  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))928    return false;929 930  return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, FPOI);931}932 933inline bool IncfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {934  const Pointer &Ptr = S.Stk.pop<Pointer>();935  if (!CheckLoad(S, OpPC, Ptr, AK_Increment))936    return false;937 938  return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, FPOI);939}940 941inline bool Decf(InterpState &S, CodePtr OpPC, uint32_t FPOI) {942  const Pointer &Ptr = S.Stk.pop<Pointer>();943  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))944    return false;945 946  return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, FPOI);947}948 949inline bool DecfPop(InterpState &S, CodePtr OpPC, uint32_t FPOI) {950  const Pointer &Ptr = S.Stk.pop<Pointer>();951  if (!CheckLoad(S, OpPC, Ptr, AK_Decrement))952    return false;953 954  return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, FPOI);955}956 957/// 1) Pops the value from the stack.958/// 2) Pushes the bitwise complemented value on the stack (~V).959template <PrimType Name, class T = typename PrimConv<Name>::T>960bool Comp(InterpState &S, CodePtr OpPC) {961  const T &Val = S.Stk.pop<T>();962 963  T Result;964  if constexpr (needsAlloc<T>())965    Result = S.allocAP<T>(Val.bitWidth());966 967  if (!T::comp(Val, &Result)) {968    S.Stk.push<T>(Result);969    return true;970  }971  return false;972}973 974//===----------------------------------------------------------------------===//975// EQ, NE, GT, GE, LT, LE976//===----------------------------------------------------------------------===//977 978using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>;979 980template <typename T>981bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) {982  assert((!std::is_same_v<T, MemberPointer>) &&983         "Non-equality comparisons on member pointer types should already be "984         "rejected in Sema.");985  using BoolT = PrimConv<PT_Bool>::T;986  const T &RHS = S.Stk.pop<T>();987  const T &LHS = S.Stk.pop<T>();988  S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS))));989  return true;990}991 992template <typename T>993bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) {994  return CmpHelper<T>(S, OpPC, Fn);995}996 997template <>998inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {999  using BoolT = PrimConv<PT_Bool>::T;1000  const Pointer &RHS = S.Stk.pop<Pointer>();1001  const Pointer &LHS = S.Stk.pop<Pointer>();1002 1003  // Function pointers cannot be compared in an ordered way.1004  if (LHS.isFunctionPointer() || RHS.isFunctionPointer() ||1005      LHS.isTypeidPointer() || RHS.isTypeidPointer()) {1006    const SourceInfo &Loc = S.Current->getSource(OpPC);1007    S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1008        << LHS.toDiagnosticString(S.getASTContext())1009        << RHS.toDiagnosticString(S.getASTContext());1010    return false;1011  }1012 1013  if (!Pointer::hasSameBase(LHS, RHS)) {1014    const SourceInfo &Loc = S.Current->getSource(OpPC);1015    S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1016        << LHS.toDiagnosticString(S.getASTContext())1017        << RHS.toDiagnosticString(S.getASTContext());1018    return false;1019  }1020 1021  // Diagnose comparisons between fields with different access specifiers.1022  if (std::optional<std::pair<Pointer, Pointer>> Split =1023          Pointer::computeSplitPoint(LHS, RHS)) {1024    const FieldDecl *LF = Split->first.getField();1025    const FieldDecl *RF = Split->second.getField();1026    if (LF && RF && !LF->getParent()->isUnion() &&1027        LF->getAccess() != RF->getAccess()) {1028      S.CCEDiag(S.Current->getSource(OpPC),1029                diag::note_constexpr_pointer_comparison_differing_access)1030          << LF << LF->getAccess() << RF << RF->getAccess() << LF->getParent();1031    }1032  }1033 1034  unsigned VL = LHS.getByteOffset();1035  unsigned VR = RHS.getByteOffset();1036  S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));1037  return true;1038}1039 1040static inline bool IsOpaqueConstantCall(const CallExpr *E) {1041  unsigned Builtin = E->getBuiltinCallee();1042  return (Builtin == Builtin::BI__builtin___CFStringMakeConstantString ||1043          Builtin == Builtin::BI__builtin___NSStringMakeConstantString ||1044          Builtin == Builtin::BI__builtin_ptrauth_sign_constant ||1045          Builtin == Builtin::BI__builtin_function_start);1046}1047 1048bool arePotentiallyOverlappingStringLiterals(const Pointer &LHS,1049                                             const Pointer &RHS);1050 1051template <>1052inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {1053  using BoolT = PrimConv<PT_Bool>::T;1054  const Pointer &RHS = S.Stk.pop<Pointer>();1055  const Pointer &LHS = S.Stk.pop<Pointer>();1056 1057  if (LHS.isZero() && RHS.isZero()) {1058    S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal)));1059    return true;1060  }1061 1062  // Reject comparisons to weak pointers.1063  for (const auto &P : {LHS, RHS}) {1064    if (P.isZero())1065      continue;1066    if (P.isWeak()) {1067      const SourceInfo &Loc = S.Current->getSource(OpPC);1068      S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)1069          << P.toDiagnosticString(S.getASTContext());1070      return false;1071    }1072  }1073 1074  if (!S.inConstantContext()) {1075    if (isConstexprUnknown(LHS) || isConstexprUnknown(RHS))1076      return false;1077  }1078 1079  if (LHS.isFunctionPointer() && RHS.isFunctionPointer()) {1080    S.Stk.push<BoolT>(BoolT::from(Fn(Compare(LHS.getIntegerRepresentation(),1081                                             RHS.getIntegerRepresentation()))));1082    return true;1083  }1084 1085  // FIXME: The source check here isn't entirely correct.1086  if (LHS.pointsToStringLiteral() && RHS.pointsToStringLiteral() &&1087      LHS.getFieldDesc()->asExpr() != RHS.getFieldDesc()->asExpr()) {1088    if (arePotentiallyOverlappingStringLiterals(LHS, RHS)) {1089      const SourceInfo &Loc = S.Current->getSource(OpPC);1090      S.FFDiag(Loc, diag::note_constexpr_literal_comparison)1091          << LHS.toDiagnosticString(S.getASTContext())1092          << RHS.toDiagnosticString(S.getASTContext());1093      return false;1094    }1095  }1096 1097  if (Pointer::hasSameBase(LHS, RHS)) {1098    size_t A = LHS.computeOffsetForComparison();1099    size_t B = RHS.computeOffsetForComparison();1100    S.Stk.push<BoolT>(BoolT::from(Fn(Compare(A, B))));1101    return true;1102  }1103 1104  // Otherwise we need to do a bunch of extra checks before returning Unordered.1105  if (LHS.isOnePastEnd() && !RHS.isOnePastEnd() && !RHS.isZero() &&1106      RHS.getOffset() == 0) {1107    const SourceInfo &Loc = S.Current->getSource(OpPC);1108    S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)1109        << LHS.toDiagnosticString(S.getASTContext());1110    return false;1111  }1112  if (RHS.isOnePastEnd() && !LHS.isOnePastEnd() && !LHS.isZero() &&1113      LHS.getOffset() == 0) {1114    const SourceInfo &Loc = S.Current->getSource(OpPC);1115    S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_past_end)1116        << RHS.toDiagnosticString(S.getASTContext());1117    return false;1118  }1119 1120  bool BothNonNull = !LHS.isZero() && !RHS.isZero();1121  // Reject comparisons to literals.1122  for (const auto &P : {LHS, RHS}) {1123    if (P.isZero())1124      continue;1125    if (BothNonNull && P.pointsToLiteral()) {1126      const Expr *E = P.getDeclDesc()->asExpr();1127      if (isa<StringLiteral>(E)) {1128        const SourceInfo &Loc = S.Current->getSource(OpPC);1129        S.FFDiag(Loc, diag::note_constexpr_literal_comparison);1130        return false;1131      }1132      if (const auto *CE = dyn_cast<CallExpr>(E);1133          CE && IsOpaqueConstantCall(CE)) {1134        const SourceInfo &Loc = S.Current->getSource(OpPC);1135        S.FFDiag(Loc, diag::note_constexpr_opaque_call_comparison)1136            << P.toDiagnosticString(S.getASTContext());1137        return false;1138      }1139    } else if (BothNonNull && P.isIntegralPointer()) {1140      const SourceInfo &Loc = S.Current->getSource(OpPC);1141      S.FFDiag(Loc, diag::note_constexpr_pointer_constant_comparison)1142          << LHS.toDiagnosticString(S.getASTContext())1143          << RHS.toDiagnosticString(S.getASTContext());1144      return false;1145    }1146  }1147 1148  if (LHS.isUnknownSizeArray() && RHS.isUnknownSizeArray()) {1149    const SourceInfo &Loc = S.Current->getSource(OpPC);1150    S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_zero_sized)1151        << LHS.toDiagnosticString(S.getASTContext())1152        << RHS.toDiagnosticString(S.getASTContext());1153    return false;1154  }1155 1156  S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered)));1157  return true;1158}1159 1160template <>1161inline bool CmpHelperEQ<MemberPointer>(InterpState &S, CodePtr OpPC,1162                                       CompareFn Fn) {1163  const auto &RHS = S.Stk.pop<MemberPointer>();1164  const auto &LHS = S.Stk.pop<MemberPointer>();1165 1166  // If either operand is a pointer to a weak function, the comparison is not1167  // constant.1168  for (const auto &MP : {LHS, RHS}) {1169    if (MP.isWeak()) {1170      const SourceInfo &Loc = S.Current->getSource(OpPC);1171      S.FFDiag(Loc, diag::note_constexpr_mem_pointer_weak_comparison)1172          << MP.getMemberFunction();1173      return false;1174    }1175  }1176 1177  // C++11 [expr.eq]p2:1178  //   If both operands are null, they compare equal. Otherwise if only one is1179  //   null, they compare unequal.1180  if (LHS.isZero() && RHS.isZero()) {1181    S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Equal));1182    return true;1183  }1184  if (LHS.isZero() || RHS.isZero()) {1185    S.Stk.push<Boolean>(Fn(ComparisonCategoryResult::Unordered));1186    return true;1187  }1188 1189  // We cannot compare against virtual declarations at compile time.1190  for (const auto &MP : {LHS, RHS}) {1191    if (const CXXMethodDecl *MD = MP.getMemberFunction();1192        MD && MD->isVirtual()) {1193      const SourceInfo &Loc = S.Current->getSource(OpPC);1194      S.CCEDiag(Loc, diag::note_constexpr_compare_virtual_mem_ptr) << MD;1195    }1196  }1197 1198  S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS))));1199  return true;1200}1201 1202template <PrimType Name, class T = typename PrimConv<Name>::T>1203bool EQ(InterpState &S, CodePtr OpPC) {1204  return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1205    return R == ComparisonCategoryResult::Equal;1206  });1207}1208 1209template <PrimType Name, class T = typename PrimConv<Name>::T>1210bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {1211  const T &RHS = S.Stk.pop<T>();1212  const T &LHS = S.Stk.pop<T>();1213  const Pointer &P = S.Stk.peek<Pointer>();1214 1215  ComparisonCategoryResult CmpResult = LHS.compare(RHS);1216  if constexpr (std::is_same_v<T, Pointer>) {1217    if (CmpResult == ComparisonCategoryResult::Unordered) {1218      const SourceInfo &Loc = S.Current->getSource(OpPC);1219      S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified)1220          << LHS.toDiagnosticString(S.getASTContext())1221          << RHS.toDiagnosticString(S.getASTContext());1222      return false;1223    }1224  }1225 1226  assert(CmpInfo);1227  const auto *CmpValueInfo =1228      CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));1229  assert(CmpValueInfo);1230  assert(CmpValueInfo->hasValidIntValue());1231  return SetThreeWayComparisonField(S, OpPC, P, CmpValueInfo->getIntValue());1232}1233 1234template <PrimType Name, class T = typename PrimConv<Name>::T>1235bool NE(InterpState &S, CodePtr OpPC) {1236  return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) {1237    return R != ComparisonCategoryResult::Equal;1238  });1239}1240 1241template <PrimType Name, class T = typename PrimConv<Name>::T>1242bool LT(InterpState &S, CodePtr OpPC) {1243  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1244    return R == ComparisonCategoryResult::Less;1245  });1246}1247 1248template <PrimType Name, class T = typename PrimConv<Name>::T>1249bool LE(InterpState &S, CodePtr OpPC) {1250  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1251    return R == ComparisonCategoryResult::Less ||1252           R == ComparisonCategoryResult::Equal;1253  });1254}1255 1256template <PrimType Name, class T = typename PrimConv<Name>::T>1257bool GT(InterpState &S, CodePtr OpPC) {1258  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1259    return R == ComparisonCategoryResult::Greater;1260  });1261}1262 1263template <PrimType Name, class T = typename PrimConv<Name>::T>1264bool GE(InterpState &S, CodePtr OpPC) {1265  return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) {1266    return R == ComparisonCategoryResult::Greater ||1267           R == ComparisonCategoryResult::Equal;1268  });1269}1270 1271//===----------------------------------------------------------------------===//1272// Dup, Pop, Test1273//===----------------------------------------------------------------------===//1274 1275template <PrimType Name, class T = typename PrimConv<Name>::T>1276bool Dup(InterpState &S, CodePtr OpPC) {1277  S.Stk.push<T>(S.Stk.peek<T>());1278  return true;1279}1280 1281template <PrimType Name, class T = typename PrimConv<Name>::T>1282bool Pop(InterpState &S, CodePtr OpPC) {1283  S.Stk.discard<T>();1284  return true;1285}1286 1287/// [Value1, Value2] -> [Value2, Value1]1288template <PrimType TopName, PrimType BottomName>1289bool Flip(InterpState &S, CodePtr OpPC) {1290  using TopT = typename PrimConv<TopName>::T;1291  using BottomT = typename PrimConv<BottomName>::T;1292 1293  const auto &Top = S.Stk.pop<TopT>();1294  const auto &Bottom = S.Stk.pop<BottomT>();1295 1296  S.Stk.push<TopT>(Top);1297  S.Stk.push<BottomT>(Bottom);1298 1299  return true;1300}1301 1302//===----------------------------------------------------------------------===//1303// Const1304//===----------------------------------------------------------------------===//1305 1306template <PrimType Name, class T = typename PrimConv<Name>::T>1307bool Const(InterpState &S, CodePtr OpPC, const T &Arg) {1308  if constexpr (needsAlloc<T>()) {1309    T Result = S.allocAP<T>(Arg.bitWidth());1310    Result.copy(Arg.toAPSInt());1311    S.Stk.push<T>(Result);1312    return true;1313  }1314  S.Stk.push<T>(Arg);1315  return true;1316}1317 1318inline bool ConstFloat(InterpState &S, CodePtr OpPC, const Floating &F) {1319  Floating Result = S.allocFloat(F.getSemantics());1320  Result.copy(F.getAPFloat());1321  S.Stk.push<Floating>(Result);1322  return true;1323}1324 1325//===----------------------------------------------------------------------===//1326// Get/Set Local/Param/Global/This1327//===----------------------------------------------------------------------===//1328 1329template <PrimType Name, class T = typename PrimConv<Name>::T>1330bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1331  const Block *B = S.Current->getLocalBlock(I);1332  if (!CheckLocalLoad(S, OpPC, B))1333    return false;1334  S.Stk.push<T>(B->deref<T>());1335  return true;1336}1337 1338bool EndLifetime(InterpState &S, CodePtr OpPC);1339bool EndLifetimePop(InterpState &S, CodePtr OpPC);1340bool StartLifetime(InterpState &S, CodePtr OpPC);1341 1342/// 1) Pops the value from the stack.1343/// 2) Writes the value to the local variable with the1344///    given offset.1345template <PrimType Name, class T = typename PrimConv<Name>::T>1346bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1347  S.Current->setLocal<T>(I, S.Stk.pop<T>());1348  return true;1349}1350 1351template <PrimType Name, class T = typename PrimConv<Name>::T>1352bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1353  if (S.checkingPotentialConstantExpression()) {1354    return false;1355  }1356  S.Stk.push<T>(S.Current->getParam<T>(I));1357  return true;1358}1359 1360template <PrimType Name, class T = typename PrimConv<Name>::T>1361bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) {1362  S.Current->setParam<T>(I, S.Stk.pop<T>());1363  return true;1364}1365 1366/// 1) Peeks a pointer on the stack1367/// 2) Pushes the value of the pointer's field on the stack1368template <PrimType Name, class T = typename PrimConv<Name>::T>1369bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) {1370  const Pointer &Obj = S.Stk.peek<Pointer>();1371  if (!CheckNull(S, OpPC, Obj, CSK_Field))1372    return false;1373  if (!CheckRange(S, OpPC, Obj, CSK_Field))1374    return false;1375  const Pointer &Field = Obj.atField(I);1376  if (!CheckLoad(S, OpPC, Field))1377    return false;1378  S.Stk.push<T>(Field.deref<T>());1379  return true;1380}1381 1382template <PrimType Name, class T = typename PrimConv<Name>::T>1383bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) {1384  const T &Value = S.Stk.pop<T>();1385  const Pointer &Obj = S.Stk.peek<Pointer>();1386  if (!CheckNull(S, OpPC, Obj, CSK_Field))1387    return false;1388  if (!CheckRange(S, OpPC, Obj, CSK_Field))1389    return false;1390  const Pointer &Field = Obj.atField(I);1391  if (!CheckStore(S, OpPC, Field))1392    return false;1393  Field.initialize();1394  Field.deref<T>() = Value;1395  return true;1396}1397 1398/// 1) Pops a pointer from the stack1399/// 2) Pushes the value of the pointer's field on the stack1400template <PrimType Name, class T = typename PrimConv<Name>::T>1401bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) {1402  const Pointer &Obj = S.Stk.pop<Pointer>();1403  if (!CheckNull(S, OpPC, Obj, CSK_Field))1404    return false;1405  if (!CheckRange(S, OpPC, Obj, CSK_Field))1406    return false;1407  const Pointer &Field = Obj.atField(I);1408  if (!CheckLoad(S, OpPC, Field))1409    return false;1410  S.Stk.push<T>(Field.deref<T>());1411  return true;1412}1413 1414template <PrimType Name, class T = typename PrimConv<Name>::T>1415bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1416  if (S.checkingPotentialConstantExpression())1417    return false;1418  if (!CheckThis(S, OpPC))1419    return false;1420  const Pointer &This = S.Current->getThis();1421  const Pointer &Field = This.atField(I);1422  if (!CheckLoad(S, OpPC, Field))1423    return false;1424  S.Stk.push<T>(Field.deref<T>());1425  return true;1426}1427 1428template <PrimType Name, class T = typename PrimConv<Name>::T>1429bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1430  if (S.checkingPotentialConstantExpression())1431    return false;1432  if (!CheckThis(S, OpPC))1433    return false;1434  const T &Value = S.Stk.pop<T>();1435  const Pointer &This = S.Current->getThis();1436  const Pointer &Field = This.atField(I);1437  if (!CheckStore(S, OpPC, Field))1438    return false;1439  Field.deref<T>() = Value;1440  return true;1441}1442 1443template <PrimType Name, class T = typename PrimConv<Name>::T>1444bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1445  const Block *B = S.P.getGlobal(I);1446 1447  if (!CheckGlobalLoad(S, OpPC, B))1448    return false;1449 1450  S.Stk.push<T>(B->deref<T>());1451  return true;1452}1453 1454/// Same as GetGlobal, but without the checks.1455template <PrimType Name, class T = typename PrimConv<Name>::T>1456bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) {1457  const Block *B = S.P.getGlobal(I);1458  const auto &Desc =1459      *reinterpret_cast<const GlobalInlineDescriptor *>(B->rawData());1460  if (Desc.InitState != GlobalInitState::Initialized)1461    return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),1462                                 AK_Read);1463 1464  S.Stk.push<T>(B->deref<T>());1465  return true;1466}1467 1468template <PrimType Name, class T = typename PrimConv<Name>::T>1469bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1470  // TODO: emit warning.1471  return false;1472}1473 1474template <PrimType Name, class T = typename PrimConv<Name>::T>1475bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1476  const Pointer &P = S.P.getGlobal(I);1477 1478  P.deref<T>() = S.Stk.pop<T>();1479 1480  if constexpr (std::is_same_v<T, Floating>) {1481    auto &Val = P.deref<Floating>();1482    if (!Val.singleWord()) {1483      uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];1484      Val.take(NewMemory);1485    }1486 1487  } else if constexpr (needsAlloc<T>()) {1488    auto &Val = P.deref<T>();1489    if (!Val.singleWord()) {1490      uint64_t *NewMemory = new (S.P) uint64_t[Val.numWords()];1491      Val.take(NewMemory);1492    }1493  }1494 1495  P.initialize();1496  return true;1497}1498 1499/// 1) Converts the value on top of the stack to an APValue1500/// 2) Sets that APValue on \Temp1501/// 3) Initializes global with index \I with that1502template <PrimType Name, class T = typename PrimConv<Name>::T>1503bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,1504                    const LifetimeExtendedTemporaryDecl *Temp) {1505  if (S.EvalMode == EvaluationMode::ConstantFold)1506    return false;1507  assert(Temp);1508 1509  const Pointer &Ptr = S.P.getGlobal(I);1510  assert(Ptr.getDeclDesc()->asExpr());1511  S.SeenGlobalTemporaries.push_back(1512      std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));1513 1514  Ptr.deref<T>() = S.Stk.pop<T>();1515  Ptr.initialize();1516  return true;1517}1518 1519/// 1) Converts the value on top of the stack to an APValue1520/// 2) Sets that APValue on \Temp1521/// 3) Initialized global with index \I with that1522inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC,1523                               const LifetimeExtendedTemporaryDecl *Temp) {1524  if (S.EvalMode == EvaluationMode::ConstantFold)1525    return false;1526  assert(Temp);1527 1528  const Pointer &Ptr = S.Stk.peek<Pointer>();1529  S.SeenGlobalTemporaries.push_back(1530      std::make_pair(Ptr.getDeclDesc()->asExpr(), Temp));1531  return true;1532}1533 1534template <PrimType Name, class T = typename PrimConv<Name>::T>1535bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1536  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1537    return false;1538  if (!CheckThis(S, OpPC))1539    return false;1540  const Pointer &This = S.Current->getThis();1541  const Pointer &Field = This.atField(I);1542  assert(Field.canBeInitialized());1543  Field.deref<T>() = S.Stk.pop<T>();1544  Field.initialize();1545  return true;1546}1547 1548template <PrimType Name, class T = typename PrimConv<Name>::T>1549bool InitThisFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {1550  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1551    return false;1552  if (!CheckThis(S, OpPC))1553    return false;1554  const Pointer &This = S.Current->getThis();1555  const Pointer &Field = This.atField(I);1556  assert(Field.canBeInitialized());1557  Field.deref<T>() = S.Stk.pop<T>();1558  Field.activate();1559  Field.initialize();1560  return true;1561}1562 1563// FIXME: The Field pointer here is too much IMO and we could instead just1564// pass an Offset + BitWidth pair.1565template <PrimType Name, class T = typename PrimConv<Name>::T>1566bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F,1567                      uint32_t FieldOffset) {1568  assert(F->isBitField());1569  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1570    return false;1571  if (!CheckThis(S, OpPC))1572    return false;1573  const Pointer &This = S.Current->getThis();1574  const Pointer &Field = This.atField(FieldOffset);1575  assert(Field.canBeInitialized());1576  const auto &Value = S.Stk.pop<T>();1577  Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1578  Field.initialize();1579  return true;1580}1581 1582template <PrimType Name, class T = typename PrimConv<Name>::T>1583bool InitThisBitFieldActivate(InterpState &S, CodePtr OpPC,1584                              const Record::Field *F, uint32_t FieldOffset) {1585  assert(F->isBitField());1586  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1587    return false;1588  if (!CheckThis(S, OpPC))1589    return false;1590  const Pointer &This = S.Current->getThis();1591  const Pointer &Field = This.atField(FieldOffset);1592  assert(Field.canBeInitialized());1593  const auto &Value = S.Stk.pop<T>();1594  Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1595  Field.initialize();1596  Field.activate();1597  return true;1598}1599 1600/// 1) Pops the value from the stack1601/// 2) Peeks a pointer from the stack1602/// 3) Pushes the value to field I of the pointer on the stack1603template <PrimType Name, class T = typename PrimConv<Name>::T>1604bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) {1605  const T &Value = S.Stk.pop<T>();1606  const Pointer &Ptr = S.Stk.peek<Pointer>();1607  if (!CheckRange(S, OpPC, Ptr, CSK_Field))1608    return false;1609  if (!CheckArray(S, OpPC, Ptr))1610    return false;1611 1612  const Pointer &Field = Ptr.atField(I);1613  Field.deref<T>() = Value;1614  Field.initialize();1615  return true;1616}1617 1618template <PrimType Name, class T = typename PrimConv<Name>::T>1619bool InitFieldActivate(InterpState &S, CodePtr OpPC, uint32_t I) {1620  const T &Value = S.Stk.pop<T>();1621  const Pointer &Ptr = S.Stk.peek<Pointer>();1622  if (!CheckRange(S, OpPC, Ptr, CSK_Field))1623    return false;1624  if (!CheckArray(S, OpPC, Ptr))1625    return false;1626 1627  const Pointer &Field = Ptr.atField(I);1628  Field.deref<T>() = Value;1629  Field.activate();1630  Field.initialize();1631  return true;1632}1633 1634template <PrimType Name, class T = typename PrimConv<Name>::T>1635bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) {1636  assert(F->isBitField());1637  const T &Value = S.Stk.pop<T>();1638  const Pointer &Ptr = S.Stk.peek<Pointer>();1639  if (!CheckRange(S, OpPC, Ptr, CSK_Field))1640    return false;1641  if (!CheckArray(S, OpPC, Ptr))1642    return false;1643 1644  const Pointer &Field = Ptr.atField(F->Offset);1645 1646  if constexpr (needsAlloc<T>()) {1647    T Result = S.allocAP<T>(Value.bitWidth());1648    if (T::isSigned())1649      Result.copy(Value.toAPSInt()1650                      .trunc(F->Decl->getBitWidthValue())1651                      .sextOrTrunc(Value.bitWidth()));1652    else1653      Result.copy(Value.toAPSInt()1654                      .trunc(F->Decl->getBitWidthValue())1655                      .zextOrTrunc(Value.bitWidth()));1656 1657    Field.deref<T>() = Result;1658  } else {1659    Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1660  }1661  Field.initialize();1662  return true;1663}1664 1665template <PrimType Name, class T = typename PrimConv<Name>::T>1666bool InitBitFieldActivate(InterpState &S, CodePtr OpPC,1667                          const Record::Field *F) {1668  assert(F->isBitField());1669  const T &Value = S.Stk.pop<T>();1670  const Pointer &Ptr = S.Stk.peek<Pointer>();1671  if (!CheckRange(S, OpPC, Ptr, CSK_Field))1672    return false;1673  if (!CheckArray(S, OpPC, Ptr))1674    return false;1675 1676  const Pointer &Field = Ptr.atField(F->Offset);1677 1678  if constexpr (needsAlloc<T>()) {1679    T Result = S.allocAP<T>(Value.bitWidth());1680    if (T::isSigned())1681      Result.copy(Value.toAPSInt()1682                      .trunc(F->Decl->getBitWidthValue())1683                      .sextOrTrunc(Value.bitWidth()));1684    else1685      Result.copy(Value.toAPSInt()1686                      .trunc(F->Decl->getBitWidthValue())1687                      .zextOrTrunc(Value.bitWidth()));1688 1689    Field.deref<T>() = Result;1690  } else {1691    Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue());1692  }1693  Field.activate();1694  Field.initialize();1695  return true;1696}1697 1698//===----------------------------------------------------------------------===//1699// GetPtr Local/Param/Global/Field/This1700//===----------------------------------------------------------------------===//1701 1702inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) {1703  S.Stk.push<Pointer>(S.Current->getLocalPointer(I));1704  return true;1705}1706 1707inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) {1708  if (S.Current->isBottomFrame())1709    return false;1710  S.Stk.push<Pointer>(S.Current->getParamPointer(I));1711  return true;1712}1713 1714inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {1715  S.Stk.push<Pointer>(S.P.getPtrGlobal(I));1716  return true;1717}1718 1719/// 1) Peeks a Pointer1720/// 2) Pushes Pointer.atField(Off) on the stack1721bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off);1722bool GetPtrFieldPop(InterpState &S, CodePtr OpPC, uint32_t Off);1723 1724inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) {1725  if (S.checkingPotentialConstantExpression() && S.Current->getDepth() == 0)1726    return false;1727  if (!CheckThis(S, OpPC))1728    return false;1729  const Pointer &This = S.Current->getThis();1730  S.Stk.push<Pointer>(This.atField(Off));1731  return true;1732}1733 1734inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off,1735                             bool NullOK, const Type *TargetType) {1736  const Pointer &Ptr = S.Stk.pop<Pointer>();1737  if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Derived))1738    return false;1739 1740  if (!Ptr.isBlockPointer()) {1741    // FIXME: We don't have the necessary information in integral pointers.1742    // The Descriptor only has a record, but that does of course not include1743    // the potential derived classes of said record.1744    S.Stk.push<Pointer>(Ptr);1745    return true;1746  }1747 1748  if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived))1749    return false;1750  if (!CheckDowncast(S, OpPC, Ptr, Off))1751    return false;1752 1753  const Record *TargetRecord = Ptr.atFieldSub(Off).getRecord();1754  assert(TargetRecord);1755 1756  if (TargetRecord->getDecl()->getCanonicalDecl() !=1757      TargetType->getAsCXXRecordDecl()->getCanonicalDecl()) {1758    QualType MostDerivedType = Ptr.getDeclDesc()->getType();1759    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_downcast)1760        << MostDerivedType << QualType(TargetType, 0);1761    return false;1762  }1763 1764  S.Stk.push<Pointer>(Ptr.atFieldSub(Off));1765  return true;1766}1767 1768inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1769  const Pointer &Ptr = S.Stk.peek<Pointer>();1770  if (!CheckNull(S, OpPC, Ptr, CSK_Base))1771    return false;1772 1773  if (!Ptr.isBlockPointer()) {1774    if (!Ptr.isIntegralPointer())1775      return false;1776    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));1777    return true;1778  }1779 1780  if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1781    return false;1782  const Pointer &Result = Ptr.atField(Off);1783  if (Result.isPastEnd() || !Result.isBaseClass())1784    return false;1785  S.Stk.push<Pointer>(Result);1786  return true;1787}1788 1789inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off,1790                          bool NullOK) {1791  const Pointer &Ptr = S.Stk.pop<Pointer>();1792 1793  if (!NullOK && !CheckNull(S, OpPC, Ptr, CSK_Base))1794    return false;1795 1796  if (!Ptr.isBlockPointer()) {1797    if (!Ptr.isIntegralPointer())1798      return false;1799    S.Stk.push<Pointer>(Ptr.asIntPointer().baseCast(S.getASTContext(), Off));1800    return true;1801  }1802 1803  if (!CheckSubobject(S, OpPC, Ptr, CSK_Base))1804    return false;1805  const Pointer &Result = Ptr.atField(Off);1806  if (Result.isPastEnd() || !Result.isBaseClass())1807    return false;1808  S.Stk.push<Pointer>(Result);1809  return true;1810}1811 1812inline bool GetMemberPtrBasePop(InterpState &S, CodePtr OpPC, int32_t Off) {1813  const auto &Ptr = S.Stk.pop<MemberPointer>();1814  S.Stk.push<MemberPointer>(Ptr.atInstanceBase(Off));1815  return true;1816}1817 1818inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) {1819  if (S.checkingPotentialConstantExpression())1820    return false;1821  if (!CheckThis(S, OpPC))1822    return false;1823  const Pointer &This = S.Current->getThis();1824  S.Stk.push<Pointer>(This.atField(Off));1825  return true;1826}1827 1828inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {1829  const Pointer &Ptr = S.Stk.pop<Pointer>();1830  if (Ptr.canBeInitialized())1831    Ptr.initialize();1832  return true;1833}1834 1835inline bool FinishInit(InterpState &S, CodePtr OpPC) {1836  const Pointer &Ptr = S.Stk.peek<Pointer>();1837  if (Ptr.canBeInitialized())1838    Ptr.initialize();1839  return true;1840}1841 1842inline bool FinishInitActivate(InterpState &S, CodePtr OpPC) {1843  const Pointer &Ptr = S.Stk.peek<Pointer>();1844  if (Ptr.canBeInitialized()) {1845    Ptr.initialize();1846    Ptr.activate();1847  }1848  return true;1849}1850 1851inline bool FinishInitActivatePop(InterpState &S, CodePtr OpPC) {1852  const Pointer &Ptr = S.Stk.pop<Pointer>();1853  if (Ptr.canBeInitialized()) {1854    Ptr.initialize();1855    Ptr.activate();1856  }1857  return true;1858}1859 1860bool FinishInitGlobal(InterpState &S, CodePtr OpPC);1861 1862inline bool Dump(InterpState &S, CodePtr OpPC) {1863  S.Stk.dump();1864  return true;1865}1866 1867inline bool CheckNull(InterpState &S, CodePtr OpPC) {1868  const auto &Ptr = S.Stk.peek<Pointer>();1869  if (Ptr.isZero()) {1870    S.FFDiag(S.Current->getSource(OpPC),1871             diag::note_constexpr_dereferencing_null);1872    return S.noteUndefinedBehavior();1873  }1874  return true;1875}1876 1877inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl,1878                           const Pointer &Ptr) {1879  Pointer Base = Ptr;1880  while (Base.isBaseClass())1881    Base = Base.getBase();1882 1883  const Record::Base *VirtBase = Base.getRecord()->getVirtualBase(Decl);1884  S.Stk.push<Pointer>(Base.atField(VirtBase->Offset));1885  return true;1886}1887 1888inline bool GetPtrVirtBasePop(InterpState &S, CodePtr OpPC,1889                              const RecordDecl *D) {1890  assert(D);1891  const Pointer &Ptr = S.Stk.pop<Pointer>();1892  if (!CheckNull(S, OpPC, Ptr, CSK_Base))1893    return false;1894  return VirtBaseHelper(S, OpPC, D, Ptr);1895}1896 1897inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC,1898                               const RecordDecl *D) {1899  assert(D);1900  if (S.checkingPotentialConstantExpression())1901    return false;1902  if (!CheckThis(S, OpPC))1903    return false;1904  const Pointer &This = S.Current->getThis();1905  return VirtBaseHelper(S, OpPC, D, This);1906}1907 1908//===----------------------------------------------------------------------===//1909// Load, Store, Init1910//===----------------------------------------------------------------------===//1911 1912template <PrimType Name, class T = typename PrimConv<Name>::T>1913bool Load(InterpState &S, CodePtr OpPC) {1914  const Pointer &Ptr = S.Stk.peek<Pointer>();1915  if (!CheckLoad(S, OpPC, Ptr))1916    return false;1917  if (!Ptr.isBlockPointer())1918    return false;1919  if (const Descriptor *D = Ptr.getFieldDesc();1920      !(D->isPrimitive() || D->isPrimitiveArray()) || D->getPrimType() != Name)1921    return false;1922  S.Stk.push<T>(Ptr.deref<T>());1923  return true;1924}1925 1926template <PrimType Name, class T = typename PrimConv<Name>::T>1927bool LoadPop(InterpState &S, CodePtr OpPC) {1928  const Pointer &Ptr = S.Stk.pop<Pointer>();1929  if (!CheckLoad(S, OpPC, Ptr))1930    return false;1931  if (!Ptr.isBlockPointer())1932    return false;1933  if (const Descriptor *D = Ptr.getFieldDesc();1934      !(D->isPrimitive() || D->isPrimitiveArray()) || D->getPrimType() != Name)1935    return false;1936  S.Stk.push<T>(Ptr.deref<T>());1937  return true;1938}1939 1940template <PrimType Name, class T = typename PrimConv<Name>::T>1941bool Store(InterpState &S, CodePtr OpPC) {1942  const T &Value = S.Stk.pop<T>();1943  const Pointer &Ptr = S.Stk.peek<Pointer>();1944  if (!CheckStore(S, OpPC, Ptr))1945    return false;1946  if (Ptr.canBeInitialized())1947    Ptr.initialize();1948  Ptr.deref<T>() = Value;1949  return true;1950}1951 1952template <PrimType Name, class T = typename PrimConv<Name>::T>1953bool StorePop(InterpState &S, CodePtr OpPC) {1954  const T &Value = S.Stk.pop<T>();1955  const Pointer &Ptr = S.Stk.pop<Pointer>();1956  if (!CheckStore(S, OpPC, Ptr))1957    return false;1958  if (Ptr.canBeInitialized())1959    Ptr.initialize();1960  Ptr.deref<T>() = Value;1961  return true;1962}1963 1964static inline bool Activate(InterpState &S, CodePtr OpPC) {1965  const Pointer &Ptr = S.Stk.peek<Pointer>();1966  if (Ptr.canBeInitialized())1967    Ptr.activate();1968  return true;1969}1970 1971static inline bool ActivateThisField(InterpState &S, CodePtr OpPC, uint32_t I) {1972  if (S.checkingPotentialConstantExpression())1973    return false;1974  if (!S.Current->hasThisPointer())1975    return false;1976 1977  const Pointer &Ptr = S.Current->getThis();1978  assert(Ptr.atField(I).canBeInitialized());1979  Ptr.atField(I).activate();1980  return true;1981}1982 1983template <PrimType Name, class T = typename PrimConv<Name>::T>1984bool StoreActivate(InterpState &S, CodePtr OpPC) {1985  const T &Value = S.Stk.pop<T>();1986  const Pointer &Ptr = S.Stk.peek<Pointer>();1987 1988  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))1989    return false;1990  if (Ptr.canBeInitialized()) {1991    Ptr.initialize();1992    Ptr.activate();1993  }1994  Ptr.deref<T>() = Value;1995  return true;1996}1997 1998template <PrimType Name, class T = typename PrimConv<Name>::T>1999bool StoreActivatePop(InterpState &S, CodePtr OpPC) {2000  const T &Value = S.Stk.pop<T>();2001  const Pointer &Ptr = S.Stk.pop<Pointer>();2002 2003  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))2004    return false;2005  if (Ptr.canBeInitialized()) {2006    Ptr.initialize();2007    Ptr.activate();2008  }2009  Ptr.deref<T>() = Value;2010  return true;2011}2012 2013template <PrimType Name, class T = typename PrimConv<Name>::T>2014bool StoreBitField(InterpState &S, CodePtr OpPC) {2015  const T &Value = S.Stk.pop<T>();2016  const Pointer &Ptr = S.Stk.peek<Pointer>();2017 2018  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))2019    return false;2020  if (Ptr.canBeInitialized())2021    Ptr.initialize();2022  if (const auto *FD = Ptr.getField())2023    Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());2024  else2025    Ptr.deref<T>() = Value;2026  return true;2027}2028 2029template <PrimType Name, class T = typename PrimConv<Name>::T>2030bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) {2031  const T &Value = S.Stk.pop<T>();2032  const Pointer &Ptr = S.Stk.pop<Pointer>();2033  if (!CheckStore(S, OpPC, Ptr))2034    return false;2035  if (Ptr.canBeInitialized())2036    Ptr.initialize();2037  if (const auto *FD = Ptr.getField())2038    Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());2039  else2040    Ptr.deref<T>() = Value;2041  return true;2042}2043 2044template <PrimType Name, class T = typename PrimConv<Name>::T>2045bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) {2046  const T &Value = S.Stk.pop<T>();2047  const Pointer &Ptr = S.Stk.peek<Pointer>();2048 2049  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))2050    return false;2051  if (Ptr.canBeInitialized()) {2052    Ptr.initialize();2053    Ptr.activate();2054  }2055  if (const auto *FD = Ptr.getField())2056    Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());2057  else2058    Ptr.deref<T>() = Value;2059  return true;2060}2061 2062template <PrimType Name, class T = typename PrimConv<Name>::T>2063bool StoreBitFieldActivatePop(InterpState &S, CodePtr OpPC) {2064  const T &Value = S.Stk.pop<T>();2065  const Pointer &Ptr = S.Stk.pop<Pointer>();2066 2067  if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))2068    return false;2069  if (Ptr.canBeInitialized()) {2070    Ptr.initialize();2071    Ptr.activate();2072  }2073  if (const auto *FD = Ptr.getField())2074    Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue());2075  else2076    Ptr.deref<T>() = Value;2077  return true;2078}2079 2080template <PrimType Name, class T = typename PrimConv<Name>::T>2081bool Init(InterpState &S, CodePtr OpPC) {2082  const T &Value = S.Stk.pop<T>();2083  const Pointer &Ptr = S.Stk.peek<Pointer>();2084  if (!CheckInit(S, OpPC, Ptr))2085    return false;2086  Ptr.initialize();2087  new (&Ptr.deref<T>()) T(Value);2088  return true;2089}2090 2091template <PrimType Name, class T = typename PrimConv<Name>::T>2092bool InitPop(InterpState &S, CodePtr OpPC) {2093  const T &Value = S.Stk.pop<T>();2094  const Pointer &Ptr = S.Stk.pop<Pointer>();2095  if (!CheckInit(S, OpPC, Ptr))2096    return false;2097  Ptr.initialize();2098  new (&Ptr.deref<T>()) T(Value);2099  return true;2100}2101 2102/// 1) Pops the value from the stack2103/// 2) Peeks a pointer and gets its index \Idx2104/// 3) Sets the value on the pointer, leaving the pointer on the stack.2105template <PrimType Name, class T = typename PrimConv<Name>::T>2106bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) {2107  const T &Value = S.Stk.pop<T>();2108  const Pointer &Ptr = S.Stk.peek<Pointer>();2109 2110  const Descriptor *Desc = Ptr.getFieldDesc();2111  if (Desc->isUnknownSizeArray())2112    return false;2113 2114  // In the unlikely event that we're initializing the first item of2115  // a non-array, skip the atIndex().2116  if (Idx == 0 && !Desc->isArray()) {2117    Ptr.initialize();2118    new (&Ptr.deref<T>()) T(Value);2119    return true;2120  }2121 2122  if (!CheckLive(S, OpPC, Ptr, AK_Assign))2123    return false;2124  if (Idx >= Desc->getNumElems()) {2125    // CheckRange.2126    if (S.getLangOpts().CPlusPlus) {2127      const SourceInfo &Loc = S.Current->getSource(OpPC);2128      S.FFDiag(Loc, diag::note_constexpr_access_past_end)2129          << AK_Assign << S.Current->getRange(OpPC);2130    }2131    return false;2132  }2133  Ptr.initializeElement(Idx);2134  new (&Ptr.elem<T>(Idx)) T(Value);2135  return true;2136}2137 2138/// The same as InitElem, but pops the pointer as well.2139template <PrimType Name, class T = typename PrimConv<Name>::T>2140bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) {2141  const T &Value = S.Stk.pop<T>();2142  const Pointer &Ptr = S.Stk.pop<Pointer>();2143 2144  const Descriptor *Desc = Ptr.getFieldDesc();2145  if (Desc->isUnknownSizeArray())2146    return false;2147 2148  // In the unlikely event that we're initializing the first item of2149  // a non-array, skip the atIndex().2150  if (Idx == 0 && !Desc->isArray()) {2151    Ptr.initialize();2152    new (&Ptr.deref<T>()) T(Value);2153    return true;2154  }2155 2156  if (!CheckLive(S, OpPC, Ptr, AK_Assign))2157    return false;2158  if (Idx >= Desc->getNumElems()) {2159    // CheckRange.2160    if (S.getLangOpts().CPlusPlus) {2161      const SourceInfo &Loc = S.Current->getSource(OpPC);2162      S.FFDiag(Loc, diag::note_constexpr_access_past_end)2163          << AK_Assign << S.Current->getRange(OpPC);2164    }2165    return false;2166  }2167  Ptr.initializeElement(Idx);2168  new (&Ptr.elem<T>(Idx)) T(Value);2169  return true;2170}2171 2172inline bool Memcpy(InterpState &S, CodePtr OpPC) {2173  const Pointer &Src = S.Stk.pop<Pointer>();2174  Pointer &Dest = S.Stk.peek<Pointer>();2175 2176  if (!CheckLoad(S, OpPC, Src))2177    return false;2178 2179  return DoMemcpy(S, OpPC, Src, Dest);2180}2181 2182inline bool ToMemberPtr(InterpState &S, CodePtr OpPC) {2183  const auto &Member = S.Stk.pop<MemberPointer>();2184  const auto &Base = S.Stk.pop<Pointer>();2185 2186  S.Stk.push<MemberPointer>(Member.takeInstance(Base));2187  return true;2188}2189 2190inline bool CastMemberPtrPtr(InterpState &S, CodePtr OpPC) {2191  const auto &MP = S.Stk.pop<MemberPointer>();2192 2193  if (std::optional<Pointer> Ptr = MP.toPointer(S.Ctx)) {2194    S.Stk.push<Pointer>(*Ptr);2195    return true;2196  }2197  return Invalid(S, OpPC);2198}2199 2200//===----------------------------------------------------------------------===//2201// AddOffset, SubOffset2202//===----------------------------------------------------------------------===//2203 2204template <class T, ArithOp Op>2205std::optional<Pointer> OffsetHelper(InterpState &S, CodePtr OpPC,2206                                    const T &Offset, const Pointer &Ptr,2207                                    bool IsPointerArith = false) {2208  // A zero offset does not change the pointer.2209  if (Offset.isZero())2210    return Ptr;2211 2212  if (IsPointerArith && !CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {2213    // The CheckNull will have emitted a note already, but we only2214    // abort in C++, since this is fine in C.2215    if (S.getLangOpts().CPlusPlus)2216      return std::nullopt;2217  }2218 2219  // Arrays of unknown bounds cannot have pointers into them.2220  if (!CheckArray(S, OpPC, Ptr))2221    return std::nullopt;2222 2223  // This is much simpler for integral pointers, so handle them first.2224  if (Ptr.isIntegralPointer()) {2225    uint64_t V = Ptr.getIntegerRepresentation();2226    uint64_t O = static_cast<uint64_t>(Offset) * Ptr.elemSize();2227    if constexpr (Op == ArithOp::Add)2228      return Pointer(V + O, Ptr.asIntPointer().Desc);2229    else2230      return Pointer(V - O, Ptr.asIntPointer().Desc);2231  } else if (Ptr.isFunctionPointer()) {2232    uint64_t O = static_cast<uint64_t>(Offset);2233    uint64_t N;2234    if constexpr (Op == ArithOp::Add)2235      N = Ptr.getByteOffset() + O;2236    else2237      N = Ptr.getByteOffset() - O;2238 2239    if (N > 1)2240      S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)2241          << N << /*non-array*/ true << 0;2242    return Pointer(Ptr.asFunctionPointer().getFunction(), N);2243  } else if (!Ptr.isBlockPointer()) {2244    return std::nullopt;2245  }2246 2247  assert(Ptr.isBlockPointer());2248 2249  uint64_t MaxIndex = static_cast<uint64_t>(Ptr.getNumElems());2250  uint64_t Index;2251  if (Ptr.isOnePastEnd())2252    Index = MaxIndex;2253  else2254    Index = Ptr.getIndex();2255 2256  bool Invalid = false;2257  // Helper to report an invalid offset, computed as APSInt.2258  auto DiagInvalidOffset = [&]() -> void {2259    const unsigned Bits = Offset.bitWidth();2260    APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), /*IsUnsigend=*/false);2261    APSInt APIndex(APInt(Bits + 2, Index, /*IsSigned=*/true),2262                   /*IsUnsigned=*/false);2263    APSInt NewIndex =2264        (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset);2265    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index)2266        << NewIndex << /*array*/ static_cast<int>(!Ptr.inArray()) << MaxIndex;2267    Invalid = true;2268  };2269 2270  if (Ptr.isBlockPointer()) {2271    uint64_t IOffset = static_cast<uint64_t>(Offset);2272    uint64_t MaxOffset = MaxIndex - Index;2273 2274    if constexpr (Op == ArithOp::Add) {2275      // If the new offset would be negative, bail out.2276      if (Offset.isNegative() && (Offset.isMin() || -IOffset > Index))2277        DiagInvalidOffset();2278 2279      // If the new offset would be out of bounds, bail out.2280      if (Offset.isPositive() && IOffset > MaxOffset)2281        DiagInvalidOffset();2282    } else {2283      // If the new offset would be negative, bail out.2284      if (Offset.isPositive() && Index < IOffset)2285        DiagInvalidOffset();2286 2287      // If the new offset would be out of bounds, bail out.2288      if (Offset.isNegative() && (Offset.isMin() || -IOffset > MaxOffset))2289        DiagInvalidOffset();2290    }2291  }2292 2293  if (Invalid && (S.getLangOpts().CPlusPlus || Ptr.inArray()))2294    return std::nullopt;2295 2296  // Offset is valid - compute it on unsigned.2297  int64_t WideIndex = static_cast<int64_t>(Index);2298  int64_t WideOffset = static_cast<int64_t>(Offset);2299  int64_t Result;2300  if constexpr (Op == ArithOp::Add)2301    Result = WideIndex + WideOffset;2302  else2303    Result = WideIndex - WideOffset;2304 2305  // When the pointer is one-past-end, going back to index 0 is the only2306  // useful thing we can do. Any other index has been diagnosed before and2307  // we don't get here.2308  if (Result == 0 && Ptr.isOnePastEnd()) {2309    if (Ptr.getFieldDesc()->isArray())2310      return Ptr.atIndex(0);2311    return Pointer(Ptr.asBlockPointer().Pointee, Ptr.asBlockPointer().Base);2312  }2313 2314  return Ptr.atIndex(static_cast<uint64_t>(Result));2315}2316 2317template <PrimType Name, class T = typename PrimConv<Name>::T>2318bool AddOffset(InterpState &S, CodePtr OpPC) {2319  const T &Offset = S.Stk.pop<T>();2320  const Pointer &Ptr = S.Stk.pop<Pointer>().expand();2321 2322  if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Add>(2323          S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {2324    S.Stk.push<Pointer>(Result->narrow());2325    return true;2326  }2327  return false;2328}2329 2330template <PrimType Name, class T = typename PrimConv<Name>::T>2331bool SubOffset(InterpState &S, CodePtr OpPC) {2332  const T &Offset = S.Stk.pop<T>();2333  const Pointer &Ptr = S.Stk.pop<Pointer>().expand();2334 2335  if (std::optional<Pointer> Result = OffsetHelper<T, ArithOp::Sub>(2336          S, OpPC, Offset, Ptr, /*IsPointerArith=*/true)) {2337    S.Stk.push<Pointer>(Result->narrow());2338    return true;2339  }2340  return false;2341}2342 2343template <ArithOp Op>2344static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC,2345                                   const Pointer &Ptr) {2346  if (Ptr.isDummy())2347    return false;2348 2349  using OneT = Integral<8, false>;2350 2351  const Pointer &P = Ptr.deref<Pointer>();2352  if (!CheckNull(S, OpPC, P, CSK_ArrayIndex))2353    return false;2354 2355  // Get the current value on the stack.2356  S.Stk.push<Pointer>(P);2357 2358  // Now the current Ptr again and a constant 1.2359  OneT One = OneT::from(1);2360  if (std::optional<Pointer> Result =2361          OffsetHelper<OneT, Op>(S, OpPC, One, P, /*IsPointerArith=*/true)) {2362    // Store the new value.2363    Ptr.deref<Pointer>() = Result->narrow();2364    return true;2365  }2366  return false;2367}2368 2369static inline bool IncPtr(InterpState &S, CodePtr OpPC) {2370  const Pointer &Ptr = S.Stk.pop<Pointer>();2371 2372  if (!Ptr.isInitialized())2373    return DiagnoseUninitialized(S, OpPC, Ptr, AK_Increment);2374 2375  return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr);2376}2377 2378static inline bool DecPtr(InterpState &S, CodePtr OpPC) {2379  const Pointer &Ptr = S.Stk.pop<Pointer>();2380 2381  if (!Ptr.isInitialized())2382    return DiagnoseUninitialized(S, OpPC, Ptr, AK_Decrement);2383 2384  return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr);2385}2386 2387/// 1) Pops a Pointer from the stack.2388/// 2) Pops another Pointer from the stack.2389/// 3) Pushes the difference of the indices of the two pointers on the stack.2390template <PrimType Name, class T = typename PrimConv<Name>::T>2391inline bool SubPtr(InterpState &S, CodePtr OpPC, bool ElemSizeIsZero) {2392  const Pointer &LHS = S.Stk.pop<Pointer>().expand();2393  const Pointer &RHS = S.Stk.pop<Pointer>().expand();2394 2395  if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {2396    S.FFDiag(S.Current->getSource(OpPC),2397             diag::note_constexpr_pointer_arith_unspecified)2398        << LHS.toDiagnosticString(S.getASTContext())2399        << RHS.toDiagnosticString(S.getASTContext());2400    return false;2401  }2402 2403  if (ElemSizeIsZero) {2404    QualType PtrT = LHS.getType();2405    while (auto *AT = dyn_cast<ArrayType>(PtrT))2406      PtrT = AT->getElementType();2407 2408    QualType ArrayTy = S.getASTContext().getConstantArrayType(2409        PtrT, APInt::getZero(1), nullptr, ArraySizeModifier::Normal, 0);2410    S.FFDiag(S.Current->getSource(OpPC),2411             diag::note_constexpr_pointer_subtraction_zero_size)2412        << ArrayTy;2413 2414    return false;2415  }2416 2417  if (LHS == RHS) {2418    S.Stk.push<T>();2419    return true;2420  }2421 2422  int64_t A64 =2423      LHS.isBlockPointer()2424          ? (LHS.isElementPastEnd() ? LHS.getNumElems() : LHS.getIndex())2425          : LHS.getIntegerRepresentation();2426 2427  int64_t B64 =2428      RHS.isBlockPointer()2429          ? (RHS.isElementPastEnd() ? RHS.getNumElems() : RHS.getIndex())2430          : RHS.getIntegerRepresentation();2431 2432  int64_t R64 = A64 - B64;2433  if (static_cast<int64_t>(T::from(R64)) != R64)2434    return handleOverflow(S, OpPC, R64);2435 2436  S.Stk.push<T>(T::from(R64));2437  return true;2438}2439 2440//===----------------------------------------------------------------------===//2441// Destroy2442//===----------------------------------------------------------------------===//2443 2444inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) {2445  assert(S.Current->getFunction());2446 2447  // FIXME: We iterate the scope once here and then again in the destroy() call2448  // below.2449  for (auto &Local : S.Current->getFunction()->getScope(I).locals_reverse()) {2450    const Pointer &Ptr = S.Current->getLocalPointer(Local.Offset);2451 2452    if (Ptr.getLifetime() == Lifetime::Ended) {2453      // Try to use the declaration for better diagnostics2454      if (const Decl *D = Ptr.getDeclDesc()->asDecl()) {2455        auto *ND = cast<NamedDecl>(D);2456        S.FFDiag(ND->getLocation(),2457                 diag::note_constexpr_destroy_out_of_lifetime)2458            << ND->getNameAsString();2459      } else {2460        S.FFDiag(Ptr.getDeclDesc()->getLocation(),2461                 diag::note_constexpr_destroy_out_of_lifetime)2462            << Ptr.toDiagnosticString(S.getASTContext());2463      }2464      return false;2465    }2466  }2467 2468  S.Current->destroy(I);2469  return true;2470}2471 2472inline bool InitScope(InterpState &S, CodePtr OpPC, uint32_t I) {2473  S.Current->initScope(I);2474  return true;2475}2476 2477inline bool EnableLocal(InterpState &S, CodePtr OpPC, uint32_t I) {2478  assert(!S.Current->isLocalEnabled(I));2479  S.Current->enableLocal(I);2480  return true;2481}2482 2483inline bool GetLocalEnabled(InterpState &S, CodePtr OpPC, uint32_t I) {2484  assert(S.Current);2485  S.Stk.push<bool>(S.Current->isLocalEnabled(I));2486  return true;2487}2488 2489//===----------------------------------------------------------------------===//2490// Cast, CastFP2491//===----------------------------------------------------------------------===//2492 2493template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) {2494  using T = typename PrimConv<TIn>::T;2495  using U = typename PrimConv<TOut>::T;2496  S.Stk.push<U>(U::from(S.Stk.pop<T>()));2497  return true;2498}2499 2500/// 1) Pops a Floating from the stack.2501/// 2) Pushes a new floating on the stack that uses the given semantics.2502inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem,2503                   llvm::RoundingMode RM) {2504  Floating F = S.Stk.pop<Floating>();2505  Floating Result = S.allocFloat(*Sem);2506  F.toSemantics(Sem, RM, &Result);2507  S.Stk.push<Floating>(Result);2508  return true;2509}2510 2511inline bool CastFixedPoint(InterpState &S, CodePtr OpPC, uint32_t FPS) {2512  FixedPointSemantics TargetSemantics =2513      FixedPointSemantics::getFromOpaqueInt(FPS);2514  const auto &Source = S.Stk.pop<FixedPoint>();2515 2516  bool Overflow;2517  FixedPoint Result = Source.toSemantics(TargetSemantics, &Overflow);2518 2519  if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2520    return false;2521 2522  S.Stk.push<FixedPoint>(Result);2523  return true;2524}2525 2526/// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need2527/// to know what bitwidth the result should be.2528template <PrimType Name, class T = typename PrimConv<Name>::T>2529bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2530  auto Result = S.allocAP<IntegralAP<false>>(BitWidth);2531  // Copy data.2532  {2533    APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);2534    Result.copy(Source);2535  }2536  S.Stk.push<IntegralAP<false>>(Result);2537  return true;2538}2539 2540template <PrimType Name, class T = typename PrimConv<Name>::T>2541bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2542  auto Result = S.allocAP<IntegralAP<true>>(BitWidth);2543  // Copy data.2544  {2545    APInt Source = S.Stk.pop<T>().toAPSInt().extOrTrunc(BitWidth);2546    Result.copy(Source);2547  }2548  S.Stk.push<IntegralAP<true>>(Result);2549  return true;2550}2551 2552template <PrimType Name, class T = typename PrimConv<Name>::T>2553bool CastIntegralFloating(InterpState &S, CodePtr OpPC,2554                          const llvm::fltSemantics *Sem, uint32_t FPOI) {2555  const T &From = S.Stk.pop<T>();2556  APSInt FromAP = From.toAPSInt();2557 2558  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2559  Floating Result = S.allocFloat(*Sem);2560  auto Status =2561      Floating::fromIntegral(FromAP, *Sem, getRoundingMode(FPO), &Result);2562  S.Stk.push<Floating>(Result);2563 2564  return CheckFloatResult(S, OpPC, Result, Status, FPO);2565}2566 2567template <PrimType Name, class T = typename PrimConv<Name>::T>2568bool CastFloatingIntegral(InterpState &S, CodePtr OpPC, uint32_t FPOI) {2569  const Floating &F = S.Stk.pop<Floating>();2570 2571  if constexpr (std::is_same_v<T, Boolean>) {2572    S.Stk.push<T>(T(F.isNonZero()));2573    return true;2574  } else {2575    APSInt Result(std::max(8u, T::bitWidth()),2576                  /*IsUnsigned=*/!T::isSigned());2577    auto Status = F.convertToInteger(Result);2578 2579    // Float-to-Integral overflow check.2580    if ((Status & APFloat::opStatus::opInvalidOp)) {2581      const Expr *E = S.Current->getExpr(OpPC);2582      QualType Type = E->getType();2583 2584      S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type;2585      if (S.noteUndefinedBehavior()) {2586        S.Stk.push<T>(T(Result));2587        return true;2588      }2589      return false;2590    }2591 2592    FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2593    S.Stk.push<T>(T(Result));2594    return CheckFloatResult(S, OpPC, F, Status, FPO);2595  }2596}2597 2598static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC,2599                                          uint32_t BitWidth, uint32_t FPOI) {2600  const Floating &F = S.Stk.pop<Floating>();2601 2602  APSInt Result(BitWidth, /*IsUnsigned=*/true);2603  auto Status = F.convertToInteger(Result);2604 2605  // Float-to-Integral overflow check.2606  if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())2607    return handleOverflow(S, OpPC, F.getAPFloat());2608 2609  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2610 2611  auto ResultAP = S.allocAP<IntegralAP<false>>(BitWidth);2612  ResultAP.copy(Result);2613 2614  S.Stk.push<IntegralAP<false>>(ResultAP);2615 2616  return CheckFloatResult(S, OpPC, F, Status, FPO);2617}2618 2619static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC,2620                                           uint32_t BitWidth, uint32_t FPOI) {2621  const Floating &F = S.Stk.pop<Floating>();2622 2623  APSInt Result(BitWidth, /*IsUnsigned=*/false);2624  auto Status = F.convertToInteger(Result);2625 2626  // Float-to-Integral overflow check.2627  if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite())2628    return handleOverflow(S, OpPC, F.getAPFloat());2629 2630  FPOptions FPO = FPOptions::getFromOpaqueInt(FPOI);2631 2632  auto ResultAP = S.allocAP<IntegralAP<true>>(BitWidth);2633  ResultAP.copy(Result);2634 2635  S.Stk.push<IntegralAP<true>>(ResultAP);2636 2637  return CheckFloatResult(S, OpPC, F, Status, FPO);2638}2639 2640bool CheckPointerToIntegralCast(InterpState &S, CodePtr OpPC,2641                                const Pointer &Ptr, unsigned BitWidth);2642bool CastPointerIntegralAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth);2643bool CastPointerIntegralAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth);2644 2645template <PrimType Name, class T = typename PrimConv<Name>::T>2646bool CastPointerIntegral(InterpState &S, CodePtr OpPC) {2647  const Pointer &Ptr = S.Stk.pop<Pointer>();2648 2649  if (!CheckPointerToIntegralCast(S, OpPC, Ptr, T::bitWidth()))2650    return Invalid(S, OpPC);2651 2652  S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation()));2653  return true;2654}2655 2656template <PrimType Name, class T = typename PrimConv<Name>::T>2657static inline bool CastIntegralFixedPoint(InterpState &S, CodePtr OpPC,2658                                          uint32_t FPS) {2659  const T &Int = S.Stk.pop<T>();2660 2661  FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);2662 2663  bool Overflow;2664  FixedPoint Result = FixedPoint::from(Int.toAPSInt(), Sem, &Overflow);2665 2666  if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2667    return false;2668 2669  S.Stk.push<FixedPoint>(Result);2670  return true;2671}2672 2673static inline bool CastFloatingFixedPoint(InterpState &S, CodePtr OpPC,2674                                          uint32_t FPS) {2675  const auto &Float = S.Stk.pop<Floating>();2676 2677  FixedPointSemantics Sem = FixedPointSemantics::getFromOpaqueInt(FPS);2678 2679  bool Overflow;2680  FixedPoint Result = FixedPoint::from(Float.getAPFloat(), Sem, &Overflow);2681 2682  if (Overflow && !handleFixedPointOverflow(S, OpPC, Result))2683    return false;2684 2685  S.Stk.push<FixedPoint>(Result);2686  return true;2687}2688 2689static inline bool CastFixedPointFloating(InterpState &S, CodePtr OpPC,2690                                          const llvm::fltSemantics *Sem) {2691  const auto &Fixed = S.Stk.pop<FixedPoint>();2692  Floating Result = S.allocFloat(*Sem);2693  Result.copy(Fixed.toFloat(Sem));2694  S.Stk.push<Floating>(Result);2695  return true;2696}2697 2698template <PrimType Name, class T = typename PrimConv<Name>::T>2699static inline bool CastFixedPointIntegral(InterpState &S, CodePtr OpPC) {2700  const auto &Fixed = S.Stk.pop<FixedPoint>();2701 2702  bool Overflow;2703  APSInt Int = Fixed.toInt(T::bitWidth(), T::isSigned(), &Overflow);2704 2705  if (Overflow && !handleOverflow(S, OpPC, Int))2706    return false;2707 2708  S.Stk.push<T>(Int);2709  return true;2710}2711 2712static inline bool FnPtrCast(InterpState &S, CodePtr OpPC) {2713  const SourceInfo &E = S.Current->getSource(OpPC);2714  S.CCEDiag(E, diag::note_constexpr_invalid_cast)2715      << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret2716      << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);2717  return true;2718}2719 2720static inline bool PtrPtrCast(InterpState &S, CodePtr OpPC, bool SrcIsVoidPtr) {2721  const auto &Ptr = S.Stk.peek<Pointer>();2722 2723  if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {2724    bool HasValidResult = !Ptr.isZero();2725 2726    if (HasValidResult) {2727      if (S.getStdAllocatorCaller("allocate"))2728        return true;2729 2730      const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));2731      if (S.getLangOpts().CPlusPlus26 &&2732          S.getASTContext().hasSimilarType(Ptr.getType(),2733                                           E->getType()->getPointeeType()))2734        return true;2735 2736      S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)2737          << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus262738          << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();2739    } else if (!S.getLangOpts().CPlusPlus26) {2740      const SourceInfo &E = S.Current->getSource(OpPC);2741      S.CCEDiag(E, diag::note_constexpr_invalid_cast)2742          << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"2743          << S.Current->getRange(OpPC);2744    }2745  } else {2746    const SourceInfo &E = S.Current->getSource(OpPC);2747    S.CCEDiag(E, diag::note_constexpr_invalid_cast)2748        << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret2749        << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);2750  }2751 2752  return true;2753}2754 2755//===----------------------------------------------------------------------===//2756// Zero, Nullptr2757//===----------------------------------------------------------------------===//2758 2759template <PrimType Name, class T = typename PrimConv<Name>::T>2760bool Zero(InterpState &S, CodePtr OpPC) {2761  S.Stk.push<T>(T::zero());2762  return true;2763}2764 2765static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2766  auto Result = S.allocAP<IntegralAP<false>>(BitWidth);2767  if (!Result.singleWord())2768    std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));2769  S.Stk.push<IntegralAP<false>>(Result);2770  return true;2771}2772 2773static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {2774  auto Result = S.allocAP<IntegralAP<true>>(BitWidth);2775  if (!Result.singleWord())2776    std::memset(Result.Memory, 0, Result.numWords() * sizeof(uint64_t));2777  S.Stk.push<IntegralAP<true>>(Result);2778  return true;2779}2780 2781template <PrimType Name, class T = typename PrimConv<Name>::T>2782inline bool Null(InterpState &S, CodePtr OpPC, uint64_t Value,2783                 const Descriptor *Desc) {2784  // FIXME(perf): This is a somewhat often-used function and the value of a2785  // null pointer is almost always 0.2786  S.Stk.push<T>(Value, Desc);2787  return true;2788}2789 2790template <PrimType Name, class T = typename PrimConv<Name>::T>2791inline bool IsNonNull(InterpState &S, CodePtr OpPC) {2792  const auto &P = S.Stk.pop<T>();2793  if (P.isWeak())2794    return false;2795  S.Stk.push<Boolean>(Boolean::from(!P.isZero()));2796  return true;2797}2798 2799//===----------------------------------------------------------------------===//2800// This, ImplicitThis2801//===----------------------------------------------------------------------===//2802 2803inline bool This(InterpState &S, CodePtr OpPC) {2804  // Cannot read 'this' in this mode.2805  if (S.checkingPotentialConstantExpression())2806    return false;2807  if (!CheckThis(S, OpPC))2808    return false;2809  const Pointer &This = S.Current->getThis();2810 2811  // Ensure the This pointer has been cast to the correct base.2812  if (!This.isDummy()) {2813    assert(isa<CXXMethodDecl>(S.Current->getFunction()->getDecl()));2814    if (!This.isTypeidPointer()) {2815      [[maybe_unused]] const Record *R = This.getRecord();2816      if (!R)2817        R = This.narrow().getRecord();2818      assert(R);2819      assert(R->getDecl() ==2820             cast<CXXMethodDecl>(S.Current->getFunction()->getDecl())2821                 ->getParent());2822    }2823  }2824 2825  S.Stk.push<Pointer>(This);2826  return true;2827}2828 2829inline bool RVOPtr(InterpState &S, CodePtr OpPC) {2830  assert(S.Current->getFunction()->hasRVO());2831  if (S.checkingPotentialConstantExpression())2832    return false;2833  S.Stk.push<Pointer>(S.Current->getRVOPtr());2834  return true;2835}2836 2837//===----------------------------------------------------------------------===//2838// Shr, Shl2839//===----------------------------------------------------------------------===//2840 2841template <class LT, class RT, ShiftDir Dir>2842inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS,2843                    LT *Result) {2844  static_assert(!needsAlloc<LT>());2845  const unsigned Bits = LHS.bitWidth();2846 2847  // OpenCL 6.3j: shift values are effectively % word size of LHS.2848  if (S.getLangOpts().OpenCL)2849    RT::bitAnd(RHS, RT::from(LHS.bitWidth() - 1, RHS.bitWidth()),2850               RHS.bitWidth(), &RHS);2851 2852  if (RHS.isNegative()) {2853    // During constant-folding, a negative shift is an opposite shift. Such a2854    // shift is not a constant expression.2855    const SourceInfo &Loc = S.Current->getSource(OpPC);2856    S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt();2857    if (!S.noteUndefinedBehavior())2858      return false;2859    RHS = -RHS;2860    return DoShift<LT, RT,2861                   Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(2862        S, OpPC, LHS, RHS, Result);2863  }2864 2865  if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))2866    return false;2867 2868  // Limit the shift amount to Bits - 1. If this happened,2869  // it has already been diagnosed by CheckShift() above,2870  // but we still need to handle it.2871  // Note that we have to be extra careful here since we're doing the shift in2872  // any case, but we need to adjust the shift amount or the way we do the shift2873  // for the potential error cases.2874  typename LT::AsUnsigned R;2875  unsigned MaxShiftAmount = LHS.bitWidth() - 1;2876  if constexpr (Dir == ShiftDir::Left) {2877    if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==2878        ComparisonCategoryResult::Greater) {2879      if (LHS.isNegative())2880        R = LT::AsUnsigned::zero(LHS.bitWidth());2881      else {2882        RHS = RT::from(LHS.countLeadingZeros(), RHS.bitWidth());2883        LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2884                                  LT::AsUnsigned::from(RHS, Bits), Bits, &R);2885      }2886    } else if (LHS.isNegative()) {2887      if (LHS.isMin()) {2888        R = LT::AsUnsigned::zero(LHS.bitWidth());2889      } else {2890        // If the LHS is negative, perform the cast and invert the result.2891        typename LT::AsUnsigned LHSU = LT::AsUnsigned::from(-LHS);2892        LT::AsUnsigned::shiftLeft(LHSU, LT::AsUnsigned::from(RHS, Bits), Bits,2893                                  &R);2894        R = -R;2895      }2896    } else {2897      // The good case, a simple left shift.2898      LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),2899                                LT::AsUnsigned::from(RHS, Bits), Bits, &R);2900    }2901    S.Stk.push<LT>(LT::from(R));2902    return true;2903  }2904 2905    // Right shift.2906    if (Compare(RHS, RT::from(MaxShiftAmount, RHS.bitWidth())) ==2907        ComparisonCategoryResult::Greater) {2908      R = LT::AsUnsigned::from(-1);2909    } else {2910      // Do the shift on potentially signed LT, then convert to unsigned type.2911      LT A;2912      LT::shiftRight(LHS, LT::from(RHS, Bits), Bits, &A);2913      R = LT::AsUnsigned::from(A);2914    }2915 2916  S.Stk.push<LT>(LT::from(R));2917  return true;2918}2919 2920/// A version of DoShift that works on IntegralAP.2921template <class LT, class RT, ShiftDir Dir>2922inline bool DoShiftAP(InterpState &S, CodePtr OpPC, const APSInt &LHS,2923                      APSInt RHS, LT *Result) {2924  const unsigned Bits = LHS.getBitWidth();2925 2926  // OpenCL 6.3j: shift values are effectively % word size of LHS.2927  if (S.getLangOpts().OpenCL)2928    RHS &=2929        APSInt(llvm::APInt(RHS.getBitWidth(), static_cast<uint64_t>(Bits - 1)),2930               RHS.isUnsigned());2931 2932  if (RHS.isNegative()) {2933    // During constant-folding, a negative shift is an opposite shift. Such a2934    // shift is not a constant expression.2935    const SourceInfo &Loc = S.Current->getSource(OpPC);2936    S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS; //.toAPSInt();2937    if (!S.noteUndefinedBehavior())2938      return false;2939    return DoShiftAP<LT, RT,2940                     Dir == ShiftDir::Left ? ShiftDir::Right : ShiftDir::Left>(2941        S, OpPC, LHS, -RHS, Result);2942  }2943 2944  if (!CheckShift<Dir>(S, OpPC, static_cast<LT>(LHS), static_cast<RT>(RHS),2945                       Bits))2946    return false;2947 2948  unsigned SA = (unsigned)RHS.getLimitedValue(Bits - 1);2949  if constexpr (Dir == ShiftDir::Left) {2950    if constexpr (needsAlloc<LT>())2951      Result->copy(LHS << SA);2952    else2953      *Result = LT(LHS << SA);2954  } else {2955    if constexpr (needsAlloc<LT>())2956      Result->copy(LHS >> SA);2957    else2958      *Result = LT(LHS >> SA);2959  }2960 2961  S.Stk.push<LT>(*Result);2962  return true;2963}2964 2965template <PrimType NameL, PrimType NameR>2966inline bool Shr(InterpState &S, CodePtr OpPC) {2967  using LT = typename PrimConv<NameL>::T;2968  using RT = typename PrimConv<NameR>::T;2969  auto RHS = S.Stk.pop<RT>();2970  auto LHS = S.Stk.pop<LT>();2971 2972  if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {2973    LT Result;2974    if constexpr (needsAlloc<LT>())2975      Result = S.allocAP<LT>(LHS.bitWidth());2976    return DoShiftAP<LT, RT, ShiftDir::Right>(S, OpPC, LHS.toAPSInt(),2977                                              RHS.toAPSInt(), &Result);2978  } else {2979    LT Result;2980    return DoShift<LT, RT, ShiftDir::Right>(S, OpPC, LHS, RHS, &Result);2981  }2982}2983 2984template <PrimType NameL, PrimType NameR>2985inline bool Shl(InterpState &S, CodePtr OpPC) {2986  using LT = typename PrimConv<NameL>::T;2987  using RT = typename PrimConv<NameR>::T;2988  auto RHS = S.Stk.pop<RT>();2989  auto LHS = S.Stk.pop<LT>();2990 2991  if constexpr (needsAlloc<LT>() || needsAlloc<RT>()) {2992    LT Result;2993    if constexpr (needsAlloc<LT>())2994      Result = S.allocAP<LT>(LHS.bitWidth());2995    return DoShiftAP<LT, RT, ShiftDir::Left>(S, OpPC, LHS.toAPSInt(),2996                                             RHS.toAPSInt(), &Result);2997  } else {2998    LT Result;2999    return DoShift<LT, RT, ShiftDir::Left>(S, OpPC, LHS, RHS, &Result);3000  }3001}3002 3003static inline bool ShiftFixedPoint(InterpState &S, CodePtr OpPC, bool Left) {3004  const auto &RHS = S.Stk.pop<FixedPoint>();3005  const auto &LHS = S.Stk.pop<FixedPoint>();3006  llvm::FixedPointSemantics LHSSema = LHS.getSemantics();3007 3008  unsigned ShiftBitWidth =3009      LHSSema.getWidth() - (unsigned)LHSSema.hasUnsignedPadding() - 1;3010 3011  // Embedded-C 4.1.6.2.2:3012  //   The right operand must be nonnegative and less than the total number3013  //   of (nonpadding) bits of the fixed-point operand ...3014  if (RHS.isNegative()) {3015    S.CCEDiag(S.Current->getLocation(OpPC), diag::note_constexpr_negative_shift)3016        << RHS.toAPSInt();3017  } else if (static_cast<unsigned>(RHS.toAPSInt().getLimitedValue(3018                 ShiftBitWidth)) != RHS.toAPSInt()) {3019    const Expr *E = S.Current->getExpr(OpPC);3020    S.CCEDiag(E, diag::note_constexpr_large_shift)3021        << RHS.toAPSInt() << E->getType() << ShiftBitWidth;3022  }3023 3024  FixedPoint Result;3025  if (Left) {3026    if (FixedPoint::shiftLeft(LHS, RHS, ShiftBitWidth, &Result) &&3027        !handleFixedPointOverflow(S, OpPC, Result))3028      return false;3029  } else {3030    if (FixedPoint::shiftRight(LHS, RHS, ShiftBitWidth, &Result) &&3031        !handleFixedPointOverflow(S, OpPC, Result))3032      return false;3033  }3034 3035  S.Stk.push<FixedPoint>(Result);3036  return true;3037}3038 3039//===----------------------------------------------------------------------===//3040// NoRet3041//===----------------------------------------------------------------------===//3042 3043inline bool NoRet(InterpState &S, CodePtr OpPC) {3044  SourceLocation EndLoc = S.Current->getCallee()->getEndLoc();3045  S.FFDiag(EndLoc, diag::note_constexpr_no_return);3046  return false;3047}3048 3049//===----------------------------------------------------------------------===//3050// NarrowPtr, ExpandPtr3051//===----------------------------------------------------------------------===//3052 3053inline bool NarrowPtr(InterpState &S, CodePtr OpPC) {3054  const Pointer &Ptr = S.Stk.pop<Pointer>();3055  S.Stk.push<Pointer>(Ptr.narrow());3056  return true;3057}3058 3059inline bool ExpandPtr(InterpState &S, CodePtr OpPC) {3060  const Pointer &Ptr = S.Stk.pop<Pointer>();3061  if (Ptr.isBlockPointer())3062    S.Stk.push<Pointer>(Ptr.expand());3063  else3064    S.Stk.push<Pointer>(Ptr);3065  return true;3066}3067 3068// 1) Pops an integral value from the stack3069// 2) Peeks a pointer3070// 3) Pushes a new pointer that's a narrowed array3071//   element of the peeked pointer with the value3072//   from 1) added as offset.3073//3074// This leaves the original pointer on the stack and pushes a new one3075// with the offset applied and narrowed.3076template <PrimType Name, class T = typename PrimConv<Name>::T>3077inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {3078  const T &Offset = S.Stk.pop<T>();3079  const Pointer &Ptr = S.Stk.peek<Pointer>();3080 3081  if (!Ptr.isZero() && !Offset.isZero()) {3082    if (!CheckArray(S, OpPC, Ptr))3083      return false;3084  }3085 3086  if (Offset.isZero()) {3087    if (const Descriptor *Desc = Ptr.getFieldDesc();3088        Desc && Desc->isArray() && Ptr.getIndex() == 0) {3089      S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());3090      return true;3091    }3092    S.Stk.push<Pointer>(Ptr.narrow());3093    return true;3094  }3095 3096  assert(!Offset.isZero());3097 3098  if (std::optional<Pointer> Result =3099          OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {3100    S.Stk.push<Pointer>(Result->narrow());3101    return true;3102  }3103 3104  return false;3105}3106 3107template <PrimType Name, class T = typename PrimConv<Name>::T>3108inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {3109  const T &Offset = S.Stk.pop<T>();3110  const Pointer &Ptr = S.Stk.pop<Pointer>();3111 3112  if (!Ptr.isZero() && !Offset.isZero()) {3113    if (!CheckArray(S, OpPC, Ptr))3114      return false;3115  }3116 3117  if (Offset.isZero()) {3118    if (const Descriptor *Desc = Ptr.getFieldDesc();3119        Desc && Desc->isArray() && Ptr.getIndex() == 0) {3120      S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());3121      return true;3122    }3123    S.Stk.push<Pointer>(Ptr.narrow());3124    return true;3125  }3126 3127  assert(!Offset.isZero());3128 3129  if (std::optional<Pointer> Result =3130          OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) {3131    S.Stk.push<Pointer>(Result->narrow());3132    return true;3133  }3134  return false;3135}3136 3137template <PrimType Name, class T = typename PrimConv<Name>::T>3138inline bool ArrayElem(InterpState &S, CodePtr OpPC, uint32_t Index) {3139  const Pointer &Ptr = S.Stk.peek<Pointer>();3140 3141  if (!CheckLoad(S, OpPC, Ptr))3142    return false;3143 3144  assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);3145  S.Stk.push<T>(Ptr.elem<T>(Index));3146  return true;3147}3148 3149template <PrimType Name, class T = typename PrimConv<Name>::T>3150inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) {3151  const Pointer &Ptr = S.Stk.pop<Pointer>();3152 3153  if (!CheckLoad(S, OpPC, Ptr))3154    return false;3155 3156  assert(Ptr.atIndex(Index).getFieldDesc()->getPrimType() == Name);3157  S.Stk.push<T>(Ptr.elem<T>(Index));3158  return true;3159}3160 3161template <PrimType Name, class T = typename PrimConv<Name>::T>3162inline bool CopyArray(InterpState &S, CodePtr OpPC, uint32_t SrcIndex,3163                      uint32_t DestIndex, uint32_t Size) {3164  const auto &SrcPtr = S.Stk.pop<Pointer>();3165  const auto &DestPtr = S.Stk.peek<Pointer>();3166 3167  if (SrcPtr.isDummy() || DestPtr.isDummy())3168    return false;3169 3170  for (uint32_t I = 0; I != Size; ++I) {3171    const Pointer &SP = SrcPtr.atIndex(SrcIndex + I);3172 3173    if (!CheckLoad(S, OpPC, SP))3174      return false;3175 3176    DestPtr.elem<T>(DestIndex + I) = SrcPtr.elem<T>(SrcIndex + I);3177    DestPtr.initializeElement(DestIndex + I);3178  }3179  return true;3180}3181 3182/// Just takes a pointer and checks if it's an incomplete3183/// array type.3184inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {3185  const Pointer &Ptr = S.Stk.pop<Pointer>();3186 3187  if (Ptr.isZero()) {3188    S.Stk.push<Pointer>(Ptr);3189    return true;3190  }3191 3192  if (!Ptr.isZeroSizeArray()) {3193    if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer))3194      return false;3195  }3196 3197  if (Ptr.isRoot() || !Ptr.isUnknownSizeArray()) {3198    S.Stk.push<Pointer>(Ptr.atIndex(0).narrow());3199    return true;3200  }3201 3202  const SourceInfo &E = S.Current->getSource(OpPC);3203  S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);3204 3205  return false;3206}3207 3208inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {3209  assert(Func);3210  S.Stk.push<Pointer>(Func);3211  return true;3212}3213 3214template <PrimType Name, class T = typename PrimConv<Name>::T>3215inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {3216  const T &IntVal = S.Stk.pop<T>();3217 3218  S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)3219      << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret3220      << S.getLangOpts().CPlusPlus;3221 3222  S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);3223  return true;3224}3225 3226inline bool GetMemberPtr(InterpState &S, CodePtr OpPC, const ValueDecl *D) {3227  S.Stk.push<MemberPointer>(D);3228  return true;3229}3230 3231inline bool GetMemberPtrBase(InterpState &S, CodePtr OpPC) {3232  const auto &MP = S.Stk.pop<MemberPointer>();3233 3234  if (!MP.isBaseCastPossible())3235    return false;3236 3237  S.Stk.push<Pointer>(MP.getBase());3238  return true;3239}3240 3241inline bool GetMemberPtrDecl(InterpState &S, CodePtr OpPC) {3242  const auto &MP = S.Stk.pop<MemberPointer>();3243 3244  const auto *FD = cast<FunctionDecl>(MP.getDecl());3245  const auto *Func = S.getContext().getOrCreateFunction(FD);3246 3247  S.Stk.push<Pointer>(Func);3248  return true;3249}3250 3251/// Just emit a diagnostic. The expression that caused emission of this3252/// op is not valid in a constant context.3253 3254inline bool Unsupported(InterpState &S, CodePtr OpPC) {3255  const SourceLocation &Loc = S.Current->getLocation(OpPC);3256  S.FFDiag(Loc, diag::note_constexpr_stmt_expr_unsupported)3257      << S.Current->getRange(OpPC);3258  return false;3259}3260 3261inline bool StartSpeculation(InterpState &S, CodePtr OpPC) {3262  ++S.SpeculationDepth;3263  if (S.SpeculationDepth != 1)3264    return true;3265 3266  assert(S.PrevDiags == nullptr);3267  S.PrevDiags = S.getEvalStatus().Diag;3268  S.getEvalStatus().Diag = nullptr;3269  return true;3270}3271inline bool EndSpeculation(InterpState &S, CodePtr OpPC) {3272  assert(S.SpeculationDepth != 0);3273  --S.SpeculationDepth;3274  if (S.SpeculationDepth == 0) {3275    S.getEvalStatus().Diag = S.PrevDiags;3276    S.PrevDiags = nullptr;3277  }3278  return true;3279}3280 3281inline bool PushCC(InterpState &S, CodePtr OpPC, bool Value) {3282  S.ConstantContextOverride = Value;3283  return true;3284}3285inline bool PopCC(InterpState &S, CodePtr OpPC) {3286  S.ConstantContextOverride = std::nullopt;3287  return true;3288}3289 3290/// Do nothing and just abort execution.3291inline bool Error(InterpState &S, CodePtr OpPC) { return false; }3292 3293inline bool SideEffect(InterpState &S, CodePtr OpPC) {3294  return S.noteSideEffect();3295}3296 3297inline bool CheckBitCast(InterpState &S, CodePtr OpPC, const Type *TargetType,3298                         bool SrcIsVoidPtr) {3299  const auto &Ptr = S.Stk.peek<Pointer>();3300  if (Ptr.isZero())3301    return true;3302  if (!Ptr.isBlockPointer())3303    return true;3304 3305  if (TargetType->isIntegerType())3306    return true;3307 3308  if (SrcIsVoidPtr && S.getLangOpts().CPlusPlus) {3309    bool HasValidResult = !Ptr.isZero();3310 3311    if (HasValidResult) {3312      if (S.getStdAllocatorCaller("allocate"))3313        return true;3314 3315      const auto &E = cast<CastExpr>(S.Current->getExpr(OpPC));3316      if (S.getLangOpts().CPlusPlus26 &&3317          S.getASTContext().hasSimilarType(Ptr.getType(),3318                                           QualType(TargetType, 0)))3319        return true;3320 3321      S.CCEDiag(E, diag::note_constexpr_invalid_void_star_cast)3322          << E->getSubExpr()->getType() << S.getLangOpts().CPlusPlus263323          << Ptr.getType().getCanonicalType() << E->getType()->getPointeeType();3324    } else if (!S.getLangOpts().CPlusPlus26) {3325      const SourceInfo &E = S.Current->getSource(OpPC);3326      S.CCEDiag(E, diag::note_constexpr_invalid_cast)3327          << diag::ConstexprInvalidCastKind::CastFrom << "'void *'"3328          << S.Current->getRange(OpPC);3329    }3330  }3331 3332  QualType PtrType = Ptr.getType();3333  if (PtrType->isRecordType() &&3334      PtrType->getAsRecordDecl() != TargetType->getAsRecordDecl()) {3335    S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_invalid_cast)3336        << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret3337        << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);3338    return false;3339  }3340  return true;3341}3342 3343/// Same here, but only for casts.3344inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind,3345                        bool Fatal) {3346  const SourceLocation &Loc = S.Current->getLocation(OpPC);3347 3348  switch (Kind) {3349  case CastKind::Reinterpret:3350    S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)3351        << diag::ConstexprInvalidCastKind::Reinterpret3352        << S.Current->getRange(OpPC);3353    return !Fatal;3354  case CastKind::ReinterpretLike:3355    S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)3356        << diag::ConstexprInvalidCastKind::ThisConversionOrReinterpret3357        << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC);3358    return !Fatal;3359  case CastKind::Volatile:3360    if (!S.checkingPotentialConstantExpression()) {3361      const auto *E = cast<CastExpr>(S.Current->getExpr(OpPC));3362      if (S.getLangOpts().CPlusPlus)3363        S.FFDiag(E, diag::note_constexpr_access_volatile_type)3364            << AK_Read << E->getSubExpr()->getType();3365      else3366        S.FFDiag(E);3367    }3368 3369    return false;3370  case CastKind::Dynamic:3371    assert(!S.getLangOpts().CPlusPlus20);3372    S.CCEDiag(Loc, diag::note_constexpr_invalid_cast)3373        << diag::ConstexprInvalidCastKind::Dynamic;3374    return true;3375  }3376  llvm_unreachable("Unhandled CastKind");3377  return false;3378}3379 3380inline bool InvalidStore(InterpState &S, CodePtr OpPC, const Type *T) {3381  if (S.getLangOpts().CPlusPlus) {3382    QualType VolatileType = QualType(T, 0).withVolatile();3383    S.FFDiag(S.Current->getSource(OpPC),3384             diag::note_constexpr_access_volatile_type)3385        << AK_Assign << VolatileType;3386  } else {3387    S.FFDiag(S.Current->getSource(OpPC));3388  }3389  return false;3390}3391 3392inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR,3393                           bool InitializerFailed) {3394  assert(DR);3395 3396  if (InitializerFailed) {3397    const SourceInfo &Loc = S.Current->getSource(OpPC);3398    const auto *VD = cast<VarDecl>(DR->getDecl());3399    S.FFDiag(Loc, diag::note_constexpr_var_init_non_constant, 1) << VD;3400    S.Note(VD->getLocation(), diag::note_declared_at);3401    return false;3402  }3403 3404  return CheckDeclRef(S, OpPC, DR);3405}3406 3407inline bool SizelessVectorElementSize(InterpState &S, CodePtr OpPC) {3408  if (S.inConstantContext()) {3409    const SourceRange &ArgRange = S.Current->getRange(OpPC);3410    const Expr *E = S.Current->getExpr(OpPC);3411    S.CCEDiag(E, diag::note_constexpr_non_const_vectorelements) << ArgRange;3412  }3413  return false;3414}3415 3416inline bool CheckPseudoDtor(InterpState &S, CodePtr OpPC) {3417  if (!S.getLangOpts().CPlusPlus20)3418    S.CCEDiag(S.Current->getSource(OpPC),3419              diag::note_constexpr_pseudo_destructor);3420  return true;3421}3422 3423inline bool Assume(InterpState &S, CodePtr OpPC) {3424  const auto Val = S.Stk.pop<Boolean>();3425 3426  if (Val)3427    return true;3428 3429  // Else, diagnose.3430  const SourceLocation &Loc = S.Current->getLocation(OpPC);3431  S.CCEDiag(Loc, diag::note_constexpr_assumption_failed);3432  return false;3433}3434 3435template <PrimType Name, class T = typename PrimConv<Name>::T>3436inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {3437  llvm::SmallVector<int64_t> ArrayIndices;3438  for (size_t I = 0; I != E->getNumExpressions(); ++I)3439    ArrayIndices.emplace_back(S.Stk.pop<int64_t>());3440 3441  int64_t Result;3442  if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result))3443    return false;3444 3445  S.Stk.push<T>(T::from(Result));3446 3447  return true;3448}3449 3450template <PrimType Name, class T = typename PrimConv<Name>::T>3451inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {3452  const T &Arg = S.Stk.peek<T>();3453  if (!Arg.isZero())3454    return true;3455 3456  const SourceLocation &Loc = S.Current->getLocation(OpPC);3457  S.CCEDiag(Loc, diag::note_non_null_attribute_failed);3458 3459  return false;3460}3461 3462void diagnoseEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED,3463                       const APSInt &Value);3464 3465template <PrimType Name, class T = typename PrimConv<Name>::T>3466inline bool CheckEnumValue(InterpState &S, CodePtr OpPC, const EnumDecl *ED) {3467  assert(ED);3468  assert(!ED->isFixed());3469 3470  if (S.inConstantContext()) {3471    const APSInt Val = S.Stk.peek<T>().toAPSInt();3472    diagnoseEnumValue(S, OpPC, ED, Val);3473  }3474  return true;3475}3476 3477/// OldPtr -> Integer -> NewPtr.3478template <PrimType TIn, PrimType TOut>3479inline bool DecayPtr(InterpState &S, CodePtr OpPC) {3480  static_assert(isPtrType(TIn) && isPtrType(TOut));3481  using FromT = typename PrimConv<TIn>::T;3482  using ToT = typename PrimConv<TOut>::T;3483 3484  const FromT &OldPtr = S.Stk.pop<FromT>();3485 3486  if constexpr (std::is_same_v<FromT, FunctionPointer> &&3487                std::is_same_v<ToT, Pointer>) {3488    S.Stk.push<Pointer>(OldPtr.getFunction(), OldPtr.getOffset());3489    return true;3490  } else if constexpr (std::is_same_v<FromT, Pointer> &&3491                       std::is_same_v<ToT, FunctionPointer>) {3492    if (OldPtr.isFunctionPointer()) {3493      S.Stk.push<FunctionPointer>(OldPtr.asFunctionPointer().getFunction(),3494                                  OldPtr.getByteOffset());3495      return true;3496    }3497  }3498 3499  S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));3500  return true;3501}3502 3503inline bool CheckDecl(InterpState &S, CodePtr OpPC, const VarDecl *VD) {3504  // An expression E is a core constant expression unless the evaluation of E3505  // would evaluate one of the following: [C++23] - a control flow that passes3506  // through a declaration of a variable with static or thread storage duration3507  // unless that variable is usable in constant expressions.3508  assert(VD->isLocalVarDecl() &&3509         VD->isStaticLocal()); // Checked before emitting this.3510 3511  if (VD == S.EvaluatingDecl)3512    return true;3513 3514  if (!VD->isUsableInConstantExpressions(S.getASTContext())) {3515    S.CCEDiag(VD->getLocation(), diag::note_constexpr_static_local)3516        << (VD->getTSCSpec() == TSCS_unspecified ? 0 : 1) << VD;3517    return false;3518  }3519  return true;3520}3521 3522inline bool Alloc(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {3523  assert(Desc);3524 3525  if (!CheckDynamicMemoryAllocation(S, OpPC))3526    return false;3527 3528  DynamicAllocator &Allocator = S.getAllocator();3529  Block *B = Allocator.allocate(Desc, S.Ctx.getEvalID(),3530                                DynamicAllocator::Form::NonArray);3531  assert(B);3532  S.Stk.push<Pointer>(B);3533  return true;3534}3535 3536template <PrimType Name, class SizeT = typename PrimConv<Name>::T>3537inline bool AllocN(InterpState &S, CodePtr OpPC, PrimType T, const Expr *Source,3538                   bool IsNoThrow) {3539  if (!CheckDynamicMemoryAllocation(S, OpPC))3540    return false;3541 3542  SizeT NumElements = S.Stk.pop<SizeT>();3543  if (!CheckArraySize(S, OpPC, &NumElements, primSize(T), IsNoThrow)) {3544    if (!IsNoThrow)3545      return false;3546 3547    // If this failed and is nothrow, just return a null ptr.3548    S.Stk.push<Pointer>(0, nullptr);3549    return true;3550  }3551  if (NumElements.isNegative()) {3552    if (!IsNoThrow) {3553      S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_new_negative)3554          << NumElements.toDiagnosticString(S.getASTContext());3555      return false;3556    }3557    S.Stk.push<Pointer>(0, nullptr);3558    return true;3559  }3560 3561  if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))3562    return false;3563 3564  DynamicAllocator &Allocator = S.getAllocator();3565  Block *B =3566      Allocator.allocate(Source, T, static_cast<size_t>(NumElements),3567                         S.Ctx.getEvalID(), DynamicAllocator::Form::Array);3568  assert(B);3569  if (NumElements.isZero())3570    S.Stk.push<Pointer>(B);3571  else3572    S.Stk.push<Pointer>(Pointer(B).atIndex(0));3573  return true;3574}3575 3576template <PrimType Name, class SizeT = typename PrimConv<Name>::T>3577inline bool AllocCN(InterpState &S, CodePtr OpPC, const Descriptor *ElementDesc,3578                    bool IsNoThrow) {3579  if (!CheckDynamicMemoryAllocation(S, OpPC))3580    return false;3581 3582  if (!ElementDesc)3583    return false;3584 3585  SizeT NumElements = S.Stk.pop<SizeT>();3586  if (!CheckArraySize(S, OpPC, &NumElements, ElementDesc->getSize(),3587                      IsNoThrow)) {3588    if (!IsNoThrow)3589      return false;3590 3591    // If this failed and is nothrow, just return a null ptr.3592    S.Stk.push<Pointer>(0, ElementDesc);3593    return true;3594  }3595  assert(NumElements.isPositive());3596 3597  if (!CheckArraySize(S, OpPC, static_cast<uint64_t>(NumElements)))3598    return false;3599 3600  DynamicAllocator &Allocator = S.getAllocator();3601  Block *B =3602      Allocator.allocate(ElementDesc, static_cast<size_t>(NumElements),3603                         S.Ctx.getEvalID(), DynamicAllocator::Form::Array);3604  assert(B);3605  if (NumElements.isZero())3606    S.Stk.push<Pointer>(B);3607  else3608    S.Stk.push<Pointer>(Pointer(B).atIndex(0));3609 3610  return true;3611}3612 3613bool Free(InterpState &S, CodePtr OpPC, bool DeleteIsArrayForm,3614          bool IsGlobalDelete);3615 3616static inline bool IsConstantContext(InterpState &S, CodePtr OpPC) {3617  S.Stk.push<Boolean>(Boolean::from(S.inConstantContext()));3618  return true;3619}3620 3621static inline bool CheckAllocations(InterpState &S, CodePtr OpPC) {3622  return S.maybeDiagnoseDanglingAllocations();3623}3624 3625/// Check if the initializer and storage types of a placement-new expression3626/// match.3627bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, const Expr *E,3628                          std::optional<uint64_t> ArraySize = std::nullopt);3629 3630template <PrimType Name, class T = typename PrimConv<Name>::T>3631bool CheckNewTypeMismatchArray(InterpState &S, CodePtr OpPC, const Expr *E) {3632  const auto &Size = S.Stk.pop<T>();3633  return CheckNewTypeMismatch(S, OpPC, E, static_cast<uint64_t>(Size));3634}3635bool InvalidNewDeleteExpr(InterpState &S, CodePtr OpPC, const Expr *E);3636 3637template <PrimType Name, class T = typename PrimConv<Name>::T>3638inline bool BitCastPrim(InterpState &S, CodePtr OpPC, bool TargetIsUCharOrByte,3639                        uint32_t ResultBitWidth, const llvm::fltSemantics *Sem,3640                        const Type *TargetType) {3641  const Pointer &FromPtr = S.Stk.pop<Pointer>();3642 3643  if (!CheckLoad(S, OpPC, FromPtr))3644    return false;3645 3646  if constexpr (std::is_same_v<T, Pointer>) {3647    if (!TargetType->isNullPtrType()) {3648      S.FFDiag(S.Current->getSource(OpPC),3649               diag::note_constexpr_bit_cast_invalid_type)3650          << /*IsToType=*/true << /*IsReference=*/false << 1 /*Pointer*/;3651      return false;3652    }3653    // The only pointer type we can validly bitcast to is nullptr_t.3654    S.Stk.push<Pointer>();3655    return true;3656  } else if constexpr (std::is_same_v<T, MemberPointer>) {3657    S.FFDiag(S.Current->getSource(OpPC),3658             diag::note_constexpr_bit_cast_invalid_type)3659        << /*IsToType=*/true << /*IsReference=*/false << 2 /*MemberPointer*/;3660    return false;3661  } else {3662 3663    size_t BuffSize = ResultBitWidth / 8;3664    llvm::SmallVector<std::byte> Buff(BuffSize);3665    bool HasIndeterminateBits = false;3666 3667    Bits FullBitWidth(ResultBitWidth);3668    Bits BitWidth = FullBitWidth;3669 3670    if constexpr (std::is_same_v<T, Floating>) {3671      assert(Sem);3672      BitWidth = Bits(llvm::APFloatBase::getSizeInBits(*Sem));3673    }3674 3675    if (!DoBitCast(S, OpPC, FromPtr, Buff.data(), BitWidth, FullBitWidth,3676                   HasIndeterminateBits))3677      return false;3678 3679    if (!CheckBitCast(S, OpPC, HasIndeterminateBits, TargetIsUCharOrByte))3680      return false;3681 3682    if constexpr (std::is_same_v<T, Floating>) {3683      assert(Sem);3684      Floating Result = S.allocFloat(*Sem);3685      Floating::bitcastFromMemory(Buff.data(), *Sem, &Result);3686      S.Stk.push<Floating>(Result);3687    } else if constexpr (needsAlloc<T>()) {3688      T Result = S.allocAP<T>(ResultBitWidth);3689      T::bitcastFromMemory(Buff.data(), ResultBitWidth, &Result);3690      S.Stk.push<T>(Result);3691    } else if constexpr (std::is_same_v<T, Boolean>) {3692      // Only allow to cast single-byte integers to bool if they are either 03693      // or 1.3694      assert(FullBitWidth.getQuantity() == 8);3695      auto Val = static_cast<unsigned int>(Buff[0]);3696      if (Val > 1) {3697        S.FFDiag(S.Current->getSource(OpPC),3698                 diag::note_constexpr_bit_cast_unrepresentable_value)3699            << S.getASTContext().BoolTy << Val;3700        return false;3701      }3702      S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));3703    } else {3704      assert(!Sem);3705      S.Stk.push<T>(T::bitcastFromMemory(Buff.data(), ResultBitWidth));3706    }3707    return true;3708  }3709}3710 3711inline bool BitCast(InterpState &S, CodePtr OpPC) {3712  const Pointer &FromPtr = S.Stk.pop<Pointer>();3713  Pointer &ToPtr = S.Stk.peek<Pointer>();3714 3715  if (!CheckLoad(S, OpPC, FromPtr))3716    return false;3717 3718  if (!DoBitCastPtr(S, OpPC, FromPtr, ToPtr))3719    return false;3720 3721  return true;3722}3723 3724/// Typeid support.3725bool GetTypeid(InterpState &S, CodePtr OpPC, const Type *TypePtr,3726               const Type *TypeInfoType);3727bool GetTypeidPtr(InterpState &S, CodePtr OpPC, const Type *TypeInfoType);3728bool DiagTypeid(InterpState &S, CodePtr OpPC);3729 3730inline bool CheckDestruction(InterpState &S, CodePtr OpPC) {3731  const auto &Ptr = S.Stk.peek<Pointer>();3732  return CheckDestructor(S, OpPC, Ptr);3733}3734 3735//===----------------------------------------------------------------------===//3736// Read opcode arguments3737//===----------------------------------------------------------------------===//3738 3739template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) {3740  if constexpr (std::is_pointer<T>::value) {3741    uint32_t ID = OpPC.read<uint32_t>();3742    return reinterpret_cast<T>(S.P.getNativePointer(ID));3743  } else {3744    return OpPC.read<T>();3745  }3746}3747 3748template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) {3749  auto &Semantics =3750      llvm::APFloatBase::EnumToSemantics(Floating::deserializeSemantics(*OpPC));3751 3752  auto F = S.allocFloat(Semantics);3753  Floating::deserialize(*OpPC, &F);3754  OpPC += align(F.bytesToSerialize());3755  return F;3756}3757 3758template <>3759inline IntegralAP<false> ReadArg<IntegralAP<false>>(InterpState &S,3760                                                    CodePtr &OpPC) {3761  uint32_t BitWidth = IntegralAP<false>::deserializeSize(*OpPC);3762  auto Result = S.allocAP<IntegralAP<false>>(BitWidth);3763  assert(Result.bitWidth() == BitWidth);3764 3765  IntegralAP<false>::deserialize(*OpPC, &Result);3766  OpPC += align(Result.bytesToSerialize());3767  return Result;3768}3769 3770template <>3771inline IntegralAP<true> ReadArg<IntegralAP<true>>(InterpState &S,3772                                                  CodePtr &OpPC) {3773  uint32_t BitWidth = IntegralAP<true>::deserializeSize(*OpPC);3774  auto Result = S.allocAP<IntegralAP<true>>(BitWidth);3775  assert(Result.bitWidth() == BitWidth);3776 3777  IntegralAP<true>::deserialize(*OpPC, &Result);3778  OpPC += align(Result.bytesToSerialize());3779  return Result;3780}3781 3782template <>3783inline FixedPoint ReadArg<FixedPoint>(InterpState &S, CodePtr &OpPC) {3784  FixedPoint FP = FixedPoint::deserialize(*OpPC);3785  OpPC += align(FP.bytesToSerialize());3786  return FP;3787}3788 3789} // namespace interp3790} // namespace clang3791 3792#endif3793