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