source: src/ControlStruct/ExceptTranslateNew.cpp @ c8238c0

ADTast-experimental
Last change on this file since c8238c0 was c36814a, checked in by Andrew Beach <ajbeach@…>, 2 years ago

Adding 'final' and removing a redundent namespace in the post resolve new ast code.

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