source: src/ControlStruct/ExceptTranslate.cpp@ 0dffe91

Last change on this file since 0dffe91 was c92bdcc, checked in by Andrew Beach <ajbeach@…>, 17 months ago

Updated the rest of the names in src/ (except for the generated files).

  • Property mode set to 100644
File size: 20.1 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.hpp"
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::CompoundStmt * create_single_matcher(
150 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler );
151 ast::FunctionDecl * create_terminate_match( CatchList &handlers );
152 ast::CompoundStmt * create_terminate_caller( const CodeLocation & location,
153 ast::FunctionDecl * try_wrapper, ast::FunctionDecl * terminate_match,
154 CatchList & terminate_handlers );
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::BasicKind::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::BasicKind::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::BasicKind::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 // break;
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::BranchStmt( location, ast::BranchStmt::Break,
298 ast::Label( location ) ),
299 }
300 );
301}
302
303// Create a single check from a moddified handler.
304// except_obj is referenced, modded_handler will be freed.
305ast::CompoundStmt * TryMutatorCore::create_single_matcher(
306 const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler ) {
307 // {
308 // `modded_handler.decl`
309 // if ( `decl.name = (virtual `decl.type`)`except`
310 // [&& `modded_handler.cond`] ) {
311 // `modded_handler.body`
312 // }
313 // }
314
315 const CodeLocation loc = modded_handler->location;
316 ast::CompoundStmt * block = new ast::CompoundStmt(loc);
317
318 // Local Declaration
319 const ast::ObjectDecl * local_except =
320 modded_handler->decl.strict_as<ast::ObjectDecl>();
321 block->push_back( new ast::DeclStmt( loc, local_except ) );
322
323 // Check for type match.
324 ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
325 new ast::VariableExpr(loc, except_obj ),
326 local_except->get_type()
327 );
328 ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
329 new ast::VariableExpr(loc, local_except ), vcex );
330
331 // Add the check on the conditional if it is provided.
332 if ( modded_handler->cond ) {
333 cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
334 }
335 // Construct the match condition.
336 block->push_back( new ast::IfStmt(loc,
337 cond, modded_handler->body, nullptr ) );
338
339 return block;
340}
341
342ast::FunctionDecl * TryMutatorCore::create_terminate_match(
343 CatchList &handlers ) {
344 // int match(exception * except) {
345 // HANDLER WRAPPERS { return `index`; }
346 // }
347
348 assert( !handlers.empty() );
349 const CodeLocation & location = handlers.front()->location;
350
351 ast::CompoundStmt * body = new ast::CompoundStmt( location );
352 const ast::DeclWithType * except_obj = make_exception_object( location );
353
354 // Index 1..{number of handlers}
355 int index = 0;
356 for ( ast::CatchClause * handler : handlers ) {
357 ++index;
358
359 ast::ptr<ast::Stmt> other_body = new ast::ReturnStmt( handler->location,
360 ast::ConstantExpr::from_int( handler->location, index ) );
361 handler->body.swap( other_body );
362
363 body->push_back( create_single_matcher( except_obj, handler ) );
364
365 handler->body.swap( other_body );
366 }
367
368 body->push_back( new ast::ReturnStmt( location,
369 ast::ConstantExpr::from_int( location, 0 ) ));
370
371 // void (*match)(exception_t *) `body`
372 return new ast::FunctionDecl(
373 location,
374 "match",
375 { except_obj },
376 { make_unused_index_object( location ) },
377 body,
378 ast::Storage::Classes{},
379 ast::Linkage::Cforall
380 );
381}
382
383ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
384 const CodeLocation & loc,
385 ast::FunctionDecl * try_wrapper,
386 ast::FunctionDecl * terminate_match,
387 CatchList & terminate_handlers ) {
388 // {
389 // int __handler_index = __cfaehm_try_terminate(`try`, `match`);
390 // if ( __handler_index ) {
391 // `catch`( __handler_index, __cfaehm_get_current_termination() );
392 // }
393 // }
394
395 ast::ObjectDecl * index = make_index_object( loc );
396 index->init = new ast::SingleInit( loc,
397 new ast::UntypedExpr( loc,
398 new ast::NameExpr( loc, "__cfaehm_try_terminate" ),
399 {
400 new ast::VariableExpr( loc, try_wrapper ),
401 new ast::VariableExpr( loc, terminate_match ),
402 }
403 )
404 );
405
406 ast::ObjectDecl * except = make_exception_object( loc );
407 except->init = new ast::SingleInit( loc,
408 new ast::UntypedExpr( loc,
409 new ast::NameExpr( loc, "__cfaehm_get_current_termination" )
410 )
411 );
412
413 std::vector<ast::ptr<ast::CaseClause>> cases;
414 for ( auto const & [index, handler] : enumerate( terminate_handlers ) ) {
415 cases.emplace_back(
416 create_terminate_catch_case( except, index + 1, handler ) );
417 }
418 auto switch_stmt = new ast::SwitchStmt( loc,
419 new ast::VariableExpr( loc, index ), std::move( cases ) );
420
421 return new ast::CompoundStmt( loc, {
422 new ast::DeclStmt( loc, index ),
423 new ast::IfStmt( loc,
424 new ast::VariableExpr( loc, index ),
425 new ast::CompoundStmt( loc, {
426 new ast::DeclStmt( loc, except ),
427 switch_stmt,
428 } )
429 ),
430 } );
431}
432
433ast::FunctionDecl * TryMutatorCore::create_resume_handler(
434 CatchList &handlers ) {
435 // bool handle(exception * except) {
436 // HANDLER WRAPPERS { `hander->body`; return true; }
437 // }
438
439 assert( !handlers.empty() );
440 const CodeLocation & location = handlers.front()->location;
441
442 ast::CompoundStmt * body = new ast::CompoundStmt( location );
443 const ast::DeclWithType * except_obj = make_exception_object( location );
444
445 CatchList::iterator it;
446 for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
447 ast::CatchClause * handler = *it;
448 const CodeLocation loc = handler->location;
449 // Modifiy body.
450 ast::CompoundStmt * handling_code;
451 if (handler->body.as<ast::CompoundStmt>()) {
452 handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
453 handler->body.get_and_mutate() );
454 } else {
455 handling_code = new ast::CompoundStmt(loc);
456 handling_code->push_back( handler->body );
457 }
458 handling_code->push_back( new ast::ReturnStmt(loc,
459 ast::ConstantExpr::from_bool(loc, true ) ) );
460 handler->body = handling_code;
461
462 // Create the handler.
463 body->push_back( create_single_matcher( except_obj, handler ) );
464 *it = nullptr;
465 }
466
467 body->push_back( new ast::ReturnStmt( location,
468 ast::ConstantExpr::from_bool( location, false ) ) );
469
470 // bool (*handle)(exception_t *) `body`
471 return new ast::FunctionDecl(
472 location,
473 "handle",
474 { except_obj },
475 { make_bool_object( location ) },
476 body,
477 ast::Storage::Classes{},
478 ast::Linkage::Cforall
479 );
480}
481
482ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
483 const ast::Stmt * wraps,
484 const ast::FunctionDecl * resume_handler ) {
485 const CodeLocation loc = wraps->location;
486 ast::CompoundStmt * body = new ast::CompoundStmt(loc);
487
488 // struct __try_resume_node __resume_node
489 // __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
490 // ** unwinding of the stack here could cause problems **
491 // ** however I don't think that can happen currently **
492 // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
493
494 ast::ObjectDecl * obj = new ast::ObjectDecl(
495 loc,
496 "__resume_node",
497 new ast::StructInstType(
498 node_decl
499 ),
500 nullptr,
501 ast::Storage::Classes{},
502 ast::Linkage::Cforall,
503 nullptr,
504 {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
505 );
506 appendDeclStmt( body, obj );
507
508 ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
509 "__cfaehm_try_resume_setup" ) );
510 setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
511 setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
512
513 body->push_back( new ast::ExprStmt(loc, setup ) );
514
515 body->push_back( wraps );
516 return body;
517}
518
519ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
520 ast::TryStmt * tryStmt ) {
521 // void finally(__attribute__((unused)) void *) `finally->body`
522 const ast::FinallyClause * finally = tryStmt->finally;
523 return new ast::FunctionDecl(
524 tryStmt->location,
525 "finally",
526 { make_voidptr_object( tryStmt->location ) },
527 {}, //return void
528 ast::mutate( finally->body.get() ),
529 ast::Storage::Classes{},
530 ast::Linkage::Cforall,
531 {},
532 { ast::Function::Inline }
533 );
534}
535
536ast::ObjectDecl * TryMutatorCore::create_finally_hook(
537 ast::FunctionDecl * finally_wrapper ) {
538 // struct __cfaehm_cleanup_hook __finally_hook
539 // __attribute__((cleanup( `finally_wrapper` )));
540
541 const CodeLocation & location = finally_wrapper->location;
542 return new ast::ObjectDecl(
543 location,
544 "__finally_hook",
545 new ast::StructInstType(
546 hook_decl
547 ),
548 nullptr,
549 ast::Storage::Classes{},
550 ast::Linkage::Cforall,
551 nullptr,
552 {new ast::Attribute("cleanup", {new ast::VariableExpr(location, finally_wrapper)})}
553 );
554}
555
556ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
557 // return false;
558 const CodeLocation loc = throwStmt->location;
559 ast::Stmt * result = new ast::ReturnStmt(loc,
560 ast::ConstantExpr::from_bool( loc, false )
561 );
562 result->labels = throwStmt->labels;
563 return result;
564}
565
566// Visiting/Mutating Functions
567void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
568 if ( !structDecl->body ) {
569 // Skip children?
570 return;
571 } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
572 assert( nullptr == except_decl );
573 except_decl = structDecl;
574 } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
575 assert( nullptr == node_decl );
576 node_decl = structDecl;
577 } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
578 assert( nullptr == hook_decl );
579 hook_decl = structDecl;
580 }
581}
582
583ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
584 assert( except_decl );
585 assert( node_decl );
586 assert( hook_decl );
587
588 const CodeLocation loc = tryStmt->location;
589 ast::TryStmt * mutStmt = mutate(tryStmt);
590 // Generate a prefix for the function names?
591
592 ast::CompoundStmt * block = new ast::CompoundStmt( loc );
593 // ast::CompoundStmt * inner = take_try_block( mutStmt );
594 // this is never mutated so let node deletion do its job?
595 const ast::CompoundStmt * inner = mutStmt->body;
596
597 if ( mutStmt->finally ) {
598 // Define the helper function.
599 ast::FunctionDecl * finally_block =
600 create_finally_wrapper( mutStmt );
601 appendDeclStmt( block, finally_block );
602 // Create and add the finally cleanup hook.
603 appendDeclStmt( block, create_finally_hook( finally_block ) );
604 }
605
606 CatchList termination_handlers;
607 CatchList resumption_handlers;
608
609 for (auto & handler: mutStmt->handlers) {
610 // xxx - should always be unique? mutate as safe const-cast
611 assert(handler->unique());
612 if (handler->kind == ast::ExceptionKind::Resume) {
613 resumption_handlers.push_back(handler.get_and_mutate());
614 }
615 else {
616 termination_handlers.push_back(handler.get_and_mutate());
617 }
618 }
619
620 if ( resumption_handlers.size() ) {
621 // Define the helper function.
622 ast::FunctionDecl * resume_handler =
623 create_resume_handler( resumption_handlers );
624 appendDeclStmt( block, resume_handler );
625 // Prepare hooks
626 inner = create_resume_wrapper( inner, resume_handler );
627 }
628
629 if ( termination_handlers.size() ) {
630 // Define the two helper functions.
631 ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
632 appendDeclStmt( block, try_wrapper );
633 ast::FunctionDecl * terminate_match =
634 create_terminate_match( termination_handlers );
635 appendDeclStmt( block, terminate_match );
636 // Build the call to the try wrapper.
637 inner = create_terminate_caller(inner->location,
638 try_wrapper, terminate_match, termination_handlers );
639 }
640
641 // Embed the try block.
642 block->push_back( inner );
643
644 return block;
645}
646
647ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
648 // Only valid `throwResume;` statements should remain. (2/3 checks)
649 assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
650 return create_resume_rethrow( throwStmt );
651}
652
653} // namespace
654
655void translateThrows( ast::TranslationUnit & transUnit ) {
656 ast::Pass<TranslateThrowsCore>::run( transUnit );
657}
658
659void translateTries( ast::TranslationUnit & transUnit ) {
660 ast::Pass<TryMutatorCore>::run(transUnit);
661}
662
663} // namespace ControlStruct
664
665// Local Variables: //
666// tab-width: 4 //
667// mode: c++ //
668// compile-command: "make install" //
669// End: //
Note: See TracBrowser for help on using the repository browser.