Changeset 0a6d2045


Ignore:
Timestamp:
Dec 20, 2023, 12:04:33 PM (11 months ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
523e300
Parents:
9fba8e6
Message:

You can how use local control flow out of 'catch' clauses. Added a test to show that it works.

Files:
2 added
4 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/ExceptTranslate.cpp

    r9fba8e6 r0a6d2045  
    151151                const ast::DeclWithType * except_obj, ast::CatchClause * modded_handler );
    152152        ast::FunctionDecl * create_terminate_match( CatchList &handlers );
    153         ast::CompoundStmt * create_terminate_caller( CodeLocation loc, ast::FunctionDecl * try_wrapper,
    154                 ast::FunctionDecl * terminate_catch, ast::FunctionDecl * terminate_match );
     153        ast::CompoundStmt * create_terminate_caller( const CodeLocation & location,
     154                ast::FunctionDecl * try_wrapper, ast::FunctionDecl * terminate_match,
     155                CatchList & terminate_handlers );
    155156        ast::FunctionDecl * create_resume_handler( CatchList &handlers );
    156157        ast::CompoundStmt * create_resume_wrapper(
     
    264265        //     `handler.body`;
    265266        // }
    266         // return;
     267        // break;
    267268        const CodeLocation & location = clause->location;
    268269
     
    295296                                body,
    296297                        } ),
    297                         new ast::ReturnStmt( location, nullptr ),
     298                        new ast::BranchStmt( location, ast::BranchStmt::Break,
     299                                ast::Label( location ) ),
    298300                }
    299301        );
     
    391393        // Index 1..{number of handlers}
    392394        int index = 0;
    393         CatchList::iterator it;
    394         for ( it = handlers.begin() ; it != handlers.end() ; ++it ) {
     395        for ( ast::CatchClause * handler : handlers ) {
    395396                ++index;
    396                 ast::CatchClause * handler = *it;
    397 
    398                 // Body should have been taken by create_terminate_catch.
    399                 // xxx - just ignore it?
    400                 // assert( nullptr == handler->get_body() );
    401 
    402                 // Create new body.
    403                 handler->body = new ast::ReturnStmt( handler->location,
     397
     398                ast::ptr<ast::Stmt> other_body = new ast::ReturnStmt( handler->location,
    404399                        ast::ConstantExpr::from_int( handler->location, index ) );
    405 
    406                 // Create the handler.
     400                handler->body.swap( other_body );
     401
    407402                body->push_back( create_single_matcher( except_obj, handler ) );
    408                 *it = nullptr;
     403
     404                handler->body.swap( other_body );
    409405        }
    410406
     
    425421
    426422ast::CompoundStmt * TryMutatorCore::create_terminate_caller(
    427                 CodeLocation loc,
     423                const CodeLocation & loc,
    428424                ast::FunctionDecl * try_wrapper,
    429                 ast::FunctionDecl * terminate_catch,
    430                 ast::FunctionDecl * terminate_match ) {
     425                ast::FunctionDecl * terminate_match,
     426                CatchList & terminate_handlers ) {
    431427        // {
    432428        //     int __handler_index = __cfaehm_try_terminate(`try`, `match`);
     
    447443        );
    448444
     445        ast::ObjectDecl * except = make_exception_object( loc );
     446        except->init = new ast::SingleInit( loc,
     447                new ast::UntypedExpr( loc,
     448                        new ast::NameExpr( loc, "__cfaehm_get_current_termination" )
     449                )
     450        );
     451
     452        std::vector<ast::ptr<ast::CaseClause>> cases;
     453        for ( auto const & [index, handler] : enumerate( terminate_handlers ) ) {
     454                cases.emplace_back(
     455                        create_terminate_catch_case( except, index + 1, handler ) );
     456        }
     457        auto switch_stmt = new ast::SwitchStmt( loc,
     458                new ast::VariableExpr( loc, index ), std::move( cases ) );
     459
    449460        return new ast::CompoundStmt( loc, {
    450461                new ast::DeclStmt( loc, index ),
    451462                new ast::IfStmt( loc,
    452463                        new ast::VariableExpr( loc, index ),
    453                         new ast::ExprStmt( loc,
    454                                 new ast::UntypedExpr( loc,
    455                                         new ast::VariableExpr( loc, terminate_catch ),
    456                                         {
    457                                                 new ast::VariableExpr( loc, index ),
    458                                                 new ast::UntypedExpr( loc,
    459                                                         new ast::NameExpr( loc, "__cfaehm_get_current_termination" )
    460                                                 ),
    461                                         }
    462                                 )
    463                         )
     464                        new ast::CompoundStmt( loc, {
     465                                new ast::DeclStmt( loc, except ),
     466                                switch_stmt,
     467                        } )
    464468                ),
    465469        } );
     
    663667
    664668        if ( termination_handlers.size() ) {
    665                 // Define the three helper functions.
     669                // Define the two helper functions.
    666670                ast::FunctionDecl * try_wrapper = create_try_wrapper( inner );
    667671                appendDeclStmt( block, try_wrapper );
    668                 ast::FunctionDecl * terminate_catch =
    669                         create_terminate_catch( termination_handlers );
    670                 appendDeclStmt( block, terminate_catch );
    671672                ast::FunctionDecl * terminate_match =
    672673                        create_terminate_match( termination_handlers );
     
    674675                // Build the call to the try wrapper.
    675676                inner = create_terminate_caller(inner->location,
    676                         try_wrapper, terminate_catch, terminate_match );
     677                        try_wrapper, terminate_match, termination_handlers );
    677678        }
    678679
  • src/ControlStruct/MultiLevelExit.cpp

    r9fba8e6 r0a6d2045  
    3535        InTryWithHandler,
    3636        InResumeHandler,
    37         InTerminateHandler,
    3837        InFinally,
    3938};
     
    512511                context = "catchResume clause";
    513512                break;
    514         case ReturnContext::InTerminateHandler:
    515                 context = "catch clause";
    516                 break;
    517513        case ReturnContext::InFinally:
    518514                context = "finally clause";
     
    524520}
    525521
     522bool hasTerminate( const TryStmt * stmt ) {
     523        for ( auto clause : stmt->handlers ) {
     524                if ( ast::Terminate == clause->kind ) return true;
     525        }
     526        return false;
     527}
     528
    526529void MultiLevelExitCore::previsit( const TryStmt * stmt ) {
     530        visit_children = false;
     531
    527532        bool isLabeled = ! stmt->labels.empty();
    528533        if ( isLabeled ) {
     
    533538
    534539        // Try statements/try blocks are only sealed with a termination handler.
    535         for ( auto clause : stmt->handlers ) {
    536                 if ( ast::Terminate == clause->kind ) {
    537                         return enterSealedContext( ReturnContext::InTryWithHandler );
    538                 }
    539         }
     540        if ( hasTerminate( stmt ) ) {
     541                // This is just enterSealedContext except scoped to the block.
     542                // And that is because the state must change for a single field.
     543                ValueGuard< ReturnContext > guard0( ret_context );
     544                ret_context = ReturnContext::InTryWithHandler;
     545                auto guard = makeFuncGuard( [](){}, [this, old = std::move(enclosing_control_structures)](){ enclosing_control_structures = std::move(old); });
     546                enclosing_control_structures = vector<Entry>();
     547                visitor->maybe_accept( stmt, &TryStmt::body );
     548        } else {
     549                visitor->maybe_accept( stmt, &TryStmt::body );
     550        }
     551
     552        visitor->maybe_accept( stmt, &TryStmt::handlers );
     553        visitor->maybe_accept( stmt, &TryStmt::finally );
    540554}
    541555
     
    551565
    552566void MultiLevelExitCore::previsit( const CatchClause * clause ) {
    553         ReturnContext context = ( ast::Terminate == clause->kind )
    554                 ? ReturnContext::InTerminateHandler : ReturnContext::InResumeHandler;
    555         enterSealedContext( context );
     567        if ( ast::Resume == clause->kind ) {
     568                enterSealedContext( ReturnContext::InResumeHandler );
     569        }
    556570}
    557571
  • tests/exceptions/.expect/try-ctrl-flow.txt

    r9fba8e6 r0a6d2045  
    1515exceptions/try-ctrl-flow.cfa:148:1 error: "break" outside a loop, "switch", or labelled block
    1616exceptions/try-ctrl-flow.cfa:159:1 error: "return" may not appear in a try statement with a catch clause
    17 exceptions/try-ctrl-flow.cfa:187:1 error: "return" may not appear in a catch clause
    18 exceptions/try-ctrl-flow.cfa:195:1 error: "return" may not appear in a catchResume clause
     17exceptions/try-ctrl-flow.cfa:187:1 error: "return" may not appear in a catchResume clause
  • tests/exceptions/try-ctrl-flow.cfa

    r9fba8e6 r0a6d2045  
    181181}
    182182
    183 void return_in_catch() {
    184         try {
    185                 ;
    186         } catch (nil_exception *) {
    187                 return;
    188         }
    189 }
    190 
    191183void return_in_catchResume() {
    192184        try {
Note: See TracChangeset for help on using the changeset viewer.