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