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