- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/ControlStruct/MultiLevelExit.cpp
r2f52b18 r3b0bc16 10 10 // Created On : Mon Nov 1 13:48:00 2021 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Wed Feb 2 23:07:54202213 // Update Count : 3312 // Last Modified On : Tue Feb 1 18:48:47 2022 13 // Update Count : 29 14 14 // 15 15 … … 49 49 return target.label; 50 50 } 51 51 52 public: 52 53 Entry( const ForStmt * stmt, Label breakExit, Label contExit ) : … … 167 168 168 169 // if the stmt is labelled then generate a label to check in postvisit if the label is used 169 bool isLabeled = ! 170 bool isLabeled = !stmt->labels.empty(); 170 171 if ( isLabeled ) { 171 172 Label breakLabel = newLabel( "blockBreak", stmt ); … … 179 180 180 181 if ( isLabeled ) { 181 assert( ! 182 assert( !enclosing_control_structures.empty() ); 182 183 Entry & entry = enclosing_control_structures.back(); 183 if ( ! 184 if ( !entry.useBreakExit().empty() ) { 184 185 break_label = entry.useBreakExit(); 185 186 } … … 205 206 } 206 207 } 207 assertf( false, "C FA internal error: could not find label '%s' on statement %s",208 assertf( false, "Could not find label '%s' on statement %s", 208 209 originalTarget.name.c_str(), toString( stmt ).c_str() ); 209 210 } … … 253 254 } 254 255 // Ensure that selected target is valid. 255 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && ! 256 if ( targetEntry == enclosing_control_structures.rend() || ( isContinue && !isContinueTarget( *targetEntry ) ) ) { 256 257 SemanticError( stmt->location, toString( (isContinue ? "'continue'" : "'break'"), 257 258 " target must be an enclosing ", (isContinue ? "loop: " : "control structure: "), … … 267 268 SemanticError( stmt->location, "'fallthrough' must be enclosed in a 'switch' or 'choose'" ); 268 269 } 269 if ( ! 270 if ( !stmt->target.empty() ) { 270 271 // Labelled fallthrough: target must be a valid fallthough label. 271 if ( ! 272 if ( !fallthrough_labels.count( stmt->target ) ) { 272 273 SemanticError( stmt->location, toString( "'fallthrough' target must be a later case statement: ", 273 274 stmt->originalTarget ) ); 274 275 } 275 return new BranchStmt( stmt->location, BranchStmt::Goto, stmt->originalTarget ); 276 return new BranchStmt( 277 stmt->location, BranchStmt::Goto, stmt->originalTarget ); 276 278 } 277 279 break; … … 305 307 } 306 308 307 // Branch error checks: get the appropriate label name, which is always replaced. 309 // Branch error checks: get the appropriate label name: 310 // (This label is always replaced.) 308 311 Label exitLabel( CodeLocation(), "" ); 309 312 switch ( stmt->kind ) { 310 313 case BranchStmt::Break: 311 assert( ! 314 assert( !targetEntry->useBreakExit().empty() ); 312 315 exitLabel = targetEntry->useBreakExit(); 313 316 break; 314 317 case BranchStmt::Continue: 315 assert( ! 318 assert( !targetEntry->useContExit().empty() ); 316 319 exitLabel = targetEntry->useContExit(); 317 320 break; 318 321 case BranchStmt::FallThrough: 319 assert( ! 322 assert( !targetEntry->useFallExit().empty() ); 320 323 exitLabel = targetEntry->useFallExit(); 321 324 break; 322 325 case BranchStmt::FallThroughDefault: 323 assert( ! 326 assert( !targetEntry->useFallDefaultExit().empty() ); 324 327 exitLabel = targetEntry->useFallDefaultExit(); 325 328 // Check that fallthrough default comes before the default clause. 326 if ( ! 329 if ( !targetEntry->isFallDefaultValid() ) { 327 330 SemanticError( stmt->location, "'fallthrough default' must precede the 'default' clause" ); 328 331 } … … 370 373 // If default, mark seen. 371 374 if ( stmt->isDefault() ) { 372 assert( ! 375 assert( !enclosing_control_structures.empty() ); 373 376 enclosing_control_structures.back().seenDefault(); 374 377 } … … 396 399 Entry & entry = enclosing_control_structures.back(); 397 400 if ( entry.isFallUsed() ) { 398 mutStmt->stmts.push_back( labelledNullStmt( mutStmt->location, entry.useFallExit() ) ); 401 mutStmt->stmts.push_back( 402 labelledNullStmt( mutStmt->location, entry.useFallExit() ) ); 399 403 } 400 404 } … … 402 406 Entry & entry = enclosing_control_structures.back(); 403 407 assertf( dynamic_cast< const SwitchStmt * >( entry.stmt ), 404 "C FA internal error: control structure enclosing a case clause must be a switch, but is: %s",408 "Control structure enclosing a case clause must be a switch, but is: %s", 405 409 toString( entry.stmt ).c_str() ); 406 410 if ( mutStmt->isDefault() ) { 407 411 if ( entry.isFallDefaultUsed() ) { 408 412 // Add fallthrough default label if necessary. 409 push_front( mutStmt->stmts, labelledNullStmt( stmt->location, entry.useFallDefaultExit() ) ); 413 push_front( mutStmt->stmts, labelledNullStmt( 414 stmt->location, entry.useFallDefaultExit() 415 ) ); 410 416 } 411 417 } … … 414 420 415 421 void MultiLevelExitCore::previsit( const IfStmt * stmt ) { 416 bool labeledBlock = ! 422 bool labeledBlock = !stmt->labels.empty(); 417 423 if ( labeledBlock ) { 418 424 Label breakLabel = newLabel( "blockBreak", stmt ); … … 423 429 424 430 const IfStmt * MultiLevelExitCore::postvisit( const IfStmt * stmt ) { 425 bool labeledBlock = ! 431 bool labeledBlock = !stmt->labels.empty(); 426 432 if ( labeledBlock ) { 427 433 auto this_label = enclosing_control_structures.back().useBreakExit(); 428 if ( ! 434 if ( !this_label.empty() ) { 429 435 break_label = this_label; 430 436 } … … 442 448 auto it = find_if( stmt->stmts.rbegin(), stmt->stmts.rend(), isDefaultCase ); 443 449 444 const CaseStmt * defaultCase = it != stmt->stmts.rend() ? (it)->strict_as<CaseStmt>() : nullptr; 445 Label defaultLabel = defaultCase ? newLabel( "fallThroughDefault", defaultCase ) : Label( stmt->location, "" ); 450 const CaseStmt * defaultCase = it != stmt->stmts.rend() 451 ? (it)->strict_as<CaseStmt>() : nullptr; 452 Label defaultLabel = defaultCase 453 ? newLabel( "fallThroughDefault", defaultCase ) 454 : Label( stmt->location, "" ); 446 455 enclosing_control_structures.emplace_back( stmt, label, defaultLabel ); 447 456 GuardAction( [this]() { enclosing_control_structures.pop_back(); } ); 448 457 449 // Collect valid labels for fallthrough. It starts with all labels at this level, then remove as each is seen during450 // t raversal.458 // Collect valid labels for fallthrough. It starts with all labels at 459 // this level, then remove as each is seen during traversal. 451 460 for ( const Stmt * stmt : stmt->stmts ) { 452 461 auto * caseStmt = strict_dynamic_cast< const CaseStmt * >( stmt ); … … 462 471 463 472 const SwitchStmt * MultiLevelExitCore::postvisit( const SwitchStmt * stmt ) { 464 assert( ! 473 assert( !enclosing_control_structures.empty() ); 465 474 Entry & entry = enclosing_control_structures.back(); 466 475 assert( entry.stmt == stmt ); … … 468 477 // Only run to generate the break label. 469 478 if ( entry.isBreakUsed() ) { 470 // To keep the switch statements uniform (all direct children of a SwitchStmt should be CastStmts), append the 471 // exit label and break to the last case, create a default case if no cases. 479 // To keep the switch statements uniform (all direct children of a 480 // SwitchStmt should be CastStmts), append the exit label and break 481 // to the last case, create a default case is there are no cases. 472 482 SwitchStmt * mutStmt = mutate( stmt ); 473 483 if ( mutStmt->stmts.empty() ) { 474 mutStmt->stmts.push_back( new CaseStmt( mutStmt->location, nullptr, {} ) ); 484 mutStmt->stmts.push_back( new CaseStmt( 485 mutStmt->location, nullptr, {} )); 475 486 } 476 487 … … 496 507 497 508 void MultiLevelExitCore::previsit( const TryStmt * stmt ) { 498 bool isLabeled = ! 509 bool isLabeled = !stmt->labels.empty(); 499 510 if ( isLabeled ) { 500 511 Label breakLabel = newLabel( "blockBreak", stmt ); … … 505 516 506 517 void MultiLevelExitCore::postvisit( const TryStmt * stmt ) { 507 bool isLabeled = ! 518 bool isLabeled = !stmt->labels.empty(); 508 519 if ( isLabeled ) { 509 520 auto this_label = enclosing_control_structures.back().useBreakExit(); 510 if ( ! 521 if ( !this_label.empty() ) { 511 522 break_label = this_label; 512 523 } … … 515 526 516 527 void MultiLevelExitCore::previsit( const FinallyStmt * ) { 517 GuardAction([this, old = move( enclosing_control_structures)](){ enclosing_control_structures = move(old); }); 528 GuardAction([this, old = move(enclosing_control_structures)](){ 529 enclosing_control_structures = move(old); 530 }); 518 531 enclosing_control_structures = vector<Entry>(); 519 532 GuardValue( inFinally ) = true; … … 562 575 template<typename LoopNode> 563 576 const LoopNode * MultiLevelExitCore::posthandleLoopStmt( const LoopNode * loopStmt ) { 564 assert( ! 577 assert( !enclosing_control_structures.empty() ); 565 578 Entry & entry = enclosing_control_structures.back(); 566 579 assert( entry.stmt == loopStmt ); 567 580 568 581 // Now check if the labels are used and add them if so. 569 return mutate_field( loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) ); 582 return mutate_field( 583 loopStmt, &LoopNode::body, mutateLoop( loopStmt->body, entry ) ); 570 584 // this call to mutate_field compares loopStmt->body and the result of mutateLoop 571 585 // if they are the same the node isn't mutated, if they differ then the new mutated node is returned … … 595 609 } 596 610 597 if ( ! break_label.empty() ) { 598 ret.push_back( labelledNullStmt( ret.back()->location, break_label ) ); 611 if ( !break_label.empty() ) { 612 ret.push_back( 613 labelledNullStmt( ret.back()->location, break_label ) ); 599 614 break_label = Label( CodeLocation(), "" ); 600 615 } 601 616 } 602 617 603 if ( ! 618 if ( !errors.isEmpty() ) { 604 619 throw errors; 605 620 }
Note:
See TracChangeset
for help on using the changeset viewer.