Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MultiLevelExit.cpp

    rf75e25b r0577df2  
    1818#include "AST/Pass.hpp"
    1919#include "AST/Stmt.hpp"
     20#include "Common/CodeLocationTools.hpp"
    2021#include "LabelGeneratorNew.hpp"
    2122
     
    148149};
    149150
    150 NullStmt * labelledNullStmt(
    151         const CodeLocation & cl, const Label & label ) {
     151NullStmt * labelledNullStmt( const CodeLocation & cl, const Label & label ) {
    152152        return new NullStmt( cl, vector<Label>{ label } );
    153153}
     
    163163
    164164const CompoundStmt * MultiLevelExitCore::previsit(
    165         const CompoundStmt * stmt ) {
     165                const CompoundStmt * stmt ) {
    166166        visit_children = false;
    167167
     
    188188}
    189189
    190 size_t getUnusedIndex(
    191         const Stmt * stmt, const Label & originalTarget ) {
     190size_t getUnusedIndex( const Stmt * stmt, const Label & originalTarget ) {
    192191        const size_t size = stmt->labels.size();
    193192
     
    209208}
    210209
    211 const Stmt * addUnused(
    212         const Stmt * stmt, const Label & originalTarget ) {
     210const Stmt * addUnused( const Stmt * stmt, const Label & originalTarget ) {
    213211        size_t i = getUnusedIndex( stmt, originalTarget );
    214212        if ( i == stmt->labels.size() ) {
     
    228226        // Labels on different stmts require different approaches to access
    229227        switch ( stmt->kind ) {
    230           case BranchStmt::Goto:
     228        case BranchStmt::Goto:
    231229                return stmt;
    232           case BranchStmt::Continue:
    233           case BranchStmt::Break: {
    234                   bool isContinue = stmt->kind == BranchStmt::Continue;
    235                   // Handle unlabeled break and continue.
    236                   if ( stmt->target.empty() ) {
    237                           if ( isContinue ) {
    238                                   targetEntry = findEnclosingControlStructure( isContinueTarget );
    239                           } else {
    240                                   if ( enclosing_control_structures.empty() ) {
     230        case BranchStmt::Continue:
     231        case BranchStmt::Break: {
     232                bool isContinue = stmt->kind == BranchStmt::Continue;
     233                // Handle unlabeled break and continue.
     234                if ( stmt->target.empty() ) {
     235                        if ( isContinue ) {
     236                                targetEntry = findEnclosingControlStructure( isContinueTarget );
     237                        } else {
     238                                if ( enclosing_control_structures.empty() ) {
    241239                                          SemanticError( stmt->location,
    242240                                                                         "'break' outside a loop, 'switch', or labelled block" );
    243                                   }
    244                                   targetEntry = findEnclosingControlStructure( isBreakTarget );
    245                           }
    246                           // Handle labeled break and continue.
    247                   } else {
    248                           // Lookup label in table to find attached control structure.
    249                           targetEntry = findEnclosingControlStructure(
    250                                   [ targetStmt = target_table.at(stmt->target) ](auto entry){
     241                                }
     242                                targetEntry = findEnclosingControlStructure( isBreakTarget );
     243                        }
     244                        // Handle labeled break and continue.
     245                } else {
     246                        // Lookup label in table to find attached control structure.
     247                        targetEntry = findEnclosingControlStructure(
     248                                [ targetStmt = target_table.at(stmt->target) ](auto entry){
    251249                                          return entry.stmt == targetStmt;
    252                                   } );
    253                   }
    254                   // Ensure that selected target is valid.
    255                   if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
    256                           SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
     250                                } );
     251                }
     252                // Ensure that selected target is valid.
     253                if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
     254                        SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
    257255                                                        " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
    258256                                                        stmt->originalTarget ) );
    259                   }
    260                   break;
    261           }
    262           // handle fallthrough in case/switch stmts
    263           case BranchStmt::FallThrough: {
    264                   targetEntry = findEnclosingControlStructure( isFallthroughTarget );
    265                   // Check that target is valid.
    266                   if ( targetEntry == enclosing_control_structures.rend() ) {
    267                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    268                   }
    269                   if ( ! stmt->target.empty() ) {
    270                           // Labelled fallthrough: target must be a valid fallthough label.
    271                           if ( ! fallthrough_labels.count( stmt->target ) ) {
    272                                   SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
     257                }
     258                break;
     259        }
     260        // handle fallthrough in case/switch stmts
     261        case BranchStmt::FallThrough: {
     262                targetEntry = findEnclosingControlStructure( isFallthroughTarget );
     263                // Check that target is valid.
     264                if ( targetEntry == enclosing_control_structures.rend() ) {
     265                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     266                }
     267                if ( ! stmt->target.empty() ) {
     268                        // Labelled fallthrough: target must be a valid fallthough label.
     269                        if ( ! fallthrough_labels.count( stmt->target ) ) {
     270                                SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
    273271                                                                                                                   stmt->originalTarget ) );
    274                           }
    275                           return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
    276                   }
    277                   break;
    278           }
    279           case BranchStmt::FallThroughDefault: {
    280                   targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
    281 
    282                   // Check if in switch or choose statement.
    283                   if ( targetEntry == enclosing_control_structures.rend() ) {
    284                           SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    285                   }
    286 
    287                   // Check if switch or choose has default clause.
    288                   auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
    289                   bool foundDefault = false;
    290                   for ( auto caseStmt : switchStmt->cases ) {
    291                           if ( caseStmt->isDefault() ) {
    292                                   foundDefault = true;
    293                                   break;
    294                           }
    295                   }
    296                   if ( ! foundDefault ) {
    297                           SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
    298                                                         "control structure with a 'default' clause" );
    299                   }
    300                   break;
    301           }
    302           default:
     272                        }
     273                        return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
     274                }
     275                break;
     276        }
     277        case BranchStmt::FallThroughDefault: {
     278                targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
     279
     280                // Check if in switch or choose statement.
     281                if ( targetEntry == enclosing_control_structures.rend() ) {
     282                        SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
     283                }
     284
     285                // Check if switch or choose has default clause.
     286                auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
     287                bool foundDefault = false;
     288                for ( auto caseStmt : switchStmt->cases ) {
     289                        if ( caseStmt->isDefault() ) {
     290                                foundDefault = true;
     291                                break;
     292                        }
     293                }
     294                if ( ! foundDefault ) {
     295                        SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
     296                                                  "control structure with a 'default' clause" );
     297                }
     298                break;
     299        }
     300        default:
    303301                assert( false );
    304302        }
     
    307305        Label exitLabel( CodeLocation(), "" );
    308306        switch ( stmt->kind ) {
    309           case BranchStmt::Break:
     307        case BranchStmt::Break:
    310308                assert( ! targetEntry->useBreakExit().empty() );
    311309                exitLabel = targetEntry->useBreakExit();
    312310                break;
    313           case BranchStmt::Continue:
     311        case BranchStmt::Continue:
    314312                assert( ! targetEntry->useContExit().empty() );
    315313                exitLabel = targetEntry->useContExit();
    316314                break;
    317           case BranchStmt::FallThrough:
     315        case BranchStmt::FallThrough:
    318316                assert( ! targetEntry->useFallExit().empty() );
    319317                exitLabel = targetEntry->useFallExit();
    320318                break;
    321           case BranchStmt::FallThroughDefault:
     319        case BranchStmt::FallThroughDefault:
    322320                assert( ! targetEntry->useFallDefaultExit().empty() );
    323321                exitLabel = targetEntry->useFallDefaultExit();
     
    327325                }
    328326                break;
    329           default:
     327        default:
    330328                assert(0);
    331329        }
     
    355353
    356354// Mimic what the built-in push_front would do anyways. It is O(n).
    357 void push_front(
    358         vector<ptr<Stmt>> & vec, const Stmt * element ) {
     355void push_front( vector<ptr<Stmt>> & vec, const Stmt * element ) {
    359356        vec.emplace_back( nullptr );
    360357        for ( size_t i = vec.size() - 1 ; 0 < i ; --i ) {
     
    589586
    590587                ptr<Stmt> else_stmt = nullptr;
    591                 Stmt * loop_kid = nullptr;
     588                const Stmt * loop_kid = nullptr;
    592589                // check if loop node and if so add else clause if it exists
    593                 const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());
    594                 if ( whilePtr && whilePtr->else_) {
     590                const WhileDoStmt * whilePtr = kid.as<WhileDoStmt>();
     591                if ( whilePtr && whilePtr->else_ ) {
    595592                        else_stmt = whilePtr->else_;
    596                         WhileDoStmt * mutate_ptr = mutate(whilePtr);
    597                         mutate_ptr->else_ = nullptr;
    598                         loop_kid = mutate_ptr;
    599                 }
    600                 const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());
    601                 if ( forPtr && forPtr->else_) {
     593                        loop_kid = mutate_field( whilePtr, &WhileDoStmt::else_, nullptr );
     594                }
     595                const ForStmt * forPtr = kid.as<ForStmt>();
     596                if ( forPtr && forPtr->else_ ) {
    602597                        else_stmt = forPtr->else_;
    603                         ForStmt * mutate_ptr = mutate(forPtr);
    604                         mutate_ptr->else_ = nullptr;
    605                         loop_kid = mutate_ptr;
     598                        loop_kid = mutate_field( forPtr, &ForStmt::else_, nullptr );
    606599                }
    607600
     
    633626        Pass<MultiLevelExitCore> visitor( labelTable );
    634627        const CompoundStmt * ret = stmt->accept( visitor );
    635         return ret;
     628        // There are some unset code locations slipping in, possibly by Labels.
     629        const Node * node = localFillCodeLocations( ret->location, ret );
     630        return strict_dynamic_cast<const CompoundStmt *>( node );
    636631}
    637632} // namespace ControlStruct
Note: See TracChangeset for help on using the changeset viewer.