1 //===--- ByteCodeStmtGen.cpp - Code generator for expressions ---*- 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 "ByteCodeStmtGen.h" 10 #include "ByteCodeEmitter.h" 11 #include "ByteCodeGenError.h" 12 #include "Context.h" 13 #include "Function.h" 14 #include "PrimType.h" 15 16 using namespace clang; 17 using namespace clang::interp; 18 19 namespace clang { 20 namespace interp { 21 22 /// Scope managing label targets. 23 template <class Emitter> class LabelScope { 24 public: 25 virtual ~LabelScope() { } 26 27 protected: 28 LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {} 29 /// ByteCodeStmtGen instance. 30 ByteCodeStmtGen<Emitter> *Ctx; 31 }; 32 33 /// Sets the context for break/continue statements. 34 template <class Emitter> class LoopScope final : public LabelScope<Emitter> { 35 public: 36 using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; 37 using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; 38 39 LoopScope(ByteCodeStmtGen<Emitter> *Ctx, LabelTy BreakLabel, 40 LabelTy ContinueLabel) 41 : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), 42 OldContinueLabel(Ctx->ContinueLabel) { 43 this->Ctx->BreakLabel = BreakLabel; 44 this->Ctx->ContinueLabel = ContinueLabel; 45 } 46 47 ~LoopScope() { 48 this->Ctx->BreakLabel = OldBreakLabel; 49 this->Ctx->ContinueLabel = OldContinueLabel; 50 } 51 52 private: 53 OptLabelTy OldBreakLabel; 54 OptLabelTy OldContinueLabel; 55 }; 56 57 // Sets the context for a switch scope, mapping labels. 58 template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { 59 public: 60 using LabelTy = typename ByteCodeStmtGen<Emitter>::LabelTy; 61 using OptLabelTy = typename ByteCodeStmtGen<Emitter>::OptLabelTy; 62 using CaseMap = typename ByteCodeStmtGen<Emitter>::CaseMap; 63 64 SwitchScope(ByteCodeStmtGen<Emitter> *Ctx, CaseMap &&CaseLabels, 65 LabelTy BreakLabel, OptLabelTy DefaultLabel) 66 : LabelScope<Emitter>(Ctx), OldBreakLabel(Ctx->BreakLabel), 67 OldDefaultLabel(this->Ctx->DefaultLabel), 68 OldCaseLabels(std::move(this->Ctx->CaseLabels)) { 69 this->Ctx->BreakLabel = BreakLabel; 70 this->Ctx->DefaultLabel = DefaultLabel; 71 this->Ctx->CaseLabels = std::move(CaseLabels); 72 } 73 74 ~SwitchScope() { 75 this->Ctx->BreakLabel = OldBreakLabel; 76 this->Ctx->DefaultLabel = OldDefaultLabel; 77 this->Ctx->CaseLabels = std::move(OldCaseLabels); 78 } 79 80 private: 81 OptLabelTy OldBreakLabel; 82 OptLabelTy OldDefaultLabel; 83 CaseMap OldCaseLabels; 84 }; 85 86 } // namespace interp 87 } // namespace clang 88 89 template <class Emitter> 90 bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody( 91 const CXXMethodDecl *MD) { 92 assert(MD->isLambdaStaticInvoker()); 93 assert(MD->hasBody()); 94 assert(cast<CompoundStmt>(MD->getBody())->body_empty()); 95 96 const CXXRecordDecl *ClosureClass = MD->getParent(); 97 const CXXMethodDecl *LambdaCallOp = ClosureClass->getLambdaCallOperator(); 98 assert(ClosureClass->captures_begin() == ClosureClass->captures_end()); 99 const Function *Func = this->getFunction(LambdaCallOp); 100 if (!Func) 101 return false; 102 assert(Func->hasThisPointer()); 103 assert(Func->getNumParams() == (MD->getNumParams() + 1 + Func->hasRVO())); 104 105 if (Func->hasRVO()) { 106 if (!this->emitRVOPtr(MD)) 107 return false; 108 } 109 110 // The lambda call operator needs an instance pointer, but we don't have 111 // one here, and we don't need one either because the lambda cannot have 112 // any captures, as verified above. Emit a null pointer. This is then 113 // special-cased when interpreting to not emit any misleading diagnostics. 114 if (!this->emitNullPtr(MD)) 115 return false; 116 117 // Forward all arguments from the static invoker to the lambda call operator. 118 for (const ParmVarDecl *PVD : MD->parameters()) { 119 auto It = this->Params.find(PVD); 120 assert(It != this->Params.end()); 121 122 // We do the lvalue-to-rvalue conversion manually here, so no need 123 // to care about references. 124 PrimType ParamType = this->classify(PVD->getType()).value_or(PT_Ptr); 125 if (!this->emitGetParam(ParamType, It->second.Offset, MD)) 126 return false; 127 } 128 129 if (!this->emitCall(Func, LambdaCallOp)) 130 return false; 131 132 this->emitCleanup(); 133 if (ReturnType) 134 return this->emitRet(*ReturnType, MD); 135 136 // Nothing to do, since we emitted the RVO pointer above. 137 return this->emitRetVoid(MD); 138 } 139 140 template <class Emitter> 141 bool ByteCodeStmtGen<Emitter>::visitFunc(const FunctionDecl *F) { 142 // Classify the return type. 143 ReturnType = this->classify(F->getReturnType()); 144 145 auto emitFieldInitializer = [&](const Record::Field *F, unsigned FieldOffset, 146 const Expr *InitExpr) -> bool { 147 if (std::optional<PrimType> T = this->classify(InitExpr)) { 148 if (!this->visit(InitExpr)) 149 return false; 150 151 if (F->isBitField()) 152 return this->emitInitThisBitField(*T, F, FieldOffset, InitExpr); 153 return this->emitInitThisField(*T, FieldOffset, InitExpr); 154 } 155 // Non-primitive case. Get a pointer to the field-to-initialize 156 // on the stack and call visitInitialzer() for it. 157 if (!this->emitGetPtrThisField(FieldOffset, InitExpr)) 158 return false; 159 160 if (!this->visitInitializer(InitExpr)) 161 return false; 162 163 return this->emitPopPtr(InitExpr); 164 }; 165 166 // Emit custom code if this is a lambda static invoker. 167 if (const auto *MD = dyn_cast<CXXMethodDecl>(F); 168 MD && MD->isLambdaStaticInvoker()) 169 return this->emitLambdaStaticInvokerBody(MD); 170 171 // Constructor. Set up field initializers. 172 if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(F)) { 173 const RecordDecl *RD = Ctor->getParent(); 174 const Record *R = this->getRecord(RD); 175 if (!R) 176 return false; 177 178 for (const auto *Init : Ctor->inits()) { 179 // Scope needed for the initializers. 180 BlockScope<Emitter> Scope(this); 181 182 const Expr *InitExpr = Init->getInit(); 183 if (const FieldDecl *Member = Init->getMember()) { 184 const Record::Field *F = R->getField(Member); 185 186 if (!emitFieldInitializer(F, F->Offset, InitExpr)) 187 return false; 188 } else if (const Type *Base = Init->getBaseClass()) { 189 // Base class initializer. 190 // Get This Base and call initializer on it. 191 const auto *BaseDecl = Base->getAsCXXRecordDecl(); 192 assert(BaseDecl); 193 const Record::Base *B = R->getBase(BaseDecl); 194 assert(B); 195 if (!this->emitGetPtrThisBase(B->Offset, InitExpr)) 196 return false; 197 if (!this->visitInitializer(InitExpr)) 198 return false; 199 if (!this->emitInitPtrPop(InitExpr)) 200 return false; 201 } else if (const IndirectFieldDecl *IFD = Init->getIndirectMember()) { 202 assert(IFD->getChainingSize() >= 2); 203 204 unsigned NestedFieldOffset = 0; 205 const Record::Field *NestedField = nullptr; 206 for (const NamedDecl *ND : IFD->chain()) { 207 const auto *FD = cast<FieldDecl>(ND); 208 const Record *FieldRecord = 209 this->P.getOrCreateRecord(FD->getParent()); 210 assert(FieldRecord); 211 212 NestedField = FieldRecord->getField(FD); 213 assert(NestedField); 214 215 NestedFieldOffset += NestedField->Offset; 216 } 217 assert(NestedField); 218 219 if (!emitFieldInitializer(NestedField, NestedFieldOffset, InitExpr)) 220 return false; 221 } else { 222 assert(Init->isDelegatingInitializer()); 223 if (!this->emitThis(InitExpr)) 224 return false; 225 if (!this->visitInitializer(Init->getInit())) 226 return false; 227 if (!this->emitPopPtr(InitExpr)) 228 return false; 229 } 230 } 231 } 232 233 if (const auto *Body = F->getBody()) 234 if (!visitStmt(Body)) 235 return false; 236 237 // Emit a guard return to protect against a code path missing one. 238 if (F->getReturnType()->isVoidType()) 239 return this->emitRetVoid(SourceInfo{}); 240 else 241 return this->emitNoRet(SourceInfo{}); 242 } 243 244 template <class Emitter> 245 bool ByteCodeStmtGen<Emitter>::visitStmt(const Stmt *S) { 246 switch (S->getStmtClass()) { 247 case Stmt::CompoundStmtClass: 248 return visitCompoundStmt(cast<CompoundStmt>(S)); 249 case Stmt::DeclStmtClass: 250 return visitDeclStmt(cast<DeclStmt>(S)); 251 case Stmt::ReturnStmtClass: 252 return visitReturnStmt(cast<ReturnStmt>(S)); 253 case Stmt::IfStmtClass: 254 return visitIfStmt(cast<IfStmt>(S)); 255 case Stmt::WhileStmtClass: 256 return visitWhileStmt(cast<WhileStmt>(S)); 257 case Stmt::DoStmtClass: 258 return visitDoStmt(cast<DoStmt>(S)); 259 case Stmt::ForStmtClass: 260 return visitForStmt(cast<ForStmt>(S)); 261 case Stmt::CXXForRangeStmtClass: 262 return visitCXXForRangeStmt(cast<CXXForRangeStmt>(S)); 263 case Stmt::BreakStmtClass: 264 return visitBreakStmt(cast<BreakStmt>(S)); 265 case Stmt::ContinueStmtClass: 266 return visitContinueStmt(cast<ContinueStmt>(S)); 267 case Stmt::SwitchStmtClass: 268 return visitSwitchStmt(cast<SwitchStmt>(S)); 269 case Stmt::CaseStmtClass: 270 return visitCaseStmt(cast<CaseStmt>(S)); 271 case Stmt::DefaultStmtClass: 272 return visitDefaultStmt(cast<DefaultStmt>(S)); 273 case Stmt::GCCAsmStmtClass: 274 case Stmt::MSAsmStmtClass: 275 return visitAsmStmt(cast<AsmStmt>(S)); 276 case Stmt::AttributedStmtClass: 277 return visitAttributedStmt(cast<AttributedStmt>(S)); 278 case Stmt::CXXTryStmtClass: 279 return visitCXXTryStmt(cast<CXXTryStmt>(S)); 280 case Stmt::NullStmtClass: 281 return true; 282 default: { 283 if (auto *Exp = dyn_cast<Expr>(S)) 284 return this->discard(Exp); 285 return false; 286 } 287 } 288 } 289 290 /// Visits the given statment without creating a variable 291 /// scope for it in case it is a compound statement. 292 template <class Emitter> 293 bool ByteCodeStmtGen<Emitter>::visitLoopBody(const Stmt *S) { 294 if (isa<NullStmt>(S)) 295 return true; 296 297 if (const auto *CS = dyn_cast<CompoundStmt>(S)) { 298 for (auto *InnerStmt : CS->body()) 299 if (!visitStmt(InnerStmt)) 300 return false; 301 return true; 302 } 303 304 return this->visitStmt(S); 305 } 306 307 template <class Emitter> 308 bool ByteCodeStmtGen<Emitter>::visitCompoundStmt( 309 const CompoundStmt *CompoundStmt) { 310 BlockScope<Emitter> Scope(this); 311 for (auto *InnerStmt : CompoundStmt->body()) 312 if (!visitStmt(InnerStmt)) 313 return false; 314 return true; 315 } 316 317 template <class Emitter> 318 bool ByteCodeStmtGen<Emitter>::visitDeclStmt(const DeclStmt *DS) { 319 for (auto *D : DS->decls()) { 320 if (isa<StaticAssertDecl, TagDecl, TypedefNameDecl>(D)) 321 continue; 322 323 const auto *VD = dyn_cast<VarDecl>(D); 324 if (!VD) 325 return false; 326 if (!this->visitVarDecl(VD)) 327 return false; 328 } 329 330 return true; 331 } 332 333 template <class Emitter> 334 bool ByteCodeStmtGen<Emitter>::visitReturnStmt(const ReturnStmt *RS) { 335 if (const Expr *RE = RS->getRetValue()) { 336 ExprScope<Emitter> RetScope(this); 337 if (ReturnType) { 338 // Primitive types are simply returned. 339 if (!this->visit(RE)) 340 return false; 341 this->emitCleanup(); 342 return this->emitRet(*ReturnType, RS); 343 } else if (RE->getType()->isVoidType()) { 344 if (!this->visit(RE)) 345 return false; 346 } else { 347 // RVO - construct the value in the return location. 348 if (!this->emitRVOPtr(RE)) 349 return false; 350 if (!this->visitInitializer(RE)) 351 return false; 352 if (!this->emitPopPtr(RE)) 353 return false; 354 355 this->emitCleanup(); 356 return this->emitRetVoid(RS); 357 } 358 } 359 360 // Void return. 361 this->emitCleanup(); 362 return this->emitRetVoid(RS); 363 } 364 365 template <class Emitter> 366 bool ByteCodeStmtGen<Emitter>::visitIfStmt(const IfStmt *IS) { 367 BlockScope<Emitter> IfScope(this); 368 369 if (IS->isNonNegatedConsteval()) 370 return visitStmt(IS->getThen()); 371 if (IS->isNegatedConsteval()) 372 return IS->getElse() ? visitStmt(IS->getElse()) : true; 373 374 if (auto *CondInit = IS->getInit()) 375 if (!visitStmt(CondInit)) 376 return false; 377 378 if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) 379 if (!visitDeclStmt(CondDecl)) 380 return false; 381 382 if (!this->visitBool(IS->getCond())) 383 return false; 384 385 if (const Stmt *Else = IS->getElse()) { 386 LabelTy LabelElse = this->getLabel(); 387 LabelTy LabelEnd = this->getLabel(); 388 if (!this->jumpFalse(LabelElse)) 389 return false; 390 if (!visitStmt(IS->getThen())) 391 return false; 392 if (!this->jump(LabelEnd)) 393 return false; 394 this->emitLabel(LabelElse); 395 if (!visitStmt(Else)) 396 return false; 397 this->emitLabel(LabelEnd); 398 } else { 399 LabelTy LabelEnd = this->getLabel(); 400 if (!this->jumpFalse(LabelEnd)) 401 return false; 402 if (!visitStmt(IS->getThen())) 403 return false; 404 this->emitLabel(LabelEnd); 405 } 406 407 return true; 408 } 409 410 template <class Emitter> 411 bool ByteCodeStmtGen<Emitter>::visitWhileStmt(const WhileStmt *S) { 412 const Expr *Cond = S->getCond(); 413 const Stmt *Body = S->getBody(); 414 415 LabelTy CondLabel = this->getLabel(); // Label before the condition. 416 LabelTy EndLabel = this->getLabel(); // Label after the loop. 417 LoopScope<Emitter> LS(this, EndLabel, CondLabel); 418 419 this->emitLabel(CondLabel); 420 if (!this->visitBool(Cond)) 421 return false; 422 if (!this->jumpFalse(EndLabel)) 423 return false; 424 425 LocalScope<Emitter> Scope(this); 426 { 427 DestructorScope<Emitter> DS(Scope); 428 if (!this->visitLoopBody(Body)) 429 return false; 430 } 431 432 if (!this->jump(CondLabel)) 433 return false; 434 this->emitLabel(EndLabel); 435 436 return true; 437 } 438 439 template <class Emitter> 440 bool ByteCodeStmtGen<Emitter>::visitDoStmt(const DoStmt *S) { 441 const Expr *Cond = S->getCond(); 442 const Stmt *Body = S->getBody(); 443 444 LabelTy StartLabel = this->getLabel(); 445 LabelTy EndLabel = this->getLabel(); 446 LabelTy CondLabel = this->getLabel(); 447 LoopScope<Emitter> LS(this, EndLabel, CondLabel); 448 LocalScope<Emitter> Scope(this); 449 450 this->emitLabel(StartLabel); 451 { 452 DestructorScope<Emitter> DS(Scope); 453 454 if (!this->visitLoopBody(Body)) 455 return false; 456 this->emitLabel(CondLabel); 457 if (!this->visitBool(Cond)) 458 return false; 459 } 460 if (!this->jumpTrue(StartLabel)) 461 return false; 462 463 this->emitLabel(EndLabel); 464 return true; 465 } 466 467 template <class Emitter> 468 bool ByteCodeStmtGen<Emitter>::visitForStmt(const ForStmt *S) { 469 // for (Init; Cond; Inc) { Body } 470 const Stmt *Init = S->getInit(); 471 const Expr *Cond = S->getCond(); 472 const Expr *Inc = S->getInc(); 473 const Stmt *Body = S->getBody(); 474 475 LabelTy EndLabel = this->getLabel(); 476 LabelTy CondLabel = this->getLabel(); 477 LabelTy IncLabel = this->getLabel(); 478 LoopScope<Emitter> LS(this, EndLabel, IncLabel); 479 LocalScope<Emitter> Scope(this); 480 481 if (Init && !this->visitStmt(Init)) 482 return false; 483 this->emitLabel(CondLabel); 484 if (Cond) { 485 if (!this->visitBool(Cond)) 486 return false; 487 if (!this->jumpFalse(EndLabel)) 488 return false; 489 } 490 491 { 492 DestructorScope<Emitter> DS(Scope); 493 494 if (Body && !this->visitLoopBody(Body)) 495 return false; 496 this->emitLabel(IncLabel); 497 if (Inc && !this->discard(Inc)) 498 return false; 499 } 500 501 if (!this->jump(CondLabel)) 502 return false; 503 this->emitLabel(EndLabel); 504 return true; 505 } 506 507 template <class Emitter> 508 bool ByteCodeStmtGen<Emitter>::visitCXXForRangeStmt(const CXXForRangeStmt *S) { 509 const Stmt *Init = S->getInit(); 510 const Expr *Cond = S->getCond(); 511 const Expr *Inc = S->getInc(); 512 const Stmt *Body = S->getBody(); 513 const Stmt *BeginStmt = S->getBeginStmt(); 514 const Stmt *RangeStmt = S->getRangeStmt(); 515 const Stmt *EndStmt = S->getEndStmt(); 516 const VarDecl *LoopVar = S->getLoopVariable(); 517 518 LabelTy EndLabel = this->getLabel(); 519 LabelTy CondLabel = this->getLabel(); 520 LabelTy IncLabel = this->getLabel(); 521 LoopScope<Emitter> LS(this, EndLabel, IncLabel); 522 523 // Emit declarations needed in the loop. 524 if (Init && !this->visitStmt(Init)) 525 return false; 526 if (!this->visitStmt(RangeStmt)) 527 return false; 528 if (!this->visitStmt(BeginStmt)) 529 return false; 530 if (!this->visitStmt(EndStmt)) 531 return false; 532 533 // Now the condition as well as the loop variable assignment. 534 this->emitLabel(CondLabel); 535 if (!this->visitBool(Cond)) 536 return false; 537 if (!this->jumpFalse(EndLabel)) 538 return false; 539 540 if (!this->visitVarDecl(LoopVar)) 541 return false; 542 543 // Body. 544 LocalScope<Emitter> Scope(this); 545 { 546 DestructorScope<Emitter> DS(Scope); 547 548 if (!this->visitLoopBody(Body)) 549 return false; 550 this->emitLabel(IncLabel); 551 if (!this->discard(Inc)) 552 return false; 553 } 554 if (!this->jump(CondLabel)) 555 return false; 556 557 this->emitLabel(EndLabel); 558 return true; 559 } 560 561 template <class Emitter> 562 bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) { 563 if (!BreakLabel) 564 return false; 565 566 this->VarScope->emitDestructors(); 567 return this->jump(*BreakLabel); 568 } 569 570 template <class Emitter> 571 bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) { 572 if (!ContinueLabel) 573 return false; 574 575 this->VarScope->emitDestructors(); 576 return this->jump(*ContinueLabel); 577 } 578 579 template <class Emitter> 580 bool ByteCodeStmtGen<Emitter>::visitSwitchStmt(const SwitchStmt *S) { 581 const Expr *Cond = S->getCond(); 582 PrimType CondT = this->classifyPrim(Cond->getType()); 583 584 LabelTy EndLabel = this->getLabel(); 585 OptLabelTy DefaultLabel = std::nullopt; 586 unsigned CondVar = this->allocateLocalPrimitive(Cond, CondT, true, false); 587 588 if (const auto *CondInit = S->getInit()) 589 if (!visitStmt(CondInit)) 590 return false; 591 592 // Initialize condition variable. 593 if (!this->visit(Cond)) 594 return false; 595 if (!this->emitSetLocal(CondT, CondVar, S)) 596 return false; 597 598 CaseMap CaseLabels; 599 // Create labels and comparison ops for all case statements. 600 for (const SwitchCase *SC = S->getSwitchCaseList(); SC; 601 SC = SC->getNextSwitchCase()) { 602 if (const auto *CS = dyn_cast<CaseStmt>(SC)) { 603 // FIXME: Implement ranges. 604 if (CS->caseStmtIsGNURange()) 605 return false; 606 CaseLabels[SC] = this->getLabel(); 607 608 const Expr *Value = CS->getLHS(); 609 PrimType ValueT = this->classifyPrim(Value->getType()); 610 611 // Compare the case statement's value to the switch condition. 612 if (!this->emitGetLocal(CondT, CondVar, CS)) 613 return false; 614 if (!this->visit(Value)) 615 return false; 616 617 // Compare and jump to the case label. 618 if (!this->emitEQ(ValueT, S)) 619 return false; 620 if (!this->jumpTrue(CaseLabels[CS])) 621 return false; 622 } else { 623 assert(!DefaultLabel); 624 DefaultLabel = this->getLabel(); 625 } 626 } 627 628 // If none of the conditions above were true, fall through to the default 629 // statement or jump after the switch statement. 630 if (DefaultLabel) { 631 if (!this->jump(*DefaultLabel)) 632 return false; 633 } else { 634 if (!this->jump(EndLabel)) 635 return false; 636 } 637 638 SwitchScope<Emitter> SS(this, std::move(CaseLabels), EndLabel, DefaultLabel); 639 if (!this->visitStmt(S->getBody())) 640 return false; 641 this->emitLabel(EndLabel); 642 return true; 643 } 644 645 template <class Emitter> 646 bool ByteCodeStmtGen<Emitter>::visitCaseStmt(const CaseStmt *S) { 647 this->emitLabel(CaseLabels[S]); 648 return this->visitStmt(S->getSubStmt()); 649 } 650 651 template <class Emitter> 652 bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) { 653 this->emitLabel(*DefaultLabel); 654 return this->visitStmt(S->getSubStmt()); 655 } 656 657 template <class Emitter> 658 bool ByteCodeStmtGen<Emitter>::visitAsmStmt(const AsmStmt *S) { 659 return this->emitInvalid(S); 660 } 661 662 template <class Emitter> 663 bool ByteCodeStmtGen<Emitter>::visitAttributedStmt(const AttributedStmt *S) { 664 // Ignore all attributes. 665 return this->visitStmt(S->getSubStmt()); 666 } 667 668 template <class Emitter> 669 bool ByteCodeStmtGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) { 670 // Ignore all handlers. 671 return this->visitStmt(S->getTryBlock()); 672 } 673 674 namespace clang { 675 namespace interp { 676 677 template class ByteCodeStmtGen<ByteCodeEmitter>; 678 679 } // namespace interp 680 } // namespace clang 681