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 <limits> 17#include <vector> 18#include "Function.h" 19#include "InterpFrame.h" 20#include "InterpStack.h" 21#include "InterpState.h" 22#include "Opcode.h" 23#include "PrimType.h" 24#include "Program.h" 25#include "State.h" 26#include "clang/AST/ASTContext.h" 27#include "clang/AST/ASTDiagnostic.h" 28#include "clang/AST/CXXInheritance.h" 29#include "clang/AST/Expr.h" 30#include "llvm/ADT/APFloat.h" 31#include "llvm/ADT/APSInt.h" 32#include "llvm/Support/Endian.h" 33 34namespace clang { 35namespace interp { 36 37using APInt = llvm::APInt; 38using APSInt = llvm::APSInt; 39 40/// Convers a value to an APValue. 41template <typename T> bool ReturnValue(const T &V, APValue &R) { 42 R = V.toAPValue(); 43 return true; 44} 45 46/// Checks if the variable has externally defined storage. 47bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 48 49/// Checks if the array is offsetable. 50bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 51 52/// Checks if a pointer is live and accesible. 53bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 54 AccessKinds AK); 55/// Checks if a pointer is null. 56bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 57 CheckSubobjectKind CSK); 58 59/// Checks if a pointer is in range. 60bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 61 AccessKinds AK); 62 63/// Checks if a field from which a pointer is going to be derived is valid. 64bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 65 CheckSubobjectKind CSK); 66 67/// Checks if a pointer points to const storage. 68bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 69 70/// Checks if a pointer points to a mutable field. 71bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 72 73/// Checks if a value can be loaded from a block. 74bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 75 76/// Checks if a value can be stored in a block. 77bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 78 79/// Checks if a method can be invoked on an object. 80bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 81 82/// Checks if a value can be initialized. 83bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr); 84 85/// Checks if a method can be called. 86bool CheckCallable(InterpState &S, CodePtr OpPC, Function *F); 87 88/// Checks the 'this' pointer. 89bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This); 90 91/// Checks if a method is pure virtual. 92bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD); 93 94template <typename T> inline bool IsTrue(const T &V) { return !V.isZero(); } 95 96//===----------------------------------------------------------------------===// 97// Add, Sub, Mul 98//===----------------------------------------------------------------------===// 99 100template <typename T, bool (*OpFW)(T, T, unsigned, T *), 101 template <typename U> class OpAP> 102bool AddSubMulHelper(InterpState &S, CodePtr OpPC, unsigned Bits, const T &LHS, 103 const T &RHS) { 104 // Fast path - add the numbers with fixed width. 105 T Result; 106 if (!OpFW(LHS, RHS, Bits, &Result)) { 107 S.Stk.push<T>(Result); 108 return true; 109 } 110 111 // If for some reason evaluation continues, use the truncated results. 112 S.Stk.push<T>(Result); 113 114 // Slow path - compute the result using another bit of precision. 115 APSInt Value = OpAP<APSInt>()(LHS.toAPSInt(Bits), RHS.toAPSInt(Bits)); 116 117 // Report undefined behaviour, stopping if required. 118 const Expr *E = S.Current->getExpr(OpPC); 119 QualType Type = E->getType(); 120 if (S.checkingForUndefinedBehavior()) { 121 auto Trunc = Value.trunc(Result.bitWidth()).toString(10); 122 auto Loc = E->getExprLoc(); 123 S.report(Loc, diag::warn_integer_constant_overflow) << Trunc << Type; 124 return true; 125 } else { 126 S.CCEDiag(E, diag::note_constexpr_overflow) << Value << Type; 127 return S.noteUndefinedBehavior(); 128 } 129} 130 131template <PrimType Name, class T = typename PrimConv<Name>::T> 132bool Add(InterpState &S, CodePtr OpPC) { 133 const T &RHS = S.Stk.pop<T>(); 134 const T &LHS = S.Stk.pop<T>(); 135 const unsigned Bits = RHS.bitWidth() + 1; 136 return AddSubMulHelper<T, T::add, std::plus>(S, OpPC, Bits, LHS, RHS); 137} 138 139template <PrimType Name, class T = typename PrimConv<Name>::T> 140bool Sub(InterpState &S, CodePtr OpPC) { 141 const T &RHS = S.Stk.pop<T>(); 142 const T &LHS = S.Stk.pop<T>(); 143 const unsigned Bits = RHS.bitWidth() + 1; 144 return AddSubMulHelper<T, T::sub, std::minus>(S, OpPC, Bits, LHS, RHS); 145} 146 147template <PrimType Name, class T = typename PrimConv<Name>::T> 148bool Mul(InterpState &S, CodePtr OpPC) { 149 const T &RHS = S.Stk.pop<T>(); 150 const T &LHS = S.Stk.pop<T>(); 151 const unsigned Bits = RHS.bitWidth() * 2; 152 return AddSubMulHelper<T, T::mul, std::multiplies>(S, OpPC, Bits, LHS, RHS); 153} 154 155//===----------------------------------------------------------------------===// 156// EQ, NE, GT, GE, LT, LE 157//===----------------------------------------------------------------------===// 158 159using CompareFn = llvm::function_ref<bool(ComparisonCategoryResult)>; 160 161template <typename T> 162bool CmpHelper(InterpState &S, CodePtr OpPC, CompareFn Fn) { 163 using BoolT = PrimConv<PT_Bool>::T; 164 const T &RHS = S.Stk.pop<T>(); 165 const T &LHS = S.Stk.pop<T>(); 166 S.Stk.push<BoolT>(BoolT::from(Fn(LHS.compare(RHS)))); 167 return true; 168} 169 170template <typename T> 171bool CmpHelperEQ(InterpState &S, CodePtr OpPC, CompareFn Fn) { 172 return CmpHelper<T>(S, OpPC, Fn); 173} 174 175template <> 176inline bool CmpHelper<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 177 using BoolT = PrimConv<PT_Bool>::T; 178 const Pointer &RHS = S.Stk.pop<Pointer>(); 179 const Pointer &LHS = S.Stk.pop<Pointer>(); 180 181 if (!Pointer::hasSameBase(LHS, RHS)) { 182 const SourceInfo &Loc = S.Current->getSource(OpPC); 183 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 184 return false; 185 } else { 186 unsigned VL = LHS.getByteOffset(); 187 unsigned VR = RHS.getByteOffset(); 188 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 189 return true; 190 } 191} 192 193template <> 194inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) { 195 using BoolT = PrimConv<PT_Bool>::T; 196 const Pointer &RHS = S.Stk.pop<Pointer>(); 197 const Pointer &LHS = S.Stk.pop<Pointer>(); 198 199 if (LHS.isZero() && RHS.isZero()) { 200 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Equal))); 201 return true; 202 } 203 204 if (!Pointer::hasSameBase(LHS, RHS)) { 205 S.Stk.push<BoolT>(BoolT::from(Fn(ComparisonCategoryResult::Unordered))); 206 return true; 207 } else { 208 unsigned VL = LHS.getByteOffset(); 209 unsigned VR = RHS.getByteOffset(); 210 S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR)))); 211 return true; 212 } 213} 214 215template <PrimType Name, class T = typename PrimConv<Name>::T> 216bool EQ(InterpState &S, CodePtr OpPC) { 217 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 218 return R == ComparisonCategoryResult::Equal; 219 }); 220} 221 222template <PrimType Name, class T = typename PrimConv<Name>::T> 223bool NE(InterpState &S, CodePtr OpPC) { 224 return CmpHelperEQ<T>(S, OpPC, [](ComparisonCategoryResult R) { 225 return R != ComparisonCategoryResult::Equal; 226 }); 227} 228 229template <PrimType Name, class T = typename PrimConv<Name>::T> 230bool LT(InterpState &S, CodePtr OpPC) { 231 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 232 return R == ComparisonCategoryResult::Less; 233 }); 234} 235 236template <PrimType Name, class T = typename PrimConv<Name>::T> 237bool LE(InterpState &S, CodePtr OpPC) { 238 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 239 return R == ComparisonCategoryResult::Less || 240 R == ComparisonCategoryResult::Equal; 241 }); 242} 243 244template <PrimType Name, class T = typename PrimConv<Name>::T> 245bool GT(InterpState &S, CodePtr OpPC) { 246 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 247 return R == ComparisonCategoryResult::Greater; 248 }); 249} 250 251template <PrimType Name, class T = typename PrimConv<Name>::T> 252bool GE(InterpState &S, CodePtr OpPC) { 253 return CmpHelper<T>(S, OpPC, [](ComparisonCategoryResult R) { 254 return R == ComparisonCategoryResult::Greater || 255 R == ComparisonCategoryResult::Equal; 256 }); 257} 258 259//===----------------------------------------------------------------------===// 260// InRange 261//===----------------------------------------------------------------------===// 262 263template <PrimType Name, class T = typename PrimConv<Name>::T> 264bool InRange(InterpState &S, CodePtr OpPC) { 265 const T RHS = S.Stk.pop<T>(); 266 const T LHS = S.Stk.pop<T>(); 267 const T Value = S.Stk.pop<T>(); 268 269 S.Stk.push<bool>(LHS <= Value && Value <= RHS); 270 return true; 271} 272 273//===----------------------------------------------------------------------===// 274// Dup, Pop, Test 275//===----------------------------------------------------------------------===// 276 277template <PrimType Name, class T = typename PrimConv<Name>::T> 278bool Dup(InterpState &S, CodePtr OpPC) { 279 S.Stk.push<T>(S.Stk.peek<T>()); 280 return true; 281} 282 283template <PrimType Name, class T = typename PrimConv<Name>::T> 284bool Pop(InterpState &S, CodePtr OpPC) { 285 S.Stk.pop<T>(); 286 return true; 287} 288 289//===----------------------------------------------------------------------===// 290// Const 291//===----------------------------------------------------------------------===// 292 293template <PrimType Name, class T = typename PrimConv<Name>::T> 294bool Const(InterpState &S, CodePtr OpPC, const T &Arg) { 295 S.Stk.push<T>(Arg); 296 return true; 297} 298 299//===----------------------------------------------------------------------===// 300// Get/Set Local/Param/Global/This 301//===----------------------------------------------------------------------===// 302 303template <PrimType Name, class T = typename PrimConv<Name>::T> 304bool GetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 305 S.Stk.push<T>(S.Current->getLocal<T>(I)); 306 return true; 307} 308 309template <PrimType Name, class T = typename PrimConv<Name>::T> 310bool SetLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 311 S.Current->setLocal<T>(I, S.Stk.pop<T>()); 312 return true; 313} 314 315template <PrimType Name, class T = typename PrimConv<Name>::T> 316bool GetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 317 if (S.checkingPotentialConstantExpression()) { 318 return false; 319 } 320 S.Stk.push<T>(S.Current->getParam<T>(I)); 321 return true; 322} 323 324template <PrimType Name, class T = typename PrimConv<Name>::T> 325bool SetParam(InterpState &S, CodePtr OpPC, uint32_t I) { 326 S.Current->setParam<T>(I, S.Stk.pop<T>()); 327 return true; 328} 329 330template <PrimType Name, class T = typename PrimConv<Name>::T> 331bool GetField(InterpState &S, CodePtr OpPC, uint32_t I) { 332 const Pointer &Obj = S.Stk.peek<Pointer>(); 333 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 334 return false; 335 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 336 return false; 337 const Pointer &Field = Obj.atField(I); 338 if (!CheckLoad(S, OpPC, Field)) 339 return false; 340 S.Stk.push<T>(Field.deref<T>()); 341 return true; 342} 343 344template <PrimType Name, class T = typename PrimConv<Name>::T> 345bool SetField(InterpState &S, CodePtr OpPC, uint32_t I) { 346 const T &Value = S.Stk.pop<T>(); 347 const Pointer &Obj = S.Stk.peek<Pointer>(); 348 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 349 return false; 350 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 351 return false; 352 const Pointer &Field = Obj.atField(I); 353 if (!CheckStore(S, OpPC, Field)) 354 return false; 355 Field.deref<T>() = Value; 356 return true; 357} 358 359template <PrimType Name, class T = typename PrimConv<Name>::T> 360bool GetFieldPop(InterpState &S, CodePtr OpPC, uint32_t I) { 361 const Pointer &Obj = S.Stk.pop<Pointer>(); 362 if (!CheckNull(S, OpPC, Obj, CSK_Field)) 363 return false; 364 if (!CheckRange(S, OpPC, Obj, CSK_Field)) 365 return false; 366 const Pointer &Field = Obj.atField(I); 367 if (!CheckLoad(S, OpPC, Field)) 368 return false; 369 S.Stk.push<T>(Field.deref<T>()); 370 return true; 371} 372 373template <PrimType Name, class T = typename PrimConv<Name>::T> 374bool GetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 375 if (S.checkingPotentialConstantExpression()) 376 return false; 377 const Pointer &This = S.Current->getThis(); 378 if (!CheckThis(S, OpPC, This)) 379 return false; 380 const Pointer &Field = This.atField(I); 381 if (!CheckLoad(S, OpPC, Field)) 382 return false; 383 S.Stk.push<T>(Field.deref<T>()); 384 return true; 385} 386 387template <PrimType Name, class T = typename PrimConv<Name>::T> 388bool SetThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 389 if (S.checkingPotentialConstantExpression()) 390 return false; 391 const T &Value = S.Stk.pop<T>(); 392 const Pointer &This = S.Current->getThis(); 393 if (!CheckThis(S, OpPC, This)) 394 return false; 395 const Pointer &Field = This.atField(I); 396 if (!CheckStore(S, OpPC, Field)) 397 return false; 398 Field.deref<T>() = Value; 399 return true; 400} 401 402template <PrimType Name, class T = typename PrimConv<Name>::T> 403bool GetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 404 auto *B = S.P.getGlobal(I); 405 if (B->isExtern()) 406 return false; 407 S.Stk.push<T>(B->deref<T>()); 408 return true; 409} 410 411template <PrimType Name, class T = typename PrimConv<Name>::T> 412bool SetGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 413 // TODO: emit warning. 414 return false; 415} 416 417template <PrimType Name, class T = typename PrimConv<Name>::T> 418bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 419 S.P.getGlobal(I)->deref<T>() = S.Stk.pop<T>(); 420 return true; 421} 422 423template <PrimType Name, class T = typename PrimConv<Name>::T> 424bool InitThisField(InterpState &S, CodePtr OpPC, uint32_t I) { 425 if (S.checkingPotentialConstantExpression()) 426 return false; 427 const Pointer &This = S.Current->getThis(); 428 if (!CheckThis(S, OpPC, This)) 429 return false; 430 const Pointer &Field = This.atField(I); 431 Field.deref<T>() = S.Stk.pop<T>(); 432 Field.initialize(); 433 return true; 434} 435 436template <PrimType Name, class T = typename PrimConv<Name>::T> 437bool InitThisBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 438 if (S.checkingPotentialConstantExpression()) 439 return false; 440 const Pointer &This = S.Current->getThis(); 441 if (!CheckThis(S, OpPC, This)) 442 return false; 443 const Pointer &Field = This.atField(F->Offset); 444 const auto &Value = S.Stk.pop<T>(); 445 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 446 Field.initialize(); 447 return true; 448} 449 450template <PrimType Name, class T = typename PrimConv<Name>::T> 451bool InitThisFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 452 if (S.checkingPotentialConstantExpression()) 453 return false; 454 const Pointer &This = S.Current->getThis(); 455 if (!CheckThis(S, OpPC, This)) 456 return false; 457 const Pointer &Field = This.atField(I); 458 Field.deref<T>() = S.Stk.pop<T>(); 459 Field.activate(); 460 Field.initialize(); 461 return true; 462} 463 464template <PrimType Name, class T = typename PrimConv<Name>::T> 465bool InitField(InterpState &S, CodePtr OpPC, uint32_t I) { 466 const T &Value = S.Stk.pop<T>(); 467 const Pointer &Field = S.Stk.pop<Pointer>().atField(I); 468 Field.deref<T>() = Value; 469 Field.activate(); 470 Field.initialize(); 471 return true; 472} 473 474template <PrimType Name, class T = typename PrimConv<Name>::T> 475bool InitBitField(InterpState &S, CodePtr OpPC, const Record::Field *F) { 476 const T &Value = S.Stk.pop<T>(); 477 const Pointer &Field = S.Stk.pop<Pointer>().atField(F->Offset); 478 Field.deref<T>() = Value.truncate(F->Decl->getBitWidthValue(S.getCtx())); 479 Field.activate(); 480 Field.initialize(); 481 return true; 482} 483 484template <PrimType Name, class T = typename PrimConv<Name>::T> 485bool InitFieldActive(InterpState &S, CodePtr OpPC, uint32_t I) { 486 const T &Value = S.Stk.pop<T>(); 487 const Pointer &Ptr = S.Stk.pop<Pointer>(); 488 const Pointer &Field = Ptr.atField(I); 489 Field.deref<T>() = Value; 490 Field.activate(); 491 Field.initialize(); 492 return true; 493} 494 495//===----------------------------------------------------------------------===// 496// GetPtr Local/Param/Global/Field/This 497//===----------------------------------------------------------------------===// 498 499inline bool GetPtrLocal(InterpState &S, CodePtr OpPC, uint32_t I) { 500 S.Stk.push<Pointer>(S.Current->getLocalPointer(I)); 501 return true; 502} 503 504inline bool GetPtrParam(InterpState &S, CodePtr OpPC, uint32_t I) { 505 if (S.checkingPotentialConstantExpression()) { 506 return false; 507 } 508 S.Stk.push<Pointer>(S.Current->getParamPointer(I)); 509 return true; 510} 511 512inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { 513 S.Stk.push<Pointer>(S.P.getPtrGlobal(I)); 514 return true; 515} 516 517inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { 518 const Pointer &Ptr = S.Stk.pop<Pointer>(); 519 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 520 return false; 521 if (!CheckExtern(S, OpPC, Ptr)) 522 return false; 523 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 524 return false; 525 S.Stk.push<Pointer>(Ptr.atField(Off)); 526 return true; 527} 528 529inline bool GetPtrThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 530 if (S.checkingPotentialConstantExpression()) 531 return false; 532 const Pointer &This = S.Current->getThis(); 533 if (!CheckThis(S, OpPC, This)) 534 return false; 535 S.Stk.push<Pointer>(This.atField(Off)); 536 return true; 537} 538 539inline bool GetPtrActiveField(InterpState &S, CodePtr OpPC, uint32_t Off) { 540 const Pointer &Ptr = S.Stk.pop<Pointer>(); 541 if (!CheckNull(S, OpPC, Ptr, CSK_Field)) 542 return false; 543 if (!CheckRange(S, OpPC, Ptr, CSK_Field)) 544 return false; 545 Pointer Field = Ptr.atField(Off); 546 Ptr.deactivate(); 547 Field.activate(); 548 S.Stk.push<Pointer>(std::move(Field)); 549 return true; 550} 551 552inline bool GetPtrActiveThisField(InterpState &S, CodePtr OpPC, uint32_t Off) { 553 if (S.checkingPotentialConstantExpression()) 554 return false; 555 const Pointer &This = S.Current->getThis(); 556 if (!CheckThis(S, OpPC, This)) 557 return false; 558 Pointer Field = This.atField(Off); 559 This.deactivate(); 560 Field.activate(); 561 S.Stk.push<Pointer>(std::move(Field)); 562 return true; 563} 564 565inline bool GetPtrBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 566 const Pointer &Ptr = S.Stk.pop<Pointer>(); 567 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 568 return false; 569 S.Stk.push<Pointer>(Ptr.atField(Off)); 570 return true; 571} 572 573inline bool GetPtrThisBase(InterpState &S, CodePtr OpPC, uint32_t Off) { 574 if (S.checkingPotentialConstantExpression()) 575 return false; 576 const Pointer &This = S.Current->getThis(); 577 if (!CheckThis(S, OpPC, This)) 578 return false; 579 S.Stk.push<Pointer>(This.atField(Off)); 580 return true; 581} 582 583inline bool VirtBaseHelper(InterpState &S, CodePtr OpPC, const RecordDecl *Decl, 584 const Pointer &Ptr) { 585 Pointer Base = Ptr; 586 while (Base.isBaseClass()) 587 Base = Base.getBase(); 588 589 auto *Field = Base.getRecord()->getVirtualBase(Decl); 590 S.Stk.push<Pointer>(Base.atField(Field->Offset)); 591 return true; 592} 593 594inline bool GetPtrVirtBase(InterpState &S, CodePtr OpPC, const RecordDecl *D) { 595 const Pointer &Ptr = S.Stk.pop<Pointer>(); 596 if (!CheckNull(S, OpPC, Ptr, CSK_Base)) 597 return false; 598 return VirtBaseHelper(S, OpPC, D, Ptr); 599} 600 601inline bool GetPtrThisVirtBase(InterpState &S, CodePtr OpPC, 602 const RecordDecl *D) { 603 if (S.checkingPotentialConstantExpression()) 604 return false; 605 const Pointer &This = S.Current->getThis(); 606 if (!CheckThis(S, OpPC, This)) 607 return false; 608 return VirtBaseHelper(S, OpPC, D, S.Current->getThis()); 609} 610 611//===----------------------------------------------------------------------===// 612// Load, Store, Init 613//===----------------------------------------------------------------------===// 614 615template <PrimType Name, class T = typename PrimConv<Name>::T> 616bool Load(InterpState &S, CodePtr OpPC) { 617 const Pointer &Ptr = S.Stk.peek<Pointer>(); 618 if (!CheckLoad(S, OpPC, Ptr)) 619 return false; 620 S.Stk.push<T>(Ptr.deref<T>()); 621 return true; 622} 623 624template <PrimType Name, class T = typename PrimConv<Name>::T> 625bool LoadPop(InterpState &S, CodePtr OpPC) { 626 const Pointer &Ptr = S.Stk.pop<Pointer>(); 627 if (!CheckLoad(S, OpPC, Ptr)) 628 return false; 629 S.Stk.push<T>(Ptr.deref<T>()); 630 return true; 631} 632 633template <PrimType Name, class T = typename PrimConv<Name>::T> 634bool Store(InterpState &S, CodePtr OpPC) { 635 const T &Value = S.Stk.pop<T>(); 636 const Pointer &Ptr = S.Stk.peek<Pointer>(); 637 if (!CheckStore(S, OpPC, Ptr)) 638 return false; 639 Ptr.deref<T>() = Value; 640 return true; 641} 642 643template <PrimType Name, class T = typename PrimConv<Name>::T> 644bool StorePop(InterpState &S, CodePtr OpPC) { 645 const T &Value = S.Stk.pop<T>(); 646 const Pointer &Ptr = S.Stk.pop<Pointer>(); 647 if (!CheckStore(S, OpPC, Ptr)) 648 return false; 649 Ptr.deref<T>() = Value; 650 return true; 651} 652 653template <PrimType Name, class T = typename PrimConv<Name>::T> 654bool StoreBitField(InterpState &S, CodePtr OpPC) { 655 const T &Value = S.Stk.pop<T>(); 656 const Pointer &Ptr = S.Stk.peek<Pointer>(); 657 if (!CheckStore(S, OpPC, Ptr)) 658 return false; 659 if (auto *FD = Ptr.getField()) { 660 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 661 } else { 662 Ptr.deref<T>() = Value; 663 } 664 return true; 665} 666 667template <PrimType Name, class T = typename PrimConv<Name>::T> 668bool StoreBitFieldPop(InterpState &S, CodePtr OpPC) { 669 const T &Value = S.Stk.pop<T>(); 670 const Pointer &Ptr = S.Stk.pop<Pointer>(); 671 if (!CheckStore(S, OpPC, Ptr)) 672 return false; 673 if (auto *FD = Ptr.getField()) { 674 Ptr.deref<T>() = Value.truncate(FD->getBitWidthValue(S.getCtx())); 675 } else { 676 Ptr.deref<T>() = Value; 677 } 678 return true; 679} 680 681template <PrimType Name, class T = typename PrimConv<Name>::T> 682bool InitPop(InterpState &S, CodePtr OpPC) { 683 const T &Value = S.Stk.pop<T>(); 684 const Pointer &Ptr = S.Stk.pop<Pointer>(); 685 if (!CheckInit(S, OpPC, Ptr)) 686 return false; 687 Ptr.initialize(); 688 new (&Ptr.deref<T>()) T(Value); 689 return true; 690} 691 692template <PrimType Name, class T = typename PrimConv<Name>::T> 693bool InitElem(InterpState &S, CodePtr OpPC, uint32_t Idx) { 694 const T &Value = S.Stk.pop<T>(); 695 const Pointer &Ptr = S.Stk.peek<Pointer>().atIndex(Idx); 696 if (!CheckInit(S, OpPC, Ptr)) 697 return false; 698 Ptr.initialize(); 699 new (&Ptr.deref<T>()) T(Value); 700 return true; 701} 702 703template <PrimType Name, class T = typename PrimConv<Name>::T> 704bool InitElemPop(InterpState &S, CodePtr OpPC, uint32_t Idx) { 705 const T &Value = S.Stk.pop<T>(); 706 const Pointer &Ptr = S.Stk.pop<Pointer>().atIndex(Idx); 707 if (!CheckInit(S, OpPC, Ptr)) 708 return false; 709 Ptr.initialize(); 710 new (&Ptr.deref<T>()) T(Value); 711 return true; 712} 713 714//===----------------------------------------------------------------------===// 715// AddOffset, SubOffset 716//===----------------------------------------------------------------------===// 717 718template <class T, bool Add> bool OffsetHelper(InterpState &S, CodePtr OpPC) { 719 // Fetch the pointer and the offset. 720 const T &Offset = S.Stk.pop<T>(); 721 const Pointer &Ptr = S.Stk.pop<Pointer>(); 722 if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) 723 return false; 724 if (!CheckRange(S, OpPC, Ptr, CSK_ArrayToPointer)) 725 return false; 726 727 // Get a version of the index comparable to the type. 728 T Index = T::from(Ptr.getIndex(), Offset.bitWidth()); 729 // A zero offset does not change the pointer, but in the case of an array 730 // it has to be adjusted to point to the first element instead of the array. 731 if (Offset.isZero()) { 732 S.Stk.push<Pointer>(Index.isZero() ? Ptr.atIndex(0) : Ptr); 733 return true; 734 } 735 // Arrays of unknown bounds cannot have pointers into them. 736 if (!CheckArray(S, OpPC, Ptr)) 737 return false; 738 739 // Compute the largest index into the array. 740 unsigned MaxIndex = Ptr.getNumElems(); 741 742 // Helper to report an invalid offset, computed as APSInt. 743 auto InvalidOffset = [&]() { 744 const unsigned Bits = Offset.bitWidth(); 745 APSInt APOffset(Offset.toAPSInt().extend(Bits + 2), false); 746 APSInt APIndex(Index.toAPSInt().extend(Bits + 2), false); 747 APSInt NewIndex = Add ? (APIndex + APOffset) : (APIndex - APOffset); 748 S.CCEDiag(S.Current->getSource(OpPC), diag::note_constexpr_array_index) 749 << NewIndex 750 << /*array*/ static_cast<int>(!Ptr.inArray()) 751 << static_cast<unsigned>(MaxIndex); 752 return false; 753 }; 754 755 // If the new offset would be negative, bail out. 756 if (Add && Offset.isNegative() && (Offset.isMin() || -Offset > Index)) 757 return InvalidOffset(); 758 if (!Add && Offset.isPositive() && Index < Offset) 759 return InvalidOffset(); 760 761 // If the new offset would be out of bounds, bail out. 762 unsigned MaxOffset = MaxIndex - Ptr.getIndex(); 763 if (Add && Offset.isPositive() && Offset > MaxOffset) 764 return InvalidOffset(); 765 if (!Add && Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset)) 766 return InvalidOffset(); 767 768 // Offset is valid - compute it on unsigned. 769 int64_t WideIndex = static_cast<int64_t>(Index); 770 int64_t WideOffset = static_cast<int64_t>(Offset); 771 int64_t Result = Add ? (WideIndex + WideOffset) : (WideIndex - WideOffset); 772 S.Stk.push<Pointer>(Ptr.atIndex(static_cast<unsigned>(Result))); 773 return true; 774} 775 776template <PrimType Name, class T = typename PrimConv<Name>::T> 777bool AddOffset(InterpState &S, CodePtr OpPC) { 778 return OffsetHelper<T, true>(S, OpPC); 779} 780 781template <PrimType Name, class T = typename PrimConv<Name>::T> 782bool SubOffset(InterpState &S, CodePtr OpPC) { 783 return OffsetHelper<T, false>(S, OpPC); 784} 785 786 787//===----------------------------------------------------------------------===// 788// Destroy 789//===----------------------------------------------------------------------===// 790 791inline bool Destroy(InterpState &S, CodePtr OpPC, uint32_t I) { 792 S.Current->destroy(I); 793 return true; 794} 795 796//===----------------------------------------------------------------------===// 797// Cast, CastFP 798//===----------------------------------------------------------------------===// 799 800template <PrimType TIn, PrimType TOut> bool Cast(InterpState &S, CodePtr OpPC) { 801 using T = typename PrimConv<TIn>::T; 802 using U = typename PrimConv<TOut>::T; 803 S.Stk.push<U>(U::from(S.Stk.pop<T>())); 804 return true; 805} 806 807//===----------------------------------------------------------------------===// 808// Zero, Nullptr 809//===----------------------------------------------------------------------===// 810 811template <PrimType Name, class T = typename PrimConv<Name>::T> 812bool Zero(InterpState &S, CodePtr OpPC) { 813 S.Stk.push<T>(T::zero()); 814 return true; 815} 816 817template <PrimType Name, class T = typename PrimConv<Name>::T> 818inline bool Null(InterpState &S, CodePtr OpPC) { 819 S.Stk.push<T>(); 820 return true; 821} 822 823//===----------------------------------------------------------------------===// 824// This, ImplicitThis 825//===----------------------------------------------------------------------===// 826 827inline bool This(InterpState &S, CodePtr OpPC) { 828 // Cannot read 'this' in this mode. 829 if (S.checkingPotentialConstantExpression()) { 830 return false; 831 } 832 833 const Pointer &This = S.Current->getThis(); 834 if (!CheckThis(S, OpPC, This)) 835 return false; 836 837 S.Stk.push<Pointer>(This); 838 return true; 839} 840 841//===----------------------------------------------------------------------===// 842// Shr, Shl 843//===----------------------------------------------------------------------===// 844 845template <PrimType TR, PrimType TL, class T = typename PrimConv<TR>::T> 846unsigned Trunc(InterpState &S, CodePtr OpPC, unsigned Bits, const T &V) { 847 // C++11 [expr.shift]p1: Shift width must be less than the bit width of 848 // the shifted type. 849 if (Bits > 1 && V >= T::from(Bits, V.bitWidth())) { 850 const Expr *E = S.Current->getExpr(OpPC); 851 const APSInt Val = V.toAPSInt(); 852 QualType Ty = E->getType(); 853 S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; 854 return Bits; 855 } else { 856 return static_cast<unsigned>(V); 857 } 858} 859 860template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T> 861inline bool ShiftRight(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) { 862 if (RHS >= V.bitWidth()) { 863 S.Stk.push<T>(T::from(0, V.bitWidth())); 864 } else { 865 S.Stk.push<T>(T::from(V >> RHS, V.bitWidth())); 866 } 867 return true; 868} 869 870template <PrimType TL, PrimType TR, typename T = typename PrimConv<TL>::T> 871inline bool ShiftLeft(InterpState &S, CodePtr OpPC, const T &V, unsigned RHS) { 872 if (V.isSigned() && !S.getLangOpts().CPlusPlus20) { 873 // C++11 [expr.shift]p2: A signed left shift must have a non-negative 874 // operand, and must not overflow the corresponding unsigned type. 875 // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to 876 // E1 x 2^E2 module 2^N. 877 if (V.isNegative()) { 878 const Expr *E = S.Current->getExpr(OpPC); 879 S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << V.toAPSInt(); 880 } else if (V.countLeadingZeros() < RHS) { 881 S.CCEDiag(S.Current->getExpr(OpPC), diag::note_constexpr_lshift_discards); 882 } 883 } 884 885 if (V.bitWidth() == 1) { 886 S.Stk.push<T>(V); 887 } else if (RHS >= V.bitWidth()) { 888 S.Stk.push<T>(T::from(0, V.bitWidth())); 889 } else { 890 S.Stk.push<T>(T::from(V.toUnsigned() << RHS, V.bitWidth())); 891 } 892 return true; 893} 894 895template <PrimType TL, PrimType TR> 896inline bool Shr(InterpState &S, CodePtr OpPC) { 897 const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>(); 898 const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>(); 899 const unsigned Bits = LHS.bitWidth(); 900 901 if (RHS.isSigned() && RHS.isNegative()) { 902 const SourceInfo &Loc = S.Current->getSource(OpPC); 903 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 904 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS)); 905 } else { 906 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS)); 907 } 908} 909 910template <PrimType TL, PrimType TR> 911inline bool Shl(InterpState &S, CodePtr OpPC) { 912 const auto &RHS = S.Stk.pop<typename PrimConv<TR>::T>(); 913 const auto &LHS = S.Stk.pop<typename PrimConv<TL>::T>(); 914 const unsigned Bits = LHS.bitWidth(); 915 916 if (RHS.isSigned() && RHS.isNegative()) { 917 const SourceInfo &Loc = S.Current->getSource(OpPC); 918 S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); 919 return ShiftRight<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, -RHS)); 920 } else { 921 return ShiftLeft<TL, TR>(S, OpPC, LHS, Trunc<TR, TL>(S, OpPC, Bits, RHS)); 922 } 923} 924 925//===----------------------------------------------------------------------===// 926// NoRet 927//===----------------------------------------------------------------------===// 928 929inline bool NoRet(InterpState &S, CodePtr OpPC) { 930 SourceLocation EndLoc = S.Current->getCallee()->getEndLoc(); 931 S.FFDiag(EndLoc, diag::note_constexpr_no_return); 932 return false; 933} 934 935//===----------------------------------------------------------------------===// 936// NarrowPtr, ExpandPtr 937//===----------------------------------------------------------------------===// 938 939inline bool NarrowPtr(InterpState &S, CodePtr OpPC) { 940 const Pointer &Ptr = S.Stk.pop<Pointer>(); 941 S.Stk.push<Pointer>(Ptr.narrow()); 942 return true; 943} 944 945inline bool ExpandPtr(InterpState &S, CodePtr OpPC) { 946 const Pointer &Ptr = S.Stk.pop<Pointer>(); 947 S.Stk.push<Pointer>(Ptr.expand()); 948 return true; 949} 950 951/// Interpreter entry point. 952bool Interpret(InterpState &S, APValue &Result); 953 954} // namespace interp 955} // namespace clang 956 957#endif 958