Index: src/SymTab/Autogen.cc
===================================================================
--- src/SymTab/Autogen.cc	(revision 084feccbf17e05bce4de62ca0547934692f681fb)
+++ src/SymTab/Autogen.cc	(revision 242a902cd5fbc4b9c2f13147a4c64816af6be8b7)
@@ -125,5 +125,5 @@
 	FunctionType * genDefaultType( Type * paramType ) {
 		FunctionType *ftype = new FunctionType( Type::Qualifiers(), false );
-		ObjectDecl *dstParam = new ObjectDecl( "_dst", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new PointerType( Type::Qualifiers(), paramType->clone() ), nullptr );
+		ObjectDecl *dstParam = new ObjectDecl( "_dst", Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new ReferenceType( Type::Qualifiers(), paramType->clone() ), nullptr );
 		ftype->get_parameters().push_back( dstParam );
 
@@ -298,21 +298,9 @@
 	/// generates a single struct member operation (constructor call, destructor call, assignment call)
 	void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, bool isDynamicLayout, bool forward = true ) {
-		ObjectDecl * returnVal = NULL;
-		if ( ! func->get_functionType()->get_returnVals().empty() ) {
-			returnVal = dynamic_cast<ObjectDecl*>( func->get_functionType()->get_returnVals().front() );
-		}
-
 		InitTweak::InitExpander srcParam( src );
 
-		// assign to destination (and return value if generic)
-		UntypedExpr *derefExpr = UntypedExpr::createDeref( new VariableExpr( dstParam ) );
-		Expression *dstselect = new MemberExpr( field, derefExpr );
+		// assign to destination
+		Expression *dstselect = new MemberExpr( field, new CastExpr( new VariableExpr( dstParam ), safe_dynamic_cast< ReferenceType* >( dstParam->get_type() )->get_base()->clone() ) );
 		genImplicitCall( srcParam, dstselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
-
-		if ( isDynamicLayout && returnVal ) {
-			// xxx - there used to be a dereference on returnVal, but this seems to have been wrong?
-			Expression *retselect = new MemberExpr( field, new VariableExpr( returnVal ) );
-			genImplicitCall( srcParam, retselect, func->get_name(), back_inserter( func->get_statements()->get_kids() ), field, forward );
-		} // if
 	}
 
@@ -468,7 +456,5 @@
 					// our inheritance model. I think the correct way to handle this is to
 					// cast the structure to the type of the member and let the resolver
-					// figure out whether it's valid and have a pass afterwards that fixes
-					// the assignment to use pointer arithmetic with the offset of the
-					// member, much like how generic type members are handled.
+					// figure out whether it's valid/choose the correct unnamed member
 					continue;
 				}
@@ -486,5 +472,5 @@
 	void makeUnionFieldsAssignment( ObjectDecl * srcParam, ObjectDecl * dstParam, 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( dstParam ) ) );
 		copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) );
 		copy->get_args().push_back( new SizeofExpr( srcParam->get_type()->clone() ) );
@@ -498,11 +484,8 @@
 		ObjectDecl * dstParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().front() );
 		ObjectDecl * srcParam = safe_dynamic_cast< ObjectDecl * >( ftype->get_parameters().back() );
-		ObjectDecl * returnVal = nullptr;
-		if ( ! ftype->get_returnVals().empty() ) {
-			returnVal = safe_dynamic_cast< ObjectDecl * >( ftype->get_returnVals().front() );
-		}
 
 		makeUnionFieldsAssignment( srcParam, dstParam, back_inserter( funcDecl->get_statements()->get_kids() ) );
-		if ( returnVal ) {
+		if ( InitTweak::isAssignment( funcDecl->get_name() ) ) {
+			// also generate return statement in assignment
 			funcDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) );
 		}
@@ -513,5 +496,5 @@
 		// 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 *);
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 084feccbf17e05bce4de62ca0547934692f681fb)
+++ src/SymTab/Autogen.h	(revision 242a902cd5fbc4b9c2f13147a4c64816af6be8b7)
@@ -43,35 +43,33 @@
 	template< typename OutputIterator >
 	Statement * genScalarCall( InitTweak::InitExpander & srcParam, Expression *dstParam, const std::string & fname, OutputIterator out, Type * type, bool addCast = false ) {
-	// want to be able to generate assignment, ctor, and dtor generically,
-	// so fname is either ?=?, ?{}, or ^?{}
-	UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
+		// want to be able to generate assignment, ctor, and dtor generically,
+		// so fname is either ?=?, ?{}, or ^?{}
+		UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) );
 
-	// do something special for unnamed members
-	dstParam = new AddressExpr( dstParam );
-	if ( addCast ) {
-		// cast to T* with qualifiers removed, so that qualified objects can be constructed
-		// and destructed with the same functions as non-qualified objects.
-		// unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
-		// must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
-		// remove lvalue as a qualifier, this can change to
-		//   type->get_qualifiers() = Type::Qualifiers();
-		assert( type );
-		Type * castType = type->clone();
-		castType->get_qualifiers() -= Type::Qualifiers( Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
-		castType->set_lvalue( true ); // xxx - might not need this
-		dstParam = new CastExpr( dstParam, new PointerType( Type::Qualifiers(), castType ) );
-	}
-	fExpr->get_args().push_back( dstParam );
+		if ( addCast ) {
+			// cast to T& with qualifiers removed, so that qualified objects can be constructed
+			// and destructed with the same functions as non-qualified objects.
+			// unfortunately, lvalue is considered a qualifier. For AddressExpr to resolve, its argument
+			// must have an lvalue qualified type, so remove all qualifiers except lvalue. If we ever
+			// remove lvalue as a qualifier, this can change to
+			//   type->get_qualifiers() = Type::Qualifiers();
+			assert( type );
+			Type * castType = type->clone();
+			castType->get_qualifiers() -= Type::Qualifiers( Type::Lvalue | Type::Const | Type::Volatile | Type::Restrict | Type::Atomic );
+			// castType->set_lvalue( true ); // xxx - might not need this
+			dstParam = new CastExpr( dstParam, new ReferenceType( Type::Qualifiers(), castType ) );
+		}
+		fExpr->get_args().push_back( dstParam );
 
-	Statement * listInit = srcParam.buildListInit( fExpr );
+		Statement * listInit = srcParam.buildListInit( fExpr );
 
-	std::list< Expression * > args = *++srcParam;
-	fExpr->get_args().splice( fExpr->get_args().end(), args );
+		std::list< Expression * > args = *++srcParam;
+		fExpr->get_args().splice( fExpr->get_args().end(), args );
 
-	*out++ = new ExprStmt( noLabels, fExpr );
+		*out++ = new ExprStmt( noLabels, fExpr );
 
-	srcParam.clearArrayIndices();
+		srcParam.clearArrayIndices();
 
-	return listInit;
+		return listInit;
 	}
 
@@ -109,5 +107,5 @@
 
 		UntypedExpr *inc = new UntypedExpr( update );
-		inc->get_args().push_back( new AddressExpr( new VariableExpr( index ) ) );
+		inc->get_args().push_back( new VariableExpr( index ) );
 
 		UntypedExpr *dstIndex = new UntypedExpr( new NameExpr( "?[?]" ) );
