Index: src/SymTab/Indexer.cc
===================================================================
--- src/SymTab/Indexer.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SymTab/Indexer.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -40,4 +40,10 @@
 
 namespace SymTab {
+	struct NewScope {
+		NewScope( SymTab::Indexer & indexer ) : indexer( indexer ) { indexer.enterScope(); }
+		~NewScope() { indexer.leaveScope(); }
+		SymTab::Indexer & indexer;
+	};
+
 	template< typename TreeType, typename VisitorType >
 	inline void acceptNewScope( TreeType *tree, VisitorType &visitor ) {
@@ -454,8 +460,5 @@
 	void Indexer::visit( TupleAssignExpr *tupleExpr ) {
 		acceptNewScope( tupleExpr->get_result(), *this );
-		enterScope();
-		acceptAll( tupleExpr->get_tempDecls(), *this );
-		acceptAll( tupleExpr->get_assigns(), *this );
-		leaveScope();
+		maybeAccept( tupleExpr->get_stmtExpr(), *this );
 	}
 
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SynTree/Expression.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -524,4 +524,5 @@
 
 ImplicitCopyCtorExpr::~ImplicitCopyCtorExpr() {
+	set_env( nullptr ); // ImplicitCopyCtorExpr does not take ownership of an environment
 	delete callExpr;
 	deleteAll( tempDecls );
@@ -533,4 +534,5 @@
 	os <<  "Implicit Copy Constructor Expression: " << std::endl;
 	assert( callExpr );
+	os << std::string( indent+2, ' ' );
 	callExpr->print( os, indent + 2 );
 	os << std::endl << std::string( indent, ' ' ) << "with temporaries:" << std::endl;
@@ -584,4 +586,5 @@
 	os << std::string( indent+2, ' ' );
 	initializer->print( os, indent + 2 );
+	Expression::print( os, indent );
 }
 
@@ -603,4 +606,5 @@
 	os << " ... ";
 	high->print( os, indent );
+	Expression::print( os, indent );
 }
 
@@ -614,11 +618,25 @@
 	}
 }
-StmtExpr::StmtExpr( const StmtExpr &other ) : Expression( other ), statements( other.statements->clone() ) {}
+StmtExpr::StmtExpr( const StmtExpr &other ) : Expression( other ), statements( other.statements->clone() ) {
+	cloneAll( other.returnDecls, returnDecls );
+	cloneAll( other.dtors, dtors );
+}
 StmtExpr::~StmtExpr() {
 	delete statements;
+	deleteAll( dtors );
+	deleteAll( returnDecls );
 }
 void StmtExpr::print( std::ostream &os, int indent ) const {
 	os << "Statement Expression: " << std::endl << std::string( indent, ' ' );
 	statements->print( os, indent+2 );
+	if ( ! returnDecls.empty() ) {
+		os << std::string( indent+2, ' ' ) << "with returnDecls: ";
+		printAll( returnDecls, os, indent+2 );
+	}
+	if ( ! dtors.empty() ) {
+		os << std::string( indent+2, ' ' ) << "with dtors: ";
+		printAll( dtors, os, indent+2 );
+	}
+	Expression::print( os, indent );
 }
 
@@ -644,7 +662,8 @@
 	get_expr()->print( os, indent+2 );
 	if ( get_object() ) {
-		os << " with decl: ";
+		os << std::string( indent+2, ' ' ) << "with decl: ";
 		get_object()->printShort( os, indent+2 );
 	}
+	Expression::print( os, indent );
 }
 
Index: src/SynTree/Expression.h
===================================================================
--- src/SynTree/Expression.h	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SynTree/Expression.h	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -543,11 +543,6 @@
 
 	std::list< ObjectDecl * > & get_tempDecls() { return tempDecls; }
-	void set_tempDecls( std::list< ObjectDecl * > newValue ) { tempDecls = newValue; }
-
 	std::list< ObjectDecl * > & get_returnDecls() { return returnDecls; }
-	void set_returnDecls( std::list< ObjectDecl * > newValue ) { returnDecls = newValue; }
-
 	std::list< Expression * > & get_dtors() { return dtors; }
-	void set_dtors( std::list< Expression * > newValue ) { dtors = newValue; }
 
 	virtual ImplicitCopyCtorExpr *clone() const { return new ImplicitCopyCtorExpr( *this ); }
@@ -706,6 +701,6 @@
 	virtual ~TupleAssignExpr();
 
-	std::list< Expression * > & get_assigns() { return assigns; }
-	std::list< ObjectDecl * > & get_tempDecls() { return tempDecls; }
+	TupleAssignExpr * set_stmtExpr( StmtExpr * newValue ) { stmtExpr = newValue; return this; }
+	StmtExpr * get_stmtExpr() const { return stmtExpr; }
 
 	virtual TupleAssignExpr *clone() const { return new TupleAssignExpr( *this ); }
@@ -714,6 +709,5 @@
 	virtual void print( std::ostream &os, int indent = 0 ) const;
   private:
-	std::list< Expression * > assigns; // assignment expressions that use tempDecls
-	std::list< ObjectDecl * > tempDecls; // temporaries for address of lhs exprs
+	StmtExpr * stmtExpr = nullptr;
 };
 
@@ -728,4 +722,7 @@
 	StmtExpr * set_statements( CompoundStmt * newValue ) { statements = newValue; return this; }
 
+	std::list< ObjectDecl * > & get_returnDecls() { return returnDecls; }
+	std::list< Expression * > & get_dtors() { return dtors; }
+
 	virtual StmtExpr *clone() const { return new StmtExpr( *this ); }
 	virtual void accept( Visitor &v ) { v.visit( this ); }
@@ -734,4 +731,6 @@
 private:
 	CompoundStmt * statements;
+	std::list< ObjectDecl * > returnDecls; // return variable(s) for stmt expression
+	std::list< Expression * > dtors; // destructor(s) for return variable(s)
 };
 
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SynTree/Mutator.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -325,4 +325,5 @@
 	mutateAll( impCpCtorExpr->get_tempDecls(), *this );
 	mutateAll( impCpCtorExpr->get_returnDecls(), *this );
+	mutateAll( impCpCtorExpr->get_dtors(), *this );
 	return impCpCtorExpr;
 }
@@ -373,6 +374,5 @@
 Expression *Mutator::mutate( TupleAssignExpr *assignExpr ) {
 	assignExpr->set_result( maybeMutate( assignExpr->get_result(), *this ) );
-	mutateAll( assignExpr->get_tempDecls(), *this );
-	mutateAll( assignExpr->get_assigns(), *this );
+	assignExpr->set_stmtExpr( maybeMutate( assignExpr->get_stmtExpr(), *this ) );
 	return assignExpr;
 }
@@ -381,4 +381,6 @@
 	stmtExpr->set_result( maybeMutate( stmtExpr->get_result(), *this ) );
 	stmtExpr->set_statements( maybeMutate( stmtExpr->get_statements(), *this ) );
+	mutateAll( stmtExpr->get_returnDecls(), *this );
+	mutateAll( stmtExpr->get_dtors(), *this );
 	return stmtExpr;
 }
@@ -503,4 +505,5 @@
 Initializer *Mutator::mutate( ConstructorInit *ctorInit ) {
 	ctorInit->set_ctor( maybeMutate( ctorInit->get_ctor(), *this ) );
+	ctorInit->set_dtor( maybeMutate( ctorInit->get_dtor(), *this ) );
 	ctorInit->set_init( maybeMutate( ctorInit->get_init(), *this ) );
 	return ctorInit;
Index: src/SynTree/TupleExpr.cc
===================================================================
--- src/SynTree/TupleExpr.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SynTree/TupleExpr.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -87,41 +87,31 @@
 }
 
-
-TupleAssignExpr::TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname ) : Expression( _aname ), assigns( assigns ), tempDecls( tempDecls ) {
+TupleAssignExpr::TupleAssignExpr( const std::list< Expression * > & assigns, const std::list< ObjectDecl * > & tempDecls, Expression * _aname ) : Expression( _aname ) {
+	// convert internally into a StmtExpr which contains the declarations and produces the tuple of the assignments
 	set_result( Tuples::makeTupleType( assigns ) );
+	CompoundStmt * compoundStmt = new CompoundStmt( noLabels );
+	std::list< Statement * > & stmts = compoundStmt->get_kids();
+	for ( ObjectDecl * obj : tempDecls ) {
+		stmts.push_back( new DeclStmt( noLabels, obj ) );
+	}
+	TupleExpr * tupleExpr = new TupleExpr( assigns );
+	assert( tupleExpr->get_result() );
+	stmts.push_back( new ExprStmt( noLabels, tupleExpr ) );
+	stmtExpr = new StmtExpr( compoundStmt );
 }
 
 TupleAssignExpr::TupleAssignExpr( const TupleAssignExpr &other ) : Expression( other ) {
-	cloneAll( other.assigns, assigns );
-	cloneAll( other.tempDecls, tempDecls );
-
-	// clone needs to go into assigns and replace tempDecls
-	VarExprReplacer::DeclMap declMap;
-	std::list< ObjectDecl * >::const_iterator origit = other.tempDecls.begin();
-	for ( ObjectDecl * temp : tempDecls ) {
-		assert( origit != other.tempDecls.end() );
-		ObjectDecl * origTemp = *origit++;
-		assert( origTemp );
-		assert( temp->get_name() == origTemp->get_name() );
-		declMap[ origTemp ] = temp;
-	}
-	if ( ! declMap.empty() ) {
-		VarExprReplacer replacer( declMap );
-		for ( Expression * assn : assigns ) {
-			assn->accept( replacer );
-		}
-	}
+	assert( other.stmtExpr );
+	stmtExpr = other.stmtExpr->clone();
 }
 
 TupleAssignExpr::~TupleAssignExpr() {
-	deleteAll( assigns );
-	// deleteAll( tempDecls );
+	delete stmtExpr;
 }
 
 void TupleAssignExpr::print( std::ostream &os, int indent ) const {
-	os << "Tuple Assignment Expression, with temporaries:" << std::endl;
-	printAll( tempDecls, os, indent+4 );
-	os << std::string( indent+2, ' ' ) << "with assignments: " << std::endl;
-	printAll( assigns, os, indent+4 );
+	os << "Tuple Assignment Expression, with stmt expr:" << std::endl;
+	os << std::string( indent+2, ' ' );
+	stmtExpr->print( os, indent+4 );
 	Expression::print( os, indent );
 }
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/SynTree/Visitor.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -276,4 +276,5 @@
 	acceptAll( impCpCtorExpr->get_tempDecls(), *this );
 	acceptAll( impCpCtorExpr->get_returnDecls(), *this );
+	acceptAll( impCpCtorExpr->get_dtors(), *this );
 }
 
@@ -317,6 +318,5 @@
 void Visitor::visit( TupleAssignExpr *assignExpr ) {
 	maybeAccept( assignExpr->get_result(), *this );
-	acceptAll( assignExpr->get_tempDecls(), *this );
-	acceptAll( assignExpr->get_assigns(), *this );
+	maybeAccept( assignExpr->get_stmtExpr(), *this );
 }
 
@@ -324,4 +324,6 @@
 	maybeAccept( stmtExpr->get_result(), *this );
 	maybeAccept( stmtExpr->get_statements(), *this );
+	acceptAll( stmtExpr->get_returnDecls(), *this );
+	acceptAll( stmtExpr->get_dtors(), *this );
 }
 
@@ -425,4 +427,5 @@
 void Visitor::visit( ConstructorInit *ctorInit ) {
 	maybeAccept( ctorInit->get_ctor(), *this );
+	maybeAccept( ctorInit->get_dtor(), *this );
 	maybeAccept( ctorInit->get_init(), *this );
 }
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 1d2b64f538b2e524e418c78785233364f63db708)
+++ src/Tuples/TupleExpansion.cc	(revision d5556a3ceec1d963a2e9c0fccbfe2ff51b6eb263)
@@ -194,4 +194,5 @@
 				new CommaExpr( new CommaExpr( assignUnq, assignFinished ), var->clone() ) );
 			condExpr->set_result( var->get_result()->clone() );
+			condExpr->set_env( maybeClone( unqExpr->get_env() ) );
 			decls[id] = condExpr;
 		}
@@ -202,16 +203,11 @@
 	Expression * TupleAssignExpander::mutate( TupleAssignExpr * assnExpr ) {
 		assnExpr = safe_dynamic_cast< TupleAssignExpr * >( Parent::mutate( assnExpr ) );
-		CompoundStmt * compoundStmt = new CompoundStmt( noLabels );
-		std::list< Statement * > & stmts = compoundStmt->get_kids();
-		for ( ObjectDecl * obj : assnExpr->get_tempDecls() ) {
-			stmts.push_back( new DeclStmt( noLabels, obj ) );
-		}
-		TupleExpr * tupleExpr = new TupleExpr( assnExpr->get_assigns() );
-		assert( tupleExpr->get_result() );
-		stmts.push_back( new ExprStmt( noLabels, tupleExpr ) );
-		assnExpr->get_tempDecls().clear();
-		assnExpr->get_assigns().clear();
+		StmtExpr * ret = assnExpr->get_stmtExpr();
+		assnExpr->set_stmtExpr( nullptr );
+		// move env to StmtExpr
+		ret->set_env( assnExpr->get_env() );
+		assnExpr->set_env( nullptr );
 		delete assnExpr;
-		return new StmtExpr( compoundStmt );
+		return ret;
 	}
 
@@ -221,4 +217,5 @@
 		if ( ! typeMap.count( mangleName ) ) {
 			// generate struct type to replace tuple type
+			// xxx - should fix this to only generate one tuple struct for each number of type parameters
 			StructDecl * decl = new StructDecl( "_tuple_type_" + mangleName );
 			decl->set_body( true );
@@ -247,4 +244,6 @@
 		tupleExpr->set_tuple( nullptr );
 		unsigned int idx = tupleExpr->get_index();
+		TypeSubstitution * env = tupleExpr->get_env();
+		tupleExpr->set_env( nullptr );
 		delete tupleExpr;
 
@@ -253,16 +252,19 @@
 		assert( structDecl->get_members().size() > idx );
 		Declaration * member = *std::next(structDecl->get_members().begin(), idx);
-		return new MemberExpr( safe_dynamic_cast< DeclarationWithType * >( member ), tuple );
-	}
-
-	Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs ) {
+		MemberExpr * memExpr = new MemberExpr( safe_dynamic_cast< DeclarationWithType * >( member ), tuple );
+		memExpr->set_env( env );
+		return memExpr;
+	}
+
+	Expression * replaceTupleExpr( Type * result, const std::list< Expression * > & exprs, TypeSubstitution * env ) {
 		if ( result->isVoid() ) {
 			// void result - don't need to produce a value for cascading - just output a chain of comma exprs
 			assert( ! exprs.empty() );
 			std::list< Expression * >::const_iterator iter = exprs.begin();
-			Expression * expr = *iter++;
+			Expression * expr = new CastExpr( *iter++ );
 			for ( ; iter != exprs.end(); ++iter ) {
-				expr = new CommaExpr( expr, *iter );
-			}
+				expr = new CommaExpr( expr, new CastExpr( *iter ) );
+			}
+			expr->set_env( env );
 			return expr;
 		} else {
@@ -274,5 +276,7 @@
 				inits.push_back( new SingleInit( expr ) );
 			}
-			return new CompoundLiteralExpr( result, new ListInit( inits ) );
+			Expression * expr = new CompoundLiteralExpr( result, new ListInit( inits ) );
+			expr->set_env( env );
+			return expr;
 		}
 	}
@@ -284,11 +288,13 @@
 		std::list< Expression * > exprs = tupleExpr->get_exprs();
 		assert( result );
+		TypeSubstitution * env = tupleExpr->get_env();
 
 		// remove data from shell and delete it
 		tupleExpr->set_result( nullptr );
 		tupleExpr->get_exprs().clear();
+		tupleExpr->set_env( nullptr );
 		delete tupleExpr;
 
-		return replaceTupleExpr( result, exprs );
+		return replaceTupleExpr( result, exprs, env );
 	}
 
