Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/AST/Convert.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -168,4 +168,7 @@
 		auto attr = get<Attribute>().acceptL( node->attributes );
 
+		// This field can be unset very early on (Pre-FixReturnTypes).
+		auto newType = (type) ? type->clone() : nullptr;
+
 		auto decl = new ObjectDecl(
 			node->name,
@@ -173,5 +176,5 @@
 			LinkageSpec::Spec( node->linkage.val ),
 			bfwd,
-			type->clone(),
+			newType,
 			nullptr, // prevent infinite loop
 			attr,
@@ -1579,11 +1582,12 @@
 
 	virtual void visit( const ObjectDecl * old ) override final {
+		if ( inCache( old ) ) {
+			return;
+		}
 		auto&& type = GET_ACCEPT_1(type, Type);
 		auto&& init = GET_ACCEPT_1(init, Init);
 		auto&& bfwd = GET_ACCEPT_1(bitfieldWidth, Expr);
 		auto&& attr = GET_ACCEPT_V(attributes, Attribute);
-		if ( inCache( old ) ) {
-			return;
-		}
+
 		auto decl = new ast::ObjectDecl(
 			old->location,
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/AST/Decl.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -315,6 +315,6 @@
 
 	EnumDecl( const CodeLocation& loc, const std::string& name,
-		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, Type * base = nullptr,
-		 std::unordered_map< std::string, long long > enumValues = std::unordered_map< std::string, long long >() )
+		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, Type const * base = nullptr,
+		std::unordered_map< std::string, long long > enumValues = std::unordered_map< std::string, long long >() )
 	: AggregateDecl( loc, name, std::move(attrs), linkage ), base(base), enumValues(enumValues) {}
 
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/AST/Expr.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -272,5 +272,5 @@
 	// Adjust the length of the string for the terminator.
 	const Expr * strSize = from_ulong( loc, str.size() + 1 );
-	const Type * strType = new ArrayType( charType, strSize, FixedLen, StaticDim );
+	const Type * strType = new ArrayType( charType, strSize, FixedLen, DynamicDim );
 	const std::string strValue = "\"" + str + "\"";
 	return new ConstantExpr( loc, strType, strValue, std::nullopt );
Index: src/AST/Inspect.cpp
===================================================================
--- src/AST/Inspect.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/AST/Inspect.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// Inspect.cpp -- Helpers to get information from the AST.
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Jun 24 13:16:31 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jun 27 15:35:00 2022
+// Update Count     : 1
+//
+
+#include "AST/Decl.hpp"
+#include "AST/Type.hpp"
+
+#include <iostream>
+#include <AST/Print.hpp>
+
+namespace ast {
+
+bool structHasFlexibleArray( const ast::StructDecl * decl ) {
+	if(decl->members.size() == 0) return false;
+	const auto & last = *decl->members.rbegin();
+	auto lastd = last.as<ast::DeclWithType>();
+	// I don't know what this is possible, but it might be.
+	if(!lastd) return false;
+	auto atype = dynamic_cast<const ast::ArrayType *>(lastd->get_type());
+	if(!atype) return false;
+	return !atype->isVarLen && !atype->dimension;
+}
+
+} // namespace ast
Index: src/AST/Inspect.hpp
===================================================================
--- src/AST/Inspect.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/AST/Inspect.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -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.
+//
+// Inspect.hpp -- Helpers to get information from the AST.
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Jun 24 13:16:31 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jun 27 15:35:00 2022
+// Update Count     : 1
+//
+
+#include "AST/Fwd.hpp"
+
+namespace ast {
+
+// Does the structure end in a flexable array declaration?
+bool structHasFlexibleArray( const ast::StructDecl * );
+
+}
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/AST/Pass.impl.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -681,4 +681,5 @@
 	if ( __visit_children() ) {
 		// unlike structs, traits, and unions, enums inject their members into the global scope
+		maybe_accept( node, &EnumDecl::base );
 		maybe_accept( node, &EnumDecl::params     );
 		maybe_accept( node, &EnumDecl::members    );
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/AST/module.mk	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -37,4 +37,6 @@
 	AST/Init.cpp \
 	AST/Init.hpp \
+	AST/Inspect.cpp \
+	AST/Inspect.hpp \
 	AST/Label.hpp \
 	AST/LinkageSpec.cpp \
Index: src/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/CodeGen/CodeGenerator.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Feb  2 20:30:30 2022
-// Update Count     : 541
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 29 14:34:00 2022
+// Update Count     : 542
 //
 #include "CodeGenerator.h"
@@ -18,4 +18,5 @@
 #include <list>                      // for _List_iterator, list, list<>::it...
 
+#include "AST/Decl.hpp"              // for DeclWithType
 #include "Common/UniqueName.h"       // for UniqueName
 #include "Common/utility.h"          // for CodeLocation, toString
@@ -294,5 +295,5 @@
 				} else {
 					if ( obj->get_init() ) {
-						obj->get_init()->accept( *visitor ); 
+						obj->get_init()->accept( *visitor );
 					} else {
 						// Should not reach here!
@@ -683,8 +684,10 @@
 		extension( variableExpr );
 		const OperatorInfo * opInfo;
-		if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) {
+		if( dynamic_cast<ZeroType*>( variableExpr->get_var()->get_type() ) ) {
+			output << "0";
+		} else if ( variableExpr->get_var()->get_linkage() == LinkageSpec::Intrinsic && (opInfo = operatorLookup( variableExpr->get_var()->get_name() )) && opInfo->type == OT_CONSTANT ) {
 			output << opInfo->symbol;
 		} else {
-			// if (dynamic_cast<EnumInstType *>(variableExpr->get_var()->get_type()) 
+			// if (dynamic_cast<EnumInstType *>(variableExpr->get_var()->get_type())
 			// && dynamic_cast<EnumInstType *>(variableExpr->get_var()->get_type())->baseEnum->base) {
 			// 	output << '(' <<genType(dynamic_cast<EnumInstType *>(variableExpr->get_var()->get_type())->baseEnum->base, "", options) << ')';
@@ -1236,4 +1239,13 @@
 		} // if
 	}
+
+std::string genName( ast::DeclWithType const * decl ) {
+	if ( const OperatorInfo * opInfo = operatorLookup( decl->name ) ) {
+		return opInfo->outputName;
+	} else {
+		return decl->name;
+	}
+}
+
 } // namespace CodeGen
 
Index: src/CodeGen/CodeGenerator.h
===================================================================
--- src/CodeGen/CodeGenerator.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/CodeGen/CodeGenerator.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb  1 09:23:21 2022
-// Update Count     : 64
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jun 29 14:32:00 2022
+// Update Count     : 65
 //
 
@@ -26,4 +26,8 @@
 #include "SynTree/Visitor.h"      // for Visitor
 #include "SynTree/SynTree.h"      // for Visitor Nodes
+
+namespace ast {
+	class DeclWithType;
+}
 
 namespace CodeGen {
@@ -182,4 +186,5 @@
 	/// returns C-compatible name of declaration
 	std::string genName( DeclarationWithType * decl );
+	std::string genName( ast::DeclWithType const * decl );
 
 	inline std::ostream & operator<<( std::ostream & os, const CodeGenerator::LineEnder & endl ) {
Index: src/CodeGen/FixNames.cc
===================================================================
--- src/CodeGen/FixNames.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/CodeGen/FixNames.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FixNames.cc --
+// FixNames.cc -- Adjustments to typed declarations.
 //
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Oct 29 15:49:00 2021
-// Update Count     : 23
+// Last Modified On : Wed Jul 20 11:49:00 2022
+// Update Count     : 24
 //
 
@@ -87,5 +87,5 @@
 
 /// Does work with the main function and scopeLevels.
-class FixNames_new : public ast::WithGuards {
+class FixNames_new final {
 	int scopeLevel = 1;
 
@@ -103,14 +103,10 @@
 
 	const ast::FunctionDecl *postvisit( const ast::FunctionDecl *functionDecl ) {
-		// This store is used to ensure a maximum of one call to mutate.
-		ast::FunctionDecl * mutDecl = nullptr;
+		if ( FixMain::isMain( functionDecl ) ) {
+			auto mutDecl = ast::mutate( functionDecl );
 
-		if ( shouldSetScopeLevel( functionDecl ) ) {
-			mutDecl = ast::mutate( functionDecl );
-			mutDecl->scopeLevel = scopeLevel;
-		}
-
-		if ( FixMain::isMain( functionDecl ) ) {
-			if ( !mutDecl ) { mutDecl = ast::mutate( functionDecl ); }
+			if ( shouldSetScopeLevel( mutDecl ) ) {
+				mutDecl->scopeLevel = scopeLevel;
+			}
 
 			int nargs = mutDecl->params.size();
@@ -124,10 +120,19 @@
 				)
 			);
+
+			return mutDecl;
+		} else if ( shouldSetScopeLevel( functionDecl ) ) {
+			return ast::mutate_field( functionDecl, &ast::FunctionDecl::scopeLevel, scopeLevel );
+		} else {
+			return functionDecl;
 		}
-		return mutDecl ? mutDecl : functionDecl;
 	}
 
 	void previsit( const ast::CompoundStmt * ) {
-		GuardValue( scopeLevel ) += 1;
+		scopeLevel += 1;
+	}
+
+	void postvisit( const ast::CompoundStmt * ) {
+		scopeLevel -= 1;
 	}
 };
Index: src/CodeGen/FixNames.h
===================================================================
--- src/CodeGen/FixNames.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/CodeGen/FixNames.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FixNames.h --
+// FixNames.h -- Adjustments to typed declarations.
 //
 // Author           : Richard C. Bilson
@@ -26,5 +26,6 @@
 	/// mangles object and function names
 	void fixNames( std::list< Declaration* > & translationUnit );
-	void fixNames( ast::TranslationUnit & translationUnit );
+/// Sets scope levels and fills in main's default return.
+void fixNames( ast::TranslationUnit & translationUnit );
 } // namespace CodeGen
 
Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/CodeGen/GenType.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -254,5 +254,5 @@
 
 	void GenType::postvisit( EnumInstType * enumInst ) {
-		if ( enumInst->baseEnum->base ) {
+		if ( enumInst->baseEnum && enumInst->baseEnum->base ) {
 			typeString = genType(enumInst->baseEnum->base, "", options) + typeString;
 		} else {
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Common/Eval.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 24 15:09:06 2019
-// Update Count     : 64
+// Last Modified On : Fri Jul  1 08:41:03 2022
+// Update Count     : 117
 //
 
@@ -17,4 +17,5 @@
 
 #include "Common/PassVisitor.h"
+#include "CodeGen/OperatorTable.h"						// access: OperatorInfo
 #include "AST/Pass.hpp"
 #include "InitTweak/InitTweak.h"
@@ -24,6 +25,9 @@
 // Old AST
 struct EvalOld : public WithShortCircuiting {
-	long long int value = 0;
-	bool valid = true;
+	long long int value = 0;							// compose the result of the constant expression
+	bool valid = true;									// true => constant expression and value is the result
+														// false => not constant expression, e.g., ++i
+	bool cfavalid = true;								// true => constant expression and value computable
+														// false => constant expression but value not computable, e.g., sizeof(int)
 
 	void previsit( const BaseSyntaxNode * ) { visit_children = false; }
@@ -89,28 +93,77 @@
 // New AST
 struct EvalNew : public ast::WithShortCircuiting {
-	long long int value = 0;
-	bool valid = true;
+	long long int value = 0;							// compose the result of the constant expression
+	bool valid = true;									// true => constant expression and value is the result
+														// false => not constant expression, e.g., ++i
+	bool cfavalid = true;								// true => constant expression and value computable
+														// false => constant expression but value not computable, e.g., sizeof(int)
 
 	void previsit( const ast::Node * ) { visit_children = false; }
-	void postvisit( const ast::Node * ) { valid = false; }
-
-	void postvisit( const ast::ConstantExpr * expr ) {
+	void postvisit( const ast::Node * ) { cfavalid = valid = false; }
+
+	void postvisit( const ast::UntypedExpr * ) {
+		assertf( false, "UntypedExpr in constant expression evaluation" ); // FIX ME, resolve variable
+	}
+
+	void postvisit( const ast::ConstantExpr * expr ) {	// only handle int constants
 		value = expr->intValue();
 	}
 
-	void postvisit( const ast::SizeofExpr * expr ) {
-		if ( expr->expr ) value = eval(expr->expr).first;
-		else if ( expr->type ) value = eval(expr->expr).first;
-		else SemanticError( expr->location, ::toString( "Internal error: SizeofExpr has no expression or type value" ) );
-	}
-
-	void postvisit( const ast::CastExpr * expr ) {
+	void postvisit( const ast::SizeofExpr * ) {
+		// do not change valid or value => let C figure it out
+		cfavalid = false;
+	}
+
+	void postvisit( const ast::AlignofExpr * ) {
+		// do not change valid or value => let C figure it out
+		cfavalid = false;
+	}
+
+	void postvisit( const ast::OffsetofExpr * ) {
+		// do not change valid or value => let C figure it out
+		cfavalid = false;
+	}
+
+	void postvisit( const ast::LogicalExpr * expr ) {
+		std::pair<long long int, bool> arg1, arg2;
+		arg1 = eval( expr->arg1 );
+		valid &= arg1.second;
+		if ( ! valid ) return;
+		arg2 = eval( expr->arg2 );
+		valid &= arg2.second;
+		if ( ! valid ) return;
+
+		if ( expr->isAnd ) {
+			value = arg1.first && arg2.first;
+		} else {
+			value = arg1.first || arg2.first;
+		} // if
+	}
+
+	void postvisit( const ast::ConditionalExpr * expr ) {
+		std::pair<long long int, bool> arg1, arg2, arg3;
+		arg1 = eval( expr->arg1 );
+		valid &= arg1.second;
+		if ( ! valid ) return;
+		arg2 = eval( expr->arg2 );
+		valid &= arg2.second;
+		if ( ! valid ) return;
+		arg3 = eval( expr->arg3 );
+		valid &= arg3.second;
+		if ( ! valid ) return;
+
+		value = arg1.first ? arg2.first : arg3.first;
+	}
+
+	void postvisit( const ast::CastExpr * expr ) {		
+		// cfa-cc generates a cast before every constant and many other places, e.g., (int)3, so the cast argument must
+		// be evaluated to get the constant value.
 		auto arg = eval(expr->arg);
 		valid = arg.second;
 		value = arg.first;
-		// TODO: perform type conversion on value if valid
-	}
-
-	void postvisit( const ast::VariableExpr * expr ) { // No hit
+		cfavalid = false;
+	}
+
+	void postvisit( const ast::VariableExpr * expr ) {
 		if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
 			if ( const ast::EnumDecl * decl = inst->base ) {
@@ -128,47 +181,90 @@
 		const std::string & fname = function->name;
 		assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
-		std::pair<long long int, bool> arg1, arg2;
-		arg1 = eval(expr->args.front());
-		valid = valid && arg1.second;
-		if ( ! valid ) return;
-		if ( expr->args.size() == 2 ) {
+
+		if ( expr->args.size() == 1 ) {
+			// pre/postfix operators ++ and -- => assignment, which is not constant
+			std::pair<long long int, bool> arg1;
+			arg1 = eval(expr->args.front());
+			valid &= arg1.second;
+			if ( ! valid ) return;
+
+			if (fname == "+?") {
+				value = arg1.first;
+			} else if (fname == "-?") {
+				value = -arg1.first;
+			} else if (fname == "~?") {
+				value = ~arg1.first;
+			} else if (fname == "!?") {
+				value = ! arg1.first;
+			} else {
+				valid = false;
+			} // if
+		} else { // => expr->args.size() == 2
+			// infix assignment operators => assignment, which is not constant
+			std::pair<long long int, bool> arg1, arg2;
+			arg1 = eval(expr->args.front());
+			valid &= arg1.second;
+			if ( ! valid ) return;
 			arg2 = eval(expr->args.back());
-			valid = valid && arg2.second;
-			if ( ! valid ) return;
-		}
-		if (fname == "?+?") {
-			value = arg1.first + arg2.first;
-		} else if (fname == "?-?") {
-			value = arg1.first - arg2.first;
-		} else if (fname == "?*?") {
-			value = arg1.first * arg2.first;
-		} else if (fname == "?/?") {
-			value = arg1.first / arg2.first;
-		} else if (fname == "?%?") {
-			value = arg1.first % arg2.first;
-		} else {
-			valid = false;
-		}
+			valid &= arg2.second;
+			if ( ! valid ) return;
+
+			if (fname == "?+?") {
+				value = arg1.first + arg2.first;
+			} else if (fname == "?-?") {
+				value = arg1.first - arg2.first;
+			} else if (fname == "?*?") {
+				value = arg1.first * arg2.first;
+			} else if (fname == "?/?") {
+				value = arg1.first / arg2.first;
+			} else if (fname == "?%?") {
+				value = arg1.first % arg2.first;
+			} else if (fname == "?<<?") {
+				value = arg1.first << arg2.first;
+			} else if (fname == "?>>?") {
+				value = arg1.first >> arg2.first;
+			} else if (fname == "?<?") {
+				value = arg1.first < arg2.first;
+			} else if (fname == "?>?") {
+				value = arg1.first > arg2.first;
+			} else if (fname == "?<=?") {
+				value = arg1.first <= arg2.first;
+			} else if (fname == "?>=?") {
+				value = arg1.first >= arg2.first;
+			} else if (fname == "?==?") {
+				value = arg1.first == arg2.first;
+			} else if (fname == "?!=?") {
+				value = arg1.first != arg2.first;
+			} else if (fname == "?&?") {
+				value = arg1.first & arg2.first;
+			} else if (fname == "?^?") {
+				value = arg1.first ^ arg2.first;
+			} else if (fname == "?|?") {
+				value = arg1.first | arg2.first;
+			} else {
+				valid = false;
+			}
+		} // if
 		// TODO: implement other intrinsic functions
 	}
 };
 
-std::pair<long long int, bool> eval( const Expression * expr) {
+std::pair<long long int, bool> eval( const Expression * expr ) {
 	PassVisitor<EvalOld> ev;
-	if (expr) {
-		expr->accept(ev);
-		return std::make_pair(ev.pass.value, ev.pass.valid);
+	if ( expr ) {
+		expr->accept( ev );
+		return std::make_pair( ev.pass.value, ev.pass.valid );
 	} else {
-		return std::make_pair(0, false);
+		return std::make_pair( 0, false );
 	}
 }
 
-std::pair<long long int, bool> eval(const ast::Expr * expr) {
+std::pair<long long int, bool> eval( const ast::Expr * expr ) {
 	ast::Pass<EvalNew> ev;
-	if (expr) {
-		expr->accept(ev);
-		return std::make_pair(ev.core.value, ev.core.valid);
+	if ( expr ) {
+		expr->accept( ev );
+		return std::make_pair( ev.core.value, ev.core.valid );
 	} else {
-		return std::make_pair(0, false);
+		return std::make_pair( 0, false );
 	}
 }
Index: src/Common/ResolvProtoDump.cpp
===================================================================
--- src/Common/ResolvProtoDump.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Common/ResolvProtoDump.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -227,5 +227,5 @@
 	}
 
-	void previsit( const ast::EnumInstType * enumInst) {
+	void previsit( const ast::EnumInstType * ) {
 		// TODO: Add the meaningful text representation of typed enum
 		ss << (int)ast::BasicType::SignedInt;
Index: src/Concurrency/Keywords.h
===================================================================
--- src/Concurrency/Keywords.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Concurrency/Keywords.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -28,9 +28,9 @@
 	void implementThreadStarter( std::list< Declaration * > & translationUnit );
 
-/// Implement the sue-like keywords and the suspend keyword.
+/// Implement the sue-like keywords and the suspend keyword. Pre-Autogen
 void implementKeywords( ast::TranslationUnit & translationUnit );
-/// Implement the mutex parameters and mutex statement.
+/// Implement the mutex parameters and mutex statement. Post-Autogen
 void implementMutex( ast::TranslationUnit & translationUnit );
-/// Add the thread starter code to constructors.
+/// Add the thread starter code to constructors. Post-Autogen
 void implementThreadStarter( ast::TranslationUnit & translationUnit );
 };
Index: src/ControlStruct/ExceptDecl.cc
===================================================================
--- src/ControlStruct/ExceptDecl.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ControlStruct/ExceptDecl.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// ExceptDecl.cc --
+// ExceptDecl.cc -- Handles declarations of exception types.
 //
 // Author           : Henry Xue
Index: src/ControlStruct/ExceptDecl.h
===================================================================
--- src/ControlStruct/ExceptDecl.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ControlStruct/ExceptDecl.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,11 +5,11 @@
 // file "LICENCE" distributed with Cforall.
 //
-// ExceptDecl.h --
+// ExceptDecl.h -- Handles declarations of exception types.
 //
 // Author           : Henry Xue
 // Created On       : Tue Jul 20 04:10:50 2021
-// Last Modified By : Henry Xue
-// Last Modified On : Tue Jul 20 04:10:50 2021
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jul 12 15:49:00 2022
+// Update Count     : 2
 //
 
@@ -20,5 +20,12 @@
 class Declaration;
 
+namespace ast {
+	class TranslationUnit;
+}
+
 namespace ControlStruct {
-	void translateExcept( std::list< Declaration *> & translationUnit );
+/// Unfold exception declarations into raw structure declarations.
+/// Also builds vtable declarations and converts vtable types.
+void translateExcept( std::list< Declaration *> & translationUnit );
+void translateExcept( ast::TranslationUnit & translationUnit );
 }
Index: src/ControlStruct/ExceptDeclNew.cpp
===================================================================
--- src/ControlStruct/ExceptDeclNew.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/ControlStruct/ExceptDeclNew.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,544 @@
+//
+// 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.
+//
+// ExceptDeclNew.cpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jul 12 15:50:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul 18 11:01:00 2022
+// Update Count     : 0
+//
+
+#include "ExceptDecl.h"
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Print.hpp"
+#include "AST/Type.hpp"
+#include "Virtual/Tables.h"
+
+namespace ControlStruct {
+
+namespace {
+
+std::vector<ast::ptr<ast::Expr>> forallToParams(
+		std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
+	return map_range<std::vector<ast::ptr<ast::Expr>>>( forall,
+		[]( ast::ptr<ast::TypeDecl> const & decl ) {
+			return new ast::TypeExpr( decl->location,
+				new ast::TypeInstType( decl->name, decl->kind ) );
+		}
+	);
+}
+
+// A slightly argumented extra constructor, adds a deepCopy.
+ast::StructInstType * namedStructInstType(
+		std::string const & name, ast::CV::Qualifiers qualifiers,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::StructInstType * type = new ast::StructInstType( name, qualifiers );
+	for ( ast::ptr<ast::Expr> const & param : params ) {
+		type->params.push_back( ast::deepCopy( param ) );
+	}
+	return type;
+}
+
+ast::StructInstType * createExceptionInstType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	return namedStructInstType( exceptionName, ast::CV::Qualifiers(), params );
+}
+
+ast::StructInstType * createVTableInstType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	std::string name = Virtual::vtableTypeName( exceptionName );
+	return namedStructInstType( name, ast::CV::Const, params );
+}
+
+ast::StructInstType * createTypeIdInstType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	std::string name = Virtual::typeIdType( exceptionName );
+	return namedStructInstType( name, ast::CV::Const, params );
+}
+
+ast::FunctionType const * createCopyFuncType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
+	type->params.push_back( new ast::PointerType(
+		createExceptionInstType( exceptionName, params ) ) );
+	type->params.push_back( new ast::PointerType(
+		createExceptionInstType( exceptionName, params ) ) );
+	type->returns.push_back( new ast::VoidType() );
+	return type;
+}
+
+ast::FunctionType const * createDtorFuncType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
+	type->params.push_back( new ast::ReferenceType(
+		createExceptionInstType( exceptionName, params ) ) );
+	type->returns.push_back( new ast::VoidType() );
+	return type;
+}
+
+ast::FunctionType const * createMsgFuncType(
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::FunctionType * type = new ast::FunctionType( ast::FixedArgs );
+	type->params.push_back( new ast::PointerType(
+		createExceptionInstType( exceptionName, params ) ) );
+	type->returns.push_back( new ast::PointerType(
+		new ast::BasicType( ast::BasicType::Char, ast::CV::Const ) ) );
+	return type;
+}
+
+ast::StructDecl const * createTypeIdStruct(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::TypeDecl>> const & forallClause ) {
+	ast::StructDecl * decl = new ast::StructDecl( location,
+			Virtual::typeIdType( exceptionName ) );
+	decl->members.push_back( new ast::ObjectDecl(
+		location,
+		"parent",
+		new ast::PointerType(
+			new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	) );
+	decl->body = true;
+	for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
+		decl->params.push_back( ast::deepCopy( param ) );
+	}
+	return decl;
+}
+
+ast::ObjectDecl const * createTypeIdValue(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::StructInstType * typeIdType =
+		createTypeIdInstType( exceptionName, params );
+	return new ast::ObjectDecl(
+		location,
+		Virtual::typeIdName( exceptionName ),
+		typeIdType,
+		new ast::ListInit( location, {
+			new ast::SingleInit( location,
+				new ast::AddressExpr( location,
+					new ast::NameExpr( location, "__cfatid_exception_t" ) ),
+				ast::MaybeConstruct ),
+		}, {}, ast::MaybeConstruct ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall,
+		nullptr,
+		{ new ast::Attribute( "cfa_linkonce" ) }
+	);
+}
+
+ast::StructDecl const * createExceptionStructForward(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::TypeDecl>> const & forall ) {
+	ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
+	for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
+		decl->params.push_back( ast::deepCopy( param ) );
+	}
+	return decl;
+}
+
+ast::StructDecl const * createVirtualTableStruct(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::TypeDecl>> const & forall,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	ast::StructInstType * typeIdType =
+		createTypeIdInstType( exceptionName, params );
+	ast::ObjectDecl * typeId = new ast::ObjectDecl(
+		location,
+		"__cfavir_typeid",
+		new ast::PointerType( typeIdType ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+	ast::ObjectDecl * size = new ast::ObjectDecl(
+		location,
+		"size",
+		new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+	ast::ObjectDecl * copy = new ast::ObjectDecl(
+		location,
+		"copy",
+		new ast::PointerType( createCopyFuncType( exceptionName, params ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+	ast::ObjectDecl * dtor = new ast::ObjectDecl(
+		location,
+		"^?{}",
+		new ast::PointerType( createDtorFuncType( exceptionName, params ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+	ast::ObjectDecl * msg = new ast::ObjectDecl(
+		location,
+		"msg",
+		new ast::PointerType( createMsgFuncType( exceptionName, params ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+	ast::StructDecl * decl = new ast::StructDecl(
+		location,
+		Virtual::vtableTypeName( exceptionName ) );
+	decl->members.push_back( typeId );
+	decl->members.push_back( size );
+	decl->members.push_back( copy );
+	decl->members.push_back( dtor );
+	decl->members.push_back( msg );
+	decl->body = true;
+	for ( ast::ptr<ast::TypeDecl> const & param : forall ) {
+		decl->params.push_back( param );
+	}
+	return decl;
+}
+
+ast::StructDecl const * createExceptionStruct(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::TypeDecl>> const & forallClause,
+		std::vector<ast::ptr<ast::Expr>> const & params,
+		std::vector<ast::ptr<ast::Decl>> const & members ) {
+	ast::StructDecl * decl = new ast::StructDecl( location, exceptionName );
+	decl->members.push_back( new ast::ObjectDecl(
+		location,
+		"virtual_table",
+		new ast::PointerType(
+			createVTableInstType( exceptionName, params ) ),
+		nullptr,
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	) );
+	for ( ast::ptr<ast::Decl> const & member : members ) {
+		decl->members.push_back( ast::deepCopy( member ) );
+	}
+	decl->body = true;
+	for ( ast::ptr<ast::TypeDecl> const & param : forallClause ) {
+		decl->params.push_back( ast::deepCopy( param ) );
+	}
+	return decl;
+}
+
+ast::ObjectDecl const * createExternTypeId(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	return new ast::ObjectDecl(
+		location,
+		Virtual::typeIdName( exceptionName ),
+		createVTableInstType( exceptionName, params ),
+		nullptr,
+		ast::Storage::Extern,
+		ast::Linkage::Cforall,
+		nullptr,
+		{ new ast::Attribute( "cfa_linkonce" ) }
+	);
+}
+
+ast::ObjectDecl const * createExternVTable(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params,
+		std::string const & tableName ) {
+	return new ast::ObjectDecl(
+		location,
+		tableName,
+		createVTableInstType( exceptionName, params ),
+		nullptr,
+		ast::Storage::Extern,
+		ast::Linkage::Cforall
+	);
+}
+
+ast::FunctionDecl const * createCopy(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	return new ast::FunctionDecl(
+		location,
+		"copy",
+		{/* forall */},
+		{/* assertions */},
+		{
+			new ast::ObjectDecl(
+				location,
+				"this",
+				new ast::PointerType(
+					createExceptionInstType( exceptionName, params ) ),
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			),
+			new ast::ObjectDecl(
+				location,
+				"that",
+				new ast::PointerType(
+					createExceptionInstType( exceptionName, params ) ),
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			),
+		},
+		{
+			new ast::ObjectDecl(
+				location,
+				"",
+				new ast::VoidType(),
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			),
+		},
+		new ast::CompoundStmt( location, {
+			new ast::ExprStmt( location,
+				new ast::UntypedExpr( location,
+					new ast::NameExpr( location, "?=?" ),
+					{
+						new ast::UntypedExpr( location,
+							new ast::NameExpr( location, "*?" ),
+							{ new ast::NameExpr( location, "this" ) } ),
+						new ast::UntypedExpr( location,
+							new ast::NameExpr( location, "*?" ),
+							{ new ast::NameExpr( location, "that" ) } ),
+					}
+				)
+			),
+		} ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+}
+
+ast::FunctionDecl const * createMsg(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	std::stringstream msg;
+	msg << exceptionName;
+	// The forall variant, add parameters to the string.
+	if ( !params.empty() ) {
+		msg << "(";
+		bool first = true;
+		for ( auto & param : params ) {
+			// Seperator Logic: A comma proceeds all but the first object.
+			if ( first ) {
+				first = false;
+			} else {
+				msg << ", ";
+			}
+
+			ast::print( msg, param.get() );
+		}
+		msg << ")";
+	}
+	return new ast::FunctionDecl(
+		location,
+		"msg",
+		{/* forall */},
+		{/* assertions */},
+		{
+			new ast::ObjectDecl(
+				location,
+				"this",
+				new ast::PointerType(
+					createExceptionInstType( exceptionName, params ) ),
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			),
+		},
+		{
+			new ast::ObjectDecl(
+				location,
+				"",
+				new ast::PointerType(
+					new ast::BasicType( ast::BasicType::Char, ast::CV::Const ) ),
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::Cforall
+			),
+		},
+		new ast::CompoundStmt( location, {
+			new ast::ReturnStmt( location,
+				ast::ConstantExpr::from_string( location, msg.str() )
+			),
+		} ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+}
+
+ast::ObjectDecl const * createVirtualTable(
+		CodeLocation const & location,
+		std::string const & exceptionName,
+		std::vector<ast::ptr<ast::Expr>> const & params,
+		std::string const & tableName ) {
+	ast::StructInstType * sizeType = new ast::StructInstType( exceptionName );
+	for ( ast::ptr<ast::Expr> const & param : params ) {
+		sizeType->params.push_back( ast::deepCopy( param ) );
+	}
+	std::vector<ast::ptr<ast::Init>> inits {
+		new ast::SingleInit( location,
+			new ast::AddressExpr( location,
+				new ast::NameExpr( location,
+					Virtual::typeIdName( exceptionName ) ) ) ),
+		new ast::SingleInit( location,
+			new ast::SizeofExpr( location, sizeType )  ),
+		new ast::SingleInit( location,
+			new ast::NameExpr( location, "copy" ) ),
+		new ast::SingleInit( location,
+			new ast::NameExpr( location, "^?{}" ) ),
+		new ast::SingleInit( location,
+			new ast::NameExpr( location, "msg" ) ),
+	};
+	std::vector<ast::ptr<ast::Designation>> dsigs {
+		new ast::Designation( location, {
+			new ast::NameExpr( location, "__cfavir_typeid" ) } ),
+		new ast::Designation( location, {
+			new ast::NameExpr( location, "size" ) } ),
+		new ast::Designation( location, {
+			new ast::NameExpr( location, "copy" ) } ),
+		new ast::Designation( location, {
+			new ast::NameExpr( location, "^?{}" ) } ),
+		new ast::Designation( location, {
+			new ast::NameExpr( location, "msg" ) } ),
+	};
+	return new ast::ObjectDecl(
+		location,
+		tableName,
+		createVTableInstType( exceptionName, params ),
+		new ast::ListInit( location, std::move( inits ), std::move( dsigs ) ),
+		ast::Storage::Classes(),
+		ast::Linkage::Cforall
+	);
+}
+
+struct ExceptDeclCore : public ast::WithDeclsToAdd<> {
+	ast::StructDecl const * transformExcept( ast::StructDecl const * decl );
+	ast::ObjectDecl const * transformVTable(
+		ast::ObjectDecl const * decl, ast::VTableType const * type );
+
+	ast::StructDecl const * postvisit( ast::StructDecl const * decl ) {
+		// Exceptions don't get their own node type, so filter that.
+		if ( ast::AggregateDecl::Exception == decl->kind ) {
+			return transformExcept( decl );
+		}
+		return decl;
+	}
+
+	ast::ObjectDecl const * postvisit( ast::ObjectDecl const * decl ) {
+		// Modify remaining objects that have a vtable type.
+		if ( auto * type = decl->type.as<ast::VTableType>() ) {
+			return transformVTable( decl, type );
+		}
+		return decl;
+	}
+};
+
+ast::StructDecl const * ExceptDeclCore::transformExcept(
+		ast::StructDecl const * decl ) {
+	CodeLocation const & location = decl->location;
+	std::string const & exceptionName = decl->name;
+	std::vector<ast::ptr<ast::TypeDecl>> const & forall = decl->params;
+	std::vector<ast::ptr<ast::Expr>> params = forallToParams( forall );
+	std::vector<ast::ptr<ast::Decl>> const & members = decl->members;
+
+	declsToAddBefore.push_back(
+		createTypeIdStruct( location, exceptionName, forall ) );
+	if ( forall.empty() ) {
+		// Non-forall variant.
+		declsToAddBefore.push_back(
+			createTypeIdValue( location, exceptionName, params ) );
+	}
+	declsToAddBefore.push_back(
+		createExceptionStructForward( location, exceptionName, forall ) );
+	declsToAddBefore.push_back(
+		createVirtualTableStruct( location, exceptionName, forall, params ) );
+	return createExceptionStruct( location, exceptionName, forall, params, members );
+}
+
+ast::ObjectDecl const * ExceptDeclCore::transformVTable(
+		ast::ObjectDecl const * decl, ast::VTableType const * type ) {
+	CodeLocation const & location = decl->location;
+	auto base = type->base.strict_as<ast::TypeInstType>();
+	std::string const & exceptionName = base->name;
+	std::vector<ast::ptr<ast::Expr>> const & params = base->params;
+	std::string const & tableName = decl->name;
+
+	if ( decl->storage.is_extern ) {
+		// Unique type-ids are only needed for polymorphic instances.
+		if ( !params.empty() ) {
+			declsToAddBefore.push_back(
+				createExternTypeId( location, exceptionName, params ) );
+		}
+		return createExternVTable( location, exceptionName, params, tableName );
+	} else {
+		// Unique type-ids are only needed for polymorphic instances.
+		if ( !params.empty() ) {
+			declsToAddBefore.push_back(
+				createTypeIdValue( location, exceptionName, params ) );
+		}
+		declsToAddBefore.push_back(
+			createCopy( location, exceptionName, params ) );
+		declsToAddBefore.push_back(
+			createMsg( location, exceptionName, params ) );
+		return createVirtualTable(
+			location, exceptionName, params, tableName );
+	}
+}
+
+struct VTableCore {
+	ast::StructInstType const * postvisit( ast::VTableType const * type ) {
+		auto inst = type->base.as<ast::BaseInstType>();
+
+		std::string vtableName = Virtual::vtableTypeName( inst->name );
+		auto newType = new ast::StructInstType( vtableName );
+		for ( ast::ptr<ast::Expr> const & param : inst->params ) {
+			newType->params.push_back( param );
+		}
+
+		return newType;
+	}
+};
+
+} // namespace
+
+void translateExcept( ast::TranslationUnit & translationUnit ) {
+	// Can I combine these?
+	// Second pass really only covers what the first has missed.
+	// Maybe if the first one is all previsits and the second all postvisit.
+	ast::Pass<ExceptDeclCore>::run( translationUnit );
+	ast::Pass<VTableCore>::run( translationUnit );
+}
+
+} // namespace ControlStruct
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ControlStruct/HoistControlDecls.hpp
===================================================================
--- src/ControlStruct/HoistControlDecls.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ControlStruct/HoistControlDecls.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -21,5 +21,6 @@
 
 namespace ControlStruct {
-// Hoist declarations out of control flow statements into compound statement.
+/// Hoist declarations out of control flow statements into compound statement.
+/// Must happen before auto-gen routines are added.
 void hoistControlDecls( ast::TranslationUnit & translationUnit );
 } // namespace ControlStruct
Index: src/ControlStruct/MultiLevelExit.cpp
===================================================================
--- src/ControlStruct/MultiLevelExit.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ControlStruct/MultiLevelExit.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -149,6 +149,5 @@
 };
 
-NullStmt * labelledNullStmt(
-	const CodeLocation & cl, const Label & label ) {
+NullStmt * labelledNullStmt( const CodeLocation & cl, const Label & label ) {
 	return new NullStmt( cl, vector<Label>{ label } );
 }
@@ -164,5 +163,5 @@
 
 const CompoundStmt * MultiLevelExitCore::previsit(
-	const CompoundStmt * stmt ) {
+		const CompoundStmt * stmt ) {
 	visit_children = false;
 
@@ -189,6 +188,5 @@
 }
 
-size_t getUnusedIndex(
-	const Stmt * stmt, const Label & originalTarget ) {
+size_t getUnusedIndex( const Stmt * stmt, const Label & originalTarget ) {
 	const size_t size = stmt->labels.size();
 
@@ -210,6 +208,5 @@
 }
 
-const Stmt * addUnused(
-	const Stmt * stmt, const Label & originalTarget ) {
+const Stmt * addUnused( const Stmt * stmt, const Label & originalTarget ) {
 	size_t i = getUnusedIndex( stmt, originalTarget );
 	if ( i == stmt->labels.size() ) {
@@ -356,6 +353,5 @@
 
 // Mimic what the built-in push_front would do anyways. It is O(n).
-void push_front(
-	vector<ptr<Stmt>> & vec, const Stmt * element ) {
+void push_front( vector<ptr<Stmt>> & vec, const Stmt * element ) {
 	vec.emplace_back( nullptr );
 	for ( size_t i = vec.size() - 1 ; 0 < i ; --i ) {
@@ -590,19 +586,15 @@
 
 		ptr<Stmt> else_stmt = nullptr;
-		Stmt * loop_kid = nullptr;
+		const Stmt * loop_kid = nullptr;
 		// check if loop node and if so add else clause if it exists
-		const WhileDoStmt * whilePtr = dynamic_cast<const WhileDoStmt *>(kid.get());
-		if ( whilePtr && whilePtr->else_) {
+		const WhileDoStmt * whilePtr = kid.as<WhileDoStmt>();
+		if ( whilePtr && whilePtr->else_ ) {
 			else_stmt = whilePtr->else_;
-			WhileDoStmt * mutate_ptr = mutate(whilePtr);
-			mutate_ptr->else_ = nullptr;
-			loop_kid = mutate_ptr;
-		}
-		const ForStmt * forPtr = dynamic_cast<const ForStmt *>(kid.get());
-		if ( forPtr && forPtr->else_) {
+			loop_kid = mutate_field( whilePtr, &WhileDoStmt::else_, nullptr );
+		}
+		const ForStmt * forPtr = kid.as<ForStmt>();
+		if ( forPtr && forPtr->else_ ) {
 			else_stmt = forPtr->else_;
-			ForStmt * mutate_ptr = mutate(forPtr);
-			mutate_ptr->else_ = nullptr;
-			loop_kid = mutate_ptr;
+			loop_kid = mutate_field( forPtr, &ForStmt::else_, nullptr );
 		}
 
Index: src/ControlStruct/module.mk
===================================================================
--- src/ControlStruct/module.mk	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ControlStruct/module.mk	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -17,4 +17,5 @@
 SRC += \
 	ControlStruct/ExceptDecl.cc \
+	ControlStruct/ExceptDeclNew.cpp \
 	ControlStruct/ExceptDecl.h \
 	ControlStruct/ExceptTranslateNew.cpp \
Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/GenPoly/Box.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -189,6 +189,4 @@
 			/// Enters a new scope for type-variables, adding the type variables from ty
 			void beginTypeScope( Type *ty );
-			/// Exits the type-variable scope
-			void endTypeScope();
 			/// Enters a new scope for knowLayouts and knownOffsets and queues exit calls
 			void beginGenericScope();
@@ -198,4 +196,5 @@
 			UniqueName bufNamer;                           ///< Namer for VLA buffers
 			Expression * addrMember = nullptr;             ///< AddressExpr argument is MemberExpr?
+			bool expect_func_type = false;                 ///< used to avoid recursing too deep in type decls
 		};
 
@@ -1277,5 +1276,6 @@
 			FunctionType * ftype = functionDecl->type;
 			if ( ! ftype->returnVals.empty() && functionDecl->statements ) {
-				if ( ! isPrefix( functionDecl->name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
+				// intrinsic functions won't be using the _retval so no need to generate it.
+				if ( functionDecl->linkage != LinkageSpec::Intrinsic && !isPrefix( functionDecl->name, "_thunk" ) && ! isPrefix( functionDecl->name, "_adapter" ) ) { // xxx - remove check for prefix once thunks properly use ctor/dtors
 					assert( ftype->returnVals.size() == 1 );
 					DeclarationWithType * retval = ftype->returnVals.front();
@@ -1418,4 +1418,9 @@
 		void PolyGenericCalculator::beginGenericScope() {
 			GuardScope( *this );
+			// We expect the first function type see to be the type relating to this scope
+			// but any further type is probably some unrelated function pointer
+			// keep track of which is the first
+			GuardValue( expect_func_type );
+			expect_func_type = true;
 		}
 
@@ -1467,4 +1472,21 @@
 		void PolyGenericCalculator::premutate( FunctionType *funcType ) {
 			beginTypeScope( funcType );
+
+			GuardValue( expect_func_type );
+
+			if(!expect_func_type) {
+				GuardAction( [this]() {
+					knownLayouts.endScope();
+					knownOffsets.endScope();
+				});
+				// If this is the first function type we see
+				// Then it's the type of the declaration and we care about it
+				knownLayouts.beginScope();
+				knownOffsets.beginScope();
+			}
+
+			// The other functions type we will see in this scope are probably functions parameters
+			// they don't help us with the layout and offsets so don't mark them as known in this scope
+			expect_func_type = false;
 
 			// make sure that any type information passed into the function is accounted for
@@ -1745,4 +1767,6 @@
 				}
 
+				// std::cout << "TRUE 2" << std::endl;
+
 				return true;
 			} else if ( UnionInstType *unionTy = dynamic_cast< UnionInstType* >( ty ) ) {
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/GenPoly/GenPoly.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -64,5 +64,5 @@
 		}
 
-		__attribute__((ununsed))
+		__attribute__((unused))
 		bool hasPolyParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap & tyVars, const ast::TypeSubstitution * env) {
 			for (auto &param : params) {
Index: src/InitTweak/GenInit.cc
===================================================================
--- src/InitTweak/GenInit.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/InitTweak/GenInit.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenInit.cc --
+// GenInit.cc -- Generate initializers, and other stuff.
 //
 // Author           : Rob Schluntz
@@ -642,22 +642,22 @@
 
 ast::ConstructorInit * genCtorInit( const CodeLocation & loc, const ast::ObjectDecl * objDecl ) {
-	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each 
+	// call into genImplicitCall from Autogen.h to generate calls to ctor/dtor for each
 	// constructable object
 	InitExpander_new srcParam{ objDecl->init }, nullParam{ (const ast::Init *)nullptr };
 	ast::ptr< ast::Expr > dstParam = new ast::VariableExpr(loc, objDecl);
-	
-	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall( 
+
+	ast::ptr< ast::Stmt > ctor = SymTab::genImplicitCall(
 		srcParam, dstParam, loc, "?{}", objDecl );
-	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall( 
-		nullParam, dstParam, loc, "^?{}", objDecl, 
+	ast::ptr< ast::Stmt > dtor = SymTab::genImplicitCall(
+		nullParam, dstParam, loc, "^?{}", objDecl,
 		SymTab::LoopBackward );
-	
+
 	// check that either both ctor and dtor are present, or neither
 	assert( (bool)ctor == (bool)dtor );
 
 	if ( ctor ) {
-		// need to remember init expression, in case no ctors exist. If ctor does exist, want to 
+		// need to remember init expression, in case no ctors exist. If ctor does exist, want to
 		// use ctor expression instead of init.
-		ctor.strict_as< ast::ImplicitCtorDtorStmt >(); 
+		ctor.strict_as< ast::ImplicitCtorDtorStmt >();
 		dtor.strict_as< ast::ImplicitCtorDtorStmt >();
 
Index: src/InitTweak/GenInit.h
===================================================================
--- src/InitTweak/GenInit.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/InitTweak/GenInit.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenInit.h --
+// GenInit.h -- Generate initializers, and other stuff.
 //
 // Author           : Rodolfo G. Esteves
@@ -29,5 +29,6 @@
 	void genInit( ast::TranslationUnit & translationUnit );
 
-	/// Converts return statements into copy constructor calls on the hidden return variable
+	/// Converts return statements into copy constructor calls on the hidden return variable.
+	/// This pass must happen before auto-gen.
 	void fixReturnStatements( std::list< Declaration * > & translationUnit );
 	void fixReturnStatements( ast::TranslationUnit & translationUnit );
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Parser/lex.ll	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -82,4 +82,7 @@
 // Stop warning due to incorrectly generated flex code.
 #pragma GCC diagnostic ignored "-Wsign-compare"
+
+// lex uses __null in a boolean context, it's fine.
+#pragma GCC diagnostic ignored "-Wnull-conversion"
 %}
 
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Parser/parser.yy	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat May 14 09:16:22 2022
-// Update Count     : 5401
+// Last Modified On : Fri Jul  1 15:35:08 2022
+// Update Count     : 5405
 //
 
@@ -56,4 +56,7 @@
 
 #include "SynTree/Attribute.h"     // for Attribute
+
+// lex uses __null in a boolean context, it's fine.
+#pragma GCC diagnostic ignored "-Wparentheses-equality"
 
 extern DeclarationNode * parseTree;
@@ -1240,5 +1243,5 @@
 		{
 			$$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| WHILE '(' conditional_declaration ')' statement	%prec THEN
@@ -1251,5 +1254,5 @@
 		{
 			$$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| DO statement WHILE '(' comma_expression ')' ';'
@@ -1262,5 +1265,5 @@
 		{
 			$$ = new StatementNode( build_for( new ForCtrl( (ExpressionNode * )nullptr, (ExpressionNode * )nullptr, (ExpressionNode * )nullptr ), maybe_build_compound( $4 ) ) );
-			SemanticWarning( yylloc, Warning::SuperfluousElse );
+			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
 	| FOR '(' for_control_expression_list ')' statement	%prec THEN
@@ -2394,5 +2397,5 @@
 	| ENUM '(' cfa_abstract_parameter_declaration ')' attribute_list_opt '{' enumerator_list comma_opt '}'
 	 	{
-			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 ) 
+			if ( $3->storageClasses.val != 0 || $3->type->qualifiers.val != 0 )
 			{ SemanticError( yylloc, "storage-class and CV qualifiers are not meaningful for enumeration constants, which are const." ); }
 
@@ -2438,8 +2441,8 @@
 	// empty
 		{ $$ = nullptr; }
-	// | '=' constant_expression
-	// 	{ $$ = $2; }
-	| simple_assignment_operator initializer
-		{ $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); }
+	| '=' constant_expression					{ $$ = new InitializerNode( $2 ); }
+	| '=' '{' initializer_list_opt comma_opt '}' { $$ = new InitializerNode( $3, true ); }
+	// | simple_assignment_operator initializer
+	// 	{ $$ = $1 == OperKinds::Assign ? $2 : $2->set_maybeConstructed( false ); }
 	;
 
@@ -2841,5 +2844,5 @@
 			linkage = LinkageSpec::update( yylloc, linkage, $2 );
 		}
-	  up external_definition down 
+	  up external_definition down
 		{
 			linkage = linkageStack.top();
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -41,5 +41,4 @@
 #include "Common/utility.h"       // for move, copy
 #include "SymTab/Mangler.h"
-#include "SymTab/Validate.h"      // for validateType
 #include "Tuples/Tuples.h"        // for handleTupleAssignment
 #include "InitTweak/InitTweak.h"  // for getPointerBase
@@ -1091,5 +1090,4 @@
 			assert( toType );
 			toType = resolveTypeof( toType, context );
-			// toType = SymTab::validateType( castExpr->location, toType, symtab );
 			toType = adjustExprType( toType, tenv, symtab );
 
@@ -1590,5 +1588,4 @@
 				// calculate target type
 				const ast::Type * toType = resolveTypeof( initAlt.type, context );
-				// toType = SymTab::validateType( initExpr->location, toType, symtab );
 				toType = adjustExprType( toType, tenv, symtab );
 				// The call to find must occur inside this loop, otherwise polymorphic return
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/ResolvExpr/CurrentObject.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -9,7 +9,7 @@
 // Author           : Rob Schluntz
 // Created On       : Tue Jun 13 15:28:32 2017
-// Last Modified By : Rob Schluntz
-// Last Modified On : Tue Jun 13 15:28:44 2017
-// Update Count     : 2
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Jul  1 09:16:01 2022
+// Update Count     : 15
 //
 
@@ -73,5 +73,5 @@
 		virtual void setPosition( std::list< Expression * > & designators ) = 0;
 
-		/// retrieve the list of possible Type/Designaton pairs for the current position in the currect object
+		/// retrieve the list of possible Type/Designation pairs for the current position in the currect object
 		virtual std::list<InitAlternative> operator*() const = 0;
 
@@ -158,6 +158,6 @@
 
 	private:
-		void setSize( Expression * expr ) { // replace this logic with an eval call
-			auto res = eval(expr);
+		void setSize( Expression * expr ) {
+			auto res = eval( expr );
 			if (res.second) {
 				size = res.first;
@@ -170,24 +170,28 @@
 		void setPosition( Expression * expr ) {
 			// need to permit integer-constant-expressions, including: integer constants, enumeration constants, character constants, sizeof expressions, _Alignof expressions, cast expressions
-			if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
-				try {
-					index = constExpr->intValue();
-				} catch( SemanticErrorException & ) {
-					SemanticError( expr, "Constant expression of non-integral type in array designator: " );
-				}
-			} else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
-				setPosition( castExpr->get_arg() );
-			} else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
-				EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
-				assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
-				long long int value;
-				if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
-					index = value;
-				}
-			} else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
-				index = 0; // xxx - get actual sizeof/alignof value?
-			} else {
-				assertf( false, "bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
-			}
+			auto arg = eval( expr );
+			index = arg.first;
+			return;
+
+			// if ( ConstantExpr * constExpr = dynamic_cast< ConstantExpr * >( expr ) ) {
+			// 	try {
+			// 		index = constExpr->intValue();
+			// 	} catch( SemanticErrorException & ) {
+			// 		SemanticError( expr, "Constant expression of non-integral type in array designator: " );
+			// 	}
+			// } else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( expr ) ) {
+			// 	setPosition( castExpr->get_arg() );
+			// } else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( expr ) ) {
+			// 	EnumInstType * inst = dynamic_cast<EnumInstType *>( varExpr->get_result() );
+			// 	assertf( inst, "ArrayIterator given variable that isn't an enum constant : %s", toString( expr ).c_str() );
+			// 	long long int value;
+			// 	if ( inst->baseEnum->valueOf( varExpr->var, value ) ) {
+			// 		index = value;
+			// 	}
+			// } else if ( dynamic_cast< SizeofExpr * >( expr ) || dynamic_cast< AlignofExpr * >( expr ) ) {
+			// 	index = 0; // xxx - get actual sizeof/alignof value?
+			// } else {
+			// 	assertf( false, "4 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
+			// }
 		}
 
@@ -329,5 +333,5 @@
 					assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
 				} else {
-					assertf( false, "bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );
+					assertf( false, "3 bad designator given to %s: %s", kind.c_str(), toString( designators.front() ).c_str() );
 				} // if
 			} // if
@@ -637,8 +641,7 @@
 
 		void setSize( const Expr * expr ) {
-			auto res = eval(expr);
+			auto res = eval( expr );
 			if ( ! res.second ) {
-				SemanticError( location,
-					toString("Array designator must be a constant expression: ", expr ) );
+				SemanticError( location, toString( "Array designator must be a constant expression: ", expr ) );
 			}
 			size = res.first;
@@ -646,6 +649,5 @@
 
 	public:
-		ArrayIterator( const CodeLocation & loc, const ArrayType * at )
-		: location( loc ), array( at ), base( at->base ) {
+		ArrayIterator( const CodeLocation & loc, const ArrayType * at ) : location( loc ), array( at ), base( at->base ) {
 			PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
 			memberIter.reset( createMemberIterator( loc, base ) );
@@ -660,22 +662,22 @@
 			// enumeration constants, character constants, sizeof expressions, alignof expressions,
 			// cast expressions
-			if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
-				try {
-					index = constExpr->intValue();
-				} catch ( SemanticErrorException & ) {
-					SemanticError( expr,
-						"Constant expression of non-integral type in array designator: " );
-				}
-			} else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
-				setPosition( castExpr->arg );
-			} else if (
-				dynamic_cast< const SizeofExpr * >( expr )
-				|| dynamic_cast< const AlignofExpr * >( expr )
-			) {
-				index = 0;
-			} else {
-				assertf( false,
-					"bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
-			}
+
+			auto arg = eval( expr );
+			index = arg.first;
+			return;
+
+			// if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
+			// 	try {
+			// 		index = constExpr->intValue();
+			// 	} catch ( SemanticErrorException & ) {
+			// 		SemanticError( expr, "Constant expression of non-integral type in array designator: " );
+			// 	}
+			// } else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
+			// 	setPosition( castExpr->arg );
+			// } else if ( dynamic_cast< const SizeofExpr * >( expr ) || dynamic_cast< const AlignofExpr * >( expr ) ) {
+			// 	index = 0;
+			// } else {
+			// 	assertf( false,	"2 bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
+			// }
 		}
 
@@ -723,6 +725,5 @@
 				std::deque< InitAlternative > ret = memberIter->first();
 				for ( InitAlternative & alt : ret ) {
-					alt.designation.get_and_mutate()->designators.emplace_front(
-						ConstantExpr::from_ulong( location, index ) );
+					alt.designation.get_and_mutate()->designators.emplace_front( ConstantExpr::from_ulong( location, index ) );
 				}
 				return ret;
@@ -788,9 +789,7 @@
 					return;
 				}
-				assertf( false,
-					"could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
+				assertf( false, "could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
 			} else {
-				assertf( false,
-					"bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
+				assertf( false, "1 bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
 			}
 		}
Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/FixFunction.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 16:19:49 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Mar  6 23:36:59 2017
-// Update Count     : 6
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jul 12 14:28:00 2022
+// Update Count     : 7
 //
 
@@ -122,4 +122,10 @@
 		}
 
+		void previsit( const ast::FunctionType * ) { visit_children = false; }
+
+		const ast::Type * postvisit( const ast::FunctionType * type ) {
+			return new ast::PointerType( type );
+		}
+
 		void previsit( const ast::VoidType * ) { isVoid = true; }
 
@@ -145,4 +151,11 @@
 }
 
+const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) {
+	ast::Pass< FixFunction_new > fixer;
+	type = type->accept( fixer );
+	isVoid |= fixer.core.isVoid;
+	return type;
+}
+
 } // namespace SymTab
 
Index: src/SymTab/FixFunction.h
===================================================================
--- src/SymTab/FixFunction.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/FixFunction.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 17:02:08 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Jul 22 09:45:55 2017
-// Update Count     : 4
+// Last Modified On : Tue Jul 12 14:19:00 2022
+// Update Count     : 5
 //
 
@@ -21,4 +21,5 @@
 namespace ast {
 	class DeclWithType;
+	class Type;
 }
 
@@ -31,4 +32,5 @@
 	/// Sets isVoid to true if type is void
 	const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
+	const ast::Type * fixFunction( const ast::Type * type, bool & isVoid );
 } // namespace SymTab
 
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/Mangler.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -537,4 +537,5 @@
 		}
 
+		__attribute__((unused))
 		inline std::vector< ast::ptr< ast::Type > > getTypes( const std::vector< ast::ptr< ast::DeclWithType > > & decls ) {
 			std::vector< ast::ptr< ast::Type > > ret;
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/Validate.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 21:50:04 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue May 17 14:36:00 2022
-// Update Count     : 366
+// Last Modified On : Tue Jul 12 15:00:00 2022
+// Update Count     : 367
 //
 
@@ -294,5 +294,5 @@
 	};
 
-	void validate_A( std::list< Declaration * > & translationUnit ) {
+	void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
 		PassVisitor<HoistTypeDecls> hoistDecls;
 		{
@@ -305,19 +305,13 @@
 			decayEnumsAndPointers( translationUnit ); // must happen before VerifyCtorDtorAssign, because void return objects should not exist; before LinkReferenceToTypes_old because it is an indexer and needs correct types for mangling
 		}
-	}
-
-	void validate_B( std::list< Declaration * > & translationUnit ) {
 		PassVisitor<FixQualifiedTypes> fixQual;
 		{
 			Stats::Heap::newPass("validate-B");
 			Stats::Time::BlockGuard guard("validate-B");
-			//linkReferenceToTypes( translationUnit );
+			linkReferenceToTypes( translationUnit ); // Must happen before auto-gen, because it uses the sized flag.
 			mutateAll( translationUnit, fixQual ); // must happen after LinkReferenceToTypes_old, because aggregate members are accessed
 			HoistStruct::hoistStruct( translationUnit );
 			EliminateTypedef::eliminateTypedef( translationUnit );
 		}
-	}
-
-	void validate_C( std::list< Declaration * > & translationUnit ) {
 		PassVisitor<ValidateGenericParameters> genericParams;
 		PassVisitor<ResolveEnumInitializers> rei( nullptr );
@@ -343,7 +337,4 @@
 			});
 		}
-	}
-
-	void validate_D( std::list< Declaration * > & translationUnit ) {
 		{
 			Stats::Heap::newPass("validate-D");
@@ -362,7 +353,4 @@
 			});
 		}
-	}
-
-	void validate_E( std::list< Declaration * > & translationUnit ) {
 		PassVisitor<CompoundLiteral> compoundliteral;
 		{
@@ -384,7 +372,4 @@
 			}
 		}
-	}
-
-	void validate_F( std::list< Declaration * > & translationUnit ) {
 		PassVisitor<LabelAddressFixer> labelAddrFixer;
 		{
@@ -410,13 +395,4 @@
 			}
 		}
-	}
-
-	void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
-		validate_A( translationUnit );
-		validate_B( translationUnit );
-		validate_C( translationUnit );
-		validate_D( translationUnit );
-		validate_E( translationUnit );
-		validate_F( translationUnit );
 	}
 
Index: src/SymTab/Validate.h
===================================================================
--- src/SymTab/Validate.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/Validate.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -11,6 +11,6 @@
 // Created On       : Sun May 17 21:53:34 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue May 17 14:35:00 2022
-// Update Count     : 5
+// Last Modified On : Tue Jul 12 15:30:00 2022
+// Update Count     : 6
 //
 
@@ -19,26 +19,9 @@
 #include <list>  // for list
 
-struct CodeLocation;
-class  Declaration;
-class  Type;
-
-namespace ast {
-	class Type;
-	class SymbolTable;
-}
+class Declaration;
 
 namespace SymTab {
-	class Indexer;
-
 	/// Normalizes struct and function declarations
 	void validate( std::list< Declaration * > &translationUnit, bool doDebug = false );
-
-	// Sub-passes of validate.
-	void validate_A( std::list< Declaration * > &translationUnit );
-	void validate_B( std::list< Declaration * > &translationUnit );
-	void validate_C( std::list< Declaration * > &translationUnit );
-	void validate_D( std::list< Declaration * > &translationUnit );
-	void validate_E( std::list< Declaration * > &translationUnit );
-	void validate_F( std::list< Declaration * > &translationUnit );
 } // namespace SymTab
 
Index: src/SymTab/ValidateType.cc
===================================================================
--- src/SymTab/ValidateType.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SymTab/ValidateType.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -222,11 +222,19 @@
 	// visit enum members first so that the types of self-referencing members are updated properly
 	// Replace the enum base; right now it works only for StructEnum
-	if ( enumDecl->base && dynamic_cast<TypeInstType*>(enumDecl->base) ) {
-		std::string baseName = static_cast<TypeInstType*>(enumDecl->base)->name;
-		const StructDecl * st = local_indexer->lookupStruct( baseName );
-		if ( st ) {
-			enumDecl->base = new StructInstType(Type::Qualifiers(),const_cast<StructDecl *>(st)); // Just linking in the node
+	if ( enumDecl->base ) {
+		if ( const TypeInstType * base = dynamic_cast< TypeInstType * >(enumDecl->base) ) {
+			if ( const StructDecl * decl = local_indexer->lookupStruct( base->name ) ) {
+				enumDecl->base = new StructInstType( Type::Qualifiers(), const_cast< StructDecl * >( decl ) ); // Just linking in the node
+			}
+		} else if ( const PointerType * ptr = dynamic_cast< PointerType * >(enumDecl->base) ) {
+			if ( const TypeInstType * ptrBase = dynamic_cast< TypeInstType * >( ptr->base ) ) {
+				if ( const StructDecl * decl = local_indexer->lookupStruct( ptrBase->name ) ) {
+					enumDecl->base = new PointerType( Type::Qualifiers(),
+						new StructInstType( Type::Qualifiers(), const_cast< StructDecl * >( decl ) ) );
+				}
+			}
 		}
 	}
+	
 	if ( enumDecl->body ) {
 		ForwardEnumsType::iterator fwds = forwardEnums.find( enumDecl->name );
Index: src/SynTree/AggregateDecl.cc
===================================================================
--- src/SynTree/AggregateDecl.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SynTree/AggregateDecl.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 23:56:39 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Dec 16 15:07:20 2019
-// Update Count     : 31
+// Last Modified On : Fri Jul  1 09:12:33 2022
+// Update Count     : 32
 //
 
@@ -125,5 +125,5 @@
 				SingleInit * init = strict_dynamic_cast< SingleInit * >( field->init );
 				auto result = eval( init->value );
-				if ( ! result.second ) SemanticError( init->location, toString( "Non-constexpr in initialization of enumerator: ", field ) );
+				if ( ! result.second ) SemanticError( init->location, toString( "Enumerator value for '", field, "' is not an integer constant" ) );
 				currentValue = result.first;
 			}
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/SynTree/Type.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -274,5 +274,5 @@
 class PointerType : public Type {
   public:
-	Type *base;
+	Type * base;
 
 	// In C99, pointer types can be qualified in many ways e.g., int f( int a[ static 3 ] )
@@ -516,6 +516,6 @@
 	typedef ReferenceToType Parent;
   public:
-	// this decl is not "owned" by the union inst; it is merely a pointer to elsewhere in the tree,
-	// where the union used in this type is actually defined
+	// this decl is not "owned" by the enum inst; it is merely a pointer to elsewhere in the tree,
+	// where the enum used in this type is actually defined
 	EnumDecl *baseEnum = nullptr;
 
Index: src/Tuples/Tuples.cc
===================================================================
--- src/Tuples/Tuples.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Tuples/Tuples.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Tuples.h --
+// Tuples.cc -- A collection of tuple operations.
 //
 // Author           : Andrew Beach
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Tuples/Tuples.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Tuples.h --
+// Tuples.h -- A collection of tuple operations.
 //
 // Author           : Rodolfo G. Esteves
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/Autogen.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -28,4 +28,5 @@
 #include "AST/DeclReplacer.hpp"
 #include "AST/Expr.hpp"
+#include "AST/Inspect.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Stmt.hpp"
@@ -121,5 +122,5 @@
 
 	// Built-ins do not use autogeneration.
-	bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
+	bool shouldAutogen() const final { return !decl->linkage.is_builtin && !structHasFlexibleArray(decl); }
 private:
 	void genFuncBody( ast::FunctionDecl * decl ) final;
@@ -183,7 +184,9 @@
 	{
 		// TODO: These functions are somewhere between instrinsic and autogen,
-		// could possibly use a new linkage type. For now we just make them
-		// intrinsic to code-gen them as C assignments.
-		proto_linkage = ast::Linkage::Intrinsic;
+		// could possibly use a new linkage type. For now we just make the
+		// basic ones intrinsic to code-gen them as C assignments.
+		const auto & real_type = decl->base;
+		const auto & basic = real_type.as<ast::BasicType>();
+		if(!real_type || (basic && basic->isInteger())) proto_linkage = ast::Linkage::Intrinsic;
 	}
 
@@ -402,8 +405,4 @@
 	auto retval = srcParam();
 	retval->name = "_ret";
-	// xxx - Adding this unused attribute can slience unused variable warning
-	// However, some code might not be compiled as expected
-	// Temporarily disabled
-	// retval->attributes.push_back(new ast::Attribute("unused"));
 	return genProto( "?=?", { dstParam(), srcParam() }, { retval } );
 }
Index: src/Validate/Autogen.hpp
===================================================================
--- src/Validate/Autogen.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/Autogen.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -22,4 +22,6 @@
 namespace Validate {
 
+/// Generate routines for all data types in the translation unit.
+/// A lot of passes have to happen either before or after this pass.
 void autogenerateRoutines( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/CompoundLiteral.hpp
===================================================================
--- src/Validate/CompoundLiteral.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/CompoundLiteral.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -23,4 +23,5 @@
 
 /// Use variables to implement compound literals.
+/// Must happen after auto-gen routines are added.
 void handleCompoundLiterals( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/EliminateTypedef.cpp
===================================================================
--- src/Validate/EliminateTypedef.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/EliminateTypedef.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Wed Apr 20 16:37:00 2022
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Apr 25 14:26:00 2022
-// Update Count     : 0
+// Last Modified On : Mon Jul 11 16:30:00 2022
+// Update Count     : 1
 //
 
@@ -28,7 +28,13 @@
 
 struct EliminateTypedefCore {
+	// Remove typedefs from inside aggregates.
 	ast::StructDecl const * previsit( ast::StructDecl const * decl );
 	ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
+	// Remove typedefs from statement lists.
 	ast::CompoundStmt const * previsit( ast::CompoundStmt const * stmt );
+	// Remove typedefs from control structure initializers.
+	ast::IfStmt const * previsit( ast::IfStmt const * stmt );
+	ast::ForStmt const * previsit( ast::ForStmt const * stmt );
+	ast::WhileDoStmt const * previsit( ast::WhileDoStmt const * stmt );
 };
 
@@ -63,4 +69,16 @@
 }
 
+ast::IfStmt const * EliminateTypedefCore::previsit( ast::IfStmt const * stmt ) {
+	return field_erase_if( stmt, &ast::IfStmt::inits, isTypedefStmt );
+}
+
+ast::ForStmt const * EliminateTypedefCore::previsit( ast::ForStmt const * stmt ) {
+	return field_erase_if( stmt, &ast::ForStmt::inits, isTypedefStmt );
+}
+
+ast::WhileDoStmt const * EliminateTypedefCore::previsit( ast::WhileDoStmt const * stmt ) {
+	return field_erase_if( stmt, &ast::WhileDoStmt::inits, isTypedefStmt );
+}
+
 } // namespace
 
Index: src/Validate/EnumAndPointerDecay.cpp
===================================================================
--- src/Validate/EnumAndPointerDecay.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/EnumAndPointerDecay.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,112 @@
+//
+// 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.
+//
+// EnumAndPointerDecay.cpp -- Normalizes enumerations and types in functions.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 28 15:50:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jul 12 14:45:00 2022
+// Update Count     : 0
+//
+
+#include "EnumAndPointerDecay.hpp"
+
+#include "AST/CVQualifiers.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "SymTab/FixFunction.h"
+
+namespace Validate {
+
+namespace {
+
+struct EnumAndPointerDecayCore final : public ast::WithGuards {
+	CodeLocation const * location = nullptr;
+	void previsit( ast::ParseNode const * node );
+	ast::EnumDecl const * previsit( ast::EnumDecl const * decl );
+	ast::FunctionDecl const * previsit( ast::FunctionDecl const * decl );
+	ast::FunctionType const * previsit( ast::FunctionType const * type );
+};
+
+void EnumAndPointerDecayCore::previsit( ast::ParseNode const * node ) {
+	GuardValue( location ) = &node->location;
+}
+
+ast::EnumDecl const * EnumAndPointerDecayCore::previsit(
+		ast::EnumDecl const * decl ) {
+	if ( decl->members.empty() ) {
+		return decl;
+	}
+	// Set the type of each member of the enumeration to be EnumContant.
+	auto mut = ast::mutate( decl );
+	for ( ast::ptr<ast::Decl> & member : mut->members ) {
+		ast::ObjectDecl const * object = member.strict_as<ast::ObjectDecl>();
+		member = ast::mutate_field( object, &ast::ObjectDecl::type,
+			new ast::EnumInstType( decl, ast::CV::Const ) );
+	}
+	GuardValue( location ) = &decl->location;
+	return mut;
+}
+
+template<typename Member>
+void fixFunctionList( CodeLocation const & location, bool isVarArgs,
+		std::vector<ast::ptr<Member>> & list ) {
+	bool hasVoid = false;
+	for ( ast::ptr<Member> & member : list ) {
+		member = SymTab::fixFunction( member, hasVoid );
+	}
+
+	// The remaining code only applies if void is present.
+	if ( !hasVoid ) {
+		return;
+	}
+
+	// So there is a void, which is only valid if it is the only argument.
+	if ( 1 < list.size() || isVarArgs ) {
+		SemanticError( location, "invalid type void in function type " );
+	}
+
+	// If a single "void" thing in the list to remove it.
+	list.clear();
+}
+
+ast::FunctionDecl const * EnumAndPointerDecayCore::previsit(
+		ast::FunctionDecl const * decl ) {
+	auto mut = ast::mutate( decl );
+	GuardValue( location ) = &decl->location;
+	ast::ArgumentFlag isVarArgs = mut->type->isVarArgs;
+	// It seems fixFunction (via fixFunctionList) does the pointer decay part.
+	fixFunctionList( mut->location, isVarArgs, mut->params );
+	fixFunctionList( mut->location, false, mut->returns );
+	return mut;
+}
+
+ast::FunctionType const * EnumAndPointerDecayCore::previsit(
+		ast::FunctionType const * type ) {
+	assert( location );
+	auto mut = ast::mutate( type );
+	ast::ArgumentFlag isVarArgs = mut->isVarArgs;
+	// It seems fixFunction (via fixFunctionList) does the pointer decay part.
+	fixFunctionList( *location, isVarArgs, mut->params );
+	fixFunctionList( *location, false, mut->returns );
+	return mut;
+}
+
+} // namespace
+
+void decayEnumsAndPointers( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<EnumAndPointerDecayCore>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/EnumAndPointerDecay.hpp
===================================================================
--- src/Validate/EnumAndPointerDecay.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/EnumAndPointerDecay.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// EnumAndPointerDecay.hpp -- Normalizes enumerations and types in functions.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 28 15:48:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul  4 13:12:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Fix the parameter and return types of functions. Also assigns types to
+/// enumeration values. This must happen before Link Reference to Types,
+/// it needs correct types for mangling, and before auto-gen.
+void decayEnumsAndPointers( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/FindSpecialDecls.h
===================================================================
--- src/Validate/FindSpecialDecls.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/FindSpecialDecls.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FindSpecialDeclarations.h --
+// FindSpecialDeclarations.h -- Find special declarations used in the compiler.
 //
 // Author           : Rob Schluntz
@@ -43,5 +43,5 @@
 	void findSpecialDecls( std::list< Declaration * > & translationUnit );
 
-/// find and remember some of the special declarations that are useful for
+/// Find and remember some of the special declarations that are useful for
 /// generating code, so that they do not have to be discovered multiple times.
 void findGlobalDecls( ast::TranslationUnit & translationUnit );
Index: src/Validate/FixQualifiedTypes.cpp
===================================================================
--- src/Validate/FixQualifiedTypes.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/FixQualifiedTypes.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FixQualifiedTypes.cpp --
+// FixQualifiedTypes.cpp -- Replace the qualified type with a direct type.
 //
 // Author           : Andrew Beach
@@ -76,5 +76,4 @@
 							ret->qualifiers = type->qualifiers;
 							ast::TypeSubstitution sub( aggr->params, instp->params );
-							// = parent->genericSubstitution();
 							auto result = sub.apply(ret);
 							return result.node.release();
Index: src/Validate/FixQualifiedTypes.hpp
===================================================================
--- src/Validate/FixQualifiedTypes.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/FixQualifiedTypes.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// FixQualifiedTypes.hpp --
+// FixQualifiedTypes.hpp -- Replace the qualified type with a direct type.
 //
 // Author           : Andrew Beach
@@ -22,4 +22,7 @@
 namespace Validate {
 
+/// Replaces qualified types with an unqualified NamedTypeDecl.
+/// Must happen after Link References To Types,
+/// because aggregate members are accessed.
 void fixQualifiedTypes( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/FixReturnTypes.cpp
===================================================================
--- src/Validate/FixReturnTypes.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/FixReturnTypes.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,101 @@
+//
+// 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.
+//
+// FixReturnTypes.cpp -- Unifies the representation of return types.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 29 11:06:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jul 12 14:04:00 2022
+// Update Count     : 0
+//
+
+#include "FixReturnTypes.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "CodeGen/CodeGenerator.h"
+#include "ResolvExpr/typeops.h"
+
+namespace ast {
+    class TranslationUnit;
+}
+
+namespace Validate {
+
+namespace {
+
+struct ReturnTypeFixer final {
+	ast::FunctionDecl const * postvisit( ast::FunctionDecl const * decl );
+	ast::FunctionType const * postvisit( ast::FunctionType const * type );
+};
+
+ast::FunctionDecl const * ReturnTypeFixer::postvisit(
+		ast::FunctionDecl const * decl ) {
+	// TODO: It does not handle return values. This information needs to be
+	// saved if resolution is to use it. (But does it currently?)
+	if ( 1 < decl->returns.size() ) {
+		auto mut = ast::mutate( decl );
+		// Generate a single return value which is the tuple of all return values.
+		auto resultType = ResolvExpr::extractResultType( mut->type );
+		ast::TupleType const * tupleType = resultType.strict_as<ast::TupleType>();
+		// Ensure return values are not destructed by explicitly creating
+		// an empty ListInit node wherein the ConstructFlag is NoConstruct.
+		ast::ObjectDecl * newRet = new ast::ObjectDecl(
+			decl->location, "", tupleType,
+			new ast::ListInit( decl->location, {}, {}, ast::NoConstruct ),
+			ast::Storage::Classes(), ast::Linkage::Cforall );
+		mut->returns.clear();
+		mut->returns.push_back( newRet );
+		decl = mut;
+	}
+
+	assertf( decl->returns.size() < 2,
+		"Function %s has too many return values: %zu",
+		decl->name.c_str(), decl->returns.size() );
+	if ( 0 == decl->returns.size() ) {
+		return decl;
+	}
+	// Ensure that all function return values have a name.
+	// The function name is used to disambiguate the name (and provide
+	// debugging information) from other return values.
+	auto mut = ast::mutate( decl );
+	ast::ptr<ast::DeclWithType> & ret = mut->returns.front();
+	if ( "" == ret->name ) {
+		ret.get_and_mutate()->name = "_retval_" + CodeGen::genName( decl );
+	}
+	ret.get_and_mutate()->attributes.push_back( new ast::Attribute( "unused" ) );
+	return mut;
+}
+
+ast::FunctionType const * ReturnTypeFixer::postvisit(
+		ast::FunctionType const * type ) {
+	if ( 1 < type->returns.size() ) {
+		auto mut = ast::mutate( type );
+		// Generate a single return type which is the tuple of all return types.
+		auto resultType = ResolvExpr::extractResultType( mut );
+		ast::TupleType const * tupleType = resultType.strict_as<ast::TupleType>();
+		mut->returns.clear();
+		mut->returns.push_back( tupleType );
+		return mut;
+	}
+	return type;
+}
+
+} // namespace
+
+void fixReturnTypes( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<ReturnTypeFixer>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/FixReturnTypes.hpp
===================================================================
--- src/Validate/FixReturnTypes.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/FixReturnTypes.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// FixReturnTypes.hpp -- Unifies the representation of return types.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 29 11:01:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jun 29 11:01:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+    class TranslationUnit;
+}
+
+namespace Validate {
+
+/// This pass needs to happen early so that other passes can find tuple types
+/// in the right places, especially for function return types.
+/// Must happen before auto-gen.
+void fixReturnTypes( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/ForallPointerDecay.hpp
===================================================================
--- src/Validate/ForallPointerDecay.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/ForallPointerDecay.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -29,4 +29,7 @@
 /// Also checks that operator names are used properly on functions and
 /// assigns unique IDs. This is a "legacy" pass.
+/// Must be after implement concurrent keywords; because uniqueIds must be
+/// set on declaration before resolution.
+/// Must happen before auto-gen routines are added.
 void decayForallPointers( ast::TranslationUnit & transUnit );
 
Index: src/Validate/GenericParameter.cpp
===================================================================
--- src/Validate/GenericParameter.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/GenericParameter.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenericParameter.hpp --
+// GenericParameter.hpp -- Generic parameter related passes.
 //
 // Author           : Andrew Beach
Index: src/Validate/GenericParameter.hpp
===================================================================
--- src/Validate/GenericParameter.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/GenericParameter.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// GenericParameter.hpp --
+// GenericParameter.hpp -- Generic parameter related passes.
 //
 // Author           : Andrew Beach
@@ -23,4 +23,6 @@
 
 /// Perform substutions for generic parameters and fill in defaults.
+/// Check as early as possible, but it can't happen before Link References to
+/// Types and observed failing when attempted before eliminate typedef.
 void fillGenericParameters( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/HoistStruct.hpp
===================================================================
--- src/Validate/HoistStruct.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/HoistStruct.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -22,5 +22,5 @@
 namespace Validate {
 
-/// Flattens nested type declarations.
+/// Flattens nested type declarations. (Run right after Fix Qualified Types.)
 void hoistStruct( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/HoistTypeDecls.cpp
===================================================================
--- src/Validate/HoistTypeDecls.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/HoistTypeDecls.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,77 @@
+//
+// 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.
+//
+// HoistTypeDecls.cpp -- Hoists declarations of implicitly declared types.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Jul  4  9:52:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul 12 14:07:00 2022
+// Update Count     : 0
+//
+
+#include "HoistTypeDecls.hpp"
+
+#include "AST/Pass.hpp"
+
+namespace Validate {
+
+namespace {
+
+struct HoistTypeDecls final : public ast::WithDeclsToAdd<> {
+	void previsit( ast::SizeofExpr const * );
+	void previsit( ast::AlignofExpr const * );
+	void previsit( ast::UntypedOffsetofExpr const * );
+	void previsit( ast::CompoundLiteralExpr const * );
+	void handleType( ast::Type const * );
+};
+
+void HoistTypeDecls::previsit( ast::SizeofExpr const * expr ) {
+	handleType( expr->type );
+}
+
+void HoistTypeDecls::previsit( ast::AlignofExpr const * expr ) {
+	handleType( expr->type );
+}
+
+void HoistTypeDecls::previsit( ast::UntypedOffsetofExpr const * expr ) {
+	handleType( expr->type );
+}
+
+void HoistTypeDecls::previsit( ast::CompoundLiteralExpr const * expr ) {
+	handleType( expr->result );
+}
+
+void HoistTypeDecls::handleType( ast::Type const * type ) {
+	// Some type declarations are buried in expressions and not easy to
+	// hoist during parsing; so they are hoisted here instead.
+	// This also where some missing code locations come in.
+	ast::AggregateDecl const * aggr = nullptr;
+	if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		aggr = inst->base;
+	} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		aggr = inst->base;
+	} else if ( auto inst = dynamic_cast<ast::EnumInstType const *>( type ) ) {
+		aggr = inst->base;
+	}
+	if ( aggr && aggr->body ) {
+		declsToAddBefore.push_front( aggr );
+	}
+}
+
+} // namespace
+
+void hoistTypeDecls( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<HoistTypeDecls>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/HoistTypeDecls.hpp
===================================================================
--- src/Validate/HoistTypeDecls.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/HoistTypeDecls.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// HoistTypeDecls.hpp -- Hoists declarations of implicitly declared types.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Jul  4  9:51:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul  4  9:51:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// There are some places where a type can be declared but are usually only
+/// referenced (with an *InstType). This inserts the declarations before
+/// they are referenced.
+void hoistTypeDecls( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/LabelAddressFixer.cpp
===================================================================
--- src/Validate/LabelAddressFixer.cpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/LabelAddressFixer.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// LabelAddressFixer.cpp --
+// LabelAddressFixer.cpp -- Create label address expressions.
 //
 // Author           : Andrew Beach
Index: src/Validate/LabelAddressFixer.hpp
===================================================================
--- src/Validate/LabelAddressFixer.hpp	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/LabelAddressFixer.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// LabelAddressFixer.hpp --
+// LabelAddressFixer.hpp -- Create label address expressions.
 //
 // Author           : Andrew Beach
@@ -20,4 +20,6 @@
 namespace Validate {
 
+/// Label addresses are not actually created in the parser, this pass finds
+/// the patterns that represent the label address expression.
 void fixLabelAddresses( ast::TranslationUnit & translationUnit );
 
Index: src/Validate/LinkReferenceToTypes.cpp
===================================================================
--- src/Validate/LinkReferenceToTypes.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/LinkReferenceToTypes.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,306 @@
+//
+// 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.
+//
+// LinkReferenceToTypes.cpp -- Connect instance types to declarations.
+//
+// Author           : Andrew Beach
+// Created On       : Thr Apr 21 11:41:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jun 28 14:58:00 2022
+// Update Count     : 1
+//
+
+#include "Validate/LinkReferenceToTypes.hpp"
+
+#include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
+#include "Validate/ForallPointerDecay.hpp"
+#include "Validate/NoIdSymbolTable.hpp"
+
+namespace Validate {
+
+namespace {
+
+struct LinkTypesCore : public WithNoIdSymbolTable,
+		public ast::WithGuards,
+		public ast::WithVisitorRef<LinkTypesCore>,
+		public ast::WithShortCircuiting {
+
+	ast::TypeInstType const * postvisit( ast::TypeInstType const * type );
+	ast::EnumInstType const * postvisit( ast::EnumInstType const * type );
+	ast::StructInstType const * postvisit( ast::StructInstType const * type );
+	ast::UnionInstType const * postvisit( ast::UnionInstType const * type );
+	ast::TraitInstType const * postvisit( ast::TraitInstType const * type );
+	void previsit( ast::QualifiedType const * type );
+	void postvisit( ast::QualifiedType const * type );
+
+	void previsit( ast::ParseNode const * node );
+
+	ast::EnumDecl const * postvisit( ast::EnumDecl const * decl );
+	ast::StructDecl const * previsit( ast::StructDecl const * decl );
+	void postvisit( ast::StructDecl const * decl );
+	ast::UnionDecl const * previsit( ast::UnionDecl const * decl );
+	void postvisit( ast::UnionDecl const * decl );
+	ast::TraitDecl const * postvisit( ast::TraitDecl const * decl );
+
+private:
+	using ForwardStructsType =
+		std::map< std::string, std::list< ast::StructInstType * > >;
+	using ForwardUnionsType =
+		std::map< std::string, std::list< ast::UnionInstType * > >;
+	using ForwardEnumsType =
+		std::map< std::string, std::list< ast::EnumInstType * > >;
+
+	ForwardStructsType forwardStructs;
+	ForwardUnionsType forwardUnions;
+	ForwardEnumsType forwardEnums;
+
+	const CodeLocation * location = nullptr;
+	/// true if currently in a generic type body,
+	/// so that type parameter instances can be renamed appropriately
+	bool inGeneric = false;
+
+	template<typename AggrDecl>
+	AggrDecl const * renameGenericParams( AggrDecl const * decl );
+};
+
+ast::TypeInstType const * LinkTypesCore::postvisit( ast::TypeInstType const * type ) {
+	auto mut = ast::mutate( type );
+	if ( inGeneric && mut->base ) {
+		mut->name = mut->base->name;
+	}
+	if ( auto namedTypeDecl = symtab.lookupType( mut->name ) ) {
+		if ( auto typeDecl = dynamic_cast<ast::TypeDecl const *>( namedTypeDecl ) ) {
+			mut->kind = typeDecl->kind;
+		}
+	}
+	return mut;
+}
+
+ast::EnumInstType const * LinkTypesCore::postvisit( ast::EnumInstType const * type ) {
+	ast::EnumDecl const * decl = symtab.lookupEnum( type->name );
+	// It's not a semantic error if the enum is not found, just an implicit forward declaration.
+	if ( decl ) {
+		// Just linking in the node.
+		auto mut = ast::mutate( type );
+		mut->base = const_cast<ast::EnumDecl *>( decl );
+		type = mut;
+	}
+	if ( !decl || !decl->body ) {
+		auto mut = ast::mutate( type );
+		forwardEnums[ mut->name ].push_back( mut );
+		type = mut;
+	}
+	return type;
+}
+
+ast::StructInstType const * LinkTypesCore::postvisit( ast::StructInstType const * type ) {
+	ast::StructDecl const * decl = symtab.lookupStruct( type->name );
+	// It's not a semantic error if the struct is not found, just an implicit forward declaration.
+	if ( decl ) {
+		// Just linking in the node.
+		auto mut = ast::mutate( type );
+		mut->base = const_cast<ast::StructDecl *>( decl );
+		type = mut;
+	}
+	if ( !decl || !decl->body ) {
+		auto mut = ast::mutate( type );
+		forwardStructs[ mut->name ].push_back( mut );
+		type = mut;
+	}
+	return type;
+}
+
+ast::UnionInstType const * LinkTypesCore::postvisit( ast::UnionInstType const * type ) {
+	ast::UnionDecl const * decl = symtab.lookupUnion( type->name );
+	// It's not a semantic error if the union is not found, just an implicit forward declaration.
+	if ( decl ) {
+		// Just linking in the node.
+		auto mut = ast::mutate( type );
+		mut->base = const_cast<ast::UnionDecl *>( decl );
+		type = mut;
+	}
+	if ( !decl || !decl->body ) {
+		auto mut = ast::mutate( type );
+		forwardUnions[ mut->name ].push_back( mut );
+		type = mut;
+	}
+	return type;
+}
+
+ast::TraitInstType const * LinkTypesCore::postvisit( ast::TraitInstType const * type ) {
+	assert( location );
+
+	ast::TraitDecl const * decl = symtab.lookupTrait( type->name );
+	if ( !decl ) {
+		SemanticError( *location, "use of undeclared trait " + type->name );
+	} else if ( decl->params.size() != type->params.size() ) {
+		SemanticError( *location, "incorrect number of trait parameters: " );
+	}
+	auto mut = ast::mutate( type );
+
+	// Just linking in the node.
+	mut->base = const_cast<ast::TraitDecl *>( decl );
+
+	// Need to carry over the 'sized' status of each decl in the instance.
+	for ( auto p : group_iterate( decl->params, type->params ) ) {
+		ast::TypeExpr const * expr = std::get<1>(p).as<ast::TypeExpr>();
+		if ( !expr ) {
+			SemanticError( std::get<1>(p).get(), "Expression parameters for trait instances are currently unsupported: " );
+		}
+		if ( auto inst = expr->type.as<ast::TypeInstType>() ) {
+			ast::ptr<ast::TypeDecl> const & formalDecl = std::get<0>(p);
+			if ( !formalDecl->sized ) {
+				continue;
+			}
+			// To do this modification we need to reach through a readonly
+			// pointer. The Pass doesn't quite work in that way, so we just
+			// ensure it mutates in-place so it should work out.
+			ast::TypeDecl const * base = inst->base.get();
+			assert( base->unique() );
+			ast::TypeDecl * mutBase = ast::mutate( base );
+			mutBase->sized = true;
+		}
+	}
+	return mut;
+}
+
+void LinkTypesCore::previsit( ast::QualifiedType const * ) {
+	visit_children = false;
+}
+
+void LinkTypesCore::postvisit( ast::QualifiedType const * type ) {
+	// Linking only makes sense for the 'oldest ancestor' of the qualified type.
+	type->parent->accept( *visitor );
+}
+
+void LinkTypesCore::previsit( ast::ParseNode const * node ) {
+	GuardValue( location ) = &node->location;
+}
+
+ast::EnumDecl const * LinkTypesCore::postvisit( ast::EnumDecl const * decl ) {
+	// After visiting enum members for self-referencing members,
+	// we replace the enum base. Right now it only works for StructDecl.
+	if ( decl->base ) {
+		if ( auto base = decl->base.as<ast::TypeInstType>() ) {
+			if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
+				auto mut = ast::mutate( decl );
+				mut->base = new ast::StructInstType( structDecl );
+				decl = mut;
+			}
+		} else if ( auto ptr = decl->base.as<ast::PointerType>() ) {
+			if ( auto base = ptr->base.as<ast::TypeInstType>() ) {
+				if ( auto structDecl = symtab.lookupStruct( base->name ) ) {
+					auto mut = ast::mutate( decl );
+					mut->base = new ast::PointerType(
+						new ast::StructInstType( structDecl ) );
+					decl = mut;
+				}
+			}
+		}
+	}
+
+	// This section is common with struct/union, except for the return value.
+	if ( !decl->body ) {
+		return decl;
+	}
+
+	ForwardEnumsType::iterator fwds = forwardEnums.find( decl->name );
+	if ( fwds != forwardEnums.end() ) {
+		for ( auto inst : fwds->second ) {
+			inst->base = decl;
+		}
+		forwardEnums.erase( fwds );
+	}
+
+	return decl;
+}
+
+template<typename AggrDecl>
+AggrDecl const * LinkTypesCore::renameGenericParams( AggrDecl const * decl ) {
+	GuardValue( inGeneric ) = !decl->params.empty();
+	if ( !inGeneric ) {
+		GuardValue( location ) = &decl->location;
+		return decl;
+	}
+	auto mut = ast::mutate( decl );
+	GuardValue( location ) = &mut->location;
+	for ( ast::ptr<ast::TypeDecl> & typeDecl : mut->params ) {
+		typeDecl.get_and_mutate()->name = "__" + typeDecl->name + "_generic_";
+	}
+	return mut;
+}
+
+ast::StructDecl const * LinkTypesCore::previsit( ast::StructDecl const * decl ) {
+	return renameGenericParams( decl );
+}
+
+void LinkTypesCore::postvisit( ast::StructDecl const * decl ) {
+	if ( !decl->body ) {
+		return;
+	}
+
+	ForwardStructsType::iterator fwds = forwardStructs.find( decl->name );
+	if ( fwds != forwardStructs.end() ) {
+		for ( auto inst : fwds->second ) {
+			inst->base = decl;
+		}
+		forwardStructs.erase( fwds );
+	}
+}
+
+ast::UnionDecl const * LinkTypesCore::previsit( ast::UnionDecl const * decl ) {
+	return renameGenericParams( decl );
+}
+
+void LinkTypesCore::postvisit( ast::UnionDecl const * decl ) {
+	if ( !decl->body ) {
+		return;
+	}
+
+	ForwardUnionsType::iterator fwds = forwardUnions.find( decl->name );
+	if ( fwds != forwardUnions.end() ) {
+		for ( auto inst : fwds->second ) {
+			inst->base = decl;
+		}
+		forwardUnions.erase( fwds );
+	}
+}
+
+ast::TraitDecl const * LinkTypesCore::postvisit( ast::TraitDecl const * decl ) {
+	auto mut = ast::mutate( decl );
+	if ( mut->name == "sized" ) {
+		// "sized" is a special trait - flick the sized status on for the type variable.
+		assertf( mut->params.size() == 1, "Built-in trait 'sized' has incorrect number of parameters: %zd", decl->params.size() );
+		ast::TypeDecl * td = mut->params.front().get_and_mutate();
+		td->sized = true;
+	}
+
+	// There is some overlap with code from decayForallPointers,
+	// perhaps reorganization or shared helper functions are called for.
+	// Move assertions from type parameters into the body of the trait.
+	for ( ast::ptr<ast::TypeDecl> const & td : decl->params ) {
+		auto expanded = expandAssertions( td->assertions );
+		for ( auto declWithType : expanded ) {
+			mut->members.emplace_back( declWithType.release() );
+		}
+	}
+	return mut;
+}
+
+} // namespace
+
+void linkReferenceToTypes( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<LinkTypesCore>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/LinkReferenceToTypes.hpp
===================================================================
--- src/Validate/LinkReferenceToTypes.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/LinkReferenceToTypes.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,35 @@
+//
+// 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.
+//
+// LinkReferenceToTypes.hpp -- Connect instance types to declarations.
+//
+// Author           : Andrew Beach
+// Created On       : Thr Apr 21 11:41:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jun 28 14:58:00 2022
+// Update Count     : 1
+//
+
+#pragma once
+
+namespace ast {
+    class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Fills in the base value of various instance types, and some related
+/// adjustments, such as setting the sized flag.
+/// Because of the sized flag, it must happen before auto-gen.
+void linkReferenceToTypes( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/ReplaceTypedef.cpp
===================================================================
--- src/Validate/ReplaceTypedef.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/ReplaceTypedef.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,386 @@
+//
+// 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.
+//
+// ReplaceTypedef.cpp -- Fill in all typedefs with the underlying type.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 29 14:59:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jul 13 14:45:00 2022
+// Update Count     : 1
+//
+
+#include "ReplaceTypedef.hpp"
+
+#include "AST/Pass.hpp"
+#include "Common/ScopedMap.h"
+#include "Common/UniqueName.h"
+#include "Common/utility.h"
+#include "ResolvExpr/typeops.h"
+
+namespace Validate {
+
+namespace {
+
+bool isNonParameterAttribute( ast::Attribute const * attr ) {
+	static const std::vector<std::string> bad_names = {
+		"aligned", "__aligned__",
+	};
+	for ( auto name : bad_names ) {
+		if ( name == attr->name ) {
+			return true;
+		}
+	}
+	return false;
+}
+
+struct ReplaceTypedefCore final :
+		public ast::WithVisitorRef<ReplaceTypedefCore>,
+		public ast::WithGuards,
+		public ast::WithShortCircuiting,
+		public ast::WithDeclsToAdd<> {
+
+	void previsit( ast::ParseNode const * node );
+	void previsit( ast::QualifiedType const * );
+	ast::Type const * postvisit( ast::QualifiedType const * );
+	ast::Type const * postvisit( ast::TypeInstType const * );
+	ast::Decl const * postvisit( ast::TypedefDecl const * );
+	void previsit( ast::TypeDecl const * );
+	void previsit( ast::FunctionDecl const * );
+	void previsit( ast::ObjectDecl const * );
+	ast::DeclWithType const * postvisit( ast::ObjectDecl const * );
+
+	void previsit( ast::CastExpr const * );
+	void previsit( ast::CompoundStmt const * );
+	void postvisit( ast::CompoundStmt const * );
+
+	ast::StructDecl const * previsit( ast::StructDecl const * );
+	ast::UnionDecl const * previsit( ast::UnionDecl const * );
+	void previsit( ast::EnumDecl const * );
+	void previsit( ast::TraitDecl const * );
+
+	template<typename AggrDecl>
+	void addImplicitTypedef( AggrDecl * aggDecl );
+	template<typename AggrDecl>
+	AggrDecl const * handleAggregate( AggrDecl const * aggDecl );
+
+	using TypedefDeclPtr = ast::ptr<ast::TypedefDecl>;
+	using TypedefMap = ScopedMap<std::string, std::pair<TypedefDeclPtr, int>>;
+	using TypeDeclMap = ScopedMap<std::string, ast::TypeDecl const *>;
+
+	TypedefMap typedefNames;
+	TypeDeclMap typedeclNames;
+	CodeLocation const * nearestLocation = nullptr;
+	int scopeLevel;
+	bool isAtFunctionTop = false;
+};
+
+void ReplaceTypedefCore::previsit( ast::ParseNode const * node ) {
+	GuardValue( nearestLocation ) = &node->location;
+}
+
+void ReplaceTypedefCore::previsit( ast::QualifiedType const * ) {
+	visit_children = false;
+}
+
+ast::Type const * ReplaceTypedefCore::postvisit(
+		ast::QualifiedType const * type ) {
+	// Replacing typedefs only makes sense for the 'oldest ancestor'
+	// of the qualified type.
+	return ast::mutate_field( type, &ast::QualifiedType::parent,
+		type->parent->accept( *visitor ) );
+}
+
+ast::Type const * ReplaceTypedefCore::postvisit(
+		ast::TypeInstType const * type ) {
+	// Instances of typedef types will come here. If it is an instance
+	// of a typedef type, link the instance to its actual type.
+	TypedefMap::const_iterator def = typedefNames.find( type->name );
+	if ( def != typedefNames.end() ) {
+		ast::Type * ret = ast::deepCopy( def->second.first->base );
+		ret->qualifiers |= type->qualifiers;
+		// We ignore certain attributes on function parameters if they arrive
+		// by typedef. GCC appears to do the same thing.
+		if ( isAtFunctionTop ) {
+			erase_if( ret->attributes, isNonParameterAttribute );
+		}
+		for ( const auto & attribute : type->attributes ) {
+			ret->attributes.push_back( attribute );
+		}
+		// Place instance parameters on the typedef'd type.
+		if ( !type->params.empty() ) {
+			auto rtt = dynamic_cast<ast::BaseInstType *>( ret );
+			if ( !rtt ) {
+				assert( nearestLocation );
+				SemanticError( *nearestLocation, "Cannot apply type parameters to base type of " + type->name );
+			}
+			rtt->params.clear();
+			for ( auto it : type->params ) {
+				rtt->params.push_back( ast::deepCopy( it ) );
+			}
+			// Recursively fix typedefs on parameters.
+			ast::mutate_each( rtt, &ast::BaseInstType::params, *visitor );
+		}
+		return ret;
+	} else {
+		TypeDeclMap::const_iterator base = typedeclNames.find( type->name );
+		if ( base == typedeclNames.end() ) {
+			assert( nearestLocation );
+			SemanticError( *nearestLocation, toString( "Use of undefined type ", type->name ) );
+		}
+		return ast::mutate_field( type, &ast::TypeInstType::base, base->second );
+	}
+}
+
+struct VarLenChecker : public ast::WithShortCircuiting {
+	bool result = false;
+	void previsit( ast::FunctionType const * ) { visit_children = false; }
+	void previsit( ast::ArrayType const * at ) { result |= at->isVarLen; }
+};
+
+ast::Decl const * ReplaceTypedefCore::postvisit(
+		ast::TypedefDecl const * decl ) {
+	if ( 1 == typedefNames.count( decl->name ) &&
+			typedefNames[ decl->name ].second == scopeLevel ) {
+		ast::Type const * t0 = decl->base;
+		ast::Type const * t1 = typedefNames[ decl->name ].first->base;
+		// Cannot redefine VLA typedefs. Note: this is slightly incorrect,
+		// because our notion of VLAs at this point in the translator is
+		// imprecise. In particular, this will disallow redefining typedefs
+		// with arrays whose dimension is an enumerator or a cast of a
+		// constant/enumerator. The effort required to fix this corner case
+		// likely outweighs the utility of allowing it.
+		if ( !ResolvExpr::typesCompatible( t0, t1, ast::SymbolTable() )
+				|| ast::Pass<VarLenChecker>::read( t0 )
+				|| ast::Pass<VarLenChecker>::read( t1 ) ) {
+			SemanticError( decl->location, "Cannot redefine typedef: " + decl->name );
+		}
+	} else {
+		typedefNames[ decl->name ] =
+			std::make_pair( TypedefDeclPtr( decl ), scopeLevel );
+	}
+
+	// When a typedef is a forward declaration:
+	// >	typedef struct screen SCREEN;
+	// the declaration portion must be retained:
+	// >	struct screen;
+	// because the expansion of the typedef is:
+	// >	void func( SCREEN * p ) -> void func( struct screen * p );
+	// hence type name "screen" must be defined.
+	// Note: qualifiers on the typedef are not used for the forward declaration.
+
+	ast::Type const * designatorType = decl->base->stripDeclarator();
+	if ( auto structType = dynamic_cast<ast::StructInstType const *>( designatorType ) ) {
+		declsToAddBefore.push_back( new ast::StructDecl(
+			decl->location, structType->name, ast::AggregateDecl::Struct, {},
+			decl->linkage ) );
+	} else if ( auto unionType = dynamic_cast<ast::UnionInstType const *>( designatorType ) ) {
+		declsToAddBefore.push_back( new ast::UnionDecl(
+			decl->location, unionType->name, {}, decl->linkage ) );
+	} else if ( auto enumType = dynamic_cast<ast::EnumInstType const *>( designatorType ) ) {
+		declsToAddBefore.push_back( new ast::EnumDecl(
+			decl->location, enumType->name, {}, decl->linkage,
+			( (enumType->base) ? enumType->base->base : nullptr )
+			) );
+	}
+	return ast::deepCopy( decl );
+}
+
+void ReplaceTypedefCore::previsit( ast::TypeDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	TypedefMap::iterator iter = typedefNames.find( decl->name );
+	if ( iter != typedefNames.end() ) {
+		typedefNames.erase( iter );
+	}
+	typedeclNames.insert( decl->name, decl );
+}
+
+void ReplaceTypedefCore::previsit( ast::FunctionDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+	GuardValue( isAtFunctionTop ) = true;
+}
+
+void ReplaceTypedefCore::previsit( ast::ObjectDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+}
+
+ast::DeclWithType const * ReplaceTypedefCore::postvisit(
+		ast::ObjectDecl const * decl ) {
+	if ( ast::FunctionType const * type = decl->type.as<ast::FunctionType>() ) {
+		using DWTVector = std::vector<ast::ptr<ast::DeclWithType>>;
+		using DeclVector = std::vector<ast::ptr<ast::TypeDecl>>;
+		CodeLocation const & location = decl->location;
+		UniqueName paramNamer( decl->name + "Param" );
+
+		// Replace the current object declaration with a function declaration.
+		ast::FunctionDecl const * newDecl = new ast::FunctionDecl(
+			location,
+			decl->name,
+			map_range<DeclVector>( type->forall, []( const ast::TypeInstType * inst ) {
+				return ast::deepCopy( inst->base );
+			} ),
+			map_range<DWTVector>( type->assertions, []( const ast::VariableExpr * expr ) {
+				return ast::deepCopy( expr->var );
+			} ),
+			map_range<DWTVector>( type->params, [&location, &paramNamer]( const ast::Type * type ) {
+				assert( type );
+				return new ast::ObjectDecl( location, paramNamer.newName(), ast::deepCopy( type ) );
+			} ),
+			map_range<DWTVector>( type->returns, [&location, &paramNamer]( const ast::Type * type ) {
+				assert( type );
+				return new ast::ObjectDecl( location, paramNamer.newName(), ast::deepCopy( type ) );
+			} ),
+			nullptr,
+			decl->storage,
+			decl->linkage,
+			{/* attributes */},
+			decl->funcSpec
+		);
+		return newDecl;
+	}
+	return decl;
+}
+
+void ReplaceTypedefCore::previsit( ast::CastExpr const * expr ) {
+	previsit( (ast::ParseNode const *)expr );
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+}
+
+void ReplaceTypedefCore::previsit( ast::CompoundStmt const * expr ) {
+	previsit( (ast::ParseNode const *)expr );
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+	GuardValue( isAtFunctionTop ) = false;
+	scopeLevel += 1;
+}
+
+void ReplaceTypedefCore::postvisit( ast::CompoundStmt const * ) {
+	scopeLevel -= 1;
+}
+
+ast::StructDecl const * ReplaceTypedefCore::previsit( ast::StructDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	visit_children = false;
+	addImplicitTypedef( decl );
+	return handleAggregate( decl );
+}
+
+ast::UnionDecl const * ReplaceTypedefCore::previsit( ast::UnionDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	visit_children = false;
+	addImplicitTypedef( decl );
+	return handleAggregate( decl );
+}
+
+void ReplaceTypedefCore::previsit( ast::EnumDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	addImplicitTypedef( decl );
+}
+
+void ReplaceTypedefCore::previsit( ast::TraitDecl const * decl ) {
+	previsit( (ast::ParseNode const *)decl );
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+}
+
+template<typename AggrDecl>
+void ReplaceTypedefCore::addImplicitTypedef( AggrDecl * aggrDecl ) {
+	if ( 0 != typedefNames.count( aggrDecl->name ) ) {
+		return;
+	}
+	ast::Type * type = nullptr;
+	if ( auto structDecl = dynamic_cast<const ast::StructDecl *>( aggrDecl ) ) {
+		type = new ast::StructInstType( structDecl->name );
+	} else if ( auto unionDecl = dynamic_cast<const ast::UnionDecl *>( aggrDecl ) ) {
+		type = new ast::UnionInstType( unionDecl->name );
+	} else if ( auto enumDecl = dynamic_cast<const ast::EnumDecl *>( aggrDecl ) ) {
+		type = new ast::EnumInstType( enumDecl->name );
+	}
+	assert( type );
+
+	TypedefDeclPtr typeDecl = new ast::TypedefDecl( aggrDecl->location,
+		aggrDecl->name, ast::Storage::Classes(), type, aggrDecl->linkage );
+	// Add the implicit typedef to the AST.
+	declsToAddBefore.push_back( ast::deepCopy( typeDecl.get() ) );
+	// Shore the name in the map of names.
+	typedefNames[ aggrDecl->name ] =
+		std::make_pair( std::move( typeDecl ), scopeLevel );
+}
+
+template<typename AggrDecl>
+AggrDecl const * ReplaceTypedefCore::handleAggregate( AggrDecl const * decl ) {
+	SemanticErrorException errors;
+
+	ValueGuard<decltype(declsToAddBefore)> oldBeforeDecls( declsToAddBefore );
+	ValueGuard<decltype(declsToAddAfter )> oldAfterDecls(  declsToAddAfter );
+	declsToAddBefore.clear();
+	declsToAddAfter.clear();
+
+	GuardScope( typedefNames );
+	GuardScope( typedeclNames );
+	decl = mutate_each( decl, &ast::AggregateDecl::params, *visitor );
+	decl = mutate_each( decl, &ast::AggregateDecl::attributes, *visitor );
+
+	auto mut = ast::mutate( decl );
+
+	std::vector<ast::ptr<ast::Decl>> members;
+	// Unroll accept_all for decl->members so that implicit typedefs for
+	// nested types are added to the aggregate body.
+	for ( ast::ptr<ast::Decl> const & member : mut->members ) {
+		assert( declsToAddAfter.empty() );
+		ast::Decl const * newMember = nullptr;
+		try {
+			newMember = member->accept( *visitor );
+		} catch ( SemanticErrorException & e ) {
+			errors.append( e );
+		}
+		if ( !declsToAddBefore.empty() ) {
+			for ( auto declToAdd : declsToAddBefore ) {
+				members.push_back( declToAdd );
+			}
+			declsToAddBefore.clear();
+		}
+		members.push_back( newMember );
+	}
+	assert( declsToAddAfter.empty() );
+	if ( !errors.isEmpty() ) { throw errors; }
+
+	mut->members.clear();
+	for ( auto member : members ) {
+		mut->members.push_back( member );
+	}
+
+	return mut;
+}
+
+} // namespace
+
+void replaceTypedef( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<ReplaceTypedefCore> pass;
+	ast::accept_all( translationUnit, pass );
+	if ( pass.core.typedefNames.count( "size_t" ) ) {
+		translationUnit.global.sizeType =
+			ast::deepCopy( pass.core.typedefNames["size_t"].first->base );
+	} else {
+		// Missing the global definition, default to long unsigned int.
+		// Perhaps this should be a warning instead.
+		translationUnit.global.sizeType =
+			new ast::BasicType( ast::BasicType::LongUnsignedInt );
+	}
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/ReplaceTypedef.hpp
===================================================================
--- src/Validate/ReplaceTypedef.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/ReplaceTypedef.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -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.
+//
+// ReplaceTypedef.hpp -- Fill in all typedefs with the underlying type.
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 29 14:58:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul  4 13:12:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Uses of typedef are replaced with the type in the typedef.
+void replaceTypedef( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/VerifyCtorDtorAssign.cpp
===================================================================
--- src/Validate/VerifyCtorDtorAssign.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/VerifyCtorDtorAssign.cpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,61 @@
+//
+// 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.
+//
+// VerifyCtorDtorAssign.cpp -- Check the form of operators.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Jul  4 10:26:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul 12 11:26:00 2022
+// Update Count     : 0
+//
+
+#include "VerifyCtorDtorAssign.hpp"
+
+#include "AST/Pass.hpp"
+#include "CodeGen/OperatorTable.h"
+
+namespace Validate {
+
+namespace {
+
+struct VerifyCore {
+	void previsit( ast::FunctionDecl const * decl );
+};
+
+void VerifyCore::previsit( ast::FunctionDecl const * decl ) {
+	// Skip any of the functions we are not checking.
+	// Should get contructors, destructors and all forms of assignment.
+	if ( !CodeGen::isCtorDtorAssign( decl->name ) ) {
+		return;
+	}
+
+	if ( 0 == decl->params.size() ) {
+		SemanticError( decl->location, "Constructors, destructors, and assignment functions require at least one parameter." );
+	}
+	auto refType = decl->type->params.front().as<ast::ReferenceType>();
+	if ( !refType ) {
+		SemanticError( decl->location, "First parameter of a constructor, destructor, or assignment function must be a reference." );
+	}
+	if ( CodeGen::isCtorDtor( decl->name ) && 0 != decl->returns.size()
+			&& !decl->returns.front()->get_type()->isVoid() ) {
+		SemanticError( decl->location, "Constructors and destructors cannot have explicit return values." );
+	}
+}
+
+} // namespace
+
+void verifyCtorDtorAssign( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<VerifyCore>::run( translationUnit );
+}
+
+} // namespace Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/VerifyCtorDtorAssign.hpp
===================================================================
--- src/Validate/VerifyCtorDtorAssign.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
+++ src/Validate/VerifyCtorDtorAssign.hpp	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+// VerifyCtorDtorAssign.hpp -- Check the form of operators.
+//
+// Author           : Andrew Beach
+// Created On       : Mon Jul  4 10:25:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul  4 13:13:00 2022
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace Validate {
+
+/// Check that constructors, destructors and assignments all have the correct
+/// form. Must happen before auto-gen or anything that examines operators.
+void verifyCtorDtorAssign( 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 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Validate/module.mk	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -26,7 +26,11 @@
 	Validate/EliminateTypedef.cpp \
 	Validate/EliminateTypedef.hpp \
+	Validate/EnumAndPointerDecay.cpp \
+	Validate/EnumAndPointerDecay.hpp \
 	Validate/FindSpecialDeclsNew.cpp \
 	Validate/FixQualifiedTypes.cpp \
 	Validate/FixQualifiedTypes.hpp \
+	Validate/FixReturnTypes.cpp \
+	Validate/FixReturnTypes.hpp \
 	Validate/ForallPointerDecay.cpp \
 	Validate/ForallPointerDecay.hpp \
@@ -37,11 +41,19 @@
 	Validate/HoistStruct.cpp \
 	Validate/HoistStruct.hpp \
+	Validate/HoistTypeDecls.cpp \
+	Validate/HoistTypeDecls.hpp \
 	Validate/InitializerLength.cpp \
 	Validate/InitializerLength.hpp \
 	Validate/LabelAddressFixer.cpp \
 	Validate/LabelAddressFixer.hpp \
+	Validate/LinkReferenceToTypes.cpp \
+	Validate/LinkReferenceToTypes.hpp \
 	Validate/NoIdSymbolTable.hpp \
+	Validate/ReplaceTypedef.cpp \
+	Validate/ReplaceTypedef.hpp \
 	Validate/ReturnCheck.cpp \
-	Validate/ReturnCheck.hpp
+	Validate/ReturnCheck.hpp \
+	Validate/VerifyCtorDtorAssign.cpp \
+	Validate/VerifyCtorDtorAssign.hpp
 
 SRCDEMANGLE += $(SRC_VALIDATE)
Index: src/Virtual/Tables.h
===================================================================
--- src/Virtual/Tables.h	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/Virtual/Tables.h	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -19,6 +19,11 @@
 #include "AST/Fwd.hpp"
 class Declaration;
+class Expression;
+class FunctionDecl;
+class Initializer;
+class ObjectDecl;
 class StructDecl;
-class Expression;
+class StructInstType;
+class Type;
 
 namespace Virtual {
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 9e23b446e321a87bbf5f2439c8d555a808d5e53c)
+++ src/main.cc	(revision ffec1bfd5e6f76604c43a28508c5ddcc64bd3218)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Jun  7 13:29:00 2022
-// Update Count     : 674
+// Last Modified On : Mon Jul 18 11:08:00 2022
+// Update Count     : 676
 //
 
@@ -78,12 +78,18 @@
 #include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
 #include "Validate/EliminateTypedef.hpp"    // for eliminateTypedef
+#include "Validate/EnumAndPointerDecay.hpp" // for decayEnumsAndPointers
 #include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
 #include "Validate/FixQualifiedTypes.hpp"   // for fixQualifiedTypes
+#include "Validate/FixReturnTypes.hpp"      // for fixReturnTypes
 #include "Validate/ForallPointerDecay.hpp"  // for decayForallPointers
 #include "Validate/GenericParameter.hpp"    // for fillGenericParameters, tr...
 #include "Validate/HoistStruct.hpp"         // for hoistStruct
+#include "Validate/HoistTypeDecls.hpp"      // for hoistTypeDecls
 #include "Validate/InitializerLength.hpp"   // for setLengthFromInitializer
 #include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
+#include "Validate/LinkReferenceToTypes.hpp" // for linkReferenceToTypes
+#include "Validate/ReplaceTypedef.hpp"      // for replaceTypedef
 #include "Validate/ReturnCheck.hpp"         // for checkReturnStatements
+#include "Validate/VerifyCtorDtorAssign.hpp" // for verifyCtorDtorAssign
 #include "Virtual/ExpandCasts.h"            // for expandCasts
 
@@ -324,21 +330,5 @@
 		Stats::Time::StopBlock();
 
-		PASS( "Translate Exception Declarations", ControlStruct::translateExcept( translationUnit ) );
-		if ( exdeclp ) {
-			dump( translationUnit );
-			return EXIT_SUCCESS;
-		} // if
-
-		// add the assignment statement after the initialization of a type parameter
-		PASS( "Validate-A", SymTab::validate_A( translationUnit ) );
-
-		// Must happen before auto-gen, because it uses the sized flag.
-		PASS( "Link Reference To Types", SymTab::linkReferenceToTypes( translationUnit ) );
-
-		CodeTools::fillLocations( translationUnit );
-
 		if( useNewAST ) {
-			CodeTools::fillLocations( translationUnit );
-
 			if (Stats::Counters::enabled) {
 				ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
@@ -349,34 +339,34 @@
 			forceFillCodeLocations( transUnit );
 
-			// Must happen after Link References To Types,
-			// because aggregate members are accessed.
+			PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
+			if ( exdeclp ) {
+				dump( move( transUnit ) );
+				return EXIT_SUCCESS;
+			}
+
+			PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
+			PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
+			// Hoist Type Decls pulls some declarations out of contexts where
+			// locations are not tracked. Perhaps they should be, but for now
+			// the full fill solves it.
+			forceFillCodeLocations( transUnit );
+
+			PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
+			PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
+			PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
+
+			PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
+
 			PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
-
 			PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
 			PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
-
-			// Check as early as possible. Can't happen before
-			// LinkReferenceToType, observed failing when attempted
-			// before eliminateTypedef
 			PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
-
 			PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
 			PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
-
-			// Must happen before Autogen.
 			PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
-
 			PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
-
-			// Must be after implement concurrent keywords; because uniqueIds
-			//   must be set on declaration before resolution.
-			// Must happen before autogen routines are added.
 			PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
-
-			// Must happen before autogen routines are added.
 			PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
 
-			// Must be after enum and pointer decay.
-			// Must be before compound literals.
 			PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
 
@@ -454,9 +444,12 @@
 			translationUnit = convert( move( transUnit ) );
 		} else {
-			PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
-			PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
-			PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
-			PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
-			PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
+			PASS( "Translate Exception Declarations", ControlStruct::translateExcept( translationUnit ) );
+			if ( exdeclp ) {
+				dump( translationUnit );
+				return EXIT_SUCCESS;
+			} // if
+
+			// add the assignment statement after the initialization of a type parameter
+			PASS( "Validate", SymTab::validate( translationUnit ) );
 
 			if ( symtabp ) {
