Index: src/AST/Copy.hpp
===================================================================
--- src/AST/Copy.hpp	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/AST/Copy.hpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jul 10 16:13:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Thr Nov 11  9:22:00 2021
-// Update Count     : 2
+// Last Modified On : Wed Dec 15 11:07:00 2021
+// Update Count     : 3
 //
 
@@ -52,4 +52,14 @@
 Node * deepCopy<Node>( const Node * localRoot );
 
+template<typename node_t, enum Node::ref_type ref_t>
+node_t * shallowCopy( const ptr_base<node_t, ref_t> & localRoot ) {
+	return shallowCopy( localRoot.get() );
+}
+
+template<typename node_t, enum Node::ref_type ref_t>
+node_t * deepCopy( const ptr_base<node_t, ref_t> & localRoot ) {
+	return deepCopy( localRoot.get() );
+}
+
 }
 
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/AST/Node.hpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -188,4 +188,9 @@
 	}
 
+	ptr_base & operator=( const node_t * node ) {
+		assign( node );
+		return *this;
+	}
+
 	template<typename o_node_t>
 	ptr_base & operator=( const o_node_t * node ) {
Index: src/ControlStruct/HoistControlDecls.cpp
===================================================================
--- src/ControlStruct/HoistControlDecls.cpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
+++ src/ControlStruct/HoistControlDecls.cpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -0,0 +1,69 @@
+//
+// 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.
+//
+// HoistControlDecls.cpp -- Desugar Cforall control structures.
+//
+// Author           : Andrew Beach
+// Created On       : Fri Dec  3 15:34:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Dec  3 15:34:00 2021
+// Update Count     : 0
+//
+
+#include "HoistControlDecls.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/TranslationUnit.hpp"
+
+namespace ControlStruct {
+
+namespace {
+
+template<typename StmtT>
+const ast::Stmt * hoist( const StmtT * stmt ) {
+	// If no hoisting is needed, then make no changes.
+	if ( 0 == stmt->inits.size() ) {
+		return stmt;
+	}
+
+	// Put initializers and the old statement in the compound statement.
+	ast::CompoundStmt * block = new ast::CompoundStmt( stmt->location );
+	StmtT * mutStmt = ast::mutate( stmt );
+	for ( const ast::Stmt * next : mutStmt->inits ) {
+		block->kids.push_back( next );
+	}
+	mutStmt->inits.clear();
+	block->kids.push_back( mutStmt );
+	return block;
+}
+
+struct HoistControlCore {
+	const ast::Stmt * postvisit( const ast::IfStmt * stmt ) {
+		return hoist<ast::IfStmt>( stmt );
+	}
+	const ast::Stmt * postvisit( const ast::ForStmt * stmt ) {
+		return hoist<ast::ForStmt>( stmt );
+	}
+	const ast::Stmt * postvisit( const ast::WhileStmt * stmt ) {
+		return hoist<ast::WhileStmt>( stmt );
+	}
+};
+
+} // namespace
+
+/// Hoist initialization out of for statements.
+void hoistControlDecls( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<HoistControlCore>::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 a4887832b2954c416890b738e1429e4abd5bda71)
+++ src/ControlStruct/HoistControlDecls.hpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -0,0 +1,33 @@
+//
+// 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.
+//
+// HoistControlDecls.hpp -- Desugar Cforall control structures.
+//
+// Author           : Andrew Beach
+// Created On       : Fri Dec  3 15:31:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Dec  3 15:31:00 2021
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+	class TranslationUnit;
+}
+
+namespace ControlStruct {
+
+/// Hoist initialization out of control flow statements.
+void hoistControlDecls( ast::TranslationUnit & translationUnit );
+
+} // namespace ControlStruct
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/ControlStruct/module.mk
===================================================================
--- src/ControlStruct/module.mk	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/ControlStruct/module.mk	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -22,4 +22,6 @@
 	ControlStruct/ForExprMutator.cc \
 	ControlStruct/ForExprMutator.h \
+	ControlStruct/HoistControlDecls.cpp \
+	ControlStruct/HoistControlDecls.hpp \
 	ControlStruct/LabelFixer.cc \
 	ControlStruct/LabelFixer.h \
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/SymTab/Validate.cc	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -453,4 +453,9 @@
 	}
 
+	void decayForallPointers( std::list< Declaration * > & translationUnit ) {
+		PassVisitor<ForallPointerDecay_old> fpd;
+		acceptAll( translationUnit, fpd );
+	}
+
 	void validate( std::list< Declaration * > &translationUnit, __attribute__((unused)) bool doDebug ) {
 		validate_A( translationUnit );
@@ -470,5 +475,4 @@
 		type->accept( fpd );
 	}
-
 
 	void HoistTypeDecls::handleType( Type * type ) {
Index: src/SymTab/Validate.h
===================================================================
--- src/SymTab/Validate.h	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/SymTab/Validate.h	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -42,4 +42,5 @@
 	void validate_E( std::list< Declaration * > &translationUnit );
 	void validate_F( std::list< Declaration * > &translationUnit );
+	void decayForallPointers( std::list< Declaration * > & translationUnit );
 
 	const ast::Type * validateType(
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
+++ src/Validate/Autogen.cpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -0,0 +1,777 @@
+//
+// 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.
+//
+// Autogen.cpp -- Generate automatic routines for data types.
+//
+// Author           : Andrew Beach
+// Created On       : Thu Dec  2 13:44:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jan 26 13:39:00 2022
+// Update Count     : 0
+//
+
+#include "Autogen.hpp"
+
+#include <algorithm>               // for count_if
+#include <cassert>                 // for strict_dynamic_cast, assert, assertf
+#include <iterator>                // for back_insert_iterator, back_inserter
+#include <list>                    // for list, _List_iterator, list<>::iter...
+#include <set>                     // for set, _Rb_tree_const_iterator
+#include <utility>                 // for pair
+#include <vector>                  // for vector
+
+#include "AST/Attribute.hpp"
+#include "AST/Decl.hpp"
+#include "AST/DeclReplacer.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Stmt.hpp"
+#include "AST/SymbolTable.hpp"
+#include "CodeGen/OperatorTable.h" // for isCtorDtor, isCtorDtorAssign
+#include "Common/ScopedMap.h"      // for ScopedMap<>::const_iterator, Scope...
+#include "Common/utility.h"        // for cloneAll, operator+
+#include "GenPoly/ScopedSet.h"     // for ScopedSet, ScopedSet<>::iterator
+#include "InitTweak/GenInit.h"     // for fixReturnStatements
+#include "SymTab/Mangler.h"        // for Mangler
+#include "CompilationState.h"
+
+// TODO: The other new ast function should be moved over to this file.
+#include "SymTab/Autogen.h"
+
+namespace Validate {
+
+namespace {
+
+// --------------------------------------------------------------------------
+struct AutogenerateRoutines_new final :
+		public ast::WithDeclsToAdd<>,
+		public ast::WithShortCircuiting {
+	void previsit( const ast::EnumDecl * enumDecl );
+	void previsit( const ast::StructDecl * structDecl );
+	void previsit( const ast::UnionDecl * structDecl );
+	void previsit( const ast::TypeDecl * typeDecl );
+	void previsit( const ast::TraitDecl * traitDecl );
+	void previsit( const ast::FunctionDecl * functionDecl );
+	void postvisit( const ast::FunctionDecl * functionDecl );
+
+private:
+	// Current level of nested functions.
+	unsigned int functionNesting = 0;
+};
+
+// --------------------------------------------------------------------------
+/// Class used to generate functions for a particular declaration.
+/// Note it isn't really stored, it is just a class for organization and to
+/// help pass around some of the common arguments.
+class FuncGenerator {
+public:
+	std::list<ast::ptr<ast::Decl>> forwards;
+	std::list<ast::ptr<ast::Decl>> definitions;
+
+	FuncGenerator( const ast::Type * type, unsigned int functionNesting ) :
+		type( type ), functionNesting( functionNesting )
+	{}
+
+	/// Generate functions (and forward decls.) and append them to the list.
+	void generateAndAppendFunctions( std::list<ast::ptr<ast::Decl>> & );
+
+	virtual bool shouldAutogen() const = 0;
+protected:
+	const ast::Type * type;
+	unsigned int functionNesting;
+	ast::Linkage::Spec proto_linkage = ast::Linkage::AutoGen;
+
+	// Internal helpers:
+	void genStandardFuncs();
+	void produceDecl( const ast::FunctionDecl * decl );
+	void produceForwardDecl( const ast::FunctionDecl * decl );
+
+	const CodeLocation& getLocation() const { return getDecl()->location; }
+	ast::FunctionDecl * genProto( const std::string& name,
+		std::vector<ast::ptr<ast::DeclWithType>>&& params,
+		std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const;
+
+	ast::ObjectDecl * dstParam() const;
+	ast::ObjectDecl * srcParam() const;
+	ast::FunctionDecl * genCtorProto() const;
+	ast::FunctionDecl * genCopyProto() const;
+	ast::FunctionDecl * genDtorProto() const;
+	ast::FunctionDecl * genAssignProto() const;
+	ast::FunctionDecl * genFieldCtorProto( unsigned int fields ) const;
+
+	// Internal Hooks:
+	virtual void genFuncBody( ast::FunctionDecl * decl ) = 0;
+	virtual void genFieldCtors() = 0;
+	virtual bool isConcurrentType() const { return false; }
+	virtual const ast::Decl * getDecl() const = 0;
+};
+
+class StructFuncGenerator final : public FuncGenerator {
+	const ast::StructDecl * decl;
+public:
+	StructFuncGenerator( const ast::StructDecl * decl,
+			const ast::StructInstType * type,
+			unsigned int functionNesting ) :
+		FuncGenerator( type, functionNesting ), decl( decl )
+	{}
+
+	// Built-ins do not use autogeneration.
+	bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
+private:
+	void genFuncBody( ast::FunctionDecl * decl ) final;
+	void genFieldCtors() final;
+	bool isConcurrentType() const final {
+		return decl->is_thread() || decl->is_monitor();
+	}
+	virtual const ast::Decl * getDecl() const final { return decl; }
+
+	/// Generates a single struct member operation.
+	/// (constructor call, destructor call, assignment call)
+	// This is managed because it uses another helper that returns a ast::ptr.
+	ast::ptr<ast::Stmt> makeMemberOp(
+		const CodeLocation& location,
+		const ast::ObjectDecl * dstParam, const ast::Expr * src,
+		const ast::ObjectDecl * field, ast::FunctionDecl * func,
+		SymTab::LoopDirection direction );
+
+	/// Generates the body of a struct function by iterating the struct members
+	/// (via parameters). Generates default constructor, copy constructor,
+	/// copy assignment, and destructor bodies. No field constructor bodies.
+	template<typename Iterator>
+	void makeFunctionBody( Iterator member, Iterator end,
+			ast::FunctionDecl * func, SymTab::LoopDirection direction );
+
+	/// Generate the body of a constructor which takes parameters that match
+	/// fields. (With arguments for one to all of the fields.)
+	template<typename Iterator>
+	void makeFieldCtorBody( Iterator member, Iterator end,
+			ast::FunctionDecl * func );
+};
+
+class UnionFuncGenerator final : public FuncGenerator {
+	const ast::UnionDecl * decl;
+public:
+	UnionFuncGenerator( const ast::UnionDecl * decl,
+			const ast::UnionInstType * type,
+			unsigned int functionNesting ) :
+		FuncGenerator( type, functionNesting ), decl( decl )
+	{}
+
+	// Built-ins do not use autogeneration.
+	bool shouldAutogen() const final { return !decl->linkage.is_builtin; }
+private:
+	void genFuncBody( ast::FunctionDecl * decl ) final;
+	void genFieldCtors() final;
+	const ast::Decl * getDecl() const final { return decl; }
+
+	/// Generate a single union assignment expression (using memcpy).
+	ast::ExprStmt * makeAssignOp( const CodeLocation& location,
+		const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam );
+};
+
+class EnumFuncGenerator final : public FuncGenerator {
+	const ast::EnumDecl * decl;
+public:
+	EnumFuncGenerator( const ast::EnumDecl * decl,
+			const ast::EnumInstType * type,
+			unsigned int functionNesting ) :
+		FuncGenerator( type, functionNesting ), decl( decl )
+	{
+		// 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;
+	}
+
+	bool shouldAutogen() const final { return true; }
+private:
+	void genFuncBody( ast::FunctionDecl * decl ) final;
+	void genFieldCtors() final;
+	const ast::Decl * getDecl() const final { return decl; }
+};
+
+class TypeFuncGenerator final : public FuncGenerator {
+	const ast::TypeDecl * decl;
+public:
+	TypeFuncGenerator( const ast::TypeDecl * decl,
+			ast::TypeInstType * type,
+			unsigned int functionNesting ) :
+		FuncGenerator( type, functionNesting ), decl( decl )
+	{}
+
+	bool shouldAutogen() const final { return true; }
+	void genFieldCtors() final;
+private:
+	void genFuncBody( ast::FunctionDecl * decl ) final;
+	const ast::Decl * getDecl() const final { return decl; }
+};
+
+// --------------------------------------------------------------------------
+const std::vector<ast::ptr<ast::TypeDecl>>& getGenericParams( const ast::Type * t ) {
+	if ( auto inst = dynamic_cast< const ast::StructInstType * >( t ) ) {
+		return inst->base->params;
+	} else if ( auto inst = dynamic_cast< const ast::UnionInstType * >( t ) ) {
+		return inst->base->params;
+	}
+	static std::vector<ast::ptr<ast::TypeDecl>> const empty;
+	return empty;
+}
+
+/// Changes the node inside a pointer so that it has the unused attribute.
+void addUnusedAttribute( ast::ptr<ast::DeclWithType> & declPtr ) {
+	ast::DeclWithType * decl = declPtr.get_and_mutate();
+	decl->attributes.push_back( new ast::Attribute( "unused" ) );
+}
+
+// --------------------------------------------------------------------------
+void AutogenerateRoutines_new::previsit( const ast::EnumDecl * enumDecl ) {
+	// Must visit children (enum constants) to add them to the symbol table.
+	if ( !enumDecl->body ) return;
+
+	ast::EnumInstType enumInst( enumDecl->name );
+	enumInst.base = enumDecl;
+	EnumFuncGenerator gen( enumDecl, &enumInst, functionNesting );
+	gen.generateAndAppendFunctions( declsToAddAfter );
+}
+
+void AutogenerateRoutines_new::previsit( const ast::StructDecl * structDecl ) {
+	visit_children = false;
+	if ( !structDecl->body ) return;
+
+	ast::StructInstType structInst( structDecl->name );
+	structInst.base = structDecl;
+	for ( const ast::TypeDecl * typeDecl : structDecl->params ) {
+		structInst.params.push_back( new ast::TypeExpr(
+			typeDecl->location,
+			new ast::TypeInstType( typeDecl->name, typeDecl )
+		) );
+	}
+	StructFuncGenerator gen( structDecl, &structInst, functionNesting );
+	gen.generateAndAppendFunctions( declsToAddAfter );
+}
+
+void AutogenerateRoutines_new::previsit( const ast::UnionDecl * unionDecl ) {
+	visit_children = false;
+	if ( !unionDecl->body ) return;
+
+	ast::UnionInstType unionInst( unionDecl->name );
+	unionInst.base = unionDecl;
+	for ( const ast::TypeDecl * typeDecl : unionDecl->params ) {
+		unionInst.params.push_back( new ast::TypeExpr(
+			unionDecl->location,
+			new ast::TypeInstType( typeDecl->name, typeDecl )
+		) );
+	}
+	UnionFuncGenerator gen( unionDecl, &unionInst, functionNesting );
+	gen.generateAndAppendFunctions( declsToAddAfter );
+}
+
+/// Generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
+void AutogenerateRoutines_new::previsit( const ast::TypeDecl * typeDecl ) {
+	if ( !typeDecl->base ) return;
+
+	ast::TypeInstType refType( typeDecl->name, typeDecl );
+	TypeFuncGenerator gen( typeDecl, &refType, functionNesting );
+	gen.generateAndAppendFunctions( declsToAddAfter );
+}
+
+void AutogenerateRoutines_new::previsit( const ast::TraitDecl * ) {
+	// Ensure that we don't add assignment ops for types defined as part of the trait
+	visit_children = false;
+}
+
+void AutogenerateRoutines_new::previsit( const ast::FunctionDecl * ) {
+	// Track whether we're currently in a function.
+	// Can ignore function type idiosyncrasies, because function type can never
+	// declare a new type.
+	functionNesting += 1;
+}
+
+void AutogenerateRoutines_new::postvisit( const ast::FunctionDecl * ) {
+	functionNesting -= 1;
+}
+
+void FuncGenerator::generateAndAppendFunctions(
+		std::list<ast::ptr<ast::Decl>> & decls ) {
+	if ( !shouldAutogen() ) return;
+
+	// Generate the functions (they go into forwards and definitions).
+	genStandardFuncs();
+	genFieldCtors();
+
+	// Now export the lists contents.
+	decls.splice( decls.end(), forwards );
+	decls.splice( decls.end(), definitions );
+}
+
+void FuncGenerator::produceDecl( const ast::FunctionDecl * decl ) {
+	assert( nullptr != decl->stmts );
+
+	definitions.push_back( decl );
+}
+
+/// Make a forward declaration of the decl and add it to forwards.
+void FuncGenerator::produceForwardDecl( const ast::FunctionDecl * decl ) {
+	if (0 != functionNesting) return;
+	ast::FunctionDecl * fwd = ast::deepCopy( decl );
+	fwd->stmts = nullptr;
+	fwd->fixUniqueId();
+	forwards.push_back( fwd );
+}
+
+/// Generates a basic prototype function declaration.
+ast::FunctionDecl * FuncGenerator::genProto( const std::string& name,
+		std::vector<ast::ptr<ast::DeclWithType>>&& params,
+		std::vector<ast::ptr<ast::DeclWithType>>&& returns ) const {
+
+	// Handle generic prameters and assertions, if any.
+	auto const & old_type_params = getGenericParams( type );
+	std::vector<ast::ptr<ast::TypeDecl>> type_params;
+	std::vector<ast::ptr<ast::DeclWithType>> assertions;
+	for ( auto & old_param : old_type_params ) {
+		ast::TypeDecl * decl = ast::deepCopy( old_param );
+		for ( auto assertion : decl->assertions ) {
+			assertions.push_back( assertion );
+		}
+		decl->assertions.clear();
+		type_params.push_back( decl );
+	}
+	// TODO: The values in params and returns still may point at the old
+	// generic params, that does not appear to be an issue but perhaps it
+	// should be addressed.
+
+	ast::FunctionDecl * decl = new ast::FunctionDecl(
+		// Auto-generated routines use the type declaration's location.
+		getLocation(),
+		name,
+		std::move( type_params ),
+		std::move( params ),
+		std::move( returns ),
+		// Only a prototype, no body.
+		nullptr,
+		// Use static storage if we are at the top level.
+		(0 < functionNesting) ? ast::Storage::Classes() : ast::Storage::Static,
+		proto_linkage,
+		std::vector<ast::ptr<ast::Attribute>>(),
+		// Auto-generated routines are inline to avoid conflicts.
+		ast::Function::Specs( ast::Function::Inline ) );
+	decl->assertions = std::move( assertions );
+	decl->fixUniqueId();
+	return decl;
+}
+
+ast::ObjectDecl * FuncGenerator::dstParam() const {
+	return new ast::ObjectDecl( getLocation(), "_dst",
+		new ast::ReferenceType( ast::deepCopy( type ) ),
+		nullptr, {}, ast::Linkage::Cforall );
+}
+
+ast::ObjectDecl * FuncGenerator::srcParam() const {
+	return new ast::ObjectDecl( getLocation(), "_src",
+		ast::deepCopy( type ),
+		nullptr, {}, ast::Linkage::Cforall );
+}
+
+/// Use the current type T to create `void ?{}(T & _dst)`.
+ast::FunctionDecl * FuncGenerator::genCtorProto() const {
+	return genProto( "?{}", { dstParam() }, {} );
+}
+
+/// Use the current type T to create `void ?{}(T & _dst, T _src)`.
+ast::FunctionDecl * FuncGenerator::genCopyProto() const {
+	return genProto( "?{}", { dstParam(), srcParam() }, {} );
+}
+
+/// Use the current type T to create `void ?{}(T & _dst)`.
+ast::FunctionDecl * FuncGenerator::genDtorProto() const {
+	// The destructor must be mutex on a concurrent type.
+	auto dst = dstParam();
+	if ( isConcurrentType() ) {
+		add_qualifiers( dst->type, ast::CV::Qualifiers( ast::CV::Mutex ) );
+	}
+	return genProto( "^?{}", { dst }, {} );
+}
+
+/// Use the current type T to create `T ?{}(T & _dst, T _src)`.
+ast::FunctionDecl * FuncGenerator::genAssignProto() const {
+	// Only the name is different, so just reuse the generation function.
+	auto retval = srcParam();
+	retval->name = "_ret";
+	return genProto( "?=?", { dstParam(), srcParam() }, { retval } );
+}
+
+// This one can return null if the last field is an unnamed bitfield.
+ast::FunctionDecl * FuncGenerator::genFieldCtorProto(
+		unsigned int fields ) const {
+	assert( 0 < fields );
+	auto aggr = strict_dynamic_cast<const ast::AggregateDecl *>( getDecl() );
+
+	std::vector<ast::ptr<ast::DeclWithType>> params = { dstParam() };
+	for ( unsigned int index = 0 ; index < fields ; ++index ) {
+		auto member = aggr->members[index].strict_as<ast::DeclWithType>();
+		if ( SymTab::isUnnamedBitfield(
+				dynamic_cast<const ast::ObjectDecl *>( member ) ) ) {
+			if ( index == fields - 1 ) {
+				return nullptr;
+			}
+			continue;
+		}
+
+		auto * paramType = ast::deepCopy( member->get_type() );
+		paramType->attributes.clear();
+		ast::ObjectDecl * param = new ast::ObjectDecl(
+			getLocation(), member->name, paramType );
+		param->linkage = ast::Linkage::Cforall;
+		for ( auto & attr : member->attributes ) {
+			if ( attr->isValidOnFuncParam() ) {
+				param->attributes.push_back( attr );
+			}
+		}
+		params.emplace_back( param );
+	}
+	return genProto( "?{}", std::move( params ), {} );
+}
+
+void appendReturnThis( ast::FunctionDecl * decl ) {
+	assert( 1 <= decl->params.size() );
+	assert( 1 == decl->returns.size() );
+	assert( decl->stmts );
+
+	const CodeLocation& location = (decl->stmts->kids.empty())
+		? decl->stmts->location : decl->stmts->kids.back()->location;
+	const ast::DeclWithType * thisParam = decl->params.front();
+	decl->stmts.get_and_mutate()->push_back(
+		new ast::ReturnStmt( location,
+			new ast::VariableExpr( location, thisParam )
+		)
+	);
+}
+
+void FuncGenerator::genStandardFuncs() {
+	// The order here determines the order that these functions are generated.
+	// Assignment should come last since it uses copy constructor in return.
+	ast::FunctionDecl *(FuncGenerator::*standardProtos[4])() const = {
+			&FuncGenerator::genCtorProto, &FuncGenerator::genCopyProto,
+			&FuncGenerator::genDtorProto, &FuncGenerator::genAssignProto };
+	for ( auto & generator : standardProtos ) {
+		ast::FunctionDecl * decl = (this->*generator)();
+		produceForwardDecl( decl );
+		genFuncBody( decl );
+		if ( CodeGen::isAssignment( decl->name ) ) {
+			appendReturnThis( decl );
+		}
+		produceDecl( decl );
+	}
+}
+
+void StructFuncGenerator::genFieldCtors() {
+	// The field constructors are only generated if the default constructor
+	// and copy constructor are both generated, since the need both.
+	unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
+		[](const ast::Decl * decl){ return CodeGen::isConstructor( decl->name ); }
+	);
+	if ( 2 != numCtors ) return;
+
+	for ( unsigned int num = 1 ; num <= decl->members.size() ; ++num ) {
+		ast::FunctionDecl * ctor = genFieldCtorProto( num );
+		if ( nullptr == ctor ) {
+			continue;
+		}
+		produceForwardDecl( ctor );
+		makeFieldCtorBody( decl->members.begin(), decl->members.end(), ctor );
+		produceDecl( ctor );
+	}
+}
+
+void StructFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
+	// Generate appropriate calls to member constructors and assignment.
+	// Destructor needs to do everything in reverse,
+	// so pass "forward" based on whether the function is a destructor
+	if ( CodeGen::isDestructor( functionDecl->name ) ) {
+		makeFunctionBody( decl->members.rbegin(), decl->members.rend(),
+			functionDecl, SymTab::LoopBackward );
+	} else {
+		makeFunctionBody( decl->members.begin(), decl->members.end(),
+			functionDecl, SymTab::LoopForward );
+	}
+}
+
+ast::ptr<ast::Stmt> StructFuncGenerator::makeMemberOp(
+		const CodeLocation& location, const ast::ObjectDecl * dstParam,
+		const ast::Expr * src, const ast::ObjectDecl * field,
+		ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
+	InitTweak::InitExpander_new srcParam( src );
+	// Assign to destination.
+	ast::Expr * dstSelect = new ast::MemberExpr(
+		location,
+		field,
+		new ast::CastExpr(
+			location,
+			new ast::VariableExpr( location, dstParam ),
+			dstParam->type.strict_as<ast::ReferenceType>()->base
+		)
+	);
+	return genImplicitCall(
+		srcParam, dstSelect, location, func->name,
+		field, direction
+	);
+}
+
+template<typename Iterator>
+void StructFuncGenerator::makeFunctionBody( Iterator current, Iterator end,
+		ast::FunctionDecl * func, SymTab::LoopDirection direction ) {
+	// Trying to get the best code location. Should probably use a helper or
+	// just figure out what that would be given where this is called.
+	assert( nullptr == func->stmts );
+	const CodeLocation& location = func->location;
+
+	ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
+
+	for ( ; current != end ; ++current ) {
+		const ast::ptr<ast::Decl> & member = *current;
+		auto field = member.as<ast::ObjectDecl>();
+		if ( nullptr == field ) {
+			continue;
+		}
+
+		// Don't assign to constant members (but do construct/destruct them).
+		if ( CodeGen::isAssignment( func->name ) ) {
+			// For array types we need to strip off the array layers.
+			const ast::Type * type = field->get_type();
+			while ( auto at = dynamic_cast<const ast::ArrayType *>( type ) ) {
+				type = at->base;
+			}
+			if ( type->is_const() ) {
+				continue;
+			}
+		}
+
+		assert( !func->params.empty() );
+		const ast::ObjectDecl * dstParam =
+			func->params.front().strict_as<ast::ObjectDecl>();
+		const ast::ObjectDecl * srcParam = nullptr;
+		if ( 2 == func->params.size() ) {
+			srcParam = func->params.back().strict_as<ast::ObjectDecl>();
+		}
+
+		ast::Expr * srcSelect = (srcParam) ? new ast::MemberExpr(
+			location, field, new ast::VariableExpr( location, srcParam )
+		) : nullptr;
+		ast::ptr<ast::Stmt> stmt =
+			makeMemberOp( location, dstParam, srcSelect, field, func, direction );
+
+		if ( nullptr != stmt ) {
+			stmts->kids.push_back( stmt );
+		}
+	}
+
+	func->stmts = stmts;
+}
+
+template<typename Iterator>
+void StructFuncGenerator::makeFieldCtorBody( Iterator current, Iterator end,
+		ast::FunctionDecl * func ) {
+	const CodeLocation& location = func->location;
+	auto & params = func->params;
+	// Need at least the constructed parameter and one field parameter.
+	assert( 2 <= params.size() );
+
+	ast::CompoundStmt * stmts = new ast::CompoundStmt( location );
+
+	auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+	// Skip over the 'this' parameter.
+	for ( auto param = params.begin() + 1 ; current != end ; ++current ) {
+		const ast::ptr<ast::Decl> & member = *current;
+		ast::ptr<ast::Stmt> stmt = nullptr;
+		auto field = member.as<ast::ObjectDecl>();
+		// Not sure why it could be null.
+		// Don't make a function for a parameter that is an unnamed bitfield.
+		if ( nullptr == field || SymTab::isUnnamedBitfield( field ) ) {
+			continue;
+		// Matching Parameter: Initialize the field by copy.
+		} else if ( params.end() != param ) {
+			const ast::Expr *srcSelect = new ast::VariableExpr(
+				func->location, param->get() );
+			stmt = makeMemberOp( location, dstParam, srcSelect, field, func, SymTab::LoopForward );
+			++param;
+		// No Matching Parameter: Initialize the field by default constructor.
+		} else {
+			stmt = makeMemberOp( location, dstParam, nullptr, field, func, SymTab::LoopForward );
+		}
+
+		if ( nullptr != stmt ) {
+			stmts->kids.push_back( stmt );
+		}
+	}
+	func->stmts = stmts;
+}
+
+void UnionFuncGenerator::genFieldCtors() {
+	// Field constructors are only generated if default and copy constructor
+	// are generated, since they need access to both
+	unsigned numCtors = std::count_if( definitions.begin(), definitions.end(),
+		[]( const ast::Decl * d ){ return CodeGen::isConstructor( d->name ); }
+	);
+	if ( 2 != numCtors ) {
+		return;
+	}
+
+	// Create a constructor which takes the first member type as a
+	// parameter. For example for `union A { int x; char y; };` generate
+	// a function with signature `void ?{}(A *, int)`. This mimics C's
+	// behaviour which initializes the first member of the union.
+
+	// Still, there must be some members.
+	if ( !decl->members.empty() ) {
+		ast::FunctionDecl * ctor = genFieldCtorProto( 1 );
+		if ( nullptr == ctor ) {
+			return;
+		}
+		produceForwardDecl( ctor );
+		auto params = ctor->params;
+		auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+		auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+		ctor->stmts = new ast::CompoundStmt( getLocation(),
+			{ makeAssignOp( getLocation(), dstParam, srcParam ) }
+		);
+		produceDecl( ctor );
+	}
+}
+
+void UnionFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
+	const CodeLocation& location = functionDecl->location;
+	auto & params = functionDecl->params;
+	if ( InitTweak::isCopyConstructor( functionDecl )
+			|| InitTweak::isAssignment( functionDecl ) ) {
+		assert( 2 == params.size() );
+		auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+		auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+		functionDecl->stmts = new ast::CompoundStmt( location,
+			{ makeAssignOp( location, dstParam, srcParam ) }
+		);
+	} else {
+		assert( 1 == params.size() );
+		// Default constructor and destructor is empty.
+		functionDecl->stmts = new ast::CompoundStmt( location );
+		// Add unused attribute to parameter to silence warnings.
+		addUnusedAttribute( params.front() );
+
+		// Just an extra step to make the forward and declaration match.
+		if ( forwards.empty() ) return;
+		ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
+			forwards.back().get_and_mutate() );
+		addUnusedAttribute( fwd->params.front() );
+	}
+}
+
+ast::ExprStmt * UnionFuncGenerator::makeAssignOp( const CodeLocation& location,
+		const ast::ObjectDecl * dstParam, const ast::ObjectDecl * srcParam ) {
+	return new ast::ExprStmt( location, new ast::UntypedExpr(
+		location,
+		new ast::NameExpr( location, "__builtin_memcpy" ),
+		{
+			new ast::AddressExpr( location,
+				new ast::VariableExpr( location, dstParam ) ),
+			new ast::AddressExpr( location,
+				new ast::VariableExpr( location, srcParam ) ),
+			new ast::SizeofExpr( location, srcParam->type ),
+		} ) );
+}
+
+void EnumFuncGenerator::genFieldCtors() {
+	// Enumerations to not have field constructors.
+}
+
+void EnumFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
+	const CodeLocation& location = functionDecl->location;
+	auto & params = functionDecl->params;
+	if ( InitTweak::isCopyConstructor( functionDecl )
+			|| InitTweak::isAssignment( functionDecl ) ) {
+		assert( 2 == params.size() );
+		auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+		auto srcParam = params.back().strict_as<ast::ObjectDecl>();
+
+		/* This looks like a recursive call, but code-gen will turn it into
+		 * a C-style assignment.
+		 *
+		 * This is still before function pointer type conversion,
+		 * so this will have to do it manually.
+		 *
+		 * It will also reference the parent function declaration, creating
+		 * a cycle for references. This also means that the ref-counts are
+		 * now non-zero and the declaration will be deleted if it ever
+		 * returns to zero.
+		 */
+		auto callExpr = new ast::ApplicationExpr( location,
+			ast::VariableExpr::functionPointer( location, functionDecl ),
+			{
+				new ast::VariableExpr( location, dstParam ),
+				new ast::VariableExpr( location, srcParam ),
+			}
+		);
+		functionDecl->stmts = new ast::CompoundStmt( location,
+			{ new ast::ExprStmt( location, callExpr ) }
+		);
+	} else {
+		assert( 1 == params.size() );
+		// Default constructor and destructor is empty.
+		functionDecl->stmts = new ast::CompoundStmt( location );
+		// Just add unused attribute to parameter to silence warnings.
+		addUnusedAttribute( params.front() );
+
+		// Just an extra step to make the forward and declaration match.
+		if ( forwards.empty() ) return;
+		ast::FunctionDecl * fwd = strict_dynamic_cast<ast::FunctionDecl *>(
+			forwards.back().get_and_mutate() );
+		addUnusedAttribute( fwd->params.front() );
+	}
+}
+
+void TypeFuncGenerator::genFieldCtors() {
+	// Opaque types do not have field constructors.
+}
+
+void TypeFuncGenerator::genFuncBody( ast::FunctionDecl * functionDecl ) {
+	const CodeLocation& location = functionDecl->location;
+	auto & params = functionDecl->type->params;
+	assertf( 1 == params.size() || 2 == params.size(),
+		"Incorrect number of parameters in autogenerated typedecl function: %zd",
+		params.size() );
+	auto dstParam = params.front().strict_as<ast::ObjectDecl>();
+	auto srcParam = (2 == params.size())
+		? params.back().strict_as<ast::ObjectDecl>() : nullptr;
+	// Generate appropriate calls to member constructor and assignment.
+	ast::UntypedExpr * expr = new ast::UntypedExpr( location,
+		new ast::NameExpr( location, functionDecl->name )
+	);
+	expr->args.push_back( new ast::CastExpr( location,
+		new ast::VariableExpr( location, dstParam ),
+		new ast::ReferenceType( decl->base )
+	) );
+	if ( srcParam ) {
+		expr->args.push_back( new ast::CastExpr( location,
+			new ast::VariableExpr( location, srcParam ),
+			decl->base
+		) );
+	}
+	functionDecl->stmts = new ast::CompoundStmt( location,
+		{ new ast::ExprStmt( location, expr ) }
+	);
+}
+
+} // namespace
+
+void autogenerateRoutines( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<AutogenerateRoutines_new>::run( translationUnit );
+}
+
+} // Validate
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Validate/Autogen.hpp
===================================================================
--- src/Validate/Autogen.hpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
+++ src/Validate/Autogen.hpp	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -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.
+//
+// Autogen.hpp -- Generate automatic routines for data types.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Dec  1 13:42:00 2021
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Dec  2 13:56:00 2021
+// Update Count     : 0
+//
+
+#pragma once
+
+namespace ast {
+    class TranslationUnit;
+}
+
+namespace Validate {
+
+void autogenerateRoutines( 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 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/Validate/module.mk	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -16,4 +16,6 @@
 
 SRC_VALIDATE = \
+	Validate/Autogen.cpp \
+	Validate/Autogen.hpp \
 	Validate/CompoundLiteral.cpp \
 	Validate/CompoundLiteral.hpp \
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 97fed4458f48d4add95cb1d99ccefd2a77340fde)
+++ src/main.cc	(revision a4887832b2954c416890b738e1429e4abd5bda71)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Tue Nov 30 10:25:00 2021
-// Update Count     : 659
+// Last Modified On : Wed Jan 26 14:09:00 2022
+// Update Count     : 670
 //
 
@@ -55,4 +55,5 @@
 #include "ControlStruct/ExceptTranslate.h"  // for translateEHM
 #include "ControlStruct/FixLabels.hpp"      // for fixLabels
+#include "ControlStruct/HoistControlDecls.hpp" //  hoistControlDecls
 #include "ControlStruct/Mutate.h"           // for mutate
 #include "GenPoly/Box.h"                    // for box
@@ -73,4 +74,5 @@
 #include "SynTree/Visitor.h"                // for acceptAll
 #include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
+#include "Validate/Autogen.hpp"             // for autogenerateRoutines
 #include "Validate/FindSpecialDecls.h"      // for findGlobalDecls
 #include "Validate/CompoundLiteral.hpp"     // for handleCompoundLiterals
@@ -78,5 +80,4 @@
 #include "Validate/LabelAddressFixer.hpp"   // for fixLabelAddresses
 #include "Virtual/ExpandCasts.h"            // for expandCasts
-
 
 static void NewPass( const char * const name ) {
@@ -326,9 +327,12 @@
 		PASS( "Validate-B", SymTab::validate_B( translationUnit ) );
 		PASS( "Validate-C", SymTab::validate_C( translationUnit ) );
-		PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
 
 		CodeTools::fillLocations( translationUnit );
 
 		if( useNewAST ) {
+			PASS( "Apply Concurrent Keywords", Concurrency::applyKeywords( translationUnit ) );
+			PASS( "Forall Pointer Decay", SymTab::decayForallPointers( translationUnit ) );
+			CodeTools::fillLocations( translationUnit );
+
 			if (Stats::Counters::enabled) {
 				ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
@@ -338,4 +342,11 @@
 
 			forceFillCodeLocations( 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 ) );
 
 			PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
@@ -406,4 +417,5 @@
 			translationUnit = convert( move( transUnit ) );
 		} else {
+			PASS( "Validate-D", SymTab::validate_D( translationUnit ) );
 			PASS( "Validate-E", SymTab::validate_E( translationUnit ) );
 			PASS( "Validate-F", SymTab::validate_F( translationUnit ) );
