Index: src/Common/PassVisitor.impl.h
===================================================================
--- src/Common/PassVisitor.impl.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/Common/PassVisitor.impl.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -2277,40 +2277,149 @@
 }
 
-
+//--------------------------------------------------------------------------
+// TupleType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( TupleType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->forall, *this );
+	maybeAccept_impl( node->types, *this );
+	maybeAccept_impl( node->members, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( TupleType * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->forall, *this );
+	maybeMutate_impl( node->types, *this );
+	maybeMutate_impl( node->members, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeofType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( TypeofType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	assert( node->expr );
+	maybeAccept_impl( node->expr, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( TypeofType * node ) {
+	MUTATE_START( node );
+
+	assert( node->expr );
+	maybeMutate_impl( node->expr, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// AttrType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( AttrType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	if ( node->isType ) {
+		assert( node->type );
+		maybeAccept_impl( node->type, *this );
+	} else {
+		assert( node->expr );
+		maybeAccept_impl( node->expr, *this );
+	} // if
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( AttrType * node ) {
+	MUTATE_START( node );
+
+	if ( node->isType ) {
+		assert( node->type );
+		maybeMutate_impl( node->type, *this );
+	} else {
+		assert( node->expr );
+		maybeMutate_impl( node->expr, *this );
+	} // if
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// VarArgsType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( VarArgsType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->forall, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( VarArgsType * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->forall, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// ZeroType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( ZeroType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->forall, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( ZeroType * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->forall, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// OneType
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( OneType * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->forall, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Type * PassVisitor< pass_type >::mutate( OneType * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->forall, *this );
+
+	MUTATE_END( Type, node );
+}
+
+//--------------------------------------------------------------------------
+// Designation
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( Designation * node ) {
 	VISIT_START( node );
 
-	maybeAccept_impl( node->get_designators(), *this );
+	maybeAccept_impl( node->designators, *this );
 
 	VISIT_END( node );
@@ -2321,5 +2430,5 @@
 	MUTATE_START( node );
 
-	maybeMutate_impl( node->get_designators(), *this );
+	maybeMutate_impl( node->designators, *this );
 
 	MUTATE_END( Designation, node );
@@ -2332,5 +2441,5 @@
 	VISIT_START( node );
 
-	visitExpression( node->get_value() );
+	visitExpression( node->value );
 
 	VISIT_END( node );
@@ -2341,91 +2450,109 @@
 	MUTATE_START( node );
 
-	node->set_value( mutateExpression( node->get_value() ) );
+	node->value = mutateExpression( node->value );
 
 	MUTATE_END( Initializer, node );
 }
 
+//--------------------------------------------------------------------------
+// ListInit
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( ListInit * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->designations, *this );
+	maybeAccept_impl( node->initializers, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Initializer * PassVisitor< pass_type >::mutate( ListInit * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->designations, *this );
+	maybeMutate_impl( node->initializers, *this );
+
+	MUTATE_END( Initializer, node );
+}
+
+//--------------------------------------------------------------------------
+// ConstructorInit
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( ConstructorInit * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	maybeAccept_impl( node->ctor, *this );
+	maybeAccept_impl( node->dtor, *this );
+	maybeAccept_impl( node->init, *this );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Initializer * PassVisitor< pass_type >::mutate( ConstructorInit * node ) {
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->ctor, *this );
+	maybeMutate_impl( node->dtor, *this );
+	maybeMutate_impl( node->init, *this );
+
+	MUTATE_END( Initializer, node );
+}
+
+//--------------------------------------------------------------------------
+// Subrange
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( Subrange * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Subrange * PassVisitor< pass_type >::mutate( Subrange * node  )  {
+	MUTATE_START( node );
+
+	MUTATE_END( Subrange, node );
+}
+
+//--------------------------------------------------------------------------
+// Attribute
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( Constant * node ) {
-	VISIT_BODY( node );
-}
-
+	VISIT_START( node );
+
+	VISIT_END( node );
+}
+
+template< typename pass_type >
+Constant * PassVisitor< pass_type >::mutate( Constant * node  )  {
+	MUTATE_START( node );
+
+	MUTATE_END( Constant, node );
+}
+
+//--------------------------------------------------------------------------
+// Attribute
 template< typename pass_type >
 void PassVisitor< pass_type >::visit( Attribute * node ) {
-	VISIT_BODY( node );
-}
-
-//---------------------------------------------------------------------------------------------------------------
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( TupleType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( TypeofType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( AttrType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( VarArgsType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( ZeroType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Type * PassVisitor< pass_type >::mutate( OneType * node ) {
-	MUTATE_BODY( Type, node );
-}
-
-template< typename pass_type >
-Initializer * PassVisitor< pass_type >::mutate( ListInit * node ) {
-	MUTATE_BODY( Initializer, node );
-}
-
-template< typename pass_type >
-Initializer * PassVisitor< pass_type >::mutate( ConstructorInit * node ) {
-	MUTATE_BODY( Initializer, node );
-}
-
-template< typename pass_type >
-Subrange * PassVisitor< pass_type >::mutate( Subrange * node  )  {
-	MUTATE_BODY( Subrange, node );
-}
-
-template< typename pass_type >
-Constant * PassVisitor< pass_type >::mutate( Constant * node  )  {
-	MUTATE_BODY( Constant, node );
+	VISIT_START( node );
+
+	maybeAccept_impl( node->parameters, *this );
+
+	VISIT_END( node );
 }
 
 template< typename pass_type >
 Attribute * PassVisitor< pass_type >::mutate( Attribute * node  )  {
-	MUTATE_BODY( Attribute, node );
-}
-
+	MUTATE_START( node );
+
+	maybeMutate_impl( node->parameters, *this );
+
+	MUTATE_END( Attribute, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeSubstitution
 template< typename pass_type >
 TypeSubstitution * PassVisitor< pass_type >::mutate( TypeSubstitution * node ) {
Index: src/Common/SemanticError.cc
===================================================================
--- src/Common/SemanticError.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/Common/SemanticError.cc	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -14,4 +14,5 @@
 //
 
+#include <cstdarg>
 #include <cstdio>										// for fileno, stderr
 #include <unistd.h>										// for isatty
@@ -50,5 +51,26 @@
 }
 
-void SemanticWarningImpl( CodeLocation location, std::string msg ) {
+namespace {
+	// convert format string and arguments into a single string
+	std::string fmtToString(const char * fmt, va_list ap) {
+		int size = 128;
+		while ( true ) {
+			char buf[size];
+			va_list args;
+			va_copy( args, ap );
+			int n = vsnprintf(&buf[0], size, fmt, args);
+			va_end( args );
+			if ( n < size && n >= 0 ) return buf;
+			size *= 2;
+		}
+		assert( false );
+	}
+}
+
+void SemanticWarningImpl( CodeLocation location, Warning, const char * const fmt, ... ) {
+	va_list args;
+	va_start(args, fmt);
+	std::string msg = fmtToString( fmt, args );
+	va_end(args);
 	std::cerr << ErrorHelpers::bold() << location << ErrorHelpers::warning_str() << ErrorHelpers::reset_font() << msg << std::endl;
 }
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/Common/SemanticError.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -37,8 +37,9 @@
 
 constexpr const char * const WarningFormats[] = {
-
+	"self assignment of expression: %s",
 };
 
 enum class Warning {
+	SelfAssignment,
 	NUMBER_OF_WARNINGS, //This MUST be the last warning
 };
@@ -49,5 +50,5 @@
 );
 
-#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[id], __VA_ARGS__)
+#define SemanticWarning(loc, id, ...) SemanticWarningImpl(loc, id, WarningFormats[(int)id], __VA_ARGS__)
 
 void SemanticWarningImpl (CodeLocation loc, Warning warn, const char * const fmt, ...) __attribute__((format(printf, 3, 4)));
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/Common/utility.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -162,4 +162,6 @@
 }
 
+#define toCString( ... ) toString( __VA_ARGS__ ).c_str()
+
 // replace element of list with all elements of another list
 template< typename T >
Index: src/GenPoly/Specialize.cc
===================================================================
--- src/GenPoly/Specialize.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/GenPoly/Specialize.cc	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -200,26 +200,4 @@
 	}
 
-	struct EnvTrimmer {
-		TypeSubstitution * env, * newEnv;
-		EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
-		void previsit( TypeDecl * tyDecl ) {
-			// transfer known bindings for seen type variables
-			if ( Type * t = env->lookup( tyDecl->name ) ) {
-				newEnv->add( tyDecl->name, t );
-			}
-		}
-	};
-
-	/// reduce environment to just the parts that are referenced in a given expression
-	TypeSubstitution * trimEnv( ApplicationExpr * expr, TypeSubstitution * env ) {
-		if ( env ) {
-			TypeSubstitution * newEnv = new TypeSubstitution();
-			PassVisitor<EnvTrimmer> trimmer( env, newEnv );
-			expr->accept( trimmer );
-			return newEnv;
-		}
-		return nullptr;
-	}
-
 	/// Generates a thunk that calls `actual` with type `funType` and returns its address
 	Expression * Specialize::createThunkFunction( FunctionType *funType, Expression *actual, InferredParams *inferParams ) {
@@ -265,5 +243,5 @@
 		}
 
-		appExpr->set_env( trimEnv( appExpr, env ) );
+		appExpr->env = TypeSubstitution::newFromExpr( appExpr, env );
 		if ( inferParams ) {
 			appExpr->get_inferParams() = *inferParams;
Index: src/InitTweak/FixInit.cc
===================================================================
--- src/InitTweak/FixInit.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/InitTweak/FixInit.cc	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -68,4 +68,8 @@
 		typedef std::unordered_map< int, int > UnqCount;
 
+		struct SelfAssignChecker {
+			void previsit( ApplicationExpr * appExpr );
+		};
+
 		struct InsertImplicitCalls : public WithTypeSubstitution {
 			/// wrap function application expressions as ImplicitCopyCtorExpr nodes so that it is easy to identify which
@@ -235,4 +239,7 @@
 
 	void fix( std::list< Declaration * > & translationUnit, const std::string & filename, bool inLibrary ) {
+		PassVisitor<SelfAssignChecker> checker;
+		acceptAll( translationUnit, checker );
+
 		// fixes ConstructorInit for global variables. should happen before fixInitializers.
 		InitTweak::fixGlobalInit( translationUnit, filename, inLibrary );
@@ -309,4 +316,81 @@
 			PassVisitor<FixCtorExprs> fixer;
 			mutateAll( translationUnit, fixer );
+		}
+
+		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;
+						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;
+			}
+		}
+
+		void SelfAssignChecker::previsit( ApplicationExpr * appExpr ) {
+			DeclarationWithType * function = getFunction( appExpr );
+			if ( isAssignment( function ) ) {
+				if ( appExpr->args.size() == 2 ) {
+					// check for structural similarity (same variable use, ignore casts, etc. - but does not look too deeply, anything looking like a function is off limits)
+					if ( structurallySimilar( appExpr->args.front(), appExpr->args.back() ) ) {
+						SemanticWarning( appExpr->location, Warning::SelfAssignment, toCString( appExpr->args.front() ) );
+					}
+				}
+			}
 		}
 
@@ -550,4 +634,7 @@
 			// add destructors after current statement
 			for ( Expression * dtor : dtors ) {
+				// take relevant bindings from environment
+				assert( ! dtor->env );
+				dtor->env =  TypeSubstitution::newFromExpr( dtor, impCpCtorExpr->env );
 				stmtsToAddAfter.push_back( new ExprStmt( dtor ) );
 			} // for
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/Makefile.in	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -247,6 +247,4 @@
 	SynTree/driver_cfa_cpp-TypeDecl.$(OBJEXT) \
 	SynTree/driver_cfa_cpp-Initializer.$(OBJEXT) \
-	SynTree/driver_cfa_cpp-Visitor.$(OBJEXT) \
-	SynTree/driver_cfa_cpp-Mutator.$(OBJEXT) \
 	SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT) \
 	SynTree/driver_cfa_cpp-Attribute.$(OBJEXT) \
@@ -527,9 +525,8 @@
 	SynTree/FunctionDecl.cc SynTree/AggregateDecl.cc \
 	SynTree/NamedTypeDecl.cc SynTree/TypeDecl.cc \
-	SynTree/Initializer.cc SynTree/Visitor.cc SynTree/Mutator.cc \
-	SynTree/TypeSubstitution.cc SynTree/Attribute.cc \
-	SynTree/VarExprReplacer.cc Tuples/TupleAssignment.cc \
-	Tuples/TupleExpansion.cc Tuples/Explode.cc \
-	Virtual/ExpandCasts.cc
+	SynTree/Initializer.cc SynTree/TypeSubstitution.cc \
+	SynTree/Attribute.cc SynTree/VarExprReplacer.cc \
+	Tuples/TupleAssignment.cc Tuples/TupleExpansion.cc \
+	Tuples/Explode.cc Virtual/ExpandCasts.cc
 MAINTAINERCLEANFILES = Parser/parser.output ${libdir}/${notdir \
 	${cfa_cpplib_PROGRAMS}}
@@ -911,8 +908,4 @@
 SynTree/driver_cfa_cpp-Initializer.$(OBJEXT): SynTree/$(am__dirstamp) \
 	SynTree/$(DEPDIR)/$(am__dirstamp)
-SynTree/driver_cfa_cpp-Visitor.$(OBJEXT): SynTree/$(am__dirstamp) \
-	SynTree/$(DEPDIR)/$(am__dirstamp)
-SynTree/driver_cfa_cpp-Mutator.$(OBJEXT): SynTree/$(am__dirstamp) \
-	SynTree/$(DEPDIR)/$(am__dirstamp)
 SynTree/driver_cfa_cpp-TypeSubstitution.$(OBJEXT):  \
 	SynTree/$(am__dirstamp) SynTree/$(DEPDIR)/$(am__dirstamp)
@@ -1053,5 +1046,4 @@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-FunctionType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Initializer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-NamedTypeDecl.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-ObjectDecl.Po@am__quote@
@@ -1069,5 +1061,4 @@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarArgsType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VarExprReplacer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-VoidType.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@SynTree/$(DEPDIR)/driver_cfa_cpp-ZeroOneType.Po@am__quote@
@@ -2478,32 +2469,4 @@
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Initializer.obj `if test -f 'SynTree/Initializer.cc'; then $(CYGPATH_W) 'SynTree/Initializer.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Initializer.cc'; fi`
-
-SynTree/driver_cfa_cpp-Visitor.o: SynTree/Visitor.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Visitor.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Tpo -c -o SynTree/driver_cfa_cpp-Visitor.o `test -f 'SynTree/Visitor.cc' || echo '$(srcdir)/'`SynTree/Visitor.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/Visitor.cc' object='SynTree/driver_cfa_cpp-Visitor.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Visitor.o `test -f 'SynTree/Visitor.cc' || echo '$(srcdir)/'`SynTree/Visitor.cc
-
-SynTree/driver_cfa_cpp-Visitor.obj: SynTree/Visitor.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Visitor.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Tpo -c -o SynTree/driver_cfa_cpp-Visitor.obj `if test -f 'SynTree/Visitor.cc'; then $(CYGPATH_W) 'SynTree/Visitor.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Visitor.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Visitor.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/Visitor.cc' object='SynTree/driver_cfa_cpp-Visitor.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Visitor.obj `if test -f 'SynTree/Visitor.cc'; then $(CYGPATH_W) 'SynTree/Visitor.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Visitor.cc'; fi`
-
-SynTree/driver_cfa_cpp-Mutator.o: SynTree/Mutator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Mutator.o -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Tpo -c -o SynTree/driver_cfa_cpp-Mutator.o `test -f 'SynTree/Mutator.cc' || echo '$(srcdir)/'`SynTree/Mutator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/Mutator.cc' object='SynTree/driver_cfa_cpp-Mutator.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Mutator.o `test -f 'SynTree/Mutator.cc' || echo '$(srcdir)/'`SynTree/Mutator.cc
-
-SynTree/driver_cfa_cpp-Mutator.obj: SynTree/Mutator.cc
-@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -MT SynTree/driver_cfa_cpp-Mutator.obj -MD -MP -MF SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Tpo -c -o SynTree/driver_cfa_cpp-Mutator.obj `if test -f 'SynTree/Mutator.cc'; then $(CYGPATH_W) 'SynTree/Mutator.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Mutator.cc'; fi`
-@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Tpo SynTree/$(DEPDIR)/driver_cfa_cpp-Mutator.Po
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	$(AM_V_CXX)source='SynTree/Mutator.cc' object='SynTree/driver_cfa_cpp-Mutator.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCXX_FALSE@	$(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(driver_cfa_cpp_CXXFLAGS) $(CXXFLAGS) -c -o SynTree/driver_cfa_cpp-Mutator.obj `if test -f 'SynTree/Mutator.cc'; then $(CYGPATH_W) 'SynTree/Mutator.cc'; else $(CYGPATH_W) '$(srcdir)/SynTree/Mutator.cc'; fi`
 
 SynTree/driver_cfa_cpp-TypeSubstitution.o: SynTree/TypeSubstitution.cc
Index: src/SynTree/Mutator.cc
===================================================================
--- src/SynTree/Mutator.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ 	(revision )
@@ -1,127 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Mutator.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Aug 17 15:39:37 2017
-// Update Count     : 27
-//
-
-#include <cassert>             // for assert
-#include <list>                // for list
-
-#include "Attribute.h"         // for Attribute
-#include "Declaration.h"       // for ObjectDecl, Declaration, DeclarationWi...
-#include "Expression.h"        // for Expression, ConstantExpr, ConditionalExpr
-#include "Initializer.h"       // for ConstructorInit, Initializer, Designation
-#include "Mutator.h"
-#include "Statement.h"         // for Statement, CatchStmt, AsmStmt, ForStmt
-#include "Type.h"              // for Type, Type::ForallList, AttrType, Arra...
-#include "TypeSubstitution.h"  // for TypeSubstitution
-
-class Constant;
-class Subrange;
-
-Mutator::Mutator() {}
-
-Mutator::~Mutator() {}
-
-Type * Mutator::mutate( TupleType *tupleType ) {
-	mutateAll( tupleType->get_forall(), *this );
-	mutateAll( tupleType->get_types(), *this );
-	mutateAll( tupleType->get_members(), *this );
-	return tupleType;
-}
-
-Type * Mutator::mutate( TypeofType *typeofType ) {
-	assert( typeofType->get_expr() );
-	typeofType->set_expr( typeofType->get_expr()->acceptMutator( *this ) );
-	return typeofType;
-}
-
-Type * Mutator::mutate( AttrType *attrType ) {
-	if ( attrType->get_isType() ) {
-		assert( attrType->get_type() );
-		attrType->set_type( attrType->get_type()->acceptMutator( *this ) );
-	} else {
-		assert( attrType->get_expr() );
-		attrType->set_expr( attrType->get_expr()->acceptMutator( *this ) );
-	}
-	return attrType;
-}
-
-Type * Mutator::mutate( VarArgsType *varArgsType ) {
-	mutateAll( varArgsType->get_forall(), *this );
-	return varArgsType;
-}
-
-Type * Mutator::mutate( ZeroType *zeroType ) {
-	mutateAll( zeroType->get_forall(), *this );
-	return zeroType;
-}
-
-Type * Mutator::mutate( OneType *oneType ) {
-	mutateAll( oneType->get_forall(), *this );
-	return oneType;
-}
-
-
-Designation * Mutator::mutate( Designation * designation ) {
-	mutateAll( designation->get_designators(), *this );
-	return designation;
-}
-
-Initializer * Mutator::mutate( SingleInit *singleInit ) {
-	singleInit->set_value( singleInit->get_value()->acceptMutator( *this ) );
-	return singleInit;
-}
-
-Initializer * Mutator::mutate( ListInit *listInit ) {
-	mutateAll( listInit->get_designations(), *this );
-	mutateAll( listInit->get_initializers(), *this );
-	return listInit;
-}
-
-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;
-}
-
-
-Subrange * Mutator::mutate( Subrange *subrange ) {
-	return subrange;
-}
-
-
-Constant * Mutator::mutate( Constant *constant ) {
-	return constant;
-}
-
-Attribute * Mutator::mutate( Attribute * attribute ) {
-	mutateAll( attribute->parameters, *this );
-	return attribute;
-}
-
-TypeSubstitution * Mutator::mutate( TypeSubstitution * sub ) {
-	for ( auto & p : sub->typeEnv ) {
-		p.second = maybeMutate( p.second, *this );
-	}
-	for ( auto & p : sub->varEnv ) {
-		p.second = maybeMutate( p.second, *this );
-	}
-	return sub;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SynTree/Mutator.h
===================================================================
--- src/SynTree/Mutator.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/SynTree/Mutator.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -22,6 +22,6 @@
 class Mutator {
   protected:
-	Mutator();
-	virtual ~Mutator();
+	Mutator() = default;
+	virtual ~Mutator() = default;
   public:
 	virtual DeclarationWithType * mutate( ObjectDecl * objectDecl ) = 0;
Index: src/SynTree/TypeSubstitution.cc
===================================================================
--- src/SynTree/TypeSubstitution.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/SynTree/TypeSubstitution.cc	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -104,4 +104,28 @@
 bool TypeSubstitution::empty() const {
 	return typeEnv.empty() && varEnv.empty();
+}
+
+namespace {
+	struct EnvTrimmer {
+		TypeSubstitution * env, * newEnv;
+		EnvTrimmer( TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
+		void previsit( TypeDecl * tyDecl ) {
+			// transfer known bindings for seen type variables
+			if ( Type * t = env->lookup( tyDecl->name ) ) {
+				newEnv->add( tyDecl->name, t );
+			}
+		}
+	};
+} // namespace
+
+/// reduce environment to just the parts that are referenced in a given expression
+TypeSubstitution * TypeSubstitution::newFromExpr( Expression * expr, TypeSubstitution * env ) {
+	if ( env ) {
+		TypeSubstitution * newEnv = new TypeSubstitution();
+		PassVisitor<EnvTrimmer> trimmer( env, newEnv );
+		expr->accept( trimmer );
+		return newEnv;
+	}
+	return nullptr;
 }
 
Index: src/SynTree/TypeSubstitution.h
===================================================================
--- src/SynTree/TypeSubstitution.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/SynTree/TypeSubstitution.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -54,4 +54,7 @@
 	template< typename TypeInstListIterator >
 	void extract( TypeInstListIterator begin, TypeInstListIterator end, TypeSubstitution &result );
+
+	/// create a new TypeSubstitution using bindings from env containing all of the type variables in expr
+	static TypeSubstitution * newFromExpr( Expression * expr, TypeSubstitution * env );
 
 	void normalize();
Index: src/SynTree/Visitor.cc
===================================================================
--- src/SynTree/Visitor.cc	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ 	(revision )
@@ -1,100 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Visitor.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Aug 17 15:39:38 2017
-// Update Count     : 29
-//
-
-#include <cassert>        // for assert
-#include <list>           // for list
-
-#include "Attribute.h"    // for Attribute
-#include "Constant.h"     // for Constant
-#include "Declaration.h"  // for DeclarationWithType, ObjectDecl, Declaration
-#include "Expression.h"   // for Expression, ConstantExpr, ImplicitCopyCtorExpr
-#include "Initializer.h"  // for Initializer, Designation, ConstructorInit
-#include "Statement.h"    // for Statement, CatchStmt, AsmStmt, CompoundStmt
-#include "Type.h"         // for Type, Type::ForallList, AttrType, FunctionType
-#include "Visitor.h"
-
-class Subrange;
-
-Visitor::Visitor() {}
-
-Visitor::~Visitor() {}
-
-void Visitor::visit( TupleType *tupleType ) {
-	acceptAll( tupleType->get_forall(), *this );
-	acceptAll( tupleType->get_types(), *this );
-	acceptAll( tupleType->get_members(), *this );
-}
-
-void Visitor::visit( TypeofType *typeofType ) {
-	assert( typeofType->get_expr() );
-	typeofType->get_expr()->accept( *this );
-}
-
-void Visitor::visit( AttrType *attrType ) {
-	if ( attrType->get_isType() ) {
-		assert( attrType->get_type() );
-		attrType->get_type()->accept( *this );
-	} else {
-		assert( attrType->get_expr() );
-		attrType->get_expr()->accept( *this );
-	} // if
-}
-
-void Visitor::visit( VarArgsType *varArgsType ) {
-	acceptAll( varArgsType->get_forall(), *this );
-}
-
-void Visitor::visit( ZeroType *zeroType ) {
-	acceptAll( zeroType->get_forall(), *this );
-}
-
-void Visitor::visit( OneType *oneType ) {
-	acceptAll( oneType->get_forall(), *this );
-}
-
-void Visitor::visit( Designation * designation ) {
-	acceptAll( designation->get_designators(), *this );
-}
-
-void Visitor::visit( SingleInit *singleInit ) {
-	singleInit->get_value()->accept( *this );
-}
-
-void Visitor::visit( ListInit *listInit ) {
-	acceptAll( listInit->get_designations(), *this );
-	acceptAll( listInit->get_initializers(), *this );
-}
-
-void Visitor::visit( ConstructorInit *ctorInit ) {
-	maybeAccept( ctorInit->get_ctor(), *this );
-	maybeAccept( ctorInit->get_dtor(), *this );
-	maybeAccept( ctorInit->get_init(), *this );
-}
-
-
-void Visitor::visit( Subrange * ) {}
-
-
-void Visitor::visit( Constant * ) {}
-
-void Visitor::visit( Attribute * attribute ) {
-	acceptAll( attribute->parameters, *this );
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SynTree/Visitor.h
===================================================================
--- src/SynTree/Visitor.h	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/SynTree/Visitor.h	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -21,6 +21,6 @@
 class Visitor {
   protected:
-	Visitor();
-	virtual ~Visitor();
+	Visitor() = default;
+	virtual ~Visitor() = default;
   public:
 	// visit: Default implementation of all functions visits the children
Index: src/SynTree/module.mk
===================================================================
--- src/SynTree/module.mk	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/SynTree/module.mk	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -46,6 +46,4 @@
        SynTree/TypeDecl.cc \
        SynTree/Initializer.cc \
-       SynTree/Visitor.cc \
-       SynTree/Mutator.cc \
        SynTree/TypeSubstitution.cc \
        SynTree/Attribute.cc \
Index: src/libcfa/concurrency/kernel.c
===================================================================
--- src/libcfa/concurrency/kernel.c	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/libcfa/concurrency/kernel.c	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -171,5 +171,8 @@
 		__cfaabi_dbg_print_safe("Kernel : core %p signaling termination\n", &this);
 		terminate(&this);
+		verify(this.do_terminate);
+		verify(this_processor != &this);
 		P( terminated );
+		verify(this_processor != &this);
 		pthread_join( kernel_thread, NULL );
 	}
Index: src/tests/.expect/KRfunctions.x86.txt
===================================================================
--- src/tests/.expect/KRfunctions.x86.txt	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/tests/.expect/KRfunctions.x86.txt	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -82,7 +82,7 @@
     signed int __a__i_2;
     signed int __b__i_2;
-    signed int *(*_tmp_cp_ret0)(signed int __x__i_1, signed int __y__i_1);
-    ((void)(__x__PFPi_ii__2=(((void)(_tmp_cp_ret0=__f10__FPFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret0)));
-    ((void)(_tmp_cp_ret0) /* ^?{} */);
+    signed int *(*_tmp_cp_ret2)(signed int __x__i_1, signed int __y__i_1);
+    ((void)(__x__PFPi_ii__2=(((void)(_tmp_cp_ret2=__f10__FPFPi_ii__iPiPid__1(3, (&__a__i_2), (&__b__i_2), 3.5))) , _tmp_cp_ret2)));
+    ((void)(_tmp_cp_ret2) /* ^?{} */);
     const signed int __f1__FCi_iPiPi__2(signed int __a__i_2, signed int *__b__Pi_2, signed int *__c__Pi_2){
         __attribute__ ((unused)) const signed int ___retval_f1__Ci_2;
Index: src/tests/Makefile.am
===================================================================
--- src/tests/Makefile.am	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/tests/Makefile.am	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -123,2 +123,5 @@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
 
+warnings/self-assignment: warnings/self-assignment.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} ${<} -o ${@}
+	echo > ${@}
Index: src/tests/Makefile.in
===================================================================
--- src/tests/Makefile.in	(revision 2701c913ea265aaa5daab981db74b2e6ef39b237)
+++ src/tests/Makefile.in	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -800,4 +800,8 @@
 	${CC} ${AM_CFLAGS} ${CFLAGS} -DERR1 ${<} -o ${@}
 
+warnings/self-assignment: warnings/self-assignment.c @CFA_BINDIR@/@CFA_NAME@
+	${CC} ${AM_CFLAGS} ${CFLAGS} ${<} -o ${@}
+	echo > ${@}
+
 # Tell versions [3.59,3.63) of GNU make to not export all variables.
 # Otherwise a system limit (for SysV at least) may be exceeded.
Index: src/tests/warnings/self-assignment.c
===================================================================
--- src/tests/warnings/self-assignment.c	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
+++ src/tests/warnings/self-assignment.c	(revision 507e7a25c43d01f94faa1f5f24b309ae36bd70d6)
@@ -0,0 +1,38 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// self-assignment.c --
+//
+// Author           : Rob Schluntz
+// Created On       : Thu Mar 1 13:53:57 2018
+// Last Modified By : Rob Schluntz
+// Last Modified On : Thu Mar 1 13:53:57 2018
+// Update Count     : 2
+//
+
+struct S {
+  int i;
+};
+
+struct T {
+  S s;
+};
+
+int main() {
+  int j = 0;
+  S s = { 0 };
+  T t = { { 0 } };
+
+  j = j;
+  s = s;
+  s.i = s.i;
+  t.s.i = t.s.i;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa dtor-early-exit" //
+// End: //
