Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/ControlStruct/MultiLevelExit.cpp

    r491bb81 rf75e25b  
    1818#include "AST/Pass.hpp"
    1919#include "AST/Stmt.hpp"
    20 #include "Common/CodeLocationTools.hpp"
    2120#include "LabelGeneratorNew.hpp"
    2221
     
    229228        // Labels on different stmts require different approaches to access
    230229        switch ( stmt->kind ) {
    231         case BranchStmt::Goto:
     230          case BranchStmt::Goto:
    232231                return stmt;
    233         case BranchStmt::Continue:
    234         case BranchStmt::Break: {
    235                 bool isContinue = stmt->kind == BranchStmt::Continue;
    236                 // Handle unlabeled break and continue.
    237                 if ( stmt->target.empty() ) {
    238                         if ( isContinue ) {
    239                                 targetEntry = findEnclosingControlStructure( isContinueTarget );
    240                         } else {
    241                                 if ( enclosing_control_structures.empty() ) {
     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() ) {
    242241                                          SemanticError( stmt->location,
    243242                                                                         "'break' outside a loop, 'switch', or labelled block" );
    244                                 }
    245                                 targetEntry = findEnclosingControlStructure( isBreakTarget );
    246                         }
    247                         // Handle labeled break and continue.
    248                 } else {
    249                         // Lookup label in table to find attached control structure.
    250                         targetEntry = findEnclosingControlStructure(
    251                                 [ targetStmt = target_table.at(stmt->target) ](auto entry){
     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){
    252251                                          return entry.stmt == targetStmt;
    253                                 } );
    254                 }
    255                 // Ensure that selected target is valid.
    256                 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! isContinueTarget( *targetEntry ) ) ) {
    257                         SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"),
     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'"),
    258257                                                        " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "),
    259258                                                        stmt->originalTarget ) );
    260                 }
    261                 break;
    262         }
    263         // handle fallthrough in case/switch stmts
    264         case BranchStmt::FallThrough: {
    265                 targetEntry = findEnclosingControlStructure( isFallthroughTarget );
    266                 // Check that target is valid.
    267                 if ( targetEntry == enclosing_control_structures.rend() ) {
    268                         SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    269                 }
    270                 if ( ! stmt->target.empty() ) {
    271                         // Labelled fallthrough: target must be a valid fallthough label.
    272                         if ( ! fallthrough_labels.count( stmt->target ) ) {
    273                                 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ",
     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: ",
    274273                                                                                                                   stmt->originalTarget ) );
    275                         }
    276                         return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget );
    277                 }
    278                 break;
    279         }
    280         case BranchStmt::FallThroughDefault: {
    281                 targetEntry = findEnclosingControlStructure( isFallthroughDefaultTarget );
    282 
    283                 // Check if in switch or choose statement.
    284                 if ( targetEntry == enclosing_control_structures.rend() ) {
    285                         SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" );
    286                 }
    287 
    288                 // Check if switch or choose has default clause.
    289                 auto switchStmt = strict_dynamic_cast< const SwitchStmt * >( targetEntry->stmt );
    290                 bool foundDefault = false;
    291                 for ( auto caseStmt : switchStmt->cases ) {
    292                         if ( caseStmt->isDefault() ) {
    293                                 foundDefault = true;
    294                                 break;
    295                         }
    296                 }
    297                 if ( ! foundDefault ) {
    298                         SemanticError( stmt->location, "'fallthrough default' must be enclosed in a 'switch' or 'choose'"
    299                                                   "control structure with a 'default' clause" );
    300                 }
    301                 break;
    302         }
    303         default:
     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:
    304303                assert( false );
    305304        }
     
    308307        Label exitLabel( CodeLocation(), "" );
    309308        switch ( stmt->kind ) {
    310         case BranchStmt::Break:
     309          case BranchStmt::Break:
    311310                assert( ! targetEntry->useBreakExit().empty() );
    312311                exitLabel = targetEntry->useBreakExit();
    313312                break;
    314         case BranchStmt::Continue:
     313          case BranchStmt::Continue:
    315314                assert( ! targetEntry->useContExit().empty() );
    316315                exitLabel = targetEntry->useContExit();
    317316                break;
    318         case BranchStmt::FallThrough:
     317          case BranchStmt::FallThrough:
    319318                assert( ! targetEntry->useFallExit().empty() );
    320319                exitLabel = targetEntry->useFallExit();
    321320                break;
    322         case BranchStmt::FallThroughDefault:
     321          case BranchStmt::FallThroughDefault:
    323322                assert( ! targetEntry->useFallDefaultExit().empty() );
    324323                exitLabel = targetEntry->useFallDefaultExit();
     
    328327                }
    329328                break;
    330         default:
     329          default:
    331330                assert(0);
    332331        }
     
    589588                }
    590589
     590                ptr<Stmt> else_stmt = nullptr;
     591                Stmt * loop_kid = nullptr;
     592                // 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_) {
     595                        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_) {
     602                        else_stmt = forPtr->else_;
     603                        ForStmt * mutate_ptr = mutate(forPtr);
     604                        mutate_ptr->else_ = nullptr;
     605                        loop_kid = mutate_ptr;
     606                }
     607
    591608                try {
    592                         ret.push_back( kid->accept( *visitor ) );
     609                        if (else_stmt) ret.push_back( loop_kid->accept( *visitor ) );
     610                        else ret.push_back( kid->accept( *visitor ) );
    593611                } catch ( SemanticErrorException & e ) {
    594612                        errors.append( e );
    595613                }
    596614
    597                 // check if loop node and if so add else clause if it exists
    598                 const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());
    599                 if ( whilePtr && whilePtr->else_) ret.push_back(whilePtr->else_);
    600                 const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());
    601                 if ( forPtr && forPtr->else_) ret.push_back(forPtr->else_);
     615                if (else_stmt) ret.push_back(else_stmt);
    602616
    603617                if ( ! break_label.empty() ) {
     
    619633        Pass<MultiLevelExitCore> visitor( labelTable );
    620634        const CompoundStmt * ret = stmt->accept( visitor );
    621         // There are some unset code locations slipping in, possibly by Labels.
    622         const Node * node = localFillCodeLocations( ret->location, ret );
    623         return strict_dynamic_cast<const CompoundStmt *>( node );
     635        return ret;
    624636}
    625637} // namespace ControlStruct
Note: See TracChangeset for help on using the changeset viewer.