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