source: src/ControlStruct/ExceptTranslate.cpp @ 6740533e

Last change on this file since 6740533e was c92bdcc, checked in by Andrew Beach <ajbeach@…>, 6 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.