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 a pointer points to a mutable field. 81 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 82 83 /// Checks if a value can be loaded from a block. 84 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 85 86 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 87 AccessKinds AK); 88 89 /// Checks if a value can be stored in a block. 90 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 91 92 /// Checks if a method can be invoked on an object. 93 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 94 95 /// Checks if a value can be initialized. 96 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 97 98 /// Checks if a method can be called. 99 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F); 100 101 /// Checks if calling the currently active function would exceed 102 /// the allowed call depth. 103 bool CheckCallDepth(InterpState &S, CodePtr OpPC); 104 105 /// Checks the 'this' pointer. 106 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 107 108 /// Checks if a method is pure virtual. 109 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 110 111 /// Checks that all fields are initialized after a constructor call. 112 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This); 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 if (B->isExtern()) 1008 return false; 1009 S.Stk.push<T>(B->deref<T>()); 1010 return true; 1011 } 1012 1013 template <PrimType Name, class T = typename PrimConv<Name>::T> 1014 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1015 // TODO: emit warning. 1016 return false; 1017 } 1018 1019 template <PrimType Name, class T = typename PrimConv<Name>::T> 1020 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1021 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 1022 return true; 1023 } 1024 1025 /// 1) Converts the value on top of the stack to an APValue 1026 /// 2) Sets that APValue on \Temp 1027 /// 3) Initialized global with index \I with that 1028 template <PrimType Name, class T = typename PrimConv<Name>::T> 1029 bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I, 1030 const LifetimeExtendedTemporaryDecl *Temp) { 1031 assert(Temp); 1032 const T Value = S.Stk.peek<T>(); 1033 APValue APV = Value.toAPValue(); 1034 APValue *Cached = Temp->getOrCreateValue(true); 1035 *Cached = APV; 1036 1037 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 1038 return true; 1039 } 1040 1041 /// 1) Converts the value on top of the stack to an APValue 1042 /// 2) Sets that APValue on \Temp 1043 /// 3) Initialized global with index \I with that 1044 inline bool InitGlobalTempComp(InterpState &S, CodePtr OpPC, 1045 const LifetimeExtendedTemporaryDecl *Temp) { 1046 assert(Temp); 1047 const Pointer &P = S.Stk.peek<Pointer>(); 1048 APValue *Cached = Temp->getOrCreateValue(true); 1049 1050 *Cached = P.toRValue(S.getCtx()); 1051 return true; 1052 } 1053 1054 template <PrimType Name, class T = typename PrimConv<Name>::T> 1055 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 1056 if (S.checkingPotentialConstantExpression()) 1057 return false; 1058 const Pointer &This = S.Current->getThis(); 1059 if (!CheckThis(S, OpPC, This)) 1060 return false; 1061 const Pointer &Field = This.atField(I); 1062 Field.deref<T>() = S.Stk.pop<T>(); 1063 Field.initialize(); 1064 return true; 1065 } 1066 1067 template <PrimType Name, class T = typename PrimConv<Name>::T> 1068 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 1069 assert(F->isBitField()); 1070 if (S.checkingPotentialConstantExpression()) 1071 return false; 1072 const Pointer &This = S.Current->getThis(); 1073 if (!CheckThis(S, OpPC, This)) 1074 return false; 1075 const Pointer &Field = This.atField(F->Offset); 1076 const auto &Value = S.Stk.pop<T>(); 1077 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1078 Field.initialize(); 1079 return true; 1080 } 1081 1082 template <PrimType Name, class T = typename PrimConv<Name>::T> 1083 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1084 if (S.checkingPotentialConstantExpression()) 1085 return false; 1086 const Pointer &This = S.Current->getThis(); 1087 if (!CheckThis(S, OpPC, This)) 1088 return false; 1089 const Pointer &Field = This.atField(I); 1090 Field.deref<T>() = S.Stk.pop<T>(); 1091 Field.activate(); 1092 Field.initialize(); 1093 return true; 1094 } 1095 1096 /// 1) Pops the value from the stack 1097 /// 2) Peeks a pointer from the stack 1098 /// 3) Pushes the value to field I of the pointer on the stack 1099 template <PrimType Name, class T = typename PrimConv<Name>::T> 1100 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 1101 const T &Value = S.Stk.pop<T>(); 1102 const Pointer &Field = S.Stk.peek<Pointer>().atField(I); 1103 Field.deref<T>() = Value; 1104 Field.activate(); 1105 Field.initialize(); 1106 return true; 1107 } 1108 1109 template <PrimType Name, class T = typename PrimConv<Name>::T> 1110 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 1111 assert(F->isBitField()); 1112 const T &Value = S.Stk.pop<T>(); 1113 const Pointer &Field = S.Stk.peek<Pointer>().atField(F->Offset); 1114 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 1115 Field.activate(); 1116 Field.initialize(); 1117 return true; 1118 } 1119 1120 template <PrimType Name, class T = typename PrimConv<Name>::T> 1121 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 1122 const T &Value = S.Stk.pop<T>(); 1123 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1124 const Pointer &Field = Ptr.atField(I); 1125 Field.deref<T>() = Value; 1126 Field.activate(); 1127 Field.initialize(); 1128 return true; 1129 } 1130 1131 //===----------------------------------------------------------------------===// 1132 // GetPtr Local/Param/Global/Field/This 1133 //===----------------------------------------------------------------------===// 1134 1135 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 1136 S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 1137 return true; 1138 } 1139 1140 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 1141 if (S.checkingPotentialConstantExpression()) { 1142 return false; 1143 } 1144 S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 1145 return true; 1146 } 1147 1148 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 1149 S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 1150 return true; 1151 } 1152 1153 /// 1) Pops a Pointer from the stack 1154 /// 2) Pushes Pointer.atField(Off) on the stack 1155 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1156 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1157 if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field)) 1158 return false; 1159 if (!CheckExtern(S, OpPC, Ptr)) 1160 return false; 1161 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1162 return false; 1163 if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) 1164 return false; 1165 1166 S.Stk.push<Pointer>(Ptr.atField(Off)); 1167 return true; 1168 } 1169 1170 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1171 if (S.checkingPotentialConstantExpression()) 1172 return false; 1173 const Pointer &This = S.Current->getThis(); 1174 if (!CheckThis(S, OpPC, This)) 1175 return false; 1176 S.Stk.push<Pointer>(This.atField(Off)); 1177 return true; 1178 } 1179 1180 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1181 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1182 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 1183 return false; 1184 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 1185 return false; 1186 Pointer Field = Ptr.atField(Off); 1187 Ptr.deactivate(); 1188 Field.activate(); 1189 S.Stk.push<Pointer>(std::move(Field)); 1190 return true; 1191 } 1192 1193 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 1194 if (S.checkingPotentialConstantExpression()) 1195 return false; 1196 const Pointer &This = S.Current->getThis(); 1197 if (!CheckThis(S, OpPC, This)) 1198 return false; 1199 Pointer Field = This.atField(Off); 1200 This.deactivate(); 1201 Field.activate(); 1202 S.Stk.push<Pointer>(std::move(Field)); 1203 return true; 1204 } 1205 1206 inline bool GetPtrDerivedPop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1207 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1208 if (!CheckNull(S, OpPC, Ptr, CSK_Derived)) 1209 return false; 1210 if (!CheckSubobject(S, OpPC, Ptr, CSK_Derived)) 1211 return false; 1212 S.Stk.push<Pointer>(Ptr.atFieldSub(Off)); 1213 return true; 1214 } 1215 1216 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1217 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1218 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1219 return false; 1220 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1221 return false; 1222 S.Stk.push<Pointer>(Ptr.atField(Off)); 1223 return true; 1224 } 1225 1226 inline bool GetPtrBasePop(InterpState &S, CodePtr OpPC, uint32_t Off) { 1227 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1228 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1229 return false; 1230 if (!CheckSubobject(S, OpPC, Ptr, CSK_Base)) 1231 return false; 1232 S.Stk.push<Pointer>(Ptr.atField(Off)); 1233 return true; 1234 } 1235 1236 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 1237 if (S.checkingPotentialConstantExpression()) 1238 return false; 1239 const Pointer &This = S.Current->getThis(); 1240 if (!CheckThis(S, OpPC, This)) 1241 return false; 1242 S.Stk.push<Pointer>(This.atField(Off)); 1243 return true; 1244 } 1245 1246 inline bool InitPtrPop(InterpState &S, CodePtr OpPC) { 1247 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1248 Ptr.initialize(); 1249 return true; 1250 } 1251 1252 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 1253 const Pointer &Ptr) { 1254 Pointer Base = Ptr; 1255 while (Base.isBaseClass()) 1256 Base = Base.getBase(); 1257 1258 auto *Field = Base.getRecord()->getVirtualBase(Decl); 1259 S.Stk.push<Pointer>(Base.atField(Field->Offset)); 1260 return true; 1261 } 1262 1263 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { 1264 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1265 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 1266 return false; 1267 return VirtBaseHelper(S, OpPC, D, Ptr); 1268 } 1269 1270 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 1271 const RecordDecl *D) { 1272 if (S.checkingPotentialConstantExpression()) 1273 return false; 1274 const Pointer &This = S.Current->getThis(); 1275 if (!CheckThis(S, OpPC, This)) 1276 return false; 1277 return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 1278 } 1279 1280 //===----------------------------------------------------------------------===// 1281 // Load, Store, Init 1282 //===----------------------------------------------------------------------===// 1283 1284 template <PrimType Name, class T = typename PrimConv<Name>::T> 1285 bool Load(InterpState &S, CodePtr OpPC) { 1286 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1287 if (!CheckLoad(S, OpPC, Ptr)) 1288 return false; 1289 S.Stk.push<T>(Ptr.deref<T>()); 1290 return true; 1291 } 1292 1293 template <PrimType Name, class T = typename PrimConv<Name>::T> 1294 bool LoadPop(InterpState &S, CodePtr OpPC) { 1295 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1296 if (!CheckLoad(S, OpPC, Ptr)) 1297 return false; 1298 S.Stk.push<T>(Ptr.deref<T>()); 1299 return true; 1300 } 1301 1302 template <PrimType Name, class T = typename PrimConv<Name>::T> 1303 bool Store(InterpState &S, CodePtr OpPC) { 1304 const T &Value = S.Stk.pop<T>(); 1305 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1306 if (!CheckStore(S, OpPC, Ptr)) 1307 return false; 1308 if (!Ptr.isRoot()) 1309 Ptr.initialize(); 1310 Ptr.deref<T>() = Value; 1311 return true; 1312 } 1313 1314 template <PrimType Name, class T = typename PrimConv<Name>::T> 1315 bool StorePop(InterpState &S, CodePtr OpPC) { 1316 const T &Value = S.Stk.pop<T>(); 1317 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1318 if (!CheckStore(S, OpPC, Ptr)) 1319 return false; 1320 if (!Ptr.isRoot()) 1321 Ptr.initialize(); 1322 Ptr.deref<T>() = Value; 1323 return true; 1324 } 1325 1326 template <PrimType Name, class T = typename PrimConv<Name>::T> 1327 bool StoreBitField(InterpState &S, CodePtr OpPC) { 1328 const T &Value = S.Stk.pop<T>(); 1329 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1330 if (!CheckStore(S, OpPC, Ptr)) 1331 return false; 1332 if (!Ptr.isRoot()) 1333 Ptr.initialize(); 1334 if (const auto *FD = Ptr.getField()) 1335 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 1336 else 1337 Ptr.deref<T>() = Value; 1338 return true; 1339 } 1340 1341 template <PrimType Name, class T = typename PrimConv<Name>::T> 1342 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 1343 const T &Value = S.Stk.pop<T>(); 1344 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1345 if (!CheckStore(S, OpPC, Ptr)) 1346 return false; 1347 if (!Ptr.isRoot()) 1348 Ptr.initialize(); 1349 if (const auto *FD = Ptr.getField()) 1350 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 1351 else 1352 Ptr.deref<T>() = Value; 1353 return true; 1354 } 1355 1356 template <PrimType Name, class T = typename PrimConv<Name>::T> 1357 bool InitPop(InterpState &S, CodePtr OpPC) { 1358 const T &Value = S.Stk.pop<T>(); 1359 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1360 if (!CheckInit(S, OpPC, Ptr)) 1361 return false; 1362 Ptr.initialize(); 1363 new (&Ptr.deref<T>()) T(Value); 1364 return true; 1365 } 1366 1367 /// 1) Pops the value from the stack 1368 /// 2) Peeks a pointer and gets its index \Idx 1369 /// 3) Sets the value on the pointer, leaving the pointer on the stack. 1370 template <PrimType Name, class T = typename PrimConv<Name>::T> 1371 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1372 const T &Value = S.Stk.pop<T>(); 1373 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx); 1374 if (!CheckInit(S, OpPC, Ptr)) 1375 return false; 1376 Ptr.initialize(); 1377 new (&Ptr.deref<T>()) T(Value); 1378 return true; 1379 } 1380 1381 /// The same as InitElem, but pops the pointer as well. 1382 template <PrimType Name, class T = typename PrimConv<Name>::T> 1383 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1384 const T &Value = S.Stk.pop<T>(); 1385 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx); 1386 if (!CheckInit(S, OpPC, Ptr)) 1387 return false; 1388 Ptr.initialize(); 1389 new (&Ptr.deref<T>()) T(Value); 1390 return true; 1391 } 1392 1393 //===----------------------------------------------------------------------===// 1394 // AddOffset, SubOffset 1395 //===----------------------------------------------------------------------===// 1396 1397 template <class T, ArithOp Op> 1398 bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset, 1399 const Pointer &Ptr) { 1400 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 1401 return false; 1402 1403 // A zero offset does not change the pointer. 1404 if (Offset.isZero()) { 1405 S.Stk.push<Pointer>(Ptr); 1406 return true; 1407 } 1408 1409 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) 1410 return false; 1411 1412 // Arrays of unknown bounds cannot have pointers into them. 1413 if (!CheckArray(S, OpPC, Ptr)) 1414 return false; 1415 1416 // Get a version of the index comparable to the type. 1417 T Index = T::from(Ptr.getIndex(), Offset.bitWidth()); 1418 // Compute the largest index into the array. 1419 T MaxIndex = T::from(Ptr.getNumElems(), Offset.bitWidth()); 1420 1421 bool Invalid = false; 1422 // Helper to report an invalid offset, computed as APSInt. 1423 auto DiagInvalidOffset = [&]() -> void { 1424 const unsigned Bits = Offset.bitWidth(); 1425 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false); 1426 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false); 1427 APSInt NewIndex = 1428 (Op == ArithOp::Add) ? (APIndex + APOffset) : (APIndex - APOffset); 1429 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 1430 << NewIndex 1431 << /*array*/ static_cast<int>(!Ptr.inArray()) 1432 << static_cast<unsigned>(MaxIndex); 1433 Invalid = true; 1434 }; 1435 1436 T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth()); 1437 if constexpr (Op == ArithOp::Add) { 1438 // If the new offset would be negative, bail out. 1439 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) 1440 DiagInvalidOffset(); 1441 1442 // If the new offset would be out of bounds, bail out. 1443 if (Offset.isPositive() && Offset > MaxOffset) 1444 DiagInvalidOffset(); 1445 } else { 1446 // If the new offset would be negative, bail out. 1447 if (Offset.isPositive() && Index < Offset) 1448 DiagInvalidOffset(); 1449 1450 // If the new offset would be out of bounds, bail out. 1451 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) 1452 DiagInvalidOffset(); 1453 } 1454 1455 if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus) 1456 return false; 1457 1458 // Offset is valid - compute it on unsigned. 1459 int64_t WideIndex = static_cast<int64_t>(Index); 1460 int64_t WideOffset = static_cast<int64_t>(Offset); 1461 int64_t Result; 1462 if constexpr (Op == ArithOp::Add) 1463 Result = WideIndex + WideOffset; 1464 else 1465 Result = WideIndex - WideOffset; 1466 1467 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result))); 1468 return true; 1469 } 1470 1471 template <PrimType Name, class T = typename PrimConv<Name>::T> 1472 bool AddOffset(InterpState &S, CodePtr OpPC) { 1473 const T &Offset = S.Stk.pop<T>(); 1474 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1475 return OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr); 1476 } 1477 1478 template <PrimType Name, class T = typename PrimConv<Name>::T> 1479 bool SubOffset(InterpState &S, CodePtr OpPC) { 1480 const T &Offset = S.Stk.pop<T>(); 1481 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1482 return OffsetHelper<T, ArithOp::Sub>(S, OpPC, Offset, Ptr); 1483 } 1484 1485 template <ArithOp Op> 1486 static inline bool IncDecPtrHelper(InterpState &S, CodePtr OpPC, 1487 const Pointer &Ptr) { 1488 using OneT = Integral<8, false>; 1489 1490 const Pointer &P = Ptr.deref<Pointer>(); 1491 if (!CheckNull(S, OpPC, P, CSK_ArrayIndex)) 1492 return false; 1493 1494 // Get the current value on the stack. 1495 S.Stk.push<Pointer>(P); 1496 1497 // Now the current Ptr again and a constant 1. 1498 OneT One = OneT::from(1); 1499 if (!OffsetHelper<OneT, Op>(S, OpPC, One, P)) 1500 return false; 1501 1502 // Store the new value. 1503 Ptr.deref<Pointer>() = S.Stk.pop<Pointer>(); 1504 return true; 1505 } 1506 1507 static inline bool IncPtr(InterpState &S, CodePtr OpPC) { 1508 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1509 1510 if (!CheckInitialized(S, OpPC, Ptr, AK_Increment)) 1511 return false; 1512 1513 return IncDecPtrHelper<ArithOp::Add>(S, OpPC, Ptr); 1514 } 1515 1516 static inline bool DecPtr(InterpState &S, CodePtr OpPC) { 1517 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1518 1519 if (!CheckInitialized(S, OpPC, Ptr, AK_Decrement)) 1520 return false; 1521 1522 return IncDecPtrHelper<ArithOp::Sub>(S, OpPC, Ptr); 1523 } 1524 1525 /// 1) Pops a Pointer from the stack. 1526 /// 2) Pops another Pointer from the stack. 1527 /// 3) Pushes the different of the indices of the two pointers on the stack. 1528 template <PrimType Name, class T = typename PrimConv<Name>::T> 1529 inline bool SubPtr(InterpState &S, CodePtr OpPC) { 1530 const Pointer &LHS = S.Stk.pop<Pointer>(); 1531 const Pointer &RHS = S.Stk.pop<Pointer>(); 1532 1533 if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) { 1534 // TODO: Diagnose. 1535 return false; 1536 } 1537 1538 T A = T::from(LHS.getIndex()); 1539 T B = T::from(RHS.getIndex()); 1540 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B); 1541 } 1542 1543 //===----------------------------------------------------------------------===// 1544 // Destroy 1545 //===----------------------------------------------------------------------===// 1546 1547 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 1548 S.Current->destroy(I); 1549 return true; 1550 } 1551 1552 //===----------------------------------------------------------------------===// 1553 // Cast, CastFP 1554 //===----------------------------------------------------------------------===// 1555 1556 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 1557 using T = typename PrimConv<TIn>::T; 1558 using U = typename PrimConv<TOut>::T; 1559 S.Stk.push<U>(U::from(S.Stk.pop<T>())); 1560 return true; 1561 } 1562 1563 /// 1) Pops a Floating from the stack. 1564 /// 2) Pushes a new floating on the stack that uses the given semantics. 1565 inline bool CastFP(InterpState &S, CodePtr OpPC, const llvm::fltSemantics *Sem, 1566 llvm::RoundingMode RM) { 1567 Floating F = S.Stk.pop<Floating>(); 1568 Floating Result = F.toSemantics(Sem, RM); 1569 S.Stk.push<Floating>(Result); 1570 return true; 1571 } 1572 1573 /// Like Cast(), but we cast to an arbitrary-bitwidth integral, so we need 1574 /// to know what bitwidth the result should be. 1575 template <PrimType Name, class T = typename PrimConv<Name>::T> 1576 bool CastAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1577 S.Stk.push<IntegralAP<false>>( 1578 IntegralAP<false>::from(S.Stk.pop<T>(), BitWidth)); 1579 return true; 1580 } 1581 1582 template <PrimType Name, class T = typename PrimConv<Name>::T> 1583 bool CastAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1584 S.Stk.push<IntegralAP<true>>( 1585 IntegralAP<true>::from(S.Stk.pop<T>(), BitWidth)); 1586 return true; 1587 } 1588 1589 template <PrimType Name, class T = typename PrimConv<Name>::T> 1590 bool CastIntegralFloating(InterpState &S, CodePtr OpPC, 1591 const llvm::fltSemantics *Sem, 1592 llvm::RoundingMode RM) { 1593 const T &From = S.Stk.pop<T>(); 1594 APSInt FromAP = From.toAPSInt(); 1595 Floating Result; 1596 1597 auto Status = Floating::fromIntegral(FromAP, *Sem, RM, Result); 1598 S.Stk.push<Floating>(Result); 1599 1600 return CheckFloatResult(S, OpPC, Result, Status); 1601 } 1602 1603 template <PrimType Name, class T = typename PrimConv<Name>::T> 1604 bool CastFloatingIntegral(InterpState &S, CodePtr OpPC) { 1605 const Floating &F = S.Stk.pop<Floating>(); 1606 1607 if constexpr (std::is_same_v<T, Boolean>) { 1608 S.Stk.push<T>(T(F.isNonZero())); 1609 return true; 1610 } else { 1611 APSInt Result(std::max(8u, T::bitWidth()), 1612 /*IsUnsigned=*/!T::isSigned()); 1613 auto Status = F.convertToInteger(Result); 1614 1615 // Float-to-Integral overflow check. 1616 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1617 const Expr *E = S.Current->getExpr(OpPC); 1618 QualType Type = E->getType(); 1619 1620 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1621 if (S.noteUndefinedBehavior()) { 1622 S.Stk.push<T>(T(Result)); 1623 return true; 1624 } 1625 return false; 1626 } 1627 1628 S.Stk.push<T>(T(Result)); 1629 return CheckFloatResult(S, OpPC, F, Status); 1630 } 1631 } 1632 1633 static inline bool CastFloatingIntegralAP(InterpState &S, CodePtr OpPC, 1634 uint32_t BitWidth) { 1635 const Floating &F = S.Stk.pop<Floating>(); 1636 1637 APSInt Result(BitWidth, /*IsUnsigned=*/true); 1638 auto Status = F.convertToInteger(Result); 1639 1640 // Float-to-Integral overflow check. 1641 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1642 const Expr *E = S.Current->getExpr(OpPC); 1643 QualType Type = E->getType(); 1644 1645 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1646 return S.noteUndefinedBehavior(); 1647 } 1648 1649 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 1650 return CheckFloatResult(S, OpPC, F, Status); 1651 } 1652 1653 static inline bool CastFloatingIntegralAPS(InterpState &S, CodePtr OpPC, 1654 uint32_t BitWidth) { 1655 const Floating &F = S.Stk.pop<Floating>(); 1656 1657 APSInt Result(BitWidth, /*IsUnsigned=*/false); 1658 auto Status = F.convertToInteger(Result); 1659 1660 // Float-to-Integral overflow check. 1661 if ((Status & APFloat::opStatus::opInvalidOp) && F.isFinite()) { 1662 const Expr *E = S.Current->getExpr(OpPC); 1663 QualType Type = E->getType(); 1664 1665 S.CCEDiag(E, diag::note_constexpr_overflow) << F.getAPFloat() << Type; 1666 return S.noteUndefinedBehavior(); 1667 } 1668 1669 S.Stk.push<IntegralAP<true>>(IntegralAP<true>(Result)); 1670 return CheckFloatResult(S, OpPC, F, Status); 1671 } 1672 1673 template <PrimType Name, class T = typename PrimConv<Name>::T> 1674 bool CastPointerIntegral(InterpState &S, CodePtr OpPC) { 1675 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1676 1677 if (!CheckPotentialReinterpretCast(S, OpPC, Ptr)) 1678 return false; 1679 1680 S.Stk.push<T>(T::from(Ptr.getIntegerRepresentation())); 1681 return true; 1682 } 1683 1684 //===----------------------------------------------------------------------===// 1685 // Zero, Nullptr 1686 //===----------------------------------------------------------------------===// 1687 1688 template <PrimType Name, class T = typename PrimConv<Name>::T> 1689 bool Zero(InterpState &S, CodePtr OpPC) { 1690 S.Stk.push<T>(T::zero()); 1691 return true; 1692 } 1693 1694 static inline bool ZeroIntAP(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1695 S.Stk.push<IntegralAP<false>>(IntegralAP<false>::zero(BitWidth)); 1696 return true; 1697 } 1698 1699 static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) { 1700 S.Stk.push<IntegralAP<true>>(IntegralAP<true>::zero(BitWidth)); 1701 return true; 1702 } 1703 1704 template <PrimType Name, class T = typename PrimConv<Name>::T> 1705 inline bool Null(InterpState &S, CodePtr OpPC) { 1706 S.Stk.push<T>(); 1707 return true; 1708 } 1709 1710 //===----------------------------------------------------------------------===// 1711 // This, ImplicitThis 1712 //===----------------------------------------------------------------------===// 1713 1714 inline bool This(InterpState &S, CodePtr OpPC) { 1715 // Cannot read 'this' in this mode. 1716 if (S.checkingPotentialConstantExpression()) { 1717 return false; 1718 } 1719 1720 const Pointer &This = S.Current->getThis(); 1721 if (!CheckThis(S, OpPC, This)) 1722 return false; 1723 1724 S.Stk.push<Pointer>(This); 1725 return true; 1726 } 1727 1728 inline bool RVOPtr(InterpState &S, CodePtr OpPC) { 1729 assert(S.Current->getFunction()->hasRVO()); 1730 if (S.checkingPotentialConstantExpression()) 1731 return false; 1732 S.Stk.push<Pointer>(S.Current->getRVOPtr()); 1733 return true; 1734 } 1735 1736 //===----------------------------------------------------------------------===// 1737 // Shr, Shl 1738 //===----------------------------------------------------------------------===// 1739 1740 template <PrimType NameL, PrimType NameR> 1741 inline bool Shr(InterpState &S, CodePtr OpPC) { 1742 using LT = typename PrimConv<NameL>::T; 1743 using RT = typename PrimConv<NameR>::T; 1744 const auto &RHS = S.Stk.pop<RT>(); 1745 const auto &LHS = S.Stk.pop<LT>(); 1746 const unsigned Bits = LHS.bitWidth(); 1747 1748 if (!CheckShift(S, OpPC, LHS, RHS, Bits)) 1749 return false; 1750 1751 typename LT::AsUnsigned R; 1752 LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS), 1753 LT::AsUnsigned::from(RHS), Bits, &R); 1754 S.Stk.push<LT>(LT::from(R)); 1755 1756 return true; 1757 } 1758 1759 template <PrimType NameL, PrimType NameR> 1760 inline bool Shl(InterpState &S, CodePtr OpPC) { 1761 using LT = typename PrimConv<NameL>::T; 1762 using RT = typename PrimConv<NameR>::T; 1763 const auto &RHS = S.Stk.pop<RT>(); 1764 const auto &LHS = S.Stk.pop<LT>(); 1765 const unsigned Bits = LHS.bitWidth(); 1766 1767 if (!CheckShift(S, OpPC, LHS, RHS, Bits)) 1768 return false; 1769 1770 typename LT::AsUnsigned R; 1771 LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS), 1772 LT::AsUnsigned::from(RHS, Bits), Bits, &R); 1773 S.Stk.push<LT>(LT::from(R)); 1774 return true; 1775 } 1776 1777 //===----------------------------------------------------------------------===// 1778 // NoRet 1779 //===----------------------------------------------------------------------===// 1780 1781 inline bool NoRet(InterpState &S, CodePtr OpPC) { 1782 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 1783 S.FFDiag(EndLoc, diag::note_constexpr_no_return); 1784 return false; 1785 } 1786 1787 //===----------------------------------------------------------------------===// 1788 // NarrowPtr, ExpandPtr 1789 //===----------------------------------------------------------------------===// 1790 1791 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 1792 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1793 S.Stk.push<Pointer>(Ptr.narrow()); 1794 return true; 1795 } 1796 1797 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 1798 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1799 S.Stk.push<Pointer>(Ptr.expand()); 1800 return true; 1801 } 1802 1803 // 1) Pops an integral value from the stack 1804 // 2) Peeks a pointer 1805 // 3) Pushes a new pointer that's a narrowed array 1806 // element of the peeked pointer with the value 1807 // from 1) added as offset. 1808 // 1809 // This leaves the original pointer on the stack and pushes a new one 1810 // with the offset applied and narrowed. 1811 template <PrimType Name, class T = typename PrimConv<Name>::T> 1812 inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) { 1813 const T &Offset = S.Stk.pop<T>(); 1814 const Pointer &Ptr = S.Stk.peek<Pointer>(); 1815 1816 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 1817 return false; 1818 1819 return NarrowPtr(S, OpPC); 1820 } 1821 1822 /// Just takes a pointer and checks if its' an incomplete 1823 /// array type. 1824 inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { 1825 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1826 1827 if (!Ptr.isUnknownSizeArray()) { 1828 S.Stk.push<Pointer>(Ptr.atIndex(0)); 1829 return true; 1830 } 1831 1832 const SourceInfo &E = S.Current->getSource(OpPC); 1833 S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array); 1834 1835 return false; 1836 } 1837 1838 template <PrimType Name, class T = typename PrimConv<Name>::T> 1839 inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) { 1840 const T &Offset = S.Stk.pop<T>(); 1841 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1842 1843 if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr)) 1844 return false; 1845 1846 return NarrowPtr(S, OpPC); 1847 } 1848 1849 inline bool CheckGlobalCtor(InterpState &S, CodePtr OpPC) { 1850 const Pointer &Obj = S.Stk.peek<Pointer>(); 1851 return CheckCtorCall(S, OpPC, Obj); 1852 } 1853 1854 inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) { 1855 if (Func->hasThisPointer()) { 1856 size_t ThisOffset = 1857 Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 1858 1859 const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 1860 1861 // If the current function is a lambda static invoker and 1862 // the function we're about to call is a lambda call operator, 1863 // skip the CheckInvoke, since the ThisPtr is a null pointer 1864 // anyway. 1865 if (!(S.Current->getFunction() && 1866 S.Current->getFunction()->isLambdaStaticInvoker() && 1867 Func->isLambdaCallOperator())) { 1868 if (!CheckInvoke(S, OpPC, ThisPtr)) 1869 return false; 1870 } 1871 1872 if (S.checkingPotentialConstantExpression()) 1873 return false; 1874 } 1875 1876 if (!CheckCallable(S, OpPC, Func)) 1877 return false; 1878 1879 if (!CheckCallDepth(S, OpPC)) 1880 return false; 1881 1882 auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC); 1883 InterpFrame *FrameBefore = S.Current; 1884 S.Current = NewFrame.get(); 1885 1886 APValue CallResult; 1887 // Note that we cannot assert(CallResult.hasValue()) here since 1888 // Ret() above only sets the APValue if the curent frame doesn't 1889 // have a caller set. 1890 if (Interpret(S, CallResult)) { 1891 NewFrame.release(); // Frame was delete'd already. 1892 assert(S.Current == FrameBefore); 1893 return true; 1894 } 1895 1896 // Interpreting the function failed somehow. Reset to 1897 // previous state. 1898 S.Current = FrameBefore; 1899 return false; 1900 } 1901 1902 inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) { 1903 assert(Func->hasThisPointer()); 1904 assert(Func->isVirtual()); 1905 size_t ThisOffset = 1906 Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0); 1907 Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset); 1908 1909 const CXXRecordDecl *DynamicDecl = 1910 ThisPtr.getDeclDesc()->getType()->getAsCXXRecordDecl(); 1911 const auto *StaticDecl = cast<CXXRecordDecl>(Func->getParentDecl()); 1912 const auto *InitialFunction = cast<CXXMethodDecl>(Func->getDecl()); 1913 const CXXMethodDecl *Overrider = S.getContext().getOverridingFunction( 1914 DynamicDecl, StaticDecl, InitialFunction); 1915 1916 if (Overrider != InitialFunction) { 1917 // DR1872: An instantiated virtual constexpr function can't be called in a 1918 // constant expression (prior to C++20). We can still constant-fold such a 1919 // call. 1920 if (!S.getLangOpts().CPlusPlus20 && Overrider->isVirtual()) { 1921 const Expr *E = S.Current->getExpr(OpPC); 1922 S.CCEDiag(E, diag::note_constexpr_virtual_call) << E->getSourceRange(); 1923 } 1924 1925 Func = S.getContext().getOrCreateFunction(Overrider); 1926 1927 const CXXRecordDecl *ThisFieldDecl = 1928 ThisPtr.getFieldDesc()->getType()->getAsCXXRecordDecl(); 1929 if (Func->getParentDecl()->isDerivedFrom(ThisFieldDecl)) { 1930 // If the function we call is further DOWN the hierarchy than the 1931 // FieldDesc of our pointer, just get the DeclDesc instead, which 1932 // is the furthest we might go up in the hierarchy. 1933 ThisPtr = ThisPtr.getDeclPtr(); 1934 } 1935 } 1936 1937 return Call(S, OpPC, Func); 1938 } 1939 1940 inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func, 1941 const CallExpr *CE) { 1942 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC); 1943 1944 InterpFrame *FrameBefore = S.Current; 1945 S.Current = NewFrame.get(); 1946 1947 if (InterpretBuiltin(S, PC, Func, CE)) { 1948 NewFrame.release(); 1949 return true; 1950 } 1951 S.Current = FrameBefore; 1952 return false; 1953 } 1954 1955 inline bool CallPtr(InterpState &S, CodePtr OpPC) { 1956 const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>(); 1957 1958 const Function *F = FuncPtr.getFunction(); 1959 if (!F || !F->isConstexpr()) 1960 return false; 1961 1962 if (F->isVirtual()) 1963 return CallVirt(S, OpPC, F); 1964 1965 return Call(S, OpPC, F); 1966 } 1967 1968 inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) { 1969 assert(Func); 1970 S.Stk.push<FunctionPointer>(Func); 1971 return true; 1972 } 1973 1974 /// Just emit a diagnostic. The expression that caused emission of this 1975 /// op is not valid in a constant context. 1976 inline bool Invalid(InterpState &S, CodePtr OpPC) { 1977 const SourceLocation &Loc = S.Current->getLocation(OpPC); 1978 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr) 1979 << S.Current->getRange(OpPC); 1980 return false; 1981 } 1982 1983 /// Same here, but only for casts. 1984 inline bool InvalidCast(InterpState &S, CodePtr OpPC, CastKind Kind) { 1985 const SourceLocation &Loc = S.Current->getLocation(OpPC); 1986 S.FFDiag(Loc, diag::note_constexpr_invalid_cast) 1987 << static_cast<unsigned>(Kind) << S.Current->getRange(OpPC); 1988 return false; 1989 } 1990 1991 inline bool InvalidDeclRef(InterpState &S, CodePtr OpPC, 1992 const DeclRefExpr *DR) { 1993 assert(DR); 1994 return CheckDeclRef(S, OpPC, DR); 1995 } 1996 1997 template <PrimType Name, class T = typename PrimConv<Name>::T> 1998 inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) { 1999 llvm::SmallVector<int64_t> ArrayIndices; 2000 for (size_t I = 0; I != E->getNumExpressions(); ++I) 2001 ArrayIndices.emplace_back(S.Stk.pop<int64_t>()); 2002 2003 int64_t Result; 2004 if (!InterpretOffsetOf(S, OpPC, E, ArrayIndices, Result)) 2005 return false; 2006 2007 S.Stk.push<T>(T::from(Result)); 2008 2009 return true; 2010 } 2011 2012 //===----------------------------------------------------------------------===// 2013 // Read opcode arguments 2014 //===----------------------------------------------------------------------===// 2015 2016 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { 2017 if constexpr (std::is_pointer<T>::value) { 2018 uint32_t ID = OpPC.read<uint32_t>(); 2019 return reinterpret_cast<T>(S.P.getNativePointer(ID)); 2020 } else { 2021 return OpPC.read<T>(); 2022 } 2023 } 2024 2025 template <> inline Floating ReadArg<Floating>(InterpState &S, CodePtr &OpPC) { 2026 Floating F = Floating::deserialize(*OpPC); 2027 OpPC += align(F.bytesToSerialize()); 2028 return F; 2029 } 2030 2031 } // namespace interp 2032 } // namespace clang 2033 2034 #endif 2035