Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 0a267c155136ab9afb544521891b8ee255c3e029)
+++ src/SymTab/Autogen.cc	(revision 18ca28e698989f58b5b3b02c373ad9977156462e)
@@ -174,4 +174,17 @@
 	};
 
+	class EnumFuncGenerator : public FuncGenerator {
+	public:
+		EnumFuncGenerator( EnumInstType * refType, const std::vector< FuncData > & data,  unsigned int functionNesting, SymTab::Indexer & indexer ) : FuncGenerator( refType, data, functionNesting, indexer ) {}
+
+		virtual bool shouldAutogen() const override;
+		virtual bool isConcurrentType() const override;
+
+		virtual void genFuncBody( FunctionDecl * dcl ) override;
+		virtual void genFieldCtors() override;
+
+	private:
+	};
+
 	class TypeFuncGenerator : public FuncGenerator {
 		TypeDecl * typeDecl;
@@ -247,71 +260,4 @@
 		decl->fixUniqueId();
 		return decl;
-	}
-
-	/// generates a single enumeration assignment expression
-	ApplicationExpr * genEnumAssign( FunctionType * ftype, FunctionDecl * assignDecl ) {
-		// enum copy construct and assignment is just C-style assignment.
-		// this looks like a bad recursive call, but code gen will turn it into
-		// a C-style assignment.
-		// This happens before function pointer type conversion, so need to do it manually here
-		// NOTE: ftype is not necessarily the functionType belonging to assignDecl - ftype is the
-		// type of the function that this expression is being generated for (so that the correct
-		// parameters) are using in the variable exprs
-		assert( ftype->get_parameters().size() == 2 );
-		ObjectDecl * dstParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
-		ObjectDecl * srcParam = strict_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
-
-		VariableExpr * assignVarExpr = new VariableExpr( assignDecl );
-		Type * assignVarExprType = assignVarExpr->get_result();
-		assignVarExprType = new PointerType( Type::Qualifiers(), assignVarExprType );
-		assignVarExpr->set_result( assignVarExprType );
-		ApplicationExpr * assignExpr = new ApplicationExpr( assignVarExpr );
-		assignExpr->get_args().push_back( new VariableExpr( dstParam ) );
-		assignExpr->get_args().push_back( new VariableExpr( srcParam ) );
-		return assignExpr;
-	}
-
-	// E ?=?(E volatile*, int),
-	//   ?=?(E _Atomic volatile*, int);
-	void makeEnumFunctions( EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd, SymTab::Indexer & indexer ) {
-
-		// T ?=?(E *, E);
-		FunctionType *assignType = genAssignType( refType );
-
-		// void ?{}(E *); void ^?{}(E *);
-		FunctionType * ctorType = genDefaultType( refType->clone() );
-		FunctionType * dtorType = genDefaultType( refType->clone() );
-
-		// void ?{}(E *, E);
-		FunctionType *copyCtorType = genCopyType( refType->clone() );
-
-		// 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" ) );
-
-		// xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)?
-		// right now these cases work, but that might change.
-
-		// xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
-		// Really they're something of a cross between instrinsic and autogen, so should
-		// probably make a new linkage type
-		FunctionDecl *assignDecl = genFunc( "?=?", assignType, functionNesting, true );
-		FunctionDecl *ctorDecl = genFunc( "?{}", ctorType, functionNesting, true );
-		FunctionDecl *copyCtorDecl = genFunc( "?{}", copyCtorType, functionNesting, true );
-		FunctionDecl *dtorDecl = genFunc( "^?{}", dtorType, functionNesting, true );
-
-		// body is either return stmt or expr stmt
-		assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, genEnumAssign( assignType, assignDecl ) ) );
-		copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, genEnumAssign( copyCtorType, assignDecl ) ) );
-
-		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 );
 	}
 
@@ -586,4 +532,40 @@
 	}
 
+	void EnumFuncGenerator::genFuncBody( FunctionDecl * funcDecl ) {
+		// xxx - Temporary: make these functions intrinsic so they codegen as C assignment.
+		// Really they're something of a cross between instrinsic and autogen, so should
+		// probably make a new linkage type
+		funcDecl->linkage = LinkageSpec::Intrinsic;
+		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() );
+
+			// enum copy construct and assignment is just C-style assignment.
+			// this looks like a bad recursive call, but code gen will turn it into
+			// a C-style assignment.
+			// This happens before function pointer type conversion, so need to do it manually here
+			ApplicationExpr * callExpr = new ApplicationExpr( VariableExpr::functionPointer( funcDecl ) );
+			callExpr->get_args().push_back( new VariableExpr( dstParam ) );
+			callExpr->get_args().push_back( new VariableExpr( srcParam ) );
+			funcDecl->statements->push_back( new ExprStmt( noLabels, callExpr ) );
+			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" ) );
+		}
+	}
+
+	bool EnumFuncGenerator::shouldAutogen() const { return true; }
+	bool EnumFuncGenerator::isConcurrentType() const { return false; }
+	// enums do not have field constructors
+	void EnumFuncGenerator::genFieldCtors() {}
+
 	bool TypeFuncGenerator::shouldAutogen() const { return true; };
 
@@ -611,5 +593,5 @@
 
 	// opaque types do not have field constructors
-	void TypeFuncGenerator::genFieldCtors() { return; };
+	void TypeFuncGenerator::genFieldCtors() {};
 
 	//=============================================================================================
@@ -628,7 +610,8 @@
 		// must visit children (enum constants) to add them to the indexer
 		if ( enumDecl->has_body() ) {
-			EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() );
-			enumInst->set_baseEnum( enumDecl );
-			makeEnumFunctions( enumInst, functionNesting, declsToAddAfter, indexer );
+			EnumInstType enumInst( Type::Qualifiers(), enumDecl->get_name() );
+			enumInst.set_baseEnum( enumDecl );
+			EnumFuncGenerator gen( &enumInst, data, functionNesting, indexer );
+			generateFunctions( gen, declsToAddAfter );
 		}
 	}
