source: src/ControlStruct/ExceptTranslateNew.cpp@ 0577df2

ADT ast-experimental pthread-emulation qualifiedEnum
Last change on this file since 0577df2 was 400b8be, checked in by Andrew Beach <ajbeach@…>, 3 years ago

Added StmtClause and converted the existing nodes that should be clauses.

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