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