Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 276f105254aa4738569d87456723e9b72f7a5a42)
+++ src/AST/Pass.impl.hpp	(revision c15085d61a6b626ea93abfe66835758c4493d486)
@@ -28,4 +28,6 @@
 	/* setup the scope for passes that want to run code at exit */ \
 	__attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (pass, 0) ); \
+	/* begin tracing memory allocation if requested by this pass */ \
+	__pass::beginTrace( pass, 0 ); \
 	/* call the implementation of the previsit of this pass */ \
 	__pass::previsit( pass, node, 0 );
@@ -42,4 +44,6 @@
 	auto __return = __pass::postvisit( pass, node, 0 ); \
 	assertf(__return, "post visit should never return null"); \
+	/* end tracing memory allocation if requested by this pass */ \
+	__pass::endTrace( pass, 0 ); \
 	return __return;
 
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 276f105254aa4738569d87456723e9b72f7a5a42)
+++ src/AST/Pass.proto.hpp	(revision c15085d61a6b626ea93abfe66835758c4493d486)
@@ -16,4 +16,6 @@
 #pragma once
 // IWYU pragma: private, include "Pass.hpp"
+
+#include "Common/Stats/Heap.h"
 
 namespace ast {
@@ -244,4 +246,20 @@
 	#undef FIELD_PTR
 
+	template< typename pass_t >
+	static inline auto beginTrace(pass_t & pass, int) -> decltype( pass_t::traceId, void() ) {
+		Stats::Heap::stacktrace_push(pass_t::traceId);
+	}
+
+	template< typename pass_t > 
+	static inline auto endTrace(pass_t & pass, int) -> decltype( pass_t::traceId, void() ) {
+		Stats::Heap::stacktrace_pop();
+	}
+
+	template< typename pass_t >
+	static void beginTrace(pass_t &, long) {}
+
+	template< typename pass_t >
+	static void endTrace(pass_t &, long) {}
+
 	// Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
 	// All passes which have such functions are assumed desire this behaviour
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 276f105254aa4738569d87456723e9b72f7a5a42)
+++ src/AST/TypeSubstitution.cpp	(revision c15085d61a6b626ea93abfe66835758c4493d486)
@@ -18,4 +18,7 @@
 
 namespace ast {
+
+
+size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
 
 TypeSubstitution::TypeSubstitution() {
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 276f105254aa4738569d87456723e9b72f7a5a42)
+++ src/AST/TypeSubstitution.hpp	(revision c15085d61a6b626ea93abfe66835758c4493d486)
@@ -160,4 +160,5 @@
 // definitition must happen after PassVisitor is included so that WithGuards can be used
 struct TypeSubstitution::Substituter : public WithGuards, public WithVisitorRef<Substituter> {
+		static size_t traceId;
 
 		Substituter( const TypeSubstitution & sub, bool freeOnly ) : sub( sub ), freeOnly( freeOnly ) {}
