Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Decl.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -108,5 +108,5 @@
 	ObjectDecl( const CodeLocation & loc, const std::string & name, const Type * type,
 		const Init * init = nullptr, Storage::Classes storage = {},
-		Linkage::Spec linkage = Linkage::C, const Expr * bitWd = nullptr,
+		Linkage::Spec linkage = Linkage::Cforall, const Expr * bitWd = nullptr,
 		std::vector< ptr<Attribute> > && attrs = {}, Function::Specs fs = {} )
 	: DeclWithType( loc, name, storage, linkage, std::move(attrs), fs ), type( type ),
@@ -143,5 +143,5 @@
 	FunctionDecl( const CodeLocation & loc, const std::string & name, std::vector<ptr<TypeDecl>>&& forall,
 		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
-		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
+		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
 		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
 
@@ -149,5 +149,5 @@
 		std::vector<ptr<TypeDecl>>&& forall, std::vector<ptr<DeclWithType>>&& assertions,
 		std::vector<ptr<DeclWithType>>&& params, std::vector<ptr<DeclWithType>>&& returns,
-		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::C,
+		CompoundStmt * stmts, Storage::Classes storage = {}, Linkage::Spec linkage = Linkage::Cforall,
 		std::vector<ptr<Attribute>>&& attrs = {}, Function::Specs fs = {}, bool isVarArgs = false);
 
@@ -217,5 +217,5 @@
 
 	/// convenience accessor to match Type::isComplete()
-	bool isComplete() { return sized; }
+	bool isComplete() const { return sized; }
 
 	const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/DeclReplacer.cpp
===================================================================
--- src/AST/DeclReplacer.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/DeclReplacer.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -9,109 +9,109 @@
 // Author           : Aaron B. Moss
 // Created On       : Wed May 8 13:00:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Wed May 8 13:00:00 2019
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr Sep 15 11:55:00 2022
+// Update Count     : 2
 //
 
 #include "DeclReplacer.hpp"
+
 #include "Expr.hpp"
+#include "Pass.hpp"
 #include "Type.hpp"
-
-#include "Pass.hpp"
 
 namespace ast {
 
 namespace DeclReplacer {
-	namespace {
-		struct DeclReplacer {
-		private:
-			const DeclMap & declMap;
-			const TypeMap & typeMap;
-			bool debug;
 
-		public:
-			DeclReplacer(const DeclMap & declMap, const TypeMap & typeMap, bool debug)
-				: declMap( declMap ), typeMap( typeMap ), debug( debug )
-			{}
+namespace {
+	struct DeclReplacer {
+	private:
+		const DeclMap & declMap;
+		const TypeMap & typeMap;
+		bool debug;
 
-			const ast::VariableExpr * previsit( const ast::VariableExpr * );
-			const ast::TypeInstType * previsit( const ast::TypeInstType * );
-		};
+	public:
+		DeclReplacer( const DeclMap & declMap, const TypeMap & typeMap, bool debug )
+			: declMap( declMap ), typeMap( typeMap ), debug( debug )
+		{}
 
-		struct VarExprReplacer {
-		private:
-			const ExprMap & exprMap;
-			
-		public:
-			VarExprReplacer(const ExprMap & exprMap): exprMap (exprMap) {}
+		const ast::VariableExpr * previsit( const ast::VariableExpr * );
+		const ast::TypeInstType * previsit( const ast::TypeInstType * );
+	};
 
-			const Expr * postvisit (const VariableExpr *);
-		};
+	struct VarExprReplacer {
+	private:
+		const ExprMap & exprMap;
+
+	public:
+		VarExprReplacer( const ExprMap & exprMap ) : exprMap( exprMap ) {}
+
+		const Expr * postvisit( const VariableExpr * );
+	};
+} // namespace
+
+const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug ) {
+	if(!node) return nullptr;
+	Pass<DeclReplacer> replacer = { declMap, typeMap, debug };
+	return node->accept( replacer );
+}
+
+const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, bool debug ) {
+	TypeMap typeMap;
+	return replace( node, declMap, typeMap, debug );
+}
+
+const ast::Node * replace( const ast::Node * node, const TypeMap & typeMap, bool debug ) {
+	DeclMap declMap;
+	return replace( node, declMap, typeMap, debug );
+}
+
+const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap ) {
+	Pass<VarExprReplacer> replacer = {exprMap};
+	return node->accept( replacer );
+}
+
+namespace {
+	// replace variable with new node from decl map
+	const ast::VariableExpr * DeclReplacer::previsit( const VariableExpr * varExpr ) {
+		// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+		if ( !declMap.count( varExpr->var ) ) return varExpr;
+
+		auto replacement = declMap.at( varExpr->var );
+		if ( debug ) {
+			std::cerr << "replacing variable reference: "
+				<< (void*)varExpr->var.get() << " " << varExpr->var
+				<< " with " << (void*)replacement << " " << replacement
+				<< std::endl;
+		}
+		auto nexpr = mutate(varExpr);
+		nexpr->var = replacement;
+		return nexpr;
 	}
 
-	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, const TypeMap & typeMap, bool debug ) {
-		if(!node) return nullptr;
-		Pass<DeclReplacer> replacer = { declMap, typeMap, debug };
-		return node->accept( replacer );
+	const TypeInstType * DeclReplacer::previsit( const TypeInstType * inst ) {
+		if ( !typeMap.count( inst->base ) ) return inst;
+
+		auto replacement = typeMap.at( inst->base );
+		if ( debug ) {
+			std::cerr << "replacing type reference: "
+				<< (void*)inst->base.get() << " " << inst->base
+				<< " with " << (void*)replacement << " " << replacement
+				<< std::endl;
+		}
+		auto ninst = mutate(inst);
+		ninst->base = replacement;
+		return ninst;
 	}
 
-	const ast::Node * replace( const ast::Node * node, const DeclMap & declMap, bool debug ) {
-		TypeMap typeMap;
-		return replace( node, declMap, typeMap, debug );
+	const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) {
+		if ( !exprMap.count( expr->var ) ) return expr;
+		return exprMap.at( expr->var );
 	}
+} // namespace
 
-	const ast::Node * replace( const ast::Node * node, const TypeMap & typeMap, bool debug ) {
-		DeclMap declMap;
-		return replace( node, declMap, typeMap, debug );
-	}
+} // namespace DeclReplacer
 
-	const ast::Node * replace( const ast::Node * node, const ExprMap & exprMap) {
-		Pass<VarExprReplacer> replacer = {exprMap};
-		return node->accept( replacer );
-	}
-
-	namespace {
-		// replace variable with new node from decl map
-		const ast::VariableExpr * DeclReplacer::previsit( const VariableExpr * varExpr ) {
-			// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
-			if ( !declMap.count( varExpr->var ) ) return varExpr;
-
-			auto replacement = declMap.at( varExpr->var );
-			if ( debug ) {
-				std::cerr << "replacing variable reference: "
-					<< (void*)varExpr->var.get() << " " << varExpr->var
-					<< " with " << (void*)replacement << " " << replacement
-					<< std::endl;
-			}
-			auto nexpr = mutate(varExpr);
-			nexpr->var = replacement;
-			return nexpr;
-		}
-
-		const TypeInstType * DeclReplacer::previsit( const TypeInstType * inst ) {
-			if ( !typeMap.count( inst->base ) ) return inst;
-
-			auto replacement = typeMap.at( inst->base );
-			if ( debug ) {
-				std::cerr << "replacing type reference: "
-					<< (void*)inst->base.get() << " " << inst->base
-					<< " with " << (void*)replacement << " " << replacement
-					<< std::endl;
-			}
-			auto ninst = mutate(inst);
-			ninst->base = replacement;
-			return ninst;
-		}
-
-		const Expr * VarExprReplacer::postvisit( const VariableExpr * expr ) {
-			if (!exprMap.count(expr->var)) return expr;
-
-			return exprMap.at(expr->var);
-		}
-
-	}
-}
-
-}
+} // namespace ast
 
 // Local Variables: //
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Pass.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -328,4 +328,8 @@
 struct PureVisitor {};
 
+struct WithCodeLocation {
+	const CodeLocation * location = nullptr;
+};
+
 /// Keep track of the polymorphic const TypeSubstitution * typeSubs for the current expression.
 struct WithConstTypeSubstitution {
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Pass.impl.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -25,4 +25,6 @@
 #define VISIT_START( node ) \
 	using namespace ast; \
+	/* back-up the last known code location */ \
+	__attribute__((unused)) auto loc_guard = ast::__pass::make_location_guard( core, node, 0 ); \
 	/* back-up the visit children */ \
 	__attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
@@ -597,4 +599,5 @@
 			guard_symtab guard { *this };
 			// implicit add __func__ identifier as specified in the C manual 6.4.2.2
+			// This is a C name and so has C linkage.
 			static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{
 				CodeLocation{}, "__func__",
@@ -602,5 +605,8 @@
 					new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
 					nullptr, VariableLen, DynamicDim
-				}
+				},
+				nullptr,
+				ast::Storage::Classes(),
+				ast::Linkage::C,
 			} };
 			__pass::symtab::addId( core, 0, func );
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Pass.proto.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -326,4 +326,17 @@
 	}
 
+	template< typename core_t, typename node_t >
+	static auto make_location_guard( core_t & core, node_t * node, int )
+			-> decltype( node->location, ValueGuardPtr<const CodeLocation *>( &core.location ) ) {
+		ValueGuardPtr<const CodeLocation *> guard( &core.location );
+		core.location = &node->location;
+		return guard;
+	}
+
+	template< typename core_t, typename node_t >
+	static auto make_location_guard( core_t &, node_t *, long ) -> int {
+		return 0;
+	}
+
 	// Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
 	// All passes which have such functions are assumed desire this behaviour
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Print.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -33,5 +33,5 @@
 {
 	return array<C,sizeof...(T)>{
-		forward<T>(values)...
+		std::forward<T>(values)...
 	};
 }
@@ -86,5 +86,5 @@
 
 		static constexpr auto StorageClasses = make_array<const char*>(
-			"extern", "static", "auto", "register", "_Thread_local"
+			"extern", "static", "auto", "register", "__thread", "_Thread_local"
 		);
 
@@ -215,5 +215,5 @@
 			++indent;
 			ptrToEnum->base->accept( *this );
-			--indent;  
+			--indent;
 		}
 
@@ -1634,5 +1634,5 @@
 // if the wrong size is specified
 constexpr array<const char*, 3> Printer::Names::FuncSpecifiers;
-constexpr array<const char*, 5> Printer::Names::StorageClasses;
+constexpr array<const char*, 6> Printer::Names::StorageClasses;
 constexpr array<const char*, 6> Printer::Names::Qualifiers;
 }
Index: src/AST/StorageClasses.hpp
===================================================================
--- src/AST/StorageClasses.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/StorageClasses.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -24,10 +24,11 @@
 	/// Bitflags for storage classes
 	enum {
-		Extern      = 1 << 0,
-		Static      = 1 << 1,
-		Auto        = 1 << 2,
-		Register    = 1 << 3,
-		ThreadLocal = 1 << 4,
-		NumClasses       = 5
+		Extern         = 1 << 0,
+		Static         = 1 << 1,
+		Auto           = 1 << 2,
+		Register       = 1 << 3,
+		ThreadLocalGcc = 1 << 4,
+		ThreadLocalC11 = 1 << 5,
+		NumClasses          = 6
 	};
 
@@ -37,9 +38,10 @@
 			unsigned int val;
 			struct {
-				bool is_extern      : 1;
-				bool is_static      : 1;
-				bool is_auto        : 1;
-				bool is_register    : 1;
-				bool is_threadlocal : 1;
+				bool is_extern         : 1;
+				bool is_static         : 1;
+				bool is_auto           : 1;
+				bool is_register       : 1;
+				bool is_threadlocalGcc : 1;
+				bool is_threadlocalC11 : 1;
 			};
 
@@ -48,4 +50,6 @@
 
 		constexpr class_flags( unsigned int val = 0 ) : val(val) {}
+
+		bool is_threadlocal_any() { return this->is_threadlocalC11 || this->is_threadlocalGcc; }
 	};
 
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Type.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -143,5 +143,5 @@
 TraitInstType::TraitInstType(
 	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
-: BaseInstType( b->name, q, move(as) ), base( b ) {}
+: BaseInstType( b->name, q, std::move(as) ), base( b ) {}
 
 // --- TypeInstType
@@ -149,5 +149,5 @@
 TypeInstType::TypeInstType( const TypeDecl * b,
 	CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
-: BaseInstType( b->name, q, move(as) ), base( b ), kind( b->kind ) {}
+: BaseInstType( b->name, q, std::move(as) ), base( b ), kind( b->kind ) {}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
@@ -161,5 +161,5 @@
 
 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
-: Type( q ), types( move(ts) ), members() {
+: Type( q ), types( std::move(ts) ), members() {
 	// This constructor is awkward. `TupleType` needs to contain objects so that members can be
 	// named, but members without initializer nodes end up getting constructors, which breaks
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/AST/Type.hpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -83,5 +83,5 @@
 template< enum Node::ref_type ref_t >
 void reset_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q = {} ) {
-	if ( p->qualifiers.val != q.val ) p.get_and_mutate()->qualifiers = q;
+	if ( p->qualifiers != q ) p.get_and_mutate()->qualifiers = q;
 }
 
@@ -89,5 +89,5 @@
 template< enum Node::ref_type ref_t >
 void add_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q ) {
-	if ( ( p->qualifiers.val & q.val ) != q.val ) p.get_and_mutate()->qualifiers |= q;
+	if ( ( p->qualifiers & q ) != q ) p.get_and_mutate()->qualifiers |= q;
 }
 
@@ -95,5 +95,5 @@
 template< enum Node::ref_type ref_t >
 void remove_qualifiers( ptr_base< Type, ref_t > & p, CV::Qualifiers q ) {
-	if ( ( p->qualifiers.val & q.val ) != 0 ) p.get_and_mutate()->qualifiers -= q;
+	if ( ( p->qualifiers & q ) != 0 ) p.get_and_mutate()->qualifiers -= q;
 }
 
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Common/Eval.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Mon May 18 07:44:20 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul  1 08:41:03 2022
-// Update Count     : 117
+// Last Modified On : Sat Aug  6 12:11:59 2022
+// Update Count     : 119
 //
 
@@ -217,7 +217,7 @@
 				value = arg1.first * arg2.first;
 			} else if (fname == "?/?") {
-				value = arg1.first / arg2.first;
+				if ( arg2.first ) value = arg1.first / arg2.first;
 			} else if (fname == "?%?") {
-				value = arg1.first % arg2.first;
+				if ( arg2.first ) value = arg1.first % arg2.first;
 			} else if (fname == "?<<?") {
 				value = arg1.first << arg2.first;
Index: src/Common/ScopedMap.h
===================================================================
--- src/Common/ScopedMap.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Common/ScopedMap.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Wed Dec 2 11:37:00 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon May 21 15:22:40 2018
-// Update Count     : 3
+// Last Modified On : Tue Feb 15 08:41:28 2022
+// Update Count     : 5
 //
 
@@ -36,11 +36,11 @@
 
 		template<typename N>
-		Scope(N&& n) : map(), note(std::forward<N>(n)) {}
+		Scope(N && n) : map(), note(std::forward<N>(n)) {}
 		
 		Scope() = default;
-		Scope(const Scope&) = default;
-		Scope(Scope&&) = default;
-		Scope& operator= (const Scope&) = default;
-		Scope& operator= (Scope&&) = default;
+		Scope(const Scope &) = default;
+		Scope(Scope &&) = default;
+		Scope & operator= (const Scope &) = default;
+		Scope & operator= (Scope &&) = default;
 	};
 	typedef std::vector< Scope > ScopeList;
@@ -58,6 +58,5 @@
 	typedef typename MapType::const_pointer const_pointer;
 
-	class iterator : public std::iterator< std::bidirectional_iterator_tag,
-	                                       value_type > {
+	class iterator : public std::iterator< std::bidirectional_iterator_tag, value_type > {
 	friend class ScopedMap;
 	friend class const_iterator;
@@ -72,5 +71,5 @@
 
 		/// Increments on invalid
-		iterator& next_valid() {
+		iterator & next_valid() {
 			if ( ! is_valid() ) { ++(*this); }
 			return *this;
@@ -78,14 +77,14 @@
 
 		/// Decrements on invalid
-		iterator& prev_valid() {
+		iterator & prev_valid() {
 			if ( ! is_valid() ) { --(*this); }
 			return *this;
 		}
 
-		iterator(scope_list &_scopes, const wrapped_iterator &_it, size_type inLevel)
+		iterator(scope_list & _scopes, const wrapped_iterator & _it, size_type inLevel)
 			: scopes(&_scopes), it(_it), level(inLevel) {}
 	public:
-		iterator(const iterator &that) : scopes(that.scopes), it(that.it), level(that.level) {}
-		iterator& operator= (const iterator &that) {
+		iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+		iterator & operator= (const iterator & that) {
 			scopes = that.scopes; level = that.level; it = that.it;
 			return *this;
@@ -95,5 +94,5 @@
 		pointer operator-> () const { return it.operator->(); }
 
-		iterator& operator++ () {
+		iterator & operator++ () {
 			if ( it == (*scopes)[level].map.end() ) {
 				if ( level == 0 ) return *this;
@@ -107,5 +106,5 @@
 		iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
 
-		iterator& operator-- () {
+		iterator & operator-- () {
 			// may fail if this is the begin iterator; allowed by STL spec
 			if ( it == (*scopes)[level].map.begin() ) {
@@ -118,13 +117,13 @@
 		iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
 
-		bool operator== (const iterator &that) const {
+		bool operator== (const iterator & that) const {
 			return scopes == that.scopes && level == that.level && it == that.it;
 		}
-		bool operator!= (const iterator &that) const { return !( *this == that ); }
+		bool operator!= (const iterator & that) const { return !( *this == that ); }
 
 		size_type get_level() const { return level; }
 
-		Note& get_note() { return (*scopes)[level].note; }
-		const Note& get_note() const { return (*scopes)[level].note; }
+		Note & get_note() { return (*scopes)[level].note; }
+		const Note & get_note() const { return (*scopes)[level].note; }
 
 	private:
@@ -148,5 +147,5 @@
 
 		/// Increments on invalid
-		const_iterator& next_valid() {
+		const_iterator & next_valid() {
 			if ( ! is_valid() ) { ++(*this); }
 			return *this;
@@ -154,19 +153,19 @@
 
 		/// Decrements on invalid
-		const_iterator& prev_valid() {
+		const_iterator & prev_valid() {
 			if ( ! is_valid() ) { --(*this); }
 			return *this;
 		}
 
-		const_iterator(scope_list const &_scopes, const wrapped_const_iterator &_it, size_type inLevel)
+		const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
 			: scopes(&_scopes), it(_it), level(inLevel) {}
 	public:
-		const_iterator(const iterator &that) : scopes(that.scopes), it(that.it), level(that.level) {}
-		const_iterator(const const_iterator &that) : scopes(that.scopes), it(that.it), level(that.level) {}
-		const_iterator& operator= (const iterator &that) {
+		const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+		const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+		const_iterator & operator= (const iterator & that) {
 			scopes = that.scopes; level = that.level; it = that.it;
 			return *this;
 		}
-		const_iterator& operator= (const const_iterator &that) {
+		const_iterator & operator= (const const_iterator & that) {
 			scopes = that.scopes; level = that.level; it = that.it;
 			return *this;
@@ -176,5 +175,5 @@
 		const_pointer operator-> () { return it.operator->(); }
 
-		const_iterator& operator++ () {
+		const_iterator & operator++ () {
 			if ( it == (*scopes)[level].map.end() ) {
 				if ( level == 0 ) return *this;
@@ -188,5 +187,5 @@
 		const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
 
-		const_iterator& operator-- () {
+		const_iterator & operator-- () {
 			// may fail if this is the begin iterator; allowed by STL spec
 			if ( it == (*scopes)[level].map.begin() ) {
@@ -199,12 +198,12 @@
 		const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
 
-		bool operator== (const const_iterator &that) const {
+		bool operator== (const const_iterator & that) const {
 			return scopes == that.scopes && level == that.level && it == that.it;
 		}
-		bool operator!= (const const_iterator &that) const { return !( *this == that ); }
+		bool operator!= (const const_iterator & that) const { return !( *this == that ); }
 
 		size_type get_level() const { return level; }
 
-		const Note& get_note() const { return (*scopes)[level].note; }
+		const Note & get_note() const { return (*scopes)[level].note; }
 
 	private:
@@ -221,5 +220,5 @@
 	// Starts a new scope with the given note
 	template<typename N>
-	void beginScope( N&& n ) {
+	void beginScope( N && n ) {
 		scopes.emplace_back( std::forward<N>(n) );
 	}
@@ -236,5 +235,5 @@
 	/// Constructs with a given note on the outermost scope
 	template<typename N>
-	ScopedMap( N&& n ) : scopes() { beginScope(std::forward<N>(n)); }
+	ScopedMap( N && n ) : scopes() { beginScope(std::forward<N>(n)); }
 
 	iterator begin() { return iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
@@ -249,11 +248,11 @@
 
 	/// Gets the note at the given scope
-	Note& getNote() { return scopes.back().note; }
-	const Note& getNote() const { return scopes.back().note; }
-	Note& getNote( size_type i ) { return scopes[i].note; }
-	const Note& getNote( size_type i ) const { return scopes[i].note; }
+	Note & getNote() { return scopes.back().note; }
+	const Note & getNote() const { return scopes.back().note; }
+	Note & getNote( size_type i ) { return scopes[i].note; }
+	const Note & getNote( size_type i ) const { return scopes[i].note; }
 
 	/// Finds the given key in the outermost scope it occurs; returns end() for none such
-	iterator find( const Key &key ) {
+	iterator find( const Key & key ) {
 		for ( size_type i = scopes.size() - 1; ; --i ) {
 			typename MapType::iterator val = scopes[i].map.find( key );
@@ -263,20 +262,20 @@
 		return end();
 	}
-	const_iterator find( const Key &key ) const {
+	const_iterator find( const Key & key ) const {
 			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->find( key ) );
 	}
 
 	/// Finds the given key in the provided scope; returns end() for none such
-	iterator findAt( size_type scope, const Key& key ) {
+	iterator findAt( size_type scope, const Key & key ) {
 		typename MapType::iterator val = scopes[scope].map.find( key );
 		if ( val != scopes[scope].map.end() ) return iterator( scopes, val, scope );
 		return end();
 	}
-	const_iterator findAt( size_type scope, const Key& key ) const {
+	const_iterator findAt( size_type scope, const Key & key ) const {
 		return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findAt( scope, key ) );
 	}
 
 	/// Finds the given key in the outermost scope inside the given scope where it occurs
-	iterator findNext( const_iterator &it, const Key &key ) {
+	iterator findNext( const_iterator & it, const Key & key ) {
 		if ( it.level == 0 ) return end();
 		for ( size_type i = it.level - 1; ; --i ) {
@@ -287,5 +286,5 @@
 		return end();
 	}
-	const_iterator findNext( const_iterator &it, const Key &key ) const {
+	const_iterator findNext( const_iterator & it, const Key & key ) const {
 			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findNext( it, key ) );
 	}
@@ -293,5 +292,5 @@
 	/// Inserts the given key-value pair into the outermost scope
 	template< typename value_type_t >
-	std::pair< iterator, bool > insert( value_type_t&& value ) {
+	std::pair< iterator, bool > insert( value_type_t && value ) {
 		std::pair< typename MapType::iterator, bool > res = scopes.back().map.insert( std::forward<value_type_t>( value ) );
 		return std::make_pair( iterator(scopes, std::move( res.first ), scopes.size()-1), std::move( res.second ) );
@@ -299,6 +298,6 @@
 
 	template< typename value_type_t >
-	std::pair< iterator, bool > insert( iterator at, value_type_t&& value ) {
-		MapType& scope = (*at.scopes)[ at.level ].map;
+	std::pair< iterator, bool > insert( iterator at, value_type_t && value ) {
+		MapType & scope = (*at.scopes)[ at.level ].map;
 		std::pair< typename MapType::iterator, bool > res = scope.insert( std::forward<value_type_t>( value ) );
 		return std::make_pair( iterator(scopes, std::move( res.first ), at.level), std::move( res.second ) );
@@ -306,8 +305,8 @@
 
 	template< typename value_t >
-	std::pair< iterator, bool > insert( const Key &key, value_t&& value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
+	std::pair< iterator, bool > insert( const Key & key, value_t && value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
 
 	template< typename value_type_t >
-	std::pair< iterator, bool > insertAt( size_type scope, value_type_t&& value ) {
+	std::pair< iterator, bool > insertAt( size_type scope, value_type_t && value ) {
 		std::pair< typename MapType::iterator, bool > res = scopes.at(scope).map.insert( std::forward<value_type_t>( value ) );
 		return std::make_pair( iterator(scopes, std::move( res.first ), scope), std::move( res.second ) );
@@ -315,9 +314,9 @@
 
 	template< typename value_t >
-	std::pair< iterator, bool > insertAt( size_type scope, const Key& key, value_t&& value ) {
+	std::pair< iterator, bool > insertAt( size_type scope, const Key & key, value_t && value ) {
 		return insertAt( scope, std::make_pair( key, std::forward<value_t>( value ) ) );
 	}
 
-	Value& operator[] ( const Key &key ) {
+	Value & operator[] ( const Key & key ) {
 		iterator slot = find( key );
 		if ( slot != end() ) return slot->second;
@@ -326,11 +325,11 @@
 
 	iterator erase( iterator pos ) {
-		MapType& scope = (*pos.scopes)[ pos.level ].map;
-		const typename iterator::wrapped_iterator& new_it = scope.erase( pos.it );
+		MapType & scope = (*pos.scopes)[ pos.level ].map;
+		const typename iterator::wrapped_iterator & new_it = scope.erase( pos.it );
 		iterator it( *pos.scopes, new_it, pos.level );
 		return it.next_valid();
 	}
 
-	size_type count( const Key &key ) const {
+	size_type count( const Key & key ) const {
 		size_type c = 0;
 		auto it = find( key );
@@ -344,5 +343,4 @@
 		return c;
 	}
-
 };
 
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Common/utility.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -322,4 +322,6 @@
 
 	ValueGuardPtr(T * inRef) : old( inRef ? *inRef : T() ), ref(inRef) {}
+	ValueGuardPtr(const ValueGuardPtr& other) = delete;
+	ValueGuardPtr(ValueGuardPtr&& other) : old(other.old), ref(other.ref) { other.ref = nullptr; }
 	~ValueGuardPtr() { if( ref ) *ref = old; }
 };
Index: src/CompilationState.cc
===================================================================
--- src/CompilationState.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/CompilationState.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -31,5 +31,5 @@
 	genproto = false,
 	deterministic_output = false,
-	useNewAST = CFA_USE_NEW_AST,
+	useNewAST = true,
 	nomainp = false,
 	parsep = false,
Index: src/Concurrency/Keywords.cc
===================================================================
--- src/Concurrency/Keywords.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Concurrency/Keywords.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -508,5 +508,5 @@
 		ObjectDecl * vtable_object = Virtual::makeVtableForward(
 			"_default_vtable_object_declaration",
-			vtable_decl->makeInst( move( poly_args ) ) );
+			vtable_decl->makeInst( std::move( poly_args ) ) );
 		declsToAddBefore.push_back( vtable_object );
 		declsToAddBefore.push_back(
@@ -681,5 +681,5 @@
 			void lock (monitor_t & this) {
 				lock(get_monitor(this));
-			}	
+			}
 		*/
 		FunctionDecl * lock_decl = new FunctionDecl(
@@ -700,5 +700,5 @@
 		CompoundStmt * lock_statement = new CompoundStmt();
 		lock_statement->push_back(
-			new ExprStmt( 
+			new ExprStmt(
 				new UntypedExpr (
 					new NameExpr( "lock" ),
@@ -716,5 +716,5 @@
 			void unlock (monitor_t & this) {
 				unlock(get_monitor(this));
-			}	
+			}
 		*/
 		FunctionDecl * unlock_decl = new FunctionDecl(
@@ -736,5 +736,5 @@
 
 		unlock_statement->push_back(
-			new ExprStmt( 
+			new ExprStmt(
 				new UntypedExpr(
 					new NameExpr( "unlock" ),
@@ -746,5 +746,5 @@
 		);
 		unlock_decl->set_statements( unlock_statement );
-		
+
 		// pushes routines to declsToAddAfter to add at a later time
 		declsToAddAfter.push_back( lock_decl );
@@ -1054,5 +1054,5 @@
 			assert( !thread_guard_decl );
 			thread_guard_decl = decl;
-		} 
+		}
 		else if ( decl->name == "__mutex_stmt_lock_guard" && decl->body ) {
 			assert( !lock_guard_decl );
@@ -1206,5 +1206,5 @@
 							new NameExpr( "__get_mutexstmt_lock_type" ),
 							{ args.front()->clone() }
-						) 
+						)
 					)
 				),
@@ -1225,10 +1225,10 @@
 
 		StructInstType * lock_guard_struct = new StructInstType( noQualifiers, lock_guard_decl );
-		TypeExpr * lock_type_expr = new TypeExpr( 
+		TypeExpr * lock_type_expr = new TypeExpr(
 			new TypeofType( noQualifiers, new UntypedExpr(
 				new NameExpr( "__get_mutexstmt_lock_type" ),
 				{ args.front()->clone() }
-				) 
-			) 
+				)
+			)
 		);
 
Index: src/Concurrency/KeywordsNew.cpp
===================================================================
--- src/Concurrency/KeywordsNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Concurrency/KeywordsNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -398,7 +398,5 @@
 			new ast::ReferenceType( vtable_object->type, ast::CV::Const ),
 			new ast::SingleInit( location,
-				new ast::VariableExpr( location, vtable_object ) ),
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
+				new ast::VariableExpr( location, vtable_object ) )
 		)
 	);
@@ -471,8 +469,5 @@
 		location,
 		"this",
-		new ast::ReferenceType( new ast::StructInstType( decl ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::ReferenceType( new ast::StructInstType( decl ) )
 	);
 
@@ -480,8 +475,5 @@
 		location,
 		"ret",
-		new ast::PointerType( new ast::StructInstType( type_decl ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::PointerType( new ast::StructInstType( type_decl ) )
 	);
 
@@ -530,8 +522,5 @@
 		location,
 		field_name,
-		new ast::StructInstType( type_decl ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::StructInstType( type_decl )
 	);
 
@@ -577,8 +566,5 @@
 		location,
 		"this",
-		new ast::ReferenceType( new ast::StructInstType( decl ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::ReferenceType( new ast::StructInstType( decl ) )
 	);
 
@@ -1077,7 +1063,5 @@
 				) }
 			)
-		),
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		)
 	);
 
@@ -1107,7 +1091,5 @@
 				{},
 				ast::MaybeConstruct
-			),
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
+			)
 		))
 	);
@@ -1161,7 +1143,5 @@
 				}
 			)
-		),
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		)
 	);
 
@@ -1190,7 +1170,5 @@
 				{},
 				ast::MaybeConstruct
-			),
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
+			)
 		))
 	);
@@ -1296,7 +1274,5 @@
 				}
 			)
-		),
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		)
 	);
 
@@ -1370,7 +1346,5 @@
 					{},
 					ast::MaybeConstruct
-				),
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
+				)
 			)
 		)
@@ -1513,7 +1487,5 @@
 				{},
 				ast::MaybeConstruct
-			),
-			ast::Storage::Classes(),
-			ast::Linkage::Cforall
+			)
 		)
 	));
Index: src/Concurrency/WaitforNew.cpp
===================================================================
--- src/Concurrency/WaitforNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Concurrency/WaitforNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -101,5 +101,5 @@
 namespace {
 
-class GenerateWaitForCore :
+class GenerateWaitForCore final :
 		public ast::WithSymbolTable, public ast::WithConstTranslationUnit {
 	const ast::FunctionDecl * decl_waitfor    = nullptr;
Index: src/ControlStruct/ExceptDeclNew.cpp
===================================================================
--- src/ControlStruct/ExceptDeclNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/ExceptDeclNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -110,8 +110,5 @@
 		"parent",
 		new ast::PointerType(
-			new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+			new ast::StructInstType( "__cfavir_type_info", ast::CV::Const ) )
 	) );
 	decl->body = true;
@@ -166,40 +163,25 @@
 		location,
 		"__cfavir_typeid",
-		new ast::PointerType( typeIdType ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::PointerType( typeIdType )
 	);
 	ast::ObjectDecl * size = new ast::ObjectDecl(
 		location,
 		"size",
-		new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::TypeInstType( "size_t", ast::TypeDecl::Dtype )
 	);
 	ast::ObjectDecl * copy = new ast::ObjectDecl(
 		location,
 		"copy",
-		new ast::PointerType( createCopyFuncType( exceptionName, params ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::PointerType( createCopyFuncType( exceptionName, params ) )
 	);
 	ast::ObjectDecl * dtor = new ast::ObjectDecl(
 		location,
 		"^?{}",
-		new ast::PointerType( createDtorFuncType( exceptionName, params ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::PointerType( createDtorFuncType( exceptionName, params ) )
 	);
 	ast::ObjectDecl * msg = new ast::ObjectDecl(
 		location,
 		"msg",
-		new ast::PointerType( createMsgFuncType( exceptionName, params ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::PointerType( createMsgFuncType( exceptionName, params ) )
 	);
 	ast::StructDecl * decl = new ast::StructDecl(
@@ -229,8 +211,5 @@
 		"virtual_table",
 		new ast::PointerType(
-			createVTableInstType( exceptionName, params ) ),
-		nullptr,
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+			createVTableInstType( exceptionName, params ) )
 	) );
 	for ( ast::ptr<ast::Decl> const & member : members ) {
@@ -289,8 +268,5 @@
 				"this",
 				new ast::PointerType(
-					createExceptionInstType( exceptionName, params ) ),
-				nullptr,
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
+					createExceptionInstType( exceptionName, params ) )
 			),
 			new ast::ObjectDecl(
@@ -298,19 +274,9 @@
 				"that",
 				new ast::PointerType(
-					createExceptionInstType( exceptionName, params ) ),
-				nullptr,
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
+					createExceptionInstType( exceptionName, params ) )
 			),
 		},
 		{
-			new ast::ObjectDecl(
-				location,
-				"",
-				new ast::VoidType(),
-				nullptr,
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
-			),
+			new ast::ObjectDecl( location, "", new ast::VoidType() ),
 		},
 		new ast::CompoundStmt( location, {
@@ -366,8 +332,5 @@
 				"this",
 				new ast::PointerType(
-					createExceptionInstType( exceptionName, params ) ),
-				nullptr,
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
+					createExceptionInstType( exceptionName, params ) )
 			),
 		},
@@ -377,8 +340,5 @@
 				"",
 				new ast::PointerType(
-					new ast::BasicType( ast::BasicType::Char, ast::CV::Const ) ),
-				nullptr,
-				ast::Storage::Classes(),
-				ast::Linkage::Cforall
+					new ast::BasicType( ast::BasicType::Char, ast::CV::Const ) )
 			),
 		},
@@ -432,7 +392,5 @@
 		tableName,
 		createVTableInstType( exceptionName, params ),
-		new ast::ListInit( location, std::move( inits ), std::move( dsigs ) ),
-		ast::Storage::Classes(),
-		ast::Linkage::Cforall
+		new ast::ListInit( location, std::move( inits ), std::move( dsigs ) )
 	);
 }
Index: src/ControlStruct/ExceptTranslateNew.cpp
===================================================================
--- src/ControlStruct/ExceptTranslateNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/ExceptTranslateNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -32,5 +32,5 @@
 	}
 
-class TranslateThrowsCore : public ast::WithGuards {
+class TranslateThrowsCore final : public ast::WithGuards {
 	const ast::ObjectDecl * terminateHandlerExcept;
 	enum Context { NoHandler, TerHandler, ResHandler } currentContext;
@@ -136,5 +136,5 @@
 
 
-class TryMutatorCore {
+class TryMutatorCore final {
 	// The built in types used in translation.
 	const ast::StructDecl * except_decl;
@@ -190,8 +190,5 @@
 		location,
 		"__handler_index",
-		new ast::BasicType(ast::BasicType::SignedInt),
-		nullptr, //init
-		ast::Storage::Classes{},
-		ast::Linkage::Cforall
+		new ast::BasicType( ast::BasicType::SignedInt )
 		);
 }
@@ -203,10 +200,5 @@
 		location,
 		"__exception_inst",
-		new ast::PointerType(
-			new ast::StructInstType( except_decl )
-			),
-		nullptr, //init
-		ast::Storage::Classes{},
-		ast::Linkage::Cforall
+		new ast::PointerType( new ast::StructInstType( except_decl ) )
 		);
 }
Index: src/ControlStruct/LabelFixer.cc
===================================================================
--- src/ControlStruct/LabelFixer.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/LabelFixer.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -119,5 +119,5 @@
 
 // Builds a table that maps a label to its defining statement.
-std::map<Label, Statement * > * LabelFixer::resolveJumps() throw ( SemanticErrorException ) {
+std::map<Label, Statement * > * LabelFixer::resolveJumps() {
 	std::map< Label, Statement * > *ret = new std::map< Label, Statement * >();
 	for ( std::map< Label, Entry * >::iterator i = labelTable.begin(); i != labelTable.end(); ++i ) {
Index: src/ControlStruct/LabelFixer.h
===================================================================
--- src/ControlStruct/LabelFixer.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/LabelFixer.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -33,5 +33,5 @@
 	LabelFixer( LabelGenerator *gen = 0 );
 
-	std::map < Label, Statement * > *resolveJumps() throw ( SemanticErrorException );
+	std::map < Label, Statement * > *resolveJumps();
 
 	// Declarations
Index: src/ControlStruct/MLEMutator.cc
===================================================================
--- src/ControlStruct/MLEMutator.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/MLEMutator.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -141,6 +141,5 @@
 
 
-	Statement *MultiLevelExitMutator::postmutate( BranchStmt *branchStmt )
-			throw ( SemanticErrorException ) {
+	Statement *MultiLevelExitMutator::postmutate( BranchStmt *branchStmt ) {
 		std::string originalTarget = branchStmt->originalTarget;
 
Index: src/ControlStruct/MLEMutator.h
===================================================================
--- src/ControlStruct/MLEMutator.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ControlStruct/MLEMutator.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -41,5 +41,5 @@
 
 		void premutate( CompoundStmt *cmpndStmt );
-		Statement * postmutate( BranchStmt *branchStmt ) throw ( SemanticErrorException );
+		Statement * postmutate( BranchStmt *branchStmt );
 		void premutate( WhileDoStmt *whileDoStmt );
 		Statement * postmutate( WhileDoStmt *whileDoStmt );
Index: src/GenPoly/GenPoly.cc
===================================================================
--- src/GenPoly/GenPoly.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/GenPoly.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -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 Jun 29 21:45:53 2016
-// Update Count     : 14
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Sep 14  9:24:00 2022
+// Update Count     : 15
 //
 
@@ -83,4 +83,15 @@
 		}
 
+		bool hasDynParams( const std::vector<ast::ptr<ast::Expr>> & params, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs ) {
+			for ( ast::ptr<ast::Expr> const & param : params ) {
+				auto paramType = param.as<ast::TypeExpr>();
+				assertf( paramType, "Aggregate parameters should be type expressions." );
+				if ( isDynType( paramType->type, tyVars, typeSubs ) ) {
+					return true;
+				}
+			}
+			return false;
+		}
+
 		/// Checks a parameter list for inclusion of polymorphic parameters; will substitute according to env if present
 		bool includesPolyParams( std::list< Expression* >& params, const TypeSubstitution *env ) {
@@ -198,4 +209,24 @@
 		}
 		return 0;
+	}
+
+	const ast::BaseInstType *isDynType( const ast::Type *type, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs ) {
+		type = replaceTypeInst( type, typeSubs );
+
+		if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
+			auto var = tyVars.find( inst->name );
+			if ( var != tyVars.end() && var->second.isComplete ) {
+				return inst;
+			}
+		} else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+			if ( hasDynParams( inst->params, tyVars, typeSubs ) ) {
+				return inst;
+			}
+		} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+			if ( hasDynParams( inst->params, tyVars, typeSubs ) ) {
+				return inst;
+			}
+		}
+		return nullptr;
 	}
 
@@ -378,4 +409,9 @@
 		inline D* as( B* p ) { return reinterpret_cast<D*>(p); }
 
+		template<typename D, typename B>
+		inline D const * as( B const * p ) {
+			return reinterpret_cast<D const *>( p );
+		}
+
 		/// Flattens a declaration list
 		template<typename Output>
@@ -391,4 +427,11 @@
 			for ( Type* ty : src ) {
 				ResolvExpr::flatten( ty, out );
+			}
+		}
+
+		void flattenList( vector<ast::ptr<ast::Type>> const & src,
+				vector<ast::ptr<ast::Type>> & out ) {
+			for ( auto const & type : src ) {
+				ResolvExpr::flatten( type, out );
 			}
 		}
@@ -409,4 +452,29 @@
 				// if ( is<VoidType>( aparam->get_type() ) || is<VoidType>( bparam->get_type() ) ) continue;
 				if ( ! typesPolyCompatible( aparam->get_type(), bparam->get_type() ) ) return false;
+			}
+
+			return true;
+		}
+
+		bool paramListsPolyCompatible(
+				std::vector<ast::ptr<ast::Expr>> const & lparams,
+				std::vector<ast::ptr<ast::Expr>> const & rparams ) {
+			if ( lparams.size() != rparams.size() ) {
+				return false;
+			}
+
+			for ( auto lparam = lparams.begin(), rparam = rparams.begin() ;
+					lparam != lparams.end() ; ++lparam, ++rparam ) {
+				ast::TypeExpr const * lexpr = lparam->as<ast::TypeExpr>();
+				assertf( lexpr, "Aggregate parameters should be type expressions" );
+				ast::TypeExpr const * rexpr = rparam->as<ast::TypeExpr>();
+				assertf( rexpr, "Aggregate parameters should be type expressions" );
+
+				// xxx - might need to let VoidType be a wildcard here too; could have some voids
+				// stuffed in for dtype-statics.
+				// if ( is<VoidType>( lexpr->type() ) || is<VoidType>( bparam->get_type() ) ) continue;
+				if ( !typesPolyCompatible( lexpr->type, rexpr->type ) ) {
+					return false;
+				}
 			}
 
@@ -505,4 +573,116 @@
 	}
 
+bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs ) {
+	type_index const lid = typeid(*lhs);
+
+	// Polymorphic types always match:
+	if ( type_index(typeid(ast::TypeInstType)) == lid ) return true;
+
+	type_index const rid = typeid(*rhs);
+	if ( type_index(typeid(ast::TypeInstType)) == rid ) return true;
+
+	// All other types only match if they are the same type:
+	if ( lid != rid ) return false;
+
+	// So remaining types can be examined case by case.
+	// Recurse through type structure (conditions borrowed from Unify.cc).
+
+	if ( type_index(typeid(ast::BasicType)) == lid ) {
+		return as<ast::BasicType>(lhs)->kind == as<ast::BasicType>(rhs)->kind;
+	} else if ( type_index(typeid(ast::PointerType)) == lid ) {
+		ast::PointerType const * l = as<ast::PointerType>(lhs);
+		ast::PointerType const * r = as<ast::PointerType>(rhs);
+
+		// void pointers should match any other pointer type.
+		return is<ast::VoidType>( l->base.get() )
+			|| is<ast::VoidType>( r->base.get() )
+			|| typesPolyCompatible( l->base.get(), r->base.get() );
+	} else if ( type_index(typeid(ast::ReferenceType)) == lid ) {
+		ast::ReferenceType const * l = as<ast::ReferenceType>(lhs);
+		ast::ReferenceType const * r = as<ast::ReferenceType>(rhs);
+
+		// void references should match any other reference type.
+		return is<ast::VoidType>( l->base.get() )
+			|| is<ast::VoidType>( r->base.get() )
+			|| typesPolyCompatible( l->base.get(), r->base.get() );
+	} else if ( type_index(typeid(ast::ArrayType)) == lid ) {
+		ast::ArrayType const * l = as<ast::ArrayType>(lhs);
+		ast::ArrayType const * r = as<ast::ArrayType>(rhs);
+
+		if ( l->isVarLen ) {
+			if ( !r->isVarLen ) return false;
+		} else {
+			if ( r->isVarLen ) return false;
+
+			auto lc = l->dimension.as<ast::ConstantExpr>();
+			auto rc = r->dimension.as<ast::ConstantExpr>();
+			if ( lc && rc && lc->intValue() != rc->intValue() ) {
+				return false;
+			}
+		}
+
+		return typesPolyCompatible( l->base.get(), r->base.get() );
+	} else if ( type_index(typeid(ast::FunctionType)) == lid ) {
+		ast::FunctionType const * l = as<ast::FunctionType>(lhs);
+		ast::FunctionType const * r = as<ast::FunctionType>(rhs);
+
+		std::vector<ast::ptr<ast::Type>> lparams, rparams;
+		flattenList( l->params, lparams );
+		flattenList( r->params, rparams );
+		if ( lparams.size() != rparams.size() ) return false;
+		for ( unsigned i = 0; i < lparams.size(); ++i ) {
+			if ( !typesPolyCompatible( lparams[i], rparams[i] ) ) return false;
+		}
+
+		std::vector<ast::ptr<ast::Type>> lrets, rrets;
+		flattenList( l->returns, lrets );
+		flattenList( r->returns, rrets );
+		if ( lrets.size() != rrets.size() ) return false;
+		for ( unsigned i = 0; i < lrets.size(); ++i ) {
+			if ( !typesPolyCompatible( lrets[i], rrets[i] ) ) return false;
+		}
+		return true;
+	} else if ( type_index(typeid(ast::StructInstType)) == lid ) {
+		ast::StructInstType const * l = as<ast::StructInstType>(lhs);
+		ast::StructInstType const * r = as<ast::StructInstType>(rhs);
+
+		if ( l->name != r->name ) return false;
+		return paramListsPolyCompatible( l->params, r->params );
+	} else if ( type_index(typeid(ast::UnionInstType)) == lid ) {
+		ast::UnionInstType const * l = as<ast::UnionInstType>(lhs);
+		ast::UnionInstType const * r = as<ast::UnionInstType>(rhs);
+
+		if ( l->name != r->name ) return false;
+		return paramListsPolyCompatible( l->params, r->params );
+	} else if ( type_index(typeid(ast::EnumInstType)) == lid ) {
+		ast::EnumInstType const * l = as<ast::EnumInstType>(lhs);
+		ast::EnumInstType const * r = as<ast::EnumInstType>(rhs);
+
+		return l->name == r->name;
+	} else if ( type_index(typeid(ast::TraitInstType)) == lid ) {
+		ast::TraitInstType const * l = as<ast::TraitInstType>(lhs);
+		ast::TraitInstType const * r = as<ast::TraitInstType>(rhs);
+
+		return l->name == r->name;
+	} else if ( type_index(typeid(ast::TupleType)) == lid ) {
+		ast::TupleType const * l = as<ast::TupleType>(lhs);
+		ast::TupleType const * r = as<ast::TupleType>(rhs);
+
+		std::vector<ast::ptr<ast::Type>> ltypes, rtypes;
+		flattenList( l->types, ( ltypes ) );
+		flattenList( r->types, ( rtypes ) );
+		if ( ltypes.size() != rtypes.size() ) return false;
+
+		for ( unsigned i = 0 ; i < ltypes.size() ; ++i ) {
+			if ( !typesPolyCompatible( ltypes[i], rtypes[i] ) ) return false;
+		}
+		return true;
+	// The remaining types (VoidType, VarArgsType, ZeroType & OneType)
+	// have no variation so will always be equal.
+	} else {
+		return true;
+	}
+}
+
 	namespace {
 		// temporary hack to avoid re-implementing anything related to TyVarMap
Index: src/GenPoly/GenPoly.h
===================================================================
--- src/GenPoly/GenPoly.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/GenPoly.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -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 : Sat Jul 22 09:22:57 2017
-// Update Count     : 7
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Aug 19 16:03:00 2022
+// Update Count     : 8
 //
 
@@ -27,5 +27,7 @@
 namespace GenPoly {
 
+	// TODO Via some tricks this works for ast::TypeDecl::Data as well.
 	typedef ErasableScopedMap< std::string, TypeDecl::Data > TyVarMap;
+
 	/// Replaces a TypeInstType by its referrent in the environment, if applicable
 	Type* replaceTypeInst( Type* type, const TypeSubstitution* env );
@@ -41,4 +43,5 @@
 	/// returns dynamic-layout type if is dynamic-layout type in tyVars, NULL otherwise; will look up substitution in env if provided
 	ReferenceToType *isDynType( Type *type, const TyVarMap &tyVars, const TypeSubstitution *env = 0 );
+	const ast::BaseInstType *isDynType( const ast::Type *type, const TyVarMap &tyVars, const ast::TypeSubstitution *typeSubs = 0 );
 
 	/// true iff function has dynamic-layout return type under the given type variable map
@@ -83,4 +86,5 @@
 	/// true iff types are structurally identical, where TypeInstType's match any type.
 	bool typesPolyCompatible( Type *aty, Type *bty );
+	bool typesPolyCompatible( ast::Type const * lhs, ast::Type const * rhs );
 
 	/// true if arg requires boxing given exprTyVars
Index: src/GenPoly/InstantiateGeneric.h
===================================================================
--- src/GenPoly/InstantiateGeneric.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/InstantiateGeneric.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -19,10 +19,15 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace GenPoly {
-	/// Replaces all generic types that have static layout with concrete instantiations.
-	/// Types with concrete values for otype parameters will be template-expanded, while
-	/// dtype and ftype parameters will be replaced by the appropriate void type.
-	void instantiateGeneric( std::list< Declaration* > &translationUnit );
+/// Replaces all generic types that have static layout with concrete
+/// instantiations. Types with concrete values for otype parameters will be
+/// template-expanded, while dtype and ftype parameters will be replaced by
+/// the appropriate void type.
+void instantiateGeneric( std::list< Declaration* > &translationUnit );
+void instantiateGeneric( ast::TranslationUnit & translationUnit );
 } // namespace GenPoly
 
Index: src/GenPoly/InstantiateGenericNew.cpp
===================================================================
--- src/GenPoly/InstantiateGenericNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
+++ src/GenPoly/InstantiateGenericNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -0,0 +1,708 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// InstantiateGenericNew.cpp --
+//
+// Author           : Andrew Beach
+// Created On       : Tue Aug 16 10:51:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Sep 13 16:03:00 2022
+// Update Count     : 0
+//
+
+#include "InstantiateGeneric.h"
+
+#include <cassert>                     // for assertf, assert
+#include <set>                         // for set
+#include <utility>                     // for move, pair
+#include <vector>                      // for vector
+
+#include "AST/Copy.hpp"                // for deepCopy
+#include "AST/Pass.hpp"                // for Pass, WithGuard, WithShortCi...
+#include "AST/TranslationUnit.hpp"     // for TranslationUnit
+#include "CodeGen/OperatorTable.h"     // for isAssignment
+#include "Common/ScopedMap.h"          // for ScopedMap
+#include "Common/UniqueName.h"         // for UniqueName
+#include "GenPoly/GenPoly.h"           // for isPolyType, typesPolyCompatible
+#include "GenPoly/ScrubTyVars.h"       // for scrubAll
+#include "InitTweak/InitTweak.h"       // for getFunction
+#include "ResolvExpr/typeops.h"        // for typesCompatible
+
+namespace GenPoly {
+
+namespace {
+
+// Utilities:
+
+using type_vector = std::vector< ast::ptr< ast::TypeExpr > >;
+
+/// Abstracts type equality for a list of parameter types.
+struct TypeList {
+	TypeList() : params() {}
+	TypeList( std::vector< ast::ptr< ast::Type > > const & params ) :
+		params( params ) {}
+	TypeList( std::vector< ast::ptr< ast::Type > > && params ) :
+		params( std::move( params ) ) {}
+	TypeList( TypeList const & that ) : params( that.params ) {}
+	TypeList( TypeList && that ) : params( std::move( that.params ) ) {}
+
+	TypeList( std::vector< ast::ptr< ast::TypeExpr > > const & exprs ) :
+			params() {
+		for ( auto expr : exprs ) {
+			params.emplace_back( ast::deepCopy( expr->type ) );
+		}
+	}
+
+	TypeList & operator=( TypeList const & that ) {
+		params = that.params;
+		return *this;
+	}
+
+	TypeList & operator=( TypeList && that ) {
+		params = std::move( that.params );
+		return *this;
+	}
+
+	bool operator==( TypeList const & that ) const {
+		if ( params.size() != that.params.size() ) {
+			return false;
+		}
+
+		for ( auto it = params.begin(), jt = that.params.begin() ;
+				it != params.end() ; ++it, ++jt ) {
+			if ( !typesPolyCompatible( it->get(), jt->get() ) ) {
+				return false;
+			}
+		}
+		return true;
+	}
+
+	std::vector<ast::ptr<ast::Type>> params;
+};
+
+/// Maps a key and a TypeList to a valuue. Also supports scoping.
+class InstantiationMap final {
+	/// Wraps value for a specific (AggregateDecl, TypeList) combination.
+	using Instantiation = std::pair<TypeList, ast::ptr<ast::AggregateDecl>>;
+	/// List of TypeLists paired with the appropriate values.
+	using ValueList = std::vector<Instantiation>;
+	/// Underlying map type; maps keys to a linear list of corresponding
+	/// TypeLists and values.
+	using InnerMap = ScopedMap<ast::ptr<ast::AggregateDecl>, ValueList>;
+
+	InnerMap data;
+public:
+	void beginScope() { data.beginScope(); }
+	void endScope() { data.endScope(); }
+
+	/// Gets the value for the (declaration, type list) pair,
+	/// returns null if no such value exists.
+	ast::AggregateDecl const * lookup(
+			ast::AggregateDecl const * key, type_vector const & params ) const {
+		// This type repackaging is used for the helpers.
+		ast::ptr<ast::AggregateDecl> ptr = key;
+		TypeList typeList( params );
+
+		// Scan scopes for matches to the key.
+		for ( auto insts = data.find( key ) ;
+				insts != data.end() ; insts = data.findNext( insts, ptr )) {
+			for ( auto inst = insts->second.rbegin() ;
+					inst != insts->second.rend() ; ++inst ) {
+				if ( inst->first == typeList ) {
+					return inst->second;
+				}
+			}
+		}
+		return nullptr;
+	}
+
+	/// Adds a value for a (key, type list) pair to the current scope.
+	void insert( ast::AggregateDecl const * key, type_vector const & params,
+			ast::AggregateDecl const * value ) {
+		auto it = data.findAt( data.currentScope(), key );
+		if ( it == data.end() ) {
+			data.insert( key, ValueList( 1,
+				Instantiation( TypeList( params ), value ) ) );
+		} else {
+			it->second.emplace_back(
+				Instantiation( TypeList( params ), value ) );
+		}
+	}
+};
+
+/// Possible options for a given specialization of a generic type.
+enum class GenericType {
+	/// Concrete instatiation based solely on {d,f}type-to-void conversions.
+	dtypeStatic,
+	/// Concrete instatiation requiring at least one parameters type.
+	concrete,
+	/// No concrete instantiation.
+	dynamic
+};
+
+GenericType & operator|=( GenericType & gt, const GenericType & ht ) {
+	if ( gt < ht ) gt = ht;
+	return gt;
+}
+
+bool isDtypeStatic( std::vector<ast::ptr<ast::TypeDecl>> const & baseParams ) {
+	return std::all_of( baseParams.begin(), baseParams.end(),
+		[]( ast::TypeDecl const * td ){ return !td->isComplete(); }
+	);
+}
+
+/// Makes substitutions of params into baseParams; returns dtypeStatic if
+/// there is a concrete instantiation based only on {d,f}type-to-void
+/// conversions, concrete if there is a concrete instantiation requiring at
+/// least one parameter type, and dynamic if there is no concrete instantiation.
+GenericType makeSubstitutions(
+		std::vector<ast::ptr<ast::TypeExpr>> & out,
+		std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
+		std::vector<ast::ptr<ast::Expr>> const & params ) {
+	GenericType gt = GenericType::dtypeStatic;
+
+	// Substitute concrete types for given parameters,
+	// using incomplete types for placeholders.
+	auto baseParam = baseParams.begin();
+	auto param = params.begin();
+	for ( ; baseParam != baseParams.end() && param != params.end() ;
+			++baseParam, ++param ) {
+		ast::TypeExpr const * paramExpr = param->as<ast::TypeExpr>();
+		assertf( paramExpr, "Aggregate parameters should be type expressions." );
+
+		if ( (*baseParam)->isComplete() ) {
+			// Substitute parameter for complete (otype or sized dtype) type.
+			if ( isPolyType( paramExpr->type ) ) {
+				// Substitute polymorphic parameter type in to generic type.
+				out.push_back( ast::deepCopy( paramExpr ) );
+				gt = GenericType::dynamic;
+			} else {
+				// Normalize possibly dtype-static parameter type.
+				out.emplace_back( new ast::TypeExpr( paramExpr->location,
+					scrubAllTypeVars( ast::deepCopy( paramExpr->type ) ) ) );
+				gt |= GenericType::concrete;
+			}
+		} else switch ( (*baseParam)->kind ) {
+		case ast::TypeDecl::Dtype:
+			// Here, pretend that any incomplete dtype is `void`.
+			out.emplace_back( new ast::TypeExpr( paramExpr->location,
+				new ast::VoidType() ) );
+			break;
+		case ast::TypeDecl::Ftype:
+			// Here, pretend that any ftype is `void (*)(void)`.
+			out.emplace_back( new ast::TypeExpr( paramExpr->location,
+				new ast::FunctionType() ) );
+			break;
+		case ast::TypeDecl::Ttype:
+			assertf( false, "Ttype parameters are not currently allowed as parameters to generic types." );
+			break;
+		default:
+			assertf( false, "Unhandled type parameter kind" );
+			break;
+		}
+	}
+
+	assertf( baseParam == baseParams.end(), "Base Parameters not exausted." );
+	assertf( param == params.end(), "Type parameters not exausted." );
+	return gt;
+}
+
+/// Substitutes types of members according to baseParams => typeSubs,
+/// returning the result in a new vector.
+std::vector<ast::ptr<ast::Decl>> substituteMembers(
+		std::vector<ast::ptr<ast::Decl>> const & members,
+		std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
+		std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
+	std::vector<ast::ptr<ast::Decl>> out;
+	ast::TypeSubstitution subs( baseParams, typeSubs );
+	for ( ast::ptr<ast::Decl> const & member : members ) {
+		// Create a manual copy to avoid in-place mutation.
+		// If being a PureVisitor is decided to be part of apply's interface,
+		// then we can actually skip this step as it will never mutate in-
+		// place. (Then we don't need the extra guard to free temp value.)
+		ast::ptr<ast::Decl> copy = ast::deepCopy( member.get() );
+		auto result = subs.apply( copy.get() );
+		out.emplace_back( result.node );
+	}
+	return out;
+}
+
+/// Substitutes types of members according to baseParams => typeSubs,
+/// modifying them in-place.
+void substituteMembersHere(
+		std::vector<ast::ptr<ast::Decl>> & members,
+		std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
+		std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
+	ast::TypeSubstitution subs( baseParams, typeSubs );
+	for ( ast::ptr<ast::Decl> & member : members ) {
+		// The member must be mutated in place to avoid breaking
+		assert( member->unique() );
+
+		auto field = member.strict_as<ast::ObjectDecl>();
+		auto result = subs.apply( field->type.get() );
+		auto copy = ast::mutate_field(
+			field, &ast::ObjectDecl::type, result.node );
+
+		// I'm not kidding, it is very important.
+		assert( copy == member.get() );
+	}
+}
+
+/// Strips the instances' type parameters.
+void stripInstParams( ast::BaseInstType * inst ) {
+	inst->params.clear();
+}
+
+// TODO: I think this should become a generic helper.
+template<typename Aggr>
+Aggr * asForward( Aggr const * decl ) {
+	if ( !decl->body ) {
+		return nullptr;
+	}
+	Aggr * mut = ast::deepCopy( decl );
+	mut->body = false;
+	mut->members.clear();
+	return mut;
+}
+
+bool isGenericType( ast::Type const * type ) {
+	if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		return !inst->params.empty();
+	} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		return !inst->params.empty();
+	} else {
+		return false;
+	}
+}
+
+// The Passes:
+
+struct FixDtypeStatic final :
+		public ast::WithGuards,
+		public ast::WithVisitorRef<FixDtypeStatic>,
+		public ast::WithShortCircuiting,
+		public ast::WithStmtsToAdd<> {
+	ast::ApplicationExpr const * previsit( ast::ApplicationExpr const * expr );
+	void previsit( ast::AddressExpr const * expr );
+
+	ast::Expr const * postvisit( ast::MemberExpr const * expr );
+private:
+	template<typename Aggr>
+	ast::Expr const * fixMemberExpr(
+		Aggr const * inst, ast::MemberExpr const * memberExpr );
+
+	ast::Expr const * fixMemberExpr(
+		std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
+		ast::MemberExpr const * memberExpr );
+
+	bool isLValueArg = false;
+};
+
+ast::ApplicationExpr const * FixDtypeStatic::previsit(
+		ast::ApplicationExpr const * expr ) {
+	GuardValue( isLValueArg ) = false;
+	ast::Decl const * function = InitTweak::getFunction( expr );
+	if ( ast::Linkage::Intrinsic != function->linkage
+			|| !CodeGen::isAssignment( function->name ) ) {
+		return expr;
+	}
+
+	// Explicity visit children because only the first element must be a
+	// C lvalue (normally, it can only send info to both or neither).
+	visit_children = false;
+	expr = mutate_field( expr, &ast::ApplicationExpr::env,
+		maybe_accept( expr->env.get(), *visitor ) );
+	expr = mutate_field( expr, &ast::ApplicationExpr::result,
+		maybe_accept( expr->result.get(), *visitor ) );
+	expr = mutate_field( expr, &ast::ApplicationExpr::func,
+		maybe_accept( expr->func.get(), *visitor ) );
+	isLValueArg = true;
+	for ( unsigned i = 0; i < expr->args.size(); ++i ) {
+		ast::Expr const * newExpr = expr->args[i]->accept( *visitor );
+		// This is declared here for lifetime reasons.
+		ast::ptr<ast::CastExpr> cast;
+		if ( newExpr != expr->args[i].get() &&
+				(cast = dynamic_cast<ast::CastExpr const *>( newExpr )) ) {
+			newExpr = cast->arg.get();
+		}
+		expr = mutate_field_index( expr, &ast::ApplicationExpr::args,
+			i, newExpr );
+		isLValueArg = false;
+	}
+	return expr;
+}
+
+void FixDtypeStatic::previsit( ast::AddressExpr const * ) {
+	// The argument of an address expression (`&`) must be a C lvalue.
+	GuardValue( isLValueArg ) = true;
+}
+
+ast::Expr const * FixDtypeStatic::postvisit( ast::MemberExpr const * expr ) {
+	ast::ptr<ast::Type> const & type = expr->aggregate->result;
+	if ( !isGenericType( type ) ) {
+		return expr;
+	} else if ( auto inst = type.as<ast::StructInstType>() ) {
+		return fixMemberExpr( inst, expr );
+	} else if ( auto inst = type.as<ast::UnionInstType>() ) {
+		return fixMemberExpr( inst, expr );
+	}
+	return expr;
+}
+
+template<typename Aggr>
+ast::Expr const * FixDtypeStatic::fixMemberExpr(
+		Aggr const * inst, ast::MemberExpr const * memberExpr ) {
+	return fixMemberExpr( inst->base->params, memberExpr );
+}
+
+ast::Expr const * FixDtypeStatic::fixMemberExpr(
+		std::vector<ast::ptr<ast::TypeDecl>> const & baseParams,
+		ast::MemberExpr const * memberExpr ) {
+	// Need to cast dtype-static member expressions to their actual type
+	// before the actual type type is erased.
+	// NOTE: The casts here have the third argument (isGenerated) set to
+	// ExplicitCast so that they casts persist until Box, where they are needed.
+
+	if ( !isDtypeStatic( baseParams ) ||
+			ResolvExpr::typesCompatible(
+				memberExpr->result,
+				memberExpr->member->get_type(), ast::SymbolTable() ) ) {
+		return memberExpr;
+	}
+
+	// Type of member and type of expression differ.
+	ast::Type const * concType = ast::deepCopy( memberExpr->result );
+	CodeLocation const & location = memberExpr->location;
+	if ( isLValueArg ) {
+		// The result must be a C lvalue expression. So make a new reference
+		// variable with the correct actual type to replace the
+		// member expression.
+		//   forall(T &)
+		//   struct Ptr {
+		//     T * x;
+		//   };
+		//   Ptr(int) p;
+		//   int i;
+		//   p.x = &i;
+		// becomes
+		//   int *& _dtype_static_member_0 = (int **)&p.x;
+		//   _dtype_static_member_0 = &i;
+		static UniqueName tmpNamer( "_dtype_static_member_" );
+		ast::Expr * init = new ast::CastExpr( location,
+			new ast::AddressExpr( location, memberExpr ),
+			new ast::PointerType( ast::deepCopy( concType ) ),
+			ast::ExplicitCast
+		);
+		ast::ObjectDecl * tmp = new ast::ObjectDecl( location,
+			tmpNamer.newName(),
+			new ast::ReferenceType( concType ),
+			new ast::SingleInit( location, init ),
+			ast::Storage::Classes(),
+			ast::Linkage::C
+		);
+		stmtsToAddBefore.push_back( new ast::DeclStmt( location, tmp ) );
+		return new ast::VariableExpr( location, tmp );
+	} else {
+		// Here, it can simply add a cast to actual types.
+		return new ast::CastExpr( location,
+			memberExpr,
+			concType,
+			ast::ExplicitCast
+		);
+	}
+}
+
+struct GenericInstantiator final :
+		public ast::WithCodeLocation,
+		public ast::WithConstTypeSubstitution,
+		public ast::WithDeclsToAdd<>,
+		public ast::WithGuards,
+		public ast::WithVisitorRef<GenericInstantiator>
+{
+	/// Map of (generic type, parameter list) pairs
+	/// to concrete type instantiations.
+	InstantiationMap instantiations;
+	/// Set of types which are dtype-only generic
+	/// (and therefore have static layout).
+	std::set<ast::AggregateDecl const *> dtypeStatics;
+	/// Namer for concrete types.
+	UniqueName typeNamer;
+	/// Should not make use of type environment to replace types of function
+	/// parameter and return values.
+	bool inFunctionType = false;
+	/// Index of current member, used to recreate MemberExprs with the
+	/// member from an instantiation.
+	int memberIndex = -1;
+
+	GenericInstantiator() :
+		instantiations(), dtypeStatics(), typeNamer("_conc_") {}
+
+	ast::Type const * postvisit( ast::StructInstType const * inst );
+	ast::Type const * postvisit( ast::UnionInstType const * inst );
+
+	void previsit( ast::MemberExpr const * expr );
+	ast::Expr const * postvisit( ast::MemberExpr const * expr );
+	ast::Expr const * postvisit( ast::Expr const * expr );
+	void previsit( ast::ParseNode const * node );
+
+	void previsit( ast::FunctionType const * ) {
+		GuardValue( inFunctionType ) = true;
+	}
+	void beginScope() {
+		instantiations.beginScope();
+	}
+	void endScope() {
+		instantiations.endScope();
+	}
+private:
+	/// Wrap instantiation lookup for structures.
+	ast::StructDecl const * lookup(
+		ast::StructInstType const * inst, type_vector const & typeSubs ) const;
+	/// Wrap instantiation lookup for unions.
+	ast::UnionDecl const * lookup(
+		ast::UnionInstType const * inst, type_vector const & typeSubs ) const;
+	/// Wrap instantiation insertion for structures.
+	void insert( ast::StructInstType const * inst,
+		type_vector const & typeSubs, ast::StructDecl const * decl );
+	/// Wrap instantiation insertion for unions.
+	void insert( ast::UnionInstType const * inst,
+		type_vector const & typeSubs, ast::UnionDecl const * decl );
+
+	void replaceParametersWithConcrete( std::vector<ast::ptr<ast::Expr>> & params );
+	ast::Type const * replaceWithConcrete( ast::Type const * type, bool doClone );
+
+	template<typename AggrDecl>
+	ast::Type const * fixInstType( ast::SueInstType<AggrDecl> const * inst );
+
+	/// Strips a dtype-static aggregate decl of its type parameters,
+	/// marks it as stripped.
+	void stripDtypeParams( ast::AggregateDecl * base,
+		std::vector<ast::ptr<ast::TypeDecl>> & baseParams,
+		std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs );
+};
+
+// I think this and the UnionInstType can be made into a template function.
+ast::Type const * GenericInstantiator::postvisit(
+		ast::StructInstType const * inst ) {
+	return fixInstType( inst );
+}
+
+ast::Type const * GenericInstantiator::postvisit(
+		ast::UnionInstType const * inst ) {
+	return fixInstType( inst );
+}
+
+template<typename AggrDecl>
+ast::Type const * GenericInstantiator::fixInstType(
+		ast::SueInstType<AggrDecl> const * inst ) {
+	assert( location );
+
+	// There is nothing to mutate if the params are empty.
+	if ( inst->params.empty() ) return inst;
+
+	// Need to replace type variables to ensure that generic types are
+	// instantiated for the return values of polymorphic functions (in
+	// particular, for thunks, because they are not [currently] copy
+	// constructed).
+	// (This used to be run only on structures, but I believe both need it.)
+	inst = strict_dynamic_cast<ast::SueInstType<AggrDecl> const *>(
+		replaceWithConcrete( inst, false ) );
+
+	// Check for an already-instantiatiated dtype-static type.
+	if ( dtypeStatics.find( inst->base ) != dtypeStatics.end() ) {
+		auto mutInst = ast::mutate( inst );
+		stripInstParams( mutInst );
+		return mutInst;
+	}
+
+	// Check if the type can be concretely instantiated;
+	// and put substitutions in typeSubs.
+	assertf( inst->base, "Base data-type has parameters." );
+	std::vector<ast::ptr<ast::TypeExpr>> typeSubs;
+	GenericType gt = makeSubstitutions( typeSubs, inst->base->params, inst->params );
+	switch ( gt ) {
+	case GenericType::dtypeStatic:
+	{
+		auto mutInst = ast::mutate( inst );
+		assert( mutInst->base->unique() );
+		auto mutBase = mutInst->base.get_and_mutate();
+		stripDtypeParams( mutBase, mutBase->params, typeSubs );
+		stripInstParams( mutInst );
+		return mutInst;
+	}
+	case GenericType::concrete:
+	{
+		// Make concrete instantiation of generic type.
+		AggrDecl const * concDecl = lookup( inst, typeSubs );
+		if ( !concDecl ) {
+			// Set concDecl to new type, insert type declaration
+			// into statements to add.
+			AggrDecl * newDecl = new AggrDecl( *location,
+				typeNamer.newName( inst->name )
+			);
+			newDecl->body = inst->base->body;
+			newDecl->members = substituteMembers(
+				inst->base->members,
+				inst->base->params,
+				typeSubs
+			);
+
+			// Forward declare before recursion. (TODO: Only when needed, #199.)
+			insert( inst, typeSubs, newDecl );
+			if ( AggrDecl const * forwardDecl = asForward( newDecl ) ) {
+				declsToAddBefore.push_back( forwardDecl );
+			}
+			// Recursively instantiate members:
+			concDecl = strict_dynamic_cast<AggrDecl const *>(
+				newDecl->accept( *visitor ) );
+			// Must occur before declaration is added so
+			// that member instantiation appear first.
+			declsToAddBefore.push_back( concDecl );
+		}
+		return new ast::SueInstType<AggrDecl>( concDecl, inst->qualifiers );
+	}
+	case GenericType::dynamic:
+		// Do nothing.
+	default:
+		// Should never happen.
+		return inst;
+	}
+}
+
+void GenericInstantiator::previsit( ast::MemberExpr const * expr ) {
+	GuardValue( location ) = &expr->location;
+	GuardValue( memberIndex ) = -1;
+	// Only run on expressions where the field being accessed is generic.
+	if ( isGenericType( expr->aggregate->result ) ) {
+		// Find the location of the member:
+		ast::AggregateDecl const * aggr =
+			expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
+		std::vector<ast::ptr<ast::Decl>> const & members = aggr->members;
+		auto it = std::find( members.begin(), members.end(), expr->member );
+		memberIndex = std::distance( members.begin(), it );
+		assertf( memberIndex < (int)members.size(), "Could not find member %s in generic type %s.", toString( expr->member ).c_str(), toString( expr->aggregate ).c_str() );
+	}
+}
+
+ast::Expr const * GenericInstantiator::postvisit(
+		ast::MemberExpr const * expr ) {
+	if ( memberIndex == -1 ) {
+		return expr;
+	}
+
+	// Using the location from the generic type, find the member
+	// in the instantiation and rebuild the member expression.
+	ast::AggregateDecl const * aggr =
+		expr->aggregate->result.strict_as<ast::BaseInstType>()->aggr();
+	assertf( memberIndex < (int)aggr->members.size(), "Instantiation somehow has fewer members than the generic type." );
+	ast::Decl const * member = *std::next( aggr->members.begin(), memberIndex );
+	assertf( member->name == expr->member->name, "Instantiation has different member order than the generic type. %s / %s", toString( member ).c_str(), toString( expr->member ).c_str() );
+	auto field = strict_dynamic_cast< ast::DeclWithType const * >( member );
+	ast::MemberExpr * ret = new ast::MemberExpr( expr->location,
+		field,
+		ast::deepCopy( expr->aggregate )
+	);
+	// For pointer decay:
+	ret->result = ResolvExpr::adjustExprType(
+		ret->result,
+		ast::TypeEnvironment(),
+		ast::SymbolTable()
+	);
+	ret->env = expr->env;
+	return ret;
+}
+
+ast::Expr const * GenericInstantiator::postvisit( ast::Expr const * expr ) {
+	// We are not modifying env on MemberExpr, but that seems to work.
+	if ( expr->env ) {
+		auto newEnv = expr->env->accept( *visitor );
+		expr = ast::mutate_field( expr, &ast::Expr::env, newEnv );
+	}
+	return expr;
+}
+
+void GenericInstantiator::previsit( ast::ParseNode const * node ) {
+	GuardValue( location ) = &node->location;
+}
+
+ast::StructDecl const * GenericInstantiator::lookup(
+		ast::StructInstType const * inst,
+		type_vector const & typeSubs ) const {
+	auto ret = instantiations.lookup( inst->base, typeSubs );
+	return strict_dynamic_cast<ast::StructDecl const *, nullptr>( ret );
+}
+
+ast::UnionDecl const * GenericInstantiator::lookup(
+		ast::UnionInstType const * inst,
+		type_vector const & typeSubs ) const {
+	auto ret = instantiations.lookup( inst->base, typeSubs );
+	return strict_dynamic_cast<ast::UnionDecl const *, nullptr>( ret );
+}
+
+void GenericInstantiator::insert( ast::StructInstType const * inst,
+		type_vector const & typeSubs, ast::StructDecl const * decl ) {
+	instantiations.insert( inst->base, typeSubs, decl );
+}
+
+void GenericInstantiator::insert( ast::UnionInstType const * inst,
+		type_vector const & typeSubs, ast::UnionDecl const * decl ) {
+	instantiations.insert( inst->base, typeSubs, decl );
+}
+
+void GenericInstantiator::replaceParametersWithConcrete(
+		std::vector<ast::ptr<ast::Expr>> & params ) {
+	for ( ast::ptr<ast::Expr> & param : params ) {
+		auto paramType = param.as<ast::TypeExpr>();
+		assertf( paramType, "Aggregate parameters should be type expressions." );
+		auto type = replaceWithConcrete( paramType->type, false );
+		param = ast::mutate_field( paramType, &ast::TypeExpr::type, type );
+	}
+}
+
+ast::Type const * GenericInstantiator::replaceWithConcrete(
+		ast::Type const * type, bool doClone ) {
+	if ( auto inst = dynamic_cast<ast::TypeInstType const *>( type ) ) {
+		if ( typeSubs && !inFunctionType ) {
+			ast::Type const * concType = typeSubs->lookup( inst );
+			return ast::deepCopy( ( concType ) ? concType : inst );
+		}
+	} else if ( auto inst = dynamic_cast<ast::StructInstType const *>( type ) ) {
+		auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
+		replaceParametersWithConcrete( mut->params );
+		return mut;
+	} else if ( auto inst = dynamic_cast<ast::UnionInstType const *>( type ) ) {
+		auto mut = ( doClone ) ? ast::deepCopy( inst ) : ast::mutate( inst );
+		replaceParametersWithConcrete( mut->params );
+		return mut;
+	}
+	return type;
+}
+
+void GenericInstantiator::stripDtypeParams(
+		ast::AggregateDecl * base,
+		std::vector<ast::ptr<ast::TypeDecl>> & baseParams,
+		std::vector<ast::ptr<ast::TypeExpr>> const & typeSubs ) {
+	substituteMembersHere( base->members, baseParams, typeSubs );
+
+	baseParams.clear();
+
+	dtypeStatics.insert( base );
+}
+
+} // namespace
+
+void instantiateGeneric( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<FixDtypeStatic>::run( translationUnit );
+	ast::Pass<GenericInstantiator>::run( translationUnit );
+}
+
+} // namespace GenPoly
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/GenPoly/ScrubTyVars.cc
===================================================================
--- src/GenPoly/ScrubTyVars.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/ScrubTyVars.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -9,14 +9,16 @@
 // Author           : Richard C. Bilson
 // Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Mar 16 15:44:27 2017
-// Update Count     : 3
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Aug 19 16:10:00 2022
+// Update Count     : 4
 //
 
 #include <utility>                      // for pair
 
+#include "AST/Pass.hpp"
 #include "GenPoly.h"                    // for mangleType, TyVarMap, alignof...
 #include "GenPoly/ErasableScopedMap.h"  // for ErasableScopedMap<>::const_it...
 #include "ScrubTyVars.h"
+#include "SymTab/Mangler.h"             // for mangle, typeMode
 #include "SynTree/Declaration.h"        // for TypeDecl, TypeDecl::Data, Typ...
 #include "SynTree/Expression.h"         // for Expression (ptr only), NameExpr
@@ -112,4 +114,162 @@
 		return pointer;
 	}
+
+namespace {
+
+enum class ScrubMode {
+	FromMap,
+	DynamicFromMap,
+	All,
+};
+
+struct ScrubTypeVars :
+	public ast::WithGuards,
+	public ast::WithShortCircuiting,
+	public ast::WithVisitorRef<ScrubTypeVars> {
+
+	ScrubTypeVars( ScrubMode m, TyVarMap const * tv ) :
+			mode ( m ), typeVars( tv ) {}
+
+	void previsit( ast::TypeInstType const * ) { visit_children = false; }
+	void previsit( ast::StructInstType const * ) { visit_children = false; }
+	void previsit( ast::UnionInstType const * ) { visit_children = false; }
+	void previsit( ast::SizeofExpr const * expr ) { primeBaseScrub( expr->type ); }
+	void previsit( ast::AlignofExpr const * expr ) { primeBaseScrub( expr->type ); }
+	void previsit( ast::PointerType const * type ) { primeBaseScrub( type->base ); }
+
+	ast::Type const * postvisit( ast::TypeInstType const * type );
+	ast::Type const * postvisit( ast::StructInstType const * type );
+	ast::Type const * postvisit( ast::UnionInstType const * type );
+	ast::Expr const * postvisit( ast::SizeofExpr const * expr );
+	ast::Expr const * postvisit( ast::AlignofExpr const * expr );
+	ast::Type const * postvisit( ast::PointerType const * type );
+
+private:
+	ScrubMode const mode;
+	/// Type varriables to scrub.
+	TyVarMap const * const typeVars;
+	/// Value cached by primeBaseScrub.
+	ast::Type const * dynType = nullptr;
+
+	/// Returns the type if it should be scrubbed, nullptr otherwise.
+	ast::Type const * shouldScrub( ast::Type const * type ) {
+		switch ( mode ) {
+		case ScrubMode::FromMap:
+			return isPolyType( type, *typeVars );
+		case ScrubMode::DynamicFromMap:
+			return isDynType( type, *typeVars );
+		case ScrubMode::All:
+			return isPolyType( type );
+		default:
+			assertf( false, "Invalid ScrubMode in shouldScrub." );
+			throw;
+		}
+	}
+
+	void primeBaseScrub( ast::Type const * type ) {
+		// Need to determine whether type needs to be scrubbed to
+		// determine whether automatic recursion is necessary.
+		if ( ast::Type const * t = shouldScrub( type ) ) {
+			visit_children = false;
+			GuardValue( dynType ) = t;
+		}
+	}
+
+	ast::Type const * postvisitAggregateType(
+			ast::BaseInstType const * type ) {
+		if ( !shouldScrub( type ) ) return type;
+		return new ast::PointerType( new ast::VoidType( type->qualifiers ) );
+	}
+};
+
+ast::Type const * ScrubTypeVars::postvisit( ast::TypeInstType const * type ) {
+	// This implies that mode == ScrubMode::All.
+	if ( !typeVars ) {
+		if ( ast::TypeDecl::Ftype == type->kind ) {
+			return new ast::PointerType(
+				new ast::FunctionType( ast::FixedArgs ) );
+		} else {
+			return new ast::PointerType(
+				new ast::VoidType( type->qualifiers ) );
+		}
+	}
+
+	auto typeVar = typeVars->find( type->name );
+	if ( typeVar == typeVars->end() ) {
+		return type;
+	}
+
+	switch ( typeVar->second.kind ) {
+	case ast::TypeDecl::Dtype:
+	case ast::TypeDecl::Ttype:
+		return new ast::PointerType(
+			new ast::VoidType( type->qualifiers ) );
+	case ast::TypeDecl::Ftype:
+		return new ast::PointerType(
+			new ast::FunctionType( ast::VariableArgs ) );
+	default:
+		assertf( false,
+			"Unhandled type variable kind: %d", typeVar->second.kind );
+		throw; // Just in case the assert is removed, stop here.
+	}
+}
+
+ast::Type const * ScrubTypeVars::postvisit( ast::StructInstType const * type ) {
+	return postvisitAggregateType( type );
+}
+
+ast::Type const * ScrubTypeVars::postvisit( ast::UnionInstType const * type ) {
+	return postvisitAggregateType( type );
+}
+
+ast::Expr const * ScrubTypeVars::postvisit( ast::SizeofExpr const * expr ) {
+	// sizeof( T ) becomes the _sizeof_T parameter.
+	if ( dynType ) {
+		return new ast::NameExpr( expr->location,
+			sizeofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
+	} else {
+		return expr;
+	}
+}
+
+ast::Expr const * ScrubTypeVars::postvisit( ast::AlignofExpr const * expr ) {
+	// alignof( T ) becomes the _alignof_T parameter.
+	if ( dynType ) {
+		return new ast::NameExpr( expr->location,
+			alignofName( Mangle::mangle( dynType, Mangle::typeMode() ) ) );
+	} else {
+		return expr;
+	}
+}
+
+ast::Type const * ScrubTypeVars::postvisit( ast::PointerType const * type ) {
+	if ( dynType ) {
+		ast::Type * ret = ast::mutate( dynType->accept( *visitor ) );
+		ret->qualifiers |= type->qualifiers;
+		return ret;
+	} else {
+		return type;
+	}
+}
+
+const ast::Node * scrubTypeVarsBase(
+		const ast::Node * target,
+		ScrubMode mode, const TyVarMap * typeVars ) {
+	if ( ScrubMode::All == mode ) {
+		assert( nullptr == typeVars );
+	} else {
+		assert( nullptr != typeVars );
+	}
+	ast::Pass<ScrubTypeVars> visitor( mode, typeVars );
+	return target->accept( visitor );
+}
+
+} // namespace
+
+template<>
+ast::Node const * scrubAllTypeVars<ast::Node>( const ast::Node * target ) {
+	return scrubTypeVarsBase( target, ScrubMode::All, nullptr );
+}
+
 } // namespace GenPoly
 
Index: src/GenPoly/ScrubTyVars.h
===================================================================
--- src/GenPoly/ScrubTyVars.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/ScrubTyVars.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -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 : Sat Jul 22 09:21:47 2017
-// Update Count     : 2
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Aug 19 14:14:00 2022
+// Update Count     : 3
 //
 
@@ -18,4 +18,5 @@
 #include <cassert>            // for assert
 
+#include "AST/Fwd.hpp"        // for Node
 #include "Common/PassVisitor.h"
 #include "GenPoly.h"          // for TyVarMap, isPolyType, isDynType
@@ -108,4 +109,14 @@
 	}
 
+/// For all polymorphic types, replaces generic types, with the appropriate
+/// void type, and sizeof/alignof expressions with the proper variable.
+template<typename node_t>
+node_t const * scrubAllTypeVars( node_t const * target ) {
+	return strict_dynamic_cast<node_t const *>( scrubAllTypeVars<ast::Node>( target ) );
+}
+
+template<>
+ast::Node const * scrubAllTypeVars<ast::Node>( const ast::Node * target );
+
 } // namespace GenPoly
 
Index: src/GenPoly/Specialize.h
===================================================================
--- src/GenPoly/Specialize.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/Specialize.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// Specialize.h -- 
+// Specialize.h -- Generate thunks to specialize polymorphic functions.
 //
 // Author           : Richard C. Bilson
@@ -17,7 +17,9 @@
 
 #include <list>  // for list
-#include "AST/TranslationUnit.hpp"
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace GenPoly {
Index: src/GenPoly/SpecializeNew.cpp
===================================================================
--- src/GenPoly/SpecializeNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/SpecializeNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// SpecializeNew.cpp --
+// SpecializeNew.cpp -- Generate thunks to specialize polymorphic functions.
 //
 // Author           : Andrew Beach
@@ -201,9 +201,4 @@
 			*formal, *actual, getInferredParams( expr ) );
 	}
-	//for ( auto pair : group_iterate( formal->params, mut->args ) ) {
-	//	const ast::ptr<ast::Type> & formal = std::get<0>( pair );
-	//	ast::ptr<ast::Expr> & actual = std::get<1>( pair );
-	//	*actual = doSpecialization( (*actual)->location, *formal, *actual, getInferredParams( expr ) );
-	//}
 	return mut;
 }
@@ -227,29 +222,13 @@
 }
 
-// Restructures the arguments to match the structure of the formal parameters
-// of the actual function. [begin, end) are the exploded arguments.
-template<typename Iterator, typename OutIterator>
-void structureArg( const CodeLocation & location, const ast::Type * type,
-		Iterator & begin, Iterator end, OutIterator out ) {
-	if ( auto tuple = dynamic_cast<const ast::TupleType *>( type ) ) {
-		std::vector<ast::ptr<ast::Expr>> exprs;
-		for ( const ast::Type * t : *tuple ) {
-			structureArg( location, t, begin, end, std::back_inserter( exprs ) );
-		}
-		*out++ = new ast::TupleExpr( location, std::move( exprs ) );
-	} else {
-		assertf( begin != end, "reached the end of the arguments while structuring" );
-		*out++ = *begin++;
-	}
-}
-
-#if 0
+// Restructures arguments to match the structure of the formal parameters
+// of the actual function. Returns the next structured argument.
 template<typename Iterator>
 const ast::Expr * structureArg(
 		const CodeLocation& location, const ast::ptr<ast::Type> & type,
 		Iterator & begin, const Iterator & end ) {
-	if ( auto tuple = type->as<ast::TupleType>() ) {
+	if ( auto tuple = type.as<ast::TupleType>() ) {
 		std::vector<ast::ptr<ast::Expr>> exprs;
-		for ( const ast::Type * t : *tuple ) {
+		for ( const ast::ptr<ast::Type> & t : *tuple ) {
 			exprs.push_back( structureArg( location, t, begin, end ) );
 		}
@@ -260,22 +239,20 @@
 	}
 }
-#endif
-
-namespace {
-	struct TypeInstFixer : public ast::WithShortCircuiting {
-		std::map<const ast::TypeDecl *, std::pair<int, int>> typeMap;
-
-		void previsit(const ast::TypeDecl *) { visit_children = false; }
-		const ast::TypeInstType * postvisit(const ast::TypeInstType * typeInst) {
-			if (typeMap.count(typeInst->base)) {
-				ast::TypeInstType * newInst = mutate(typeInst);
-				newInst->expr_id = typeMap[typeInst->base].first;
-				newInst->formal_usage = typeMap[typeInst->base].second;
-				return newInst;
-			}
-			return typeInst;
-		}
-	};
-}
+
+struct TypeInstFixer final : public ast::WithShortCircuiting {
+	std::map<const ast::TypeDecl *, std::pair<int, int>> typeMap;
+
+	void previsit(const ast::TypeDecl *) { visit_children = false; }
+	const ast::TypeInstType * postvisit(const ast::TypeInstType * typeInst) {
+		if (typeMap.count(typeInst->base)) {
+			ast::TypeInstType * newInst = mutate(typeInst);
+			auto const & pair = typeMap[typeInst->base];
+			newInst->expr_id = pair.first;
+			newInst->formal_usage = pair.second;
+			return newInst;
+		}
+		return typeInst;
+	}
+};
 
 const ast::Expr * SpecializeCore::createThunkFunction(
@@ -291,6 +268,4 @@
 		// Must replace only occurrences of type variables
 		// that occure free in the thunk's type.
-		//ast::TypeSubstitution::ApplyResult<ast::FunctionType>
-		//	typeSubs->applyFree( newType );
 		auto result = typeSubs->applyFree( newType );
 		newType = result.node.release();
@@ -300,21 +275,14 @@
 	using DeclVector = std::vector<ast::ptr<ast::TypeDecl>>;
 
-	//const std::string & thunkName = thunkNamer.newName();
-	//UniqueName paramNamer(thunkName + "Param");
 	UniqueName paramNamer( paramPrefix );
 
-	//auto toParamDecl = [&location, &paramNamer]( const ast::Type * type ) {
-	//	return new ast::ObjectDecl(
-	//		location, paramNamer.newName(), ast::deepCopy( type ) );
-	//};
-
 	// Create new thunk with same signature as formal type.
-
-	// std::map<const ast::TypeDecl *, std::pair<int, int>> typeMap;
 	ast::Pass<TypeInstFixer> fixer;
 	for (const auto & kv : newType->forall) {
 		if (fixer.core.typeMap.count(kv->base)) {
-			std::cerr << location << ' ' << kv->base->name << ' ' << kv->expr_id << '_' << kv->formal_usage << ',' 
-			<< fixer.core.typeMap[kv->base].first << '_' << fixer.core.typeMap[kv->base].second << std::endl;
+			std::cerr << location << ' ' << kv->base->name
+				<< ' ' << kv->expr_id << '_' << kv->formal_usage
+				<< ',' << fixer.core.typeMap[kv->base].first
+				<< '_' << fixer.core.typeMap[kv->base].second << std::endl;
 			assertf(false, "multiple formals in specialize");
 		}
@@ -322,5 +290,5 @@
 			fixer.core.typeMap[kv->base] = std::make_pair(kv->expr_id, kv->formal_usage);
 		}
-	} 
+	}
 
 	ast::CompoundStmt * thunkBody = new ast::CompoundStmt( location );
@@ -345,8 +313,5 @@
 		);
 
-	// thunkFunc->accept(fixer);
 	thunkFunc->fixUniqueId();
-
-
 
 	// Thunks may be generated and not used, avoid them.
@@ -375,8 +340,5 @@
 		// Name each thunk parameter and explode it.
 		// These are then threaded back into the actual function call.
-		//param->name = paramNamer.newName();
 		ast::DeclWithType * mutParam = ast::mutate( param.get() );
-		// - Should be renamed earlier. -
-		//mutParam->name = paramNamer.newName();
 		explodeSimple( location, new ast::VariableExpr( location, mutParam ),
 			std::back_inserter( args ) );
@@ -388,6 +350,6 @@
 		argBegin = args.begin(), argEnd = args.end();
 	for ( const auto & actualArg : actualType->params ) {
-		structureArg( location, actualArg.get(), argBegin, argEnd,
-			std::back_inserter( app->args ) );
+		app->args.push_back(
+			structureArg( location, actualArg.get(), argBegin, argEnd ) );
 	}
 	assertf( argBegin == argEnd, "Did not structure all arguments." );
@@ -469,10 +431,9 @@
 	// Create thunks for the inferred parameters.
 	// This is not needed for intrinsic calls, because they aren't
-	// actually passed
-	//
-	// need to handle explicit params before inferred params so that
-	// explicit params do not recieve a changed set of inferParams (and
-	// change them again) alternatively, if order starts to matter then
-	// copy appExpr's inferParams and pass them to handleExplicitParams.
+	// actually passed to the function. It needs to handle explicit params
+	// before inferred params so that explicit params do not recieve a
+	// changed set of inferParams (and change them again).
+	// Alternatively, if order starts to matter then copy expr's inferParams
+	// and pass them to handleExplicitParams.
 	ast::ApplicationExpr * mut = handleExplicitParams( expr );
 	if ( !mut->inferred.hasParams() ) {
@@ -500,5 +461,4 @@
 	if ( specialized != expr->arg ) {
 		// Assume that the specialization incorporates the cast.
-		std::cerr << expr <<std::endl;
 		return specialized;
 	} else {
Index: src/GenPoly/module.mk
===================================================================
--- src/GenPoly/module.mk	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/GenPoly/module.mk	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -27,4 +27,5 @@
 	GenPoly/FindFunction.cc \
 	GenPoly/FindFunction.h \
+	GenPoly/InstantiateGenericNew.cpp \
 	GenPoly/InstantiateGeneric.cc \
 	GenPoly/InstantiateGeneric.h \
Index: src/InitTweak/FixInitNew.cpp
===================================================================
--- src/InitTweak/FixInitNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/InitTweak/FixInitNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -595,5 +595,4 @@
 		if ( arg && isIntrinsicCallExpr( dtor ) ) {
 			return new ast::CommaExpr(loc, arg, new ast::VariableExpr(loc, ret ) );
-			// return;
 		}
 
@@ -654,5 +653,4 @@
 		if ( ! result->isVoid() ) {
 			static UniqueName retNamer("_tmp_cp_ret");
-			// result = result->clone();
 			auto subResult = env->apply( result ).node;
 			auto ret = new ast::ObjectDecl(loc, retNamer.newName(), subResult, nullptr );
@@ -833,6 +831,4 @@
 			}
 
-			// stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
-			// stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
 			unqMap[mutExpr->id] = mutExpr;
 		} else {
@@ -1349,5 +1345,4 @@
 		auto tmp = new ast::ObjectDecl(loc, tempNamer.newName(), callExpr->args.front()->result );
 		declsToAddBefore.push_back( tmp );
-		// delete ctorExpr;
 
 		// build assignment and replace constructor's first argument with new temporary
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/InitTweak/InitTweak.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -27,4 +27,5 @@
 #include "AST/Stmt.hpp"
 #include "AST/Type.hpp"
+#include "CodeGen/OperatorTable.h" // for isConstructor, isDestructor, isCto...
 #include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"  // for SemanticError
@@ -770,5 +771,4 @@
 			std::list< Expression * > callExprs;
 			collectCtorDtorCalls( stmt, callExprs );
-			// if ( callExprs.empty() ) return false; // xxx - do I still need this check?
 			return std::all_of( callExprs.begin(), callExprs.end(), pred);
 		}
@@ -901,5 +901,5 @@
 			} else if ( VariableExpr * varExpr = dynamic_cast< VariableExpr * >( func ) ) {
 				return varExpr->get_var()->get_name();
-			}	else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
+			} else if ( CastExpr * castExpr = dynamic_cast< CastExpr * >( func ) ) {
 				return funcName( castExpr->get_arg() );
 			} else if ( MemberExpr * memberExpr = dynamic_cast< MemberExpr * >( func ) ) {
@@ -923,5 +923,5 @@
 			} else if ( const ast::VariableExpr * varExpr = dynamic_cast< const ast::VariableExpr * >( func ) ) {
 				return varExpr->var->name;
-			}	else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( func ) ) {
+			} else if ( const ast::CastExpr * castExpr = dynamic_cast< const ast::CastExpr * >( func ) ) {
 				return funcName( castExpr->arg );
 			} else if ( const ast::MemberExpr * memberExpr = dynamic_cast< const ast::MemberExpr * >( func ) ) {
@@ -991,6 +991,5 @@
 
 	Type * isPointerType( Type * type ) {
-		if ( getPointerBase( type ) ) return type;
-		else return nullptr;
+		return getPointerBase( type ) ? type : nullptr;
 	}
 
@@ -1014,5 +1013,4 @@
 				src = new AddressExpr( src );
 			}
-			// src = new CastExpr( src, new ReferenceType( noQualifiers, src->result->stripReferences()->clone() ) );
 		}
 		return new ApplicationExpr( VariableExpr::functionPointer( assign ), { dst, src } );
@@ -1167,10 +1165,4 @@
 	}
 
-	bool isConstructor( const std::string & str ) { return str == "?{}"; }
-	bool isDestructor( const std::string & str ) { return str == "^?{}"; }
-	bool isAssignment( const std::string & str ) { return str == "?=?"; }
-	bool isCtorDtor( const std::string & str ) { return isConstructor( str ) || isDestructor( str ); }
-	bool isCtorDtorAssign( const std::string & str ) { return isCtorDtor( str ) || isAssignment( str ); }
-
 	const FunctionDecl * isCopyFunction( const Declaration * decl, const std::string & fname ) {
 		const FunctionDecl * function = dynamic_cast< const FunctionDecl * >( decl );
@@ -1192,17 +1184,17 @@
 
 bool isAssignment( const ast::FunctionDecl * decl ) {
-	return isAssignment( decl->name ) && isCopyFunction( decl );
+	return CodeGen::isAssignment( decl->name ) && isCopyFunction( decl );
 }
 
 bool isDestructor( const ast::FunctionDecl * decl ) {
-	return isDestructor( decl->name );
+	return CodeGen::isDestructor( decl->name );
 }
 
 bool isDefaultConstructor( const ast::FunctionDecl * decl ) {
-	return isConstructor( decl->name ) && 1 == decl->params.size();
+	return CodeGen::isConstructor( decl->name ) && 1 == decl->params.size();
 }
 
 bool isCopyConstructor( const ast::FunctionDecl * decl ) {
-	return isConstructor( decl->name ) && 2 == decl->params.size();
+	return CodeGen::isConstructor( decl->name ) && 2 == decl->params.size();
 }
 
@@ -1222,5 +1214,5 @@
 	}
 	const FunctionDecl * isDestructor( const Declaration * decl ) {
-		if ( isDestructor( decl->name ) ) {
+		if ( CodeGen::isDestructor( decl->name ) ) {
 			return dynamic_cast< const FunctionDecl * >( decl );
 		}
@@ -1228,5 +1220,5 @@
 	}
 	const FunctionDecl * isDefaultConstructor( const Declaration * decl ) {
-		if ( isConstructor( decl->name ) ) {
+		if ( CodeGen::isConstructor( decl->name ) ) {
 			if ( const FunctionDecl * func = dynamic_cast< const FunctionDecl * >( decl ) ) {
 				if ( func->type->parameters.size() == 1 ) {
@@ -1249,5 +1241,5 @@
 	static const char * const tlsd_section = ".tdata" ASM_COMMENT;
 	void addDataSectionAttribute( ObjectDecl * objDecl ) {
-		const bool is_tls = objDecl->get_storageClasses().is_threadlocal;
+		const bool is_tls = objDecl->get_storageClasses().is_threadlocal_any();
 		const char * section = is_tls ? tlsd_section : data_section;
 		objDecl->attributes.push_back(new Attribute("section", {
@@ -1257,5 +1249,5 @@
 
 	void addDataSectionAttribute( ast::ObjectDecl * objDecl ) {
-		const bool is_tls = objDecl->storage.is_threadlocal;
+		const bool is_tls = objDecl->storage.is_threadlocal_any();
 		const char * section = is_tls ? tlsd_section : data_section;
 		objDecl->attributes.push_back(new ast::Attribute("section", {
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Makefile.am	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -71,5 +71,5 @@
 EXTRA_DIST = include/cassert include/optional BasicTypes-gen.cc
 
-AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -Werror=return-type -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++14 $(TCMALLOCFLAG)
+AM_CXXFLAGS = @HOST_FLAGS@ -Wno-deprecated -Wall -Wextra -Werror=return-type -DDEBUG_ALL -I./Parser -I$(srcdir)/Parser -I$(srcdir)/include -DYY_NO_INPUT -O3 -g -std=c++17 $(TCMALLOCFLAG)
 AM_LDFLAGS  = @HOST_FLAGS@ -Xlinker -export-dynamic
 ARFLAGS     = cr
Index: src/Parser/DeclarationNode.cc
===================================================================
--- src/Parser/DeclarationNode.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/DeclarationNode.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 12:34:05 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 14 17:36:57 2021
-// Update Count     : 1154
+// Last Modified On : Mon Aug  8 17:07:00 2022
+// Update Count     : 1185
 //
 
@@ -128,6 +128,4 @@
 	if ( name ) {
 		os << *name << ": ";
-	} else {
-		os << "unnamed: ";
 	} // if
 
@@ -154,6 +152,9 @@
 		initializer->printOneLine( os );
 		os << " maybe constructed? " << initializer->get_maybeConstructed();
-
-	} // if
+	} // if
+
+	for ( Attribute * attr: reverseIterate( attributes ) ) {
+		os << string( indent + 2, ' ' ) << "attr " << attr->name.c_str();
+	} // for
 
 	os << endl;
@@ -243,5 +244,5 @@
 	newnode->type = new TypeData( TypeData::Aggregate );
 	newnode->type->aggregate.kind = kind;
-	newnode->type->aggregate.name =  name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
+	newnode->type->aggregate.name = name == nullptr ? new string( DeclarationNode::anonymous.newName() ) : name;
 	newnode->type->aggregate.actuals = actuals;
 	newnode->type->aggregate.fields = fields;
@@ -262,5 +263,5 @@
 	newnode->type->enumeration.typed = typed;
 	if ( base && base->type)  {
-		newnode->type->base = base->type;	
+		newnode->type->base = base->type;
 	} // if
 
@@ -504,5 +505,5 @@
 			} // for
 			// src is the new item being added and has a single bit
-		} else if ( ! src->storageClasses.is_threadlocal ) { // conflict ?
+		} else if ( ! src->storageClasses.is_threadlocal_any() ) { // conflict ?
 			appendError( error, string( "conflicting " ) + Type::StorageClassesNames[storageClasses.ffs()] +
 						 " & " + Type::StorageClassesNames[src->storageClasses.ffs()] );
@@ -518,5 +519,5 @@
 	storageClasses |= q->storageClasses;
 
-	for ( Attribute *attr: reverseIterate( q->attributes ) ) {
+	for ( Attribute * attr: reverseIterate( q->attributes ) ) {
 		attributes.push_front( attr->clone() );
 	} // for
@@ -683,4 +684,5 @@
 	} // if
 	delete o;
+
 	return this;
 }
Index: src/Parser/TypeData.cc
===================================================================
--- src/Parser/TypeData.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/TypeData.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -9,7 +9,7 @@
 // Author           : Rodolfo G. Esteves
 // Created On       : Sat May 16 15:12:51 2015
-// Last Modified By : Henry Xue
-// Last Modified On : Tue Jul 20 04:10:50 2021
-// Update Count     : 673
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue May 10 22:36:52 2022
+// Update Count     : 677
 //
 
@@ -283,12 +283,6 @@
 		if ( signedness != DeclarationNode::NoSignedness ) os << DeclarationNode::signednessNames[ signedness ] << " ";
 		if ( length != DeclarationNode::NoLength ) os << DeclarationNode::lengthNames[ length ] << " ";
-		if ( complextype == DeclarationNode::NoComplexType ) { // basic type
-			assert( basictype != DeclarationNode::NoBasicType );
-			os << DeclarationNode::basicTypeNames[ basictype ] << " ";
-		} else {										// complex type
-			// handle double _Complex
-			if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " ";
-			os << DeclarationNode::complexTypeNames[ complextype ] << " ";
-		} // if
+		if ( complextype != DeclarationNode::NoComplexType ) os << DeclarationNode::complexTypeNames[ complextype ] << " ";
+		if ( basictype != DeclarationNode::NoBasicType ) os << DeclarationNode::basicTypeNames[ basictype ] << " ";
 		break;
 	  case Pointer:
@@ -437,4 +431,5 @@
 			__attribute__((fallthrough));
 		#endif
+		// FALL THROUGH
 	  case Typeof:
 		os << "type-of expression ";
@@ -442,4 +437,7 @@
 			typeexpr->print( os, indent + 2 );
 		} // if
+		break;
+	  case Vtable:
+		os << "vtable";
 		break;
 	  case Builtin:
Index: src/Parser/TypeData.h
===================================================================
--- src/Parser/TypeData.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/TypeData.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:18:36 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 14 17:44:05 2021
-// Update Count     : 202
+// Last Modified On : Tue May 10 22:18:49 2022
+// Update Count     : 203
 //
 
@@ -27,5 +27,5 @@
 struct TypeData {
 	enum Kind { Basic, Pointer, Reference, Array, Function, Aggregate, AggregateInst, Enum, EnumConstant, Symbolic,
-				SymbolicInst, Tuple, Typeof, Basetypeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
+				SymbolicInst, Tuple, Basetypeof, Typeof, Vtable, Builtin, GlobalScope, Qualified, Unknown };
 
 	struct Aggregate_t {
Index: src/Parser/TypedefTable.cc
===================================================================
--- src/Parser/TypedefTable.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/TypedefTable.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 15:20:13 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed May 19 08:30:14 2021
-// Update Count     : 262
+// Last Modified On : Tue Feb 15 08:27:24 2022
+// Update Count     : 275
 //
 
@@ -18,4 +18,5 @@
 #include <cassert>										// for assert
 #include <iostream>
+using namespace std;
 
 #if 0
@@ -28,16 +29,16 @@
 
 debugPrint(
-static const char *kindName( int kind ) {
-	switch ( kind ) {
-	  case IDENTIFIER: return "identifier";
-	  case TYPEDIMname: return "typedim";
-	  case TYPEDEFname: return "typedef";
-	  case TYPEGENname: return "typegen";
-	  default:
-		cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
-		abort();
-	} // switch
-} // kindName
-)
+	static const char *kindName( int kind ) {
+		switch ( kind ) {
+		  case IDENTIFIER: return "identifier";
+		  case TYPEDIMname: return "typedim";
+		  case TYPEDEFname: return "typedef";
+		  case TYPEGENname: return "typegen";
+		  default:
+			cerr << "Error: cfa-cpp internal error, invalid kind of identifier" << endl;
+			abort();
+		} // switch
+	} // kindName
+);
 
 TypedefTable::~TypedefTable() {
@@ -80,5 +81,5 @@
 
 void TypedefTable::addToScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
-	auto scope = kindTable.currentScope();
+	KindTable::size_type scope = kindTable.currentScope();
 	debugPrint( cerr << "Adding current at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << endl );
 	kindTable.insertAt( scope, identifier, kind );
@@ -86,8 +87,8 @@
 
 void TypedefTable::addToEnclosingScope( const string & identifier, int kind, const char * locn __attribute__((unused)) ) {
-	auto scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level;
-//	auto scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level;
+	KindTable::size_type scope = kindTable.currentScope() - 1 - kindTable.getNote( kindTable.currentScope() - 1 ).level;
+//	size_type scope = level - kindTable.getNote( kindTable.currentScope() - 1 ).level;
 	debugPrint( cerr << "Adding enclosing at " << locn << " " << identifier << " as " << kindName( kind ) << " scope " << scope << " level " << level << " note " << kindTable.getNote( kindTable.currentScope() - 1 ).level << endl );
-	auto ret = kindTable.insertAt( scope, identifier, kind );
+	pair< KindTable::iterator, bool > ret = kindTable.insertAt( scope, identifier, kind );
 	if ( ! ret.second ) ret.first->second = kind;		// exists => update
 } // TypedefTable::addToEnclosingScope
Index: src/Parser/lex.ll
===================================================================
--- src/Parser/lex.ll	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/lex.ll	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
  * Created On       : Sat Sep 22 08:58:10 2001
  * Last Modified By : Peter A. Buhr
- * Last Modified On : Sun Jun 20 18:41:09 2021
- * Update Count     : 759
+ * Last Modified On : Tue Aug 30 18:39:54 2022
+ * Update Count     : 760
  */
 
@@ -314,5 +314,6 @@
 switch			{ KEYWORD_RETURN(SWITCH); }
 thread			{ KEYWORD_RETURN(THREAD); }				// C11
-_Thread_local	{ KEYWORD_RETURN(THREADLOCAL); }		// C11
+__thread		{ KEYWORD_RETURN(THREADLOCALGCC); }		// GCC
+_Thread_local	{ KEYWORD_RETURN(THREADLOCALC11); }		// C11
 throw			{ KEYWORD_RETURN(THROW); }				// CFA
 throwResume		{ KEYWORD_RETURN(THROWRESUME); }		// CFA
Index: src/Parser/parser.yy
===================================================================
--- src/Parser/parser.yy	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Parser/parser.yy	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  1 20:22:55 2001
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul  1 15:35:08 2022
-// Update Count     : 5405
+// Last Modified On : Sat Aug 27 13:21:28 2022
+// Update Count     : 5661
 //
 
@@ -58,5 +58,7 @@
 
 // lex uses __null in a boolean context, it's fine.
+#pragma GCC diagnostic ignored "-Wpragmas"
 #pragma GCC diagnostic ignored "-Wparentheses-equality"
+#pragma GCC diagnostic warning "-Wpragmas"
 
 extern DeclarationNode * parseTree;
@@ -197,4 +199,25 @@
 } // fieldDecl
 
+#define NEW_ZERO new ExpressionNode( build_constantInteger( *new string( "0" ) ) )
+#define NEW_ONE  new ExpressionNode( build_constantInteger( *new string( "1" ) ) )
+#define UPDOWN( compop, left, right ) (compop == OperKinds::LThan || compop == OperKinds::LEThan ? left : right)
+#define MISSING_ANON_FIELD "Missing loop fields with an anonymous loop index is meaningless as loop index is unavailable in loop body."
+#define MISSING_LOW "Missing low value for up-to range so index is uninitialized."
+#define MISSING_HIGH "Missing high value for down-to range so index is uninitialized."
+
+ForCtrl * forCtrl( DeclarationNode * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
+	if ( index->initializer ) {
+		SemanticError( yylloc, "Direct initialization disallowed. Use instead: type var; initialization ~ comparison ~ increment." );
+	} // if
+	if ( index->next ) {
+		SemanticError( yylloc, "Multiple loop indexes disallowed in for-loop declaration." );
+	} // if
+	return new ForCtrl( index->addInitializer( new InitializerNode( start ) ),
+		// NULL comp/inc => leave blank
+		comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index->name ) ) ), comp ) ) : nullptr,
+		inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
+							OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index->name ) ) ), inc ) ) : nullptr );
+} // forCtrl
+
 ForCtrl * forCtrl( ExpressionNode * type, string * index, ExpressionNode * start, enum OperKinds compop, ExpressionNode * comp, ExpressionNode * inc ) {
 	ConstantExpr * constant = dynamic_cast<ConstantExpr *>(type->expr.get());
@@ -206,7 +229,7 @@
 		distAttr( DeclarationNode::newTypeof( type, true ), DeclarationNode::newName( index )->addInitializer( new InitializerNode( start ) ) ),
 		// NULL comp/inc => leave blank
-		comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : 0,
+		comp ? new ExpressionNode( build_binary_val( compop, new ExpressionNode( build_varref( new string( *index ) ) ), comp ) ) : nullptr,
 		inc ? new ExpressionNode( build_binary_val( compop == OperKinds::LThan || compop == OperKinds::LEThan ? // choose += or -= for upto/downto
-							OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : 0 );
+							OperKinds::PlusAssn : OperKinds::MinusAssn, new ExpressionNode( build_varref( new string( *index ) ) ), inc ) ) : nullptr );
 } // forCtrl
 
@@ -272,5 +295,5 @@
 %token TYPEDEF
 %token EXTERN STATIC AUTO REGISTER
-%token THREADLOCAL										// C11
+%token THREADLOCALGCC THREADLOCALC11						// GCC, C11
 %token INLINE FORTRAN									// C99, extension ISO/IEC 9899:1999 Section J.5.9(1)
 %token NORETURN											// C11
@@ -346,5 +369,5 @@
 %type<ifctl> conditional_declaration
 %type<fctl> for_control_expression		for_control_expression_list
-%type<compop> inclexcl
+%type<compop> updown updowneq downupdowneq
 %type<en> subrange
 %type<decl> asm_name_opt
@@ -1239,8 +1262,8 @@
 iteration_statement:
 	WHILE '(' ')' statement								%prec THEN // CFA => while ( 1 )
-		{ $$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) ); }
+		{ $$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) ); }
 	| WHILE '(' ')' statement ELSE statement			// CFA
 		{
-			$$ = new StatementNode( build_while( new CondCtl( nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ), maybe_build_compound( $4 ) ) );
+			$$ = new StatementNode( build_while( new CondCtl( nullptr, NEW_ONE ), maybe_build_compound( $4 ) ) );
 			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
@@ -1250,8 +1273,8 @@
 		{ $$ = new StatementNode( build_while( $3, maybe_build_compound( $5 ), $7 ) ); }
 	| DO statement WHILE '(' ')' ';'					// CFA => do while( 1 )
-		{ $$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) ); }
+		{ $$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) ); }
 	| DO statement WHILE '(' ')' ELSE statement			// CFA
 		{
-			$$ = new StatementNode( build_do_while( new ExpressionNode( build_constantInteger( *new string( "1" ) ) ), maybe_build_compound( $2 ) ) );
+			$$ = new StatementNode( build_do_while( NEW_ONE, maybe_build_compound( $2 ) ) );
 			SemanticWarning( yylloc, Warning::SuperfluousElse, "" );
 		}
@@ -1304,53 +1327,179 @@
 		{ $$ = new ForCtrl( $1, $2, $4 ); }
 
-	| comma_expression									// CFA
-		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
-						OperKinds::LThan, $1->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| '=' comma_expression								// CFA
-		{ $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
-						OperKinds::LEThan, $2->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression inclexcl comma_expression		// CFA
-		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression inclexcl comma_expression '~' comma_expression // CFA
-		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), $1->clone(), $2, $3, $5 ); }
-	| comma_expression ';'								// CFA
-		{ $$ = forCtrl( new ExpressionNode( build_constantInteger( *new string( "0u" ) ) ), $1, nullptr, OperKinds::LThan, nullptr, nullptr ); }
+	| '@' ';' comma_expression							// CFA, empty loop-index
+		{ $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, nullptr ); }
+	| '@' ';' comma_expression ';' comma_expression		// CFA, empty loop-index
+		{ $$ = new ForCtrl( (ExpressionNode *)nullptr, $3, $5 ); }
+
+	| comma_expression									// CFA, anonymous loop-index
+		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), NEW_ZERO, OperKinds::LThan, $1->clone(), NEW_ONE ); }
+	| downupdowneq comma_expression						// CFA, anonymous loop-index
+		{ $$ = forCtrl( $2, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $1, NEW_ZERO, $2->clone() ), $1, UPDOWN( $1, $2->clone(), NEW_ZERO ), NEW_ONE ); }
+
+	| comma_expression updowneq comma_expression		// CFA, anonymous loop-index
+		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), NEW_ONE ); }
+	| '@' updowneq comma_expression						// CFA, anonymous loop-index
+		{
+			if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, NEW_ONE );
+		}
+	| comma_expression updowneq '@'						// CFA, anonymous loop-index
+		{
+			if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+			else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+		}
+	| comma_expression updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
+		{ $$ = forCtrl( $1, new string( DeclarationNode::anonymous.newName() ), UPDOWN( $2, $1->clone(), $3 ), $2, UPDOWN( $2, $3->clone(), $1->clone() ), $5 ); }
+	| '@' updowneq comma_expression '~' comma_expression // CFA, anonymous loop-index
+		{
+			if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $3, new string( DeclarationNode::anonymous.newName() ), $3->clone(), $2, nullptr, $5 );
+		}
+	| comma_expression updowneq '@' '~' comma_expression // CFA, anonymous loop-index
+		{
+			if ( $2 == OperKinds::LThan || $2 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+			else { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+		}
+	| comma_expression updowneq comma_expression '~' '@' // CFA, error
+		{ SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+	| '@' updowneq '@'									// CFA, error
+		{ SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+	| '@' updowneq comma_expression '~' '@'				// CFA, error
+		{ SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+	| comma_expression updowneq '@' '~' '@'				// CFA, error
+		{ SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+	| '@' updowneq '@' '~' '@'							// CFA, error
+		{ SemanticError( yylloc, MISSING_ANON_FIELD ); $$ = nullptr; }
+
 	| comma_expression ';' comma_expression				// CFA
-		{ $$ = forCtrl( $3, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
-						OperKinds::LThan, $3->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression ';' '=' comma_expression			// CFA
-		{ $$ = forCtrl( $4, $1, new ExpressionNode( build_constantInteger( *new string( "0" ) ) ),
-						OperKinds::LEThan, $4->clone(), new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression ';' comma_expression inclexcl comma_expression // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), $4, $5, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression ';' comma_expression inclexcl comma_expression '~' comma_expression // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), $4, $5, $7 ); }
+		{ $$ = forCtrl( $3, $1, NEW_ZERO, OperKinds::LThan, $3->clone(), NEW_ONE ); }
+	| comma_expression ';' downupdowneq comma_expression // CFA
+		{ $$ = forCtrl( $4, $1, UPDOWN( $3, NEW_ZERO, $4->clone() ), $3, UPDOWN( $3, $4->clone(), NEW_ZERO ), NEW_ONE ); }
+
+	| comma_expression ';' comma_expression updowneq comma_expression // CFA
+		{ $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), NEW_ONE ); }
+	| comma_expression ';' '@' updowneq comma_expression // CFA
+		{
+			if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, NEW_ONE );
+		}
+	| comma_expression ';' comma_expression updowneq '@' // CFA
+		{
+			if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, NEW_ONE );
+		}
+	| comma_expression ';' '@' updowneq '@'				// CFA, error
+		{ SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
+
+	| comma_expression ';' comma_expression updowneq comma_expression '~' comma_expression // CFA
+		{ $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), $7 ); }
+	| comma_expression ';' '@' updowneq comma_expression '~' comma_expression // CFA, error
+		{
+			if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, $7 );
+		}
+	| comma_expression ';' comma_expression updowneq '@' '~' comma_expression // CFA
+		{
+			if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, $7 );
+		}
+	| comma_expression ';' comma_expression updowneq comma_expression '~' '@' // CFA
+		{ $$ = forCtrl( $3, $1, UPDOWN( $4, $3->clone(), $5 ), $4, UPDOWN( $4, $5->clone(), $3->clone() ), nullptr ); }
+	| comma_expression ';' '@' updowneq comma_expression '~' '@' // CFA, error
+		{
+			if ( $4 == OperKinds::LThan || $4 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $5, $1, $5->clone(), $4, nullptr, nullptr );
+		}
+	| comma_expression ';' comma_expression updowneq '@' '~' '@' // CFA
+		{
+			if ( $4 == OperKinds::GThan || $4 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $4 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $3, $1, $3->clone(), $4, nullptr, nullptr );
+		}
+	| comma_expression ';' '@' updowneq '@' '~' '@' // CFA
+		{ SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
+
+	| declaration comma_expression						// CFA
+		{ $$ = forCtrl( $1, NEW_ZERO, OperKinds::LThan, $2, NEW_ONE ); }
+	| declaration downupdowneq comma_expression			// CFA
+		{ $$ = forCtrl( $1, UPDOWN( $2, NEW_ZERO, $3 ), $2, UPDOWN( $2, $3->clone(), NEW_ZERO ), NEW_ONE ); }
+
+	| declaration comma_expression updowneq comma_expression // CFA
+		{ $$ = forCtrl( $1, UPDOWN( $3, $2->clone(), $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), NEW_ONE ); }
+	| declaration '@' updowneq comma_expression			// CFA
+		{
+			if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $4, $3, nullptr, NEW_ONE );
+		}
+	| declaration comma_expression updowneq '@'			// CFA
+		{
+			if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $2, $3, nullptr, NEW_ONE );
+		}
+
+	| declaration comma_expression updowneq comma_expression '~' comma_expression // CFA
+		{ $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), $6 ); }
+	| declaration '@' updowneq comma_expression '~' comma_expression // CFA
+		{
+			if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $4, $3, nullptr, $6 );
+		}
+	| declaration comma_expression updowneq '@' '~' comma_expression // CFA
+		{
+			if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $2, $3, nullptr, $6 );
+		}
+	| declaration comma_expression updowneq comma_expression '~' '@' // CFA
+		{ $$ = forCtrl( $1, UPDOWN( $3, $2, $4 ), $3, UPDOWN( $3, $4->clone(), $2->clone() ), nullptr ); }
+	| declaration '@' updowneq comma_expression '~' '@' // CFA
+		{
+			if ( $3 == OperKinds::LThan || $3 == OperKinds::LEThan ) { SemanticError( yylloc, MISSING_LOW ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $4, $3, nullptr, nullptr );
+		}
+	| declaration comma_expression updowneq '@' '~' '@'	// CFA
+		{
+			if ( $3 == OperKinds::GThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, MISSING_HIGH ); $$ = nullptr; }
+			else if ( $3 == OperKinds::LEThan ) { SemanticError( yylloc, "Equality with missing high value is meaningless. Use \"~\"." ); $$ = nullptr; }
+			else $$ = forCtrl( $1, $2, $3, nullptr, nullptr );
+		}
+	| declaration '@' updowneq '@' '~' '@'				// CFA, error
+		{ SemanticError( yylloc, "Missing low/high value for up/down-to range so index is uninitialized." ); $$ = nullptr; }
 
 	| comma_expression ';' TYPEDEFname					// CFA, array type
 		{
-			SemanticError( yylloc, "Array interator is currently unimplemented." ); $$ = nullptr;
-			$$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr );
-		}
-
-		// There is a S/R conflicit if ~ and -~ are factored out.
-	| comma_expression ';' comma_expression '~' '@'		// CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression ';' comma_expression ErangeDown '@' // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, new ExpressionNode( build_constantInteger( *new string( "1" ) ) ) ); }
-	| comma_expression ';' comma_expression '~' '@' '~' comma_expression // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, $7 ); }
-	| comma_expression ';' comma_expression ErangeDown '@' '~' comma_expression // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), OperKinds::GThan, nullptr, $7 ); }
-	| comma_expression ';' comma_expression '~' '@' '~' '@' // CFA
-		{ $$ = forCtrl( $3, $1, $3->clone(), OperKinds::LThan, nullptr, nullptr ); }
+			SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
+			//$$ = forCtrl( new ExpressionNode( build_varref( $3 ) ), $1, nullptr, OperKinds::Range, nullptr, nullptr );
+		}
+	| comma_expression ';' downupdowneq TYPEDEFname		// CFA, array type
+		{
+			if ( $3 == OperKinds::LEThan || $3 == OperKinds::GEThan ) { SemanticError( yylloc, "All enumation ranges are equal (all values). Remove \"=~\"." ); $$ = nullptr; }
+			SemanticError( yylloc, "Type iterator is currently unimplemented." ); $$ = nullptr;
+		}
  	;
 
-inclexcl:
+downupdowneq:
+	ErangeDown
+		{ $$ = OperKinds::GThan; }
+	| ErangeUpEq
+		{ $$ = OperKinds::LEThan; }
+	| ErangeDownEq
+		{ $$ = OperKinds::GEThan; }
+ 	;
+
+updown:
 	'~'
 		{ $$ = OperKinds::LThan; }
+	| ErangeDown
+		{ $$ = OperKinds::GThan; }
+ 	;
+
+updowneq:
+	updown
 	| ErangeUpEq
 		{ $$ = OperKinds::LEThan; }
-	| ErangeDown
-		{ $$ = OperKinds::GThan; }
 	| ErangeDownEq
 		{ $$ = OperKinds::GEThan; }
@@ -1935,6 +2084,8 @@
 	| REGISTER
 		{ $$ = DeclarationNode::newStorageClass( Type::Register ); }
-	| THREADLOCAL										// C11
-		{ $$ = DeclarationNode::newStorageClass( Type::Threadlocal ); }
+	| THREADLOCALGCC										// GCC
+		{ $$ = DeclarationNode::newStorageClass( Type::ThreadlocalGcc ); }
+	| THREADLOCALC11										// C11
+		{ $$ = DeclarationNode::newStorageClass( Type::ThreadlocalC11 ); }
 		// Put function specifiers here to simplify parsing rules, but separate them semantically.
 	| INLINE											// C99
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -269,6 +269,6 @@
 			unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
 			unsigned nextExpl = 0, unsigned explAlt = 0 )
-		: parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
-		  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
+		: parent(parent), expr( expr ), cost( cost ), env( std::move( env ) ), need( std::move( need ) ),
+		  have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
 		  nextExpl( nextExpl ), explAlt( explAlt ) {}
 
@@ -276,6 +276,6 @@
 			const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
 			ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
-		: parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
-		  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
+		: parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( std::move( env ) ),
+		  need( std::move( need ) ), have( std::move( have ) ), open( std::move( open ) ), nextArg( nextArg ),
 		  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
 
@@ -301,5 +301,5 @@
 			// reset pack to appropriate tuple
 			std::vector< ast::ptr< ast::Expr > > exprv( exprs.begin(), exprs.end() );
-			expr = new ast::TupleExpr{ expr->location, move( exprv ) };
+			expr = new ast::TupleExpr{ expr->location, std::move( exprv ) };
 			tupleStart = pack->tupleStart - 1;
 			parent = pack->parent;
@@ -404,5 +404,5 @@
 								newResult.open, symtab )
 						) {
-							finalResults.emplace_back( move( newResult ) );
+							finalResults.emplace_back( std::move( newResult ) );
 						}
 
@@ -423,6 +423,6 @@
 						if ( expl.exprs.empty() ) {
 							results.emplace_back(
-								results[i], move( env ), copy( results[i].need ),
-								copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
+								results[i], std::move( env ), copy( results[i].need ),
+								copy( results[i].have ), std::move( open ), nextArg + 1, expl.cost );
 
 							continue;
@@ -431,6 +431,6 @@
 						// add new result
 						results.emplace_back(
-							i, expl.exprs.front(), move( env ), copy( results[i].need ),
-							copy( results[i].have ), move( open ), nextArg + 1, nTuples,
+							i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
+							copy( results[i].have ), std::move( open ), nextArg + 1, nTuples,
 							expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 					}
@@ -444,5 +444,5 @@
 			// splice final results onto results
 			for ( std::size_t i = 0; i < finalResults.size(); ++i ) {
-				results.emplace_back( move( finalResults[i] ) );
+				results.emplace_back( std::move( finalResults[i] ) );
 			}
 			return ! finalResults.empty();
@@ -478,5 +478,5 @@
 
 					results.emplace_back(
-						i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
+						i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ), nextArg,
 						nTuples, Cost::zero, nextExpl, results[i].explAlt );
 				}
@@ -494,6 +494,6 @@
 					if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
 						results.emplace_back(
-							i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
-							move( need ), move( have ), move( open ), nextArg, nTuples );
+							i, new ast::DefaultArgExpr{ cnst->location, cnst }, std::move( env ),
+							std::move( need ), std::move( have ), std::move( open ), nextArg, nTuples );
 					}
 				}
@@ -516,5 +516,5 @@
 				if ( expl.exprs.empty() ) {
 					results.emplace_back(
-						results[i], move( env ), move( need ), move( have ), move( open ),
+						results[i], std::move( env ), std::move( need ), std::move( have ), std::move( open ),
 						nextArg + 1, expl.cost );
 
@@ -538,5 +538,5 @@
 					// add new result
 					results.emplace_back(
-						i, expr, move( env ), move( need ), move( have ), move( open ),
+						i, expr, std::move( env ), std::move( need ), std::move( have ), std::move( open ),
 						nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 				}
@@ -576,5 +576,5 @@
 					restructureCast( idx, toType->getComponent( i ), isGenerated ) );
 			}
-			return new ast::TupleExpr{ arg->location, move( components ) };
+			return new ast::TupleExpr{ arg->location, std::move( components ) };
 		} else {
 			// handle normally
@@ -672,5 +672,5 @@
 			}
 			std::vector< ast::ptr< ast::Expr > > vargs( args.begin(), args.end() );
-			appExpr->args = move( vargs );
+			appExpr->args = std::move( vargs );
 			// build and validate new candidate
 			auto newCand =
@@ -783,6 +783,6 @@
 							if ( expl.exprs.empty() ) {
 								results.emplace_back(
-									results[i], move( env ), copy( results[i].need ),
-									copy( results[i].have ), move( open ), nextArg + 1,
+									results[i], std::move( env ), copy( results[i].need ),
+									copy( results[i].have ), std::move( open ), nextArg + 1,
 									expl.cost );
 
@@ -792,6 +792,6 @@
 							// add new result
 							results.emplace_back(
-								i, expl.exprs.front(), move( env ), copy( results[i].need ),
-								copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
+								i, expl.exprs.front(), std::move( env ), copy( results[i].need ),
+								copy( results[i].have ), std::move( open ), nextArg + 1, 0, expl.cost,
 								expl.exprs.size() == 1 ? 0 : 1, j );
 						}
@@ -843,5 +843,5 @@
 				// as a member expression
 				addAnonConversions( newCand );
-				candidates.emplace_back( move( newCand ) );
+				candidates.emplace_back( std::move( newCand ) );
 			}
 		}
@@ -991,5 +991,5 @@
 					funcE.emplace_back( *func, symtab );
 				}
-				argExpansions.emplace_front( move( funcE ) );
+				argExpansions.emplace_front( std::move( funcE ) );
 
 				for ( const CandidateRef & op : opFinder ) {
@@ -1035,8 +1035,8 @@
 				if ( cvtCost != Cost::infinity ) {
 					withFunc->cvtCost = cvtCost;
-					candidates.emplace_back( move( withFunc ) );
-				}
-			}
-			found = move( candidates );
+					candidates.emplace_back( std::move( withFunc ) );
+				}
+			}
+			found = std::move( candidates );
 
 			// use a new list so that candidates are not examined by addAnonConversions twice
@@ -1136,5 +1136,5 @@
 					CandidateRef newCand = std::make_shared<Candidate>(
 						restructureCast( cand->expr, toType, castExpr->isGenerated ),
-						copy( cand->env ), move( open ), move( need ), cand->cost,
+						copy( cand->env ), std::move( open ), std::move( need ), cand->cost,
 						cand->cost + thisCost );
 					inferParameters( newCand, matches );
@@ -1290,5 +1290,5 @@
 				// as a name expression
 				addAnonConversions( newCand );
-				candidates.emplace_back( move( newCand ) );
+				candidates.emplace_back( std::move( newCand ) );
 			}
 		}
@@ -1399,5 +1399,5 @@
 						new ast::LogicalExpr{
 							logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
-						move( env ), move( open ), move( need ), r1->cost + r2->cost );
+						std::move( env ), std::move( open ), std::move( need ), r1->cost + r2->cost );
 				}
 			}
@@ -1457,5 +1457,5 @@
 							// output candidate
 							CandidateRef newCand = std::make_shared<Candidate>(
-								newExpr, move( env ), move( open ), move( need ), cost );
+								newExpr, std::move( env ), std::move( open ), std::move( need ), cost );
 							inferParameters( newCand, candidates );
 						}
@@ -1524,5 +1524,5 @@
 						// add candidate
 						CandidateRef newCand = std::make_shared<Candidate>(
-							newExpr, move( env ), move( open ), move( need ),
+							newExpr, std::move( env ), std::move( open ), std::move( need ),
 							r1->cost + r2->cost );
 						inferParameters( newCand, candidates );
@@ -1553,6 +1553,6 @@
 
 				addCandidate(
-					new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
-					move( env ), move( open ), move( need ), sumCost( subs ) );
+					new ast::TupleExpr{ tupleExpr->location, std::move( exprs ) },
+					std::move( env ), std::move( open ), std::move( need ), sumCost( subs ) );
 			}
 		}
@@ -1640,5 +1640,5 @@
 								initExpr->location, restructureCast( cand->expr, toType ),
 								initAlt.designation },
-							move(env), move( open ), move( need ), cand->cost, thisCost );
+							std::move(env), std::move( open ), std::move( need ), cand->cost, thisCost );
 						inferParameters( newCand, matches );
 					}
@@ -1773,5 +1773,5 @@
 		cand->env.applyFree( newResult );
 		cand->expr = ast::mutate_field(
-			cand->expr.get(), &ast::Expr::result, move( newResult ) );
+			cand->expr.get(), &ast::Expr::result, std::move( newResult ) );
 
 		out.emplace_back( cand );
@@ -1859,5 +1859,5 @@
 
 		auto oldsize = candidates.size();
-		candidates = move( pruned );
+		candidates = std::move( pruned );
 
 		PRINT(
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/ResolvExpr/Resolver.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -1542,5 +1542,4 @@
 	}
 
-
 	const ast::StaticAssertDecl * Resolver_new::previsit(
 		const ast::StaticAssertDecl * assertDecl
@@ -1554,11 +1553,9 @@
 	const PtrType * handlePtrType( const PtrType * type, const ResolveContext & context ) {
 		if ( type->dimension ) {
-			ast::ptr< ast::Type > sizeType = context.global.sizeType;
+			const ast::Type * sizeType = context.global.sizeType.get();
 			ast::ptr< ast::Expr > dimension = findSingleExpression( type->dimension, sizeType, context );
 			assertf(dimension->env->empty(), "array dimension expr has nonempty env");
 			dimension.get_and_mutate()->env = nullptr;
-			ast::mutate_field(
-				type, &PtrType::dimension,
-				dimension);
+			ast::mutate_field( type, &PtrType::dimension, dimension );
 		}
 		return type;
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/SymTab/Autogen.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -258,10 +258,10 @@
 	}
 
-	/// 
+	/// Given type T, generate type of default ctor/dtor, i.e. function type void (*) (T &).
 	ast::FunctionDecl * genDefaultFunc(const CodeLocation loc, const std::string fname, const ast::Type * paramType, bool maybePolymorphic) {
 		std::vector<ast::ptr<ast::TypeDecl>> typeParams;
 		if (maybePolymorphic) typeParams = getGenericParams(paramType);
 		auto dstParam = new ast::ObjectDecl(loc, "_dst", new ast::ReferenceType(paramType), nullptr, {}, ast::Linkage::Cforall);
-		return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc));
+		return new ast::FunctionDecl(loc, fname, std::move(typeParams), {dstParam}, {}, new ast::CompoundStmt(loc), {}, ast::Linkage::Cforall);
 	}
 
Index: src/SynTree/Statement.cc
===================================================================
--- src/SynTree/Statement.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/SynTree/Statement.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -105,5 +105,5 @@
 };
 
-BranchStmt::BranchStmt( Label target, Type type ) throw ( SemanticErrorException ) :
+BranchStmt::BranchStmt( Label target, Type type ) :
 	Statement(), originalTarget( target ), target( target ), computedTarget( nullptr ), type( type ) {
 	//actually this is a syntactic error signaled by the parser
@@ -113,5 +113,5 @@
 }
 
-BranchStmt::BranchStmt( Expression * computedTarget, Type type ) throw ( SemanticErrorException ) :
+BranchStmt::BranchStmt( Expression * computedTarget, Type type ) :
 	Statement(), computedTarget( computedTarget ), type( type ) {
 	if ( type != BranchStmt::Goto || computedTarget == nullptr ) {
@@ -211,5 +211,5 @@
 }
 
-CaseStmt::CaseStmt( Expression * condition, const list<Statement *> & statements, bool deflt ) throw ( SemanticErrorException ) :
+CaseStmt::CaseStmt( Expression * condition, const list<Statement *> & statements, bool deflt ) :
 		Statement(), condition( condition ), stmts( statements ), _isDefault( deflt ) {
 	if ( isDefault() && condition != nullptr ) SemanticError( condition, "default case with condition: " );
@@ -575,5 +575,5 @@
 }
 
-MutexStmt::MutexStmt( Statement * stmt, const list<Expression *> mutexObjs ) 
+MutexStmt::MutexStmt( Statement * stmt, const list<Expression *> mutexObjs )
 	: Statement(), stmt( stmt ), mutexObjs( mutexObjs ) { }
 
Index: src/SynTree/Statement.h
===================================================================
--- src/SynTree/Statement.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/SynTree/Statement.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -200,5 +200,5 @@
 	std::list<Statement *> stmts;
 
-	CaseStmt( Expression * conditions, const std::list<Statement *> & stmts, bool isdef = false ) throw (SemanticErrorException);
+	CaseStmt( Expression * conditions, const std::list<Statement *> & stmts, bool isdef = false );
 	CaseStmt( const CaseStmt & other );
 	virtual ~CaseStmt();
@@ -289,6 +289,6 @@
 	Type type;
 
-	BranchStmt( Label target, Type ) throw (SemanticErrorException);
-	BranchStmt( Expression * computedTarget, Type ) throw (SemanticErrorException);
+	BranchStmt( Label target, Type );
+	BranchStmt( Expression * computedTarget, Type );
 
 	Label get_originalTarget() { return originalTarget; }
Index: src/SynTree/Type.cc
===================================================================
--- src/SynTree/Type.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/SynTree/Type.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -80,5 +80,5 @@
 // These must remain in the same order as the corresponding bit fields.
 const char * Type::FuncSpecifiersNames[] = { "inline", "_Noreturn", "fortran" };
-const char * Type::StorageClassesNames[] = { "extern", "static", "auto", "register", "_Thread_local" };
+const char * Type::StorageClassesNames[] = { "extern", "static", "auto", "register", "__thread", "_Thread_local" };
 const char * Type::QualifiersNames[] = { "const", "restrict", "volatile", "mutex", "_Atomic" };
 
Index: src/SynTree/Type.h
===================================================================
--- src/SynTree/Type.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/SynTree/Type.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -84,5 +84,5 @@
 	}; // FuncSpecifiers
 
-	enum { Extern = 1 << 0, Static = 1 << 1, Auto = 1 << 2, Register = 1 << 3, Threadlocal = 1 << 4, NumStorageClass = 5 };
+	enum { Extern = 1 << 0, Static = 1 << 1, Auto = 1 << 2, Register = 1 << 3, ThreadlocalGcc = 1 << 4, ThreadlocalC11 = 1 << 5, NumStorageClass = 6 };
 	static const char * StorageClassesNames[];
 	union StorageClasses {
@@ -93,5 +93,6 @@
 			bool is_auto : 1;
 			bool is_register : 1;
-			bool is_threadlocal : 1;
+			bool is_threadlocalGcc : 1;
+			bool is_threadlocalC11 : 1;
 		};
 
@@ -100,4 +101,6 @@
 		// equality (==, !=) works implicitly on first field "val", relational operations are undefined.
 		BFCommon( StorageClasses, NumStorageClass )
+
+		bool is_threadlocal_any() { return this->is_threadlocalC11 || this->is_threadlocalGcc; }
 	}; // StorageClasses
 
Index: src/Tuples/TupleExpansionNew.cpp
===================================================================
--- src/Tuples/TupleExpansionNew.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Tuples/TupleExpansionNew.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -9,21 +9,256 @@
 // Author           : Henry Xue
 // Created On       : Mon Aug 23 15:36:09 2021
-// Last Modified By : Henry Xue
-// Last Modified On : Mon Aug 23 15:36:09 2021
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Aug 15 17:00:00 2022
+// Update Count     : 3
 //
 
 #include "Tuples.h"
 
+#include "AST/Pass.hpp"
+#include "Common/ScopedMap.h"
+
 namespace Tuples {
+
 namespace {
-	struct MemberTupleExpander final : public ast::WithShortCircuiting, public ast::WithVisitorRef< MemberTupleExpander > {
-		void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; }
-        const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr );
-	};
-	struct UniqueExprExpander final : public ast::WithDeclsToAdd<> {
-		const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr );
-		std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order
-	};
+
+struct MemberTupleExpander final : public ast::WithShortCircuiting, public ast::WithVisitorRef< MemberTupleExpander > {
+	void previsit( const ast::UntypedMemberExpr * ) { visit_children = false; }
+	const ast::Expr * postvisit( const ast::UntypedMemberExpr * memberExpr );
+};
+
+struct UniqueExprExpander final : public ast::WithDeclsToAdd<> {
+	const ast::Expr * postvisit( const ast::UniqueExpr * unqExpr );
+	std::map< int, ast::ptr<ast::Expr> > decls; // not vector, because order added may not be increasing order
+};
+
+/// given a expression representing the member and an expression representing the aggregate,
+/// reconstructs a flattened UntypedMemberExpr with the right precedence
+const ast::Expr * reconstructMemberExpr( const ast::Expr * member, const ast::Expr * aggr, const CodeLocation & loc ) {
+	if ( auto memberExpr = dynamic_cast< const ast::UntypedMemberExpr * >( member ) ) {
+		// construct a new UntypedMemberExpr with the correct structure , and recursively
+		// expand that member expression.
+		ast::Pass< MemberTupleExpander > expander;
+		auto inner = new ast::UntypedMemberExpr( loc, memberExpr->aggregate, aggr );
+		auto newMemberExpr = new ast::UntypedMemberExpr( loc, memberExpr->member, inner );
+		return newMemberExpr->accept( expander );
+	} else {
+		// not a member expression, so there is nothing to do but attach and return
+		return new ast::UntypedMemberExpr( loc, member, aggr );
+	}
+}
+
+const ast::Expr * MemberTupleExpander::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
+	const CodeLocation loc = memberExpr->location;
+	if ( auto tupleExpr = memberExpr->member.as< ast::UntypedTupleExpr >() ) {
+		auto mutExpr = mutate( tupleExpr );
+		ast::ptr< ast::Expr > aggr = memberExpr->aggregate->accept( *visitor );
+		// aggregate expressions which might be impure must be wrapped in unique expressions
+		if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new ast::UniqueExpr( loc, aggr );
+		for ( auto & expr : mutExpr->exprs ) {
+			expr = reconstructMemberExpr( expr, aggr, loc );
+		}
+		return mutExpr;
+	} else {
+		// there may be a tuple expr buried in the aggregate
+		return new ast::UntypedMemberExpr( loc, memberExpr->member, memberExpr->aggregate->accept( *visitor ) );
+	}
+}
+
+const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) {
+	const CodeLocation loc = unqExpr->location;
+	const int id = unqExpr->id;
+
+	// on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
+	// and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
+	if ( ! decls.count( id ) ) {
+		ast::ptr< ast::Expr > assignUnq;
+		const ast::VariableExpr * var = unqExpr->var;
+		if ( unqExpr->object ) {
+			// an object was generated to represent this unique expression -- it should be added to the list of declarations now
+			declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() );
+			// deep copy required due to unresolved issues with UniqueExpr
+			assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr );
+		} else {
+			const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >();
+			assignUnq = commaExpr->arg1;
+		}
+		auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ),
+			new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall );
+		declsToAddBefore.push_back( finished );
+		// (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
+		// This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
+		auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ),
+			ast::ConstantExpr::from_int( loc, 1 ) );
+		auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var,
+			new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) );
+		condExpr->result = var->result;
+		condExpr->env = unqExpr->env;
+		decls[id] = condExpr;
+	}
+	return ast::deepCopy(decls[id].get());
+}
+
+/// Replaces Tuple Assign & Index Expressions, and Tuple Types.
+struct TupleMainExpander final :
+		public ast::WithGuards,
+		public ast::WithVisitorRef<TupleMainExpander>,
+		public ast::WithDeclsToAdd<> {
+	ast::Expr const * postvisit( ast::TupleAssignExpr const * expr ) {
+		// Just move the env on the new top level expression.
+		return ast::mutate_field( expr->stmtExpr.get(),
+			&ast::TupleAssignExpr::env, expr->env.get() );
+	}
+
+	void previsit( ast::ParseNode const * node ) {
+		GuardValue( location ) = &node->location;
+	}
+
+	void previsit( ast::CompoundStmt const * stmt ) {
+		previsit( (ast::ParseNode const *)stmt );
+		GuardScope( typeMap );
+	}
+
+	ast::Expr const * postvisit( ast::Expr const * expr ) {
+		if ( nullptr == expr->env ) {
+			return expr;
+		}
+		// TypeSubstitutions are never visited in the new Pass template,
+		// so it is done manually here, where all types have to be replaced.
+		return ast::mutate_field( expr, &ast::Expr::env,
+			expr->env->accept( *visitor ) );
+	}
+
+	ast::Type const * postvisit( ast::TupleType const * type ) {
+		assert( location );
+		unsigned tupleSize = type->size();
+		if ( !typeMap.count( tupleSize ) ) {
+			ast::StructDecl * decl = new ast::StructDecl( *location,
+				toString( "_tuple", tupleSize, "_" )
+			);
+			decl->body = true;
+
+			for ( size_t i = 0 ; i < tupleSize ; ++i ) {
+				ast::TypeDecl * typeParam = new ast::TypeDecl( *location,
+					toString( "tuple_param_", tupleSize, "_", i ),
+					ast::Storage::Classes(),
+					nullptr,
+					ast::TypeDecl::Dtype,
+					true
+					);
+				ast::ObjectDecl * member = new ast::ObjectDecl( *location,
+					toString( "field_", i ),
+					new ast::TypeInstType( typeParam )
+					);
+				decl->params.push_back( typeParam );
+				decl->members.push_back( member );
+			}
+
+			// Empty structures are not standard C. Add a dummy field to
+			// empty tuples to silence warnings when a compound literal
+			// `_tuple0_` is created.
+			if ( tupleSize == 0 ) {
+				decl->members.push_back(
+					new ast::ObjectDecl( *location,
+						"dummy",
+						new ast::BasicType( ast::BasicType::SignedInt ),
+						nullptr,
+						ast::Storage::Classes(),
+						// Does this have to be a C linkage?
+						ast::Linkage::C
+					)
+				);
+			}
+			typeMap[tupleSize] = decl;
+			declsToAddBefore.push_back( decl );
+		}
+
+		ast::StructDecl const * decl = typeMap[ tupleSize ];
+		ast::StructInstType * newType =
+			new ast::StructInstType( decl, type->qualifiers );
+		for ( auto pair : group_iterate( type->types, decl->params ) ) {
+			ast::Type const * t = std::get<0>( pair );
+			newType->params.push_back(
+				new ast::TypeExpr( *location, ast::deepCopy( t ) ) );
+		}
+		return newType;
+	}
+
+	ast::Expr const * postvisit( ast::TupleIndexExpr const * expr ) {
+		CodeLocation const & location = expr->location;
+		ast::Expr const * tuple = expr->tuple.get();
+		assert( tuple );
+		unsigned int index = expr->index;
+		ast::TypeSubstitution const * env = expr->env.get();
+
+		if ( auto tupleExpr = dynamic_cast<ast::TupleExpr const *>( tuple ) ) {
+			// Optimization: If it is a definitely pure tuple expr,
+			// then it can reduce to the only relevant component.
+			if ( !maybeImpureIgnoreUnique( tupleExpr ) ) {
+				assert( index < tupleExpr->exprs.size() );
+				ast::ptr<ast::Expr> const & expr =
+					*std::next( tupleExpr->exprs.begin(), index );
+				ast::Expr * ret = ast::mutate( expr.get() );
+				ret->env = env;
+				return ret;
+			}
+		}
+
+		auto type = tuple->result.strict_as<ast::StructInstType>();
+		ast::StructDecl const * structDecl = type->base;
+		assert( index < structDecl->members.size() );
+		ast::ptr<ast::Decl> const & member =
+			*std::next( structDecl->members.begin(), index );
+		ast::MemberExpr * memberExpr = new ast::MemberExpr( location,
+			member.strict_as<ast::DeclWithType>(), tuple );
+		memberExpr->env = env;
+		return memberExpr;
+	}
+private:
+	ScopedMap< int, ast::StructDecl const * > typeMap;
+	CodeLocation const * location = nullptr;
+};
+
+ast::Expr const * replaceTupleExpr(
+		CodeLocation const & location,
+		ast::Type const * result,
+		std::vector<ast::ptr<ast::Expr>> const & exprs,
+		ast::TypeSubstitution const * env ) {
+	assert( result );
+	// A void result: It doesn't need to produce a value for cascading,
+	// just output a chain of comma exprs.
+	if ( result->isVoid() ) {
+		assert( !exprs.empty() );
+		std::vector<ast::ptr<ast::Expr>>::const_iterator iter = exprs.begin();
+		ast::Expr * expr = new ast::CastExpr( *iter++ );
+		for ( ; iter != exprs.end() ; ++iter ) {
+			expr = new ast::CommaExpr( location,
+				expr, new ast::CastExpr( *iter ) );
+		}
+		expr->env = env;
+		return expr;
+	// Typed tuple expression: Produce a compound literal which performs
+	// each of the expressions as a distinct part of its initializer. The
+	// produced compound literal may be used as part of another expression.
+	} else {
+		auto inits = map_range<std::vector<ast::ptr<ast::Init>>>( exprs,
+			[]( ast::Expr const * expr ) {
+				return new ast::SingleInit( expr->location, expr );
+			}
+		);
+		ast::Expr * expr = new ast::CompoundLiteralExpr( location,
+			result, new ast::ListInit( location, std::move( inits ) ) );
+		expr->env = env;
+		return expr;
+	}
+}
+
+struct TupleExprExpander final {
+	ast::Expr const * postvisit( ast::TupleExpr const * expr ) {
+		return replaceTupleExpr( expr->location,
+			expr->result, expr->exprs, expr->env );
+	}
+};
+
 } // namespace
 
@@ -32,82 +267,13 @@
 }
 
-namespace {
-	namespace {
-		/// given a expression representing the member and an expression representing the aggregate,
-		/// reconstructs a flattened UntypedMemberExpr with the right precedence
-		const ast::Expr * reconstructMemberExpr( const ast::Expr * member, const ast::Expr * aggr, const CodeLocation & loc ) {
-			if ( auto memberExpr = dynamic_cast< const ast::UntypedMemberExpr * >( member ) ) {
-				// construct a new UntypedMemberExpr with the correct structure , and recursively
-				// expand that member expression.
-				ast::Pass< MemberTupleExpander > expander;
-				auto inner = new ast::UntypedMemberExpr( loc, memberExpr->aggregate, aggr );
-				auto newMemberExpr = new ast::UntypedMemberExpr( loc, memberExpr->member, inner );
-				//delete memberExpr;
-				return newMemberExpr->accept( expander );
-			} else {
-				// not a member expression, so there is nothing to do but attach and return
-				return new ast::UntypedMemberExpr( loc, member, aggr );
-			}
-		}
-	}
-
-	const ast::Expr * MemberTupleExpander::postvisit( const ast::UntypedMemberExpr * memberExpr ) {
-		const CodeLocation loc = memberExpr->location;
-        if ( auto tupleExpr = memberExpr->member.as< ast::UntypedTupleExpr >() ) {
-			auto mutExpr = mutate( tupleExpr );
-			ast::ptr< ast::Expr > aggr = memberExpr->aggregate->accept( *visitor );
-			// aggregate expressions which might be impure must be wrapped in unique expressions
-			if ( Tuples::maybeImpureIgnoreUnique( memberExpr->aggregate ) ) aggr = new ast::UniqueExpr( loc, aggr );
-			for ( auto & expr : mutExpr->exprs ) {
-				expr = reconstructMemberExpr( expr, aggr, loc );
-			}
-			//delete aggr;
-			return mutExpr;
-		} else {
-			// there may be a tuple expr buried in the aggregate
-			return new ast::UntypedMemberExpr( loc, memberExpr->member, memberExpr->aggregate->accept( *visitor ) );
-		}
-	}
-} // namespace
-
 void expandUniqueExpr( ast::TranslationUnit & translationUnit ) {
 	ast::Pass< UniqueExprExpander >::run( translationUnit );
 }
 
-namespace {
-	const ast::Expr * UniqueExprExpander::postvisit( const ast::UniqueExpr * unqExpr ) {
-		const CodeLocation loc = unqExpr->location;
-		const int id = unqExpr->id;
-
-		// on first time visiting a unique expr with a particular ID, generate the expression that replaces all UniqueExprs with that ID,
-		// and lookup on subsequent hits. This ensures that all unique exprs with the same ID reference the same variable.
-		if ( ! decls.count( id ) ) {
-			ast::ptr< ast::Expr > assignUnq;
-			const ast::VariableExpr * var = unqExpr->var;
-			if ( unqExpr->object ) {
-				// an object was generated to represent this unique expression -- it should be added to the list of declarations now
-				declsToAddBefore.push_back( unqExpr->object.as< ast::Decl >() );
-				// deep copy required due to unresolved issues with UniqueExpr
-				assignUnq = ast::UntypedExpr::createAssign( loc, var, unqExpr->expr );
-			} else {
-				const auto commaExpr = unqExpr->expr.strict_as< ast::CommaExpr >();
-				assignUnq = commaExpr->arg1;
-			}
-			auto finished = new ast::ObjectDecl( loc, toString( "_unq", id, "_finished_" ), new ast::BasicType( ast::BasicType::Kind::Bool ),
-				new ast::SingleInit( loc, ast::ConstantExpr::from_int( loc, 0 ) ), {}, ast::Linkage::Cforall );
-			declsToAddBefore.push_back( finished );
-			// (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
-			// This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
-			auto assignFinished = ast::UntypedExpr::createAssign( loc, new ast::VariableExpr( loc, finished ),
-				ast::ConstantExpr::from_int( loc, 1 ) );
-			auto condExpr = new ast::ConditionalExpr( loc, new ast::VariableExpr( loc, finished ), var,
-				new ast::CommaExpr( loc, new ast::CommaExpr( loc, assignUnq, assignFinished ), var ) );
-			condExpr->result = var->result;
-			condExpr->env = unqExpr->env;
-			decls[id] = condExpr;
-		}
-		//delete unqExpr;
-		return ast::deepCopy(decls[id].get());
-	}
-} // namespace
+void expandTuples( ast::TranslationUnit & translationUnit ) {
+	// These can't just be combined simply (there might be a way with work).
+	ast::Pass<TupleMainExpander>::run( translationUnit );
+	ast::Pass<TupleExprExpander>::run( translationUnit );
+}
+
 } // namespace Tuples
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Tuples/Tuples.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -32,6 +32,6 @@
 	void handleTupleAssignment( ResolvExpr::AlternativeFinder & currentFinder, UntypedExpr * assign,
 		std::vector< ResolvExpr::AlternativeFinder >& args );
-	void handleTupleAssignment( 
-		ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign, 
+	void handleTupleAssignment(
+		ResolvExpr::CandidateFinder & finder, const ast::UntypedExpr * assign,
 		std::vector< ResolvExpr::CandidateFinder > & args );
 
@@ -43,4 +43,5 @@
 	/// replaces tuple-related elements, such as TupleType, TupleExpr, TupleAssignExpr, etc.
 	void expandTuples( std::list< Declaration * > & translationUnit );
+	void expandTuples( ast::TranslationUnit & translaionUnit );
 
 	/// replaces UniqueExprs with a temporary variable and one call
Index: src/Validate/Autogen.cpp
===================================================================
--- src/Validate/Autogen.cpp	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Validate/Autogen.cpp	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -377,12 +377,10 @@
 ast::ObjectDecl * FuncGenerator::dstParam() const {
 	return new ast::ObjectDecl( getLocation(), "_dst",
-		new ast::ReferenceType( ast::deepCopy( type ) ),
-		nullptr, {}, ast::Linkage::Cforall );
+		new ast::ReferenceType( ast::deepCopy( type ) ) );
 }
 
 ast::ObjectDecl * FuncGenerator::srcParam() const {
 	return new ast::ObjectDecl( getLocation(), "_src",
-		ast::deepCopy( type ),
-		nullptr, {}, ast::Linkage::Cforall );
+		ast::deepCopy( type ) );
 }
 
@@ -436,5 +434,4 @@
 		ast::ObjectDecl * param = new ast::ObjectDecl(
 			getLocation(), member->name, paramType );
-		param->linkage = ast::Linkage::Cforall;
 		for ( auto & attr : member->attributes ) {
 			if ( attr->isValidOnFuncParam() ) {
Index: src/Virtual/ExpandCasts.cc
===================================================================
--- src/Virtual/ExpandCasts.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Virtual/ExpandCasts.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jul 24 13:59:00 2017
 // Last Modified By : Andrew Beach
-// Last Modified On : Fri Jul 31 10:29:00 2020
-// Update Count     : 4
+// Last Modified On : Thu Aug 11 12:06:00 2022
+// Update Count     : 5
 //
 
@@ -20,4 +20,7 @@
 #include <string>                  // for string, allocator, operator==, ope...
 
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Pass.hpp"
 #include "Common/PassVisitor.h"    // for PassVisitor
 #include "Common/ScopedMap.h"      // for ScopedMap
@@ -32,12 +35,18 @@
 namespace Virtual {
 
-static bool is_prefix( const std::string & prefix, const std::string& entire ) {
+namespace {
+
+bool is_prefix( const std::string & prefix, const std::string& entire ) {
 	size_t const p_size = prefix.size();
 	return (p_size < entire.size() && prefix == entire.substr(0, p_size));
 }
 
-static bool is_type_id_object( const ObjectDecl * objectDecl ) {
+bool is_type_id_object( const ObjectDecl * objectDecl ) {
 	const std::string & objectName = objectDecl->name;
 	return is_prefix( "__cfatid_", objectName );
+}
+
+bool is_type_id_object( const ast::ObjectDecl * decl ) {
+	return is_prefix( "__cfatid_", decl->name );
 }
 
@@ -124,6 +133,4 @@
 		}
 	}
-
-	namespace {
 
 	/// Better error locations for generated casts.
@@ -229,6 +236,4 @@
 	}
 
-	} // namespace
-
 	Expression * VirtualCastCore::postmutate( VirtualCastExpr * castExpr ) {
 		assertf( castExpr->result, "Virtual Cast target not found before expansion." );
@@ -265,7 +270,237 @@
 	}
 
-	void expandCasts( std::list< Declaration * > & translationUnit ) {
-		PassVisitor<VirtualCastCore> translator;
-		mutateAll( translationUnit, translator );
-	}
-}
+/// Better error locations for generated casts.
+// TODO: Does the improved distribution of code locations make this unneeded?
+CodeLocation castLocation( const ast::VirtualCastExpr * castExpr ) {
+	if ( castExpr->location.isSet() ) {
+		return castExpr->location;
+	} else if ( castExpr->arg->location.isSet() ) {
+		return castExpr->arg->location;
+	} else {
+		return CodeLocation();
+	}
+}
+
+[[noreturn]] void castError( ast::VirtualCastExpr const * castExpr, std::string const & message ) {
+	SemanticError( castLocation( castExpr ), message );
+}
+
+class TypeIdTable final {
+	ScopedMap<std::string, ast::ObjectDecl const *> instances;
+public:
+	void enterScope() { instances.beginScope(); }
+	void leaveScope() { instances.endScope(); }
+
+	// Attempt to insert an instance into the map. If there is a conflict,
+	// returns the previous declaration for error messages.
+	ast::ObjectDecl const * insert( ast::ObjectDecl const * typeIdDecl ) {
+		std::string const & mangledName =
+				Mangle::mangle( typeIdDecl->type, Mangle::typeMode() );
+		ast::ObjectDecl const *& value = instances[ mangledName ];
+		if ( value ) {
+			if ( typeIdDecl->storage.is_extern ) {
+				return nullptr;
+			} else if ( !value->storage.is_extern ) {
+				return value;
+			}
+		}
+		value = typeIdDecl;
+		return nullptr;
+	}
+
+	ast::ObjectDecl const * lookup( ast::Type const * typeIdType ) {
+		std::string const & mangledName =
+				Mangle::mangle( typeIdType, Mangle::typeMode() );
+		auto const it = instances.find( mangledName );
+		return ( instances.end() == it ) ? nullptr : it->second;
+	}
+};
+
+struct ExpandCastsCore final {
+	void previsit( ast::FunctionDecl const * decl );
+	void previsit( ast::StructDecl const * decl );
+	void previsit( ast::ObjectDecl const * decl );
+	ast::Expr const * postvisit( ast::VirtualCastExpr const * expr );
+
+	ast::CastExpr const * cast_to_type_id(
+		ast::Expr const * expr, unsigned int level_of_indirection );
+
+	ast::FunctionDecl const * vcast_decl = nullptr;
+	ast::StructDecl const * info_decl = nullptr;
+
+	TypeIdTable symtab;
+};
+
+void ExpandCastsCore::previsit( ast::FunctionDecl const * decl ) {
+	if ( !vcast_decl && "__cfavir_virtual_cast" == decl->name ) {
+		vcast_decl = decl;
+	}
+}
+
+void ExpandCastsCore::previsit( ast::StructDecl const * decl ) {
+	if ( !info_decl && decl->body && "__cfavir_type_info" == decl->name ) {
+		info_decl = decl;
+	}
+}
+
+void ExpandCastsCore::previsit( ast::ObjectDecl const * decl ) {
+	if ( is_type_id_object( decl ) ) {
+		// Multiple definitions should be fine because of linkonce.
+		symtab.insert( decl );
+	}
+}
+
+/// Get the base type from a pointer or reference.
+ast::Type const * getBaseType( ast::ptr<ast::Type> const & type ) {
+	if ( auto target = type.as<ast::PointerType>() ) {
+		return target->base.get();
+	} else if ( auto target = type.as<ast::ReferenceType>() ) {
+		return target->base.get();
+	} else {
+		return nullptr;
+	}
+}
+
+/// Copy newType, but give the copy the params of the oldType.
+ast::StructInstType * polyCopy(
+		ast::StructInstType const * oldType,
+		ast::StructInstType const * newType ) {
+	assert( oldType->params.size() == newType->params.size() );
+	ast::StructInstType * retType = ast::deepCopy( newType );
+	if ( ! oldType->params.empty() ) {
+		retType->params.clear();
+		for ( auto oldParams : oldType->params ) {
+			retType->params.push_back( ast::deepCopy( oldParams ) );
+		}
+	}
+	return retType;
+}
+
+/// Follow the "head" field of the structure to get the type that is pointed
+/// to by that field.
+ast::StructInstType const * followHeadPointerType(
+		CodeLocation const & errorLocation,
+		ast::StructInstType const * oldType,
+		std::string const & fieldName ) {
+	ast::StructDecl const * oldDecl = oldType->base;
+	assert( oldDecl );
+
+	// Helper function for throwing semantic errors.
+	auto throwError = [&fieldName, &errorLocation, &oldDecl](
+			std::string const & message ) {
+		std::string const & context = "While following head pointer of " +
+			oldDecl->name + " named '" + fieldName + "': ";
+		SemanticError( errorLocation, context + message );
+	};
+
+	if ( oldDecl->members.empty() ) {
+		throwError( "Type has no fields." );
+	}
+	ast::ptr<ast::Decl> const & memberDecl = oldDecl->members.front();
+	assert( memberDecl );
+	ast::ObjectDecl const * fieldDecl = memberDecl.as<ast::ObjectDecl>();
+	assert( fieldDecl );
+	if ( fieldName != fieldDecl->name ) {
+		throwError( "Head field did not have expected name." );
+	}
+
+	ast::ptr<ast::Type> const & fieldType = fieldDecl->type;
+	if ( nullptr == fieldType ) {
+		throwError( "Could not get head field." );
+	}
+	auto ptrType = fieldType.as<ast::PointerType>();
+	if ( nullptr == ptrType ) {
+		throwError( "First field is not a pointer type." );
+	}
+	assert( ptrType->base );
+	auto newType = ptrType->base.as<ast::StructInstType>();
+	if ( nullptr == newType ) {
+		throwError( "First field does not point to a structure type." );
+	}
+
+	return polyCopy( oldType, newType );
+}
+
+/// Get the type-id type from a virtual type.
+ast::StructInstType const * getTypeIdType(
+		CodeLocation const & errorLocation,
+		ast::Type const * type ) {
+	auto typeInst = dynamic_cast<ast::StructInstType const *>( type );
+	if ( nullptr == typeInst ) {
+		return nullptr;
+	}
+	ast::ptr<ast::StructInstType> tableInst =
+		followHeadPointerType( errorLocation, typeInst, "virtual_table" );
+	if ( nullptr == tableInst ) {
+		return nullptr;
+	}
+	ast::StructInstType const * typeIdInst =
+		followHeadPointerType( errorLocation, tableInst, "__cfavir_typeid" );
+	return typeIdInst;
+}
+
+ast::Expr const * ExpandCastsCore::postvisit(
+		ast::VirtualCastExpr const * expr ) {
+	assertf( expr->result, "Virtual cast target not found before expansion." );
+
+	assert( vcast_decl );
+	assert( info_decl );
+
+	ast::Type const * base_type = getBaseType( expr->result );
+	if ( nullptr == base_type ) {
+		castError( expr, "Virtual cast target must be a pointer or reference type." );
+	}
+	ast::StructInstType const * type_id_type =
+			getTypeIdType( castLocation( expr ), base_type );
+	if ( nullptr == type_id_type ) {
+		castError( expr, "Ill formed virtual cast target type." );
+	}
+	ast::ObjectDecl const * type_id = symtab.lookup( type_id_type );
+	if ( nullptr == type_id ) {
+		// I'm trying to give a different error for polymorpic types as
+		// different things can go wrong there.
+		if ( type_id_type->params.empty() ) {
+			castError( expr, "Virtual cast does not target a virtual type." );
+		} else {
+			castError( expr, "Virtual cast does not target a type with a "
+				"type id (possible missing virtual table)." );
+		}
+	}
+
+	return new ast::CastExpr( expr->location,
+		new ast::ApplicationExpr( expr->location,
+			ast::VariableExpr::functionPointer( expr->location, vcast_decl ),
+			{
+				cast_to_type_id(
+					new ast::AddressExpr( expr->location,
+						new ast::VariableExpr( expr->location, type_id ) ),
+					1 ),
+				cast_to_type_id( expr->arg, 2 ),
+			}
+		),
+		ast::deepCopy( expr->result )
+	);
+}
+
+ast::CastExpr const * ExpandCastsCore::cast_to_type_id(
+		ast::Expr const * expr, unsigned int level_of_indirection ) {
+	assert( info_decl );
+	ast::Type * type = new ast::StructInstType( info_decl, ast::CV::Const );
+	for ( unsigned int i = 0 ; i < level_of_indirection ; ++i ) {
+		type = new ast::PointerType( type );
+	}
+	return new ast::CastExpr( expr->location, expr, type );
+}
+
+} // namespace
+
+void expandCasts( std::list< Declaration * > & translationUnit ) {
+	PassVisitor<VirtualCastCore> translator;
+	mutateAll( translationUnit, translator );
+}
+
+void expandCasts( ast::TranslationUnit & translationUnit ) {
+	ast::Pass<ExpandCastsCore>::run( translationUnit );
+}
+
+} // namespace Virtual
Index: src/Virtual/ExpandCasts.h
===================================================================
--- src/Virtual/ExpandCasts.h	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/Virtual/ExpandCasts.h	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jul 24 13:54:00 2017
 // Last Modified By : Andrew Beach
-// Last Modified On : Tus Jul 25 14:51:00 2017
-// Update Count     : 0
+// Last Modified On : Fri Jul 29 14:40:00 2022
+// Update Count     : 1
 //
 
@@ -19,10 +19,14 @@
 
 class Declaration;
+namespace ast {
+	class TranslationUnit;
+}
 
 namespace Virtual {
-	void expandCasts( std::list< Declaration * > & translationUnit );
-	// Breaks all virtual cast nodes up into translatable nodes.
+void expandCasts( std::list< Declaration * > & translationUnit );
+void expandCasts( ast::TranslationUnit & translationUnit );
+// Breaks all virtual cast nodes up into translatable nodes.
 
-	// Later this might just set some information so it can happen at CodeGen.
+// Later this might just set some information so it can happen at CodeGen.
 
 }
Index: src/config.h.in
===================================================================
--- src/config.h.in	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/config.h.in	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -27,8 +27,4 @@
 /* Location of cfa install. */
 #undef CFA_PREFIX
-
-/* Sets whether or not to use the new-ast, this is adefault value and can be
-   overrided by --old-ast and --new-ast */
-#undef CFA_USE_NEW_AST
 
 /* Major.Minor */
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 12df6fe35a1d7d73a64293320db6c3a0b195af33)
+++ src/main.cc	(revision 4520b77e192c372763501afd950a0f1452141b3b)
@@ -10,6 +10,6 @@
 // Created On       : Fri May 15 23:12:02 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Jul 18 11:08:00 2022
-// Update Count     : 676
+// Last Modified On : Thu Sep 15 13:58:00 2022
+// Update Count     : 678
 //
 
@@ -38,6 +38,4 @@
 #include "CodeGen/Generate.h"               // for generate
 #include "CodeGen/LinkOnce.h"               // for translateLinkOnce
-#include "CodeTools/DeclStats.h"            // for printDeclStats
-#include "CodeTools/ResolvProtoDump.h"      // for dumpAsResolvProto
 #include "CodeTools/TrackLoc.h"             // for fillLocations
 #include "Common/CodeLocationTools.hpp"     // for forceFillCodeLocations
@@ -45,7 +43,5 @@
 #include "Common/DeclStats.hpp"             // for printDeclStats
 #include "Common/ResolvProtoDump.hpp"       // for dumpAsResolverProto
-#include "Common/Stats.h"
-#include "Common/PassVisitor.h"
-#include "Common/SemanticError.h"           // for SemanticError
+#include "Common/Stats.h"                   // for Stats
 #include "Common/UnimplementedError.h"      // for UnimplementedError
 #include "Common/utility.h"                 // for deleteAll, filter, printAll
@@ -53,8 +49,7 @@
 #include "Concurrency/Waitfor.h"            // for generateWaitfor
 #include "ControlStruct/ExceptDecl.h"       // for translateExcept
-#include "ControlStruct/ExceptTranslate.h"  // for translateEHM
+#include "ControlStruct/ExceptTranslate.h"  // for translateThrows, translat...
 #include "ControlStruct/FixLabels.hpp"      // for fixLabels
 #include "ControlStruct/HoistControlDecls.hpp" //  hoistControlDecls
-#include "ControlStruct/Mutate.h"           // for mutate
 #include "GenPoly/Box.h"                    // for box
 #include "GenPoly/InstantiateGeneric.h"     // for instantiateGeneric
@@ -66,12 +61,8 @@
 #include "Parser/ParseNode.h"               // for DeclarationNode, buildList
 #include "Parser/TypedefTable.h"            // for TypedefTable
-#include "ResolvExpr/AlternativePrinter.h"  // for AlternativePrinter
 #include "ResolvExpr/CandidatePrinter.hpp"  // for printCandidates
 #include "ResolvExpr/Resolver.h"            // for resolve
-#include "SymTab/Validate.h"                // for validate
-#include "SymTab/ValidateType.h"            // for linkReferenceToTypes
 #include "SynTree/LinkageSpec.h"            // for Spec, Cforall, Intrinsic
 #include "SynTree/Declaration.h"            // for Declaration
-#include "SynTree/Visitor.h"                // for acceptAll
 #include "Tuples/Tuples.h"                  // for expandMemberTuples, expan...
 #include "Validate/Autogen.hpp"             // for autogenerateRoutines
@@ -330,206 +321,130 @@
 		Stats::Time::StopBlock();
 
-		if( useNewAST ) {
-			if (Stats::Counters::enabled) {
-				ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
-				ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
-			}
-			auto transUnit = convert( move( translationUnit ) );
-
-			forceFillCodeLocations( transUnit );
-
-			PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
-			if ( exdeclp ) {
-				dump( move( transUnit ) );
-				return EXIT_SUCCESS;
-			}
-
-			PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
-			PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
-			// Hoist Type Decls pulls some declarations out of contexts where
-			// locations are not tracked. Perhaps they should be, but for now
-			// the full fill solves it.
-			forceFillCodeLocations( transUnit );
-
-			PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
-			PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
-			PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
-
-			PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
-
-			PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
-			PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
-			PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
-			PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
-			PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
-			PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
-			PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
-			PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
-			PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
-			PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
-
-			PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
-
-			PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
-			PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
-			PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
-			PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
-			PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
-			PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
-
-			if ( symtabp ) {
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( expraltp ) {
-				ResolvExpr::printCandidates( transUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( validp ) {
-				dump( move( transUnit ) );
-				return EXIT_SUCCESS;
-			} // if
-
-			PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
-			PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
-			PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
-			PASS( "Gen Init", InitTweak::genInit( transUnit ) );
-			PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
-
-			if ( libcfap ) {
-				// Generate the bodies of cfa library functions.
-				LibCfa::makeLibCfa( transUnit );
-			} // if
-
-			if ( declstatsp ) {
-				printDeclStats( transUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( bresolvep ) {
-				dump( move( transUnit ) );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( resolvprotop ) {
-				dumpAsResolverProto( transUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
-			if ( exprp ) {
-				dump( move( transUnit ) );
-				return EXIT_SUCCESS;
-			} // if
-
-			forceFillCodeLocations( transUnit );
-
-			PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
-
-			// fix ObjectDecl - replaces ConstructorInit nodes
-			if ( ctorinitp ) {
-				dump( move( transUnit ) );
-				return EXIT_SUCCESS;
-			} // if
-
-			// Currently not working due to unresolved issues with UniqueExpr
-			PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
-
-			PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
-			PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
-			PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) ); // needs to happen before tuple types are expanded
-
-
-			translationUnit = convert( move( transUnit ) );
-		} else {
-			PASS( "Translate Exception Declarations", ControlStruct::translateExcept( translationUnit ) );
-			if ( exdeclp ) {
-				dump( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			// add the assignment statement after the initialization of a type parameter
-			PASS( "Validate", SymTab::validate( translationUnit ) );
-
-			if ( symtabp ) {
-				deleteAll( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( expraltp ) {
-				PassVisitor<ResolvExpr::AlternativePrinter> printer( cout );
-				acceptAll( translationUnit, printer );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( validp ) {
-				dump( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			PASS( "Translate Throws", ControlStruct::translateThrows( translationUnit ) );
-			PASS( "Fix Labels", ControlStruct::fixLabels( translationUnit ) );
-			PASS( "Fix Names", CodeGen::fixNames( translationUnit ) );
-			PASS( "Gen Init", InitTweak::genInit( translationUnit ) );
-			PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( translationUnit ) );
-
-			if ( libcfap ) {
-				// Generate the bodies of cfa library functions.
-				LibCfa::makeLibCfa( translationUnit );
-			} // if
-
-			if ( declstatsp ) {
-				CodeTools::printDeclStats( translationUnit );
-				deleteAll( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			if ( bresolvep ) {
-				dump( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			CodeTools::fillLocations( translationUnit );
-
-			if ( resolvprotop ) {
-				CodeTools::dumpAsResolvProto( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
-			if ( exprp ) {
-				dump( translationUnit );
-				return EXIT_SUCCESS;
-			}
-
-			PASS( "Fix Init", InitTweak::fix( translationUnit, buildingLibrary() ) );
-
-			// fix ObjectDecl - replaces ConstructorInit nodes
-			if ( ctorinitp ) {
-				dump ( translationUnit );
-				return EXIT_SUCCESS;
-			} // if
-
-			PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( translationUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
-			PASS( "Translate Tries", ControlStruct::translateTries( translationUnit ) );
-			PASS( "Gen Waitfor", Concurrency::generateWaitFor( translationUnit ) );
-			PASS( "Convert Specializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
-
+		if (Stats::Counters::enabled) {
+			ast::pass_visitor_stats.avg = Stats::Counters::build<Stats::Counters::AverageCounter<double>>("Average Depth - New");
+			ast::pass_visitor_stats.max = Stats::Counters::build<Stats::Counters::MaxCounter<double>>("Max depth - New");
 		}
-
-
-		// PASS( "Convert Specializations",  GenPoly::convertSpecializations( translationUnit ) ); // needs to happen before tuple types are expanded
-
-		PASS( "Expand Tuples", Tuples::expandTuples( translationUnit ) ); // xxx - is this the right place for this?
+		auto transUnit = convert( std::move( translationUnit ) );
+
+		forceFillCodeLocations( transUnit );
+
+		PASS( "Translate Exception Declarations", ControlStruct::translateExcept( transUnit ) );
+		if ( exdeclp ) {
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		}
+
+		PASS( "Verify Ctor, Dtor & Assign", Validate::verifyCtorDtorAssign( transUnit ) );
+		PASS( "Hoist Type Decls", Validate::hoistTypeDecls( transUnit ) );
+		// Hoist Type Decls pulls some declarations out of contexts where
+		// locations are not tracked. Perhaps they should be, but for now
+		// the full fill solves it.
+		forceFillCodeLocations( transUnit );
+
+		PASS( "Replace Typedefs", Validate::replaceTypedef( transUnit ) );
+		PASS( "Fix Return Types", Validate::fixReturnTypes( transUnit ) );
+		PASS( "Enum and Pointer Decay", Validate::decayEnumsAndPointers( transUnit ) );
+
+		PASS( "Link Reference To Types", Validate::linkReferenceToTypes( transUnit ) );
+
+		PASS( "Fix Qualified Types", Validate::fixQualifiedTypes( transUnit ) );
+		PASS( "Hoist Struct", Validate::hoistStruct( transUnit ) );
+		PASS( "Eliminate Typedef", Validate::eliminateTypedef( transUnit ) );
+		PASS( "Validate Generic Parameters", Validate::fillGenericParameters( transUnit ) );
+		PASS( "Translate Dimensions", Validate::translateDimensionParameters( transUnit ) );
+		PASS( "Check Function Returns", Validate::checkReturnStatements( transUnit ) );
+		PASS( "Fix Return Statements", InitTweak::fixReturnStatements( transUnit ) );
+		PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords( transUnit ) );
+		PASS( "Forall Pointer Decay", Validate::decayForallPointers( transUnit ) );
+		PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls( transUnit ) );
+
+		PASS( "Generate Autogen Routines", Validate::autogenerateRoutines( transUnit ) );
+
+		PASS( "Implement Mutex", Concurrency::implementMutex( transUnit ) );
+		PASS( "Implement Thread Start", Concurrency::implementThreadStarter( transUnit ) );
+		PASS( "Compound Literal", Validate::handleCompoundLiterals( transUnit ) );
+		PASS( "Set Length From Initializer", Validate::setLengthFromInitializer( transUnit ) );
+		PASS( "Find Global Decls", Validate::findGlobalDecls( transUnit ) );
+		PASS( "Fix Label Address", Validate::fixLabelAddresses( transUnit ) );
+
+		if ( symtabp ) {
+			return EXIT_SUCCESS;
+		} // if
+
+		if ( expraltp ) {
+			ResolvExpr::printCandidates( transUnit );
+			return EXIT_SUCCESS;
+		} // if
+
+		if ( validp ) {
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		} // if
+
+		PASS( "Translate Throws", ControlStruct::translateThrows( transUnit ) );
+		PASS( "Fix Labels", ControlStruct::fixLabels( transUnit ) );
+		PASS( "Fix Names", CodeGen::fixNames( transUnit ) );
+		PASS( "Gen Init", InitTweak::genInit( transUnit ) );
+		PASS( "Expand Member Tuples" , Tuples::expandMemberTuples( transUnit ) );
+
+		if ( libcfap ) {
+			// Generate the bodies of cfa library functions.
+			LibCfa::makeLibCfa( transUnit );
+		} // if
+
+		if ( declstatsp ) {
+			printDeclStats( transUnit );
+			return EXIT_SUCCESS;
+		} // if
+
+		if ( bresolvep ) {
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		} // if
+
+		if ( resolvprotop ) {
+			dumpAsResolverProto( transUnit );
+			return EXIT_SUCCESS;
+		} // if
+
+		PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
+		if ( exprp ) {
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		} // if
+
+		forceFillCodeLocations( transUnit );
+
+		PASS( "Fix Init", InitTweak::fix(transUnit, buildingLibrary()));
+
+		// fix ObjectDecl - replaces ConstructorInit nodes
+		if ( ctorinitp ) {
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		} // if
+
+		// Currently not working due to unresolved issues with UniqueExpr
+		PASS( "Expand Unique Expr", Tuples::expandUniqueExpr( transUnit ) ); // xxx - is this the right place for this? want to expand ASAP so tha, sequent passes don't need to worry about double-visiting a unique expr - needs to go after InitTweak::fix so that copy constructed return declarations are reused
+
+		PASS( "Translate Tries", ControlStruct::translateTries( transUnit ) );
+		PASS( "Gen Waitfor", Concurrency::generateWaitFor( transUnit ) );
+
+		// Needs to happen before tuple types are expanded.
+		PASS( "Convert Specializations",  GenPoly::convertSpecializations( transUnit ) );
+
+		PASS( "Expand Tuples", Tuples::expandTuples( transUnit ) );
 
 		if ( tuplep ) {
-			dump( translationUnit );
-			return EXIT_SUCCESS;
-		} // if
-
-		PASS( "Virtual Expand Casts", Virtual::expandCasts( translationUnit ) ); // Must come after translateEHM
-
-		PASS( "Instantiate Generics", GenPoly::instantiateGeneric( translationUnit ) );
+			dump( std::move( transUnit ) );
+			return EXIT_SUCCESS;
+		} // if
+
+		// Must come after Translate Tries.
+		PASS( "Virtual Expand Casts", Virtual::expandCasts( transUnit ) );
+
+		PASS( "Instantiate Generics", GenPoly::instantiateGeneric( transUnit ) );
+
+		translationUnit = convert( std::move( transUnit ) );
+
 		if ( genericsp ) {
 			dump( translationUnit );
@@ -614,5 +529,5 @@
 
 
-static const char optstring[] = ":c:ghlLmNnpdOAP:S:twW:D:";
+static const char optstring[] = ":c:ghlLmNnpdP:S:twW:D:";
 
 enum { PreludeDir = 128 };
@@ -628,6 +543,4 @@
 	{ "prototypes", no_argument, nullptr, 'p' },
 	{ "deterministic-out", no_argument, nullptr, 'd' },
-	{ "old-ast", no_argument, nullptr, 'O'},
-	{ "new-ast", no_argument, nullptr, 'A'},
 	{ "print", required_argument, nullptr, 'P' },
 	{ "prelude-dir", required_argument, nullptr, PreludeDir },
@@ -651,6 +564,4 @@
 	"do not generate prelude prototypes => prelude not printed", // -p
 	"only print deterministic output",                  // -d
-	"Use the old-ast",									// -O
-	"Use the new-ast",									// -A
 	"print",											// -P
 	"<directory> prelude directory for debug/nodebug",	// no flag
@@ -761,10 +672,4 @@
 			deterministic_output = true;
 			break;
-		  case 'O':                                     // don't print non-deterministic output
-			useNewAST = false;
-			break;
-		  case 'A':                                     // don't print non-deterministic output
-			useNewAST = true;
-			break;
 		  case 'P':										// print options
 			for ( int i = 0;; i += 1 ) {
@@ -883,5 +788,5 @@
 
 static void dump( ast::TranslationUnit && transUnit, ostream & out ) {
-	std::list< Declaration * > translationUnit = convert( move( transUnit ) );
+	std::list< Declaration * > translationUnit = convert( std::move( transUnit ) );
 	dump( translationUnit, out );
 }
