Index: src/Concurrency/Keywords.h
===================================================================
--- src/Concurrency/Keywords.h	(revision 0351e9f1e5c3fe891d91f323ca0e444084c78b16)
+++ src/Concurrency/Keywords.h	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Keywords.h --
+// Keywords.h -- Implement concurrency constructs from their keywords.
 //
 // Author           : Thierry Delisle
@@ -19,4 +19,7 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace Concurrency {
@@ -24,4 +27,11 @@
 	void implementMutexFuncs( std::list< Declaration * > & translationUnit );
 	void implementThreadStarter( std::list< Declaration * > & translationUnit );
+
+/// Implement the sue-like keywords and the suspend keyword.
+void implementKeywords( ast::TranslationUnit & translationUnit );
+/// Implement the mutex parameters and mutex statement.
+void implementMutex( ast::TranslationUnit & translationUnit );
+/// Add the thread starter code to constructors.
+void implementThreadStarter( ast::TranslationUnit & translationUnit );
 };
 
Index: src/Concurrency/KeywordsNew.cpp
===================================================================
--- src/Concurrency/KeywordsNew.cpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
+++ src/Concurrency/KeywordsNew.cpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -0,0 +1,588 @@
+//
+// 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.
+//
+// KeywordsNew.cpp -- Implement concurrency constructs from their keywords.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Nov 16  9:53:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Nov 30 11:04:00 2021
+// Update Count     : 0
+//
+
+#include "Concurrency/Keywords.h"
+
+#include "AST/Copy.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "CodeGen/OperatorTable.h"
+#include "Common/utility.h"
+#include "InitTweak/InitTweak.h"
+
+namespace Concurrency {
+
+namespace {
+
+inline static 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();
+}
+
+// --------------------------------------------------------------------------
+struct MutexKeyword final {
+	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
+	void postvisit( const ast::StructDecl * decl );
+	const ast::Stmt * postvisit( const ast::MutexStmt * stmt );
+
+	std::vector<const ast::DeclWithType *> findMutexArgs(
+			const ast::FunctionDecl * decl, bool & first );
+	void validate( const ast::DeclWithType * decl );
+	ast::CompoundStmt * addDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
+	ast::CompoundStmt * addStatements( const ast::FunctionDecl* func, const ast::CompoundStmt *, const std::vector<const ast::DeclWithType *> &);
+	ast::CompoundStmt * addStatements( const ast::CompoundStmt * body, const std::vector<ast::ptr<ast::Expr>> & args );
+	ast::CompoundStmt * addThreadDtorStatements( const ast::FunctionDecl* func, const ast::CompoundStmt * body, const std::vector<const ast::DeclWithType *> & args );
+
+public:
+	const ast::StructDecl * monitor_decl = nullptr;
+	const ast::StructDecl * guard_decl = nullptr;
+	const ast::StructDecl * dtor_guard_decl = nullptr;
+	const ast::StructDecl * thread_guard_decl = nullptr;
+	const ast::StructDecl * lock_guard_decl = nullptr;
+
+	static ast::ptr<ast::Type> generic_func;
+};
+
+const ast::FunctionDecl * MutexKeyword::postvisit(
+		const ast::FunctionDecl * decl ) {
+	bool is_first_argument_mutex = false;
+	const std::vector<const ast::DeclWithType *> mutexArgs =
+		findMutexArgs( decl, is_first_argument_mutex );
+	bool const isDtor = CodeGen::isDestructor( decl->name );
+
+	// Does this function have any mutex arguments that connect to monitors?
+	if ( mutexArgs.empty() ) {
+		// If this is the destructor for a monitor it must be mutex.
+		if ( isDtor ) {
+			// This reflects MutexKeyword::validate, but no error messages.
+			const ast::Type * type = decl->type->params.front();
+
+			// If it's a copy, it's not a mutex.
+			const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
+			if ( nullptr == refType ) {
+				return decl;
+			}
+
+			// If it is not pointing directly to a type, it's not a mutex.
+			auto base = refType->base;
+			if ( base.as<ast::ReferenceType>() ) return decl;
+			if ( base.as<ast::PointerType>() ) return decl;
+
+			// If it is not a struct, it's not a mutex.
+			auto baseStruct = base.as<ast::StructInstType>();
+			if ( nullptr == baseStruct ) return decl;
+
+			// If it is a monitor, then it is a monitor.
+			if( baseStruct->base->is_monitor() || baseStruct->base->is_thread() ) {
+				SemanticError( decl, "destructors for structures declared as \"monitor\" must use mutex parameters\n" );
+			}
+		}
+		return decl;
+	}
+
+	// Monitors can't be constructed with mutual exclusion.
+	if ( CodeGen::isConstructor( decl->name ) && !is_first_argument_mutex ) {
+		SemanticError( decl, "constructors cannot have mutex parameters" );
+	}
+
+	// It makes no sense to have multiple mutex parameters for the destructor.
+	if ( isDtor && mutexArgs.size() != 1 ) {
+		SemanticError( decl, "destructors can only have 1 mutex argument" );
+	}
+
+	// Make sure all the mutex arguments are monitors.
+	for ( auto arg : mutexArgs ) {
+		validate( arg );
+	}
+
+	// Check to see if the body needs to be instrument the body.
+	const ast::CompoundStmt * body = decl->stmts;
+	if ( !body ) return decl;
+
+	// Check to if the required headers have been seen.
+	if ( !monitor_decl || !guard_decl || !dtor_guard_decl ) {
+		SemanticError( decl, "mutex keyword requires monitors to be in scope, add #include <monitor.hfa>\n" );
+	}
+
+	// Instrument the body.
+	ast::CompoundStmt * newBody = nullptr;
+	if ( isDtor && isThread( mutexArgs.front() ) ) {
+		if ( !thread_guard_decl ) {
+			SemanticError( decl, "thread destructor requires threads to be in scope, add #include <thread.hfa>\n" );
+		}
+		newBody = addThreadDtorStatements( decl, body, mutexArgs );
+	} else if ( isDtor ) {
+		newBody = addDtorStatements( decl, body, mutexArgs );
+	} else {
+		newBody = addStatements( decl, body, mutexArgs );
+	}
+	assert( newBody );
+	return ast::mutate_field( decl, &ast::FunctionDecl::stmts, newBody );
+}
+
+void MutexKeyword::postvisit( const ast::StructDecl * decl ) {
+	if ( !decl->body ) {
+		return;
+	} else if ( decl->name == "monitor$" ) {
+		assert( !monitor_decl );
+		monitor_decl = decl;
+	} else if ( decl->name == "monitor_guard_t" ) {
+		assert( !guard_decl );
+		guard_decl = decl;
+	} else if ( decl->name == "monitor_dtor_guard_t" ) {
+		assert( !dtor_guard_decl );
+		dtor_guard_decl = decl;
+	} else if ( decl->name == "thread_dtor_guard_t" ) {
+		assert( !thread_guard_decl );
+		thread_guard_decl = decl;
+	} else if ( decl->name == "__mutex_stmt_lock_guard" ) {
+		assert( !lock_guard_decl );
+		lock_guard_decl = decl;
+	}
+}
+
+const ast::Stmt * MutexKeyword::postvisit( const ast::MutexStmt * stmt ) {
+	ast::CompoundStmt * body =
+			new ast::CompoundStmt( stmt->location, { stmt->stmt } );
+	addStatements( body, stmt->mutexObjs );
+	return body;
+}
+
+std::vector<const ast::DeclWithType *> MutexKeyword::findMutexArgs(
+		const ast::FunctionDecl * decl, bool & first ) {
+	std::vector<const ast::DeclWithType *> mutexArgs;
+
+	bool once = true;
+	for ( auto arg : decl->params ) {
+		const ast::Type * type = arg->get_type();
+		if ( !type->is_mutex() ) continue;
+
+		if ( once ) {
+			first = true;
+			once = false;
+		}
+
+		mutexArgs.push_back( arg.get() );
+	}
+	return mutexArgs;
+}
+
+void MutexKeyword::validate( const ast::DeclWithType * decl ) {
+	const ast::Type * type = decl->get_type();
+
+	// If it's a copy, it's not a mutex.
+	const ast::ReferenceType * refType = dynamic_cast<const ast::ReferenceType *>( type );
+	if ( nullptr == refType ) {
+		SemanticError( decl, "Mutex argument must be of reference type " );
+	}
+
+	// If it is not pointing directly to a type, it's not a mutex.
+	auto base = refType->base;
+	if ( base.as<ast::ReferenceType>() || base.as<ast::PointerType>() ) {
+		SemanticError( decl, "Mutex argument have exactly one level of indirection " );
+	}
+
+	// If it is not a struct, it's not a mutex.
+	auto baseStruct = base.as<ast::StructInstType>();
+	if ( nullptr == baseStruct ) return;
+
+	// Make sure that only the outer reference is mutex.
+	if( baseStruct->is_mutex() ) {
+		SemanticError( decl, "mutex keyword may only appear once per argument " );
+	}
+}
+
+ast::CompoundStmt * MutexKeyword::addDtorStatements(
+		const ast::FunctionDecl* func, const ast::CompoundStmt * body,
+		const std::vector<const ast::DeclWithType *> & args ) {
+	ast::Type * argType = ast::shallowCopy( args.front()->get_type() );
+	argType->set_mutex( false );
+
+	ast::CompoundStmt * mutBody = ast::mutate( body );
+
+	// Generated code goes near the beginning of body:
+	const CodeLocation & location = mutBody->location;
+
+	const ast::ObjectDecl * monitor = new ast::ObjectDecl(
+		location,
+		"__monitor",
+		new ast::PointerType( new ast::StructInstType( monitor_decl ) ),
+		new ast::SingleInit(
+			location,
+			new ast::UntypedExpr(
+				location,
+				new ast::NameExpr( location, "get_monitor" ),
+				{ new ast::CastExpr(
+					location,
+					new ast::VariableExpr( location, args.front() ),
+					argType, ast::ExplicitCast
+				) }
+			)
+		),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	assert( generic_func );
+
+	// In reverse order:
+	// monitor_dtor_guard_t __guard = { __monitor, func, false };
+	mutBody->push_front(
+		new ast::DeclStmt( location, new ast::ObjectDecl(
+			location,
+			"__guard",
+			new ast::StructInstType( dtor_guard_decl ),
+			new ast::ListInit(
+				location,
+				{
+					new ast::SingleInit( location,
+						new ast::AddressExpr(
+							new ast::VariableExpr( location, monitor ) ) ),
+					new ast::SingleInit( location,
+						new ast::CastExpr( location,
+							new ast::VariableExpr( location, func ),
+							generic_func,
+							ast::ExplicitCast ) ),
+					new ast::SingleInit( location,
+						ast::ConstantExpr::from_bool( location, false ) ),
+				},
+				{},
+				ast::MaybeConstruct
+			),
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		))
+	);
+
+	// monitor$ * __monitor = get_monitor(a);
+	mutBody->push_front( new ast::DeclStmt( location, monitor ) );
+
+	return mutBody;
+}
+
+ast::CompoundStmt * MutexKeyword::addStatements(
+		const ast::FunctionDecl* func, const ast::CompoundStmt * body,
+		const std::vector<const ast::DeclWithType * > & args ) {
+	ast::CompoundStmt * mutBody = ast::mutate( body );
+
+	// Code is generated near the beginning of the compound statement.
+	const CodeLocation & location = mutBody->location;
+
+	// Make pointer to the monitors.
+	ast::ObjectDecl * monitors = new ast::ObjectDecl(
+		location,
+		"__monitors",
+		new ast::ArrayType(
+			new ast::PointerType(
+				new ast::StructInstType( monitor_decl )
+			),
+			ast::ConstantExpr::from_ulong( location, args.size() ),
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		new ast::ListInit(
+			location,
+			map_range<std::vector<ast::ptr<ast::Init>>>(
+				args,
+				[]( const ast::DeclWithType * decl ) {
+					return new ast::SingleInit(
+						decl->location,
+						new ast::UntypedExpr(
+							decl->location,
+							new ast::NameExpr( decl->location, "get_monitor" ),
+							{
+								new ast::CastExpr(
+									decl->location,
+									new ast::VariableExpr( decl->location, decl ),
+									decl->get_type(),
+									ast::ExplicitCast
+								)
+							}
+						)
+					);
+				}
+			)
+		),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	assert( generic_func );
+
+	// In Reverse Order:
+	mutBody->push_front(
+		new ast::DeclStmt( location, new ast::ObjectDecl(
+			location,
+			"__guard",
+			new ast::StructInstType( guard_decl ),
+			new ast::ListInit(
+				location,
+				{
+					new ast::SingleInit( location,
+						new ast::VariableExpr( location, monitors ) ),
+					new ast::SingleInit( location,
+						ast::ConstantExpr::from_ulong( location, args.size() ) ),
+					new ast::SingleInit( location, new ast::CastExpr(
+						location,
+						new ast::VariableExpr( location, func ),
+						generic_func,
+						ast::ExplicitCast
+					) ),
+				},
+				{},
+				ast::MaybeConstruct
+			),
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		))
+	);
+
+	// monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
+	mutBody->push_front( new ast::DeclStmt( location, monitors ) );
+
+	return mutBody;
+}
+
+ast::CompoundStmt * MutexKeyword::addStatements(
+		const ast::CompoundStmt * body,
+		const std::vector<ast::ptr<ast::Expr>> & args ) {
+	ast::CompoundStmt * mutBody = ast::mutate( body );
+
+	// Code is generated near the beginning of the compound statement.
+	const CodeLocation & location = mutBody->location;
+
+	// Make pointer to the monitors.
+	ast::ObjectDecl * monitors = new ast::ObjectDecl(
+		location,
+		"__monitors",
+		new ast::ArrayType(
+			new ast::PointerType(
+				new ast::TypeofType(
+					new ast::UntypedExpr(
+						location,
+						new ast::NameExpr( location, "__get_type" ),
+						{ args.front() }
+					)
+				)
+			),
+			ast::ConstantExpr::from_ulong( location, args.size() ),
+			ast::FixedLen,
+			ast::DynamicDim
+		),
+		new ast::ListInit(
+			location,
+			map_range<std::vector<ast::ptr<ast::Init>>>(
+				args, [](const ast::Expr * expr) {
+					return new ast::SingleInit(
+						expr->location,
+						new ast::UntypedExpr(
+							expr->location,
+							new ast::NameExpr( expr->location, "__get_ptr" ),
+							{ expr }
+						)
+					);
+				}
+			)
+		),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+
+	ast::StructInstType * lock_guard_struct =
+			new ast::StructInstType( lock_guard_decl );
+	ast::TypeExpr * lock_type_expr = new ast::TypeExpr(
+		location,
+		new ast::TypeofType(
+			new ast::UntypedExpr(
+				location,
+				new ast::NameExpr( location, "__get_type" ),
+				{ args.front() }
+			)
+		)
+	);
+
+	lock_guard_struct->params.push_back( lock_type_expr );
+
+	// In reverse order:
+	// monitor_guard_t __guard = { __monitors, # };
+	mutBody->push_front(
+		new ast::DeclStmt(
+			location,
+			new ast::ObjectDecl(
+				location,
+				"__guard",
+				lock_guard_struct,
+				new ast::ListInit(
+					location,
+					{
+						new ast::SingleInit(
+							location,
+							new ast::VariableExpr( location, monitors ) ),
+						new ast::SingleInit(
+							location,
+							ast::ConstantExpr::from_ulong( location, args.size() ) ),
+					},
+					{},
+					ast::MaybeConstruct
+				),
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			)
+		)
+	);
+
+	// monitor$ * __monitors[] = { get_monitor(a), get_monitor(b) };
+	mutBody->push_front( new ast::DeclStmt( location, monitors ) );
+
+	return mutBody;
+}
+
+ast::CompoundStmt * MutexKeyword::addThreadDtorStatements(
+		const ast::FunctionDecl*, const ast::CompoundStmt * body,
+		const std::vector<const ast::DeclWithType * > & args ) {
+	assert( args.size() == 1 );
+	const ast::DeclWithType * arg = args.front();
+	const ast::Type * argType = arg->get_type();
+	assert( argType->is_mutex() );
+
+	ast::CompoundStmt * mutBody = ast::mutate( body );
+
+	// The code is generated near the front of the body.
+	const CodeLocation & location = mutBody->location;
+
+	// thread_dtor_guard_t __guard = { this, intptr( 0 ) };
+	mutBody->push_front( new ast::DeclStmt(
+		location,
+		new ast::ObjectDecl(
+			location,
+			"__guard",
+			new ast::StructInstType( thread_guard_decl ),
+			new ast::ListInit(
+				location,
+				{
+					new ast::SingleInit( location,
+						new ast::CastExpr( location,
+							new ast::VariableExpr( location, arg ), argType ) ),
+					new ast::SingleInit(
+						location,
+						new ast::UntypedExpr(
+							location,
+							new ast::NameExpr( location, "intptr" ), {
+								ast::ConstantExpr::from_int( location, 0 ),
+							}
+						) ),
+				},
+				{},
+				ast::MaybeConstruct
+			),
+			ast::Storage::Classes(),
+			ast::Linkage::Cforall
+		)
+	));
+
+	return mutBody;
+}
+
+ast::ptr<ast::Type> MutexKeyword::generic_func =
+	new ast::FunctionType( ast::VariableArgs );
+
+// --------------------------------------------------------------------------
+struct ThreadStarter final {
+	void previsit( const ast::StructDecl * decl );
+	const ast::FunctionDecl * postvisit( const ast::FunctionDecl * decl );
+
+private:
+	bool thread_ctor_seen = false;
+	const ast::StructDecl * thread_decl = nullptr;
+};
+
+void ThreadStarter::previsit( const ast::StructDecl * decl ) {
+	if ( decl->body && decl->name == "thread$" ) {
+		assert( !thread_decl );
+		thread_decl = decl;
+	}
+}
+
+const ast::FunctionDecl * ThreadStarter::postvisit( const ast::FunctionDecl * decl ) {
+	if ( !CodeGen::isConstructor( decl->name ) ) return decl;
+
+	// Seach for the thread constructor.
+	// (Are the "prefixes" of these to blocks the same?)
+	const ast::Type * typeof_this = InitTweak::getTypeofThis( decl->type );
+	auto ctored_type = dynamic_cast<const ast::StructInstType *>( typeof_this );
+	if ( ctored_type && ctored_type->base == thread_decl ) {
+		thread_ctor_seen = true;
+	}
+
+	// Modify this declaration, the extra checks to see if we will are first.
+	const ast::ptr<ast::DeclWithType> & param = decl->params.front();
+	auto type = dynamic_cast<const ast::StructInstType *>(
+		InitTweak::getPointerBase( param->get_type() ) );
+	if ( nullptr == type ) return decl;
+	if ( !type->base->is_thread() ) return decl;
+	if ( !thread_decl || !thread_ctor_seen ) {
+		SemanticError( type->base->location, "thread keyword requires threads to be in scope, add #include <thread.hfa>" );
+	}
+	const ast::CompoundStmt * stmt = decl->stmts;
+	if ( nullptr == stmt ) return decl;
+
+	// Now do the actual modification:
+	ast::CompoundStmt * mutStmt = ast::mutate( stmt );
+	const CodeLocation & location = mutStmt->location;
+	mutStmt->push_back(
+		new ast::ExprStmt(
+			location,
+			new ast::UntypedExpr(
+				location,
+				new ast::NameExpr( location, "__thrd_start" ),
+				{
+					new ast::VariableExpr( location, param ),
+					new ast::NameExpr( location, "main" ),
+				}
+			)
+		)
+	);
+
+	return ast::mutate_field( decl, &ast::FunctionDecl::stmts, mutStmt );
+}
+
+} // namespace
+
+// --------------------------------------------------------------------------
+
+void implementKeywords( ast::TranslationUnit & translationUnit ) {
+	(void)translationUnit;
+	assertf(false, "Apply Keywords not implemented." );
+}
+
+void implementMutex( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<MutexKeyword>::run( translationUnit );
+}
+
+void implementThreadStarter( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<ThreadStarter>::run( translationUnit );
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Concurrency/module.mk
===================================================================
--- src/Concurrency/module.mk	(revision 0351e9f1e5c3fe891d91f323ca0e444084c78b16)
+++ src/Concurrency/module.mk	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -15,5 +15,13 @@
 ###############################################################################
 
-SRC += Concurrency/Keywords.cc Concurrency/Keywords.h Concurrency/Waitfor.cc Concurrency/Waitfor.h
-SRCDEMANGLE += Concurrency/Keywords.cc
+SRC_CONCURRENCY = \
+	Concurrency/KeywordsNew.cpp \
+	Concurrency/Keywords.cc
 
+SRC += $(SRC_CONCURRENCY) \
+	Concurrency/Keywords.h \
+	Concurrency/Waitfor.cc \
+	Concurrency/Waitfor.h
+
+SRCDEMANGLE += $(SRC_CONCURRENCY)
+
Index: src/Validate/CompoundLiteral.cpp
===================================================================
--- src/Validate/CompoundLiteral.cpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
+++ src/Validate/CompoundLiteral.cpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -0,0 +1,70 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CompoundLiteral.cpp -- Use variables to implement compound literals.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Nov 15 16:33:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Nov 16  9:47:00 2021
+// Update Count     : 0
+//
+
+#include "CompoundLiteral.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "Common/UniqueName.h"
+
+namespace Validate {
+
+namespace {
+
+struct CompoundLiteral final :
+		public ast::WithDeclsToAdd<>,
+		public ast::WithVisitorRef<CompoundLiteral> {
+	ast::Storage::Classes storageClasses;
+
+	void previsit( const ast::ObjectDecl * decl );
+	const ast::Expr * postvisit( const ast::CompoundLiteralExpr * expr );
+};
+
+void CompoundLiteral::previsit( const ast::ObjectDecl * decl ) {
+	storageClasses = decl->storage;
+}
+
+const ast::Expr * CompoundLiteral::postvisit(
+		const ast::CompoundLiteralExpr * expr ) {
+	static UniqueName litName( "_compLit" );
+
+	// Transform: [storageClasses] ... (struct S){...} ...
+	// Into:      [storageClasses] struct S _compLit = {...}; / ... temp ...
+	ast::ObjectDecl * temp = new ast::ObjectDecl(
+		expr->location,
+		litName.newName(),
+		expr->result,
+		expr->init,
+		storageClasses
+		);
+	declsToAddBefore.push_back( temp );
+	return new ast::VariableExpr( expr->location, temp );
+}
+
+} // namespace
+
+void handleCompoundLiterals( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<CompoundLiteral>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/CompoundLiteral.hpp
===================================================================
--- src/Validate/CompoundLiteral.hpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
+++ src/Validate/CompoundLiteral.hpp	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -0,0 +1,33 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// CompoundLiteral.hpp -- Use variables to implement compound literals.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Nov 15 16:37:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Nov 15 17:56:00 2021
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Use variables to implement compound literals.
+void handleCompoundLiterals( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/module.mk
===================================================================
--- src/Validate/module.mk	(revision 0351e9f1e5c3fe891d91f323ca0e444084c78b16)
+++ src/Validate/module.mk	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -16,4 +16,6 @@
 
 SRC_VALIDATE = \
+	Validate/CompoundLiteral.cpp \
+	Validate/CompoundLiteral.hpp \
 	Validate/HandleAttributes.cc \
 	Validate/HandleAttributes.h \
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 0351e9f1e5c3fe891d91f323ca0e444084c78b16)
+++ src/main.cc	(revision 2cf3b87c585cfb9fa6dcb8ea9d77ad576fccea3b)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Nov 12 11:06:00 2021
-// Update Count     : 658
+// Last Modified On : Tue Nov 30 10:25:00 2021
+// Update Count     : 659
 //
 
@@ -50,4 +50,5 @@
 #include "Common/UnimplementedError.h"      // for UnimplementedError
 #include "Common/utility.h"                 // for deleteAll, filter, printAll
+#include "Concurrency/Keywords.h"           // for implementMutex, implement...
 #include "Concurrency/Waitfor.h"            // for generateWaitfor
 #include "ControlStruct/ExceptDecl.h"       // for translateExcept
@@ -73,4 +74,5 @@
 #include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
 #include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
+#include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
 #include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
 #include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
@@ -325,5 +327,4 @@
 		PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
 		PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
-		PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
 
 		CodeTools::fillLocations( translationUnit );
@@ -338,4 +339,7 @@
 			forceFillCodeLocations( transUnit );
 
+			PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
+			PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
+			PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
 			PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
 			PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
@@ -402,4 +406,5 @@
 			translationUnit = convert( move( transUnit ) );
 		} else {
+			PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
 			PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
 
