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