Changeset a554e5f4 for src/ControlStruct


Ignore:
Timestamp:
Feb 9, 2022, 3:33:42 PM (4 years ago)
Author:
caparsons <caparson@…>
Branches:
ADT, ast-experimental, enum, forall-pointer-decay, master, pthread-emulation, qualifiedEnum
Children:
850aff1
Parents:
21a99cc (diff), c4f81702 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

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

Location:
src/ControlStruct
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/ExceptTranslate.h

    r21a99cc ra554e5f4  
    3131
    3232        void translateTries( std::list< Declaration *> & translationUnit );
     33        void translateTries( ast::TranslationUnit & transUnit );
    3334        /* Replaces all try blocks (and their many clauses) with function definitions and calls.
    3435         * This uses the exception built-ins to produce typed output and should take place after
  • src/ControlStruct/ExceptTranslateNew.cpp

    r21a99cc ra554e5f4  
    2020#include "AST/Stmt.hpp"
    2121#include "AST/TranslationUnit.hpp"
     22#include "AST/DeclReplacer.hpp"
    2223
    2324namespace 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        }
    2446
    2547class TranslateThrowsCore : public ast::WithGuards {
     
    126148}
    127149
     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
    128749void translateThrows( ast::TranslationUnit & transUnit ) {
    129750        ast::Pass<TranslateThrowsCore>::run( transUnit );
     751}
     752
     753void translateTries( ast::TranslationUnit & transUnit ) {
     754        ast::Pass<TryMutatorCore>::run(transUnit);
    130755}
    131756
  • src/ControlStruct/MLEMutator.cc

    r21a99cc ra554e5f4  
    1010// Created On       : Mon May 18 07:44:20 2015
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 09:26:28 2022
    13 // Update Count     : 225
     12// Last Modified On : Wed Feb  2 20:18:57 2022
     13// Update Count     : 227
    1414//
    1515
     
    136136                        }
    137137                }
    138                 assertf( false, "Could not find label '%s' on statement %s",
     138                assertf( false, "CFA internal error: could not find label '%s' on statement %s",
    139139                        originalTarget.get_name().c_str(), toString( stmt ).c_str() );
    140140        }
     
    395395                }
    396396                assert( ! enclosingControlStructures.empty() );
    397                 assertf( dynamic_cast<SwitchStmt *>( enclosingControlStructures.back().get_controlStructure() ), "Control structure enclosing a case clause must be a switch, but is: %s", toCString( enclosingControlStructures.back().get_controlStructure() ) );
     397                assertf( dynamic_cast<SwitchStmt *>( enclosingControlStructures.back().get_controlStructure() ),
     398                                 "CFA internal error: control structure enclosing a case clause must be a switch, but is: %s",
     399                                 toCString( enclosingControlStructures.back().get_controlStructure() ) );
    398400                if ( caseStmt->isDefault() ) {
    399401                        if ( enclosingControlStructures.back().isFallDefaultUsed() ) {
  • src/ControlStruct/MultiLevelExit.cpp

    r21a99cc ra554e5f4  
    1010// Created On       : Mon Nov  1 13:48:00 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  1 18:48:47 2022
    13 // Update Count     : 29
     12// Last Modified On : Wed Feb  2 23:07:54 2022
     13// Update Count     : 33
    1414//
    1515
     
    4949                return target.label;
    5050        }
    51 
    5251  public:
    5352        Entry( const ForStmt * stmt, Label breakExit, Label contExit ) :
     
    168167
    169168        // if the stmt is labelled then generate a label to check in postvisit if the label is used
    170         bool isLabeled = !stmt->labels.empty();
     169        bool isLabeled = ! stmt->labels.empty();
    171170        if ( isLabeled ) {
    172171                Label breakLabel = newLabel( "blockBreak", stmt );
     
    180179
    181180        if ( isLabeled ) {
    182                 assert( !enclosing_control_structures.empty() );
     181                assert( ! enclosing_control_structures.empty() );
    183182                Entry & entry = enclosing_control_structures.back();
    184                 if ( !entry.useBreakExit().empty() ) {
     183                if ( ! entry.useBreakExit().empty() ) {
    185184                        break_label = entry.useBreakExit();
    186185                }
     
    206205                }
    207206        }
    208         assertf( false, "Could not find label '%s' on statement %s",
     207        assertf( false, "CFA internal error: could not find label '%s' on statement %s",
    209208                         originalTarget.name.c_str(), toString( stmt ).c_str() );
    210209}
     
    254253                  }
    255254                  // Ensure that selected target is valid.
    256                   if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && !isContinueTarget( *targetEntry ) ) ) {
     255                  if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
    257256                          SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
    258257                                                        " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
     
    268267                          SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    269268                  }
    270                   if ( !stmt->target.empty() ) {
     269                  if ( ! stmt->target.empty() ) {
    271270                          // Labelled fallthrough: target must be a valid fallthough label.
    272                           if ( !fallthrough_labels.count( stmt->target ) ) {
     271                          if ( ! fallthrough_labels.count( stmt->target ) ) {
    273272                                  SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
    274273                                                                                                                   stmt->originalTarget ) );
    275274                          }
    276                           return new BranchStmt(
    277                                   stmt->location, BranchStmt::Goto, stmt->originalTarget );
     275                          return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
    278276                  }
    279277                  break;
     
    307305        }
    308306
    309         // Branch error checks: get the appropriate label name:
    310         // (This label is always replaced.)
     307        // Branch error checks: get the appropriate label name, which is always replaced.
    311308        Label exitLabel( CodeLocation(), "" );
    312309        switch ( stmt->kind ) {
    313310          case BranchStmt::Break:
    314                 assert( !targetEntry->useBreakExit().empty() );
     311                assert( ! targetEntry->useBreakExit().empty() );
    315312                exitLabel = targetEntry->useBreakExit();
    316313                break;
    317314          case BranchStmt::Continue:
    318                 assert( !targetEntry->useContExit().empty() );
     315                assert( ! targetEntry->useContExit().empty() );
    319316                exitLabel = targetEntry->useContExit();
    320317                break;
    321318          case BranchStmt::FallThrough:
    322                 assert( !targetEntry->useFallExit().empty() );
     319                assert( ! targetEntry->useFallExit().empty() );
    323320                exitLabel = targetEntry->useFallExit();
    324321                break;
    325322          case BranchStmt::FallThroughDefault:
    326                 assert( !targetEntry->useFallDefaultExit().empty() );
     323                assert( ! targetEntry->useFallDefaultExit().empty() );
    327324                exitLabel = targetEntry->useFallDefaultExit();
    328325                // Check that fallthrough default comes before the default clause.
    329                 if ( !targetEntry->isFallDefaultValid() ) {
     326                if ( ! targetEntry->isFallDefaultValid() ) {
    330327                        SemanticError( stmt->location, "'fallthrough default' must precede the 'default' clause" );
    331328                }
     
    373370        // If default, mark seen.
    374371        if ( stmt->isDefault() ) {
    375                 assert( !enclosing_control_structures.empty() );
     372                assert( ! enclosing_control_structures.empty() );
    376373                enclosing_control_structures.back().seenDefault();
    377374        }
     
    399396                Entry & entry = enclosing_control_structures.back();
    400397                if ( entry.isFallUsed() ) {
    401                         mutStmt->stmts.push_back(
    402                                 labelledNullStmt( mutStmt->location, entry.useFallExit() ) );
     398                        mutStmt->stmts.push_back( labelledNullStmt( mutStmt->location, entry.useFallExit() ) );
    403399                }
    404400        }
     
    406402        Entry & entry = enclosing_control_structures.back();
    407403        assertf( dynamic_cast< const SwitchStmt * >( entry.stmt ),
    408                          "Control structure enclosing a case clause must be a switch, but is: %s",
     404                         "CFA internal error: control structure enclosing a case clause must be a switch, but is: %s",
    409405                         toString( entry.stmt ).c_str() );
    410406        if ( mutStmt->isDefault() ) {
    411407                if ( entry.isFallDefaultUsed() ) {
    412408                        // Add fallthrough default label if necessary.
    413                         push_front( mutStmt->stmts, labelledNullStmt(
    414                                                         stmt->location, entry.useFallDefaultExit()
    415                                                         ) );
     409                        push_front( mutStmt->stmts, labelledNullStmt( stmt->location, entry.useFallDefaultExit() ) );
    416410                }
    417411        }
     
    420414
    421415void MultiLevelExitCore::previsit( const IfStmt * stmt ) {
    422         bool labeledBlock = !stmt->labels.empty();
     416        bool labeledBlock = ! stmt->labels.empty();
    423417        if ( labeledBlock ) {
    424418                Label breakLabel = newLabel( "blockBreak", stmt );
     
    429423
    430424const IfStmt * MultiLevelExitCore::postvisit( const IfStmt * stmt ) {
    431         bool labeledBlock = !stmt->labels.empty();
     425        bool labeledBlock = ! stmt->labels.empty();
    432426        if ( labeledBlock ) {
    433427                auto this_label = enclosing_control_structures.back().useBreakExit();
    434                 if ( !this_label.empty() ) {
     428                if ( ! this_label.empty() ) {
    435429                        break_label = this_label;
    436430                }
     
    448442        auto it = find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase );
    449443
    450         const CaseStmt * defaultCase = it != stmt->stmts.rend()
    451                 ? (it)->strict_as<CaseStmt>() : nullptr;
    452         Label defaultLabel = defaultCase
    453                 ? newLabel( "fallThroughDefault", defaultCase )
    454                 : Label( stmt->location, "" );
     444        const CaseStmt * defaultCase = it != stmt->stmts.rend() ? (it)->strict_as<CaseStmt>() : nullptr;
     445        Label defaultLabel = defaultCase ? newLabel( "fallThroughDefault", defaultCase ) : Label( stmt->location, "" );
    455446        enclosing_control_structures.emplace_back( stmt, label, defaultLabel );
    456447        GuardAction( [this]() { enclosing_control_structures.pop_back(); } );
    457448
    458         // Collect valid labels for fallthrough. It starts with all labels at
    459         // this level, then remove as each is seen during traversal.
     449        // Collect valid labels for fallthrough. It starts with all labels at this level, then remove as each is seen during
     450        // traversal.
    460451        for ( const Stmt * stmt : stmt->stmts ) {
    461452                auto * caseStmt = strict_dynamic_cast< const CaseStmt * >( stmt );
     
    471462
    472463const SwitchStmt * MultiLevelExitCore::postvisit( const SwitchStmt * stmt ) {
    473         assert( !enclosing_control_structures.empty() );
     464        assert( ! enclosing_control_structures.empty() );
    474465        Entry & entry = enclosing_control_structures.back();
    475466        assert( entry.stmt == stmt );
     
    477468        // Only run to generate the break label.
    478469        if ( entry.isBreakUsed() ) {
    479                 // To keep the switch statements uniform (all direct children of a
    480                 // SwitchStmt should be CastStmts), append the exit label and break
    481                 // to the last case, create a default case is there are no cases.
     470                // To keep the switch statements uniform (all direct children of a SwitchStmt should be CastStmts), append the
     471                // exit label and break to the last case, create a default case if no cases.
    482472                SwitchStmt * mutStmt = mutate( stmt );
    483473                if ( mutStmt->stmts.empty() ) {
    484                         mutStmt->stmts.push_back( new CaseStmt(
    485                                                                                   mutStmt->location, nullptr, {} ));
     474                        mutStmt->stmts.push_back( new CaseStmt( mutStmt->location, nullptr, {} ) );
    486475                }
    487476
     
    507496
    508497void MultiLevelExitCore::previsit( const TryStmt * stmt ) {
    509         bool isLabeled = !stmt->labels.empty();
     498        bool isLabeled = ! stmt->labels.empty();
    510499        if ( isLabeled ) {
    511500                Label breakLabel = newLabel( "blockBreak", stmt );
     
    516505
    517506void MultiLevelExitCore::postvisit( const TryStmt * stmt ) {
    518         bool isLabeled = !stmt->labels.empty();
     507        bool isLabeled = ! stmt->labels.empty();
    519508        if ( isLabeled ) {
    520509                auto this_label = enclosing_control_structures.back().useBreakExit();
    521                 if ( !this_label.empty() ) {
     510                if ( ! this_label.empty() ) {
    522511                        break_label = this_label;
    523512                }
     
    526515
    527516void MultiLevelExitCore::previsit( const FinallyStmt * ) {
    528         GuardAction([this, old = move(enclosing_control_structures)](){
    529                                         enclosing_control_structures = move(old);
    530                                 });
     517        GuardAction([this, old = move( enclosing_control_structures)](){ enclosing_control_structures = move(old); });
    531518        enclosing_control_structures = vector<Entry>();
    532519        GuardValue( inFinally ) = true;
     
    575562template<typename LoopNode>
    576563const LoopNode * MultiLevelExitCore::posthandleLoopStmt( const LoopNode * loopStmt ) {
    577         assert( !enclosing_control_structures.empty() );
     564        assert( ! enclosing_control_structures.empty() );
    578565        Entry & entry = enclosing_control_structures.back();
    579566        assert( entry.stmt == loopStmt );
    580567
    581568        // Now check if the labels are used and add them if so.
    582         return mutate_field(
    583                 loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
     569        return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
    584570        // this call to mutate_field compares loopStmt->body and the result of mutateLoop
    585571        //              if they are the same the node isn't mutated, if they differ then the new mutated node is returned
     
    609595                }
    610596
    611                 if ( !break_label.empty() ) {
    612                         ret.push_back(
    613                                 labelledNullStmt( ret.back()->location, break_label ) );
     597                if ( ! break_label.empty() ) {
     598                        ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
    614599                        break_label = Label( CodeLocation(), "" );
    615600                }
    616601        }
    617602
    618         if ( !errors.isEmpty() ) {
     603        if ( ! errors.isEmpty() ) {
    619604                throw errors;
    620605        }
Note: See TracChangeset for help on using the changeset viewer.