source: src/ControlStruct/ExceptTranslate.cc @ 9cc0472

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resndemanglerenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprnew-envno_listpersistent-indexerpthread-emulationqualifiedEnumresolv-newwith_gc
Last change on this file since 9cc0472 was ac10576, checked in by Andrew Beach <ajbeach@…>, 7 years ago

Replaced emptyQualifiers with noQualifiers for consistancy with noLabels and noAttributes.

  • Property mode set to 100644
File size: 17.3 KB
RevLine 
[ba912706]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// ExceptVisitor.cc --
8//
9// Author           : Andrew Beach
10// Created On       : Wed Jun 14 16:49:00 2017
11// Last Modified By : Andrew Beach
[ac10576]12// Last Modified On : Tus Jul 18 10:09:00 2017
13// Update Count     : 4
[ba912706]14//
15
16#include "ExceptTranslate.h"
17#include "Common/PassVisitor.h"
[288eede]18#include "SynTree/Statement.h"
19#include "SynTree/Declaration.h"
20#include "SynTree/Expression.h"
21#include "SynTree/Type.h"
22#include "SynTree/Attribute.h"
[ba912706]23
[307a732]24namespace ControlStruct {
[ba912706]25
26        // This (large) section could probably be moved out of the class
27        // and be static helpers instead.
28
29        // Type(Qualifiers &, false, std::list<Attribute *> &)
30
[307a732]31        // void (*function)();
32        static FunctionType try_func_t(Type::Qualifiers(), false);
[ba912706]33        // void (*function)(int, exception);
34        static FunctionType catch_func_t(Type::Qualifiers(), false);
35        // int (*function)(exception);
36        static FunctionType match_func_t(Type::Qualifiers(), false);
37        // bool (*function)(exception);
38        static FunctionType handle_func_t(Type::Qualifiers(), false);
[307a732]39        // void (*function)(__attribute__((unused)) void *);
40        static FunctionType finally_func_t(Type::Qualifiers(), false);
[ba912706]41
42        static void init_func_types() {
[288eede]43                static bool init_complete = false;
[ba912706]44                if (init_complete) {
45                        return;
46                }
47                ObjectDecl index_obj(
[288eede]48                        "__handler_index",
[ba912706]49                        Type::StorageClasses(),
50                        LinkageSpec::Cforall,
51                        /*bitfieldWidth*/ NULL,
[ac10576]52                        new BasicType( noQualifiers, BasicType::SignedInt ),
[ba912706]53                        /*init*/ NULL
[307a732]54                        );
[ba912706]55                ObjectDecl exception_obj(
[288eede]56                        "__exception_inst",
[ba912706]57                        Type::StorageClasses(),
58                        LinkageSpec::Cforall,
59                        /*bitfieldWidth*/ NULL,
[307a732]60                        new PointerType(
[ac10576]61                                noQualifiers,
62                                new BasicType( noQualifiers, BasicType::SignedInt )
[307a732]63                                ),
[ba912706]64                        /*init*/ NULL
[307a732]65                        );
[ba912706]66                ObjectDecl bool_obj(
[288eede]67                        "__ret_bool",
[ba912706]68                        Type::StorageClasses(),
69                        LinkageSpec::Cforall,
70                        /*bitfieldWidth*/ NULL,
[ac10576]71                        new BasicType(noQualifiers, BasicType::Bool),
[ba912706]72                        /*init*/ NULL
[307a732]73                        );
74                ObjectDecl voidptr_obj(
75                        "__hook",
76                        Type::StorageClasses(),
77                        LinkageSpec::Cforall,
78                        NULL,
79                        new PointerType(
[ac10576]80                                noQualifiers,
[307a732]81                                new VoidType(
[ac10576]82                                        noQualifiers
[307a732]83                                        ),
84                                std::list<Attribute *>{new Attribute("unused")}
85                                ),
86                        NULL
87                        );
[ba912706]88
[307a732]89                catch_func_t.get_parameters().push_back( index_obj.clone() );
90                catch_func_t.get_parameters().push_back( exception_obj.clone() );
91                match_func_t.get_returnVals().push_back( index_obj.clone() );
92                match_func_t.get_parameters().push_back( exception_obj.clone() );
93                handle_func_t.get_returnVals().push_back( bool_obj.clone() );
94                handle_func_t.get_parameters().push_back( exception_obj.clone() );
95                finally_func_t.get_parameters().push_back( voidptr_obj.clone() );
[ba912706]96
97                init_complete = true;
98        }
99
100        // Buricratic Helpers (Not having to do with the paritular operation.)
101
102        typedef std::list<CatchStmt*> CatchList;
103
104        void split( CatchList& allHandlers, CatchList& terHandlers,
[1abc5ab]105                                CatchList& resHandlers ) {
[ba912706]106                while ( !allHandlers.empty() ) {
[288eede]107                        CatchStmt * stmt = allHandlers.front();
[ba912706]108                        allHandlers.pop_front();
[288eede]109                        if (CatchStmt::Terminate == stmt->get_kind()) {
[ba912706]110                                terHandlers.push_back(stmt);
111                        } else {
112                                resHandlers.push_back(stmt);
113                        }
114                }
115        }
116
117        template<typename T>
118        void free_all( std::list<T *> &list ) {
[288eede]119                typename std::list<T *>::iterator it;
[ba912706]120                for ( it = list.begin() ; it != list.end() ; ++it ) {
121                        delete *it;
122                }
123                list.clear();
124        }
125
126        void appendDeclStmt( CompoundStmt * block, Declaration * item ) {
[288eede]127                block->push_back(new DeclStmt(noLabels, item));
[ba912706]128        }
129
[288eede]130        Expression * nameOf( DeclarationWithType * decl ) {
131                return new VariableExpr( decl );
[ba912706]132        }
133
134        // ThrowStmt Mutation Helpers
135
[307a732]136        Statement * create_given_throw(
137                        const char * throwFunc, ThrowStmt * throwStmt ) {
138                // { int NAME = EXPR; throwFunc( &NAME ); }
139                CompoundStmt * result = new CompoundStmt( noLabels );
140                ObjectDecl * local = new ObjectDecl(
141                        "__local_exception_copy",
142                        Type::StorageClasses(),
143                        LinkageSpec::Cforall,
144                        NULL,
[ac10576]145                        new BasicType( noQualifiers, BasicType::SignedInt ),
[307a732]146                        new SingleInit( throwStmt->get_expr() )
147                        );
148                appendDeclStmt( result, local );
149                UntypedExpr * call = new UntypedExpr( new NameExpr( throwFunc ) );
150                call->get_args().push_back( new AddressExpr( nameOf( local ) ) );
151                result->push_back( new ExprStmt( throwStmt->get_labels(), call ) );
[ba912706]152                throwStmt->set_expr( nullptr );
153                delete throwStmt;
154                return result;
155        }
[307a732]156
157        Statement * create_terminate_throw( ThrowStmt *throwStmt ) {
158                // { int NAME = EXPR; __throw_terminate( &NAME ); }
[38ac6ec]159                return create_given_throw( "__cfaehm__throw_terminate", throwStmt );
[307a732]160        }
[ba912706]161        Statement * create_terminate_rethrow( ThrowStmt *throwStmt ) {
162                // __rethrow_terminate();
[288eede]163                assert( nullptr == throwStmt->get_expr() );
[ba912706]164                Statement * result = new ExprStmt(
165                        throwStmt->get_labels(),
[38ac6ec]166                        new UntypedExpr( new NameExpr( "__cfaehm__rethrow_terminate" ) )
[ba912706]167                        );
168                delete throwStmt;
169                return result;
170        }
171        Statement * create_resume_throw( ThrowStmt *throwStmt ) {
172                // __throw_resume( EXPR );
[38ac6ec]173                return create_given_throw( "__cfaehm__throw_resume", throwStmt );
[ba912706]174        }
175        Statement * create_resume_rethrow( ThrowStmt *throwStmt ) {
176                // return false;
177                Statement * result = new ReturnStmt(
178                        throwStmt->get_labels(),
[288eede]179                        new ConstantExpr( Constant::from_bool( false ) )
[ba912706]180                        );
181                delete throwStmt;
182                return result;
183        }
184
185        // TryStmt Mutation Helpers
186
187        CompoundStmt * take_try_block( TryStmt *tryStmt ) {
188                CompoundStmt * block = tryStmt->get_block();
189                tryStmt->set_block( nullptr );
190                return block;
191        }
[288eede]192        FunctionDecl * create_try_wrapper( CompoundStmt *body ) {
[ba912706]193
[288eede]194                return new FunctionDecl( "try", Type::StorageClasses(),
[307a732]195                        LinkageSpec::Cforall, try_func_t.clone(), body );
[ba912706]196        }
197
198        FunctionDecl * create_terminate_catch( CatchList &handlers ) {
199                std::list<CaseStmt *> handler_wrappers;
200
[288eede]201                FunctionType *func_type = catch_func_t.clone();
202                DeclarationWithType * index_obj = func_type->get_parameters().front();
203        //      DeclarationWithType * except_obj = func_type->get_parameters().back();
204
[ba912706]205                // Index 1..{number of handlers}
206                int index = 0;
207                CatchList::iterator it = handlers.begin();
208                for ( ; it != handlers.end() ; ++it ) {
209                        ++index;
210                        CatchStmt * handler = *it;
211
[288eede]212                        // INTEGERconstant Version
213                        // case `index`:
214                        // {
215                        //     `handler.body`
216                        // }
217                        // return;
218                        std::list<Statement *> caseBody;
219                        caseBody.push_back( handler->get_body() );
220                        handler->set_body( nullptr );
221                        caseBody.push_back( new ReturnStmt( noLabels, nullptr ) );
222
223                        handler_wrappers.push_back( new CaseStmt(
[ba912706]224                                noLabels,
225                                new ConstantExpr( Constant::from_int( index ) ),
[288eede]226                                caseBody
227                                ) );
[ba912706]228                }
229                // TODO: Some sort of meaningful error on default perhaps?
230
[288eede]231                std::list<Statement*> stmt_handlers;
232                while ( !handler_wrappers.empty() ) {
233                        stmt_handlers.push_back( handler_wrappers.front() );
234                        handler_wrappers.pop_front();
235                }
236
[ba912706]237                SwitchStmt * handler_lookup = new SwitchStmt(
238                        noLabels,
[288eede]239                        nameOf( index_obj ),
240                        stmt_handlers
[ba912706]241                        );
242                CompoundStmt * body = new CompoundStmt( noLabels );
243                body->push_back( handler_lookup );
244
245                return new FunctionDecl("catch", Type::StorageClasses(),
[288eede]246                        LinkageSpec::Cforall, func_type, body);
[ba912706]247        }
248
249        // Create a single check from a moddified handler.
[288eede]250        // except_obj is referenced, modded_handler will be freed.
251        CompoundStmt *create_single_matcher(
252                        DeclarationWithType * except_obj, CatchStmt * modded_handler ) {
253                CompoundStmt * block = new CompoundStmt( noLabels );
254
255                // INTEGERconstant Version
256                assert( nullptr == modded_handler->get_decl() );
257                ConstantExpr * number =
258                        dynamic_cast<ConstantExpr*>( modded_handler->get_cond() );
259                assert( number );
260                modded_handler->set_cond( nullptr );
[ba912706]261
[288eede]262                Expression * cond;
263                {
264                        std::list<Expression *> args;
265                        args.push_back( number );
[307a732]266
267                        std::list<Expression *> rhs_args;
268                        rhs_args.push_back( nameOf( except_obj ) );
269                        Expression * rhs = new UntypedExpr(
270                                new NameExpr( "*?" ), rhs_args );
271                        args.push_back( rhs );
272
[288eede]273                        cond = new UntypedExpr( new NameExpr( "?==?" /*???*/), args );
274                }
[ba912706]275
276                if ( modded_handler->get_cond() ) {
[288eede]277                        cond = new LogicalExpr( cond, modded_handler->get_cond() );
[ba912706]278                }
279                block->push_back( new IfStmt( noLabels,
[288eede]280                        cond, modded_handler->get_body(), nullptr ) );
[ba912706]281
282                modded_handler->set_decl( nullptr );
283                modded_handler->set_cond( nullptr );
284                modded_handler->set_body( nullptr );
285                delete modded_handler;
286                return block;
287        }
288
289        FunctionDecl * create_terminate_match( CatchList &handlers ) {
290                CompoundStmt * body = new CompoundStmt( noLabels );
291
[288eede]292                FunctionType * func_type = match_func_t.clone();
293                DeclarationWithType * except_obj = func_type->get_parameters().back();
294
[ba912706]295                // Index 1..{number of handlers}
296                int index = 0;
297                CatchList::iterator it;
298                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
299                        ++index;
300                        CatchStmt * handler = *it;
301
[288eede]302                        // Body should have been taken by create_terminate_catch.
303                        assert( nullptr == handler->get_body() );
304
305                        // Create new body.
[ba912706]306                        handler->set_body( new ReturnStmt( noLabels,
307                                new ConstantExpr( Constant::from_int( index ) ) ) );
308
[288eede]309                        // Create the handler.
310                        body->push_back( create_single_matcher( except_obj, handler ) );
311                        *it = nullptr;
[ba912706]312                }
313
[307a732]314                body->push_back( new ReturnStmt( noLabels, new ConstantExpr(
315                        Constant::from_int( 0 ) ) ) );
316
[ba912706]317                return new FunctionDecl("match", Type::StorageClasses(),
[288eede]318                        LinkageSpec::Cforall, func_type, body);
[ba912706]319        }
320
[288eede]321        CompoundStmt * create_terminate_caller(
[ba912706]322                        FunctionDecl * try_wrapper,
323                        FunctionDecl * terminate_catch,
324                        FunctionDecl * terminate_match) {
325
[288eede]326                UntypedExpr * caller = new UntypedExpr( new NameExpr(
327                        "__cfaehm__try_terminate" ) );
328                std::list<Expression *>& args = caller->get_args();
[ba912706]329                args.push_back( nameOf( try_wrapper ) );
330                args.push_back( nameOf( terminate_catch ) );
331                args.push_back( nameOf( terminate_match ) );
332
[288eede]333                CompoundStmt * callStmt = new CompoundStmt( noLabels );
334                callStmt->push_back( new ExprStmt( noLabels, caller ) );
335                return callStmt;
[ba912706]336        }
337
338        FunctionDecl * create_resume_handler( CatchList &handlers ) {
[288eede]339                CompoundStmt * body = new CompoundStmt( noLabels );
340
341                FunctionType * func_type = match_func_t.clone();
342                DeclarationWithType * except_obj = func_type->get_parameters().back();
[ba912706]343
344                CatchList::iterator it;
345                for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
346                        CatchStmt * handler = *it;
347
348                        // Modifiy body.
349                        CompoundStmt * handling_code =
350                                dynamic_cast<CompoundStmt*>( handler->get_body() );
351                        if ( ! handling_code ) {
352                                handling_code = new CompoundStmt( noLabels );
353                                handling_code->push_back( handler->get_body() );
354                        }
[288eede]355                        handling_code->push_back( new ReturnStmt( noLabels,
[ad0be81]356                                new ConstantExpr( Constant::from_bool( true ) ) ) );
[ba912706]357                        handler->set_body( handling_code );
358
359                        // Create the handler.
[288eede]360                        body->push_back( create_single_matcher( except_obj, handler ) );
361                        *it = nullptr;
[ba912706]362                }
363
[ad0be81]364                body->push_back( new ReturnStmt( noLabels, new ConstantExpr(
365                        Constant::from_bool( false ) ) ) );
366
[ba912706]367                return new FunctionDecl("handle", Type::StorageClasses(),
[288eede]368                        LinkageSpec::Cforall, func_type, body);
[ba912706]369        }
370
[288eede]371        CompoundStmt * create_resume_wrapper(
372                        StructDecl * node_decl,
[ba912706]373                        Statement * wraps,
374                        FunctionDecl * resume_handler ) {
375                CompoundStmt * body = new CompoundStmt( noLabels );
376
[288eede]377                // struct __try_resume_node __resume_node
378                //      __attribute__((cleanup( __cfaehm__try_resume_cleanup )));
379                // ** unwinding of the stack here could cause problems **
380                // ** however I don't think that can happen currently **
381                // __cfaehm__try_resume_setup( &__resume_node, resume_handler );
[ba912706]382
383                std::list< Attribute * > attributes;
384                {
385                        std::list< Expression * > attr_params;
[288eede]386                        attr_params.push_back( new NameExpr(
387                                "__cfaehm__try_resume_cleanup" ) );
388                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]389                }
390
[288eede]391                ObjectDecl * obj = new ObjectDecl(
392                        "__resume_node",
[ba912706]393                        Type::StorageClasses(),
394                        LinkageSpec::Cforall,
395                        nullptr,
[288eede]396                        new StructInstType(
397                                Type::Qualifiers(),
398                                node_decl
399                                ),
400                        nullptr,
[ba912706]401                        attributes
[288eede]402                        );
403                appendDeclStmt( body, obj );
404
405                UntypedExpr *setup = new UntypedExpr( new NameExpr(
406                        "__cfaehm__try_resume_setup" ) );
[307a732]407                setup->get_args().push_back( new AddressExpr( nameOf( obj ) ) );
[288eede]408                setup->get_args().push_back( nameOf( resume_handler ) );
409
410                body->push_back( new ExprStmt( noLabels, setup ) );
411
[ba912706]412                body->push_back( wraps );
413                return body;
414        }
415
416        FunctionDecl * create_finally_wrapper( TryStmt * tryStmt ) {
[288eede]417                FinallyStmt * finally = tryStmt->get_finally();
418                CompoundStmt * body = finally->get_block();
419                finally->set_block( nullptr );
420                delete finally;
[ba912706]421                tryStmt->set_finally( nullptr );
422
423                return new FunctionDecl("finally", Type::StorageClasses(),
[307a732]424                        LinkageSpec::Cforall, finally_func_t.clone(), body);
[ba912706]425        }
426
[288eede]427        ObjectDecl * create_finally_hook(
428                        StructDecl * hook_decl, FunctionDecl * finally_wrapper ) {
429                // struct __cfaehm__cleanup_hook __finally_hook
430                //      __attribute__((cleanup( finally_wrapper )));
[ba912706]431
432                // Make Cleanup Attribute.
433                std::list< Attribute * > attributes;
434                {
435                        std::list< Expression * > attr_params;
436                        attr_params.push_back( nameOf( finally_wrapper ) );
[288eede]437                        attributes.push_back( new Attribute( "cleanup", attr_params ) );
[ba912706]438                }
439
[288eede]440                return new ObjectDecl(
441                        "__finally_hook",
[ba912706]442                        Type::StorageClasses(),
443                        LinkageSpec::Cforall,
444                        nullptr,
[288eede]445                        new StructInstType(
[ac10576]446                                noQualifiers,
[288eede]447                                hook_decl
448                                ),
[ba912706]449                        nullptr,
450                        attributes
451                        );
452        }
453
454
[1abc5ab]455        class ExceptionMutatorCore : public WithGuards {
[ba912706]456                enum Context { NoHandler, TerHandler, ResHandler };
457
458                // Also need to handle goto, break & continue.
459                // They need to be cut off in a ResHandler, until we enter another
460                // loop, switch or the goto stays within the function.
461
[288eede]462                Context cur_context;
[ba912706]463
464                // We might not need this, but a unique base for each try block's
465                // generated functions might be nice.
466                //std::string curFunctionName;
467                //unsigned int try_count = 0;
468
[288eede]469                StructDecl *node_decl;
470                StructDecl *hook_decl;
[ba912706]471
472        public:
473                ExceptionMutatorCore() :
[288eede]474                        cur_context(NoHandler),
475                        node_decl(nullptr), hook_decl(nullptr)
[ba912706]476                {}
477
[288eede]478                void premutate( CatchStmt *catchStmt );
479                void premutate( StructDecl *structDecl );
[ba912706]480                Statement * postmutate( ThrowStmt *throwStmt );
481                Statement * postmutate( TryStmt *tryStmt );
482        };
483
484        Statement * ExceptionMutatorCore::postmutate( ThrowStmt *throwStmt ) {
485                // Ignoring throwStmt->get_target() for now.
486                if ( ThrowStmt::Terminate == throwStmt->get_kind() ) {
487                        if ( throwStmt->get_expr() ) {
488                                return create_terminate_throw( throwStmt );
[288eede]489                        } else if ( TerHandler == cur_context ) {
[ba912706]490                                return create_terminate_rethrow( throwStmt );
491                        } else {
492                                assertf(false, "Invalid throw in %s at %i\n",
[288eede]493                                        throwStmt->location.filename.c_str(),
[ba912706]494                                        throwStmt->location.linenumber);
495                                return nullptr;
496                        }
497                } else {
498                        if ( throwStmt->get_expr() ) {
499                                return create_resume_throw( throwStmt );
[288eede]500                        } else if ( ResHandler == cur_context ) {
[ba912706]501                                return create_resume_rethrow( throwStmt );
502                        } else {
503                                assertf(false, "Invalid throwResume in %s at %i\n",
[288eede]504                                        throwStmt->location.filename.c_str(),
[ba912706]505                                        throwStmt->location.linenumber);
506                                return nullptr;
507                        }
508                }
509        }
510
511        Statement * ExceptionMutatorCore::postmutate( TryStmt *tryStmt ) {
[288eede]512                assert( node_decl );
513                assert( hook_decl );
514
[ba912706]515                // Generate a prefix for the function names?
516
[288eede]517                CompoundStmt * block = new CompoundStmt( noLabels );
518                CompoundStmt * inner = take_try_block( tryStmt );
[ba912706]519
520                if ( tryStmt->get_finally() ) {
521                        // Define the helper function.
522                        FunctionDecl * finally_block =
523                                create_finally_wrapper( tryStmt );
524                        appendDeclStmt( block, finally_block );
525                        // Create and add the finally cleanup hook.
[288eede]526                        appendDeclStmt( block,
527                                create_finally_hook( hook_decl, finally_block ) );
[ba912706]528                }
529
[288eede]530                CatchList termination_handlers;
531                CatchList resumption_handlers;
532                split( tryStmt->get_catchers(),
[1abc5ab]533                           termination_handlers, resumption_handlers );
[ba912706]534
[288eede]535                if ( resumption_handlers.size() ) {
[ba912706]536                        // Define the helper function.
537                        FunctionDecl * resume_handler =
538                                create_resume_handler( resumption_handlers );
539                        appendDeclStmt( block, resume_handler );
540                        // Prepare hooks
[288eede]541                        inner = create_resume_wrapper( node_decl, inner, resume_handler );
[ba912706]542                }
543
544                if ( termination_handlers.size() ) {
545                        // Define the three helper functions.
546                        FunctionDecl * try_wrapper = create_try_wrapper( inner );
547                        appendDeclStmt( block, try_wrapper );
548                        FunctionDecl * terminate_catch =
549                                create_terminate_catch( termination_handlers );
550                        appendDeclStmt( block, terminate_catch );
551                        FunctionDecl * terminate_match =
552                                create_terminate_match( termination_handlers );
553                        appendDeclStmt( block, terminate_match );
554                        // Build the call to the try wrapper.
555                        inner = create_terminate_caller(
556                                try_wrapper, terminate_catch, terminate_match );
557                }
558
559                // Embed the try block.
560                block->push_back( inner );
561
[288eede]562                //free_all( termination_handlers );
563                //free_all( resumption_handlers );
[ba912706]564
565                return block;
566        }
567
568        void ExceptionMutatorCore::premutate( CatchStmt *catchStmt ) {
[288eede]569                GuardValue( cur_context );
570                if ( CatchStmt::Terminate == catchStmt->get_kind() ) {
571                        cur_context = TerHandler;
[ba912706]572                } else {
[288eede]573                        cur_context = ResHandler;
[ba912706]574                }
575        }
576
[288eede]577        void ExceptionMutatorCore::premutate( StructDecl *structDecl ) {
578                if ( !structDecl->has_body() ) {
579                        // Skip children?
580                        return;
581                } else if ( structDecl->get_name() == "__cfaehm__try_resume_node" ) {
582                        assert( nullptr == node_decl );
583                        node_decl = structDecl;
584                } else if ( structDecl->get_name() == "__cfaehm__cleanup_hook" ) {
585                        assert( nullptr == hook_decl );
586                        hook_decl = structDecl;
587                }
588                // Later we might get the exception type as well.
589        }
590
[1abc5ab]591        void translateEHM( std::list< Declaration *> & translationUnit ) {
[288eede]592                init_func_types();
593
[ba912706]594                PassVisitor<ExceptionMutatorCore> translator;
[6fca7ea]595                mutateAll( translationUnit, translator );
[ba912706]596        }
597}
Note: See TracBrowser for help on using the repository browser.