source: src/ControlStruct/ExceptTranslate.cpp@ 40ab446

Last change on this file since 40ab446 was 2554f24, checked in by Andrew Beach <ajbeach@…>, 22 months ago

Try terminate now does not call the catch function, now they have the same caller. This involved updating some platform dependent code which should be correct in all cases.

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