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 "Function.h" 18 #include "InterpFrame.h" 19 #include "InterpStack.h" 20 #include "InterpState.h" 21 #include "Opcode.h" 22 #include "PrimType.h" 23 #include "Program.h" 24 #include "State.h" 25 #include "clang/AST/ASTContext.h" 26 #include "clang/AST/ASTDiagnostic.h" 27 #include "clang/AST/CXXInheritance.h" 28 #include "clang/AST/Expr.h" 29 #include "llvm/ADT/APFloat.h" 30 #include "llvm/ADT/APSInt.h" 31 #include "llvm/Support/Endian.h" 32 #include <limits> 33 #include <type_traits> 34 35 namespace clang { 36 namespace interp { 37 38 using APInt = llvm::APInt; 39 using APSInt = llvm::APSInt; 40 41 /// Convert a value to an APValue. 42 template <typename T> bool ReturnValue(const T &V, APValue &R) { 43 R = V.toAPValue(); 44 return true; 45 } 46 47 /// Checks if the variable has externally defined storage. 48 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 49 50 /// Checks if the array is offsetable. 51 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 52 53 /// Checks if a pointer is live and accessible. 54 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 55 AccessKinds AK); 56 /// Checks if a pointer is null. 57 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 58 CheckSubobjectKind CSK); 59 60 /// Checks if a pointer is in range. 61 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 62 AccessKinds AK); 63 64 /// Checks if a field from which a pointer is going to be derived is valid. 65 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 66 CheckSubobjectKind CSK); 67 68 /// Checks if a pointer points to const storage. 69 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 70 71 /// Checks if a pointer points to a mutable field. 72 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 73 74 /// Checks if a value can be loaded from a block. 75 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 76 77 /// Checks if a value can be stored in a block. 78 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 79 80 /// Checks if a method can be invoked on an object. 81 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 82 83 /// Checks if a value can be initialized. 84 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 85 86 /// Checks if a method can be called. 87 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F); 88 89 /// Checks the 'this' pointer. 90 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 91 92 /// Checks if a method is pure virtual. 93 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 94 95 /// Checks that all fields are initialized after a constructor call. 96 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This); 97 98 /// Checks if the shift operation is legal. 99 template <typename RT> 100 bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) { 101 if (RHS.isNegative()) { 102 const SourceInfo &Loc = S.Current->getSource(OpPC); 103 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 104 return false; 105 } 106 107 // C++11 [expr.shift]p1: Shift width must be less than the bit width of 108 // the shifted type. 109 if (Bits > 1 && RHS >= RT::from(Bits, RHS.bitWidth())) { 110 const Expr *E = S.Current->getExpr(OpPC); 111 const APSInt Val = RHS.toAPSInt(); 112 QualType Ty = E->getType(); 113 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; 114 return false; 115 } 116 return true; 117 } 118 119 /// Checks if Div/Rem operation on LHS and RHS is valid. 120 template <typename T> 121 bool CheckDivRem(InterpState &S, CodePtr OpPC, const T &LHS, const T &RHS) { 122 if (RHS.isZero()) { 123 const SourceInfo &Loc = S.Current->getSource(OpPC); 124 S.FFDiag(Loc, diag::note_expr_divide_by_zero); 125 return false; 126 } 127 128 if (LHS.isSigned() && LHS.isMin() && RHS.isNegative() && RHS.isMinusOne()) { 129 APSInt LHSInt = LHS.toAPSInt(); 130 SmallString<32> Trunc; 131 (-LHSInt.extend(LHSInt.getBitWidth() + 1)).toString(Trunc, 10); 132 const SourceInfo &Loc = S.Current->getSource(OpPC); 133 const Expr *E = S.Current->getExpr(OpPC); 134 S.CCEDiag(Loc, diag::note_constexpr_overflow) << Trunc << E->getType(); 135 return false; 136 } 137 return true; 138 } 139 140 /// Interpreter entry point. 141 bool Interpret(InterpState &S, APValue &Result); 142 143 //===----------------------------------------------------------------------===// 144 // Add, Sub, Mul 145 //===----------------------------------------------------------------------===// 146 147 template <typename T, bool (*OpFW)(T, T, unsigned, T *), 148 template <typename U> class OpAP> 149 bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, 150 const T &RHS) { 151 // Fast path - add the numbers with fixed width. 152 T Result; 153 if (!OpFW(LHS, RHS, Bits, &Result)) { 154 S.Stk.push<T>(Result); 155 return true; 156 } 157 158 // If for some reason evaluation continues, use the truncated results. 159 S.Stk.push<T>(Result); 160 161 // Slow path - compute the result using another bit of precision. 162 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); 163 164 // Report undefined behaviour, stopping if required. 165 const Expr *E = S.Current->getExpr(OpPC); 166 QualType Type = E->getType(); 167 if (S.checkingForUndefinedBehavior()) { 168 SmallString<32> Trunc; 169 Value.trunc(Result.bitWidth()).toString(Trunc, 10); 170 auto Loc = E->getExprLoc(); 171 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type; 172 return true; 173 } else { 174 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 175 return S.noteUndefinedBehavior(); 176 } 177 } 178 179 template <PrimType Name, class T = typename PrimConv<Name>::T> 180 bool Add(InterpState &S, CodePtr OpPC) { 181 const T &RHS = S.Stk.pop<T>(); 182 const T &LHS = S.Stk.pop<T>(); 183 const unsigned Bits = RHS.bitWidth() + 1; 184 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); 185 } 186 187 template <PrimType Name, class T = typename PrimConv<Name>::T> 188 bool Sub(InterpState &S, CodePtr OpPC) { 189 const T &RHS = S.Stk.pop<T>(); 190 const T &LHS = S.Stk.pop<T>(); 191 const unsigned Bits = RHS.bitWidth() + 1; 192 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); 193 } 194 195 template <PrimType Name, class T = typename PrimConv<Name>::T> 196 bool Mul(InterpState &S, CodePtr OpPC) { 197 const T &RHS = S.Stk.pop<T>(); 198 const T &LHS = S.Stk.pop<T>(); 199 const unsigned Bits = RHS.bitWidth() * 2; 200 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); 201 } 202 203 /// 1) Pops the RHS from the stack. 204 /// 2) Pops the LHS from the stack. 205 /// 3) Pushes 'LHS & RHS' on the stack 206 template <PrimType Name, class T = typename PrimConv<Name>::T> 207 bool BitAnd(InterpState &S, CodePtr OpPC) { 208 const T &RHS = S.Stk.pop<T>(); 209 const T &LHS = S.Stk.pop<T>(); 210 211 unsigned Bits = RHS.bitWidth(); 212 T Result; 213 if (!T::bitAnd(LHS, RHS, Bits, &Result)) { 214 S.Stk.push<T>(Result); 215 return true; 216 } 217 return false; 218 } 219 220 /// 1) Pops the RHS from the stack. 221 /// 2) Pops the LHS from the stack. 222 /// 3) Pushes 'LHS | RHS' on the stack 223 template <PrimType Name, class T = typename PrimConv<Name>::T> 224 bool BitOr(InterpState &S, CodePtr OpPC) { 225 const T &RHS = S.Stk.pop<T>(); 226 const T &LHS = S.Stk.pop<T>(); 227 228 unsigned Bits = RHS.bitWidth(); 229 T Result; 230 if (!T::bitOr(LHS, RHS, Bits, &Result)) { 231 S.Stk.push<T>(Result); 232 return true; 233 } 234 return false; 235 } 236 237 /// 1) Pops the RHS from the stack. 238 /// 2) Pops the LHS from the stack. 239 /// 3) Pushes 'LHS ^ RHS' on the stack 240 template <PrimType Name, class T = typename PrimConv<Name>::T> 241 bool BitXor(InterpState &S, CodePtr OpPC) { 242 const T &RHS = S.Stk.pop<T>(); 243 const T &LHS = S.Stk.pop<T>(); 244 245 unsigned Bits = RHS.bitWidth(); 246 T Result; 247 if (!T::bitXor(LHS, RHS, Bits, &Result)) { 248 S.Stk.push<T>(Result); 249 return true; 250 } 251 return false; 252 } 253 254 /// 1) Pops the RHS from the stack. 255 /// 2) Pops the LHS from the stack. 256 /// 3) Pushes 'LHS % RHS' on the stack (the remainder of dividing LHS by RHS). 257 template <PrimType Name, class T = typename PrimConv<Name>::T> 258 bool Rem(InterpState &S, CodePtr OpPC) { 259 const T &RHS = S.Stk.pop<T>(); 260 const T &LHS = S.Stk.pop<T>(); 261 262 if (!CheckDivRem(S, OpPC, LHS, RHS)) 263 return false; 264 265 const unsigned Bits = RHS.bitWidth() * 2; 266 T Result; 267 if (!T::rem(LHS, RHS, Bits, &Result)) { 268 S.Stk.push<T>(Result); 269 return true; 270 } 271 return false; 272 } 273 274 /// 1) Pops the RHS from the stack. 275 /// 2) Pops the LHS from the stack. 276 /// 3) Pushes 'LHS / RHS' on the stack 277 template <PrimType Name, class T = typename PrimConv<Name>::T> 278 bool Div(InterpState &S, CodePtr OpPC) { 279 const T &RHS = S.Stk.pop<T>(); 280 const T &LHS = S.Stk.pop<T>(); 281 282 if (!CheckDivRem(S, OpPC, LHS, RHS)) 283 return false; 284 285 const unsigned Bits = RHS.bitWidth() * 2; 286 T Result; 287 if (!T::div(LHS, RHS, Bits, &Result)) { 288 S.Stk.push<T>(Result); 289 return true; 290 } 291 return false; 292 } 293 294 //===----------------------------------------------------------------------===// 295 // Inv 296 //===----------------------------------------------------------------------===// 297 298 template <PrimType Name, class T = typename PrimConv<Name>::T> 299 bool Inv(InterpState &S, CodePtr OpPC) { 300 using BoolT = PrimConv<PT_Bool>::T; 301 const T &Val = S.Stk.pop<T>(); 302 const unsigned Bits = Val.bitWidth(); 303 Boolean R; 304 Boolean::inv(BoolT::from(Val, Bits), &R); 305 306 S.Stk.push<BoolT>(R); 307 return true; 308 } 309 310 //===----------------------------------------------------------------------===// 311 // Neg 312 //===----------------------------------------------------------------------===// 313 314 template <PrimType Name, class T = typename PrimConv<Name>::T> 315 bool Neg(InterpState &S, CodePtr OpPC) { 316 const T &Val = S.Stk.pop<T>(); 317 T Result; 318 T::neg(Val, &Result); 319 320 S.Stk.push<T>(Result); 321 return true; 322 } 323 324 enum class PushVal : bool { 325 No, 326 Yes, 327 }; 328 enum class IncDecOp { 329 Inc, 330 Dec, 331 }; 332 333 template <typename T, IncDecOp Op, PushVal DoPush> 334 bool IncDecHelper(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 335 T Value = Ptr.deref<T>(); 336 T Result; 337 338 if constexpr (DoPush == PushVal::Yes) 339 S.Stk.push<T>(Result); 340 341 if constexpr (Op == IncDecOp::Inc) { 342 if (!T::increment(Value, &Result)) { 343 Ptr.deref<T>() = Result; 344 return true; 345 } 346 } else { 347 if (!T::decrement(Value, &Result)) { 348 Ptr.deref<T>() = Result; 349 return true; 350 } 351 } 352 353 // Something went wrong with the previous operation. Compute the 354 // result with another bit of precision. 355 unsigned Bits = Value.bitWidth() + 1; 356 APSInt APResult; 357 if constexpr (Op == IncDecOp::Inc) 358 APResult = ++Value.toAPSInt(Bits); 359 else 360 APResult = --Value.toAPSInt(Bits); 361 362 // Report undefined behaviour, stopping if required. 363 const Expr *E = S.Current->getExpr(OpPC); 364 QualType Type = E->getType(); 365 if (S.checkingForUndefinedBehavior()) { 366 SmallString<32> Trunc; 367 APResult.trunc(Result.bitWidth()).toString(Trunc, 10); 368 auto Loc = E->getExprLoc(); 369 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type; 370 return true; 371 } 372 373 S.CCEDiag(E, diag::note_constexpr_overflow) << APResult << Type; 374 return S.noteUndefinedBehavior(); 375 } 376 377 /// 1) Pops a pointer from the stack 378 /// 2) Load the value from the pointer 379 /// 3) Writes the value increased by one back to the pointer 380 /// 4) Pushes the original (pre-inc) value on the stack. 381 template <PrimType Name, class T = typename PrimConv<Name>::T> 382 bool Inc(InterpState &S, CodePtr OpPC) { 383 // FIXME: Check initialization of Ptr 384 const Pointer &Ptr = S.Stk.pop<Pointer>(); 385 386 return IncDecHelper<T, IncDecOp::Inc, PushVal::Yes>(S, OpPC, Ptr); 387 } 388 389 /// 1) Pops a pointer from the stack 390 /// 2) Load the value from the pointer 391 /// 3) Writes the value increased by one back to the pointer 392 template <PrimType Name, class T = typename PrimConv<Name>::T> 393 bool IncPop(InterpState &S, CodePtr OpPC) { 394 // FIXME: Check initialization of Ptr 395 const Pointer &Ptr = S.Stk.pop<Pointer>(); 396 397 return IncDecHelper<T, IncDecOp::Inc, PushVal::No>(S, OpPC, Ptr); 398 } 399 400 /// 1) Pops a pointer from the stack 401 /// 2) Load the value from the pointer 402 /// 3) Writes the value decreased by one back to the pointer 403 /// 4) Pushes the original (pre-dec) value on the stack. 404 template <PrimType Name, class T = typename PrimConv<Name>::T> 405 bool Dec(InterpState &S, CodePtr OpPC) { 406 // FIXME: Check initialization of Ptr 407 const Pointer &Ptr = S.Stk.pop<Pointer>(); 408 409 return IncDecHelper<T, IncDecOp::Dec, PushVal::Yes>(S, OpPC, Ptr); 410 } 411 412 /// 1) Pops a pointer from the stack 413 /// 2) Load the value from the pointer 414 /// 3) Writes the value decreased by one back to the pointer 415 template <PrimType Name, class T = typename PrimConv<Name>::T> 416 bool DecPop(InterpState &S, CodePtr OpPC) { 417 // FIXME: Check initialization of Ptr 418 const Pointer &Ptr = S.Stk.pop<Pointer>(); 419 420 return IncDecHelper<T, IncDecOp::Dec, PushVal::No>(S, OpPC, Ptr); 421 } 422 423 /// 1) Pops the value from the stack. 424 /// 2) Pushes the bitwise complemented value on the stack (~V). 425 template <PrimType Name, class T = typename PrimConv<Name>::T> 426 bool Comp(InterpState &S, CodePtr OpPC) { 427 const T &Val = S.Stk.pop<T>(); 428 T Result; 429 if (!T::comp(Val, &Result)) { 430 S.Stk.push<T>(Result); 431 return true; 432 } 433 434 return false; 435 } 436 437 //===----------------------------------------------------------------------===// 438 // EQ, NE, GT, GE, LT, LE 439 //===----------------------------------------------------------------------===// 440 441 using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; 442 443 template <typename T> 444 bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { 445 using BoolT = PrimConv<PT_Bool>::T; 446 const T &RHS = S.Stk.pop<T>(); 447 const T &LHS = S.Stk.pop<T>(); 448 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); 449 return true; 450 } 451 452 template <typename T> 453 bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { 454 return CmpHelper<T>(S, OpPC, Fn); 455 } 456 457 template <> 458 inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 459 using BoolT = PrimConv<PT_Bool>::T; 460 const Pointer &RHS = S.Stk.pop<Pointer>(); 461 const Pointer &LHS = S.Stk.pop<Pointer>(); 462 463 if (!Pointer::hasSameBase(LHS, RHS)) { 464 const SourceInfo &Loc = S.Current->getSource(OpPC); 465 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 466 return false; 467 } else { 468 unsigned VL = LHS.getByteOffset(); 469 unsigned VR = RHS.getByteOffset(); 470 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 471 return true; 472 } 473 } 474 475 template <> 476 inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 477 using BoolT = PrimConv<PT_Bool>::T; 478 const Pointer &RHS = S.Stk.pop<Pointer>(); 479 const Pointer &LHS = S.Stk.pop<Pointer>(); 480 481 if (LHS.isZero() && RHS.isZero()) { 482 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); 483 return true; 484 } 485 486 if (!Pointer::hasSameBase(LHS, RHS)) { 487 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); 488 return true; 489 } else { 490 unsigned VL = LHS.getByteOffset(); 491 unsigned VR = RHS.getByteOffset(); 492 493 // In our Pointer class, a pointer to an array and a pointer to the first 494 // element in the same array are NOT equal. They have the same Base value, 495 // but a different Offset. This is a pretty rare case, so we fix this here 496 // by comparing pointers to the first elements. 497 if (LHS.inArray() && LHS.isRoot()) 498 VL = LHS.atIndex(0).getByteOffset(); 499 if (RHS.inArray() && RHS.isRoot()) 500 VR = RHS.atIndex(0).getByteOffset(); 501 502 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 503 return true; 504 } 505 } 506 507 template <PrimType Name, class T = typename PrimConv<Name>::T> 508 bool EQ(InterpState &S, CodePtr OpPC) { 509 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 510 return R == ComparisonCategoryResult::Equal; 511 }); 512 } 513 514 template <PrimType Name, class T = typename PrimConv<Name>::T> 515 bool NE(InterpState &S, CodePtr OpPC) { 516 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 517 return R != ComparisonCategoryResult::Equal; 518 }); 519 } 520 521 template <PrimType Name, class T = typename PrimConv<Name>::T> 522 bool LT(InterpState &S, CodePtr OpPC) { 523 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 524 return R == ComparisonCategoryResult::Less; 525 }); 526 } 527 528 template <PrimType Name, class T = typename PrimConv<Name>::T> 529 bool LE(InterpState &S, CodePtr OpPC) { 530 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 531 return R == ComparisonCategoryResult::Less || 532 R == ComparisonCategoryResult::Equal; 533 }); 534 } 535 536 template <PrimType Name, class T = typename PrimConv<Name>::T> 537 bool GT(InterpState &S, CodePtr OpPC) { 538 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 539 return R == ComparisonCategoryResult::Greater; 540 }); 541 } 542 543 template <PrimType Name, class T = typename PrimConv<Name>::T> 544 bool GE(InterpState &S, CodePtr OpPC) { 545 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 546 return R == ComparisonCategoryResult::Greater || 547 R == ComparisonCategoryResult::Equal; 548 }); 549 } 550 551 //===----------------------------------------------------------------------===// 552 // InRange 553 //===----------------------------------------------------------------------===// 554 555 template <PrimType Name, class T = typename PrimConv<Name>::T> 556 bool InRange(InterpState &S, CodePtr OpPC) { 557 const T RHS = S.Stk.pop<T>(); 558 const T LHS = S.Stk.pop<T>(); 559 const T Value = S.Stk.pop<T>(); 560 561 S.Stk.push<bool>(LHS <= Value && Value <= RHS); 562 return true; 563 } 564 565 //===----------------------------------------------------------------------===// 566 // Dup, Pop, Test 567 //===----------------------------------------------------------------------===// 568 569 template <PrimType Name, class T = typename PrimConv<Name>::T> 570 bool Dup(InterpState &S, CodePtr OpPC) { 571 S.Stk.push<T>(S.Stk.peek<T>()); 572 return true; 573 } 574 575 template <PrimType Name, class T = typename PrimConv<Name>::T> 576 bool Pop(InterpState &S, CodePtr OpPC) { 577 S.Stk.pop<T>(); 578 return true; 579 } 580 581 //===----------------------------------------------------------------------===// 582 // Const 583 //===----------------------------------------------------------------------===// 584 585 template <PrimType Name, class T = typename PrimConv<Name>::T> 586 bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { 587 S.Stk.push<T>(Arg); 588 return true; 589 } 590 591 //===----------------------------------------------------------------------===// 592 // Get/Set Local/Param/Global/This 593 //===----------------------------------------------------------------------===// 594 595 template <PrimType Name, class T = typename PrimConv<Name>::T> 596 bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 597 const Pointer &Ptr = S.Current->getLocalPointer(I); 598 if (!CheckLoad(S, OpPC, Ptr)) 599 return false; 600 S.Stk.push<T>(Ptr.deref<T>()); 601 return true; 602 } 603 604 template <PrimType Name, class T = typename PrimConv<Name>::T> 605 bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 606 S.Current->setLocal<T>(I, S.Stk.pop<T>()); 607 return true; 608 } 609 610 template <PrimType Name, class T = typename PrimConv<Name>::T> 611 bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 612 if (S.checkingPotentialConstantExpression()) { 613 return false; 614 } 615 S.Stk.push<T>(S.Current->getParam<T>(I)); 616 return true; 617 } 618 619 template <PrimType Name, class T = typename PrimConv<Name>::T> 620 bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 621 S.Current->setParam<T>(I, S.Stk.pop<T>()); 622 return true; 623 } 624 625 /// 1) Peeks a pointer on the stack 626 /// 2) Pushes the value of the pointer's field on the stack 627 template <PrimType Name, class T = typename PrimConv<Name>::T> 628 bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { 629 const Pointer &Obj = S.Stk.peek<Pointer>(); 630 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 631 return false; 632 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 633 return false; 634 const Pointer &Field = Obj.atField(I); 635 if (!CheckLoad(S, OpPC, Field)) 636 return false; 637 S.Stk.push<T>(Field.deref<T>()); 638 return true; 639 } 640 641 template <PrimType Name, class T = typename PrimConv<Name>::T> 642 bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { 643 const T &Value = S.Stk.pop<T>(); 644 const Pointer &Obj = S.Stk.peek<Pointer>(); 645 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 646 return false; 647 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 648 return false; 649 const Pointer &Field = Obj.atField(I); 650 if (!CheckStore(S, OpPC, Field)) 651 return false; 652 Field.deref<T>() = Value; 653 return true; 654 } 655 656 /// 1) Pops a pointer from the stack 657 /// 2) Pushes the value of the pointer's field on the stack 658 template <PrimType Name, class T = typename PrimConv<Name>::T> 659 bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { 660 const Pointer &Obj = S.Stk.pop<Pointer>(); 661 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 662 return false; 663 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 664 return false; 665 const Pointer &Field = Obj.atField(I); 666 if (!CheckLoad(S, OpPC, Field)) 667 return false; 668 S.Stk.push<T>(Field.deref<T>()); 669 return true; 670 } 671 672 template <PrimType Name, class T = typename PrimConv<Name>::T> 673 bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 674 if (S.checkingPotentialConstantExpression()) 675 return false; 676 const Pointer &This = S.Current->getThis(); 677 if (!CheckThis(S, OpPC, This)) 678 return false; 679 const Pointer &Field = This.atField(I); 680 if (!CheckLoad(S, OpPC, Field)) 681 return false; 682 S.Stk.push<T>(Field.deref<T>()); 683 return true; 684 } 685 686 template <PrimType Name, class T = typename PrimConv<Name>::T> 687 bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 688 if (S.checkingPotentialConstantExpression()) 689 return false; 690 const T &Value = S.Stk.pop<T>(); 691 const Pointer &This = S.Current->getThis(); 692 if (!CheckThis(S, OpPC, This)) 693 return false; 694 const Pointer &Field = This.atField(I); 695 if (!CheckStore(S, OpPC, Field)) 696 return false; 697 Field.deref<T>() = Value; 698 return true; 699 } 700 701 template <PrimType Name, class T = typename PrimConv<Name>::T> 702 bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 703 auto *B = S.P.getGlobal(I); 704 if (B->isExtern()) 705 return false; 706 S.Stk.push<T>(B->deref<T>()); 707 return true; 708 } 709 710 template <PrimType Name, class T = typename PrimConv<Name>::T> 711 bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 712 // TODO: emit warning. 713 return false; 714 } 715 716 template <PrimType Name, class T = typename PrimConv<Name>::T> 717 bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 718 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 719 return true; 720 } 721 722 template <PrimType Name, class T = typename PrimConv<Name>::T> 723 bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 724 if (S.checkingPotentialConstantExpression()) 725 return false; 726 const Pointer &This = S.Current->getThis(); 727 if (!CheckThis(S, OpPC, This)) 728 return false; 729 const Pointer &Field = This.atField(I); 730 Field.deref<T>() = S.Stk.pop<T>(); 731 Field.initialize(); 732 return true; 733 } 734 735 template <PrimType Name, class T = typename PrimConv<Name>::T> 736 bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 737 if (S.checkingPotentialConstantExpression()) 738 return false; 739 const Pointer &This = S.Current->getThis(); 740 if (!CheckThis(S, OpPC, This)) 741 return false; 742 const Pointer &Field = This.atField(F->Offset); 743 const auto &Value = S.Stk.pop<T>(); 744 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 745 Field.initialize(); 746 return true; 747 } 748 749 template <PrimType Name, class T = typename PrimConv<Name>::T> 750 bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 751 if (S.checkingPotentialConstantExpression()) 752 return false; 753 const Pointer &This = S.Current->getThis(); 754 if (!CheckThis(S, OpPC, This)) 755 return false; 756 const Pointer &Field = This.atField(I); 757 Field.deref<T>() = S.Stk.pop<T>(); 758 Field.activate(); 759 Field.initialize(); 760 return true; 761 } 762 763 /// 1) Pops the value from the stack 764 /// 2) Peeks a pointer from the stack 765 /// 3) Pushes the value to field I of the pointer on the stack 766 template <PrimType Name, class T = typename PrimConv<Name>::T> 767 bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 768 const T &Value = S.Stk.pop<T>(); 769 const Pointer &Field = S.Stk.peek<Pointer>().atField(I); 770 Field.deref<T>() = Value; 771 Field.activate(); 772 Field.initialize(); 773 return true; 774 } 775 776 template <PrimType Name, class T = typename PrimConv<Name>::T> 777 bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 778 const T &Value = S.Stk.pop<T>(); 779 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset); 780 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 781 Field.activate(); 782 Field.initialize(); 783 return true; 784 } 785 786 template <PrimType Name, class T = typename PrimConv<Name>::T> 787 bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 788 const T &Value = S.Stk.pop<T>(); 789 const Pointer &Ptr = S.Stk.pop<Pointer>(); 790 const Pointer &Field = Ptr.atField(I); 791 Field.deref<T>() = Value; 792 Field.activate(); 793 Field.initialize(); 794 return true; 795 } 796 797 //===----------------------------------------------------------------------===// 798 // GetPtr Local/Param/Global/Field/This 799 //===----------------------------------------------------------------------===// 800 801 inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 802 S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 803 return true; 804 } 805 806 inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 807 if (S.checkingPotentialConstantExpression()) { 808 return false; 809 } 810 S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 811 return true; 812 } 813 814 inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 815 S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 816 return true; 817 } 818 819 /// 1) Pops a Pointer from the stack 820 /// 2) Pushes Pointer.atField(Off) on the stack 821 inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { 822 const Pointer &Ptr = S.Stk.pop<Pointer>(); 823 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 824 return false; 825 if (!CheckExtern(S, OpPC, Ptr)) 826 return false; 827 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 828 return false; 829 S.Stk.push<Pointer>(Ptr.atField(Off)); 830 return true; 831 } 832 833 inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 834 if (S.checkingPotentialConstantExpression()) 835 return false; 836 const Pointer &This = S.Current->getThis(); 837 if (!CheckThis(S, OpPC, This)) 838 return false; 839 S.Stk.push<Pointer>(This.atField(Off)); 840 return true; 841 } 842 843 inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 844 const Pointer &Ptr = S.Stk.pop<Pointer>(); 845 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 846 return false; 847 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 848 return false; 849 Pointer Field = Ptr.atField(Off); 850 Ptr.deactivate(); 851 Field.activate(); 852 S.Stk.push<Pointer>(std::move(Field)); 853 return true; 854 } 855 856 inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 857 if (S.checkingPotentialConstantExpression()) 858 return false; 859 const Pointer &This = S.Current->getThis(); 860 if (!CheckThis(S, OpPC, This)) 861 return false; 862 Pointer Field = This.atField(Off); 863 This.deactivate(); 864 Field.activate(); 865 S.Stk.push<Pointer>(std::move(Field)); 866 return true; 867 } 868 869 inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 870 const Pointer &Ptr = S.Stk.pop<Pointer>(); 871 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 872 return false; 873 S.Stk.push<Pointer>(Ptr.atField(Off)); 874 return true; 875 } 876 877 inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 878 if (S.checkingPotentialConstantExpression()) 879 return false; 880 const Pointer &This = S.Current->getThis(); 881 if (!CheckThis(S, OpPC, This)) 882 return false; 883 S.Stk.push<Pointer>(This.atField(Off)); 884 return true; 885 } 886 887 inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 888 const Pointer &Ptr) { 889 Pointer Base = Ptr; 890 while (Base.isBaseClass()) 891 Base = Base.getBase(); 892 893 auto *Field = Base.getRecord()->getVirtualBase(Decl); 894 S.Stk.push<Pointer>(Base.atField(Field->Offset)); 895 return true; 896 } 897 898 inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { 899 const Pointer &Ptr = S.Stk.pop<Pointer>(); 900 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 901 return false; 902 return VirtBaseHelper(S, OpPC, D, Ptr); 903 } 904 905 inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 906 const RecordDecl *D) { 907 if (S.checkingPotentialConstantExpression()) 908 return false; 909 const Pointer &This = S.Current->getThis(); 910 if (!CheckThis(S, OpPC, This)) 911 return false; 912 return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 913 } 914 915 //===----------------------------------------------------------------------===// 916 // Load, Store, Init 917 //===----------------------------------------------------------------------===// 918 919 template <PrimType Name, class T = typename PrimConv<Name>::T> 920 bool Load(InterpState &S, CodePtr OpPC) { 921 const Pointer &Ptr = S.Stk.peek<Pointer>(); 922 if (!CheckLoad(S, OpPC, Ptr)) 923 return false; 924 S.Stk.push<T>(Ptr.deref<T>()); 925 return true; 926 } 927 928 template <PrimType Name, class T = typename PrimConv<Name>::T> 929 bool LoadPop(InterpState &S, CodePtr OpPC) { 930 const Pointer &Ptr = S.Stk.pop<Pointer>(); 931 if (!CheckLoad(S, OpPC, Ptr)) 932 return false; 933 S.Stk.push<T>(Ptr.deref<T>()); 934 return true; 935 } 936 937 template <PrimType Name, class T = typename PrimConv<Name>::T> 938 bool Store(InterpState &S, CodePtr OpPC) { 939 const T &Value = S.Stk.pop<T>(); 940 const Pointer &Ptr = S.Stk.peek<Pointer>(); 941 if (!CheckStore(S, OpPC, Ptr)) 942 return false; 943 if (!Ptr.isRoot()) 944 Ptr.initialize(); 945 Ptr.deref<T>() = Value; 946 return true; 947 } 948 949 template <PrimType Name, class T = typename PrimConv<Name>::T> 950 bool StorePop(InterpState &S, CodePtr OpPC) { 951 const T &Value = S.Stk.pop<T>(); 952 const Pointer &Ptr = S.Stk.pop<Pointer>(); 953 if (!CheckStore(S, OpPC, Ptr)) 954 return false; 955 if (!Ptr.isRoot()) 956 Ptr.initialize(); 957 Ptr.deref<T>() = Value; 958 return true; 959 } 960 961 template <PrimType Name, class T = typename PrimConv<Name>::T> 962 bool StoreBitField(InterpState &S, CodePtr OpPC) { 963 const T &Value = S.Stk.pop<T>(); 964 const Pointer &Ptr = S.Stk.peek<Pointer>(); 965 if (!CheckStore(S, OpPC, Ptr)) 966 return false; 967 if (!Ptr.isRoot()) 968 Ptr.initialize(); 969 if (auto *FD = Ptr.getField()) { 970 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 971 } else { 972 Ptr.deref<T>() = Value; 973 } 974 return true; 975 } 976 977 template <PrimType Name, class T = typename PrimConv<Name>::T> 978 bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 979 const T &Value = S.Stk.pop<T>(); 980 const Pointer &Ptr = S.Stk.pop<Pointer>(); 981 if (!CheckStore(S, OpPC, Ptr)) 982 return false; 983 if (!Ptr.isRoot()) 984 Ptr.initialize(); 985 if (auto *FD = Ptr.getField()) { 986 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 987 } else { 988 Ptr.deref<T>() = Value; 989 } 990 return true; 991 } 992 993 template <PrimType Name, class T = typename PrimConv<Name>::T> 994 bool InitPop(InterpState &S, CodePtr OpPC) { 995 const T &Value = S.Stk.pop<T>(); 996 const Pointer &Ptr = S.Stk.pop<Pointer>(); 997 if (!CheckInit(S, OpPC, Ptr)) 998 return false; 999 Ptr.initialize(); 1000 new (&Ptr.deref<T>()) T(Value); 1001 return true; 1002 } 1003 1004 /// 1) Pops the value from the stack 1005 /// 2) Peeks a pointer and gets its index \Idx 1006 /// 3) Sets the value on the pointer, leaving the pointer on the stack. 1007 template <PrimType Name, class T = typename PrimConv<Name>::T> 1008 bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1009 const T &Value = S.Stk.pop<T>(); 1010 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx); 1011 if (!CheckInit(S, OpPC, Ptr)) 1012 return false; 1013 Ptr.initialize(); 1014 new (&Ptr.deref<T>()) T(Value); 1015 return true; 1016 } 1017 1018 /// The same as InitElem, but pops the pointer as well. 1019 template <PrimType Name, class T = typename PrimConv<Name>::T> 1020 bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 1021 const T &Value = S.Stk.pop<T>(); 1022 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx); 1023 if (!CheckInit(S, OpPC, Ptr)) 1024 return false; 1025 Ptr.initialize(); 1026 new (&Ptr.deref<T>()) T(Value); 1027 return true; 1028 } 1029 1030 //===----------------------------------------------------------------------===// 1031 // AddOffset, SubOffset 1032 //===----------------------------------------------------------------------===// 1033 1034 template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) { 1035 // Fetch the pointer and the offset. 1036 const T &Offset = S.Stk.pop<T>(); 1037 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1038 1039 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 1040 return false; 1041 1042 // A zero offset does not change the pointer. 1043 if (Offset.isZero()) { 1044 S.Stk.push<Pointer>(Ptr); 1045 return true; 1046 } 1047 1048 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) 1049 return false; 1050 1051 // Arrays of unknown bounds cannot have pointers into them. 1052 if (!CheckArray(S, OpPC, Ptr)) 1053 return false; 1054 1055 // Get a version of the index comparable to the type. 1056 T Index = T::from(Ptr.getIndex(), Offset.bitWidth()); 1057 // Compute the largest index into the array. 1058 unsigned MaxIndex = Ptr.getNumElems(); 1059 1060 // Helper to report an invalid offset, computed as APSInt. 1061 auto InvalidOffset = [&]() { 1062 const unsigned Bits = Offset.bitWidth(); 1063 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false); 1064 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false); 1065 APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset); 1066 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 1067 << NewIndex 1068 << /*array*/ static_cast<int>(!Ptr.inArray()) 1069 << static_cast<unsigned>(MaxIndex); 1070 return false; 1071 }; 1072 1073 unsigned MaxOffset = MaxIndex - Ptr.getIndex(); 1074 if constexpr (Add) { 1075 // If the new offset would be negative, bail out. 1076 if (Offset.isNegative() && (Offset.isMin() || -Offset > Index)) 1077 return InvalidOffset(); 1078 1079 // If the new offset would be out of bounds, bail out. 1080 if (Offset.isPositive() && Offset > MaxOffset) 1081 return InvalidOffset(); 1082 } else { 1083 // If the new offset would be negative, bail out. 1084 if (Offset.isPositive() && Index < Offset) 1085 return InvalidOffset(); 1086 1087 // If the new offset would be out of bounds, bail out. 1088 if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) 1089 return InvalidOffset(); 1090 } 1091 1092 // Offset is valid - compute it on unsigned. 1093 int64_t WideIndex = static_cast<int64_t>(Index); 1094 int64_t WideOffset = static_cast<int64_t>(Offset); 1095 int64_t Result; 1096 if constexpr (Add) 1097 Result = WideIndex + WideOffset; 1098 else 1099 Result = WideIndex - WideOffset; 1100 1101 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result))); 1102 return true; 1103 } 1104 1105 template <PrimType Name, class T = typename PrimConv<Name>::T> 1106 bool AddOffset(InterpState &S, CodePtr OpPC) { 1107 return OffsetHelper<T, true>(S, OpPC); 1108 } 1109 1110 template <PrimType Name, class T = typename PrimConv<Name>::T> 1111 bool SubOffset(InterpState &S, CodePtr OpPC) { 1112 return OffsetHelper<T, false>(S, OpPC); 1113 } 1114 1115 /// 1) Pops a Pointer from the stack. 1116 /// 2) Pops another Pointer from the stack. 1117 /// 3) Pushes the different of the indices of the two pointers on the stack. 1118 template <PrimType Name, class T = typename PrimConv<Name>::T> 1119 inline bool SubPtr(InterpState &S, CodePtr OpPC) { 1120 const Pointer &LHS = S.Stk.pop<Pointer>(); 1121 const Pointer &RHS = S.Stk.pop<Pointer>(); 1122 1123 if (!Pointer::hasSameArray(LHS, RHS)) { 1124 // TODO: Diagnose. 1125 return false; 1126 } 1127 1128 T A = T::from(LHS.getIndex()); 1129 T B = T::from(RHS.getIndex()); 1130 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, A.bitWidth(), A, B); 1131 } 1132 1133 //===----------------------------------------------------------------------===// 1134 // Destroy 1135 //===----------------------------------------------------------------------===// 1136 1137 inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 1138 S.Current->destroy(I); 1139 return true; 1140 } 1141 1142 //===----------------------------------------------------------------------===// 1143 // Cast, CastFP 1144 //===----------------------------------------------------------------------===// 1145 1146 template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 1147 using T = typename PrimConv<TIn>::T; 1148 using U = typename PrimConv<TOut>::T; 1149 S.Stk.push<U>(U::from(S.Stk.pop<T>())); 1150 return true; 1151 } 1152 1153 //===----------------------------------------------------------------------===// 1154 // Zero, Nullptr 1155 //===----------------------------------------------------------------------===// 1156 1157 template <PrimType Name, class T = typename PrimConv<Name>::T> 1158 bool Zero(InterpState &S, CodePtr OpPC) { 1159 S.Stk.push<T>(T::zero()); 1160 return true; 1161 } 1162 1163 template <PrimType Name, class T = typename PrimConv<Name>::T> 1164 inline bool Null(InterpState &S, CodePtr OpPC) { 1165 S.Stk.push<T>(); 1166 return true; 1167 } 1168 1169 //===----------------------------------------------------------------------===// 1170 // This, ImplicitThis 1171 //===----------------------------------------------------------------------===// 1172 1173 inline bool This(InterpState &S, CodePtr OpPC) { 1174 // Cannot read 'this' in this mode. 1175 if (S.checkingPotentialConstantExpression()) { 1176 return false; 1177 } 1178 1179 const Pointer &This = S.Current->getThis(); 1180 if (!CheckThis(S, OpPC, This)) 1181 return false; 1182 1183 S.Stk.push<Pointer>(This); 1184 return true; 1185 } 1186 1187 inline bool RVOPtr(InterpState &S, CodePtr OpPC) { 1188 assert(S.Current->getFunction()->hasRVO()); 1189 S.Stk.push<Pointer>(S.Current->getRVOPtr()); 1190 return true; 1191 } 1192 1193 //===----------------------------------------------------------------------===// 1194 // Shr, Shl 1195 //===----------------------------------------------------------------------===// 1196 1197 template <PrimType NameL, PrimType NameR> 1198 inline bool Shr(InterpState &S, CodePtr OpPC) { 1199 using LT = typename PrimConv<NameL>::T; 1200 using RT = typename PrimConv<NameR>::T; 1201 const auto &RHS = S.Stk.pop<RT>(); 1202 const auto &LHS = S.Stk.pop<LT>(); 1203 const unsigned Bits = LHS.bitWidth(); 1204 1205 if (!CheckShift<RT>(S, OpPC, RHS, Bits)) 1206 return false; 1207 1208 unsigned URHS = static_cast<unsigned>(RHS); 1209 S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth())); 1210 return true; 1211 } 1212 1213 template <PrimType NameL, PrimType NameR> 1214 inline bool Shl(InterpState &S, CodePtr OpPC) { 1215 using LT = typename PrimConv<NameL>::T; 1216 using RT = typename PrimConv<NameR>::T; 1217 const auto &RHS = S.Stk.pop<RT>(); 1218 const auto &LHS = S.Stk.pop<LT>(); 1219 const unsigned Bits = LHS.bitWidth(); 1220 1221 if (!CheckShift<RT>(S, OpPC, RHS, Bits)) 1222 return false; 1223 1224 unsigned URHS = static_cast<unsigned>(RHS); 1225 S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth())); 1226 1227 return true; 1228 } 1229 1230 //===----------------------------------------------------------------------===// 1231 // NoRet 1232 //===----------------------------------------------------------------------===// 1233 1234 inline bool NoRet(InterpState &S, CodePtr OpPC) { 1235 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 1236 S.FFDiag(EndLoc, diag::note_constexpr_no_return); 1237 return false; 1238 } 1239 1240 //===----------------------------------------------------------------------===// 1241 // NarrowPtr, ExpandPtr 1242 //===----------------------------------------------------------------------===// 1243 1244 inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 1245 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1246 S.Stk.push<Pointer>(Ptr.narrow()); 1247 return true; 1248 } 1249 1250 inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 1251 const Pointer &Ptr = S.Stk.pop<Pointer>(); 1252 S.Stk.push<Pointer>(Ptr.expand()); 1253 return true; 1254 } 1255 1256 inline bool Call(InterpState &S, CodePtr &PC, const Function *Func) { 1257 auto NewFrame = std::make_unique<InterpFrame>(S, Func, PC); 1258 Pointer ThisPtr; 1259 if (Func->hasThisPointer()) { 1260 ThisPtr = NewFrame->getThis(); 1261 if (!CheckInvoke(S, PC, ThisPtr)) { 1262 return false; 1263 } 1264 } 1265 1266 if (!CheckCallable(S, PC, Func)) 1267 return false; 1268 1269 InterpFrame *FrameBefore = S.Current; 1270 S.Current = NewFrame.get(); 1271 1272 APValue CallResult; 1273 // Note that we cannot assert(CallResult.hasValue()) here since 1274 // Ret() above only sets the APValue if the curent frame doesn't 1275 // have a caller set. 1276 if (Interpret(S, CallResult)) { 1277 NewFrame.release(); // Frame was delete'd already. 1278 assert(S.Current == FrameBefore); 1279 1280 // For constructors, check that all fields have been initialized. 1281 if (Func->isConstructor() && !CheckCtorCall(S, PC, ThisPtr)) 1282 return false; 1283 1284 return true; 1285 } 1286 1287 // Interpreting the function failed somehow. Reset to 1288 // previous state. 1289 S.Current = FrameBefore; 1290 return false; 1291 } 1292 1293 //===----------------------------------------------------------------------===// 1294 // Read opcode arguments 1295 //===----------------------------------------------------------------------===// 1296 1297 template <typename T> inline T ReadArg(InterpState &S, CodePtr &OpPC) { 1298 if constexpr (std::is_pointer<T>::value) { 1299 uint32_t ID = OpPC.read<uint32_t>(); 1300 return reinterpret_cast<T>(S.P.getNativePointer(ID)); 1301 } else { 1302 return OpPC.read<T>(); 1303 } 1304 } 1305 1306 } // namespace interp 1307 } // namespace clang 1308 1309 #endif 1310