Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -121,4 +121,7 @@
 	last = 0p;
 	cancellation = 0p;
+    ehm_state.ehm_buffer{};
+    ehm_state.buffer_lock{};
+    ehm_state.ehm_enabled = false;
 }
 
@@ -283,4 +286,56 @@
 }
 
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// non local ehm routines
+
+// helper for popping from coroutine's ehm buffer
+inline nonlocal_exception * pop_ehm_head( coroutine$ * this ) {
+    lock( this->ehm_state.buffer_lock __cfaabi_dbg_ctx2 );
+    nonlocal_exception * nl_ex = pop_head( this->ehm_state.ehm_buffer );
+    unlock( this->ehm_state.buffer_lock );
+    return nl_ex;
+}
+
+// user facing ehm operations
+forall(T & | is_coroutine(T)) {
+    // enable/disable non-local exceptions
+    void enable_ehm( T & cor ) libcfa_public { get_coroutine( cor )->ehm_state.ehm_enabled = true; }
+    void disable_ehm( T & cor ) libcfa_public { get_coroutine( cor )->ehm_state.ehm_enabled = false; }
+
+    // poll for non-local exceptions
+    bool poll( T & cor ) libcfa_public {
+        coroutine$ * base_cor = get_coroutine( cor );
+        nonlocal_exception * nl_ex = pop_ehm_head( base_cor );
+
+        // if no exceptions return false
+        if ( nl_ex == 0p ) return false;
+        
+        // otherwise loop and throwResume all pending exceptions
+        while ( nl_ex != 0p ){
+            exception_t * ex = nl_ex->the_exception;
+            free( nl_ex );
+            throwResume *ex;
+            nl_ex = pop_ehm_head( base_cor );
+        }
+        
+        return true;
+    }
+
+    // poll iff nonlocal ehm is enabled
+    bool checked_poll( T & cor ) libcfa_public { return get_coroutine( cor )->ehm_state.ehm_enabled ? poll( cor ) : false; }
+}
+
+// resume non local exception at receiver (i.e. enqueue in ehm buffer)
+forall(exceptT &, T & | ehm_resume_at( exceptT, T ))
+void resumeAt( T & receiver, exceptT & ex )  libcfa_public {
+    coroutine$ * cor = get_coroutine( receiver );
+    nonlocal_exception * nl_ex = alloc();
+    (*nl_ex){ (exception_t *)&ex };
+    lock( cor->ehm_state.buffer_lock __cfaabi_dbg_ctx2 );
+    append( cor->ehm_state.ehm_buffer, nl_ex ); 
+    unlock( cor->ehm_state.buffer_lock );
+}
+
 // Local Variables: //
 // mode: c //
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -19,4 +19,19 @@
 #include "invoke.h"
 #include "../exception.hfa"
+
+//-----------------------------------------------------------------------------
+// Type used to store and queue nonlocal exceptions on coroutines
+struct nonlocal_exception {
+    exception_t * the_exception;
+    nonlocal_exception * next;
+};
+static inline void ?{} ( nonlocal_exception & this, exception_t * ex ) with(this) {
+    the_exception = ex;
+    next = 0p;
+}
+
+static inline nonlocal_exception *& get_next( nonlocal_exception & this ) __attribute__((const)) {
+    return this.next;
+}
 
 //-----------------------------------------------------------------------------
@@ -203,4 +218,19 @@
 }
 
+// non local ehm routines
+forall(T & | is_coroutine(T)) {
+    void enable_ehm( T & cor );
+    void disable_ehm( T & cor );
+    bool poll( T & cor );
+    bool checked_poll( T & cor );
+}
+
+// trait for exceptions able to be resumed at another coroutine
+forall(exceptT &, T & | is_coroutine(T))
+trait ehm_resume_at { void $throwResume(exceptT &); };
+
+forall(exceptT &, T & | ehm_resume_at( exceptT, T ))
+void resumeAt( T & receiver, exceptT & ex );
+
 // Local Variables: //
 // mode: c //
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ libcfa/src/concurrency/invoke.h	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -74,4 +74,15 @@
 	};
 
+    struct nonlocal_ehm {
+        // list of pending nonlocal exceptions
+        __queue_t(struct nonlocal_exception) ehm_buffer;
+
+        // lock to protect the buffer
+        struct __spinlock_t buffer_lock;
+
+        // enable/disabled flag
+        bool ehm_enabled;
+    };
+
 	enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled, Halting };
 
@@ -98,4 +109,6 @@
 		struct _Unwind_Exception * cancellation;
 
+        // Non-local exception handling information
+        struct nonlocal_ehm ehm_state;
 	};
 	// Wrapper for gdb
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/AST/Decl.hpp	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -69,5 +69,4 @@
 public:
 	/// Represents the type with all types and typedefs expanded.
-	/// This field is generated by SymTab::Validate::Pass2
 	std::string mangleName;
 	/// Stores the scope level at which the variable was declared.
Index: src/AST/SymbolTable.cpp
===================================================================
--- src/AST/SymbolTable.cpp	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/AST/SymbolTable.cpp	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -19,7 +19,4 @@
 
 #include "Copy.hpp"
-#include <iostream>
-#include <algorithm>
-
 #include "Decl.hpp"
 #include "Expr.hpp"
@@ -206,6 +203,4 @@
 			out.push_back(decl.second);
 		}
-
-		// std::cerr << otypeKey << ' ' << out.size() << std::endl;
 	}
 
Index: src/GenPoly/SpecializeNew.cpp
===================================================================
--- src/GenPoly/SpecializeNew.cpp	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/GenPoly/SpecializeNew.cpp	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -104,5 +104,5 @@
 
 bool needsPolySpecialization(
-		const ast::Type * formalType,
+		const ast::Type * /*formalType*/,
 		const ast::Type * actualType,
 		const ast::TypeSubstitution * subs ) {
@@ -126,6 +126,5 @@
 			if ( closedVars.find( *inst ) == closedVars.end() ) {
 				return true;
-			}
-			else {
+			} else {
 				assertf(false, "closed: %s", inst->name.c_str());
 			}
Index: src/InitTweak/FixInitNew.cpp
===================================================================
--- src/InitTweak/FixInitNew.cpp	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/InitTweak/FixInitNew.cpp	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -22,7 +22,5 @@
 #include "AST/SymbolTable.hpp"
 #include "AST/Type.hpp"
-#include "CodeGen/GenType.h"           // for genPrettyType
-#include "CodeGen/OperatorTable.h"
-#include "Common/PassVisitor.h"        // for PassVisitor, WithStmtsToAdd
+#include "CodeGen/OperatorTable.h"     // for isConstructor, isCtorDtor, isD...
 #include "Common/SemanticError.h"      // for SemanticError
 #include "Common/ToString.hpp"         // for toCString
@@ -33,22 +31,5 @@
 #include "ResolvExpr/Resolver.h"       // for findVoidExpression
 #include "ResolvExpr/Unify.h"          // for typesCompatible
-#include "SymTab/Autogen.h"            // for genImplicitCall
 #include "SymTab/GenImplicitCall.hpp"  // for genImplicitCall
-#include "SymTab/Indexer.h"            // for Indexer
-#include "SymTab/Mangler.h"            // for Mangler
-#include "SynTree/LinkageSpec.h"       // for C, Spec, Cforall, isBuiltin
-#include "SynTree/Attribute.h"         // for Attribute
-#include "SynTree/Constant.h"          // for Constant
-#include "SynTree/Declaration.h"       // for ObjectDecl, FunctionDecl, Decl...
-#include "SynTree/Expression.h"        // for UniqueExpr, VariableExpr, Unty...
-#include "SynTree/Initializer.h"       // for ConstructorInit, SingleInit
-#include "SynTree/Label.h"             // for Label, operator<
-#include "SynTree/Mutator.h"           // for mutateAll, Mutator, maybeMutate
-#include "SynTree/Statement.h"         // for ExprStmt, CompoundStmt, Branch...
-#include "SynTree/Type.h"              // for Type, Type::StorageClasses
-#include "SynTree/TypeSubstitution.h"  // for TypeSubstitution, operator<<
-#include "SynTree/DeclReplacer.h"      // for DeclReplacer
-#include "SynTree/Visitor.h"           // for acceptAll, maybeAccept
-#include "Validate/FindSpecialDecls.h" // for dtorStmt, dtorStructDestroy
 
 extern bool ctordtorp; // print all debug
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/ResolvExpr/CommonType.cc	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -696,17 +696,4 @@
 		void postvisit( const ast::BasicType * basic ) {
 			if ( auto basic2 = dynamic_cast< const ast::BasicType * >( type2 ) ) {
-				#warning remove casts when `commonTypes` moved to new AST
-				
-				/*
-				ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)basic2->kind ];
-				if (
-					( ( kind == basic->kind && basic->qualifiers >= basic2->qualifiers )
-						|| widen.first )
-					&& ( ( kind == basic2->kind && basic->qualifiers <= basic2->qualifiers )
-						|| widen.second )
-				) {
-					result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
-				}
-				*/
 				ast::BasicType::Kind kind;
 				if (basic->kind != basic2->kind && !widen.first && !widen.second) return;
@@ -719,28 +706,17 @@
 					result = new ast::BasicType{ kind, basic->qualifiers | basic2->qualifiers };
 				}
-				
 			} else if (
 				dynamic_cast< const ast::ZeroType * >( type2 )
 				|| dynamic_cast< const ast::OneType * >( type2 )
 			) {
-				#warning remove casts when `commonTypes` moved to new AST
-				ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
-				/*
-				if ( // xxx - what does qualifier even do here??
-					( ( basic->qualifiers >= type2->qualifiers )
-						|| widen.first )
-					 && ( ( /* kind != basic->kind && basic->qualifiers <= type2->qualifiers )
-						|| widen.second )
-				) 
-				*/
 				if (widen.second) {
 					result = new ast::BasicType{ basic->kind, basic->qualifiers | type2->qualifiers };
 				}
 			} else if ( const ast::EnumInstType * enumInst = dynamic_cast< const ast::EnumInstType * >( type2 ) ) {
-				#warning remove casts when `commonTypes` moved to new AST
 				const ast::EnumDecl* enumDecl = enumInst->base;
 				if ( enumDecl->base ) {
 					result = enumDecl->base.get();
 				} else {
+					#warning remove casts when `commonTypes` moved to new AST
 					ast::BasicType::Kind kind = (ast::BasicType::Kind)(int)commonTypes[ (BasicType::Kind)(int)basic->kind ][ (BasicType::Kind)(int)ast::BasicType::SignedInt ];
 					if (
@@ -763,5 +739,4 @@
 				auto entry = open.find( *var );
 				if ( entry != open.end() ) {
-				// if (tenv.lookup(*var)) {
 					ast::AssertionSet need, have;
 					if ( ! tenv.bindVar(
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/ResolvExpr/Unify.cc	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -1298,23 +1298,7 @@
 		auto var1 = dynamic_cast< const ast::TypeInstType * >( type1 );
 		auto var2 = dynamic_cast< const ast::TypeInstType * >( type2 );
-		ast::OpenVarSet::const_iterator
-			entry1 = var1 ? open.find( *var1 ) : open.end(),
-			entry2 = var2 ? open.find( *var2 ) : open.end();
-		// bool isopen1 = entry1 != open.end();
-		// bool isopen2 = entry2 != open.end();
 		bool isopen1 = var1 && env.lookup(*var1);
 		bool isopen2 = var2 && env.lookup(*var2);
 
-		/*
-		if ( isopen1 && isopen2 ) {
-			if ( entry1->second.kind != entry2->second.kind ) return false;
-			return env.bindVarToVar(
-				var1, var2, ast::TypeData{ entry1->second, entry2->second }, need, have,
-				open, widen );
-		} else if ( isopen1 ) {
-			return env.bindVar( var1, type2, entry1->second, need, have, open, widen );
-		} else if ( isopen2 ) {
-			return env.bindVar( var2, type1, entry2->second, need, have, open, widen, symtab );
-		} */
 		if ( isopen1 && isopen2 ) {
 			if ( var1->base->kind != var2->base->kind ) return false;
@@ -1326,9 +1310,8 @@
 		} else if ( isopen2 ) {
 			return env.bindVar( var2, type1, ast::TypeData{var2->base}, need, have, open, widen );
-		}else {
+		} else {
 			return ast::Pass<Unify_new>::read(
 				type1, type2, env, need, have, open, widen );
 		}
-		
 	}
 
Index: src/Validate/LinkReferenceToTypes.cpp
===================================================================
--- src/Validate/LinkReferenceToTypes.cpp	(revision e6e1a1206cdd5defb28fcd401966d2d7b93b358d)
+++ src/Validate/LinkReferenceToTypes.cpp	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -80,51 +80,42 @@
 ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
 	ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
+	ast::EnumInstType * mut = ast::mutate( type );
 	// It's not a semantic error if the enum is not found, just an implicit forward declaration.
 	if ( decl ) {
 		// Just linking in the node.
-		auto mut = ast::mutate( type );
 		mut->base = decl;
-		type = mut;
 	}
 	if ( !decl || !decl->body ) {
-		auto mut = ast::mutate( type );
 		forwardEnums[ mut->name ].push_back( mut );
-		type = mut;
-	}
-	return type;
+	}
+	return mut;
 }
 
 ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
 	ast::StructDecl const * decl = symtab.lookupStruct( type->name );
+	ast::StructInstType * mut = ast::mutate( type );
 	// It's not a semantic error if the struct is not found, just an implicit forward declaration.
 	if ( decl ) {
 		// Just linking in the node.
-		auto mut = ast::mutate( type );
 		mut->base = decl;
-		type = mut;
 	}
 	if ( !decl || !decl->body ) {
-		auto mut = ast::mutate( type );
 		forwardStructs[ mut->name ].push_back( mut );
-		type = mut;
-	}
-	return type;
+	}
+	return mut;
 }
 
 ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
 	ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
+	ast::UnionInstType * mut = ast::mutate( type );
 	// It's not a semantic error if the union is not found, just an implicit forward declaration.
 	if ( decl ) {
 		// Just linking in the node.
-		auto mut = ast::mutate( type );
 		mut->base = decl;
-		type = mut;
 	}
 	if ( !decl || !decl->body ) {
-		auto mut = ast::mutate( type );
 		forwardUnions[ mut->name ].push_back( mut );
-		type = mut;
-	}
-	return type;
+	}
+	return mut;
 }
 
Index: tests/exceptions/.expect/fibonacci_nonlocal.txt
===================================================================
--- tests/exceptions/.expect/fibonacci_nonlocal.txt	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
+++ tests/exceptions/.expect/fibonacci_nonlocal.txt	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -0,0 +1,8 @@
+    0     0
+    1     1
+    1     1
+    2     2
+    3     3
+    5     5
+    8     8
+   13    13
Index: tests/exceptions/.expect/pingpong_nonlocal.txt
===================================================================
--- tests/exceptions/.expect/pingpong_nonlocal.txt	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
+++ tests/exceptions/.expect/pingpong_nonlocal.txt	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -0,0 +1,2 @@
+start
+done
Index: tests/exceptions/fibonacci_nonlocal.cfa
===================================================================
--- tests/exceptions/fibonacci_nonlocal.cfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
+++ tests/exceptions/fibonacci_nonlocal.cfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -0,0 +1,60 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2017 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// fibonacci.c -- 3-state finite-state machine
+//
+// Author           : Colby Parsons
+// Created On       : Thu July  6 07:29:37 2023
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Jul  6 21:49:04 2023
+// Update Count     : 18
+//
+
+#include <fstream.hfa>
+#include <coroutine.hfa>
+#include <stdlib.hfa>
+
+exception fib_num {};
+vtable(fib_num) fib_num_vt;
+fib_num except{ &fib_num_vt };
+
+coroutine Fibonacci { int fn; };						// used for communication
+
+void main( Fibonacci & fib ) with( fib ) {				// called on first resume
+	int fn1, fn2;										// retained between resumes
+	try {
+		poll( fib );
+		suspend;										// restart last resume
+	} catchResume ( fib_num * e ) {
+		fn = 0;  fn1 = fn;								// 1st case
+	}
+	try {
+		poll( fib );
+		suspend;										// restart last resume
+	} catchResume ( fib_num * e ) {
+		fn = 1;  fn2 = fn1;  fn1 = fn;					// 2nd case
+	}
+	try {
+		for () {
+			poll( fib );
+			suspend;									// restart last resume
+		} // for
+	} catchResume ( fib_num * e ) {
+		fn = fn1 + fn2;  fn2 = fn1;  fn1 = fn;			// general case
+	}
+}
+
+int main() {
+	Fibonacci f1, f2;
+	for ( i; 8 ) {
+		resumeAt( f1, except );  resumeAt( f2, except );
+		sout | wd( 5, resume( f1 ).fn ) | wd( 5, resume( f2 ).fn );
+	}
+}
+
+// Local Variables: //
+// compile-command: "cfa fibonacci_nonlocal.cfa" //
+// End: //
Index: tests/exceptions/pingpong_nonlocal.cfa
===================================================================
--- tests/exceptions/pingpong_nonlocal.cfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
+++ tests/exceptions/pingpong_nonlocal.cfa	(revision 713905fd5896af66e2ddcd8cbaa19e2eeeb16119)
@@ -0,0 +1,66 @@
+#include <fstream.hfa>
+#include <thread.hfa>
+#include <coroutine.hfa>
+#include <stdlib.hfa>
+#include <fstream.hfa>
+
+exception num_pings { int num; };
+vtable(num_pings) num_pings_vt;
+
+exception num_pongs { int num; };
+vtable(num_pongs) num_pongs_vt;
+
+thread Ping;
+thread Pong { Ping & p; int cnt; };
+thread Ping { Pong & p; int cnt; };
+
+int numtimes = 100000;
+
+void main( Pong & this ) with(this) {
+    try {
+        for ( ;; ) {
+            while( !poll( this ) ) {}
+            num_pongs except{ &num_pongs_vt, cnt + 1 };
+            resumeAt( p, except );
+        }
+    } catchResume ( num_pings * e; e->num < numtimes ) {
+        cnt = e->num;
+    } catch( num_pings * e ) {
+        if ( e->num == numtimes ){
+            num_pongs except{ &num_pongs_vt, e->num + 1 };
+            resumeAt( p, except );
+        }
+    }
+}
+
+void main( Ping & this ) with(this) {
+    try {
+        for ( ;; ) {
+            while( !poll( this ) ) {}
+            num_pings except{ &num_pings_vt, cnt + 1 };
+            resumeAt( p, except );
+        }
+    } catchResume ( num_pongs * e; e->num < numtimes ) {
+        cnt = e->num;
+    } catch( num_pongs * e ) {
+        if ( e->num == numtimes ){
+            num_pings except{ &num_pings_vt, e->num + 1 };
+            resumeAt( p, except );
+        }
+    }
+}
+
+int main() {
+    processor p;
+    sout | "start";
+    {
+        Ping ping;
+        Pong pong;
+        &ping.p = &pong;
+        &pong.p = &ping;
+        num_pings except{ &num_pings_vt, 0 };
+        resumeAt( pong, except );
+    }
+    sout | "done";
+}
+
