Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/concurrency/coroutine.cfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -47,4 +47,45 @@
 
 //-----------------------------------------------------------------------------
+FORALL_DATA_INSTANCE(CoroutineCancelled,
+		(dtype coroutine_t | sized(coroutine_t)), (coroutine_t))
+
+struct __cfaehm_node {
+	struct _Unwind_Exception unwind_exception;
+	struct __cfaehm_node * next;
+	int handler_index;
+};
+
+forall(dtype T)
+void mark_exception(CoroutineCancelled(T) *) {}
+
+forall(dtype T | sized(T))
+void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
+	dst->the_coroutine = src->the_coroutine;
+	dst->the_exception = src->the_exception;
+}
+
+forall(dtype T)
+const char * msg(CoroutineCancelled(T) *) {
+	return "CoroutineCancelled(...)";
+}
+
+// This code should not be inlined. It is the error path on resume.
+forall(dtype T | is_coroutine(T))
+void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
+	verify( desc->cancellation );
+	desc->state = Cancelled;
+	exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);
+
+	CoroutineCancelled(T) except;
+	except.the_coroutine = &cor;
+	except.the_exception = except;
+	throwResume except;
+
+	except->virtual_table->free( except );
+	free( desc->cancellation );
+	desc->cancellation = 0p;
+}
+
+//-----------------------------------------------------------------------------
 // Global state variables
 
@@ -180,4 +221,6 @@
 	this->storage->limit = storage;
 	this->storage->base  = (void*)((intptr_t)storage + size);
+	this->storage->exception_context.top_resume = 0p;
+	this->storage->exception_context.current_exception = 0p;
 	__attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage;
 	*istorage |= userStack ? 0x1 : 0x0;
Index: libcfa/src/concurrency/coroutine.hfa
===================================================================
--- libcfa/src/concurrency/coroutine.hfa	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/concurrency/coroutine.hfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -18,4 +18,23 @@
 #include <assert.h>
 #include "invoke.h"
+#include "../exception.hfa"
+
+//-----------------------------------------------------------------------------
+// Exception thrown from resume when a coroutine stack is cancelled.
+// Should not have to be be sized (see trac #196).
+FORALL_DATA_EXCEPTION(CoroutineCancelled,
+		(dtype coroutine_t | sized(coroutine_t)), (coroutine_t)) (
+	coroutine_t * the_coroutine;
+	exception_t * the_exception;
+);
+
+forall(dtype T)
+void mark_exception(CoroutineCancelled(T) *);
+
+forall(dtype T | sized(T))
+void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
+
+forall(dtype T)
+const char * msg(CoroutineCancelled(T) *);
 
 //-----------------------------------------------------------------------------
@@ -23,7 +42,9 @@
 // Anything that implements this trait can be resumed.
 // Anything that is resumed is a coroutine.
-trait is_coroutine(dtype T) {
-      void main(T & this);
-      $coroutine * get_coroutine(T & this);
+trait is_coroutine(dtype T | sized(T)
+		| is_resumption_exception(CoroutineCancelled(T))
+		| VTABLE_ASSERTION(CoroutineCancelled, (T))) {
+	void main(T & this);
+	$coroutine * get_coroutine(T & this);
 };
 
@@ -112,4 +133,7 @@
 	}
 }
+
+forall(dtype T | is_coroutine(T))
+void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
 
 // Resume implementation inlined for performance
@@ -145,4 +169,7 @@
 	// always done for performance testing
 	$ctx_switch( src, dst );
+	if ( unlikely(dst->cancellation) ) {
+		__cfaehm_cancelled_coroutine( cor, dst );
+	}
 
 	return cor;
Index: libcfa/src/concurrency/exception.cfa
===================================================================
--- libcfa/src/concurrency/exception.cfa	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/concurrency/exception.cfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -57,5 +57,8 @@
 
 STOP_AT_END_FUNCTION(coroutine_cancelstop,
-	// TODO: Instead pass information to the last resumer.
+	struct $coroutine * src = ($coroutine *)stop_param;
+	struct $coroutine * dst = src->last;
+
+	$ctx_switch( src, dst );
 	abort();
 )
Index: libcfa/src/concurrency/exception.hfa
===================================================================
--- libcfa/src/concurrency/exception.hfa	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/concurrency/exception.hfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -18,11 +18,11 @@
 #include "bits/defs.hfa"
 #include "invoke.h"
-struct _Unwind_Exception;
-
-// It must also be usable as a C header file.
 
 #ifdef __cforall
 extern "C" {
+
+#define HIDE_EXPORTS
 #endif
+#include "unwind.h"
 
 struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD;
@@ -32,4 +32,5 @@
 
 #ifdef __cforall
+#undef HIDE_EXPORTS
 }
 #endif
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/concurrency/invoke.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -68,5 +68,5 @@
 	};
 
-	enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active };
+	enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled };
 
 	struct $coroutine {
Index: libcfa/src/exception.h
===================================================================
--- libcfa/src/exception.h	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/exception.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -76,22 +76,22 @@
 // implemented in the .c file either so they all have to be inline.
 
-trait is_exception(dtype T) {
+trait is_exception(dtype exceptT) {
 	/* The first field must be a pointer to a virtual table.
 	 * That virtual table must be a decendent of the base exception virtual tab$
 	 */
-	void mark_exception(T *);
+	void mark_exception(exceptT *);
 	// This is never used and should be a no-op.
 };
 
-trait is_termination_exception(dtype T | is_exception(T)) {
-	void defaultTerminationHandler(T &);
+trait is_termination_exception(dtype exceptT | is_exception(exceptT)) {
+	void defaultTerminationHandler(exceptT &);
 };
 
-trait is_resumption_exception(dtype T | is_exception(T)) {
-	void defaultResumptionHandler(T &);
+trait is_resumption_exception(dtype exceptT | is_exception(exceptT)) {
+	void defaultResumptionHandler(exceptT &);
 };
 
-forall(dtype T | is_termination_exception(T))
-static inline void $throw(T & except) {
+forall(dtype exceptT | is_termination_exception(exceptT))
+static inline void $throw(exceptT & except) {
 	__cfaehm_throw_terminate(
 		(exception_t *)&except,
@@ -100,6 +100,6 @@
 }
 
-forall(dtype T | is_resumption_exception(T))
-static inline void $throwResume(T & except) {
+forall(dtype exceptT | is_resumption_exception(exceptT))
+static inline void $throwResume(exceptT & except) {
 	__cfaehm_throw_resume(
 		(exception_t *)&except,
@@ -108,16 +108,16 @@
 }
 
-forall(dtype T | is_exception(T))
-static inline void cancel_stack(T & except) __attribute__((noreturn)) {
+forall(dtype exceptT | is_exception(exceptT))
+static inline void cancel_stack(exceptT & except) __attribute__((noreturn)) {
 	__cfaehm_cancel_stack( (exception_t *)&except );
 }
 
-forall(dtype T | is_exception(T))
-static inline void defaultTerminationHandler(T & except) {
+forall(dtype exceptT | is_exception(exceptT))
+static inline void defaultTerminationHandler(exceptT & except) {
 	return cancel_stack( except );
 }
 
-forall(dtype T | is_exception(T))
-static inline void defaultResumptionHandler(T & except) {
+forall(dtype exceptT | is_exception(exceptT))
+static inline void defaultResumptionHandler(exceptT & except) {
 	throw except;
 }
Index: libcfa/src/exception.hfa
===================================================================
--- libcfa/src/exception.hfa	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ libcfa/src/exception.hfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -192,5 +192,5 @@
 		size_t size; \
 		void (*copy)(exception_name * this, exception_name * other); \
-		void (*free)(exception_name & this); \
+		void (*^?{})(exception_name & this); \
 		const char * (*msg)(exception_name * this); \
 		_CLOSE
@@ -213,5 +213,5 @@
 		size_t size; \
 		void (*copy)(exception_name parameters * this, exception_name parameters * other); \
-		void (*free)(exception_name parameters & this); \
+		void (*^?{})(exception_name parameters & this); \
 		const char * (*msg)(exception_name parameters * this); \
 		_CLOSE
Index: src/Common/Examine.cc
===================================================================
--- src/Common/Examine.cc	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ src/Common/Examine.cc	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Examine.h --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Sept 2 14:02 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Sep  8 12:15 2020
+// Update Count     : 0
+//
+
+#include "Common/Examine.h"
+
+#include "CodeGen/OperatorTable.h"
+
+DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
+	if (func->name != "main") return nullptr;
+	if (func->type->parameters.size() != 1) return nullptr;
+
+	auto param = func->type->parameters.front();
+
+	auto type = dynamic_cast<ReferenceType * >(param->get_type());
+	if (!type) return nullptr;
+
+	auto obj = dynamic_cast<StructInstType *>(type->base);
+	if (!obj) return nullptr;
+
+	if (kind != obj->baseStruct->kind) return nullptr;
+
+	return param;
+}
+
+namespace {
+	Type * getDestructorParam( FunctionDecl * func ) {
+		if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
+
+		auto params = func->type->parameters;
+		if ( 1 != params.size() ) return nullptr;
+
+		auto ref = dynamic_cast<ReferenceType *>( params.front()->get_type() );
+		if ( ref ) {
+			return ref->base;
+		}
+		return nullptr;
+	}
+}
+
+bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl ) {
+	if ( Type * type = getDestructorParam( func ) ) {
+		auto stype = dynamic_cast<StructInstType *>( type );
+		return stype && stype->baseStruct == type_decl;
+	}
+	return false;
+}
Index: src/Common/Examine.h
===================================================================
--- src/Common/Examine.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ src/Common/Examine.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,23 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Examine.h --
+//
+// Author           : Andrew Beach
+// Created On       : Wed Sept 2 13:57 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Sep  8 12:08 2020
+// Update Count     : 0
+//
+
+#include "SynTree/Declaration.h"
+
+/// Check if this is a main function for a type of an aggregate kind.
+DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind );
+// Returns a pointer to the parameter if true, nullptr otherwise.
+
+/// Check if this function is a destructor for the given structure.
+bool isDestructorFor( FunctionDecl * func, StructDecl * type_decl );
Index: src/Common/module.mk
===================================================================
--- src/Common/module.mk	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ src/Common/module.mk	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -22,4 +22,6 @@
       Common/ErrorObjects.h \
       Common/Eval.cc \
+      Common/Examine.cc \
+      Common/Examine.h \
       Common/FilterCombos.h \
       Common/Indenter.h \
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ src/Concurrency/Keywords.cc	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -19,4 +19,7 @@
 #include <string>                         // for string, operator==
 
+#include <iostream>
+
+#include "Common/Examine.h"               // for isMainFor
 #include "Common/PassVisitor.h"           // for PassVisitor
 #include "Common/SemanticError.h"         // for SemanticError
@@ -34,8 +37,13 @@
 #include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
 #include "SynTree/Visitor.h"              // for Visitor, acceptAll
+#include "Virtual/Tables.h"
 
 class Attribute;
 
 namespace Concurrency {
+	inline static std::string getVTableName( std::string const & exception_name ) {
+		return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
+	}
+
 	//=============================================================================================
 	// Pass declarations
@@ -54,6 +62,10 @@
 	  public:
 
-	  	ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
-		  type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
+		ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name,
+			std::string&& getter_name, std::string&& context_error, std::string&& exception_name,
+			bool needs_main, AggregateDecl::Aggregate cast_target ) :
+		  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
+		  context_error( context_error ), vtable_name( getVTableName( exception_name ) ),
+		  needs_main( needs_main ), cast_target( cast_target ) {}
 
 		virtual ~ConcurrentSueKeyword() {}
@@ -63,4 +75,5 @@
 
 		void handle( StructDecl * );
+		void addVtableForward( StructDecl * );
 		FunctionDecl * forwardDeclare( StructDecl * );
 		ObjectDecl * addField( StructDecl * );
@@ -76,4 +89,5 @@
 		const std::string getter_name;
 		const std::string context_error;
+		const std::string vtable_name;
 		bool needs_main;
 		AggregateDecl::Aggregate cast_target;
@@ -81,4 +95,5 @@
 		StructDecl   * type_decl = nullptr;
 		FunctionDecl * dtor_decl = nullptr;
+		StructDecl * vtable_decl = nullptr;
 	};
 
@@ -101,4 +116,5 @@
 			"get_thread",
 			"thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
+			"",
 			true,
 			AggregateDecl::Thread
@@ -133,4 +149,5 @@
 			"get_coroutine",
 			"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
+			"CoroutineCancelled",
 			true,
 			AggregateDecl::Coroutine
@@ -167,4 +184,5 @@
 			"get_monitor",
 			"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
+			"",
 			false,
 			AggregateDecl::Monitor
@@ -198,4 +216,5 @@
 			"get_generator",
 			"Unable to find builtin type $generator\n",
+			"",
 			true,
 			AggregateDecl::Generator
@@ -231,5 +250,4 @@
 
 	private:
-		DeclarationWithType * is_main( FunctionDecl * );
 		bool is_real_suspend( FunctionDecl * );
 
@@ -359,22 +377,30 @@
 			handle( decl );
 		}
+		else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
+			vtable_decl = decl;
+		}
+		// Might be able to get ride of is target.
+		assert( is_target(decl) == (cast_target == decl->kind) );
 		return decl;
 	}
 
 	DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
-		if( !type_decl ) return decl;
-		if( !CodeGen::isDestructor( decl->name ) ) return decl;
-
-		auto params = decl->type->parameters;
-		if( params.size() != 1 ) return decl;
-
-		auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
-		if( !type ) return decl;
-
-		auto stype = dynamic_cast<StructInstType*>( type->base );
-		if( !stype ) return decl;
-		if( stype->baseStruct != type_decl ) return decl;
-
-		if( !dtor_decl ) dtor_decl = decl;
+		if ( type_decl && isDestructorFor( decl, type_decl ) )
+			dtor_decl = decl;
+		else if ( vtable_name.empty() )
+			;
+		else if ( auto param = isMainFor( decl, cast_target ) ) {
+			// This should never trigger.
+			assert( vtable_decl );
+			// Should be safe because of isMainFor.
+			StructInstType * struct_type = static_cast<StructInstType *>(
+				static_cast<ReferenceType *>( param->get_type() )->base );
+			assert( struct_type );
+
+			declsToAddAfter.push_back( Virtual::makeVtableInstance( vtable_decl, {
+				new TypeExpr( struct_type->clone() ),
+			}, struct_type, nullptr ) );
+		}
+
 		return decl;
 	}
@@ -400,7 +426,19 @@
 		if( !dtor_decl ) SemanticError( decl, context_error );
 
+		addVtableForward( decl );
 		FunctionDecl * func = forwardDeclare( decl );
 		ObjectDecl * field = addField( decl );
 		addRoutines( field, func );
+	}
+
+	void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
+		if ( vtable_decl ) {
+			declsToAddBefore.push_back( Virtual::makeVtableForward( vtable_decl, {
+				new TypeExpr( new StructInstType( noQualifiers, decl ) ),
+			} ) );
+		// Its only an error if we want a vtable and don't have one.
+		} else if ( ! vtable_name.empty() ) {
+			SemanticError( decl, context_error );
+		}
 	}
 
@@ -528,21 +566,4 @@
 	// Suspend keyword implementation
 	//=============================================================================================
-	DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
-		if(func->name != "main") return nullptr;
-		if(func->type->parameters.size() != 1) return nullptr;
-
-		auto param = func->type->parameters.front();
-
-		auto type  = dynamic_cast<ReferenceType * >(param->get_type());
-		if(!type) return nullptr;
-
-		auto obj   = dynamic_cast<StructInstType *>(type->base);
-		if(!obj) return nullptr;
-
-		if(!obj->baseStruct->is_generator()) return nullptr;
-
-		return param;
-	}
-
 	bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
 		if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
@@ -565,5 +586,5 @@
 
 		// Is this the main of a generator?
-		auto param = is_main( func );
+		auto param = isMainFor( func, AggregateDecl::Aggregate::Generator );
 		if(!param) return;
 
@@ -1033,2 +1054,3 @@
 // tab-width: 4 //
 // End: //
+
Index: src/Virtual/Tables.cc
===================================================================
--- src/Virtual/Tables.cc	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ src/Virtual/Tables.cc	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,117 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Tables.cc --
+//
+// Author           : Andrew Beach
+// Created On       : Mon Aug 31 11:11:00 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Sep  3 14:56:00 2020
+// Update Count     : 0
+//
+
+#include <SynTree/Declaration.h>
+#include <SynTree/Expression.h>
+#include <SynTree/Type.h>
+
+namespace Virtual {
+
+std::string vtableTypeName( std::string const & name ) {
+	return name + "_vtable";
+}
+
+std::string instanceName( std::string const & name ) {
+	return std::string("_") + name + "_instance";
+}
+
+std::string vtableInstanceName( std::string const & name ) {
+	return instanceName( vtableTypeName( name ) );
+}
+
+bool isVTableInstanceName( std::string const & name ) {
+	// There are some delicate length calculations here.
+	return 17 < name.size() && '_' == name[0] &&
+		std::string("_vtable_instance") == name.substr(1, name.size() - 17);
+}
+
+// Fuse base polymorphic declaration and forall arguments into a new type.
+static StructInstType * vtableInstType(
+		StructDecl * polyDecl, std::list< Expression * > && parameters ) {
+	assert( parameters.size() == polyDecl->parameters.size() );
+	StructInstType * type = new StructInstType(
+			Type::Qualifiers( /* Type::Const */ ), polyDecl );
+	type->parameters = std::move( parameters );
+	return type;
+}
+
+static ObjectDecl * makeVtableDeclaration(
+		StructInstType * type, Initializer * init ) {
+	std::string const & name = instanceName( type->name );
+	Type::StorageClasses storage = noStorageClasses;
+	if ( nullptr == init ) {
+		storage.is_extern = true;
+	}
+	return new ObjectDecl(
+		name,
+		storage,
+		LinkageSpec::Cforall,
+		nullptr,
+		type,
+		init
+	);
+}
+
+ObjectDecl * makeVtableForward( StructInstType * type ) {
+	return makeVtableDeclaration( type, nullptr );
+}
+
+ObjectDecl * makeVtableForward(
+		StructDecl * polyDecl, std::list< Expression * > && parameters ) {
+	return makeVtableForward( vtableInstType( polyDecl, std::move( parameters ) ) );
+}
+
+ObjectDecl * makeVtableInstance(
+		StructInstType * vtableType, Type * vobject_type, Initializer * init ) {
+	StructDecl * vtableStruct = vtableType->baseStruct;
+	// Build the initialization
+	if ( nullptr == init ) {
+		std::list< Initializer * > inits;
+
+		// This is going to have to be run before the resolver to connect expressions.
+		for ( auto field : vtableStruct->members ) {
+			if ( std::string( "parent" ) == field->name ) {
+				// This will not work with polymorphic state.
+				auto oField = strict_dynamic_cast< ObjectDecl * >( field );
+				auto fieldType = strict_dynamic_cast< PointerType * >( oField->type );
+				auto parentType = strict_dynamic_cast< StructInstType * >( fieldType->base );
+				std::string const & parentInstance = instanceName( parentType->name );
+				inits.push_back(
+						new SingleInit( new AddressExpr( new NameExpr( parentInstance ) ) ) );
+			} else if ( std::string( "size" ) == field->name ) {
+				inits.push_back( new SingleInit( new SizeofExpr( vobject_type->clone() ) ) );
+			} else if ( std::string( "align" ) == field->name ) {
+				inits.push_back( new SingleInit( new AlignofExpr( vobject_type->clone() ) ) );
+			} else {
+				inits.push_back( new SingleInit( new NameExpr( field->name ) ) );
+			}
+		}
+		init = new ListInit( inits );
+	// This should initialize everything except the parent pointer, the
+	// size-of and align-of fields. These should be inserted.
+	} else {
+		assert(false);
+	}
+	return makeVtableDeclaration( vtableType, init );
+}
+
+ObjectDecl * makeVtableInstance(
+		StructDecl * polyDecl, std::list< Expression * > && parameters,
+		Type * vobject, Initializer * init ) {
+	return makeVtableInstance(
+		vtableInstType( polyDecl, std::move( parameters ) ), vobject, init );
+}
+
+}
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ src/Virtual/Tables.h	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,52 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Tables.h --
+//
+// Author           : Andrew Beach
+// Created On       : Mon Aug 31 11:07:00 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Sep  1 14:29:00 2020
+// Update Count     : 0
+//
+
+#include <list>  // for list
+
+class Declaration;
+class StructDecl;
+class Expression;
+
+namespace Virtual {
+
+std::string vtableTypeName( std::string const & type_name );
+std::string instanceName( std::string const & vtable_name );
+std::string vtableInstanceName( std::string const & type_name );
+bool isVTableInstanceName( std::string const & name );
+
+/// Converts exceptions into regular structures.
+//void ( std::list< Declaration * > & translationUnit );
+
+ObjectDecl * makeVtableForward( StructInstType * );
+ObjectDecl * makeVtableForward( StructDecl *, std::list< Expression * > && );
+/* Create a forward definition of a vtable of the given type.
+ *
+ * Instead of the virtual table type you may provide the declaration and all
+ * the forall parameters.
+ */
+
+ObjectDecl * makeVtableInstance( StructInstType *, Type *, Initializer * );
+ObjectDecl * makeVtableInstance(
+	StructDecl *, std::list< Expression * > &&, Type *, Initializer * );
+/* Create an initialized definition of a vtable.
+ *
+ * The parameters are the virtual table type (or the base declaration and the
+ * forall parameters), the object type and optionally an initializer.
+ *
+ * Instead of the virtual table type you may provide the declaration and all
+ * the forall parameters.
+ */
+
+}
Index: src/Virtual/module.mk
===================================================================
--- src/Virtual/module.mk	(revision 2b7f6f0640b5662ebc28adf12da366d602734a60)
+++ src/Virtual/module.mk	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -15,3 +15,6 @@
 ###############################################################################
 
-SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h
+SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
+	Virtual/Tables.cc Virtual/Tables.h
+
+SRCDEMANGLE += Virtual/Tables.cc
Index: tests/exceptions/cancel/.expect/coroutine.txt
===================================================================
--- tests/exceptions/cancel/.expect/coroutine.txt	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ tests/exceptions/cancel/.expect/coroutine.txt	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,1 @@
+012345
Index: tests/exceptions/cancel/coroutine.cfa
===================================================================
--- tests/exceptions/cancel/coroutine.cfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
+++ tests/exceptions/cancel/coroutine.cfa	(revision 1c01c5836c12d14d4c519d76550c0381bc562aaf)
@@ -0,0 +1,34 @@
+// Try cancelling a coroutine.
+
+#include <stdio.h>
+#include <coroutine.hfa>
+#include <exception.hfa>
+
+TRIVIAL_EXCEPTION(internal_error);
+
+coroutine WillCancel {};
+
+const char * msg(CoroutineCancelled(WillCancel) * this) {
+	return "CoroutineCancelled(WillCancel)";
+}
+
+void main(WillCancel & wc) {
+	printf("1");
+	cancel_stack((internal_error){});
+	printf("!");
+}
+
+int main(int argc, char * argv[]) {
+	WillCancel cancel;
+	try {
+		printf("0");
+		resume(cancel);
+		printf("4");
+	} catchResume (CoroutineCancelled(WillCancel) * error) {
+		printf("2");
+		if ((virtual internal_error *)error->the_exception) {
+			printf("3");
+		}
+	}
+	printf("5\n");
+}
