Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 23b6643f5ea88fa1b0e11583e2f0ed9315a515de)
+++ src/InitTweak/FixInit.cc	(revision 1132b62939ee72e624dd65d3bacb0e67cb1a0347)
@@ -70,6 +70,9 @@
 			/// create and resolve ctor/dtor expression: fname(var, [cpArg])
 			ApplicationExpr * makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg = NULL );
+			ApplicationExpr * makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg = NULL );
 			/// true if type does not need to be copy constructed to ensure correctness
-			bool skipCopyConstruct( Type * );
+			bool skipCopyConstruct( Type * type );
+			void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr );
+			void destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
 		private:
 			TypeSubstitution * env;
@@ -359,6 +362,11 @@
 		ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, ObjectDecl * var, Expression * cpArg ) {
 			assert( var );
+			return makeCtorDtor( fname, new AddressExpr( new VariableExpr( var ) ), cpArg );
+		}
+
+		ApplicationExpr * ResolveCopyCtors::makeCtorDtor( const std::string & fname, Expression * thisArg, Expression * cpArg ) {
+			assert( thisArg );
 			UntypedExpr * untyped = new UntypedExpr( new NameExpr( fname ) );
-			untyped->get_args().push_back( new AddressExpr( new VariableExpr( var ) ) );
+			untyped->get_args().push_back( thisArg );
 			if (cpArg) untyped->get_args().push_back( cpArg->clone() );
 
@@ -377,8 +385,53 @@
 		}
 
+		void ResolveCopyCtors::copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr ) {
+			static UniqueName tempNamer("_tmp_cp");
+			CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; )
+			assert( arg->has_result() );
+			Type * result = arg->get_result();
+			if ( skipCopyConstruct( result ) ) return; // skip certain non-copyable types
+
+			if ( TupleExpr * tupleExpr = dynamic_cast< TupleExpr * >( arg ) ) {
+				for ( Expression * & expr : tupleExpr->get_exprs() ) {
+					copyConstructArg( expr, impCpCtorExpr );
+				}
+				return;
+			}
+
+			// type may involve type variables, so apply type substitution to get temporary variable's actual type
+			result = result->clone();
+			impCpCtorExpr->get_env()->apply( result );
+			ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
+			tmp->get_type()->set_isConst( false );
+
+			// create and resolve copy constructor
+			CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
+			ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg );
+
+			// if the chosen constructor is intrinsic, the copy is unnecessary, so
+			// don't create the temporary and don't call the copy constructor
+			VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() );
+			assert( function );
+			if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) {
+				// replace argument to function call with temporary
+				arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
+				impCpCtorExpr->get_tempDecls().push_back( tmp );
+				impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
+			} // if
+		}
+
+		void ResolveCopyCtors::destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
+			if ( TupleType * tupleType = dynamic_cast< TupleType * > ( ret->get_result() ) ) {
+				int idx = 0;
+				for ( Type *& t : tupleType->get_types() ) {
+					(void)t;
+					destructRet( new TupleIndexExpr( ret->clone(), idx++ ), impCpCtorExpr );
+				}
+				return;
+			}
+			impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", new AddressExpr( ret ) ) );
+		}
+
 		void ResolveCopyCtors::visit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
-			static UniqueName tempNamer("_tmp_cp");
-			static UniqueName retNamer("_tmp_cp_ret");
-
 			CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
 			Visitor::visit( impCpCtorExpr );
@@ -389,29 +442,5 @@
 			// take each argument and attempt to copy construct it.
 			for ( Expression * & arg : appExpr->get_args() ) {
-				CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *impCpCtorExpr->get_env() << std::endl; )
-				// xxx - need to handle tuple arguments
-				assert( arg->has_result() );
-				Type * result = arg->get_result();
-				if ( skipCopyConstruct( result ) ) continue; // skip certain non-copyable types
-				// type may involve type variables, so apply type substitution to get temporary variable's actual type
-				result = result->clone();
-				impCpCtorExpr->get_env()->apply( result );
-				ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
-				tmp->get_type()->set_isConst( false );
-
-				// create and resolve copy constructor
-				CP_CTOR_PRINT( std::cerr << "makeCtorDtor for an argument" << std::endl; )
-				ApplicationExpr * cpCtor = makeCtorDtor( "?{}", tmp, arg );
-
-				// if the chosen constructor is intrinsic, the copy is unnecessary, so
-				// don't create the temporary and don't call the copy constructor
-				VariableExpr * function = dynamic_cast< VariableExpr * >( cpCtor->get_function() );
-				assert( function );
-				if ( function->get_var()->get_linkage() != LinkageSpec::Intrinsic ) {
-					// replace argument to function call with temporary
-					arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
-					impCpCtorExpr->get_tempDecls().push_back( tmp );
-					impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", tmp ) );
-				} // if
+				copyConstructArg( arg, impCpCtorExpr );
 			} // for
 
@@ -425,5 +454,5 @@
 			Type * result = appExpr->get_result();
 			if ( ! result->isVoid() ) {
-				// need to flatten result type and construct each
+				static UniqueName retNamer("_tmp_cp_ret");
 				result = result->clone();
 				impCpCtorExpr->get_env()->apply( result );
@@ -432,5 +461,5 @@
 				impCpCtorExpr->get_returnDecls().push_back( ret );
 				CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
-				impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
+				destructRet( new VariableExpr( ret ) , impCpCtorExpr );
 			} // for
 			CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 23b6643f5ea88fa1b0e11583e2f0ed9315a515de)
+++ src/SynTree/TupleExpr.cc	(revision 1132b62939ee72e624dd65d3bacb0e67cb1a0347)
@@ -46,4 +46,5 @@
 	assert( type->size() > index );
 	set_result( (*std::next( type->get_types().begin(), index ))->clone() );
+	get_result()->set_isLvalue( type->get_isLvalue() );
 }
 
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 23b6643f5ea88fa1b0e11583e2f0ed9315a515de)
+++ src/Tuples/TupleExpansion.cc	(revision 1132b62939ee72e624dd65d3bacb0e67cb1a0347)
@@ -27,4 +27,5 @@
 #include "SymTab/Mangler.h"
 #include "Common/ScopedMap.h"
+#include "ResolvExpr/typeops.h"
 
 namespace Tuples {
@@ -48,4 +49,5 @@
 
 			virtual Type * mutate( TupleType * tupleType );
+			virtual Type * mutate( FunctionType * ftype );
 
 			virtual CompoundStmt * mutate( CompoundStmt * stmt ) {
@@ -119,4 +121,17 @@
 	}
 
+	Type * TupleTypeReplacer::mutate( FunctionType * ftype ) {
+		// replace multiple-returning functions with functions which return a tuple
+		if ( ftype->get_returnVals().size() > 1 ) {
+			TupleType * tupleType = safe_dynamic_cast<TupleType *>( ResolvExpr::extractResultType( ftype ) );
+			ObjectDecl * retVal = new ObjectDecl( "__tuple_ret", DeclarationNode::NoStorageClass, LinkageSpec::C, nullptr, tupleType, nullptr );
+			// xxx - replace all uses of return vals with appropriate tuple index expr
+			deleteAll( ftype->get_returnVals() );
+			ftype->get_returnVals().clear();
+			ftype->get_returnVals().push_back( retVal );
+		}
+		return Parent::mutate( ftype );
+	}
+
 	Type * TupleTypeReplacer::mutate( TupleType * tupleType ) {
 		std::string mangleName = SymTab::Mangler::mangleType( tupleType );
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 23b6643f5ea88fa1b0e11583e2f0ed9315a515de)
+++ src/main.cc	(revision 1132b62939ee72e624dd65d3bacb0e67cb1a0347)
@@ -269,13 +269,13 @@
 		OPTPRINT( "convertLvalue" )
 		GenPoly::convertLvalue( translationUnit );
+
+		if ( bboxp ) {
+			dump( translationUnit );
+			return 0;
+		} // if
+		OPTPRINT( "box" )
+		GenPoly::box( translationUnit );
 		OPTPRINT( "expandTuples" ); // xxx - is this the right place for this?
 		Tuples::expandTuples( translationUnit );
-
-		if ( bboxp ) {
-			dump( translationUnit );
-			return 0;
-		} // if
-		OPTPRINT( "box" )
-		GenPoly::box( translationUnit );
 
 		// print tree right before code generation
