Ignore:
Timestamp:
Jul 16, 2024, 5:28:10 PM (2 days ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
master
Children:
97f9619
Parents:
2363147
Message:

Breaks (and some other control flow) in a loop else clause now work. I also implemented else clauses in printing and code generation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MultiLevelExit.cpp

    r2363147 r88bc876  
    7878                stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmtK ) {}
    7979
     80        // Check if this entry can be the target of the given type of control flow.
    8081        bool isContTarget() const { return kind <= WhileDoStmtK; }
    8182        bool isBreakTarget() const { return kind != CaseClauseK; }
     
    207208
    208209        // If the label is empty, do not add unused attribute.
    209   if ( originalTarget.empty() ) return size;
     210        if ( originalTarget.empty() ) return size;
    210211
    211212        // Search for a label that matches the originalTarget.
     
    343344                assert(0);
    344345        }
     346        assert( !exitLabel.empty() );
    345347
    346348        // Add unused attribute to silence warnings.
     
    486488                }
    487489
    488                 auto caseStmt = mutStmt->cases.back().get();
    489                 auto mutCase = mutate( caseStmt );
    490                 mutStmt->cases.back() = mutCase;
     490                auto mutCase = mutStmt->cases.back().get_and_mutate();
    491491
    492492                Label label( mutCase->location, "breakLabel" );
     
    597597template<typename LoopNode>
    598598void MultiLevelExitCore::prehandleLoopStmt( const LoopNode * loopStmt ) {
    599         // Remember is loop before going onto mutate the body.
     599        // Create temporary labels and mark the enclosing loop before traversal.
    600600        // The labels will be folded in if they are used.
    601601        Label breakLabel = newLabel( "loopBreak", loopStmt );
    602602        Label contLabel = newLabel( "loopContinue", loopStmt );
    603603        enclosing_control_structures.emplace_back( loopStmt, breakLabel, contLabel );
    604         // labels are added temporarily to see if they are used and then added permanently in postvisit if ther are used
    605         // children will tag labels as being used during their traversal which occurs before postvisit
    606 
    607         // GuardAction calls the lambda after the node is done being visited
     604
    608605        GuardAction( [this](){ enclosing_control_structures.pop_back(); } );
     606
     607        // Because of fixBlock, this should be empty now (and must be).
     608        assert( nullptr == loopStmt->else_ );
    609609}
    610610
     
    617617        // Now check if the labels are used and add them if so.
    618618        return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) );
    619         // this call to mutate_field compares loopStmt->body and the result of mutateLoop
    620         //              if they are the same the node isn't mutated, if they differ then the new mutated node is returned
    621         //              the stmts will only differ if a label is used
    622619}
    623620
     
    639636
    640637                ptr<Stmt> else_stmt = nullptr;
    641                 const Stmt * loop_kid = nullptr;
     638                const Stmt * to_visit;
    642639                // check if loop node and if so add else clause if it exists
    643                 const WhileDoStmt * whilePtr = kid.as<WhileDoStmt>();
    644                 if ( whilePtr && whilePtr->else_ ) {
    645                         else_stmt = whilePtr->else_;
    646                         loop_kid = mutate_field( whilePtr, &WhileDoStmt::else_, nullptr );
    647                 }
    648                 const ForStmt * forPtr = kid.as<ForStmt>();
    649                 if ( forPtr && forPtr->else_ ) {
    650                         else_stmt = forPtr->else_;
    651                         loop_kid = mutate_field( forPtr, &ForStmt::else_, nullptr );
    652                 }
    653 
     640                if ( auto ptr = kid.as<WhileDoStmt>() ; ptr && ptr->else_ ) {
     641                        else_stmt = ptr->else_;
     642                        to_visit = mutate_field( ptr, &WhileDoStmt::else_, nullptr );
     643                } else if ( auto ptr = kid.as<ForStmt>() ; ptr && ptr->else_ ) {
     644                        else_stmt = ptr->else_;
     645                        to_visit = mutate_field( ptr, &ForStmt::else_, nullptr );
     646                } else {
     647                        to_visit = kid.get();
     648                }
     649
     650                // This is the main (safe) visit of the child node.
    654651                try {
    655                         if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) );
    656                         else ret.push_back( kid->accept( *visitor ) );
     652                        ret.push_back( to_visit->accept( *visitor ) );
    657653                } catch ( SemanticErrorException & e ) {
    658654                        errors.append( e );
    659655                }
    660656
    661                 if (else_stmt) ret.push_back(else_stmt);
    662 
    663                 if ( ! break_label.empty() ) {
     657                // The following sections handle visiting loop else clause and makes
     658                // sure breaking from a loop body does not execute that clause.
     659                Label local_break_label = std::move( break_label );
     660                break_label = Label( CodeLocation(), "" );
     661
     662                if ( else_stmt ) try {
     663                        ret.push_back( else_stmt->accept( *visitor ) );
     664                } catch ( SemanticErrorException & e ) {
     665                        errors.append( e );
     666                }
     667
     668                if ( !break_label.empty() ) {
    664669                        ret.push_back( labelledNullStmt( ret.back()->location, break_label ) );
    665670                        break_label = Label( CodeLocation(), "" );
    666671                }
    667         }
    668 
    669         if ( ! errors.isEmpty() ) {
     672
     673                // This handles a break from the body or non-loop statement.
     674                if ( !local_break_label.empty() ) {
     675                        ret.push_back( labelledNullStmt( ret.back()->location, local_break_label ) );
     676                }
     677        }
     678
     679        if ( !errors.isEmpty() ) {
    670680                throw errors;
    671681        }
Note: See TracChangeset for help on using the changeset viewer.