source: src/ControlStruct/ExceptTranslateNew.cpp @ 6a823241

ADTast-experimentalenumforall-pointer-decaypthread-emulationqualifiedEnum
Last change on this file since 6a823241 was b56ad5e, checked in by Fangren Yu <f37yu@…>, 3 years ago

Merge branch 'master' of plg.uwaterloo.ca:software/cfa/cfa-cc

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