1 //===------- Interp.cpp - 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 #include "Interp.h" 10 #include <limits> 11 #include <vector> 12 #include "Function.h" 13 #include "InterpFrame.h" 14 #include "InterpStack.h" 15 #include "Opcode.h" 16 #include "PrimType.h" 17 #include "Program.h" 18 #include "State.h" 19 #include "clang/AST/ASTContext.h" 20 #include "clang/AST/ASTDiagnostic.h" 21 #include "clang/AST/CXXInheritance.h" 22 #include "clang/AST/Expr.h" 23 #include "clang/AST/ExprCXX.h" 24 #include "llvm/ADT/APSInt.h" 25 26 using namespace clang; 27 using namespace clang::interp; 28 29 static bool RetValue(InterpState &S, CodePtr &Pt, APValue &Result) { 30 llvm::report_fatal_error("Interpreter cannot return values"); 31 } 32 33 //===----------------------------------------------------------------------===// 34 // Jmp, Jt, Jf 35 //===----------------------------------------------------------------------===// 36 37 static bool Jmp(InterpState &S, CodePtr &PC, int32_t Offset) { 38 PC += Offset; 39 return true; 40 } 41 42 static bool Jt(InterpState &S, CodePtr &PC, int32_t Offset) { 43 if (S.Stk.pop<bool>()) { 44 PC += Offset; 45 } 46 return true; 47 } 48 49 static bool Jf(InterpState &S, CodePtr &PC, int32_t Offset) { 50 if (!S.Stk.pop<bool>()) { 51 PC += Offset; 52 } 53 return true; 54 } 55 56 static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 57 AccessKinds AK) { 58 if (Ptr.isActive()) 59 return true; 60 61 // Get the inactive field descriptor. 62 const FieldDecl *InactiveField = Ptr.getField(); 63 64 // Walk up the pointer chain to find the union which is not active. 65 Pointer U = Ptr.getBase(); 66 while (!U.isActive()) { 67 U = U.getBase(); 68 } 69 70 // Find the active field of the union. 71 const Record *R = U.getRecord(); 72 assert(R && R->isUnion() && "Not a union"); 73 const FieldDecl *ActiveField = nullptr; 74 for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) { 75 const Pointer &Field = U.atField(R->getField(I)->Offset); 76 if (Field.isActive()) { 77 ActiveField = Field.getField(); 78 break; 79 } 80 } 81 82 const SourceInfo &Loc = S.Current->getSource(OpPC); 83 S.FFDiag(Loc, diag::note_constexpr_access_inactive_union_member) 84 << AK << InactiveField << !ActiveField << ActiveField; 85 return false; 86 } 87 88 static bool CheckTemporary(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 89 AccessKinds AK) { 90 if (auto ID = Ptr.getDeclID()) { 91 if (!Ptr.isStaticTemporary()) 92 return true; 93 94 if (Ptr.getDeclDesc()->getType().isConstQualified()) 95 return true; 96 97 if (S.P.getCurrentDecl() == ID) 98 return true; 99 100 const SourceInfo &E = S.Current->getSource(OpPC); 101 S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK; 102 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 103 return false; 104 } 105 return true; 106 } 107 108 static bool CheckGlobal(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 109 if (auto ID = Ptr.getDeclID()) { 110 if (!Ptr.isStatic()) 111 return true; 112 113 if (S.P.getCurrentDecl() == ID) 114 return true; 115 116 S.FFDiag(S.Current->getLocation(OpPC), diag::note_constexpr_modify_global); 117 return false; 118 } 119 return true; 120 } 121 122 namespace clang { 123 namespace interp { 124 static void popArg(InterpState &S, const Expr *Arg) { 125 PrimType Ty = S.getContext().classify(Arg->getType()).value_or(PT_Ptr); 126 TYPE_SWITCH(Ty, S.Stk.discard<T>()); 127 } 128 129 void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) { 130 assert(S.Current); 131 const Function *CurFunc = S.Current->getFunction(); 132 assert(CurFunc); 133 134 if (CurFunc->isUnevaluatedBuiltin()) 135 return; 136 137 if (S.Current->Caller && CurFunc->isVariadic()) { 138 // CallExpr we're look for is at the return PC of the current function, i.e. 139 // in the caller. 140 // This code path should be executed very rarely. 141 const auto *CE = 142 cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC())); 143 unsigned FixedParams = CurFunc->getNumParams(); 144 int32_t ArgsToPop = CE->getNumArgs() - FixedParams; 145 assert(ArgsToPop >= 0); 146 for (int32_t I = ArgsToPop - 1; I >= 0; --I) { 147 const Expr *A = CE->getArg(FixedParams + I); 148 popArg(S, A); 149 } 150 } 151 // And in any case, remove the fixed parameters (the non-variadic ones) 152 // at the end. 153 S.Current->popArgs(); 154 } 155 156 bool CheckExtern(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 157 if (!Ptr.isExtern()) 158 return true; 159 160 if (!S.checkingPotentialConstantExpression() && S.getLangOpts().CPlusPlus) { 161 const auto *VD = Ptr.getDeclDesc()->asValueDecl(); 162 const SourceInfo &Loc = S.Current->getSource(OpPC); 163 S.FFDiag(Loc, diag::note_constexpr_ltor_non_constexpr, 1) << VD; 164 S.Note(VD->getLocation(), diag::note_declared_at); 165 } 166 return false; 167 } 168 169 bool CheckArray(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 170 if (!Ptr.isUnknownSizeArray()) 171 return true; 172 const SourceInfo &E = S.Current->getSource(OpPC); 173 S.FFDiag(E, diag::note_constexpr_unsized_array_indexed); 174 return false; 175 } 176 177 bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 178 AccessKinds AK) { 179 if (Ptr.isZero()) { 180 const auto &Src = S.Current->getSource(OpPC); 181 182 if (Ptr.isField()) 183 S.FFDiag(Src, diag::note_constexpr_null_subobject) << CSK_Field; 184 else 185 S.FFDiag(Src, diag::note_constexpr_access_null) << AK; 186 187 return false; 188 } 189 190 if (!Ptr.isLive()) { 191 const auto &Src = S.Current->getSource(OpPC); 192 bool IsTemp = Ptr.isTemporary(); 193 194 S.FFDiag(Src, diag::note_constexpr_lifetime_ended, 1) << AK << !IsTemp; 195 196 if (IsTemp) 197 S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here); 198 else 199 S.Note(Ptr.getDeclLoc(), diag::note_declared_at); 200 201 return false; 202 } 203 204 return true; 205 } 206 207 bool CheckDummy(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 208 return !Ptr.isZero() && !Ptr.isDummy(); 209 } 210 211 bool CheckNull(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 212 CheckSubobjectKind CSK) { 213 if (!Ptr.isZero()) 214 return true; 215 const SourceInfo &Loc = S.Current->getSource(OpPC); 216 S.FFDiag(Loc, diag::note_constexpr_null_subobject) << CSK; 217 return false; 218 } 219 220 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 221 AccessKinds AK) { 222 if (!Ptr.isOnePastEnd()) 223 return true; 224 const SourceInfo &Loc = S.Current->getSource(OpPC); 225 S.FFDiag(Loc, diag::note_constexpr_access_past_end) << AK; 226 return false; 227 } 228 229 bool CheckRange(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 230 CheckSubobjectKind CSK) { 231 if (!Ptr.isElementPastEnd()) 232 return true; 233 const SourceInfo &Loc = S.Current->getSource(OpPC); 234 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; 235 return false; 236 } 237 238 bool CheckSubobject(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 239 CheckSubobjectKind CSK) { 240 if (!Ptr.isOnePastEnd()) 241 return true; 242 243 const SourceInfo &Loc = S.Current->getSource(OpPC); 244 S.FFDiag(Loc, diag::note_constexpr_past_end_subobject) << CSK; 245 return false; 246 } 247 248 bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 249 assert(Ptr.isLive() && "Pointer is not live"); 250 if (!Ptr.isConst()) 251 return true; 252 253 // The This pointer is writable in constructors and destructors, 254 // even if isConst() returns true. 255 if (const Function *Func = S.Current->getFunction(); 256 Func && (Func->isConstructor() || Func->isDestructor()) && 257 Ptr.block() == S.Current->getThis().block()) { 258 return true; 259 } 260 261 const QualType Ty = Ptr.getType(); 262 const SourceInfo &Loc = S.Current->getSource(OpPC); 263 S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty; 264 return false; 265 } 266 267 bool CheckMutable(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 268 assert(Ptr.isLive() && "Pointer is not live"); 269 if (!Ptr.isMutable()) { 270 return true; 271 } 272 273 const SourceInfo &Loc = S.Current->getSource(OpPC); 274 const FieldDecl *Field = Ptr.getField(); 275 S.FFDiag(Loc, diag::note_constexpr_access_mutable, 1) << AK_Read << Field; 276 S.Note(Field->getLocation(), diag::note_declared_at); 277 return false; 278 } 279 280 bool CheckInitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr, 281 AccessKinds AK) { 282 if (Ptr.isInitialized()) 283 return true; 284 285 if (!S.checkingPotentialConstantExpression()) { 286 S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit) 287 << AK << /*uninitialized=*/true << S.Current->getRange(OpPC); 288 } 289 return false; 290 } 291 292 bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 293 if (!CheckLive(S, OpPC, Ptr, AK_Read)) 294 return false; 295 if (!CheckDummy(S, OpPC, Ptr)) 296 return false; 297 if (!CheckExtern(S, OpPC, Ptr)) 298 return false; 299 if (!CheckRange(S, OpPC, Ptr, AK_Read)) 300 return false; 301 if (!CheckInitialized(S, OpPC, Ptr, AK_Read)) 302 return false; 303 if (!CheckActive(S, OpPC, Ptr, AK_Read)) 304 return false; 305 if (!CheckTemporary(S, OpPC, Ptr, AK_Read)) 306 return false; 307 if (!CheckMutable(S, OpPC, Ptr)) 308 return false; 309 return true; 310 } 311 312 bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 313 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 314 return false; 315 if (!CheckExtern(S, OpPC, Ptr)) 316 return false; 317 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 318 return false; 319 if (!CheckGlobal(S, OpPC, Ptr)) 320 return false; 321 if (!CheckConst(S, OpPC, Ptr)) 322 return false; 323 return true; 324 } 325 326 bool CheckInvoke(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 327 if (!CheckLive(S, OpPC, Ptr, AK_MemberCall)) 328 return false; 329 if (!CheckExtern(S, OpPC, Ptr)) 330 return false; 331 if (!CheckRange(S, OpPC, Ptr, AK_MemberCall)) 332 return false; 333 return true; 334 } 335 336 bool CheckInit(InterpState &S, CodePtr OpPC, const Pointer &Ptr) { 337 if (!CheckLive(S, OpPC, Ptr, AK_Assign)) 338 return false; 339 if (!CheckRange(S, OpPC, Ptr, AK_Assign)) 340 return false; 341 return true; 342 } 343 344 bool CheckCallable(InterpState &S, CodePtr OpPC, const Function *F) { 345 346 if (F->isVirtual() && !S.getLangOpts().CPlusPlus20) { 347 const SourceLocation &Loc = S.Current->getLocation(OpPC); 348 S.CCEDiag(Loc, diag::note_constexpr_virtual_call); 349 return false; 350 } 351 352 if (!F->isConstexpr()) { 353 const SourceLocation &Loc = S.Current->getLocation(OpPC); 354 if (S.getLangOpts().CPlusPlus11) { 355 const FunctionDecl *DiagDecl = F->getDecl(); 356 357 // If this function is not constexpr because it is an inherited 358 // non-constexpr constructor, diagnose that directly. 359 const auto *CD = dyn_cast<CXXConstructorDecl>(DiagDecl); 360 if (CD && CD->isInheritingConstructor()) { 361 const auto *Inherited = CD->getInheritedConstructor().getConstructor(); 362 if (!Inherited->isConstexpr()) 363 DiagDecl = CD = Inherited; 364 } 365 366 // FIXME: If DiagDecl is an implicitly-declared special member function 367 // or an inheriting constructor, we should be much more explicit about why 368 // it's not constexpr. 369 if (CD && CD->isInheritingConstructor()) { 370 S.FFDiag(Loc, diag::note_constexpr_invalid_inhctor, 1) 371 << CD->getInheritedConstructor().getConstructor()->getParent(); 372 S.Note(DiagDecl->getLocation(), diag::note_declared_at); 373 } else { 374 // Don't emit anything if the function isn't defined and we're checking 375 // for a constant expression. It might be defined at the point we're 376 // actually calling it. 377 if (!DiagDecl->isDefined() && S.checkingPotentialConstantExpression()) 378 return false; 379 380 S.FFDiag(Loc, diag::note_constexpr_invalid_function, 1) 381 << DiagDecl->isConstexpr() << (bool)CD << DiagDecl; 382 S.Note(DiagDecl->getLocation(), diag::note_declared_at); 383 } 384 } else { 385 S.FFDiag(Loc, diag::note_invalid_subexpr_in_const_expr); 386 } 387 return false; 388 } 389 390 return true; 391 } 392 393 bool CheckCallDepth(InterpState &S, CodePtr OpPC) { 394 if ((S.Current->getDepth() + 1) > S.getLangOpts().ConstexprCallDepth) { 395 S.FFDiag(S.Current->getSource(OpPC), 396 diag::note_constexpr_depth_limit_exceeded) 397 << S.getLangOpts().ConstexprCallDepth; 398 return false; 399 } 400 401 return true; 402 } 403 404 bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This) { 405 if (!This.isZero()) 406 return true; 407 408 const SourceInfo &Loc = S.Current->getSource(OpPC); 409 410 bool IsImplicit = false; 411 if (const auto *E = dyn_cast_if_present<CXXThisExpr>(Loc.asExpr())) 412 IsImplicit = E->isImplicit(); 413 414 if (S.getLangOpts().CPlusPlus11) 415 S.FFDiag(Loc, diag::note_constexpr_this) << IsImplicit; 416 else 417 S.FFDiag(Loc); 418 419 return false; 420 } 421 422 bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD) { 423 if (!MD->isPure()) 424 return true; 425 const SourceInfo &E = S.Current->getSource(OpPC); 426 S.FFDiag(E, diag::note_constexpr_pure_virtual_call, 1) << MD; 427 S.Note(MD->getLocation(), diag::note_declared_at); 428 return false; 429 } 430 431 static void DiagnoseUninitializedSubobject(InterpState &S, const SourceInfo &SI, 432 const FieldDecl *SubObjDecl) { 433 assert(SubObjDecl && "Subobject declaration does not exist"); 434 S.FFDiag(SI, diag::note_constexpr_uninitialized) 435 << /*(name)*/ 1 << SubObjDecl; 436 S.Note(SubObjDecl->getLocation(), 437 diag::note_constexpr_subobject_declared_here); 438 } 439 440 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 441 const Pointer &BasePtr, const Record *R); 442 443 static bool CheckArrayInitialized(InterpState &S, CodePtr OpPC, 444 const Pointer &BasePtr, 445 const ConstantArrayType *CAT) { 446 bool Result = true; 447 size_t NumElems = CAT->getSize().getZExtValue(); 448 QualType ElemType = CAT->getElementType(); 449 450 if (ElemType->isRecordType()) { 451 const Record *R = BasePtr.getElemRecord(); 452 for (size_t I = 0; I != NumElems; ++I) { 453 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 454 Result &= CheckFieldsInitialized(S, OpPC, ElemPtr, R); 455 } 456 } else if (const auto *ElemCAT = dyn_cast<ConstantArrayType>(ElemType)) { 457 for (size_t I = 0; I != NumElems; ++I) { 458 Pointer ElemPtr = BasePtr.atIndex(I).narrow(); 459 Result &= CheckArrayInitialized(S, OpPC, ElemPtr, ElemCAT); 460 } 461 } else { 462 for (size_t I = 0; I != NumElems; ++I) { 463 if (!BasePtr.atIndex(I).isInitialized()) { 464 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), 465 BasePtr.getField()); 466 Result = false; 467 } 468 } 469 } 470 471 return Result; 472 } 473 474 static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC, 475 const Pointer &BasePtr, const Record *R) { 476 assert(R); 477 bool Result = true; 478 // Check all fields of this record are initialized. 479 for (const Record::Field &F : R->fields()) { 480 Pointer FieldPtr = BasePtr.atField(F.Offset); 481 QualType FieldType = F.Decl->getType(); 482 483 if (FieldType->isRecordType()) { 484 Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord()); 485 } else if (FieldType->isIncompleteArrayType()) { 486 // Nothing to do here. 487 } else if (FieldType->isArrayType()) { 488 const auto *CAT = 489 cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe()); 490 Result &= CheckArrayInitialized(S, OpPC, FieldPtr, CAT); 491 } else if (!FieldPtr.isInitialized()) { 492 DiagnoseUninitializedSubobject(S, S.Current->getSource(OpPC), F.Decl); 493 Result = false; 494 } 495 } 496 497 // Check Fields in all bases 498 for (const Record::Base &B : R->bases()) { 499 Pointer P = BasePtr.atField(B.Offset); 500 if (!P.isInitialized()) { 501 S.FFDiag(BasePtr.getDeclDesc()->asDecl()->getLocation(), 502 diag::note_constexpr_uninitialized_base) 503 << B.Desc->getType(); 504 return false; 505 } 506 Result &= CheckFieldsInitialized(S, OpPC, P, B.R); 507 } 508 509 // TODO: Virtual bases 510 511 return Result; 512 } 513 514 bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This) { 515 assert(!This.isZero()); 516 if (const Record *R = This.getRecord()) 517 return CheckFieldsInitialized(S, OpPC, This, R); 518 const auto *CAT = 519 cast<ConstantArrayType>(This.getType()->getAsArrayTypeUnsafe()); 520 return CheckArrayInitialized(S, OpPC, This, CAT); 521 } 522 523 bool CheckPotentialReinterpretCast(InterpState &S, CodePtr OpPC, 524 const Pointer &Ptr) { 525 if (!S.inConstantContext()) 526 return true; 527 528 const SourceInfo &E = S.Current->getSource(OpPC); 529 S.CCEDiag(E, diag::note_constexpr_invalid_cast) 530 << 2 << S.getLangOpts().CPlusPlus << S.Current->getRange(OpPC); 531 return false; 532 } 533 534 bool CheckFloatResult(InterpState &S, CodePtr OpPC, const Floating &Result, 535 APFloat::opStatus Status) { 536 const SourceInfo &E = S.Current->getSource(OpPC); 537 538 // [expr.pre]p4: 539 // If during the evaluation of an expression, the result is not 540 // mathematically defined [...], the behavior is undefined. 541 // FIXME: C++ rules require us to not conform to IEEE 754 here. 542 if (Result.isNan()) { 543 S.CCEDiag(E, diag::note_constexpr_float_arithmetic) 544 << /*NaN=*/true << S.Current->getRange(OpPC); 545 return S.noteUndefinedBehavior(); 546 } 547 548 // In a constant context, assume that any dynamic rounding mode or FP 549 // exception state matches the default floating-point environment. 550 if (S.inConstantContext()) 551 return true; 552 553 FPOptions FPO = E.asExpr()->getFPFeaturesInEffect(S.Ctx.getLangOpts()); 554 555 if ((Status & APFloat::opInexact) && 556 FPO.getRoundingMode() == llvm::RoundingMode::Dynamic) { 557 // Inexact result means that it depends on rounding mode. If the requested 558 // mode is dynamic, the evaluation cannot be made in compile time. 559 S.FFDiag(E, diag::note_constexpr_dynamic_rounding); 560 return false; 561 } 562 563 if ((Status != APFloat::opOK) && 564 (FPO.getRoundingMode() == llvm::RoundingMode::Dynamic || 565 FPO.getExceptionMode() != LangOptions::FPE_Ignore || 566 FPO.getAllowFEnvAccess())) { 567 S.FFDiag(E, diag::note_constexpr_float_arithmetic_strict); 568 return false; 569 } 570 571 if ((Status & APFloat::opStatus::opInvalidOp) && 572 FPO.getExceptionMode() != LangOptions::FPE_Ignore) { 573 // There is no usefully definable result. 574 S.FFDiag(E); 575 return false; 576 } 577 578 return true; 579 } 580 581 /// We aleady know the given DeclRefExpr is invalid for some reason, 582 /// now figure out why and print appropriate diagnostics. 583 bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) { 584 const ValueDecl *D = DR->getDecl(); 585 const SourceInfo &E = S.Current->getSource(OpPC); 586 587 if (isa<ParmVarDecl>(D)) { 588 if (S.getLangOpts().CPlusPlus11) { 589 S.FFDiag(E, diag::note_constexpr_function_param_value_unknown) << D; 590 S.Note(D->getLocation(), diag::note_declared_at) << D->getSourceRange(); 591 } else { 592 S.FFDiag(E); 593 } 594 } else if (const auto *VD = dyn_cast<VarDecl>(D)) { 595 if (!VD->getType().isConstQualified()) { 596 S.FFDiag(E, 597 VD->getType()->isIntegralOrEnumerationType() 598 ? diag::note_constexpr_ltor_non_const_int 599 : diag::note_constexpr_ltor_non_constexpr, 600 1) 601 << VD; 602 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); 603 return false; 604 } 605 606 // const, but no initializer. 607 if (!VD->getAnyInitializer()) { 608 S.FFDiag(E, diag::note_constexpr_var_init_unknown, 1) << VD; 609 S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange(); 610 return false; 611 } 612 } 613 614 return false; 615 } 616 617 bool Interpret(InterpState &S, APValue &Result) { 618 // The current stack frame when we started Interpret(). 619 // This is being used by the ops to determine wheter 620 // to return from this function and thus terminate 621 // interpretation. 622 const InterpFrame *StartFrame = S.Current; 623 assert(!S.Current->isRoot()); 624 CodePtr PC = S.Current->getPC(); 625 626 // Empty program. 627 if (!PC) 628 return true; 629 630 for (;;) { 631 auto Op = PC.read<Opcode>(); 632 CodePtr OpPC = PC; 633 634 switch (Op) { 635 #define GET_INTERP 636 #include "Opcodes.inc" 637 #undef GET_INTERP 638 } 639 } 640 } 641 642 } // namespace interp 643 } // namespace clang 644