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