Changeset 553f032f
- Timestamp:
- Sep 8, 2023, 5:15:41 PM (18 months ago)
- Branches:
- master
- Children:
- 5cfb8b1
- Parents:
- 2fa0237
- Files:
-
- 1 added
- 1 deleted
- 1 edited
- 1 moved
Legend:
- Unmodified
- Added
- Removed
-
TabularUnified src/ControlStruct/MultiLevelExit.cpp ¶
r2fa0237 r553f032f 10 10 // Created On : Mon Nov 1 13:48:00 2021 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Wed Sep 6 12:00:00 202313 // Update Count : 3 512 // Last Modified On : Fri Sep 8 17:04:00 2023 13 // Update Count : 36 14 14 // 15 15 … … 27 27 28 28 namespace { 29 30 /// The return context is used to remember if returns are allowed and if 31 /// not, why not. It is the nearest local control flow blocking construct. 32 enum ReturnContext { 33 MayReturn, 34 InTryWithHandler, 35 InResumeHandler, 36 InTerminateHandler, 37 InFinally, 38 }; 29 39 30 40 class Entry { … … 126 136 void previsit( const TryStmt * ); 127 137 void postvisit( const TryStmt * ); 138 void previsit( const CatchClause * ); 128 139 void previsit( const FinallyClause * ); 129 140 … … 134 145 vector<Entry> enclosing_control_structures; 135 146 Label break_label; 136 bool inFinally;147 ReturnContext ret_context; 137 148 138 149 template<typename LoopNode> … … 144 155 const list<ptr<Stmt>> & kids, bool caseClause ); 145 156 157 void enterSealedContext( ReturnContext ); 158 146 159 template<typename UnaryPredicate> 147 160 auto findEnclosingControlStructure( UnaryPredicate pred ) { … … 157 170 MultiLevelExitCore::MultiLevelExitCore( const LabelToStmt & lt ) : 158 171 target_table( lt ), break_label( CodeLocation(), "" ), 159 inFinally( false)172 ret_context( ReturnContext::MayReturn ) 160 173 {} 161 174 … … 488 501 489 502 void MultiLevelExitCore::previsit( const ReturnStmt * stmt ) { 490 if ( inFinally ) { 491 SemanticError( stmt->location, "'return' may not appear in a finally clause" ); 492 } 503 char const * context; 504 switch ( ret_context ) { 505 case ReturnContext::MayReturn: 506 return; 507 case ReturnContext::InTryWithHandler: 508 context = "try statement with a catch clause"; 509 break; 510 case ReturnContext::InResumeHandler: 511 context = "catchResume clause"; 512 break; 513 case ReturnContext::InTerminateHandler: 514 context = "catch clause"; 515 break; 516 case ReturnContext::InFinally: 517 context = "finally clause"; 518 break; 519 default: 520 assert(0); 521 } 522 SemanticError( stmt->location, toString( "'return' may not appear in a ", context ) ); 493 523 } 494 524 … … 500 530 GuardAction([this](){ enclosing_control_structures.pop_back(); } ); 501 531 } 532 533 // Try statements/try blocks are only sealed with a termination handler. 534 for ( auto clause : stmt->handlers ) { 535 if ( ast::Terminate == clause->kind ) { 536 return enterSealedContext( ReturnContext::InTryWithHandler ); 537 } 538 } 502 539 } 503 540 … … 512 549 } 513 550 551 void MultiLevelExitCore::previsit( const CatchClause * clause ) { 552 ReturnContext context = ( ast::Terminate == clause->kind ) 553 ? ReturnContext::InTerminateHandler : ReturnContext::InResumeHandler; 554 enterSealedContext( context ); 555 } 556 514 557 void MultiLevelExitCore::previsit( const FinallyClause * ) { 515 GuardAction([this, old = std::move( enclosing_control_structures)](){ enclosing_control_structures = std::move(old); }); 516 enclosing_control_structures = vector<Entry>(); 517 GuardValue( inFinally ) = true; 558 enterSealedContext( ReturnContext::InFinally ); 518 559 } 519 560 … … 617 658 } 618 659 660 void MultiLevelExitCore::enterSealedContext( ReturnContext enter_context ) { 661 GuardAction([this, old = std::move(enclosing_control_structures)](){ enclosing_control_structures = std::move(old); }); 662 enclosing_control_structures = vector<Entry>(); 663 GuardValue( ret_context ) = enter_context; 664 } 665 619 666 } // namespace 620 667 -
TabularUnified tests/exceptions/try-ctrl-flow.cfa ¶
r2fa0237 r553f032f 1 // All of these should be caught as long as the check remains in the same2 // pass. (Although not even all of the checks are in place yet.)1 // Check all the local control flow structures that are "sealed" by some the 2 // try statement clauses; where structured programming is stricter. 3 3 4 4 void break_in_finally() { … … 151 151 } 152 152 153 // Now just use return to test the other try control flow interactions. 154 155 exception nil_exception {}; 156 157 void return_in_try_with_catch() { 158 try { 159 return; 160 } catch (nil_exception *) { 161 ; 162 } 163 } 164 165 // Allowed. 166 void return_in_try_with_catchReturn() { 167 try { 168 return; 169 } catchResume (nil_exception *) { 170 ; 171 } 172 } 173 174 // Allowed. 175 void return_in_try_with_finally() { 176 try { 177 return; 178 } finally { 179 ; 180 } 181 } 182 183 void return_in_catch() { 184 try { 185 ; 186 } catch (nil_exception *) { 187 return; 188 } 189 } 190 191 void return_in_catchResume() { 192 try { 193 ; 194 } catchResume (nil_exception *) { 195 return; 196 } 197 } 198 153 199 void main() { 154 200 // Should not compile.
Note: See TracChangeset
for help on using the changeset viewer.