Ignore:
Timestamp:
Dec 20, 2023, 12:04:33 PM (7 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.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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
Note: See TracChangeset for help on using the changeset viewer.