Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision f65822430a8f660dc48e724c1be1ea7c9978fa0b)
+++ src/Tuples/TupleExpansion.cc	(revision d104b0259d2af56d64a4f024802ad2afa0236505)
@@ -41,9 +41,6 @@
 		};
 
-		struct UniqueExprExpander final : public GenPoly::DeclMutator {
-			typedef GenPoly::DeclMutator Parent;
-			using Parent::mutate;
-
-			virtual Expression * mutate( UniqueExpr * unqExpr ) override;
+		struct UniqueExprExpander final : public WithDeclsToAdd {
+			Expression * postmutate( UniqueExpr * unqExpr );
 
 			std::map< int, Expression * > decls; // not vector, because order added may not be increasing order
@@ -56,9 +53,6 @@
 		};
 
-		struct TupleAssignExpander : public Mutator {
-			typedef Mutator Parent;
-			using Parent::mutate;
-
-			virtual Expression * mutate( TupleAssignExpr * tupleExpr );
+		struct TupleAssignExpander {
+			Expression * postmutate( TupleAssignExpr * tupleExpr );
 		};
 
@@ -77,9 +71,6 @@
 		};
 
-		struct TupleExprExpander final : public Mutator {
-			typedef Mutator Parent;
-			using Parent::mutate;
-
-			virtual Expression * mutate( TupleExpr * tupleExpr ) override;
+		struct TupleExprExpander final {
+			Expression * postmutate( TupleExpr * tupleExpr );
 		};
 	}
@@ -91,10 +82,10 @@
 
 	void expandUniqueExpr( std::list< Declaration * > & translationUnit ) {
-		UniqueExprExpander unqExpander;
-		unqExpander.mutateDeclarationList( translationUnit );
+		PassVisitor<UniqueExprExpander> unqExpander;
+		mutateAll( translationUnit, unqExpander );
 	}
 
 	void expandTuples( std::list< Declaration * > & translationUnit ) {
-		TupleAssignExpander assnExpander;
+		PassVisitor<TupleAssignExpander> assnExpander;
 		mutateAll( translationUnit, assnExpander );
 
@@ -105,5 +96,5 @@
 		mutateAll( translationUnit, idxExpander );
 
-		TupleExprExpander exprExpander;
+		PassVisitor<TupleExprExpander> exprExpander;
 		mutateAll( translationUnit, exprExpander );
 	}
@@ -138,5 +129,5 @@
 			// aggregate expressions which might be impure must be wrapped in unique expressions
 			// xxx - if there's a member-tuple expression nested in the aggregate, this currently generates the wrong code if a UniqueExpr is not used, and it's purely an optimization to remove the UniqueExpr
-			// if ( Tuples::maybeImpure( memberExpr->get_aggregate() ) ) aggr = new UniqueExpr( aggr );
+			// if ( Tuples::maybeImpureIgnoreUnique( memberExpr->get_aggregate() ) ) aggr = new UniqueExpr( aggr );
 			aggr = new UniqueExpr( aggr );
 			for ( Expression *& expr : tupleExpr->get_exprs() ) {
@@ -156,6 +147,5 @@
 	}
 
-	Expression * UniqueExprExpander::mutate( UniqueExpr * unqExpr ) {
-		unqExpr = safe_dynamic_cast< UniqueExpr * > ( Parent::mutate( unqExpr ) );
+	Expression * UniqueExprExpander::postmutate( UniqueExpr * unqExpr ) {
 		const int id = unqExpr->get_id();
 
@@ -167,5 +157,5 @@
 			if ( unqExpr->get_object() ) {
 				// an object was generated to represent this unique expression -- it should be added to the list of declarations now
-				addDeclaration( unqExpr->get_object() );
+				declsToAddBefore.push_back( unqExpr->get_object() );
 				unqExpr->set_object( nullptr );
 				// steal the expr from the unqExpr
@@ -181,5 +171,5 @@
 			ObjectDecl * finished = new ObjectDecl( toString( "_unq", id, "_finished_" ), Type::StorageClasses(), LinkageSpec::Cforall, nullptr, new BasicType( Type::Qualifiers(), BasicType::Bool ),
 													new SingleInit( new ConstantExpr( Constant::from_int( 0 ) ) ) );
-			addDeclaration( finished );
+			declsToAddBefore.push_back( finished );
 			// (finished ? _unq_expr_N : (_unq_expr_N = <unqExpr->get_expr()>, finished = 1, _unq_expr_N))
 			// This pattern ensures that each unique expression is evaluated once, regardless of evaluation order of the generated C code.
@@ -195,6 +185,5 @@
 	}
 
-	Expression * TupleAssignExpander::mutate( TupleAssignExpr * assnExpr ) {
-		assnExpr = safe_dynamic_cast< TupleAssignExpr * >( Parent::mutate( assnExpr ) );
+	Expression * TupleAssignExpander::postmutate( TupleAssignExpr * assnExpr ) {
 		StmtExpr * ret = assnExpr->get_stmtExpr();
 		assnExpr->set_stmtExpr( nullptr );
@@ -279,7 +268,5 @@
 	}
 
-	Expression * TupleExprExpander::mutate( TupleExpr * tupleExpr ) {
-		// recursively expand sub-tuple-expressions
-		tupleExpr = safe_dynamic_cast<TupleExpr *>(Parent::mutate(tupleExpr));
+	Expression * TupleExprExpander::postmutate( TupleExpr * tupleExpr ) {
 		Type * result = tupleExpr->get_result();
 		std::list< Expression * > exprs = tupleExpr->get_exprs();
@@ -328,4 +315,6 @@
 		class ImpurityDetector : public Visitor {
 		public:
+			ImpurityDetector( bool ignoreUnique ) : ignoreUnique( ignoreUnique ) {}
+
 			typedef Visitor Parent;
 			virtual void visit( ApplicationExpr * appExpr ) {
@@ -341,11 +330,28 @@
 				maybeImpure = true;
 			}
-			virtual void visit( __attribute__((unused)) UntypedExpr * untypedExpr ) { maybeImpure = true; }
+			virtual void visit( UntypedExpr * ) { maybeImpure = true; }
+			virtual void visit( UniqueExpr * unq ) {
+				if ( ignoreUnique ) {
+					// bottom out at unique expression.
+					// The existence of a unique expression doesn't change the purity of an expression.
+					// That is, even if the wrapped expression is impure, the wrapper protects the rest of the expression.
+					return;
+				}
+				maybeAccept( unq->expr, *this );
+			}
+
 			bool maybeImpure = false;
+			bool ignoreUnique;
 		};
 	} // namespace
 
 	bool maybeImpure( Expression * expr ) {
-		ImpurityDetector detector;
+		ImpurityDetector detector( false );
+		expr->accept( detector );
+		return detector.maybeImpure;
+	}
+
+	bool maybeImpureIgnoreUnique( Expression * expr ) {
+		ImpurityDetector detector( true );
 		expr->accept( detector );
 		return detector.maybeImpure;
Index: src/Tuples/Tuples.h
===================================================================
--- src/Tuples/Tuples.h	(revision f65822430a8f660dc48e724c1be1ea7c9978fa0b)
+++ src/Tuples/Tuples.h	(revision d104b0259d2af56d64a4f024802ad2afa0236505)
@@ -46,4 +46,7 @@
 	/// returns true if the expression may contain side-effects.
 	bool maybeImpure( Expression * expr );
+
+	/// returns true if the expression may contain side-effect, ignoring the presence of unique expressions.
+	bool maybeImpureIgnoreUnique( Expression * expr );
 } // namespace Tuples
 
