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

source code of clang/lib/AST/Interp/ByteCodeStmtGen.cpp