Index: src/CodeGen/GenType.cc
===================================================================
--- src/CodeGen/GenType.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/CodeGen/GenType.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -26,24 +26,26 @@
 
 namespace CodeGen {
-	class GenType : public Visitor {
-	  public:
+	struct GenType : public WithVisitorRef<GenType>, public WithShortCircuiting {
 		GenType( const std::string &typeString, bool pretty = false, bool genC = false, bool lineMarks = false );
 		std::string get_typeString() const { return typeString; }
 		void set_typeString( const std::string &newValue ) { typeString = newValue; }
 
-		virtual void visit( FunctionType *funcType );
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( StructInstType *structInst );
-		virtual void visit( UnionInstType *unionInst );
-		virtual void visit( EnumInstType *enumInst );
-		virtual void visit( TypeInstType *typeInst );
-		virtual void visit( TupleType * tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
+		void previsit( BaseSyntaxNode * );
+		void postvisit( BaseSyntaxNode * );
+
+		void postvisit( FunctionType * funcType );
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( StructInstType * structInst );
+		void postvisit( UnionInstType * unionInst );
+		void postvisit( EnumInstType * enumInst );
+		void postvisit( TypeInstType * typeInst );
+		void postvisit( TupleType  * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 
 	  private:
@@ -59,5 +61,5 @@
 
 	std::string genType( Type *type, const std::string &baseString, bool pretty, bool genC , bool lineMarks ) {
-		GenType gt( baseString, pretty, genC, lineMarks );
+		PassVisitor<GenType> gt( baseString, pretty, genC, lineMarks );
 		std::ostringstream os;
 
@@ -68,5 +70,5 @@
 
 		type->accept( gt );
-		return os.str() + gt.get_typeString();
+		return os.str() + gt.pass.get_typeString();
 	}
 
@@ -77,11 +79,24 @@
 	GenType::GenType( const std::string &typeString, bool pretty, bool genC, bool lineMarks ) : typeString( typeString ), pretty( pretty ), genC( genC ), lineMarks( lineMarks ) {}
 
-	void GenType::visit( VoidType *voidType ) {
+	// *** BaseSyntaxNode
+	void GenType::previsit( BaseSyntaxNode * ) {
+		// turn off automatic recursion for all nodes, to allow each visitor to
+		// precisely control the order in which its children are visited.
+		visit_children = false;
+	}
+
+	void GenType::postvisit( BaseSyntaxNode * node ) {
+		std::stringstream ss;
+		node->print( ss );
+		assertf( false, "Unhandled node reached in GenType: %s", ss.str().c_str() );
+	}
+
+	void GenType::postvisit( VoidType * voidType ) {
 		typeString = "void " + typeString;
 		handleQualifiers( voidType );
 	}
 
-	void GenType::visit( BasicType *basicType ) {
-		BasicType::Kind kind = basicType->get_kind();
+	void GenType::postvisit( BasicType * basicType ) {
+		BasicType::Kind kind = basicType->kind;
 		assert( 0 <= kind && kind < BasicType::NUMBER_OF_BASIC_TYPES );
 		typeString = std::string( BasicType::typeNames[kind] ) + " " + typeString;
@@ -89,5 +104,5 @@
 	}
 
-	void GenType::genArray( const Type::Qualifiers &qualifiers, Type *base, Expression *dimension, bool isVarLen, bool isStatic ) {
+	void GenType::genArray( const Type::Qualifiers & qualifiers, Type * base, Expression *dimension, bool isVarLen, bool isStatic ) {
 		std::ostringstream os;
 		if ( typeString != "" ) {
@@ -126,11 +141,11 @@
 		typeString = os.str();
 
-		base->accept( *this );
-	}
-
-	void GenType::visit( PointerType *pointerType ) {
-		assert( pointerType->get_base() != 0);
-		if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->get_dimension() ) {
-			genArray( pointerType->get_qualifiers(), pointerType->get_base(), pointerType->get_dimension(), pointerType->get_isVarLen(), pointerType->get_isStatic() );
+		base->accept( *visitor );
+	}
+
+	void GenType::postvisit( PointerType * pointerType ) {
+		assert( pointerType->base != 0);
+		if ( pointerType->get_isStatic() || pointerType->get_isVarLen() || pointerType->dimension ) {
+			genArray( pointerType->get_qualifiers(), pointerType->base, pointerType->dimension, pointerType->get_isVarLen(), pointerType->get_isStatic() );
 		} else {
 			handleQualifiers( pointerType );
@@ -140,21 +155,21 @@
 				typeString = "*" + typeString;
 			} // if
-			pointerType->get_base()->accept( *this );
-		} // if
-	}
-
-	void GenType::visit( ArrayType *arrayType ) {
-		genArray( arrayType->get_qualifiers(), arrayType->get_base(), arrayType->get_dimension(), arrayType->get_isVarLen(), arrayType->get_isStatic() );
-	}
-
-	void GenType::visit( ReferenceType *refType ) {
-		assert( refType->get_base() != 0);
+			pointerType->base->accept( *visitor );
+		} // if
+	}
+
+	void GenType::postvisit( ArrayType * arrayType ) {
+		genArray( arrayType->get_qualifiers(), arrayType->base, arrayType->dimension, arrayType->get_isVarLen(), arrayType->get_isStatic() );
+	}
+
+	void GenType::postvisit( ReferenceType * refType ) {
+		assert( refType->base != 0);
 		assertf( ! genC, "Reference types should not reach code generation." );
 		handleQualifiers( refType );
 		typeString = "&" + typeString;
-		refType->get_base()->accept( *this );
-	}
-
-	void GenType::visit( FunctionType *funcType ) {
+		refType->base->accept( *visitor );
+	}
+
+	void GenType::postvisit( FunctionType * funcType ) {
 		std::ostringstream os;
 
@@ -169,5 +184,5 @@
 		/************* parameters ***************/
 
-		const std::list<DeclarationWithType *> &pars = funcType->get_parameters();
+		const std::list<DeclarationWithType *> &pars = funcType->parameters;
 
 		if ( pars.empty() ) {
@@ -191,17 +206,17 @@
 		typeString = os.str();
 
-		if ( funcType->get_returnVals().size() == 0 ) {
+		if ( funcType->returnVals.size() == 0 ) {
 			typeString = "void " + typeString;
 		} else {
-			funcType->get_returnVals().front()->get_type()->accept( *this );
+			funcType->returnVals.front()->get_type()->accept( *visitor );
 		} // if
 
 		// add forall
-		if( ! funcType->get_forall().empty() && ! genC ) {
+		if( ! funcType->forall.empty() && ! genC ) {
 			// assertf( ! genC, "Aggregate type parameters should not reach code generation." );
 			std::ostringstream os;
 			PassVisitor<CodeGenerator> cg( os, pretty, genC, lineMarks );
 			os << "forall(";
-			cg.pass.genCommaList( funcType->get_forall().begin(), funcType->get_forall().end() );
+			cg.pass.genCommaList( funcType->forall.begin(), funcType->forall.end() );
 			os << ")" << std::endl;
 			typeString = os.str() + typeString;
@@ -221,28 +236,28 @@
 	}
 
-	void GenType::visit( StructInstType *structInst )  {
-		typeString = structInst->get_name() + handleGeneric( structInst ) + " " + typeString;
+	void GenType::postvisit( StructInstType * structInst )  {
+		typeString = structInst->name + handleGeneric( structInst ) + " " + typeString;
 		if ( genC ) typeString = "struct " + typeString;
 		handleQualifiers( structInst );
 	}
 
-	void GenType::visit( UnionInstType *unionInst ) {
-		typeString = unionInst->get_name() + handleGeneric( unionInst ) + " " + typeString;
+	void GenType::postvisit( UnionInstType * unionInst ) {
+		typeString = unionInst->name + handleGeneric( unionInst ) + " " + typeString;
 		if ( genC ) typeString = "union " + typeString;
 		handleQualifiers( unionInst );
 	}
 
-	void GenType::visit( EnumInstType *enumInst ) {
-		typeString = enumInst->get_name() + " " + typeString;
+	void GenType::postvisit( EnumInstType * enumInst ) {
+		typeString = enumInst->name + " " + typeString;
 		if ( genC ) typeString = "enum " + typeString;
 		handleQualifiers( enumInst );
 	}
 
-	void GenType::visit( TypeInstType *typeInst ) {
-		typeString = typeInst->get_name() + " " + typeString;
+	void GenType::postvisit( TypeInstType * typeInst ) {
+		typeString = typeInst->name + " " + typeString;
 		handleQualifiers( typeInst );
 	}
 
-	void GenType::visit( TupleType * tupleType ) {
+	void GenType::postvisit( TupleType * tupleType ) {
 		assertf( ! genC, "Tuple types should not reach code generation." );
 		unsigned int i = 0;
@@ -257,10 +272,10 @@
 	}
 
-	void GenType::visit( VarArgsType *varArgsType ) {
+	void GenType::postvisit( VarArgsType * varArgsType ) {
 		typeString = "__builtin_va_list " + typeString;
 		handleQualifiers( varArgsType );
 	}
 
-	void GenType::visit( ZeroType *zeroType ) {
+	void GenType::postvisit( ZeroType * zeroType ) {
 		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
 		typeString = (pretty ? "zero_t " : "long int ") + typeString;
@@ -268,5 +283,5 @@
 	}
 
-	void GenType::visit( OneType *oneType ) {
+	void GenType::postvisit( OneType * oneType ) {
 		// ideally these wouldn't hit codegen at all, but should be safe to make them ints
 		typeString = (pretty ? "one_t " : "long int ") + typeString;
@@ -274,5 +289,5 @@
 	}
 
-	void GenType::handleQualifiers( Type *type ) {
+	void GenType::handleQualifiers( Type * type ) {
 		if ( type->get_const() ) {
 			typeString = "const " + typeString;
Index: src/ControlStruct/ExceptTranslate.cc
===================================================================
--- src/ControlStruct/ExceptTranslate.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ControlStruct/ExceptTranslate.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -316,6 +316,5 @@
 				VarExprReplacer::DeclMap mapping;
 				mapping[ handler_decl ] = local_except;
-				VarExprReplacer mapper( mapping );
-				handler->get_body()->accept( mapper );
+				VarExprReplacer::replace( handler->body, mapping );
 			}
 
Index: src/ResolvExpr/AlternativeFinder.cc
===================================================================
--- src/ResolvExpr/AlternativeFinder.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/AlternativeFinder.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -152,5 +152,5 @@
 
 		void renameTypes( Expression *expr ) {
-			expr->get_result()->accept( global_renamer );
+			renameTyVars( expr->result );
 		}
 	} // namespace
@@ -485,5 +485,5 @@
 			Type *adjType = candidate->get_type()->clone();
 			adjustExprType( adjType, newEnv, indexer );
-			adjType->accept( global_renamer );
+			renameTyVars( adjType );
 			PRINT(
 				std::cerr << "unifying ";
@@ -595,5 +595,5 @@
 
 		ArgPack()
-			: parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0), 
+			: parent(0), expr(), cost(Cost::zero), env(), need(), have(), openVars(), nextArg(0),
 			  tupleStart(0), nextExpl(0), explAlt(0) {}
 
@@ -706,5 +706,5 @@
 
 						if ( nTuples > 0 || ! results[i].expr ) {
-							// first iteration or no expression to clone, 
+							// first iteration or no expression to clone,
 							// push empty tuple expression
 							newResult.parent = i;
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/CommonType.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -18,4 +18,5 @@
 #include <utility>                       // for pair
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for OpenVarSet, AssertionSet
 #include "SymTab/Indexer.h"              // for Indexer
@@ -29,25 +30,27 @@
 
 namespace ResolvExpr {
-	class CommonType : public Visitor {
-	  public:
+	struct CommonType : public WithShortCircuiting {
 		CommonType( Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars );
 		Type *get_result() const { return result; }
+
+		void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * aggregateUseType );
+		void postvisit( UnionInstType * aggregateUseType );
+		void postvisit( EnumInstType * aggregateUseType );
+		void postvisit( TraitInstType * aggregateUseType );
+		void postvisit( TypeInstType * aggregateUseType );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
+
 	  private:
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TraitInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
 		template< typename Pointer > void getCommonWithVoidPointer( Pointer* voidPointer, Pointer* otherPointer );
 		template< typename RefType > void handleRefType( RefType *inst, Type *other );
@@ -80,5 +83,5 @@
 
 	Type *commonType( Type *type1, Type *type2, bool widenFirst, bool widenSecond, const SymTab::Indexer &indexer, TypeEnvironment &env, const OpenVarSet &openVars ) {
-		CommonType visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
+		PassVisitor<CommonType> visitor( type2, widenFirst, widenSecond, indexer, env, openVars );
 
 		int depth1 = type1->referenceDepth();
@@ -116,5 +119,5 @@
 
 		type1->accept( visitor );
-		Type *result = visitor.get_result();
+		Type *result = visitor.pass.get_result();
 		if ( ! result ) {
 			// this appears to be handling for opaque type declarations
@@ -188,7 +191,7 @@
 	}
 
-	void CommonType::visit( VoidType * ) {}
-
-	void CommonType::visit( BasicType *basicType ) {
+	void CommonType::postvisit( VoidType * ) {}
+
+	void CommonType::postvisit( BasicType *basicType ) {
 		if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
 			BasicType::Kind newType = combinedType[ basicType->get_kind() ][ otherBasic->get_kind() ];
@@ -219,5 +222,5 @@
 	}
 
-	void CommonType::visit( PointerType *pointerType ) {
+	void CommonType::postvisit( PointerType *pointerType ) {
 		if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
 			// std::cerr << "commonType: two pointers: " << pointerType << " / " << otherPointer << std::endl;
@@ -254,7 +257,7 @@
 	}
 
-	void CommonType::visit( ArrayType * ) {}
-
-	void CommonType::visit( ReferenceType *refType ) {
+	void CommonType::postvisit( ArrayType * ) {}
+
+	void CommonType::postvisit( ReferenceType *refType ) {
 		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
 			// std::cerr << "commonType: both references: " << refType << " / " << otherRef << std::endl;
@@ -291,21 +294,19 @@
 	}
 
-	void CommonType::visit( FunctionType * ) {}
-	void CommonType::visit( StructInstType * ) {}
-	void CommonType::visit( UnionInstType * ) {}
-
-	void CommonType::visit( EnumInstType *enumInstType ) {
+	void CommonType::postvisit( FunctionType * ) {}
+	void CommonType::postvisit( StructInstType * ) {}
+	void CommonType::postvisit( UnionInstType * ) {}
+
+	void CommonType::postvisit( EnumInstType *enumInstType ) {
 		if ( dynamic_cast< BasicType * >( type2 ) || dynamic_cast< ZeroType* >( type2 ) || dynamic_cast< OneType* >( type2 ) ) {
 			// reuse BasicType, EnumInstType code by swapping type2 with enumInstType
-			ValueGuard< Type * > temp( type2 );
-			type2 = enumInstType;
-			temp.old->accept( *this );
-		} // if
-	}
-
-	void CommonType::visit( TraitInstType * ) {
-	}
-
-	void CommonType::visit( TypeInstType *inst ) {
+			result = commonType( type2, enumInstType, widenSecond, widenFirst, indexer, env, openVars );
+		} // if
+	}
+
+	void CommonType::postvisit( TraitInstType * ) {
+	}
+
+	void CommonType::postvisit( TypeInstType *inst ) {
 		if ( widenFirst ) {
 			NamedTypeDecl *nt = indexer.lookupType( inst->get_name() );
@@ -329,8 +330,8 @@
 	}
 
-	void CommonType::visit( TupleType * ) {}
-	void CommonType::visit( VarArgsType * ) {}
-
-	void CommonType::visit( ZeroType *zeroType ) {
+	void CommonType::postvisit( TupleType * ) {}
+	void CommonType::postvisit( VarArgsType * ) {}
+
+	void CommonType::postvisit( ZeroType *zeroType ) {
 		if ( widenFirst ) {
 			if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< PointerType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
@@ -346,5 +347,5 @@
 	}
 
-	void CommonType::visit( OneType *oneType ) {
+	void CommonType::postvisit( OneType *oneType ) {
 		if ( widenFirst ) {
 			if ( dynamic_cast< BasicType* >( type2 ) || dynamic_cast< EnumInstType* >( type2 ) ) {
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/CurrentObject.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -443,5 +443,5 @@
 				return new UnionIterator( uit );
 			} else {
-				assertf( dynamic_cast< TypeInstType * >( type ), "some other reftotype" );
+				assertf( dynamic_cast< EnumInstType * >( type ) || dynamic_cast< TypeInstType * >( type ), "Encountered unhandled ReferenceToType in createMemberIterator: %s", toString( type ).c_str() );
 				return new SimpleIterator( type );
 			}
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -14,4 +14,5 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 #include "SynTree/Type.h"                // for TypeInstType, Type, BasicType
@@ -20,24 +21,25 @@
 
 namespace ResolvExpr {
-	class PtrsAssignable : public Visitor {
-	  public:
+	struct PtrsAssignable : public WithShortCircuiting {
 		PtrsAssignable( Type *dest, const TypeEnvironment &env );
 
 		int get_result() const { return result; }
 
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *inst );
-		virtual void visit( UnionInstType *inst );
-		virtual void visit( EnumInstType *inst );
-		virtual void visit( TraitInstType *inst );
-		virtual void visit( TypeInstType *inst );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
+		void previsit( Type * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * inst );
+		void postvisit( UnionInstType * inst );
+		void postvisit( EnumInstType * inst );
+		void postvisit( TraitInstType * inst );
+		void postvisit( TypeInstType * inst );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 	  private:
 		Type *dest;
@@ -59,7 +61,7 @@
 			return -1;
 		} else {
-			PtrsAssignable ptrs( dest, env );
+			PassVisitor<PtrsAssignable> ptrs( dest, env );
 			src->accept( ptrs );
-			return ptrs.get_result();
+			return ptrs.pass.get_result();
 		} // if
 	}
@@ -67,18 +69,18 @@
 	PtrsAssignable::PtrsAssignable( Type *dest, const TypeEnvironment &env ) : dest( dest ), result( 0 ), env( env ) {}
 
-	void PtrsAssignable::visit( VoidType * ) {
+	void PtrsAssignable::postvisit( VoidType * ) {
 		// T * = void * is disallowed - this is a change from C, where any
 		// void * can be assigned or passed to a non-void pointer without a cast.
 	}
 
-	void PtrsAssignable::visit( __attribute__((unused)) BasicType *basicType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) PointerType *pointerType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) ArrayType *arrayType ) {}
-	void PtrsAssignable::visit( __attribute__((unused)) FunctionType *functionType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) BasicType *basicType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) PointerType *pointerType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) ArrayType *arrayType ) {}
+	void PtrsAssignable::postvisit( __attribute__((unused)) FunctionType *functionType ) {}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) StructInstType *inst ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) UnionInstType *inst ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) StructInstType *inst ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) UnionInstType *inst ) {}
 
-	void PtrsAssignable::visit( EnumInstType * ) {
+	void PtrsAssignable::postvisit( EnumInstType * ) {
 		if ( dynamic_cast< BasicType* >( dest ) ) {
 			// int * = E *, etc. is safe. This isn't technically correct, as each
@@ -91,6 +93,6 @@
 	}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) TraitInstType *inst ) {}
-	void PtrsAssignable::visit( TypeInstType *inst ) {
+	void PtrsAssignable::postvisit(  __attribute__((unused)) TraitInstType *inst ) {}
+	void PtrsAssignable::postvisit( TypeInstType *inst ) {
 		EqvClass eqvClass;
 		if ( env.lookup( inst->get_name(), eqvClass ) && eqvClass.type ) {
@@ -100,8 +102,8 @@
 	}
 
-	void PtrsAssignable::visit(  __attribute__((unused)) TupleType *tupleType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) VarArgsType *varArgsType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) ZeroType *zeroType ) {}
-	void PtrsAssignable::visit(  __attribute__((unused)) OneType *oneType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) TupleType *tupleType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) VarArgsType *varArgsType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) ZeroType *zeroType ) {}
+	void PtrsAssignable::postvisit(  __attribute__((unused)) OneType *oneType ) {}
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/PtrsCastable.cc
===================================================================
--- src/ResolvExpr/PtrsCastable.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/PtrsCastable.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -14,4 +14,5 @@
 //
 
+#include "Common/PassVisitor.h"
 #include "ResolvExpr/TypeEnvironment.h"  // for EqvClass, TypeEnvironment
 #include "SymTab/Indexer.h"              // for Indexer
@@ -21,7 +22,6 @@
 #include "typeops.h"                     // for ptrsAssignable
 
-
 namespace ResolvExpr {
-	class PtrsCastable : public Visitor {
+	struct PtrsCastable : public WithShortCircuiting  {
 	  public:
 		PtrsCastable( Type *dest, const TypeEnvironment &env, const SymTab::Indexer &indexer );
@@ -29,18 +29,20 @@
 		int get_result() const { return result; }
 
-		virtual void visit(VoidType *voidType);
-		virtual void visit(BasicType *basicType);
-		virtual void visit(PointerType *pointerType);
-		virtual void visit(ArrayType *arrayType);
-		virtual void visit(FunctionType *functionType);
-		virtual void visit(StructInstType *inst);
-		virtual void visit(UnionInstType *inst);
-		virtual void visit(EnumInstType *inst);
-		virtual void visit(TraitInstType *inst);
-		virtual void visit(TypeInstType *inst);
-		virtual void visit(TupleType *tupleType);
-		virtual void visit(VarArgsType *varArgsType);
-		virtual void visit(ZeroType *zeroType);
-		virtual void visit(OneType *oneType);
+		void previsit( Type * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * inst );
+		void postvisit( UnionInstType * inst );
+		void postvisit( EnumInstType * inst );
+		void postvisit( TraitInstType * inst );
+		void postvisit( TypeInstType * inst );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
 	  private:
 		Type *dest;
@@ -79,4 +81,5 @@
 			EqvClass eqvClass;
 			if ( env.lookup( destAsTypeInst->get_name(), eqvClass ) ) {
+				// xxx - should this be ptrsCastable?
 				return ptrsAssignable( src, eqvClass.type, env );
 			} // if
@@ -85,7 +88,7 @@
 			return objectCast( src, env, indexer );
 		} else {
-			PtrsCastable ptrs( dest, env, indexer );
+			PassVisitor<PtrsCastable> ptrs( dest, env, indexer );
 			src->accept( ptrs );
-			return ptrs.get_result();
+			return ptrs.pass.get_result();
 		} // if
 	}
@@ -95,34 +98,34 @@
 	}
 
-	void PtrsCastable::visit( VoidType * ) {
+	void PtrsCastable::postvisit( VoidType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( BasicType * ) {
+	void PtrsCastable::postvisit( BasicType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( PointerType * ) {
+	void PtrsCastable::postvisit( PointerType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( ArrayType * ) {
+	void PtrsCastable::postvisit( ArrayType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( FunctionType * ) {
+	void PtrsCastable::postvisit( FunctionType * ) {
 		// result = -1;
 		result = functionCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( StructInstType * ) {
+	void PtrsCastable::postvisit( StructInstType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( UnionInstType * ) {
+	void PtrsCastable::postvisit( UnionInstType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( EnumInstType * ) {
+	void PtrsCastable::postvisit( EnumInstType * ) {
 		if ( dynamic_cast< EnumInstType* >( dest ) ) {
 			result = 1;
@@ -138,24 +141,24 @@
 	}
 
-	void PtrsCastable::visit( TraitInstType * ) {}
+	void PtrsCastable::postvisit( TraitInstType * ) {}
 
-	void PtrsCastable::visit(TypeInstType *inst) {
+	void PtrsCastable::postvisit(TypeInstType *inst) {
 		//result = objectCast( inst, env, indexer ) > 0 && objectCast( dest, env, indexer ) > 0 ? 1 : -1;
 		result = objectCast( inst, env, indexer ) == objectCast( dest, env, indexer ) ? 1 : -1;
 	}
 
-	void PtrsCastable::visit( TupleType * ) {
+	void PtrsCastable::postvisit( TupleType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( VarArgsType * ) {
+	void PtrsCastable::postvisit( VarArgsType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( ZeroType * ) {
+	void PtrsCastable::postvisit( ZeroType * ) {
 		result = objectCast( dest, env, indexer );
 	}
 
-	void PtrsCastable::visit( OneType * ) {
+	void PtrsCastable::postvisit( OneType * ) {
 		result = objectCast( dest, env, indexer );
 	}
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/RenameVars.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -19,4 +19,5 @@
 #include <utility>                 // for pair
 
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "RenameVars.h"
@@ -27,126 +28,72 @@
 
 namespace ResolvExpr {
-	RenameVars global_renamer;
+	namespace {
+		struct RenameVars {
+			RenameVars();
+			void reset();
 
-	RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
-		mapStack.push_front( std::map< std::string, std::string >() );
+			void previsit( TypeInstType * instType );
+			void previsit( Type * );
+			void postvisit( Type * );
+
+		  private:
+			int level, resetCount;
+			std::list< std::map< std::string, std::string > > mapStack;
+		};
+
+		PassVisitor<RenameVars> global_renamer;
+	} // namespace
+
+	void renameTyVars( Type * t ) {
+		t->accept( global_renamer );
 	}
 
-	void RenameVars::reset() {
-		level = 0;
-		resetCount++;
+	void resetTyVarRenaming() {
+		global_renamer.pass.reset();
 	}
 
-	void RenameVars::visit( VoidType *voidType ) {
-		typeBefore( voidType );
-		typeAfter( voidType );
-	}
+	namespace {
+		RenameVars::RenameVars() : level( 0 ), resetCount( 0 ) {
+			mapStack.push_front( std::map< std::string, std::string >() );
+		}
 
-	void RenameVars::visit( BasicType *basicType ) {
-		typeBefore( basicType );
-		typeAfter( basicType );
-	}
+		void RenameVars::reset() {
+			level = 0;
+			resetCount++;
+		}
 
-	void RenameVars::visit( PointerType *pointerType ) {
-		typeBefore( pointerType );
-		maybeAccept( pointerType->get_base(), *this );
-		typeAfter( pointerType );
-	}
+		void RenameVars::previsit( TypeInstType * instType ) {
+			previsit( (Type *)instType );
+			std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->name );
+			if ( i != mapStack.front().end() ) {
+				instType->name = i->second;
+			} // if
+		}
 
-	void RenameVars::visit( ArrayType *arrayType ) {
-		typeBefore( arrayType );
-		maybeAccept( arrayType->get_dimension(), *this );
-		maybeAccept( arrayType->get_base(), *this );
-		typeAfter( arrayType );
-	}
+		void RenameVars::previsit( Type * type ) {
+			if ( ! type->forall.empty() ) {
+				// copies current name mapping into new mapping
+				mapStack.push_front( mapStack.front() );
+				// renames all "forall" type names to `_${level}_${name}'
+				for ( auto td : type->forall ) {
+					std::ostringstream output;
+					output << "_" << resetCount << "_" << level << "_" << td->name;
+					std::string newname( output.str() );
+					mapStack.front()[ td->get_name() ] = newname;
+					td->name = newname;
+					// ditto for assertion names, the next level in
+					level++;
+					// acceptAll( td->assertions, *this );
+				} // for
+			} // if
+		}
 
-	void RenameVars::visit( FunctionType *functionType ) {
-		typeBefore( functionType );
-		acceptAll( functionType->get_returnVals(), *this );
-		acceptAll( functionType->get_parameters(), *this );
-		typeAfter( functionType );
-	}
-
-	void RenameVars::visit( StructInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( UnionInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( EnumInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( TraitInstType *aggregateUseType ) {
-		typeBefore( aggregateUseType );
-		acceptAll( aggregateUseType->get_parameters(), *this );
-		typeAfter( aggregateUseType );
-	}
-
-	void RenameVars::visit( TypeInstType *instType ) {
-		typeBefore( instType );
-		std::map< std::string, std::string >::const_iterator i = mapStack.front().find( instType->get_name() );
-		if ( i != mapStack.front().end() ) {
-			instType->set_name( i->second );
-		} else {
-		} // if
-		acceptAll( instType->get_parameters(), *this );
-		typeAfter( instType );
-	}
-
-	void RenameVars::visit( TupleType *tupleType ) {
-		typeBefore( tupleType );
-		acceptAll( tupleType->get_types(), *this );
-		typeAfter( tupleType );
-	}
-
-	void RenameVars::visit( VarArgsType *varArgsType ) {
-		typeBefore( varArgsType );
-		typeAfter( varArgsType );
-	}
-
-	void RenameVars::visit( ZeroType *zeroType ) {
-		typeBefore( zeroType );
-		typeAfter( zeroType );
-	}
-
-	void RenameVars::visit( OneType *oneType ) {
-		typeBefore( oneType );
-		typeAfter( oneType );
-	}
-
-	void RenameVars::typeBefore( Type *type ) {
-		if ( ! type->get_forall().empty() ) {
-			// copies current name mapping into new mapping
-			mapStack.push_front( mapStack.front() );
-			// renames all "forall" type names to `_${level}_${name}'
-			for ( Type::ForallList::iterator i = type->get_forall().begin(); i != type->get_forall().end(); ++i ) {
-				std::ostringstream output;
-				output << "_" << resetCount << "_" << level << "_" << (*i)->get_name();
-				std::string newname( output.str() );
-				mapStack.front()[ (*i)->get_name() ] = newname;
-				(*i)->set_name( newname );
-				// ditto for assertion names, the next level in
-				level++;
-				acceptAll( (*i)->get_assertions(), *this );
-			} // for
-		} // if
-	}
-
-	void RenameVars::typeAfter( Type *type ) {
-		// clears name mapping added by typeBefore()
-		if ( ! type->get_forall().empty() ) {
-			mapStack.pop_front();
-		} // if
-	}
-
+		void RenameVars::postvisit( Type * type ) {
+			// clears name mapping added by typeBefore()
+			if ( ! type->forall.empty() ) {
+				mapStack.pop_front();
+			} // if
+		}
+	} // namespace
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/RenameVars.h
===================================================================
--- src/ResolvExpr/RenameVars.h	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/RenameVars.h	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -24,33 +24,9 @@
 
 namespace ResolvExpr {
+	/// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
+	void renameTyVars( Type * );
 
-	/// Provides a consistent renaming of forall type names in a hierarchy by prefixing them with a unique "level" ID
-	class RenameVars : public Visitor {
-	  public:
-		RenameVars();
-		void reset();
-	  private:
-		virtual void visit( VoidType *basicType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TraitInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
-		void typeBefore( Type *type );
-		void typeAfter( Type *type );
-		int level, resetCount;
-		std::list< std::map< std::string, std::string > > mapStack;
-	};
-
-	extern RenameVars global_renamer;
+	/// resets internal state of renamer to avoid overflow
+	void resetTyVarRenaming();
 } // namespace ResolvExpr
 
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/Resolver.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -132,5 +132,5 @@
 
 	void findVoidExpression( Expression *& untyped, const SymTab::Indexer &indexer ) {
-		global_renamer.reset();
+		resetTyVarRenaming();
 		TypeEnvironment env;
 		Expression *newExpr = resolveInVoidContext( untyped, indexer, env );
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/ResolvExpr/Unify.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -44,26 +44,28 @@
 namespace ResolvExpr {
 
-	class Unify : public Visitor {
-	  public:
+	struct Unify : public WithShortCircuiting {
 		Unify( Type *type2, TypeEnvironment &env, AssertionSet &needAssertions, AssertionSet &haveAssertions, const OpenVarSet &openVars, WidenMode widenMode, const SymTab::Indexer &indexer );
 
 		bool get_result() const { return result; }
+
+		void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+		void postvisit( VoidType * voidType );
+		void postvisit( BasicType * basicType );
+		void postvisit( PointerType * pointerType );
+		void postvisit( ArrayType * arrayType );
+		void postvisit( ReferenceType * refType );
+		void postvisit( FunctionType * functionType );
+		void postvisit( StructInstType * aggregateUseType );
+		void postvisit( UnionInstType * aggregateUseType );
+		void postvisit( EnumInstType * aggregateUseType );
+		void postvisit( TraitInstType * aggregateUseType );
+		void postvisit( TypeInstType * aggregateUseType );
+		void postvisit( TupleType * tupleType );
+		void postvisit( VarArgsType * varArgsType );
+		void postvisit( ZeroType * zeroType );
+		void postvisit( OneType * oneType );
+
 	  private:
-		virtual void visit(VoidType *voidType);
-		virtual void visit(BasicType *basicType);
-		virtual void visit(PointerType *pointerType);
-		virtual void visit(ArrayType *arrayType);
-		virtual void visit(ReferenceType *refType);
-		virtual void visit(FunctionType *functionType);
-		virtual void visit(StructInstType *aggregateUseType);
-		virtual void visit(UnionInstType *aggregateUseType);
-		virtual void visit(EnumInstType *aggregateUseType);
-		virtual void visit(TraitInstType *aggregateUseType);
-		virtual void visit(TypeInstType *aggregateUseType);
-		virtual void visit(TupleType *tupleType);
-		virtual void visit(VarArgsType *varArgsType);
-		virtual void visit(ZeroType *zeroType);
-		virtual void visit(OneType *oneType);
-
 		template< typename RefType > void handleRefType( RefType *inst, Type *other );
 		template< typename RefType > void handleGenericRefType( RefType *inst, Type *other );
@@ -325,7 +327,7 @@
 			result = bindVar( var2, type1, entry2->second, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
 		} else {
-			Unify comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
+			PassVisitor<Unify> comparator( type2, env, needAssertions, haveAssertions, openVars, widenMode, indexer );
 			type1->accept( comparator );
-			result = comparator.get_result();
+			result = comparator.pass.get_result();
 		} // if
 #ifdef DEBUG
@@ -404,9 +406,9 @@
 	}
 
-	void Unify::visit( __attribute__((unused)) VoidType *voidType) {
+	void Unify::postvisit( __attribute__((unused)) VoidType *voidType) {
 		result = dynamic_cast< VoidType* >( type2 );
 	}
 
-	void Unify::visit(BasicType *basicType) {
+	void Unify::postvisit(BasicType *basicType) {
 		if ( BasicType *otherBasic = dynamic_cast< BasicType* >( type2 ) ) {
 			result = basicType->get_kind() == otherBasic->get_kind();
@@ -436,5 +438,5 @@
 	}
 
-	void Unify::visit(PointerType *pointerType) {
+	void Unify::postvisit(PointerType *pointerType) {
 		if ( PointerType *otherPointer = dynamic_cast< PointerType* >( type2 ) ) {
 			result = unifyExact( pointerType->get_base(), otherPointer->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
@@ -444,5 +446,5 @@
 	}
 
-	void Unify::visit(ReferenceType *refType) {
+	void Unify::postvisit(ReferenceType *refType) {
 		if ( ReferenceType *otherRef = dynamic_cast< ReferenceType* >( type2 ) ) {
 			result = unifyExact( refType->get_base(), otherRef->get_base(), env, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
@@ -452,5 +454,5 @@
 	}
 
-	void Unify::visit(ArrayType *arrayType) {
+	void Unify::postvisit(ArrayType *arrayType) {
 		ArrayType *otherArray = dynamic_cast< ArrayType* >( type2 );
 		// to unify, array types must both be VLA or both not VLA
@@ -567,5 +569,5 @@
 	}
 
-	void Unify::visit(FunctionType *functionType) {
+	void Unify::postvisit(FunctionType *functionType) {
 		FunctionType *otherFunction = dynamic_cast< FunctionType* >( type2 );
 		if ( otherFunction && functionType->get_isVarArgs() == otherFunction->get_isVarArgs() ) {
@@ -669,21 +671,21 @@
 	}
 
-	void Unify::visit(StructInstType *structInst) {
+	void Unify::postvisit(StructInstType *structInst) {
 		handleGenericRefType( structInst, type2 );
 	}
 
-	void Unify::visit(UnionInstType *unionInst) {
+	void Unify::postvisit(UnionInstType *unionInst) {
 		handleGenericRefType( unionInst, type2 );
 	}
 
-	void Unify::visit(EnumInstType *enumInst) {
+	void Unify::postvisit(EnumInstType *enumInst) {
 		handleRefType( enumInst, type2 );
 	}
 
-	void Unify::visit(TraitInstType *contextInst) {
+	void Unify::postvisit(TraitInstType *contextInst) {
 		handleRefType( contextInst, type2 );
 	}
 
-	void Unify::visit(TypeInstType *typeInst) {
+	void Unify::postvisit(TypeInstType *typeInst) {
 		assert( openVars.find( typeInst->get_name() ) == openVars.end() );
 		TypeInstType *otherInst = dynamic_cast< TypeInstType* >( type2 );
@@ -740,5 +742,5 @@
 	}
 
-	void Unify::visit(TupleType *tupleType) {
+	void Unify::postvisit(TupleType *tupleType) {
 		if ( TupleType *otherTuple = dynamic_cast< TupleType* >( type2 ) ) {
 			std::unique_ptr<TupleType> flat1( tupleType->clone() );
@@ -757,13 +759,13 @@
 	}
 
-	void Unify::visit( __attribute__((unused)) VarArgsType *varArgsType ) {
+	void Unify::postvisit( __attribute__((unused)) VarArgsType *varArgsType ) {
 		result = dynamic_cast< VarArgsType* >( type2 );
 	}
 
-	void Unify::visit( __attribute__((unused)) ZeroType *zeroType ) {
+	void Unify::postvisit( __attribute__((unused)) ZeroType *zeroType ) {
 		result = dynamic_cast< ZeroType* >( type2 );
 	}
 
-	void Unify::visit( __attribute__((unused)) OneType *oneType ) {
+	void Unify::postvisit( __attribute__((unused)) OneType *oneType ) {
 		result = dynamic_cast< OneType* >( type2 );
 	}
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SymTab/Mangler.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -23,4 +23,5 @@
 
 #include "CodeGen/OperatorTable.h"  // for OperatorInfo, operatorLookup
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"   // for SemanticError
 #include "Common/utility.h"         // for toString
@@ -31,285 +32,340 @@
 
 namespace SymTab {
-	std::string Mangler::mangleType( Type * ty ) {
-		Mangler mangler( false, true, true );
-		maybeAccept( ty, mangler );
-		return mangler.get_mangleName();
-	}
-
-	std::string Mangler::mangleConcrete( Type* ty ) {
-		Mangler mangler( false, false, false );
-		maybeAccept( ty, mangler );
-		return mangler.get_mangleName();
-	}
-
-	Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
-		: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ), mangleGenericParams( mangleGenericParams ) {}
-
-	Mangler::Mangler( const Mangler &rhs ) : mangleName() {
-		varNums = rhs.varNums;
-		nextVarNum = rhs.nextVarNum;
-		isTopLevel = rhs.isTopLevel;
-		mangleOverridable = rhs.mangleOverridable;
-		typeMode = rhs.typeMode;
-	}
-
-	void Mangler::mangleDecl( DeclarationWithType * declaration ) {
-		bool wasTopLevel = isTopLevel;
-		if ( isTopLevel ) {
-			varNums.clear();
-			nextVarNum = 0;
-			isTopLevel = false;
-		} // if
-		mangleName << "__";
-		CodeGen::OperatorInfo opInfo;
-		if ( operatorLookup( declaration->get_name(), opInfo ) ) {
-			mangleName << opInfo.outputName;
-		} else {
-			mangleName << declaration->get_name();
-		} // if
-		mangleName << "__";
-		maybeAccept( declaration->get_type(), *this );
-		if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
-			// want to be able to override autogenerated and intrinsic routines,
-			// so they need a different name mangling
-			if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
-				mangleName << "autogen__";
-			} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
-				mangleName << "intrinsic__";
-			} else {
-				// if we add another kind of overridable function, this has to change
-				assert( false && "unknown overrideable linkage" );
-			} // if
+	namespace Mangler {
+		namespace {
+			/// Mangles names to a unique C identifier
+			struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler> {
+				Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
+				Mangler( const Mangler & );
+
+				void previsit( BaseSyntaxNode * ) { visit_children = false; }
+
+				void postvisit( ObjectDecl * declaration );
+				void postvisit( FunctionDecl * declaration );
+				void postvisit( TypeDecl * declaration );
+
+				void postvisit( VoidType * voidType );
+				void postvisit( BasicType * basicType );
+				void postvisit( PointerType * pointerType );
+				void postvisit( ArrayType * arrayType );
+				void postvisit( ReferenceType * refType );
+				void postvisit( FunctionType * functionType );
+				void postvisit( StructInstType * aggregateUseType );
+				void postvisit( UnionInstType * aggregateUseType );
+				void postvisit( EnumInstType * aggregateUseType );
+				void postvisit( TypeInstType * aggregateUseType );
+				void postvisit( TupleType * tupleType );
+				void postvisit( VarArgsType * varArgsType );
+				void postvisit( ZeroType * zeroType );
+				void postvisit( OneType * oneType );
+
+				std::string get_mangleName() { return mangleName.str(); }
+			  private:
+				std::ostringstream mangleName;  ///< Mangled name being constructed
+				typedef std::map< std::string, std::pair< int, int > > VarMapType;
+				VarMapType varNums;             ///< Map of type variables to indices
+				int nextVarNum;                 ///< Next type variable index
+				bool isTopLevel;                ///< Is the Mangler at the top level
+				bool mangleOverridable;         ///< Specially mangle overridable built-in methods
+				bool typeMode;                  ///< Produce a unique mangled name for a type
+				bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
+
+				void mangleDecl( DeclarationWithType *declaration );
+				void mangleRef( ReferenceToType *refType, std::string prefix );
+
+				void printQualifiers( Type *type );
+			}; // Mangler
+		} // namespace
+
+		std::string mangle( BaseSyntaxNode * decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
+			PassVisitor<Mangler> mangler( mangleOverridable, typeMode, mangleGenericParams );
+			maybeAccept( decl, mangler );
+			return mangler.pass.get_mangleName();
 		}
-		isTopLevel = wasTopLevel;
-	}
-
-	void Mangler::visit( ObjectDecl * declaration ) {
-		mangleDecl( declaration );
-	}
-
-	void Mangler::visit( FunctionDecl * declaration ) {
-		mangleDecl( declaration );
-	}
-
-	void Mangler::visit( VoidType * voidType ) {
-		printQualifiers( voidType );
-		mangleName << "v";
-	}
-
-	void Mangler::visit( BasicType * basicType ) {
-		static const char *btLetter[] = {
-			"b",	// Bool
-			"c",	// Char
-			"Sc",	// SignedChar
-			"Uc",	// UnsignedChar
-			"s",	// ShortSignedInt
-			"Us",	// ShortUnsignedInt
-			"i",	// SignedInt
-			"Ui",	// UnsignedInt
-			"l",	// LongSignedInt
-			"Ul",	// LongUnsignedInt
-			"q",	// LongLongSignedInt
-			"Uq",	// LongLongUnsignedInt
-			"f",	// Float
-			"d",	// Double
-			"r",	// LongDouble
-			"Xf",	// FloatComplex
-			"Xd",	// DoubleComplex
-			"Xr",	// LongDoubleComplex
-			"If",	// FloatImaginary
-			"Id",	// DoubleImaginary
-			"Ir",	// LongDoubleImaginary
-			"w",	// SignedInt128
-			"Uw",	// UnsignedInt128
-		};
-
-		printQualifiers( basicType );
-		mangleName << btLetter[ basicType->get_kind() ];
-	}
-
-	void Mangler::visit( PointerType * pointerType ) {
-		printQualifiers( pointerType );
-		mangleName << "P";
-		maybeAccept( pointerType->get_base(), *this );
-	}
-
-	void Mangler::visit( ArrayType * arrayType ) {
-		// TODO: encode dimension
-		printQualifiers( arrayType );
-		mangleName << "A0";
-		maybeAccept( arrayType->get_base(), *this );
-	}
-
-	void Mangler::visit( ReferenceType * refType ) {
-		printQualifiers( refType );
-		mangleName << "R";
-		maybeAccept( refType->get_base(), *this );
-	}
-
-	namespace {
-		inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
-			std::list< Type* > ret;
-			std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
-							std::mem_fun( &DeclarationWithType::get_type ) );
-			return ret;
+
+		std::string mangleType( Type * ty ) {
+			PassVisitor<Mangler> mangler( false, true, true );
+			maybeAccept( ty, mangler );
+			return mangler.pass.get_mangleName();
 		}
-	}
-
-	void Mangler::visit( FunctionType * functionType ) {
-		printQualifiers( functionType );
-		mangleName << "F";
-		std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
-		acceptAll( returnTypes, *this );
-		mangleName << "_";
-		std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
-		acceptAll( paramTypes, *this );
-		mangleName << "_";
-	}
-
-	void Mangler::mangleRef( ReferenceToType * refType, std::string prefix ) {
-		printQualifiers( refType );
-
-		mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();
-
-		if ( mangleGenericParams ) {
-			std::list< Expression* >& params = refType->get_parameters();
-			if ( ! params.empty() ) {
+
+		std::string mangleConcrete( Type * ty ) {
+			PassVisitor<Mangler> mangler( false, false, false );
+			maybeAccept( ty, mangler );
+			return mangler.pass.get_mangleName();
+		}
+
+		namespace {
+			Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams )
+				: nextVarNum( 0 ), isTopLevel( true ), mangleOverridable( mangleOverridable ), typeMode( typeMode ), mangleGenericParams( mangleGenericParams ) {}
+
+			Mangler::Mangler( const Mangler &rhs ) : mangleName() {
+				varNums = rhs.varNums;
+				nextVarNum = rhs.nextVarNum;
+				isTopLevel = rhs.isTopLevel;
+				mangleOverridable = rhs.mangleOverridable;
+				typeMode = rhs.typeMode;
+			}
+
+			void Mangler::mangleDecl( DeclarationWithType * declaration ) {
+				bool wasTopLevel = isTopLevel;
+				if ( isTopLevel ) {
+					varNums.clear();
+					nextVarNum = 0;
+					isTopLevel = false;
+				} // if
+				mangleName << "__";
+				CodeGen::OperatorInfo opInfo;
+				if ( operatorLookup( declaration->get_name(), opInfo ) ) {
+					mangleName << opInfo.outputName;
+				} else {
+					mangleName << declaration->get_name();
+				} // if
+				mangleName << "__";
+				maybeAccept( declaration->get_type(), *visitor );
+				if ( mangleOverridable && LinkageSpec::isOverridable( declaration->get_linkage() ) ) {
+					// want to be able to override autogenerated and intrinsic routines,
+					// so they need a different name mangling
+					if ( declaration->get_linkage() == LinkageSpec::AutoGen ) {
+						mangleName << "autogen__";
+					} else if ( declaration->get_linkage() == LinkageSpec::Intrinsic ) {
+						mangleName << "intrinsic__";
+					} else {
+						// if we add another kind of overridable function, this has to change
+						assert( false && "unknown overrideable linkage" );
+					} // if
+				}
+				isTopLevel = wasTopLevel;
+			}
+
+			void Mangler::postvisit( ObjectDecl * declaration ) {
+				mangleDecl( declaration );
+			}
+
+			void Mangler::postvisit( FunctionDecl * declaration ) {
+				mangleDecl( declaration );
+			}
+
+			void Mangler::postvisit( VoidType * voidType ) {
+				printQualifiers( voidType );
+				mangleName << "v";
+			}
+
+			void Mangler::postvisit( BasicType * basicType ) {
+				static const char *btLetter[] = {
+					"b",	// Bool
+					"c",	// Char
+					"Sc",	// SignedChar
+					"Uc",	// UnsignedChar
+					"s",	// ShortSignedInt
+					"Us",	// ShortUnsignedInt
+					"i",	// SignedInt
+					"Ui",	// UnsignedInt
+					"l",	// LongSignedInt
+					"Ul",	// LongUnsignedInt
+					"q",	// LongLongSignedInt
+					"Uq",	// LongLongUnsignedInt
+					"f",	// Float
+					"d",	// Double
+					"r",	// LongDouble
+					"Xf",	// FloatComplex
+					"Xd",	// DoubleComplex
+					"Xr",	// LongDoubleComplex
+					"If",	// FloatImaginary
+					"Id",	// DoubleImaginary
+					"Ir",	// LongDoubleImaginary
+					"w",	// SignedInt128
+					"Uw",	// UnsignedInt128
+				};
+
+				printQualifiers( basicType );
+				mangleName << btLetter[ basicType->get_kind() ];
+			}
+
+			void Mangler::postvisit( PointerType * pointerType ) {
+				printQualifiers( pointerType );
+				mangleName << "P";
+				maybeAccept( pointerType->get_base(), *visitor );
+			}
+
+			void Mangler::postvisit( ArrayType * arrayType ) {
+				// TODO: encode dimension
+				printQualifiers( arrayType );
+				mangleName << "A0";
+				maybeAccept( arrayType->get_base(), *visitor );
+			}
+
+			void Mangler::postvisit( ReferenceType * refType ) {
+				printQualifiers( refType );
+				mangleName << "R";
+				maybeAccept( refType->get_base(), *visitor );
+			}
+
+			namespace {
+				inline std::list< Type* > getTypes( const std::list< DeclarationWithType* > decls ) {
+					std::list< Type* > ret;
+					std::transform( decls.begin(), decls.end(), std::back_inserter( ret ),
+									std::mem_fun( &DeclarationWithType::get_type ) );
+					return ret;
+				}
+			}
+
+			void Mangler::postvisit( FunctionType * functionType ) {
+				printQualifiers( functionType );
+				mangleName << "F";
+				std::list< Type* > returnTypes = getTypes( functionType->get_returnVals() );
+				acceptAll( returnTypes, *visitor );
 				mangleName << "_";
-				for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) {
-					TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
-					assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str());
-					maybeAccept( paramType->get_type(), *this );
+				std::list< Type* > paramTypes = getTypes( functionType->get_parameters() );
+				acceptAll( paramTypes, *visitor );
+				mangleName << "_";
+			}
+
+			void Mangler::mangleRef( ReferenceToType * refType, std::string prefix ) {
+				printQualifiers( refType );
+
+				mangleName << ( refType->get_name().length() + prefix.length() ) << prefix << refType->get_name();
+
+				if ( mangleGenericParams ) {
+					std::list< Expression* >& params = refType->get_parameters();
+					if ( ! params.empty() ) {
+						mangleName << "_";
+						for ( std::list< Expression* >::const_iterator param = params.begin(); param != params.end(); ++param ) {
+							TypeExpr *paramType = dynamic_cast< TypeExpr* >( *param );
+							assertf(paramType, "Aggregate parameters should be type expressions: %s", toString(*param).c_str());
+							maybeAccept( paramType->get_type(), *visitor );
+						}
+						mangleName << "_";
+					}
 				}
+			}
+
+			void Mangler::postvisit( StructInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "s" );
+			}
+
+			void Mangler::postvisit( UnionInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "u" );
+			}
+
+			void Mangler::postvisit( EnumInstType * aggregateUseType ) {
+				mangleRef( aggregateUseType, "e" );
+			}
+
+			void Mangler::postvisit( TypeInstType * typeInst ) {
+				VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
+				if ( varNum == varNums.end() ) {
+					mangleRef( typeInst, "t" );
+				} else {
+					printQualifiers( typeInst );
+					std::ostringstream numStream;
+					numStream << varNum->second.first;
+					switch ( (TypeDecl::Kind )varNum->second.second ) {
+					  case TypeDecl::Dtype:
+						mangleName << "d";
+						break;
+					  case TypeDecl::Ftype:
+						mangleName << "f";
+						break;
+						case TypeDecl::Ttype:
+						mangleName << "tVARGS";
+						break;
+						default:
+						assert( false );
+					} // switch
+					mangleName << numStream.str();
+				} // if
+			}
+
+			void Mangler::postvisit( TupleType * tupleType ) {
+				printQualifiers( tupleType );
+				mangleName << "T";
+				acceptAll( tupleType->types, *visitor );
 				mangleName << "_";
 			}
-		}
-	}
-
-	void Mangler::visit( StructInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "s" );
-	}
-
-	void Mangler::visit( UnionInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "u" );
-	}
-
-	void Mangler::visit( EnumInstType * aggregateUseType ) {
-		mangleRef( aggregateUseType, "e" );
-	}
-
-	void Mangler::visit( TypeInstType * typeInst ) {
-		VarMapType::iterator varNum = varNums.find( typeInst->get_name() );
-		if ( varNum == varNums.end() ) {
-			mangleRef( typeInst, "t" );
-		} else {
-			printQualifiers( typeInst );
-			std::ostringstream numStream;
-			numStream << varNum->second.first;
-			switch ( (TypeDecl::Kind )varNum->second.second ) {
-			  case TypeDecl::Dtype:
-				mangleName << "d";
-				break;
-			  case TypeDecl::Ftype:
-				mangleName << "f";
-				break;
-				case TypeDecl::Ttype:
-				mangleName << "tVARGS";
-				break;
-				default:
-				assert( false );
-			} // switch
-			mangleName << numStream.str();
-		} // if
-	}
-
-	void Mangler::visit( TupleType * tupleType ) {
-		printQualifiers( tupleType );
-		mangleName << "T";
-		acceptAll( tupleType->types, *this );
-		mangleName << "_";
-	}
-
-	void Mangler::visit( VarArgsType * varArgsType ) {
-		printQualifiers( varArgsType );
-		mangleName << "VARGS";
-	}
-
-	void Mangler::visit( ZeroType * ) {
-		mangleName << "Z";
-	}
-
-	void Mangler::visit( OneType * ) {
-		mangleName << "O";
-	}
-
-	void Mangler::visit( TypeDecl * decl ) {
-		static const char *typePrefix[] = { "BT", "BD", "BF" };
-		mangleName << typePrefix[ decl->get_kind() ] << ( decl->name.length() + 1 ) << decl->name;
-	}
-
-	void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
-		for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
-			os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
-		} // for
-	}
-
-	void Mangler::printQualifiers( Type * type ) {
-		// skip if not including qualifiers
-		if ( typeMode ) return;
-
-		if ( ! type->get_forall().empty() ) {
-			std::list< std::string > assertionNames;
-			int tcount = 0, dcount = 0, fcount = 0, vcount = 0;
-			mangleName << "A";
-			for ( Type::ForallList::iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
-				switch ( (*i)->get_kind() ) {
-				  case TypeDecl::Dtype:
-					dcount++;
-					break;
-				  case TypeDecl::Ftype:
-					fcount++;
-					break;
-				  case TypeDecl::Ttype:
-					vcount++;
-					break;
-				  default:
-					assert( false );
-				} // switch
-				varNums[ (*i)->name ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
-				for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
-					Mangler sub_mangler( mangleOverridable, typeMode, mangleGenericParams );
-					sub_mangler.nextVarNum = nextVarNum;
-					sub_mangler.isTopLevel = false;
-					sub_mangler.varNums = varNums;
-					(*assert)->accept( sub_mangler );
-					assertionNames.push_back( sub_mangler.mangleName.str() );
+
+			void Mangler::postvisit( VarArgsType * varArgsType ) {
+				printQualifiers( varArgsType );
+				mangleName << "VARGS";
+			}
+
+			void Mangler::postvisit( ZeroType * ) {
+				mangleName << "Z";
+			}
+
+			void Mangler::postvisit( OneType * ) {
+				mangleName << "O";
+			}
+
+			void Mangler::postvisit( TypeDecl * decl ) {
+				static const char *typePrefix[] = { "BT", "BD", "BF" };
+				mangleName << typePrefix[ decl->get_kind() ] << ( decl->name.length() + 1 ) << decl->name;
+			}
+
+			__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
+				for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
+					os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
 				} // for
-			} // for
-			mangleName << tcount << "_" << dcount << "_" << fcount << "_" << vcount << "_";
-			std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
-			mangleName << "_";
-		} // if
-		if ( type->get_const() ) {
-			mangleName << "C";
-		} // if
-		if ( type->get_volatile() ) {
-			mangleName << "V";
-		} // if
-		if ( type->get_mutex() ) {
-			mangleName << "M";
-		} // if
-		// Removed due to restrict not affecting function compatibility in GCC
-//		if ( type->get_isRestrict() ) {
-//			mangleName << "E";
-//		} // if
-		if ( type->get_lvalue() ) {
-			// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
-			mangleName << "L";
-		}
-		if ( type->get_atomic() ) {
-			mangleName << "A";
-		} // if
-	}
+			}
+
+			void Mangler::printQualifiers( Type * type ) {
+				// skip if not including qualifiers
+				if ( typeMode ) return;
+
+				if ( ! type->get_forall().empty() ) {
+					std::list< std::string > assertionNames;
+					int tcount = 0, dcount = 0, fcount = 0, vcount = 0;
+					mangleName << "A";
+					for ( Type::ForallList::iterator i = type->forall.begin(); i != type->forall.end(); ++i ) {
+						switch ( (*i)->get_kind() ) {
+						  case TypeDecl::Dtype:
+							dcount++;
+							break;
+						  case TypeDecl::Ftype:
+							fcount++;
+							break;
+						  case TypeDecl::Ttype:
+							vcount++;
+							break;
+						  default:
+							assert( false );
+						} // switch
+						varNums[ (*i)->name ] = std::pair< int, int >( nextVarNum++, (int)(*i)->get_kind() );
+						for ( std::list< DeclarationWithType* >::iterator assert = (*i)->assertions.begin(); assert != (*i)->assertions.end(); ++assert ) {
+							PassVisitor<Mangler> sub_mangler( mangleOverridable, typeMode, mangleGenericParams );
+							sub_mangler.pass.nextVarNum = nextVarNum;
+							sub_mangler.pass.isTopLevel = false;
+							sub_mangler.pass.varNums = varNums;
+							(*assert)->accept( sub_mangler );
+							assertionNames.push_back( sub_mangler.pass.mangleName.str() );
+						} // for
+					} // for
+					mangleName << tcount << "_" << dcount << "_" << fcount << "_" << vcount << "_";
+					std::copy( assertionNames.begin(), assertionNames.end(), std::ostream_iterator< std::string >( mangleName, "" ) );
+					mangleName << "_";
+				} // if
+				if ( type->get_const() ) {
+					mangleName << "C";
+				} // if
+				if ( type->get_volatile() ) {
+					mangleName << "V";
+				} // if
+				if ( type->get_mutex() ) {
+					mangleName << "M";
+				} // if
+				// Removed due to restrict not affecting function compatibility in GCC
+		//		if ( type->get_isRestrict() ) {
+		//			mangleName << "E";
+		//		} // if
+				if ( type->get_lvalue() ) {
+					// mangle based on whether the type is lvalue, so that the resolver can differentiate lvalues and rvalues
+					mangleName << "L";
+				}
+				if ( type->get_atomic() ) {
+					mangleName << "A";
+				} // if
+			}
+		}	// namespace
+	} // namespace Mangler
 } // namespace SymTab
 
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SymTab/Mangler.h	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -25,61 +25,13 @@
 
 namespace SymTab {
-	/// Mangles names to a unique C identifier
-	class Mangler : public Visitor {
-	  public:
+	namespace Mangler {
 		/// Mangle syntax tree object; primary interface to clients
-		template< typename SynTreeClass >
-	    static std::string mangle( SynTreeClass *decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
+		std::string mangle( BaseSyntaxNode * decl, bool mangleOverridable = true, bool typeMode = false, bool mangleGenericParams = true );
+
 		/// Mangle a type name; secondary interface
-		static std::string mangleType( Type* ty );
+		std::string mangleType( Type* ty );
 		/// Mangle ignoring generic type parameters
-		static std::string mangleConcrete( Type* ty );
-
-
-		virtual void visit( ObjectDecl *declaration );
-		virtual void visit( FunctionDecl *declaration );
-		virtual void visit( TypeDecl *declaration );
-
-		virtual void visit( VoidType *voidType );
-		virtual void visit( BasicType *basicType );
-		virtual void visit( PointerType *pointerType );
-		virtual void visit( ArrayType *arrayType );
-		virtual void visit( ReferenceType *refType );
-		virtual void visit( FunctionType *functionType );
-		virtual void visit( StructInstType *aggregateUseType );
-		virtual void visit( UnionInstType *aggregateUseType );
-		virtual void visit( EnumInstType *aggregateUseType );
-		virtual void visit( TypeInstType *aggregateUseType );
-		virtual void visit( TupleType *tupleType );
-		virtual void visit( VarArgsType *varArgsType );
-		virtual void visit( ZeroType *zeroType );
-		virtual void visit( OneType *oneType );
-
-		std::string get_mangleName() { return mangleName.str(); }
-	  private:
-		std::ostringstream mangleName;  ///< Mangled name being constructed
-		typedef std::map< std::string, std::pair< int, int > > VarMapType;
-		VarMapType varNums;             ///< Map of type variables to indices
-		int nextVarNum;                 ///< Next type variable index
-		bool isTopLevel;                ///< Is the Mangler at the top level
-		bool mangleOverridable;         ///< Specially mangle overridable built-in methods
-		bool typeMode;                  ///< Produce a unique mangled name for a type
-		bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
-
-		Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
-		Mangler( const Mangler & );
-
-		void mangleDecl( DeclarationWithType *declaration );
-		void mangleRef( ReferenceToType *refType, std::string prefix );
-
-		void printQualifiers( Type *type );
-	}; // Mangler
-
-	template< typename SynTreeClass >
-	std::string Mangler::mangle( SynTreeClass *decl, bool mangleOverridable, bool typeMode, bool mangleGenericParams ) {
-		Mangler mangler( mangleOverridable, typeMode, mangleGenericParams );
-		maybeAccept( decl, mangler );
-		return mangler.get_mangleName();
-	}
+		std::string mangleConcrete( Type* ty );
+	} // Mangler
 } // SymTab
 
Index: src/SynTree/CompoundStmt.cc
===================================================================
--- src/SynTree/CompoundStmt.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SynTree/CompoundStmt.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -64,6 +64,5 @@
 	}
 	if ( ! declMap.empty() ) {
-		VarExprReplacer replacer( declMap );
-		accept( replacer );
+		VarExprReplacer::replace( this, declMap );
 	}
 }
Index: src/SynTree/FunctionDecl.cc
===================================================================
--- src/SynTree/FunctionDecl.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SynTree/FunctionDecl.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -49,6 +49,5 @@
 	}
 	if ( ! declMap.empty() ) {
-		VarExprReplacer replacer( declMap );
-		accept( replacer );
+		VarExprReplacer::replace( this, declMap );
 	}
 }
Index: src/SynTree/VarExprReplacer.cc
===================================================================
--- src/SynTree/VarExprReplacer.cc	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SynTree/VarExprReplacer.cc	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -16,18 +16,49 @@
 #include <iostream>       // for operator<<, basic_ostream, ostream, basic_o...
 
+#include "Common/PassVisitor.h"
 #include "Declaration.h"  // for operator<<, DeclarationWithType
 #include "Expression.h"   // for VariableExpr
 #include "VarExprReplacer.h"
 
-VarExprReplacer::VarExprReplacer( const DeclMap & declMap, bool debug ) : declMap( declMap ), debug( debug ) {}
+namespace VarExprReplacer {
+	namespace {
+		/// Visitor that replaces the declarations that VariableExprs refer to, according to the supplied mapping
+		struct VarExprReplacer {
+		private:
+			const DeclMap & declMap;
+			bool debug;
+		public:
+			VarExprReplacer( const DeclMap & declMap, bool debug = false );
 
-// replace variable with new node from decl map
-void VarExprReplacer::visit( VariableExpr * varExpr ) {
-	// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
-	if ( declMap.count( varExpr->get_var() ) ) {
-		if ( debug ) {
-			std::cerr << "replacing variable reference: " << (void*)varExpr->get_var() << " " << varExpr->get_var() << " with " << (void*)declMap.at( varExpr->get_var() ) << " " << declMap.at( varExpr->get_var() ) << std::endl;
+			// replace variable with new node from decl map
+			void previsit( VariableExpr * varExpr );
+		};
+	}
+
+	void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug ) {
+		PassVisitor<VarExprReplacer> replacer( declMap, debug );
+		maybeAccept( node, replacer );
+	}
+
+	namespace {
+		VarExprReplacer::VarExprReplacer( const DeclMap & declMap, bool debug ) : declMap( declMap ), debug( debug ) {}
+
+		// replace variable with new node from decl map
+		void VarExprReplacer::previsit( VariableExpr * varExpr ) {
+			// xxx - assertions and parameters aren't accounted for in this... (i.e. they aren't inserted into the map when it's made, only DeclStmts are)
+			if ( declMap.count( varExpr->var ) ) {
+				if ( debug ) {
+					std::cerr << "replacing variable reference: " << (void*)varExpr->var << " " << varExpr->var << " with " << (void*)declMap.at( varExpr->var ) << " " << declMap.at( varExpr->var ) << std::endl;
+				}
+				varExpr->var = declMap.at( varExpr->var );
+			}
 		}
-		varExpr->set_var( declMap.at( varExpr->get_var() ) );
 	}
-}
+} // namespace VarExprReplacer
+
+
+
+
+
+
+
Index: src/SynTree/VarExprReplacer.h
===================================================================
--- src/SynTree/VarExprReplacer.h	(revision 4bf3b2bad1e7f01cf2d5cf84aa3ab12f7d5271ec)
+++ src/SynTree/VarExprReplacer.h	(revision 891c3e3de8ac39bcaa6e6b31e0c0ea8625ee47bf)
@@ -23,22 +23,9 @@
 class VariableExpr;
 
-/// Visitor that replaces the declarations that VariableExprs refer to, according to the supplied mapping
-class VarExprReplacer : public Visitor {
-public:
+namespace VarExprReplacer {
 	typedef std::map< DeclarationWithType *, DeclarationWithType * > DeclMap;
-private:
-	const DeclMap & declMap;
-	bool debug;
-public:
-	VarExprReplacer( const DeclMap & declMap, bool debug = false );
 
-	// replace variable with new node from decl map
-	virtual void visit( VariableExpr * varExpr );
-
-	static void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug = false ) {
-		VarExprReplacer replacer( declMap, debug );
-		maybeAccept( node, replacer );
-	}
-};
+	void replace( BaseSyntaxNode * node, const DeclMap & declMap, bool debug = false );
+}
 
 // Local Variables: //
