Index: src/GenPoly/Box.cc
===================================================================
--- src/GenPoly/Box.cc	(revision aea71684e6fdc8b8f2abddf24378fdf621bdd40b)
+++ src/GenPoly/Box.cc	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -62,91 +62,4 @@
 
 		FunctionType *makeAdapterType( FunctionType *adaptee, const TyVarMap &tyVars );
-
-		/// Abstracts type equality for a list of parameter types
-		struct TypeList {
-			TypeList() : params() {}
-			TypeList( const std::list< Type* > &_params ) : params() { cloneAll(_params, params); }
-			TypeList( std::list< Type* > &&_params ) : params( _params ) {}
-
-			TypeList( const TypeList &that ) : params() { cloneAll(that.params, params); }
-			TypeList( TypeList &&that ) : params( std::move( that.params ) ) {}
-
-			/// Extracts types from a list of TypeExpr*
-			TypeList( const std::list< TypeExpr* >& _params ) : params() {
-				for ( std::list< TypeExpr* >::const_iterator param = _params.begin(); param != _params.end(); ++param ) {
-					params.push_back( (*param)->get_type()->clone() );
-				}
-			}
-
-			TypeList& operator= ( const TypeList &that ) {
-				deleteAll( params );
-
-				params.clear();
-				cloneAll( that.params, params );
-
-				return *this;
-			}
-
-			TypeList& operator= ( TypeList &&that ) {
-				deleteAll( params );
-
-				params = std::move( that.params );
-
-				return *this;
-			}
-
-			~TypeList() { deleteAll( params ); }
-
-			bool operator== ( const TypeList& that ) const {
-				if ( params.size() != that.params.size() ) return false;
-
-				SymTab::Indexer dummy;
-				for ( std::list< Type* >::const_iterator it = params.begin(), jt = that.params.begin(); it != params.end(); ++it, ++jt ) {
-					if ( ! ResolvExpr::typesCompatible( *it, *jt, dummy ) ) return false;
-				}
-				return true;
-			}
-
-			std::list< Type* > params;  ///< Instantiation parameters
-		};
-
-		/// Maps a key and a TypeList to the some value, accounting for scope
-		template< typename Key, typename Value >
-		class InstantiationMap {
-			/// Wraps value for a specific (Key, TypeList) combination
-			typedef std::pair< TypeList, Value* > Instantiation;
-			/// List of TypeLists paired with their appropriate values
-			typedef std::vector< Instantiation > ValueList;
-			/// Underlying map type; maps keys to a linear list of corresponding TypeLists and values
-			typedef ScopedMap< Key*, ValueList > InnerMap;
-
-			InnerMap instantiations;  ///< instantiations
-
-		public:
-			/// Starts a new scope
-			void beginScope() { instantiations.beginScope(); }
-
-			/// Ends a scope
-			void endScope() { instantiations.endScope(); }
-
-			/// Gets the value for the (key, typeList) pair, returns NULL on none such.
-			Value *lookup( Key *key, const std::list< TypeExpr* >& params ) const {
- 				TypeList typeList( params );
-
-				// scan scopes for matches to the key
-				for ( typename InnerMap::const_iterator insts = instantiations.find( key ); insts != instantiations.end(); insts = instantiations.findNext( insts, key ) ) {
-					for ( typename ValueList::const_reverse_iterator inst = insts->second.rbegin(); inst != insts->second.rend(); ++inst ) {
-						if ( inst->first == typeList ) return inst->second;
-					}
-				}
-				// no matching instantiations found
-				return 0;
-			}
-
-			/// Adds a value for a (key, typeList) pair to the current scope
-			void insert( Key *key, const std::list< TypeExpr* > &params, Value *value ) {
-				instantiations[ key ].push_back( Instantiation( TypeList( params ), value ) );
-			}
-		};
 
 		/// Adds layout-generation functions to polymorphic types
@@ -239,32 +152,4 @@
 		};
 
-		/// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
-		class GenericInstantiator : public DeclMutator {
-			/// Map of (generic type, parameter list) pairs to concrete type instantiations
-			InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
-			/// Namer for concrete types
-			UniqueName typeNamer;
-
-		public:
-			GenericInstantiator() : DeclMutator(), instantiations(), typeNamer("_conc_") {}
-
-			virtual Type* mutate( StructInstType *inst );
-			virtual Type* mutate( UnionInstType *inst );
-
-	// 		virtual Expression* mutate( MemberExpr *memberExpr );
-
-			virtual void doBeginScope();
-			virtual void doEndScope();
-		private:
-			/// Wrap instantiation lookup for structs
-			StructDecl* lookup( StructInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (StructDecl*)instantiations.lookup( inst->get_baseStruct(), typeSubs ); }
-			/// Wrap instantiation lookup for unions
-			UnionDecl* lookup( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (UnionDecl*)instantiations.lookup( inst->get_baseUnion(), typeSubs ); }
-			/// Wrap instantiation insertion for structs
-			void insert( StructInstType *inst, const std::list< TypeExpr* > &typeSubs, StructDecl *decl ) { instantiations.insert( inst->get_baseStruct(), typeSubs, decl ); }
-			/// Wrap instantiation insertion for unions
-			void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { instantiations.insert( inst->get_baseUnion(), typeSubs, decl ); }
-		};
-
 		/// Replaces member and size/align/offsetof expressions on polymorphic generic types with calculated expressions.
 		/// * Replaces member expressions for polymorphic types with calculated add-field-offset-and-dereference
@@ -354,5 +239,4 @@
 		Pass1 pass1;
 		Pass2 pass2;
-		GenericInstantiator instantiator;
 		PolyGenericCalculator polyCalculator;
 		Pass3 pass3;
@@ -361,5 +245,4 @@
 		mutateTranslationUnit/*All*/( translationUnit, pass1 );
 		mutateTranslationUnit/*All*/( translationUnit, pass2 );
-		instantiator.mutateDeclarationList( translationUnit );
 		mutateTranslationUnit/*All*/( translationUnit, polyCalculator );
 		mutateTranslationUnit/*All*/( translationUnit, pass3 );
@@ -889,5 +772,5 @@
 						arg++;
 					} else {
-						/// xxx - should this be an assertion?
+						// xxx - should this be an assertion?
 						throw SemanticError( "unbound type variable: " + tyParm->first + " in application ", appExpr );
 					} // if
@@ -902,5 +785,5 @@
 			std::list< DeclarationWithType* >::const_iterator fnParm = funcType->get_parameters().begin();
 			std::list< Expression* >::const_iterator fnArg = arg;
-			std::set< std::string > seenTypes; //< names for generic types we've seen
+			std::set< std::string > seenTypes; ///< names for generic types we've seen
 
 			// a polymorphic return type may need to be added to the argument list
@@ -1042,6 +925,6 @@
 		/// this gets rid of warnings from gcc.
 		void addCast( Expression *&actual, Type *formal, const TyVarMap &tyVars ) {
-			Type * newType = formal->clone();
-			if ( getFunctionType( newType ) ) {
+			if ( getFunctionType( formal ) ) {
+				Type * newType = formal->clone();
 				newType = ScrubTyVars::scrub( newType, tyVars );
 				actual = new CastExpr( actual, newType );
@@ -1775,193 +1658,4 @@
 		}
 
-//////////////////////////////////////// GenericInstantiator //////////////////////////////////////////////////
-
-		/// Makes substitutions of params into baseParams; returns true if all parameters substituted for a concrete type
-		bool makeSubstitutions( const std::list< TypeDecl* >& baseParams, const std::list< Expression* >& params, std::list< TypeExpr* >& out ) {
-			bool allConcrete = true;  // will finish the substitution list even if they're not all concrete
-
-			// substitute concrete types for given parameters, and incomplete types for placeholders
-			std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
-			std::list< Expression* >::const_iterator param = params.begin();
-			for ( ; baseParam != baseParams.end() && param != params.end(); ++baseParam, ++param ) {
-	// 			switch ( (*baseParam)->get_kind() ) {
-	// 			case TypeDecl::Any: {   // any type is a valid substitution here; complete types can be used to instantiate generics
-					TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
-					assert(paramType && "Aggregate parameters should be type expressions");
-					out.push_back( paramType->clone() );
-					// check that the substituted type isn't a type variable itself
-					if ( dynamic_cast< TypeInstType* >( paramType->get_type() ) ) {
-						allConcrete = false;
-					}
-	// 				break;
-	// 			}
-	// 			case TypeDecl::Dtype:  // dtype can be consistently replaced with void [only pointers, which become void*]
-	// 				out.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
-	// 				break;
-	// 			case TypeDecl::Ftype:  // pointer-to-ftype can be consistently replaced with void (*)(void) [similar to dtype]
-	// 				out.push_back( new TypeExpr( new FunctionType( Type::Qualifiers(), false ) ) );
-	// 				break;
-	// 			}
-			}
-
-			// if any parameters left over, not done
-			if ( baseParam != baseParams.end() ) return false;
-	// 		// if not enough parameters given, substitute remaining incomplete types for placeholders
-	// 		for ( ; baseParam != baseParams.end(); ++baseParam ) {
-	// 			switch ( (*baseParam)->get_kind() ) {
-	// 			case TypeDecl::Any:    // no more substitutions here, fail early
-	// 				return false;
-	// 			case TypeDecl::Dtype:  // dtype can be consistently replaced with void [only pointers, which become void*]
-	// 				out.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
-	// 				break;
-	// 			case TypeDecl::Ftype:  // pointer-to-ftype can be consistently replaced with void (*)(void) [similar to dtype]
-	// 				out.push_back( new TypeExpr( new FunctionType( Type::Qualifiers(), false ) ) );
-	// 				break;
-	// 			}
-	// 		}
-
-			return allConcrete;
-		}
-
-		/// Substitutes types of members of in according to baseParams => typeSubs, appending the result to out
-		void substituteMembers( const std::list< Declaration* >& in, const std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs,
-								std::list< Declaration* >& out ) {
-			// substitute types into new members
-			TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
-			for ( std::list< Declaration* >::const_iterator member = in.begin(); member != in.end(); ++member ) {
-				Declaration *newMember = (*member)->clone();
-				subs.apply(newMember);
-				out.push_back( newMember );
-			}
-		}
-
-		Type* GenericInstantiator::mutate( StructInstType *inst ) {
-			// mutate subtypes
-			Type *mutated = Mutator::mutate( inst );
-			inst = dynamic_cast< StructInstType* >( mutated );
-			if ( ! inst ) return mutated;
-
-			// exit early if no need for further mutation
-			if ( inst->get_parameters().empty() ) return inst;
-			assert( inst->get_baseParameters() && "Base struct has parameters" );
-
-			// check if type can be concretely instantiated; put substitutions into typeSubs
-			std::list< TypeExpr* > typeSubs;
-			if ( ! makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs ) ) {
-				deleteAll( typeSubs );
-				return inst;
-			}
-
-			// make concrete instantiation of generic type
-			StructDecl *concDecl = lookup( inst, typeSubs );
-			if ( ! concDecl ) {
-				// set concDecl to new type, insert type declaration into statements to add
-				concDecl = new StructDecl( typeNamer.newName( inst->get_name() ) );
-				substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, 	concDecl->get_members() );
-				DeclMutator::addDeclaration( concDecl );
-				insert( inst, typeSubs, concDecl );
-			}
-			StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() );
-			newInst->set_baseStruct( concDecl );
-
-			deleteAll( typeSubs );
-			delete inst;
-			return newInst;
-		}
-
-		Type* GenericInstantiator::mutate( UnionInstType *inst ) {
-			// mutate subtypes
-			Type *mutated = Mutator::mutate( inst );
-			inst = dynamic_cast< UnionInstType* >( mutated );
-			if ( ! inst ) return mutated;
-
-			// exit early if no need for further mutation
-			if ( inst->get_parameters().empty() ) return inst;
-			assert( inst->get_baseParameters() && "Base union has parameters" );
-
-			// check if type can be concretely instantiated; put substitutions into typeSubs
-			std::list< TypeExpr* > typeSubs;
-			if ( ! makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs ) ) {
-				deleteAll( typeSubs );
-				return inst;
-			}
-
-			// make concrete instantiation of generic type
-			UnionDecl *concDecl = lookup( inst, typeSubs );
-			if ( ! concDecl ) {
-				// set concDecl to new type, insert type declaration into statements to add
-				concDecl = new UnionDecl( typeNamer.newName( inst->get_name() ) );
-				substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
-				DeclMutator::addDeclaration( concDecl );
-				insert( inst, typeSubs, concDecl );
-			}
-			UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() );
-			newInst->set_baseUnion( concDecl );
-
-			deleteAll( typeSubs );
-			delete inst;
-			return newInst;
-		}
-
-	// 	/// Gets the base struct or union declaration for a member expression; NULL if not applicable
-	// 	AggregateDecl* getMemberBaseDecl( MemberExpr *memberExpr ) {
-	// 		// get variable for member aggregate
-	// 		VariableExpr *varExpr = dynamic_cast< VariableExpr* >( memberExpr->get_aggregate() );
-	// 		if ( ! varExpr ) return NULL;
-	//
-	// 		// get object for variable
-	// 		ObjectDecl *objectDecl = dynamic_cast< ObjectDecl* >( varExpr->get_var() );
-	// 		if ( ! objectDecl ) return NULL;
-	//
-	// 		// get base declaration from object type
-	// 		Type *objectType = objectDecl->get_type();
-	// 		StructInstType *structType = dynamic_cast< StructInstType* >( objectType );
-	// 		if ( structType ) return structType->get_baseStruct();
-	// 		UnionInstType *unionType = dynamic_cast< UnionInstType* >( objectType );
-	// 		if ( unionType ) return unionType->get_baseUnion();
-	//
-	// 		return NULL;
-	// 	}
-	//
-	// 	/// Finds the declaration with the given name, returning decls.end() if none such
-	// 	std::list< Declaration* >::const_iterator findDeclNamed( const std::list< Declaration* > &decls, const std::string &name ) {
-	// 		for( std::list< Declaration* >::const_iterator decl = decls.begin(); decl != decls.end(); ++decl ) {
-	// 			if ( (*decl)->get_name() == name ) return decl;
-	// 		}
-	// 		return decls.end();
-	// 	}
-	//
-	// 	Expression* Instantiate::mutate( MemberExpr *memberExpr ) {
-	// 		// mutate, exiting early if no longer MemberExpr
-	// 		Expression *expr = Mutator::mutate( memberExpr );
-	// 		memberExpr = dynamic_cast< MemberExpr* >( expr );
-	// 		if ( ! memberExpr ) return expr;
-	//
-	// 		// get declaration of member and base declaration of member, exiting early if not found
-	// 		AggregateDecl *memberBase = getMemberBaseDecl( memberExpr );
-	// 		if ( ! memberBase ) return memberExpr;
-	// 		DeclarationWithType *memberDecl = memberExpr->get_member();
-	// 		std::list< Declaration* >::const_iterator baseIt = findDeclNamed( memberBase->get_members(), memberDecl->get_name() );
-	// 		if ( baseIt == memberBase->get_members().end() ) return memberExpr;
-	// 		DeclarationWithType *baseDecl = dynamic_cast< DeclarationWithType* >( *baseIt );
-	// 		if ( ! baseDecl ) return memberExpr;
-	//
-	// 		// check if stated type of the member is not the type of the member's declaration; if so, need a cast
-	// 		// this *SHOULD* be safe, I don't think anything but the void-replacements I put in for dtypes would make it past the typechecker
-	// 		SymTab::Indexer dummy;
-	// 		if ( ResolvExpr::typesCompatible( memberDecl->get_type(), baseDecl->get_type(), dummy ) ) return memberExpr;
-	// 		else return new CastExpr( memberExpr, memberDecl->get_type() );
-	// 	}
-
-		void GenericInstantiator::doBeginScope() {
-			DeclMutator::doBeginScope();
-			instantiations.beginScope();
-		}
-
-		void GenericInstantiator::doEndScope() {
-			DeclMutator::doEndScope();
-			instantiations.endScope();
-		}
-
 ////////////////////////////////////////// PolyGenericCalculator ////////////////////////////////////////////////////
 
@@ -2107,4 +1801,5 @@
 			findGeneric( objectType ); // ensure layout for this type is available
 
+			// replace member expression with dynamically-computed layout expression
 			Expression *newMemberExpr = 0;
 			if ( StructInstType *structType = dynamic_cast< StructInstType* >( objectType ) ) {
Index: src/GenPoly/InstantiateGeneric.cc
===================================================================
--- src/GenPoly/InstantiateGeneric.cc	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
+++ src/GenPoly/InstantiateGeneric.cc	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -0,0 +1,326 @@
+//
+// 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.
+//
+// InstantiateGeneric.cc --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Aug 04 18:33:00 2016
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Aug 04 18:33:00 2016
+// Update Count     : 1
+//
+
+#include <cassert>
+#include <list>
+#include <utility>
+#include <vector>
+
+#include "InstantiateGeneric.h"
+
+#include "DeclMutator.h"
+#include "GenPoly.h"
+#include "ScopedMap.h"
+
+#include "ResolvExpr/typeops.h"
+
+#include "SynTree/Declaration.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Type.h"
+
+#include "Common/UniqueName.h"
+#include "Common/utility.h"
+
+namespace GenPoly {
+
+	/// Abstracts type equality for a list of parameter types
+	struct TypeList {
+		TypeList() : params() {}
+		TypeList( const std::list< Type* > &_params ) : params() { cloneAll(_params, params); }
+		TypeList( std::list< Type* > &&_params ) : params( _params ) {}
+
+		TypeList( const TypeList &that ) : params() { cloneAll(that.params, params); }
+		TypeList( TypeList &&that ) : params( std::move( that.params ) ) {}
+
+		/// Extracts types from a list of TypeExpr*
+		TypeList( const std::list< TypeExpr* >& _params ) : params() {
+			for ( std::list< TypeExpr* >::const_iterator param = _params.begin(); param != _params.end(); ++param ) {
+				params.push_back( (*param)->get_type()->clone() );
+			}
+		}
+
+		TypeList& operator= ( const TypeList &that ) {
+			deleteAll( params );
+
+			params.clear();
+			cloneAll( that.params, params );
+
+			return *this;
+		}
+
+		TypeList& operator= ( TypeList &&that ) {
+			deleteAll( params );
+
+			params = std::move( that.params );
+
+			return *this;
+		}
+
+		~TypeList() { deleteAll( params ); }
+
+		bool operator== ( const TypeList& that ) const {
+			if ( params.size() != that.params.size() ) return false;
+
+			SymTab::Indexer dummy;
+			for ( std::list< Type* >::const_iterator it = params.begin(), jt = that.params.begin(); it != params.end(); ++it, ++jt ) {
+				if ( ! ResolvExpr::typesCompatible( *it, *jt, dummy ) ) return false;
+			}
+			return true;
+		}
+
+		std::list< Type* > params;  ///< Instantiation parameters
+	};
+	
+	/// Maps a key and a TypeList to the some value, accounting for scope
+	template< typename Key, typename Value >
+	class InstantiationMap {
+		/// Wraps value for a specific (Key, TypeList) combination
+		typedef std::pair< TypeList, Value* > Instantiation;
+		/// List of TypeLists paired with their appropriate values
+		typedef std::vector< Instantiation > ValueList;
+		/// Underlying map type; maps keys to a linear list of corresponding TypeLists and values
+		typedef ScopedMap< Key*, ValueList > InnerMap;
+
+		InnerMap instantiations;  ///< instantiations
+
+	public:
+		/// Starts a new scope
+		void beginScope() { instantiations.beginScope(); }
+
+		/// Ends a scope
+		void endScope() { instantiations.endScope(); }
+
+		/// Gets the value for the (key, typeList) pair, returns NULL on none such.
+		Value *lookup( Key *key, const std::list< TypeExpr* >& params ) const {
+			TypeList typeList( params );
+
+			// scan scopes for matches to the key
+			for ( typename InnerMap::const_iterator insts = instantiations.find( key ); insts != instantiations.end(); insts = instantiations.findNext( insts, key ) ) {
+				for ( typename ValueList::const_reverse_iterator inst = insts->second.rbegin(); inst != insts->second.rend(); ++inst ) {
+					if ( inst->first == typeList ) return inst->second;
+				}
+			}
+			// no matching instantiations found
+			return 0;
+		}
+
+		/// Adds a value for a (key, typeList) pair to the current scope
+		void insert( Key *key, const std::list< TypeExpr* > &params, Value *value ) {
+			instantiations[ key ].push_back( Instantiation( TypeList( params ), value ) );
+		}
+	};
+	
+	/// Mutator pass that replaces concrete instantiations of generic types with actual struct declarations, scoped appropriately
+	class GenericInstantiator : public DeclMutator {
+		/// Map of (generic type, parameter list) pairs to concrete type instantiations
+		InstantiationMap< AggregateDecl, AggregateDecl > instantiations;
+		/// Namer for concrete types
+		UniqueName typeNamer;
+
+	public:
+		GenericInstantiator() : DeclMutator(), instantiations(), typeNamer("_conc_") {}
+
+		virtual Type* mutate( StructInstType *inst );
+		virtual Type* mutate( UnionInstType *inst );
+
+		virtual void doBeginScope();
+		virtual void doEndScope();
+	private:
+		/// Wrap instantiation lookup for structs
+		StructDecl* lookup( StructInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (StructDecl*)instantiations.lookup( inst->get_baseStruct(), typeSubs ); }
+		/// Wrap instantiation lookup for unions
+		UnionDecl* lookup( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs ) { return (UnionDecl*)instantiations.lookup( inst->get_baseUnion(), typeSubs ); }
+		/// Wrap instantiation insertion for structs
+		void insert( StructInstType *inst, const std::list< TypeExpr* > &typeSubs, StructDecl *decl ) { instantiations.insert( inst->get_baseStruct(), typeSubs, decl ); }
+		/// Wrap instantiation insertion for unions
+		void insert( UnionInstType *inst, const std::list< TypeExpr* > &typeSubs, UnionDecl *decl ) { instantiations.insert( inst->get_baseUnion(), typeSubs, decl ); }
+	};
+
+	void instantiateGeneric( std::list< Declaration* > &translationUnit ) {
+		GenericInstantiator instantiator;
+		instantiator.mutateDeclarationList( translationUnit );
+	}
+
+	//////////////////////////////////////// GenericInstantiator //////////////////////////////////////////////////
+
+	/// Possible options for a given specialization of a generic type
+	enum class genericType {
+		dtypeStatic,  ///< Concrete instantiation based solely on {d,f}type-to-void conversions
+		concrete,     ///< Concrete instantiation requiring at least one parameter type
+		dynamic       ///< No concrete instantiation
+	};
+
+	genericType& operator |= ( genericType& gt, const genericType& ht ) {
+		switch ( gt ) {
+		case genericType::dtypeStatic:
+			gt = ht;
+			break;
+		case genericType::concrete:
+			if ( ht == genericType::dynamic ) { gt = genericType::dynamic; }
+			break;
+		case genericType::dynamic:
+			// nothing possible
+			break;
+		}
+		return gt;
+	}
+
+	/// Makes substitutions of params into baseParams; returns true if all parameters substituted for a concrete type
+	genericType makeSubstitutions( const std::list< TypeDecl* >& baseParams, const std::list< Expression* >& params, std::list< TypeExpr* >& out ) {
+		genericType gt = genericType::dtypeStatic;
+
+		// substitute concrete types for given parameters, and incomplete types for placeholders
+		std::list< TypeDecl* >::const_iterator baseParam = baseParams.begin();
+		std::list< Expression* >::const_iterator param = params.begin();
+		for ( ; baseParam != baseParams.end() && param != params.end(); ++baseParam, ++param ) {
+			TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
+			assert(paramType && "Aggregate parameters should be type expressions");
+			
+			switch ( (*baseParam)->get_kind() ) {
+			case TypeDecl::Any: {
+				// substitute parameter for otype; makes the type concrete or dynamic depending on the parameter
+				out.push_back( paramType->clone() );
+				gt |= isPolyType( paramType->get_type() ) ? genericType::dynamic : genericType::concrete;
+				break;
+			}
+			case TypeDecl::Dtype:
+				// can pretend that any dtype is `void`
+				out.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
+				break;
+			case TypeDecl::Ftype:
+				// can pretend that any ftype is `void (*)(void)`
+				out.push_back( new TypeExpr( new FunctionType( Type::Qualifiers(), false ) ) );
+				break;
+			}
+		}
+
+		assert( baseParam == baseParams.end() && param == params.end() && "Type parameters should match type variables" );
+		return gt;
+	}
+
+	/// Substitutes types of members of in according to baseParams => typeSubs, appending the result to out
+	void substituteMembers( const std::list< Declaration* >& in, const std::list< TypeDecl* >& baseParams, const std::list< TypeExpr* >& typeSubs,
+							std::list< Declaration* >& out ) {
+		// substitute types into new members
+		TypeSubstitution subs( baseParams.begin(), baseParams.end(), typeSubs.begin() );
+		for ( std::list< Declaration* >::const_iterator member = in.begin(); member != in.end(); ++member ) {
+			Declaration *newMember = (*member)->clone();
+			subs.apply(newMember);
+			out.push_back( newMember );
+		}
+	}
+
+	Type* GenericInstantiator::mutate( StructInstType *inst ) {
+		// mutate subtypes
+		Type *mutated = Mutator::mutate( inst );
+		inst = dynamic_cast< StructInstType* >( mutated );
+		if ( ! inst ) return mutated;
+
+		// exit early if no need for further mutation
+		if ( inst->get_parameters().empty() ) return inst;
+		assert( inst->get_baseParameters() && "Base struct has parameters" );
+
+		// check if type can be concretely instantiated; put substitutions into typeSubs
+		std::list< TypeExpr* > typeSubs;
+		genericType gt = makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs );
+		switch ( gt ) {
+		case genericType::dtypeStatic: // TODO strip params off original decl and reuse here
+		case genericType::concrete:
+		{
+			// make concrete instantiation of generic type
+			StructDecl *concDecl = lookup( inst, typeSubs );
+			if ( ! concDecl ) {
+				// set concDecl to new type, insert type declaration into statements to add
+				concDecl = new StructDecl( typeNamer.newName( inst->get_name() ) );
+				substituteMembers( inst->get_baseStruct()->get_members(), *inst->get_baseParameters(), typeSubs, 	concDecl->get_members() );
+				DeclMutator::addDeclaration( concDecl );
+				insert( inst, typeSubs, concDecl );
+			}
+			StructInstType *newInst = new StructInstType( inst->get_qualifiers(), concDecl->get_name() );
+			newInst->set_baseStruct( concDecl );
+
+			delete inst;
+			inst = newInst;
+			break;
+		}
+
+		case genericType::dynamic:
+			// do nothing
+			break;
+		}
+
+		deleteAll( typeSubs );
+		return inst;
+	}
+
+	Type* GenericInstantiator::mutate( UnionInstType *inst ) {
+		// mutate subtypes
+		Type *mutated = Mutator::mutate( inst );
+		inst = dynamic_cast< UnionInstType* >( mutated );
+		if ( ! inst ) return mutated;
+
+		// exit early if no need for further mutation
+		if ( inst->get_parameters().empty() ) return inst;
+		assert( inst->get_baseParameters() && "Base union has parameters" );
+
+		// check if type can be concretely instantiated; put substitutions into typeSubs
+		std::list< TypeExpr* > typeSubs;
+		genericType gt = makeSubstitutions( *inst->get_baseParameters(), inst->get_parameters(), typeSubs );
+		switch ( gt ) {
+		case genericType::dtypeStatic:  // TODO strip params off original decls and reuse here
+		case genericType::concrete:
+		{
+			// make concrete instantiation of generic type
+			UnionDecl *concDecl = lookup( inst, typeSubs );
+			if ( ! concDecl ) {
+				// set concDecl to new type, insert type declaration into statements to add
+				concDecl = new UnionDecl( typeNamer.newName( inst->get_name() ) );
+				substituteMembers( inst->get_baseUnion()->get_members(), *inst->get_baseParameters(), typeSubs, concDecl->get_members() );
+				DeclMutator::addDeclaration( concDecl );
+				insert( inst, typeSubs, concDecl );
+			}
+			UnionInstType *newInst = new UnionInstType( inst->get_qualifiers(), concDecl->get_name() );
+			newInst->set_baseUnion( concDecl );
+
+			delete inst;
+			inst = newInst;
+			break;
+		}
+		case genericType::dynamic:
+			// do nothing
+			break;
+		}
+
+		deleteAll( typeSubs );
+		return inst;
+	}
+
+	void GenericInstantiator::doBeginScope() {
+		DeclMutator::doBeginScope();
+		instantiations.beginScope();
+	}
+
+	void GenericInstantiator::doEndScope() {
+		DeclMutator::doEndScope();
+		instantiations.endScope();
+	}
+
+} // namespace GenPoly
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/GenPoly/InstantiateGeneric.h
===================================================================
--- src/GenPoly/InstantiateGeneric.h	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
+++ src/GenPoly/InstantiateGeneric.h	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -0,0 +1,34 @@
+//
+// 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.
+//
+// InstantiateGeneric.h --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Aug 04 18:33:00 2016
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Aug 04 18:33:00 2016
+// Update Count     : 1
+//
+
+#ifndef _INSTANTIATEGENERIC_H
+#define _INSTANTIATEGENERIC_H
+
+#include "SynTree/SynTree.h"
+
+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 );
+} // namespace GenPoly
+
+#endif // _INSTANTIATEGENERIC_H
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/GenPoly/module.mk
===================================================================
--- src/GenPoly/module.mk	(revision aea71684e6fdc8b8f2abddf24378fdf621bdd40b)
+++ src/GenPoly/module.mk	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -23,3 +23,4 @@
        GenPoly/CopyParams.cc \
        GenPoly/FindFunction.cc \
-       GenPoly/DeclMutator.cc
+       GenPoly/DeclMutator.cc \
+       GenPoly/InstantiateGeneric.cc
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision aea71684e6fdc8b8f2abddf24378fdf621bdd40b)
+++ src/Makefile.in	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -122,4 +122,5 @@
 	GenPoly/driver_cfa_cpp-FindFunction.$(OBJEXT) \
 	GenPoly/driver_cfa_cpp-DeclMutator.$(OBJEXT) \
+	GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT) \
 	InitTweak/driver_cfa_cpp-GenInit.$(OBJEXT) \
 	InitTweak/driver_cfa_cpp-FixInit.$(OBJEXT) \
@@ -378,12 +379,12 @@
 	GenPoly/ScrubTyVars.cc GenPoly/Lvalue.cc GenPoly/Specialize.cc \
 	GenPoly/CopyParams.cc GenPoly/FindFunction.cc \
-	GenPoly/DeclMutator.cc InitTweak/GenInit.cc \
-	InitTweak/FixInit.cc InitTweak/FixGlobalInit.cc \
-	InitTweak/InitTweak.cc Parser/parser.yy Parser/lex.ll \
-	Parser/TypedefTable.cc Parser/ParseNode.cc \
-	Parser/DeclarationNode.cc Parser/ExpressionNode.cc \
-	Parser/StatementNode.cc Parser/InitializerNode.cc \
-	Parser/TypeData.cc Parser/LinkageSpec.cc \
-	Parser/parseutility.cc Parser/Parser.cc \
+	GenPoly/DeclMutator.cc GenPoly/InstantiateGeneric.cc \
+	InitTweak/GenInit.cc InitTweak/FixInit.cc \
+	InitTweak/FixGlobalInit.cc InitTweak/InitTweak.cc \
+	Parser/parser.yy Parser/lex.ll Parser/TypedefTable.cc \
+	Parser/ParseNode.cc Parser/DeclarationNode.cc \
+	Parser/ExpressionNode.cc Parser/StatementNode.cc \
+	Parser/InitializerNode.cc Parser/TypeData.cc \
+	Parser/LinkageSpec.cc Parser/parseutility.cc Parser/Parser.cc \
 	ResolvExpr/AlternativeFinder.cc ResolvExpr/Alternative.cc \
 	ResolvExpr/Unify.cc ResolvExpr/PtrsAssignable.cc \
@@ -589,4 +590,6 @@
 GenPoly/driver_cfa_cpp-DeclMutator.$(OBJEXT): GenPoly/$(am__dirstamp) \
 	GenPoly/$(DEPDIR)/$(am__dirstamp)
+GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT):  \
+	GenPoly/$(am__dirstamp) GenPoly/$(DEPDIR)/$(am__dirstamp)
 InitTweak/$(am__dirstamp):
 	@$(MKDIR_P) InitTweak
@@ -833,4 +836,5 @@
 	-rm -f GenPoly/driver_cfa_cpp-FindFunction.$(OBJEXT)
 	-rm -f GenPoly/driver_cfa_cpp-GenPoly.$(OBJEXT)
+	-rm -f GenPoly/driver_cfa_cpp-InstantiateGeneric.$(OBJEXT)
 	-rm -f GenPoly/driver_cfa_cpp-Lvalue.$(OBJEXT)
 	-rm -f GenPoly/driver_cfa_cpp-PolyMutator.$(OBJEXT)
@@ -943,4 +947,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-FindFunction.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-GenPoly.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-Lvalue.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@GenPoly/$(DEPDIR)/driver_cfa_cpp-PolyMutator.Po@am__quote@
@@ -1408,4 +1413,18 @@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-DeclMutator.obj `if test -f 'GenPoly/DeclMutator.cc'; then $(CYGPATH_W) 'GenPoly/DeclMutator.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/DeclMutator.cc'; fi`
 
+GenPoly/driver_cfa_cpp-InstantiateGeneric.o: GenPoly/InstantiateGeneric.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-InstantiateGeneric.o -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.o `test -f 'GenPoly/InstantiateGeneric.cc' || echo '$(srcdir)/'`GenPoly/InstantiateGeneric.cc
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='GenPoly/InstantiateGeneric.cc' object='GenPoly/driver_cfa_cpp-InstantiateGeneric.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.o `test -f 'GenPoly/InstantiateGeneric.cc' || echo '$(srcdir)/'`GenPoly/InstantiateGeneric.cc
+
+GenPoly/driver_cfa_cpp-InstantiateGeneric.obj: GenPoly/InstantiateGeneric.cc
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT GenPoly/driver_cfa_cpp-InstantiateGeneric.obj -MD -MP -MF GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.obj `if test -f 'GenPoly/InstantiateGeneric.cc'; then $(CYGPATH_W) 'GenPoly/InstantiateGeneric.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/InstantiateGeneric.cc'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Tpo GenPoly/$(DEPDIR)/driver_cfa_cpp-InstantiateGeneric.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='GenPoly/InstantiateGeneric.cc' object='GenPoly/driver_cfa_cpp-InstantiateGeneric.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o GenPoly/driver_cfa_cpp-InstantiateGeneric.obj `if test -f 'GenPoly/InstantiateGeneric.cc'; then $(CYGPATH_W) 'GenPoly/InstantiateGeneric.cc'; else $(CYGPATH_W) '$(srcdir)/GenPoly/InstantiateGeneric.cc'; fi`
+
 InitTweak/driver_cfa_cpp-GenInit.o: InitTweak/GenInit.cc
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT InitTweak/driver_cfa_cpp-GenInit.o -MD -MP -MF InitTweak/$(DEPDIR)/driver_cfa_cpp-GenInit.Tpo -c -o InitTweak/driver_cfa_cpp-GenInit.o `test -f 'InitTweak/GenInit.cc' || echo '$(srcdir)/'`InitTweak/GenInit.cc
Index: src/main.cc
===================================================================
--- src/main.cc	(revision aea71684e6fdc8b8f2abddf24378fdf621bdd40b)
+++ src/main.cc	(revision ea5daeb4b5e91cb1198c40e000259aabd648fe5a)
@@ -28,4 +28,5 @@
 #include "GenPoly/Box.h"
 #include "GenPoly/CopyParams.h"
+#include "GenPoly/InstantiateGeneric.h"
 #include "CodeGen/Generate.h"
 #include "CodeGen/FixNames.h"
@@ -312,4 +313,6 @@
 		}
 
+		OPTPRINT("instantiateGenerics")
+		GenPoly::instantiateGeneric( translationUnit );
 		OPTPRINT( "copyParams" );
 		GenPoly::copyParams( translationUnit );
