Index: src/AST/GenericSubstitution.cpp
===================================================================
--- src/AST/GenericSubstitution.cpp	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/AST/GenericSubstitution.cpp	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -45,5 +45,5 @@
 			visit_children = false;
 			const AggregateDecl * aggr = ty->aggr();
-			sub = TypeSubstitution{ aggr->params.begin(), aggr->params.end(), ty->params.begin() };
+			sub = TypeSubstitution( aggr->params, ty->params );
 		}
 
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/AST/TypeSubstitution.hpp	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -37,4 +37,6 @@
   public:
 	TypeSubstitution();
+	template< typename FormalContainer, typename ActualContainer >
+	TypeSubstitution( FormalContainer formals, ActualContainer actuals );
 	template< typename FormalIterator, typename ActualIterator >
 	TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
@@ -76,6 +78,8 @@
 	bool empty() const;
 
+	template< typename FormalContainer, typename ActualContainer >
+	void addAll( FormalContainer formals, ActualContainer actuals );
 	template< typename FormalIterator, typename ActualIterator >
-	void add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
+	void addAll( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin );
 
 	/// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
@@ -112,7 +116,24 @@
 };
 
+template< typename FormalContainer, typename ActualContainer >
+TypeSubstitution::TypeSubstitution( FormalContainer formals, ActualContainer actuals ) {
+	assert( formals.size() == actuals.size() );
+	addAll( formals.begin(), formals.end(), actuals.begin() );
+}
+
+template< typename FormalIterator, typename ActualIterator >
+TypeSubstitution::TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+	addAll( formalBegin, formalEnd, actualBegin );
+}
+
+template< typename FormalContainer, typename ActualContainer >
+void TypeSubstitution::addAll( FormalContainer formals, ActualContainer actuals ) {
+	assert( formals.size() == actuals.size() );
+	addAll( formals.begin(), formals.end(), actuals.begin() );
+}
+
 // this is the only place where type parameters outside a function formal may be substituted.
 template< typename FormalIterator, typename ActualIterator >
-void TypeSubstitution::add( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
+void TypeSubstitution::addAll( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
 	// FormalIterator points to a TypeDecl
 	// ActualIterator points to a Type
@@ -129,16 +150,8 @@
 			} // if
 		} else {
-			
+			// Is this an error?
 		} // if
 	} // for
 }
-
-
-
-template< typename FormalIterator, typename ActualIterator >
-TypeSubstitution::TypeSubstitution( FormalIterator formalBegin, FormalIterator formalEnd, ActualIterator actualBegin ) {
-	add( formalBegin, formalEnd, actualBegin );
-}
-
 
 } // namespace ast
Index: src/Common/Examine.cc
===================================================================
--- src/Common/Examine.cc	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Common/Examine.cc	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -5,16 +5,18 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Examine.h --
+// Examine.cc -- Helpers for examining AST code.
 //
 // 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
+// Last Modified On : Fri Dec 10 10:27 2021
+// Update Count     : 1
 //
 
 #include "Common/Examine.h"
 
+#include "AST/Type.hpp"
 #include "CodeGen/OperatorTable.h"
+#include "InitTweak/InitTweak.h"
 
 DeclarationWithType * isMainFor( FunctionDecl * func, AggregateDecl::Aggregate kind ) {
@@ -36,4 +38,35 @@
 
 namespace {
+
+// getTypeofThis but does some extra checks used in this module.
+const ast::Type * getTypeofThisSolo( const ast::FunctionDecl * func ) {
+	if ( 1 != func->params.size() ) {
+		return nullptr;
+	}
+	auto ref = func->type->params.front().as<ast::ReferenceType>();
+	return (ref) ? ref->base : nullptr;
+}
+
+}
+
+const ast::DeclWithType * isMainFor(
+		const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ) {
+	if ( "main" != func->name ) return nullptr;
+	if ( 1 != func->params.size() ) return nullptr;
+
+	auto param = func->params.front();
+
+	auto type = dynamic_cast<const ast::ReferenceType *>( param->get_type() );
+	if ( !type ) return nullptr;
+
+	auto obj = type->base.as<ast::StructInstType>();
+	if ( !obj ) return nullptr;
+
+	if ( kind != obj->base->kind ) return nullptr;
+
+	return param;
+}
+
+namespace {
 	Type * getDestructorParam( FunctionDecl * func ) {
 		if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
@@ -48,4 +81,11 @@
 		return nullptr;
 	}
+
+const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
+	if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
+	//return InitTweak::getParamThis( func )->type;
+	return getTypeofThisSolo( func );
+}
+
 }
 
@@ -57,2 +97,11 @@
 	return false;
 }
+
+bool isDestructorFor(
+		const ast::FunctionDecl * func, const ast::StructDecl * type_decl ) {
+	if ( const ast::Type * type = getDestructorParam( func ) ) {
+		auto stype = dynamic_cast<const ast::StructInstType *>( type );
+		return stype && stype->base.get() == type_decl;
+	}
+	return false;
+}
Index: src/Common/Examine.h
===================================================================
--- src/Common/Examine.h	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Common/Examine.h	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -5,19 +5,24 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Examine.h --
+// Examine.h -- Helpers for examining AST code.
 //
 // 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
+// Last Modified On : Fri Dec 10 10:28 2021
+// Update Count     : 1
 //
 
+#include "AST/Decl.hpp"
 #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 );
+const ast::DeclWithType * isMainFor(
+	const ast::FunctionDecl * func, ast::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 );
+bool isDestructorFor(
+	const ast::FunctionDecl * func, const ast::StructDecl * type );
Index: src/Concurrency/KeywordsNew.cpp
===================================================================
--- src/Concurrency/KeywordsNew.cpp	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Concurrency/KeywordsNew.cpp	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -10,6 +10,6 @@
 // Created On       : Tue Nov 16  9:53:00 2021
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Dec  1 11:24:00 2021
-// Update Count     : 1
+// Last Modified On : Fri Mar 11 10:40:00 2022
+// Update Count     : 2
 //
 
@@ -18,10 +18,15 @@
 #include "AST/Copy.hpp"
 #include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Stmt.hpp"
+#include "AST/DeclReplacer.hpp"
 #include "AST/TranslationUnit.hpp"
 #include "CodeGen/OperatorTable.h"
+#include "Common/Examine.h"
 #include "Common/utility.h"
+#include "ControlStruct/LabelGeneratorNew.hpp"
 #include "InitTweak/InitTweak.h"
+#include "Virtual/Tables.h"
 
 namespace Concurrency {
@@ -29,9 +34,841 @@
 namespace {
 
-inline static bool isThread( const ast::DeclWithType * decl ) {
+// --------------------------------------------------------------------------
+// Loose Helper Functions:
+
+/// Detect threads constructed with the keyword thread.
+bool isThread( const ast::DeclWithType * decl ) {
 	auto baseType = decl->get_type()->stripDeclarator();
 	auto instType = dynamic_cast<const ast::StructInstType *>( baseType );
 	if ( nullptr == instType ) { return false; }
 	return instType->base->is_thread();
+}
+
+/// Get the virtual type id if given a type name.
+std::string typeIdType( std::string const & exception_name ) {
+	return exception_name.empty() ? std::string()
+		: Virtual::typeIdType( exception_name );
+}
+
+/// Get the vtable type name if given a type name.
+std::string vtableTypeName( std::string const & exception_name ) {
+	return exception_name.empty() ? std::string()
+		: Virtual::vtableTypeName( exception_name );
+}
+
+static ast::Type * mutate_under_references( ast::ptr<ast::Type>& type ) {
+	ast::Type * mutType = type.get_and_mutate();
+	for ( ast::ReferenceType * mutRef
+		; (mutRef = dynamic_cast<ast::ReferenceType *>( mutType ))
+		; mutType = mutRef->base.get_and_mutate() );
+	return mutType;
+}
+
+// Describe that it adds the generic parameters and the uses of the generic
+// parameters on the function and first "this" argument.
+ast::FunctionDecl * fixupGenerics(
+		const ast::FunctionDecl * func, const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+	// We have to update both the declaration
+	auto mutFunc = ast::mutate( func );
+	auto mutType = mutFunc->type.get_and_mutate();
+
+	if ( decl->params.empty() ) {
+		return mutFunc;
+	}
+
+	assert( 0 != mutFunc->params.size() );
+	assert( 0 != mutType->params.size() );
+
+	// Add the "forall" clause information.
+	for ( const ast::ptr<ast::TypeDecl> & typeParam : decl->params ) {
+		auto typeDecl = ast::deepCopy( typeParam );
+		mutFunc->type_params.push_back( typeDecl );
+		mutType->forall.push_back(
+			new ast::TypeInstType( typeDecl->name, typeDecl ) );
+		for ( auto & assertion : typeDecl->assertions ) {
+			mutFunc->assertions.push_back( assertion );
+			mutType->assertions.emplace_back(
+				new ast::VariableExpr( location, assertion ) );
+		}
+		typeDecl->assertions.clear();
+	}
+
+	// Even chain_mutate is not powerful enough for this:
+	ast::ptr<ast::Type>& paramType = strict_dynamic_cast<ast::ObjectDecl *>(
+		mutFunc->params[0].get_and_mutate() )->type;
+	auto paramTypeInst = strict_dynamic_cast<ast::StructInstType *>(
+		mutate_under_references( paramType ) );
+	auto typeParamInst = strict_dynamic_cast<ast::StructInstType *>(
+		mutate_under_references( mutType->params[0] ) );
+
+	for ( const ast::ptr<ast::TypeDecl> & typeDecl : mutFunc->type_params ) {
+		paramTypeInst->params.push_back(
+			new ast::TypeExpr( location,
+				new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
+		typeParamInst->params.push_back(
+			new ast::TypeExpr( location,
+				new ast::TypeInstType( typeDecl->name, typeDecl ) ) );
+	}
+
+	return mutFunc;
+}
+
+// --------------------------------------------------------------------------
+struct ConcurrentSueKeyword : public ast::WithDeclsToAdd<> {
+	ConcurrentSueKeyword(
+		std::string&& type_name, std::string&& field_name,
+		std::string&& getter_name, std::string&& context_error,
+		std::string&& exception_name,
+		bool needs_main, ast::AggregateDecl::Aggregate cast_target
+	) :
+		type_name( type_name ), field_name( field_name ),
+		getter_name( getter_name ), context_error( context_error ),
+		exception_name( exception_name ),
+		typeid_name( typeIdType( exception_name ) ),
+		vtable_name( vtableTypeName( exception_name ) ),
+		needs_main( needs_main ), cast_target( cast_target )
+	{}
+
+	virtual ~ConcurrentSueKeyword() {}
+
+	const ast::Decl * postvisit( const ast::StructDecl * decl );
+	const ast::DeclWithType * postvisit( const ast::FunctionDecl * decl );
+	const ast::Expr * postvisit( const ast::KeywordCastExpr * expr );
+
+	struct StructAndField {
+		const ast::StructDecl * decl;
+		const ast::ObjectDecl * field;
+	};
+
+	const ast::StructDecl * handleStruct( const ast::StructDecl * );
+	void handleMain( const ast::FunctionDecl *, const ast::StructInstType * );
+	void addTypeId( const ast::StructDecl * );
+	void addVtableForward( const ast::StructDecl * );
+	const ast::FunctionDecl * forwardDeclare( const ast::StructDecl * );
+	StructAndField addField( const ast::StructDecl * );
+	void addGetRoutines( const ast::ObjectDecl *, const ast::FunctionDecl * );
+	void addLockUnlockRoutines( const ast::StructDecl * );
+
+private:
+	const std::string type_name;
+	const std::string field_name;
+	const std::string getter_name;
+	const std::string context_error;
+	const std::string exception_name;
+	const std::string typeid_name;
+	const std::string vtable_name;
+	const bool needs_main;
+	const ast::AggregateDecl::Aggregate cast_target;
+
+	const ast::StructDecl   * type_decl = nullptr;
+	const ast::FunctionDecl * dtor_decl = nullptr;
+	const ast::StructDecl * except_decl = nullptr;
+	const ast::StructDecl * typeid_decl = nullptr;
+	const ast::StructDecl * vtable_decl = nullptr;
+};
+
+// Handles thread type declarations:
+//
+// thread Mythread {                         struct MyThread {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             thread$ __thrd_d;
+// };                                        };
+//                                           static inline thread$ * get_thread( MyThread * this ) { return &this->__thrd_d; }
+//
+struct ThreadKeyword final : public ConcurrentSueKeyword {
+	ThreadKeyword() : ConcurrentSueKeyword(
+		"thread$",
+		"__thrd",
+		"get_thread",
+		"thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
+		"ThreadCancelled",
+		true,
+		ast::AggregateDecl::Thread )
+	{}
+
+	virtual ~ThreadKeyword() {}
+};
+
+// Handles coroutine type declarations:
+//
+// coroutine MyCoroutine {                   struct MyCoroutine {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             coroutine$ __cor_d;
+// };                                        };
+//                                           static inline coroutine$ * get_coroutine( MyCoroutine * this ) { return &this->__cor_d; }
+//
+struct CoroutineKeyword final : public ConcurrentSueKeyword {
+	CoroutineKeyword() : ConcurrentSueKeyword(
+		"coroutine$",
+		"__cor",
+		"get_coroutine",
+		"coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
+		"CoroutineCancelled",
+		true,
+		ast::AggregateDecl::Coroutine )
+	{}
+
+	virtual ~CoroutineKeyword() {}
+};
+
+// Handles monitor type declarations:
+//
+// monitor MyMonitor {                       struct MyMonitor {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             monitor$ __mon_d;
+// };                                        };
+//                                           static inline monitor$ * get_coroutine( MyMonitor * this ) {
+//                                               return &this->__cor_d;
+//                                           }
+//                                           void lock(MyMonitor & this) {
+//                                               lock(get_monitor(this));
+//                                           }
+//                                           void unlock(MyMonitor & this) {
+//                                               unlock(get_monitor(this));
+//                                           }
+//
+struct MonitorKeyword final : public ConcurrentSueKeyword {
+	MonitorKeyword() : ConcurrentSueKeyword(
+		"monitor$",
+		"__mon",
+		"get_monitor",
+		"monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
+		"",
+		false,
+		ast::AggregateDecl::Monitor )
+	{}
+
+	virtual ~MonitorKeyword() {}
+};
+
+// Handles generator type declarations:
+//
+// generator MyGenerator {                   struct MyGenerator {
+//  int data;                                  int data;
+//  a_struct_t more_data;                      a_struct_t more_data;
+//                                =>             int __generator_state;
+// };                                        };
+//
+struct GeneratorKeyword final : public ConcurrentSueKeyword {
+	GeneratorKeyword() : ConcurrentSueKeyword(
+		"generator$",
+		"__generator_state",
+		"get_generator",
+		"Unable to find builtin type generator$\n",
+		"",
+		true,
+		ast::AggregateDecl::Generator )
+	{}
+
+	virtual ~GeneratorKeyword() {}
+};
+
+const ast::Decl * ConcurrentSueKeyword::postvisit(
+		const ast::StructDecl * decl ) {
+	if ( !decl->body ) {
+		return decl;
+	} else if ( cast_target == decl->kind ) {
+		return handleStruct( decl );
+	} else if ( type_name == decl->name ) {
+		assert( !type_decl );
+		type_decl = decl;
+	} else if ( exception_name == decl->name ) {
+		assert( !except_decl );
+		except_decl = decl;
+	} else if ( typeid_name == decl->name ) {
+		assert( !typeid_decl );
+		typeid_decl = decl;
+	} else if ( vtable_name == decl->name ) {
+		assert( !vtable_decl );
+		vtable_decl = decl;
+	}
+	return decl;
+}
+
+// Try to get the full definition, but raise an error on conflicts.
+const ast::FunctionDecl * getDefinition(
+		const ast::FunctionDecl * old_decl,
+		const ast::FunctionDecl * new_decl ) {
+	if ( !new_decl->stmts ) {
+		return old_decl;
+	} else if ( !old_decl->stmts ) {
+		return new_decl;
+	} else {
+		assert( !old_decl->stmts || !new_decl->stmts );
+		return nullptr;
+	}
+}
+
+const ast::DeclWithType * ConcurrentSueKeyword::postvisit(
+		const ast::FunctionDecl * decl ) {
+	if ( type_decl && isDestructorFor( decl, type_decl ) ) {
+		// Check for forward declarations, try to get the full definition.
+		dtor_decl = (dtor_decl) ? getDefinition( dtor_decl, decl ) : decl;
+	} else if ( !vtable_name.empty() && decl->has_body() ) {
+		if (const ast::DeclWithType * param = isMainFor( decl, cast_target )) {
+			if ( !vtable_decl ) {
+				SemanticError( decl, context_error );
+			}
+			// Should be safe because of isMainFor.
+			const ast::StructInstType * struct_type =
+				static_cast<const ast::StructInstType *>(
+					static_cast<const ast::ReferenceType *>(
+						param->get_type() )->base.get() );
+
+			handleMain( decl, struct_type );
+		}
+	}
+	return decl;
+}
+
+const ast::Expr * ConcurrentSueKeyword::postvisit(
+		const ast::KeywordCastExpr * expr ) {
+	if ( cast_target == expr->target ) {
+		// Convert `(thread &)ex` to `(thread$ &)*get_thread(ex)`, etc.
+		if ( !type_decl || !dtor_decl ) {
+			SemanticError( expr, context_error );
+		}
+		assert( nullptr == expr->result );
+		auto cast = ast::mutate( expr );
+		cast->result = new ast::ReferenceType( new ast::StructInstType( type_decl ) );
+		cast->concrete_target.field  = field_name;
+		cast->concrete_target.getter = getter_name;
+		return cast;
+	}
+	return expr;
+}
+
+const ast::StructDecl * ConcurrentSueKeyword::handleStruct(
+		const ast::StructDecl * decl ) {
+	assert( decl->body );
+
+	if ( !type_decl || !dtor_decl ) {
+		SemanticError( decl, context_error );
+	}
+
+	if ( !exception_name.empty() ) {
+		if( !typeid_decl || !vtable_decl ) {
+			SemanticError( decl, context_error );
+		}
+		addTypeId( decl );
+		addVtableForward( decl );
+	}
+
+	const ast::FunctionDecl * func = forwardDeclare( decl );
+	StructAndField addFieldRet = addField( decl );
+	decl = addFieldRet.decl;
+	const ast::ObjectDecl * field = addFieldRet.field;
+
+	addGetRoutines( field, func );
+	// Add routines to monitors for use by mutex stmt.
+	if ( ast::AggregateDecl::Monitor == cast_target ) {
+		addLockUnlockRoutines( decl );
+	}
+
+	return decl;
+}
+
+void ConcurrentSueKeyword::handleMain(
+		const ast::FunctionDecl * decl, const ast::StructInstType * type ) {
+	assert( vtable_decl );
+	assert( except_decl );
+
+	const CodeLocation & location = decl->location;
+
+	std::vector<ast::ptr<ast::Expr>> poly_args = {
+		new ast::TypeExpr( location, type ),
+	};
+	ast::ObjectDecl * vtable_object = Virtual::makeVtableInstance(
+		location,
+		"_default_vtable_object_declaration",
+		new ast::StructInstType( vtable_decl, copy( poly_args ) ),
+		type,
+		nullptr
+	);
+	declsToAddAfter.push_back( vtable_object );
+	declsToAddAfter.push_back(
+		new ast::ObjectDecl(
+			location,
+			Virtual::concurrentDefaultVTableName(),
+			new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
+			new ast::SingleInit( location,
+				new ast::VariableExpr( location, vtable_object ) ),
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		)
+	);
+	declsToAddAfter.push_back( Virtual::makeGetExceptionFunction(
+		location,
+		vtable_object,
+		new ast::StructInstType( except_decl, copy( poly_args ) )
+	) );
+}
+
+void ConcurrentSueKeyword::addTypeId( const ast::StructDecl * decl ) {
+	assert( typeid_decl );
+	const CodeLocation & location = decl->location;
+
+	ast::StructInstType * typeid_type =
+		new ast::StructInstType( typeid_decl, ast::CV::Const );
+	typeid_type->params.push_back(
+		new ast::TypeExpr( location, new ast::StructInstType( decl ) ) );
+	declsToAddBefore.push_back(
+		Virtual::makeTypeIdInstance( location, typeid_type ) );
+	// If the typeid_type is going to be kept, the other reference will have
+	// been made by now, but we also get to avoid extra mutates.
+	ast::ptr<ast::StructInstType> typeid_cleanup = typeid_type;
+}
+
+void ConcurrentSueKeyword::addVtableForward( const ast::StructDecl * decl ) {
+	assert( vtable_decl );
+	const CodeLocation& location = decl->location;
+
+	std::vector<ast::ptr<ast::Expr>> poly_args = {
+		new ast::TypeExpr( location, new ast::StructInstType( decl ) ),
+	};
+	declsToAddBefore.push_back( Virtual::makeGetExceptionForward(
+		location,
+		new ast::StructInstType( vtable_decl, copy( poly_args ) ),
+		new ast::StructInstType( except_decl, copy( poly_args ) )
+	) );
+	ast::ObjectDecl * vtable_object = Virtual::makeVtableForward(
+		location,
+		"_default_vtable_object_declaration",
+		new ast::StructInstType( vtable_decl, std::move( poly_args ) )
+	);
+	declsToAddBefore.push_back( vtable_object );
+	declsToAddBefore.push_back(
+		new ast::ObjectDecl(
+			location,
+			Virtual::concurrentDefaultVTableName(),
+			new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
+			nullptr,
+			ast::Storage::Extern,
+			ast::Linkage::Cforall
+		)
+	);
+}
+
+const ast::FunctionDecl * ConcurrentSueKeyword::forwardDeclare(
+		const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+
+	ast::StructDecl * forward = ast::deepCopy( decl );
+	{
+		// If removing members makes ref-count go to zero, do not free.
+		ast::ptr<ast::StructDecl> forward_ptr = forward;
+		forward->body = false;
+		forward->members.clear();
+		forward_ptr.release();
+	}
+
+	ast::ObjectDecl * this_decl = new ast::ObjectDecl(
+		location,
+		"this",
+		new ast::ReferenceType( new ast::StructInstType( decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::ObjectDecl * ret_decl = new ast::ObjectDecl(
+		location,
+		"ret",
+		new ast::PointerType( new ast::StructInstType( type_decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::FunctionDecl * get_decl = new ast::FunctionDecl(
+		location,
+		getter_name,
+		{}, // forall
+		{ this_decl }, // params
+		{ ret_decl }, // returns
+		nullptr, // stmts
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ new ast::Attribute( "const" ) },
+		ast::Function::Inline
+	);
+	get_decl = fixupGenerics( get_decl, decl );
+
+	ast::FunctionDecl * main_decl = nullptr;
+	if ( needs_main ) {
+		// `this_decl` is copied here because the original was used above.
+		main_decl = new ast::FunctionDecl(
+			location,
+			"main",
+			{},
+			{ ast::deepCopy( this_decl ) },
+			{},
+			nullptr,
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		);
+		main_decl = fixupGenerics( main_decl, decl );
+	}
+
+	declsToAddBefore.push_back( forward );
+	if ( needs_main ) declsToAddBefore.push_back( main_decl );
+	declsToAddBefore.push_back( get_decl );
+
+	return get_decl;
+}
+
+ConcurrentSueKeyword::StructAndField ConcurrentSueKeyword::addField(
+		const ast::StructDecl * decl ) {
+	const CodeLocation & location = decl->location;
+
+	ast::ObjectDecl * field = new ast::ObjectDecl(
+		location,
+		field_name,
+		new ast::StructInstType( type_decl ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	auto mutDecl = ast::mutate( decl );
+	mutDecl->members.push_back( field );
+
+	return {mutDecl, field};
+}
+
+void ConcurrentSueKeyword::addGetRoutines(
+		const ast::ObjectDecl * field, const ast::FunctionDecl * forward ) {
+	// Say it is generated at the "same" places as the forward declaration.
+	const CodeLocation & location = forward->location;
+
+	const ast::DeclWithType * param = forward->params.front();
+	ast::Stmt * stmt = new ast::ReturnStmt( location,
+		new ast::AddressExpr( location,
+			new ast::MemberExpr( location,
+				field,
+				new ast::CastExpr( location,
+					new ast::VariableExpr( location, param ),
+					ast::deepCopy( param->get_type()->stripReferences() ),
+					ast::ExplicitCast
+				)
+			)
+		)
+	);
+
+	ast::FunctionDecl * decl = ast::deepCopy( forward );
+	decl->stmts = new ast::CompoundStmt( location, { stmt } );
+	declsToAddAfter.push_back( decl );
+}
+
+void ConcurrentSueKeyword::addLockUnlockRoutines(
+		const ast::StructDecl * decl ) {
+	// This should only be used on monitors.
+	assert( ast::AggregateDecl::Monitor == cast_target );
+
+	const CodeLocation & location = decl->location;
+
+	// The parameter for both routines.
+	ast::ObjectDecl * this_decl = new ast::ObjectDecl(
+		location,
+		"this",
+		new ast::ReferenceType( new ast::StructInstType( decl ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::FunctionDecl * lock_decl = new ast::FunctionDecl(
+		location,
+		"lock",
+		{ /* forall */ },
+		{
+			// Copy the declaration of this.
+			ast::deepCopy( this_decl ),
+		},
+		{ /* returns */ },
+		nullptr,
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ /* attributes */ },
+		ast::Function::Inline
+	);
+	lock_decl = fixupGenerics( lock_decl, decl );
+
+	lock_decl->stmts = new ast::CompoundStmt( location, {
+		new ast::ExprStmt( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "lock" ),
+				{
+					new ast::UntypedExpr( location,
+						new ast::NameExpr( location, "get_monitor" ),
+						{ new ast::VariableExpr( location,
+							InitTweak::getParamThis( lock_decl ) ) }
+					)
+				}
+			)
+		)
+	} );
+
+	ast::FunctionDecl * unlock_decl = new ast::FunctionDecl(
+		location,
+		"unlock",
+		{ /* forall */ },
+		{
+			// Last use, consume the declaration of this.
+			this_decl,
+		},
+		{ /* returns */ },
+		nullptr,
+		ast::Storage::Static,
+		ast::Linkage::Cforall,
+		{ /* attributes */ },
+		ast::Function::Inline
+	);
+	unlock_decl = fixupGenerics( unlock_decl, decl );
+
+	unlock_decl->stmts = new ast::CompoundStmt( location, {
+		new ast::ExprStmt( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "unlock" ),
+				{
+					new ast::UntypedExpr( location,
+						new ast::NameExpr( location, "get_monitor" ),
+						{ new ast::VariableExpr( location,
+							InitTweak::getParamThis( unlock_decl ) ) }
+					)
+				}
+			)
+		)
+	} );
+
+	declsToAddAfter.push_back( lock_decl );
+	declsToAddAfter.push_back( unlock_decl );
+}
+
+
+// --------------------------------------------------------------------------
+struct SuspendKeyword final :
+		public ast::WithStmtsToAdd<>, public ast::WithGuards {
+	SuspendKeyword() = default;
+	virtual ~SuspendKeyword() = default;
+
+	void previsit( const ast::FunctionDecl * );
+	const ast::DeclWithType * postvisit( const ast::FunctionDecl * );
+	const ast::Stmt * postvisit( const ast::SuspendStmt * );
+
+private:
+	bool is_real_suspend( const ast::FunctionDecl * );
+
+	const ast::Stmt * make_generator_suspend( const ast::SuspendStmt * );
+	const ast::Stmt * make_coroutine_suspend( const ast::SuspendStmt * );
+
+	struct LabelPair {
+		ast::Label obj;
+		int idx;
+	};
+
+	LabelPair make_label(const ast::Stmt * stmt ) {
+		labels.push_back( ControlStruct::newLabel( "generator", stmt ) );
+		return { labels.back(), int(labels.size()) };
+	}
+
+	const ast::DeclWithType * in_generator = nullptr;
+	const ast::FunctionDecl * decl_suspend = nullptr;
+	std::vector<ast::Label> labels;
+};
+
+void SuspendKeyword::previsit( const ast::FunctionDecl * decl ) {
+	GuardValue( in_generator ); in_generator = nullptr;
+
+	// If it is the real suspend, grab it if we don't have one already.
+	if ( is_real_suspend( decl ) ) {
+		decl_suspend = decl_suspend ? decl_suspend : decl;
+		return;
+	}
+
+	// Otherwise check if this is a generator main and, if so, handle it.
+	auto param = isMainFor( decl, ast::AggregateDecl::Generator );
+	if ( !param ) return;
+
+	if ( 0 != decl->returns.size() ) {
+		SemanticError( decl->location, "Generator main must return void" );
+	}
+
+	in_generator = param;
+	GuardValue( labels ); labels.clear();
+}
+
+const ast::DeclWithType * SuspendKeyword::postvisit(
+		const ast::FunctionDecl * decl ) {
+	// Only modify a full definition of a generator with states.
+	if ( !decl->stmts || !in_generator || labels.empty() ) return decl;
+
+	const CodeLocation & location = decl->location;
+
+	// Create a new function body:
+	// static void * __generator_labels[] = {&&s0, &&s1, ...};
+	// void * __generator_label = __generator_labels[GEN.__generator_state];
+	// goto * __generator_label;
+	// s0: ;
+	// OLD_BODY
+
+	// This is the null statement inserted right before the body.
+	ast::NullStmt * noop = new ast::NullStmt( location );
+	noop->labels.push_back( ControlStruct::newLabel( "generator", noop ) );
+	const ast::Label & first_label = noop->labels.back();
+
+	// Add each label to the init, starting with the first label.
+	std::vector<ast::ptr<ast::Init>> inits = {
+		new ast::SingleInit( location,
+			new ast::LabelAddressExpr( location, copy( first_label ) ) ) };
+	// Then go through all the stored labels, and clear the store.
+	for ( auto && label : labels ) {
+		inits.push_back( new ast::SingleInit( label.location,
+			new ast::LabelAddressExpr( label.location, std::move( label )
+			) ) );
+	}
+	labels.clear();
+	// Then construct the initializer itself.
+	auto init = new ast::ListInit( location, std::move( inits ) );
+
+	ast::ObjectDecl * generatorLabels = new ast::ObjectDecl(
+		location,
+		"__generator_labels",
+		new ast::ArrayType(
+			new ast::PointerType( new ast::VoidType() ),
+			nullptr,
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		init,
+		ast::Storage::Classes(),
+		ast::Linkage::AutoGen
+	);
+
+	ast::ObjectDecl * generatorLabel = new ast::ObjectDecl(
+		location,
+		"__generator_label",
+		new ast::PointerType( new ast::VoidType() ),
+		new ast::SingleInit( location,
+			new ast::UntypedExpr( location,
+				new ast::NameExpr( location, "?[?]" ),
+				{
+					// TODO: Could be a variable expr.
+					new ast::NameExpr( location, "__generator_labels" ),
+					new ast::UntypedMemberExpr( location,
+						new ast::NameExpr( location, "__generator_state" ),
+						new ast::VariableExpr( location, in_generator )
+					)
+				}
+			)
+		),
+		ast::Storage::Classes(),
+		ast::Linkage::AutoGen
+	);
+
+	ast::BranchStmt * theGoTo = new ast::BranchStmt(
+		location, new ast::VariableExpr( location, generatorLabel )
+	);
+
+	// The noop goes here in order.
+
+	ast::CompoundStmt * body = new ast::CompoundStmt( location, {
+		{ new ast::DeclStmt( location, generatorLabels ) },
+		{ new ast::DeclStmt( location, generatorLabel ) },
+		{ theGoTo },
+		{ noop },
+		{ decl->stmts },
+	} );
+
+	auto mutDecl = ast::mutate( decl );
+	mutDecl->stmts = body;
+	return mutDecl;
+}
+
+const ast::Stmt * SuspendKeyword::postvisit( const ast::SuspendStmt * stmt ) {
+	switch ( stmt->type ) {
+	case ast::SuspendStmt::None:
+		// Use the context to determain the implicit target.
+		if ( in_generator ) {
+			return make_generator_suspend( stmt );
+		} else {
+			return make_coroutine_suspend( stmt );
+		}
+	case ast::SuspendStmt::Coroutine:
+		return make_coroutine_suspend( stmt );
+	case ast::SuspendStmt::Generator:
+		// Generator suspends must be directly in a generator.
+		if ( !in_generator ) SemanticError( stmt->location, "'suspend generator' must be used inside main of generator type." );
+		return make_generator_suspend( stmt );
+	}
+	assert( false );
+	return stmt;
+}
+
+/// Find the real/official suspend declaration.
+bool SuspendKeyword::is_real_suspend( const ast::FunctionDecl * decl ) {
+	return ( !decl->linkage.is_mangled
+		&& 0 == decl->params.size()
+		&& 0 == decl->returns.size()
+		&& "__cfactx_suspend" == decl->name );
+}
+
+const ast::Stmt * SuspendKeyword::make_generator_suspend(
+		const ast::SuspendStmt * stmt ) {
+	assert( in_generator );
+	// Target code is:
+	//   GEN.__generator_state = X;
+	//   THEN
+	//   return;
+	//   __gen_X:;
+
+	const CodeLocation & location = stmt->location;
+
+	LabelPair label = make_label( stmt );
+
+	// This is the context saving statement.
+	stmtsToAddBefore.push_back( new ast::ExprStmt( location,
+		new ast::UntypedExpr( location,
+			new ast::NameExpr( location, "?=?" ),
+			{
+				new ast::UntypedMemberExpr( location,
+					new ast::NameExpr( location, "__generator_state" ),
+					new ast::VariableExpr( location, in_generator )
+				),
+				ast::ConstantExpr::from_int( location, label.idx ),
+			}
+		)
+	) );
+
+	// The THEN component is conditional (return is not).
+	if ( stmt->then ) {
+		stmtsToAddBefore.push_back( stmt->then.get() );
+	}
+	stmtsToAddBefore.push_back( new ast::ReturnStmt( location, nullptr ) );
+
+	// The null statement replaces the old suspend statement.
+	return new ast::NullStmt( location, { label.obj } );
+}
+
+const ast::Stmt * SuspendKeyword::make_coroutine_suspend(
+		const ast::SuspendStmt * stmt ) {
+	// The only thing we need from the old statement is the location.
+	const CodeLocation & location = stmt->location;
+
+	if ( !decl_suspend ) {
+		SemanticError( location, "suspend keyword applied to coroutines requires coroutines to be in scope, add #include <coroutine.hfa>\n" );
+	}
+	if ( stmt->then ) {
+		SemanticError( location, "Compound statement following coroutines is not implemented." );
+	}
+
+	return new ast::ExprStmt( location,
+		new ast::UntypedExpr( location,
+			ast::VariableExpr::functionPointer( location, decl_suspend ) )
+	);
 }
 
@@ -251,5 +1088,5 @@
 				{
 					new ast::SingleInit( location,
-						new ast::AddressExpr(
+						new ast::AddressExpr( location,
 							new ast::VariableExpr( location, monitor ) ) ),
 					new ast::SingleInit( location,
@@ -564,8 +1401,12 @@
 
 // --------------------------------------------------------------------------
+// Interface Functions:
 
 void implementKeywords( ast::TranslationUnit & translationUnit ) {
-	(void)translationUnit;
-	assertf(false, "Apply Keywords not implemented." );
+	ast::Pass<ThreadKeyword>::run( translationUnit );
+	ast::Pass<CoroutineKeyword>::run( translationUnit );
+	ast::Pass<MonitorKeyword>::run( translationUnit );
+	ast::Pass<GeneratorKeyword>::run( translationUnit );
+	ast::Pass<SuspendKeyword>::run( translationUnit );
 }
 
Index: src/Validate/ForallPointerDecay.cpp
===================================================================
--- src/Validate/ForallPointerDecay.cpp	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Validate/ForallPointerDecay.cpp	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -70,9 +70,5 @@
 		AssertionList assertions;
 		// Substitute trait decl parameters for instance parameters.
-		ast::TypeSubstitution sub(
-			inst->base->params.begin(),
-			inst->base->params.end(),
-			inst->params.begin()
-		);
+		ast::TypeSubstitution sub( inst->base->params, inst->params );
 		for ( const ast::ptr<ast::Decl> & decl : inst->base->members ) {
 			ast::ptr<ast::DeclWithType> copy =
Index: src/Virtual/Tables.cc
===================================================================
--- src/Virtual/Tables.cc	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Virtual/Tables.cc	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -10,8 +10,15 @@
 // Created On       : Mon Aug 31 11:11:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr 21 15:36:00 2021
-// Update Count     : 2
-//
-
+// Last Modified On : Fri Mar 11 10:40:00 2022
+// Update Count     : 3
+//
+
+#include "AST/Attribute.hpp"
+#include "AST/Copy.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Init.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/Type.hpp"
 #include <SynTree/Attribute.h>
 #include <SynTree/Declaration.h>
@@ -77,7 +84,31 @@
 }
 
+static ast::ObjectDecl * makeVtableDeclaration(
+		CodeLocation const & location, std::string const & name,
+		ast::StructInstType const * type, ast::Init const * init ) {
+	ast::Storage::Classes storage;
+	if ( nullptr == init ) {
+		storage.is_extern = true;
+	}
+	return new ast::ObjectDecl(
+		location,
+		name,
+		type,
+		init,
+		storage,
+		ast::Linkage::Cforall
+	);
+}
+
 ObjectDecl * makeVtableForward( std::string const & name, StructInstType * type ) {
 	assert( type );
 	return makeVtableDeclaration( name, type, nullptr );
+}
+
+ast::ObjectDecl * makeVtableForward(
+		CodeLocation const & location, std::string const & name,
+		ast::StructInstType const * vtableType ) {
+	assert( vtableType );
+	return makeVtableDeclaration( location, name, vtableType, nullptr );
 }
 
@@ -123,4 +154,70 @@
 }
 
+static std::vector<ast::ptr<ast::Init>> buildInits(
+		CodeLocation const & location,
+		//std::string const & name,
+		ast::StructInstType const * vtableType,
+		ast::Type const * objectType ) {
+	ast::StructDecl const * vtableStruct = vtableType->base;
+
+	std::vector<ast::ptr<ast::Init>> inits;
+	inits.reserve( vtableStruct->members.size() );
+
+	// This is designed to run before the resolver.
+	for ( auto field : vtableStruct->members ) {
+		if ( std::string( "parent" ) == field->name ) {
+			// This will not work with polymorphic state.
+			auto oField = field.strict_as<ast::ObjectDecl>();
+			auto fieldType = oField->type.strict_as<ast::PointerType>();
+			auto parentType = fieldType->base.strict_as<ast::StructInstType>();
+			std::string const & parentInstance = instanceName( parentType->name );
+			inits.push_back(
+					new ast::SingleInit( location, new ast::AddressExpr( new ast::NameExpr( location, parentInstance ) ) ) );
+		} else if ( std::string( "__cfavir_typeid" ) == field->name ) {
+			std::string const & baseType = baseTypeName( vtableType->name );
+			std::string const & typeId = typeIdName( baseType );
+			inits.push_back( new ast::SingleInit( location, new ast::AddressExpr( new ast::NameExpr( location, typeId ) ) ) );
+		} else if ( std::string( "size" ) == field->name ) {
+			inits.push_back( new ast::SingleInit( location, new ast::SizeofExpr( location, objectType )
+			) );
+		} else if ( std::string( "align" ) == field->name ) {
+			inits.push_back( new ast::SingleInit( location,
+				new ast::AlignofExpr( location, objectType )
+			) );
+		} else {
+			inits.push_back( new ast::SingleInit( location,
+				new ast::NameExpr( location, field->name )
+			) );
+		}
+		//ast::Expr * expr = buildInitExpr(...);
+		//inits.push_back( new ast::SingleInit( location, expr ) )
+	}
+
+	return inits;
+}
+
+ast::ObjectDecl * makeVtableInstance(
+		CodeLocation const & location,
+		std::string const & name,
+		ast::StructInstType const * vtableType,
+		ast::Type const * objectType,
+		ast::Init const * init ) {
+	assert( vtableType );
+	assert( objectType );
+
+	// Build the initialization.
+	if ( nullptr == init ) {
+		init = new ast::ListInit( location,
+			buildInits( location, vtableType, objectType ) );
+
+	// The provided init should initialize everything except the parent
+	// pointer, the size-of and align-of fields. These should be inserted.
+	} else {
+		// Except this is not yet supported.
+		assert(false);
+	}
+	return makeVtableDeclaration( location, name, vtableType, init );
+}
+
 namespace {
 	std::string const functionName = "get_exception_vtable";
@@ -140,5 +237,5 @@
 		new ReferenceType( noQualifiers, vtableType ),
 		nullptr,
-        { new Attribute("unused") }
+		{ new Attribute("unused") }
 	) );
 	type->parameters.push_back( new ObjectDecl(
@@ -157,4 +254,31 @@
 		type,
 		nullptr
+	);
+}
+
+ast::FunctionDecl * makeGetExceptionForward(
+		CodeLocation const & location,
+		ast::Type const * vtableType,
+		ast::Type const * exceptType ) {
+	assert( vtableType );
+	assert( exceptType );
+	return new ast::FunctionDecl(
+		location,
+		functionName,
+		{ /* forall */ },
+		{ new ast::ObjectDecl(
+			location,
+			"__unused",
+			new ast::PointerType( exceptType )
+		) },
+		{ new ast::ObjectDecl(
+			location,
+			"_retvalue",
+			new ast::ReferenceType( vtableType )
+		) },
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall,
+		{ new ast::Attribute( "unused" ) }
 	);
 }
@@ -172,4 +296,17 @@
 }
 
+ast::FunctionDecl * makeGetExceptionFunction(
+		CodeLocation const & location,
+		ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType ) {
+	assert( vtableInstance );
+	assert( exceptType );
+	ast::FunctionDecl * func = makeGetExceptionForward(
+			location, ast::deepCopy( vtableInstance->type ), exceptType );
+	func->stmts = new ast::CompoundStmt( location, {
+		new ast::ReturnStmt( location, new ast::VariableExpr( location, vtableInstance ) )
+	} );
+	return func;
+}
+
 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType ) {
 	assert( typeIdType );
@@ -191,3 +328,26 @@
 }
 
-}
+ast::ObjectDecl * makeTypeIdInstance(
+		CodeLocation const & location,
+		ast::StructInstType const * typeIdType ) {
+	assert( typeIdType );
+	ast::StructInstType * type = ast::mutate( typeIdType );
+	type->set_const( true );
+	std::string const & typeid_name = typeIdTypeToInstance( typeIdType->name );
+	return new ast::ObjectDecl(
+		location,
+		typeid_name,
+		type,
+		new ast::ListInit( location, {
+			new ast::SingleInit( location,
+				new ast::AddressExpr( location,
+					new ast::NameExpr( location, "__cfatid_exception_t" ) ) )
+		} ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall,
+		nullptr,
+		{ new ast::Attribute( "cfa_linkonce" ) }
+	);
+}
+
+}
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/Virtual/Tables.h	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -10,10 +10,12 @@
 // Created On       : Mon Aug 31 11:07:00 2020
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Apr 21 10:30:00 2021
-// Update Count     : 2
+// Last Modified On : Wec Dec  8 16:58:00 2021
+// Update Count     : 3
 //
 
 #include <list>  // for list
 
+#include <string>
+#include "AST/Fwd.hpp"
 class Declaration;
 class StructDecl;
@@ -35,4 +37,7 @@
  * vtableType node is consumed.
  */
+ast::ObjectDecl * makeVtableForward(
+	CodeLocation const & location, std::string const & name,
+	ast::StructInstType const * vtableType );
 
 ObjectDecl * makeVtableInstance(
@@ -43,4 +48,10 @@
  * vtableType and init (if provided) nodes are consumed.
  */
+ast::ObjectDecl * makeVtableInstance(
+	CodeLocation const & location,
+	std::string const & name,
+	ast::StructInstType const * vtableType,
+	ast::Type const * objectType,
+	ast::Init const * init = nullptr );
 
 // Some special code for how exceptions interact with virtual tables.
@@ -49,4 +60,8 @@
  * linking the vtableType to the exceptType. Both nodes are consumed.
  */
+ast::FunctionDecl * makeGetExceptionForward(
+	CodeLocation const & location,
+	ast::Type const * vtableType,
+	ast::Type const * exceptType );
 
 FunctionDecl * makeGetExceptionFunction(
@@ -55,4 +70,7 @@
  * exceptType node is consumed.
  */
+ast::FunctionDecl * makeGetExceptionFunction(
+	CodeLocation const & location,
+	ast::ObjectDecl const * vtableInstance, ast::Type const * exceptType );
 
 ObjectDecl * makeTypeIdInstance( StructInstType const * typeIdType );
@@ -60,4 +78,6 @@
  * TODO: Should take the parent type. Currently locked to the exception_t.
  */
+ast::ObjectDecl * makeTypeIdInstance(
+	const CodeLocation & location, ast::StructInstType const * typeIdType );
 
 }
Index: src/main.cc
===================================================================
--- src/main.cc	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ src/main.cc	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Jan 26 14:09:00 2022
-// Update Count     : 670
+// Last Modified On : Fri Mar 11 10:39:00 2022
+// Update Count     : 671
 //
 
@@ -333,9 +333,4 @@
 
 		if( useNewAST ) {
-			PASS( "Implement Concurrent Keywords", Concurrency::applyKeywords( translationUnit ) );
-			//PASS( "Forall Pointer Decay - A", SymTab::decayForallPointersA( translationUnit ) );
-			//PASS( "Forall Pointer Decay - B", SymTab::decayForallPointersB( translationUnit ) );
-			//PASS( "Forall Pointer Decay - C", SymTab::decayForallPointersC( translationUnit ) );
-			//PASS( "Forall Pointer Decay - D", SymTab::decayForallPointersD( translationUnit ) );
 			CodeTools::fillLocations( translationUnit );
 
@@ -347,4 +342,6 @@
 
 			forceFillCodeLocations( transUnit );
+
+			PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
 
 			// Must be after implement concurrent keywords; because uniqueIds
@@ -497,6 +494,4 @@
 			PASS( "Translate Tries" , ControlStruct::translateTries( translationUnit ) );
 		}
-
-		
 
 		PASS( "Gen Waitfor" , Concurrency::generateWaitFor( translationUnit ) );
Index: tests/concurrent/.expect/keywordErrors.nast.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.nast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
+++ tests/concurrent/.expect/keywordErrors.nast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -0,0 +1,6 @@
+concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread A with body
+
+concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread B with body
+
Index: tests/concurrent/.expect/keywordErrors.oast.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.oast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
+++ tests/concurrent/.expect/keywordErrors.oast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -0,0 +1,6 @@
+concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread A: with body 1
+
+concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread B: with body 1
+
Index: sts/concurrent/.expect/keywordErrors.txt
===================================================================
--- tests/concurrent/.expect/keywordErrors.txt	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ 	(revision )
@@ -1,6 +1,0 @@
-concurrent/keywordErrors.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-thread A: with body 1
-
-concurrent/keywordErrors.cfa:6:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-thread B: with body 1
-
Index: tests/concurrent/.expect/mainError.nast.txt
===================================================================
--- tests/concurrent/.expect/mainError.nast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
+++ tests/concurrent/.expect/mainError.nast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -0,0 +1,11 @@
+concurrent/mainError.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread Test with body
+
+concurrent/mainError.cfa:2:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+main: function
+... with parameters
+  reference to instance of struct Test with body
+... returning nothing
+ with body
+  Compound Statement:
+
Index: tests/concurrent/.expect/mainError.oast.txt
===================================================================
--- tests/concurrent/.expect/mainError.oast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
+++ tests/concurrent/.expect/mainError.oast.txt	(revision 4f6dda063e7b3a906904ff494b7cf4bb41f5a5c5)
@@ -0,0 +1,11 @@
+concurrent/mainError.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+thread Test: with body 1
+
+concurrent/mainError.cfa:2:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
+main: function
+... with parameters
+  reference to instance of struct Test with body 1
+... returning nothing
+... with body
+  CompoundStmt
+
Index: sts/concurrent/.expect/mainError.txt
===================================================================
--- tests/concurrent/.expect/mainError.txt	(revision b05308311d934d0d8b5bd3010e77f9240dc4ca24)
+++ 	(revision )
@@ -1,11 +1,0 @@
-concurrent/mainError.cfa:1:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-thread Test: with body 1
-
-concurrent/mainError.cfa:2:1 error: thread keyword requires threads to be in scope, add #include <thread.hfa>
-main: function
-... with parameters
-  reference to instance of struct Test with body 1
-... returning nothing
-... with body
-  CompoundStmt
-
