source: src/ControlStruct/ExceptTranslate.cpp @ 610354a

Last change on this file since 610354a was c40157e, checked in by Andrew Beach <ajbeach@…>, 11 months ago

Minimal change to get exceptions running the old way while a fix is found. Or even more details on the problem.

  • 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_catch ),
499                                        new ast::VariableExpr( loc, terminate_match ),
500                                }
501                        )
502                )
503        );
504
505        return new ast::CompoundStmt( loc, {
506                new ast::DeclStmt( loc, index ),
507                new ast::IfStmt( loc,
508                        new ast::VariableExpr( loc, index ),
509                        new ast::ExprStmt( loc,
510                                new ast::UntypedExpr( loc,
511                                        new ast::VariableExpr( loc, terminate_catch ),
512                                        {
513                                                new ast::VariableExpr( loc, index ),
514                                                new ast::UntypedExpr( loc,
515                                                        new ast::NameExpr( loc, "__cfaehm_get_current_exception" )
516                                                ),
517                                        }
518                                )
519                        )
520                ),
521        } );
522}
523
524ast::FunctionDecl * TryMutatorCore::create_resume_handler(
525                CatchList &handlers ) {
526        // bool handle(exception * except) {
527        //     HANDLER WRAPPERS { `hander->body`; return true; }
528        // }
529        assert (!handlers.empty());
530        const CodeLocation loc = handlers.front()->location;
531        ast::CompoundStmt * body = new ast::CompoundStmt(loc);
532
533        ast::FunctionDecl * func_t = make_handle_function( loc );
534        const ast::DeclWithType * except_obj = func_t->params.back();
535
536        CatchList::iterator it;
537        for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
538                ast::CatchClause * handler = *it;
539                const CodeLocation loc = handler->location;
540                // Modifiy body.
541                ast::CompoundStmt * handling_code;
542                if (handler->body.as<ast::CompoundStmt>()) {
543                        handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
544                                handler->body.get_and_mutate() );
545                } else {
546                        handling_code = new ast::CompoundStmt(loc);
547                        handling_code->push_back( handler->body );
548                }
549                handling_code->push_back( new ast::ReturnStmt(loc,
550                        ast::ConstantExpr::from_bool(loc, true ) ) );
551                handler->body = handling_code;
552
553                // Create the handler.
554                body->push_back( create_single_matcher( except_obj, handler ) );
555                *it = nullptr;
556        }
557
558        body->push_back( new ast::ReturnStmt(loc,
559                ast::ConstantExpr::from_bool(loc, false ) ) );
560        func_t->stmts = body;
561
562        return func_t;
563}
564
565ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
566                const ast::Stmt * wraps,
567                const ast::FunctionDecl * resume_handler ) {
568        const CodeLocation loc = wraps->location;
569        ast::CompoundStmt * body = new ast::CompoundStmt(loc);
570
571        // struct __try_resume_node __resume_node
572        //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
573        // ** unwinding of the stack here could cause problems **
574        // ** however I don't think that can happen currently **
575        // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
576
577        ast::ObjectDecl * obj = new ast::ObjectDecl(
578                loc,
579                "__resume_node",
580                new ast::StructInstType(
581                        node_decl
582                        ),
583                nullptr,
584                ast::Storage::Classes{},
585                ast::Linkage::Cforall,
586                nullptr,
587                {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
588                );
589        appendDeclStmt( body, obj );
590
591        ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
592                "__cfaehm_try_resume_setup" ) );
593        setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
594        setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
595
596        body->push_back( new ast::ExprStmt(loc, setup ) );
597
598        body->push_back( wraps );
599        return body;
600}
601
602ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
603                ast::TryStmt * tryStmt ) {
604        // void finally() { `finally->block` }
605        const ast::FinallyClause * finally = tryStmt->finally;
606        const ast::CompoundStmt * body = finally->body;
607
608        ast::FunctionDecl * func_t = make_finally_function( tryStmt->location );
609        func_t->stmts = body;
610
611        tryStmt->finally = nullptr;
612
613        return func_t;
614}
615
616ast::ObjectDecl * TryMutatorCore::create_finally_hook(
617                ast::FunctionDecl * finally_wrapper ) {
618        // struct __cfaehm_cleanup_hook __finally_hook
619        //      __attribute__((cleanup( `finally_wrapper` )));
620
621        const CodeLocation loc = finally_wrapper->location;
622        return new ast::ObjectDecl(
623                loc,
624                "__finally_hook",
625                new ast::StructInstType(
626                        hook_decl
627                        ),
628                nullptr,
629                ast::Storage::Classes{},
630                ast::Linkage::Cforall,
631                nullptr,
632                {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}
633                );
634}
635
636ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
637        // return false;
638        const CodeLocation loc = throwStmt->location;
639        ast::Stmt * result = new ast::ReturnStmt(loc,
640                ast::ConstantExpr::from_bool( loc, false )
641                );
642        result->labels = throwStmt->labels;
643        return result;
644}
645
646// Visiting/Mutating Functions
647void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
648        if ( !structDecl->body ) {
649                // Skip children?
650                return;
651        } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
652                assert( nullptr == except_decl );
653                except_decl = structDecl;
654        } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
655                assert( nullptr == node_decl );
656                node_decl = structDecl;
657        } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
658                assert( nullptr == hook_decl );
659                hook_decl = structDecl;
660        }
661}
662
663ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
664        assert( except_decl );
665        assert( node_decl );
666        assert( hook_decl );
667
668        const CodeLocation loc = tryStmt->location;
669        ast::TryStmt * mutStmt = mutate(tryStmt);
670        // Generate a prefix for the function names?
671
672        ast::CompoundStmt * block = new ast::CompoundStmt( loc );
673        // ast::CompoundStmt * inner = take_try_block( mutStmt );
674        // this is never mutated so let node deletion do its job?
675        const ast::CompoundStmt * inner = mutStmt->body;
676
677        if ( mutStmt->finally ) {
678                // Define the helper function.
679                ast::FunctionDecl * finally_block =
680                        create_finally_wrapper( mutStmt );
681                appendDeclStmt( block, finally_block );
682                // Create and add the finally cleanup hook.
683                appendDeclStmt( block, create_finally_hook( finally_block ) );
684        }
685
686        CatchList termination_handlers;
687        CatchList resumption_handlers;
688
689        for (auto & handler: mutStmt->handlers) {
690                // xxx - should always be unique? mutate as safe const-cast
691                assert(handler->unique());
692                if (handler->kind == ast::ExceptionKind::Resume) {
693                        resumption_handlers.push_back(handler.get_and_mutate());
694                }
695                else {
696                        termination_handlers.push_back(handler.get_and_mutate());
697                }
698        }
699
700        if ( resumption_handlers.size() ) {
701                // Define the helper function.
702                ast::FunctionDecl * resume_handler =
703                        create_resume_handler( resumption_handlers );
704                appendDeclStmt( block, resume_handler );
705                // Prepare hooks
706                inner = create_resume_wrapper( inner, resume_handler );
707        }
708
709        if ( termination_handlers.size() ) {
710                // Define the three helper functions.
711                ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
712                appendDeclStmt( block, try_wrapper );
713                ast::FunctionDecl * terminate_catch =
714                        create_terminate_catch( termination_handlers );
715                appendDeclStmt( block, terminate_catch );
716                ast::FunctionDecl * terminate_match =
717                        create_terminate_match( termination_handlers );
718                appendDeclStmt( block, terminate_match );
719                // Build the call to the try wrapper.
720                inner = create_terminate_caller(inner->location,
721                        try_wrapper, terminate_catch, terminate_match );
722        }
723
724        // Embed the try block.
725        block->push_back( inner );
726
727        return block;
728}
729
730ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
731        // Only valid `throwResume;` statements should remain. (2/3 checks)
732        assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
733        return create_resume_rethrow( throwStmt );
734}
735
736} // namespace
737
738void translateThrows( ast::TranslationUnit & transUnit ) {
739        ast::Pass<TranslateThrowsCore>::run( transUnit );
740}
741
742void translateTries( ast::TranslationUnit & transUnit ) {
743        ast::Pass<TryMutatorCore>::run(transUnit);
744}
745
746} // namespace ControlStruct
747
748// Local Variables: //
749// tab-width: 4 //
750// mode: c++ //
751// compile-command: "make install" //
752// End: //
Note: See TracBrowser for help on using the repository browser.