Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision 4a40fca7195d07e090f940cfac3fc4e3c345c052)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision c58ead7c304c33bc8c33d1ca270fffcfa955ec02)
@@ -10,6 +10,6 @@
 // Created On       : Mon Nov  1 13:48:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Sep  6 12:00:00 2023
-// Update Count     : 35
+// Last Modified On : Fri Sep  8 17:04:00 2023
+// Update Count     : 36
 //
 
@@ -27,4 +27,14 @@
 
 namespace {
+
+/// The return context is used to remember if returns are allowed and if
+/// not, why not. It is the nearest local control flow blocking construct.
+enum ReturnContext {
+	MayReturn,
+	InTryWithHandler,
+	InResumeHandler,
+	InTerminateHandler,
+	InFinally,
+};
 
 class Entry {
@@ -126,4 +136,5 @@
 	void previsit( const TryStmt * );
 	void postvisit( const TryStmt * );
+	void previsit( const CatchClause * );
 	void previsit( const FinallyClause * );
 
@@ -134,5 +145,5 @@
 	vector<Entry> enclosing_control_structures;
 	Label break_label;
-	bool inFinally;
+	ReturnContext ret_context;
 
 	template<typename LoopNode>
@@ -144,4 +155,6 @@
 		const list<ptr<Stmt>> & kids, bool caseClause );
 
+	void enterSealedContext( ReturnContext );
+
 	template<typename UnaryPredicate>
 	auto findEnclosingControlStructure( UnaryPredicate pred ) {
@@ -157,5 +170,5 @@
 MultiLevelExitCore::MultiLevelExitCore( const LabelToStmt & lt ) :
 	target_table( lt ), break_label( CodeLocation(), "" ),
-	inFinally( false )
+	ret_context( ReturnContext::MayReturn )
 {}
 
@@ -488,7 +501,24 @@
 
 void MultiLevelExitCore::previsit( const ReturnStmt * stmt ) {
-	if ( inFinally ) {
-		SemanticError( stmt->location, "'return' may not appear in a finally clause" );
-	}
+	char const * context;
+	switch ( ret_context ) {
+	case ReturnContext::MayReturn:
+		return;
+	case ReturnContext::InTryWithHandler:
+		context = "try statement with a catch clause";
+		break;
+	case ReturnContext::InResumeHandler:
+		context = "catchResume clause";
+		break;
+	case ReturnContext::InTerminateHandler:
+		context = "catch clause";
+		break;
+	case ReturnContext::InFinally:
+		context = "finally clause";
+		break;
+	default:
+		assert(0);
+	}
+	SemanticError( stmt->location, toString( "'return' may not appear in a ", context ) );
 }
 
@@ -500,4 +530,11 @@
 		GuardAction([this](){ enclosing_control_structures.pop_back(); } );
 	}
+
+	// Try statements/try blocks are only sealed with a termination handler.
+	for ( auto clause : stmt->handlers ) {
+		if ( ast::Terminate == clause->kind ) {
+			return enterSealedContext( ReturnContext::InTryWithHandler );
+		}
+	}
 }
 
@@ -512,8 +549,12 @@
 }
 
+void MultiLevelExitCore::previsit( const CatchClause * clause ) {
+	ReturnContext context = ( ast::Terminate == clause->kind )
+		? ReturnContext::InTerminateHandler : ReturnContext::InResumeHandler;
+	enterSealedContext( context );
+}
+
 void MultiLevelExitCore::previsit( const FinallyClause * ) {
-	GuardAction([this, old = std::move( enclosing_control_structures)](){ enclosing_control_structures = std::move(old); });
-	enclosing_control_structures = vector<Entry>();
-	GuardValue( inFinally ) = true;
+	enterSealedContext( ReturnContext::InFinally );
 }
 
@@ -617,4 +658,10 @@
 }
 
+void MultiLevelExitCore::enterSealedContext( ReturnContext enter_context ) {
+	GuardAction([this, old = std::move(enclosing_control_structures)](){ enclosing_control_structures = std::move(old); });
+	enclosing_control_structures = vector<Entry>();
+	GuardValue( ret_context ) = enter_context;
+}
+
 } // namespace
 
