Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
+++ src/InitTweak/FixInit.cc	(revision 31f379c6412cdf1bd9e7efed78d6788bbf58ed10)
@@ -49,12 +49,20 @@
 namespace InitTweak {
 	namespace {
+		typedef std::unordered_map< Expression *, TypeSubstitution * > EnvMap;
+
 		class InsertImplicitCalls final : public GenPoly::PolyMutator {
 		public:
 			/// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
 			/// function calls need their parameters to be copy constructed
-			static void insert( std::list< Declaration * > & translationUnit );
-
-			using GenPoly::PolyMutator::mutate;
+			static void insert( std::list< Declaration * > & translationUnit, EnvMap & envMap );
+
+			InsertImplicitCalls( EnvMap & envMap ) : envMap( envMap ) {}
+			typedef GenPoly::PolyMutator Parent;
+			using Parent::mutate;
 			virtual Expression * mutate( ApplicationExpr * appExpr ) override;
+			virtual Expression * mutate( StmtExpr * stmtExpr ) override;
+
+			// collects environments for relevant nodes
+			EnvMap & envMap;
 		};
 
@@ -64,11 +72,14 @@
 			/// generate/resolve copy construction expressions for each, and generate/resolve destructors for both
 			/// arguments and return value temporaries
-			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
+			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap );
 
 			typedef SymTab::Indexer Parent;
 			using Parent::visit;
 
+			ResolveCopyCtors( const EnvMap & envMap ) : envMap( envMap ) {}
+
 			virtual void visit( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
-			virtual void visit( UniqueExpr * unqExpr );
+			virtual void visit( UniqueExpr * unqExpr ) override;
+			virtual void visit( StmtExpr * stmtExpr ) override;
 
 			/// create and resolve ctor/dtor expression: fname(var, [cpArg])
@@ -79,6 +90,7 @@
 			void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr );
 			void destructRet( Expression * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
-		private:
+
 			TypeSubstitution * env;
+			const EnvMap & envMap;
 		};
 
@@ -174,5 +186,6 @@
 			static void fixInitializers( std::list< Declaration * > &translationUnit );
 
-			using GenPoly::PolyMutator::mutate;
+			typedef GenPoly::PolyMutator Parent;
+			using Parent::mutate;
 			virtual DeclarationWithType * mutate( ObjectDecl *objDecl ) override;
 
@@ -186,7 +199,9 @@
 			static void fixCopyCtors( std::list< Declaration * > &translationUnit );
 
-			using GenPoly::PolyMutator::mutate;
+			typedef GenPoly::PolyMutator Parent;
+			using Parent::mutate;
 			virtual Expression * mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) override;
 			virtual Expression * mutate( UniqueExpr * unqExpr ) override;
+			virtual Expression * mutate( StmtExpr * stmtExpr ) override;
 		};
 
@@ -248,7 +263,8 @@
 		InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
 
-
-		InsertImplicitCalls::insert( translationUnit );
-		ResolveCopyCtors::resolveImplicitCalls( translationUnit );
+		EnvMap envMap;
+
+		InsertImplicitCalls::insert( translationUnit, envMap );
+		ResolveCopyCtors::resolveImplicitCalls( translationUnit, envMap );
 		InsertDtors::insert( translationUnit );
 		FixInit::fixInitializers( translationUnit );
@@ -269,11 +285,11 @@
 
 	namespace {
-		void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit ) {
-			InsertImplicitCalls inserter;
+		void InsertImplicitCalls::insert( std::list< Declaration * > & translationUnit, EnvMap & envMap ) {
+			InsertImplicitCalls inserter( envMap );
 			mutateAll( translationUnit, inserter );
 		}
 
-		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
-			ResolveCopyCtors resolver;
+		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, const EnvMap & envMap ) {
+			ResolveCopyCtors resolver( envMap );
 			acceptAll( translationUnit, resolver );
 		}
@@ -326,5 +342,5 @@
 
 		Expression * InsertImplicitCalls::mutate( ApplicationExpr * appExpr ) {
-			appExpr = dynamic_cast< ApplicationExpr * >( Mutator::mutate( appExpr ) );
+			appExpr = dynamic_cast< ApplicationExpr * >( Parent::mutate( appExpr ) );
 			assert( appExpr );
 
@@ -339,6 +355,5 @@
 						Type * t1 = ftype->get_parameters().front()->get_type();
 						Type * t2 = ftype->get_parameters().back()->get_type();
-						PointerType * ptrType = dynamic_cast< PointerType * > ( t1 );
-						assert( ptrType );
+						PointerType * ptrType = safe_dynamic_cast< PointerType * > ( t1 );
 
 						if ( ResolvExpr::typesCompatible( ptrType->get_base(), t2, SymTab::Indexer() ) ) {
@@ -357,5 +372,5 @@
 			// wrap each function call so that it is easy to identify nodes that have to be copy constructed
 			ImplicitCopyCtorExpr * expr = new ImplicitCopyCtorExpr( appExpr );
-			// save the type substitution onto the new node so that it is easy to find.
+			// save the type substitution into the envMap so that it is easy to find.
 			// Ensure it is not deleted with the ImplicitCopyCtorExpr by removing it before deletion.
 			// The substitution is needed to obtain the type of temporary variables so that copy constructor
@@ -366,6 +381,12 @@
 			// constructor calls together.
 			assert( env );
-			expr->set_env( env );
+			envMap[expr] = env;
 			return expr;
+		}
+
+		Expression * InsertImplicitCalls::mutate( StmtExpr * stmtExpr ) {
+			assert( env );
+			envMap[stmtExpr] = env;
+			return Parent::mutate( stmtExpr );
 		}
 
@@ -392,5 +413,8 @@
 			assert( resolved );
 			if ( resolved->get_env() ) {
+				// Extract useful information and discard new environments. Keeping them causes problems in PolyMutator passes.
 				env->add( *resolved->get_env() );
+				delete resolved->get_env();
+				resolved->set_env( nullptr );
 			} // if
 
@@ -401,5 +425,6 @@
 		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( env );
+			CP_CTOR_PRINT( std::cerr << "Type Substitution: " << *env << std::endl; )
 			assert( arg->has_result() );
 			Type * result = arg->get_result();
@@ -408,5 +433,5 @@
 			// type may involve type variables, so apply type substitution to get temporary variable's actual type
 			result = result->clone();
-			impCpCtorExpr->get_env()->apply( result );
+			env->apply( result );
 			ObjectDecl * tmp = new ObjectDecl( tempNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
 			tmp->get_type()->set_isConst( false );
@@ -437,5 +462,6 @@
 			CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
 			Parent::visit( impCpCtorExpr );
-			env = impCpCtorExpr->get_env(); // xxx - maybe we really should just have a PolyIndexer...
+			env = envMap.at(impCpCtorExpr);
+			assert( env );
 
 			ApplicationExpr * appExpr = impCpCtorExpr->get_callExpr();
@@ -448,14 +474,10 @@
 			// each return value from the call needs to be connected with an ObjectDecl at the call site, which is
 			// initialized with the return value and is destructed later
-			// xxx - handle multiple return values
-			ApplicationExpr * callExpr = impCpCtorExpr->get_callExpr();
-			// xxx - is this right? callExpr may not have the right environment, because it was attached at a higher
-			// level. Trying to pass that environment along.
-			callExpr->set_env( impCpCtorExpr->get_env()->clone() );
+			// xxx - handle named return values?
 			Type * result = appExpr->get_result();
 			if ( ! result->isVoid() ) {
 				static UniqueName retNamer("_tmp_cp_ret");
 				result = result->clone();
-				impCpCtorExpr->get_env()->apply( result );
+				env->apply( result );
 				ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
 				ret->get_type()->set_isConst( false );
@@ -468,4 +490,31 @@
 			} // for
 			CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
+		}
+
+		void ResolveCopyCtors::visit( StmtExpr * stmtExpr ) {
+			Parent::visit( stmtExpr );
+			env = envMap.at(stmtExpr);
+			assert( stmtExpr->get_result() );
+			Type * result = stmtExpr->get_result();
+			if ( ! result->isVoid() ) {
+				static UniqueName retNamer("_tmp_stmtexpr_ret");
+
+				// create variable that will hold the result of the stmt expr
+				result = result->clone();
+				env->apply( result );
+				ObjectDecl * ret = new ObjectDecl( retNamer.newName(), DeclarationNode::NoStorageClass, LinkageSpec::C, 0, result, 0 );
+				ret->get_type()->set_isConst( false );
+				stmtExpr->get_returnDecls().push_front( ret );
+
+				// must have a non-empty body, otherwise it wouldn't have a result
+				CompoundStmt * body = stmtExpr->get_statements();
+				assert( ! body->get_kids().empty() );
+				// must be an ExprStmt, otherwise it wouldn't have a result
+				ExprStmt * last = safe_dynamic_cast< ExprStmt * >( body->get_kids().back() );
+				last->set_expr( makeCtorDtor( "?{}", ret, last->get_expr() ) );
+
+				stmtExpr->get_dtors().push_front( makeCtorDtor( "^?{}", new AddressExpr( new VariableExpr( ret ) ) ) );
+			} // if
+
 		}
 
@@ -492,11 +541,8 @@
 		}
 
-
 		Expression * FixCopyCtors::mutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
 			CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
 
-			impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( Mutator::mutate( impCpCtorExpr ) );
-			assert( impCpCtorExpr );
-
+			impCpCtorExpr = safe_dynamic_cast< ImplicitCopyCtorExpr * >( Parent::mutate( impCpCtorExpr ) );
 			std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->get_tempDecls();
 			std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->get_returnDecls();
@@ -558,5 +604,7 @@
 					retExpr = UntypedExpr::createDeref( retExpr );
 				} // if
-				retExpr->set_env( env->clone() );
+				// move env from callExpr to retExpr
+				retExpr->set_env( callExpr->get_env() );
+				callExpr->set_env( nullptr );
 				return retExpr;
 			} else {
@@ -565,9 +613,31 @@
 		}
 
+		Expression * FixCopyCtors::mutate( StmtExpr * stmtExpr ) {
+			stmtExpr = safe_dynamic_cast< StmtExpr * >( Parent::mutate( stmtExpr ) );
+			assert( stmtExpr->get_result() );
+			Type * result = stmtExpr->get_result();
+			if ( ! result->isVoid() ) {
+				for ( ObjectDecl * obj : stmtExpr->get_returnDecls() ) {
+					stmtsToAdd.push_back( new DeclStmt( noLabels, obj ) );
+				} // for
+				// add destructors after current statement
+				for ( Expression * dtor : stmtExpr->get_dtors() ) {
+					stmtsToAddAfter.push_back( new ExprStmt( noLabels, dtor ) );
+				} // for
+				// must have a non-empty body, otherwise it wouldn't have a result
+				CompoundStmt * body = stmtExpr->get_statements();
+				assert( ! body->get_kids().empty() );
+				assert( ! stmtExpr->get_returnDecls().empty() );
+				body->get_kids().push_back( new ExprStmt( noLabels, new VariableExpr( stmtExpr->get_returnDecls().front() ) ) );
+			}
+			stmtExpr->get_returnDecls().clear();
+			stmtExpr->get_dtors().clear();
+			return stmtExpr;
+		}
+
 		Expression * FixCopyCtors::mutate( UniqueExpr * unqExpr ) {
 			static std::unordered_map< int, UniqueExpr * > unqMap;
 			static std::unordered_set< int > addDeref;
 			// has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
-			unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) );
 			if ( unqMap.count( unqExpr->get_id() ) ) {
 				// take data from other UniqueExpr to ensure consistency
@@ -582,4 +652,5 @@
 				return unqExpr;
 			}
+			unqExpr = safe_dynamic_cast< UniqueExpr * >( Parent::mutate( unqExpr ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
 			unqMap[unqExpr->get_id()] = unqExpr;
 			if ( UntypedExpr * deref = dynamic_cast< UntypedExpr * >( unqExpr->get_expr() ) ) {
@@ -599,6 +670,5 @@
 			// first recursively handle pieces of ObjectDecl so that they aren't missed by other visitors when the init
 			// is removed from the ObjectDecl
-			objDecl = dynamic_cast< ObjectDecl * >( Mutator::mutate( objDecl ) );
-
+			objDecl = dynamic_cast< ObjectDecl * >( Parent::mutate( objDecl ) );
 			if ( ConstructorInit * ctorInit = dynamic_cast< ConstructorInit * >( objDecl->get_init() ) ) {
 				// a decision should have been made by the resolver, so ctor and init are not both non-NULL
