Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/AST/Convert.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/AST/Decl.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -315,5 +315,5 @@
 
 	EnumDecl( const CodeLocation& loc, const std::string& name,
-		std::vector<ptr<Attribute>>&& attrs = {}, Linkage::Spec linkage = Linkage::Cforall, Type * base = nullptr,
+		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/CodeGen/CodeGenerator.cc
===================================================================
--- src/CodeGen/CodeGenerator.cc	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/CodeGen/CodeGenerator.cc	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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
@@ -1238,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 f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/CodeGen/CodeGenerator.h	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/CodeGen/GenType.cc	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/SymTab/FixFunction.cc	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/SymTab/FixFunction.h	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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/Validate/EliminateTypedef.cpp
===================================================================
--- src/Validate/EliminateTypedef.cpp	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/Validate/EliminateTypedef.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/EnumAndPointerDecay.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/EnumAndPointerDecay.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/FixReturnTypes.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/FixReturnTypes.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/HoistTypeDecls.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/HoistTypeDecls.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/ReplaceTypedef.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/ReplaceTypedef.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/VerifyCtorDtorAssign.cpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 1931bb01089a99a839382b07c869b845128790a0)
+++ src/Validate/VerifyCtorDtorAssign.hpp	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/Validate/module.mk	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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)
Index: src/main.cc
===================================================================
--- src/main.cc	(revision f37d9e7046a9c6349e0b0e9fbabf75209183a3ef)
+++ src/main.cc	(revision 1931bb01089a99a839382b07c869b845128790a0)
@@ -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 : Tue Jul 12 12:02:00 2022
+// Update Count     : 675
 //
 
@@ -78,13 +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
 
@@ -331,7 +336,4 @@
 		} // if
 
-		// add the assignment statement after the initialization of a type parameter
-		PASS( "Validate-A", SymTab::validate_A( translationUnit ) );
-
 		CodeTools::fillLocations( translationUnit );
 
@@ -346,4 +348,22 @@
 
 			forceFillCodeLocations( transUnit );
+
+			// Must happen before auto-gen, or anything that examines ops.
+			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 ) );
+
+			// Must happen before auto-gen.
+			PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
+
+			// Must happen before Link Reference to Types, it needs correct
+			// types for mangling.
+			PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
 
 			// Must happen before auto-gen, because it uses the sized flag.
@@ -453,4 +473,6 @@
 			translationUnit = convert( move( transUnit ) );
 		} else {
+			// add the assignment statement after the initialization of a type parameter
+			PASS( "Validate-A", SymTab::validate_A( translationUnit ) );
 			PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
 			PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
