Index: src/AST/Attribute.hpp
===================================================================
--- src/AST/Attribute.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Attribute.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -19,4 +19,5 @@
 #include <vector>
 
+#include "Fwd.hpp"
 #include "Node.hpp"     // for ptr
 #include "Visitor.hpp"
@@ -31,6 +32,7 @@
 	std::vector<ptr<Expr>> parameters;
 
-	Attribute( const std::string& name = "", std::vector<ptr<Expr>>&& params = {})
+	Attribute( const std::string & name = "", std::vector<ptr<Expr>> && params = {})
 	: name( name ), parameters( params ) {}
+	virtual ~Attribute() = default;
 
 	bool empty() const { return name.empty(); }
@@ -42,7 +44,11 @@
 	bool isValidOnFuncParam() const;
 
-	Attribute* accept( Visitor& v ) override { return v.visit( this ); }
+	const Attribute * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	Attribute* clone() const override { return new Attribute{ *this }; }
+	Attribute * clone() const override { return new Attribute{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
+++ src/AST/Convert.cpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -0,0 +1,612 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Convert.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu May 09 15::37::05 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Convert.hpp"
+
+#include "AST/Pass.hpp"
+
+#include "AST/Attribute.hpp"
+#include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Init.hpp"
+#include "AST/Stmt.hpp"
+
+
+#include "SynTree/Attribute.h"
+#include "SynTree/Declaration.h"
+
+//================================================================================================
+// Utilities
+template<template <class...> class C>
+struct to {
+	template<typename T>
+	static auto from( T && v ) -> C< typename T::value_type > {
+		C< typename T::value_type > l;
+		std::move(std::begin(v), std::end(v), std::back_inserter(l));
+		return l;
+	}
+};
+
+//================================================================================================
+class ConverterNewToOld {
+public:
+	std::list< Declaration * > translationUnit;
+};
+
+std::list< Declaration * > convert( std::list< ast::ptr< ast::Decl > > & translationUnit ) {
+	ast::Pass<ConverterNewToOld> converter;
+	ast::accept_all(translationUnit, converter);
+	return converter.pass.translationUnit;
+}
+
+//================================================================================================
+
+#define ACCEPT_1(name, child, type) \
+	old->child->accept(*this); \
+	auto name = strict_dynamic_cast< ast::type * >( node );
+
+#define ACCEPT_N(name, child, type) \
+	std::vector< ast::ptr<ast::type> > name; \
+	name.reserve( old->child.size() ); \
+	for( auto a : old->child ) { \
+		a->accept( *this ); \
+		name.emplace_back( strict_dynamic_cast< ast::type * >(node) ); \
+	}
+
+class ConverterOldToNew : public Visitor {
+public:
+	ast::Decl * decl() {
+		return strict_dynamic_cast< ast::Decl * >( node );
+	}
+private:
+	ast::Node * node;
+
+	template<template <class...> class C>
+	C<ast::Label> make_labels(C<Label> olds) {
+		C<ast::Label> ret;
+		for(auto oldn : olds) {
+			auto old = &oldn; // to reuse the MACRO
+			ACCEPT_N(attr, attributes, Attribute)
+			ast::Label l(
+				{},
+				old->get_name(),
+				to<std::vector>::from( std::move( attr ) )
+			);
+			ret.push_back( l );
+		}
+		return ret;
+	}
+
+	virtual void visit( ObjectDecl * old ) override final {
+		ACCEPT_1(type, type, Type)
+		ACCEPT_1(init, init, Init)
+		ACCEPT_1(bitWd, bitfieldWidth, Expr)
+		ACCEPT_N(attr, attributes, Attribute)
+
+		auto decl = new ast::ObjectDecl(
+			old->location,
+			old->name,
+			type,
+			init,
+			{ old->get_storageClasses().val },
+			{ old->linkage.val },
+			bitWd,
+			std::move( attr ),
+			{ old->get_funcSpec().val }
+		);
+		decl->scopeLevel = old->scopeLevel;
+		decl->mangleName = old->mangleName;
+		decl->isDeleted  = old->isDeleted;
+		decl->uniqueId   = old->uniqueId;
+		decl->extension  = old->extension;
+
+		this->node = decl;
+	}
+
+	virtual void visit( FunctionDecl * ) override final {
+
+	}
+
+	virtual void visit( StructDecl * old ) override final {
+		ACCEPT_N(members, members, Decl)
+		ACCEPT_N(params, parameters, TypeDecl)
+		ACCEPT_1(parent, parent, AggregateDecl)
+		ACCEPT_N(attr, attributes, Attribute)
+
+		auto decl = new ast::StructDecl(
+			old->location,
+			old->name,
+			old->kind,
+			std::move( attr ),
+			{ old->linkage.val }
+		);
+		decl->parent = parent;
+		decl->body   = old->body;
+		decl->parameters = params;
+		decl->members    = members;
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( UnionDecl * old ) override final {
+		ACCEPT_N(members, members, Decl)
+		ACCEPT_N(params, parameters, TypeDecl)
+		ACCEPT_1(parent, parent, AggregateDecl)
+		ACCEPT_N(attr, attributes, Attribute)
+
+		auto decl = new ast::UnionDecl(
+			old->location,
+			old->name,
+			std::move( attr ),
+			{ old->linkage.val }
+		);
+		decl->parent = parent;
+		decl->body   = old->body;
+		decl->parameters = params;
+		decl->members    = members;
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( EnumDecl * old ) override final {
+		ACCEPT_N(members, members, Decl)
+		ACCEPT_N(params, parameters, TypeDecl)
+		ACCEPT_1(parent, parent, AggregateDecl)
+		ACCEPT_N(attr, attributes, Attribute)
+
+		auto decl = new ast::UnionDecl(
+			old->location,
+			old->name,
+			std::move( attr ),
+			{ old->linkage.val }
+		);
+		decl->parent = parent;
+		decl->body   = old->body;
+		decl->parameters = params;
+		decl->members    = members;
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( TraitDecl * old ) override final {
+		ACCEPT_N(members, members, Decl)
+		ACCEPT_N(params, parameters, TypeDecl)
+		ACCEPT_1(parent, parent, AggregateDecl)
+		ACCEPT_N(attr, attributes, Attribute)
+
+		auto decl = new ast::UnionDecl(
+			old->location,
+			old->name,
+			std::move( attr ),
+			{ old->linkage.val }
+		);
+		decl->parent = parent;
+		decl->body   = old->body;
+		decl->parameters = params;
+		decl->members    = members;
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( TypeDecl * ) override final {
+
+	}
+
+	virtual void visit( TypedefDecl * old ) override final {
+		ACCEPT_1(type, base, Type)
+		ACCEPT_N(params, parameters, TypeDecl)
+		ACCEPT_N(asserts, assertions, DeclWithType)
+		auto decl = new ast::TypedefDecl(
+			old->location,
+			old->name,
+			{ old->storageClasses.val },
+			type,
+			{ old->linkage.val }
+		);
+
+		decl->assertions = asserts;
+		decl->parameters = params;
+		decl->extension  = old->extension;
+		decl->uniqueId   = old->uniqueId;
+		decl->storage    = { old->storageClasses.val };
+
+		this->node = decl;
+	}
+
+	virtual void visit( AsmDecl * ) override final {
+
+	}
+
+	virtual void visit( StaticAssertDecl * ) override final {
+
+	}
+
+	virtual void visit( CompoundStmt * old ) override final {
+		ACCEPT_N(kids, kids, Stmt)
+		auto stmt = new ast::CompoundStmt(
+			old->location,
+			to<std::list>::from( std::move(kids) )
+		);
+		stmt->labels = to<std::vector>::from( make_labels( std::move( old->labels ) ) );
+
+		this->node = stmt;
+	}
+
+	virtual void visit( ExprStmt * old ) override final {
+		ACCEPT_1(expr, expr, Expr)
+		auto stmt = new ast::ExprStmt(
+			old->location,
+			expr
+		);
+		stmt->labels = to<std::vector>::from( make_labels( std::move( old->labels ) ) );
+
+		this->node = stmt;
+	}
+
+	virtual void visit( AsmStmt * ) override final {
+
+	}
+
+	virtual void visit( DirectiveStmt * ) override final {
+
+	}
+
+	virtual void visit( IfStmt * ) override final {
+
+	}
+
+	virtual void visit( WhileStmt * ) override final {
+
+	}
+
+	virtual void visit( ForStmt * ) override final {
+
+	}
+
+	virtual void visit( SwitchStmt * ) override final {
+
+	}
+
+	virtual void visit( CaseStmt * ) override final {
+
+	}
+
+	virtual void visit( BranchStmt * ) override final {
+
+	}
+
+	virtual void visit( ReturnStmt * ) override final {
+
+	}
+
+	virtual void visit( ThrowStmt * ) override final {
+
+	}
+
+	virtual void visit( TryStmt * ) override final {
+
+	}
+
+	virtual void visit( CatchStmt * ) override final {
+
+	}
+
+	virtual void visit( FinallyStmt * ) override final {
+
+	}
+
+	virtual void visit( WaitForStmt * ) override final {
+
+	}
+
+	virtual void visit( WithStmt * ) override final {
+
+	}
+
+	virtual void visit( NullStmt * old ) override final {
+		auto stmt = new ast::NullStmt(
+			old->location,
+			to<std::vector>::from( make_labels( std::move( old->labels ) ) )
+		);
+
+		this->node = stmt;
+	}
+
+	virtual void visit( DeclStmt * ) override final {
+
+	}
+
+	virtual void visit( ImplicitCtorDtorStmt * ) override final {
+
+	}
+
+	virtual void visit( ApplicationExpr * ) override final {
+
+	}
+
+	virtual void visit( UntypedExpr * ) override final {
+
+	}
+
+	virtual void visit( NameExpr * ) override final {
+
+	}
+
+	virtual void visit( CastExpr * ) override final {
+
+	}
+
+	virtual void visit( KeywordCastExpr * ) override final {
+
+	}
+
+	virtual void visit( VirtualCastExpr * ) override final {
+
+	}
+
+	virtual void visit( AddressExpr * ) override final {
+
+	}
+
+	virtual void visit( LabelAddressExpr * ) override final {
+
+	}
+
+	virtual void visit( UntypedMemberExpr * ) override final {
+
+	}
+
+	virtual void visit( MemberExpr * ) override final {
+
+	}
+
+	virtual void visit( VariableExpr * ) override final {
+
+	}
+
+	virtual void visit( ConstantExpr * ) override final {
+
+	}
+
+	virtual void visit( SizeofExpr * ) override final {
+
+	}
+
+	virtual void visit( AlignofExpr * ) override final {
+
+	}
+
+	virtual void visit( UntypedOffsetofExpr * ) override final {
+
+	}
+
+	virtual void visit( OffsetofExpr * ) override final {
+
+	}
+
+	virtual void visit( OffsetPackExpr * ) override final {
+
+	}
+
+	virtual void visit( AttrExpr * ) override final {
+
+	}
+
+	virtual void visit( LogicalExpr * ) override final {
+
+	}
+
+	virtual void visit( ConditionalExpr * ) override final {
+
+	}
+
+	virtual void visit( CommaExpr * ) override final {
+
+	}
+
+	virtual void visit( TypeExpr * ) override final {
+
+	}
+
+	virtual void visit( AsmExpr * ) override final {
+
+	}
+
+	virtual void visit( ImplicitCopyCtorExpr * ) override final {
+
+	}
+
+	virtual void visit( ConstructorExpr *  ) override final {
+
+	}
+
+	virtual void visit( CompoundLiteralExpr * ) override final {
+
+	}
+
+	virtual void visit( RangeExpr * ) override final {
+
+	}
+
+	virtual void visit( UntypedTupleExpr * ) override final {
+
+	}
+
+	virtual void visit( TupleExpr * ) override final {
+
+	}
+
+	virtual void visit( TupleIndexExpr * ) override final {
+
+	}
+
+	virtual void visit( TupleAssignExpr * ) override final {
+
+	}
+
+	virtual void visit( StmtExpr *  ) override final {
+
+	}
+
+	virtual void visit( UniqueExpr *  ) override final {
+
+	}
+
+	virtual void visit( UntypedInitExpr *  ) override final {
+
+	}
+
+	virtual void visit( InitExpr *  ) override final {
+
+	}
+
+	virtual void visit( DeletedExpr * ) override final {
+
+	}
+
+	virtual void visit( DefaultArgExpr * ) override final {
+
+	}
+
+	virtual void visit( GenericExpr * ) override final {
+
+	}
+
+	virtual void visit( VoidType * ) override final {
+
+	}
+
+	virtual void visit( BasicType * ) override final {
+
+	}
+
+	virtual void visit( PointerType * ) override final {
+
+	}
+
+	virtual void visit( ArrayType * ) override final {
+
+	}
+
+	virtual void visit( ReferenceType * ) override final {
+
+	}
+
+	virtual void visit( QualifiedType * ) override final {
+
+	}
+
+	virtual void visit( FunctionType * ) override final {
+
+	}
+
+	virtual void visit( StructInstType * ) override final {
+
+	}
+
+	virtual void visit( UnionInstType * ) override final {
+
+	}
+
+	virtual void visit( EnumInstType * ) override final {
+
+	}
+
+	virtual void visit( TraitInstType * ) override final {
+
+	}
+
+	virtual void visit( TypeInstType * ) override final {
+
+	}
+
+	virtual void visit( TupleType * ) override final {
+
+	}
+
+	virtual void visit( TypeofType * ) override final {
+
+	}
+
+	virtual void visit( AttrType * ) override final {
+
+	}
+
+	virtual void visit( VarArgsType * ) override final {
+
+	}
+
+	virtual void visit( ZeroType * ) override final {
+
+	}
+
+	virtual void visit( OneType * ) override final {
+
+	}
+
+	virtual void visit( GlobalScopeType * ) override final {
+
+	}
+
+	virtual void visit( Designation * ) override final {
+
+	}
+
+	virtual void visit( SingleInit * ) override final {
+
+	}
+
+	virtual void visit( ListInit * ) override final {
+
+	}
+
+	virtual void visit( ConstructorInit * ) override final {
+
+	}
+
+	virtual void visit( Constant * ) override final {
+
+	}
+
+	virtual void visit( Attribute * ) override final {
+
+	}
+};
+
+#undef ACCEPT_N
+#undef ACCEPT_1
+
+std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > & translationUnit ) {
+	ConverterOldToNew c;
+	std::list< ast::ptr< ast::Decl > > decls;
+	for(auto d : translationUnit) {
+		d->accept( c );
+		decls.emplace_back( c.decl() );
+		delete d;
+	}
+	return decls;
+}
Index: src/AST/Convert.hpp
===================================================================
--- src/AST/Convert.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
+++ src/AST/Convert.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -0,0 +1,28 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Convert.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu May 09 15::37::05 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include <list>
+
+#include "AST/Node.hpp"
+
+class Declaration;
+namespace ast {
+	class Decl;
+};
+
+std::list< Declaration * > convert( const std::list< ast::ptr< ast::Decl > > & translationUnit );
+std::list< ast::ptr< ast::Decl > > convert( const std::list< Declaration * > & translationUnit );
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Decl.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -57,7 +57,7 @@
 	static readonly<Decl> fromId( UniqueId id );
 
-	virtual Decl* accept( Visitor& v ) override = 0;
-private:
-	virtual Decl* clone() const override = 0;
+	virtual const Decl * accept( Visitor & v ) const override = 0;
+private:
+	virtual Decl * clone() const override = 0;
 };
 
@@ -85,11 +85,11 @@
 
 	/// Get type of this declaration. May be generated by subclass
-	virtual const Type* get_type() const = 0;
+	virtual const Type * get_type() const = 0;
 	/// Set type of this declaration. May be verified by subclass
 	virtual void set_type(Type*) = 0;
 
-	virtual DeclWithType* accept( Visitor& v ) override = 0;
-private:
-	virtual DeclWithType* clone() const override = 0;
+	virtual const DeclWithType * accept( Visitor & v ) const override = 0;
+private:
+	virtual DeclWithType * clone() const override = 0;
 };
 
@@ -110,7 +110,11 @@
 	void set_type( Type* ty ) override { type = ty; }
 
-	DeclWithType* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	ObjectDecl* clone() const override { return new ObjectDecl{ *this }; }
+	virtual const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
+private:
+	virtual ObjectDecl * clone() const override { return new ObjectDecl{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
@@ -166,7 +170,7 @@
 	std::string genTypeString() const;
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	TypeDecl* clone() const override { return new TypeDecl{ *this }; }
+	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	virtual TypeDecl * clone() const override { return new TypeDecl{ *this }; }
 };
 
@@ -180,7 +184,7 @@
 	std::string typeString() const override { return "typedef"; }
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	TypedefDecl* clone() const override { return new TypedefDecl{ *this }; }
+	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	virtual TypedefDecl * clone() const override { return new TypedefDecl{ *this }; }
 };
 
@@ -220,7 +224,7 @@
 	bool is_thread() { return kind == DeclarationNode::Thread; }
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	StructDecl* clone() const override { return new StructDecl{ *this }; }
+	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	virtual StructDecl * clone() const override { return new StructDecl{ *this }; }
 
 	std::string typeString() const override { return "struct"; }
@@ -234,7 +238,7 @@
 	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	UnionDecl* clone() const override { return new UnionDecl{ *this }; }
+	virtual const Decl * accept( Visitor& v ) const override { return v.visit( this ); }
+private:
+	virtual UnionDecl * clone() const override { return new UnionDecl{ *this }; }
 
 	std::string typeString() const override { return "union"; }
@@ -251,7 +255,7 @@
 	bool valueOf( Decl* enumerator, long long& value ) const;
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	EnumDecl* clone() const override { return new EnumDecl{ *this }; }
+	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	virtual EnumDecl * clone() const override { return new EnumDecl{ *this }; }
 
 	std::string typeString() const override { return "enum"; }
@@ -268,7 +272,7 @@
 	: AggregateDecl( loc, name, std::move(attrs), linkage ) {}
 
-	Decl* accept( Visitor& v ) override { return v.visit( this ); }
-private:
-	TraitDecl* clone() const override { return new TraitDecl{ *this }; }
+	virtual const Decl * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	virtual TraitDecl * clone() const override { return new TraitDecl{ *this }; }
 
 	std::string typeString() const override { return "trait"; }
@@ -287,6 +291,6 @@
 inline void increment( const class ObjectDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class ObjectDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
-inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class FunctionDecl * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class FunctionDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 inline void increment( const class AggregateDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class AggregateDecl * node, Node::ref_type ref ) { node->decrement(ref); }
@@ -303,14 +307,14 @@
 inline void increment( const class TypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class TypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-inline void increment( const class FtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
-inline void decrement( const class FtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-inline void increment( const class DtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
-inline void decrement( const class DtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class FtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class FtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class DtypeDecl * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class DtypeDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 inline void increment( const class TypedefDecl * node, Node::ref_type ref ) { node->increment(ref); }
 inline void decrement( const class TypedefDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
-inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
-inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
-inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class AsmDecl * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class AsmDecl * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class StaticAssertDecl * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class StaticAssertDecl * node, Node::ref_type ref ) { node->decrement(ref); }
 
 }
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Expr.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -27,5 +27,5 @@
 namespace ast {
 
-/// Contains the ID of a declaration and a type that is derived from that declaration, 
+/// Contains the ID of a declaration and a type that is derived from that declaration,
 /// but subject to decay-to-pointer and type parameter renaming
 struct ParamEntry {
@@ -74,5 +74,5 @@
 			case Empty:  return;
 			case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
-			case Params: 
+			case Params:
 				new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
 			}
@@ -121,9 +121,95 @@
 	Expr* set_extension( bool ex ) { extension = ex; return this; }
 
-	virtual Expr* accept( Visitor& v ) override = 0;
+	virtual const Expr * accept( Visitor& v ) const override = 0;
 private:
-	virtual Expr* clone() const override = 0;
+	virtual Expr * clone() const override = 0;
 };
 
+
+//=================================================================================================
+/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
+/// remove only if there is a better solution
+/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
+/// forward declarations
+inline void increment( const class Expr * node, Node::ref_type ref ) { node->increment(ref); }
+inline void decrement( const class Expr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class ApplicationExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class ApplicationExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class NameExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class NameExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class AddressExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class AddressExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class LabelAddressExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class LabelAddressExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class CastExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class CastExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class KeywordCastExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class KeywordCastExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class VirtualCastExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class VirtualCastExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class MemberExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class MemberExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class VariableExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class VariableExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class ConstantExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class ConstantExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class SizeofExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class SizeofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class AlignofExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class AlignofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class OffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class OffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class OffsetPackExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class OffsetPackExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class AttrExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class AttrExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class LogicalExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class LogicalExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class ConditionalExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class ConditionalExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class CommaExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class CommaExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class TypeExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class TypeExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class AsmExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class AsmExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class ConstructorExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class ConstructorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class CompoundLiteralExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedValofExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedValofExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class RangeExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class RangeExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedTupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class TupleExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class TupleExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class TupleIndexExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class TupleIndexExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class TupleAssignExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class TupleAssignExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class StmtExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class StmtExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UniqueExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UniqueExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class UntypedInitExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class UntypedInitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class InitExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class InitExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class DeletedExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class DeletedExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class DefaultArgExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class DefaultArgExpr * node, Node::ref_type ref ) { node->decrement(ref); }
+// inline void increment( const class GenericExpr * node, Node::ref_type ref ) { node->increment(ref); }
+// inline void decrement( const class GenericExpr * node, Node::ref_type ref ) { node->decrement(ref); }
 }
 
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Fwd.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -137,4 +137,6 @@
 
 class TypeSubstitution;
+
+std::string toString( const Node * );
 
 //=================================================================================================
@@ -355,6 +357,4 @@
 inline void increment( const class Constant *, Node::ref_type );
 inline void decrement( const class Constant *, Node::ref_type );
-inline void increment( const class Label *, Node::ref_type );
-inline void decrement( const class Label *, Node::ref_type );
 inline void increment( const class Attribute *, Node::ref_type );
 inline void decrement( const class Attribute *, Node::ref_type );
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Init.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -37,7 +37,7 @@
 	: ParseNode( loc ), designators( std::move(ds) ) {}
 
-	Designation* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const Designation* accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	Designation* clone() const override { return new Designation{ *this }; }
+	virtual Designation* clone() const override { return new Designation{ *this }; }
 };
 
@@ -49,7 +49,7 @@
 	Init( const CodeLocation& loc, bool mc ) : ParseNode( loc ), maybeConstructed( mc ) {}
 
-	virtual Init* accept( Visitor& v ) override = 0;
+	virtual const Init * accept( Visitor& v ) const override = 0;
 private:
-	virtual Init* clone() const override = 0;
+	virtual const Init * clone() const override = 0;
 };
 
@@ -63,7 +63,11 @@
 	: Init( loc, mc ), value( val ) {}
 
-	Init* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	SingleInit* clone() const override { return new SingleInit{ *this }; }
+	virtual SingleInit * clone() const override { return new SingleInit{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
@@ -87,7 +91,11 @@
 	const_iterator end() const { return initializers.end(); }
 
-	Init* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	ListInit* clone() const override { return new ListInit{ *this }; }
+	virtual ListInit * clone() const override { return new ListInit{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
@@ -106,7 +114,11 @@
 	: Init( loc, true ), ctor( ctor ), dtor( dtor ), init( init ) {}
 
-	Init* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const Init * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
-	ConstructorInit* clone() const override { return new ConstructorInit{ *this }; }
+	virtual ConstructorInit * clone() const override { return new ConstructorInit{ *this }; }
+
+	/// Must be copied in ALL derived classes
+	template<typename node_t>
+	friend auto mutate(const node_t * node);
 };
 
Index: src/AST/Label.hpp
===================================================================
--- src/AST/Label.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Label.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -35,5 +35,5 @@
 
 	Label( CodeLocation loc, const std::string& name = "",
-		const std::vector<ptr<Attribute>>& attrs = std::vector<ptr<Attribute>>{} )
+		std::vector<ptr<Attribute>> && attrs = std::vector<ptr<Attribute>>{} )
 	: location( loc ), name( name ), attributes( attrs ) {}
 
@@ -48,13 +48,4 @@
 inline std::ostream& operator<< ( std::ostream& out, const Label& l ) { return out << l.name; }
 
-
-//=================================================================================================
-/// This disgusting and giant piece of boiler-plate is here to solve a cyclic dependency
-/// remove only if there is a better solution
-/// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
-/// forward declarations
-inline void increment( const class Label * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class Label * node, Node::ref_type ref ) { node->decrement( ref ); }
-
 }
 
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Node.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -30,11 +30,11 @@
 	// change/share reference counts
 	Node() = default;
-	Node(const Node&) : strong_ref(0), weak_ref(0) {}
-	Node(Node&&) : strong_ref(0), weak_ref(0) {}
+	Node(const Node&) : strong_count(0), weak_count(0) {}
+	Node(Node&&) : strong_count(0), weak_count(0) {}
 	Node& operator= (const Node&) = delete;
 	Node& operator= (Node&&) = delete;
 	virtual ~Node() = default;
 
-	virtual Node* accept( Visitor& v ) = 0;
+	virtual const Node * accept( Visitor & v ) const = 0;
 
 	/// Types of node references
@@ -46,6 +46,6 @@
 	inline void increment(ref_type ref) const {
 		switch (ref) {
-			case ref_type::strong: strong_ref++; break;
-			case ref_type::weak  : weak_ref  ++; break;
+			case ref_type::strong: strong_count++; break;
+			case ref_type::weak  : weak_count  ++; break;
 		}
 	}
@@ -53,22 +53,22 @@
 	inline void decrement(ref_type ref) const {
 		switch (ref) {
-			case ref_type::strong: strong_ref--; break;
-			case ref_type::weak  : weak_ref  --; break;
+			case ref_type::strong: strong_count--; break;
+			case ref_type::weak  : weak_count  --; break;
 		}
 
-		if(!strong_ref && !weak_ref) {
+		if(!strong_count && !weak_count) {
 			delete this;
 		}
 	}
+private:
+	/// Make a copy of this node; should be overridden in subclass with more precise return type
+	virtual const Node * clone() const = 0;
 
+	/// Must be copied in ALL derived classes
 	template<typename node_t>
 	friend auto mutate(const node_t * node);
 
-private:
-	/// Make a copy of this node; should be overridden in subclass with more precise return type
-	virtual Node* clone() const = 0;
-
-	mutable size_t strong_ref = 0;
-	mutable size_t weak_ref = 0;
+	mutable size_t strong_count = 0;
+	mutable size_t weak_count = 0;
 };
 
@@ -100,16 +100,22 @@
 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); }
+	ptr_base( const node_t * n ) : node(n) { if( !node ) increment(node, ref_t); }
+	~ptr_base() { if( node ) decrement(node, 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);
+		increment(node, 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 ) increment(node, ref_t);
+	}
+
+	template<typename o_node_t>
+	ptr_base & operator=( const o_node_t * node ) {
+		assign(strict_dynamic_cast<const node_t *>(node));
+		return *this;
 	}
 
@@ -136,12 +142,12 @@
 
 private:
-	void assign(node_t * other ) {
-		if( other ) other->increment(ref_t);
-		if( node  ) node ->decrement(ref_t);
+	void assign(const node_t * other ) {
+		if( other ) increment(other, ref_t);
+		if( node  ) decrement(node , ref_t);
 		node = other;
 	}
 
 protected:
-	node_t * node;
+	const node_t * node;
 };
 
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Pass.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -23,5 +23,11 @@
 #include "AST/Fwd.hpp"
 #include "AST/Node.hpp"
+
+#include "AST/Attribute.hpp"
 #include "AST/Decl.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Init.hpp"
+#include "AST/Stmt.hpp"
+
 #include "AST/Visitor.hpp"
 
@@ -79,98 +85,98 @@
 
 	/// Visit function declarations
-	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;
+	virtual const ast::DeclWithType *     visit( const ast::ObjectDecl           * ) override final;
+	virtual const ast::DeclWithType *     visit( const ast::FunctionDecl         * ) override final;
+	virtual const ast::Decl *             visit( const ast::StructDecl           * ) override final;
+	virtual const ast::Decl *             visit( const ast::UnionDecl            * ) override final;
+	virtual const ast::Decl *             visit( const ast::EnumDecl             * ) override final;
+	virtual const ast::Decl *             visit( const ast::TraitDecl            * ) override final;
+	virtual const ast::Decl *             visit( const ast::TypeDecl             * ) override final;
+	virtual const ast::Decl *             visit( const ast::TypedefDecl          * ) override final;
+	virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * ) override final;
+	virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) override final;
+	virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) override final;
+	virtual const ast::Stmt *             visit( const ast::ExprStmt             * ) override final;
+	virtual const ast::Stmt *             visit( const ast::AsmStmt              * ) override final;
+	virtual const ast::Stmt *             visit( const ast::DirectiveStmt        * ) override final;
+	virtual const ast::Stmt *             visit( const ast::IfStmt               * ) override final;
+	virtual const ast::Stmt *             visit( const ast::WhileStmt            * ) override final;
+	virtual const ast::Stmt *             visit( const ast::ForStmt              * ) override final;
+	virtual const ast::Stmt *             visit( const ast::SwitchStmt           * ) override final;
+	virtual const ast::Stmt *             visit( const ast::CaseStmt             * ) override final;
+	virtual const ast::Stmt *             visit( const ast::BranchStmt           * ) override final;
+	virtual const ast::Stmt *             visit( const ast::ReturnStmt           * ) override final;
+	virtual const ast::Stmt *             visit( const ast::ThrowStmt            * ) override final;
+	virtual const ast::Stmt *             visit( const ast::TryStmt              * ) override final;
+	virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) override final;
+	virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) override final;
+	virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
+	virtual const ast::Stmt *             visit( const ast::WithStmt             * ) override final;
+	virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
+	virtual const ast::Stmt *             visit( const ast::DeclStmt             * ) override final;
+	virtual const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) override final;
+	virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) override final;
+	virtual const ast::Expr *             visit( const ast::NameExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::AddressExpr          * ) override final;
+	virtual const ast::Expr *             visit( const ast::LabelAddressExpr     * ) override final;
+	virtual const ast::Expr *             visit( const ast::CastExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::KeywordCastExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::VirtualCastExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::UntypedMemberExpr    * ) override final;
+	virtual const ast::Expr *             visit( const ast::MemberExpr           * ) override final;
+	virtual const ast::Expr *             visit( const ast::VariableExpr         * ) override final;
+	virtual const ast::Expr *             visit( const ast::ConstantExpr         * ) override final;
+	virtual const ast::Expr *             visit( const ast::SizeofExpr           * ) override final;
+	virtual const ast::Expr *             visit( const ast::AlignofExpr          * ) override final;
+	virtual const ast::Expr *             visit( const ast::UntypedOffsetofExpr  * ) override final;
+	virtual const ast::Expr *             visit( const ast::OffsetofExpr         * ) override final;
+	virtual const ast::Expr *             visit( const ast::OffsetPackExpr       * ) override final;
+	virtual const ast::Expr *             visit( const ast::AttrExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::LogicalExpr          * ) override final;
+	virtual const ast::Expr *             visit( const ast::ConditionalExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::CommaExpr            * ) override final;
+	virtual const ast::Expr *             visit( const ast::TypeExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::AsmExpr              * ) override final;
+	virtual const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) override final;
+	virtual const ast::Expr *             visit( const ast::ConstructorExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::CompoundLiteralExpr  * ) override final;
+	virtual const ast::Expr *             visit( const ast::RangeExpr            * ) override final;
+	virtual const ast::Expr *             visit( const ast::UntypedTupleExpr     * ) override final;
+	virtual const ast::Expr *             visit( const ast::TupleExpr            * ) override final;
+	virtual const ast::Expr *             visit( const ast::TupleIndexExpr       * ) override final;
+	virtual const ast::Expr *             visit( const ast::TupleAssignExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::StmtExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::UniqueExpr           * ) override final;
+	virtual const ast::Expr *             visit( const ast::UntypedInitExpr      * ) override final;
+	virtual const ast::Expr *             visit( const ast::InitExpr             * ) override final;
+	virtual const ast::Expr *             visit( const ast::DeletedExpr          * ) override final;
+	virtual const ast::Expr *             visit( const ast::DefaultArgExpr       * ) override final;
+	virtual const ast::Expr *             visit( const ast::GenericExpr          * ) override final;
+	virtual const ast::Type *             visit( const ast::VoidType             * ) override final;
+	virtual const ast::Type *             visit( const ast::BasicType            * ) override final;
+	virtual const ast::Type *             visit( const ast::PointerType          * ) override final;
+	virtual const ast::Type *             visit( const ast::ArrayType            * ) override final;
+	virtual const ast::Type *             visit( const ast::ReferenceType        * ) override final;
+	virtual const ast::Type *             visit( const ast::QualifiedType        * ) override final;
+	virtual const ast::Type *             visit( const ast::FunctionType         * ) override final;
+	virtual const ast::Type *             visit( const ast::StructInstType       * ) override final;
+	virtual const ast::Type *             visit( const ast::UnionInstType        * ) override final;
+	virtual const ast::Type *             visit( const ast::EnumInstType         * ) override final;
+	virtual const ast::Type *             visit( const ast::TraitInstType        * ) override final;
+	virtual const ast::Type *             visit( const ast::TypeInstType         * ) override final;
+	virtual const ast::Type *             visit( const ast::TupleType            * ) override final;
+	virtual const ast::Type *             visit( const ast::TypeofType           * ) override final;
+	virtual const ast::Type *             visit( const ast::AttrType             * ) override final;
+	virtual const ast::Type *             visit( const ast::VarArgsType          * ) override final;
+	virtual const ast::Type *             visit( const ast::ZeroType             * ) override final;
+	virtual const ast::Type *             visit( const ast::OneType              * ) override final;
+	virtual const ast::Type *             visit( const ast::GlobalScopeType      * ) override final;
+	virtual const ast::Designation *      visit( const ast::Designation          * ) override final;
+	virtual const ast::Init *             visit( const ast::SingleInit           * ) override final;
+	virtual const ast::Init *             visit( const ast::ListInit             * ) override final;
+	virtual const ast::Init *             visit( const ast::ConstructorInit      * ) override final;
+	virtual const ast::Constant *         visit( const ast::Constant             * ) override final;
+	virtual const ast::Attribute *        visit( const ast::Attribute            * ) override final;
+	virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
 
 	friend void acceptAll( std::list< ptr<Decl> > & decls, Pass<pass_t>& visitor );
@@ -180,16 +186,19 @@
 
 private:
+	const ast::Stmt * call_accept( const ast::Stmt * );
+	const ast::Expr * call_accept( const ast::Expr * );
+
+	template< typename node_t >
+	auto call_accept( const node_t * node ) -> decltype( node->accept(*this) );
+
+	template< template <class...> class container_t >
+	container_t< ptr<Stmt> > call_accept( const container_t< ptr<Stmt> > & );
+
+	template< template <class...> class container_t, typename node_t >
+	container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
+
 	/// Logic to call the accept and mutate the parent if needed, delegates call to accept
-	template<typename parent_t, typename child_t>
-	void maybe_accept(parent_t * & , typename parent_t::child_t *);
-
-	Stmt * call_accept( const Stmt * );
-	Expr * call_accept( const Expr * );
-
-	template< template <class> class container_t >
-	container_t< ptr<Stmt> > call_accept( const container_t< ptr<Stmt> > & );
-
-	template< template <class> class container_t, typename node_t >
-	container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
+	template<typename node_t, typename parent_t, typename child_t>
+	void maybe_accept(const node_t * &, child_t parent_t::* child);
 
 private:
@@ -210,5 +219,5 @@
 
 template<typename pass_t>
-void acceptAll( std::list< ptr<Decl> >, Pass<pass_t>& visitor );
+void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
 
 //-------------------------------------------------------------------------------------------------
@@ -216,7 +225,4 @@
 //-------------------------------------------------------------------------------------------------
 
-template<typename T>
-using std_list = std::list<T>;
-
 /// Keep track of the polymorphic const TypeSubstitution * env for the current expression
 struct WithConstTypeSubstitution {
@@ -226,5 +232,5 @@
 /// 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 >
+template< template<class...> class container_t = std::list >
 struct WithStmtsToAdd {
 	container_t< ptr<Stmt> > stmtsToAddBefore;
@@ -234,5 +240,5 @@
 /// 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 >
+template< template<class...> class container_t = std::list >
 struct WithDeclsToAdd {
 	container_t< ptr<Decl> > declsToAddBefore;
@@ -286,2 +292,12 @@
 };
 }
+
+#include "Common/Stats.h"
+
+extern struct PassVisitorStats {
+	size_t depth = 0;
+	Stats::Counters::MaxCounter<double> * max = nullptr;
+	Stats::Counters::AverageCounter<double> * avg = nullptr;
+} pass_visitor_stats;
+
+#include "AST/Pass.impl.hpp"
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Pass.impl.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -16,4 +16,7 @@
 #pragma once
 // IWYU pragma: private, include "AST/Pass.hpp"
+
+#include <type_traits>
+#include <unordered_map>
 
 #define VISIT_START( node ) \
@@ -26,5 +29,5 @@
 	__pass::previsit( pass, node, 0 );
 
-#define VISIT( code ) \
+#define VISIT( code... ) \
 	/* if this node should visit its children */ \
 	if ( __visit_children() ) { \
@@ -35,13 +38,13 @@
 #define VISIT_END( type, node ) \
 	/* call the implementation of the postvisit of this pass */ \
-	auto __return = __pass::postvisit< type * >( node ); \
+	auto __return = __pass::postvisit( pass, node, 0 ); \
 	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__)
+#define __pedantic_pass_assert(...) assert (__VA_ARGS__)
+#define __pedantic_pass_assertf(...) assertf(__VA_ARGS__)
 #else
-#define __pedantic_pass_assert (...)
+#define __pedantic_pass_assert(...)
 #define __pedantic_pass_assertf(...)
 #endif
@@ -55,9 +58,10 @@
 		}
 
-		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 ) {
+		//------------------------------
+		template<typename it_t, template <class...> class container_t>
+		static inline void take_all( it_t it, container_t<ast::ptr<ast::Decl>> * decls, bool * mutated = nullptr ) {
 			if(empty(decls)) return;
 
-			std::transform(decls->begin(), decls->end(), it, [](Declaration * decl) -> auto {
+			std::transform(decls->begin(), decls->end(), it, [](const ast::Decl * decl) -> auto {
 					return new DeclStmt( decl );
 				});
@@ -66,6 +70,6 @@
 		}
 
-		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 ) {
+		template<typename it_t, template <class...> class container_t>
+		static inline void take_all( it_t it, container_t<ast::ptr<ast::Stmt>> * decls, bool * mutated = nullptr ) {
 			if(empty(decls)) return;
 
@@ -75,30 +79,39 @@
 		}
 
+		//------------------------------
+		/// Check if should be skipped, different for pointers and containers
 		template<typename node_t>
-		bool differs( const node_t * old_val, const node_t * new_val ) {
+		bool skip( const ast::ptr<node_t> & val) {
+			return !val;
+		}
+
+		template< template <class...> class container_t, typename node_t >
+		bool skip( const container_t<ast::ptr< node_t >> & val ) {
+			return val.empty();
+		}
+
+		//------------------------------
+		/// Get the value to visit, different for pointers and containers
+		template<typename node_t>
+		auto get( const ast::ptr<node_t> & val, int ) -> decltype(val.get()) {
+			return val.get();
+		}
+
+		template<typename node_t>
+		const node_t & get( const node_t & val, long) {
+			return val;
+		}
+
+
+		//------------------------------
+		/// Check if value was mutated, different for pointers and containers
+		template<typename lhs_t, typename rhs_t>
+		bool differs( const lhs_t * old_val, const rhs_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 ) {
+		template< template <class...> class container_t, typename node_t >
+		bool differs( const container_t<ast::ptr< node_t >> &, const container_t<ast::ptr< node_t >> & 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;
 		}
 	}
@@ -106,13 +119,16 @@
 	template< typename pass_t >
 	template< typename node_t >
-	auto Pass< pass_t >::call_accept( const node_t * node ) {
+	auto Pass< pass_t >::call_accept( const node_t * node ) -> decltype( node->accept(*this) ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( expr );
 
+		static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
+		static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR");
+
 		return node->accept( *this );
 	}
 
 	template< typename pass_t >
-	ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
+	const ast::Expr * Pass< pass_t >::call_accept( const ast::Expr * expr ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( expr );
@@ -127,5 +143,5 @@
 
 	template< typename pass_t >
-	Stmt * Pass< pass_t >::call_accept( const Stmt * stmt ) {
+	const ast::Stmt * Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( stmt );
@@ -141,12 +157,12 @@
 
 		// These may be modified by subnode but most be restored once we exit this statemnet.
-		ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( 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  );
+		ValueGuardPtr< const ast::TypeSubstitution * > __old_env         ( __pass::env( 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 );
+		const ast::Stmt * nstmt = stmt->accept( *this );
 
 		// If the pass doesn't want to add anything then we are done
@@ -161,5 +177,5 @@
 
 		// Create a new Compound Statement to hold the new decls/stmts
-		ast::CompoundStmt * compound = new ast::CompoundStmt( parent->*child.location );
+		ast::CompoundStmt * compound = new ast::CompoundStmt( stmt->location );
 
 		// Take all the declarations that go before
@@ -168,5 +184,5 @@
 
 		// Insert the original declaration
-		compound->kids.push_back( nstmt );
+		compound->kids.emplace_back( nstmt );
 
 		// Insert all the declarations that go before
@@ -178,5 +194,5 @@
 
 	template< typename pass_t >
-	template< template <class> class container_t >
+	template< template <class...> class container_t >
 	container_t< ptr<Stmt> > Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
 		__pedantic_pass_assert( __visit_children() );
@@ -196,8 +212,8 @@
 
 		// 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  );
+		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
@@ -211,5 +227,5 @@
 			try {
 				__pedantic_pass_assert( stmt );
-				const ast::Statment * new_stmt = stmt->accept( visitor );
+				const ast::Stmt * new_stmt = stmt->accept( *this );
 				assert( new_stmt );
 				if(new_stmt != stmt ) mutated = true;
@@ -240,9 +256,9 @@
 		if ( !errors.isEmpty() ) { throw errors; }
 
-		return mutated ? new_kids : {};
+		return mutated ? new_kids : container_t< ptr<Stmt> >();
 	}
 
 	template< typename pass_t >
-	template< template <class> class container_t, typename node_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() );
@@ -259,6 +275,6 @@
 			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;
+				const node_t * new_stmt = strict_dynamic_cast< const node_t * >( node->accept( *this ) );
+				if(new_stmt != node ) mutated = true;
 
 				new_kids.emplace_back( new_stmt );
@@ -271,6 +287,31 @@
 		if ( ! errors.isEmpty() ) { throw errors; }
 
-		return mutated ? new_kids : {};
-	}
+		return mutated ? new_kids : container_t< ast::ptr<node_t> >();
+	}
+
+	template< typename pass_t >
+	template<typename node_t, typename parent_t, typename child_t>
+	void Pass< pass_t >::maybe_accept(
+		const node_t * & parent,
+		child_t parent_t::*child
+	) {
+		static_assert( std::is_base_of<parent_t, node_t>::value, "Error deductiing member object" );
+
+		if(__pass::skip(parent->*child)) return;
+		const auto & old_val = __pass::get(parent->*child, 0);
+
+		static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR");
+
+		auto new_val = call_accept( old_val );
+
+		static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR");
+
+		if( __pass::differs(old_val, new_val) ) {
+			auto new_parent = mutate(parent);
+			new_parent->*child = new_val;
+			parent = new_parent;
+		}
+	}
+
 }
 
@@ -284,5 +325,5 @@
 
 template< typename pass_t >
-inline void ast::acceptAll( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
+inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
 	// We are going to aggregate errors for all these statements
 	SemanticErrorException errors;
@@ -292,6 +333,6 @@
 
 	// get the stmts/decls that will need to be spliced in
-	auto decls_before = __pass::declsToAddBefore( pass, 0);
-	auto decls_after  = __pass::declsToAddAfter ( pass, 0);
+	auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
+	auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
 
 	// update pass statitistics
@@ -343,51 +384,118 @@
 // ObjectDecl
 template< typename pass_t >
-ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
+const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
 	VISIT_START( node );
 
 	VISIT(
 		{
-			indexer_guard guard { *this };
-			maybe_accept( node, ObjectDecl::type );
-		}
-		maybe_accept( node, ObjectDecl::init          );
-		maybe_accept( node, ObjectDecl::bitfieldWidth );
-		maybe_accept( node, ObjectDecl::attributes    );
+			guard_indexer guard { *this };
+			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( pass, 0, node );
+	__pass::indexer::addId( pass, 0, node );
 
 	VISIT_END( DeclWithType, node );
+}
+
+//--------------------------------------------------------------------------
+// SingleInit
+template< typename pass_t >
+const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &SingleInit::value );
+	)
+
+	VISIT_END( Init, node );
+}
+
+//--------------------------------------------------------------------------
+// ListInit
+template< typename pass_t >
+const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &ListInit::designations );
+		maybe_accept( node, &ListInit::initializers );
+	)
+
+	VISIT_END( Init, node );
+}
+
+//--------------------------------------------------------------------------
+// ConstructorInit
+template< typename pass_t >
+const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		maybe_accept( node, &ConstructorInit::ctor );
+		maybe_accept( node, &ConstructorInit::dtor );
+		maybe_accept( node, &ConstructorInit::init );
+	)
+
+	VISIT_END( Init, node );
 }
 
 //--------------------------------------------------------------------------
 // Attribute
-template< typename pass_type >
-ast::Attribute * ast::Pass< pass_type >::visit( const ast::Attribute * node  )  {
-	VISIT_START(node);
+template< typename pass_t >
+const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
+	VISIT_START( node );
 
 	VISIT(
-		maybe_accept( node, ast::Attribute::parameters );
+		maybe_accept( node, &Attribute::parameters );
 	)
 
-	VISIT_END(ast::Attribute *, node );
+	VISIT_END( Attribute *, node );
 }
 
 //--------------------------------------------------------------------------
 // TypeSubstitution
-template< typename pass_type >
-TypeSubstitution * PassVisitor< pass_type >::mutate( const 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 );
+template< typename pass_t >
+const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		{
+			bool mutated = false;
+			std::unordered_map< std::string, ast::ptr< ast::Type > > new_map;
+			for ( const auto & p : node->typeEnv ) {
+				guard_indexer guard { *this };
+				auto new_node = p.second->accept( *this );
+				if (new_node != p.second) mutated = false;
+				new_map.insert({ p.first, new_node });
+			}
+			if (mutated) {
+				auto new_node = mutate( node );
+				new_node->typeEnv.swap( new_map );
+				node = new_node;
+			}
+		}
+
+		{
+			bool mutated = false;
+			std::unordered_map< std::string, ast::ptr< ast::Expr > > new_map;
+			for ( const auto & p : node->varEnv ) {
+				guard_indexer guard { *this };
+				auto new_node = p.second->accept( *this );
+				if (new_node != p.second) mutated = false;
+				new_map.insert({ p.first, new_node });
+			}
+			if (mutated) {
+				auto new_node = mutate( node );
+				new_node->varEnv.swap( new_map );
+				node = new_node;
+			}
+		}
+	)
+
+	VISIT_END( TypeSubstitution, node );
 }
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Pass.proto.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -162,5 +162,5 @@
 
 	// List of fields and their expected types
-	FIELD_PTR( env, const ast::TypeSubstitution )
+	FIELD_PTR( env, const ast::TypeSubstitution * )
 	FIELD_PTR( stmtsToAddBefore, std::list< ast::ptr< ast::Stmt > > )
 	FIELD_PTR( stmtsToAddAfter , std::list< ast::ptr< ast::Stmt > > )
@@ -235,52 +235,52 @@
 		static inline void func( pass_t &, long, type1, type2 ) {}
 
-		INDEXER_FUNC1( addId     , DeclWithType *  );
-		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 * > &, Node * );
+		INDEXER_FUNC1( addId     , const DeclWithType *  );
+		INDEXER_FUNC1( addType   , const NamedTypeDecl * );
+		INDEXER_FUNC1( addStruct , const StructDecl *    );
+		INDEXER_FUNC1( addEnum   , const EnumDecl *      );
+		INDEXER_FUNC1( addUnion  , const UnionDecl *     );
+		INDEXER_FUNC1( addTrait  , const TraitDecl *     );
+		INDEXER_FUNC2( addWith   , const std::list< Expression * > &, const Node * );
 
 		// 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 & ) {}
+		template<typename pass_t>
+		static inline auto addStructFwd( pass_t & pass, int, const 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, const ast::StructDecl * ) {}
+
+		template<typename pass_t>
+		static inline auto addUnionFwd( pass_t & pass, int, const ast::UnionDecl * decl ) -> decltype( pass.indexer.addUnion( decl ), void() ) {
+			UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
+			fwd->parameters = decl->parameters;
+			pass.indexer.addUnion( fwd );
+		}
+
+		template<typename pass_t>
+		static inline void addUnionFwd( pass_t &, long, const 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
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Stmt.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -40,5 +40,5 @@
 	Stmt(const Stmt& o) : ParseNode(o), labels(o.labels) {}
 
-	virtual Stmt* accept( Visitor& v ) override = 0;
+	virtual const Stmt* accept( Visitor& v ) const override = 0;
 private:
 	virtual Stmt* clone() const override = 0;
@@ -59,7 +59,7 @@
 	void push_front( Stmt* s ) { kids.emplace_front( s ); }
 
-	CompoundStmt* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const CompoundStmt* accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	CompoundStmt* clone() const override { return new CompoundStmt{ *this }; }
+	virtual CompoundStmt* clone() const override { return new CompoundStmt{ *this }; }
 };
 
@@ -70,7 +70,7 @@
 	: Stmt(loc, std::move(labels)) {}
 
-	NullStmt* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const NullStmt * accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	NullStmt* clone() const override { return new NullStmt{ *this }; }
+	virtual NullStmt * clone() const override { return new NullStmt{ *this }; }
 };
 
@@ -82,7 +82,7 @@
 	ExprStmt( const CodeLocation& loc, Expr* e ) : Stmt(loc), expr(e) {}
 
-	Stmt* accept( Visitor& v ) override { return v.visit( this ); }
+	virtual const Stmt * accept( Visitor& v ) const override { return v.visit( this ); }
 private:
-	ExprStmt* clone() const override { return new ExprStmt{ *this }; }
+	virtual ExprStmt * clone() const override { return new ExprStmt{ *this }; }
 };
 
@@ -100,40 +100,40 @@
 inline void increment( const class ExprStmt * node, Node::ref_type ref ) { node->increment( ref ); }
 inline void decrement( const class ExprStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class AsmStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class AsmStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class DirectiveStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class DirectiveStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class IfStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class IfStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class WhileStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class WhileStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class SwitchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class SwitchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class CaseStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class CaseStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class BranchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class BranchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ReturnStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ReturnStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ThrowStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ThrowStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class TryStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class TryStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class CatchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class CatchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class FinallyStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class FinallyStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class WaitForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class WaitForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class WithStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class WithStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class DeclStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class DeclStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class AsmStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class AsmStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class DirectiveStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class DirectiveStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class IfStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class IfStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class WhileStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class WhileStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class SwitchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class SwitchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class CaseStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class CaseStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class BranchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class BranchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ReturnStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ReturnStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ThrowStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ThrowStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class TryStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class TryStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class CatchStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class CatchStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class FinallyStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class FinallyStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class WaitForStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class WaitForStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class WithStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class WithStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class DeclStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class DeclStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
 inline void increment( const class NullStmt * node, Node::ref_type ref ) { node->increment( ref ); }
 inline void decrement( const class NullStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ImplicitCtorDtorStmt * node, Node::ref_type ref ) { node->decrement( ref ); }
 
 }
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Type.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -21,5 +21,6 @@
 
 class Type : public Node {
-
+public:
+virtual const Type * accept( Visitor & v) const = 0;
 };
 
@@ -31,46 +32,46 @@
 /// The problem is that ast::ptr< ... > uses increment/decrement which won't work well with
 /// forward declarations
-inline void increment( const class Type * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class Type * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class VoidType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class VoidType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class BasicType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class BasicType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class PointerType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class PointerType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ArrayType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ArrayType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ReferenceType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ReferenceType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class QualifiedType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class QualifiedType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class FunctionType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class FunctionType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ReferenceToType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ReferenceToType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class StructInstType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class StructInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class UnionInstType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class UnionInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class EnumInstType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class EnumInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class TraitInstType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class TraitInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class TypeInstType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class TypeInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class TupleType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class TupleType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class TypeofType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class TypeofType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class AttrType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class AttrType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class VarArgsType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class VarArgsType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class ZeroType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class ZeroType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class OneType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class OneType * node, Node::ref_type ref ) { node->decrement( ref ); }
-inline void increment( const class GlobalScopeType * node, Node::ref_type ref ) { node->increment( ref ); }
-inline void decrement( const class GlobalScopeType * node, Node::ref_type ref ) { node->decrement( ref ); }
+inline void increment( const class Type * /*node*/, Node::ref_type /*ref*/ ) { /*node->increment( ref );*/ }
+inline void decrement( const class Type * /*node*/, Node::ref_type /*ref*/ ) { /*node->decrement( ref );*/ }
+// inline void increment( const class VoidType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class VoidType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class BasicType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class BasicType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class PointerType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class PointerType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ArrayType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ArrayType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ReferenceType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ReferenceType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class QualifiedType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class QualifiedType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class FunctionType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class FunctionType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ReferenceToType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ReferenceToType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class StructInstType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class StructInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class UnionInstType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class UnionInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class EnumInstType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class EnumInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class TraitInstType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class TraitInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class TypeInstType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class TypeInstType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class TupleType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class TupleType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class TypeofType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class TypeofType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class AttrType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class AttrType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class VarArgsType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class VarArgsType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class ZeroType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class ZeroType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class OneType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class OneType * node, Node::ref_type ref ) { node->decrement( ref ); }
+// inline void increment( const class GlobalScopeType * node, Node::ref_type ref ) { node->increment( ref ); }
+// inline void decrement( const class GlobalScopeType * node, Node::ref_type ref ) { node->decrement( ref ); }
 
 }
Index: src/AST/Visitor.hpp
===================================================================
--- src/AST/Visitor.hpp	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/Visitor.hpp	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -22,98 +22,98 @@
 class Visitor {
 public:
-    virtual DeclWithType *     visit( const ObjectDecl           * ) = 0;
-    virtual DeclWithType *     visit( const FunctionDecl         * ) = 0;
-    virtual Decl *             visit( const StructDecl           * ) = 0;
-    virtual Decl *             visit( const UnionDecl            * ) = 0;
-    virtual Decl *             visit( const EnumDecl             * ) = 0;
-    virtual Decl *             visit( const TraitDecl            * ) = 0;
-    virtual Decl *             visit( const TypeDecl             * ) = 0;
-    virtual Decl *             visit( const TypedefDecl          * ) = 0;
-    virtual AsmDecl *          visit( const AsmDecl              * ) = 0;
-    virtual StaticAssertDecl * visit( const StaticAssertDecl     * ) = 0;
-    virtual CompoundStmt *     visit( const CompoundStmt         * ) = 0;
-    virtual Stmt *             visit( const ExprStmt             * ) = 0;
-    virtual Stmt *             visit( const AsmStmt              * ) = 0;
-    virtual Stmt *             visit( const DirectiveStmt        * ) = 0;
-    virtual Stmt *             visit( const IfStmt               * ) = 0;
-    virtual Stmt *             visit( const WhileStmt            * ) = 0;
-    virtual Stmt *             visit( const ForStmt              * ) = 0;
-    virtual Stmt *             visit( const SwitchStmt           * ) = 0;
-    virtual Stmt *             visit( const CaseStmt             * ) = 0;
-    virtual Stmt *             visit( const BranchStmt           * ) = 0;
-    virtual Stmt *             visit( const ReturnStmt           * ) = 0;
-    virtual Stmt *             visit( const ThrowStmt            * ) = 0;
-    virtual Stmt *             visit( const TryStmt              * ) = 0;
-    virtual Stmt *             visit( const CatchStmt            * ) = 0;
-    virtual Stmt *             visit( const FinallyStmt          * ) = 0;
-    virtual Stmt *             visit( const WaitForStmt          * ) = 0;
-    virtual Stmt *             visit( const WithStmt             * ) = 0;
-    virtual NullStmt *         visit( const NullStmt             * ) = 0;
-    virtual Stmt *             visit( const DeclStmt             * ) = 0;
-    virtual Stmt *             visit( const ImplicitCtorDtorStmt * ) = 0;
-    virtual Expr *             visit( const ApplicationExpr      * ) = 0;
-    virtual Expr *             visit( const UntypedExpr          * ) = 0;
-    virtual Expr *             visit( const NameExpr             * ) = 0;
-    virtual Expr *             visit( const AddressExpr          * ) = 0;
-    virtual Expr *             visit( const LabelAddressExpr     * ) = 0;
-    virtual Expr *             visit( const CastExpr             * ) = 0;
-    virtual Expr *             visit( const KeywordCastExpr      * ) = 0;
-    virtual Expr *             visit( const VirtualCastExpr      * ) = 0;
-    virtual Expr *             visit( const UntypedMemberExpr    * ) = 0;
-    virtual Expr *             visit( const MemberExpr           * ) = 0;
-    virtual Expr *             visit( const VariableExpr         * ) = 0;
-    virtual Expr *             visit( const ConstantExpr         * ) = 0;
-    virtual Expr *             visit( const SizeofExpr           * ) = 0;
-    virtual Expr *             visit( const AlignofExpr          * ) = 0;
-    virtual Expr *             visit( const UntypedOffsetofExpr  * ) = 0;
-    virtual Expr *             visit( const OffsetofExpr         * ) = 0;
-    virtual Expr *             visit( const OffsetPackExpr       * ) = 0;
-    virtual Expr *             visit( const AttrExpr             * ) = 0;
-    virtual Expr *             visit( const LogicalExpr          * ) = 0;
-    virtual Expr *             visit( const ConditionalExpr      * ) = 0;
-    virtual Expr *             visit( const CommaExpr            * ) = 0;
-    virtual Expr *             visit( const TypeExpr             * ) = 0;
-    virtual Expr *             visit( const AsmExpr              * ) = 0;
-    virtual Expr *             visit( const ImplicitCopyCtorExpr * ) = 0;
-    virtual Expr *             visit( const ConstructorExpr      * ) = 0;
-    virtual Expr *             visit( const CompoundLiteralExpr  * ) = 0;
-    virtual Expr *             visit( const RangeExpr            * ) = 0;
-    virtual Expr *             visit( const UntypedTupleExpr     * ) = 0;
-    virtual Expr *             visit( const TupleExpr            * ) = 0;
-    virtual Expr *             visit( const TupleIndexExpr       * ) = 0;
-    virtual Expr *             visit( const TupleAssignExpr      * ) = 0;
-    virtual Expr *             visit( const StmtExpr             * ) = 0;
-    virtual Expr *             visit( const UniqueExpr           * ) = 0;
-    virtual Expr *             visit( const UntypedInitExpr      * ) = 0;
-    virtual Expr *             visit( const InitExpr             * ) = 0;
-    virtual Expr *             visit( const DeletedExpr          * ) = 0;
-    virtual Expr *             visit( const DefaultArgExpr       * ) = 0;
-    virtual Expr *             visit( const GenericExpr          * ) = 0;
-    virtual Type *             visit( const VoidType             * ) = 0;
-    virtual Type *             visit( const BasicType            * ) = 0;
-    virtual Type *             visit( const PointerType          * ) = 0;
-    virtual Type *             visit( const ArrayType            * ) = 0;
-    virtual Type *             visit( const ReferenceType        * ) = 0;
-    virtual Type *             visit( const QualifiedType        * ) = 0;
-    virtual Type *             visit( const FunctionType         * ) = 0;
-    virtual Type *             visit( const StructInstType       * ) = 0;
-    virtual Type *             visit( const UnionInstType        * ) = 0;
-    virtual Type *             visit( const EnumInstType         * ) = 0;
-    virtual Type *             visit( const TraitInstType        * ) = 0;
-    virtual Type *             visit( const TypeInstType         * ) = 0;
-    virtual Type *             visit( const TupleType            * ) = 0;
-    virtual Type *             visit( const TypeofType           * ) = 0;
-    virtual Type *             visit( const AttrType             * ) = 0;
-    virtual Type *             visit( const VarArgsType          * ) = 0;
-    virtual Type *             visit( const ZeroType             * ) = 0;
-    virtual Type *             visit( const OneType              * ) = 0;
-    virtual Type *             visit( const GlobalScopeType      * ) = 0;
-    virtual Designation *      visit( const Designation          * ) = 0;
-    virtual Init *             visit( const SingleInit           * ) = 0;
-    virtual Init *             visit( const ListInit             * ) = 0;
-    virtual Init *             visit( const ConstructorInit      * ) = 0;
-    virtual Constant *         visit( const Constant             * ) = 0;
-    virtual Attribute *        visit( const Attribute            * ) = 0;
-    virtual TypeSubstitution * visit( const TypeSubstitution     * ) = 0;
+    virtual const ast::DeclWithType *     visit( const ast::ObjectDecl           * ) = 0;
+    virtual const ast::DeclWithType *     visit( const ast::FunctionDecl         * ) = 0;
+    virtual const ast::Decl *             visit( const ast::StructDecl           * ) = 0;
+    virtual const ast::Decl *             visit( const ast::UnionDecl            * ) = 0;
+    virtual const ast::Decl *             visit( const ast::EnumDecl             * ) = 0;
+    virtual const ast::Decl *             visit( const ast::TraitDecl            * ) = 0;
+    virtual const ast::Decl *             visit( const ast::TypeDecl             * ) = 0;
+    virtual const ast::Decl *             visit( const ast::TypedefDecl          * ) = 0;
+    virtual const ast::AsmDecl *          visit( const ast::AsmDecl              * ) = 0;
+    virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl     * ) = 0;
+    virtual const ast::CompoundStmt *     visit( const ast::CompoundStmt         * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ExprStmt             * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::AsmStmt              * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::DirectiveStmt        * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::IfStmt               * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::WhileStmt            * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ForStmt              * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::SwitchStmt           * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::CaseStmt             * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::BranchStmt           * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ReturnStmt           * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ThrowStmt            * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::TryStmt              * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::CatchStmt            * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::FinallyStmt          * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::WithStmt             * ) = 0;
+    virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::DeclStmt             * ) = 0;
+    virtual const ast::Stmt *             visit( const ast::ImplicitCtorDtorStmt * ) = 0;
+    virtual const ast::Expr *             visit( const ast::ApplicationExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UntypedExpr          * ) = 0;
+    virtual const ast::Expr *             visit( const ast::NameExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::AddressExpr          * ) = 0;
+    virtual const ast::Expr *             visit( const ast::LabelAddressExpr     * ) = 0;
+    virtual const ast::Expr *             visit( const ast::CastExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::KeywordCastExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::VirtualCastExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UntypedMemberExpr    * ) = 0;
+    virtual const ast::Expr *             visit( const ast::MemberExpr           * ) = 0;
+    virtual const ast::Expr *             visit( const ast::VariableExpr         * ) = 0;
+    virtual const ast::Expr *             visit( const ast::ConstantExpr         * ) = 0;
+    virtual const ast::Expr *             visit( const ast::SizeofExpr           * ) = 0;
+    virtual const ast::Expr *             visit( const ast::AlignofExpr          * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UntypedOffsetofExpr  * ) = 0;
+    virtual const ast::Expr *             visit( const ast::OffsetofExpr         * ) = 0;
+    virtual const ast::Expr *             visit( const ast::OffsetPackExpr       * ) = 0;
+    virtual const ast::Expr *             visit( const ast::AttrExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::LogicalExpr          * ) = 0;
+    virtual const ast::Expr *             visit( const ast::ConditionalExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::CommaExpr            * ) = 0;
+    virtual const ast::Expr *             visit( const ast::TypeExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::AsmExpr              * ) = 0;
+    virtual const ast::Expr *             visit( const ast::ImplicitCopyCtorExpr * ) = 0;
+    virtual const ast::Expr *             visit( const ast::ConstructorExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::CompoundLiteralExpr  * ) = 0;
+    virtual const ast::Expr *             visit( const ast::RangeExpr            * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UntypedTupleExpr     * ) = 0;
+    virtual const ast::Expr *             visit( const ast::TupleExpr            * ) = 0;
+    virtual const ast::Expr *             visit( const ast::TupleIndexExpr       * ) = 0;
+    virtual const ast::Expr *             visit( const ast::TupleAssignExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::StmtExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UniqueExpr           * ) = 0;
+    virtual const ast::Expr *             visit( const ast::UntypedInitExpr      * ) = 0;
+    virtual const ast::Expr *             visit( const ast::InitExpr             * ) = 0;
+    virtual const ast::Expr *             visit( const ast::DeletedExpr          * ) = 0;
+    virtual const ast::Expr *             visit( const ast::DefaultArgExpr       * ) = 0;
+    virtual const ast::Expr *             visit( const ast::GenericExpr          * ) = 0;
+    virtual const ast::Type *             visit( const ast::VoidType             * ) = 0;
+    virtual const ast::Type *             visit( const ast::BasicType            * ) = 0;
+    virtual const ast::Type *             visit( const ast::PointerType          * ) = 0;
+    virtual const ast::Type *             visit( const ast::ArrayType            * ) = 0;
+    virtual const ast::Type *             visit( const ast::ReferenceType        * ) = 0;
+    virtual const ast::Type *             visit( const ast::QualifiedType        * ) = 0;
+    virtual const ast::Type *             visit( const ast::FunctionType         * ) = 0;
+    virtual const ast::Type *             visit( const ast::StructInstType       * ) = 0;
+    virtual const ast::Type *             visit( const ast::UnionInstType        * ) = 0;
+    virtual const ast::Type *             visit( const ast::EnumInstType         * ) = 0;
+    virtual const ast::Type *             visit( const ast::TraitInstType        * ) = 0;
+    virtual const ast::Type *             visit( const ast::TypeInstType         * ) = 0;
+    virtual const ast::Type *             visit( const ast::TupleType            * ) = 0;
+    virtual const ast::Type *             visit( const ast::TypeofType           * ) = 0;
+    virtual const ast::Type *             visit( const ast::AttrType             * ) = 0;
+    virtual const ast::Type *             visit( const ast::VarArgsType          * ) = 0;
+    virtual const ast::Type *             visit( const ast::ZeroType             * ) = 0;
+    virtual const ast::Type *             visit( const ast::OneType              * ) = 0;
+    virtual const ast::Type *             visit( const ast::GlobalScopeType      * ) = 0;
+    virtual const ast::Designation *      visit( const ast::Designation          * ) = 0;
+    virtual const ast::Init *             visit( const ast::SingleInit           * ) = 0;
+    virtual const ast::Init *             visit( const ast::ListInit             * ) = 0;
+    virtual const ast::Init *             visit( const ast::ConstructorInit      * ) = 0;
+    virtual const ast::Constant *         visit( const ast::Constant             * ) = 0;
+    virtual const ast::Attribute *        visit( const ast::Attribute            * ) = 0;
+    virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) = 0;
 };
 
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 712348a6bab746947dbfecacd0d8d02b9ce19734)
+++ src/AST/porting.md	(revision 6d51bd7cd93d2958aac506ca3e6ef1f91b13168b)
@@ -8,5 +8,5 @@
 ## Visitors ##
 * `Visitor` and `Mutator` are combined into a single `ast::Visitor` class
-  * Base nodes now override `Node* accept( Visitor& v ) = 0` with, e.g. `Stmt* accept( Visitor& v ) override = 0`
+  * Base nodes now override `const Node * accept( Visitor & v ) const = 0` with, e.g. `const Stmt * accept( Visitor & v ) const override = 0`
 * `PassVisitor` is replaced with `ast::Pass`
 
@@ -24,5 +24,9 @@
 `clone` is private to `Node` now
 * still needs to be overriden to return appropriate type
-  * e.g. `private: virtual Stmt* clone() const override = 0;`
+  * e.g. `private: virtual Stmt * clone() const override = 0;`
+  * because friendship is not inherited, all implementations of clone need
+      /// Must be copied in ALL derived classes
+      template<typename node_t>
+      friend auto mutate(const node_t * node);
 
 All leaves of the `Node` inheritance tree are now declared `final`
