Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision 5339a87ca7689b734a2eb1d355830ea9713784a1)
+++ 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: //
+
