Index: src/Validate/EliminateTypedef.cpp
===================================================================
--- src/Validate/EliminateTypedef.cpp	(revision 72e76fd79ca74c8a20af8bb1560c3808f736579a)
+++ src/Validate/EliminateTypedef.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/EnumAndPointerDecay.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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 --
+//
+// 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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/EnumAndPointerDecay.hpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -0,0 +1,32 @@
+//
+// 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 --
+//
+// 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 {
+
+void decayEnumsAndPointers( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/FixReturnTypes.cpp
===================================================================
--- src/Validate/FixReturnTypes.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/FixReturnTypes.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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 --
+//
+// 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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/FixReturnTypes.hpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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.
+//
+// FixReturnTypes.hpp --
+//
+// 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.
+void fixReturnTypes( ast::TranslationUnit & translationUnit );
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/HoistTypeDecls.cpp
===================================================================
--- src/Validate/HoistTypeDecls.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/HoistTypeDecls.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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 --
+//
+// 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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/HoistTypeDecls.hpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -0,0 +1,32 @@
+//
+// 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 --
+//
+// 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 {
+
+void hoistTypeDecls( 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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/ReplaceTypedef.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -0,0 +1,392 @@
+//
+// 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 --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Jun 29 14:59:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Jul 12 14:17:00 2022
+// Update Count     : 0
+//
+
+#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 * );
+
+	void previsit( ast::FunctionType 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 inFunctionType = 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;
+		// GCC ignores certain attributes if they arrive by typedef,
+		// this mimics that.
+		// TODO: This might cover too much, it should just cover arguments
+		//   and return values of a function.
+		if ( visitor->isInFunction() ) {
+			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 );
+}
+
+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 );
+	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 );
+}
+
+void ReplaceTypedefCore::previsit( ast::FunctionType const * ) {
+	GuardValue( inFunctionType ) = true;
+}
+
+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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/ReplaceTypedef.hpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -0,0 +1,32 @@
+//
+// 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 --
+//
+// 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 {
+
+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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/VerifyCtorDtorAssign.cpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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 --
+//
+// 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 d4b37ab7ced315c944dd4895d790e996564f3d61)
+++ src/Validate/VerifyCtorDtorAssign.hpp	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -0,0 +1,32 @@
+//
+// 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 --
+//
+// 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 {
+
+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 72e76fd79ca74c8a20af8bb1560c3808f736579a)
+++ src/Validate/module.mk	(revision d4b37ab7ced315c944dd4895d790e996564f3d61)
@@ -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,4 +41,6 @@
 	Validate/HoistStruct.cpp \
 	Validate/HoistStruct.hpp \
+	Validate/HoistTypeDecls.cpp \
+	Validate/HoistTypeDecls.hpp \
 	Validate/InitializerLength.cpp \
 	Validate/InitializerLength.hpp \
@@ -44,6 +50,10 @@
 	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)
