source: src/ControlStruct/ExceptTranslateNew.cpp @ 400b8be

ADTast-experimentalenumpthread-emulationqualifiedEnum
Last change on this file since 400b8be was 400b8be, checked in by Andrew Beach <ajbeach@…>, 21 months ago

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

  • Property mode set to 100644
File size: 22.2 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ExceptTranslateNew.cpp -- Conversion of exception control flow structures.
8//
9// Author           : Andrew Beach
10// Created On       : Mon Nov  8 11:53:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Fri Mar 11 17:51:00 2022
13// Update Count     : 2
14//
15
16#include "ExceptTranslate.h"
17
18#include "AST/Expr.hpp"
19#include "AST/Pass.hpp"
20#include "AST/Stmt.hpp"
21#include "AST/TranslationUnit.hpp"
22#include "AST/DeclReplacer.hpp"
23
24namespace ControlStruct {
25
26namespace {
27
28        typedef std::list<ast::CatchClause*> CatchList;
29
30        void appendDeclStmt( ast::CompoundStmt * block, ast::DeclWithType * item ) {
31                block->push_back(new ast::DeclStmt(block->location, item));
32        }
33
34class TranslateThrowsCore : public ast::WithGuards {
35        const ast::ObjectDecl * terminateHandlerExcept;
36        enum Context { NoHandler, TerHandler, ResHandler } currentContext;
37
38        const ast::Stmt * createEitherThrow(
39                const ast::ThrowStmt * throwStmt, const char * funcName );
40        const ast::Stmt * createTerminateRethrow( const ast::ThrowStmt * );
41
42public:
43        TranslateThrowsCore() :
44                terminateHandlerExcept( nullptr ), currentContext( NoHandler )
45        {}
46
47        void previsit( const ast::CatchClause * stmt );
48        const ast::Stmt * postvisit( const ast::ThrowStmt * stmt );
49};
50
51const ast::Stmt * TranslateThrowsCore::createEitherThrow(
52                const ast::ThrowStmt * throwStmt, const char * funcName ) {
53        // `throwFunc`( `throwStmt->name` );
54        ast::UntypedExpr * call = new ast::UntypedExpr( throwStmt->location,
55                new ast::NameExpr( throwStmt->location, funcName )
56        );
57        call->args.push_back( throwStmt->expr );
58        return new ast::ExprStmt( throwStmt->location, call );
59}
60
61ast::VariableExpr * varOf( const ast::DeclWithType * decl ) {
62        return new ast::VariableExpr( decl->location, decl );
63}
64
65const ast::Stmt * TranslateThrowsCore::createTerminateRethrow(
66                const ast::ThrowStmt * stmt ) {
67        // { `terminate_handler_except` = 0p; __rethrow_terminate(); }
68        assert( nullptr == stmt->expr );
69        assert( terminateHandlerExcept );
70
71        ast::CompoundStmt * result = new ast::CompoundStmt(
72                stmt->location, {}, std::vector<ast::Label>( stmt->labels ) );
73        result->push_back( new ast::ExprStmt( stmt->location,
74                ast::UntypedExpr::createAssign(
75                        stmt->location,
76                        varOf( terminateHandlerExcept ),
77                        ast::ConstantExpr::null(
78                                stmt->location,
79                                terminateHandlerExcept->type
80                        )
81                )
82        ) );
83        result->push_back( new ast::ExprStmt( stmt->location, new ast::UntypedExpr(
84                stmt->location,
85                new ast::NameExpr( stmt->location, "__cfaehm_rethrow_terminate" )
86        ) ) );
87        return result;
88}
89
90void TranslateThrowsCore::previsit( const ast::CatchClause * stmt ) {
91        // Validate the statement's form.
92        const ast::ObjectDecl * decl = stmt->decl.as<ast::ObjectDecl>();
93        // Also checking the type would be nice.
94        if ( !decl || !decl->type.as<ast::PointerType>() ) {
95                std::string kind = (ast::Terminate == stmt->kind) ? "catch" : "catchResume";
96                SemanticError( stmt->location, kind + " must have pointer to an exception type" );
97        }
98
99        // Track the handler context.
100        if ( ast::Terminate == stmt->kind ) {
101                GuardValue( currentContext ) = TerHandler;
102                GuardValue( terminateHandlerExcept ) = decl;
103        } else {
104                GuardValue( currentContext ) = ResHandler;
105        }
106}
107
108const ast::Stmt * TranslateThrowsCore::postvisit(
109                const ast::ThrowStmt * stmt ) {
110        // Ignoring ThrowStmt::target for now.
111        // Handle Termination (Raise, Reraise, Error):
112        if ( ast::Terminate == stmt->kind ) {
113                if ( stmt->expr ) {
114                        return createEitherThrow( stmt, "$throw" );
115                } else if ( TerHandler == currentContext ) {
116                        return createTerminateRethrow( stmt );
117                } else {
118                        abort( "Invalid throw in %s at %i\n",
119                                stmt->location.filename.c_str(),
120                                stmt->location.first_line);
121                }
122        // Handle Resumption (Raise, Reraise, Error):
123        } else {
124                if ( stmt->expr ) {
125                        return createEitherThrow( stmt, "$throwResume" );
126                } else if ( ResHandler == currentContext ) {
127                        // This has to be handled later.
128                        return stmt;
129                } else {
130                        abort( "Invalid throwResume in %s at %i\n",
131                                stmt->location.filename.c_str(),
132                                stmt->location.first_line);
133                }
134        }
135}
136
137
138class TryMutatorCore {
139        // The built in types used in translation.
140        const ast::StructDecl * except_decl;
141        const ast::StructDecl * node_decl;
142        const ast::StructDecl * hook_decl;
143
144        // The many helper functions for code/syntree generation.
145        ast::CompoundStmt * take_try_block( ast::TryStmt * tryStmt );
146        ast::FunctionDecl * create_try_wrapper( const ast::CompoundStmt * body );
147        ast::FunctionDecl * create_terminate_catch( CatchList &handlers );
148        ast::CompoundStmt * create_single_matcher(
149                const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler );
150        ast::FunctionDecl * create_terminate_match( CatchList &handlers );
151        ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
152                ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
153        ast::FunctionDecl * create_resume_handler( CatchList &handlers );
154        ast::CompoundStmt * create_resume_wrapper(
155                const ast::Stmt * wraps, const ast::FunctionDecl * resume_handler );
156        ast::FunctionDecl * create_finally_wrapper( ast::TryStmt * tryStmt );
157        ast::ObjectDecl * create_finally_hook( ast::FunctionDecl * finally_wrapper );
158        ast::Stmt * create_resume_rethrow( const ast::ThrowStmt * throwStmt );
159
160        // Types used in translation, first group are internal.
161        ast::ObjectDecl * make_index_object( CodeLocation const & ) const;
162        ast::ObjectDecl * make_exception_object( CodeLocation const & ) const;
163        ast::ObjectDecl * make_bool_object( CodeLocation const & ) const;
164        ast::ObjectDecl * make_voidptr_object( CodeLocation const & ) const;
165        ast::ObjectDecl * make_unused_index_object( CodeLocation const & ) const;
166        // void (*function)();
167        ast::FunctionDecl * make_try_function( CodeLocation const & ) const;
168        // void (*function)(int, exception);
169        ast::FunctionDecl * make_catch_function( CodeLocation const & ) const;
170        // int (*function)(exception);
171        ast::FunctionDecl * make_match_function( CodeLocation const & ) const;
172        // bool (*function)(exception);
173        ast::FunctionDecl * make_handle_function( CodeLocation const & ) const;
174        // void (*function)(__attribute__((unused)) void *);
175        ast::FunctionDecl * make_finally_function( CodeLocation const & ) const;
176
177public:
178        TryMutatorCore() :
179                except_decl( nullptr ), node_decl( nullptr ), hook_decl( nullptr )
180        {}
181
182        void previsit( const ast::StructDecl *structDecl );
183        ast::Stmt * postvisit( const ast::TryStmt *tryStmt );
184        ast::Stmt * postvisit( const ast::ThrowStmt *throwStmt );
185};
186
187ast::ObjectDecl * TryMutatorCore::make_index_object(
188                CodeLocation const & location ) const {
189        return new ast::ObjectDecl(
190                location,
191                "__handler_index",
192                new ast::BasicType(ast::BasicType::SignedInt),
193                nullptr, //init
194                ast::Storage::Classes{},
195                ast::Linkage::Cforall
196                );
197}
198
199ast::ObjectDecl * TryMutatorCore::make_exception_object(
200                CodeLocation const & location ) const {
201        assert( except_decl );
202        return new ast::ObjectDecl(
203                location,
204                "__exception_inst",
205                new ast::PointerType(
206                        new ast::StructInstType( except_decl )
207                        ),
208                nullptr, //init
209                ast::Storage::Classes{},
210                ast::Linkage::Cforall
211                );
212}
213
214ast::ObjectDecl * TryMutatorCore::make_bool_object(
215                CodeLocation const & location ) const {
216        return new ast::ObjectDecl(
217                location,
218                "__ret_bool",
219                new ast::BasicType( ast::BasicType::Bool ),
220                nullptr, //init
221                ast::Storage::Classes{},
222                ast::Linkage::Cforall,
223                nullptr, //width
224                std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
225                );
226}
227
228ast::ObjectDecl * TryMutatorCore::make_voidptr_object(
229                CodeLocation const & location ) const {
230        return new ast::ObjectDecl(
231                location,
232                "__hook",
233                new ast::PointerType(
234                        new ast::VoidType()
235                ),
236                nullptr, //init
237                ast::Storage::Classes{},
238                ast::Linkage::Cforall,
239                nullptr, //width
240                std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
241                );
242}
243
244ast::ObjectDecl * TryMutatorCore::make_unused_index_object(
245                CodeLocation const & location ) const {
246        return new ast::ObjectDecl(
247                location,
248                "__handler_index",
249                new ast::BasicType(ast::BasicType::SignedInt),
250                nullptr,
251                ast::Storage::Classes{},
252                ast::Linkage::Cforall,
253                nullptr, //width
254                std::vector<ast::ptr<ast::Attribute>>{ new ast::Attribute( "unused" ) }
255        );
256}
257
258ast::FunctionDecl * TryMutatorCore::make_try_function(
259                CodeLocation const & location ) const {
260        return new ast::FunctionDecl(
261                location,
262                "try",
263                {}, //forall
264                {}, //no param
265                {}, //no return
266                nullptr,
267                ast::Storage::Classes{},
268                ast::Linkage::Cforall
269        );
270}
271
272ast::FunctionDecl * TryMutatorCore::make_catch_function(
273                CodeLocation const & location ) const {
274        return new ast::FunctionDecl(
275                location,
276                "catch",
277                {}, //forall
278                { make_index_object( location ), make_exception_object( location ) },
279                {}, //return void
280                nullptr,
281                ast::Storage::Classes{},
282                ast::Linkage::Cforall
283        );
284}
285
286ast::FunctionDecl * TryMutatorCore::make_match_function(
287                CodeLocation const & location ) const {
288        return new ast::FunctionDecl(
289                location,
290                "match",
291                {}, //forall
292                { make_exception_object( location ) },
293                { make_unused_index_object( location ) },
294                nullptr,
295                ast::Storage::Classes{},
296                ast::Linkage::Cforall
297        );
298}
299
300ast::FunctionDecl * TryMutatorCore::make_handle_function(
301                CodeLocation const & location ) const {
302        return new ast::FunctionDecl(
303                location,
304                "handle",
305                {}, //forall
306                { make_exception_object( location ) },
307                { make_bool_object( location ) },
308                nullptr,
309                ast::Storage::Classes{},
310                ast::Linkage::Cforall
311        );
312}
313
314ast::FunctionDecl * TryMutatorCore::make_finally_function(
315                CodeLocation const & location ) const {
316        return new ast::FunctionDecl(
317                location,
318                "finally",
319                {}, //forall
320                { make_voidptr_object( location ) },
321                {}, //return void
322                nullptr,
323                ast::Storage::Classes{},
324                ast::Linkage::Cforall
325        );
326}
327
328// TryStmt Mutation Helpers
329
330ast::FunctionDecl * TryMutatorCore::create_try_wrapper(
331                const ast::CompoundStmt *body ) {
332
333        ast::FunctionDecl * ret = make_try_function( body->location );
334        ret->stmts = body;
335        return ret;
336}
337
338ast::FunctionDecl * TryMutatorCore::create_terminate_catch(
339                CatchList &handlers ) {
340        std::vector<ast::ptr<ast::CaseClause>> handler_wrappers;
341
342        assert (!handlers.empty());
343        const CodeLocation loc = handlers.front()->location;
344
345        ast::FunctionDecl * func_t = make_catch_function( loc );
346        const ast::DeclWithType * index_obj = func_t->params.front();
347        const ast::DeclWithType * except_obj = func_t->params.back();
348
349        // Index 1..{number of handlers}
350        int index = 0;
351        CatchList::iterator it = handlers.begin();
352        for ( ; it != handlers.end() ; ++it ) {
353                ++index;
354                ast::CatchClause * handler = *it;
355                const CodeLocation loc = handler->location;
356
357                // case `index`:
358                // {
359                //     `handler.decl` = { (virtual `decl.type`)`except` };
360                //     `handler.body`;
361                // }
362                // return;
363                ast::CompoundStmt * block = new ast::CompoundStmt(loc);
364
365                // Just copy the exception value. (Post Validation)
366                const ast::ObjectDecl * handler_decl =
367                        handler->decl.strict_as<ast::ObjectDecl>();
368                ast::ObjectDecl * local_except = ast::deepCopy(handler_decl);
369                ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
370                        new ast::VariableExpr( loc, except_obj ),
371                        local_except->get_type()
372                        );
373                vcex->location = handler->location;
374                local_except->init = new ast::ListInit(loc, { new ast::SingleInit( loc, vcex ) });
375                block->push_back( new ast::DeclStmt( loc, local_except ) );
376
377                // Add the cleanup attribute.
378                local_except->attributes.push_back( new ast::Attribute(
379                        "cleanup",
380                        { new ast::NameExpr( loc, "__cfaehm_cleanup_terminate" ) }
381                        ) );
382
383                ast::DeclReplacer::DeclMap mapping;
384                mapping[handler_decl] = local_except;
385                const ast::Stmt * mutBody = strict_dynamic_cast<const ast::Stmt *>(
386                        ast::DeclReplacer::replace(handler->body, mapping));
387
388
389                block->push_back( mutBody );
390                // handler->body = nullptr;
391
392                handler_wrappers.push_back( new ast::CaseClause(loc,
393                        ast::ConstantExpr::from_int(loc, index) ,
394                        { block, new ast::ReturnStmt( loc, nullptr ) }
395                        ));
396        }
397        // TODO: Some sort of meaningful error on default perhaps?
398
399        ast::SwitchStmt * handler_lookup = new ast::SwitchStmt( loc,
400                new ast::VariableExpr( loc, index_obj ),
401                std::move(handler_wrappers)
402                );
403        ast::CompoundStmt * body = new ast::CompoundStmt( loc, {handler_lookup} );
404
405        func_t->stmts = body;
406        return func_t;
407}
408
409// Create a single check from a moddified handler.
410// except_obj is referenced, modded_handler will be freed.
411ast::CompoundStmt * TryMutatorCore::create_single_matcher(
412                const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler ) {
413        // {
414        //     `modded_handler.decl`
415        //     if ( `decl.name = (virtual `decl.type`)`except`
416        //             [&& `modded_handler.cond`] ) {
417        //         `modded_handler.body`
418        //     }
419        // }
420
421        const CodeLocation loc = modded_handler->location;
422        ast::CompoundStmt * block = new ast::CompoundStmt(loc);
423
424        // Local Declaration
425        const ast::ObjectDecl * local_except =
426                modded_handler->decl.strict_as<ast::ObjectDecl>();
427        block->push_back( new ast::DeclStmt( loc,  local_except ) );
428
429        // Check for type match.
430        ast::VirtualCastExpr * vcex = new ast::VirtualCastExpr(loc,
431                new ast::VariableExpr(loc, except_obj ),
432                local_except->get_type()
433                );
434        ast::Expr * cond = ast::UntypedExpr::createAssign(loc,
435                new ast::VariableExpr(loc, local_except ), vcex );
436
437        // Add the check on the conditional if it is provided.
438        if ( modded_handler->cond ) {
439                cond = new ast::LogicalExpr( loc, cond, modded_handler->cond, ast::LogicalFlag::AndExpr );
440        }
441        // Construct the match condition.
442        block->push_back( new ast::IfStmt(loc,
443                cond, modded_handler->body, nullptr ) );
444
445        return block;
446}
447
448ast::FunctionDecl * TryMutatorCore::create_terminate_match(
449                CatchList &handlers ) {
450        // int match(exception * except) {
451        //     HANDLER WRAPPERS { return `index`; }
452        // }
453
454        assert (!handlers.empty());
455        const CodeLocation loc = handlers.front()->location;
456
457        ast::CompoundStmt * body = new ast::CompoundStmt(loc);
458
459        ast::FunctionDecl * func_t = make_match_function( loc );
460        const ast::DeclWithType * except_obj = func_t->params.back();
461
462        // Index 1..{number of handlers}
463        int index = 0;
464        CatchList::iterator it;
465        for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
466                ++index;
467                ast::CatchClause * handler = *it;
468
469                // Body should have been taken by create_terminate_catch.
470                // xxx - just ignore it?
471                // assert( nullptr == handler->get_body() );
472
473                // Create new body.
474                handler->body = new ast::ReturnStmt( handler->location,
475                        ast::ConstantExpr::from_int( handler->location, index ) );
476
477                // Create the handler.
478                body->push_back( create_single_matcher( except_obj, handler ) );
479                *it = nullptr;
480        }
481
482        body->push_back( new ast::ReturnStmt(loc,
483                ast::ConstantExpr::from_int( loc, 0 ) ));
484
485        func_t->stmts = body;
486
487        return func_t;
488}
489
490ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
491                CodeLocation loc,
492                ast::FunctionDecl * try_wrapper,
493                ast::FunctionDecl * terminate_catch,
494                ast::FunctionDecl * terminate_match ) {
495        // { __cfaehm_try_terminate(`try`, `catch`, `match`); }
496
497        ast::UntypedExpr * caller = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
498                "__cfaehm_try_terminate" ) );
499        caller->args.push_back( new ast::VariableExpr(loc, try_wrapper ) );
500        caller->args.push_back( new ast::VariableExpr(loc, terminate_catch ) );
501        caller->args.push_back( new ast::VariableExpr(loc, terminate_match ) );
502
503        ast::CompoundStmt * callStmt = new ast::CompoundStmt(loc);
504        callStmt->push_back( new ast::ExprStmt( loc, caller ) );
505        return callStmt;
506}
507
508ast::FunctionDecl * TryMutatorCore::create_resume_handler(
509                CatchList &handlers ) {
510        // bool handle(exception * except) {
511        //     HANDLER WRAPPERS { `hander->body`; return true; }
512        // }
513        assert (!handlers.empty());
514        const CodeLocation loc = handlers.front()->location;
515        ast::CompoundStmt * body = new ast::CompoundStmt(loc);
516
517        ast::FunctionDecl * func_t = make_handle_function( loc );
518        const ast::DeclWithType * except_obj = func_t->params.back();
519
520        CatchList::iterator it;
521        for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
522                ast::CatchClause * handler = *it;
523                const CodeLocation loc = handler->location;
524                // Modifiy body.
525                ast::CompoundStmt * handling_code;
526                if (handler->body.as<ast::CompoundStmt>()) {
527                        handling_code = strict_dynamic_cast<ast::CompoundStmt*>(
528                                handler->body.get_and_mutate() );
529                } else {
530                        handling_code = new ast::CompoundStmt(loc);
531                        handling_code->push_back( handler->body );
532                }
533                handling_code->push_back( new ast::ReturnStmt(loc,
534                        ast::ConstantExpr::from_bool(loc, true ) ) );
535                handler->body = handling_code;
536
537                // Create the handler.
538                body->push_back( create_single_matcher( except_obj, handler ) );
539                *it = nullptr;
540        }
541
542        body->push_back( new ast::ReturnStmt(loc,
543                ast::ConstantExpr::from_bool(loc, false ) ) );
544        func_t->stmts = body;
545
546        return func_t;
547}
548
549ast::CompoundStmt * TryMutatorCore::create_resume_wrapper(
550                const ast::Stmt * wraps,
551                const ast::FunctionDecl * resume_handler ) {
552        const CodeLocation loc = wraps->location;
553        ast::CompoundStmt * body = new ast::CompoundStmt(loc);
554
555        // struct __try_resume_node __resume_node
556        //      __attribute__((cleanup( __cfaehm_try_resume_cleanup )));
557        // ** unwinding of the stack here could cause problems **
558        // ** however I don't think that can happen currently **
559        // __cfaehm_try_resume_setup( &__resume_node, resume_handler );
560
561        ast::ObjectDecl * obj = new ast::ObjectDecl(
562                loc,
563                "__resume_node",
564                new ast::StructInstType(
565                        node_decl
566                        ),
567                nullptr,
568                ast::Storage::Classes{},
569                ast::Linkage::Cforall,
570                nullptr,
571                {new ast::Attribute("cleanup", {new ast::NameExpr(loc, "__cfaehm_try_resume_cleanup")})}
572                );
573        appendDeclStmt( body, obj );
574
575        ast::UntypedExpr *setup = new ast::UntypedExpr(loc, new ast::NameExpr(loc,
576                "__cfaehm_try_resume_setup" ) );
577        setup->args.push_back( new ast::AddressExpr( loc, new ast::VariableExpr(loc, obj ) ) );
578        setup->args.push_back( new ast::VariableExpr( loc, resume_handler ) );
579
580        body->push_back( new ast::ExprStmt(loc, setup ) );
581
582        body->push_back( wraps );
583        return body;
584}
585
586ast::FunctionDecl * TryMutatorCore::create_finally_wrapper(
587                ast::TryStmt * tryStmt ) {
588        // void finally() { `finally->block` }
589        const ast::FinallyClause * finally = tryStmt->finally;
590        const ast::CompoundStmt * body = finally->body;
591
592        ast::FunctionDecl * func_t = make_finally_function( tryStmt->location );
593        func_t->stmts = body;
594
595        tryStmt->finally = nullptr;
596
597        return func_t;
598}
599
600ast::ObjectDecl * TryMutatorCore::create_finally_hook(
601                ast::FunctionDecl * finally_wrapper ) {
602        // struct __cfaehm_cleanup_hook __finally_hook
603        //      __attribute__((cleanup( `finally_wrapper` )));
604
605        const CodeLocation loc = finally_wrapper->location;
606        return new ast::ObjectDecl(
607                loc,
608                "__finally_hook",
609                new ast::StructInstType(
610                        hook_decl
611                        ),
612                nullptr,
613                ast::Storage::Classes{},
614                ast::Linkage::Cforall,
615                nullptr,
616                {new ast::Attribute("cleanup", {new ast::VariableExpr{loc, finally_wrapper}})}
617                );
618}
619
620ast::Stmt * TryMutatorCore::create_resume_rethrow( const ast::ThrowStmt *throwStmt ) {
621        // return false;
622        const CodeLocation loc = throwStmt->location;
623        ast::Stmt * result = new ast::ReturnStmt(loc,
624                ast::ConstantExpr::from_bool( loc, false )
625                );
626        result->labels = throwStmt->labels;
627        return result;
628}
629
630// Visiting/Mutating Functions
631void TryMutatorCore::previsit( const ast::StructDecl *structDecl ) {
632        if ( !structDecl->body ) {
633                // Skip children?
634                return;
635        } else if ( structDecl->name == "__cfaehm_base_exception_t" ) {
636                assert( nullptr == except_decl );
637                except_decl = structDecl;
638        } else if ( structDecl->name == "__cfaehm_try_resume_node" ) {
639                assert( nullptr == node_decl );
640                node_decl = structDecl;
641        } else if ( structDecl->name == "__cfaehm_cleanup_hook" ) {
642                assert( nullptr == hook_decl );
643                hook_decl = structDecl;
644        }
645}
646
647ast::Stmt * TryMutatorCore::postvisit( const ast::TryStmt *tryStmt ) {
648        assert( except_decl );
649        assert( node_decl );
650        assert( hook_decl );
651
652        const CodeLocation loc = tryStmt->location;
653        ast::TryStmt * mutStmt = mutate(tryStmt);
654        // Generate a prefix for the function names?
655
656        ast::CompoundStmt * block = new ast::CompoundStmt( loc );
657        // ast::CompoundStmt * inner = take_try_block( mutStmt );
658        // this is never mutated so let node deletion do its job?
659        const ast::CompoundStmt * inner = mutStmt->body;
660
661        if ( mutStmt->finally ) {
662                // Define the helper function.
663                ast::FunctionDecl * finally_block =
664                        create_finally_wrapper( mutStmt );
665                appendDeclStmt( block, finally_block );
666                // Create and add the finally cleanup hook.
667                appendDeclStmt( block, create_finally_hook( finally_block ) );
668        }
669
670        CatchList termination_handlers;
671        CatchList resumption_handlers;
672
673        for (auto & handler: mutStmt->handlers) {
674                // xxx - should always be unique? mutate as safe const-cast
675                assert(handler->unique());
676                if (handler->kind == ast::ExceptionKind::Resume) {
677                        resumption_handlers.push_back(handler.get_and_mutate());
678                }
679                else {
680                        termination_handlers.push_back(handler.get_and_mutate());
681                }
682        }
683
684        if ( resumption_handlers.size() ) {
685                // Define the helper function.
686                ast::FunctionDecl * resume_handler =
687                        create_resume_handler( resumption_handlers );
688                appendDeclStmt( block, resume_handler );
689                // Prepare hooks
690                inner = create_resume_wrapper( inner, resume_handler );
691        }
692
693        if ( termination_handlers.size() ) {
694                // Define the three helper functions.
695                ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
696                appendDeclStmt( block, try_wrapper );
697                ast::FunctionDecl * terminate_catch =
698                        create_terminate_catch( termination_handlers );
699                appendDeclStmt( block, terminate_catch );
700                ast::FunctionDecl * terminate_match =
701                        create_terminate_match( termination_handlers );
702                appendDeclStmt( block, terminate_match );
703                // Build the call to the try wrapper.
704                inner = create_terminate_caller(inner->location,
705                        try_wrapper, terminate_catch, terminate_match );
706        }
707
708        // Embed the try block.
709        block->push_back( inner );
710
711        return block;
712}
713
714ast::Stmt * TryMutatorCore::postvisit( const ast::ThrowStmt *throwStmt ) {
715        // Only valid `throwResume;` statements should remain. (2/3 checks)
716        assert( ast::ExceptionKind::Resume == throwStmt->kind && ! throwStmt->expr );
717        return create_resume_rethrow( throwStmt );
718}
719
720} // namespace
721
722void translateThrows( ast::TranslationUnit & transUnit ) {
723        ast::Pass<TranslateThrowsCore>::run( transUnit );
724}
725
726void translateTries( ast::TranslationUnit & transUnit ) {
727        ast::Pass<TryMutatorCore>::run(transUnit);
728}
729
730} // namespace ControlStruct
731
732// Local Variables: //
733// tab-width: 4 //
734// mode: c++ //
735// compile-command: "make install" //
736// End: //
Note: See TracBrowser for help on using the repository browser.