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 | |
15 | using namespace clang; |
16 | using namespace clang::interp; |
17 | |
18 | namespace clang { |
19 | namespace interp { |
20 | |
21 | /// Scope managing label targets. |
22 | template <class Emitter> class LabelScope { |
23 | public: |
24 | virtual ~LabelScope() { } |
25 | |
26 | protected: |
27 | LabelScope(ByteCodeStmtGen<Emitter> *Ctx) : Ctx(Ctx) {} |
28 | /// ByteCodeStmtGen instance. |
29 | ByteCodeStmtGen<Emitter> *Ctx; |
30 | }; |
31 | |
32 | /// Sets the context for break/continue statements. |
33 | template <class Emitter> class LoopScope final : public LabelScope<Emitter> { |
34 | public: |
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 | |
51 | private: |
52 | OptLabelTy OldBreakLabel; |
53 | OptLabelTy OldContinueLabel; |
54 | }; |
55 | |
56 | // Sets the context for a switch scope, mapping labels. |
57 | template <class Emitter> class SwitchScope final : public LabelScope<Emitter> { |
58 | public: |
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 | |
79 | private: |
80 | OptLabelTy OldBreakLabel; |
81 | OptLabelTy OldDefaultLabel; |
82 | CaseMap OldCaseLabels; |
83 | }; |
84 | |
85 | } // namespace interp |
86 | } // namespace clang |
87 | |
88 | template <class Emitter> |
89 | bool 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 | |
139 | template <class Emitter> |
140 | bool 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 | |
247 | template <class Emitter> |
248 | bool 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. |
298 | template <class Emitter> |
299 | bool 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 | |
313 | template <class Emitter> |
314 | bool 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 | |
323 | template <class Emitter> |
324 | bool 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 | |
339 | template <class Emitter> |
340 | bool 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 | |
371 | template <class Emitter> |
372 | bool 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 | |
416 | template <class Emitter> |
417 | bool 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 | |
450 | template <class Emitter> |
451 | bool 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 | |
478 | template <class Emitter> |
479 | bool 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 | |
522 | template <class Emitter> |
523 | bool 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 | |
576 | template <class Emitter> |
577 | bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) { |
578 | if (!BreakLabel) |
579 | return false; |
580 | |
581 | this->VarScope->emitDestructors(); |
582 | return this->jump(*BreakLabel); |
583 | } |
584 | |
585 | template <class Emitter> |
586 | bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) { |
587 | if (!ContinueLabel) |
588 | return false; |
589 | |
590 | this->VarScope->emitDestructors(); |
591 | return this->jump(*ContinueLabel); |
592 | } |
593 | |
594 | template <class Emitter> |
595 | bool 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 | |
664 | template <class Emitter> |
665 | bool ByteCodeStmtGen<Emitter>::visitCaseStmt(const CaseStmt *S) { |
666 | this->emitLabel(CaseLabels[S]); |
667 | return this->visitStmt(S->getSubStmt()); |
668 | } |
669 | |
670 | template <class Emitter> |
671 | bool ByteCodeStmtGen<Emitter>::visitDefaultStmt(const DefaultStmt *S) { |
672 | this->emitLabel(*DefaultLabel); |
673 | return this->visitStmt(S->getSubStmt()); |
674 | } |
675 | |
676 | template <class Emitter> |
677 | bool 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 | |
705 | template <class Emitter> |
706 | bool ByteCodeStmtGen<Emitter>::visitCXXTryStmt(const CXXTryStmt *S) { |
707 | // Ignore all handlers. |
708 | return this->visitStmt(S->getTryBlock()); |
709 | } |
710 | |
711 | namespace clang { |
712 | namespace interp { |
713 | |
714 | template class ByteCodeStmtGen<ByteCodeEmitter>; |
715 | |
716 | } // namespace interp |
717 | } // namespace clang |
718 | |