Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 7ba13249ea0da313a9eabcdbd2aa54d5a9b18b29)
+++ src/InitTweak/FixInit.cc	(revision ec42ff2e16a4d9e4fa25a7afb0cc135b75bfdf53)
@@ -234,4 +234,12 @@
 			Expression * postmutate( ConstructorExpr * ctorExpr );
 		};
+
+		struct SplitExpressions : public WithShortCircuiting, public WithTypeSubstitution, public WithStmtsToAdd {
+			/// add CompoundStmts around top-level expressions so that temporaries are destroyed in the correct places.
+			static void split( std::list< Declaration * > &translationUnit );
+
+			Statement * postmutate( ExprStmt * stmt );
+			void premutate( TupleAssignExpr * expr );
+		};
 	} // namespace
 
@@ -244,4 +252,7 @@
 
 		UnqCount unqCount;
+
+		// must happen before ResolveCopyCtors because temporaries have to be inserted into the correct scope
+		SplitExpressions::split( translationUnit );
 
 		InsertImplicitCalls::insert( translationUnit );
@@ -312,4 +323,9 @@
 
 			return dtorFunc;
+		}
+
+		void SplitExpressions::split( std::list< Declaration * > & translationUnit ) {
+			PassVisitor<SplitExpressions> splitter;
+			mutateAll( translationUnit, splitter );
 		}
 
@@ -364,67 +380,77 @@
 		}
 
-		namespace {
-			// Relatively simple structural comparison for expressions, needed to determine
-			// if two expressions are "the same" (used to determine if self assignment occurs)
-			struct StructuralChecker {
-				Expression * stripCasts( Expression * expr ) {
-					// this might be too permissive. It's possible that only particular casts are relevant.
-					while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
-						expr = cast->arg;
-					}
-					return expr;
-				}
-
-				void previsit( Expression * ) {
-					// anything else does not qualify
-					isSimilar = false;
-				}
-
-				template<typename T>
-				T * cast( Expression * node ) {
-					// all expressions need to ignore casts, so this bit has been factored out
-					return dynamic_cast< T * >( stripCasts( node ) );
-				}
-
-				// ignore casts
-				void previsit( CastExpr * ) {}
-
-				void previsit( MemberExpr * memExpr ) {
-					if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
-						if ( otherMember->member == memExpr->member ) {
-							other = otherMember->aggregate;
-							return;
-						}
-					}
-					isSimilar = false;
-				}
-
-				void previsit( VariableExpr * varExpr ) {
-					if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
-						if ( otherVar->var == varExpr->var ) {
-							return;
-						}
-					}
-					isSimilar = false;
-				}
-
-				void previsit( AddressExpr * ) {
-					if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
-						other = addrExpr->arg;
+		Statement * SplitExpressions::postmutate( ExprStmt * stmt ) {
+			// wrap each top-level ExprStmt in a block so that destructors for argument and return temporaries are destroyed
+			// in the correct places
+			CompoundStmt * ret = new CompoundStmt( { stmt } );
+			return ret;
+		}
+
+		void SplitExpressions::premutate( TupleAssignExpr * ) {
+			// don't do this within TupleAssignExpr, since it is already broken up into multiple expressions
+			visit_children = false;
+		}
+
+		// Relatively simple structural comparison for expressions, needed to determine
+		// if two expressions are "the same" (used to determine if self assignment occurs)
+		struct StructuralChecker {
+			Expression * stripCasts( Expression * expr ) {
+				// this might be too permissive. It's possible that only particular casts are relevant.
+				while ( CastExpr * cast = dynamic_cast< CastExpr * >( expr ) ) {
+					expr = cast->arg;
+				}
+				return expr;
+			}
+
+			void previsit( Expression * ) {
+				// anything else does not qualify
+				isSimilar = false;
+			}
+
+			template<typename T>
+			T * cast( Expression * node ) {
+				// all expressions need to ignore casts, so this bit has been factored out
+				return dynamic_cast< T * >( stripCasts( node ) );
+			}
+
+			// ignore casts
+			void previsit( CastExpr * ) {}
+
+			void previsit( MemberExpr * memExpr ) {
+				if ( MemberExpr * otherMember = cast< MemberExpr >( other ) ) {
+					if ( otherMember->member == memExpr->member ) {
+						other = otherMember->aggregate;
 						return;
 					}
-					isSimilar = false;
-				}
-
-				Expression * other = nullptr;
-				bool isSimilar = true;
-			};
-
-			bool structurallySimilar( Expression * e1, Expression * e2 ) {
-				PassVisitor<StructuralChecker> checker;
-				checker.pass.other = e2;
-				e1->accept( checker );
-				return checker.pass.isSimilar;
-			}
+				}
+				isSimilar = false;
+			}
+
+			void previsit( VariableExpr * varExpr ) {
+				if ( VariableExpr * otherVar = cast< VariableExpr >( other ) ) {
+					if ( otherVar->var == varExpr->var ) {
+						return;
+					}
+				}
+				isSimilar = false;
+			}
+
+			void previsit( AddressExpr * ) {
+				if ( AddressExpr * addrExpr = cast< AddressExpr >( other ) ) {
+					other = addrExpr->arg;
+					return;
+				}
+				isSimilar = false;
+			}
+
+			Expression * other = nullptr;
+			bool isSimilar = true;
+		};
+
+		bool structurallySimilar( Expression * e1, Expression * e2 ) {
+			PassVisitor<StructuralChecker> checker;
+			checker.pass.other = e2;
+			e1->accept( checker );
+			return checker.pass.isSimilar;
 		}
 
@@ -535,4 +561,5 @@
 					// so that the object isn't changed inside of the polymorphic function
 					if ( ! GenPoly::needsBoxing( formal, result, impCpCtorExpr->callExpr, env ) ) return;
+					// xxx - leaking tmp
 				}
 			}
