source: src/ControlStruct/ExceptTranslate.cpp@ 9fba8e6

Last change on this file since 9fba8e6 was 9fba8e6, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Clean-up in the exception translate pass. This changes some patterns from pre-translation and sets some things up for later reworks.

  • Property mode set to 100644
File size: 21.3 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::CaseClause * create_terminate_catch_case(
148 const ast::DeclWithType * except_obj, int index, ast::CatchClause * clause );
149 ast::FunctionDecl * create_terminate_catch( CatchList &handlers );
150 ast::CompoundStmt * create_single_matcher(
151 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler );
152 ast::FunctionDecl * create_terminate_match( CatchList &handlers );
153 ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
154 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
155 ast::FunctionDecl * create_resume_handler( CatchList &handlers );
156 ast::CompoundStmt * create_resume_wrapper(
157 const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );
158 ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );
159 ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );
160 ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
161
162 // Types used in translation, first group are internal.
163 ast::ObjectDecl * make_index_object( CodeLocation const & ) const;
164 ast::ObjectDecl * make_exception_object( CodeLocation const & ) const;
165 ast::ObjectDecl * make_bool_object( CodeLocation const & ) const;
166 ast::ObjectDecl * make_voidptr_object( CodeLocation const & ) const;
167 ast::ObjectDecl * make_unused_index_object( CodeLocation const & ) const;
168
169public:
170 TryMutatorCore() :
171 except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )
172 {}
173
174 void previsit( const ast::StructDecl *structDecl );
175 ast::Stmt * postvisit( const ast::TryStmt *tryStmt );
176 ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );
177};
178
179ast::ObjectDecl * TryMutatorCore::make_index_object(
180 CodeLocation const & location ) const {
181 return new ast::ObjectDecl(
182 location,
183 "__handler_index",
184 new ast::BasicType( ast::BasicType::SignedInt )
185 );
186}
187
188ast::ObjectDecl * TryMutatorCore::make_exception_object(
189 CodeLocation const & location ) const {
190 assert( except_decl );
191 return new ast::ObjectDecl(
192 location,
193 "__exception_inst",
194 new ast::PointerType( new ast::StructInstType( except_decl ) )
195 );
196}
197
198ast::ObjectDecl * TryMutatorCore::make_bool_object(
199 CodeLocation const & location ) const {
200 return new ast::ObjectDecl(
201 location,
202 "__ret_bool",
203 new ast::BasicType( ast::BasicType::Bool ),
204 nullptr, //init
205 ast::Storage::Classes{},
206 ast::Linkage::Cforall,
207 nullptr, //width
208 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
209 );
210}
211
212ast::ObjectDecl * TryMutatorCore::make_voidptr_object(
213 CodeLocation const & location ) const {
214 return new ast::ObjectDecl(
215 location,
216 "__hook",
217 new ast::PointerType(
218 new ast::VoidType()
219 ),
220 nullptr, //init
221 ast::Storage::Classes{},
222 ast::Linkage::Cforall,
223 nullptr, //width
224 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
225 );
226}
227
228ast::ObjectDecl * TryMutatorCore::make_unused_index_object(
229 CodeLocation const & location ) const {
230 return new ast::ObjectDecl(
231 location,
232 "__handler_index",
233 new ast::BasicType(ast::BasicType::SignedInt),
234 nullptr,
235 ast::Storage::Classes{},
236 ast::Linkage::Cforall,
237 nullptr, //width
238 std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
239 );
240}
241
242// TryStmt Mutation Helpers
243
244ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
245 const ast::CompoundStmt *body ) {
246 // void (*try)(void) `body`
247 return new ast::FunctionDecl(
248 body->location,
249 "try",
250 {}, //no param
251 {}, //no return
252 ast::mutate( body ),
253 ast::Storage::Classes{},
254 ast::Linkage::Cforall
255 );
256}
257
258ast::CaseClause * TryMutatorCore::create_terminate_catch_case(
259 const ast::DeclWithType * except_obj, int index, ast::CatchClause * clause ) {
260 // case `index`:
261 // {
262 // __attribute__((cleanup(__cfaehm_cleanup_terminate)))
263 // `handler.decl` = { (virtual `decl.type`)`except` };
264 // `handler.body`;
265 // }
266 // return;
267 const CodeLocation & location = clause->location;
268
269 auto clause_except = clause->decl.strict_as<ast::ObjectDecl>();
270 auto local_except = ast::deepCopy( clause_except );
271 local_except->attributes.push_back( new ast::Attribute(
272 "cleanup",
273 { new ast::NameExpr( location, "__cfaehm_cleanup_terminate" ) }
274 ) );
275
276 local_except->init = new ast::ListInit( location, {
277 new ast::SingleInit( location,
278 new ast::VirtualCastExpr( location,
279 new ast::VariableExpr( location, except_obj ),
280 ast::deepCopy( local_except->get_type() )
281 )
282 )
283 } );
284
285 ast::DeclReplacer::DeclMap mapping;
286 mapping[clause_except] = local_except;
287 const ast::Stmt * body = strict_dynamic_cast<const ast::Stmt *>(
288 ast::DeclReplacer::replace(clause->body, mapping));
289
290 return new ast::CaseClause( location,
291 ast::ConstantExpr::from_int( location, index ),
292 {
293 new ast::CompoundStmt( location, {
294 new ast::DeclStmt( location, local_except ),
295 body,
296 } ),
297 new ast::ReturnStmt( location, nullptr ),
298 }
299 );
300}
301
302ast::FunctionDecl * TryMutatorCore::create_terminate_catch(
303 CatchList &handlers ) {
304 // void catch(int index, exception * except) {
305 // switch (index) { CATCH_CASE... }
306 // }
307
308 assert( !handlers.empty() );
309 std::vector<ast::ptr<ast::CaseClause>> handler_wrappers;
310 const CodeLocation & location = handlers.front()->location;
311
312 const ast::DeclWithType * index_obj = make_index_object( location );
313 const ast::DeclWithType * except_obj = make_exception_object( location );
314
315 // Index 1..{number of handlers}
316 for ( const auto & [index, handler] : enumerate( handlers ) ) {
317 handler_wrappers.push_back(
318 create_terminate_catch_case( except_obj, index + 1, handler ) );
319 }
320 // TODO: Some sort of meaningful error on default perhaps?
321
322 ast::SwitchStmt * handler_lookup = new ast::SwitchStmt( location,
323 new ast::VariableExpr( location, index_obj ),
324 std::move(handler_wrappers)
325 );
326 ast::CompoundStmt * body = new ast::CompoundStmt( location, {handler_lookup} );
327
328 // void (*catch)(int, exception_t *) `body`
329 return new ast::FunctionDecl(
330 location,
331 "catch",
332 { index_obj, except_obj },
333 {}, //return void
334 body,
335 ast::Storage::Classes{},
336 ast::Linkage::Cforall
337 );
338}
339
340// Create a single check from a moddified handler.
341// except_obj is referenced, modded_handler will be freed.
342ast::CompoundStmt * TryMutatorCore::create_single_matcher(
343 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler ) {
344 // {
345 // `modded_handler.decl`
346 // if ( `decl.name = (virtual `decl.type`)`except`
347 // [&& `modded_handler.cond`] ) {
348 // `modded_handler.body`
349 // }
350 // }
351
352 const CodeLocation loc = modded_handler->location;
353 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
354
355 // Local Declaration
356 const ast::ObjectDecl * local_except =
357 modded_handler->decl.strict_as<ast::ObjectDecl>();
358 block->push_back( new ast::DeclStmt( loc, local_except ) );
359
360 // Check for type match.
361 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
362 new ast::VariableExpr(loc, except_obj ),
363 local_except->get_type()
364 );
365 ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
366 new ast::VariableExpr(loc, local_except ), vcex );
367
368 // Add the check on the conditional if it is provided.
369 if ( modded_handler->cond ) {
370 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
371 }
372 // Construct the match condition.
373 block->push_back( new ast::IfStmt(loc,
374 cond, modded_handler->body, nullptr ) );
375
376 return block;
377}
378
379ast::FunctionDecl * TryMutatorCore::create_terminate_match(
380 CatchList &handlers ) {
381 // int match(exception * except) {
382 // HANDLER WRAPPERS { return `index`; }
383 // }
384
385 assert( !handlers.empty() );
386 const CodeLocation & location = handlers.front()->location;
387
388 ast::CompoundStmt * body = new ast::CompoundStmt( location );
389 const ast::DeclWithType * except_obj = make_exception_object( location );
390
391 // Index 1..{number of handlers}
392 int index = 0;
393 CatchList::iterator it;
394 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
395 ++index;
396 ast::CatchClause * handler = *it;
397
398 // Body should have been taken by create_terminate_catch.
399 // xxx - just ignore it?
400 // assert( nullptr == handler->get_body() );
401
402 // Create new body.
403 handler->body = new ast::ReturnStmt( handler->location,
404 ast::ConstantExpr::from_int( handler->location, index ) );
405
406 // Create the handler.
407 body->push_back( create_single_matcher( except_obj, handler ) );
408 *it = nullptr;
409 }
410
411 body->push_back( new ast::ReturnStmt( location,
412 ast::ConstantExpr::from_int( location, 0 ) ));
413
414 // void (*match)(exception_t *) `body`
415 return new ast::FunctionDecl(
416 location,
417 "match",
418 { except_obj },
419 { make_unused_index_object( location ) },
420 body,
421 ast::Storage::Classes{},
422 ast::Linkage::Cforall
423 );
424}
425
426ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
427 CodeLocation loc,
428 ast::FunctionDecl * try_wrapper,
429 ast::FunctionDecl * terminate_catch,
430 ast::FunctionDecl * terminate_match ) {
431 // {
432 // int __handler_index = __cfaehm_try_terminate(`try`, `match`);
433 // if ( __handler_index ) {
434 // `catch`( __handler_index, __cfaehm_get_current_termination() );
435 // }
436 // }
437
438 ast::ObjectDecl * index = make_index_object( loc );
439 index->init = new ast::SingleInit( loc,
440 new ast::UntypedExpr( loc,
441 new ast::NameExpr( loc, "__cfaehm_try_terminate" ),
442 {
443 new ast::VariableExpr( loc, try_wrapper ),
444 new ast::VariableExpr( loc, terminate_match ),
445 }
446 )
447 );
448
449 return new ast::CompoundStmt( loc, {
450 new ast::DeclStmt( loc, index ),
451 new ast::IfStmt( loc,
452 new ast::VariableExpr( loc, index ),
453 new ast::ExprStmt( loc,
454 new ast::UntypedExpr( loc,
455 new ast::VariableExpr( loc, terminate_catch ),
456 {
457 new ast::VariableExpr( loc, index ),
458 new ast::UntypedExpr( loc,
459 new ast::NameExpr( loc, "__cfaehm_get_current_termination" )
460 ),
461 }
462 )
463 )
464 ),
465 } );
466}
467
468ast::FunctionDecl * TryMutatorCore::create_resume_handler(
469 CatchList &handlers ) {
470 // bool handle(exception * except) {
471 // HANDLER WRAPPERS { `hander->body`; return true; }
472 // }
473
474 assert( !handlers.empty() );
475 const CodeLocation & location = handlers.front()->location;
476
477 ast::CompoundStmt * body = new ast::CompoundStmt( location );
478 const ast::DeclWithType * except_obj = make_exception_object( location );
479
480 CatchList::iterator it;
481 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
482 ast::CatchClause * handler = *it;
483 const CodeLocation loc = handler->location;
484 // Modifiy body.
485 ast::CompoundStmt * handling_code;
486 if (handler->body.as<ast::CompoundStmt>()) {
487 handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
488 handler->body.get_and_mutate() );
489 } else {
490 handling_code = new ast::CompoundStmt(loc);
491 handling_code->push_back( handler->body );
492 }
493 handling_code->push_back( new ast::ReturnStmt(loc,
494 ast::ConstantExpr::from_bool(loc, true ) ) );
495 handler->body = handling_code;
496
497 // Create the handler.
498 body->push_back( create_single_matcher( except_obj, handler ) );
499 *it = nullptr;
500 }
501
502 body->push_back( new ast::ReturnStmt( location,
503 ast::ConstantExpr::from_bool( location, false ) ) );
504
505 // bool (*handle)(exception_t *) `body`
506 return new ast::FunctionDecl(
507 location,
508 "handle",
509 { except_obj },
510 { make_bool_object( location ) },
511 body,
512 ast::Storage::Classes{},
513 ast::Linkage::Cforall
514 );
515}
516
517ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
518 const ast::Stmt * wraps,
519 const ast::FunctionDecl * resume_handler ) {
520 const CodeLocation loc = wraps->location;
521 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
522
523 // struct __try_resume_node __resume_node
524 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
525 // ** unwinding of the stack here could cause problems **
526 // ** however I don't think that can happen currently **
527 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
528
529 ast::ObjectDecl * obj = new ast::ObjectDecl(
530 loc,
531 "__resume_node",
532 new ast::StructInstType(
533 node_decl
534 ),
535 nullptr,
536 ast::Storage::Classes{},
537 ast::Linkage::Cforall,
538 nullptr,
539 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
540 );
541 appendDeclStmt( body, obj );
542
543 ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
544 "__cfaehm_try_resume_setup" ) );
545 setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
546 setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
547
548 body->push_back( new ast::ExprStmt(loc, setup ) );
549
550 body->push_back( wraps );
551 return body;
552}
553
554ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
555 ast::TryStmt * tryStmt ) {
556 // void finally(__attribute__((unused)) void *) `finally->body`
557 const ast::FinallyClause * finally = tryStmt->finally;
558 return new ast::FunctionDecl(
559 tryStmt->location,
560 "finally",
561 { make_voidptr_object( tryStmt->location ) },
562 {}, //return void
563 ast::mutate( finally->body.get() ),
564 ast::Storage::Classes{},
565 ast::Linkage::Cforall,
566 {},
567 { ast::Function::Inline }
568 );
569}
570
571ast::ObjectDecl * TryMutatorCore::create_finally_hook(
572 ast::FunctionDecl * finally_wrapper ) {
573 // struct __cfaehm_cleanup_hook __finally_hook
574 // __attribute__((cleanup( `finally_wrapper` )));
575
576 const CodeLocation & location = finally_wrapper->location;
577 return new ast::ObjectDecl(
578 location,
579 "__finally_hook",
580 new ast::StructInstType(
581 hook_decl
582 ),
583 nullptr,
584 ast::Storage::Classes{},
585 ast::Linkage::Cforall,
586 nullptr,
587 {new ast::Attribute("cleanup", {new ast::VariableExpr(location, finally_wrapper)})}
588 );
589}
590
591ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
592 // return false;
593 const CodeLocation loc = throwStmt->location;
594 ast::Stmt * result = new ast::ReturnStmt(loc,
595 ast::ConstantExpr::from_bool( loc, false )
596 );
597 result->labels = throwStmt->labels;
598 return result;
599}
600
601// Visiting/Mutating Functions
602void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
603 if ( !structDecl->body ) {
604 // Skip children?
605 return;
606 } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
607 assert( nullptr == except_decl );
608 except_decl = structDecl;
609 } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
610 assert( nullptr == node_decl );
611 node_decl = structDecl;
612 } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
613 assert( nullptr == hook_decl );
614 hook_decl = structDecl;
615 }
616}
617
618ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
619 assert( except_decl );
620 assert( node_decl );
621 assert( hook_decl );
622
623 const CodeLocation loc = tryStmt->location;
624 ast::TryStmt * mutStmt = mutate(tryStmt);
625 // Generate a prefix for the function names?
626
627 ast::CompoundStmt * block = new ast::CompoundStmt( loc );
628 // ast::CompoundStmt * inner = take_try_block( mutStmt );
629 // this is never mutated so let node deletion do its job?
630 const ast::CompoundStmt * inner = mutStmt->body;
631
632 if ( mutStmt->finally ) {
633 // Define the helper function.
634 ast::FunctionDecl * finally_block =
635 create_finally_wrapper( mutStmt );
636 appendDeclStmt( block, finally_block );
637 // Create and add the finally cleanup hook.
638 appendDeclStmt( block, create_finally_hook( finally_block ) );
639 }
640
641 CatchList termination_handlers;
642 CatchList resumption_handlers;
643
644 for (auto & handler: mutStmt->handlers) {
645 // xxx - should always be unique? mutate as safe const-cast
646 assert(handler->unique());
647 if (handler->kind == ast::ExceptionKind::Resume) {
648 resumption_handlers.push_back(handler.get_and_mutate());
649 }
650 else {
651 termination_handlers.push_back(handler.get_and_mutate());
652 }
653 }
654
655 if ( resumption_handlers.size() ) {
656 // Define the helper function.
657 ast::FunctionDecl * resume_handler =
658 create_resume_handler( resumption_handlers );
659 appendDeclStmt( block, resume_handler );
660 // Prepare hooks
661 inner = create_resume_wrapper( inner, resume_handler );
662 }
663
664 if ( termination_handlers.size() ) {
665 // Define the three helper functions.
666 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
667 appendDeclStmt( block, try_wrapper );
668 ast::FunctionDecl * terminate_catch =
669 create_terminate_catch( termination_handlers );
670 appendDeclStmt( block, terminate_catch );
671 ast::FunctionDecl * terminate_match =
672 create_terminate_match( termination_handlers );
673 appendDeclStmt( block, terminate_match );
674 // Build the call to the try wrapper.
675 inner = create_terminate_caller(inner->location,
676 try_wrapper, terminate_catch, terminate_match );
677 }
678
679 // Embed the try block.
680 block->push_back( inner );
681
682 return block;
683}
684
685ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
686 // Only valid `throwResume;` statements should remain. (2/3 checks)
687 assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
688 return create_resume_rethrow( throwStmt );
689}
690
691} // namespace
692
693void translateThrows( ast::TranslationUnit & transUnit ) {
694 ast::Pass<TranslateThrowsCore>::run( transUnit );
695}
696
697void translateTries( ast::TranslationUnit & transUnit ) {
698 ast::Pass<TryMutatorCore>::run(transUnit);
699}
700
701} // namespace ControlStruct
702
703// Local Variables: //
704// tab-width: 4 //
705// mode: c++ //
706// compile-command: "make install" //
707// End: //
Note: See TracBrowser for help on using the repository browser.