Changeset 1b6ec23
- Timestamp:
- Mar 11, 2026, 5:38:44 PM (21 hours ago)
- Branches:
- master
- Children:
- 4acd1f8
- Parents:
- 54c01bb
- File:
-
- 1 edited
-
src/ControlStruct/MultiLevelExit.cpp (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/ControlStruct/MultiLevelExit.cpp
r54c01bb r1b6ec23 10 10 // Created On : Mon Nov 1 13:48:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Thu Dec 14 17:34:12 202313 // Update Count : 3912 // Last Modified On : Wed Mar 11 17:35:25 2026 13 // Update Count : 137 14 14 // 15 15 … … 160 160 const LoopNode * posthandleLoopStmt( const LoopNode * loopStmt ); 161 161 162 list<ptr<Stmt>> fixBlock( 163 const list<ptr<Stmt>> & kids, bool caseClause ); 162 list<ptr<Stmt>> fixBlock( const list<ptr<Stmt>> & kids, bool caseClause ); 164 163 165 164 void enterSealedContext( ReturnContext ); … … 185 184 } 186 185 187 const CompoundStmt * MultiLevelExitCore::previsit( 188 const CompoundStmt * stmt ) { 186 const CompoundStmt * MultiLevelExitCore::previsit( const CompoundStmt * stmt ) { 189 187 visit_children = false; 190 188 … … 244 242 // label is used by the BranchStmt that is passed 245 243 const BranchStmt * MultiLevelExitCore::postvisit( const BranchStmt * stmt ) { 246 vector<Entry>::reverse_iterator targetEntry = 247 enclosing_control_structures.rend(); 244 vector<Entry>::reverse_iterator targetEntry = enclosing_control_structures.rend(); 248 245 249 246 // Labels on different stmts require different approaches to access … … 584 581 } 585 582 586 const Stmt * MultiLevelExitCore::mutateLoop( 587 const Stmt * body, Entry & entry ) { 583 const Stmt * MultiLevelExitCore::mutateLoop( const Stmt * body, Entry & entry ) { 588 584 if ( entry.isBreakUsed() ) { 589 585 break_label = entry.useBreakExit(); … … 608 604 void MultiLevelExitCore::prehandleLoopStmt( const LoopNode * loopStmt ) { 609 605 // Create temporary labels and mark the enclosing loop before traversal. 610 // The labels will be folded in if they are used.606 // The labels are folded in if they are used. 611 607 Label breakLabel = newLabel( "loopBreak", loopStmt ); 612 608 Label contLabel = newLabel( "loopContinue", loopStmt ); … … 614 610 615 611 GuardAction( [this](){ enclosing_control_structures.pop_back(); } ); 616 617 // Because of fixBlock, this should be empty now (and must be).618 assert( nullptr == loopStmt->else_ );619 612 } 620 613 … … 629 622 } 630 623 631 list<ptr<Stmt>> MultiLevelExitCore::fixBlock( 632 const list<ptr<Stmt>> & kids, bool is_case_clause ) { 633 // Unfortunately cannot use automatic error collection. 634 SemanticErrorException errors; 635 636 list<ptr<Stmt>> ret; 637 638 // Manually visit each child. 624 list<ptr<Stmt>> MultiLevelExitCore::fixBlock( const list<ptr<Stmt>> & kids, bool is_case_clause ) { 625 // SKULLDUGGERY: While the loop-else clause is not part of C, it is allowed to proceed to codegen via the else_ 626 // field and printed there as a compound statement. The alternative is another pass after hoist-control-declarations 627 // to make the else clause a separate compound statement, which seems unnecessary. 628 629 SemanticErrorException errors; // cannot use automatic error collection 630 list<ptr<Stmt>> ret; // list of augmented statements 631 632 // Manually visit each each control structure in a block checking for untargeted break and continue statements. 639 633 for ( const ptr<Stmt> & kid : kids ) { 640 634 if ( is_case_clause ) { 641 // Once a label is seen, it 's no longer avalid for fallthrough.635 // Once a label is seen, it is no longer valid for fallthrough. 642 636 for ( const Label & l : kid->labels ) { 643 637 fallthrough_labels.erase( l ); 644 } 645 } 638 } // for 639 } // if 646 640 647 641 ptr<Stmt> else_stmt = nullptr; 648 const Stmt * to_visit ;649 // check if loop node and if so add else clause if it exists642 const Stmt * to_visit = nullptr; 643 // SKULLDUGGERY: temporarily hide the else clause on a loop statement, by setting the else_ field to NULL. 650 644 if ( auto ptr = kid.as<WhileDoStmt>() ; ptr && ptr->else_ ) { 651 645 else_stmt = ptr->else_; … … 655 649 to_visit = mutate_field( ptr, &ForStmt::else_, nullptr ); 656 650 } else { 657 to_visit = kid.get(); 658 } 659 660 // This is the main (safe) visit of the child node. 661 try { 651 // Process all other statements as a whole rather than parts, as is done below for loop-else. 652 try { 653 ret.push_back( kid.get()->accept( *visitor ) ); 654 } catch ( SemanticErrorException & e ) { 655 errors.append( e ); 656 } // try 657 } // if 658 659 // Process loops with hidden else clause. 660 if ( else_stmt ) try { 661 // In both else_stmt cases, we already modified to_visit, so its location won't change 662 const Stmt * subvisit_rslt = to_visit->accept( *visitor ); 663 assert( subvisit_rslt == to_visit ); 664 } catch ( SemanticErrorException & e ) { 665 errors.append( e ); 666 } // try 667 668 // Create untargeted break-label for all statements. (global) break_label must be copied here, as it is changed 669 // by subsequent processing. 670 Label local_break_label = std::move( break_label ); 671 break_label = Label( CodeLocation(), "" ); 672 673 if ( else_stmt ) try { 674 // SKULLDUGGERY: now reconnect the else clause to the loop and process it seperately looking for untargeted 675 // breaks. These breaks apply to the containing switch or loop, not the connected loop-else. 676 if ( auto ptr = dynamic_cast<const WhileDoStmt *>(to_visit) ) { 677 assert( ptr->else_ == nullptr ); 678 else_stmt->accept( *visitor ); 679 mutate_field( ptr, &WhileDoStmt::else_, else_stmt ); 680 } else if ( auto ptr = dynamic_cast<const ForStmt *>(to_visit) ) { 681 assert( ptr->else_ == nullptr ); 682 else_stmt->accept( *visitor ); 683 mutate_field( ptr, &ForStmt::else_, else_stmt ); 684 } // if 685 // Now process the else clause so breaks apply to the containing scope. 662 686 ret.push_back( to_visit->accept( *visitor ) ); 663 687 } catch ( SemanticErrorException & e ) { 664 688 errors.append( e ); 665 } 666 667 // The following sections handle visiting loop else clause and makes 668 // sure breaking from a loop body does not execute that clause. 669 Label local_break_label = std::move( break_label ); 670 break_label = Label( CodeLocation(), "" ); 671 672 if ( else_stmt ) try { 673 ret.push_back( else_stmt->accept( *visitor ) ); 674 } catch ( SemanticErrorException & e ) { 675 errors.append( e ); 676 } 677 678 if ( !break_label.empty() ) { 679 ret.push_back( labelledNullStmt( ret.back()->location, break_label ) ); 680 break_label = Label( CodeLocation(), "" ); 681 } 682 683 // This handles a break from the body or non-loop statement. 684 if ( !local_break_label.empty() ) { 689 } // try 690 691 // Generate untargeted break-label AFTER its containing control structure, including else clause, if present. 692 if ( ! local_break_label.empty() ) { 685 693 ret.push_back( labelledNullStmt( ret.back()->location, local_break_label ) ); 686 } 687 } 694 } // if 695 } // for 688 696 689 697 errors.throwIfNonEmpty(); 698 // Return a new list of augmented statements with untargeted breaks replaced by goto statements that transfer after 699 // the containing switch/loop. 690 700 return ret; 691 701 } … … 699 709 } // namespace 700 710 701 const CompoundStmt * multiLevelExitUpdate( 702 const CompoundStmt * stmt, const LabelToStmt & labelTable ) { 711 const CompoundStmt * multiLevelExitUpdate( const CompoundStmt * stmt, const LabelToStmt & labelTable ) { 703 712 // Must start in the body, so FunctionDecls can be a stopping point. 704 713 Pass<MultiLevelExitCore> visitor( labelTable );
Note:
See TracChangeset
for help on using the changeset viewer.