Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.hpp	(revision cdb4eaa683e28a6751e0b414eb1f7d519898ac0c)
@@ -252,23 +252,13 @@
 private:
 
-	__pass::result1<ast::Stmt> call_accept( const ast::Stmt * );
-	__pass::result1<ast::Expr> call_accept( const ast::Expr * );
-
-	/// This has a `type` member that is the return type for the
-	/// generic call_accept if the generic call_accept is defined.
+	/// The return type of the general call_accept function.
 	template< typename node_t >
-	using generic_call_accept_result =
-		std::enable_if<
-				!std::is_base_of<ast::Expr, node_t>::value &&
-				!std::is_base_of<ast::Stmt, node_t>::value
-			, __pass::result1<
-				typename std::remove_pointer< typename std::result_of<
-					decltype(&node_t::accept)(node_t*, type&) >::type >::type
-			>
+	using call_accept_result_t = __pass::result1<
+		typename std::remove_pointer< typename std::result_of<
+			decltype(&node_t::accept)(node_t*, type&) >::type >::type
 		>;
 
 	template< typename node_t >
-	auto call_accept( const node_t * node )
-		-> typename generic_call_accept_result<node_t>::type;
+	auto call_accept( const node_t * node ) -> call_accept_result_t<node_t>;
 
 	// requests WithStmtsToAdd directly add to this statement, as if it is a compound.
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.impl.hpp	(revision cdb4eaa683e28a6751e0b414eb1f7d519898ac0c)
@@ -109,16 +109,4 @@
 		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, 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();
-	}
 }
 
@@ -126,37 +114,10 @@
 template< typename node_t >
 auto ast::Pass< core_t >::call_accept( const node_t * node ) ->
-	typename ast::Pass< core_t >::template generic_call_accept_result<node_t>::type
-{
+		ast::Pass< core_t >::call_accept_result_t<node_t> {
 	__pedantic_pass_assert( __visit_children() );
 	__pedantic_pass_assert( node );
 
-	static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR" );
-	static_assert( !std::is_base_of<ast::Stmt, node_t>::value, "ERROR" );
-
 	auto nval = node->accept( *this );
-	__pass::result1<
-		typename std::remove_pointer< decltype( node->accept(*this) ) >::type
-	> res;
-	res.differs = nval != node;
-	res.value = nval;
-	return res;
-}
-
-template< typename core_t >
-ast::__pass::template result1<ast::Expr> ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
-	__pedantic_pass_assert( __visit_children() );
-	__pedantic_pass_assert( expr );
-
-	auto nval = expr->accept( *this );
-	return { nval != expr, nval };
-}
-
-template< typename core_t >
-ast::__pass::template result1<ast::Stmt> ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
-	__pedantic_pass_assert( __visit_children() );
-	__pedantic_pass_assert( stmt );
-
-	const ast::Stmt * nval = stmt->accept( *this );
-	return { nval != stmt, nval };
+	return { nval != node, nval };
 }
 
@@ -230,5 +191,5 @@
 ast::__pass::template resultNstmt<container_t> ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
 	__pedantic_pass_assert( __visit_children() );
-	if ( statements.empty() ) return {};
+	__pedantic_pass_assert( !statements.empty() );
 
 	// We are going to aggregate errors for all these statements
@@ -263,5 +224,4 @@
 			const ast::Stmt * new_stmt = stmt->accept( *this );
 			assert( new_stmt );
-			if ( new_stmt != stmt ) { new_kids.differs = true; }
 
 			// Make sure that it is either adding statements or declartions but not both
@@ -276,7 +236,8 @@
 			// Now add the statement if there is one
 			if ( new_stmt != stmt ) {
-				new_kids.values.emplace_back( new_stmt, i, false );
+				new_kids.differs = true;
+				new_kids.values.emplace_back( new_stmt );
 			} else {
-				new_kids.values.emplace_back( nullptr, i, true );
+				new_kids.values.emplace_back( i );
 			}
 
@@ -298,5 +259,7 @@
 ast::__pass::template resultN<container_t, node_t> ast::Pass< core_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
 	__pedantic_pass_assert( __visit_children() );
-	if ( container.empty() ) return {};
+	__pedantic_pass_assert( !container.empty() );
+
+	// Collect errors from processing all these nodes.
 	SemanticErrorException errors;
 
@@ -342,11 +305,8 @@
 	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 ( new_val.differs ) {
+	auto result = call_accept( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply(new_parent, field);
+		result.apply( new_parent, field );
 		parent = new_parent;
 	}
@@ -366,11 +326,8 @@
 	static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
 
-	auto new_val = call_accept_top( old_val );
-
-	static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value /* || std::is_same<int, decltype(old_val)>::value */, "ERROR" );
-
-	if ( new_val.differs ) {
+	auto result = call_accept_top( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply(new_parent, field);
+		result.apply( new_parent, field );
 		parent = new_parent;
 	}
@@ -390,11 +347,8 @@
 	static_assert( !std::is_same<const ast::Node * &, decltype(old_val)>::value, "ERROR" );
 
-	auto new_val = call_accept_as_compound( old_val );
-
-	static_assert( !std::is_same<const ast::Node *, decltype(new_val)>::value || std::is_same<int, decltype(old_val)>::value, "ERROR" );
-
-	if ( new_val.differs ) {
+	auto result = call_accept_as_compound( old_val );
+	if ( result.differs ) {
 		auto new_parent = __pass::mutate<core_t>(parent);
-		new_val.apply( new_parent, child );
+		result.apply( new_parent, child );
 		parent = new_parent;
 	}
@@ -452,5 +406,5 @@
 template< typename core_t >
 inline void ast::accept_all( ast::TranslationUnit & unit, ast::Pass< core_t > & visitor ) {
-	if ( auto ptr = __pass::translation_unit::get_cptr( visitor.core, 0 ) ) {
+	if ( auto ptr = __pass::translationUnit( visitor.core, 0 ) ) {
 		ValueGuard<const TranslationUnit *> guard( *ptr );
 		*ptr = &unit;
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision af746ccdf606483f8f89907b52e8b9471c72df7c)
+++ src/AST/Pass.proto.hpp	(revision cdb4eaa683e28a6751e0b414eb1f7d519898ac0c)
@@ -154,6 +154,6 @@
 		bool is_old;
 
-		delta(const Stmt * s, ssize_t i, bool old) :
-			new_val(s), old_idx(i), is_old(old) {}
+		explicit delta(const Stmt * s) : new_val(s), old_idx(-1), is_old(false) {}
+		explicit delta(ssize_t i) : new_val(nullptr), old_idx(i), is_old(true) {}
 	};
 
@@ -188,5 +188,5 @@
 		std::transform( stmts->begin(), stmts->end(), std::back_inserter( values ),
 			[](ast::ptr<ast::Stmt>& stmt) -> delta {
-				return delta( stmt.release(), -1, false );
+				return delta( stmt.release() );
 			});
 		stmts->clear();
@@ -201,5 +201,5 @@
 			[](ast::ptr<ast::Decl>& decl) -> delta {
 				ast::Decl const * d = decl.release();
-				return delta( new DeclStmt( d->location, d ), -1, false );
+				return delta( new DeclStmt( d->location, d ) );
 			});
 		decls->clear();
@@ -226,50 +226,4 @@
 		// Now the original containers should still have the unchanged values
 		// but also contain the new values.
-	}
-};
-
-/// Used by previsit implementation
-/// We need to reassign the result to 'node', unless the function
-/// returns void, then we just leave 'node' unchanged
-template<bool is_void>
-struct __assign;
-
-template<>
-struct __assign<true> {
-	template<typename core_t, typename node_t>
-	static inline void result( core_t & core, const node_t * & node ) {
-		core.previsit( node );
-	}
-};
-
-template<>
-struct __assign<false> {
-	template<typename core_t, typename node_t>
-	static inline void result( core_t & core, const node_t * & node ) {
-		node = core.previsit( node );
-		assertf(node, "Previsit must not return NULL");
-	}
-};
-
-/// Used by postvisit implementation
-/// We need to return the result unless the function
-/// returns void, then we just return the original node
-template<bool is_void>
-struct __return;
-
-template<>
-struct __return<true> {
-	template<typename core_t, typename node_t>
-	static inline const node_t * result( core_t & core, const node_t * & node ) {
-		core.postvisit( node );
-		return node;
-	}
-};
-
-template<>
-struct __return<false> {
-	template<typename core_t, typename node_t>
-	static inline auto result( core_t & core, const node_t * & node ) {
-		return core.postvisit( node );
 	}
 };
@@ -297,9 +251,12 @@
 	);
 
-	__assign<
-		std::is_void<
-			decltype( core.previsit( node ) )
-		>::value
-	>::result( core, node );
+	// We need to reassign the result to 'node', unless the function
+	// returns void, then we just leave 'node' unchanged
+	if constexpr ( std::is_void_v<decltype( core.previsit( node ) )> ) {
+		core.previsit( node );
+	} else {
+		node = core.previsit( node );
+		assertf( node, "Previsit must not return nullptr." );
+	}
 }
 
@@ -312,9 +269,12 @@
 	decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
 {
-	return __return<
-		std::is_void<
-			decltype( core.postvisit( node ) )
-		>::value
-	>::result( core, node );
+	// We need to return the result unless the function
+	// returns void, then we just return the original node
+	if constexpr ( std::is_void_v<decltype( core.postvisit( node ) )> ) {
+		core.postvisit( node );
+		return node;
+	} else {
+		return core.postvisit( node );
+	}
 }
 
@@ -350,4 +310,5 @@
 FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
 FIELD_PTR( visitor, ast::Pass<core_t> * const )
+FIELD_PTR( translationUnit, const TranslationUnit * )
 
 // Remove the macro to make sure we don't clash
@@ -546,18 +507,4 @@
 } // namespace forall
 
-// For passes that need access to the global context. Searches `translationUnit`
-namespace translation_unit {
-	template<typename core_t>
-	static inline auto get_cptr( core_t & core, int )
-			-> decltype( &core.translationUnit ) {
-		return &core.translationUnit;
-	}
-
-	template<typename core_t>
-	static inline const TranslationUnit ** get_cptr( core_t &, long ) {
-		return nullptr;
-	}
-}
-
 // For passes, usually utility passes, that have a result.
 namespace result {
