Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 8135d4c79504a6c3047246007261186efa5ba4c9)
+++ src/SymTab/Autogen.cc	(revision 108f3cdb1c308290d06b0f98d2f61dcf43a681bc)
@@ -163,5 +163,4 @@
 		// 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.
-//		DeclarationNode::StorageClass sc = functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static;
 		Type::StorageClasses scs = functionNesting > 0 ? Type::StorageClasses() : Type::StorageClasses( Type::Static );
 		LinkageSpec::Spec spec = isIntrinsic ? LinkageSpec::Intrinsic : LinkageSpec::AutoGen;
@@ -186,4 +185,5 @@
 	/// using map and t, determines if is constructable, etc.
 	bool lookup( const TypeMap & map, Type * t ) {
+		assertf( t, "Autogenerate lookup was given non-type: %s", toString( t ).c_str() );
 		if ( dynamic_cast< PointerType * >( t ) ) {
 			// will need more complicated checking if we want this to work with pointer types, since currently
@@ -200,10 +200,8 @@
 
 	/// using map and aggr, examines each member to determine if constructor, etc. should be generated
-	template<typename AggrDecl>
-	bool shouldGenerate( const TypeMap & map, AggrDecl * aggr ) {
-		for ( Declaration * dcl : aggr->get_members() ) {
-			if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( dcl ) ) {
-				if ( ! lookup( map, dwt->get_type() ) ) return false;
-			}
+	template<typename Container>
+	bool shouldGenerate( const TypeMap & map, const Container & container ) {
+		for ( Type * t : container ) {
+			if ( ! lookup( map, t ) ) return false;
 		}
 		return true;
@@ -211,23 +209,23 @@
 
 	/// data structure for abstracting the generation of special functions
-	template< typename OutputIterator >
+	template< typename OutputIterator, typename Container >
 	struct FuncGenerator {
-		StructDecl *aggregateDecl;
-		StructInstType *refType;
+		const Container & container;
+		Type *refType;
 		unsigned int functionNesting;
 		const std::list< TypeDecl* > & typeParams;
 		OutputIterator out;
-		FuncGenerator( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) : aggregateDecl( aggregateDecl ), refType( refType ), functionNesting( functionNesting ), typeParams( typeParams ), out( out ) {}
+		FuncGenerator( const Container & container, Type *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) : container( container ), refType( refType ), functionNesting( functionNesting ), typeParams( typeParams ), out( out ) {}
 
 		/// generates a function (?{}, ?=?, ^?{}) based on the data argument and members. If function is generated, inserts the type into the map.
 		void gen( const FuncData & data, bool concurrent_type ) {
-			if ( ! shouldGenerate( data.map, aggregateDecl ) ) return;
+			if ( ! shouldGenerate( data.map, container ) ) return;
 			FunctionType * ftype = data.genType( refType );
 
 			if(concurrent_type && CodeGen::isDestructor( data.fname )) {
-				ftype->get_parameters().front()->get_type()->set_mutex( true );
-			}
-
-			cloneAll( typeParams, ftype->get_forall() );
+				ftype->parameters.front()->get_type()->set_mutex( true );
+			}
+
+			cloneAll( typeParams, ftype->forall );
 			*out++ = genFunc( data.fname, ftype, functionNesting );
 			data.map.insert( Mangler::mangleType( refType ), true );
@@ -235,7 +233,7 @@
 	};
 
-	template< typename OutputIterator >
-	FuncGenerator<OutputIterator> makeFuncGenerator( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) {
-		return FuncGenerator<OutputIterator>( aggregateDecl, refType, functionNesting, typeParams, out );
+	template< typename OutputIterator, typename Container >
+	FuncGenerator<OutputIterator, Container> makeFuncGenerator( const Container & container, Type *refType, unsigned int functionNesting, const std::list< TypeDecl* > & typeParams, OutputIterator out ) {
+		return FuncGenerator<OutputIterator, Container>( container, refType, functionNesting, typeParams, out );
 	}
 
@@ -393,4 +391,11 @@
 	}
 
+	Type * declToType( Declaration * decl ) {
+		if ( DeclarationWithType * dwt = dynamic_cast< DeclarationWithType * >( decl ) ) {
+			return dwt->get_type();
+		}
+		return nullptr;
+	}
+
 	/// generates struct constructors, destructor, and assignment functions
 	void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd, const std::vector< FuncData > & data ) {
@@ -406,5 +411,6 @@
 		// generate each of the functions based on the supplied FuncData objects
 		std::list< FunctionDecl * > newFuncs;
-		auto generator = makeFuncGenerator( aggregateDecl, refType, functionNesting, typeParams, back_inserter( newFuncs ) );
+		// structure that iterates aggregate decl members, returning their types
+		auto generator = makeFuncGenerator( lazy_map( aggregateDecl->members, declToType ), refType, functionNesting, typeParams, back_inserter( newFuncs ) );
 		for ( const FuncData & d : data ) {
 			generator.gen( d, aggregateDecl->is_thread() || aggregateDecl->is_monitor() );
@@ -605,26 +611,55 @@
 	}
 
+	Type * declToTypeDeclBase( Declaration * decl ) {
+		if ( TypeDecl * td = dynamic_cast< TypeDecl * >( decl ) ) {
+			return td->base;
+		}
+		return nullptr;
+	}
+
+	// generate ctor/dtors/assign for typedecls, e.g., otype T = int *;
 	void AutogenerateRoutines::visit( TypeDecl *typeDecl ) {
-		TypeInstType *typeInst = new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), false );
-		typeInst->set_baseType( typeDecl );
-		ObjectDecl *src = new ObjectDecl( "_src", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, typeInst->clone(), nullptr );
-		ObjectDecl *dst = new ObjectDecl( "_dst", Type::StorageClasses(), 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 *;
-			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.push_back( new ReturnStmt( std::list< Label >(), assign ) );
-		} // if
-		FunctionType *type = new FunctionType( Type::Qualifiers(), false );
-		type->get_returnVals().push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::Cforall, 0, typeInst, 0 ) );
-		type->get_parameters().push_back( dst );
-		type->get_parameters().push_back( src );
-		FunctionDecl *func = genFunc( "?=?", type, functionNesting );
-		func->get_statements()->get_kids() = stmts;
-		declsToAddAfter.push_back( func );
+		if ( ! typeDecl->base ) return;
+
+		// generate each of the functions based on the supplied FuncData objects
+		std::list< FunctionDecl * > newFuncs;
+		std::list< Declaration * > tds { typeDecl };
+		std::list< TypeDecl * > typeParams;
+		TypeInstType refType( Type::Qualifiers(), typeDecl->name, typeDecl );
+		auto generator = makeFuncGenerator( lazy_map( tds, declToTypeDeclBase ), &refType, functionNesting, typeParams, back_inserter( newFuncs ) );
+		for ( const FuncData & d : data ) {
+			generator.gen( d, false );
+		}
+
+		if ( functionNesting == 0 ) {
+			// forward declare if top-level struct, so that
+			// type is complete as soon as its body ends
+			// Note: this is necessary if we want structs which contain
+			// generic (otype) structs as members.
+			for ( FunctionDecl * dcl : newFuncs ) {
+				addForwardDecl( dcl, declsToAddAfter );
+			}
+		}
+
+		for ( FunctionDecl * dcl : newFuncs ) {
+			FunctionType * ftype = dcl->type;
+			assertf( ftype->parameters.size() == 1 || ftype->parameters.size() == 2, "Incorrect number of parameters in autogenerated typedecl function: %zd", ftype->parameters.size() );
+			DeclarationWithType * dst = ftype->parameters.front();
+			DeclarationWithType * src = ftype->parameters.size() == 2 ? ftype->parameters.back() : nullptr;
+			// generate appropriate calls to member ctor, assignment
+			// destructor needs to do everything in reverse, so pass "forward" based on whether the function is a destructor
+			UntypedExpr * expr = new UntypedExpr( new NameExpr( dcl->name ) );
+			expr->args.push_back( new CastExpr( new VariableExpr( dst ), new ReferenceType( Type::Qualifiers(), typeDecl->base->clone() ) ) );
+			if ( src ) expr->args.push_back( new CastExpr( new VariableExpr( src ), typeDecl->base->clone() ) );
+			dcl->statements->kids.push_back( new ExprStmt( noLabels, expr ) );
+			if ( CodeGen::isAssignment( dcl->get_name() ) ) {
+				// assignment needs to return a value
+				FunctionType * assignType = dcl->type;
+				assert( assignType->parameters.size() == 2 );
+				ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( assignType->parameters.back() );
+				dcl->statements->kids.push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+			}
+			declsToAddAfter.push_back( dcl );
+		}
 	}
 
