Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision d9fa60af0bc172d6842f414cb608e0615d3582a5)
+++ src/SymTab/Autogen.cc	(revision 186fd864a423a60033d1f353374a4070a3294b18)
@@ -32,4 +32,7 @@
 		std::list< Declaration * > &get_declsToAdd() { return declsToAdd; }
 
+		typedef Visitor Parent;
+		using Parent::visit;
+
 		virtual void visit( EnumDecl *enumDecl );
 		virtual void visit( StructDecl *structDecl );
@@ -63,56 +66,72 @@
 	}
 
-	template< typename OutputIterator >
-	void makeUnionFieldsAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, OutputIterator out ) {
-		UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
-		copy->get_args().push_back( new VariableExpr( dstParam ) );
-		copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
-		copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
-
-		*out++ = new ExprStmt( noLabels, copy );
-	}
-
-	//E ?=?(E volatile*, int),
-	//  ?=?(E _Atomic volatile*, int);
-	void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
-		FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), refType ), 0 );
-		assignType->get_parameters().push_back( dstParam );
-
-		// void ?{}(E *); void ^?{}(E *);
-		FunctionType * ctorType = assignType->clone();
-		FunctionType * dtorType = assignType->clone();
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, refType->clone(), 0 );
-		assignType->get_parameters().push_back( srcParam );
-		// void ?{}(E *, E);
-		FunctionType *copyCtorType = assignType->clone();
-
-		// T ?=?(E *, E);
-		ObjectDecl *returnVal = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, refType->clone(), 0 );
-		assignType->get_returnVals().push_back( returnVal );
-
-		// xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)?
-		// right now these cases work, but that might change.
-
-		// Routines at global scope marked "static" to prevent multiple definitions is separate translation units
+	/// inserts a forward declaration for functionDecl into declsToAdd
+	void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
+		FunctionDecl * decl = functionDecl->clone();
+		delete decl->get_statements();
+		decl->set_statements( NULL );
+		declsToAdd.push_back( decl );
+		decl->fixUniqueId();
+	}
+
+	/// given type T, generate type of default ctor/dtor, i.e. function type void (*) (T *)
+	FunctionType * genDefaultType( Type * paramType ) {
+		FunctionType *ftype = new FunctionType( Type::Qualifiers(), false );
+		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), paramType->clone() ), nullptr );
+		ftype->get_parameters().push_back( dstParam );
+
+		return ftype;
+	}
+
+	/// given type T, generate type of copy ctor, i.e. function type void (*) (T *, T)
+	FunctionType * genCopyType( Type * paramType ) {
+		FunctionType *ftype = genDefaultType( paramType );
+		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
+		ftype->get_parameters().push_back( srcParam );
+		return ftype;
+	}
+
+	/// given type T, generate type of assignment, i.e. function type T (*) (T *, T)
+	FunctionType * genAssignType( Type * paramType, const std::list< Expression* > & params = std::list< Expression* >() ) {
+		FunctionType *ftype = genCopyType( paramType );
+		ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, paramType->clone(), nullptr );
+		ftype->get_returnVals().push_back( returnVal );
+		return ftype;
+	}
+
+	/// true if the aggregate's layout is dynamic
+	template< typename AggrDecl >
+	bool hasDynamicLayout( AggrDecl * aggregateDecl ) {
+		for ( TypeDecl * param : aggregateDecl->get_parameters() ) {
+			if ( param->get_kind() == TypeDecl::Any ) return true;
+		}
+		return false;
+	}
+
+	/// generate a function decl from a name and type. Nesting depth determines whether
+	/// the declaration is static or not; optional paramter determines if declaration is intrinsic
+	FunctionDecl * genFunc( const std::string & fname, FunctionType * ftype, unsigned int functionNesting, bool isIntrinsic = false  ) {
+		// Routines at global scope marked "static" to prevent multiple definitions in separate translation units
 		// because each unit generates copies of the default routines for each aggregate.
-		// xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
-		// Really they're something of a cross between instrinsic and autogen, so should
-		// probably make a new linkage type
-		FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, assignType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, ctorType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, copyCtorType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, dtorType, new CompoundStmt( noLabels ), true, false );
-		assignDecl->fixUniqueId();
-		ctorDecl->fixUniqueId();
-		copyCtorDecl->fixUniqueId();
-		dtorDecl->fixUniqueId();
-
+		DeclarationNode::StorageClass sc = functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static;
+		LinkageSpec::Spec spec = isIntrinsic ? LinkageSpec::Intrinsic : LinkageSpec::AutoGen;
+		FunctionDecl * decl = new FunctionDecl( fname, sc, spec, ftype, new CompoundStmt( noLabels ), true, false );
+		decl->fixUniqueId();
+		return decl;
+	}
+
+	/// generates a single enumeration assignment expression
+	ApplicationExpr * genEnumAssign( FunctionType * ftype, FunctionDecl * assignDecl ) {
 		// enum copy construct and assignment is just C-style assignment.
 		// this looks like a bad recursive call, but code gen will turn it into
 		// a C-style assignment.
 		// This happens before function pointer type conversion, so need to do it manually here
+		// NOTE: ftype is not necessarily the functionType belonging to assignDecl - ftype is the
+		// type of the function that this expression is being generated for (so that the correct
+		// parameters) are using in the variable exprs
+		assert( ftype->get_parameters().size() == 2 );
+		ObjectDecl * dstParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
+		ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
+
 		VariableExpr * assignVarExpr = new VariableExpr( assignDecl );
 		Type * assignVarExprType = assignVarExpr->get_result();
@@ -122,8 +141,35 @@
 		assignExpr->get_args().push_back( new VariableExpr( dstParam ) );
 		assignExpr->get_args().push_back( new VariableExpr( srcParam ) );
+		return assignExpr;
+	}
+
+	// E ?=?(E volatile*, int),
+	//   ?=?(E _Atomic volatile*, int);
+	void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
+
+		// T ?=?(E *, E);
+		FunctionType *assignType = genAssignType( refType );
+
+		// void ?{}(E *); void ^?{}(E *);
+		FunctionType * ctorType = genDefaultType( refType->clone() );
+		FunctionType * dtorType = genDefaultType( refType->clone() );
+
+		// void ?{}(E *, E);
+		FunctionType *copyCtorType = genCopyType( refType->clone() );
+
+		// xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)?
+		// right now these cases work, but that might change.
+
+		// xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
+		// Really they're something of a cross between instrinsic and autogen, so should
+		// probably make a new linkage type
+		FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting, true );
+		FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting, true );
+		FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting, true );
+		FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting, true );
 
 		// body is either return stmt or expr stmt
-		assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, assignExpr ) );
-		copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, assignExpr->clone() ) );
+		assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, genEnumAssign( assignType, assignDecl ) ) );
+		copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, genEnumAssign( copyCtorType, assignDecl ) ) );
 
 		declsToAdd.push_back( assignDecl );
@@ -133,46 +179,6 @@
 	}
 
-	/// Clones a reference type, replacing any parameters it may have with a clone of the provided list
-	template< typename GenericInstType >
-	GenericInstType *cloneWithParams( GenericInstType *refType, const std::list< Expression* >& params ) {
-		GenericInstType *clone = refType->clone();
-		clone->get_parameters().clear();
-		cloneAll( params, clone->get_parameters() );
-		return clone;
-	}
-
-	/// Creates a new type decl that's the same as src, but renamed and with only the ?=?, ?{} (default and copy), and ^?{} assertions (for complete types only)
-	TypeDecl *cloneAndRename( TypeDecl *src, const std::string &name ) {
-		// TypeDecl *dst = new TypeDecl( name, src->get_storageClass(), 0, src->get_kind() );
-
-		// if ( src->get_kind() == TypeDecl::Any ) {
-		// 	TypeInstType *opParamType = new TypeInstType( Type::Qualifiers(), name, dst );
-		// 	FunctionType *opFunctionType = new FunctionType( Type::Qualifiers(), false );
-		// 	opFunctionType->get_parameters().push_back(
-		// 		new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), opParamType->clone() ), 0 ) );
-		// 	FunctionDecl *ctorAssert = new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false );
-		// 	FunctionDecl *dtorAssert = new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false );
-
-		// 	opFunctionType->get_parameters().push_back(
-		// 		new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, opParamType, 0 ) );
-		// 	FunctionDecl *copyCtorAssert = new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false );
-
-		// 	opFunctionType->get_returnVals().push_back(
-		// 		new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, opParamType->clone(), 0 ) );
-		// 	FunctionDecl *assignAssert = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType, 0, false, false );
-
-
-		// 	dst->get_assertions().push_back( assignAssert );
-		// 	dst->get_assertions().push_back( ctorAssert );
-		// 	dst->get_assertions().push_back( dtorAssert );
-		// 	dst->get_assertions().push_back( copyCtorAssert );
-		// }
-
-		TypeDecl *dst = new TypeDecl( src->get_name(), src->get_storageClass(), 0, src->get_kind() );
-		cloneAll(src->get_assertions(), dst->get_assertions());
-		return dst;
-	}
-
-	void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout, bool forward = true ) {
+	/// generates a single struct member operation (constructor call, destructor call, assignment call)
+	void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool isDynamicLayout, bool forward = true ) {
 		ObjectDecl * returnVal = NULL;
 		if ( ! func->get_functionType()->get_returnVals().empty() ) {
@@ -194,6 +200,7 @@
 	}
 
+	/// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies
 	template<typename Iterator>
-	void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout, bool forward = true ) {
+	void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool isDynamicLayout, bool forward = true ) {
 		for ( ; member != end; ++member ) {
 			if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate
@@ -231,5 +238,5 @@
 
 				Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : NULL;
-				makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isDynamicLayout, forward );
+				makeStructMemberOp( dstParam, srcselect, field, func, isDynamicLayout, forward );
 			} // if
 		} // for
@@ -239,5 +246,5 @@
 	/// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields.
 	template<typename Iterator>
-	void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isDynamicLayout ) {
+	void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, bool isDynamicLayout ) {
 		FunctionType * ftype = func->get_functionType();
 		std::list<DeclarationWithType*> & params = ftype->get_parameters();
@@ -265,9 +272,9 @@
 					// matching parameter, initialize field with copy ctor
 					Expression *srcselect = new VariableExpr(*parameter);
-					makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isDynamicLayout );
+					makeStructMemberOp( dstParam, srcselect, field, func, isDynamicLayout );
 					++parameter;
 				} else {
 					// no matching parameter, initialize field with default ctor
-					makeStructMemberOp( dstParam, NULL, field, func, genericSubs, isDynamicLayout );
+					makeStructMemberOp( dstParam, NULL, field, func, isDynamicLayout );
 				}
 			}
@@ -275,56 +282,29 @@
 	}
 
-	void addForwardDecl( FunctionDecl * functionDecl, std::list< Declaration * > & declsToAdd ) {
-		FunctionDecl * decl = functionDecl->clone();
-		delete decl->get_statements();
-		decl->set_statements( NULL );
-		declsToAdd.push_back( decl );
-		decl->fixUniqueId();
-	}
-
+	/// generates struct constructors, destructor, and assignment functions
 	void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
-		FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
 
 		// Make function polymorphic in same parameters as generic struct, if applicable
-		bool isDynamicLayout = false;  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
-		std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters();
-		std::list< Expression* > structParams;  // List of matching parameters to put on types
-		TypeSubstitution genericSubs; // Substitutions to make to member types of struct
-		for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) {
-			if ( (*param)->get_kind() == TypeDecl::Any ) isDynamicLayout = true;
-			TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() );
-			assignType->get_forall().push_back( typeParam );
-			TypeInstType *newParamType = new TypeInstType( Type::Qualifiers(), typeParam->get_name(), typeParam );
-			genericSubs.add( (*param)->get_name(), newParamType );
-			structParams.push_back( new TypeExpr( newParamType ) );
-		}
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, structParams ) ), 0 );
-		assignType->get_parameters().push_back( dstParam );
+		const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
+		bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union)
+
+		// T ?=?(T *, T);
+		FunctionType *assignType = genAssignType( refType );
+		cloneAll( typeParams, assignType->get_forall() );
 
 		// void ?{}(T *); void ^?{}(T *);
-		FunctionType *ctorType = assignType->clone();
-		FunctionType *dtorType = assignType->clone();
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 );
-		assignType->get_parameters().push_back( srcParam );
+		FunctionType *ctorType = genDefaultType( refType );
+		cloneAll( typeParams, ctorType->get_forall() );
+		FunctionType *dtorType = genDefaultType( refType );
+		cloneAll( typeParams, dtorType->get_forall() );
 
 		// void ?{}(T *, T);
-		FunctionType *copyCtorType = assignType->clone();
-
-		// T ?=?(T *, T);
-		ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 );
-		assignType->get_returnVals().push_back( returnVal );
-
-		// Routines at global scope marked "static" to prevent multiple definitions is separate translation units
-		// because each unit generates copies of the default routines for each aggregate.
-		FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, assignType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, copyCtorType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, dtorType, new CompoundStmt( noLabels ), true, false );
-		assignDecl->fixUniqueId();
-		ctorDecl->fixUniqueId();
-		copyCtorDecl->fixUniqueId();
-		dtorDecl->fixUniqueId();
+		FunctionType *copyCtorType = genCopyType( refType );
+		cloneAll( typeParams, copyCtorType->get_forall() );
+
+		FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
+		FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting );
+		FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
+		FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
 
 		if ( functionNesting == 0 ) {
@@ -359,7 +339,6 @@
 			}
 			memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) );
-			FunctionDecl * ctor = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, memCtorType->clone(), new CompoundStmt( noLabels ), true, false );
-			ctor->fixUniqueId();
-			makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, genericSubs, isDynamicLayout );
+			FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
+			makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, isDynamicLayout );
 			memCtors.push_back( ctor );
 		}
@@ -367,11 +346,15 @@
 
 		// generate appropriate calls to member ctor, assignment
-		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, genericSubs, isDynamicLayout );
-		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, genericSubs, isDynamicLayout );
-		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, genericSubs, isDynamicLayout );
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, isDynamicLayout );
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, isDynamicLayout );
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, isDynamicLayout );
 		// needs to do everything in reverse, so pass "forward" as false
-		makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, genericSubs, isDynamicLayout, false );
-
-		if ( ! isDynamicLayout ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+		makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, isDynamicLayout, false );
+
+		if ( ! isDynamicLayout ) {
+			assert( assignType->get_parameters().size() == 2 );
+			ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( assignType->get_parameters().back() );
+			assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+		}
 
 		declsToAdd.push_back( assignDecl );
@@ -382,53 +365,66 @@
 	}
 
+	/// generate a single union assignment expression (using memcpy)
+	template< typename OutputIterator >
+	void makeUnionFieldsAssignment( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {
+		UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
+		copy->get_args().push_back( new VariableExpr( dstParam ) );
+		copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
+		copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
+		*out++ = new ExprStmt( noLabels, copy );
+	}
+
+	/// generates the body of a union assignment/copy constructor/field constructor
+	void makeUnionAssignBody( FunctionDecl * funcDecl, bool isDynamicLayout ) {
+		FunctionType * ftype = funcDecl->get_functionType();
+		assert( ftype->get_parameters().size() == 2 );
+		ObjectDecl * dstParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
+		ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
+		ObjectDecl * returnVal = nullptr;
+		if ( ! ftype->get_returnVals().empty() ) {
+			returnVal = safe_dynamic_cast< ObjectDecl * >( ftype->get_returnVals().front() );
+		}
+
+		makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( funcDecl->get_statements()->get_kids() ) );
+		if ( returnVal ) {
+			if ( isDynamicLayout ) makeUnionFieldsAssignment( srcParam, returnVal, back_inserter( funcDecl->get_statements()->get_kids() ) );
+			else funcDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+		}
+	}
+
+	/// generates union constructors, destructors, and assignment operator
 	void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) {
-		FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
-
 		// Make function polymorphic in same parameters as generic union, if applicable
-		bool isDynamicLayout = false; // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
-		std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters();
-		std::list< Expression* > unionParams;  // List of matching parameters to put on types
-		for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) {
-			if ( (*param)->get_kind() == TypeDecl::Any ) isDynamicLayout = true;
-			TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() );
-			assignType->get_forall().push_back( typeParam );
-			unionParams.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeParam->get_name(), typeParam ) ) );
-		}
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, unionParams ) ), 0 );
-		assignType->get_parameters().push_back( dstParam );
+		const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
+		bool isDynamicLayout = hasDynamicLayout( aggregateDecl );  // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct)
 
 		// default ctor/dtor need only first parameter
-		FunctionType * ctorType = assignType->clone();
-		FunctionType * dtorType = assignType->clone();
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
-		assignType->get_parameters().push_back( srcParam );
+		// void ?{}(T *); void ^?{}(T *);
+		FunctionType *ctorType = genDefaultType( refType );
+		cloneAll( typeParams, ctorType->get_forall() );
+		FunctionType *dtorType = genDefaultType( refType );
+		cloneAll( typeParams, dtorType->get_forall() );
 
 		// copy ctor needs both parameters
-		FunctionType * copyCtorType = assignType->clone();
+		// void ?{}(T *, T);
+		FunctionType *copyCtorType = genCopyType( refType );
+		cloneAll( typeParams, copyCtorType->get_forall() );
 
 		// assignment needs both and return value
-		ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
-		assignType->get_returnVals().push_back( returnVal );
+		// T ?=?(T *, T);
+		FunctionType *assignType = genAssignType( refType );
+		cloneAll( typeParams, assignType->get_forall() );
 
 		// Routines at global scope marked "static" to prevent multiple definitions is separate translation units
 		// because each unit generates copies of the default routines for each aggregate.
-		FunctionDecl *assignDecl = new FunctionDecl( "?=?",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, assignType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *ctorDecl = new FunctionDecl( "?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, new CompoundStmt( noLabels ), true, false );
-		FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, copyCtorType, NULL, true, false );
-		FunctionDecl *dtorDecl = new FunctionDecl( "^?{}",  functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, dtorType, new CompoundStmt( noLabels ), true, false );
-
-		assignDecl->fixUniqueId();
-		ctorDecl->fixUniqueId();
-		copyCtorDecl->fixUniqueId();
-		dtorDecl->fixUniqueId();
-
-		makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( assignDecl->get_statements()->get_kids() ) );
-		if ( isDynamicLayout ) makeUnionFieldsAssignment( srcParam, returnVal, back_inserter( assignDecl->get_statements()->get_kids() ) );
-		else assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+		FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting );
+		FunctionDecl *ctorDecl = genFunc( "?{}",  ctorType, functionNesting );
+		FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
+		FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
+
+		makeUnionAssignBody( assignDecl, isDynamicLayout );
 
 		// body of assignment and copy ctor is the same
-		copyCtorDecl->set_statements( assignDecl->get_statements()->clone() );
+		makeUnionAssignBody( copyCtorDecl, isDynamicLayout );
 
 		// create a constructor which takes the first member type as a parameter.
@@ -443,8 +439,7 @@
 				FunctionType * memCtorType = ctorType->clone();
 				memCtorType->get_parameters().push_back( srcParam );
-				FunctionDecl * ctor = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, memCtorType, new CompoundStmt( noLabels ), true, false );
-				ctor->fixUniqueId();
-
-				makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( ctor->get_statements()->get_kids() ) );
+				FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting );
+
+				makeUnionAssignBody( ctor, isDynamicLayout );
 				memCtors.push_back( ctor );
 				// only generate a ctor for the first field
@@ -472,4 +467,7 @@
 		if ( ! structDecl->get_members().empty() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) {
 			StructInstType structInst( Type::Qualifiers(), structDecl->get_name() );
+			for ( TypeDecl * typeDecl : structDecl->get_parameters() ) {
+				structInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
+			}
 			structInst.set_baseStruct( structDecl );
 			makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd );
@@ -482,4 +480,7 @@
 			UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() );
 			unionInst.set_baseUnion( unionDecl );
+			for ( TypeDecl * typeDecl : unionDecl->get_parameters() ) {
+				unionInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
+			}
 			makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAdd );
 		} // if
@@ -487,17 +488,17 @@
 
 	void AutogenerateRoutines::visit( TypeDecl *typeDecl ) {
-		CompoundStmt *stmts = 0;
 		TypeInstType *typeInst = new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), false );
 		typeInst->set_baseType( typeDecl );
-		ObjectDecl *src = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, typeInst->clone(), 0 );
-		ObjectDecl *dst = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), typeInst->clone() ), 0 );
+		ObjectDecl *src = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, typeInst->clone(), nullptr );
+		ObjectDecl *dst = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), typeInst->clone() ), nullptr );
+
+		std::list< Statement * > stmts;
 		if ( typeDecl->get_base() ) {
 			// xxx - generate ctor/dtors for typedecls, e.g.
 			// otype T = int *;
-			stmts = new CompoundStmt( std::list< Label >() );
 			UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) );
 			assign->get_args().push_back( new CastExpr( new VariableExpr( dst ), new PointerType( Type::Qualifiers(), typeDecl->get_base()->clone() ) ) );
 			assign->get_args().push_back( new CastExpr( new VariableExpr( src ), typeDecl->get_base()->clone() ) );
-			stmts->get_kids().push_back( new ReturnStmt( std::list< Label >(), assign ) );
+			stmts.push_back( new ReturnStmt( std::list< Label >(), assign ) );
 		} // if
 		FunctionType *type = new FunctionType( Type::Qualifiers(), false );
@@ -505,5 +506,6 @@
 		type->get_parameters().push_back( dst );
 		type->get_parameters().push_back( src );
-		FunctionDecl *func = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::AutoGen, type, stmts, true, false );
+		FunctionDecl *func = genFunc( "?=?", type, functionNesting );
+		func->get_statements()->get_kids() = stmts;
 		declsToAdd.push_back( func );
 	}
