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 "Boolean.h" 17 #include "Floating.h" 18 #include "Function.h" 19 #include "FunctionPointer.h" 20 #include "InterpFrame.h" 21 #include "InterpStack.h" 22 #include "InterpState.h" 23 #include "Opcode.h" 24 #include "PrimType.h" 25 #include "Program.h" 26 #include "State.h" 27 #include "clang/AST/ASTContext.h" 28 #include "clang/AST/ASTDiagnostic.h" 29 #include "clang/AST/CXXInheritance.h" 30 #include "clang/AST/Expr.h" 31 #include "llvm/ADT/APFloat.h" 32 #include "llvm/ADT/APSInt.h" 33 #include "llvm/Support/Endian.h" 34 #include <limits> 35 #include <type_traits> 36 37 namespace clang { 38 namespace interp { 39 40 using APSInt = llvm::APSInt; 41 42 /// Convert a value to an APValue. 43 template <typename T> bool ReturnValue(const T &V, APValue &R) { 44 R = V.toAPValue(); 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 61 /// Checks if a pointer is null. 62 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 63 CheckSubobjectKind CSK); 64 65 /// Checks if a pointer is in range. 66 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 67 AccessKinds AK); 68 69 /// Checks if a field from which a pointer is going to be derived is valid. 70 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 71 CheckSubobjectKind CSK); 72 73 /// Checks if Ptr is a one-past-the-end pointer. 74 bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 75 CheckSubobjectKind CSK); 76 77 /// Checks if a pointer points to const storage. 78 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 79 80 /// Checks if the Descriptor is of a constexpr or const global variable. 81 bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc); 82 83 /// Checks if a pointer points to a mutable field. 84 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 85 86 /// Checks if a value can be loaded from a block. 87 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 88 89 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 90 AccessKinds AK); 91 92 /// Checks if a value can be stored in a block. 93 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 94 95 /// Checks if a method can be invoked on an object. 96 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 97 98 /// Checks if a value can be initialized. 99 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 100 101 /// Checks if a method can be called. 102 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F); 103 104 /// Checks if calling the currently active function would exceed 105 /// the allowed call depth. 106 bool CheckCallDepth(InterpState &S, CodePtr OpPC); 107 108 /// Checks the 'this' pointer. 109 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 110 111 /// Checks if a method is pure virtual. 112 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 113 114 /// Checks if reinterpret casts are legal in the current context. 115 bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, 116 const Pointer &Ptr); 117 118 /// Sets the given integral value to the pointer, which is of 119 /// a std::{weak,partial,strong}_ordering type. 120 bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC, 121 const Pointer &Ptr, const APSInt &IntValue); 122 123 /// Checks if the shift operation is legal. 124 template <typename LT, typename RT> 125 bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, 126 unsigned Bits) { 127 if (RHS.isNegative()) { 128 const SourceInfo &Loc = S.Current->getSource(OpPC); 129 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 130 return false; 131 } 132 133 // C++11 [expr.shift]p1: Shift width must be less than the bit width of 134 // the shifted type. 135 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { 136 const Expr *E = S.Current->getExpr(OpPC); 137 const APSInt Val = RHS.toAPSInt(); 138 QualType Ty = E->getType(); 139 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; 140 return false; 141 } 142 143 if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) { 144 const Expr *E = S.Current->getExpr(OpPC); 145 // C++11 [expr.shift]p2: A signed left shift must have a non-negative 146 // operand, and must not overflow the corresponding unsigned type. 147 if (LHS.isNegative()) 148 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); 149 else if (LHS.toUnsigned().countLeadingZeros() < static_cast<unsigned>(RHS)) 150 S.CCEDiag(E, diag::note_constexpr_lshift_discards); 151 } 152 153 // C++2a [expr.shift]p2: [P0907R4]: 154 // E1 << E2 is the unique value congruent to 155 // E1 x 2^E2 module 2^N. 156 return true; 157 } 158 159 /// Checks if Div/Rem operation on LHS and RHS is valid. 160 template <typename T> 161 bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { 162 if (RHS.isZero()) { 163 const auto *Op = cast<BinaryOperator>(S.Current->getExpr(OpPC)); 164 S.FFDiag(Op, diag::note_expr_divide_by_zero) 165 << Op->getRHS()->getSourceRange(); 166 return false; 167 } 168 169 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { 170 APSInt LHSInt = LHS.toAPSInt(); 171 SmallString<32> Trunc; 172 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); 173 const SourceInfo &Loc = S.Current->getSource(OpPC); 174 const Expr *E = S.Current->getExpr(OpPC); 175 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); 176 return false; 177 } 178 return true; 179 } 180 181 /// Checks if the result of a floating-point operation is valid 182 /// in the current context. 183 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, 184 APFloat::opStatus Status); 185 186 /// Checks why the given DeclRefExpr is invalid. 187 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR); 188 189 /// Interpreter entry point. 190 bool Interpret(InterpState &S, APValue &Result); 191 192 /// Interpret a builtin function. 193 bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F, 194 const CallExpr *Call); 195 196 /// Interpret an offsetof operation. 197 bool InterpretOffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E, 198 llvm::ArrayRef<int64_t> ArrayIndices, int64_t &Result); 199 200 enum class ArithOp { Add, Sub }; 201 202 //===----------------------------------------------------------------------===// 203 // Returning values 204 //===----------------------------------------------------------------------===// 205 206 void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC); 207 208 template <PrimType Name, class T = typename PrimConv<Name>::T> 209 bool Ret(InterpState &S, CodePtr &PC, APValue &Result) { 210 const T &Ret = S.Stk.pop<T>(); 211 212 // Make sure returned pointers are live. We might be trying to return a 213 // pointer or reference to a local variable. 214 // Just return false, since a diagnostic has already been emitted in Sema. 215 if constexpr (std::is_same_v<T, Pointer>) { 216 // FIXME: We could be calling isLive() here, but the emitted diagnostics 217 // seem a little weird, at least if the returned expression is of 218 // pointer type. 219 // Null pointers are considered live here. 220 if (!Ret.isZero() && !Ret.isLive()) 221 return false; 222 } 223 224 assert(S.Current); 225 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 226 if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 227 cleanupAfterFunctionCall(S, PC); 228 229 if (InterpFrame *Caller = S.Current->Caller) { 230 PC = S.Current->getRetPC(); 231 delete S.Current; 232 S.Current = Caller; 233 S.Stk.push<T>(Ret); 234 } else { 235 delete S.Current; 236 S.Current = nullptr; 237 if (!ReturnValue<T>(Ret, Result)) 238 return false; 239 } 240 return true; 241 } 242 243 inline bool RetVoid(InterpState &S, CodePtr &PC, APValue &Result) { 244 assert(S.Current->getFrameOffset() == S.Stk.size() && "Invalid frame"); 245 246 if (!S.checkingPotentialConstantExpression() || S.Current->Caller) 247 cleanupAfterFunctionCall(S, PC); 248 249 if (InterpFrame *Caller = S.Current->Caller) { 250 PC = S.Current->getRetPC(); 251 delete S.Current; 252 S.Current = Caller; 253 } else { 254 delete S.Current; 255 S.Current = nullptr; 256 } 257 return true; 258 } 259 260 //===----------------------------------------------------------------------===// 261 // Add, Sub, Mul 262 //===----------------------------------------------------------------------===// 263 264 template <typename T, bool (*OpFW)(T, T, unsigned, T *), 265 template <typename U> class OpAP> 266 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, 267 const T &RHS) { 268 // Fast path - add the numbers with fixed width. 269 T Result; 270 if (!OpFW(LHS, RHS, Bits, &Result)) { 271 S.Stk.push<T>(Result); 272 return true; 273 } 274 275 // If for some reason evaluation continues, use the truncated results. 276 S.Stk.push<T>(Result); 277 278 // Slow path - compute the result using another bit of precision. 279 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); 280 281 // Report undefined behaviour, stopping if required. 282 const Expr *E = S.Current->getExpr(OpPC); 283 QualType Type = E->getType(); 284 if (S.checkingForUndefinedBehavior()) { 285 SmallString<32> Trunc; 286 Value.trunc(Result.bitWidth()).toString(Trunc, 10); 287 auto Loc = E->getExprLoc(); 288 S.report(Loc, diag::warn_integer_constant_overflow) 289 << Trunc << Type << E->getSourceRange(); 290 return true; 291 } else { 292 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 293 if (!S.noteUndefinedBehavior()) { 294 S.Stk.pop<T>(); 295 return false; 296 } 297 return true; 298 } 299 } 300 301 template <PrimType Name, class T = typename PrimConv<Name>::T> 302 bool Add(InterpState &S, CodePtr OpPC) { 303 const T &RHS = S.Stk.pop<T>(); 304 const T &LHS = S.Stk.pop<T>(); 305 const unsigned Bits = RHS.bitWidth() + 1; 306 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); 307 } 308 309 inline bool Addf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 310 const Floating &RHS = S.Stk.pop<Floating>(); 311 const Floating &LHS = S.Stk.pop<Floating>(); 312 313 Floating Result; 314 auto Status = Floating::add(LHS, RHS, RM, &Result); 315 S.Stk.push<Floating>(Result); 316 return CheckFloatResult(S, OpPC, Result, Status); 317 } 318 319 template <PrimType Name, class T = typename PrimConv<Name>::T> 320 bool Sub(InterpState &S, CodePtr OpPC) { 321 const T &RHS = S.Stk.pop<T>(); 322 const T &LHS = S.Stk.pop<T>(); 323 const unsigned Bits = RHS.bitWidth() + 1; 324 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); 325 } 326 327 inline bool Subf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 328 const Floating &RHS = S.Stk.pop<Floating>(); 329 const Floating &LHS = S.Stk.pop<Floating>(); 330 331 Floating Result; 332 auto Status = Floating::sub(LHS, RHS, RM, &Result); 333 S.Stk.push<Floating>(Result); 334 return CheckFloatResult(S, OpPC, Result, Status); 335 } 336 337 template <PrimType Name, class T = typename PrimConv<Name>::T> 338 bool Mul(InterpState &S, CodePtr OpPC) { 339 const T &RHS = S.Stk.pop<T>(); 340 const T &LHS = S.Stk.pop<T>(); 341 const unsigned Bits = RHS.bitWidth() * 2; 342 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); 343 } 344 345 inline bool Mulf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 346 const Floating &RHS = S.Stk.pop<Floating>(); 347 const Floating &LHS = S.Stk.pop<Floating>(); 348 349 Floating Result; 350 auto Status = Floating::mul(LHS, RHS, RM, &Result); 351 S.Stk.push<Floating>(Result); 352 return CheckFloatResult(S, OpPC, Result, Status); 353 } 354 /// 1) Pops the RHS from the stack. 355 /// 2) Pops the LHS from the stack. 356 /// 3) Pushes 'LHS & RHS' on the stack 357 template <PrimType Name, class T = typename PrimConv<Name>::T> 358 bool BitAnd(InterpState &S, CodePtr OpPC) { 359 const T &RHS = S.Stk.pop<T>(); 360 const T &LHS = S.Stk.pop<T>(); 361 362 unsigned Bits = RHS.bitWidth(); 363 T Result; 364 if (!T::bitAnd(LHS, RHS, Bits, &Result)) { 365 S.Stk.push<T>(Result); 366 return true; 367 } 368 return false; 369 } 370 371 /// 1) Pops the RHS from the stack. 372 /// 2) Pops the LHS from the stack. 373 /// 3) Pushes 'LHS | RHS' on the stack 374 template <PrimType Name, class T = typename PrimConv<Name>::T> 375 bool BitOr(InterpState &S, CodePtr OpPC) { 376 const T &RHS = S.Stk.pop<T>(); 377 const T &LHS = S.Stk.pop<T>(); 378 379 unsigned Bits = RHS.bitWidth(); 380 T Result; 381 if (!T::bitOr(LHS, RHS, Bits, &Result)) { 382 S.Stk.push<T>(Result); 383 return true; 384 } 385 return false; 386 } 387 388 /// 1) Pops the RHS from the stack. 389 /// 2) Pops the LHS from the stack. 390 /// 3) Pushes 'LHS ^ RHS' on the stack 391 template <PrimType Name, class T = typename PrimConv<Name>::T> 392 bool BitXor(InterpState &S, CodePtr OpPC) { 393 const T &RHS = S.Stk.pop<T>(); 394 const T &LHS = S.Stk.pop<T>(); 395 396 unsigned Bits = RHS.bitWidth(); 397 T Result; 398 if (!T::bitXor(LHS, RHS, Bits, &Result)) { 399 S.Stk.push<T>(Result); 400 return true; 401 } 402 return false; 403 } 404 405 /// 1) Pops the RHS from the stack. 406 /// 2) Pops the LHS from the stack. 407 /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS). 408 template <PrimType Name, class T = typename PrimConv<Name>::T> 409 bool Rem(InterpState &S, CodePtr OpPC) { 410 const T &RHS = S.Stk.pop<T>(); 411 const T &LHS = S.Stk.pop<T>(); 412 413 if (!CheckDivRem(S, OpPC, LHS, RHS)) 414 return false; 415 416 const unsigned Bits = RHS.bitWidth() * 2; 417 T Result; 418 if (!T::rem(LHS, RHS, Bits, &Result)) { 419 S.Stk.push<T>(Result); 420 return true; 421 } 422 return false; 423 } 424 425 /// 1) Pops the RHS from the stack. 426 /// 2) Pops the LHS from the stack. 427 /// 3) Pushes 'LHS / RHS' on the stack 428 template <PrimType Name, class T = typename PrimConv<Name>::T> 429 bool Div(InterpState &S, CodePtr OpPC) { 430 const T &RHS = S.Stk.pop<T>(); 431 const T &LHS = S.Stk.pop<T>(); 432 433 if (!CheckDivRem(S, OpPC, LHS, RHS)) 434 return false; 435 436 const unsigned Bits = RHS.bitWidth() * 2; 437 T Result; 438 if (!T::div(LHS, RHS, Bits, &Result)) { 439 S.Stk.push<T>(Result); 440 return true; 441 } 442 return false; 443 } 444 445 inline bool Divf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 446 const Floating &RHS = S.Stk.pop<Floating>(); 447 const Floating &LHS = S.Stk.pop<Floating>(); 448 449 if (!CheckDivRem(S, OpPC, LHS, RHS)) 450 return false; 451 452 Floating Result; 453 auto Status = Floating::div(LHS, RHS, RM, &Result); 454 S.Stk.push<Floating>(Result); 455 return CheckFloatResult(S, OpPC, Result, Status); 456 } 457 458 //===----------------------------------------------------------------------===// 459 // Inv 460 //===----------------------------------------------------------------------===// 461 462 template <PrimType Name, class T = typename PrimConv<Name>::T> 463 bool Inv(InterpState &S, CodePtr OpPC) { 464 using BoolT = PrimConv<PT_Bool>::T; 465 const T &Val = S.Stk.pop<T>(); 466 const unsigned Bits = Val.bitWidth(); 467 Boolean R; 468 Boolean::inv(BoolT::from(Val, Bits), &R); 469 470 S.Stk.push<BoolT>(R); 471 return true; 472 } 473 474 //===----------------------------------------------------------------------===// 475 // Neg 476 //===----------------------------------------------------------------------===// 477 478 template <PrimType Name, class T = typename PrimConv<Name>::T> 479 bool Neg(InterpState &S, CodePtr OpPC) { 480 const T &Value = S.Stk.pop<T>(); 481 T Result; 482 483 if (!T::neg(Value, &Result)) { 484 S.Stk.push<T>(Result); 485 return true; 486 } 487 488 assert(isIntegralType(Name) && 489 "don't expect other types to fail at constexpr negation"); 490 S.Stk.push<T>(Result); 491 492 APSInt NegatedValue = -Value.toAPSInt(Value.bitWidth() + 1); 493 const Expr *E = S.Current->getExpr(OpPC); 494 QualType Type = E->getType(); 495 496 if (S.checkingForUndefinedBehavior()) { 497 SmallString<32> Trunc; 498 NegatedValue.trunc(Result.bitWidth()).toString(Trunc, 10); 499 auto Loc = E->getExprLoc(); 500 S.report(Loc, diag::warn_integer_constant_overflow) 501 << Trunc << Type << E->getSourceRange(); 502 return true; 503 } 504 505 S.CCEDiag(E, diag::note_constexpr_overflow) << NegatedValue << Type; 506 return S.noteUndefinedBehavior(); 507 } 508 509 enum class PushVal : bool { 510 No, 511 Yes, 512 }; 513 enum class IncDecOp { 514 Inc, 515 Dec, 516 }; 517 518 template <typename T, IncDecOp Op, PushVal DoPush> 519 bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 520 const T &Value = Ptr.deref<T>(); 521 T Result; 522 523 if constexpr (DoPush == PushVal::Yes) 524 S.Stk.push<T>(Value); 525 526 if constexpr (Op == IncDecOp::Inc) { 527 if (!T::increment(Value, &Result)) { 528 Ptr.deref<T>() = Result; 529 return true; 530 } 531 } else { 532 if (!T::decrement(Value, &Result)) { 533 Ptr.deref<T>() = Result; 534 return true; 535 } 536 } 537 538 // Something went wrong with the previous operation. Compute the 539 // result with another bit of precision. 540 unsigned Bits = Value.bitWidth() + 1; 541 APSInt APResult; 542 if constexpr (Op == IncDecOp::Inc) 543 APResult = ++Value.toAPSInt(Bits); 544 else 545 APResult = --Value.toAPSInt(Bits); 546 547 // Report undefined behaviour, stopping if required. 548 const Expr *E = S.Current->getExpr(OpPC); 549 QualType Type = E->getType(); 550 if (S.checkingForUndefinedBehavior()) { 551 SmallString<32> Trunc; 552 APResult.trunc(Result.bitWidth()).toString(Trunc, 10); 553 auto Loc = E->getExprLoc(); 554 S.report(Loc, diag::warn_integer_constant_overflow) 555 << Trunc << Type << E->getSourceRange(); 556 return true; 557 } 558 559 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type; 560 return S.noteUndefinedBehavior(); 561 } 562 563 /// 1) Pops a pointer from the stack 564 /// 2) Load the value from the pointer 565 /// 3) Writes the value increased by one back to the pointer 566 /// 4) Pushes the original (pre-inc) value on the stack. 567 template <PrimType Name, class T = typename PrimConv<Name>::T> 568 bool Inc(InterpState &S, CodePtr OpPC) { 569 const Pointer &Ptr = S.Stk.pop<Pointer>(); 570 571 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 572 return false; 573 574 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr); 575 } 576 577 /// 1) Pops a pointer from the stack 578 /// 2) Load the value from the pointer 579 /// 3) Writes the value increased by one back to the pointer 580 template <PrimType Name, class T = typename PrimConv<Name>::T> 581 bool IncPop(InterpState &S, CodePtr OpPC) { 582 const Pointer &Ptr = S.Stk.pop<Pointer>(); 583 584 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 585 return false; 586 587 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr); 588 } 589 590 /// 1) Pops a pointer from the stack 591 /// 2) Load the value from the pointer 592 /// 3) Writes the value decreased by one back to the pointer 593 /// 4) Pushes the original (pre-dec) value on the stack. 594 template <PrimType Name, class T = typename PrimConv<Name>::T> 595 bool Dec(InterpState &S, CodePtr OpPC) { 596 const Pointer &Ptr = S.Stk.pop<Pointer>(); 597 598 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 599 return false; 600 601 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr); 602 } 603 604 /// 1) Pops a pointer from the stack 605 /// 2) Load the value from the pointer 606 /// 3) Writes the value decreased by one back to the pointer 607 template <PrimType Name, class T = typename PrimConv<Name>::T> 608 bool DecPop(InterpState &S, CodePtr OpPC) { 609 const Pointer &Ptr = S.Stk.pop<Pointer>(); 610 611 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 612 return false; 613 614 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr); 615 } 616 617 template <IncDecOp Op, PushVal DoPush> 618 bool IncDecFloatHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 619 llvm::RoundingMode RM) { 620 Floating Value = Ptr.deref<Floating>(); 621 Floating Result; 622 623 if constexpr (DoPush == PushVal::Yes) 624 S.Stk.push<Floating>(Value); 625 626 llvm::APFloat::opStatus Status; 627 if constexpr (Op == IncDecOp::Inc) 628 Status = Floating::increment(Value, RM, &Result); 629 else 630 Status = Floating::decrement(Value, RM, &Result); 631 632 Ptr.deref<Floating>() = Result; 633 634 return CheckFloatResult(S, OpPC, Result, Status); 635 } 636 637 inline bool Incf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 638 const Pointer &Ptr = S.Stk.pop<Pointer>(); 639 640 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 641 return false; 642 643 return IncDecFloatHelper<IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr, RM); 644 } 645 646 inline bool IncfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 647 const Pointer &Ptr = S.Stk.pop<Pointer>(); 648 649 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 650 return false; 651 652 return IncDecFloatHelper<IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr, RM); 653 } 654 655 inline bool Decf(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 656 const Pointer &Ptr = S.Stk.pop<Pointer>(); 657 658 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 659 return false; 660 661 return IncDecFloatHelper<IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr, RM); 662 } 663 664 inline bool DecfPop(InterpState &S, CodePtr OpPC, llvm::RoundingMode RM) { 665 const Pointer &Ptr = S.Stk.pop<Pointer>(); 666 667 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 668 return false; 669 670 return IncDecFloatHelper<IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr, RM); 671 } 672 673 /// 1) Pops the value from the stack. 674 /// 2) Pushes the bitwise complemented value on the stack (~V). 675 template <PrimType Name, class T = typename PrimConv<Name>::T> 676 bool Comp(InterpState &S, CodePtr OpPC) { 677 const T &Val = S.Stk.pop<T>(); 678 T Result; 679 if (!T::comp(Val, &Result)) { 680 S.Stk.push<T>(Result); 681 return true; 682 } 683 684 return false; 685 } 686 687 //===----------------------------------------------------------------------===// 688 // EQ, NE, GT, GE, LT, LE 689 //===----------------------------------------------------------------------===// 690 691 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; 692 693 template <typename T> 694 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { 695 using BoolT = PrimConv<PT_Bool>::T; 696 const T &RHS = S.Stk.pop<T>(); 697 const T &LHS = S.Stk.pop<T>(); 698 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); 699 return true; 700 } 701 702 template <typename T> 703 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { 704 return CmpHelper<T>(S, OpPC, Fn); 705 } 706 707 /// Function pointers cannot be compared in an ordered way. 708 template <> 709 inline bool CmpHelper<FunctionPointer>(InterpState &S, CodePtr OpPC, 710 CompareFn Fn) { 711 const auto &RHS = S.Stk.pop<FunctionPointer>(); 712 const auto &LHS = S.Stk.pop<FunctionPointer>(); 713 714 const SourceInfo &Loc = S.Current->getSource(OpPC); 715 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 716 << LHS.toDiagnosticString(S.getCtx()) 717 << RHS.toDiagnosticString(S.getCtx()); 718 return false; 719 } 720 721 template <> 722 inline bool CmpHelperEQ<FunctionPointer>(InterpState &S, CodePtr OpPC, 723 CompareFn Fn) { 724 const auto &RHS = S.Stk.pop<FunctionPointer>(); 725 const auto &LHS = S.Stk.pop<FunctionPointer>(); 726 S.Stk.push<Boolean>(Boolean::from(Fn(LHS.compare(RHS)))); 727 return true; 728 } 729 730 template <> 731 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 732 using BoolT = PrimConv<PT_Bool>::T; 733 const Pointer &RHS = S.Stk.pop<Pointer>(); 734 const Pointer &LHS = S.Stk.pop<Pointer>(); 735 736 if (!Pointer::hasSameBase(LHS, RHS)) { 737 const SourceInfo &Loc = S.Current->getSource(OpPC); 738 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 739 << LHS.toDiagnosticString(S.getCtx()) 740 << RHS.toDiagnosticString(S.getCtx()); 741 return false; 742 } else { 743 unsigned VL = LHS.getByteOffset(); 744 unsigned VR = RHS.getByteOffset(); 745 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 746 return true; 747 } 748 } 749 750 template <> 751 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 752 using BoolT = PrimConv<PT_Bool>::T; 753 const Pointer &RHS = S.Stk.pop<Pointer>(); 754 const Pointer &LHS = S.Stk.pop<Pointer>(); 755 756 if (LHS.isZero() && RHS.isZero()) { 757 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); 758 return true; 759 } 760 761 if (!Pointer::hasSameBase(LHS, RHS)) { 762 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); 763 return true; 764 } else { 765 unsigned VL = LHS.getByteOffset(); 766 unsigned VR = RHS.getByteOffset(); 767 768 // In our Pointer class, a pointer to an array and a pointer to the first 769 // element in the same array are NOT equal. They have the same Base value, 770 // but a different Offset. This is a pretty rare case, so we fix this here 771 // by comparing pointers to the first elements. 772 if (LHS.isArrayRoot()) 773 VL = LHS.atIndex(0).getByteOffset(); 774 if (RHS.isArrayRoot()) 775 VR = RHS.atIndex(0).getByteOffset(); 776 777 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 778 return true; 779 } 780 } 781 782 template <PrimType Name, class T = typename PrimConv<Name>::T> 783 bool EQ(InterpState &S, CodePtr OpPC) { 784 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 785 return R == ComparisonCategoryResult::Equal; 786 }); 787 } 788 789 template <PrimType Name, class T = typename PrimConv<Name>::T> 790 bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) { 791 const T &RHS = S.Stk.pop<T>(); 792 const T &LHS = S.Stk.pop<T>(); 793 const Pointer &P = S.Stk.peek<Pointer>(); 794 795 ComparisonCategoryResult CmpResult = LHS.compare(RHS); 796 if (CmpResult == ComparisonCategoryResult::Unordered) { 797 // This should only happen with pointers. 798 const SourceInfo &Loc = S.Current->getSource(OpPC); 799 S.FFDiag(Loc, diag::note_constexpr_pointer_comparison_unspecified) 800 << LHS.toDiagnosticString(S.getCtx()) 801 << RHS.toDiagnosticString(S.getCtx()); 802 return false; 803 } 804 805 assert(CmpInfo); 806 const auto *CmpValueInfo = CmpInfo->getValueInfo(CmpResult); 807 assert(CmpValueInfo); 808 assert(CmpValueInfo->hasValidIntValue()); 809 APSInt IntValue = CmpValueInfo->getIntValue(); 810 return SetThreeWayComparisonField(S, OpPC, P, IntValue); 811 } 812 813 template <PrimType Name, class T = typename PrimConv<Name>::T> 814 bool NE(InterpState &S, CodePtr OpPC) { 815 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 816 return R != ComparisonCategoryResult::Equal; 817 }); 818 } 819 820 template <PrimType Name, class T = typename PrimConv<Name>::T> 821 bool LT(InterpState &S, CodePtr OpPC) { 822 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 823 return R == ComparisonCategoryResult::Less; 824 }); 825 } 826 827 template <PrimType Name, class T = typename PrimConv<Name>::T> 828 bool LE(InterpState &S, CodePtr OpPC) { 829 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 830 return R == ComparisonCategoryResult::Less || 831 R == ComparisonCategoryResult::Equal; 832 }); 833 } 834 835 template <PrimType Name, class T = typename PrimConv<Name>::T> 836 bool GT(InterpState &S, CodePtr OpPC) { 837 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 838 return R == ComparisonCategoryResult::Greater; 839 }); 840 } 841 842 template <PrimType Name, class T = typename PrimConv<Name>::T> 843 bool GE(InterpState &S, CodePtr OpPC) { 844 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 845 return R == ComparisonCategoryResult::Greater || 846 R == ComparisonCategoryResult::Equal; 847 }); 848 } 849 850 //===----------------------------------------------------------------------===// 851 // InRange 852 //===----------------------------------------------------------------------===// 853 854 template <PrimType Name, class T = typename PrimConv<Name>::T> 855 bool InRange(InterpState &S, CodePtr OpPC) { 856 const T RHS = S.Stk.pop<T>(); 857 const T LHS = S.Stk.pop<T>(); 858 const T Value = S.Stk.pop<T>(); 859 860 S.Stk.push<bool>(LHS <= Value && Value <= RHS); 861 return true; 862 } 863 864 //===----------------------------------------------------------------------===// 865 // Dup, Pop, Test 866 //===----------------------------------------------------------------------===// 867 868 template <PrimType Name, class T = typename PrimConv<Name>::T> 869 bool Dup(InterpState &S, CodePtr OpPC) { 870 S.Stk.push<T>(S.Stk.peek<T>()); 871 return true; 872 } 873 874 template <PrimType Name, class T = typename PrimConv<Name>::T> 875 bool Pop(InterpState &S, CodePtr OpPC) { 876 S.Stk.pop<T>(); 877 return true; 878 } 879 880 //===----------------------------------------------------------------------===// 881 // Const 882 //===----------------------------------------------------------------------===// 883 884 template <PrimType Name, class T = typename PrimConv<Name>::T> 885 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { 886 S.Stk.push<T>(Arg); 887 return true; 888 } 889 890 //===----------------------------------------------------------------------===// 891 // Get/Set Local/Param/Global/This 892 //===----------------------------------------------------------------------===// 893 894 template <PrimType Name, class T = typename PrimConv<Name>::T> 895 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 896 const Pointer &Ptr = S.Current->getLocalPointer(I); 897 if (!CheckLoad(S, OpPC, Ptr)) 898 return false; 899 S.Stk.push<T>(Ptr.deref<T>()); 900 return true; 901 } 902 903 /// 1) Pops the value from the stack. 904 /// 2) Writes the value to the local variable with the 905 /// given offset. 906 template <PrimType Name, class T = typename PrimConv<Name>::T> 907 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 908 S.Current->setLocal<T>(I, S.Stk.pop<T>()); 909 return true; 910 } 911 912 template <PrimType Name, class T = typename PrimConv<Name>::T> 913 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 914 if (S.checkingPotentialConstantExpression()) { 915 return false; 916 } 917 S.Stk.push<T>(S.Current->getParam<T>(I)); 918 return true; 919 } 920 921 template <PrimType Name, class T = typename PrimConv<Name>::T> 922 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 923 S.Current->setParam<T>(I, S.Stk.pop<T>()); 924 return true; 925 } 926 927 /// 1) Peeks a pointer on the stack 928 /// 2) Pushes the value of the pointer's field on the stack 929 template <PrimType Name, class T = typename PrimConv<Name>::T> 930 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { 931 const Pointer &Obj = S.Stk.peek<Pointer>(); 932 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 933 return false; 934 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 935 return false; 936 const Pointer &Field = Obj.atField(I); 937 if (!CheckLoad(S, OpPC, Field)) 938 return false; 939 S.Stk.push<T>(Field.deref<T>()); 940 return true; 941 } 942 943 template <PrimType Name, class T = typename PrimConv<Name>::T> 944 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { 945 const T &Value = S.Stk.pop<T>(); 946 const Pointer &Obj = S.Stk.peek<Pointer>(); 947 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 948 return false; 949 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 950 return false; 951 const Pointer &Field = Obj.atField(I); 952 if (!CheckStore(S, OpPC, Field)) 953 return false; 954 Field.initialize(); 955 Field.deref<T>() = Value; 956 return true; 957 } 958 959 /// 1) Pops a pointer from the stack 960 /// 2) Pushes the value of the pointer's field on the stack 961 template <PrimType Name, class T = typename PrimConv<Name>::T> 962 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { 963 const Pointer &Obj = S.Stk.pop<Pointer>(); 964 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 965 return false; 966 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 967 return false; 968 const Pointer &Field = Obj.atField(I); 969 if (!CheckLoad(S, OpPC, Field)) 970 return false; 971 S.Stk.push<T>(Field.deref<T>()); 972 return true; 973 } 974 975 template <PrimType Name, class T = typename PrimConv<Name>::T> 976 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 977 if (S.checkingPotentialConstantExpression()) 978 return false; 979 const Pointer &This = S.Current->getThis(); 980 if (!CheckThis(S, OpPC, This)) 981 return false; 982 const Pointer &Field = This.atField(I); 983 if (!CheckLoad(S, OpPC, Field)) 984 return false; 985 S.Stk.push<T>(Field.deref<T>()); 986 return true; 987 } 988 989 template <PrimType Name, class T = typename PrimConv<Name>::T> 990 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 991 if (S.checkingPotentialConstantExpression()) 992 return false; 993 const T &Value = S.Stk.pop<T>(); 994 const Pointer &This = S.Current->getThis(); 995 if (!CheckThis(S, OpPC, This)) 996 return false; 997 const Pointer &Field = This.atField(I); 998 if (!CheckStore(S, OpPC, Field)) 999 return false; 1000 Field.deref<T>() = Value; 1001 return true; 1002 } 1003 1004 template <PrimType Name, class T = typename PrimConv<Name>::T> 1005 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1006 const Block *B = S.P.getGlobal(I); 1007 1008 if (!CheckConstant(S, OpPC, B->getDescriptor())) 1009 return false; 1010 if (B->isExtern()) 1011 return false; 1012 S.Stk.push<T>(B->deref<T>()); 1013 return true; 1014 } 1015 1016 /// Same as GetGlobal, but without the checks. 1017 template <PrimType Name, class T = typename PrimConv<Name>::T> 1018 bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, uint32_t I) { 1019 auto *B = S.P.getGlobal(I); 1020 S.Stk.push<T>(B->deref<T>()); 1021 return true; 1022 } 1023 1024 template <PrimType Name, class T = typename PrimConv<Name>::T> 1025 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1026 // TODO: emit warning. 1027 return false; 1028 } 1029 1030 template <PrimType Name, class T = typename PrimConv<Name>::T> 1031 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1032 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 1033 return true; 1034 } 1035 1036 /// 1) Converts the value on top of the stack to an APValue 1037 /// 2) Sets that APValue on \Temp 1038 /// 3) Initialized global with index \I with that 1039 template <PrimType Name, class T = typename PrimConv<Name>::T> 1040 bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, 1041 const LifetimeExtendedTemporaryDecl *Temp) { 1042 assert(Temp); 1043 const T Value = S.Stk.peek<T>(); 1044 APValue APV = Value.toAPValue(); 1045 APValue *Cached = Temp->getOrCreateValue(true); 1046 *Cached = APV; 1047 1048 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 1049 return true; 1050 } 1051 1052 /// 1) Converts the value on top of the stack to an APValue 1053 /// 2) Sets that APValue on \Temp 1054 /// 3) Initialized global with index \I with that 1055 inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, 1056 const LifetimeExtendedTemporaryDecl *Temp) { 1057 assert(Temp); 1058 const Pointer &P = S.Stk.peek<Pointer>(); 1059 APValue *Cached = Temp->getOrCreateValue(true); 1060 1061 if (std::optional<APValue> APV = P.toRValue(S.getCtx())) { 1062 *Cached = *APV; 1063 return true; 1064 } 1065 1066 return false; 1067 } 1068 1069 template <PrimType Name, class T = typename PrimConv<Name>::T> 1070 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1071 if (S.checkingPotentialConstantExpression()) 1072 return false; 1073 const Pointer &This = S.Current->getThis(); 1074 if (!CheckThis(S, OpPC, This)) 1075 return false; 1076 const Pointer &Field = This.atField(I); 1077 Field.deref<T>() = S.Stk.pop<T>(); 1078 Field.initialize(); 1079 return true; 1080 } 1081 1082 // FIXME: The Field pointer here is too much IMO and we could instead just 1083 // pass an Offset + BitWidth pair. 1084 template <PrimType Name, class T = typename PrimConv<Name>::T> 1085 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F, 1086 uint32_t FieldOffset) { 1087 assert(F->isBitField()); 1088 if (S.checkingPotentialConstantExpression()) 1089 return false; 1090 const Pointer &This = S.Current->getThis(); 1091 if (!CheckThis(S, OpPC, This)) 1092 return false; 1093 const Pointer &Field = This.atField(FieldOffset); 1094 const auto &Value = S.Stk.pop<T>(); 1095 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1096 Field.initialize(); 1097 return true; 1098 } 1099 1100 template <PrimType Name, class T = typename PrimConv<Name>::T> 1101 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1102 if (S.checkingPotentialConstantExpression()) 1103 return false; 1104 const Pointer &This = S.Current->getThis(); 1105 if (!CheckThis(S, OpPC, This)) 1106 return false; 1107 const Pointer &Field = This.atField(I); 1108 Field.deref<T>() = S.Stk.pop<T>(); 1109 Field.activate(); 1110 Field.initialize(); 1111 return true; 1112 } 1113 1114 /// 1) Pops the value from the stack 1115 /// 2) Peeks a pointer from the stack 1116 /// 3) Pushes the value to field I of the pointer on the stack 1117 template <PrimType Name, class T = typename PrimConv<Name>::T> 1118 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 1119 const T &Value = S.Stk.pop<T>(); 1120 const Pointer &Field = S.Stk.peek<Pointer>().atField(I); 1121 Field.deref<T>() = Value; 1122 Field.activate(); 1123 Field.initialize(); 1124 return true; 1125 } 1126 1127 template <PrimType Name, class T = typename PrimConv<Name>::T> 1128 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 1129 assert(F->isBitField()); 1130 const T &Value = S.Stk.pop<T>(); 1131 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); 1132 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1133 Field.activate(); 1134 Field.initialize(); 1135 return true; 1136 } 1137 1138 template <PrimType Name, class T = typename PrimConv<Name>::T> 1139 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1140 const T &Value = S.Stk.pop<T>(); 1141 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1142 const Pointer &Field = Ptr.atField(I); 1143 Field.deref<T>() = Value; 1144 Field.activate(); 1145 Field.initialize(); 1146 return true; 1147 } 1148 1149 //===----------------------------------------------------------------------===// 1150 // GetPtr Local/Param/Global/Field/This 1151 //===----------------------------------------------------------------------===// 1152 1153 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1154 S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 1155 return true; 1156 } 1157 1158 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1159 if (S.checkingPotentialConstantExpression()) { 1160 return false; 1161 } 1162 S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 1163 return true; 1164 } 1165 1166 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1167 S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 1168 return true; 1169 } 1170 1171 /// 1) Pops a Pointer from the stack 1172 /// 2) Pushes Pointer.atField(Off) on the stack 1173 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1174 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1175 if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field)) 1176 return false; 1177 if (!CheckExtern(S, OpPC, Ptr)) 1178 return false; 1179 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1180 return false; 1181 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) 1182 return false; 1183 1184 S.Stk.push<Pointer>(Ptr.atField(Off)); 1185 return true; 1186 } 1187 1188 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1189 if (S.checkingPotentialConstantExpression()) 1190 return false; 1191 const Pointer &This = S.Current->getThis(); 1192 if (!CheckThis(S, OpPC, This)) 1193 return false; 1194 S.Stk.push<Pointer>(This.atField(Off)); 1195 return true; 1196 } 1197 1198 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1199 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1200 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 1201 return false; 1202 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1203 return false; 1204 Pointer Field = Ptr.atField(Off); 1205 Ptr.deactivate(); 1206 Field.activate(); 1207 S.Stk.push<Pointer>(std::move(Field)); 1208 return true; 1209 } 1210 1211 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1212 if (S.checkingPotentialConstantExpression()) 1213 return false; 1214 const Pointer &This = S.Current->getThis(); 1215 if (!CheckThis(S, OpPC, This)) 1216 return false; 1217 Pointer Field = This.atField(Off); 1218 This.deactivate(); 1219 Field.activate(); 1220 S.Stk.push<Pointer>(std::move(Field)); 1221 return true; 1222 } 1223 1224 inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1225 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1226 if (!CheckNull(S, OpPC, Ptr, CSK_Derived)) 1227 return false; 1228 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived)) 1229 return false; 1230 S.Stk.push<Pointer>(Ptr.atFieldSub(Off)); 1231 return true; 1232 } 1233 1234 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1235 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1236 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1237 return false; 1238 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1239 return false; 1240 S.Stk.push<Pointer>(Ptr.atField(Off)); 1241 return true; 1242 } 1243 1244 inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1245 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1246 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1247 return false; 1248 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1249 return false; 1250 S.Stk.push<Pointer>(Ptr.atField(Off)); 1251 return true; 1252 } 1253 1254 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1255 if (S.checkingPotentialConstantExpression()) 1256 return false; 1257 const Pointer &This = S.Current->getThis(); 1258 if (!CheckThis(S, OpPC, This)) 1259 return false; 1260 S.Stk.push<Pointer>(This.atField(Off)); 1261 return true; 1262 } 1263 1264 inline bool InitPtrPop(InterpState &S, CodePtr OpPC) { 1265 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1266 Ptr.initialize(); 1267 return true; 1268 } 1269 1270 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 1271 const Pointer &Ptr) { 1272 Pointer Base = Ptr; 1273 while (Base.isBaseClass()) 1274 Base = Base.getBase(); 1275 1276 auto *Field = Base.getRecord()->getVirtualBase(Decl); 1277 S.Stk.push<Pointer>(Base.atField(Field->Offset)); 1278 return true; 1279 } 1280 1281 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { 1282 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1283 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1284 return false; 1285 return VirtBaseHelper(S, OpPC, D, Ptr); 1286 } 1287 1288 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 1289 const RecordDecl *D) { 1290 if (S.checkingPotentialConstantExpression()) 1291 return false; 1292 const Pointer &This = S.Current->getThis(); 1293 if (!CheckThis(S, OpPC, This)) 1294 return false; 1295 return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 1296 } 1297 1298 //===----------------------------------------------------------------------===// 1299 // Load, Store, Init 1300 //===----------------------------------------------------------------------===// 1301 1302 template <PrimType Name, class T = typename PrimConv<Name>::T> 1303 bool Load(InterpState &S, CodePtr OpPC) { 1304 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1305 if (!CheckLoad(S, OpPC, Ptr)) 1306 return false; 1307 S.Stk.push<T>(Ptr.deref<T>()); 1308 return true; 1309 } 1310 1311 template <PrimType Name, class T = typename PrimConv<Name>::T> 1312 bool LoadPop(InterpState &S, CodePtr OpPC) { 1313 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1314 if (!CheckLoad(S, OpPC, Ptr)) 1315 return false; 1316 S.Stk.push<T>(Ptr.deref<T>()); 1317 return true; 1318 } 1319 1320 template <PrimType Name, class T = typename PrimConv<Name>::T> 1321 bool Store(InterpState &S, CodePtr OpPC) { 1322 const T &Value = S.Stk.pop<T>(); 1323 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1324 if (!CheckStore(S, OpPC, Ptr)) 1325 return false; 1326 if (!Ptr.isRoot()) 1327 Ptr.initialize(); 1328 Ptr.deref<T>() = Value; 1329 return true; 1330 } 1331 1332 template <PrimType Name, class T = typename PrimConv<Name>::T> 1333 bool StorePop(InterpState &S, CodePtr OpPC) { 1334 const T &Value = S.Stk.pop<T>(); 1335 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1336 if (!CheckStore(S, OpPC, Ptr)) 1337 return false; 1338 if (!Ptr.isRoot()) 1339 Ptr.initialize(); 1340 Ptr.deref<T>() = Value; 1341 return true; 1342 } 1343 1344 template <PrimType Name, class T = typename PrimConv<Name>::T> 1345 bool StoreBitField(InterpState &S, CodePtr OpPC) { 1346 const T &Value = S.Stk.pop<T>(); 1347 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1348 if (!CheckStore(S, OpPC, Ptr)) 1349 return false; 1350 if (!Ptr.isRoot()) 1351 Ptr.initialize(); 1352 if (const auto *FD = Ptr.getField()) 1353 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 1354 else 1355 Ptr.deref<T>() = Value; 1356 return true; 1357 } 1358 1359 template <PrimType Name, class T = typename PrimConv<Name>::T> 1360 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 1361 const T &Value = S.Stk.pop<T>(); 1362 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1363 if (!CheckStore(S, OpPC, Ptr)) 1364 return false; 1365 if (!Ptr.isRoot()) 1366 Ptr.initialize(); 1367 if (const auto *FD = Ptr.getField()) 1368 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 1369 else 1370 Ptr.deref<T>() = Value; 1371 return true; 1372 } 1373 1374 template <PrimType Name, class T = typename PrimConv<Name>::T> 1375 bool InitPop(InterpState &S, CodePtr OpPC) { 1376 const T &Value = S.Stk.pop<T>(); 1377 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1378 if (!CheckInit(S, OpPC, Ptr)) 1379 return false; 1380 Ptr.initialize(); 1381 new (&Ptr.deref<T>()) T(Value); 1382 return true; 1383 } 1384 1385 /// 1) Pops the value from the stack 1386 /// 2) Peeks a pointer and gets its index \Idx 1387 /// 3) Sets the value on the pointer, leaving the pointer on the stack. 1388 template <PrimType Name, class T = typename PrimConv<Name>::T> 1389 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1390 const T &Value = S.Stk.pop<T>(); 1391 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx); 1392 if (!CheckInit(S, OpPC, Ptr)) 1393 return false; 1394 Ptr.initialize(); 1395 new (&Ptr.deref<T>()) T(Value); 1396 return true; 1397 } 1398 1399 /// The same as InitElem, but pops the pointer as well. 1400 template <PrimType Name, class T = typename PrimConv<Name>::T> 1401 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1402 const T &Value = S.Stk.pop<T>(); 1403 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx); 1404 if (!CheckInit(S, OpPC, Ptr)) 1405 return false; 1406 Ptr.initialize(); 1407 new (&Ptr.deref<T>()) T(Value); 1408 return true; 1409 } 1410 1411 //===----------------------------------------------------------------------===// 1412 // AddOffset, SubOffset 1413 //===----------------------------------------------------------------------===// 1414 1415 template <class T, ArithOp Op> 1416 bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, 1417 const Pointer &Ptr) { 1418 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 1419 return false; 1420 1421 // A zero offset does not change the pointer. 1422 if (Offset.isZero()) { 1423 S.Stk.push<Pointer>(Ptr); 1424 return true; 1425 } 1426 1427 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) 1428 return false; 1429 1430 // Arrays of unknown bounds cannot have pointers into them. 1431 if (!CheckArray(S, OpPC, Ptr)) 1432 return false; 1433 1434 // Get a version of the index comparable to the type. 1435 T Index = T::from(Ptr.getIndex(), Offset.bitWidth()); 1436 // Compute the largest index into the array. 1437 T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth()); 1438 1439 bool Invalid = false; 1440 // Helper to report an invalid offset, computed as APSInt. 1441 auto DiagInvalidOffset = [&]() -> void { 1442 const unsigned Bits = Offset.bitWidth(); 1443 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false); 1444 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false); 1445 APSInt NewIndex = 1446 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset); 1447 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 1448 << NewIndex 1449 << /*array*/ static_cast<int>(!Ptr.inArray()) 1450 << static_cast<unsigned>(MaxIndex); 1451 Invalid = true; 1452 }; 1453 1454 T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); 1455 if constexpr (Op == ArithOp::Add) { 1456 // If the new offset would be negative, bail out. 1457 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) 1458 DiagInvalidOffset(); 1459 1460 // If the new offset would be out of bounds, bail out. 1461 if (Offset.isPositive() && Offset > MaxOffset) 1462 DiagInvalidOffset(); 1463 } else { 1464 // If the new offset would be negative, bail out. 1465 if (Offset.isPositive() && Index < Offset) 1466 DiagInvalidOffset(); 1467 1468 // If the new offset would be out of bounds, bail out. 1469 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) 1470 DiagInvalidOffset(); 1471 } 1472 1473 if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus) 1474 return false; 1475 1476 // Offset is valid - compute it on unsigned. 1477 int64_t WideIndex = static_cast<int64_t>(Index); 1478 int64_t WideOffset = static_cast<int64_t>(Offset); 1479 int64_t Result; 1480 if constexpr (Op == ArithOp::Add) 1481 Result = WideIndex + WideOffset; 1482 else 1483 Result = WideIndex - WideOffset; 1484 1485 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result))); 1486 return true; 1487 } 1488 1489 template <PrimType Name, class T = typename PrimConv<Name>::T> 1490 bool AddOffset(InterpState &S, CodePtr OpPC) { 1491 const T &Offset = S.Stk.pop<T>(); 1492 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1493 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr); 1494 } 1495 1496 template <PrimType Name, class T = typename PrimConv<Name>::T> 1497 bool SubOffset(InterpState &S, CodePtr OpPC) { 1498 const T &Offset = S.Stk.pop<T>(); 1499 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1500 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr); 1501 } 1502 1503 template <ArithOp Op> 1504 static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, 1505 const Pointer &Ptr) { 1506 using OneT = Integral<8, false>; 1507 1508 const Pointer &P = Ptr.deref<Pointer>(); 1509 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex)) 1510 return false; 1511 1512 // Get the current value on the stack. 1513 S.Stk.push<Pointer>(P); 1514 1515 // Now the current Ptr again and a constant 1. 1516 OneT One = OneT::from(1); 1517 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P)) 1518 return false; 1519 1520 // Store the new value. 1521 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>(); 1522 return true; 1523 } 1524 1525 static inline bool IncPtr(InterpState &S, CodePtr OpPC) { 1526 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1527 1528 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 1529 return false; 1530 1531 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); 1532 } 1533 1534 static inline bool DecPtr(InterpState &S, CodePtr OpPC) { 1535 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1536 1537 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 1538 return false; 1539 1540 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); 1541 } 1542 1543 /// 1) Pops a Pointer from the stack. 1544 /// 2) Pops another Pointer from the stack. 1545 /// 3) Pushes the different of the indices of the two pointers on the stack. 1546 template <PrimType Name, class T = typename PrimConv<Name>::T> 1547 inline bool SubPtr(InterpState &S, CodePtr OpPC) { 1548 const Pointer &LHS = S.Stk.pop<Pointer>(); 1549 const Pointer &RHS = S.Stk.pop<Pointer>(); 1550 1551 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { 1552 // TODO: Diagnose. 1553 return false; 1554 } 1555 1556 T A = T::from(LHS.getIndex()); 1557 T B = T::from(RHS.getIndex()); 1558 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B); 1559 } 1560 1561 //===----------------------------------------------------------------------===// 1562 // Destroy 1563 //===----------------------------------------------------------------------===// 1564 1565 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 1566 S.Current->destroy(I); 1567 return true; 1568 } 1569 1570 //===----------------------------------------------------------------------===// 1571 // Cast, CastFP 1572 //===----------------------------------------------------------------------===// 1573 1574 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 1575 using T = typename PrimConv<TIn>::T; 1576 using U = typename PrimConv<TOut>::T; 1577 S.Stk.push<U>(U::from(S.Stk.pop<T>())); 1578 return true; 1579 } 1580 1581 /// 1) Pops a Floating from the stack. 1582 /// 2) Pushes a new floating on the stack that uses the given semantics. 1583 inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, 1584 llvm::RoundingMode RM) { 1585 Floating F = S.Stk.pop<Floating>(); 1586 Floating Result = F.toSemantics(Sem, RM); 1587 S.Stk.push<Floating>(Result); 1588 return true; 1589 } 1590 1591 /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need 1592 /// to know what bitwidth the result should be. 1593 template <PrimType Name, class T = typename PrimConv<Name>::T> 1594 bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1595 S.Stk.push<IntegralAP<false>>( 1596 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth)); 1597 return true; 1598 } 1599 1600 template <PrimType Name, class T = typename PrimConv<Name>::T> 1601 bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1602 S.Stk.push<IntegralAP<true>>( 1603 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth)); 1604 return true; 1605 } 1606 1607 template <PrimType Name, class T = typename PrimConv<Name>::T> 1608 bool CastIntegralFloating(InterpState &S, CodePtr OpPC, 1609 const llvm::fltSemantics *Sem, 1610 llvm::RoundingMode RM) { 1611 const T &From = S.Stk.pop<T>(); 1612 APSInt FromAP = From.toAPSInt(); 1613 Floating Result; 1614 1615 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result); 1616 S.Stk.push<Floating>(Result); 1617 1618 return CheckFloatResult(S, OpPC, Result, Status); 1619 } 1620 1621 template <PrimType Name, class T = typename PrimConv<Name>::T> 1622 bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) { 1623 const Floating &F = S.Stk.pop<Floating>(); 1624 1625 if constexpr (std::is_same_v<T, Boolean>) { 1626 S.Stk.push<T>(T(F.isNonZero())); 1627 return true; 1628 } else { 1629 APSInt Result(std::max(8u, T::bitWidth()), 1630 /*IsUnsigned=*/!T::isSigned()); 1631 auto Status = F.convertToInteger(Result); 1632 1633 // Float-to-Integral overflow check. 1634 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1635 const Expr *E = S.Current->getExpr(OpPC); 1636 QualType Type = E->getType(); 1637 1638 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1639 if (S.noteUndefinedBehavior()) { 1640 S.Stk.push<T>(T(Result)); 1641 return true; 1642 } 1643 return false; 1644 } 1645 1646 S.Stk.push<T>(T(Result)); 1647 return CheckFloatResult(S, OpPC, F, Status); 1648 } 1649 } 1650 1651 static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, 1652 uint32_t BitWidth) { 1653 const Floating &F = S.Stk.pop<Floating>(); 1654 1655 APSInt Result(BitWidth, /*IsUnsigned=*/true); 1656 auto Status = F.convertToInteger(Result); 1657 1658 // Float-to-Integral overflow check. 1659 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1660 const Expr *E = S.Current->getExpr(OpPC); 1661 QualType Type = E->getType(); 1662 1663 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1664 return S.noteUndefinedBehavior(); 1665 } 1666 1667 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 1668 return CheckFloatResult(S, OpPC, F, Status); 1669 } 1670 1671 static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, 1672 uint32_t BitWidth) { 1673 const Floating &F = S.Stk.pop<Floating>(); 1674 1675 APSInt Result(BitWidth, /*IsUnsigned=*/false); 1676 auto Status = F.convertToInteger(Result); 1677 1678 // Float-to-Integral overflow check. 1679 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1680 const Expr *E = S.Current->getExpr(OpPC); 1681 QualType Type = E->getType(); 1682 1683 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1684 return S.noteUndefinedBehavior(); 1685 } 1686 1687 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 1688 return CheckFloatResult(S, OpPC, F, Status); 1689 } 1690 1691 template <PrimType Name, class T = typename PrimConv<Name>::T> 1692 bool CastPointerIntegral(InterpState &S, CodePtr OpPC) { 1693 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1694 1695 if (!CheckPotentialReinterpretCast(S, OpPC, Ptr)) 1696 return false; 1697 1698 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation())); 1699 return true; 1700 } 1701 1702 //===----------------------------------------------------------------------===// 1703 // Zero, Nullptr 1704 //===----------------------------------------------------------------------===// 1705 1706 template <PrimType Name, class T = typename PrimConv<Name>::T> 1707 bool Zero(InterpState &S, CodePtr OpPC) { 1708 S.Stk.push<T>(T::zero()); 1709 return true; 1710 } 1711 1712 static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1713 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth)); 1714 return true; 1715 } 1716 1717 static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1718 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth)); 1719 return true; 1720 } 1721 1722 template <PrimType Name, class T = typename PrimConv<Name>::T> 1723 inline bool Null(InterpState &S, CodePtr OpPC) { 1724 S.Stk.push<T>(); 1725 return true; 1726 } 1727 1728 //===----------------------------------------------------------------------===// 1729 // This, ImplicitThis 1730 //===----------------------------------------------------------------------===// 1731 1732 inline bool This(InterpState &S, CodePtr OpPC) { 1733 // Cannot read 'this' in this mode. 1734 if (S.checkingPotentialConstantExpression()) { 1735 return false; 1736 } 1737 1738 const Pointer &This = S.Current->getThis(); 1739 if (!CheckThis(S, OpPC, This)) 1740 return false; 1741 1742 S.Stk.push<Pointer>(This); 1743 return true; 1744 } 1745 1746 inline bool RVOPtr(InterpState &S, CodePtr OpPC) { 1747 assert(S.Current->getFunction()->hasRVO()); 1748 if (S.checkingPotentialConstantExpression()) 1749 return false; 1750 S.Stk.push<Pointer>(S.Current->getRVOPtr()); 1751 return true; 1752 } 1753 1754 //===----------------------------------------------------------------------===// 1755 // Shr, Shl 1756 //===----------------------------------------------------------------------===// 1757 1758 template <PrimType NameL, PrimType NameR> 1759 inline bool Shr(InterpState &S, CodePtr OpPC) { 1760 using LT = typename PrimConv<NameL>::T; 1761 using RT = typename PrimConv<NameR>::T; 1762 const auto &RHS = S.Stk.pop<RT>(); 1763 const auto &LHS = S.Stk.pop<LT>(); 1764 const unsigned Bits = LHS.bitWidth(); 1765 1766 if (!CheckShift(S, OpPC, LHS, RHS, Bits)) 1767 return false; 1768 1769 typename LT::AsUnsigned R; 1770 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), 1771 LT::AsUnsigned::from(RHS), Bits, &R); 1772 S.Stk.push<LT>(LT::from(R)); 1773 1774 return true; 1775 } 1776 1777 template <PrimType NameL, PrimType NameR> 1778 inline bool Shl(InterpState &S, CodePtr OpPC) { 1779 using LT = typename PrimConv<NameL>::T; 1780 using RT = typename PrimConv<NameR>::T; 1781 const auto &RHS = S.Stk.pop<RT>(); 1782 const auto &LHS = S.Stk.pop<LT>(); 1783 const unsigned Bits = LHS.bitWidth(); 1784 1785 if (!CheckShift(S, OpPC, LHS, RHS, Bits)) 1786 return false; 1787 1788 typename LT::AsUnsigned R; 1789 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 1790 LT::AsUnsigned::from(RHS, Bits), Bits, &R); 1791 S.Stk.push<LT>(LT::from(R)); 1792 return true; 1793 } 1794 1795 //===----------------------------------------------------------------------===// 1796 // NoRet 1797 //===----------------------------------------------------------------------===// 1798 1799 inline bool NoRet(InterpState &S, CodePtr OpPC) { 1800 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 1801 S.FFDiag(EndLoc, diag::note_constexpr_no_return); 1802 return false; 1803 } 1804 1805 //===----------------------------------------------------------------------===// 1806 // NarrowPtr, ExpandPtr 1807 //===----------------------------------------------------------------------===// 1808 1809 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 1810 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1811 S.Stk.push<Pointer>(Ptr.narrow()); 1812 return true; 1813 } 1814 1815 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 1816 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1817 S.Stk.push<Pointer>(Ptr.expand()); 1818 return true; 1819 } 1820 1821 // 1) Pops an integral value from the stack 1822 // 2) Peeks a pointer 1823 // 3) Pushes a new pointer that's a narrowed array 1824 // element of the peeked pointer with the value 1825 // from 1) added as offset. 1826 // 1827 // This leaves the original pointer on the stack and pushes a new one 1828 // with the offset applied and narrowed. 1829 template <PrimType Name, class T = typename PrimConv<Name>::T> 1830 inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { 1831 const T &Offset = S.Stk.pop<T>(); 1832 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1833 1834 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 1835 return false; 1836 1837 return NarrowPtr(S, OpPC); 1838 } 1839 1840 /// Just takes a pointer and checks if its' an incomplete 1841 /// array type. 1842 inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { 1843 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1844 1845 if (!Ptr.isUnknownSizeArray()) { 1846 S.Stk.push<Pointer>(Ptr.atIndex(0)); 1847 return true; 1848 } 1849 1850 const SourceInfo &E = S.Current->getSource(OpPC); 1851 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array); 1852 1853 return false; 1854 } 1855 1856 template <PrimType Name, class T = typename PrimConv<Name>::T> 1857 inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { 1858 const T &Offset = S.Stk.pop<T>(); 1859 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1860 1861 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 1862 return false; 1863 1864 return NarrowPtr(S, OpPC); 1865 } 1866 1867 inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) { 1868 if (Func->hasThisPointer()) { 1869 size_t ThisOffset = 1870 Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 1871 1872 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 1873 1874 // If the current function is a lambda static invoker and 1875 // the function we're about to call is a lambda call operator, 1876 // skip the CheckInvoke, since the ThisPtr is a null pointer 1877 // anyway. 1878 if (!(S.Current->getFunction() && 1879 S.Current->getFunction()->isLambdaStaticInvoker() && 1880 Func->isLambdaCallOperator())) { 1881 if (!CheckInvoke(S, OpPC, ThisPtr)) 1882 return false; 1883 } 1884 1885 if (S.checkingPotentialConstantExpression()) 1886 return false; 1887 } 1888 1889 if (!CheckCallable(S, OpPC, Func)) 1890 return false; 1891 1892 if (!CheckCallDepth(S, OpPC)) 1893 return false; 1894 1895 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC); 1896 InterpFrame *FrameBefore = S.Current; 1897 S.Current = NewFrame.get(); 1898 1899 APValue CallResult; 1900 // Note that we cannot assert(CallResult.hasValue()) here since 1901 // Ret() above only sets the APValue if the curent frame doesn't 1902 // have a caller set. 1903 if (Interpret(S, CallResult)) { 1904 NewFrame.release(); // Frame was delete'd already. 1905 assert(S.Current == FrameBefore); 1906 return true; 1907 } 1908 1909 // Interpreting the function failed somehow. Reset to 1910 // previous state. 1911 S.Current = FrameBefore; 1912 return false; 1913 } 1914 1915 inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) { 1916 assert(Func->hasThisPointer()); 1917 assert(Func->isVirtual()); 1918 size_t ThisOffset = 1919 Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 1920 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 1921 1922 const CXXRecordDecl *DynamicDecl = 1923 ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl(); 1924 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl()); 1925 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl()); 1926 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( 1927 DynamicDecl, StaticDecl, InitialFunction); 1928 1929 if (Overrider != InitialFunction) { 1930 // DR1872: An instantiated virtual constexpr function can't be called in a 1931 // constant expression (prior to C++20). We can still constant-fold such a 1932 // call. 1933 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) { 1934 const Expr *E = S.Current->getExpr(OpPC); 1935 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange(); 1936 } 1937 1938 Func = S.getContext().getOrCreateFunction(Overrider); 1939 1940 const CXXRecordDecl *ThisFieldDecl = 1941 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl(); 1942 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) { 1943 // If the function we call is further DOWN the hierarchy than the 1944 // FieldDesc of our pointer, just get the DeclDesc instead, which 1945 // is the furthest we might go up in the hierarchy. 1946 ThisPtr = ThisPtr.getDeclPtr(); 1947 } 1948 } 1949 1950 return Call(S, OpPC, Func); 1951 } 1952 1953 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, 1954 const CallExpr *CE) { 1955 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC); 1956 1957 InterpFrame *FrameBefore = S.Current; 1958 S.Current = NewFrame.get(); 1959 1960 if (InterpretBuiltin(S, PC, Func, CE)) { 1961 NewFrame.release(); 1962 return true; 1963 } 1964 S.Current = FrameBefore; 1965 return false; 1966 } 1967 1968 inline bool CallPtr(InterpState &S, CodePtr OpPC) { 1969 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>(); 1970 1971 const Function *F = FuncPtr.getFunction(); 1972 if (!F || !F->isConstexpr()) 1973 return false; 1974 1975 if (F->isVirtual()) 1976 return CallVirt(S, OpPC, F); 1977 1978 return Call(S, OpPC, F); 1979 } 1980 1981 inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { 1982 assert(Func); 1983 S.Stk.push<FunctionPointer>(Func); 1984 return true; 1985 } 1986 1987 /// Just emit a diagnostic. The expression that caused emission of this 1988 /// op is not valid in a constant context. 1989 inline bool Invalid(InterpState &S, CodePtr OpPC) { 1990 const SourceLocation &Loc = S.Current->getLocation(OpPC); 1991 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) 1992 << S.Current->getRange(OpPC); 1993 return false; 1994 } 1995 1996 /// Same here, but only for casts. 1997 inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) { 1998 const SourceLocation &Loc = S.Current->getLocation(OpPC); 1999 S.FFDiag(Loc, diag::note_constexpr_invalid_cast) 2000 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC); 2001 return false; 2002 } 2003 2004 inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, 2005 const DeclRefExpr *DR) { 2006 assert(DR); 2007 return CheckDeclRef(S, OpPC, DR); 2008 } 2009 2010 template <PrimType Name, class T = typename PrimConv<Name>::T> 2011 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) { 2012 llvm::SmallVector<int64_t> ArrayIndices; 2013 for (size_t I = 0; I != E->getNumExpressions(); ++I) 2014 ArrayIndices.emplace_back(S.Stk.pop<int64_t>()); 2015 2016 int64_t Result; 2017 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result)) 2018 return false; 2019 2020 S.Stk.push<T>(T::from(Result)); 2021 2022 return true; 2023 } 2024 2025 //===----------------------------------------------------------------------===// 2026 // Read opcode arguments 2027 //===----------------------------------------------------------------------===// 2028 2029 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { 2030 if constexpr (std::is_pointer<T>::value) { 2031 uint32_t ID = OpPC.read<uint32_t>(); 2032 return reinterpret_cast<T>(S.P.getNativePointer(ID)); 2033 } else { 2034 return OpPC.read<T>(); 2035 } 2036 } 2037 2038 template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { 2039 Floating F = Floating::deserialize(*OpPC); 2040 OpPC += align(F.bytesToSerialize()); 2041 return F; 2042 } 2043 2044 } // namespace interp 2045 } // namespace clang 2046 2047 #endif 2048