Index: src/SymTab/AddVisit.h
===================================================================
--- src/SymTab/AddVisit.h	(revision 0cb1d61bd1400ff6dd262a8ac61fc7d75dcf5f5c)
+++ src/SymTab/AddVisit.h	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
@@ -5,10 +5,10 @@
 // file "LICENCE" distributed with Cforall.
 //
-// AddVisit.h -- 
+// AddVisit.h --
 //
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 16:14:32 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Apr  7 14:42:21 2016
+// Last Modified By : Rob Schluntz
+// Last Modified On : Thu Apr 14 15:52:42 2016
 // Update Count     : 5
 //
@@ -48,4 +48,19 @@
 	// 	maybeAccept( caseStmt->get_condition(), visitor );
 	// }
+
+	template< typename Visitor >
+	void acceptAndAdd( std::list< Declaration * > &translationUnit, Visitor &visitor, bool addBefore ) {
+		std::list< Declaration * >::iterator i = translationUnit.begin();
+		while ( i != translationUnit.end() ) {
+			(*i)->accept( visitor );
+			std::list< Declaration * >::iterator next = i;
+			next++;
+			if ( ! visitor.get_declsToAdd().empty() ) {
+				translationUnit.splice( addBefore ? i : next, visitor.get_declsToAdd() );
+			} // if
+			i = next;
+		} // while
+	}
+
 } // namespace SymTab
 
Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
+++ src/SymTab/Autogen.cc	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
@@ -0,0 +1,508 @@
+//
+// 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 Apr 14 16:58:35 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( TraitDecl *ctxDecl );
+		virtual void visit( FunctionDecl *functionDecl );
+
+		virtual void visit( FunctionType *ftype );
+		virtual void visit( PointerType *ftype );
+
+		virtual void visit( CompoundStmt *compoundStmt );
+		virtual void visit( SwitchStmt *switchStmt );
+		virtual void visit( ChooseStmt *chooseStmt );
+		// virtual void visit( CaseStmt *caseStmt );
+
+		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 );
+	}
+
+	bool isUnnamedBitfield( ObjectDecl * obj ) {
+		return obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL;
+	}
+
+	template< typename OutputIterator >
+	void makeScalarFunction( Expression *src, 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 ( isUnnamedBitfield( obj ) ) 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 );
+
+		if ( src ) {
+			fExpr->get_args().push_back( src );
+		}
+
+		*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 makeEnumFunctions( 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;
+	}
+
+	void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) {
+		if ( isGeneric ) {
+			// rewrite member type in terms of the type variables on this operator
+			field = field->clone();
+			genericSubs.apply( field );
+		}
+
+		ObjectDecl * returnVal = NULL;
+		if ( ! func->get_functionType()->get_returnVals().empty() ) {
+			returnVal = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_returnVals().front() );
+		}
+
+		// assign to destination (and return value if generic)
+		if ( ArrayType *array = dynamic_cast< ArrayType * >( field->get_type() ) ) {
+			UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
+			derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
+			Expression *dstselect = new MemberExpr( field, derefExpr );
+
+			makeArrayFunction( src, 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( field, derefRet );
+
+				makeArrayFunction( src, retselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward );
+			}
+		} else {
+			makeScalarFunction( src, dstParam, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
+			if ( isGeneric && returnVal ) makeScalarFunction( src, returnVal, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) );
+		} // if
+	}
+
+	template<typename Iterator>
+	void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) {
+		for ( ; member != end; ++member ) {
+			if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate
+				// 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 = field->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() );
+				}
+				// srcParam may be NULL, in which case we have default ctor/dtor
+				assert( dstParam );
+
+				Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : NULL;
+				makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric, forward );
+			} // if
+		} // for
+	} // makeStructFunctionBody
+
+	/// generate the body of a constructor which takes parameters that match fields, e.g.
+	/// 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 isGeneric ) {
+		FunctionType * ftype = func->get_functionType();
+		std::list<DeclarationWithType*> & params = ftype->get_parameters();
+		assert( params.size() >= 2 );  // should not call this function for default ctor, etc.
+
+		// skip 'this' parameter
+		ObjectDecl * dstParam = dynamic_cast<ObjectDecl*>( params.front() );
+		assert( dstParam );
+		std::list<DeclarationWithType*>::iterator parameter = params.begin()+1;
+		for ( ; member != end; ++member ) {
+			if ( DeclarationWithType * field = dynamic_cast<DeclarationWithType*>( *member ) ) {
+				if ( parameter != params.end() ) {
+					// matching parameter, initialize field with copy ctor
+					Expression *srcselect = new VariableExpr(*parameter);
+					makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric );
+					++parameter;
+				} else {
+					// no matching parameter, initialize field with default ctor
+					makeStructMemberOp( dstParam, NULL, field, func, genericSubs, isGeneric );
+				}
+			}
+		}
+	}
+
+	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();
+
+		// create constructors which take each member type as a parameter.
+		// for example, for struct A { int x, y; }; generate
+		// void ?{}(A *, int) and void ?{}(A *, int, int)
+		std::list<Declaration *> memCtors;
+		FunctionType * memCtorType = ctorType->clone();
+		for ( std::list<Declaration *>::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) {
+			DeclarationWithType * member = dynamic_cast<DeclarationWithType *>( *i );
+			assert( member );
+			if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) {
+				// don't make a function whose parameter is an unnamed bitfield
+				continue;
+			}
+			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, isGeneric );
+			memCtors.push_back( ctor );
+		}
+		delete memCtorType;
+
+		// 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 );
+		declsToAdd.splice( declsToAdd.end(), memCtors );
+	}
+
+	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(
+			makeEnumFunctions( 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( TraitDecl *) {
+		// ensure that we don't add assignment ops for types defined as part of the trait
+	}
+
+	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( SwitchStmt *switchStmt ) {
+		visitStatement( switchStmt );
+	}
+
+	void AutogenerateRoutines::visit( ChooseStmt *switchStmt ) {
+		visitStatement( switchStmt );
+	}
+
+	// void AutogenerateRoutines::visit( CaseStmt *caseStmt ) {
+	// 	visitStatement( caseStmt );
+	// }
+} // SymTab
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
+++ src/SymTab/Autogen.h	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
@@ -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
+
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision 0cb1d61bd1400ff6dd262a8ac61fc7d75dcf5f5c)
+++ src/SymTab/Validate.cc	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
@@ -9,7 +9,7 @@
 // Author           : Richard C. Bilson
 // Created On       : Sun May 17 21:50:04 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Apr 13 16:39:30 2016
-// Update Count     : 251
+// Last Modified By : Rob Schluntz
+// Last Modified On : Thu Apr 14 15:37:23 2016
+// Update Count     : 297
 //
 
@@ -56,4 +56,5 @@
 #include "MakeLibCfa.h"
 #include "TypeEquality.h"
+#include "Autogen.h"
 #include "ResolvExpr/typeops.h"
 
@@ -122,35 +123,4 @@
 
 		const Indexer *indexer;
-	};
-
-	class AutogenerateRoutines : public Visitor {
-	  public:
-		/// Generates assignment operators for aggregate types as required
-		static void autogenerateRoutines( std::list< Declaration * > &translationUnit );
-
-		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( TraitDecl *ctxDecl );
-		virtual void visit( FunctionDecl *functionDecl );
-
-		virtual void visit( FunctionType *ftype );
-		virtual void visit( PointerType *ftype );
-
-		virtual void visit( CompoundStmt *compoundStmt );
-		virtual void visit( SwitchStmt *switchStmt );
-		virtual void visit( ChooseStmt *chooseStmt );
-		// virtual void visit( CaseStmt *caseStmt );
-
-		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
 	};
 
@@ -192,9 +162,19 @@
 		template<typename AggDecl>
 		void addImplicitTypedef( AggDecl * aggDecl );
-		
+
 		typedef std::map< std::string, std::pair< TypedefDecl *, int > > TypedefMap;
 		TypedefMap typedefNames;
 		int scopeLevel;
 	};
+
+	class VerifyCtorDtor : public Visitor {
+	public:
+		/// ensure that constructors and destructors have at least one
+		/// parameter, the first of which must be a pointer, and no
+		/// return values.
+		static void verify( std::list< Declaration * > &translationUnit );
+
+		virtual void visit( FunctionDecl *funcDecl );
+};
 
 	class CompoundLiteral : public GenPoly::DeclMutator {
@@ -217,6 +197,7 @@
 		ReturnChecker::checkFunctionReturns( translationUnit );
 		mutateAll( translationUnit, compoundliteral );
-		AutogenerateRoutines::autogenerateRoutines( translationUnit );
+		autogenerateRoutines( translationUnit );
 		acceptAll( translationUnit, pass3 );
+		VerifyCtorDtor::verify( translationUnit );
 	}
 
@@ -228,18 +209,4 @@
 		type->accept( pass2 );
 		type->accept( pass3 );
-	}
-
-	template< typename Visitor >
-	void acceptAndAdd( std::list< Declaration * > &translationUnit, Visitor &visitor, bool addBefore ) {
-		std::list< Declaration * >::iterator i = translationUnit.begin();
-		while ( i != translationUnit.end() ) {
-			(*i)->accept( visitor );
-			std::list< Declaration * >::iterator next = i;
-			next++;
-			if ( ! visitor.get_declsToAdd().empty() ) {
-				translationUnit.splice( addBefore ? i : next, visitor.get_declsToAdd() );
-			} // if
-			i = next;
-		} // while
 	}
 
@@ -503,377 +470,4 @@
 	}
 
-	static const std::list< std::string > noLabels;
-
-	void AutogenerateRoutines::autogenerateRoutines( std::list< Declaration * > &translationUnit ) {
-		AutogenerateRoutines visitor;
-		acceptAndAdd( translationUnit, visitor, false );
-	}
-
-	template< typename OutputIterator >
-	void makeScalarAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, 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;
-
-		UntypedExpr *assignExpr = new UntypedExpr( new NameExpr( "?=?" ) );
-
-		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 ) );
-		assignExpr->get_args().push_back( dstselect );
-
-		Expression *srcselect = new MemberExpr( member, new VariableExpr( srcParam ) );
-		assignExpr->get_args().push_back( srcselect );
-
-		*out++ = new ExprStmt( noLabels, assignExpr );
-	}
-
-	template< typename OutputIterator >
-	void makeArrayAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, DeclarationWithType *member, ArrayType *array, OutputIterator out ) {
-		static UniqueName indexName( "_index" );
-
-		// for a flexible array member nothing is done -- user must define own assignment
-		if ( ! array->get_dimension() ) return;
-
-		ObjectDecl *index = new ObjectDecl( indexName.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, new BasicType( Type::Qualifiers(), BasicType::SignedInt ), 0 );
-		*out++ = new DeclStmt( noLabels, index );
-
-		UntypedExpr *init = new UntypedExpr( new NameExpr( "?=?" ) );
-		init->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
-		init->get_args().push_back( new NameExpr( "0" ) );
-		Statement *initStmt = new ExprStmt( noLabels, init );
-		std::list<Statement *> initList;
-		initList.push_back( initStmt );
-
-		UntypedExpr *cond = new UntypedExpr( new NameExpr( "?<?" ) );
-		cond->get_args().push_back( new VariableExpr( index ) );
-		cond->get_args().push_back( array->get_dimension()->clone() );
-
-		UntypedExpr *inc = new UntypedExpr( new NameExpr( "++?" ) );
-		inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
-
-		UntypedExpr *assignExpr = new UntypedExpr( new NameExpr( "?=?" ) );
-
-		UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) );
-		derefExpr->get_args().push_back( new VariableExpr( dstParam ) );
-
-		Expression *dstselect = new MemberExpr( member, derefExpr );
-		UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?+?" ) );
-		dstIndex->get_args().push_back( dstselect );
-		dstIndex->get_args().push_back( new VariableExpr( index ) );
-		assignExpr->get_args().push_back( dstIndex );
-
-		Expression *srcselect = new MemberExpr( member, new VariableExpr( srcParam ) );
-		UntypedExpr *srcIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
-		srcIndex->get_args().push_back( srcselect );
-		srcIndex->get_args().push_back( new VariableExpr( index ) );
-		assignExpr->get_args().push_back( srcIndex );
-
-		*out++ = new ForStmt( noLabels, initList, cond, inc, new ExprStmt( noLabels, assignExpr ) );
-	}
-
-	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;
-	}
-
-	Declaration *makeStructAssignment( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting ) {
-		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 *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 );
-		assignType->get_returnVals().push_back( returnVal );
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, structParams ) ), 0 );
-		assignType->get_parameters().push_back( dstParam );
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 );
-		assignType->get_parameters().push_back( srcParam );
-
-		// 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 );
-		assignDecl->fixUniqueId();
-
-		for ( std::list< Declaration * >::const_iterator member = aggregateDecl->get_members().begin(); member != aggregateDecl->get_members().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;
-				}
-
-				if ( isGeneric ) {
-					// rewrite member type in terms of the type variables on this operator
-					DeclarationWithType *fixedMember = dwt->clone();
-					genericSubs.apply( fixedMember );
-
-					// assign to both destination and return value
-					if ( ArrayType *array = dynamic_cast< ArrayType * >( fixedMember->get_type() ) ) {
-						makeArrayAssignment( srcParam, dstParam, fixedMember, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
-						makeArrayAssignment( srcParam, returnVal, fixedMember, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
-					} else {
-						makeScalarAssignment( srcParam, dstParam, fixedMember, back_inserter( assignDecl->get_statements()->get_kids() ) );
-						makeScalarAssignment( srcParam, returnVal, fixedMember, back_inserter( assignDecl->get_statements()->get_kids() ) );
-					} // if
-				} else {
-					// assign to destination
-					if ( ArrayType *array = dynamic_cast< ArrayType * >( dwt->get_type() ) ) {
-						makeArrayAssignment( srcParam, dstParam, dwt, array, back_inserter( assignDecl->get_statements()->get_kids() ) );
-					} else {
-						makeScalarAssignment( srcParam, dstParam, dwt, back_inserter( assignDecl->get_statements()->get_kids() ) );
-					} // if
-				} // if
-			} // if
-		} // for
-		if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
-
-		return assignDecl;
-	}
-
-	Declaration *makeUnionAssignment( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting ) {
-		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 *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
-		assignType->get_returnVals().push_back( returnVal );
-
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, unionParams ) ), 0 );
-		assignType->get_parameters().push_back( dstParam );
-
-		ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 );
-		assignType->get_parameters().push_back( srcParam );
-
-		// 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 );
-		assignDecl->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 ) ) );
-
-		return assignDecl;
-	}
-
-	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 );
-			declsToAdd.push_back( makeStructAssignment( structDecl, &structInst, functionNesting ) );
-			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 );
-			declsToAdd.push_back( makeUnionAssignment( unionDecl, &unionInst, functionNesting ) );
-		} // 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( TraitDecl *) {
-		// 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( SwitchStmt *switchStmt ) {
-		visitStatement( switchStmt );
-	}
-
-	void AutogenerateRoutines::visit( ChooseStmt *switchStmt ) {
-		visitStatement( switchStmt );
-	}
-
-	// void AutogenerateRoutines::visit( CaseStmt *caseStmt ) {
-	// 	visitStatement( caseStmt );
-	// }
-
 	void ReturnChecker::checkFunctionReturns( std::list< Declaration * > & translationUnit ) {
 		ReturnChecker checker;
@@ -1033,5 +627,5 @@
 		return aggDecl;
 	}
-	
+
 	template<typename AggDecl>
 	void EliminateTypedef::addImplicitTypedef( AggDecl * aggDecl ) {
@@ -1072,4 +666,37 @@
 	}
 
+	void VerifyCtorDtor::verify( std::list< Declaration * > & translationUnit ) {
+		VerifyCtorDtor verifier;
+		acceptAll( translationUnit, verifier );
+	}
+
+	void VerifyCtorDtor::visit( FunctionDecl * funcDecl ) {
+		FunctionType * funcType = funcDecl->get_functionType();
+		std::list< DeclarationWithType * > &returnVals = funcType->get_returnVals();
+		std::list< DeclarationWithType * > &params = funcType->get_parameters();
+
+		if ( funcDecl->get_name() == "?{}" || funcDecl->get_name() == "^?{}" ) {
+			if ( params.size() == 0 ) {
+				throw SemanticError( "Constructors and destructors require at least one parameter ", funcDecl );
+			}
+			if ( ! dynamic_cast< PointerType * >( params.front()->get_type() ) ) {
+				throw SemanticError( "First parameter of a constructor or destructor must be a pointer ", funcDecl );
+			}
+			if ( returnVals.size() != 0 ) {
+				throw SemanticError( "Constructors and destructors cannot have explicit return values ", funcDecl );
+			}
+		}
+
+		Visitor::visit( funcDecl );
+		// original idea: modify signature of ctor/dtors and insert appropriate return statements
+		// to cause desired behaviour
+		// new idea: add comma exprs to every ctor call to produce first parameter.
+		// this requires some memoization of the first parameter, because it can be a
+		// complicated expression with side effects (see: malloc). idea: add temporary variable
+		// that is assigned address of constructed object in ctor argument position and
+		// return the temporary. It should also be done after all implicit ctors are
+		// added, so not in this pass!
+	}
+
 	DeclarationWithType * CompoundLiteral::mutate( ObjectDecl *objectDecl ) {
 		storageclass = objectDecl->get_storageClass();
Index: src/SymTab/module.mk
===================================================================
--- src/SymTab/module.mk	(revision 0cb1d61bd1400ff6dd262a8ac61fc7d75dcf5f5c)
+++ src/SymTab/module.mk	(revision fbfb38e115e532f4ffb93eb36c9df8163dd09f7d)
@@ -6,5 +6,5 @@
 ## file "LICENCE" distributed with Cforall.
 ##
-## module.mk -- 
+## module.mk --
 ##
 ## Author           : Richard C. Bilson
@@ -20,3 +20,4 @@
        SymTab/FixFunction.cc \
        SymTab/ImplementationType.cc \
-       SymTab/TypeEquality.cc
+       SymTab/TypeEquality.cc \
+       SymTab/Autogen.cc
