Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision a117f7c8c1b582839efb906967e6dda9e0840614)
+++ src/SymTab/Autogen.cc	(revision 0a267c155136ab9afb544521891b8ee255c3e029)
@@ -105,5 +105,5 @@
 		std::list< Declaration * > definitions, forwards;
 
-		FuncGenerator( Type * type, unsigned int functionNesting, const std::vector< FuncData > & data, SymTab::Indexer & indexer ) : type( type ), functionNesting( functionNesting ), data( data ), indexer( indexer ) {}
+		FuncGenerator( Type * type, const std::vector< FuncData > & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : type( type ), data( data ), functionNesting( functionNesting ), indexer( indexer ) {}
 
 		virtual bool shouldAutogen() const = 0;
@@ -112,6 +112,6 @@
 	protected:
 		Type * type;
+		const std::vector< FuncData > & data;
 		unsigned int functionNesting;
-		const std::vector< FuncData > & data;
 		SymTab::Indexer & indexer;
 
@@ -126,5 +126,5 @@
 		StructDecl * aggregateDecl;
 	public:
-		StructFuncGenerator( StructDecl * aggregateDecl, StructInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, functionNesting, data, indexer ), aggregateDecl( aggregateDecl) {}
+		StructFuncGenerator( StructDecl * aggregateDecl, StructInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}
 
 		virtual bool shouldAutogen() const override;
@@ -148,8 +148,34 @@
 	};
 
+	class UnionFuncGenerator : public FuncGenerator {
+		UnionDecl * aggregateDecl;
+	public:
+		UnionFuncGenerator( UnionDecl * aggregateDecl, UnionInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), aggregateDecl( aggregateDecl) {}
+
+		virtual bool shouldAutogen() const override;
+		virtual bool isConcurrentType() const override;
+
+		virtual void genFuncBody( FunctionDecl * dcl ) override;
+		virtual void genFieldCtors() override;
+
+	private:
+		/// generates a single struct member operation (constructor call, destructor call, assignment call)
+		template<typename OutputIterator>
+		void makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out );
+
+		/// generates the body of a struct function by iterating the struct members (via parameters) - generates default ctor, copy ctor, assignment, and dtor bodies, but NOT field ctor bodies
+		template<typename Iterator>
+		void makeFunctionBody( Iterator member, Iterator end, FunctionDecl * func, bool forward = true );
+
+		/// 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 makeFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func );
+	};
+
 	class TypeFuncGenerator : public FuncGenerator {
 		TypeDecl * typeDecl;
 	public:
-		TypeFuncGenerator( TypeDecl * typeDecl, TypeInstType * refType, unsigned int functionNesting, const std::vector<FuncData> & data, SymTab::Indexer & indexer ) : FuncGenerator( refType, functionNesting, data, indexer ), typeDecl( typeDecl ) {}
+		TypeFuncGenerator( TypeDecl * typeDecl, TypeInstType * refType, const std::vector<FuncData> & data, unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ), typeDecl( typeDecl ) {}
 
 		virtual bool shouldAutogen() const override;
@@ -395,26 +421,26 @@
 		unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->get_name() ); } );
 
+		// Field constructors are only generated if default and copy constructor
+		// are generated, since they need access to both
+		if ( numCtors != 2 ) return;
+
 		// 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)
-		// Field constructors are only generated if default and copy constructor
-		// are generated, since they need access to both
-		if ( numCtors == 2 ) {
-			const auto & typeParams = aggregateDecl->parameters;
-			FunctionType * memCtorType = genDefaultType( type );
-			cloneAll( typeParams, memCtorType->forall );
-			for ( Declaration * member : aggregateDecl->members ) {
-				DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member );
-				if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
-					// don't make a function whose parameter is an unnamed bitfield
-					continue;
-				}
-				memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 ) );
-				FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
-				makeFieldCtorBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), ctor );
-				resolve( ctor );
-			}
-			delete memCtorType;
-		}
+		const auto & typeParams = aggregateDecl->parameters;
+		FunctionType * memCtorType = genDefaultType( type );
+		cloneAll( typeParams, memCtorType->forall );
+		for ( Declaration * member : aggregateDecl->members ) {
+			DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member );
+			if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
+				// don't make a function whose parameter is an unnamed bitfield
+				continue;
+			}
+			memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 ) );
+			FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
+			makeFieldCtorBody( aggregateDecl->members.begin(), aggregateDecl->members.end(), ctor );
+			resolve( ctor );
+		}
+		delete memCtorType;
 	}
 
@@ -486,66 +512,52 @@
 	}
 
+	bool UnionFuncGenerator::shouldAutogen() const {
+		// Builtins do not use autogeneration.
+		return ! aggregateDecl->linkage.is_builtin;
+	}
+
+	// xxx - is this right?
+	bool UnionFuncGenerator::isConcurrentType() const { return false; };
+
 	/// generate a single union assignment expression (using memcpy)
 	template< typename OutputIterator >
-	void makeUnionFieldsAssignment( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {
+	void UnionFuncGenerator::makeMemberOp( ObjectDecl * srcParam, ObjectDecl * dstParam, OutputIterator out ) {
 		UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) );
-		copy->get_args().push_back( new AddressExpr( new VariableExpr( dstParam ) ) );
-		copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
-		copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
+		copy->args.push_back( new AddressExpr( new VariableExpr( dstParam ) ) );
+		copy->args.push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
+		copy->args.push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
 		*out++ = new ExprStmt( noLabels, copy );
 	}
 
 	/// generates the body of a union assignment/copy constructor/field constructor
-	void makeUnionAssignBody( FunctionDecl * funcDecl ) {
-		FunctionType * ftype = funcDecl->get_functionType();
-		assert( ftype->get_parameters().size() == 2 );
-		ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
-		ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
-
-		makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( funcDecl->get_statements()->get_kids() ) );
-		if ( CodeGen::isAssignment( funcDecl->get_name() ) ) {
-			// also generate return statement in assignment
-			funcDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
-		}
-	}
-
-	/// generates union constructors, destructors, and assignment operator
-	void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd, SymTab::Indexer & indexer ) {
-		// Make function polymorphic in same parameters as generic union, if applicable
-		const std::list< TypeDecl* > & typeParams = aggregateDecl->get_parameters(); // List of type variables to be placed on the generated functions
-
-		// default ctor/dtor need only first parameter
-		// void ?{}(T *); void ^?{}(T *);
-		FunctionType *ctorType = genDefaultType( refType );
-		FunctionType *dtorType = genDefaultType( refType );
-
-		// copy ctor needs both parameters
-		// void ?{}(T *, T);
-		FunctionType *copyCtorType = genCopyType( refType );
-
-		// assignment needs both and return value
-		// T ?=?(T *, T);
-		FunctionType *assignType = genAssignType( refType );
-
-		cloneAll( typeParams, ctorType->get_forall() );
-		cloneAll( typeParams, dtorType->get_forall() );
-		cloneAll( typeParams, copyCtorType->get_forall() );
-		cloneAll( typeParams, assignType->get_forall() );
-
-		// add unused attribute to parameters of default constructor and destructor
-		ctorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) );
-		dtorType->get_parameters().front()->get_attributes().push_back( new Attribute( "unused" ) );
-
-		// 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 = genFunc( "?=?", assignType, functionNesting );
-		FunctionDecl *ctorDecl = genFunc( "?{}",  ctorType, functionNesting );
-		FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting );
-		FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting );
-
-		makeUnionAssignBody( assignDecl );
-
-		// body of assignment and copy ctor is the same
-		makeUnionAssignBody( copyCtorDecl );
+	void UnionFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) {
+		FunctionType * ftype = funcDecl->type;
+		if ( InitTweak::isCopyConstructor( funcDecl ) || InitTweak::isAssignment( funcDecl ) ) {
+			assert( ftype->parameters.size() == 2 );
+			ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
+			ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.back() );
+
+			makeMemberOp( srcParam, dstParam, back_inserter( funcDecl->statements->kids ) );
+			if ( CodeGen::isAssignment( funcDecl->name ) ) {
+				// also generate return statement in assignment
+				funcDecl->statements->push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
+			}
+		} else {
+			// default ctor/dtor body is empty - add unused attribute to parameter to silence warnings
+			assert( ftype->parameters.size() == 1 );
+			ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->parameters.front() );
+			dstParam->attributes.push_back( new Attribute( "unused" ) );
+		}
+	}
+
+	/// 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.
+	void UnionFuncGenerator::genFieldCtors() {
+		// field ctors are only generated if default constructor and copy constructor are both generated
+		unsigned numCtors = std::count_if( definitions.begin(), definitions.end(), [](Declaration * dcl) { return CodeGen::isConstructor( dcl->get_name() ); } );
+
+		// Field constructors are only generated if default and copy constructor
+		// are generated, since they need access to both
+		if ( numCtors != 2 ) return;
 
 		// create a constructor which takes the first member type as a parameter.
@@ -553,31 +565,23 @@
 		// void ?{}(A *, int)
 		// This is to mimic C's behaviour which initializes the first member of the union.
-		std::list<Declaration *> memCtors;
-		for ( Declaration * member : aggregateDecl->get_members() ) {
-			if ( DeclarationWithType * field = dynamic_cast< DeclarationWithType * >( member ) ) {
-				ObjectDecl * srcParam = new ObjectDecl( "src", Type::StorageClasses(), LinkageSpec::Cforall, 0, field->get_type()->clone(), 0 );
-
-				FunctionType * memCtorType = ctorType->clone();
-				memCtorType->get_parameters().push_back( srcParam );
-				FunctionDecl * ctor = genFunc( "?{}", memCtorType, functionNesting );
-
-				makeUnionAssignBody( ctor );
-				memCtors.push_back( ctor );
-				// only generate a ctor for the first field
+		const auto & typeParams = aggregateDecl->parameters;
+		FunctionType * memCtorType = genDefaultType( type );
+		cloneAll( typeParams, memCtorType->forall );
+		for ( Declaration * member : aggregateDecl->members ) {
+			DeclarationWithType * field = strict_dynamic_cast<DeclarationWithType *>( member );
+			if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( field ) ) ) {
+				// don't make a function whose parameter is an unnamed bitfield
 				break;
 			}
-		}
-
-		declsToAdd.push_back( ctorDecl );
-		declsToAdd.push_back( copyCtorDecl );
-		declsToAdd.push_back( dtorDecl );
-		declsToAdd.push_back( assignDecl ); // assignment should come last since it uses copy constructor in return
-
-		indexer.addId( ctorDecl );
-		indexer.addId( copyCtorDecl );
-		indexer.addId( dtorDecl );
-		indexer.addId( assignDecl );
-
-		declsToAdd.splice( declsToAdd.end(), memCtors );
+			memCtorType->parameters.push_back( new ObjectDecl( field->name, Type::StorageClasses(), LinkageSpec::Cforall, nullptr, field->get_type()->clone(), nullptr ) );
+			FunctionDecl * ctor = genFunc( "?{}", memCtorType->clone(), functionNesting );
+			ObjectDecl * srcParam = strict_dynamic_cast<ObjectDecl *>( ctor->type->parameters.back() );
+			ObjectDecl * dstParam = InitTweak::getParamThis( ctor->type );
+			makeMemberOp( srcParam, dstParam, back_inserter( ctor->statements->kids ) );
+			resolve( ctor );
+			// only generate one field ctor for unions
+			break;
+		}
+		delete memCtorType;
 	}
 
@@ -651,5 +655,6 @@
 				unionInst.get_parameters().push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), typeDecl ) ) );
 			}
-			makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAddAfter, indexer );
+			UnionFuncGenerator gen( unionDecl, &unionInst, data, functionNesting, indexer );
+			generateFunctions( gen, declsToAddAfter );
 		} // if
 	}
@@ -661,5 +666,5 @@
 
 		TypeInstType refType( Type::Qualifiers(), typeDecl->name, typeDecl );
-		TypeFuncGenerator gen( typeDecl, &refType, functionNesting, data, indexer );
+		TypeFuncGenerator gen( typeDecl, &refType, data, functionNesting, indexer );
 		generateFunctions( gen, declsToAddAfter );
 	}
