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

Last change on this file since 9fba8e6 was 9fba8e6, checked in by Andrew Beach <ajbeach@…>, 9 months 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.