source: src/ControlStruct/ExceptTranslateNew.cpp@ 1eec0b0

ADT ast-experimental enum pthread-emulation qualifiedEnum
Last change on this file since 1eec0b0 was b56ad5e, checked in by Fangren Yu <f37yu@…>, 4 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

  • Property mode set to 100644
File size: 22.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ExceptTranslateNew.cpp -- Conversion of exception control flow structures.
8//
9// Author : Andrew Beach
10// Created On : Mon Nov 8 11:53:00 2021
11// Last Modified By : Peter A. Buhr
12// Last Modified On : Mon Jan 31 18:49:58 2022
13// Update Count : 1
14//
15
16#include "ExceptTranslate.h"
17
18#include "AST/Expr.hpp"
19#include "AST/Pass.hpp"
20#include "AST/Stmt.hpp"
21#include "AST/TranslationUnit.hpp"
22#include "AST/DeclReplacer.hpp"
23
24namespace ControlStruct {
25
26namespace {
27
28 typedef std::list<ast::CatchStmt*> CatchList;
29
30 void split( CatchList& allHandlers, CatchList& terHandlers,
31 CatchList& resHandlers ) {
32 while ( !allHandlers.empty() ) {
33 ast::CatchStmt * stmt = allHandlers.front();
34 allHandlers.pop_front();
35 if (stmt->kind == ast::ExceptionKind::Terminate) {
36 terHandlers.push_back(stmt);
37 } else {
38 resHandlers.push_back(stmt);
39 }
40 }
41 }
42
43 void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {
44 block->push_back(new ast::DeclStmt(block->location, item));
45 }
46
47class TranslateThrowsCore : public ast::WithGuards {
48 const ast::ObjectDecl * terminateHandlerExcept;
49 enum Context { NoHandler, TerHandler, ResHandler } currentContext;
50
51 const ast::Stmt * createEitherThrow(
52 const ast::ThrowStmt * throwStmt, const char * funcName );
53 const ast::Stmt * createTerminateRethrow( const ast::ThrowStmt * );
54
55public:
56 TranslateThrowsCore() :
57 terminateHandlerExcept( nullptr ), currentContext( NoHandler )
58 {}
59
60 void previsit( const ast::CatchStmt * stmt );
61 const ast::Stmt * postvisit( const ast::ThrowStmt * stmt );
62};
63
64const ast::Stmt * TranslateThrowsCore::createEitherThrow(
65 const ast::ThrowStmt * throwStmt, const char * funcName ) {
66 // `throwFunc`( `throwStmt->name` );
67 ast::UntypedExpr * call = new ast::UntypedExpr( throwStmt->location,
68 new ast::NameExpr( throwStmt->location, funcName )
69 );
70 call->args.push_back( throwStmt->expr );
71 return new ast::ExprStmt( throwStmt->location, call );
72}
73
74ast::VariableExpr * varOf( const ast::DeclWithType * decl ) {
75 return new ast::VariableExpr( decl->location, decl );
76}
77
78const ast::Stmt * TranslateThrowsCore::createTerminateRethrow(
79 const ast::ThrowStmt * stmt ) {
80 // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
81 assert( nullptr == stmt->expr );
82 assert( terminateHandlerExcept );
83
84 ast::CompoundStmt * result = new ast::CompoundStmt(
85 stmt->location, {}, std::vector<ast::Label>( stmt->labels ) );
86 result->push_back( new ast::ExprStmt( stmt->location,
87 ast::UntypedExpr::createAssign(
88 stmt->location,
89 varOf( terminateHandlerExcept ),
90 ast::ConstantExpr::null(
91 stmt->location,
92 terminateHandlerExcept->type
93 )
94 )
95 ) );
96 result->push_back( new ast::ExprStmt( stmt->location, new ast::UntypedExpr(
97 stmt->location,
98 new ast::NameExpr( stmt->location, "__cfaehm_rethrow_terminate" )
99 ) ) );
100 return result;
101}
102
103void TranslateThrowsCore::previsit( const ast::CatchStmt * stmt ) {
104 // Validate the statement's form.
105 const ast::ObjectDecl * decl = stmt->decl.as<ast::ObjectDecl>();
106 // Also checking the type would be nice.
107 if ( !decl || !decl->type.as<ast::PointerType>() ) {
108 std::string kind = (ast::Terminate == stmt->kind) ? "catch" : "catchResume";
109 SemanticError( stmt->location, kind + " must have pointer to an exception type" );
110 }
111
112 // Track the handler context.
113 if ( ast::Terminate == stmt->kind ) {
114 GuardValue( currentContext ) = TerHandler;
115 GuardValue( terminateHandlerExcept ) = decl;
116 } else {
117 GuardValue( currentContext ) = ResHandler;
118 }
119}
120
121const ast::Stmt * TranslateThrowsCore::postvisit(
122 const ast::ThrowStmt * stmt ) {
123 // Ignoring ThrowStmt::target for now.
124 // Handle Termination (Raise, Reraise, Error):
125 if ( ast::Terminate == stmt->kind ) {
126 if ( stmt->expr ) {
127 return createEitherThrow( stmt, "$throw" );
128 } else if ( TerHandler == currentContext ) {
129 return createTerminateRethrow( stmt );
130 } else {
131 abort( "Invalid throw in %s at %i\n",
132 stmt->location.filename.c_str(),
133 stmt->location.first_line);
134 }
135 // Handle Resumption (Raise, Reraise, Error):
136 } else {
137 if ( stmt->expr ) {
138 return createEitherThrow( stmt, "$throwResume" );
139 } else if ( ResHandler == currentContext ) {
140 // This has to be handled later.
141 return stmt;
142 } else {
143 abort( "Invalid throwResume in %s at %i\n",
144 stmt->location.filename.c_str(),
145 stmt->location.first_line);
146 }
147 }
148}
149
150
151class TryMutatorCore {
152 // The built in types used in translation.
153 const ast::StructDecl * except_decl;
154 const ast::StructDecl * node_decl;
155 const ast::StructDecl * hook_decl;
156
157 // The many helper functions for code/syntree generation.
158 ast::CompoundStmt * take_try_block( ast::TryStmt * tryStmt );
159 ast::FunctionDecl * create_try_wrapper( const ast::CompoundStmt * body );
160 ast::FunctionDecl * create_terminate_catch( CatchList &handlers );
161 ast::CompoundStmt * create_single_matcher(
162 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler );
163 ast::FunctionDecl * create_terminate_match( CatchList &handlers );
164 ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
165 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
166 ast::FunctionDecl * create_resume_handler( CatchList &handlers );
167 ast::CompoundStmt * create_resume_wrapper(
168 const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );
169 ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );
170 ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );
171 ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
172
173 // Types used in translation, make sure to use clone.
174 // void (*function)();
175 ast::FunctionDecl * try_func_t;
176 // void (*function)(int, exception);
177 ast::FunctionDecl * catch_func_t;
178 // int (*function)(exception);
179 ast::FunctionDecl * match_func_t;
180 // bool (*function)(exception);
181 ast::FunctionDecl * handle_func_t;
182 // void (*function)(__attribute__((unused)) void *);
183 ast::FunctionDecl * finally_func_t;
184
185 ast::StructInstType * create_except_type() {
186 assert( except_decl );
187 return new ast::StructInstType( except_decl );
188 }
189 void init_func_types();
190
191public:
192 TryMutatorCore() :
193 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )
194 {}
195
196 void previsit( const ast::StructDecl *structDecl );
197 ast::Stmt * postvisit( const ast::TryStmt *tryStmt );
198 ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );
199};
200
201void TryMutatorCore::init_func_types() {
202 assert( except_decl );
203
204 ast::ObjectDecl index_obj(
205 {},
206 "__handler_index",
207 new ast::BasicType(ast::BasicType::SignedInt)
208 );
209 ast::ObjectDecl exception_obj(
210 {},
211 "__exception_inst",
212 new ast::PointerType(
213 new ast::StructInstType( except_decl )
214 ),
215 NULL
216 );
217 ast::ObjectDecl bool_obj(
218 {},
219 "__ret_bool",
220 new ast::BasicType( ast::BasicType::Bool ),
221 nullptr, //init
222 ast::Storage::Classes{},
223 ast::Linkage::Cforall,
224 nullptr, //width
225 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
226 );
227 ast::ObjectDecl voidptr_obj(
228 {},
229 "__hook",
230 new ast::PointerType(
231 new ast::VoidType()
232 ),
233 nullptr, //init
234 ast::Storage::Classes{},
235 ast::Linkage::Cforall,
236 nullptr, //width
237 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
238 );
239
240 ast::ObjectDecl unused_index_obj(
241 {},
242 "__handler_index",
243 new ast::BasicType(ast::BasicType::SignedInt),
244 nullptr,
245 ast::Storage::Classes{},
246 ast::Linkage::Cforall,
247 nullptr, //width
248 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
249 );
250 //unused_index_obj->attributes.push_back( new Attribute( "unused" ) );
251
252 try_func_t = new ast::FunctionDecl(
253 {},
254 "try",
255 {}, //forall
256 {}, //no param
257 {}, //no return
258 nullptr,
259 ast::Storage::Classes{},
260 ast::Linkage::Cforall
261 );
262
263 catch_func_t = new ast::FunctionDecl(
264 {},
265 "catch",
266 {}, //forall
267 {ast::deepCopy(&index_obj), ast::deepCopy(&exception_obj)},//param
268 {}, //return void
269 nullptr,
270 ast::Storage::Classes{},
271 ast::Linkage::Cforall
272 );
273
274 match_func_t = new ast::FunctionDecl(
275 {},
276 "match",
277 {}, //forall
278 {ast::deepCopy(&exception_obj)},
279 {ast::deepCopy(&unused_index_obj)},
280 nullptr,
281 ast::Storage::Classes{},
282 ast::Linkage::Cforall
283 );
284
285 handle_func_t = new ast::FunctionDecl(
286 {},
287 "handle",
288 {}, //forall
289 {ast::deepCopy(&exception_obj)},
290 {ast::deepCopy(&bool_obj)},
291 nullptr,
292 ast::Storage::Classes{},
293 ast::Linkage::Cforall
294 );
295
296 finally_func_t = new ast::FunctionDecl(
297 {},
298 "finally",
299 {}, //forall
300 {ast::deepCopy(&voidptr_obj)},
301 {}, //return void
302 nullptr,
303 ast::Storage::Classes{},
304 ast::Linkage::Cforall
305 );
306
307 //catch_func_t.get_parameters().push_back( index_obj.clone() );
308 //catch_func_t.get_parameters().push_back( exception_obj.clone() );
309 //match_func_t.get_returnVals().push_back( unused_index_obj );
310 //match_func_t.get_parameters().push_back( exception_obj.clone() );
311 //handle_func_t.get_returnVals().push_back( bool_obj.clone() );
312 //handle_func_t.get_parameters().push_back( exception_obj.clone() );
313 //finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
314}
315
316// TryStmt Mutation Helpers
317
318/*
319ast::CompoundStmt * TryMutatorCore::take_try_block( ast::TryStmt *tryStmt ) {
320 ast::CompoundStmt * block = tryStmt->body;
321 tryStmt->body = nullptr;
322 return block;
323}
324*/
325
326ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
327 const ast::CompoundStmt *body ) {
328
329 ast::FunctionDecl * ret = ast::deepCopy(try_func_t);
330 ret->stmts = body;
331 return ret;
332}
333
334ast::FunctionDecl * TryMutatorCore::create_terminate_catch(
335 CatchList &handlers ) {
336 std::vector<ast::ptr<ast::Stmt>> handler_wrappers;
337
338 assert (!handlers.empty());
339 const CodeLocation loc = handlers.front()->location;
340
341 ast::FunctionDecl * func_t = ast::deepCopy(catch_func_t);
342 const ast::DeclWithType * index_obj = func_t->params.front();
343 const ast::DeclWithType * except_obj = func_t->params.back();
344
345 // Index 1..{number of handlers}
346 int index = 0;
347 CatchList::iterator it = handlers.begin();
348 for ( ; it != handlers.end() ; ++it ) {
349 ++index;
350 ast::CatchStmt * handler = *it;
351 const CodeLocation loc = handler->location;
352
353 // case `index`:
354 // {
355 // `handler.decl` = { (virtual `decl.type`)`except` };
356 // `handler.body`;
357 // }
358 // return;
359 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
360
361 // Just copy the exception value. (Post Validation)
362 const ast::ObjectDecl * handler_decl =
363 handler->decl.strict_as<ast::ObjectDecl>();
364 ast::ObjectDecl * local_except = ast::deepCopy(handler_decl);
365 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
366 new ast::VariableExpr( loc, except_obj ),
367 local_except->get_type()
368 );
369 vcex->location = handler->location;
370 local_except->init = new ast::ListInit(loc, { new ast::SingleInit( loc, vcex ) });
371 block->push_back( new ast::DeclStmt( loc, local_except ) );
372
373 // Add the cleanup attribute.
374 local_except->attributes.push_back( new ast::Attribute(
375 "cleanup",
376 { new ast::NameExpr( loc, "__cfaehm_cleanup_terminate" ) }
377 ) );
378
379 ast::DeclReplacer::DeclMap mapping;
380 mapping[handler_decl] = local_except;
381 const ast::Stmt * mutBody = strict_dynamic_cast<const ast::Stmt *>(
382 ast::DeclReplacer::replace(handler->body, mapping));
383
384
385 block->push_back( mutBody );
386 // handler->body = nullptr;
387
388 handler_wrappers.push_back( new ast::CaseStmt(loc,
389 ast::ConstantExpr::from_int(loc, index) ,
390 { block, new ast::ReturnStmt( loc, nullptr ) }
391 ));
392 }
393 // TODO: Some sort of meaningful error on default perhaps?
394
395 /*
396 std::list<Statement*> stmt_handlers;
397 while ( !handler_wrappers.empty() ) {
398 stmt_handlers.push_back( handler_wrappers.front() );
399 handler_wrappers.pop_front();
400 }
401 */
402
403 ast::SwitchStmt * handler_lookup = new ast::SwitchStmt(loc,
404 new ast::VariableExpr( loc, index_obj ),
405 std::move(handler_wrappers)
406 );
407 ast::CompoundStmt * body = new ast::CompoundStmt(loc,
408 {handler_lookup});
409
410 func_t->stmts = body;
411 return func_t;
412}
413
414// Create a single check from a moddified handler.
415// except_obj is referenced, modded_handler will be freed.
416ast::CompoundStmt * TryMutatorCore::create_single_matcher(
417 const ast::DeclWithType * except_obj, ast::CatchStmt * modded_handler ) {
418 // {
419 // `modded_handler.decl`
420 // if ( `decl.name = (virtual `decl.type`)`except`
421 // [&& `modded_handler.cond`] ) {
422 // `modded_handler.body`
423 // }
424 // }
425
426 const CodeLocation loc = modded_handler->location;
427 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
428
429 // Local Declaration
430 const ast::ObjectDecl * local_except =
431 modded_handler->decl.strict_as<ast::ObjectDecl>();
432 block->push_back( new ast::DeclStmt( loc, local_except ) );
433
434 // Check for type match.
435 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
436 new ast::VariableExpr(loc, except_obj ),
437 local_except->get_type()
438 );
439 ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
440 new ast::VariableExpr(loc, local_except ), vcex );
441
442 // Add the check on the conditional if it is provided.
443 if ( modded_handler->cond ) {
444 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
445 }
446 // Construct the match condition.
447 block->push_back( new ast::IfStmt(loc,
448 cond, modded_handler->body, nullptr ) );
449
450 // xxx - how does this work in new ast
451 //modded_handler->set_decl( nullptr );
452 //modded_handler->set_cond( nullptr );
453 //modded_handler->set_body( nullptr );
454 //delete modded_handler;
455 return block;
456}
457
458ast::FunctionDecl * TryMutatorCore::create_terminate_match(
459 CatchList &handlers ) {
460 // int match(exception * except) {
461 // HANDLER WRAPPERS { return `index`; }
462 // }
463
464 assert (!handlers.empty());
465 const CodeLocation loc = handlers.front()->location;
466
467 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
468
469 ast::FunctionDecl * func_t = ast::deepCopy(match_func_t);
470 const ast::DeclWithType * except_obj = func_t->params.back();
471
472 // Index 1..{number of handlers}
473 int index = 0;
474 CatchList::iterator it;
475 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
476 ++index;
477 ast::CatchStmt * handler = *it;
478
479 // Body should have been taken by create_terminate_catch.
480 // xxx - just ignore it?
481 // assert( nullptr == handler->get_body() );
482
483 // Create new body.
484 handler->body = new ast::ReturnStmt( handler->location,
485 ast::ConstantExpr::from_int( handler->location, index ) );
486
487 // Create the handler.
488 body->push_back( create_single_matcher( except_obj, handler ) );
489 *it = nullptr;
490 }
491
492 body->push_back( new ast::ReturnStmt(loc,
493 ast::ConstantExpr::from_int( loc, 0 ) ));
494
495 func_t->stmts = body;
496
497 return func_t;
498}
499
500ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
501 CodeLocation loc,
502 ast::FunctionDecl * try_wrapper,
503 ast::FunctionDecl * terminate_catch,
504 ast::FunctionDecl * terminate_match ) {
505 // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
506
507 ast::UntypedExpr * caller = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
508 "__cfaehm_try_terminate" ) );
509 caller->args.push_back( new ast::VariableExpr(loc, try_wrapper ) );
510 caller->args.push_back( new ast::VariableExpr(loc, terminate_catch ) );
511 caller->args.push_back( new ast::VariableExpr(loc, terminate_match ) );
512
513 ast::CompoundStmt * callStmt = new ast::CompoundStmt(loc);
514 callStmt->push_back( new ast::ExprStmt( loc, caller ) );
515 return callStmt;
516}
517
518ast::FunctionDecl * TryMutatorCore::create_resume_handler(
519 CatchList &handlers ) {
520 // bool handle(exception * except) {
521 // HANDLER WRAPPERS { `hander->body`; return true; }
522 // }
523 assert (!handlers.empty());
524 const CodeLocation loc = handlers.front()->location;
525 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
526
527 ast::FunctionDecl * func_t = ast::deepCopy(handle_func_t);
528 const ast::DeclWithType * except_obj = func_t->params.back();
529
530 CatchList::iterator it;
531 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
532 ast::CatchStmt * handler = *it;
533 const CodeLocation loc = handler->location;
534 // Modifiy body.
535 ast::CompoundStmt * handling_code;
536 if (handler->body.as<ast::CompoundStmt>()) {
537 handling_code =
538 strict_dynamic_cast<ast::CompoundStmt*>( handler->body.get_and_mutate() );
539 } else {
540 handling_code = new ast::CompoundStmt(loc);
541 handling_code->push_back( handler->body );
542 }
543 handling_code->push_back( new ast::ReturnStmt(loc,
544 ast::ConstantExpr::from_bool(loc, true ) ) );
545 handler->body = handling_code;
546
547 // Create the handler.
548 body->push_back( create_single_matcher( except_obj, handler ) );
549 *it = nullptr;
550 }
551
552 body->push_back( new ast::ReturnStmt(loc,
553 ast::ConstantExpr::from_bool(loc, false ) ) );
554 func_t->stmts = body;
555
556 return func_t;
557}
558
559ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
560 const ast::Stmt * wraps,
561 const ast::FunctionDecl * resume_handler ) {
562 const CodeLocation loc = wraps->location;
563 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
564
565 // struct __try_resume_node __resume_node
566 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
567 // ** unwinding of the stack here could cause problems **
568 // ** however I don't think that can happen currently **
569 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
570
571 ast::ObjectDecl * obj = new ast::ObjectDecl(
572 loc,
573 "__resume_node",
574 new ast::StructInstType(
575 node_decl
576 ),
577 nullptr,
578 ast::Storage::Classes{},
579 ast::Linkage::Cforall,
580 nullptr,
581 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
582 );
583 appendDeclStmt( body, obj );
584
585 ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
586 "__cfaehm_try_resume_setup" ) );
587 setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
588 setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
589
590 body->push_back( new ast::ExprStmt(loc, setup ) );
591
592 body->push_back( wraps );
593 return body;
594}
595
596ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
597 ast::TryStmt * tryStmt ) {
598 // void finally() { `finally->block` }
599 const ast::FinallyStmt * finally = tryStmt->finally;
600 const ast::CompoundStmt * body = finally->body;
601
602 ast::FunctionDecl * func_t = ast::deepCopy(finally_func_t);
603 func_t->stmts = body;
604
605 // finally->set_block( nullptr );
606 // delete finally;
607 tryStmt->finally = nullptr;
608
609
610 return func_t;
611}
612
613ast::ObjectDecl * TryMutatorCore::create_finally_hook(
614 ast::FunctionDecl * finally_wrapper ) {
615 // struct __cfaehm_cleanup_hook __finally_hook
616 // __attribute__((cleanup( `finally_wrapper` )));
617
618 const CodeLocation loc = finally_wrapper->location;
619 // Make Cleanup Attribute.
620 /*
621 std::list< ast::Attribute * > attributes;
622 {
623 std::list< > attr_params;
624 attr_params.push_back( nameOf( finally_wrapper ) );
625 attributes.push_back( new Attribute( "cleanup", attr_params ) );
626 }
627 */
628
629 return new ast::ObjectDecl(
630 loc,
631 "__finally_hook",
632 new ast::StructInstType(
633 hook_decl
634 ),
635 nullptr,
636 ast::Storage::Classes{},
637 ast::Linkage::Cforall,
638 nullptr,
639 {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}
640 );
641}
642
643ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
644 // return false;
645 const CodeLocation loc = throwStmt->location;
646 ast::Stmt * result = new ast::ReturnStmt(loc,
647 ast::ConstantExpr::from_bool( loc, false )
648 );
649 result->labels = throwStmt->labels;
650 // delete throwStmt; done by postvisit
651 return result;
652}
653
654// Visiting/Mutating Functions
655void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
656 if ( !structDecl->body ) {
657 // Skip children?
658 return;
659 } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
660 assert( nullptr == except_decl );
661 except_decl = structDecl;
662 init_func_types();
663 } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
664 assert( nullptr == node_decl );
665 node_decl = structDecl;
666 } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
667 assert( nullptr == hook_decl );
668 hook_decl = structDecl;
669 }
670}
671
672ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
673 assert( except_decl );
674 assert( node_decl );
675 assert( hook_decl );
676
677 const CodeLocation loc = tryStmt->location;
678 ast::TryStmt * mutStmt = mutate(tryStmt);
679 // Generate a prefix for the function names?
680
681 ast::CompoundStmt * block = new ast::CompoundStmt( loc );
682 // ast::CompoundStmt * inner = take_try_block( mutStmt );
683 // this is never mutated so let node deletion do its job?
684 const ast::CompoundStmt * inner = mutStmt->body;
685
686 if ( mutStmt->finally ) {
687 // Define the helper function.
688 ast::FunctionDecl * finally_block =
689 create_finally_wrapper( mutStmt );
690 appendDeclStmt( block, finally_block );
691 // Create and add the finally cleanup hook.
692 appendDeclStmt( block, create_finally_hook( finally_block ) );
693 }
694
695 CatchList termination_handlers;
696 CatchList resumption_handlers;
697
698 for (auto & handler: mutStmt->handlers) {
699 // xxx - should always be unique? mutate as safe const-cast
700 assert(handler->unique());
701 if (handler->kind == ast::ExceptionKind::Resume) {
702 resumption_handlers.push_back(handler.get_and_mutate());
703 }
704 else {
705 termination_handlers.push_back(handler.get_and_mutate());
706 }
707 }
708 // split( mutStmt->handlers,
709 // termination_handlers, resumption_handlers );
710
711 if ( resumption_handlers.size() ) {
712 // Define the helper function.
713 ast::FunctionDecl * resume_handler =
714 create_resume_handler( resumption_handlers );
715 appendDeclStmt( block, resume_handler );
716 // Prepare hooks
717 inner = create_resume_wrapper( inner, resume_handler );
718 }
719
720 if ( termination_handlers.size() ) {
721 // Define the three helper functions.
722 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
723 appendDeclStmt( block, try_wrapper );
724 ast::FunctionDecl * terminate_catch =
725 create_terminate_catch( termination_handlers );
726 appendDeclStmt( block, terminate_catch );
727 ast::FunctionDecl * terminate_match =
728 create_terminate_match( termination_handlers );
729 appendDeclStmt( block, terminate_match );
730 // Build the call to the try wrapper.
731 inner = create_terminate_caller(inner->location,
732 try_wrapper, terminate_catch, terminate_match );
733 }
734
735 // Embed the try block.
736 block->push_back( inner );
737
738 return block;
739}
740
741ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
742 // Only valid `throwResume;` statements should remain. (2/3 checks)
743 assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
744 return create_resume_rethrow( throwStmt );
745}
746
747} // namespace
748
749void translateThrows( ast::TranslationUnit & transUnit ) {
750 ast::Pass<TranslateThrowsCore>::run( transUnit );
751}
752
753void translateTries( ast::TranslationUnit & transUnit ) {
754 ast::Pass<TryMutatorCore>::run(transUnit);
755}
756
757} // namespace ControlStruct
758
759// Local Variables: //
760// tab-width: 4 //
761// mode: c++ //
762// compile-command: "make install" //
763// End: //
Note: See TracBrowser for help on using the repository browser.