source: src/ControlStruct/ExceptTranslate.cpp @ 2554f24

Last change on this file since 2554f24 was 2554f24, checked in by Andrew Beach <ajbeach@…>, 7 months ago

Try terminate now does not call the catch function, now they have the same caller. This involved updating some platform dependent code which should be correct in all cases.

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