Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision ec42ff2e16a4d9e4fa25a7afb0cc135b75bfdf53)
+++ src/Common/PassVisitor.impl.h	(revision 2f86ddf839c92a4a8670497106e33770cf52c2bc)
@@ -1778,9 +1778,6 @@
 	VISIT_START( node );
 
-	indexerScopedAccept( node->result     , *this );
-	maybeAccept_impl   ( node->callExpr   , *this );
-	maybeAccept_impl   ( node->tempDecls  , *this );
-	maybeAccept_impl   ( node->returnDecls, *this );
-	maybeAccept_impl   ( node->dtors      , *this );
+	indexerScopedAccept( node->result    , *this );
+	maybeAccept_impl   ( node->callExpr  , *this );
 
 	VISIT_END( node );
@@ -1791,10 +1788,7 @@
 	MUTATE_START( node );
 
-	indexerScopedMutate( node->env        , *this );
-	indexerScopedMutate( node->result     , *this );
-	maybeMutate_impl   ( node->callExpr   , *this );
-	maybeMutate_impl   ( node->tempDecls  , *this );
-	maybeMutate_impl   ( node->returnDecls, *this );
-	maybeMutate_impl   ( node->dtors      , *this );
+	indexerScopedMutate( node->env       , *this );
+	indexerScopedMutate( node->result    , *this );
+	maybeMutate_impl   ( node->callExpr  , *this );
 
 	MUTATE_END( Expression, node );
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision ec42ff2e16a4d9e4fa25a7afb0cc135b75bfdf53)
+++ src/InitTweak/FixInit.cc	(revision 2f86ddf839c92a4a8670497106e33770cf52c2bc)
@@ -68,6 +68,4 @@
 namespace InitTweak {
 	namespace {
-		typedef std::unordered_map< int, int > UnqCount;
-
 		struct SelfAssignChecker {
 			void previsit( ApplicationExpr * appExpr );
@@ -82,16 +80,13 @@
 		};
 
-		struct ResolveCopyCtors final : public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution {
+		struct ResolveCopyCtors final : public WithStmtsToAdd, public WithIndexer, public WithShortCircuiting, public WithTypeSubstitution, public WithVisitorRef<ResolveCopyCtors> {
 			/// generate temporary ObjectDecls for each argument and return value of each ImplicitCopyCtorExpr,
 			/// 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, UnqCount & unqCount );
-
-			ResolveCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ) {}
-
-			void postvisit( ImplicitCopyCtorExpr * impCpCtorExpr );
-			void postvisit( StmtExpr * stmtExpr );
-			void previsit( UniqueExpr * unqExpr );
-			void postvisit( UniqueExpr * unqExpr );
+			static void resolveImplicitCalls( std::list< Declaration * > & translationUnit );
+
+			Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
+			void premutate( StmtExpr * stmtExpr );
+			void premutate( UniqueExpr * unqExpr );
 
 			/// create and resolve ctor/dtor expression: fname(var, [cpArg])
@@ -100,8 +95,5 @@
 			bool skipCopyConstruct( Type * type );
 			void copyConstructArg( Expression *& arg, ImplicitCopyCtorExpr * impCpCtorExpr, Type * formal );
-			void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr );
-
-			UnqCount & unqCount; // count the number of times each unique expr ID appears
-			std::unordered_set< int > vars;
+			void destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg );
 		};
 
@@ -185,18 +177,4 @@
 		};
 
-		class FixCopyCtors final : public WithStmtsToAdd, public WithShortCircuiting, public WithVisitorRef<FixCopyCtors>, public WithTypeSubstitution {
-		  public:
-			FixCopyCtors( UnqCount & unqCount ) : unqCount( unqCount ){}
-			/// expand ImplicitCopyCtorExpr nodes into the temporary declarations, copy constructors, call expression,
-			/// and destructors
-			static void fixCopyCtors( std::list< Declaration * > &translationUnit, UnqCount & unqCount );
-
-			Expression * postmutate( ImplicitCopyCtorExpr * impCpCtorExpr );
-			void premutate( StmtExpr * stmtExpr );
-			void premutate( UniqueExpr * unqExpr );
-
-			UnqCount & unqCount;
-		};
-
 		struct GenStructMemberCalls final : public WithGuards, public WithShortCircuiting, public WithIndexer, public WithVisitorRef<GenStructMemberCalls> {
 			/// generate default/copy ctor and dtor calls for user-defined struct ctor/dtors
@@ -251,17 +229,15 @@
 		InitTweak::fixGlobalInit( translationUnit, inLibrary );
 
-		UnqCount unqCount;
-
 		// must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
 		SplitExpressions::split( translationUnit );
 
 		InsertImplicitCalls::insert( translationUnit );
-		ResolveCopyCtors::resolveImplicitCalls( translationUnit, unqCount );
+
+		// Needs to happen before ResolveCopyCtors, because argument/return temporaries should not be considered in
+		// error checking branch statements
 		InsertDtors::insert( translationUnit );
+
+		ResolveCopyCtors::resolveImplicitCalls( translationUnit );
 		FixInit::fixInitializers( translationUnit );
-
-		// FixCopyCtors must happen after FixInit, so that destructors are placed correctly
-		FixCopyCtors::fixCopyCtors( translationUnit, unqCount );
-
 		GenStructMemberCalls::generate( translationUnit );
 
@@ -335,7 +311,7 @@
 		}
 
-		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
-			PassVisitor<ResolveCopyCtors> resolver( unqCount );
-			acceptAll( translationUnit, resolver );
+		void ResolveCopyCtors::resolveImplicitCalls( std::list< Declaration * > & translationUnit ) {
+			PassVisitor<ResolveCopyCtors> resolver;
+			mutateAll( translationUnit, resolver );
 		}
 
@@ -363,9 +339,4 @@
 			PassVisitor<InsertDtors> inserter( finder );
 			acceptAll( translationUnit, inserter );
-		}
-
-		void FixCopyCtors::fixCopyCtors( std::list< Declaration * > & translationUnit, UnqCount & unqCount ) {
-			PassVisitor<FixCopyCtors> fixer( unqCount );
-			mutateAll( translationUnit, fixer );
 		}
 
@@ -529,5 +500,5 @@
 			if ( TupleAssignExpr * assign = dynamic_cast< TupleAssignExpr * >( resolved ) ) {
 				// fix newly generated StmtExpr
-				postvisit( assign->stmtExpr );
+				premutate( assign->stmtExpr );
 			}
 			return resolved;
@@ -569,17 +540,59 @@
 
 			// replace argument to function call with temporary
-			arg = new CommaExpr( cpCtor, new VariableExpr( tmp ) );
-			impCpCtorExpr->tempDecls.push_back( tmp );
-			impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
-		}
-
-		void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr ) {
-			impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
-		}
-
-		void ResolveCopyCtors::postvisit( ImplicitCopyCtorExpr *impCpCtorExpr ) {
+			stmtsToAddBefore.push_back( new DeclStmt( tmp ) );
+			arg = cpCtor;
+			destructRet( tmp, impCpCtorExpr, arg );
+
+			// impCpCtorExpr->dtors.push_front( makeCtorDtor( "^?{}", tmp ) );
+		}
+
+		void ResolveCopyCtors::destructRet( ObjectDecl * ret, ImplicitCopyCtorExpr * impCpCtorExpr, Expression *& arg ) {
+			// TODO: refactor code for generating cleanup attribute, since it's common and reused in ~3-4 places
+			// check for existing cleanup attribute before adding another(?)
+			// need to add __Destructor for _tmp_cp variables as well
+
+			assertf( Validate::dtorStruct && Validate::dtorStruct->members.size() == 2, "Destructor generation requires __Destructor definition." );
+			assertf( Validate::dtorStructDestroy, "Destructor generation requires __destroy_Destructor." );
+
+			// generate a __Destructor for ret that calls the destructor
+			Expression * dtor = makeCtorDtor( "^?{}", ret );
+
+			// // xxx - check if intrinsic and elide if so
+			// if ( arg && isIntrinsicCallExpr( dtor ) ) {
+			// 	arg = new CommaExpr( arg, new VariableExpr( ret ) );
+			// 	return;
+			// }
+
+			if ( ! dtor->env ) dtor->env = maybeClone( env );
+			DeclarationWithType * dtorFunc = getDtorFunc( ret, new ExprStmt( dtor ), stmtsToAddBefore );
+
+			StructInstType * dtorStructType = new StructInstType( Type::Qualifiers(), Validate::dtorStruct );
+			dtorStructType->parameters.push_back( new TypeExpr( new VoidType( Type::Qualifiers() ) ) );
+
+			// cast destructor pointer to void (*)(void *), to silence GCC incompatible pointer warnings
+			FunctionType * dtorFtype = new FunctionType( Type::Qualifiers(), false );
+			dtorFtype->parameters.push_back( ObjectDecl::newObject( "", new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ), nullptr ) );
+			Type * dtorType = new PointerType( Type::Qualifiers(), dtorFtype );
+
+			static UniqueName namer( "_ret_dtor" );
+			ObjectDecl * retDtor = ObjectDecl::newObject( namer.newName(), dtorStructType, new ListInit( { new SingleInit( new ConstantExpr( Constant::null() ) ), new SingleInit( new CastExpr( new VariableExpr( dtorFunc ), dtorType ) ) } ) );
+			retDtor->attributes.push_back( new Attribute( "cleanup", { new VariableExpr( Validate::dtorStructDestroy ) } ) );
+			stmtsToAddBefore.push_back( new DeclStmt( retDtor ) );
+
+			if ( arg ) {
+				Expression * member = new MemberExpr( strict_dynamic_cast<DeclarationWithType *>( Validate::dtorStruct->members.front() ), new VariableExpr( retDtor ) );
+				Expression * object = new CastExpr( new AddressExpr( new VariableExpr( ret ) ), new PointerType( Type::Qualifiers(), new VoidType( Type::Qualifiers() ) ) );
+				Expression * assign = createBitwiseAssignment( member, object );
+				arg = new CommaExpr( new CommaExpr( arg, assign ), new VariableExpr( ret ) );
+			}
+
+			// impCpCtorExpr->get_dtors().push_front( makeCtorDtor( "^?{}", ret ) );
+		}
+
+		Expression * ResolveCopyCtors::postmutate( ImplicitCopyCtorExpr *impCpCtorExpr ) {
 			CP_CTOR_PRINT( std::cerr << "ResolveCopyCtors: " << impCpCtorExpr << std::endl; )
 
 			ApplicationExpr * appExpr = impCpCtorExpr->callExpr;
+			ObjectDecl * returnDecl = nullptr;
 
 			// take each argument and attempt to copy construct it.
@@ -590,5 +603,5 @@
 			for ( Expression * & arg : appExpr->args ) {
 				Type * formal = nullptr;
-				if ( iter != params.end() ) {
+				if ( iter != params.end() ) { // does not copy construct C-style variadic arguments
 					DeclarationWithType * param = *iter++;
 					formal = param->get_type();
@@ -608,18 +621,56 @@
 				ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
 				ret->type->set_const( false );
-				impCpCtorExpr->returnDecls.push_back( ret );
+				returnDecl = ret;
+				stmtsToAddBefore.push_back( new DeclStmt( ret ) );
 				CP_CTOR_PRINT( std::cerr << "makeCtorDtor for a return" << std::endl; )
+			} // for
+			CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
+			// ------------------------------------------------------
+
+			CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
+
+			// detach fields from wrapper node so that it can be deleted without deleting too much
+			impCpCtorExpr->callExpr = nullptr;
+			std::swap( impCpCtorExpr->env, appExpr->env );
+			assert( impCpCtorExpr->env == nullptr );
+			delete impCpCtorExpr;
+
+			if ( returnDecl ) {
+				Expression * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), appExpr );
 				if ( ! dynamic_cast< ReferenceType * >( result ) ) {
 					// destructing reference returns is bad because it can cause multiple destructor calls to the same object - the returned object is not a temporary
-					destructRet( ret, impCpCtorExpr );
-				}
+					destructRet( returnDecl, impCpCtorExpr, assign );
+				} else {
+					assign = new CommaExpr( assign, new VariableExpr( returnDecl ) );
+				}
+				// move env from appExpr to retExpr
+				std::swap( assign->env, appExpr->env );
+				return assign;
+			} else {
+				return appExpr;
+			} // if
+		}
+
+		void ResolveCopyCtors::premutate( StmtExpr * stmtExpr ) {
+			// function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
+			// since temporaries can be shared across sub-expressions, e.g.
+			//   [A, A] f();
+			//   g([A] x, [A] y);
+			//   g(f());
+			// f is executed once, so the return temporary is shared across the tuple constructors for x and y.
+			// Explicitly mutating children instead of mutating the inner compound statement forces the temporaries to be added
+			// to the outer context, rather than inside of the statement expression.
+			visit_children = false;
+
+			assert( env );
+
+			// visit all statements
+			std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
+			for ( Statement *& stmt : stmts ) {
+				stmt = stmt->acceptMutator( *visitor );
 			} // for
-			CP_CTOR_PRINT( std::cerr << "after Resolving: " << impCpCtorExpr << std::endl; )
-		}
-
-		void ResolveCopyCtors::postvisit( StmtExpr * stmtExpr ) {
-			assert( env );
-			assert( stmtExpr->get_result() );
-			Type * result = stmtExpr->get_result();
+
+			assert( stmtExpr->result );
+			Type * result = stmtExpr->result;
 			if ( ! result->isVoid() ) {
 				static UniqueName retNamer("_tmp_stmtexpr_ret");
@@ -635,23 +686,25 @@
 				ObjectDecl * ret = ObjectDecl::newObject( retNamer.newName(), result, nullptr );
 				ret->type->set_const( false );
-				stmtExpr->returnDecls.push_front( ret );
+				stmtsToAddBefore.push_back( new DeclStmt( ret ) );
 
 				// must have a non-empty body, otherwise it wouldn't have a result
 				CompoundStmt * body = stmtExpr->statements;
-				assert( ! body->get_kids().empty() );
+				assert( ! body->kids.empty() );
 				// must be an ExprStmt, otherwise it wouldn't have a result
-				ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->get_kids().back() );
-				last->expr = makeCtorDtor( "?{}", ret, last->get_expr() );
-
-				stmtExpr->dtors.push_front( makeCtorDtor( "^?{}", ret ) );
+				ExprStmt * last = strict_dynamic_cast< ExprStmt * >( body->kids.back() );
+				last->expr = makeCtorDtor( "?{}", ret, last->expr );
+
+				// add destructors after current statement
+				stmtsToAddAfter.push_back( new ExprStmt( makeCtorDtor( "^?{}", ret ) ) );
+
+				// must have a non-empty body, otherwise it wouldn't have a result
+				assert( ! stmts.empty() );
+
+				// if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
+				stmts.push_back( new ExprStmt( new VariableExpr( ret ) ) );
 			} // if
-		}
-
-		void ResolveCopyCtors::previsit( UniqueExpr * unqExpr ) {
-			unqCount[ unqExpr->get_id() ]++;  // count the number of unique expressions for each ID
-			if ( vars.count( unqExpr->get_id() ) ) {
-				// xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
-				visit_children = false;
-			}
+
+			assert( stmtExpr->returnDecls.empty() );
+			assert( stmtExpr->dtors.empty() );
 		}
 
@@ -670,137 +723,38 @@
 		}
 
-		void ResolveCopyCtors::postvisit( UniqueExpr * unqExpr ) {
-			if ( vars.count( unqExpr->get_id() ) ) {
-				// xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
-				return;
-			}
-
-			// it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
-			assert( unqExpr->result );
-			if ( ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast<ImplicitCopyCtorExpr*>( unqExpr->expr ) ) {
-				// note the variable used as the result from the call
-				assert( impCpCtorExpr->result && impCpCtorExpr->returnDecls.size() == 1 );
-				unqExpr->set_var( new VariableExpr( impCpCtorExpr->returnDecls.front() ) );
+		void ResolveCopyCtors::premutate( UniqueExpr * unqExpr ) {
+			visit_children = false;
+			// xxx - hack to prevent double-handling of unique exprs, otherwise too many temporary variables and destructors are generated
+			static std::unordered_map< int, UniqueExpr * > unqMap;
+			if ( ! unqMap.count( unqExpr->get_id() ) ) {
+				// resolve expr and find its
+
+				ImplicitCopyCtorExpr * impCpCtorExpr = dynamic_cast< ImplicitCopyCtorExpr * >( unqExpr->expr );
+				// PassVisitor<ResolveCopyCtors> fixer;
+				unqExpr->expr = unqExpr->expr->acceptMutator( *visitor );
+
+				// it should never be necessary to wrap a void-returning expression in a UniqueExpr - if this assumption changes, this needs to be rethought
+				assert( unqExpr->result );
+				if ( impCpCtorExpr ) {
+					CommaExpr * comma = strict_dynamic_cast< CommaExpr * >( unqExpr->expr );
+					VariableExpr * var = strict_dynamic_cast<VariableExpr *>( comma->arg2 );
+					// note the variable used as the result from the call
+					unqExpr->var = var->clone();
+				} else {
+					// expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
+					unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
+					unqExpr->var = new VariableExpr( unqExpr->object );
+				}
+
+				// stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
+				// stmtsToAddAfter.splice( stmtsToAddAfter.end(), fixer.pass.stmtsToAddAfter );
+				unqMap[unqExpr->get_id()] = unqExpr;
 			} else {
-				// expr isn't a call expr, so create a new temporary variable to use to hold the value of the unique expression
-				unqExpr->object = ObjectDecl::newObject( toString("_unq", unqExpr->get_id()), unqExpr->result->clone(), makeInit( unqExpr->result ) );
-				unqExpr->var = new VariableExpr( unqExpr->object );
-			}
-			vars.insert( unqExpr->get_id() );
-		}
-
-		Expression * FixCopyCtors::postmutate( ImplicitCopyCtorExpr * impCpCtorExpr ) {
-			CP_CTOR_PRINT( std::cerr << "FixCopyCtors: " << impCpCtorExpr << std::endl; )
-
-			std::list< ObjectDecl * > & tempDecls = impCpCtorExpr->tempDecls;
-			std::list< ObjectDecl * > & returnDecls = impCpCtorExpr->returnDecls;
-			std::list< Expression * > & dtors = impCpCtorExpr->dtors;
-
-			// add all temporary declarations and their constructors
-			for ( ObjectDecl * obj : tempDecls ) {
-				stmtsToAddBefore.push_back( new DeclStmt( obj ) );
-			} // for
-			for ( ObjectDecl * obj : returnDecls ) {
-				stmtsToAddBefore.push_back( new DeclStmt( obj ) );
-			} // for
-
-			// add destructors after current statement
-			for ( Expression * dtor : dtors ) {
-				// take relevant bindings from environment
-				assert( ! dtor->env );
-				dtor->env =  maybeClone( env );
-				stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
-			} // for
-
-			ObjectDecl * returnDecl = returnDecls.empty() ? nullptr : returnDecls.front();
-			Expression * callExpr = impCpCtorExpr->get_callExpr();
-
-			CP_CTOR_PRINT( std::cerr << "Coming out the back..." << impCpCtorExpr << std::endl; )
-
-			// detach fields from wrapper node so that it can be deleted without deleting too much
-			dtors.clear();
-			tempDecls.clear();
-			returnDecls.clear();
-			impCpCtorExpr->callExpr = nullptr;
-			std::swap( impCpCtorExpr->env, callExpr->env );
-			assert( impCpCtorExpr->env == nullptr );
-			delete impCpCtorExpr;
-
-			if ( returnDecl ) {
-				ApplicationExpr * assign = createBitwiseAssignment( new VariableExpr( returnDecl ), callExpr );
-				Expression * retExpr = new CommaExpr( assign, new VariableExpr( returnDecl ) );
-				// move env from callExpr to retExpr
-				std::swap( retExpr->env, callExpr->env );
-				return retExpr;
-			} else {
-				return callExpr;
-			} // if
-		}
-
-		void FixCopyCtors::premutate( StmtExpr * stmtExpr ) {
-			// function call temporaries should be placed at statement-level, rather than nested inside of a new statement expression,
-			// since temporaries can be shared across sub-expressions, e.g.
-			//   [A, A] f();
-			//   g([A] x, [A] y);
-			//   g(f());
-			// f is executed once, so the return temporary is shared across the tuple constructors for x and y.
-			// Explicitly mutating children instead of mutating the inner compound statment forces the temporaries to be added
-			// to the outer context, rather than inside of the statement expression.
-			visit_children = false;
-			std::list< Statement * > & stmts = stmtExpr->statements->get_kids();
-			for ( Statement *& stmt : stmts ) {
-				stmt = stmt->acceptMutator( *visitor );
-			} // for
-			assert( stmtExpr->result );
-			Type * result = stmtExpr->result;
-			if ( ! result->isVoid() ) {
-				for ( ObjectDecl * obj : stmtExpr->returnDecls ) {
-					stmtsToAddBefore.push_back( new DeclStmt( obj ) );
-				} // for
-				// add destructors after current statement
-				for ( Expression * dtor : stmtExpr->dtors ) {
-					stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
-				} // for
-				// must have a non-empty body, otherwise it wouldn't have a result
-				assert( ! stmts.empty() );
-				assertf( ! stmtExpr->returnDecls.empty() || stmtExpr->dtors.empty(), "StmtExpr returns non-void, but no return decls: %s", toString( stmtExpr ).c_str() );
-				// if there is a return decl, add a use as the last statement; will not have return decl on non-constructable returns
-				if ( ! stmtExpr->returnDecls.empty() ) {
-					stmts.push_back( new ExprStmt( new VariableExpr( stmtExpr->returnDecls.front() ) ) );
-				}
-				stmtExpr->returnDecls.clear();
-				stmtExpr->dtors.clear();
-			}
-			assert( stmtExpr->returnDecls.empty() );
-			assert( stmtExpr->dtors.empty() );
-		}
-
-		void FixCopyCtors::premutate( UniqueExpr * unqExpr ) {
-			visit_children = false;
-			unqCount[ unqExpr->get_id() ]--;
-			static std::unordered_map< int, std::list< Statement * > > dtors;
-			static std::unordered_map< int, UniqueExpr * > unqMap;
-			// has to be done to clean up ImplicitCopyCtorExpr nodes, even when this node was skipped in previous passes
-			if ( unqMap.count( unqExpr->get_id() ) ) {
 				// take data from other UniqueExpr to ensure consistency
 				delete unqExpr->get_expr();
-				unqExpr->set_expr( unqMap[unqExpr->get_id()]->get_expr()->clone() );
-				delete unqExpr->get_result();
-				unqExpr->set_result( maybeClone( unqExpr->get_expr()->get_result() ) );
-				if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
-					stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
-				}
-				return;
-			}
-			PassVisitor<FixCopyCtors> fixer( unqCount );
-			unqExpr->set_expr( unqExpr->get_expr()->acceptMutator( fixer ) ); // stmtexprs contained should not be separately fixed, so this must occur after the lookup
-			stmtsToAddBefore.splice( stmtsToAddBefore.end(), fixer.pass.stmtsToAddBefore );
-			unqMap[unqExpr->get_id()] = unqExpr;
-			if ( unqCount[ unqExpr->get_id() ] == 0 ) {  // insert destructor after the last use of the unique expression
-				stmtsToAddAfter.splice( stmtsToAddAfter.end(), dtors[ unqExpr->get_id() ] );
-			} else { // remember dtors for last instance of unique expr
-				dtors[ unqExpr->get_id() ] = fixer.pass.stmtsToAddAfter;
-			}
-			return;
+				unqExpr->expr = unqMap[unqExpr->get_id()]->expr->clone();
+				delete unqExpr->result;
+				unqExpr->result = maybeClone( unqExpr->expr->result );
+			}
 		}
 
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision ec42ff2e16a4d9e4fa25a7afb0cc135b75bfdf53)
+++ src/SynTree/Expression.cc	(revision 2f86ddf839c92a4a8670497106e33770cf52c2bc)
@@ -538,11 +538,8 @@
 	assert( callExpr );
 	assert( callExpr->result );
-	set_result( callExpr->get_result()->clone() );
+	set_result( callExpr->result->clone() );
 }
 
 ImplicitCopyCtorExpr::ImplicitCopyCtorExpr( const ImplicitCopyCtorExpr & other ) : Expression( other ), callExpr( maybeClone( other.callExpr ) ) {
-	cloneAll( other.tempDecls, tempDecls );
-	cloneAll( other.returnDecls, returnDecls );
-	cloneAll( other.dtors, dtors );
 }
 
@@ -550,7 +547,4 @@
 	set_env( nullptr ); // ImplicitCopyCtorExpr does not take ownership of an environment
 	delete callExpr;
-	deleteAll( tempDecls );
-	deleteAll( returnDecls );
-	deleteAll( dtors );
 }
 
@@ -558,9 +552,4 @@
 	os <<  "Implicit Copy Constructor Expression: " << std::endl << indent+1;
 	callExpr->print( os, indent+1 );
-	os << std::endl << indent << "... with temporaries:" << std::endl;
-	printAll( tempDecls, os, indent+1 );
-	os << std::endl << indent << "... with return temporaries:" << std::endl;
-	printAll( returnDecls, os, indent+1 );
-	Expression::print( os, indent );
 }
 
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision ec42ff2e16a4d9e4fa25a7afb0cc135b75bfdf53)
+++ src/SynTree/Expression.h	(revision 2f86ddf839c92a4a8670497106e33770cf52c2bc)
@@ -591,19 +591,9 @@
 class ImplicitCopyCtorExpr : public Expression {
 public:
-	ApplicationExpr * callExpr;
-	std::list< ObjectDecl * > tempDecls;
-	std::list< ObjectDecl * > returnDecls;
-	std::list< Expression * > dtors;
+	ApplicationExpr * callExpr = nullptr;
 
 	ImplicitCopyCtorExpr( ApplicationExpr * callExpr );
 	ImplicitCopyCtorExpr( const ImplicitCopyCtorExpr & other );
 	virtual ~ImplicitCopyCtorExpr();
-
-	ApplicationExpr * get_callExpr() const { return callExpr; }
-	void set_callExpr( ApplicationExpr * newValue ) { callExpr = newValue; }
-
-	std::list< ObjectDecl * > & get_tempDecls() { return tempDecls; }
-	std::list< ObjectDecl * > & get_returnDecls() { return returnDecls; }
-	std::list< Expression * > & get_dtors() { return dtors; }
 
 	virtual ImplicitCopyCtorExpr * clone() const { return new ImplicitCopyCtorExpr( * this ); }
