Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 972e6f723601cda15cf0579d257a4373a83330d4)
+++ src/SymTab/Autogen.cc	(revision 972e6f723601cda15cf0579d257a4373a83330d4)
@@ -0,0 +1,474 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Autogen.cc --
+//
+// Author           : Rob Schluntz
+// Created On       : Thu Mar 03 15:45:56 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Thu Mar 03 15:45:56 2016
+// Update Count     : 1
+//
+
+#include <list>
+#include <iterator>
+#include "SynTree/Visitor.h"
+#include "SynTree/Type.h"
+#include "SynTree/Statement.h"
+#include "SynTree/TypeSubstitution.h"
+#include "Common/utility.h"
+#include "AddVisit.h"
+#include "MakeLibCfa.h"
+#include "Autogen.h"
+
+namespace SymTab {
+	class AutogenerateRoutines : public Visitor {
+		public:
+		std::list< Declaration * > &get_declsToAdd() { return declsToAdd; }
+
+		virtual void visit( EnumDecl *enumDecl );
+		virtual void visit( StructDecl *structDecl );
+		virtual void visit( UnionDecl *structDecl );
+		virtual void visit( TypeDecl *typeDecl );
+		virtual void visit( ContextDecl *ctxDecl );
+		virtual void visit( FunctionDecl *functionDecl );
+
+		virtual void visit( FunctionType *ftype );
+		virtual void visit( PointerType *ftype );
+
+		virtual void visit( CompoundStmt *compoundStmt );
+		virtual void visit( IfStmt *ifStmt );
+		virtual void visit( WhileStmt *whileStmt );
+		virtual void visit( ForStmt *forStmt );
+		virtual void visit( SwitchStmt *switchStmt );
+		virtual void visit( ChooseStmt *chooseStmt );
+		virtual void visit( CaseStmt *caseStmt );
+		virtual void visit( CatchStmt *catchStmt );
+
+		AutogenerateRoutines() : functionNesting( 0 ) {}
+		private:
+		template< typename StmtClass > void visitStatement( StmtClass *stmt );
+
+		std::list< Declaration * > declsToAdd;
+		std::set< std::string > structsDone;
+		unsigned int functionNesting;     // current level of nested functions
+	};
+
+	void autogenerateRoutines( std::list< Declaration * > &translationUnit ) {
+		AutogenerateRoutines visitor;
+		acceptAndAdd( translationUnit, visitor, false );
+	}
+
+	template< typename OutputIterator >
+	void makeScalarFunction( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, std::string fname, OutputIterator out ) {
+		ObjectDecl *obj = dynamic_cast<ObjectDecl *>( member );
+		// unnamed bit fields are not copied as they cannot be accessed
+		if ( obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL ) return;
+
+		// want to be able to generate assignment, ctor, and dtor generically,
+		// so fname is either ?=?, ?{}, or ^?{}
+		UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
+
+		UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
+		derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
+
+		// do something special for unnamed members
+		Expression *dstselect = new AddressExpr( new MemberExpr( member, derefExpr ) );
+		fExpr->get_args().push_back( dstselect );
+
+		Expression *srcselect = new MemberExpr( member, new VariableExpr( srcParam ) );
+		fExpr->get_args().push_back( srcselect );
+
+		*out++ = new ExprStmt( noLabels, fExpr );
+	}
+
+	template< typename OutputIterator >
+	void makeUnionFieldsAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, UnionInstType *unionType, 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( unionType ) );
+
+		*out++ = new ExprStmt( noLabels, copy );
+	}
+
+	//E ?=?(E volatile*, int),
+	//  ?=?(E _Atomic volatile*, int);
+	void makeEnumAssignment( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) {
+		FunctionType *assignType = new FunctionType( Type::Qualifiers(), false );
+
+		ObjectDecl *returnVal = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, refType->clone(), 0 );
+		assignType->get_returnVals().push_back( returnVal );
+
+		// need two assignment operators with different types
+		FunctionType * assignType2 = assignType->clone();
+
+		// E ?=?(E volatile *, E)
+		Type *etype = refType->clone();
+		// etype->get_qualifiers() += Type::Qualifiers(false, true, false, false, false, false);
+
+		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), etype ), 0 );
+		assignType->get_parameters().push_back( dstParam );
+
+		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, etype->clone(), 0 );
+		assignType->get_parameters().push_back( srcParam );
+
+		// E ?=?(E volatile *, int)
+		assignType2->get_parameters().push_back( dstParam->clone() );
+		BasicType * paramType = new BasicType(Type::Qualifiers(), BasicType::SignedInt);
+		ObjectDecl *srcParam2 = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, paramType, 0 );
+		assignType2->get_parameters().push_back( srcParam2 );
+
+		// 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.
+
+		// since there is no definition, these should not be inline
+		// make these intrinsic so that the code generator does not make use of them
+		FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, assignType, 0, false, false );
+		assignDecl->fixUniqueId();
+		FunctionDecl *assignDecl2 = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, assignType2, 0, false, false );
+		assignDecl2->fixUniqueId();
+
+		// these should be built in the same way that the prelude
+		// functions are, so build a list containing the prototypes
+		// and allow MakeLibCfa to autogenerate the bodies.
+		std::list< Declaration * > assigns;
+		assigns.push_back( assignDecl );
+		assigns.push_back( assignDecl2 );
+
+		LibCfa::makeLibCfa( assigns );
+
+		// need to remove the prototypes, since this may be nested in a routine
+		for (int start = 0, end = assigns.size()/2; start < end; start++) {
+			delete assigns.front();
+			assigns.pop_front();
+		} // for
+
+		declsToAdd.insert( declsToAdd.begin(), assigns.begin(), assigns.end() );
+	}
+
+	/// 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 ?=? assertion (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 ) {
+			// just include assignment operator assertion
+			TypeInstType *assignParamType = new TypeInstType( Type::Qualifiers(), name, dst );
+			FunctionType *assignFunctionType = new FunctionType( Type::Qualifiers(), false );
+			assignFunctionType->get_returnVals().push_back(
+				new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, assignParamType->clone(), 0 ) );
+			assignFunctionType->get_parameters().push_back(
+				new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), assignParamType->clone() ), 0 ) );
+			assignFunctionType->get_parameters().push_back(
+				new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, assignParamType, 0 ) );
+			FunctionDecl *assignAssert = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, assignFunctionType, 0, false, false );
+			dst->get_assertions().push_back( assignAssert );
+		}
+
+		return dst;
+	}
+
+	template<typename Iterator>
+	void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) {
+		for ( ; member != end; ++member ) {
+			if ( DeclarationWithType *dwt = dynamic_cast< DeclarationWithType * >( *member ) ) {
+				// query the type qualifiers of this field and skip assigning it if it is marked const.
+				// If it is an array type, we need to strip off the array layers to find its qualifiers.
+				Type * type = dwt->get_type();
+				while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) {
+					type = at->get_base();
+				}
+
+				if ( type->get_qualifiers().isConst ) {
+					// don't assign const members
+					continue;
+				}
+
+				assert( ! func->get_functionType()->get_parameters().empty() );
+				ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().front() );
+				ObjectDecl * srcParam = NULL;
+				if ( func->get_functionType()->get_parameters().size() == 2 ) {
+					srcParam = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_parameters().back() );
+				}
+				ObjectDecl * returnVal = NULL;
+				if ( ! func->get_functionType()->get_returnVals().empty() ) {
+					returnVal = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_returnVals().front() );
+				}
+				// srcParam may be NULL, in which case we have default ctor/dtor
+				assert( dstParam );
+
+
+				DeclarationWithType * memType = dwt;
+				if ( isGeneric ) {
+					// rewrite member type in terms of the type variables on this operator
+					memType = memType->clone();
+					genericSubs.apply( memType );
+				}
+
+
+				// assign to destination (and return value if generic)
+				if ( ArrayType *array = dynamic_cast< ArrayType * >( memType->get_type() ) ) {
+					UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
+					derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
+					Expression *dstselect = new MemberExpr( memType, derefExpr );
+					Expression *srcselect = srcParam ? new MemberExpr( memType, new VariableExpr( srcParam ) ) : NULL;
+
+					makeArrayFunction( srcselect, dstselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
+					if ( isGeneric && returnVal ) {
+						UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) );
+						derefRet->get_args().push_back( new VariableExpr( returnVal ) );
+						Expression *retselect = new MemberExpr( memType, derefRet );
+
+						makeArrayFunction( srcselect, retselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
+					}
+				} else {
+					makeScalarFunction( srcParam, dstParam, memType, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
+					if ( isGeneric && returnVal ) makeScalarFunction( srcParam, returnVal, memType, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
+				} // if
+			} // if
+		} // for
+	} // makeStructFunctionBody
+
+	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 isGeneric = 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 ) {
+			isGeneric = 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 );
+
+		// 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 );
+
+		// 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();
+
+		// generate appropriate calls to member ctor, assignment
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, genericSubs, isGeneric );
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, genericSubs, isGeneric );
+		makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, genericSubs, isGeneric );
+		// needs to do everything in reverse, so pass "forward" as false
+		makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, genericSubs, isGeneric, false );
+
+		if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+
+		declsToAdd.push_back( assignDecl );
+		declsToAdd.push_back( ctorDecl );
+		declsToAdd.push_back( copyCtorDecl );
+		declsToAdd.push_back( dtorDecl );
+	}
+
+	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 isGeneric = 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 ) {
+			isGeneric = 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 );
+
+		// 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 );
+
+		// copy ctor needs both parameters
+		FunctionType * copyCtorType = assignType->clone();
+
+		// 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 );
+
+		// 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, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
+		if ( isGeneric ) makeUnionFieldsAssignment( srcParam, returnVal, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) );
+
+		if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+
+		// body of assignment and copy ctor is the same
+		copyCtorDecl->set_statements( assignDecl->get_statements()->clone() );
+
+		declsToAdd.push_back( assignDecl );
+		declsToAdd.push_back( ctorDecl );
+		declsToAdd.push_back( copyCtorDecl );
+		declsToAdd.push_back( dtorDecl );
+	}
+
+	void AutogenerateRoutines::visit( EnumDecl *enumDecl ) {
+		if ( ! enumDecl->get_members().empty() ) {
+			EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() );
+			// enumInst->set_baseEnum( enumDecl );
+			// declsToAdd.push_back(
+			makeEnumAssignment( enumDecl, enumInst, functionNesting, declsToAdd );
+		}
+	}
+
+	void AutogenerateRoutines::visit( StructDecl *structDecl ) {
+		if ( ! structDecl->get_members().empty() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) {
+			StructInstType structInst( Type::Qualifiers(), structDecl->get_name() );
+			structInst.set_baseStruct( structDecl );
+			makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd );
+			structsDone.insert( structDecl->get_name() );
+		} // if
+	}
+
+	void AutogenerateRoutines::visit( UnionDecl *unionDecl ) {
+		if ( ! unionDecl->get_members().empty() ) {
+			UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() );
+			unionInst.set_baseUnion( unionDecl );
+			makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAdd );
+		} // if
+	}
+
+	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 );
+		if ( typeDecl->get_base() ) {
+			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 ) );
+		} // if
+		FunctionType *type = new FunctionType( Type::Qualifiers(), false );
+		type->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, typeInst, 0 ) );
+		type->get_parameters().push_back( dst );
+		type->get_parameters().push_back( src );
+		FunctionDecl *func = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::AutoGen, type, stmts, false, false );
+		declsToAdd.push_back( func );
+	}
+
+	void addDecls( std::list< Declaration * > &declsToAdd, std::list< Statement * > &statements, std::list< Statement * >::iterator i ) {
+		for ( std::list< Declaration * >::iterator decl = declsToAdd.begin(); decl != declsToAdd.end(); ++decl ) {
+			statements.insert( i, new DeclStmt( noLabels, *decl ) );
+		} // for
+		declsToAdd.clear();
+	}
+
+	void AutogenerateRoutines::visit( FunctionType *) {
+		// ensure that we don't add assignment ops for types defined as part of the function
+	}
+
+	void AutogenerateRoutines::visit( PointerType *) {
+		// ensure that we don't add assignment ops for types defined as part of the pointer
+	}
+
+	void AutogenerateRoutines::visit( ContextDecl *) {
+		// ensure that we don't add assignment ops for types defined as part of the context
+	}
+
+	template< typename StmtClass >
+	inline void AutogenerateRoutines::visitStatement( StmtClass *stmt ) {
+		std::set< std::string > oldStructs = structsDone;
+		addVisit( stmt, *this );
+		structsDone = oldStructs;
+	}
+
+	void AutogenerateRoutines::visit( FunctionDecl *functionDecl ) {
+		maybeAccept( functionDecl->get_functionType(), *this );
+		acceptAll( functionDecl->get_oldDecls(), *this );
+		functionNesting += 1;
+		maybeAccept( functionDecl->get_statements(), *this );
+		functionNesting -= 1;
+	}
+
+	void AutogenerateRoutines::visit( CompoundStmt *compoundStmt ) {
+		visitStatement( compoundStmt );
+	}
+
+	void AutogenerateRoutines::visit( IfStmt *ifStmt ) {
+		visitStatement( ifStmt );
+	}
+
+	void AutogenerateRoutines::visit( WhileStmt *whileStmt ) {
+		visitStatement( whileStmt );
+	}
+
+	void AutogenerateRoutines::visit( ForStmt *forStmt ) {
+		visitStatement( forStmt );
+	}
+
+	void AutogenerateRoutines::visit( SwitchStmt *switchStmt ) {
+		visitStatement( switchStmt );
+	}
+
+	void AutogenerateRoutines::visit( ChooseStmt *switchStmt ) {
+		visitStatement( switchStmt );
+	}
+
+	void AutogenerateRoutines::visit( CaseStmt *caseStmt ) {
+		visitStatement( caseStmt );
+	}
+
+	void AutogenerateRoutines::visit( CatchStmt *cathStmt ) {
+		visitStatement( cathStmt );
+	}
+
+} // SymTab
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 972e6f723601cda15cf0579d257a4373a83330d4)
+++ src/SymTab/Autogen.h	(revision 972e6f723601cda15cf0579d257a4373a83330d4)
@@ -0,0 +1,99 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Autogen.h --
+//
+// Author           : Rob Schluntz
+// Created On       : Sun May 17 21:53:34 2015
+// Last Modified By : Rob Schluntz
+// Last Modified On : Tue May 19 16:49:43 2015
+// Update Count     : 1
+//
+
+#ifndef AUTOGEN_H
+#define AUTOGEN_H
+
+#include <string>
+#include "SynTree/Statement.h"
+#include "SynTree/Expression.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Initializer.h"
+
+namespace SymTab {
+  static const std::list< std::string > noLabels;
+
+  /// Generates assignment operators, constructors, and destructor for aggregate types as required
+  void autogenerateRoutines( std::list< Declaration * > &translationUnit );
+
+  // originally makeArrayAssignment - changed to Function because it is now used for ctors and dtors as well
+  // admittedly not a great name change. This used to live in Validate.cc, but has been moved so it can be reused elsewhere
+
+  /// Store in out a loop which calls fname on each element of the array with srcParam and dstParam as arguments.
+  /// If forward is true, loop goes from 0 to N-1, else N-1 to 0
+  template< typename OutputIterator >
+  void makeArrayFunction( Expression *srcParam, Expression *dstParam, ArrayType *array, std::string fname, OutputIterator out, bool forward = true ) {
+    static UniqueName indexName( "_index" );
+
+    // for a flexible array member nothing is done -- user must define own assignment
+    if ( ! array->get_dimension() ) return;
+
+    Expression * begin, * end, * update, * cmp;
+    if ( forward ) {
+      // generate: for ( int i = 0; i < 0; ++i )
+      begin = new NameExpr( "0" );
+      end = array->get_dimension()->clone();
+      cmp = new NameExpr( "?<?" );
+      update = new NameExpr( "++?" );
+    } else {
+      // generate: for ( int i = N-1; i >= 0; --i )
+      begin = new UntypedExpr( new NameExpr( "?-?" ) );
+      ((UntypedExpr*)begin)->get_args().push_back( array->get_dimension()->clone() );
+      ((UntypedExpr*)begin)->get_args().push_back( new NameExpr( "1" ) );
+      end = new NameExpr( "0" );
+      cmp = new NameExpr( "?>=?" );
+      update = new NameExpr( "--?" );
+    }
+
+    ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), NULL );
+
+    UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
+    init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
+    init->get_args().push_back( begin );
+    index->set_init( new SingleInit( init, std::list<Expression*>() ) );
+
+    UntypedExpr *cond = new UntypedExpr( cmp );
+    cond->get_args().push_back( new VariableExpr( index ) );
+    cond->get_args().push_back( end );
+
+    UntypedExpr *inc = new UntypedExpr( update );
+    inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
+
+    // want to be able to generate assignment, ctor, and dtor generically,
+    // so fname is either ?=?, ?{}, or ^?{}
+    UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
+
+    UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?+?" ) );
+    dstIndex->get_args().push_back( dstParam );
+    dstIndex->get_args().push_back( new VariableExpr( index ) );
+    fExpr->get_args().push_back( dstIndex );
+
+    // srcParam is NULL for default ctor/dtor
+    if ( srcParam ) {
+      UntypedExpr *srcIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
+      srcIndex->get_args().push_back( srcParam );
+      srcIndex->get_args().push_back( new VariableExpr( index ) );
+      fExpr->get_args().push_back( srcIndex );
+    }
+
+    std::list<Statement *> initList;
+    CompoundStmt * block = new CompoundStmt( noLabels );
+    block->get_kids().push_back( new DeclStmt( noLabels, index ) );
+    block->get_kids().push_back( new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, fExpr ) ) );
+    *out++ = block;
+  }
+} // namespace SymTab
+#endif // AUTOGEN_H
+
