Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision ee7a29fe6f7711f04b7afa158cac15262c000e35)
+++ src/AST/Node.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
@@ -4,128 +4,116 @@
 
 namespace ast {
+class Node {
+public:
+	virtual ~Node() = default;
 
-	class Node {
-	public:
-		virtual ~Node() = default;
+	enum class ref_type {
+		strong,
+		weak
+	};
 
-		enum class ref_type {
-			strong,
-			weak
-		};
+	inline void increment(ref_type ref) const {
+		switch (ref) {
+			case ref_type::strong: strong_ref++; break;
+			case ref_type::weak  : weak_ref  ++; break;
+		}
+	}
 
-		void increment(ref_type ref) {
-			switch (ref) 			{
-				case ref_type::strong: strong_ref++; break;
-				case ref_type::weak  : weak_ref  ++; break;
-			}
+	inline void decrement(ref_type ref) const {
+		switch (ref) {
+			case ref_type::strong: strong_ref--; break;
+			case ref_type::weak  : weak_ref  --; break;
 		}
 
-		void decrement(ref_type ref) {
-			switch (ref) 			{
-				case ref_type::strong: strong_ref--; break;
-				case ref_type::weak  : weak_ref  --; break;
-			}
-
-			if(!strong_ref && !weak_ref) {
-				delete this;
-			}
+		if(!strong_ref && !weak_ref) {
+			delete this;
 		}
-
-		template<typename node_t>
-		friend auto mutate(const node_t * node);
-
-	private:
-		size_t strong_ref = 0;
-		size_t weak_ref = 0;
-	};
-
-	// Mutate a node, non-member function to avoid static type
-	// problems and be able to use auto return
-	template<typename node_t>
-	auto mutate(const node_t * node) {
-		assertf(
-			node->strong_count >= 1,
-			"Error: attempting to mutate a node that appears to have been linked"
-		);
-		if (node->strong_count == 1) {
-			return const_cast<node_t *>(node);
-		}
-
-		assertf(
-			node->weak_count == 0,
-			"Error: mutating node with weak references to it will invalided some references"
-		);
-		return node->clone();
 	}
 
-	// All accept routines should look as follows :
-	// virtual void accept( Visitor &v ) override {
-	// 	return v.visit(this);
-	// }
-	// Using the following wrapper to handle the node type
-	template< typename node_t >
-	auto visit_this( visitor & v, node_t * node ) {
-		ptr<node_t> p;
-		p.node = node;
-		auto r = v.visit(p);
-		p.node = nullptr;
-		return r;
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
+
+private:
+	mutable size_t strong_ref = 0;
+	mutable size_t weak_ref = 0;
+};
+
+// Mutate a node, non-member function to avoid static type
+// problems and be able to use auto return
+template<typename node_t>
+auto mutate(const node_t * node) {
+	assertf(
+		node->strong_count >= 1,
+		"Error: attempting to mutate a node that appears to have been linked"
+	);
+	if (node->strong_count == 1) {
+		return const_cast<node_t *>(node);
 	}
 
-	// Base class for the smart pointer types
-	// should never really be used.
-	template< typename node_t, enum Node::ref_type ref_t>
-	class ptr_base {
-	public:
-		ptr_base() : node(nullptr) {}
-		ptr_base( node_t * n ) : node(n) { if( !node ) node->increment(ref_t); }
-		~ptr_base() { if( node ) node->decrement(ref_t); }
+	assertf(
+		node->weak_count == 0,
+		"Error: mutating node with weak references to it will invalided some references"
+	);
+	return node->clone();
+}
 
-		template< enum  Node::ref_type o_ref_t >
-		ptr_base( const ptr_base<node_t, o_ref_t> & o ) : node(o.node) {
-			if( !node ) return;
-			node->increment(ref_t);
-		}
+// Base class for the smart pointer types
+// should never really be used.
+template< typename node_t, enum Node::ref_type ref_t>
+class ptr_base {
+public:
+	ptr_base() : node(nullptr) {}
+	ptr_base( node_t * n ) : node(n) { if( !node ) node->increment(ref_t); }
+	~ptr_base() { if( node ) node->decrement(ref_t); }
 
-		template< enum  Node::ref_type o_ref_t >
-		ptr_base( ptr_base<node_t, o_ref_t> && o ) : node(o.node) {
-			if( node ) node->increment(ref_t);
-			if( node ) node->decrement(o_ref_t);
-		}
+	template< enum  Node::ref_type o_ref_t >
+	ptr_base( const ptr_base<node_t, o_ref_t> & o ) : node(o.node) {
+		if( !node ) return;
+		node->increment(ref_t);
+	}
 
-		template< enum  Node::ref_type o_ref_t >
-		ptr_base & operator=( const ptr_base<node_t, o_ref_t> & o ) {
-			assign(o.node);
-			return *this;
-		}
+	template< enum  Node::ref_type o_ref_t >
+	ptr_base( ptr_base<node_t, o_ref_t> && o ) : node(o.node) {
+		if( node ) node->increment(ref_t);
+		if( node ) node->decrement(o_ref_t);
+	}
 
-		template< enum  Node::ref_type o_ref_t >
-		ptr_base & operator=( ptr_base<node_t, o_ref_t> && o ) {
-			if(o.node == node) return *this;
-			assign(o.node);
-			if( node ) node->decrement(o_ref_t);
-			return *this;
-		}
+	template< enum  Node::ref_type o_ref_t >
+	ptr_base & operator=( const ptr_base<node_t, o_ref_t> & o ) {
+		assign(o.node);
+		return *this;
+	}
 
-		const node_t * get() const { return  node; }
-		const node_t * operator->() const { return  node; }
-		const node_t & operator* () const { return *node; }
-		operator bool() const { return node; }
+	template< enum  Node::ref_type o_ref_t >
+	ptr_base & operator=( ptr_base<node_t, o_ref_t> && o ) {
+		if(o.node == node) return *this;
+		assign(o.node);
+		if( node ) node->decrement(o_ref_t);
+		return *this;
+	}
 
-	private:
-		void assign(node_t * other ) {
-			if( other ) other->increment(ref_t);
-			if( node  ) node ->decrement(ref_t);
-			node = other;
-		}
+	const node_t * get() const { return  node; }
+	const node_t * operator->() const { return  node; }
+	const node_t & operator* () const { return *node; }
+	explicit operator bool() const { return node; }
+	operator const node_t * const() const { return node; }
 
-	protected:
-		node_t * node;
-	};
+	using ptr = const node_t *;
 
-	template< typename node_t >
-	using ptr = ptr_base< node_t, Node::ref_type::strong >;
+private:
+	void assign(node_t * other ) {
+		if( other ) other->increment(ref_t);
+		if( node  ) node ->decrement(ref_t);
+		node = other;
+	}
 
-	template< typename node_t >
-	using readonly = ptr_base< node_t, Node::ref_type::weak >;
+protected:
+	node_t * node;
+};
+
+template< typename node_t >
+using ptr = ptr_base< node_t, Node::ref_type::strong >;
+
+template< typename node_t >
+using readonly = ptr_base< node_t, Node::ref_type::weak >;
 }
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
+++ src/AST/Pass.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
@@ -0,0 +1,274 @@
+#pragma once
+// IWYU pragma: private, include "Common/PassVisitor.h"
+
+#include <functional>
+#include <list>
+#include <stack>
+
+#include "Fwd.hpp"
+#include "Node.hpp"
+
+// Private prelude header, needed for some of the magic tricks this class pulls off
+#include "Pass.proto.hpp"
+
+namespace ast {
+//-------------------------------------------------------------------------------------------------
+// Templated visitor type
+// To use declare a Pass< YOUR VISITOR TYPE >
+// The visitor type should specify the previsit/postvisit for types that are desired.
+// Note: previsit/postvisit must be **public** members
+//
+// Several additional features are available through inheritance
+// | WithTypeSubstitution - provides polymorphic TypeSubstitution * env for the current expression
+// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
+//                          statement by adding new statements into stmtsToAddBefore or
+//                          stmtsToAddAfter respectively.
+// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
+//                          to false in pre{visit,visit} to skip visiting children
+// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
+//                          call GuardValue with the variable to save, the variable will
+//                          automatically be restored to its previous value after the corresponding
+//                          postvisit/postmutate teminates.
+//-------------------------------------------------------------------------------------------------
+template< typename pass_t >
+class Pass final : public ast::Visitor {
+public:
+	template< typename... Args >
+	Pass( Args &&... args)
+		: m_pass( std::forward<Args>( args )... )
+	{
+		// After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
+		typedef Pass<pass_t> this_t;
+		this_t * const * visitor = __pass::visitor(m_pass, 0);
+		if(visitor) {
+			*const_cast<this_t **>( visitor ) = this;
+		}
+	}
+
+	virtual ~Pass() = default;
+
+	pass_t m_pass;
+
+	virtual DeclWithType *     visit( const ObjectDecl           * ) override final;
+	virtual DeclWithType *     visit( const FunctionDecl         * ) override final;
+	virtual Decl *             visit( const StructDecl           * ) override final;
+	virtual Decl *             visit( const UnionDecl            * ) override final;
+	virtual Decl *             visit( const EnumDecl             * ) override final;
+	virtual Decl *             visit( const TraitDecl            * ) override final;
+	virtual Decl *             visit( const TypeDecl             * ) override final;
+	virtual Decl *             visit( const TypedefDecl          * ) override final;
+	virtual AsmDecl *          visit( const AsmDecl              * ) override final;
+	virtual StaticAssertDecl * visit( const StaticAssertDecl     * ) override final;
+	virtual CompoundStmt *     visit( const CompoundStmt         * ) override final;
+	virtual Stmt *             visit( const ExprStmt             * ) override final;
+	virtual Stmt *             visit( const AsmStmt              * ) override final;
+	virtual Stmt *             visit( const DirectiveStmt        * ) override final;
+	virtual Stmt *             visit( const IfStmt               * ) override final;
+	virtual Stmt *             visit( const WhileStmt            * ) override final;
+	virtual Stmt *             visit( const ForStmt              * ) override final;
+	virtual Stmt *             visit( const SwitchStmt           * ) override final;
+	virtual Stmt *             visit( const CaseStmt             * ) override final;
+	virtual Stmt *             visit( const BranchStmt           * ) override final;
+	virtual Stmt *             visit( const ReturnStmt           * ) override final;
+	virtual Stmt *             visit( const ThrowStmt            * ) override final;
+	virtual Stmt *             visit( const TryStmt              * ) override final;
+	virtual Stmt *             visit( const CatchStmt            * ) override final;
+	virtual Stmt *             visit( const FinallyStmt          * ) override final;
+	virtual Stmt *             visit( const WaitForStmt          * ) override final;
+	virtual Stmt *             visit( const WithStmt             * ) override final;
+	virtual NullStmt *         visit( const NullStmt             * ) override final;
+	virtual Stmt *             visit( const DeclStmt             * ) override final;
+	virtual Stmt *             visit( const ImplicitCtorDtorStmt * ) override final;
+	virtual Expr *             visit( const ApplicationExpr      * ) override final;
+	virtual Expr *             visit( const UntypedExpr          * ) override final;
+	virtual Expr *             visit( const NameExpr             * ) override final;
+	virtual Expr *             visit( const AddressExpr          * ) override final;
+	virtual Expr *             visit( const LabelAddressExpr     * ) override final;
+	virtual Expr *             visit( const CastExpr             * ) override final;
+	virtual Expr *             visit( const KeywordCastExpr      * ) override final;
+	virtual Expr *             visit( const VirtualCastExpr      * ) override final;
+	virtual Expr *             visit( const UntypedMemberExpr    * ) override final;
+	virtual Expr *             visit( const MemberExpr           * ) override final;
+	virtual Expr *             visit( const VariableExpr         * ) override final;
+	virtual Expr *             visit( const ConstantExpr         * ) override final;
+	virtual Expr *             visit( const SizeofExpr           * ) override final;
+	virtual Expr *             visit( const AlignofExpr          * ) override final;
+	virtual Expr *             visit( const UntypedOffsetofExpr  * ) override final;
+	virtual Expr *             visit( const OffsetofExpr         * ) override final;
+	virtual Expr *             visit( const OffsetPackExpr       * ) override final;
+	virtual Expr *             visit( const AttrExpr             * ) override final;
+	virtual Expr *             visit( const LogicalExpr          * ) override final;
+	virtual Expr *             visit( const ConditionalExpr      * ) override final;
+	virtual Expr *             visit( const CommaExpr            * ) override final;
+	virtual Expr *             visit( const TypeExpr             * ) override final;
+	virtual Expr *             visit( const AsmExpr              * ) override final;
+	virtual Expr *             visit( const ImplicitCopyCtorExpr * ) override final;
+	virtual Expr *             visit( const ConstructorExpr      * ) override final;
+	virtual Expr *             visit( const CompoundLiteralExpr  * ) override final;
+	virtual Expr *             visit( const RangeExpr            * ) override final;
+	virtual Expr *             visit( const UntypedTupleExpr     * ) override final;
+	virtual Expr *             visit( const TupleExpr            * ) override final;
+	virtual Expr *             visit( const TupleIndexExpr       * ) override final;
+	virtual Expr *             visit( const TupleAssignExpr      * ) override final;
+	virtual Expr *             visit( const StmtExpr             * ) override final;
+	virtual Expr *             visit( const UniqueExpr           * ) override final;
+	virtual Expr *             visit( const UntypedInitExpr      * ) override final;
+	virtual Expr *             visit( const InitExpr             * ) override final;
+	virtual Expr *             visit( const DeletedExpr          * ) override final;
+	virtual Expr *             visit( const DefaultArgExpr       * ) override final;
+	virtual Expr *             visit( const GenericExpr          * ) override final;
+	virtual Type *             visit( const VoidType             * ) override final;
+	virtual Type *             visit( const BasicType            * ) override final;
+	virtual Type *             visit( const PointerType          * ) override final;
+	virtual Type *             visit( const ArrayType            * ) override final;
+	virtual Type *             visit( const ReferenceType        * ) override final;
+	virtual Type *             visit( const QualifiedType        * ) override final;
+	virtual Type *             visit( const FunctionType         * ) override final;
+	virtual Type *             visit( const StructInstType       * ) override final;
+	virtual Type *             visit( const UnionInstType        * ) override final;
+	virtual Type *             visit( const EnumInstType         * ) override final;
+	virtual Type *             visit( const TraitInstType        * ) override final;
+	virtual Type *             visit( const TypeInstType         * ) override final;
+	virtual Type *             visit( const TupleType            * ) override final;
+	virtual Type *             visit( const TypeofType           * ) override final;
+	virtual Type *             visit( const AttrType             * ) override final;
+	virtual Type *             visit( const VarArgsType          * ) override final;
+	virtual Type *             visit( const ZeroType             * ) override final;
+	virtual Type *             visit( const OneType              * ) override final;
+	virtual Type *             visit( const GlobalScopeType      * ) override final;
+	virtual Designation *      visit( const Designation          * ) override final;
+	virtual Init *             visit( const SingleInit           * ) override final;
+	virtual Init *             visit( const ListInit             * ) override final;
+	virtual Init *             visit( const ConstructorInit      * ) override final;
+	virtual Constant *         visit( const Constant             * ) override final;
+	virtual Attribute *        visit( const Attribute            * ) override final;
+	virtual TypeSubstitution * visit( const TypeSubstitution     * ) override final;
+
+private:
+
+	bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(m_pass, 0); return ptr ? *ptr : true; }
+
+private:
+	template<typename parent_t, typename child_t>
+	void maybe_accept(parent_t * & , typename parent_t::child_t *);
+
+	ast::Statement  * call_accept( const ast::Statement  * );
+	ast::Expression * call_accept( const ast::Expression * );
+
+	template< template <class> class container_t >
+	container_t< ast::ptr<ast::Statement> > call_accept( const container_t< ast::ptr<ast::Statement> > & );
+
+	template< template <class> class container_t, typename node_t >
+	container_t< ast::ptr<node_t> > call_accept( const container_t< ast::ptr<node_t> > & container );
+
+private:
+	struct indexer_guard {
+		Pass<pass_t> & pass;
+
+		indexer_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::indexer::enter(pass, 0); }
+		~indexer_guard()                                    { __pass::indexer::leave(pass, 0); }
+	};
+
+	indexer_guard make_indexer_guard() { return { *this }; }
+
+private:
+	struct scope_guard {
+		Pass<pass_t> & pass;
+
+		scope_guard( Pass<pass_t> & pass ) : pass( pass ) { __pass::scope::enter(pass, 0); }
+		~scope_guard()                                    { __pass::scope::leave(pass, 0); }
+	};
+
+	scope_guard make_scope_guard() { return { *this }; }
+};
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// Guard value : RAII type to restore a value when the Pass finishes visiting this node
+template<typename pass_t, typename T>
+void GuardValue( pass_t * pass, T& val ) {
+	pass->at_cleanup( [ val ]( void * newVal ) {
+		* static_cast< T * >( newVal ) = val;
+	}, static_cast< void * >( & val ) );
+}
+
+//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+// PASS ACCESSORIES
+//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+// Keep track of the type substitution
+struct WithConstTypeSubstitution {
+	const ast::TypeSubstitution * env = nullptr;
+};
+
+template<typename T>
+using std_list = std::list<T>;
+
+// Used if visitor requires added statements before or after the current node.
+// The Pass template handles what *before* and *after* means automatically
+template< template<class> class container_t = std_list >
+struct WithStmtsToAdd {
+	container_t< ast::ptr< ast::Statement > > stmtsToAddBefore;
+	container_t< ast::ptr< ast::Statement > > stmtsToAddAfter;
+};
+
+// Used if visitor requires added declarations before or after the current node.
+// The Pass template handles what *before* and *after* means automatically
+template< template<class> class container_t = std_list >
+struct WithDeclsToAdd {
+	~WithDeclsToAdd() {
+		assert( declsToAddBefore.empty() );
+	}
+
+	container_t< ast::ptr< ast::Declaration > > declsToAddBefore;
+	container_t< ast::ptr< ast::Declaration > > declsToAddAfter;
+};
+
+// Use if visitation should stop at certain levels
+// set visit_children false of all child nodes should be ignored
+struct WithShortCircuiting {
+	__pass::bool_ref visit_children;
+};
+
+// class WithGuards {
+// protected:
+// 	WithGuards() = default;
+// 	~WithGuards() = default;
+
+// public:
+// 	at_cleanup_t at_cleanup;
+
+// 	template< typename T >
+// 	void GuardValue( T& val ) {
+// 		at_cleanup( [ val ]( void * newVal ) {
+// 			* static_cast< T * >( newVal ) = val;
+// 		}, static_cast< void * >( & val ) );
+// 	}
+
+// 	template< typename T >
+// 	void GuardScope( T& val ) {
+// 		val.beginScope();
+// 		at_cleanup( []( void * val ) {
+// 			static_cast< T * >( val )->endScope();
+// 		}, static_cast< void * >( & val ) );
+// 	}
+
+// 	template< typename Func >
+// 	void GuardAction( Func func ) {
+// 		at_cleanup( [func](__attribute__((unused)) void *) { func(); }, nullptr );
+// 	}
+// };
+
+// template<typename pass_type>
+// class WithVisitorRef {
+// protected:
+// 	WithVisitorRef() {}
+// 	~WithVisitorRef() {}
+
+// public:
+// 	PassVisitor<pass_type> * const visitor = nullptr;
+// };
+
+struct WithIndexer {
+	SymTab::Indexer indexer;
+};
+}
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
+++ src/AST/Pass.impl.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
@@ -0,0 +1,342 @@
+#pragma once
+// IWYU pragma: private, include "Pass.hpp"
+
+#define VISIT_START( node ) \
+	/* back-up the visit children */ \
+	__attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(m_pass, 0) ); \
+	/* setup the scope for passes that want to run code at exit */ \
+	__attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (m_pass, 0) ); \
+	/* call the implementation of the previsit of this pass */ \
+	__pass::previsit( m_pass, node, 0 );
+
+#define VISIT( code ) \
+	/* if this node should visit its children */ \
+	if ( __visit_children() ) { \
+		/* visit the children */ \
+		code \
+	}
+
+#define VISIT_END( type, node ) \
+	/* call the implementation of the postvisit of this pass */ \
+	auto __return = __pass::postvisit< type * >( node ); \
+	assertf(__return, "post visit should never return null"); \
+	return __return;
+
+#ifdef PEDANTIC_PASS_ASSERT
+#define __pedantic_pass_assert (...) assert (__VAR_ARGS__)
+#define __pedantic_pass_assertf(...) assertf(__VAR_ARGS__)
+#else
+#define __pedantic_pass_assert (...)
+#define __pedantic_pass_assertf(...)
+#endif
+
+namespace ast {
+	namespace __pass {
+		// Check if this is either a null pointer or a pointer to an empty container
+		template<typename T>
+		static inline bool empty( T * ptr ) {
+			return !ptr || ptr->empty();
+		}
+
+		template<typename it_t, template <class> class container_t>
+		static inline void take_all( it_t it, container_t<ast::ptr<ast::Declaration>> * decls, bool * mutated = nullptr ) {
+			if(empty(decls)) return;
+
+			std::transform(decls->begin(), decls->end(), it, [](Declaration * decl) -> auto {
+					return new DeclStmt( decl );
+				});
+			decls->clear();
+			if(mutated) *mutated = true;
+		}
+
+		template<typename it_t, template <class> class container_t>
+		static inline void take_all( it_t it, container_t<ast::ptr<ast::Statement>> * decls, bool * mutated = nullptr ) {
+			if(empty(decls)) return;
+
+			std::move(decls->begin(), decls->end(), it);
+			decls->clear();
+			if(mutated) *mutated = true;
+		}
+
+		template<typename node_t>
+		bool differs( const node_t * old_val, const node_t * new_val ) {
+			return old_val != new_val;
+		}
+
+		template< template <class> class container_t >
+		bool differs( const container_t<ast::ptr< ast::Statement >> &, const container_t<ast::ptr< ast::Statement >> & new_val ) {
+			return !new_val.empty();
+		}
+	}
+
+	template<typename parent_t, typename child_t>
+	template< typename pass_t >
+	void Pass< pass_t >::maybe_accept(
+		const parent_t * & parent,
+		const typename parent_t::child_t * child
+	) {
+		const auto & old_val = parent->*child;
+		if(!old_val) return;
+
+		auto new_val = call_accept(old_val);
+
+		if( __pass::differs(old_val, new_val) ) {
+			auto new_parent = mutate(parent);
+			new_parent->*child = new_val;
+			parent = new_parent;
+		}
+	}
+
+	template< typename pass_t >
+	template< typename node_t >
+	auto Pass< pass_t >::call_accept( const node_t * node ) {
+		__pedantic_pass_assert( __visit_children() );
+		__pedantic_pass_assert( expr );
+
+		return node->accept( *this );
+	}
+
+	template< typename pass_t >
+	ast::Expression * Pass< pass_t >::call_accept( const ast::Expression * expr ) {
+		__pedantic_pass_assert( __visit_children() );
+		__pedantic_pass_assert( expr );
+
+		const ast::TypeSubstitution ** env_ptr = __pass::env( m_pass, 0);
+		if ( env_ptr && expr->env ) {
+			*env_ptr = expr->env;
+		}
+
+		return expr->accept( *this );
+	}
+
+	template< typename pass_t >
+	ast::Statement * Pass< pass_t >::call_accept( const ast::Statement * stmt ) {
+		__pedantic_pass_assert( __visit_children() );
+		__pedantic_pass_assert( stmt );
+
+		// add a few useful symbols to the scope
+		using __pass::empty;
+		using decls_t = typename std::remove_pointer< decltype(__decls_before()) >::type;
+		using stmts_t = typename std::remove_pointer< decltype(__stmts_before()) >::type;
+
+		// get the stmts/decls that will need to be spliced in
+		auto stmts_before = __pass::stmtsToAddBefore( m_pass, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( m_pass, 0);
+		auto decls_before = __pass::declsToAddBefore( m_pass, 0);
+		auto decls_after  = __pass::declsToAddAfter ( m_pass, 0);
+
+		// These may be modified by subnode but most be restored once we exit this statemnet.
+		ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( m_pass, 0);  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
+
+		// Now is the time to actually visit the node
+		ast::Statement * nstmt = stmt->accept( *this );
+
+		// If the pass doesn't want to add anything then we are done
+		if( empty(stmts_before) && empty(stmts_after) && empty(decls_before) && empty(decls_after) ) {
+			return nstmt;
+		}
+
+		// Make sure that it is either adding statements or declartions but not both
+		// this is because otherwise the order would be awkward to predict
+		assert(( empty( stmts_before ) && empty( stmts_after ))
+		    || ( empty( decls_before ) && empty( decls_after )) );
+
+		// Create a new Compound Statement to hold the new decls/stmts
+		ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
+
+		// Take all the declarations that go before
+		__pass::take_all( std::back_inserter( compound->kids ), decls_before );
+		__pass::take_all( std::back_inserter( compound->kids ), stmts_before );
+
+		// Insert the original declaration
+		compound->kids.push_back( nstmt );
+
+		// Insert all the declarations that go before
+		__pass::take_all( std::back_inserter( compound->kids ), decls_after );
+		__pass::take_all( std::back_inserter( compound->kids ), stmts_after );
+
+		return compound;
+	}
+
+	template< typename pass_t >
+	template< template <class> class container_t >
+	container_t< ast::ptr<ast::Statement> > Pass< pass_t >::call_accept( const container_t< ast::ptr<ast::Statement> > & statements ) {
+		__pedantic_pass_assert( __visit_children() );
+		if( statements.empty() ) return {};
+
+		// We are going to aggregate errors for all these statements
+		SemanticErrorException errors;
+
+		// add a few useful symbols to the scope
+		using __pass::empty;
+
+		// get the stmts/decls that will need to be spliced in
+		auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
+		auto decls_before = __pass::declsToAddBefore( pass, 0);
+		auto decls_after  = __pass::declsToAddAfter ( pass, 0);
+
+		// These may be modified by subnode but most be restored once we exit this statemnet.
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) > __old_decls_before( stmts_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) > __old_decls_after ( stmts_after  );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_before) > __old_stmts_before( decls_before );
+		ValueGuardPtr< typename std::remove_pointer< decltype(decls_after ) > __old_stmts_after ( decls_after  );
+
+		// update pass statitistics
+		pass_visitor_stats.depth++;
+		pass_visitor_stats.max->push(pass_visitor_stats.depth);
+		pass_visitor_stats.avg->push(pass_visitor_stats.depth);
+
+		bool mutated = false;
+		container_t<ast::ptr< ast::Statement >> new_kids;
+		for( const ast::Statement * stmt : statements ) {
+			try {
+				__pedantic_pass_assert( stmt );
+				const ast::Statment * new_stmt = stmt->accept( visitor );
+				assert( new_stmt );
+				if(new_stmt != stmt ) mutated = true;
+
+				// Make sure that it is either adding statements or declartions but not both
+				// this is because otherwise the order would be awkward to predict
+				assert(( empty( stmts_before ) && empty( stmts_after ))
+				    || ( empty( decls_before ) && empty( decls_after )) );
+
+
+
+				// Take all the statements which should have gone after, N/A for first iteration
+				__pass::take_all( std::back_inserter( new_kids ), decls_before, &mutated );
+				__pass::take_all( std::back_inserter( new_kids ), stmts_before, &mutated );
+
+				// Now add the statement if there is one
+				new_kids.emplace_back( new_stmt );
+
+				// Take all the declarations that go before
+				__pass::take_all( std::back_inserter( new_kids ), decls_after, &mutated );
+				__pass::take_all( std::back_inserter( new_kids ), stmts_after, &mutated );
+			}
+			catch ( SemanticErrorException &e ) {
+				errors.append( e );
+			}
+		}
+		pass_visitor_stats.depth--;
+		if ( !errors.isEmpty() ) { throw errors; }
+
+		return mutated ? new_kids : {};
+	}
+
+	template< typename pass_t >
+	template< template <class> class container_t, typename node_t >
+	container_t< ast::ptr<node_t> > Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
+		__pedantic_pass_assert( __visit_children() );
+		if( container.empty() ) return {};
+		SemanticErrorException errors;
+
+		pass_visitor_stats.depth++;
+		pass_visitor_stats.max->push(pass_visitor_stats.depth);
+		pass_visitor_stats.avg->push(pass_visitor_stats.depth);
+
+		bool mutated = false;
+		container_t< ast::ptr<node_t> > new_kids;
+		for ( const node_t * node : container ) {
+			try {
+				__pedantic_pass_assert( node );
+				const node_t * new_node = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
+				if(new_stmt != stmt ) mutated = true;
+
+				new_kids.emplace_back( new_stmt );
+			}
+			catch( SemanticErrorException &e ) {
+				errors.append( e );
+			}
+		}
+		pass_visitor_stats.depth--;
+		if ( ! errors.isEmpty() ) { throw errors; }
+
+		return mutated ? new_kids : {};
+	}
+}
+
+//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+//========================================================================================================================================================================
+//========================================================================================================================================================================
+//========================================================================================================================================================================
+//========================================================================================================================================================================
+//========================================================================================================================================================================
+//------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+
+// A NOTE ON THE ORDER OF TRAVERSAL
+//
+// Types and typedefs have their base types visited before they are added to the type table.  This is ok, since there is
+// no such thing as a recursive type or typedef.
+//
+//             typedef struct { T *x; } T; // never allowed
+//
+// for structs/unions, it is possible to have recursion, so the decl should be added as if it's incomplete to begin, the
+// members are traversed, and then the complete type should be added (assuming the type is completed by this particular
+// declaration).
+//
+//             struct T { struct T *x; }; // allowed
+//
+// It is important to add the complete type to the symbol table *after* the members/base has been traversed, since that
+// traversal may modify the definition of the type and these modifications should be visible when the symbol table is
+// queried later in this pass.
+
+//--------------------------------------------------------------------------
+// ObjectDecl
+template< typename pass_t >
+ast::DeclarationWithType * Pass< pass_t >::mutate( ast::ObjectDecl * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		{
+			auto guard = make_indexer_guard();
+			maybe_accept( node, ast::ObjectDecl::type );
+		}
+		maybe_accept( node, ast::ObjectDecl::init          );
+		maybe_accept( node, ast::ObjectDecl::bitfieldWidth );
+		maybe_accept( node, ast::ObjectDecl::attributes    );
+	)
+
+	__pass::indexer::AddId( m_pass, 0, node );
+
+	VISIT_END( DeclarationWithType, node );
+}
+
+//--------------------------------------------------------------------------
+// Attribute
+template< typename pass_type >
+ast::Attribute * ast::Pass< pass_type >::visit( ast::ptr<ast::Attribute> & node  )  {
+	VISIT_START(node);
+
+	VISIT(
+		maybe_accept( node, ast::Attribute::parameters );
+	)
+
+	VISIT_END(ast::Attribute *, node );
+}
+
+//--------------------------------------------------------------------------
+// TypeSubstitution
+template< typename pass_type >
+TypeSubstitution * PassVisitor< pass_type >::mutate( TypeSubstitution * node ) {
+	MUTATE_START( node );
+
+	#error this is broken
+
+	for ( auto & p : node->typeEnv ) {
+		indexerScopedMutate( p.second, *this );
+	}
+	for ( auto & p : node->varEnv ) {
+		indexerScopedMutate( p.second, *this );
+	}
+
+	MUTATE_END( TypeSubstitution, node );
+}
+
+#undef VISIT_START
+#undef VISIT
+#undef VISIT_END
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
+++ src/AST/Pass.proto.hpp	(revision f47f8876561ac211c0d7f0c72e79060c8ab30298)
@@ -0,0 +1,274 @@
+#pragma once
+// IWYU pragma: private, include "Pass.hpp"
+
+namespace ast {
+	template<typename pass_type>
+	class Pass;
+
+	namespace __pass {
+		typedef std::function<void( void * )> cleanup_func_t;
+		typedef std::function<void( cleanup_func_t, void * )> at_cleanup_t;
+
+
+		// boolean reference that may be null
+		// either refers to a boolean value or is null and returns true
+		class bool_ref {
+		public:
+			bool_ref() = default;
+			~bool_ref() = default;
+
+			operator bool() { return m_ref ? *m_ref : true; }
+			bool operator=( bool val ) { assert(m_ref); return *m_ref = val; }
+
+		private:
+
+			friend class visit_children_guard;
+
+			bool * set( bool * val ) {
+				bool * prev = m_ref;
+				m_ref = val;
+				return prev;
+			}
+
+			bool * m_ref = nullptr;
+		};
+
+		// Implementation of the guard value
+		// Created inside the visit scope
+		class guard_value {
+		public:
+			guard_value( at_cleanup_t * at_cleanup ) {
+				if( at_cleanup ) {
+					*at_cleanup = [this]( cleanup_func_t && func, void* val ) {
+						push( std::move( func ), val );
+					};
+				}
+			}
+
+			~guard_value() {
+				while( !cleanups.empty() ) {
+					auto& cleanup = cleanups.top();
+					cleanup.func( cleanup.val );
+					cleanups.pop();
+				}
+			}
+
+			void push( cleanup_func_t && func, void* val ) {
+				cleanups.emplace( std::move(func), val );
+			}
+
+		private:
+			struct cleanup_t {
+				cleanup_func_t func;
+				void * val;
+
+				cleanup_t( cleanup_func_t&& func, void * val ) : func(func), val(val) {}
+			};
+
+			std::stack< cleanup_t > cleanups;
+		};
+
+		// Guard structure implementation for whether or not children should be visited
+		class visit_children_guard {
+		public:
+
+			visit_children_guard( bool_ref * ref )
+				: m_val ( true )
+				, m_prev( ref ? ref->set( &m_val ) : nullptr )
+				, m_ref ( ref )
+			{}
+
+			~visit_children_guard() {
+				if( m_ref ) {
+					m_ref->set( m_prev );
+				}
+			}
+
+			operator bool() { return m_val; }
+
+		private:
+			bool       m_val;
+			bool     * m_prev;
+			bool_ref * m_ref;
+		};
+
+		//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+		// Deep magic (a.k.a template meta programming) to make the templated visitor work
+		// Basically the goal is to make 2 previsit
+		// 1 - Use when a pass implements a valid previsit. This uses overloading which means the any overload of
+		//     'pass.previsit( node )' that compiles will be used for that node for that type
+		//     This requires that this option only compile for passes that actually define an appropriate visit.
+		//     SFINAE will make sure the compilation errors in this function don't halt the build.
+		//     See http://en.cppreference.com/w/cpp/language/sfinae for details on SFINAE
+		// 2 - Since the first implementation might not be specilizable, the second implementation exists and does nothing.
+		//     This is needed only to eliminate the need for passes to specify any kind of handlers.
+		//     The second implementation only works because it has a lower priority. This is due to the bogus last parameter.
+		//     The second implementation takes a long while the first takes an int. Since the caller always passes an literal 0
+		//     the first implementation takes priority in regards to overloading.
+		//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+		// PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
+		template<typename pass_t, typename node_t>
+		static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
+			node = pass.previsit( node );
+			assert(node);
+		}
+
+		template<typename pass_t, typename node_t>
+		static inline auto previsit( pass_t &, const node_t *, long ) {}
+
+		// PostVisit : never mutates the passed pointer but may return a different node
+		template<typename pass_t, typename node_t>
+		static inline auto postvisit( pass_t & pass, const node_t * node, int ) -> decltype( pass.postvisit( node ), (const node_t *)nullptr ) {
+			return pass.postvisit( node );
+		}
+
+		template<typename pass_t, typename node_t>
+		static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
+
+		//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+		// Deep magic (a.k.a template meta programming) continued
+		// To make the templated visitor be more expressive, we allow 'accessories' : classes/structs the implementation can inherit
+		// from in order to get extra functionallity for example
+		// class ErrorChecker : WithShortCircuiting { ... };
+		// Pass<ErrorChecker> checker;
+		// this would define a pass that uses the templated visitor with the additionnal feature that it has short circuiting
+		// Note that in all cases the accessories are not required but guarantee the requirements of the feature is matched
+		//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+		// For several accessories, the feature is enabled by detecting that a specific field is present
+		// Use a macro the encapsulate the logic of detecting a particular field
+		// The type is not strictly enforced but does match the accessory
+		#define FIELD_PTR( name, default_type ) \
+		template< typename pass_t > \
+		static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
+		\
+		template< typename pass_t > \
+		static inline default_type * name( pass_t &, long ) { return nullptr; }
+
+		// List of fields and their expected types
+		FIELD_PTR( env, const ast::TypeSubstitution )
+		FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
+		FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
+		FIELD_PTR( declsToAddBefore, std::list< ast::ptr< ast::Decl > > )
+		FIELD_PTR( declsToAddAfter , std::list< ast::ptr< ast::Decl > > )
+		FIELD_PTR( visit_children, __pass::bool_ref )
+		FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
+		FIELD_PTR( visitor, ast::Pass<pass_t> * const )
+
+		// Remove the macro to make sure we don't clash
+		#undef FIELD_PTR
+
+		// Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
+		// All passes which have such functions are assumed desire this behaviour
+		// detect it using the same strategy
+		namespace scope {
+			template<typename pass_t>
+			static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
+				pass.beginScope();
+			}
+
+			template<typename pass_t>
+			static inline void enter( pass_t &, long ) {}
+
+			template<typename pass_t>
+			static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
+				pass.endScope();
+			}
+
+			template<typename pass_t>
+			static inline void leave( pass_t &, long ) {}
+		};
+
+		// Finally certain pass desire an up to date indexer automatically
+		// detect the presence of a member name indexer and call all the members appropriately
+		namespace indexer {
+			// Some simple scoping rules
+			template<typename pass_t>
+			static inline auto enter( pass_t & pass, int ) -> decltype( pass.indexer.enterScope(), void() ) {
+				pass.indexer.enterScope();
+			}
+
+			template<typename pass_t>
+			static inline auto enter( pass_t &, long ) {}
+
+			template<typename pass_t>
+			static inline auto leave( pass_t & pass, int ) -> decltype( pass.indexer.leaveScope(), void() ) {
+				pass.indexer.leaveScope();
+			}
+
+			template<typename pass_t>
+			static inline auto leave( pass_t &, long ) {}
+
+			// The indexer has 2 kind of functions mostly, 1 argument and 2 arguments
+			// Create macro to condense these common patterns
+			#define INDEXER_FUNC1( func, type ) \
+			template<typename pass_t> \
+			static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.indexer.func( arg ), void() ) {\
+				pass.indexer.func( arg ); \
+			} \
+			\
+			template<typename pass_t> \
+			static inline void func( pass_t &, long, type ) {}
+
+			#define INDEXER_FUNC2( func, type1, type2 ) \
+			template<typename pass_t> \
+			static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.indexer.func( arg1, arg2 ), void () ) {\
+				pass.indexer.func( arg1, arg2 ); \
+			} \
+			 \
+			template<typename pass_t> \
+			static inline void func( pass_t &, long, type1, type2 ) {}
+
+			INDEXER_FUNC1( addId     , DeclarationWithType *       );
+			INDEXER_FUNC1( addType   , NamedTypeDecl *             );
+			INDEXER_FUNC1( addStruct , StructDecl *                );
+			INDEXER_FUNC1( addEnum   , EnumDecl *                  );
+			INDEXER_FUNC1( addUnion  , UnionDecl *                 );
+			INDEXER_FUNC1( addTrait  , TraitDecl *                 );
+			INDEXER_FUNC2( addWith   , std::list< Expression * > &, BaseSyntaxNode * );
+
+			// A few extra functions have more complicated behaviour, they are hand written
+			template<typename pass_t>
+			static inline auto addStructFwd( pass_t & pass, int, ast::StructDecl * decl ) -> decltype( pass.indexer.addStruct( decl ), void() ) {
+				ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
+				fwd->parameters = decl->parameters;
+				pass.indexer.addStruct( fwd );
+			}
+
+			template<typename pass_t>
+			static inline void addStructFwd( pass_t &, long, ast::StructDecl * ) {}
+
+			template<typename pass_t>
+			static inline auto addUnionFwd( pass_t & pass, int, ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
+				UnionDecl * fwd = new UnionDecl( decl->name );
+				fwd->parameters = decl->parameters;
+				pass.indexer.addUnion( fwd );
+			}
+
+			template<typename pass_t>
+			static inline void addUnionFwd( pass_t &, long, ast::UnionDecl * ) {}
+
+			template<typename pass_t>
+			static inline auto addStruct( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addStruct( str ), void() ) {
+				if ( ! pass.indexer.lookupStruct( str ) ) {
+					pass.indexer.addStruct( str );
+				}
+			}
+
+			template<typename pass_t>
+			static inline void addStruct( pass_t &, long, const std::string & ) {}
+
+			template<typename pass_t>
+			static inline auto addUnion( pass_t & pass, int, const std::string & str ) -> decltype( pass.indexer.addUnion( str ), void() ) {
+				if ( ! pass.indexer.lookupUnion( str ) ) {
+					pass.indexer.addUnion( str );
+				}
+			}
+
+			template<typename pass_t>
+			static inline void addUnion( pass_t &, long, const std::string & ) {}
+
+			#undef INDEXER_FUNC1
+			#undef INDEXER_FUNC2
+		};
+	};
+};
