Index: benchmark/benchcltr.hfa
===================================================================
--- benchmark/benchcltr.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ benchmark/benchcltr.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1,8 +1,16 @@
 #pragma once
+#include <assert.h>
+#include <stdint.h>
 
-#include <assert.h>
-#include <kernel.hfa>
-#include <thread.hfa>
-#include <stats.hfa>
+#ifdef __cforall
+	#include <kernel.hfa>
+	#include <thread.hfa>
+	#include <stats.hfa>
+#else
+#include <time.h>										// timespec
+#include <sys/time.h>									// timeval
+
+enum { TIMEGRAN = 1000000000LL };					// nanosecond granularity, except for timeval
+#endif
 
 #define BENCH_OPT_SHORT "d:p:t:SPV"
@@ -14,9 +22,4 @@
 	{"procstat",     no_argument      , 0, 'P'}, \
 	{"viewhalts",    no_argument      , 0, 'V'},
-
-#define BENCH_DECL \
-	double duration = 5; \
-	int nprocs = 1; \
-	int nthreads = 1;
 
 #define BENCH_OPT_CASE \
@@ -52,7 +55,24 @@
 		break;
 
+double duration = 5;
+int nprocs = 1;
+int nthreads = 1;
 bool silent = false;
+bool continuous = false;
 bool procstats = false;
 bool viewhalts = false;
+
+#define BENCH_OPT_CFA \
+	{'d', "duration",  "Duration of the experiments in seconds", duration }, \
+	{'t', "nthreads",  "Number of threads to use", nthreads }, \
+	{'p', "nprocs",    "Number of processors to use", nprocs }, \
+	{'S', "nostats",   "Don't print statistics", silent, parse_settrue }, \
+	{'C', "constats",  "Regularly print statistics", continuous, parse_settrue }, \
+	{'P', "procstat",  "Print statistics for each processors", procstats, parse_settrue }, \
+	{'V', "viewhalts", "Visualize halts, prints timestamp and Processor id for each halt.", viewhalts, parse_settrue },
+
+#ifdef __cforall
+#include <parseargs.hfa>
+
 struct cluster * the_benchmark_cluster = 0p;
 struct BenchCluster {
@@ -60,6 +80,6 @@
 };
 
-void ?{}( BenchCluster & this, int flags, int stats ) {
-	(this.self){ "Benchmark Cluster", flags };
+void ?{}( BenchCluster & this, int num_io, const io_context_params & io_params, int stats ) {
+	(this.self){ "Benchmark Cluster", num_io, io_params };
 
 	assert( the_benchmark_cluster == 0p );
@@ -105,4 +125,32 @@
 	}
 }
+#else
+uint64_t getTimeNsec() {
+	timespec curr;
+	clock_gettime( CLOCK_REALTIME, &curr );
+	return (int64_t)curr.tv_sec * TIMEGRAN + curr.tv_nsec;
+}
+
+uint64_t to_miliseconds( uint64_t durtn ) { return durtn / (TIMEGRAN / 1000LL); }
+double to_fseconds(uint64_t durtn ) { return durtn / (double)TIMEGRAN; }
+uint64_t from_fseconds(double sec) { return sec * TIMEGRAN; }
+
+
+void wait_duration(double duration, uint64_t & start, uint64_t & end, bool is_tty) {
+	for(;;) {
+		usleep(100000);
+		end = getTimeNsec();
+		uint64_t delta = end - start;
+		/*if(is_tty)*/ {
+			printf(" %.1f\r", to_fseconds(delta));
+			fflush(stdout);
+		}
+		if( delta >= from_fseconds(duration) ) {
+			break;
+		}
+	}
+}
+#endif
+
 
 void bench_usage( char * argv [] ) {
Index: benchmark/io/http/options.cfa
===================================================================
--- benchmark/io/http/options.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ benchmark/io/http/options.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,7 +10,5 @@
 
 #include <kernel.hfa>
-
-#include "parseargs.hfa"
-
+#include <parseargs.hfa>
 
 Options options @= {
Index: nchmark/io/http/parseargs.cfa
===================================================================
--- benchmark/io/http/parseargs.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ 	(revision )
@@ -1,192 +1,0 @@
-#include "parseargs.hfa"
-
-// #include <stdio.h>
-// #include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-extern "C" {
-	#include <getopt.h>
-	#include <sys/ioctl.h>
-
-	struct FILE;
-	extern FILE * stderr;
-	extern FILE * stdout;
-
-	extern int fileno(FILE *stream);
-
-	extern int fprintf ( FILE * stream, const char * format, ... );
-
-	extern          long long int strtoll (const char* str, char** endptr, int base);
-	extern unsigned long long int strtoull(const char* str, char** endptr, int base);
-}
-
-#include <common.hfa>
-#include <limits.hfa>
-
-void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
-	int hwidth = max - (11 + width);
-	if(hwidth <= 0) hwidth = max;
-
-	fprintf(out, "  -%c, --%-*s   %.*s\n", sn, width, ln, hwidth, help);
-	for() {
-		help += min(strlen(help), hwidth);
-		if('\0' == *help) break;
-		fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
-	}
-}
-
-void parse_args(
-	int argc,
-	char * argv[],
-	cfa_option options[],
-	size_t opt_count,
-	const char * usage,
-	char ** & left
-) {
-	struct option optarr[opt_count + 2];
-	int width = 0;
-	int max_width = 1_000_000;
-	{
-		int idx = 0;
-		for(i; opt_count) {
-			if(options[i].long_name) {
-				optarr[idx].name = options[i].long_name;
-				optarr[idx].flag = 0p;
-				optarr[idx].val  = options[i].short_name;
-				if(    ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue)
-				    || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) {
-					optarr[idx].has_arg = no_argument;
-				} else {
-					optarr[idx].has_arg = required_argument;
-				}
-				idx++;
-
-				int w = strlen(options[i].long_name);
-				if(w > width) width = w;
-			}
-		}
-		optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0p, 'h'];
-		optarr[idx+1].[name, has_arg, flag, val] = [0p, no_argument, 0p, 0];
-	}
-
-	char optstring[opt_count * 3] = { '\0' };
-	{
-		int idx = 0;
-		for(i; opt_count) {
-			optstring[idx] = options[i].short_name;
-			idx++;
-			if(    ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
-			    && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
-				optstring[idx] = ':';
-				idx++;
-			}
-		}
-		optstring[idx+0] = 'h';
-		optstring[idx+1] = '\0';
-	}
-
-	FILE * out = stderr;
-	NEXT_ARG:
-	for() {
-		int idx = 0;
-		int opt = getopt_long(argc, argv, optstring, optarr, &idx);
-		switch(opt) {
-			case -1:
-				if(&left != 0p) left = argv + optind;
-				return;
-			case 'h':
-				out = stdout;
-			case '?':
-				goto USAGE;
-			default:
-				for(i; opt_count) {
-					if(opt == options[i].short_name) {
-						const char * arg = optarg ? optarg : "";
-						bool success = options[i].parse( arg, options[i].variable );
-						if(success) continue NEXT_ARG;
-
-						fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
-						goto USAGE;
-					}
-				}
-				abort("Internal parse arg error\n");
-		}
-
-	}
-
-	USAGE:;
-	int outfd = fileno(out);
-	if(isatty(outfd)) {
-		struct winsize size;
-		int ret = ioctl(outfd, TIOCGWINSZ, &size);
-		if(ret < 0) abort( "ioctl error: (%d) %s\n", (int)errno, strerror(errno) );
-		max_width = size.ws_col;
-	}
-
-	fprintf(out, "Usage:\n  %s %s\n", argv[0], usage);
-
-	for(i; opt_count) {
-		printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
-	}
-	fprintf(out, "  -%c, --%-*s   %s\n", 'h', width, "help", "print this help message");
-	exit(out == stdout ? 0 : 1);
-}
-
-bool parse_yesno(const char * arg, bool & value ) {
-	if(strcmp(arg, "yes") == 0) {
-		value = true;
-		return true;
-	}
-
-	if(strcmp(arg, "no") == 0) {
-		value = false;
-		return true;
-	}
-
-	return false;
-}
-
-bool parse_settrue (const char *, bool & value ) {
-	value = true;
-	return true;
-}
-
-bool parse_setfalse(const char *, bool & value )  {
-	value = false;
-	return true;
-}
-
-bool parse(const char * arg, const char * & value ) {
-	value = arg;
-	return true;
-}
-
-bool parse(const char * arg, unsigned & value) {
-	char * end;
-	unsigned long long int r = strtoull(arg, &end, 10);
-	if(*end != '\0') return false;
-	if(r > (unsigned)MAX) return false;
-
-	value = r;
-	return true;
-}
-
-bool parse(const char * arg, size_t & value) {
-	char * end;
-	unsigned long long int r = strtoull(arg, &end, 10);
-	if(*end != '\0') return false;
-	if(r > (size_t)MAX) return false;
-
-	value = r;
-	return true;
-}
-
-bool parse(const char * arg, int & value) {
-	char * end;
-	int r = strtoll(arg, &end, 10);
-	if(*end != '\0') return false;
-
-	value = r;
-	return true;
-}
Index: nchmark/io/http/parseargs.hfa
===================================================================
--- benchmark/io/http/parseargs.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ 	(revision )
@@ -1,42 +1,0 @@
-#pragma once
-
-struct cfa_option {
-      char short_name;
-      const char * long_name;
-      const char * help;
-      void * variable;
-      bool (*parse)(const char *, void * );
-};
-
-extern cfa_option last_option;
-
-static inline void ?{}( cfa_option & this ) {}
-
-forall(dtype T | { bool parse(const char *, T & ); })
-static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable ) {
-      this.short_name = short_name;
-      this.long_name  = long_name;
-      this.help       = help;
-      this.variable   = (void*)&variable;
-      this.parse      = (bool (*)(const char *, void * ))parse;
-}
-
-forall(dtype T)
-static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable, bool (*parse)(const char *, T & )) {
-      this.short_name = short_name;
-      this.long_name  = long_name;
-      this.help       = help;
-      this.variable   = (void*)&variable;
-      this.parse      = (bool (*)(const char *, void * ))parse;
-}
-
-void parse_args( int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, char ** & left );
-
-bool parse_yesno   (const char *, bool & );
-bool parse_settrue (const char *, bool & );
-bool parse_setfalse(const char *, bool & );
-
-bool parse(const char *, const char * & );
-bool parse(const char *, unsigned & );
-bool parse(const char *, size_t & );
-bool parse(const char *, int & );
Index: benchmark/io/readv-posix.c
===================================================================
--- benchmark/io/readv-posix.c	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ benchmark/io/readv-posix.c	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,138 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+	#include <locale.h>
+	#include <getopt.h>
+	#include <fcntl.h>
+	#include <sys/uio.h>
+}
+
+#include <unistd.h>
+
+#include <pthread.h>
+
+#include "../benchcltr.hfa"
+
+int fd;
+volatile bool run = false;
+volatile size_t count = 0;
+
+unsigned long int buflen = 50;
+
+void * reader_main( void * arg ) {
+      pthread_barrier_wait( (pthread_barrier_t*) arg );
+	/* paranoid */ assert( true == __atomic_load_n(&run, __ATOMIC_RELAXED) );
+
+	char data[buflen];
+	struct iovec iov = { data, buflen };
+
+	while(__atomic_load_n(&run, __ATOMIC_RELAXED)) {
+		int r = preadv2(fd, &iov, 1, 0, 0);
+		if(r < 0) {
+                  fprintf(stderr, "%s\n", strerror(-r));
+                  abort();
+            }
+
+		__atomic_fetch_add( &count, 1, __ATOMIC_SEQ_CST );
+	}
+
+      return NULL;
+}
+
+int main(int argc, char * argv[]) {
+	unsigned flags = 0;
+	unsigned sublen = 16;
+
+      setlocale(LC_ALL, "");
+
+	for(;;) {
+		static struct option options[] = {
+			BENCH_OPT_LONG
+			{"polled-io",    required_argument, 0, 'i'},
+			{"bufsize",      required_argument, 0, 'b'},
+			{0, 0, 0, 0}
+		};
+
+		int idx = 0;
+		int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "ib:", options, &idx);
+
+		const char * arg = optarg ? optarg : "";
+		char * end;
+		switch(opt) {
+			// Exit Case
+			case -1:
+				goto arg_loop;
+			BENCH_OPT_CASE
+			case 'i':
+				flags |= O_DIRECT;
+				break;
+			case 'b':
+				buflen = strtoul(arg, &end, 10);
+				if(*end != '\0' && buflen < 10) {
+					fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg);
+					goto usage;
+				}
+				break;
+			default: /* ? */
+				fprintf(stderr, "%d\n", opt);
+			usage:
+				bench_usage( argv );
+				fprintf( stderr, "  -i, --polled-io          If set opens the file with O_DIRECT\n" );
+				fprintf( stderr, "  -b, --buflen=SIZE        Number of bytes to read per request\n" );
+				exit(EXIT_FAILURE);
+		}
+	}
+      arg_loop:
+
+	fd = open(__FILE__, flags);
+	if(fd < 0) {
+		fprintf(stderr, "Could not open source file\n");
+		exit(EXIT_FAILURE);
+	}
+
+	printf("Running %d threads, reading %lu bytes each, over %d processors for %f seconds\n", nthreads, buflen, nprocs, duration);
+
+	{
+		uint64_t start, end;
+		{
+			pthread_barrier_t barrier;
+                  pthread_barrier_init(&barrier, NULL, nthreads + 1);
+			{
+				pthread_t threads[nthreads];
+                        for(int i = 0; i < nthreads; i++) {
+                        	pthread_attr_t attr;
+                              pthread_attr_init( &attr );
+                              pthread_create( &threads[i], &attr, reader_main, &barrier );
+                        }
+
+				printf("Starting\n");
+				bool is_tty = isatty(STDOUT_FILENO);
+				start = getTimeNsec();
+				run = true;
+
+				pthread_barrier_wait( &barrier );
+				wait_duration(duration, start, end, is_tty);
+
+				run = false;
+				end = getTimeNsec();
+				printf("\nDone\n");
+
+                        for(int i = 0; i < nthreads; i++) {
+                              void * ret;
+                              pthread_join( threads[i], &ret );
+                        }
+			}
+                  pthread_barrier_destroy(&barrier);
+		}
+		printf("Took %'ld ms\n", to_miliseconds(end - start));
+		printf("Total reads      : %'15zu\n", count);
+		printf("Reads per second : %'18.2lf\n", ((double)count) / to_fseconds(end - start));
+		printf("Total read size  : %'15zu\n", buflen * count);
+		printf("Bytes per second : %'18.2lf\n", ((double)count * buflen) / to_fseconds(end - start));
+	}
+
+	close(fd);
+}
Index: benchmark/io/readv.cfa
===================================================================
--- benchmark/io/readv.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ benchmark/io/readv.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -40,5 +40,11 @@
 int do_read(int fd, struct iovec * iov) {
 	// extern ssize_t cfa_preadv2(int, const struct iovec *, int, off_t, int, int = 0, Duration = -1`s, io_cancellation * = 0p, io_context * = 0p);
-	int sflags = 0;
+	int sflags = 0
+	#if defined(CFA_HAVE_IOSQE_ASYNC)
+		| CFA_IO_ASYNC
+	#else
+	#warning no CFA_IO_ASYNC support
+	#endif
+	;
 	if(fixed_file) {
 		sflags |= CFA_IO_FIXED_FD1;
@@ -63,80 +69,54 @@
 
 int main(int argc, char * argv[]) {
-	BENCH_DECL
+	int file_flags = 0;
 	unsigned num_io = 1;
-	io_context_params params;
-	int file_flags = 0;
 	unsigned sublen = 16;
+	unsigned nentries = 0;
 
-	arg_loop:
-	for(;;) {
-		static struct option options[] = {
-			BENCH_OPT_LONG
-			{"bufsize",       required_argument, 0, 'b'},
-			{"submitthread",  no_argument      , 0, 's'},
-			{"eagersubmit",   no_argument      , 0, 'e'},
-			{"kpollsubmit",   no_argument      , 0, 'k'},
-			{"kpollcomplete", no_argument      , 0, 'i'},
-			{"fixed-files",   no_argument      , 0, 'f'},
-			{"open-direct",   no_argument      , 0, 'o'},
-			{"submitlength",  required_argument, 0, 'l'},
-			{0, 0, 0, 0}
-		};
+	bool subthrd = false;
+	bool subeagr = false;
+	bool odirect = false;
+	bool kpollsb = false;
+	bool kpollcp = false;
 
-		int idx = 0;
-		int opt = getopt_long(argc, argv, BENCH_OPT_SHORT "b:sekil:", options, &idx);
+	cfa_option opt[] = {
+		BENCH_OPT_CFA
+		{'b', "bufsize",       "Number of bytes to read per request", buflen},
+		{'s', "submitthread",  "If set, cluster uses polling thread to submit I/O", subthrd, parse_settrue},
+		{'e', "eagersubmit",   "If set, cluster submits I/O eagerly but still aggregates submits", subeagr, parse_settrue},
+		{'f', "fixed-files",   "Pre-register files with the io_contexts", fixed_file, parse_settrue},
+		{'o', "open-direct",   "Open files with O_DIRECT flag, bypassing the file cache", odirect, parse_settrue},
+		{'k', "kpollsubmit",   "If set, cluster uses an in kernel thread to poll submission, implies -f, requires elevated permissions", kpollsb, parse_settrue},
+		{'i', "kpollcomplete", "If set, cluster polls fds for completions instead of relying on interrupts to get notifications, implies -o", kpollcp, parse_settrue},
+		{'l', "submitlength",  "Size of the buffer that stores ready submissions", sublen},
+		{'r', "numentries",    "Number of entries each of the io_context have", nentries},
+		{'n', "numcontexts",   "Number of io_contexts to the cluster", num_io},
+	};
+	int opt_cnt = sizeof(opt) / sizeof(cfa_option);
 
-		const char * arg = optarg ? optarg : "";
-		char * end;
-		switch(opt) {
-			// Exit Case
-			case -1:
-				break arg_loop;
-			BENCH_OPT_CASE
-			case 'b':
-				buflen = strtoul(arg, &end, 10);
-				if(*end != '\0' && buflen < 10) {
-					fprintf(stderr, "Buffer size must be at least 10, was %s\n", arg);
-					goto usage;
-				}
-				break;
-			case 's':
-				params.poller_submits = true;
-				break;
-			case 'e':
-				params.eager_submits = true;
-				break;
-			case 'k':
-				params.poll_submit = true;
-			case 'f':
-				fixed_file = true;
-				break;
-			case 'i':
-				params.poll_complete = true;
-			case 'o':
-				file_flags |= O_DIRECT;
-				break;
-			case 'l':
-				sublen = strtoul(arg, &end, 10);
-				if(*end != '\0' && sublen < 16) {
-					fprintf(stderr, "Submit length must be at least 16, was %s\n", arg);
-					goto usage;
-				}
-				// flags |= (sublen << CFA_CLUSTER_IO_BUFFLEN_OFFSET);
-				break;
-			default: /* ? */
-				fprintf(stderr, "%d\n", opt);
-			usage:
-				bench_usage( argv );
-				fprintf( stderr, "  -b, --buflen=SIZE        Number of bytes to read per request\n" );
-				fprintf( stderr, "  -u, --userthread         If set, cluster uses user-thread to poll I/O\n" );
-				fprintf( stderr, "  -s, --submitthread       If set, cluster uses polling thread to submit I/O\n" );
-				fprintf( stderr, "  -e, --eagersubmit        If set, cluster submits I/O eagerly but still aggregates submits\n" );
-				fprintf( stderr, "  -k, --kpollsubmit        If set, cluster uses IORING_SETUP_SQPOLL\n" );
-				fprintf( stderr, "  -i, --kpollcomplete      If set, cluster uses IORING_SETUP_IOPOLL\n" );
-				fprintf( stderr, "  -l, --submitlength=LEN   Max number of submitions that can be submitted together\n" );
-				exit(EXIT_FAILURE);
+	char **left;
+	parse_args( opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
+
+	if(kpollcp || odirect) {
+		if( (buflen % 512) != 0 ) {
+			fprintf(stderr, "Buffer length must be a multiple of 512 when using O_DIRECT, was %lu\n\n", buflen);
+			print_args_usage(opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", true);
 		}
 	}
+
+	io_context_params params;
+
+	if( subthrd ) params.poller_submits = true;
+	if( subeagr ) params.eager_submits  = true;
+	if( kpollsb ) params.poll_submit    = true;
+	if( kpollcp ) params.poll_complete  = true;
+
+	if(params.poll_submit  ) fixed_file = true;
+	if(params.poll_complete) odirect    = true;
+
+	params.num_ready = sublen;
+	params.num_entries = nentries;
+
+	if(odirect) file_flags |= O_DIRECT;
 
 	int lfd = open(__FILE__, file_flags);
Index: benchmark/readyQ/yield.cfa
===================================================================
--- benchmark/readyQ/yield.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ benchmark/readyQ/yield.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -43,29 +43,14 @@
 
 int main(int argc, char * argv[]) {
-	BENCH_DECL
+	unsigned num_io = 1;
+	io_context_params params;
 
-	for(;;) {
-		static struct option options[] = {
-			BENCH_OPT_LONG
-			{0, 0, 0, 0}
-		};
+	cfa_option opt[] = {
+		BENCH_OPT_CFA
+	};
+	int opt_cnt = sizeof(opt) / sizeof(cfa_option);
 
-		int idx = 0;
-		int opt = getopt_long(argc, argv, BENCH_OPT_SHORT, options, &idx);
-
-		const char * arg = optarg ? optarg : "";
-		char * end;
-		switch(opt) {
-			case -1:
-				goto run;
-			BENCH_OPT_CASE
-			default: /* ? */
-				fprintf( stderr, "Unkown option '%c'\n", opt);
-			usage:
-				bench_usage( argv );
-				exit(1);
-		}
-	}
-	run:
+	char **left;
+	parse_args( argc, argv, opt, opt_cnt, "[OPTIONS]...\ncforall yield benchmark", left );
 
 	{
@@ -73,5 +58,5 @@
 
 		Time start, end;
-		BenchCluster cl = { 0, CFA_STATS_READY_Q };
+		BenchCluster cl = { num_io, params, CFA_STATS_READY_Q };
 		{
 			BenchProc procs[nprocs];
Index: configure.ac
===================================================================
--- configure.ac	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ configure.ac	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -24,4 +24,16 @@
 #Trasforming cc1 will break compilation
 M4CFA_PROGRAM_NAME
+
+#==============================================================================
+# New AST toggling support
+AH_TEMPLATE([CFA_USE_NEW_AST],[Sets whether or not to use the new-ast, this is adefault value and can be overrided by --old-ast and --new-ast])
+AC_ARG_ENABLE(new-ast,
+	[  --enable-new-ast     whether or not to use new ast as the default AST algorithm],
+	[case "${enableval}" in
+		yes) newast=true ;;
+		no)  newast=false ;;
+		*) AC_MSG_ERROR([bad value ${enableval} for --enable-new-ast]) ;;
+	esac],[newast=false])
+AC_DEFINE_UNQUOTED([CFA_USE_NEW_AST], $newast)
 
 #==============================================================================
Index: driver/cc1.cc
===================================================================
--- driver/cc1.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ driver/cc1.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Fri Aug 26 14:23:51 2005
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat May 30 18:09:05 2020
-// Update Count     : 404
+// Last Modified On : Sun Aug 16 21:03:02 2020
+// Update Count     : 413
 //
 
@@ -24,5 +24,5 @@
 #include <unistd.h>										// execvp, fork, unlink
 #include <sys/wait.h>									// wait
-#include <fcntl.h>
+#include <fcntl.h>										// creat
 
 
@@ -59,5 +59,5 @@
 
 
-static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );		// "N__=" suffix
+static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );		// "__CFA_FLAG__=" suffix
 
 static void checkEnv1( const char * args[], int & nargs ) { // stage 1
@@ -111,6 +111,7 @@
 } // checkEnv2
 
-
-static char tmpname[] = P_tmpdir "/CFAXXXXXX.ifa";
+#define CFA_SUFFIX ".ifa"
+
+static char tmpname[] = P_tmpdir "/CFAXXXXXX" CFA_SUFFIX;
 static int tmpfilefd = -1;
 static bool startrm = false;
@@ -170,5 +171,5 @@
 			if ( arg == "-quiet" ) {
 			} else if ( arg == "-imultilib" || arg == "-imultiarch" ) {
-				i += 1;									// and the argument
+				i += 1;									// and argument
 			} else if ( prefix( arg, "-A" ) ) {
 			} else if ( prefix( arg, "-D__GNU" ) ) {
@@ -177,5 +178,5 @@
 				//********
 			} else if ( arg == "-D" && prefix( argv[i + 1], "__GNU" ) ) {
-				i += 1;									// and the argument
+				i += 1;									// and argument
 
 				// strip flags controlling cpp step
@@ -184,5 +185,5 @@
 				cpp_flag = true;
 			} else if ( arg == "-D" && string( argv[i + 1] ) == "__CPP__" ) {
-				i += 1;									// and the argument
+				i += 1;									// and argument
 				cpp_flag = true;
 
@@ -194,5 +195,5 @@
 				cpp_out = argv[i];
 			} else {
-				args[nargs++] = argv[i];				// pass the flag along
+				args[nargs++] = argv[i];				// pass flag along
 				// CPP flags with an argument
 				if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
@@ -200,12 +201,14 @@
 					 arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
 					i += 1;
-					args[nargs++] = argv[i];			// pass the argument along
+					args[nargs++] = argv[i];			// pass argument along
 					#ifdef __DEBUG_H__
 					cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
 					#endif // __DEBUG_H__
 				} else if ( arg == "-MD" || arg == "-MMD" ) {
+					// gcc frontend generates the dependency file-name after the -MD/-MMD flag, but it is necessary to
+					// prefix that file name with -MF.
 					args[nargs++] = "-MF";				// insert before file
 					i += 1;
-					args[nargs++] = argv[i];			// pass the argument along
+					args[nargs++] = argv[i];			// pass argument along
 					#ifdef __DEBUG_H__
 					cerr << "argv[" << i << "]:\"" << argv[i] << "\"" << endl;
@@ -279,5 +282,5 @@
 	// Run the C preprocessor and save the output in the given file.
 
-	if ( fork() == 0 ) {								 // child process ?
+	if ( fork() == 0 ) {								// child process ?
 		// -o xxx.ii cannot be used to write the output file from cpp because no output file is created if cpp detects
 		// an error (e.g., cannot find include file). Whereas, output is always generated, even when there is an error,
@@ -319,9 +322,10 @@
 
 	if ( WIFSIGNALED(code) ) {							// child failed ?
+		rmtmpfile();									// remove tmpname
 		cerr << "CC1 Translator error: stage 1, child failed " << WTERMSIG(code) << endl;
 		exit( EXIT_FAILURE );
 	} // if
 
-	exit( WEXITSTATUS(code) );							// bad cpp result stops top-level gcc
+	exit( WEXITSTATUS( code ) );						// bad cpp result stops top-level gcc
 } // Stage1
 
@@ -371,9 +375,9 @@
 			} else if ( arg == "-fno-diagnostics-color" ) {
 				color_arg = Color_Auto;
-			}
+			} // if
 
 			if ( arg == "-quiet" || arg == "-version" || arg == "-fpreprocessed" ||
-				// Currently CFA does not suppose precompiled .h files.
-				prefix( arg, "--output-pch" ) ) {
+				 // Currently CFA does not suppose precompiled .h files.
+				 prefix( arg, "--output-pch" ) ) {
 
 				// strip inappropriate flags with an argument
@@ -388,9 +392,9 @@
 
 			} else {
-				args[nargs++] = argv[i];				// pass the flag along
+				args[nargs++] = argv[i];				// pass flag along
 				if ( arg == "-o" ) {
 					i += 1;
 					cpp_out = argv[i];
-					args[nargs++] = argv[i];			// pass the argument along
+					args[nargs++] = argv[i];			// pass argument along
 					#ifdef __DEBUG_H__
 					cerr << "arg:\"" << argv[i] << "\"" << endl;
@@ -439,5 +443,5 @@
 			} // if
 
-			cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + ".ifa";
+			cfa_cpp_out = cfa_cpp_out.substr( 0, dot ) + CFA_SUFFIX;
 			if ( creat( cfa_cpp_out.c_str(), 0666 ) == -1 ) {
 				perror( "CC1 Translator error: stage 2, creat" );
@@ -460,5 +464,5 @@
 	// output.  Otherwise, run the cfa-cpp preprocessor on the temporary file and save the result into the output file.
 
-	if ( fork() == 0 ) {								// child runs CFA
+	if ( fork() == 0 ) {								// child runs CFA preprocessor
 		cargs[0] = ( *new string( bprefix + "cfa-cpp" ) ).c_str();
 		cargs[ncargs++] = cpp_in;
@@ -518,5 +522,5 @@
 	#endif // __DEBUG_H__
 
-	if ( fork() == 0 ) {								// child runs CFA
+	if ( fork() == 0 ) {								// child runs gcc
 		args[0] = compiler_path.c_str();
 		args[nargs++] = "-S";							// only compile and put assembler output in specified file
Index: driver/cfa.cc
===================================================================
--- driver/cfa.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ driver/cfa.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,17 +10,16 @@
 // Created On       : Tue Aug 20 13:44:49 2002
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Aug 18 16:40:22 2020
-// Update Count     : 435
+// Last Modified On : Thu Aug 20 23:43:59 2020
+// Update Count     : 436
 //
 
 #include <iostream>
-#include <cstdio>      // perror
-#include <cstdlib>     // putenv, exit
-#include <climits>     // PATH_MAX
-#include <unistd.h>    // execvp
-#include <string>      // STL version
-#include <string.h>    // strcmp
-#include <algorithm>   // find
-
+#include <cstdio>										// perror
+#include <cstdlib>										// putenv, exit
+#include <climits>										// PATH_MAX
+#include <string>										// STL version
+#include <algorithm>									// find
+
+#include <unistd.h>										// execvp
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -34,10 +33,12 @@
 using std::to_string;
 
-// #define __DEBUG_H__
-
-// "N__=" suffix
-static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );
-
-void Putenv( char * argv[], string arg ) {
+//#define __DEBUG_H__
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+static string __CFA_FLAGPREFIX__( "__CFA_FLAG" );		// "__CFA_FLAG__=" suffix
+
+static void Putenv( char * argv[], string arg ) {
 	// environment variables must have unique names
 	static int flags = 0;
@@ -49,10 +50,9 @@
 } // Putenv
 
-// check if string has prefix
-bool prefix( const string & arg, const string & pre ) {
+static bool prefix( const string & arg, const string & pre ) { // check if string has prefix
 	return arg.substr( 0, pre.size() ) == pre;
 } // prefix
 
-inline bool ends_with(const string & str, const string & sfix) {
+static inline bool ends_with(const string & str, const string & sfix) {
 	if (sfix.size() > str.size()) return false;
 	return std::equal(str.rbegin(), str.rbegin() + sfix.size(), sfix.rbegin(), sfix.rend());
@@ -60,5 +60,5 @@
 
 // check if string has suffix
-bool suffix( const string & arg ) {
+static bool suffix( const string & arg ) {
 	enum { NumSuffixes = 3 };
 	static const string suffixes[NumSuffixes] = { "cfa", "hfa", "ifa" };
@@ -70,5 +70,4 @@
 } // suffix
 
-
 static inline bool dirExists( const string & path ) {	// check if directory exists
     struct stat info;
@@ -79,5 +78,5 @@
 static inline string dir(const string & path) {
 	return path.substr(0, path.find_last_of('/'));
-}
+} // dir
 
 // Different path modes
@@ -118,7 +117,4 @@
 }
 
-
-#define xstr(s) str(s)
-#define str(s) #s
 
 int main( int argc, char * argv[] ) {
@@ -158,9 +154,9 @@
 	PathMode path = FromProc();
 
-	const char *args[argc + 100];						// cfa command line values, plus some space for additional flags
+	const char * args[argc + 100];						// cfa command line values, plus some space for additional flags
 	int sargs = 1;										// starting location for arguments in args list
 	int nargs = sargs;									// number of arguments in args list; 0 => command name
 
-	const char *libs[argc + 20];						// non-user libraries must come separately, plus some added libraries and flags
+	const char * libs[argc + 20];						// non-user libraries must come separately, plus some added libraries and flags
 	int nlibs = 0;
 
@@ -180,26 +176,22 @@
 
 			if ( arg == "-Xlinker" || arg == "-o" ) {
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 				i += 1;
 				if ( i == argc ) continue;				// next argument available ?
 				args[nargs++] = argv[i];				// pass argument along
 				if ( arg == "-o" ) o_file = i;			// remember file
-			} else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) {				// CFA pass through
-				if(arg.size() == 5) {
+
+				// CFA specific arguments
+
+			} else if ( strncmp(arg.c_str(), "-XCFA", 5) == 0 ) { // CFA pass through
+				if ( arg.size() == 5 ) {
 					i += 1;
-					if ( i == argc ) continue;				// next argument available ?
+					if ( i == argc ) continue;			// next argument available ?
 					Putenv( argv, argv[i] );
-
-					// CFA specific arguments
-				}
-				else if(arg[5] == ',') {
+				} else if ( arg[5] == ',' ) {			// CFA specific arguments
 					Putenv( argv, argv[i] + 6 );
-
-					// CFA specific arguments
-				}
-				else {
+				} else {								// CFA specific arguments
 					args[nargs++] = argv[i];
-				}
-
+				} // if
 			} else if ( arg == "-CFA" ) {
 				CFA_flag = true;						// strip the -CFA flag
@@ -210,16 +202,16 @@
 			} else if ( arg == "-nodebug" ) {
 				debug = false;							// strip the nodebug flag
-			} else if ( arg == "-nolib" ) {
-				nolib = true;							// strip the nodebug flag
 			} else if ( arg == "-quiet" ) {
 				quiet = true;							// strip the quiet flag
 			} else if ( arg == "-noquiet" ) {
 				quiet = false;							// strip the noquiet flag
+			} else if ( arg == "-no-include-stdhdr" ) {
+				noincstd_flag = true;					// strip the no-include-stdhdr flag
+			} else if ( arg == "-nolib" ) {
+				nolib = true;							// strip the nolib flag
 			} else if ( arg == "-help" ) {
 				help = true;							// strip the help flag
 			} else if ( arg == "-nohelp" ) {
 				help = false;							// strip the nohelp flag
-			} else if ( arg == "-no-include-stdhdr" ) {
-				noincstd_flag = true;					// strip the no-include-stdhdr flag
 			} else if ( arg == "-cfalib") {
 				compiling_libs = true;
@@ -235,14 +227,14 @@
 			} else if ( arg == "-v" ) {
 				verbose = true;							// verbosity required
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 			} else if ( arg == "-g" ) {
 				debugging = true;						// symbolic debugging required
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 			} else if ( arg == "-save-temps" ) {
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 				Putenv( argv, arg );					// save cfa-cpp output
 			} else if ( prefix( arg, "-x" ) ) {			// file suffix ?
 				string lang;
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 				if ( arg.length() == 2 ) {				// separate argument ?
 					i += 1;
@@ -261,11 +253,11 @@
 			} else if ( prefix( arg, "-std=" ) || prefix( arg, "--std=" ) ) {
 				std_flag = true;						// -std=XX provided
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 			} else if ( arg == "-w" ) {
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 				Putenv( argv, arg );
 			} else if ( prefix( arg, "-W" ) ) {			// check before next tests
 				if ( arg == "-Werror" || arg == "-Wall" ) {
-					args[nargs++] = argv[i];			// pass argument along
+					args[nargs++] = argv[i];			// pass flag along
 					Putenv( argv, argv[i] );
 				} else {
@@ -281,9 +273,15 @@
 				bprefix = arg.substr(2);				// strip the -B flag
 			} else if ( arg == "-c" || arg == "-S" || arg == "-E" || arg == "-M" || arg == "-MM" ) {
-				args[nargs++] = argv[i];				// pass argument along
+				args[nargs++] = argv[i];				// pass flag along
 				if ( arg == "-E" || arg == "-M" || arg == "-MM" ) {
 					cpp_flag = true;					// cpp only
 				} // if
 				link = false;                           // no linkage required
+			} else if ( arg == "-D" || arg == "-U" || arg == "-I" || arg == "-MF" || arg == "-MT" || arg == "-MQ" ||
+						arg == "-include" || arg == "-imacros" || arg == "-idirafter" || arg == "-iprefix" ||
+						arg == "-iwithprefix" || arg == "-iwithprefixbefore" || arg == "-isystem" || arg == "-isysroot" ) {
+				args[nargs++] = argv[i];				// pass flag along
+				i += 1;
+				args[nargs++] = argv[i];				// pass argument along
 			} else if ( arg[1] == 'l' ) {
 				// if the user specifies a library, load it after user code
@@ -337,5 +335,5 @@
 	string libbase;
 	switch(path) {
-	case Installed:
+	  case Installed:
 		args[nargs++] = "-I" CFA_INCDIR;
 		// do not use during build
@@ -347,6 +345,6 @@
 		libbase = CFA_LIBDIR;
 		break;
-	case BuildTree:
-	case Distributed:
+	  case BuildTree:
+	  case Distributed:
 		args[nargs++] = "-I" TOP_SRCDIR "libcfa/src";
 		// do not use during build
@@ -382,5 +380,5 @@
 	string libdir = libbase + arch + "-" + config;
 
-	if (path != Distributed) {
+	if ( path != Distributed ) {
 		if ( ! nolib && ! dirExists( libdir ) ) {
 			cerr << argv[0] << " internal error, configuration " << config << " not installed." << endl;
@@ -402,8 +400,8 @@
 	string preludedir;
 	switch(path) {
-	case Installed   : preludedir = libdir; break;
-	case BuildTree   : preludedir = libdir + "/prelude"; break;
-	case Distributed : preludedir = dir(argv[0]); break;
-	}
+	  case Installed   : preludedir = libdir; break;
+	  case BuildTree   : preludedir = libdir + "/prelude"; break;
+	  case Distributed : preludedir = dir(argv[0]); break;
+	} // switch
 
 	Putenv( argv, "--prelude-dir=" + preludedir );
@@ -477,11 +475,11 @@
 	if ( bprefix.length() == 0 ) {
 		switch(path) {
-		case Installed   : bprefix = installlibdir; break;
-		case BuildTree   : bprefix = srcdriverdir ; break;
-		case Distributed : bprefix = dir(argv[0]) ; break;
-		}
-		if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
-		Putenv( argv, string("-B=") + bprefix );
-	} // if
+		  case Installed   : bprefix = installlibdir; break;
+		  case BuildTree   : bprefix = srcdriverdir ; break;
+		  case Distributed : bprefix = dir(argv[0]) ; break;
+		} // switch
+	} // if
+	if ( bprefix[bprefix.length() - 1] != '/' ) bprefix += '/';
+	Putenv( argv, string("-B=") + bprefix );
 
 	args[nargs++] = "-Xlinker";							// used by backtrace
@@ -505,6 +503,6 @@
 		args[nargs++] = "-Wno-cast-function-type";
 		#endif // HAVE_CAST_FUNCTION_TYPE
-		if ( ! std_flag ) {								// default c11, if none specified
-			args[nargs++] = "-std=gnu11";
+		if ( ! std_flag && ! x_flag ) {
+			args[nargs++] = "-std=gnu11";				// default c11, if none specified
 		} // if
 		args[nargs++] = "-fgnu89-inline";
@@ -556,5 +554,5 @@
 	// execute the command and return the result
 
-	execvp( args[0], (char *const *)args );				// should not return
+	execvp( args[0], (char * const *)args );			// should not return
 	perror( "CFA Translator error: execvp" );
 	exit( EXIT_FAILURE );
Index: libcfa/prelude/bootloader.cf
===================================================================
--- libcfa/prelude/bootloader.cf	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/prelude/bootloader.cf	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1,5 +1,11 @@
 extern "C" { static inline int invoke_main(int argc, char* argv[], char* envp[]); }
+int cfa_args_argc;
+char ** cfa_args_argv;
+char ** cfa_args_envp;
 
 int main(int argc, char* argv[], char* envp[]) {
+	cfa_args_argc = argc;
+	cfa_args_argv = argv;
+	cfa_args_envp = envp;
 	return invoke_main(argc, argv, envp);
 }
Index: libcfa/src/Makefile.am
===================================================================
--- libcfa/src/Makefile.am	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/Makefile.am	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -44,5 +44,5 @@
 
 headers = common.hfa fstream.hfa heap.hfa iostream.hfa iterator.hfa limits.hfa rational.hfa \
-		time.hfa stdlib.hfa memory.hfa \
+		time.hfa stdlib.hfa parseargs.hfa \
 		containers/maybe.hfa containers/pair.hfa containers/result.hfa containers/vector.hfa
 
Index: libcfa/src/bits/locks.hfa
===================================================================
--- libcfa/src/bits/locks.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/bits/locks.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -217,3 +217,37 @@
 		}
 	}
+
+	// Semaphore which only supports a single thread and one post
+	// Semaphore which only supports a single thread
+	struct oneshot {
+		struct $thread * volatile ptr;
+	};
+
+	static inline {
+		void  ?{}(oneshot & this) {
+			this.ptr = 0p;
+		}
+
+		void ^?{}(oneshot & this) {}
+
+		bool wait(oneshot & this) {
+			for() {
+				struct $thread * expected = this.ptr;
+				if(expected == 1p) return false;
+				/* paranoid */ verify( expected == 0p );
+				if(__atomic_compare_exchange_n(&this.ptr, &expected, active_thread(), false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)) {
+					park( __cfaabi_dbg_ctx );
+					/* paranoid */ verify( this.ptr == 1p );
+					return true;
+				}
+			}
+		}
+
+		bool post(oneshot & this) {
+			struct $thread * got = __atomic_exchange_n( &this.ptr, 1p, __ATOMIC_SEQ_CST);
+			if( got == 0p ) return false;
+			unpark( got __cfaabi_dbg_ctx2 );
+			return true;
+		}
+	}
 #endif
Index: libcfa/src/common.hfa
===================================================================
--- libcfa/src/common.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/common.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed Jul 11 17:54:36 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 12 08:02:18 2018
-// Update Count     : 5
+// Last Modified On : Sat Aug 15 08:51:29 2020
+// Update Count     : 14
 // 
 
@@ -67,7 +67,13 @@
 
 static inline {
+	char min( char t1, char t2 ) { return t1 < t2 ? t1 : t2; } // optimization
+	intptr_t min( intptr_t t1, intptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
+	uintptr_t min( uintptr_t t1, uintptr_t t2 ) { return t1 < t2 ? t1 : t2; } // optimization
 	forall( otype T | { int ?<?( T, T ); } )
 	T min( T t1, T t2 ) { return t1 < t2 ? t1 : t2; }
 
+	char max( char t1, char t2 ) { return t1 > t2 ? t1 : t2; } // optimization
+	intptr_t max( intptr_t t1, intptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
+	uintptr_t max( uintptr_t t1, uintptr_t t2 ) { return t1 > t2 ? t1 : t2; } // optimization
 	forall( otype T | { int ?>?( T, T ); } )
 	T max( T t1, T t2 ) { return t1 > t2 ? t1 : t2; }
Index: libcfa/src/concurrency/alarm.hfa
===================================================================
--- libcfa/src/concurrency/alarm.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/alarm.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -23,5 +23,5 @@
 #include "time.hfa"
 
-#include <containers/list.hfa>
+#include "containers/list.hfa"
 
 struct $thread;
Index: libcfa/src/concurrency/coroutine.cfa
===================================================================
--- libcfa/src/concurrency/coroutine.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/coroutine.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -215,4 +215,8 @@
 		return cor;
 	}
+
+	struct $coroutine * __cfactx_cor_active(void) {
+		return active_coroutine();
+	}
 }
 
Index: libcfa/src/concurrency/invoke.c
===================================================================
--- libcfa/src/concurrency/invoke.c	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/invoke.c	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Tue Jan 17 12:27:26 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Aug 20 18:54:34 2020
-// Update Count     : 30
+// Last Modified On : Thu Aug 20 23:43:23 2020
+// Update Count     : 31
 //
 
@@ -29,4 +29,5 @@
 // Called from the kernel when starting a coroutine or task so must switch back to user mode.
 
+extern struct $coroutine * __cfactx_cor_active(void);
 extern struct $coroutine * __cfactx_cor_finish(void);
 extern void __cfactx_cor_leave ( struct $coroutine * );
@@ -35,4 +36,8 @@
 extern void disable_interrupts() OPTIONAL_THREAD;
 extern void enable_interrupts( __cfaabi_dbg_ctx_param );
+
+struct exception_context_t * this_exception_context() {
+	return &__get_stack( __cfactx_cor_active() )->exception_context;
+}
 
 void __cfactx_invoke_coroutine(
@@ -146,5 +151,13 @@
 
 #elif defined( __ARM_ARCH_32 )
-#warning ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
+#error ARM needs to be upgrade to use two parameters like X86/X64 (A.K.A. : I broke this and do not know how to fix it)
+	// More details about the error:
+	// To avoid the thunk problem, I changed the invoke routine to pass the main explicitly
+	// instead of relying on an assertion. This effectively hoists any required thunk one level
+	// which was enough to get to global scope in most cases.
+	// This means that __cfactx_invoke_... now takes two parameters and the FakeStack needs
+	// to be adjusted as a consequence of that.
+	// I don't know how to do that for ARM, hence the #error
+
 	struct FakeStack {
 		float fpRegs[16];								// floating point registers
Index: libcfa/src/concurrency/invoke.h
===================================================================
--- libcfa/src/concurrency/invoke.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/invoke.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -26,4 +26,11 @@
 #ifndef _INVOKE_H_
 #define _INVOKE_H_
+
+	struct __cfaehm_try_resume_node;
+	struct __cfaehm_base_exception_t;
+	struct exception_context_t {
+		struct __cfaehm_try_resume_node * top_resume;
+		struct __cfaehm_base_exception_t * current_exception;
+	};
 
 	struct __stack_context_t {
@@ -51,4 +58,7 @@
 		// base of stack
 		void * base;
+
+		// Information for exception handling.
+		struct exception_context_t exception_context;
 	};
 
@@ -84,5 +94,9 @@
 	};
 
-	static inline struct __stack_t * __get_stack( struct $coroutine * cor ) { return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2)); }
+	static inline struct __stack_t * __get_stack( struct $coroutine * cor ) {
+		return (struct __stack_t*)(((uintptr_t)cor->stack.storage) & ((uintptr_t)-2));
+	}
+
+	struct exception_context_t * this_exception_context();
 
 	// struct which calls the monitor is accepting
Index: libcfa/src/concurrency/io.cfa
===================================================================
--- libcfa/src/concurrency/io.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/io.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -41,4 +41,67 @@
 	#include "kernel/fwd.hfa"
 	#include "io/types.hfa"
+
+	// returns true of acquired as leader or second leader
+	static inline bool try_lock( __leaderlock_t & this ) {
+		const uintptr_t thrd = 1z | (uintptr_t)active_thread();
+		bool block;
+		disable_interrupts();
+		for() {
+			struct $thread * expected = this.value;
+			if( 1p != expected && 0p != expected ) {
+				/* paranoid */ verify( thrd != (uintptr_t)expected ); // We better not already be the next leader
+				enable_interrupts( __cfaabi_dbg_ctx );
+				return false;
+			}
+			struct $thread * desired;
+			if( 0p == expected ) {
+				// If the lock isn't locked acquire it, no need to block
+				desired = 1p;
+				block = false;
+			}
+			else {
+				// If the lock is already locked try becomming the next leader
+				desired = (struct $thread *)thrd;
+				block = true;
+			}
+			if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
+		}
+		if( block ) {
+			enable_interrupts( __cfaabi_dbg_ctx );
+			park( __cfaabi_dbg_ctx );
+			disable_interrupts();
+		}
+		return true;
+	}
+
+	static inline bool next( __leaderlock_t & this ) {
+		/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+		struct $thread * nextt;
+		for() {
+			struct $thread * expected = this.value;
+			/* paranoid */ verify( (1 & (uintptr_t)expected) == 1 ); // The lock better be locked
+
+			struct $thread * desired;
+			if( 1p == expected ) {
+				// No next leader, just unlock
+				desired = 0p;
+				nextt   = 0p;
+			}
+			else {
+				// There is a next leader, remove but keep locked
+				desired = 1p;
+				nextt   = (struct $thread *)(~1z & (uintptr_t)expected);
+			}
+			if( __atomic_compare_exchange_n(&this.value, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST) ) break;
+		}
+
+		if(nextt) {
+			unpark( nextt __cfaabi_dbg_ctx2 );
+			enable_interrupts( __cfaabi_dbg_ctx );
+			return true;
+		}
+		enable_interrupts( __cfaabi_dbg_ctx );
+		return false;
+	}
 
 //=============================================================================================
@@ -93,5 +156,5 @@
 //=============================================================================================
 	static unsigned __collect_submitions( struct __io_data & ring );
-	static uint32_t __release_consumed_submission( struct __io_data & ring );
+	static __u32 __release_consumed_submission( struct __io_data & ring );
 
 	static inline void process(struct io_uring_cqe & cqe ) {
@@ -100,5 +163,5 @@
 
 		data->result = cqe.res;
-		unpark( data->thrd __cfaabi_dbg_ctx2 );
+		post( data->sem );
 	}
 
@@ -136,5 +199,5 @@
 		unsigned head = *ring.completion_q.head;
 		unsigned tail = *ring.completion_q.tail;
-		const uint32_t mask = *ring.completion_q.mask;
+		const __u32 mask = *ring.completion_q.mask;
 
 		// Nothing was new return 0
@@ -143,5 +206,5 @@
 		}
 
-		uint32_t count = tail - head;
+		__u32 count = tail - head;
 		/* paranoid */ verify( count != 0 );
 		for(i; count) {
@@ -182,5 +245,5 @@
 				__STATS__( true,
 					io.complete_q.completed_avg.val += count;
-					io.complete_q.completed_avg.fast_cnt += 1;
+					io.complete_q.completed_avg.cnt += 1;
 				)
 			enable_interrupts( __cfaabi_dbg_ctx );
@@ -192,4 +255,7 @@
 			// We didn't get anything baton pass to the slow poller
 			else {
+				__STATS__( false,
+					io.complete_q.blocks += 1;
+				)
 				__cfadbg_print_safe(io_core, "Kernel I/O : Parking io poller %p\n", &this.self);
 				reset = 0;
@@ -224,5 +290,5 @@
 //
 
-	[* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data ) {
+	[* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data ) {
 		/* paranoid */ verify( data != 0 );
 
@@ -230,9 +296,9 @@
 		__attribute((unused)) int len   = 0;
 		__attribute((unused)) int block = 0;
-		uint32_t cnt = *ring.submit_q.num;
-		uint32_t mask = *ring.submit_q.mask;
+		__u32 cnt = *ring.submit_q.num;
+		__u32 mask = *ring.submit_q.mask;
 
 		disable_interrupts();
-			uint32_t off = __tls_rand();
+			__u32 off = __tls_rand();
 		enable_interrupts( __cfaabi_dbg_ctx );
 
@@ -241,8 +307,8 @@
 			// Look through the list starting at some offset
 			for(i; cnt) {
-				uint64_t expected = 0;
-				uint32_t idx = (i + off) & mask;
+				__u64 expected = 0;
+				__u32 idx = (i + off) & mask;
 				struct io_uring_sqe * sqe = &ring.submit_q.sqes[idx];
-				volatile uint64_t * udata = (volatile uint64_t *)&sqe->user_data;
+				volatile __u64 * udata = &sqe->user_data;
 
 				if( *udata == expected &&
@@ -270,5 +336,5 @@
 	}
 
-	static inline uint32_t __submit_to_ready_array( struct __io_data & ring, uint32_t idx, const uint32_t mask ) {
+	static inline __u32 __submit_to_ready_array( struct __io_data & ring, __u32 idx, const __u32 mask ) {
 		/* paranoid */ verify( idx <= mask   );
 		/* paranoid */ verify( idx != -1ul32 );
@@ -277,15 +343,15 @@
 		__attribute((unused)) int len   = 0;
 		__attribute((unused)) int block = 0;
-		uint32_t ready_mask = ring.submit_q.ready_cnt - 1;
+		__u32 ready_mask = ring.submit_q.ready_cnt - 1;
 
 		disable_interrupts();
-			uint32_t off = __tls_rand();
+			__u32 off = __tls_rand();
 		enable_interrupts( __cfaabi_dbg_ctx );
 
-		uint32_t picked;
+		__u32 picked;
 		LOOKING: for() {
 			for(i; ring.submit_q.ready_cnt) {
 				picked = (i + off) & ready_mask;
-				uint32_t expected = -1ul32;
+				__u32 expected = -1ul32;
 				if( __atomic_compare_exchange_n( &ring.submit_q.ready[picked], &expected, idx, true, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED ) ) {
 					break LOOKING;
@@ -297,9 +363,7 @@
 
 			block++;
-			if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
-				__release_consumed_submission( ring );
-				unlock( ring.submit_q.lock );
-			}
-			else {
+
+			__u32 released = __release_consumed_submission( ring );
+			if( released == 0 ) {
 				yield();
 			}
@@ -316,9 +380,9 @@
 	}
 
-	void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1))) {
+	void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1))) {
 		__io_data & ring = *ctx->thrd.ring;
 		// Get now the data we definetely need
-		volatile uint32_t * const tail = ring.submit_q.tail;
-		const uint32_t mask  = *ring.submit_q.mask;
+		volatile __u32 * const tail = ring.submit_q.tail;
+		const __u32 mask  = *ring.submit_q.mask;
 
 		// There are 2 submission schemes, check which one we are using
@@ -332,12 +396,8 @@
 		}
 		else if( ring.eager_submits ) {
-			uint32_t picked = __submit_to_ready_array( ring, idx, mask );
-
-			for() {
-				yield();
-
-				// If some one else collected our index, we are done
-				#warning ABA problem
-				if( ring.submit_q.ready[picked] != idx ) {
+			__u32 picked = __submit_to_ready_array( ring, idx, mask );
+
+			#if defined(LEADER_LOCK)
+				if( !try_lock(ring.submit_q.submit_lock) ) {
 					__STATS__( false,
 						io.submit_q.helped += 1;
@@ -345,26 +405,48 @@
 					return;
 				}
-
-				if( try_lock(ring.submit_q.lock __cfaabi_dbg_ctx2) ) {
+				/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+				__STATS__( true,
+					io.submit_q.leader += 1;
+				)
+			#else
+				for() {
+					yield();
+
+					if( try_lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2) ) {
+						__STATS__( false,
+							io.submit_q.leader += 1;
+						)
+						break;
+					}
+
+					// If some one else collected our index, we are done
+					#warning ABA problem
+					if( ring.submit_q.ready[picked] != idx ) {
+						__STATS__( false,
+							io.submit_q.helped += 1;
+						)
+						return;
+					}
+
 					__STATS__( false,
-						io.submit_q.leader += 1;
+						io.submit_q.busy += 1;
 					)
-					break;
-				}
-
-				__STATS__( false,
-					io.submit_q.busy += 1;
-				)
-			}
+				}
+			#endif
 
 			// We got the lock
+			// Collect the submissions
 			unsigned to_submit = __collect_submitions( ring );
+
+			// Actually submit
 			int ret = __io_uring_enter( ring, to_submit, false );
-			if( ret < 0 ) {
-				unlock(ring.submit_q.lock);
-				return;
-			}
-
-			/* paranoid */ verify( ret > 0 || to_submit == 0 || (ring.ring_flags & IORING_SETUP_SQPOLL) );
+
+			#if defined(LEADER_LOCK)
+				/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+				next(ring.submit_q.submit_lock);
+			#else
+				unlock(ring.submit_q.submit_lock);
+			#endif
+			if( ret < 0 ) return;
 
 			// Release the consumed SQEs
@@ -372,15 +454,17 @@
 
 			// update statistics
-			__STATS__( true,
+			__STATS__( false,
 				io.submit_q.submit_avg.rdy += to_submit;
 				io.submit_q.submit_avg.csm += ret;
 				io.submit_q.submit_avg.cnt += 1;
 			)
-
-			unlock(ring.submit_q.lock);
 		}
 		else {
 			// get mutual exclusion
-			lock(ring.submit_q.lock __cfaabi_dbg_ctx2);
+			#if defined(LEADER_LOCK)
+				while(!try_lock(ring.submit_q.submit_lock));
+			#else
+				lock(ring.submit_q.submit_lock __cfaabi_dbg_ctx2);
+			#endif
 
 			/* paranoid */ verifyf( ring.submit_q.sqes[ idx ].user_data != 0,
@@ -420,5 +504,9 @@
 			__release_consumed_submission( ring );
 
-			unlock(ring.submit_q.lock);
+			#if defined(LEADER_LOCK)
+				next(ring.submit_q.submit_lock);
+			#else
+				unlock(ring.submit_q.submit_lock);
+			#endif
 
 			__cfadbg_print_safe( io, "Kernel I/O : Performed io_submit for %p, returned %d\n", active_thread(), ret );
@@ -426,4 +514,5 @@
 	}
 
+	// #define PARTIAL_SUBMIT 32
 	static unsigned __collect_submitions( struct __io_data & ring ) {
 		/* paranoid */ verify( ring.submit_q.ready != 0p );
@@ -431,11 +520,24 @@
 
 		unsigned to_submit = 0;
-		uint32_t tail = *ring.submit_q.tail;
-		const uint32_t mask = *ring.submit_q.mask;
+		__u32 tail = *ring.submit_q.tail;
+		const __u32 mask = *ring.submit_q.mask;
+		#if defined(PARTIAL_SUBMIT)
+			#if defined(LEADER_LOCK)
+				#error PARTIAL_SUBMIT and LEADER_LOCK cannot co-exist
+			#endif
+			const __u32 cnt = ring.submit_q.ready_cnt > PARTIAL_SUBMIT ? PARTIAL_SUBMIT : ring.submit_q.ready_cnt;
+			const __u32 offset = ring.submit_q.prev_ready;
+			ring.submit_q.prev_ready += cnt;
+		#else
+			const __u32 cnt = ring.submit_q.ready_cnt;
+			const __u32 offset = 0;
+		#endif
 
 		// Go through the list of ready submissions
-		for( i; ring.submit_q.ready_cnt ) {
+		for( c; cnt ) {
+			__u32 i = (offset + c) % ring.submit_q.ready_cnt;
+
 			// replace any submission with the sentinel, to consume it.
-			uint32_t idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
+			__u32 idx = __atomic_exchange_n( &ring.submit_q.ready[i], -1ul32, __ATOMIC_RELAXED);
 
 			// If it was already the sentinel, then we are done
@@ -453,16 +555,16 @@
 	}
 
-	static uint32_t __release_consumed_submission( struct __io_data & ring ) {
-		const uint32_t smask = *ring.submit_q.mask;
+	static __u32 __release_consumed_submission( struct __io_data & ring ) {
+		const __u32 smask = *ring.submit_q.mask;
 
 		if( !try_lock(ring.submit_q.release_lock __cfaabi_dbg_ctx2) ) return 0;
-		uint32_t chead = *ring.submit_q.head;
-		uint32_t phead = ring.submit_q.prev_head;
+		__u32 chead = *ring.submit_q.head;
+		__u32 phead = ring.submit_q.prev_head;
 		ring.submit_q.prev_head = chead;
 		unlock(ring.submit_q.release_lock);
 
-		uint32_t count = chead - phead;
+		__u32 count = chead - phead;
 		for( i; count ) {
-			uint32_t idx = ring.submit_q.array[ (phead + i) & smask ];
+			__u32 idx = ring.submit_q.array[ (phead + i) & smask ];
 			ring.submit_q.sqes[ idx ].user_data = 0;
 		}
Index: libcfa/src/concurrency/io/setup.cfa
===================================================================
--- libcfa/src/concurrency/io/setup.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/io/setup.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -228,5 +228,5 @@
 		if( cluster_context ) {
 			cluster & cltr = *thrd.curr_cluster;
-			/* paranoid */ verify( cltr.nprocessors == 0 || &cltr == mainCluster );
+			/* paranoid */ verify( cltr.idles.total == 0 || &cltr == mainCluster );
 			/* paranoid */ verify( !ready_mutate_islocked() );
 
@@ -298,5 +298,11 @@
 		if( params_in.poll_complete ) params.flags |= IORING_SETUP_IOPOLL;
 
-		uint32_t nentries = params_in.num_entries;
+		__u32 nentries = params_in.num_entries != 0 ? params_in.num_entries : 256;
+		if( !is_pow2(nentries) ) {
+			abort("ERROR: I/O setup 'num_entries' must be a power of 2\n");
+		}
+		if( params_in.poller_submits && params_in.eager_submits ) {
+			abort("ERROR: I/O setup 'poller_submits' and 'eager_submits' cannot be used together\n");
+		}
 
 		int fd = syscall(__NR_io_uring_setup, nentries, &params );
@@ -356,15 +362,15 @@
 		// Get the pointers from the kernel to fill the structure
 		// submit queue
-		sq.head    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
-		sq.tail    = (volatile uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
-		sq.mask    = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
-		sq.num     = (   const uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
-		sq.flags   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
-		sq.dropped = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
-		sq.array   = (         uint32_t *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
+		sq.head    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.head);
+		sq.tail    = (volatile __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.tail);
+		sq.mask    = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_mask);
+		sq.num     = (   const __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.ring_entries);
+		sq.flags   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.flags);
+		sq.dropped = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.dropped);
+		sq.array   = (         __u32 *)(((intptr_t)sq.ring_ptr) + params.sq_off.array);
 		sq.prev_head = *sq.head;
 
 		{
-			const uint32_t num = *sq.num;
+			const __u32 num = *sq.num;
 			for( i; num ) {
 				sq.sqes[i].user_data = 0ul64;
@@ -372,5 +378,5 @@
 		}
 
-		(sq.lock){};
+		(sq.submit_lock){};
 		(sq.release_lock){};
 
@@ -382,17 +388,19 @@
 				sq.ready[i] = -1ul32;
 			}
+			sq.prev_ready = 0;
 		}
 		else {
 			sq.ready_cnt = 0;
 			sq.ready = 0p;
+			sq.prev_ready = 0;
 		}
 
 		// completion queue
-		cq.head     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
-		cq.tail     = (volatile uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
-		cq.mask     = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
-		cq.num      = (   const uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
-		cq.overflow = (         uint32_t *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
-		cq.cqes   = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
+		cq.head      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.head);
+		cq.tail      = (volatile __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.tail);
+		cq.mask      = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_mask);
+		cq.num       = (   const __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.ring_entries);
+		cq.overflow  = (         __u32 *)(((intptr_t)cq.ring_ptr) + params.cq_off.overflow);
+		cq.cqes = (struct io_uring_cqe *)(((intptr_t)cq.ring_ptr) + params.cq_off.cqes);
 
 		// some paranoid checks
@@ -442,5 +450,5 @@
 	void __ioctx_register($io_ctx_thread & ctx, struct epoll_event & ev) {
 		ev.events = EPOLLIN | EPOLLONESHOT;
-		ev.data.u64 = (uint64_t)&ctx;
+		ev.data.u64 = (__u64)&ctx;
 		int ret = epoll_ctl(iopoll.epollfd, EPOLL_CTL_ADD, ctx.ring->fd, &ev);
 		if (ret < 0) {
Index: libcfa/src/concurrency/io/types.hfa
===================================================================
--- libcfa/src/concurrency/io/types.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/io/types.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -17,5 +17,16 @@
 
 #if defined(CFA_HAVE_LINUX_IO_URING_H)
+	extern "C" {
+		#include <linux/types.h>
+	}
+
       #include "bits/locks.hfa"
+
+	#define LEADER_LOCK
+	struct __leaderlock_t {
+		struct $thread * volatile value;	// ($thread) next_leader | (bool:1) is_locked
+	};
+
+	static inline void ?{}( __leaderlock_t & this ) { this.value = 0p; }
 
 	//-----------------------------------------------------------------------
@@ -23,28 +34,33 @@
       struct __submition_data {
 		// Head and tail of the ring (associated with array)
-		volatile uint32_t * head;
-		volatile uint32_t * tail;
-		volatile uint32_t prev_head;
+		volatile __u32 * head;
+		volatile __u32 * tail;
+		volatile __u32 prev_head;
 
 		// The actual kernel ring which uses head/tail
 		// indexes into the sqes arrays
-		uint32_t * array;
+		__u32 * array;
 
 		// number of entries and mask to go with it
-		const uint32_t * num;
-		const uint32_t * mask;
+		const __u32 * num;
+		const __u32 * mask;
 
 		// Submission flags (Not sure what for)
-		uint32_t * flags;
+		__u32 * flags;
 
 		// number of sqes not submitted (whatever that means)
-		uint32_t * dropped;
+		__u32 * dropped;
 
 		// Like head/tail but not seen by the kernel
-		volatile uint32_t * ready;
-		uint32_t ready_cnt;
+		volatile __u32 * ready;
+		__u32 ready_cnt;
+		__u32 prev_ready;
 
-		__spinlock_t lock;
-		__spinlock_t release_lock;
+		#if defined(LEADER_LOCK)
+			__leaderlock_t submit_lock;
+		#else
+			__spinlock_t submit_lock;
+		#endif
+		__spinlock_t  release_lock;
 
 		// A buffer of sqes (not the actual ring)
@@ -58,13 +74,13 @@
 	struct __completion_data {
 		// Head and tail of the ring
-		volatile uint32_t * head;
-		volatile uint32_t * tail;
+		volatile __u32 * head;
+		volatile __u32 * tail;
 
 		// number of entries and mask to go with it
-		const uint32_t * mask;
-		const uint32_t * num;
+		const __u32 * mask;
+		const __u32 * num;
 
 		// number of cqes not submitted (whatever that means)
-		uint32_t * overflow;
+		__u32 * overflow;
 
 		// the kernel ring
@@ -79,5 +95,5 @@
 		struct __submition_data submit_q;
 		struct __completion_data completion_q;
-		uint32_t ring_flags;
+		__u32 ring_flags;
 		int fd;
 		bool eager_submits:1;
@@ -89,6 +105,6 @@
 	// IO user data
 	struct __io_user_data_t {
-		int32_t result;
-		$thread * thrd;
+		__s32 result;
+		oneshot sem;
 	};
 
Index: libcfa/src/concurrency/iocall.cfa
===================================================================
--- libcfa/src/concurrency/iocall.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/iocall.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -32,8 +32,8 @@
 	#include "io/types.hfa"
 
-	extern [* struct io_uring_sqe, uint32_t] __submit_alloc( struct __io_data & ring, uint64_t data );
-	extern void __submit( struct io_context * ctx, uint32_t idx ) __attribute__((nonnull (1)));
-
-	static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd) {
+	extern [* struct io_uring_sqe, __u32] __submit_alloc( struct __io_data & ring, __u64 data );
+	extern void __submit( struct io_context * ctx, __u32 idx ) __attribute__((nonnull (1)));
+
+	static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd) {
 		this.opcode = opcode;
 		#if !defined(IOSQE_ASYNC)
@@ -51,8 +51,8 @@
 	}
 
-	static inline void ?{}(struct io_uring_sqe & this, uint8_t opcode, int fd, void * addr, uint32_t len, uint64_t off ) {
+	static inline void ?{}(struct io_uring_sqe & this, __u8 opcode, int fd, void * addr, __u32 len, __u64 off ) {
 		(this){ opcode, fd };
 		this.off = off;
-		this.addr = (uint64_t)(uintptr_t)addr;
+		this.addr = (__u64)(uintptr_t)addr;
 		this.len = len;
 	}
@@ -101,21 +101,21 @@
 	#endif
 
-
 	#define __submit_prelude \
 		if( 0 != (submit_flags & LINK_FLAGS) ) { errno = ENOTSUP; return -1; } \
 		(void)timeout; (void)cancellation; \
 		if( !context ) context = __get_io_context(); \
-		__io_user_data_t data = { 0, active_thread() }; \
+		__io_user_data_t data = { 0 }; \
 		struct __io_data & ring = *context->thrd.ring; \
 		struct io_uring_sqe * sqe; \
-		uint32_t idx; \
-		[sqe, idx] = __submit_alloc( ring, (uint64_t)(uintptr_t)&data ); \
-		sqe->flags = REGULAR_FLAGS & submit_flags;
+		__u32 idx; \
+		__u8 sflags = REGULAR_FLAGS & submit_flags; \
+		[sqe, idx] = __submit_alloc( ring, (__u64)(uintptr_t)&data ); \
+		sqe->flags = sflags;
 
 	#define __submit_wait \
 		/*__cfaabi_bits_print_safe( STDERR_FILENO, "Preparing user data %p for %p\n", &data, data.thrd );*/ \
-		verify( sqe->user_data == (uint64_t)(uintptr_t)&data ); \
+		verify( sqe->user_data == (__u64)(uintptr_t)&data ); \
 		__submit( context, idx ); \
-		park( __cfaabi_dbg_ctx ); \
+		wait( data.sem ); \
 		if( data.result < 0 ) { \
 			errno = -data.result; \
@@ -149,5 +149,12 @@
 
 	extern int fsync(int fd);
-	extern int sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags);
+
+	#if __OFF_T_MATCHES_OFF64_T
+		typedef __off64_t off_t;
+	#else
+		typedef __off_t off_t;
+	#endif
+	typedef __off64_t off64_t;
+	extern int sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags);
 
 	struct msghdr;
@@ -160,6 +167,6 @@
 	extern int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
 
-	extern int fallocate(int fd, int mode, uint64_t offset, uint64_t len);
-	extern int posix_fadvise(int fd, uint64_t offset, uint64_t len, int advice);
+	extern int fallocate(int fd, int mode, off_t offset, off_t len);
+	extern int posix_fadvise(int fd, off_t offset, off_t len, int advice);
 	extern int madvise(void *addr, size_t length, int advice);
 
@@ -186,5 +193,12 @@
 			__submit_prelude
 
-			(*sqe){ IORING_OP_READV, fd, iov, iovcnt, offset };
+			sqe->opcode = IORING_OP_READV;
+			sqe->ioprio = 0;
+			sqe->fd = fd;
+			sqe->off = offset;
+			sqe->addr = (__u64)iov;
+			sqe->len = iovcnt;
+			sqe->rw_flags = 0;
+			sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
 
 			__submit_wait
@@ -200,5 +214,12 @@
 			__submit_prelude
 
-			(*sqe){ IORING_OP_WRITEV, fd, iov, iovcnt, offset };
+			sqe->opcode = IORING_OP_WRITEV;
+			sqe->ioprio = 0;
+			sqe->fd = fd;
+			sqe->off = offset;
+			sqe->addr = (__u64)iov;
+			sqe->len = iovcnt;
+			sqe->rw_flags = 0;
+			sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
 
 			__submit_wait
@@ -213,11 +234,18 @@
 		__submit_prelude
 
-		(*sqe){ IORING_OP_FSYNC, fd };
-
-		__submit_wait
-	#endif
-}
-
-int cfa_sync_file_range(int fd, int64_t offset, int64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
+		sqe->opcode = IORING_OP_FSYNC;
+		sqe->ioprio = 0;
+		sqe->fd = fd;
+		sqe->off = 0;
+		sqe->addr = 0;
+		sqe->len = 0;
+		sqe->rw_flags = 0;
+		sqe->__pad2[0] = sqe->__pad2[1] = sqe->__pad2[2] = 0;
+
+		__submit_wait
+	#endif
+}
+
+int cfa_sync_file_range(int fd, off64_t offset, off64_t nbytes, unsigned int flags, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
 	#if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_SYNC_FILE_RANGE)
 		return sync_file_range(fd, offset, nbytes, flags);
@@ -268,5 +296,5 @@
 
 		(*sqe){ IORING_OP_SEND, sockfd };
-		sqe->addr = (uint64_t)buf;
+		sqe->addr = (__u64)buf;
 		sqe->len = len;
 		sqe->msg_flags = flags;
@@ -283,5 +311,5 @@
 
 		(*sqe){ IORING_OP_RECV, sockfd };
-		sqe->addr = (uint64_t)buf;
+		sqe->addr = (__u64)buf;
 		sqe->len = len;
 		sqe->msg_flags = flags;
@@ -298,6 +326,6 @@
 
 		(*sqe){ IORING_OP_ACCEPT, sockfd };
-		sqe->addr = (uint64_t)(uintptr_t)addr;
-		sqe->addr2 = (uint64_t)(uintptr_t)addrlen;
+		sqe->addr  = (__u64)addr;
+		sqe->addr2 = (__u64)addrlen;
 		sqe->accept_flags = flags;
 
@@ -313,12 +341,12 @@
 
 		(*sqe){ IORING_OP_CONNECT, sockfd };
-		sqe->addr = (uint64_t)(uintptr_t)addr;
-		sqe->off  = (uint64_t)(uintptr_t)addrlen;
-
-		__submit_wait
-	#endif
-}
-
-int cfa_fallocate(int fd, int mode, uint64_t offset, uint64_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
+		sqe->addr = (__u64)addr;
+		sqe->off  = (__u64)addrlen;
+
+		__submit_wait
+	#endif
+}
+
+int cfa_fallocate(int fd, int mode, off_t offset, off_t len, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
 	#if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FALLOCATE)
 		return fallocate( fd, mode, offset, len );
@@ -337,5 +365,5 @@
 }
 
-int cfa_fadvise(int fd, uint64_t offset, uint64_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
+int cfa_fadvise(int fd, off_t offset, off_t len, int advice, int submit_flags, Duration timeout, io_cancellation * cancellation, io_context * context) {
 	#if !defined(CFA_HAVE_LINUX_IO_URING_H) || !defined(CFA_HAVE_IORING_OP_FADVISE)
 		return posix_fadvise( fd, offset, len, advice );
@@ -344,5 +372,5 @@
 
 		(*sqe){ IORING_OP_FADVISE, fd };
-		sqe->off = (uint64_t)offset;
+		sqe->off = (__u64)offset;
 		sqe->len = len;
 		sqe->fadvise_advice = advice;
@@ -359,5 +387,5 @@
 
 		(*sqe){ IORING_OP_MADVISE, 0 };
-		sqe->addr = (uint64_t)addr;
+		sqe->addr = (__u64)addr;
 		sqe->len = length;
 		sqe->fadvise_advice = advice;
@@ -374,5 +402,5 @@
 
 		(*sqe){ IORING_OP_OPENAT, dirfd };
-		sqe->addr = (uint64_t)pathname;
+		sqe->addr = (__u64)pathname;
 		sqe->open_flags = flags;
 		sqe->len = mode;
@@ -407,5 +435,5 @@
 		__submit_prelude
 
-		(*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (uint64_t)statxbuf };
+		(*sqe){ IORING_OP_STATX, dirfd, pathname, mask, (__u64)statxbuf };
 		sqe->statx_flags = flags;
 
@@ -449,5 +477,5 @@
 		}
 		else {
-			sqe->off = (uint64_t)-1;
+			sqe->off = (__u64)-1;
 		}
 		sqe->len = len;
@@ -457,5 +485,5 @@
 		}
 		else {
-			sqe->splice_off_in = (uint64_t)-1;
+			sqe->splice_off_in = (__u64)-1;
 		}
 		sqe->splice_flags  = flags | (SPLICE_FLAGS & submit_flags);
Index: libcfa/src/concurrency/kernel.cfa
===================================================================
--- libcfa/src/concurrency/kernel.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/kernel.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -102,9 +102,12 @@
 // Kernel Scheduling logic
 static $thread * __next_thread(cluster * this);
-static bool __has_next_thread(cluster * this);
+static $thread * __next_thread_slow(cluster * this);
 static void __run_thread(processor * this, $thread * dst);
-static bool __wake_one(struct __processor_id_t * id, cluster * cltr);
-static void __halt(processor * this);
-bool __wake_proc(processor *);
+static void __wake_one(struct __processor_id_t * id, cluster * cltr);
+
+static void push  (__cluster_idles & idles, processor & proc);
+static void remove(__cluster_idles & idles, processor & proc);
+static [unsigned idle, unsigned total, * processor] query( & __cluster_idles idles );
+
 
 //=============================================================================================
@@ -116,4 +119,6 @@
 	// Do it here
 	kernelTLS.rand_seed ^= rdtscl();
+	kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&runner);
+	__tls_rand_advance_bck();
 
 	processor * this = runner.proc;
@@ -134,27 +139,67 @@
 
 		$thread * readyThread = 0p;
-		for( unsigned int spin_count = 0;; spin_count++ ) {
+		MAIN_LOOP:
+		for() {
 			// Try to get the next thread
 			readyThread = __next_thread( this->cltr );
 
-			// Check if we actually found a thread
-			if( readyThread ) {
-				/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
-				/* paranoid */ verifyf( readyThread->state == Ready || readyThread->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", readyThread->state, readyThread->preempted);
-				/* paranoid */ verifyf( readyThread->link.next == 0p, "Expected null got %p", readyThread->link.next );
-				__builtin_prefetch( readyThread->context.SP );
-
-				// We found a thread run it
-				__run_thread(this, readyThread);
-
-				/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+			if( !readyThread ) {
+				readyThread = __next_thread_slow( this->cltr );
 			}
 
-			if(__atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST)) break;
-
+			HALT:
 			if( !readyThread ) {
-				// Block until a thread is ready
-				__halt(this);
+				// Don't block if we are done
+				if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
+
+				#if !defined(__CFA_NO_STATISTICS__)
+					__tls_stats()->ready.sleep.halts++;
+				#endif
+
+				// Push self to idle stack
+				push(this->cltr->idles, * this);
+
+				// Confirm the ready-queue is empty
+				readyThread = __next_thread_slow( this->cltr );
+				if( readyThread ) {
+					// A thread was found, cancel the halt
+					remove(this->cltr->idles, * this);
+
+					#if !defined(__CFA_NO_STATISTICS__)
+						__tls_stats()->ready.sleep.cancels++;
+					#endif
+
+					// continue the mai loop
+					break HALT;
+				}
+
+				#if !defined(__CFA_NO_STATISTICS__)
+					if(this->print_halts) {
+						__cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
+					}
+				#endif
+
+				wait( this->idle );
+
+				#if !defined(__CFA_NO_STATISTICS__)
+					if(this->print_halts) {
+						__cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
+					}
+				#endif
+
+				// We were woken up, remove self from idle
+				remove(this->cltr->idles, * this);
+
+				// DON'T just proceed, start looking again
+				continue MAIN_LOOP;
 			}
+
+			/* paranoid */ verify( readyThread );
+
+			// We found a thread run it
+			__run_thread(this, readyThread);
+
+			// Are we done?
+			if( __atomic_load_n(&this->do_terminate, __ATOMIC_SEQ_CST) ) break MAIN_LOOP;
 		}
 
@@ -181,4 +226,9 @@
 // from the processor coroutine to the target thread
 static void __run_thread(processor * this, $thread * thrd_dst) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+	/* paranoid */ verifyf( thrd_dst->state == Ready || thrd_dst->preempted != __NO_PREEMPTION, "state : %d, preempted %d\n", thrd_dst->state, thrd_dst->preempted);
+	/* paranoid */ verifyf( thrd_dst->link.next == 0p, "Expected null got %p", thrd_dst->link.next );
+	__builtin_prefetch( thrd_dst->context.SP );
+
 	$coroutine * proc_cor = get_coroutine(this->runner);
 
@@ -260,4 +310,6 @@
 	proc_cor->state = Active;
 	kernelTLS.this_thread = 0p;
+
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 }
 
@@ -316,13 +368,5 @@
 	ready_schedule_lock  ( id );
 		push( thrd->curr_cluster, thrd );
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			bool woke =
-		#endif
-			__wake_one(id, thrd->curr_cluster);
-
-		#if !defined(__CFA_NO_STATISTICS__)
-			if(woke) __tls_stats()->ready.sleep.wakes++;
-		#endif
+		__wake_one(id, thrd->curr_cluster);
 	ready_schedule_unlock( id );
 
@@ -331,25 +375,25 @@
 
 // KERNEL ONLY
-static $thread * __next_thread(cluster * this) with( *this ) {
+static inline $thread * __next_thread(cluster * this) with( *this ) {
 	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 
 	ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
-		$thread * head = pop( this );
+		$thread * thrd = pop( this );
 	ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
 
 	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
-	return head;
+	return thrd;
 }
 
 // KERNEL ONLY
-static bool __has_next_thread(cluster * this) with( *this ) {
+static inline $thread * __next_thread_slow(cluster * this) with( *this ) {
 	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 
 	ready_schedule_lock  ( (__processor_id_t*)kernelTLS.this_processor );
-		bool not_empty = query( this );
+		$thread * thrd = pop_slow( this );
 	ready_schedule_unlock( (__processor_id_t*)kernelTLS.this_processor );
 
 	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
-	return not_empty;
+	return thrd;
 }
 
@@ -441,21 +485,32 @@
 //=============================================================================================
 // Wake a thread from the front if there are any
-static bool __wake_one(struct __processor_id_t * id, cluster * this) {
+static void __wake_one(struct __processor_id_t * id, cluster * this) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 	/* paranoid */ verify( ready_schedule_islocked( id ) );
 
 	// Check if there is a sleeping processor
-	processor * p = pop(this->idles);
+	processor * p;
+	unsigned idle;
+	unsigned total;
+	[idle, total, p] = query(this->idles);
 
 	// If no one is sleeping, we are done
-	if( 0p == p ) return false;
+	if( idle == 0 ) return;
 
 	// We found a processor, wake it up
 	post( p->idle );
 
-	return true;
+	#if !defined(__CFA_NO_STATISTICS__)
+		__tls_stats()->ready.sleep.wakes++;
+	#endif
+
+	/* paranoid */ verify( ready_schedule_islocked( id ) );
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+
+	return;
 }
 
 // Unconditionnaly wake a thread
-bool __wake_proc(processor * this) {
+void __wake_proc(processor * this) {
 	__cfadbg_print_safe(runtime_core, "Kernel : waking Processor %p\n", this);
 
@@ -464,42 +519,40 @@
 		bool ret = post( this->idle );
 	enable_interrupts( __cfaabi_dbg_ctx );
-
-	return ret;
-}
-
-static void __halt(processor * this) with( *this ) {
-	if( do_terminate ) return;
-
-	#if !defined(__CFA_NO_STATISTICS__)
-		__tls_stats()->ready.sleep.halts++;
-	#endif
-	// Push self to queue
-	push(cltr->idles, *this);
-
-	// Makre sure we don't miss a thread
-	if( __has_next_thread(cltr) ) {
-		// A thread was posted, make sure a processor is woken up
-		struct __processor_id_t *id = (struct __processor_id_t *) this;
-		ready_schedule_lock  ( id );
-			__wake_one( id, cltr );
-		ready_schedule_unlock( id );
-		#if !defined(__CFA_NO_STATISTICS__)
-			__tls_stats()->ready.sleep.cancels++;
-		#endif
-	}
-
-	#if !defined(__CFA_NO_STATISTICS__)
-		if(this->print_halts) {
-			__cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 0\n", this->id, rdtscl());
-		}
-	#endif
-
-	wait( idle );
-
-	#if !defined(__CFA_NO_STATISTICS__)
-		if(this->print_halts) {
-			__cfaabi_bits_print_safe( STDOUT_FILENO, "PH:%d - %lld 1\n", this->id, rdtscl());
-		}
-	#endif
+}
+
+static void push  (__cluster_idles & this, processor & proc) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+	lock( this );
+		this.idle++;
+		/* paranoid */ verify( this.idle <= this.total );
+
+		insert_first(this.list, proc);
+	unlock( this );
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+}
+
+static void remove(__cluster_idles & this, processor & proc) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+	lock( this );
+		this.idle--;
+		/* paranoid */ verify( this.idle >= 0 );
+
+		remove(proc);
+	unlock( this );
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+}
+
+static [unsigned idle, unsigned total, * processor] query( & __cluster_idles this ) {
+	for() {
+		uint64_t l = __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST);
+		if( 1 == (l % 2) ) { Pause(); continue; }
+		unsigned idle    = this.idle;
+		unsigned total   = this.total;
+		processor * proc = &this.list`first;
+		// Compiler fence is unnecessary, but gcc-8 and older incorrectly reorder code without it
+		asm volatile("": : :"memory");
+		if(l != __atomic_load_n(&this.lock, __ATOMIC_SEQ_CST)) { Pause(); continue; }
+		return [idle, total, proc];
+	}
 }
 
Index: libcfa/src/concurrency/kernel.hfa
===================================================================
--- libcfa/src/concurrency/kernel.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/kernel.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -20,5 +20,5 @@
 #include "coroutine.hfa"
 
-#include "containers/stackLockFree.hfa"
+#include "containers/list.hfa"
 
 extern "C" {
@@ -99,5 +99,5 @@
 
 	// Link lists fields
-	Link(processor) link;
+	DLISTED_MGD_IMPL_IN(processor)
 
 	#if !defined(__CFA_NO_STATISTICS__)
@@ -119,5 +119,5 @@
 static inline void  ?{}(processor & this, const char name[]) { this{name, *mainCluster }; }
 
-static inline Link(processor) * ?`next( processor * this ) { return &this->link; }
+DLISTED_MGD_IMPL_OUT(processor)
 
 //-----------------------------------------------------------------------------
@@ -206,4 +206,19 @@
 void ^?{}(__ready_queue_t & this);
 
+// Idle Sleep
+struct __cluster_idles {
+	// Spin lock protecting the queue
+	volatile uint64_t lock;
+
+	// Total number of processors
+	unsigned total;
+
+	// Total number of idle processors
+	unsigned idle;
+
+	// List of idle processors
+	dlist(processor, processor) list;
+};
+
 //-----------------------------------------------------------------------------
 // Cluster
@@ -219,6 +234,5 @@
 
 	// List of idle processors
-	StackLF(processor) idles;
-	volatile unsigned int nprocessors;
+	__cluster_idles idles;
 
 	// List of threads
Index: libcfa/src/concurrency/kernel/fwd.hfa
===================================================================
--- libcfa/src/concurrency/kernel/fwd.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/kernel/fwd.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -50,5 +50,11 @@
 				uint64_t rand_seed;
 			#endif
+			struct {
+				uint64_t fwd_seed;
+				uint64_t bck_seed;
+			} ready_rng;
 		} kernelTLS __attribute__ ((tls_model ( "initial-exec" )));
+
+
 
 		static inline uint64_t __tls_rand() {
@@ -58,4 +64,32 @@
 				return __xorshift64( kernelTLS.rand_seed );
 			#endif
+		}
+
+		#define M  (1_l64u << 48_l64u)
+		#define A  (25214903917_l64u)
+		#define AI (18446708753438544741_l64u)
+		#define C  (11_l64u)
+		#define D  (16_l64u)
+
+		static inline unsigned __tls_rand_fwd() {
+
+			kernelTLS.ready_rng.fwd_seed = (A * kernelTLS.ready_rng.fwd_seed + C) & (M - 1);
+			return kernelTLS.ready_rng.fwd_seed >> D;
+		}
+
+		static inline unsigned __tls_rand_bck() {
+			unsigned int r = kernelTLS.ready_rng.bck_seed >> D;
+			kernelTLS.ready_rng.bck_seed = AI * (kernelTLS.ready_rng.bck_seed - C) & (M - 1);
+			return r;
+		}
+
+		#undef M
+		#undef A
+		#undef AI
+		#undef C
+		#undef D
+
+		static inline void __tls_rand_advance_bck(void) {
+			kernelTLS.ready_rng.bck_seed = kernelTLS.ready_rng.fwd_seed;
 		}
 	}
Index: libcfa/src/concurrency/kernel/startup.cfa
===================================================================
--- libcfa/src/concurrency/kernel/startup.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/kernel/startup.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -78,4 +78,8 @@
 static void ?{}(processorCtx_t & this, processor * proc, current_stack_info_t * info);
 
+#if defined(__CFA_WITH_VERIFY__)
+	static bool verify_fwd_bck_rng(void);
+#endif
+
 //-----------------------------------------------------------------------------
 // Forward Declarations for other modules
@@ -87,5 +91,5 @@
 //-----------------------------------------------------------------------------
 // Other Forward Declarations
-extern bool __wake_proc(processor *);
+extern void __wake_proc(processor *);
 
 //-----------------------------------------------------------------------------
@@ -158,4 +162,6 @@
 	__cfa_dbg_global_clusters.list{ __get };
 	__cfa_dbg_global_clusters.lock{};
+
+	/* paranoid */ verify( verify_fwd_bck_rng() );
 
 	// Initialize the global scheduler lock
@@ -475,5 +481,7 @@
 	#endif
 
-	int target = __atomic_add_fetch( &cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
+	lock( this.cltr->idles );
+		int target = this.cltr->idles.total += 1u;
+	unlock( this.cltr->idles );
 
 	id = doregister((__processor_id_t*)&this);
@@ -493,6 +501,7 @@
 // Not a ctor, it just preps the destruction but should not destroy members
 static void deinit(processor & this) {
-
-	int target = __atomic_sub_fetch( &this.cltr->nprocessors, 1u, __ATOMIC_SEQ_CST );
+	lock( this.cltr->idles );
+		int target = this.cltr->idles.total -= 1u;
+	unlock( this.cltr->idles );
 
 	// Lock the RWlock so no-one pushes/pops while we are changing the queue
@@ -501,7 +510,4 @@
 		// Adjust the ready queue size
 		ready_queue_shrink( this.cltr, target );
-
-		// Make sure we aren't on the idle queue
-		unsafe_remove( this.cltr->idles, &this );
 
 	// Unlock the RWlock
@@ -516,5 +522,8 @@
 	( this.terminated ){ 0 };
 	( this.runner ){};
-	init( this, name, _cltr );
+
+	disable_interrupts();
+		init( this, name, _cltr );
+	enable_interrupts( __cfaabi_dbg_ctx );
 
 	__cfadbg_print_safe(runtime_core, "Kernel : Starting core %p\n", &this);
@@ -540,13 +549,21 @@
 	free( this.stack );
 
-	deinit( this );
+	disable_interrupts();
+		deinit( this );
+	enable_interrupts( __cfaabi_dbg_ctx );
 }
 
 //-----------------------------------------------------------------------------
 // Cluster
+static void ?{}(__cluster_idles & this) {
+	this.lock  = 0;
+	this.idle  = 0;
+	this.total = 0;
+	(this.list){};
+}
+
 void ?{}(cluster & this, const char name[], Duration preemption_rate, unsigned num_io, const io_context_params & io_params) with( this ) {
 	this.name = name;
 	this.preemption_rate = preemption_rate;
-	this.nprocessors = 0;
 	ready_queue{};
 
@@ -666,2 +683,23 @@
 	return stack;
 }
+
+#if defined(__CFA_WITH_VERIFY__)
+static bool verify_fwd_bck_rng(void) {
+	kernelTLS.ready_rng.fwd_seed = 25214903917_l64u * (rdtscl() ^ (uintptr_t)&verify_fwd_bck_rng);
+
+	unsigned values[10];
+	for(i; 10) {
+		values[i] = __tls_rand_fwd();
+	}
+
+	__tls_rand_advance_bck();
+
+	for ( i; 9 -~= 0 ) {
+		if(values[i] != __tls_rand_bck()) {
+			return false;
+		}
+	}
+
+	return true;
+}
+#endif
Index: libcfa/src/concurrency/kernel_private.hfa
===================================================================
--- libcfa/src/concurrency/kernel_private.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/kernel_private.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -121,4 +121,22 @@
 void     unregister( struct __processor_id_t * proc );
 
+//-----------------------------------------------------------------------
+// Cluster idle lock/unlock
+static inline void lock(__cluster_idles & this) {
+	for() {
+		uint64_t l = this.lock;
+		if(
+			(0 == (l % 2))
+			&& __atomic_compare_exchange_n(&this.lock, &l, l + 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST)
+		) return;
+		Pause();
+	}
+}
+
+static inline void unlock(__cluster_idles & this) {
+	/* paranoid */ verify( 1 == (this.lock % 2) );
+	__atomic_fetch_add( &this.lock, 1, __ATOMIC_SEQ_CST );
+}
+
 //=======================================================================
 // Reader-writer lock implementation
@@ -248,5 +266,12 @@
 // pop thread from the ready queue of a cluster
 // returns 0p if empty
+// May return 0p spuriously
 __attribute__((hot)) struct $thread * pop(struct cluster * cltr);
+
+//-----------------------------------------------------------------------
+// pop thread from the ready queue of a cluster
+// returns 0p if empty
+// guaranteed to find any threads added before this call
+__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr);
 
 //-----------------------------------------------------------------------
Index: libcfa/src/concurrency/ready_queue.cfa
===================================================================
--- libcfa/src/concurrency/ready_queue.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/ready_queue.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -17,4 +17,6 @@
 // #define __CFA_DEBUG_PRINT_READY_QUEUE__
 
+// #define USE_SNZI
+
 #include "bits/defs.hfa"
 #include "kernel_private.hfa"
@@ -148,4 +150,6 @@
 //  queues or removing them.
 uint_fast32_t ready_mutate_lock( void ) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+
 	// Step 1 : lock global lock
 	// It is needed to avoid processors that register mid Critical-Section
@@ -162,8 +166,11 @@
 	}
 
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 	return s;
 }
 
 void ready_mutate_unlock( uint_fast32_t last_s ) with(*__scheduler_lock) {
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
+
 	// Step 1 : release local locks
 	// This must be done while the global lock is held to avoid
@@ -180,4 +187,6 @@
 	/*paranoid*/ assert(true == lock);
 	__atomic_store_n(&lock, (bool)false, __ATOMIC_RELEASE);
+
+	/* paranoid */ verify( ! kernelTLS.preemption_state.enabled );
 }
 
@@ -192,5 +201,7 @@
 void ^?{}(__ready_queue_t & this) with (this) {
 	verify( 1 == lanes.count );
-	verify( !query( snzi ) );
+	#ifdef USE_SNZI
+		verify( !query( snzi ) );
+	#endif
 	free(lanes.data);
 }
@@ -198,5 +209,8 @@
 //-----------------------------------------------------------------------
 __attribute__((hot)) bool query(struct cluster * cltr) {
-	return query(cltr->ready_queue.snzi);
+	#ifdef USE_SNZI
+		return query(cltr->ready_queue.snzi);
+	#endif
+	return true;
 }
 
@@ -262,12 +276,14 @@
 	bool lane_first = push(lanes.data[i], thrd);
 
-	// If this lane used to be empty we need to do more
-	if(lane_first) {
-		// Check if the entire queue used to be empty
-		first = !query(snzi);
-
-		// Update the snzi
-		arrive( snzi, i );
-	}
+	#ifdef USE_SNZI
+		// If this lane used to be empty we need to do more
+		if(lane_first) {
+			// Check if the entire queue used to be empty
+			first = !query(snzi);
+
+			// Update the snzi
+			arrive( snzi, i );
+		}
+	#endif
 
 	// Unlock and return
@@ -294,4 +310,5 @@
 __attribute__((hot)) $thread * pop(struct cluster * cltr) with (cltr->ready_queue) {
 	/* paranoid */ verify( lanes.count > 0 );
+	unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
 	#if defined(BIAS)
 		// Don't bother trying locally too much
@@ -300,5 +317,9 @@
 
 	// As long as the list is not empty, try finding a lane that isn't empty and pop from it
-	while( query(snzi) ) {
+	#ifdef USE_SNZI
+		while( query(snzi) ) {
+	#else
+		for(25) {
+	#endif
 		// Pick two lists at random
 		unsigned i,j;
@@ -336,6 +357,6 @@
 		#endif
 
-		i %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
-		j %= __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
+		i %= count;
+		j %= count;
 
 		// try popping from the 2 picked lists
@@ -353,4 +374,21 @@
 }
 
+__attribute__((hot)) struct $thread * pop_slow(struct cluster * cltr) with (cltr->ready_queue) {
+	/* paranoid */ verify( lanes.count > 0 );
+	unsigned count = __atomic_load_n( &lanes.count, __ATOMIC_RELAXED );
+	unsigned offset = __tls_rand();
+	for(i; count) {
+		unsigned idx = (offset + i) % count;
+		struct $thread * thrd = try_pop(cltr, idx);
+		if(thrd) {
+			return thrd;
+		}
+	}
+
+	// All lanes where empty return 0p
+	return 0p;
+}
+
+
 //-----------------------------------------------------------------------
 // Given 2 indexes, pick the list with the oldest push an try to pop from it
@@ -388,14 +426,15 @@
 	// Actually pop the list
 	struct $thread * thrd;
-	bool emptied;
-	[thrd, emptied] = pop(lane);
+	thrd = pop(lane);
 
 	/* paranoid */ verify(thrd);
 	/* paranoid */ verify(lane.lock);
 
-	// If this was the last element in the lane
-	if(emptied) {
-		depart( snzi, w );
-	}
+	#ifdef USE_SNZI
+		// If this was the last element in the lane
+		if(emptied) {
+			depart( snzi, w );
+		}
+	#endif
 
 	// Unlock and return
@@ -424,13 +463,14 @@
 			if(head(lane)->link.next == thrd) {
 				$thread * pthrd;
-				bool emptied;
-				[pthrd, emptied] = pop(lane);
+				pthrd = pop(lane);
 
 				/* paranoid */ verify( pthrd == thrd );
 
 				removed = true;
-				if(emptied) {
-					depart( snzi, i );
-				}
+				#ifdef USE_SNZI
+					if(emptied) {
+						depart( snzi, i );
+					}
+				#endif
 			}
 		__atomic_unlock(&lane.lock);
@@ -494,5 +534,7 @@
 	// grow the ready queue
 	with( cltr->ready_queue ) {
-		^(snzi){};
+		#ifdef USE_SNZI
+			^(snzi){};
+		#endif
 
 		// Find new count
@@ -516,11 +558,13 @@
 		lanes.count = ncount;
 
-		// Re-create the snzi
-		snzi{ log2( lanes.count / 8 ) };
-		for( idx; (size_t)lanes.count ) {
-			if( !is_empty(lanes.data[idx]) ) {
-				arrive(snzi, idx);
-			}
-		}
+		#ifdef USE_SNZI
+			// Re-create the snzi
+			snzi{ log2( lanes.count / 8 ) };
+			for( idx; (size_t)lanes.count ) {
+				if( !is_empty(lanes.data[idx]) ) {
+					arrive(snzi, idx);
+				}
+			}
+		#endif
 	}
 
@@ -542,5 +586,7 @@
 
 	with( cltr->ready_queue ) {
-		^(snzi){};
+		#ifdef USE_SNZI
+			^(snzi){};
+		#endif
 
 		// Remember old count
@@ -567,6 +613,5 @@
 			while(!is_empty(lanes.data[idx])) {
 				struct $thread * thrd;
-				__attribute__((unused)) bool _;
-				[thrd, _] = pop(lanes.data[idx]);
+				thrd = pop(lanes.data[idx]);
 
 				push(cltr, thrd);
@@ -596,11 +641,13 @@
 		}
 
-		// Re-create the snzi
-		snzi{ log2( lanes.count / 8 ) };
-		for( idx; (size_t)lanes.count ) {
-			if( !is_empty(lanes.data[idx]) ) {
-				arrive(snzi, idx);
-			}
-		}
+		#ifdef USE_SNZI
+			// Re-create the snzi
+			snzi{ log2( lanes.count / 8 ) };
+			for( idx; (size_t)lanes.count ) {
+				if( !is_empty(lanes.data[idx]) ) {
+					arrive(snzi, idx);
+				}
+			}
+		#endif
 	}
 
Index: libcfa/src/concurrency/ready_subqueue.hfa
===================================================================
--- libcfa/src/concurrency/ready_subqueue.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/ready_subqueue.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -144,5 +144,5 @@
 // returns popped
 // returns true of lane was empty before push, false otherwise
-[$thread *, bool] pop(__intrusive_lane_t & this) {
+$thread * pop(__intrusive_lane_t & this) {
 	/* paranoid */ verify(this.lock);
 	/* paranoid */ verify(this.before.link.ts != 0ul);
@@ -162,5 +162,6 @@
 	head->link.next = next;
 	next->link.prev = head;
-	node->link.[next, prev] = 0p;
+	node->link.next = 0p;
+	node->link.prev = 0p;
 
 	// Update head time stamp
@@ -180,5 +181,5 @@
 		/* paranoid */ verify(tail(this)->link.prev == head(this));
 		/* paranoid */ verify(head(this)->link.next == tail(this));
-		return [node, true];
+		return node;
 	}
 	else {
@@ -187,5 +188,5 @@
 		/* paranoid */ verify(head(this)->link.next != tail(this));
 		/* paranoid */ verify(this.before.link.ts != 0);
-		return [node, false];
+		return node;
 	}
 }
Index: libcfa/src/concurrency/stats.cfa
===================================================================
--- libcfa/src/concurrency/stats.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/stats.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -38,6 +38,6 @@
 			stats->io.submit_q.busy   = 0;
 			stats->io.complete_q.completed_avg.val = 0;
-			stats->io.complete_q.completed_avg.slow_cnt = 0;
-			stats->io.complete_q.completed_avg.fast_cnt = 0;
+			stats->io.complete_q.completed_avg.cnt = 0;
+			stats->io.complete_q.blocks = 0;
 		#endif
 	}
@@ -60,20 +60,20 @@
 
 		#if defined(CFA_HAVE_LINUX_IO_URING_H)
-			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy          , proc->io.submit_q.submit_avg.rdy          , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm          , proc->io.submit_q.submit_avg.csm          , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl          , proc->io.submit_q.submit_avg.avl          , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt          , proc->io.submit_q.submit_avg.cnt          , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.look_avg.val            , proc->io.submit_q.look_avg.val            , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt            , proc->io.submit_q.look_avg.cnt            , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.look_avg.block          , proc->io.submit_q.look_avg.block          , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val           , proc->io.submit_q.alloc_avg.val           , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt           , proc->io.submit_q.alloc_avg.cnt           , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block         , proc->io.submit_q.alloc_avg.block         , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.helped                  , proc->io.submit_q.helped                  , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.leader                  , proc->io.submit_q.leader                  , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.submit_q.busy                    , proc->io.submit_q.busy                    , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.complete_q.completed_avg.val     , proc->io.complete_q.completed_avg.val     , __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.complete_q.completed_avg.slow_cnt, proc->io.complete_q.completed_avg.slow_cnt, __ATOMIC_SEQ_CST );
-			__atomic_fetch_add( &cltr->io.complete_q.completed_avg.fast_cnt, proc->io.complete_q.completed_avg.fast_cnt, __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.rdy     , proc->io.submit_q.submit_avg.rdy     , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.csm     , proc->io.submit_q.submit_avg.csm     , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.avl     , proc->io.submit_q.submit_avg.avl     , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.submit_avg.cnt     , proc->io.submit_q.submit_avg.cnt     , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.look_avg.val       , proc->io.submit_q.look_avg.val       , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.look_avg.cnt       , proc->io.submit_q.look_avg.cnt       , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.look_avg.block     , proc->io.submit_q.look_avg.block     , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.val      , proc->io.submit_q.alloc_avg.val      , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.cnt      , proc->io.submit_q.alloc_avg.cnt      , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.alloc_avg.block    , proc->io.submit_q.alloc_avg.block    , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.helped             , proc->io.submit_q.helped             , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.leader             , proc->io.submit_q.leader             , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.submit_q.busy               , proc->io.submit_q.busy               , __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.complete_q.completed_avg.val, proc->io.complete_q.completed_avg.val, __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.complete_q.completed_avg.cnt, proc->io.complete_q.completed_avg.cnt, __ATOMIC_SEQ_CST );
+			__atomic_fetch_add( &cltr->io.complete_q.blocks           , proc->io.complete_q.blocks           , __ATOMIC_SEQ_CST );
 		#endif
 	}
@@ -154,6 +154,7 @@
 					"- avg alloc search len   : %'18.2lf\n"
 					"- avg alloc search block : %'18.2lf\n"
-					"- total wait calls       : %'15" PRIu64 "   (%'" PRIu64 " slow, %'" PRIu64 " fast)\n"
+					"- total wait calls       : %'15" PRIu64 "\n"
 					"- avg completion/wait    : %'18.2lf\n"
+					"- total completion blocks: %'15" PRIu64 "\n"
 					"\n"
 					, cluster ? "Cluster" : "Processor",  name, id
@@ -165,7 +166,7 @@
 					, io.submit_q.alloc_avg.cnt
 					, aavgv, aavgb
-					, io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt
-					, io.complete_q.completed_avg.slow_cnt,  io.complete_q.completed_avg.fast_cnt
-					, ((double)io.complete_q.completed_avg.val) / (io.complete_q.completed_avg.slow_cnt + io.complete_q.completed_avg.fast_cnt)
+					, io.complete_q.completed_avg.cnt
+					, ((double)io.complete_q.completed_avg.val) / io.complete_q.completed_avg.cnt
+					, io.complete_q.blocks
 				);
 			}
Index: libcfa/src/concurrency/stats.hfa
===================================================================
--- libcfa/src/concurrency/stats.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/concurrency/stats.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -90,7 +90,7 @@
 				struct {
 					volatile uint64_t val;
-					volatile uint64_t slow_cnt;
-					volatile uint64_t fast_cnt;
+					volatile uint64_t cnt;
 				} completed_avg;
+				volatile uint64_t blocks;
 			} complete_q;
 		};
Index: libcfa/src/containers/list.hfa
===================================================================
--- libcfa/src/containers/list.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/containers/list.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -13,4 +13,6 @@
 // Update Count     : 1
 //
+
+#pragma once
 
 #include <assert.h>
Index: libcfa/src/exception.c
===================================================================
--- libcfa/src/exception.c	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/exception.c	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Mon Jun 26 15:13:00 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Aug 15 07:17:19 2020
-// Update Count     : 26
+// Last Modified On : Thu Aug 20 23:45:45 2020
+// Update Count     : 27
 //
 
@@ -31,4 +31,5 @@
 #include <unwind.h>
 #include <bits/debug.hfa>
+#include "concurrency/invoke.h"
 #include "stdhdr/assert.h"
 
@@ -61,16 +62,9 @@
 
 
-// Temperary global exception context. Does not work with concurency.
-struct exception_context_t {
-	struct __cfaehm_try_resume_node * top_resume;
-
-	exception_t * current_exception;
-	int current_handler_index;
-} static shared_stack = {NULL, NULL, 0};
-
 // Get the current exception context.
 // There can be a single global until multithreading occurs, then each stack
-// needs its own. It will have to be updated to handle that.
-struct exception_context_t * this_exception_context() {
+// needs its own. We get this from libcfathreads (no weak attribute).
+__attribute__((weak)) struct exception_context_t * this_exception_context() {
+	static struct exception_context_t shared_stack = {NULL, NULL};
 	return &shared_stack;
 }
@@ -125,4 +119,15 @@
 
 // MEMORY MANAGEMENT =========================================================
+
+struct __cfaehm_node {
+	struct _Unwind_Exception unwind_exception;
+	struct __cfaehm_node * next;
+	int handler_index;
+};
+
+#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
+#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
+#define UNWIND_TO_NODE(unwind) ((struct __cfaehm_node *)(unwind))
+#define NULL_MAP(map, ptr) ((ptr) ? (map(ptr)) : NULL)
 
 // How to clean up an exception in various situations.
@@ -140,15 +145,4 @@
 }
 
-// We need a piece of storage to raise the exception, for now its a single
-// piece.
-static struct _Unwind_Exception this_exception_storage;
-
-struct __cfaehm_node {
-	struct __cfaehm_node * next;
-};
-
-#define NODE_TO_EXCEPT(node) ((exception_t *)(1 + (node)))
-#define EXCEPT_TO_NODE(except) ((struct __cfaehm_node *)(except) - 1)
-
 // Creates a copy of the indicated exception and sets current_exception to it.
 static void __cfaehm_allocate_exception( exception_t * except ) {
@@ -164,14 +158,14 @@
 	}
 
+	// Initialize the node:
+	exception_t * except_store = NODE_TO_EXCEPT(store);
+	store->unwind_exception.exception_class = __cfaehm_exception_class;
+	store->unwind_exception.exception_cleanup = __cfaehm_exception_cleanup;
+	store->handler_index = 0;
+	except->virtual_table->copy( except_store, except );
+
 	// Add the node to the list:
-	store->next = EXCEPT_TO_NODE(context->current_exception);
-	context->current_exception = NODE_TO_EXCEPT(store);
-
-	// Copy the exception to storage.
-	except->virtual_table->copy( context->current_exception, except );
-
-	// Set up the exception storage.
-	this_exception_storage.exception_class = __cfaehm_exception_class;
-	this_exception_storage.exception_cleanup = __cfaehm_exception_cleanup;
+	store->next = NULL_MAP(EXCEPT_TO_NODE, context->current_exception);
+	context->current_exception = except_store;
 }
 
@@ -188,5 +182,5 @@
 	if ( context->current_exception == except ) {
 		node = to_free->next;
-		context->current_exception = (node) ? NODE_TO_EXCEPT(node) : 0;
+		context->current_exception = NULL_MAP(NODE_TO_EXCEPT, node);
 	} else {
 		node = EXCEPT_TO_NODE(context->current_exception);
@@ -216,5 +210,5 @@
 	// Verify actions follow the rules we expect.
 	verify((actions & _UA_CLEANUP_PHASE) && (actions & _UA_FORCE_UNWIND));
-	verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDER_FRAME)));
+	verify(!(actions & (_UA_SEARCH_PHASE | _UA_HANDLER_FRAME)));
 
 	if ( actions & _UA_END_OF_STACK ) {
@@ -225,9 +219,11 @@
 }
 
+static struct _Unwind_Exception cancel_exception_storage;
+
 // Cancel the current stack, prefroming approprate clean-up and messaging.
 void __cfaehm_cancel_stack( exception_t * exception ) {
 	// TODO: Detect current stack and pick a particular stop-function.
 	_Unwind_Reason_Code ret;
-	ret = _Unwind_ForcedUnwind( &this_exception_storage, _Stop_Fn, (void*)0x22 );
+	ret = _Unwind_ForcedUnwind( &cancel_exception_storage, _Stop_Fn, (void*)0x22 );
 	printf("UNWIND ERROR %d after force unwind\n", ret);
 	abort();
@@ -250,9 +246,10 @@
 static void __cfaehm_begin_unwind(void(*defaultHandler)(exception_t *)) {
 	struct exception_context_t * context = this_exception_context();
-	struct _Unwind_Exception * storage = &this_exception_storage;
 	if ( NULL == context->current_exception ) {
 		printf("UNWIND ERROR missing exception in begin unwind\n");
 		abort();
 	}
+	struct _Unwind_Exception * storage =
+		&EXCEPT_TO_NODE(context->current_exception)->unwind_exception;
 
 	// Call stdlibc to raise the exception
@@ -426,5 +423,5 @@
 				_Unwind_Reason_Code ret = (0 == index)
 					? _URC_CONTINUE_UNWIND : _URC_HANDLER_FOUND;
-				context->current_handler_index = index;
+				UNWIND_TO_NODE(unwind_exception)->handler_index = index;
 
 				// Based on the return value, check if we matched the exception
@@ -432,4 +429,5 @@
 					__cfadbg_print_safe(exception, " handler found\n");
 				} else {
+					// TODO: Continue the search if there is more in the table.
 					__cfadbg_print_safe(exception, " no handler\n");
 				}
@@ -523,5 +521,5 @@
 	// Exception handler
 	// Note: Saving the exception context on the stack breaks termination exceptions.
-	catch_block( this_exception_context()->current_handler_index,
+	catch_block( EXCEPT_TO_NODE( this_exception_context()->current_exception )->handler_index,
 	             this_exception_context()->current_exception );
 }
Index: libcfa/src/heap.cfa
===================================================================
--- libcfa/src/heap.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/heap.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Tue Dec 19 21:58:35 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Aug  9 12:23:20 2020
-// Update Count     : 894
+// Last Modified On : Wed Aug 12 16:43:38 2020
+// Update Count     : 902
 //
 
@@ -650,5 +650,8 @@
 		for ( HeapManager.Storage * p = freeLists[i].freeList; p != 0p; p = p->header.kind.real.next ) {
 		#else
-		for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
+		// for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; p = (p)`next->top ) {
+		for ( HeapManager.Storage * p = top( freeLists[i].freeList ); p != 0p; /* p = getNext( p )->top */) {
+			typeof(p) temp = (( p )`next)->top;			// FIX ME: direct assignent fails, initialization works
+			p = temp;
 		#endif // BUCKETLOCK
 			total += size;
@@ -1162,5 +1165,5 @@
 		choose( option ) {
 		  case M_TOP_PAD:
-			heapExpand = ceiling( value, pageSize ); return 1;
+			heapExpand = ceiling2( value, pageSize ); return 1;
 		  case M_MMAP_THRESHOLD:
 			if ( setMmapStart( value ) ) return 1;
Index: libcfa/src/iostream.cfa
===================================================================
--- libcfa/src/iostream.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/iostream.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Aug 10 09:32:14 2020
-// Update Count     : 1126
+// Last Modified On : Tue Aug 11 22:16:33 2020
+// Update Count     : 1128
 //
 
@@ -37,22 +37,4 @@
 
 forall( dtype ostype | ostream( ostype ) ) {
-	ostype & ?|?( ostype & os, zero_t ) {
-		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
-		fmt( os, "%d", 0n );
-		return os;
-	} // ?|?
-	void ?|?( ostype & os, zero_t z ) {
-		(ostype &)(os | z); ends( os );
-	} // ?|?
-
-	ostype & ?|?( ostype & os, one_t ) {
-		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
-		fmt( os, "%d", 1n );
-		return os;
-	} // ?|?
-	void ?|?( ostype & os, one_t o ) {
-		(ostype &)(os | o); ends( os );
-	} // ?|?
-
 	ostype & ?|?( ostype & os, bool b ) {
 		if ( $sepPrt( os ) ) fmt( os, "%s", $sepGetCur( os ) );
Index: libcfa/src/iostream.hfa
===================================================================
--- libcfa/src/iostream.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/iostream.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 16 07:43:32 2020
-// Update Count     : 348
+// Last Modified On : Tue Aug 11 22:16:14 2020
+// Update Count     : 350
 //
 
@@ -67,9 +67,4 @@
 
 forall( dtype ostype | ostream( ostype ) ) {
-	ostype & ?|?( ostype &, zero_t );
-	void ?|?( ostype &, zero_t );
-	ostype & ?|?( ostype &, one_t );
-	void ?|?( ostype &, one_t );
-
 	ostype & ?|?( ostype &, bool );
 	void ?|?( ostype &, bool );
Index: libcfa/src/parseargs.cfa
===================================================================
--- libcfa/src/parseargs.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ libcfa/src/parseargs.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,242 @@
+#include "parseargs.hfa"
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+extern "C" {
+	#include <getopt.h>
+	#include <sys/ioctl.h>
+
+	struct FILE;
+	extern FILE * stderr;
+	extern FILE * stdout;
+
+	extern int fileno(FILE *stream);
+
+	extern int fprintf ( FILE * stream, const char * format, ... );
+
+	extern          long long int strtoll (const char* str, char** endptr, int base);
+	extern unsigned long long int strtoull(const char* str, char** endptr, int base);
+	extern                 double strtod  (const char* str, char** endptr);
+}
+
+#include "common.hfa"
+#include "limits.hfa"
+
+extern int cfa_args_argc;
+extern char ** cfa_args_argv;
+extern char ** cfa_args_envp;
+
+static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * usage, FILE * out)  __attribute__ ((noreturn));
+
+void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left ) {
+	parse_args(cfa_args_argc, cfa_args_argv, options, opt_count, usage, left );
+}
+
+//-----------------------------------------------------------------------------
+// getopt_long wrapping
+void parse_args(
+	int argc,
+	char * argv[],
+	cfa_option options[],
+	size_t opt_count,
+	const char * usage,
+	char ** & left
+) {
+	struct option optarr[opt_count + 2];
+	{
+		int idx = 0;
+		for(i; opt_count) {
+			if(options[i].long_name) {
+				optarr[idx].name = options[i].long_name;
+				optarr[idx].flag = 0p;
+				optarr[idx].val  = options[i].short_name;
+				if(    ((intptr_t)options[i].parse) == ((intptr_t)parse_settrue)
+				    || ((intptr_t)options[i].parse) == ((intptr_t)parse_setfalse) ) {
+					optarr[idx].has_arg = no_argument;
+				} else {
+					optarr[idx].has_arg = required_argument;
+				}
+				idx++;
+			}
+		}
+		optarr[idx+0].[name, has_arg, flag, val] = ["help", no_argument, 0, 'h'];
+		optarr[idx+1].[name, has_arg, flag, val] = [0, no_argument, 0, 0];
+	}
+
+	char optstring[opt_count * 3] = { '\0' };
+	{
+		int idx = 0;
+		for(i; opt_count) {
+			optstring[idx] = options[i].short_name;
+			idx++;
+			if(    ((intptr_t)options[i].parse) != ((intptr_t)parse_settrue)
+			    && ((intptr_t)options[i].parse) != ((intptr_t)parse_setfalse) ) {
+				optstring[idx] = ':';
+				idx++;
+			}
+		}
+		optstring[idx+0] = 'h';
+		optstring[idx+1] = '\0';
+	}
+
+	FILE * out = stderr;
+	NEXT_ARG:
+	for() {
+		int idx = 0;
+		int opt = getopt_long(argc, argv, optstring, optarr, &idx);
+		switch(opt) {
+			case -1:
+				if(&left != 0p) left = argv + optind;
+				return;
+			case 'h':
+				out = stdout;
+			case '?':
+				usage(argv[0], options, opt_count, usage, out);
+			default:
+				for(i; opt_count) {
+					if(opt == options[i].short_name) {
+						const char * arg = optarg ? optarg : "";
+						bool success = options[i].parse( arg, options[i].variable );
+						if(success) continue NEXT_ARG;
+
+						fprintf(out, "Argument '%s' for option %c could not be parsed\n\n", arg, (char)opt);
+						usage(argv[0], options, opt_count, usage, out);
+					}
+				}
+				abort("Internal parse arg error\n");
+		}
+
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Print usage
+static void printopt(FILE * out, int width, int max, char sn, const char * ln, const char * help) {
+	int hwidth = max - (11 + width);
+	if(hwidth <= 0) hwidth = max;
+
+	fprintf(out, "  -%c, --%-*s   %.*s\n", sn, width, ln, hwidth, help);
+	for() {
+		help += min(strlen(help), hwidth);
+		if('\0' == *help) break;
+		fprintf(out, "%*s%.*s\n", width + 11, "", hwidth, help);
+	}
+}
+
+void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn)) {
+	usage(cfa_args_argv[0], options, opt_count, usage, error ? stderr : stdout);
+}
+
+void print_args_usage(int , char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn)) {
+	usage(argv[0], options, opt_count, usage, error ? stderr : stdout);
+}
+
+static void usage(char * cmd, cfa_option options[], size_t opt_count, const char * help, FILE * out) __attribute__((noreturn)) {
+	int width = 0;
+	{
+		for(i; opt_count) {
+			if(options[i].long_name) {
+				int w = strlen(options[i].long_name);
+				if(w > width) width = w;
+			}
+		}
+	}
+
+	int max_width = 1_000_000;
+	int outfd = fileno(out);
+	if(isatty(outfd)) {
+		struct winsize size;
+		int ret = ioctl(outfd, TIOCGWINSZ, &size);
+		if(ret < 0) abort( "ioctl error: (%d) %s\n", (int)errno, strerror(errno) );
+		max_width = size.ws_col;
+	}
+
+	fprintf(out, "Usage:\n  %s %s\n", cmd, help);
+
+	for(i; opt_count) {
+		printopt(out, width, max_width, options[i].short_name, options[i].long_name, options[i].help);
+	}
+	fprintf(out, "  -%c, --%-*s   %s\n", 'h', width, "help", "print this help message");
+	exit(out == stdout ? 0 : 1);
+}
+
+//-----------------------------------------------------------------------------
+// Typed argument parsing
+bool parse_yesno(const char * arg, bool & value ) {
+	if(strcmp(arg, "yes") == 0) {
+		value = true;
+		return true;
+	}
+
+	if(strcmp(arg, "no") == 0) {
+		value = false;
+		return true;
+	}
+
+	return false;
+}
+
+bool parse_settrue (const char *, bool & value ) {
+	value = true;
+	return true;
+}
+
+bool parse_setfalse(const char *, bool & value )  {
+	value = false;
+	return true;
+}
+
+bool parse(const char * arg, const char * & value ) {
+	value = arg;
+	return true;
+}
+
+bool parse(const char * arg, int & value) {
+	char * end;
+	int r = strtoll(arg, &end, 10);
+	if(*end != '\0') return false;
+
+	value = r;
+	return true;
+}
+
+bool parse(const char * arg, unsigned & value) {
+	char * end;
+	unsigned long long int r = strtoull(arg, &end, 10);
+	if(*end != '\0') return false;
+	if(r > (unsigned)MAX) return false;
+
+	value = r;
+	return true;
+}
+
+bool parse(const char * arg, unsigned long & value) {
+	char * end;
+	unsigned long long int r = strtoull(arg, &end, 10);
+	if(*end != '\0') return false;
+	if(r > (unsigned long)MAX) return false;
+
+	value = r;
+	return true;
+}
+
+bool parse(const char * arg, unsigned long long & value) {
+        char * end;
+        unsigned long long int r = strtoull(arg, &end, 10);
+        if(*end != '\0') return false;
+        if(r > (unsigned long long)MAX) return false;
+
+        value = r;
+        return true;
+}
+
+bool parse(const char * arg, double & value) {
+	char * end;
+	double r = strtod(arg, &end);
+	if(*end != '\0') return false;
+
+	value = r;
+	return true;
+}
Index: libcfa/src/parseargs.hfa
===================================================================
--- libcfa/src/parseargs.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ libcfa/src/parseargs.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,48 @@
+#pragma once
+
+struct cfa_option {
+      char short_name;
+      const char * long_name;
+      const char * help;
+      void * variable;
+      bool (*parse)(const char *, void * );
+};
+
+extern cfa_option last_option;
+
+static inline void ?{}( cfa_option & this ) {}
+
+forall(dtype T | { bool parse(const char *, T & ); })
+static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable ) {
+      this.short_name = short_name;
+      this.long_name  = long_name;
+      this.help       = help;
+      this.variable   = (void*)&variable;
+      this.parse      = (bool (*)(const char *, void * ))parse;
+}
+
+forall(dtype T)
+static inline void ?{}( cfa_option & this, char short_name, const char * long_name, const char * help, T & variable, bool (*parse)(const char *, T & )) {
+      this.short_name = short_name;
+      this.long_name  = long_name;
+      this.help       = help;
+      this.variable   = (void*)&variable;
+      this.parse      = (bool (*)(const char *, void * ))parse;
+}
+
+void parse_args( cfa_option options[], size_t opt_count, const char * usage, char ** & left );
+void parse_args( int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, char ** & left );
+
+void print_args_usage(cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn));
+void print_args_usage(int argc, char * argv[], cfa_option options[], size_t opt_count, const char * usage, bool error)  __attribute__ ((noreturn));
+
+bool parse_yesno   (const char *, bool & );
+bool parse_settrue (const char *, bool & );
+bool parse_setfalse(const char *, bool & );
+
+bool parse(const char *, const char * & );
+bool parse(const char *, int & );
+bool parse(const char *, unsigned & );
+bool parse(const char *, unsigned long & );
+bool parse(const char *, unsigned long long & );
+bool parse(const char *, double & );
Index: libcfa/src/stdlib.hfa
===================================================================
--- libcfa/src/stdlib.hfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ libcfa/src/stdlib.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Thu Jan 28 17:12:35 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Jul 30 16:14:58 2020
-// Update Count     : 490
+// Last Modified On : Fri Aug 14 23:38:50 2020
+// Update Count     : 504
 //
 
@@ -39,4 +39,8 @@
 //---------------------------------------
 
+#include "common.hfa"
+
+//---------------------------------------
+
 // Macro because of returns
 #define $VAR_ALLOC( allocation, alignment ) \
@@ -136,23 +140,23 @@
 	T * alloc_set( char fill ) {
 		return (T *)memset( (T *)alloc(), (int)fill, sizeof(T) ); // initialize with fill value
-	} // alloc
-
-	T * alloc_set( T fill ) {
+	} // alloc_set
+
+	T * alloc_set( const T & fill ) {
 		return (T *)memcpy( (T *)alloc(), &fill, sizeof(T) ); // initialize with fill value
-	} // alloc
+	} // alloc_set
 
 	T * alloc_set( size_t dim, char fill ) {
 		return (T *)memset( (T *)alloc( dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
-	} // alloc
-
-	T * alloc_set( size_t dim, T fill ) {
+	} // alloc_set
+
+	T * alloc_set( size_t dim, const T & fill ) {
 		T * r = (T *)alloc( dim );
 		for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
 		return r;
-	} // alloc
-
-	T * alloc_set( size_t dim, const T fill[] ) {
-		return (T *)memcpy( (T *)alloc( dim ), fill, dim * sizeof(T) ); // initialize with fill value
-	} // alloc
+	} // alloc_set
+
+	T * alloc_set( size_t dimNew, const T fill[], size_t dimOld ) {
+		return (T *)memcpy( (T *)alloc( dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) ); // initialize with fill value
+	} // alloc_set
 
 	T * alloc_set( T ptr[], size_t dim, char fill ) {	// realloc array with fill
@@ -166,5 +170,5 @@
 	} // alloc_set
 
-	T * alloc_set( T ptr[], size_t dim, T & fill ) {	// realloc array with fill
+	T * alloc_set( T ptr[], size_t dim, const T & fill ) {	// realloc array with fill
 		size_t odim = malloc_size( ptr ) / sizeof(T);	// current dimension
 		size_t nsize = dim * sizeof(T);					// new allocation
@@ -177,5 +181,5 @@
 		} // if
 		return nptr;
-	} // alloc_align_set
+	} // alloc_set
 } // distribution
 
@@ -204,23 +208,23 @@
 	T * alloc_align_set( size_t align, char fill ) {
 		return (T *)memset( (T *)alloc_align( align ), (int)fill, sizeof(T) ); // initialize with fill value
-	} // alloc_align
-
-	T * alloc_align_set( size_t align, T fill ) {
+	} // alloc_align_set
+
+	T * alloc_align_set( size_t align, const T & fill ) {
 		return (T *)memcpy( (T *)alloc_align( align ), &fill, sizeof(T) ); // initialize with fill value
-	} // alloc_align
+	} // alloc_align_set
 
 	T * alloc_align_set( size_t align, size_t dim, char fill ) {
 		return (T *)memset( (T *)alloc_align( align, dim ), (int)fill, dim * sizeof(T) ); // initialize with fill value
-	} // alloc_align
-
-	T * alloc_align_set( size_t align, size_t dim, T fill ) {
+	} // alloc_align_set
+
+	T * alloc_align_set( size_t align, size_t dim, const T & fill ) {
 		T * r = (T *)alloc_align( align, dim );
 		for ( i; dim ) { memcpy( &r[i], &fill, sizeof(T) ); } // initialize with fill value
 		return r;
-	} // alloc_align
-
-	T * alloc_align_set( size_t align, size_t dim, const T fill[] ) {
-		return (T *)memcpy( (T *)alloc_align( align, dim ), fill, dim * sizeof(T) );
-	} // alloc_align
+	} // alloc_align_set
+
+	T * alloc_align_set( size_t align, size_t dimNew, const T fill[], size_t dimOld ) {
+		return (T *)memcpy( (T *)alloc_align( align, dimNew ), fill, min( dimNew, dimOld ) * sizeof(T) );
+	} // alloc_align_set
 
 	T * alloc_align_set( T ptr[], size_t align, size_t dim, char fill ) {
@@ -234,5 +238,5 @@
 	} // alloc_align_set
 
-	T * alloc_align_set( T ptr[], size_t align, size_t dim, T & fill ) {
+	T * alloc_align_set( T ptr[], size_t align, size_t dim, const T & fill ) {
 		size_t odim = malloc_size( ptr ) / sizeof(T);	// current dimension
 		size_t nsize = dim * sizeof(T);					// new allocation
@@ -374,8 +378,4 @@
 //---------------------------------------
 
-#include "common.hfa"
-
-//---------------------------------------
-
 extern bool threading_enabled(void) OPTIONAL_THREAD;
 
Index: src/AST/Attribute.hpp
===================================================================
--- src/AST/Attribute.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Attribute.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -51,4 +51,6 @@
 	template<typename node_t>
 	friend node_t * mutate(const node_t * node);
+	template<typename node_t>
+    friend node_t * shallowCopy(const node_t * node);
 };
 
Index: src/AST/CVQualifiers.hpp
===================================================================
--- src/AST/CVQualifiers.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/CVQualifiers.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -27,12 +27,11 @@
 		Restrict = 1 << 1,
 		Volatile = 1 << 2,
-		Lvalue   = 1 << 3,
-		Mutex    = 1 << 4,
-		Atomic   = 1 << 5,
-		NumQualifiers = 6
+		Mutex    = 1 << 3,
+		Atomic   = 1 << 4,
+		NumQualifiers = 5
 	};
 
 	/// Mask for equivalence-preserving qualfiers
-	enum { EquivQualifiers = ~(Restrict | Lvalue) };
+	enum { EquivQualifiers = ~Restrict };
 
 	/// Underlying data for qualifiers
@@ -44,5 +43,4 @@
 				bool is_restrict : 1;
 				bool is_volatile : 1;
-				bool is_lvalue   : 1;
 				bool is_mutex    : 1;
 				bool is_atomic   : 1;
Index: src/AST/Convert.cpp
===================================================================
--- src/AST/Convert.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Convert.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -20,4 +20,5 @@
 
 #include "AST/Attribute.hpp"
+#include "AST/Copy.hpp"
 #include "AST/Decl.hpp"
 #include "AST/Expr.hpp"
@@ -166,5 +167,5 @@
 			LinkageSpec::Spec( node->linkage.val ),
 			bfwd,
-			type,
+			type->clone(),
 			init,
 			attr,
@@ -587,5 +588,5 @@
 		assert( tgtResnSlots.empty() );
 
-		if ( srcInferred.mode == ast::Expr::InferUnion::Params ) {
+		if ( srcInferred.data.inferParams ) {
 			const ast::InferredParams &srcParams = srcInferred.inferParams();
 			for (auto & srcParam : srcParams) {
@@ -593,11 +594,12 @@
 					srcParam.second.decl,
 					get<Declaration>().accept1(srcParam.second.declptr),
-					get<Type>().accept1(srcParam.second.actualType),
-					get<Type>().accept1(srcParam.second.formalType),
-					get<Expression>().accept1(srcParam.second.expr)
+					get<Type>().accept1(srcParam.second.actualType)->clone(),
+					get<Type>().accept1(srcParam.second.formalType)->clone(),
+					get<Expression>().accept1(srcParam.second.expr)->clone()
 				));
 				assert(res.second);
 			}
-		} else if ( srcInferred.mode == ast::Expr::InferUnion::Slots  ) {
+		}
+		if ( srcInferred.data.resnSlots ) {
 			const ast::ResnSlots &srcSlots = srcInferred.resnSlots();
 			for (auto srcSlot : srcSlots) {
@@ -620,4 +622,15 @@
 
 		tgt->result = get<Type>().accept1(src->result);
+		// Unconditionally use a clone of the result type.
+		// We know this will leak some objects: much of the immediate conversion result.
+		// In some cases, using the conversion result directly gives unintended object sharing.
+		// A parameter (ObjectDecl, a child of a FunctionType) is shared by the weak-ref cache.
+		// But tgt->result must be fully owned privately by tgt.
+		// Applying these conservative copies here means
+		// - weak references point at the declaration's copy, not these expr.result copies (good)
+		// - we copy more objects than really needed (bad, tolerated)
+		if (tgt->result) {
+			tgt->result = tgt->result->clone();
+		}
 		return visitBaseExpr_skipResultType(src, tgt);
 	}
@@ -979,6 +992,11 @@
 
 	const ast::Expr * visit( const ast::StmtExpr * node ) override final {
+		auto stmts = node->stmts;
+		// disable sharing between multiple StmtExprs explicitly.
+		if (inCache(stmts)) {
+			stmts = ast::deepCopy(stmts.get());
+		}
 		auto rslt = new StmtExpr(
-			get<CompoundStmt>().accept1(node->stmts)
+			get<CompoundStmt>().accept1(stmts)
 		);
 
@@ -1986,5 +2004,5 @@
 
 		assert( oldInferParams.empty() || oldResnSlots.empty() );
-		assert( newInferred.mode == ast::Expr::InferUnion::Empty );
+		// assert( newInferred.mode == ast::Expr::InferUnion::Empty );
 
 		if ( !oldInferParams.empty() ) {
@@ -2117,5 +2135,6 @@
 				old->location,
 				GET_ACCEPT_1(member, DeclWithType),
-				GET_ACCEPT_1(aggregate, Expr)
+				GET_ACCEPT_1(aggregate, Expr),
+				ast::MemberExpr::NoOpConstructionChosen
 			)
 		);
Index: src/AST/Copy.hpp
===================================================================
--- src/AST/Copy.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ src/AST/Copy.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,133 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Copy.hpp -- Provides functions to copy the AST.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Jul 10 16:13:00 2019
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Jun 19 16:43:00 2020
+// Update Count     : 1
+//
+
+#pragma once
+
+#include "Decl.hpp"
+#include "Expr.hpp"
+#include "Pass.hpp"
+#include "Stmt.hpp"
+#include "Type.hpp"
+
+namespace ast {
+
+template<typename node_t>
+node_t * shallowCopy( const node_t * node );
+/* Create a shallow copy of the node given.
+ *
+ * The new node has all the same primitive field values and points to the
+ * same children nodes as the parent.
+ */
+
+template<typename node_t>
+node_t * deepCopy( const node_t * localRoot );
+/* Create a deep copy of the tree rooted at localRoot.
+ *
+ * This creates a copy of every node in the sub-tree (reachable by strong
+ * reference from local_root) and updates any readonly pointers on those nodes
+ * that point to another node in the sub-tree to the new version of that node.
+ */
+
+class DeepCopyCore {
+	std::unordered_map< const Node *, const Node * > nodeCache;
+	std::unordered_set< readonly<Node> * > readonlyCache;
+
+	template<typename node_t>
+	void readonlyInsert( const readonly<node_t> * ptrptr ) {
+		readonlyCache.insert( (readonly<Node> *) ptrptr );
+	}
+
+public:
+	template<typename node_t>
+	const node_t * previsit( const node_t * node ) {
+		const node_t * copy = shallowCopy( node );
+		nodeCache.insert( std::make_pair( node, copy ) );
+		return copy;
+	}
+
+	void postvisit( const AggregateDecl * node ) {
+		readonlyInsert( &node->parent );
+	}
+
+	void postvisit( const StructInstType * node ) {
+		readonlyInsert( &node->base );
+	}
+
+	void postvisit( const UnionInstType * node ) {
+		readonlyInsert( &node->base );
+	}
+
+	void postvisit( const EnumInstType * node ) {
+		readonlyInsert( &node->base );
+	}
+
+	void postvisit( const TraitInstType * node ) {
+		readonlyInsert( &node->base );
+	}
+
+	void postvisit( const TypeInstType * node ) {
+		readonlyInsert( &node->base );
+	}
+
+	void postvisit( const ImplicitCtorDtorStmt * node ) {
+		readonlyInsert( (const readonly<Stmt> *) &node->callStmt );
+	}
+
+	void postvisit( const MemberExpr * node ) {
+		readonlyInsert( &node->member );
+	}
+
+	void postvisit( const VariableExpr * node ) {
+		readonlyInsert( &node->var );
+	}
+
+	void postvisit( const OffsetofExpr * node ) {
+		readonlyInsert( &node->member );
+	}
+
+	void postvisit( const DeletedExpr * node ) {
+		readonlyInsert( &node->deleteStmt );
+	}
+
+	void readonlyUpdates() {
+		for ( readonly<Node> * ptr : readonlyCache ) {
+			auto it = nodeCache.find( ptr->get() );
+			if ( nodeCache.end() != it ) {
+				*ptr = it->second;
+			}
+		}
+	}
+};
+
+template<typename node_t>
+node_t * shallowCopy( const node_t * localRoot ) {
+	return localRoot->clone();
+}
+
+template<typename node_t>
+node_t * deepCopy( const node_t * localRoot ) {
+	Pass< DeepCopyCore > dc;
+	node_t const * newRoot = localRoot->accept( dc );
+	dc.core.readonlyUpdates();
+	return const_cast< node_t * >( newRoot );
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Decl.cpp
===================================================================
--- src/AST/Decl.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Decl.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -50,5 +50,7 @@
 
 const Type * FunctionDecl::get_type() const { return type.get(); }
-void FunctionDecl::set_type(Type * t) { type = strict_dynamic_cast< FunctionType* >( t ); }
+void FunctionDecl::set_type( const Type * t ) {
+	type = strict_dynamic_cast< const FunctionType * >( t );
+}
 
 // --- TypeDecl
Index: src/AST/Decl.hpp
===================================================================
--- src/AST/Decl.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Decl.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -33,5 +33,7 @@
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
-#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
@@ -88,5 +90,5 @@
 	virtual const Type * get_type() const = 0;
 	/// Set type of this declaration. May be verified by subclass
-	virtual void set_type(Type *) = 0;
+	virtual void set_type( const Type * ) = 0;
 
 	const DeclWithType * accept( Visitor & v ) const override = 0;
@@ -111,5 +113,5 @@
 
 	const Type* get_type() const override { return type; }
-	void set_type( Type * ty ) override { type = ty; }
+	void set_type( const Type * ty ) override { type = ty; }
 
 	const DeclWithType * accept( Visitor& v ) const override { return v.visit( this ); }
@@ -133,5 +135,5 @@
 
 	const Type * get_type() const override;
-	void set_type(Type * t) override;
+	void set_type( const Type * t ) override;
 
 	bool has_body() const { return stmts; }
@@ -150,6 +152,7 @@
 	std::vector<ptr<DeclWithType>> assertions;
 
-	NamedTypeDecl( const CodeLocation& loc, const std::string& name, Storage::Classes storage,
-		Type* b, Linkage::Spec spec = Linkage::Cforall )
+	NamedTypeDecl(
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage,
+		const Type * b, Linkage::Spec spec = Linkage::Cforall )
 	: Decl( loc, name, storage, spec ), base( b ), params(), assertions() {}
 
@@ -186,8 +189,9 @@
 	};
 
-	TypeDecl( const CodeLocation & loc, const std::string & name, Storage::Classes storage, Type * b,
-			  Kind k, bool s, Type * i = nullptr )
-		: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == Ttype || s ),
-		init( i ) {}
+	TypeDecl(
+		const CodeLocation & loc, const std::string & name, Storage::Classes storage,
+		const Type * b, TypeDecl::Kind k, bool s, const Type * i = nullptr )
+	: NamedTypeDecl( loc, name, storage, b ), kind( k ), sized( k == TypeDecl::Ttype || s ),
+	  init( i ) {}
 
 	const char * typeString() const override;
Index: src/AST/Eval.hpp
===================================================================
--- src/AST/Eval.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ src/AST/Eval.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,37 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Eval.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Created On       : Fri Jun 28 14:00:00 2019
+// Update Count     : 1
+//
+
+#include <string>
+#include <utility>
+
+#include "Expr.hpp"
+
+namespace ast {
+
+/// Create a new UntypedExpr with the given arguments
+template< typename... Args >
+UntypedExpr * call( const CodeLocation & loc, const std::string & name, Args &&... args ) {
+	return new UntypedExpr { 
+		loc, new NameExpr { loc, name }, 
+		std::vector< ptr< Expr > > { std::forward< Args >( args )... } };
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Expr.cpp
===================================================================
--- src/AST/Expr.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Expr.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -20,5 +20,8 @@
 #include <vector>
 
+#include "Copy.hpp"                // for shallowCopy
+#include "Eval.hpp"                // for call
 #include "GenericSubstitution.hpp"
+#include "LinkageSpec.hpp"
 #include "Stmt.hpp"
 #include "Type.hpp"
@@ -27,9 +30,18 @@
 #include "Common/SemanticError.h"
 #include "GenPoly/Lvalue.h"        // for referencesPermissable
-#include "InitTweak/InitTweak.h"   // for getPointerBase
+#include "InitTweak/InitTweak.h"   // for getFunction, getPointerBase
 #include "ResolvExpr/typeops.h"    // for extractResultType
 #include "Tuples/Tuples.h"         // for makeTupleType
 
 namespace ast {
+
+namespace {
+	std::set<std::string> const lvalueFunctionNames = {"*?", "?[?]"};
+}
+
+// --- Expr
+bool Expr::get_lvalue() const {
+	return false;
+}
 
 // --- ApplicationExpr
@@ -46,4 +58,11 @@
 }
 
+bool ApplicationExpr::get_lvalue() const {
+	if ( const DeclWithType * func = InitTweak::getFunction( this ) ) {
+		return func->linkage == Linkage::Intrinsic && lvalueFunctionNames.count( func->name );
+	}
+	return false;
+}
+
 // --- UntypedExpr
 
@@ -51,7 +70,5 @@
 	assert( arg );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "*?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ arg } }
-	};
+	UntypedExpr * ret = call( loc, "*?", arg );
 	if ( const Type * ty = arg->result ) {
 		const Type * base = InitTweak::getPointerBase( ty );
@@ -65,8 +82,12 @@
 			// base type
 			ret->result = base;
-			add_qualifiers( ret->result, CV::Lvalue );
 		}
 	}
 	return ret;
+}
+
+bool UntypedExpr::get_lvalue() const {
+	std::string fname = InitTweak::getFunctionName( this );
+	return lvalueFunctionNames.count( fname );
 }
 
@@ -74,7 +95,5 @@
 	assert( lhs && rhs );
 
-	UntypedExpr * ret = new UntypedExpr{
-		loc, new NameExpr{loc, "?=?"}, std::vector<ptr<Expr>>{ ptr<Expr>{ lhs }, ptr<Expr>{ rhs } }
-	};
+	UntypedExpr * ret = call( loc, "?=?", lhs, rhs );
 	if ( lhs->result && rhs->result ) {
 		// if both expressions are typed, assumes that this assignment is a C bitwise assignment,
@@ -108,8 +127,7 @@
 AddressExpr::AddressExpr( const CodeLocation & loc, const Expr * a ) : Expr( loc ), arg( a ) {
 	if ( arg->result ) {
-		if ( arg->result->is_lvalue() ) {
+		if ( arg->get_lvalue() ) {
 			// lvalue, retains all levels of reference, and gains a pointer inside the references
 			Type * res = addrType( arg->result );
-			res->set_lvalue( false ); // result of & is never an lvalue
 			result = res;
 		} else {
@@ -118,5 +136,4 @@
 					dynamic_cast< const ReferenceType * >( arg->result.get() ) ) {
 				Type * res = addrType( refType->base );
-				res->set_lvalue( false ); // result of & is never an lvalue
 				result = res;
 			} else {
@@ -139,8 +156,19 @@
 : Expr( loc, new VoidType{} ), arg( a ), isGenerated( g ) {}
 
+bool CastExpr::get_lvalue() const {
+	// This is actually wrong by C, but it works with our current set-up.
+	return arg->get_lvalue();
+}
+
 // --- KeywordCastExpr
 
 const char * KeywordCastExpr::targetString() const {
 	return AggregateDecl::aggrString( target );
+}
+
+// --- UntypedMemberExpr
+
+bool UntypedMemberExpr::get_lvalue() const {
+	return aggregate->get_lvalue();
 }
 
@@ -153,10 +181,59 @@
 	assert( aggregate->result );
 
-	// take ownership of member type
-	result = mem->get_type();
+	// Deep copy on result type avoids mutation on transitively multiply referenced object.
+	//
+	// Example, adapted from parts of builtins and bootloader:
+	//
+	// forall(dtype T)
+	// struct __Destructor {
+	//   T * object;
+	//   void (*dtor)(T *);
+	// };
+	//
+	// forall(dtype S)
+	// void foo(__Destructor(S) &d) {
+	//   if (d.dtor) {  // here
+	//   }
+	// }
+	//
+	// Let e be the "d.dtor" guard espression, which is MemberExpr after resolve.  Let d be the
+	// declaration of member __Destructor.dtor (an ObjectDecl), as accessed via the top-level
+	// declaration of __Destructor.  Consider the types e.result and d.type.  In the old AST, one
+	// is a clone of the other.  Ordinary new-AST use would set them up as a multiply-referenced
+	// object.
+	//
+	// e.result: PointerType
+	// .base: FunctionType
+	// .params.front(): ObjectDecl, the anonymous parameter of type T*
+	// .type: PointerType
+	// .base: TypeInstType
+	// let x = that
+	// let y = similar, except start from d.type
+	//
+	// Consider two code lines down, genericSubstitution(...).apply(result).
+	//
+	// Applying this chosen-candidate's type substitution means modifying x, substituting
+	// S for T.  This mutation should affect x and not y.
+
+	result = deepCopy(mem->get_type());
+
 	// substitute aggregate generic parameters into member type
 	genericSubstitution( aggregate->result ).apply( result );
-	// ensure lvalue and appropriate restrictions from aggregate type
-	add_qualifiers( result, aggregate->result->qualifiers | CV::Lvalue );
+	// ensure appropriate restrictions from aggregate type
+	add_qualifiers( result, aggregate->result->qualifiers );
+}
+
+MemberExpr::MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
+    MemberExpr::NoOpConstruction overloadSelector )
+: Expr( loc ), member( mem ), aggregate( agg ) {
+	assert( member );
+	assert( aggregate );
+	assert( aggregate->result );
+	(void) overloadSelector;
+}
+
+bool MemberExpr::get_lvalue() const {
+	// This is actually wrong by C, but it works with our current set-up.
+	return true;
 }
 
@@ -170,6 +247,10 @@
 	assert( var );
 	assert( var->get_type() );
-	result = var->get_type();
-	add_qualifiers( result, CV::Lvalue );
+	result = shallowCopy( var->get_type() );
+}
+
+bool VariableExpr::get_lvalue() const {
+	// It isn't always an lvalue, but it is never an rvalue.
+	return true;
 }
 
@@ -258,4 +339,11 @@
 : Expr( loc, new BasicType{ BasicType::SignedInt } ), arg1( a1 ), arg2( a2 ), isAnd( ia ) {}
 
+// --- CommaExpr
+bool CommaExpr::get_lvalue() const {
+	// This is wrong by C, but the current implementation uses it.
+	// (ex: Specialize, Lvalue and Box)
+	return arg2->get_lvalue();
+}
+
 // --- ConstructorExpr
 
@@ -276,5 +364,8 @@
 	assert( t && i );
 	result = t;
-	add_qualifiers( result, CV::Lvalue );
+}
+
+bool CompoundLiteralExpr::get_lvalue() const {
+	return true;
 }
 
@@ -293,5 +384,8 @@
 	// like MemberExpr, TupleIndexExpr is always an lvalue
 	result = type->types[ index ];
-	add_qualifiers( result, CV::Lvalue );
+}
+
+bool TupleIndexExpr::get_lvalue() const {
+	return tuple->get_lvalue();
 }
 
Index: src/AST/Expr.hpp
===================================================================
--- src/AST/Expr.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Expr.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -31,5 +31,8 @@
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
-#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
+
 
 class ConverterOldToNew;
@@ -42,5 +45,5 @@
 struct ParamEntry {
 	UniqueId decl;
-	ptr<Decl> declptr;
+	readonly<Decl> declptr;
 	ptr<Type> actualType;
 	ptr<Type> formalType;
@@ -62,22 +65,33 @@
 class Expr : public ParseNode {
 public:
-	/// Saves space (~16 bytes) by combining ResnSlots and InferredParams
+	/*
+	 * NOTE: the union approach is incorrect until the case of
+	 * partial resolution in InferMatcher is eliminated.
+	 * it is reverted to allow unresolved and resolved parameters
+	 * to coexist in an expression node.
+	 */
 	struct InferUnion {
+		// mode is now unused
 		enum { Empty, Slots, Params } mode;
-		union data_t {
-			char def;
-			ResnSlots resnSlots;
-			InferredParams inferParams;
-
-			data_t() : def('\0') {}
-			~data_t() {}
+		struct data_t {
+			// char def;
+			ResnSlots * resnSlots;
+			InferredParams * inferParams;
+
+			data_t(): resnSlots(nullptr), inferParams(nullptr) {}
+			data_t(const data_t &other) = delete;
+			~data_t() {
+				delete resnSlots;
+				delete inferParams;
+			}
 		} data;
 
 		/// initializes from other InferUnion
 		void init_from( const InferUnion& o ) {
-			switch ( o.mode ) {
-			case Empty:  return;
-			case Slots:  new(&data.resnSlots) ResnSlots{ o.data.resnSlots }; return;
-			case Params: new(&data.inferParams) InferredParams{ o.data.inferParams }; return;
+			if (o.data.resnSlots) {
+				data.resnSlots = new ResnSlots(*o.data.resnSlots);
+			}
+			if (o.data.inferParams) {
+				data.inferParams = new InferredParams(*o.data.inferParams);
 			}
 		}
@@ -85,19 +99,8 @@
 		/// initializes from other InferUnion (move semantics)
 		void init_from( InferUnion&& o ) {
-			switch ( o.mode ) {
-			case Empty:  return;
-			case Slots:  new(&data.resnSlots) ResnSlots{ std::move(o.data.resnSlots) }; return;
-			case Params:
-				new(&data.inferParams) InferredParams{ std::move(o.data.inferParams) }; return;
-			}
-		}
-
-		/// clears variant fields
-		void reset() {
-			switch( mode ) {
-			case Empty:  return;
-			case Slots:  data.resnSlots.~ResnSlots(); return;
-			case Params: data.inferParams.~InferredParams(); return;
-			}
+			data.resnSlots = o.data.resnSlots;
+			data.inferParams = o.data.inferParams;
+			o.data.resnSlots = nullptr;
+			o.data.inferParams = nullptr;
 		}
 
@@ -107,18 +110,17 @@
 		InferUnion& operator= ( const InferUnion& ) = delete;
 		InferUnion& operator= ( InferUnion&& ) = delete;
-		~InferUnion() { reset(); }
+
+		bool hasSlots() const { return data.resnSlots; }
 
 		ResnSlots& resnSlots() {
-			switch (mode) {
-			case Empty: new(&data.resnSlots) ResnSlots{}; mode = Slots; // fallthrough
-			case Slots: return data.resnSlots;
-			case Params: assertf(false, "Cannot return to resnSlots from Params"); abort();
+			if (!data.resnSlots) {
+				data.resnSlots = new ResnSlots();
 			}
-			assertf(false, "unreachable");
+			return *data.resnSlots;
 		}
 
 		const ResnSlots& resnSlots() const {
-			if (mode == Slots) {
-				return data.resnSlots;
+			if (data.resnSlots) {
+				return *data.resnSlots;
 			}
 			assertf(false, "Mode was not already resnSlots");
@@ -127,15 +129,13 @@
 
 		InferredParams& inferParams() {
-			switch (mode) {
-			case Slots: data.resnSlots.~ResnSlots(); // fallthrough
-			case Empty: new(&data.inferParams) InferredParams{}; mode = Params; // fallthrough
-			case Params: return data.inferParams;
+			if (!data.inferParams) {
+				data.inferParams = new InferredParams();
 			}
-			assertf(false, "unreachable");
+			return *data.inferParams;
 		}
 
 		const InferredParams& inferParams() const {
-			if (mode == Params) {
-				return data.inferParams;
+			if (data.inferParams) {
+				return *data.inferParams;
 			}
 			assertf(false, "Mode was not already Params");
@@ -143,17 +143,9 @@
 		}
 
-		void set_inferParams( InferredParams && ps ) {
-			switch(mode) {
-			case Slots:
-				data.resnSlots.~ResnSlots();
-				// fallthrough
-			case Empty:
-				new(&data.inferParams) InferredParams{ std::move( ps ) };
-				mode = Params;
-				break;
-			case Params:
-				data.inferParams = std::move( ps );
-				break;
-			}
+		void set_inferParams( InferredParams * ps ) {
+			delete data.resnSlots;
+			data.resnSlots = nullptr;
+			delete data.inferParams;
+			data.inferParams = ps;
 		}
 
@@ -161,16 +153,28 @@
 		/// and the other is in `Params`.
 		void splice( InferUnion && o ) {
-			if ( o.mode == Empty ) return;
-			if ( mode == Empty ) { init_from( o ); return; }
-			assert( mode == o.mode && "attempt to splice incompatible InferUnion" );
-
-			if ( mode == Slots ){
-				data.resnSlots.insert(
-					data.resnSlots.end(), o.data.resnSlots.begin(), o.data.resnSlots.end() );
-			} else if ( mode == Params ) {
-				for ( const auto & p : o.data.inferParams ) {
-					data.inferParams[p.first] = std::move(p.second);
+			if (o.data.resnSlots) {
+				if (data.resnSlots) {
+					data.resnSlots->insert(
+						data.resnSlots->end(), o.data.resnSlots->begin(), o.data.resnSlots->end() );
+					delete o.data.resnSlots;
 				}
-			} else assertf(false, "invalid mode");
+				else {
+					data.resnSlots = o.data.resnSlots;
+				}
+				o.data.resnSlots = nullptr;
+			}
+
+			if (o.data.inferParams) {
+				if (data.inferParams) {
+					for ( const auto & p : *o.data.inferParams ) {
+						(*data.inferParams)[p.first] = std::move(p.second);
+					}
+					delete o.data.inferParams;
+				}
+				else {
+					data.inferParams = o.data.inferParams;
+				}
+				o.data.inferParams = nullptr;
+			}
 		}
 	};
@@ -185,4 +189,5 @@
 
 	Expr * set_extension( bool ex ) { extension = ex; return this; }
+	virtual bool get_lvalue() const;
 
 	virtual const Expr * accept( Visitor & v ) const override = 0;
@@ -201,4 +206,6 @@
 	ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} );
 
+	bool get_lvalue() const final;
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
@@ -215,4 +222,6 @@
 	UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} )
 	: Expr( loc ), func( f ), args( std::move(as) ) {}
+
+	bool get_lvalue() const final;
 
 	/// Creates a new dereference expression
@@ -291,4 +300,6 @@
 	CastExpr( const Expr * a ) : CastExpr( a->location, a, GeneratedCast ) {}
 
+	bool get_lvalue() const final;
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
@@ -338,4 +349,6 @@
 	: Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); }
 
+	bool get_lvalue() const final;
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
@@ -352,8 +365,17 @@
 	MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg );
 
+	bool get_lvalue() const final;
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
 	MemberExpr * clone() const override { return new MemberExpr{ *this }; }
 	MUTATE_FRIEND
+
+	// Custructor overload meant only for AST conversion
+	enum NoOpConstruction { NoOpConstructionChosen };
+	MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg,
+	    NoOpConstruction overloadSelector );
+	friend class ::ConverterOldToNew;
+	friend class ::ConverterNewToOld;
 };
 
@@ -365,4 +387,6 @@
 	VariableExpr( const CodeLocation & loc );
 	VariableExpr( const CodeLocation & loc, const DeclWithType * v );
+
+	bool get_lvalue() const final;
 
 	/// generates a function pointer for a given function
@@ -532,5 +556,9 @@
 
 	CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 )
-	: Expr( loc ), arg1( a1 ), arg2( a2 ) {}
+	: Expr( loc ), arg1( a1 ), arg2( a2 ) {
+		this->result = a2->result;
+	}
+
+	bool get_lvalue() const final;
 
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
@@ -605,4 +633,6 @@
 	CompoundLiteralExpr( const CodeLocation & loc, const Type * t, const Init * i );
 
+	bool get_lvalue() const final;
+
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
 private:
@@ -660,4 +690,6 @@
 
 	TupleIndexExpr( const CodeLocation & loc, const Expr * t, unsigned i );
+
+	bool get_lvalue() const final;
 
 	const Expr * accept( Visitor & v ) const override { return v.visit( this ); }
Index: src/AST/ForallSubstitutionTable.cpp
===================================================================
--- src/AST/ForallSubstitutionTable.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ src/AST/ForallSubstitutionTable.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,54 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.cpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#include "ForallSubstitutionTable.hpp"
+
+#include <cassert>
+#include <vector>
+
+#include "Copy.hpp"                // for shallowCopy
+#include "Decl.hpp"
+#include "Node.hpp"
+#include "Type.hpp"
+#include "Visitor.hpp"
+
+namespace ast {
+
+std::vector< ptr< TypeDecl > > ForallSubstitutionTable::clone(
+	const std::vector< ptr< TypeDecl > > & forall, Visitor & v
+) {
+	std::vector< ptr< TypeDecl > > new_forall;
+	new_forall.reserve( forall.size() );
+
+	for ( const ast::TypeDecl * d : forall ) {
+		// create cloned type decl and insert into substitution map before further mutation
+		auto new_d = shallowCopy( d );
+		decls.insert( d, new_d );
+		// perform other mutations and add to output
+		auto newer_d = v.visit( new_d );
+		assert( new_d == newer_d && "Newly cloned TypeDecl must retain identity" );
+		new_forall.emplace_back( new_d );
+	}
+
+	return new_forall;
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutionTable.hpp
===================================================================
--- src/AST/ForallSubstitutionTable.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ src/AST/ForallSubstitutionTable.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,57 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutionTable.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Jun 27 14:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Jun 27 14:00:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <vector>
+
+#include "Node.hpp"  // for ptr
+#include "Common/ScopedMap.h"
+
+namespace ast {
+
+class TypeDecl;
+class Visitor;
+
+/// Wrapper for TypeDecl substitution table
+class ForallSubstitutionTable {
+	ScopedMap< const TypeDecl *, const TypeDecl * > decls;
+
+public:
+	/// Replaces given declaration with value in the table, if present, otherwise returns argument
+	const TypeDecl * replace( const TypeDecl * d ) {
+		auto it = decls.find( d );
+		if ( it != decls.end() ) return it->second;
+		return d;
+	}
+
+	/// Builds a new forall list mutated according to the given visitor
+	std::vector< ptr< TypeDecl > > clone( 
+		const std::vector< ptr< TypeDecl > > & forall, Visitor & v );
+
+	/// Introduces a new lexical scope
+	void beginScope() { decls.beginScope(); }
+
+	/// Concludes a lexical scope
+	void endScope() { decls.endScope(); }
+};
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/ForallSubstitutor.hpp
===================================================================
--- src/AST/ForallSubstitutor.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ src/AST/ForallSubstitutor.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ForallSubstitutor.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed Jun 26 15:00:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Wed Jun 26 15:00:00 2019
+// Update Count     : 1
+//
+
+#include "Pass.hpp"
+
+namespace ast {
+
+class Expr;
+
+/// Visitor that correctly substitutes TypeDecl while maintaining TypeInstType bindings.
+/// Also has some convenience methods to mutate fields.
+struct ForallSubstitutor : public WithForallSubstitutor, public WithVisitorRef<ForallSubstitutor> {
+	/// Substitute TypeInstType base type
+	readonly< TypeDecl > operator() ( const readonly< TypeDecl > & o ) {
+		return subs.replace( o );
+	}
+	
+	/// Make new forall-list clone
+	ParameterizedType::ForallList operator() ( const ParameterizedType::ForallList & o ) {
+		return subs.clone( o, *visitor );
+	}
+
+	/// Substitute parameter/return type
+	std::vector< ptr< DeclWithType > > operator() ( const std::vector< ptr< DeclWithType > > & o ) {
+		std::vector< ptr< DeclWithType > > n;
+		n.reserve( o.size() );
+		for ( const DeclWithType * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+
+	/// Substitute type parameter list
+	std::vector< ptr< Expr > > operator() ( const std::vector< ptr< Expr > > & o ) {
+		std::vector< ptr< Expr > > n;
+		n.reserve( o.size() );
+		for ( const Expr * d : o ) { n.emplace_back( d->accept( *visitor ) ); }
+		return n;
+	}
+};
+
+} // namespace ast
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/AST/Fwd.hpp
===================================================================
--- src/AST/Fwd.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Fwd.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed May  8 16:05:00 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Jun 24 09:48:00 2019
-// Update Count     : 1
+// Last Modified On : Thr Jul 23 14:15:00 2020
+// Update Count     : 2
 //
 
@@ -108,7 +108,8 @@
 class FunctionType;
 class ReferenceToType;
-class StructInstType;
-class UnionInstType;
-class EnumInstType;
+template<typename decl_t> class SueInstType;
+using StructInstType = SueInstType<StructDecl>;
+using UnionInstType = SueInstType<UnionDecl>;
+using EnumInstType = SueInstType<EnumDecl>;
 class TraitInstType;
 class TypeInstType;
Index: src/AST/GenericSubstitution.cpp
===================================================================
--- src/AST/GenericSubstitution.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/GenericSubstitution.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -62,5 +62,5 @@
 	Pass<GenericSubstitutionBuilder> builder;
 	maybe_accept( ty, builder );
-	return std::move(builder.pass.sub);
+	return std::move(builder.core.sub);
 }
 
Index: src/AST/Init.hpp
===================================================================
--- src/AST/Init.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Init.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -25,5 +25,7 @@
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
-#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
Index: src/AST/Node.cpp
===================================================================
--- src/AST/Node.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Node.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Thierry Delisle
 // Created On       : Thu May 16 14:16:00 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Jun  5 10:21:00 2020
+// Update Count     : 1
 //
 
@@ -17,4 +17,5 @@
 #include "Fwd.hpp"
 
+#include <csignal>  // MEMORY DEBUG -- for raise
 #include <iostream>
 
@@ -29,12 +30,51 @@
 #include "Print.hpp"
 
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) { node->increment(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node ) { node->decrement(ref_t); }
-
-template< typename node_t, enum ast::Node::ref_type ref_t >
-void ast::ptr_base<node_t, ref_t>::_check() const { if(node) assert(node->was_ever_strong == false || node->strong_count > 0); }
+/// MEMORY DEBUG -- allows breaking on ref-count changes of dynamically chosen object.
+/// Process to use in GDB:
+///   break ast::Node::_trap()
+///   run
+///   set variable MEM_TRAP_OBJ = <target>
+///   disable <first breakpoint>
+///   continue
+void * MEM_TRAP_OBJ = nullptr;
+
+void _trap( const void * node ) {
+	if ( node == MEM_TRAP_OBJ ) std::raise(SIGTRAP);
+}
+
+[[noreturn]] static inline void strict_fail(const ast::Node * node) {
+	assertf(node, "strict_as had nullptr input.");
+	const ast::ParseNode * parse = dynamic_cast<const ast::ParseNode *>( node );
+	if ( nullptr == parse ) {
+		assertf(nullptr, "%s (no location)", toString(node).c_str());
+	} else if ( parse->location.isUnset() ) {
+		assertf(nullptr, "%s (unset location)", toString(node).c_str());
+	} else {
+		assertf(nullptr, "%s (at %s:%d)", toString(node).c_str(),
+			parse->location.filename.c_str(), parse->location.first_line);
+	}
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_strict_fail() const {
+	strict_fail(node);
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_inc( const node_t * node ) {
+	node->increment(ref_t);
+	_trap( node );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_dec( const node_t * node, bool do_delete ) {
+	_trap( node );
+	node->decrement( ref_t, do_delete );
+}
+
+template< typename node_t, enum ast::Node::ref_type ref_t >
+void ast::ptr_base<node_t, ref_t>::_check() const {
+	// if(node) assert(node->was_ever_strong == false || node->strong_count > 0);
+}
 
 template< typename node_t, enum ast::Node::ref_type ref_t >
Index: src/AST/Node.hpp
===================================================================
--- src/AST/Node.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Node.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 8 10:27:04 2019
 // Last Modified By : Andrew Beach
-// Last Modified On : Mon Jun  3 13:26:00 2019
-// Update Count     : 5
+// Last Modified On : Fri Jun 5 9:47:00 2020
+// Update Count     : 6
 //
 
@@ -38,5 +38,5 @@
 	Node& operator= (const Node&) = delete;
 	Node& operator= (Node&&) = delete;
-	virtual ~Node() = default;
+	virtual ~Node() {}
 
 	virtual const Node * accept( Visitor & v ) const = 0;
@@ -57,4 +57,6 @@
 	template<typename node_t>
 	friend node_t * mutate(const node_t * node);
+	template<typename node_t>
+	friend node_t * shallowCopy(const node_t * node);
 
 	mutable size_t strong_count = 0;
@@ -69,5 +71,5 @@
 	}
 
-	void decrement(ast::Node::ref_type ref) const {
+	void decrement(ast::Node::ref_type ref, bool do_delete = true) const {
 		switch (ref) {
 			case ref_type::strong: strong_count--; break;
@@ -75,5 +77,5 @@
 		}
 
-		if(!strong_count && !weak_count) {
+		if( do_delete && !strong_count && !weak_count) {
 			delete this;
 		}
@@ -94,5 +96,5 @@
 	assertf(
 		node->weak_count == 0,
-		"Error: mutating node with weak references to it will invalided some references"
+		"Error: mutating node with weak references to it will invalidate some references"
 	);
 	return node->clone();
@@ -104,5 +106,5 @@
 	// skip mutate if equivalent
 	if ( node->*field == val ) return node;
-	
+
 	// mutate and return
 	node_t * ret = mutate( node );
@@ -123,4 +125,13 @@
 	(ret->*field)[i] = std::forward< field_t >( val );
 	return ret;
+}
+
+/// Mutate an entire indexed collection by cloning to accepted value
+template<typename node_t, typename parent_t, typename coll_t>
+const node_t * mutate_each( const node_t * node, coll_t parent_t::* field, Visitor & v ) {
+	for ( unsigned i = 0; i < (node->*field).size(); ++i ) {
+		node = mutate_field_index( node, field, i, (node->*field)[i]->accept( v ) );
+	}
+	return node;
 }
 
@@ -219,11 +230,27 @@
 	operator const node_t * () const { _check(); return node; }
 
+	const node_t * release() {
+		const node_t * ret = node;
+		if ( node ) {
+			_dec(node, false);
+			node = nullptr;
+		}
+		return ret;
+	}
+
 	/// wrapper for convenient access to dynamic_cast
 	template<typename o_node_t>
 	const o_node_t * as() const { _check(); return dynamic_cast<const o_node_t *>(node); }
 
-	/// wrapper for convenient access to strict_dynamic_cast
+	/// Wrapper that makes sure dynamic_cast returns non-null.
 	template<typename o_node_t>
-	const o_node_t * strict_as() const { _check(); return strict_dynamic_cast<const o_node_t *>(node); }
+	const o_node_t * strict_as() const {
+		if (const o_node_t * ret = as<o_node_t>()) return ret;
+		_strict_fail();
+	}
+
+	/// Wrapper that makes sure dynamic_cast does not fail.
+	template<typename o_node_t, decltype(nullptr) null>
+	const o_node_t * strict_as() const { return node ? strict_as<o_node_t>() : nullptr; }
 
 	/// Returns a mutable version of the pointer in this node.
@@ -244,6 +271,7 @@
 
 	void _inc( const node_t * other );
-	void _dec( const node_t * other );
+	void _dec( const node_t * other, bool do_delete = true );
 	void _check() const;
+	void _strict_fail() const __attribute__((noreturn));
 
 	const node_t * node;
Index: src/AST/Pass.hpp
===================================================================
--- src/AST/Pass.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Pass.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -8,5 +8,5 @@
 //
 // Author           : Thierry Delisle
-// Created On       : Thu May 09 15::37::05 2019
+// Created On       : Thu May 09 15:37:05 2019
 // Last Modified By :
 // Last Modified On :
@@ -35,4 +35,6 @@
 #include "AST/SymbolTable.hpp"
 
+#include "AST/ForallSubstitutionTable.hpp"
+
 // Private prelude header, needed for some of the magic tricks this class pulls off
 #include "AST/Pass.proto.hpp"
@@ -46,35 +48,38 @@
 //
 // Several additional features are available through inheritance
-// | WithTypeSubstitution - provides polymorphic const TypeSubstitution * env for the
-//                          current expression
-// | WithStmtsToAdd       - provides the ability to insert statements before or after the current
-//                          statement by adding new statements into stmtsToAddBefore or
-//                          stmtsToAddAfter respectively.
-// | WithDeclsToAdd       - provides the ability to insert declarations before or after the current
-//                          declarations by adding new DeclStmt into declsToAddBefore or
-//                          declsToAddAfter respectively.
-// | WithShortCircuiting  - provides the ability to skip visiting child nodes; set visit_children
-//                          to false in pre{visit,visit} to skip visiting children
-// | WithGuards           - provides the ability to save/restore data like a LIFO stack; to save,
-//                          call GuardValue with the variable to save, the variable will
-//                          automatically be restored to its previous value after the corresponding
-//                          postvisit/postmutate teminates.
-// | WithVisitorRef       - provides an pointer to the templated visitor wrapper
-// | WithSymbolTable      - provides symbol table functionality
+// | WithTypeSubstitution  - provides polymorphic const TypeSubstitution * env for the
+//                           current expression
+// | WithStmtsToAdd        - provides the ability to insert statements before or after the current
+//                           statement by adding new statements into stmtsToAddBefore or
+//                           stmtsToAddAfter respectively.
+// | WithDeclsToAdd        - provides the ability to insert declarations before or after the
+//                           current declarations by adding new DeclStmt into declsToAddBefore or
+//                           declsToAddAfter respectively.
+// | WithShortCircuiting   - provides the ability to skip visiting child nodes; set visit_children
+//                           to false in pre{visit,visit} to skip visiting children
+// | WithGuards            - provides the ability to save/restore data like a LIFO stack; to save,
+//                           call GuardValue with the variable to save, the variable will
+//                           automatically be restored to its previous value after the
+//                           corresponding postvisit/postmutate teminates.
+// | WithVisitorRef        - provides an pointer to the templated visitor wrapper
+// | WithSymbolTable       - provides symbol table functionality
+// | WithForallSubstitutor - maintains links between TypeInstType and TypeDecl under mutation
 //-------------------------------------------------------------------------------------------------
-template< typename pass_t >
+template< typename core_t >
 class Pass final : public ast::Visitor {
 public:
+	using core_type = core_t;
+	using type = Pass<core_t>;
+
 	/// Forward any arguments to the pass constructor
 	/// Propagate 'this' if necessary
 	template< typename... Args >
 	Pass( Args &&... args)
-		: pass( std::forward<Args>( args )... )
+		: core( std::forward<Args>( args )... )
 	{
 		// After the pass is constructed, check if it wants the have a pointer to the wrapping visitor
-		typedef Pass<pass_t> this_t;
-		this_t * const * visitor = __pass::visitor(pass, 0);
+		type * const * visitor = __pass::visitor(core, 0);
 		if(visitor) {
-			*const_cast<this_t **>( visitor ) = this;
+			*const_cast<type **>( visitor ) = this;
 		}
 	}
@@ -82,6 +87,19 @@
 	virtual ~Pass() = default;
 
+	/// Construct and run a pass on a translation unit.
+	template< typename... Args >
+	static void run( std::list< ptr<Decl> > & decls, Args &&... args ) {
+		Pass<core_t> visitor( std::forward<Args>( args )... );
+		accept_all( decls, visitor );
+	}
+
+	template< typename... Args >
+	static void run( std::list< ptr<Decl> > & decls ) {
+		Pass<core_t> visitor;
+		accept_all( decls, visitor );
+	}
+
 	/// Storage for the actual pass
-	pass_t pass;
+	core_t core;
 
 	/// Visit function declarations
@@ -179,9 +197,9 @@
 	const ast::TypeSubstitution * visit( const ast::TypeSubstitution     * ) override final;
 
-	template<typename pass_type>
-	friend void accept_all( std::list< ptr<Decl> > & decls, Pass<pass_type>& visitor );
+	template<typename core_type>
+	friend void accept_all( std::list< ptr<Decl> > & decls, Pass<core_type>& visitor );
 private:
 
-	bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(pass, 0); return ptr ? *ptr : true; }
+	bool __visit_children() { __pass::bool_ref * ptr = __pass::visit_children(core, 0); return ptr ? *ptr : true; }
 
 private:
@@ -202,4 +220,8 @@
 	container_t< ptr<node_t> > call_accept( const container_t< ptr<node_t> > & container );
 
+	/// Mutate forall-list, accounting for presence of type substitution map
+	template<typename node_t>
+	void mutate_forall( const node_t *& );
+
 public:
 	/// Logic to call the accept and mutate the parent if needed, delegates call to accept
@@ -210,14 +232,23 @@
 	/// Internal RAII guard for symbol table features
 	struct guard_symtab {
-		guard_symtab( Pass<pass_t> & pass ): pass( pass ) { __pass::symtab::enter(pass, 0); }
-		~guard_symtab()                                   { __pass::symtab::leave(pass, 0); }
-		Pass<pass_t> & pass;
+		guard_symtab( Pass<core_t> & pass ): pass( pass ) { __pass::symtab::enter(pass.core, 0); }
+		~guard_symtab()                                   { __pass::symtab::leave(pass.core, 0); }
+		Pass<core_t> & pass;
 	};
 
 	/// Internal RAII guard for scope features
 	struct guard_scope {
-		guard_scope( Pass<pass_t> & pass ): pass( pass ) { __pass::scope::enter(pass, 0); }
-		~guard_scope()                                   { __pass::scope::leave(pass, 0); }
-		Pass<pass_t> & pass;
+		guard_scope( Pass<core_t> & pass ): pass( pass ) { __pass::scope::enter(pass.core, 0); }
+		~guard_scope()                                   { __pass::scope::leave(pass.core, 0); }
+		Pass<core_t> & pass;
+	};
+
+	/// Internal RAII guard for forall substitutions
+	struct guard_forall_subs {
+		guard_forall_subs( Pass<core_t> & pass, const ParameterizedType * type )
+		: pass( pass ), type( type ) { __pass::forall::enter(pass.core, 0, type ); }
+		~guard_forall_subs()         { __pass::forall::leave(pass.core, 0, type ); }
+		Pass<core_t> & pass;
+		const ParameterizedType * type;
 	};
 
@@ -227,6 +258,6 @@
 
 /// Apply a pass to an entire translation unit
-template<typename pass_t>
-void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<pass_t> & visitor );
+template<typename core_t>
+void accept_all( std::list< ast::ptr<ast::Decl> > &, ast::Pass<core_t> & visitor );
 
 //-------------------------------------------------------------------------------------------------
@@ -268,6 +299,6 @@
 	};
 
-	template< typename pass_t>
-	friend auto __pass::at_cleanup( pass_t & pass, int ) -> decltype( &pass.at_cleanup );
+	template< typename core_t>
+	friend auto __pass::at_cleanup( core_t & core, int ) -> decltype( &core.at_cleanup );
 public:
 
@@ -305,7 +336,7 @@
 
 /// Used to get a pointer to the pass with its wrapped type
-template<typename pass_t>
+template<typename core_t>
 struct WithVisitorRef {
-	Pass<pass_t> * const visitor = nullptr;
+	Pass<core_t> * const visitor = nullptr;
 };
 
@@ -314,4 +345,10 @@
 	SymbolTable symtab;
 };
+
+/// Use when the templated visitor needs to keep TypeInstType instances properly linked to TypeDecl
+struct WithForallSubstitutor {
+	ForallSubstitutionTable subs;
+};
+
 }
 
@@ -321,6 +358,6 @@
 extern struct PassVisitorStats {
 	size_t depth = 0;
-	Stats::Counters::MaxCounter<double> * max = nullptr;
-	Stats::Counters::AverageCounter<double> * avg = nullptr;
+	Stats::Counters::MaxCounter<double> * max;
+	Stats::Counters::AverageCounter<double> * avg;
 } pass_visitor_stats;
 }
Index: src/AST/Pass.impl.hpp
===================================================================
--- src/AST/Pass.impl.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Pass.impl.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -25,9 +25,11 @@
 	using namespace ast; \
 	/* back-up the visit children */ \
-	__attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(pass, 0) ); \
+	__attribute__((unused)) ast::__pass::visit_children_guard guard1( ast::__pass::visit_children(core, 0) ); \
 	/* 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) ); \
+	__attribute__((unused)) ast::__pass::guard_value          guard2( ast::__pass::at_cleanup    (core, 0) ); \
+	/* begin tracing memory allocation if requested by this pass */ \
+	__pass::beginTrace( core, 0 ); \
 	/* call the implementation of the previsit of this pass */ \
-	__pass::previsit( pass, node, 0 );
+	__pass::previsit( core, node, 0 );
 
 #define VISIT( code... ) \
@@ -40,6 +42,8 @@
 #define VISIT_END( type, node ) \
 	/* call the implementation of the postvisit of this pass */ \
-	auto __return = __pass::postvisit( pass, node, 0 ); \
+	auto __return = __pass::postvisit( core, node, 0 ); \
 	assertf(__return, "post visit should never return null"); \
+	/* end tracing memory allocation if requested by this pass */ \
+	__pass::endTrace( core, 0 ); \
 	return __return;
 
@@ -119,7 +123,7 @@
 	}
 
-	template< typename pass_t >
+	template< typename core_t >
 	template< typename node_t >
-	auto ast::Pass< pass_t >::call_accept( const node_t * node )
+	auto ast::Pass< core_t >::call_accept( const node_t * node )
 		-> typename std::enable_if<
 				!std::is_base_of<ast::Expr, node_t>::value &&
@@ -127,8 +131,7 @@
 			, decltype( node->accept(*this) )
 		>::type
-
 	{
 		__pedantic_pass_assert( __visit_children() );
-		__pedantic_pass_assert( expr );
+		__pedantic_pass_assert( node );
 
 		static_assert( !std::is_base_of<ast::Expr, node_t>::value, "ERROR");
@@ -138,10 +141,10 @@
 	}
 
-	template< typename pass_t >
-	const ast::Expr * ast::Pass< pass_t >::call_accept( const ast::Expr * expr ) {
+	template< typename core_t >
+	const ast::Expr * ast::Pass< core_t >::call_accept( const ast::Expr * expr ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( expr );
 
-		const ast::TypeSubstitution ** env_ptr = __pass::env( pass, 0);
+		const ast::TypeSubstitution ** env_ptr = __pass::env( core, 0);
 		if ( env_ptr && expr->env ) {
 			*env_ptr = expr->env;
@@ -151,6 +154,6 @@
 	}
 
-	template< typename pass_t >
-	const ast::Stmt * ast::Pass< pass_t >::call_accept( const ast::Stmt * stmt ) {
+	template< typename core_t >
+	const ast::Stmt * ast::Pass< core_t >::call_accept( const ast::Stmt * stmt ) {
 		__pedantic_pass_assert( __visit_children() );
 		__pedantic_pass_assert( stmt );
@@ -160,11 +163,11 @@
 
 		// get the stmts/decls that will need to be spliced in
-		auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
-		auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
-		auto decls_before = __pass::declsToAddBefore( pass, 0);
-		auto decls_after  = __pass::declsToAddAfter ( pass, 0);
+		auto stmts_before = __pass::stmtsToAddBefore( core, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
+		auto decls_before = __pass::declsToAddBefore( core, 0);
+		auto decls_after  = __pass::declsToAddAfter ( core, 0);
 
 		// 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< const ast::TypeSubstitution * > __old_env         ( __pass::env( core, 0) );
 		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
 		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
@@ -202,7 +205,7 @@
 	}
 
-	template< typename pass_t >
+	template< typename core_t >
 	template< template <class...> class container_t >
-	container_t< ptr<Stmt> > ast::Pass< pass_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
+	container_t< ptr<Stmt> > ast::Pass< core_t >::call_accept( const container_t< ptr<Stmt> > & statements ) {
 		__pedantic_pass_assert( __visit_children() );
 		if( statements.empty() ) return {};
@@ -215,8 +218,8 @@
 
 		// get the stmts/decls that will need to be spliced in
-		auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
-		auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
-		auto decls_before = __pass::declsToAddBefore( pass, 0);
-		auto decls_after  = __pass::declsToAddAfter ( pass, 0);
+		auto stmts_before = __pass::stmtsToAddBefore( core, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
+		auto decls_before = __pass::declsToAddBefore( core, 0);
+		auto decls_after  = __pass::declsToAddAfter ( core, 0);
 
 		// These may be modified by subnode but most be restored once we exit this statemnet.
@@ -268,7 +271,7 @@
 	}
 
-	template< typename pass_t >
+	template< typename core_t >
 	template< template <class...> class container_t, typename node_t >
-	container_t< ast::ptr<node_t> > ast::Pass< pass_t >::call_accept( const container_t< ast::ptr<node_t> > & container ) {
+	container_t< ast::ptr<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 {};
@@ -299,7 +302,7 @@
 	}
 
-	template< typename pass_t >
+	template< typename core_t >
 	template<typename node_t, typename parent_t, typename child_t>
-	void ast::Pass< pass_t >::maybe_accept(
+	void ast::Pass< core_t >::maybe_accept(
 		const node_t * & parent,
 		child_t parent_t::*child
@@ -323,4 +326,20 @@
 	}
 
+
+	template< typename core_t >
+	template< typename node_t >
+	void ast::Pass< core_t >::mutate_forall( const node_t *& node ) {
+		if ( auto subs = __pass::forall::subs( core, 0 ) ) {
+			// tracking TypeDecl substitution, full clone
+			if ( node->forall.empty() ) return;
+
+			node_t * mut = mutate( node );
+			mut->forall = subs->clone( node->forall, *this );
+			node = mut;
+		} else {
+			// not tracking TypeDecl substitution, just mutate
+			maybe_accept( node, &node_t::forall );
+		}
+	}
 }
 
@@ -333,6 +352,6 @@
 //------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 
-template< typename pass_t >
-inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< pass_t > & visitor ) {
+template< typename core_t >
+inline void ast::accept_all( std::list< ast::ptr<ast::Decl> > & decls, ast::Pass< core_t > & visitor ) {
 	// We are going to aggregate errors for all these statements
 	SemanticErrorException errors;
@@ -342,6 +361,6 @@
 
 	// get the stmts/decls that will need to be spliced in
-	auto decls_before = __pass::declsToAddBefore( visitor.pass, 0);
-	auto decls_after  = __pass::declsToAddAfter ( visitor.pass, 0);
+	auto decls_before = __pass::declsToAddBefore( visitor.core, 0);
+	auto decls_after  = __pass::declsToAddAfter ( visitor.core, 0);
 
 	// update pass statitistics
@@ -392,6 +411,6 @@
 //--------------------------------------------------------------------------
 // ObjectDecl
-template< typename pass_t >
-const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::ObjectDecl * node ) {
+template< typename core_t >
+const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::ObjectDecl * node ) {
 	VISIT_START( node );
 
@@ -406,5 +425,5 @@
 	)
 
-	__pass::symtab::addId( pass, 0, node );
+	__pass::symtab::addId( core, 0, node );
 
 	VISIT_END( DeclWithType, node );
@@ -413,9 +432,9 @@
 //--------------------------------------------------------------------------
 // FunctionDecl
-template< typename pass_t >
-const ast::DeclWithType * ast::Pass< pass_t >::visit( const ast::FunctionDecl * node ) {
-	VISIT_START( node );
-
-	__pass::symtab::addId( pass, 0, node );
+template< typename core_t >
+const ast::DeclWithType * ast::Pass< core_t >::visit( const ast::FunctionDecl * node ) {
+	VISIT_START( node );
+
+	__pass::symtab::addId( core, 0, node );
 
 	VISIT(maybe_accept( node, &FunctionDecl::withExprs );)
@@ -425,16 +444,16 @@
 		// shadow with exprs and not the other way around.
 		guard_symtab guard { *this };
-		__pass::symtab::addWith( pass, 0, node->withExprs, node );
+		__pass::symtab::addWith( core, 0, node->withExprs, node );
 		{
 			guard_symtab guard { *this };
 			// implicit add __func__ identifier as specified in the C manual 6.4.2.2
-			static ast::ObjectDecl func(
-				node->location, "__func__",
-				new ast::ArrayType(
-					new ast::BasicType( ast::BasicType::Char, ast::CV::Qualifiers( ast::CV::Const ) ),
+			static ast::ptr< ast::ObjectDecl > func{ new ast::ObjectDecl{ 
+				CodeLocation{}, "__func__",
+				new ast::ArrayType{
+					new ast::BasicType{ ast::BasicType::Char, ast::CV::Const },
 					nullptr, VariableLen, DynamicDim
-				)
-			);
-			__pass::symtab::addId( pass, 0, &func );
+				}
+			} };
+			__pass::symtab::addId( core, 0, func );
 			VISIT(
 				maybe_accept( node, &FunctionDecl::type );
@@ -454,11 +473,11 @@
 //--------------------------------------------------------------------------
 // StructDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::StructDecl * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::StructDecl * node ) {
 	VISIT_START( node );
 
 	// make up a forward declaration and add it before processing the members
 	// needs to be on the heap because addStruct saves the pointer
-	__pass::symtab::addStructFwd( pass, 0, node );
+	__pass::symtab::addStructFwd( core, 0, node );
 
 	VISIT({
@@ -469,5 +488,5 @@
 
 	// this addition replaces the forward declaration
-	__pass::symtab::addStruct( pass, 0, node );
+	__pass::symtab::addStruct( core, 0, node );
 
 	VISIT_END( Decl, node );
@@ -476,10 +495,10 @@
 //--------------------------------------------------------------------------
 // UnionDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::UnionDecl * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::UnionDecl * node ) {
 	VISIT_START( node );
 
 	// make up a forward declaration and add it before processing the members
-	__pass::symtab::addUnionFwd( pass, 0, node );
+	__pass::symtab::addUnionFwd( core, 0, node );
 
 	VISIT({
@@ -489,5 +508,5 @@
 	})
 
-	__pass::symtab::addUnion( pass, 0, node );
+	__pass::symtab::addUnion( core, 0, node );
 
 	VISIT_END( Decl, node );
@@ -496,9 +515,9 @@
 //--------------------------------------------------------------------------
 // EnumDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::EnumDecl * node ) {
-	VISIT_START( node );
-
-	__pass::symtab::addEnum( pass, 0, node );
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::EnumDecl * node ) {
+	VISIT_START( node );
+
+	__pass::symtab::addEnum( core, 0, node );
 
 	VISIT(
@@ -513,6 +532,6 @@
 //--------------------------------------------------------------------------
 // TraitDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::TraitDecl * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::TraitDecl * node ) {
 	VISIT_START( node );
 
@@ -523,5 +542,5 @@
 	})
 
-	__pass::symtab::addTrait( pass, 0, node );
+	__pass::symtab::addTrait( core, 0, node );
 
 	VISIT_END( Decl, node );
@@ -530,6 +549,6 @@
 //--------------------------------------------------------------------------
 // TypeDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypeDecl * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::TypeDecl * node ) {
 	VISIT_START( node );
 
@@ -543,5 +562,5 @@
 	// note that assertions come after the type is added to the symtab, since they are not part of the type proper
 	// and may depend on the type itself
-	__pass::symtab::addType( pass, 0, node );
+	__pass::symtab::addType( core, 0, node );
 
 	VISIT(
@@ -559,6 +578,6 @@
 //--------------------------------------------------------------------------
 // TypedefDecl
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::TypedefDecl * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::TypedefDecl * node ) {
 	VISIT_START( node );
 
@@ -569,5 +588,5 @@
 	})
 
-	__pass::symtab::addType( pass, 0, node );
+	__pass::symtab::addType( core, 0, node );
 
 	VISIT( maybe_accept( node, &TypedefDecl::assertions ); )
@@ -578,6 +597,6 @@
 //--------------------------------------------------------------------------
 // AsmDecl
-template< typename pass_t >
-const ast::AsmDecl * ast::Pass< pass_t >::visit( const ast::AsmDecl * node ) {
+template< typename core_t >
+const ast::AsmDecl * ast::Pass< core_t >::visit( const ast::AsmDecl * node ) {
 	VISIT_START( node );
 
@@ -591,6 +610,6 @@
 //--------------------------------------------------------------------------
 // StaticAssertDecl
-template< typename pass_t >
-const ast::StaticAssertDecl * ast::Pass< pass_t >::visit( const ast::StaticAssertDecl * node ) {
+template< typename core_t >
+const ast::StaticAssertDecl * ast::Pass< core_t >::visit( const ast::StaticAssertDecl * node ) {
 	VISIT_START( node );
 
@@ -605,13 +624,13 @@
 //--------------------------------------------------------------------------
 // CompoundStmt
-template< typename pass_t >
-const ast::CompoundStmt * ast::Pass< pass_t >::visit( const ast::CompoundStmt * node ) {
+template< typename core_t >
+const ast::CompoundStmt * ast::Pass< core_t >::visit( const ast::CompoundStmt * node ) {
 	VISIT_START( node );
 	VISIT({
 		// do not enter a new scope if inFunction is true - needs to check old state before the assignment
-		auto guard1 = makeFuncGuard( [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::enter(pass, 0);
-		}, [this, inFunction = this->inFunction]() {
-			if ( ! inFunction ) __pass::symtab::leave(pass, 0);
+		auto guard1 = makeFuncGuard( [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::enter(core, 0);
+		}, [this, inFunctionCpy = this->inFunction]() {
+			if ( ! inFunctionCpy ) __pass::symtab::leave(core, 0);
 		});
 		ValueGuard< bool > guard2( inFunction );
@@ -625,6 +644,6 @@
 //--------------------------------------------------------------------------
 // ExprStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ExprStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ExprStmt * node ) {
 	VISIT_START( node );
 
@@ -638,6 +657,6 @@
 //--------------------------------------------------------------------------
 // AsmStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::AsmStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::AsmStmt * node ) {
 	VISIT_START( node )
 
@@ -654,6 +673,6 @@
 //--------------------------------------------------------------------------
 // DirectiveStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DirectiveStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::DirectiveStmt * node ) {
 	VISIT_START( node )
 
@@ -663,6 +682,6 @@
 //--------------------------------------------------------------------------
 // IfStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::IfStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::IfStmt * node ) {
 	VISIT_START( node );
 
@@ -681,6 +700,6 @@
 //--------------------------------------------------------------------------
 // WhileStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WhileStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::WhileStmt * node ) {
 	VISIT_START( node );
 
@@ -698,6 +717,6 @@
 //--------------------------------------------------------------------------
 // ForStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ForStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ForStmt * node ) {
 	VISIT_START( node );
 
@@ -716,6 +735,6 @@
 //--------------------------------------------------------------------------
 // SwitchStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SwitchStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::SwitchStmt * node ) {
 	VISIT_START( node );
 
@@ -730,6 +749,6 @@
 //--------------------------------------------------------------------------
 // CaseStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CaseStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::CaseStmt * node ) {
 	VISIT_START( node );
 
@@ -744,6 +763,6 @@
 //--------------------------------------------------------------------------
 // BranchStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::BranchStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::BranchStmt * node ) {
 	VISIT_START( node );
 	VISIT_END( Stmt, node );
@@ -752,6 +771,6 @@
 //--------------------------------------------------------------------------
 // ReturnStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ReturnStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ReturnStmt * node ) {
 	VISIT_START( node );
 
@@ -765,6 +784,6 @@
 //--------------------------------------------------------------------------
 // ThrowStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ThrowStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ThrowStmt * node ) {
 	VISIT_START( node );
 
@@ -779,6 +798,6 @@
 //--------------------------------------------------------------------------
 // TryStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::TryStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::TryStmt * node ) {
 	VISIT_START( node );
 
@@ -794,6 +813,6 @@
 //--------------------------------------------------------------------------
 // CatchStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::CatchStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::CatchStmt * node ) {
 	VISIT_START( node );
 
@@ -811,6 +830,6 @@
 //--------------------------------------------------------------------------
 // FinallyStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::FinallyStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::FinallyStmt * node ) {
 	VISIT_START( node );
 
@@ -824,6 +843,6 @@
 //--------------------------------------------------------------------------
 // FinallyStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::SuspendStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::SuspendStmt * node ) {
 	VISIT_START( node );
 
@@ -837,6 +856,6 @@
 //--------------------------------------------------------------------------
 // WaitForStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::WaitForStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitForStmt * node ) {
 	VISIT_START( node );
 		// for( auto & clause : node->clauses ) {
@@ -906,6 +925,6 @@
 //--------------------------------------------------------------------------
 // WithStmt
-template< typename pass_t >
-const ast::Decl * ast::Pass< pass_t >::visit( const ast::WithStmt * node ) {
+template< typename core_t >
+const ast::Decl * ast::Pass< core_t >::visit( const ast::WithStmt * node ) {
 	VISIT_START( node );
 
@@ -915,5 +934,5 @@
 			// catch statements introduce a level of scope (for the caught exception)
 			guard_symtab guard { *this };
-			__pass::symtab::addWith( pass, 0, node->exprs, node );
+			__pass::symtab::addWith( core, 0, node->exprs, node );
 			maybe_accept( node, &WithStmt::stmt );
 		}
@@ -924,6 +943,6 @@
 //--------------------------------------------------------------------------
 // NullStmt
-template< typename pass_t >
-const ast::NullStmt * ast::Pass< pass_t >::visit( const ast::NullStmt * node ) {
+template< typename core_t >
+const ast::NullStmt * ast::Pass< core_t >::visit( const ast::NullStmt * node ) {
 	VISIT_START( node );
 	VISIT_END( NullStmt, node );
@@ -932,6 +951,6 @@
 //--------------------------------------------------------------------------
 // DeclStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::DeclStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::DeclStmt * node ) {
 	VISIT_START( node );
 
@@ -945,13 +964,13 @@
 //--------------------------------------------------------------------------
 // ImplicitCtorDtorStmt
-template< typename pass_t >
-const ast::Stmt * ast::Pass< pass_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
+template< typename core_t >
+const ast::Stmt * ast::Pass< core_t >::visit( const ast::ImplicitCtorDtorStmt * node ) {
 	VISIT_START( node );
 
 	// For now this isn't visited, it is unclear if this causes problem
 	// if all tests are known to pass, remove this code
-	// VISIT(
-	// 	maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
-	// )
+	VISIT(
+		maybe_accept( node, &ImplicitCtorDtorStmt::callStmt );
+	)
 
 	VISIT_END( Stmt, node );
@@ -960,6 +979,6 @@
 //--------------------------------------------------------------------------
 // ApplicationExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::ApplicationExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::ApplicationExpr * node ) {
 	VISIT_START( node );
 
@@ -978,6 +997,6 @@
 //--------------------------------------------------------------------------
 // UntypedExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedExpr * node ) {
 	VISIT_START( node );
 
@@ -996,6 +1015,6 @@
 //--------------------------------------------------------------------------
 // NameExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::NameExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::NameExpr * node ) {
 	VISIT_START( node );
 
@@ -1010,6 +1029,6 @@
 //--------------------------------------------------------------------------
 // CastExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::CastExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::CastExpr * node ) {
 	VISIT_START( node );
 
@@ -1026,6 +1045,6 @@
 //--------------------------------------------------------------------------
 // KeywordCastExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::KeywordCastExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::KeywordCastExpr * node ) {
 	VISIT_START( node );
 
@@ -1042,6 +1061,6 @@
 //--------------------------------------------------------------------------
 // VirtualCastExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::VirtualCastExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::VirtualCastExpr * node ) {
 	VISIT_START( node );
 
@@ -1058,6 +1077,6 @@
 //--------------------------------------------------------------------------
 // AddressExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::AddressExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::AddressExpr * node ) {
 	VISIT_START( node );
 
@@ -1074,6 +1093,6 @@
 //--------------------------------------------------------------------------
 // LabelAddressExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::LabelAddressExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::LabelAddressExpr * node ) {
 	VISIT_START( node );
 
@@ -1088,6 +1107,6 @@
 //--------------------------------------------------------------------------
 // UntypedMemberExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedMemberExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedMemberExpr * node ) {
 	VISIT_START( node );
 
@@ -1105,6 +1124,6 @@
 //--------------------------------------------------------------------------
 // MemberExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::MemberExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::MemberExpr * node ) {
 	VISIT_START( node );
 
@@ -1121,6 +1140,6 @@
 //--------------------------------------------------------------------------
 // VariableExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::VariableExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::VariableExpr * node ) {
 	VISIT_START( node );
 
@@ -1135,6 +1154,6 @@
 //--------------------------------------------------------------------------
 // ConstantExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstantExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstantExpr * node ) {
 	VISIT_START( node );
 
@@ -1149,6 +1168,6 @@
 //--------------------------------------------------------------------------
 // SizeofExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::SizeofExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::SizeofExpr * node ) {
 	VISIT_START( node );
 
@@ -1169,6 +1188,6 @@
 //--------------------------------------------------------------------------
 // AlignofExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::AlignofExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::AlignofExpr * node ) {
 	VISIT_START( node );
 
@@ -1189,6 +1208,6 @@
 //--------------------------------------------------------------------------
 // UntypedOffsetofExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedOffsetofExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedOffsetofExpr * node ) {
 	VISIT_START( node );
 
@@ -1205,6 +1224,6 @@
 //--------------------------------------------------------------------------
 // OffsetofExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetofExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetofExpr * node ) {
 	VISIT_START( node );
 
@@ -1221,6 +1240,6 @@
 //--------------------------------------------------------------------------
 // OffsetPackExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::OffsetPackExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::OffsetPackExpr * node ) {
 	VISIT_START( node );
 
@@ -1237,6 +1256,6 @@
 //--------------------------------------------------------------------------
 // LogicalExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::LogicalExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::LogicalExpr * node ) {
 	VISIT_START( node );
 
@@ -1254,6 +1273,6 @@
 //--------------------------------------------------------------------------
 // ConditionalExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConditionalExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::ConditionalExpr * node ) {
 	VISIT_START( node );
 
@@ -1272,6 +1291,6 @@
 //--------------------------------------------------------------------------
 // CommaExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::CommaExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::CommaExpr * node ) {
 	VISIT_START( node );
 
@@ -1289,6 +1308,6 @@
 //--------------------------------------------------------------------------
 // TypeExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::TypeExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::TypeExpr * node ) {
 	VISIT_START( node );
 
@@ -1305,6 +1324,6 @@
 //--------------------------------------------------------------------------
 // AsmExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::AsmExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::AsmExpr * node ) {
 	VISIT_START( node );
 
@@ -1322,6 +1341,6 @@
 //--------------------------------------------------------------------------
 // ImplicitCopyCtorExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::ImplicitCopyCtorExpr * node ) {
 	VISIT_START( node );
 
@@ -1338,6 +1357,6 @@
 //--------------------------------------------------------------------------
 // ConstructorExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::ConstructorExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::ConstructorExpr * node ) {
 	VISIT_START( node );
 
@@ -1354,6 +1373,6 @@
 //--------------------------------------------------------------------------
 // CompoundLiteralExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::CompoundLiteralExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::CompoundLiteralExpr * node ) {
 	VISIT_START( node );
 
@@ -1370,6 +1389,6 @@
 //--------------------------------------------------------------------------
 // RangeExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::RangeExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::RangeExpr * node ) {
 	VISIT_START( node );
 
@@ -1387,6 +1406,6 @@
 //--------------------------------------------------------------------------
 // UntypedTupleExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedTupleExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedTupleExpr * node ) {
 	VISIT_START( node );
 
@@ -1403,6 +1422,6 @@
 //--------------------------------------------------------------------------
 // TupleExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleExpr * node ) {
 	VISIT_START( node );
 
@@ -1419,6 +1438,6 @@
 //--------------------------------------------------------------------------
 // TupleIndexExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleIndexExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleIndexExpr * node ) {
 	VISIT_START( node );
 
@@ -1435,6 +1454,6 @@
 //--------------------------------------------------------------------------
 // TupleAssignExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::TupleAssignExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::TupleAssignExpr * node ) {
 	VISIT_START( node );
 
@@ -1451,15 +1470,15 @@
 //--------------------------------------------------------------------------
 // StmtExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::StmtExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::StmtExpr * node ) {
 	VISIT_START( node );
 
 	VISIT(// don't want statements from outer CompoundStmts to be added to this StmtExpr
 		// get the stmts that will need to be spliced in
-		auto stmts_before = __pass::stmtsToAddBefore( pass, 0);
-		auto stmts_after  = __pass::stmtsToAddAfter ( pass, 0);
+		auto stmts_before = __pass::stmtsToAddBefore( core, 0);
+		auto stmts_after  = __pass::stmtsToAddAfter ( core, 0);
 
 		// 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< const ast::TypeSubstitution * > __old_env( __pass::env( core, 0) );
 		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_before) >::type > __old_decls_before( stmts_before );
 		ValueGuardPtr< typename std::remove_pointer< decltype(stmts_after ) >::type > __old_decls_after ( stmts_after  );
@@ -1479,6 +1498,6 @@
 //--------------------------------------------------------------------------
 // UniqueExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UniqueExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UniqueExpr * node ) {
 	VISIT_START( node );
 
@@ -1495,6 +1514,6 @@
 //--------------------------------------------------------------------------
 // UntypedInitExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::UntypedInitExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::UntypedInitExpr * node ) {
 	VISIT_START( node );
 
@@ -1512,6 +1531,6 @@
 //--------------------------------------------------------------------------
 // InitExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::InitExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::InitExpr * node ) {
 	VISIT_START( node );
 
@@ -1529,6 +1548,6 @@
 //--------------------------------------------------------------------------
 // DeletedExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::DeletedExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::DeletedExpr * node ) {
 	VISIT_START( node );
 
@@ -1546,6 +1565,6 @@
 //--------------------------------------------------------------------------
 // DefaultArgExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::DefaultArgExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::DefaultArgExpr * node ) {
 	VISIT_START( node );
 
@@ -1562,6 +1581,6 @@
 //--------------------------------------------------------------------------
 // GenericExpr
-template< typename pass_t >
-const ast::Expr * ast::Pass< pass_t >::visit( const ast::GenericExpr * node ) {
+template< typename core_t >
+const ast::Expr * ast::Pass< core_t >::visit( const ast::GenericExpr * node ) {
 	VISIT_START( node );
 
@@ -1602,6 +1621,6 @@
 //--------------------------------------------------------------------------
 // VoidType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::VoidType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::VoidType * node ) {
 	VISIT_START( node );
 
@@ -1611,6 +1630,6 @@
 //--------------------------------------------------------------------------
 // BasicType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::BasicType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::BasicType * node ) {
 	VISIT_START( node );
 
@@ -1620,6 +1639,6 @@
 //--------------------------------------------------------------------------
 // PointerType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::PointerType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::PointerType * node ) {
 	VISIT_START( node );
 
@@ -1634,6 +1653,6 @@
 //--------------------------------------------------------------------------
 // ArrayType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::ArrayType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::ArrayType * node ) {
 	VISIT_START( node );
 
@@ -1648,6 +1667,6 @@
 //--------------------------------------------------------------------------
 // ReferenceType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::ReferenceType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::ReferenceType * node ) {
 	VISIT_START( node );
 
@@ -1661,6 +1680,6 @@
 //--------------------------------------------------------------------------
 // QualifiedType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::QualifiedType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::QualifiedType * node ) {
 	VISIT_START( node );
 
@@ -1675,13 +1694,14 @@
 //--------------------------------------------------------------------------
 // FunctionType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::FunctionType * node ) {
-	VISIT_START( node );
-
-	VISIT(
-		maybe_accept( node, &FunctionType::forall  );
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::FunctionType * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &FunctionType::returns );
 		maybe_accept( node, &FunctionType::params  );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1690,13 +1710,14 @@
 //--------------------------------------------------------------------------
 // StructInstType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::StructInstType * node ) {
-	VISIT_START( node );
-
-	__pass::symtab::addStruct( pass, 0, node->name );
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::StructInstType * node ) {
+	VISIT_START( node );
+
+	__pass::symtab::addStruct( core, 0, node->name );
 
 	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &StructInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &StructInstType::params );
 	})
@@ -1707,15 +1728,16 @@
 //--------------------------------------------------------------------------
 // UnionInstType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::UnionInstType * node ) {
-	VISIT_START( node );
-
-	__pass::symtab::addStruct( pass, 0, node->name );
-
-	{
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::UnionInstType * node ) {
+	VISIT_START( node );
+
+	__pass::symtab::addUnion( core, 0, node->name );
+
+	VISIT({
 		guard_symtab guard { *this };
-		maybe_accept( node, &UnionInstType::forall );
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &UnionInstType::params );
-	}
+	})
 
 	VISIT_END( Type, node );
@@ -1724,12 +1746,13 @@
 //--------------------------------------------------------------------------
 // EnumInstType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::EnumInstType * node ) {
-	VISIT_START( node );
-
-	VISIT(
-		maybe_accept( node, &EnumInstType::forall );
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::EnumInstType * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &EnumInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1738,12 +1761,13 @@
 //--------------------------------------------------------------------------
 // TraitInstType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::TraitInstType * node ) {
-	VISIT_START( node );
-
-	VISIT(
-		maybe_accept( node, &TraitInstType::forall );
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::TraitInstType * node ) {
+	VISIT_START( node );
+
+	VISIT({
+		guard_forall_subs forall_guard { *this, node };
+		mutate_forall( node );
 		maybe_accept( node, &TraitInstType::params );
-	)
+	})
 
 	VISIT_END( Type, node );
@@ -1752,11 +1776,16 @@
 //--------------------------------------------------------------------------
 // TypeInstType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeInstType * node ) {
-	VISIT_START( node );
-
-	VISIT(
-		maybe_accept( node, &TypeInstType::forall );
-		maybe_accept( node, &TypeInstType::params );
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::TypeInstType * node ) {
+	VISIT_START( node );
+
+	VISIT(
+		{
+			guard_forall_subs forall_guard { *this, node };
+			mutate_forall( node );
+			maybe_accept( node, &TypeInstType::params );
+		}
+		// ensure that base re-bound if doing substitution
+		__pass::forall::replace( core, 0, node );
 	)
 
@@ -1766,6 +1795,6 @@
 //--------------------------------------------------------------------------
 // TupleType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::TupleType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::TupleType * node ) {
 	VISIT_START( node );
 
@@ -1780,6 +1809,6 @@
 //--------------------------------------------------------------------------
 // TypeofType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::TypeofType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::TypeofType * node ) {
 	VISIT_START( node );
 
@@ -1793,6 +1822,6 @@
 //--------------------------------------------------------------------------
 // VarArgsType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::VarArgsType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::VarArgsType * node ) {
 	VISIT_START( node );
 
@@ -1802,6 +1831,6 @@
 //--------------------------------------------------------------------------
 // ZeroType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::ZeroType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::ZeroType * node ) {
 	VISIT_START( node );
 
@@ -1811,6 +1840,6 @@
 //--------------------------------------------------------------------------
 // OneType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::OneType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::OneType * node ) {
 	VISIT_START( node );
 
@@ -1820,6 +1849,6 @@
 //--------------------------------------------------------------------------
 // GlobalScopeType
-template< typename pass_t >
-const ast::Type * ast::Pass< pass_t >::visit( const ast::GlobalScopeType * node ) {
+template< typename core_t >
+const ast::Type * ast::Pass< core_t >::visit( const ast::GlobalScopeType * node ) {
 	VISIT_START( node );
 
@@ -1830,6 +1859,6 @@
 //--------------------------------------------------------------------------
 // Designation
-template< typename pass_t >
-const ast::Designation * ast::Pass< pass_t >::visit( const ast::Designation * node ) {
+template< typename core_t >
+const ast::Designation * ast::Pass< core_t >::visit( const ast::Designation * node ) {
 	VISIT_START( node );
 
@@ -1841,6 +1870,6 @@
 //--------------------------------------------------------------------------
 // SingleInit
-template< typename pass_t >
-const ast::Init * ast::Pass< pass_t >::visit( const ast::SingleInit * node ) {
+template< typename core_t >
+const ast::Init * ast::Pass< core_t >::visit( const ast::SingleInit * node ) {
 	VISIT_START( node );
 
@@ -1854,6 +1883,6 @@
 //--------------------------------------------------------------------------
 // ListInit
-template< typename pass_t >
-const ast::Init * ast::Pass< pass_t >::visit( const ast::ListInit * node ) {
+template< typename core_t >
+const ast::Init * ast::Pass< core_t >::visit( const ast::ListInit * node ) {
 	VISIT_START( node );
 
@@ -1868,6 +1897,6 @@
 //--------------------------------------------------------------------------
 // ConstructorInit
-template< typename pass_t >
-const ast::Init * ast::Pass< pass_t >::visit( const ast::ConstructorInit * node ) {
+template< typename core_t >
+const ast::Init * ast::Pass< core_t >::visit( const ast::ConstructorInit * node ) {
 	VISIT_START( node );
 
@@ -1883,6 +1912,6 @@
 //--------------------------------------------------------------------------
 // Attribute
-template< typename pass_t >
-const ast::Attribute * ast::Pass< pass_t >::visit( const ast::Attribute * node  )  {
+template< typename core_t >
+const ast::Attribute * ast::Pass< core_t >::visit( const ast::Attribute * node  )  {
 	VISIT_START( node );
 
@@ -1896,6 +1925,6 @@
 //--------------------------------------------------------------------------
 // TypeSubstitution
-template< typename pass_t >
-const ast::TypeSubstitution * ast::Pass< pass_t >::visit( const ast::TypeSubstitution * node ) {
+template< typename core_t >
+const ast::TypeSubstitution * ast::Pass< core_t >::visit( const ast::TypeSubstitution * node ) {
 	VISIT_START( node );
 
@@ -1907,5 +1936,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
@@ -1923,5 +1952,5 @@
 				guard_symtab guard { *this };
 				auto new_node = p.second->accept( *this );
-				if (new_node != p.second) mutated = false;
+				if (new_node != p.second) mutated = true;
 				new_map.insert({ p.first, new_node });
 			}
Index: src/AST/Pass.proto.hpp
===================================================================
--- src/AST/Pass.proto.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Pass.proto.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -17,6 +17,8 @@
 // IWYU pragma: private, include "Pass.hpp"
 
+#include "Common/Stats/Heap.h"
+
 namespace ast {
-template<typename pass_type>
+template<typename core_t>
 class Pass;
 
@@ -82,5 +84,5 @@
 		};
 
-		std::stack< cleanup_t > cleanups;
+		std::stack< cleanup_t, std::vector<cleanup_t> > cleanups;
 	};
 
@@ -111,7 +113,7 @@
 	/// "Short hand" to check if this is a valid previsit function
 	/// Mostly used to make the static_assert look (and print) prettier
-	template<typename pass_t, typename node_t>
+	template<typename core_t, typename node_t>
 	struct is_valid_previsit {
-		using ret_t = decltype( ((pass_t*)nullptr)->previsit( (const node_t *)nullptr ) );
+		using ret_t = decltype( ((core_t*)nullptr)->previsit( (const node_t *)nullptr ) );
 
 		static constexpr bool value = std::is_void< ret_t >::value ||
@@ -127,7 +129,7 @@
 	template<>
 	struct __assign<true> {
-		template<typename pass_t, typename node_t>
-		static inline void result( pass_t & pass, const node_t * & node ) {
-			pass.previsit( node );
+		template<typename core_t, typename node_t>
+		static inline void result( core_t & core, const node_t * & node ) {
+			core.previsit( node );
 		}
 	};
@@ -135,7 +137,7 @@
 	template<>
 	struct __assign<false> {
-		template<typename pass_t, typename node_t>
-		static inline void result( pass_t & pass, const node_t * & node ) {
-			node = pass.previsit( node );
+		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");
 		}
@@ -150,7 +152,7 @@
 	template<>
 	struct __return<true> {
-		template<typename pass_t, typename node_t>
-		static inline const node_t * result( pass_t & pass, const node_t * & node ) {
-			pass.postvisit( node );
+		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;
 		}
@@ -159,7 +161,7 @@
 	template<>
 	struct __return<false> {
-		template<typename pass_t, typename node_t>
-		static inline auto result( pass_t & pass, const node_t * & node ) {
-			return pass.postvisit( node );
+		template<typename core_t, typename node_t>
+		static inline auto result( core_t & core, const node_t * & node ) {
+			return core.postvisit( node );
 		}
 	};
@@ -180,8 +182,8 @@
 	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 	// PreVisit : may mutate the pointer passed in if the node is mutated in the previsit call
-	template<typename pass_t, typename node_t>
-	static inline auto previsit( pass_t & pass, const node_t * & node, int ) -> decltype( pass.previsit( node ), void() ) {
+	template<typename core_t, typename node_t>
+	static inline auto previsit( core_t & core, const node_t * & node, int ) -> decltype( core.previsit( node ), void() ) {
 		static_assert(
-			is_valid_previsit<pass_t, node_t>::value,
+			is_valid_previsit<core_t, node_t>::value,
 			"Previsit may not change the type of the node. It must return its paremeter or void."
 		);
@@ -189,26 +191,26 @@
 		__assign<
 			std::is_void<
-				decltype( pass.previsit( node ) )
+				decltype( core.previsit( node ) )
 			>::value
-		>::result( pass, node );
+		>::result( core, node );
 	}
 
-	template<typename pass_t, typename node_t>
-	static inline auto previsit( pass_t &, const node_t *, long ) {}
+	template<typename core_t, typename node_t>
+	static inline auto previsit( core_t &, const node_t *, long ) {}
 
 	// PostVisit : never mutates the passed pointer but may return a different node
-	template<typename pass_t, typename node_t>
-	static inline auto postvisit( pass_t & pass, const node_t * node, int ) ->
-		decltype( pass.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
+	template<typename core_t, typename node_t>
+	static inline auto postvisit( core_t & core, const node_t * node, int ) ->
+		decltype( core.postvisit( node ), node->accept( *(Visitor*)nullptr ) )
 	{
 		return __return<
 			std::is_void<
-				decltype( pass.postvisit( node ) )
+				decltype( core.postvisit( node ) )
 			>::value
-		>::result( pass, node );
+		>::result( core, node );
 	}
 
-	template<typename pass_t, typename node_t>
-	static inline const node_t * postvisit( pass_t &, const node_t * node, long ) { return node; }
+	template<typename core_t, typename node_t>
+	static inline const node_t * postvisit( core_t &, const node_t * node, long ) { return node; }
 
 	//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -225,9 +227,9 @@
 	// The type is not strictly enforced but does match the accessory
 	#define FIELD_PTR( name, default_type ) \
-	template< typename pass_t > \
-	static inline auto name( pass_t & pass, int ) -> decltype( &pass.name ) { return &pass.name; } \
+	template< typename core_t > \
+	static inline auto name( core_t & core, int ) -> decltype( &core.name ) { return &core.name; } \
 	\
-	template< typename pass_t > \
-	static inline default_type * name( pass_t &, long ) { return nullptr; }
+	template< typename core_t > \
+	static inline default_type * name( core_t &, long ) { return nullptr; }
 
 	// List of fields and their expected types
@@ -239,8 +241,24 @@
 	FIELD_PTR( visit_children, __pass::bool_ref )
 	FIELD_PTR( at_cleanup, __pass::at_cleanup_t )
-	FIELD_PTR( visitor, ast::Pass<pass_t> * const )
+	FIELD_PTR( visitor, ast::Pass<core_t> * const )
 
 	// Remove the macro to make sure we don't clash
 	#undef FIELD_PTR
+
+	template< typename core_t >
+	static inline auto beginTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
+		// Stats::Heap::stacktrace_push(core_t::traceId);
+	}
+
+	template< typename core_t >
+	static inline auto endTrace(core_t &, int) -> decltype( core_t::traceId, void() ) {
+		// Stats::Heap::stacktrace_pop();
+	}
+
+	template< typename core_t >
+	static void beginTrace(core_t &, long) {}
+
+	template< typename core_t >
+	static void endTrace(core_t &, long) {}
 
 	// Another feature of the templated visitor is that it calls beginScope()/endScope() for compound statement.
@@ -248,60 +266,60 @@
 	// detect it using the same strategy
 	namespace scope {
-		template<typename pass_t>
-		static inline auto enter( pass_t & pass, int ) -> decltype( pass.beginScope(), void() ) {
-			pass.beginScope();
-		}
-
-		template<typename pass_t>
-		static inline void enter( pass_t &, long ) {}
-
-		template<typename pass_t>
-		static inline auto leave( pass_t & pass, int ) -> decltype( pass.endScope(), void() ) {
-			pass.endScope();
-		}
-
-		template<typename pass_t>
-		static inline void leave( pass_t &, long ) {}
-	};
-
-	// Finally certain pass desire an up to date symbol table automatically
+		template<typename core_t>
+		static inline auto enter( core_t & core, int ) -> decltype( core.beginScope(), void() ) {
+			core.beginScope();
+		}
+
+		template<typename core_t>
+		static inline void enter( core_t &, long ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int ) -> decltype( core.endScope(), void() ) {
+			core.endScope();
+		}
+
+		template<typename core_t>
+		static inline void leave( core_t &, long ) {}
+	} // namespace scope
+
+	// Certain passes desire an up to date symbol table automatically
 	// detect the presence of a member name `symtab` and call all the members appropriately
 	namespace symtab {
 		// Some simple scoping rules
-		template<typename pass_t>
-		static inline auto enter( pass_t & pass, int ) -> decltype( pass.symtab.enterScope(), void() ) {
-			pass.symtab.enterScope();
-		}
-
-		template<typename pass_t>
-		static inline auto enter( pass_t &, long ) {}
-
-		template<typename pass_t>
-		static inline auto leave( pass_t & pass, int ) -> decltype( pass.symtab.leaveScope(), void() ) {
-			pass.symtab.leaveScope();
-		}
-
-		template<typename pass_t>
-		static inline auto leave( pass_t &, long ) {}
+		template<typename core_t>
+		static inline auto enter( core_t & core, int ) -> decltype( core.symtab, void() ) {
+			core.symtab.enterScope();
+		}
+
+		template<typename core_t>
+		static inline auto enter( core_t &, long ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int ) -> decltype( core.symtab, void() ) {
+			core.symtab.leaveScope();
+		}
+
+		template<typename core_t>
+		static inline auto leave( core_t &, long ) {}
 
 		// The symbol table has 2 kind of functions mostly, 1 argument and 2 arguments
 		// Create macro to condense these common patterns
 		#define SYMTAB_FUNC1( func, type ) \
-		template<typename pass_t> \
-		static inline auto func( pass_t & pass, int, type arg ) -> decltype( pass.symtab.func( arg ), void() ) {\
-			pass.symtab.func( arg ); \
+		template<typename core_t> \
+		static inline auto func( core_t & core, int, type arg ) -> decltype( core.symtab.func( arg ), void() ) {\
+			core.symtab.func( arg ); \
 		} \
 		\
-		template<typename pass_t> \
-		static inline void func( pass_t &, long, type ) {}
+		template<typename core_t> \
+		static inline void func( core_t &, long, type ) {}
 
 		#define SYMTAB_FUNC2( func, type1, type2 ) \
-		template<typename pass_t> \
-		static inline auto func( pass_t & pass, int, type1 arg1, type2 arg2 ) -> decltype( pass.symtab.func( arg1, arg2 ), void () ) {\
-			pass.symtab.func( arg1, arg2 ); \
+		template<typename core_t> \
+		static inline auto func( core_t & core, int, type1 arg1, type2 arg2 ) -> decltype( core.symtab.func( arg1, arg2 ), void () ) {\
+			core.symtab.func( arg1, arg2 ); \
 		} \
 			\
-		template<typename pass_t> \
-		static inline void func( pass_t &, long, type1, type2 ) {}
+		template<typename core_t> \
+		static inline void func( core_t &, long, type1, type2 ) {}
 
 		SYMTAB_FUNC1( addId     , const DeclWithType *  );
@@ -311,50 +329,94 @@
 		SYMTAB_FUNC1( addUnion  , const UnionDecl *     );
 		SYMTAB_FUNC1( addTrait  , const TraitDecl *     );
-		SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Node * );
+		SYMTAB_FUNC2( addWith   , const std::vector< ptr<Expr> > &, const Decl * );
 
 		// A few extra functions have more complicated behaviour, they are hand written
-		template<typename pass_t>
-		static inline auto addStructFwd( pass_t & pass, int, const ast::StructDecl * decl ) -> decltype( pass.symtab.addStruct( decl ), void() ) {
+		template<typename core_t>
+		static inline auto addStructFwd( core_t & core, int, const ast::StructDecl * decl ) -> decltype( core.symtab.addStruct( decl ), void() ) {
 			ast::StructDecl * fwd = new ast::StructDecl( decl->location, decl->name );
 			fwd->params = decl->params;
-			pass.symtab.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.symtab.addUnion( decl ), void() ) {
+			core.symtab.addStruct( fwd );
+		}
+
+		template<typename core_t>
+		static inline void addStructFwd( core_t &, long, const ast::StructDecl * ) {}
+
+		template<typename core_t>
+		static inline auto addUnionFwd( core_t & core, int, const ast::UnionDecl * decl ) -> decltype( core.symtab.addUnion( decl ), void() ) {
 			UnionDecl * fwd = new UnionDecl( decl->location, decl->name );
 			fwd->params = decl->params;
-			pass.symtab.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.symtab.addStruct( str ), void() ) {
-			if ( ! pass.symtab.lookupStruct( str ) ) {
-				pass.symtab.addStruct( str );
+			core.symtab.addUnion( fwd );
+		}
+
+		template<typename core_t>
+		static inline void addUnionFwd( core_t &, long, const ast::UnionDecl * ) {}
+
+		template<typename core_t>
+		static inline auto addStruct( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addStruct( str ), void() ) {
+			if ( ! core.symtab.lookupStruct( str ) ) {
+				core.symtab.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.symtab.addUnion( str ), void() ) {
-			if ( ! pass.symtab.lookupUnion( str ) ) {
-				pass.symtab.addUnion( str );
+		template<typename core_t>
+		static inline void addStruct( core_t &, long, const std::string & ) {}
+
+		template<typename core_t>
+		static inline auto addUnion( core_t & core, int, const std::string & str ) -> decltype( core.symtab.addUnion( str ), void() ) {
+			if ( ! core.symtab.lookupUnion( str ) ) {
+				core.symtab.addUnion( str );
 			}
 		}
 
-		template<typename pass_t>
-		static inline void addUnion( pass_t &, long, const std::string & ) {}
+		template<typename core_t>
+		static inline void addUnion( core_t &, long, const std::string & ) {}
 
 		#undef SYMTAB_FUNC1
 		#undef SYMTAB_FUNC2
-	};
-};
-};
+	} // namespace symtab
+
+	// Some passes need to mutate TypeDecl and properly update their pointing TypeInstType.
+	// Detect the presence of a member name `subs` and call all members appropriately
+	namespace forall {
+		// Some simple scoping rules
+		template<typename core_t>
+		static inline auto enter( core_t & core, int, const ast::ParameterizedType * type )
+		-> decltype( core.subs, void() ) {
+			if ( ! type->forall.empty() ) core.subs.beginScope();
+		}
+
+		template<typename core_t>
+		static inline auto enter( core_t &, long, const ast::ParameterizedType * ) {}
+
+		template<typename core_t>
+		static inline auto leave( core_t & core, int, const ast::ParameterizedType * type )
+		-> decltype( core.subs, void() ) {
+			if ( ! type->forall.empty() ) { core.subs.endScope(); }
+		}
+
+		template<typename core_t>
+		static inline auto leave( core_t &, long, const ast::ParameterizedType * ) {}
+
+		// Get the substitution table, if present
+		template<typename core_t>
+		static inline auto subs( core_t & core, int ) -> decltype( &core.subs ) {
+			return &core.subs;
+		}
+
+		template<typename core_t>
+		static inline ast::ForallSubstitutionTable * subs( core_t &, long ) { return nullptr; }
+
+		// Replaces a TypeInstType's base TypeDecl according to the table
+		template<typename core_t>
+		static inline auto replace( core_t & core, int, const ast::TypeInstType *& inst )
+		-> decltype( core.subs, void() ) {
+			inst = ast::mutate_field(
+				inst, &ast::TypeInstType::base, core.subs.replace( inst->base ) );
+		}
+
+		template<typename core_t>
+		static inline auto replace( core_t &, long, const ast::TypeInstType *& ) {}
+
+	} // namespace forall
+} // namespace __pass
+} // namespace ast
Index: src/AST/Print.cpp
===================================================================
--- src/AST/Print.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Print.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -29,6 +29,5 @@
 
 template <typename C, typename... T>
-constexpr auto make_array(T&&... values) ->
-	array<C,sizeof...(T)>
+constexpr array<C,sizeof...(T)> make_array(T&&... values)
 {
 	return array<C,sizeof...(T)>{
@@ -129,23 +128,18 @@
 
 	void print( const ast::Expr::InferUnion & inferred, unsigned level = 0 ) {
-		switch ( inferred.mode ) {
-		case ast::Expr::InferUnion::Empty: return;
-		case ast::Expr::InferUnion::Slots: {
-			os << indent << "with " << inferred.data.resnSlots.size()
+		if (inferred.data.resnSlots && !inferred.data.resnSlots->empty()) {
+			os << indent << "with " << inferred.data.resnSlots->size()
 			   << " pending inference slots" << endl;
-			return;
-		}
-		case ast::Expr::InferUnion::Params: {
+		}
+		if (inferred.data.inferParams && !inferred.data.inferParams->empty()) {
 			os << indent << "with inferred parameters " << level << ":" << endl;
 			++indent;
-			for ( const auto & i : inferred.data.inferParams ) {
+			for ( const auto & i : *inferred.data.inferParams ) {
 				os << indent;
-				short_print( Decl::fromId( i.second.decl ) );
+				short_print( i.second.declptr );
 				os << endl;
 				print( i.second.expr->inferred, level+1 );
 			}
 			--indent;
-			return;
-		}
 		}
 	}
@@ -233,5 +227,5 @@
 		}
 
-		if ( ! short_mode && ! node->assertions.empty() ) {
+		if ( ! node->assertions.empty() ) {
 			os << endl << indent << "... with assertions" << endl;
 			++indent;
@@ -243,4 +237,12 @@
 	void postprint( const ast::Expr * node ) {
 		print( node->inferred );
+
+		if ( node->result ) {
+			os << endl << indent << "... with resolved type:" << endl;
+			++indent;
+			os << indent;
+			node->result->accept( *this );
+			--indent;
+		}
 
 		if ( node->env ) {
@@ -842,5 +844,5 @@
 	virtual const ast::Expr * visit( const ast::CastExpr * node ) override final {
 		++indent;
-		os << (node->isGenerated ? "Generated" : "Explicit") << " cast of:" << endl << indent;
+		os << (node->isGenerated ? "Generated" : "Explicit") << " Cast of:" << endl << indent;
 		safe_print( node->arg );
 		os << endl << indent-1 << "... to:";
Index: src/AST/Stmt.hpp
===================================================================
--- src/AST/Stmt.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Stmt.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -27,5 +27,7 @@
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
-#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
@@ -412,5 +414,5 @@
 class ImplicitCtorDtorStmt final : public Stmt {
 public:
-	readonly<Stmt> callStmt;
+	ptr<Stmt> callStmt;
 
 	ImplicitCtorDtorStmt( const CodeLocation & loc, const Stmt * callStmt,
Index: src/AST/Type.cpp
===================================================================
--- src/AST/Type.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Type.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Mon May 13 15:00:00 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sun Dec 15 16:56:28 2019
-// Update Count     : 4
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Jul 23 14:16:00 2020
+// Update Count     : 5
 //
 
@@ -21,5 +21,7 @@
 
 #include "Decl.hpp"
+#include "ForallSubstitutor.hpp" // for substituteForall
 #include "Init.hpp"
+#include "Common/utility.h"      // for copy, move
 #include "InitTweak/InitTweak.h" // for getPointerBase
 #include "Tuples/Tuples.h"       // for isTtype
@@ -90,5 +92,22 @@
 // GENERATED END
 
+// --- ParameterizedType
+
+void ParameterizedType::initWithSub(
+	const ParameterizedType & o, Pass< ForallSubstitutor > & sub
+) {
+	forall = sub.core( o.forall );
+}
+
 // --- FunctionType
+
+FunctionType::FunctionType( const FunctionType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), returns(), params(),
+  isVarArgs( o.isVarArgs ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );           // initialize substitution map
+	returns = sub.core( o.returns ); // apply to return and parameter types
+	params = sub.core( o.params );
+}
 
 namespace {
@@ -106,4 +125,17 @@
 
 // --- ReferenceToType
+
+void ReferenceToType::initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub ) {
+	ParameterizedType::initWithSub( o, sub ); // initialize substitution
+	params = sub.core( o.params );            // apply to parameters
+}
+
+ReferenceToType::ReferenceToType( const ReferenceToType & o )
+: ParameterizedType( o.qualifiers, copy( o.attributes ) ), params(), name( o.name ), 
+  hoistType( o.hoistType ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );
+}
+
 std::vector<readonly<Decl>> ReferenceToType::lookup( const std::string& name ) const {
 	assertf( aggr(), "Must have aggregate to perform lookup" );
@@ -116,35 +148,34 @@
 }
 
-// --- StructInstType
-
-StructInstType::StructInstType( const StructDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
-
-bool StructInstType::isComplete() const { return base ? base->body : false; }
-
-// --- UnionInstType
-
-UnionInstType::UnionInstType( const UnionDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
-
-bool UnionInstType::isComplete() const { return base ? base->body : false; }
-
-// --- EnumInstType
-
-EnumInstType::EnumInstType( const EnumDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
-
-bool EnumInstType::isComplete() const { return base ? base->body : false; }
+// --- SueInstType (StructInstType, UnionInstType, EnumInstType)
+
+template<typename decl_t>
+SueInstType<decl_t>::SueInstType(
+	const decl_t * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
+
+template<typename decl_t>
+bool SueInstType<decl_t>::isComplete() const {
+	return base ? base->body : false;
+}
+
+template class SueInstType<StructDecl>;
+template class SueInstType<UnionDecl>;
+template class SueInstType<EnumDecl>;
 
 // --- TraitInstType
 
-TraitInstType::TraitInstType( const TraitDecl * b, CV::Qualifiers q,
-	std::vector<ptr<Attribute>>&& as )
-: ReferenceToType( b->name, q, std::move(as) ), base( b ) {}
+TraitInstType::TraitInstType(
+	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
+: ReferenceToType( b->name, q, move(as) ), base( b ) {}
 
 // --- TypeInstType
+
+TypeInstType::TypeInstType( const TypeInstType & o )
+: ReferenceToType( o.name, o.qualifiers, copy( o.attributes ) ), base(), kind( o.kind ) {
+	Pass< ForallSubstitutor > sub;
+	initWithSub( o, sub );      // initialize substitution
+	base = sub.core( o.base );  // apply to base type
+}
 
 void TypeInstType::set_base( const TypeDecl * b ) {
@@ -158,5 +189,5 @@
 
 TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
-: Type( q ), types( std::move(ts) ), members() {
+: Type( q ), types( move(ts) ), members() {
 	// This constructor is awkward. `TupleType` needs to contain objects so that members can be
 	// named, but members without initializer nodes end up getting constructors, which breaks
Index: src/AST/Type.hpp
===================================================================
--- src/AST/Type.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/Type.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Thu May 9 10:00:00 2019
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Dec 11 21:56:46 2019
-// Update Count     : 5
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Jul 23 14:15:00 2020
+// Update Count     : 6
 //
 
@@ -29,7 +29,13 @@
 
 // Must be included in *all* AST classes; should be #undef'd at the end of the file
-#define MUTATE_FRIEND template<typename node_t> friend node_t * mutate(const node_t * node);
+#define MUTATE_FRIEND \
+    template<typename node_t> friend node_t * mutate(const node_t * node); \
+	template<typename node_t> friend node_t * shallowCopy(const node_t * node);
 
 namespace ast {
+
+template< typename T > class Pass;
+
+struct ForallSubstitutor;
 
 class Type : public Node {
@@ -44,5 +50,4 @@
 	bool is_volatile() const { return qualifiers.is_volatile; }
 	bool is_restrict() const { return qualifiers.is_restrict; }
-	bool is_lvalue() const { return qualifiers.is_lvalue; }
 	bool is_mutex() const { return qualifiers.is_mutex; }
 	bool is_atomic() const { return qualifiers.is_atomic; }
@@ -51,5 +56,4 @@
 	Type * set_volatile( bool v ) { qualifiers.is_volatile = v; return this; }
 	Type * set_restrict( bool v ) { qualifiers.is_restrict = v; return this; }
-	Type * set_lvalue( bool v ) { qualifiers.is_lvalue = v; return this; }
 	Type * set_mutex( bool v ) { qualifiers.is_mutex = v; return this; }
 	Type * set_atomic( bool v ) { qualifiers.is_atomic = v; return this; }
@@ -163,5 +167,5 @@
 	static const char *typeNames[];
 
-	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} ) 
+	BasicType( Kind k, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: Type(q, std::move(as)), kind(k) {}
 
@@ -265,4 +269,7 @@
 /// Base type for potentially forall-qualified types
 class ParameterizedType : public Type {
+protected:
+	/// initializes forall with substitutor
+	void initWithSub( const ParameterizedType & o, Pass< ForallSubstitutor > & sub );
 public:
 	using ForallList = std::vector<ptr<TypeDecl>>;
@@ -276,4 +283,11 @@
 	ParameterizedType( CV::Qualifiers q, std::vector<ptr<Attribute>> && as = {} )
 	: Type(q, std::move(as)), forall() {}
+
+	// enforce use of ForallSubstitutor to copy parameterized type
+	ParameterizedType( const ParameterizedType & ) = delete;
+
+	ParameterizedType( ParameterizedType && ) = default;
+
+	// no need to change destructor, and operator= deleted in Node
 
 private:
@@ -301,4 +315,6 @@
 	: ParameterizedType(q), returns(), params(), isVarArgs(va) {}
 
+	FunctionType( const FunctionType & o );
+
 	/// true if either the parameters or return values contain a tttype
 	bool isTtype() const;
@@ -314,4 +330,7 @@
 /// base class for types that refer to types declared elsewhere (aggregates and typedefs)
 class ReferenceToType : public ParameterizedType {
+protected:
+	/// Initializes forall and parameters based on substitutor
+	void initWithSub( const ReferenceToType & o, Pass< ForallSubstitutor > & sub );
 public:
 	std::vector<ptr<Expr>> params;
@@ -319,7 +338,9 @@
 	bool hoistType = false;
 
-	ReferenceToType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	ReferenceToType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ParameterizedType(q, std::move(as)), params(), name(n) {}
+
+	ReferenceToType( const ReferenceToType & o );
 
 	/// Gets aggregate declaration this type refers to
@@ -333,77 +354,48 @@
 };
 
-/// instance of struct type
-class StructInstType final : public ReferenceToType {
-public:
-	readonly<StructDecl> base;
-
-	StructInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+// Common implementation for the SUE instance types. Not to be used directly.
+template<typename decl_t>
+class SueInstType final : public ReferenceToType {
+public:
+	using base_type = decl_t;
+	readonly<decl_t> base;
+
+	SueInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	StructInstType( const StructDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	SueInstType(
+		const decl_t * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	bool isComplete() const override;
 
-	const StructDecl * aggr() const override { return base; }
-
-	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	StructInstType * clone() const override { return new StructInstType{ *this }; }
-	MUTATE_FRIEND
-};
-
-/// instance of union type
-class UnionInstType final : public ReferenceToType {
-public:
-	readonly<UnionDecl> base;
-
-	UnionInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
+	const decl_t * aggr() const override { return base; }
+
+	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
+private:
+	SueInstType<decl_t> * clone() const override { return new SueInstType<decl_t>{ *this }; }
+	MUTATE_FRIEND
+};
+
+/// An instance of a struct type.
+using StructInstType = SueInstType<StructDecl>;
+
+/// An instance of a union type.
+using UnionInstType = SueInstType<UnionDecl>;
+
+/// An instance of an enum type.
+using EnumInstType = SueInstType<EnumDecl>;
+
+/// An instance of a trait type.
+class TraitInstType final : public ReferenceToType {
+public:
+	readonly<TraitDecl> base;
+
+	TraitInstType(
+		const std::string& n, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base() {}
-	UnionInstType( const UnionDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
-
-	bool isComplete() const override;
-
-	const UnionDecl * aggr() const override { return base; }
-
-	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	UnionInstType * clone() const override { return new UnionInstType{ *this }; }
-	MUTATE_FRIEND
-};
-
-/// instance of enum type
-class EnumInstType final : public ReferenceToType {
-public:
-	readonly<EnumDecl> base;
-
-	EnumInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
-	: ReferenceToType( n, q, std::move(as) ), base() {}
-	EnumInstType( const EnumDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
-
-	bool isComplete() const override;
-
-	const EnumDecl * aggr() const override { return base; }
-
-	const Type * accept( Visitor & v ) const override { return v.visit( this ); }
-private:
-	EnumInstType * clone() const override { return new EnumInstType{ *this }; }
-	MUTATE_FRIEND
-};
-
-/// instance of trait type
-class TraitInstType final : public ReferenceToType {
-public:
-	readonly<TraitDecl> base;
-
-	TraitInstType( const std::string& n, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} )
-	: ReferenceToType( n, q, std::move(as) ), base() {}
-	TraitInstType( const TraitDecl * b, CV::Qualifiers q = {},
-		std::vector<ptr<Attribute>> && as = {} );
+
+	TraitInstType(
+		const TraitDecl * b, CV::Qualifiers q = {}, std::vector<ptr<Attribute>> && as = {} );
 
 	// not meaningful for TraitInstType
@@ -424,5 +416,6 @@
 	TypeDecl::Kind kind;
 
-	TypeInstType( const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
+	TypeInstType(
+		const std::string& n, const TypeDecl * b, CV::Qualifiers q = {},
 		std::vector<ptr<Attribute>> && as = {} )
 	: ReferenceToType( n, q, std::move(as) ), base( b ), kind( b->kind ) {}
@@ -431,4 +424,6 @@
 	: ReferenceToType( n, q, std::move(as) ), base(), kind( k ) {}
 
+	TypeInstType( const TypeInstType & o );
+
 	/// sets `base`, updating `kind` correctly
 	void set_base( const TypeDecl * );
Index: src/AST/TypeEnvironment.cpp
===================================================================
--- src/AST/TypeEnvironment.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/TypeEnvironment.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -59,5 +59,5 @@
 	std::copy( clz.vars.begin(), clz.vars.end(), std::ostream_iterator< std::string >( out, " " ) );
 	out << ")";
-	
+
 	if ( clz.bound ) {
 		out << " -> ";
@@ -92,5 +92,5 @@
 				}
 			}
-			
+
 			i = next;  // go to next node even if this removed
 		}
@@ -161,9 +161,9 @@
 		Pass<Occurs> occur{ var, env };
 		maybe_accept( ty, occur );
-		return occur.pass.result;
-	}
-}
-
-bool TypeEnvironment::combine( 
+		return occur.core.result;
+	}
+}
+
+bool TypeEnvironment::combine(
 		const TypeEnvironment & o, OpenVarSet & open, const SymbolTable & symtab ) {
 	// short-circuit easy cases
@@ -199,5 +199,5 @@
 				auto st = internal_lookup( *vt );
 				if ( st == env.end() ) {
-					// unbound, safe to add if occurs 
+					// unbound, safe to add if occurs
 					if ( r.bound && occurs( r.bound, *vt, *this ) ) return false;
 					r.vars.emplace( *vt );
@@ -266,8 +266,8 @@
 }
 
-bool TypeEnvironment::bindVar( 
-		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
-		AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen, 
-		const SymbolTable & symtab 
+bool TypeEnvironment::bindVar(
+		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
+		AssertionSet & need, AssertionSet & have, const OpenVarSet & open, WidenMode widen,
+		const SymbolTable & symtab
 ) {
 	// remove references from bound type, so that type variables can only bind to value types
@@ -286,6 +286,6 @@
 			ptr<Type> newType = it->bound;
 			reset_qualifiers( newType, typeInst->qualifiers );
-			if ( unifyInexact( 
-					newType, target, *this, need, have, open, 
+			if ( unifyInexact(
+					newType, target, *this, need, have, open,
 					widen & WidenMode{ it->allowWidening, true }, symtab, common ) ) {
 				if ( common ) {
@@ -300,5 +300,5 @@
 		}
 	} else {
-		env.emplace_back( 
+		env.emplace_back(
 			typeInst->name, target, widen.first && widen.second, data );
 	}
@@ -306,12 +306,12 @@
 }
 
-bool TypeEnvironment::bindVarToVar( 
-		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
-		AssertionSet & need, AssertionSet & have, const OpenVarSet & open, 
-		WidenMode widen, const SymbolTable & symtab 
+bool TypeEnvironment::bindVarToVar(
+		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
+		AssertionSet & need, AssertionSet & have, const OpenVarSet & open,
+		WidenMode widen, const SymbolTable & symtab
 ) {
 	auto c1 = internal_lookup( var1->name );
 	auto c2 = internal_lookup( var2->name );
-	
+
 	// exit early if variables already bound together
 	if ( c1 != env.end() && c1 == c2 ) {
@@ -396,5 +396,5 @@
 }
 
-bool TypeEnvironment::mergeBound( 
+bool TypeEnvironment::mergeBound(
 		EqvClass & to, const EqvClass & from, OpenVarSet & open, const SymbolTable & symtab ) {
 	if ( from.bound ) {
@@ -406,5 +406,5 @@
 			AssertionSet need, have;
 
-			if ( unifyInexact( 
+			if ( unifyInexact(
 					toType, fromType, *this, need, have, open, widen, symtab, common ) ) {
 				// unifies, set common type if necessary
@@ -424,5 +424,5 @@
 }
 
-bool TypeEnvironment::mergeClasses( 
+bool TypeEnvironment::mergeClasses(
 	ClassList::iterator to, ClassList::iterator from, OpenVarSet & open, const SymbolTable & symtab
 ) {
Index: src/AST/TypeEnvironment.hpp
===================================================================
--- src/AST/TypeEnvironment.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/TypeEnvironment.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -37,20 +37,20 @@
 /// Adding this comparison operator significantly improves assertion satisfaction run time for
 /// some cases. The current satisfaction algorithm's speed partially depends on the order of
-/// assertions. Assertions which have fewer possible matches should appear before assertions 
-/// which have more possible matches. This seems to imply that this could be further improved 
-/// by providing an indexer as an additional argument and ordering based on the number of 
+/// assertions. Assertions which have fewer possible matches should appear before assertions
+/// which have more possible matches. This seems to imply that this could be further improved
+/// by providing an indexer as an additional argument and ordering based on the number of
 /// matches of the same kind (object, function) for the names of the declarations.
 ///
-/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this 
+/// I've seen a TU go from 54 minutes to 1 minute 34 seconds with the addition of this
 /// comparator.
 ///
-/// Note: since this compares pointers for position, minor changes in the source file that 
-/// affect memory layout can alter compilation time in unpredictable ways. For example, the 
-/// placement of a line directive can reorder type pointers with respect to each other so that 
-/// assertions are seen in different orders, causing a potentially different number of 
-/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27 
-/// seconds by reordering line directives alone, so it would be nice to fix this comparison so 
-/// that assertions compare more consistently. I've tried to modify this to compare on mangle 
-/// name instead of type as the second comparator, but this causes some assertions to never be 
+/// Note: since this compares pointers for position, minor changes in the source file that
+/// affect memory layout can alter compilation time in unpredictable ways. For example, the
+/// placement of a line directive can reorder type pointers with respect to each other so that
+/// assertions are seen in different orders, causing a potentially different number of
+/// unification calls when resolving assertions. I've seen a TU go from 36 seconds to 27
+/// seconds by reordering line directives alone, so it would be nice to fix this comparison so
+/// that assertions compare more consistently. I've tried to modify this to compare on mangle
+/// name instead of type as the second comparator, but this causes some assertions to never be
 /// recorded. More investigation is needed.
 struct AssertCompare {
@@ -86,5 +86,5 @@
 void print( std::ostream &, const OpenVarSet &, Indenter indent = {} );
 
-/// Represents an equivalence class of bound type variables, optionally with the concrete type 
+/// Represents an equivalence class of bound type variables, optionally with the concrete type
 /// they bind to.
 struct EqvClass {
@@ -95,7 +95,7 @@
 
 	EqvClass() : vars(), bound(), allowWidening( true ), data() {}
-	
+
 	/// Copy-with-bound constructor
-	EqvClass( const EqvClass & o, const Type * b ) 
+	EqvClass( const EqvClass & o, const Type * b )
 	: vars( o.vars ), bound( b ), allowWidening( o.allowWidening ), data( o.data ) {}
 
@@ -142,16 +142,16 @@
 	void writeToSubstitution( TypeSubstitution & sub ) const;
 
-	template< typename node_t, enum Node::ref_type ref_t >
-	int apply( ptr_base< node_t, ref_t > & type ) const {
+	template< typename node_t >
+	auto apply( node_t && type ) const {
 		TypeSubstitution sub;
 		writeToSubstitution( sub );
-		return sub.apply( type );
-	}
-
-	template< typename node_t, enum Node::ref_type ref_t >
-	int applyFree( ptr_base< node_t, ref_t > & type ) const {
+		return sub.apply( std::forward<node_t>(type) );
+	}
+
+	template< typename node_t >
+	auto applyFree( node_t && type ) const {
 		TypeSubstitution sub;
 		writeToSubstitution( sub );
-		return sub.applyFree( type );
+		return sub.applyFree( std::forward<node_t>(type) );
 	}
 
@@ -172,16 +172,16 @@
 	void addActual( const TypeEnvironment & actualEnv, OpenVarSet & openVars );
 
-	/// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if 
+	/// Binds the type class represented by `typeInst` to the type `bindTo`; will add the class if
 	/// needed. Returns false on failure.
-	bool bindVar( 
-		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data, 
-		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
+	bool bindVar(
+		const TypeInstType * typeInst, const Type * bindTo, const TypeDecl::Data & data,
+		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
 		ResolvExpr::WidenMode widen, const SymbolTable & symtab );
-	
-	/// Binds the type classes represented by `var1` and `var2` together; will add one or both 
+
+	/// Binds the type classes represented by `var1` and `var2` together; will add one or both
 	/// classes if needed. Returns false on failure.
-	bool bindVarToVar( 
-		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data, 
-		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars, 
+	bool bindVarToVar(
+		const TypeInstType * var1, const TypeInstType * var2, TypeDecl::Data && data,
+		AssertionSet & need, AssertionSet & have, const OpenVarSet & openVars,
 		ResolvExpr::WidenMode widen, const SymbolTable & symtab );
 
@@ -198,10 +198,10 @@
 
 	/// Unifies the type bound of `to` with the type bound of `from`, returning false if fails
-	bool mergeBound( 
+	bool mergeBound(
 		EqvClass & to, const EqvClass & from, OpenVarSet & openVars, const SymbolTable & symtab );
 
 	/// Merges two type classes from local environment, returning false if fails
-	bool mergeClasses( 
-		ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars, 
+	bool mergeClasses(
+		ClassList::iterator to, ClassList::iterator from, OpenVarSet & openVars,
 		const SymbolTable & symtab );
 
Index: src/AST/TypeSubstitution.cpp
===================================================================
--- src/AST/TypeSubstitution.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/TypeSubstitution.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -18,4 +18,7 @@
 
 namespace ast {
+
+
+// size_t TypeSubstitution::Substituter::traceId = Stats::Heap::new_stacktrace_id("TypeSubstitution");
 
 TypeSubstitution::TypeSubstitution() {
@@ -92,5 +95,5 @@
 namespace {
 	struct EnvTrimmer {
-		ptr<TypeSubstitution> env;
+		const TypeSubstitution * env;
 		TypeSubstitution * newEnv;
 		EnvTrimmer( const TypeSubstitution * env, TypeSubstitution * newEnv ) : env( env ), newEnv( newEnv ){}
@@ -108,11 +111,6 @@
 	if ( env ) {
 		TypeSubstitution * newEnv = new TypeSubstitution();
-#if TIME_TO_CONVERT_PASSES
 		Pass<EnvTrimmer> trimmer( env, newEnv );
 		expr->accept( trimmer );
-#else
-		(void)expr;
-		(void)env;
-#endif
 		return newEnv;
 	}
@@ -121,19 +119,15 @@
 
 void TypeSubstitution::normalize() {
-#if TIME_TO_CONVERT_PASSES
-	PassVisitor<Substituter> sub( *this, true );
+	Pass<Substituter> sub( *this, true );
 	do {
-		sub.pass.subCount = 0;
-		sub.pass.freeOnly = true;
+		sub.core.subCount = 0;
+		sub.core.freeOnly = true;
 		for ( TypeEnvType::iterator i = typeEnv.begin(); i != typeEnv.end(); ++i ) {
-			i->second = i->second->acceptMutator( sub );
-		}
-	} while ( sub.pass.subCount );
-#endif
-}
-
-#if TIME_TO_CONVERT_PASSES
-
-Type * TypeSubstitution::Substituter::postmutate( TypeInstType *inst ) {
+			i->second = i->second->accept( sub );
+		}
+	} while ( sub.core.subCount );
+}
+
+const Type * TypeSubstitution::Substituter::postvisit( const TypeInstType *inst ) {
 	BoundVarsType::const_iterator bound = boundVars.find( inst->name );
 	if ( bound != boundVars.end() ) return inst;
@@ -146,5 +140,5 @@
 		// Note: this does not prevent cycles in the general case, so it may be necessary to do something more sophisticated here.
 		// TODO: investigate preventing type variables from being bound to themselves in the first place.
-		if ( TypeInstType * replacement = i->second.as<TypeInstType>() ) {
+		if ( const TypeInstType * replacement = i->second.as<TypeInstType>() ) {
 			if ( inst->name == replacement->name ) {
 				return inst;
@@ -153,13 +147,14 @@
 		// std::cerr << "found " << inst->name << ", replacing with " << i->second << std::endl;
 		subCount++;
-		Type * newtype = i->second->clone();
-		newtype->get_qualifiers() |= inst->get_qualifiers();
-		delete inst;
-		// Note: need to recursively apply substitution to the new type because normalize does not substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
-		return newtype->acceptMutator( *visitor );
-	} // if
-}
-
-Expression * TypeSubstitution::Substituter::postmutate( NameExpr * nameExpr ) {
+		ptr<Type> newType = i->second; // force clone if needed
+		add_qualifiers( newType, inst->qualifiers );
+		// Note: need to recursively apply substitution to the new type because normalize does not
+		// substitute bound vars, but bound vars must be substituted when not in freeOnly mode.
+		newType = newType->accept( *visitor );
+		return newType.release();
+	} // if
+}
+
+const Expr * TypeSubstitution::Substituter::postvisit( const NameExpr * nameExpr ) {
 	VarEnvType::const_iterator i = sub.varEnv.find( nameExpr->name );
 	if ( i == sub.varEnv.end() ) {
@@ -167,46 +162,43 @@
 	} else {
 		subCount++;
-		delete nameExpr;
-		return i->second->clone();
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( Type * type ) {
+		return i->second;
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const ParameterizedType * ptype ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : ptype->forall ) {
+				boundVars.insert( tyvar->name );
 		} // for
 	} // if
 }
 
-template< typename TypeClass >
-void TypeSubstitution::Substituter::handleAggregateType( TypeClass * type ) {
+void TypeSubstitution::Substituter::handleAggregateType( const ReferenceToType * type ) {
 	GuardValue( boundVars );
 	// bind type variables from forall-qualifiers
 	if ( freeOnly ) {
-		for ( Type::ForallList::const_iterator tyvar = type->forall.begin(); tyvar != type->forall.end(); ++tyvar ) {
-			boundVars.insert( (*tyvar)->name );
+		for ( const TypeDecl * tyvar : type->forall ) {
+			boundVars.insert( tyvar->name );
 		} // for
 		// bind type variables from generic type instantiations
-		std::list< TypeDecl* > *baseParameters = type->get_baseParameters();
-		if ( baseParameters && ! type->parameters.empty() ) {
-			for ( std::list< TypeDecl* >::const_iterator tyvar = baseParameters->begin(); tyvar != baseParameters->end(); ++tyvar ) {
-				boundVars.insert( (*tyvar)->name );
-			} // for
-		} // if
-	} // if
-}
-
-void TypeSubstitution::Substituter::premutate( StructInstType * aggregateUseType ) {
+		if ( auto decl = type->aggr() ) {
+			if ( ! type->params.empty() ) {
+				for ( const TypeDecl * tyvar : decl->params ) {
+					boundVars.insert( tyvar->name );
+				} // for
+			} // if
+		}
+	} // if
+}
+
+void TypeSubstitution::Substituter::previsit( const StructInstType * aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
 
-void TypeSubstitution::Substituter::premutate( UnionInstType *aggregateUseType ) {
+void TypeSubstitution::Substituter::previsit( const UnionInstType *aggregateUseType ) {
 	handleAggregateType( aggregateUseType );
 }
-
-#endif
 
 } // namespace ast
Index: src/AST/TypeSubstitution.hpp
===================================================================
--- src/AST/TypeSubstitution.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/TypeSubstitution.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -44,13 +44,20 @@
 	TypeSubstitution &operator=( const TypeSubstitution &other );
 
-	template< typename SynTreeClass > int apply( const SynTreeClass *& input ) const;
-	template< typename SynTreeClass > int applyFree( const SynTreeClass *& input ) const;
+	template< typename SynTreeClass >
+	struct ApplyResult {
+		// const SynTreeClass * node;
+		ast::ptr<SynTreeClass> node;
+		int count;
+	};
+
+	template< typename SynTreeClass > ApplyResult<SynTreeClass> apply( const SynTreeClass * input ) const;
+	template< typename SynTreeClass > ApplyResult<SynTreeClass> applyFree( const SynTreeClass * input ) const;
 
 	template< typename node_t, enum Node::ref_type ref_t >
 	int apply( ptr_base< node_t, ref_t > & input ) const {
 		const node_t * p = input.get();
-		int ret = apply(p);
-		input = p;
-		return ret;
+		auto ret = apply(p);
+		input = ret.node;
+		return ret.count;
 	}
 
@@ -58,7 +65,7 @@
 	int applyFree( ptr_base< node_t, ref_t > & input ) const {
 		const node_t * p = input.get();
-		int ret = applyFree(p);
-		input = p;
-		return ret;
+		auto ret = applyFree(p);
+		input = ret.node;
+		return ret.count;
 	}
 
@@ -92,5 +99,5 @@
 	void initialize( const TypeSubstitution &src, TypeSubstitution &dest );
 
-	template<typename pass_type>
+	template<typename core_t>
 	friend class Pass;
 
@@ -147,4 +154,5 @@
 // PassVisitor are defined before PassVisitor implementation accesses TypeSubstitution internals.
 #include "Pass.hpp"
+#include "Copy.hpp"
 
 namespace ast {
@@ -152,21 +160,18 @@
 // 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 ) {}
 
-#if TIME_TO_CONVERT_PASSES
-
-		Type * postmutate( TypeInstType * aggregateUseType );
-		Expression * postmutate( NameExpr * nameExpr );
+		const Type * postvisit( const TypeInstType * aggregateUseType );
+		const Expr * postvisit( const NameExpr * nameExpr );
 
 		/// Records type variable bindings from forall-statements
-		void premutate( Type * type );
+		void previsit( const ParameterizedType * type );
 		/// Records type variable bindings from forall-statements and instantiations of generic types
-		template< typename TypeClass > void handleAggregateType( TypeClass * type );
-
-		void premutate( StructInstType * aggregateUseType );
-		void premutate( UnionInstType * aggregateUseType );
-
-#endif
+		void handleAggregateType( const ReferenceToType * type );
+
+		void previsit( const StructInstType * aggregateUseType );
+		void previsit( const UnionInstType * aggregateUseType );
 
 		const TypeSubstitution & sub;
@@ -179,23 +184,17 @@
 
 template< typename SynTreeClass >
-int TypeSubstitution::apply( const SynTreeClass *& input ) const {
+TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::apply( const SynTreeClass * input ) const {
 	assert( input );
 	Pass<Substituter> sub( *this, false );
-	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
-///	std::cerr << "substitution result is: ";
-///	newType->print( std::cerr );
-///	std::cerr << std::endl;
-	return sub.pass.subCount;
+	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+	return { input, sub.core.subCount };
 }
 
 template< typename SynTreeClass >
-int TypeSubstitution::applyFree( const SynTreeClass *& input ) const {
+TypeSubstitution::ApplyResult<SynTreeClass> TypeSubstitution::applyFree( const SynTreeClass * input ) const {
 	assert( input );
 	Pass<Substituter> sub( *this, true );
-	input = strict_dynamic_cast< const SynTreeClass * >( input->accept( sub ) );
-///	std::cerr << "substitution result is: ";
-///	newType->print( std::cerr );
-///	std::cerr << std::endl;
-	return sub.pass.subCount;
+	input = strict_dynamic_cast< const SynTreeClass * >( deepCopy(input)->accept( sub ) );
+	return { input, sub.core.subCount };
 }
 
Index: src/AST/module.mk
===================================================================
--- src/AST/module.mk	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/module.mk	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -22,4 +22,5 @@
 	AST/DeclReplacer.cpp \
 	AST/Expr.cpp \
+	AST/ForallSubstitutionTable.cpp \
 	AST/GenericSubstitution.cpp \
 	AST/Init.cpp \
Index: src/AST/porting.md
===================================================================
--- src/AST/porting.md	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/AST/porting.md	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -47,4 +47,9 @@
       template<typename node_t>
       friend node_t * mutate(const node_t * node);
+      template<typename node_t>
+      friend node_t * shallowCopy(const node_t * node);
+    or equilant.
+* You should use the `mutate` function where possible as it avoids extra copies.
+  * If you must copy use `shallowCopy` or `deepCopy` as required.
 
 All leaves of the `Node` inheritance tree are now declared `final`
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Common/Eval.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -168,5 +168,5 @@
 	if (expr) {
 		expr->accept(ev);
-		return std::make_pair(ev.pass.value, ev.pass.valid);
+		return std::make_pair(ev.core.value, ev.core.valid);
 	} else {
 		return std::make_pair(0, false);
Index: src/Common/ScopedMap.h
===================================================================
--- src/Common/ScopedMap.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Common/ScopedMap.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -249,4 +249,6 @@
 
 	/// Gets the note at the given scope
+	Note& getNote() { return scopes.back().note; }
+	const Note& getNote() const { return scopes.back().note; }
 	Note& getNote( size_type i ) { return scopes[i].note; }
 	const Note& getNote( size_type i ) const { return scopes[i].note; }
Index: src/Common/Stats/Heap.cc
===================================================================
--- src/Common/Stats/Heap.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Common/Stats/Heap.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -53,4 +53,28 @@
 		const size_t passes_size = sizeof(passes) / sizeof(passes[0]);
 		size_t       passes_cnt = 1;
+
+		StatBlock    stacktrace_stats[100];
+		size_t       stacktrace_stats_count = 0;
+		bool         stacktrace_stats_enabled = true;
+
+		size_t       trace[1000];
+		const size_t stacktrace_max_depth = sizeof(trace) / sizeof(size_t);
+		size_t       stacktrace_depth;
+
+		size_t new_stacktrace_id(const char * const name) {
+			stacktrace_stats[stacktrace_stats_count].name = name;
+			return stacktrace_stats_count++;
+		}
+
+		void stacktrace_push(size_t id) {
+			++stacktrace_depth;
+			assertf(stacktrace_depth < stacktrace_max_depth, "Stack trace too deep: increase size of array in Heap.cc");
+			trace[stacktrace_depth] = id;
+		}
+
+		void stacktrace_pop() {
+			assertf(stacktrace_depth > 0, "Invalid stack tracing operation: trace is empty");
+			--stacktrace_depth;
+		}
 
 		void newPass( const char * const name ) {
@@ -116,4 +140,13 @@
 			for(size_t i = 0; i < passes_cnt; i++) {
 				print(passes[i], nc, total_mallocs, total_frees, overall_peak);
+			}
+
+			print('-', nct);
+			std::cerr << std::setw(nc) << "Trace";
+			std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
+
+			print('-', nct);
+			for (size_t i = 0; i < stacktrace_stats_count; i++) {
+				print(stacktrace_stats[i], nc, total_mallocs, total_frees, overall_peak);
 			}
 			print('-', nct);
@@ -188,4 +221,8 @@
 						= std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
 				}
+
+				if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
+					stacktrace_stats[trace[stacktrace_depth]].mallocs++;
+				}
 				return __malloc( size );
 			}
@@ -196,4 +233,7 @@
 					passes[passes_cnt - 1].frees++;
 					passes[passes_cnt - 1].n_allocs--;
+				}
+				if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
+					stacktrace_stats[trace[stacktrace_depth]].frees++;
 				}
 				return __free( ptr );
@@ -208,4 +248,7 @@
 						= std::max(passes[passes_cnt - 1].peak_allocs, passes[passes_cnt - 1].n_allocs);
 				}
+				if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
+					stacktrace_stats[trace[stacktrace_depth]].mallocs++;
+				}
 				return __calloc( nelem, size );
 			}
@@ -218,4 +261,8 @@
 					passes[passes_cnt - 1].frees++;
 				} // if
+				if ( stacktrace_stats_enabled && stacktrace_depth > 0) {
+					stacktrace_stats[trace[stacktrace_depth]].mallocs++;
+					stacktrace_stats[trace[stacktrace_depth]].frees++;
+				}
 				return s;
 			}
Index: src/Common/Stats/Heap.h
===================================================================
--- src/Common/Stats/Heap.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Common/Stats/Heap.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -20,4 +20,8 @@
 		void newPass( const char * const name );
 		void print();
+
+		size_t new_stacktrace_id(const char * const name);
+		void stacktrace_push(size_t id);
+		void stacktrace_pop();
 	}
 }
Index: src/CompilationState.cc
===================================================================
--- src/CompilationState.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/CompilationState.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -14,4 +14,6 @@
 //
 
+#include "config.h"
+
 int
 	astp = false,
@@ -28,4 +30,5 @@
 	genproto = false,
 	deterministic_output = false,
+	useNewAST = CFA_USE_NEW_AST,
 	nomainp = false,
 	parsep = false,
Index: src/CompilationState.h
===================================================================
--- src/CompilationState.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/CompilationState.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -29,4 +29,5 @@
 	genproto,
 	deterministic_output,
+	useNewAST,
 	nomainp,
 	parsep,
Index: src/InitTweak/InitTweak.cc
===================================================================
--- src/InitTweak/InitTweak.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/InitTweak/InitTweak.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -127,5 +127,5 @@
 	ast::Pass< InitFlattener_new > flattener;
 	maybe_accept( init, flattener );
-	return std::move( flattener.pass.argList );
+	return std::move( flattener.core.argList );
 }
 
@@ -561,5 +561,5 @@
 		ast::Pass< CallFinder_new > finder{ std::vector< std::string >{ "?{}", "^?{}" } };
 		maybe_accept( stmt, finder );
-		return std::move( finder.pass.matches );
+		return std::move( finder.core.matches );
 	}
 
Index: src/Parser/ExpressionNode.cc
===================================================================
--- src/Parser/ExpressionNode.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Parser/ExpressionNode.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Sat May 16 13:17:07 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Wed Jul 15 08:24:08 2020
-// Update Count     : 1046
+// Last Modified On : Thu Aug 20 14:01:46 2020
+// Update Count     : 1076
 //
 
@@ -65,9 +65,11 @@
 
 void lnthSuffix( string & str, int & type, int & ltype ) {
+	// 'u' can appear before or after length suffix
 	string::size_type posn = str.find_last_of( "lL" );
 
 	if ( posn == string::npos ) return;					// no suffix
-	if ( posn == str.length() - 1 ) { type = 3; return; } // no length => long
-
+	size_t end = str.length() - 1;
+	if ( posn == end ) { type = 3; return; }			// no length after 'l' => long
+	
 	string::size_type next = posn + 1;					// advance to length
 	if ( str[next] == '3' ) {							// 32
@@ -84,6 +86,12 @@
 		} // if
 	} // if
-	// remove "lL" for these cases because it may not imply long
-	str.erase( posn );									// remove length suffix and "uU"
+
+	char fix = '\0';
+	if ( str[end] == 'u' || str[end] == 'U' ) fix = str[end]; // ends with 'uU' ?
+	str.erase( posn );									// remove length suffix and possibly uU
+	if ( type == 5 ) {									// L128 does not need uU
+		end = str.length() - 1;
+		if ( str[end] == 'u' || str[end] == 'U' ) str.erase( end ); // ends with 'uU' ? remove
+	} else if ( fix != '\0' ) str += fix;				// put 'uU' back if removed
 } // lnthSuffix
 
@@ -156,5 +164,4 @@
 	if ( isdigit( str[str.length() - 1] ) ) {			// no suffix ?
 		lnthSuffix( str, type, ltype );					// could have length suffix
-		if ( type == 5 && Unsigned ) str.erase( str.length() - 1 ); // L128 and terminating "uU" ?
 	} else {
 		// At least one digit in integer constant, so safe to backup while looking for suffix.
@@ -195,4 +202,5 @@
 			if ( type < 5 ) {							// not L128 ?
 				sscanf( (char *)str.c_str(), "%llx", &v );
+#if defined(__SIZEOF_INT128__)
 			} else {									// hex int128 constant
 				unsigned int len = str.length();
@@ -204,7 +212,9 @@
 			  FHEX1: ;
 				sscanf( (char *)str.c_str(), "%llx", &v );
+#endif // __SIZEOF_INT128__
 			} // if
 			//printf( "%llx %llu\n", v, v );
 		} else if ( checkB( str[1] ) ) {				// binary constant ?
+#if defined(__SIZEOF_INT128__)
 			unsigned int len = str.length();
 			if ( type == 5 && len > 2 + 64 ) {
@@ -214,4 +224,5 @@
 				scanbin( str2, v2 );
 			} // if
+#endif // __SIZEOF_INT128__
 			scanbin( str, v );
 			//printf( "%#llx %llu\n", v, v );
@@ -223,6 +234,7 @@
 				unsigned int len = str.length();
 				if ( len > 1 + 43 || (len == 1 + 43 && str[0] > '3') ) SemanticError( yylloc, "128-bit octal constant to large " + str );
+				char buf[32];
 				if ( len <= 1 + 21 ) {					// value < 21 octal digitis
-					sscanf( (char *)str.c_str(), "%llo", &v ); // leave value in octal
+					sscanf( (char *)str.c_str(), "%llo", &v );
 				} else {
 					sscanf( &str[len - 21], "%llo", &v );
@@ -237,10 +249,9 @@
 					} // if
 					v = val >> 64; v2 = (uint64_t)val;	// replace octal constant with 2 hex constants
-					char buf[32];
 					sprintf( buf, "%#llx", v2 );
 					str2 = buf;
-					sprintf( buf, "%#llx", v );
-					str = buf;
 				} // if
+				sprintf( buf, "%#llx", v );
+				str = buf;
 #endif // __SIZEOF_INT128__
 			} // if
@@ -256,6 +267,7 @@
 			if ( str.length() == 39 && str > (Unsigned ? "340282366920938463463374607431768211455" : "170141183460469231731687303715884105727") )
 				SemanticError( yylloc, "128-bit decimal constant to large " + str );
+			char buf[32];
 			if ( len <= 19 ) {							// value < 19 decimal digitis
-				sscanf( (char *)str.c_str(), "%llu", &v ); // leave value in decimal
+				sscanf( (char *)str.c_str(), "%llu", &v );
 			} else {
 				sscanf( &str[len - 19], "%llu", &v );
@@ -270,10 +282,9 @@
 				} // if
 				v = val >> 64; v2 = (uint64_t)val;		// replace decimal constant with 2 hex constants
-				char buf[32];
 				sprintf( buf, "%#llx", v2 );
 				str2 = buf;
-				sprintf( buf, "%#llx", v );
-				str = buf;
 			} // if
+			sprintf( buf, "%#llx", v );
+			str = buf;
 #endif // __SIZEOF_INT128__
 		} // if
Index: src/ResolvExpr/AdjustExprType.cc
===================================================================
--- src/ResolvExpr/AdjustExprType.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/AdjustExprType.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -100,35 +100,36 @@
 
 namespace {
-	struct AdjustExprType_new final : public ast::WithShortCircuiting {
+	class AdjustExprType_new final : public ast::WithShortCircuiting {
+		const ast::SymbolTable & symtab;
+	public:
 		const ast::TypeEnvironment & tenv;
-		const ast::SymbolTable & symtab;
 
 		AdjustExprType_new( const ast::TypeEnvironment & e, const ast::SymbolTable & syms )
-		: tenv( e ), symtab( syms ) {}
+		: symtab( syms ), tenv( e ) {}
 
-		void premutate( const ast::VoidType * ) { visit_children = false; }
-		void premutate( const ast::BasicType * ) { visit_children = false; }
-		void premutate( const ast::PointerType * ) { visit_children = false; }
-		void premutate( const ast::ArrayType * ) { visit_children = false; }
-		void premutate( const ast::FunctionType * ) { visit_children = false; }
-		void premutate( const ast::StructInstType * ) { visit_children = false; }
-		void premutate( const ast::UnionInstType * ) { visit_children = false; }
-		void premutate( const ast::EnumInstType * ) { visit_children = false; }
-		void premutate( const ast::TraitInstType * ) { visit_children = false; }
-		void premutate( const ast::TypeInstType * ) { visit_children = false; }
-		void premutate( const ast::TupleType * ) { visit_children = false; }
-		void premutate( const ast::VarArgsType * ) { visit_children = false; }
-		void premutate( const ast::ZeroType * ) { visit_children = false; }
-		void premutate( const ast::OneType * ) { visit_children = false; }
+		void previsit( const ast::VoidType * ) { visit_children = false; }
+		void previsit( const ast::BasicType * ) { visit_children = false; }
+		void previsit( const ast::PointerType * ) { visit_children = false; }
+		void previsit( const ast::ArrayType * ) { visit_children = false; }
+		void previsit( const ast::FunctionType * ) { visit_children = false; }
+		void previsit( const ast::StructInstType * ) { visit_children = false; }
+		void previsit( const ast::UnionInstType * ) { visit_children = false; }
+		void previsit( const ast::EnumInstType * ) { visit_children = false; }
+		void previsit( const ast::TraitInstType * ) { visit_children = false; }
+		void previsit( const ast::TypeInstType * ) { visit_children = false; }
+		void previsit( const ast::TupleType * ) { visit_children = false; }
+		void previsit( const ast::VarArgsType * ) { visit_children = false; }
+		void previsit( const ast::ZeroType * ) { visit_children = false; }
+		void previsit( const ast::OneType * ) { visit_children = false; }
 
-		const ast::Type * postmutate( const ast::ArrayType * at ) {
+		const ast::Type * postvisit( const ast::ArrayType * at ) {
 			return new ast::PointerType{ at->base, at->qualifiers };
 		}
 
-		const ast::Type * postmutate( const ast::FunctionType * ft ) {
+		const ast::Type * postvisit( const ast::FunctionType * ft ) {
 			return new ast::PointerType{ ft };
 		}
 
-		const ast::Type * postmutate( const ast::TypeInstType * inst ) {
+		const ast::Type * postvisit( const ast::TypeInstType * inst ) {
 			// replace known function-type-variables with pointer-to-function
 			if ( const ast::EqvClass * eqvClass = tenv.lookup( inst->name ) ) {
Index: src/ResolvExpr/Candidate.hpp
===================================================================
--- src/ResolvExpr/Candidate.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/Candidate.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -51,14 +51,20 @@
 
 	Candidate( const ast::Expr * x, const ast::TypeEnvironment & e )
-	: expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {}
+	: expr( x ), cost( Cost::zero ), cvtCost( Cost::zero ), env( e ), open(), need() {
+		assert(x->result);
+	}
 
 	Candidate( const Candidate & o, const ast::Expr * x, const Cost & addedCost = Cost::zero )
 	: expr( x ), cost( o.cost + addedCost ), cvtCost( Cost::zero ), env( o.env ), open( o.open ),
-	  need( o.need ) {}
+	  need( o.need ) {
+		assert(x->result);
+	}
 
 	Candidate(
-		const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
+		const ast::Expr * x, const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
 		const ast::AssertionSet & n, const Cost & c, const Cost & cvt = Cost::zero )
-	: expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {}
+	: expr( x ), cost( c ), cvtCost( cvt ), env( e ), open( o ), need( n.begin(), n.end() ) {
+		assert(x->result);
+	}
 
 	Candidate(
@@ -66,5 +72,7 @@
 		ast::AssertionSet && n, const Cost & c, const Cost & cvt = Cost::zero )
 	: expr( x ), cost( c ), cvtCost( cvt ), env( std::move( e ) ), open( std::move( o ) ),
-	  need( n.begin(), n.end() ) {}
+	  need( n.begin(), n.end() ) {
+		assert(x->result);
+	}
 };
 
Index: src/ResolvExpr/CandidateFinder.cpp
===================================================================
--- src/ResolvExpr/CandidateFinder.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/CandidateFinder.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Wed Jun 5 14:30:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Wed Jun 5 14:30:00 2019
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Oct  1 14:55:00 2019
+// Update Count     : 2
 //
 
@@ -54,5 +54,5 @@
 		return new ast::CastExpr{ expr, expr->result->stripReferences() };
 	}
-	
+
 	return expr;
 }
@@ -61,7 +61,7 @@
 UniqueId globalResnSlot = 0;
 
-Cost computeConversionCost( 
-	const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab, 
-	const ast::TypeEnvironment & env 
+Cost computeConversionCost(
+	const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
 ) {
 	PRINT(
@@ -74,5 +74,5 @@
 		std::cerr << std::endl;
 	)
-	Cost convCost = conversionCost( argType, paramType, symtab, env );
+	Cost convCost = conversionCost( argType, paramType, argIsLvalue, symtab, env );
 	PRINT(
 		std::cerr << std::endl << "cost is " << convCost << std::endl;
@@ -107,12 +107,13 @@
 
 	/// Computes conversion cost for a given expression to a given type
-	const ast::Expr * computeExpressionConversionCost( 
-		const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost 
+	const ast::Expr * computeExpressionConversionCost(
+		const ast::Expr * arg, const ast::Type * paramType, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, Cost & outCost
 	) {
-		Cost convCost = computeConversionCost( arg->result, paramType, symtab, env );
+		Cost convCost = computeConversionCost(
+				arg->result, paramType, arg->get_lvalue(), symtab, env );
 		outCost += convCost;
 
-		// If there is a non-zero conversion cost, ignoring poly cost, then the expression requires 
-		// conversion. Ignore poly cost for now, since this requires resolution of the cast to 
+		// If there is a non-zero conversion cost, ignoring poly cost, then the expression requires
+		// conversion. Ignore poly cost for now, since this requires resolution of the cast to
 		// infer parameters and this does not currently work for the reason stated below
 		Cost tmpCost = convCost;
@@ -123,16 +124,16 @@
 			return new ast::CastExpr{ arg, newType };
 
-			// xxx - *should* be able to resolve this cast, but at the moment pointers are not 
-			// castable to zero_t, but are implicitly convertible. This is clearly inconsistent, 
+			// xxx - *should* be able to resolve this cast, but at the moment pointers are not
+			// castable to zero_t, but are implicitly convertible. This is clearly inconsistent,
 			// once this is fixed it should be possible to resolve the cast.
-			// xxx - this isn't working, it appears because type1 (parameter) is seen as widenable, 
-			// but it shouldn't be because this makes the conversion from DT* to DT* since 
+			// xxx - this isn't working, it appears because type1 (parameter) is seen as widenable,
+			// but it shouldn't be because this makes the conversion from DT* to DT* since
 			// commontype(zero_t, DT*) is DT*, rather than nothing
 
 			// CandidateFinder finder{ symtab, env };
 			// finder.find( arg, ResolvMode::withAdjustment() );
-			// assertf( finder.candidates.size() > 0, 
+			// assertf( finder.candidates.size() > 0,
 			// 	"Somehow castable expression failed to find alternatives." );
-			// assertf( finder.candidates.size() == 1, 
+			// assertf( finder.candidates.size() == 1,
 			// 	"Somehow got multiple alternatives for known cast expression." );
 			// return finder.candidates.front()->expr;
@@ -143,6 +144,6 @@
 
 	/// Computes conversion cost for a given candidate
-	Cost computeApplicationConversionCost( 
-		CandidateRef cand, const ast::SymbolTable & symtab 
+	Cost computeApplicationConversionCost(
+		CandidateRef cand, const ast::SymbolTable & symtab
 	) {
 		auto appExpr = cand->expr.strict_as< ast::ApplicationExpr >();
@@ -167,9 +168,9 @@
 				if ( function->isVarArgs ) {
 					convCost.incUnsafe();
-					PRINT( std::cerr << "end of params with varargs function: inc unsafe: " 
+					PRINT( std::cerr << "end of params with varargs function: inc unsafe: "
 						<< convCost << std::endl; ; )
 					// convert reference-typed expressions into value-typed expressions
-					cand->expr = ast::mutate_field_index( 
-						appExpr, &ast::ApplicationExpr::args, i, 
+					cand->expr = ast::mutate_field_index(
+						appExpr, &ast::ApplicationExpr::args, i,
 						referenceToRvalueConversion( args[i], convCost ) );
 					continue;
@@ -180,5 +181,5 @@
 				// Default arguments should be free - don't include conversion cost.
 				// Unwrap them here because they are not relevant to the rest of the system
-				cand->expr = ast::mutate_field_index( 
+				cand->expr = ast::mutate_field_index(
 					appExpr, &ast::ApplicationExpr::args, i, def->expr );
 				++param;
@@ -188,7 +189,7 @@
 			// mark conversion cost and also specialization cost of param type
 			const ast::Type * paramType = (*param)->get_type();
-			cand->expr = ast::mutate_field_index( 
-				appExpr, &ast::ApplicationExpr::args, i, 
-				computeExpressionConversionCost( 
+			cand->expr = ast::mutate_field_index(
+				appExpr, &ast::ApplicationExpr::args, i,
+				computeExpressionConversionCost(
 					args[i], paramType, symtab, cand->env, convCost ) );
 			convCost.decSpec( specCost( paramType ) );
@@ -198,5 +199,5 @@
 		if ( param != params.end() ) return Cost::infinity;
 
-		// specialization cost of return types can't be accounted for directly, it disables 
+		// specialization cost of return types can't be accounted for directly, it disables
 		// otherwise-identical calls, like this example based on auto-newline in the I/O lib:
 		//
@@ -215,7 +216,7 @@
 	}
 
-	void makeUnifiableVars( 
-		const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars, 
-		ast::AssertionSet & need 
+	void makeUnifiableVars(
+		const ast::ParameterizedType * type, ast::OpenVarSet & unifiableVars,
+		ast::AssertionSet & need
 	) {
 		for ( const ast::TypeDecl * tyvar : type->forall ) {
@@ -254,29 +255,29 @@
 
 		ArgPack()
-		: parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ), 
+		: parent( 0 ), expr(), cost( Cost::zero ), env(), need(), have(), open(), nextArg( 0 ),
 		  tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
-		
-		ArgPack( 
-			const ast::TypeEnvironment & env, const ast::AssertionSet & need, 
+
+		ArgPack(
+			const ast::TypeEnvironment & env, const ast::AssertionSet & need,
 			const ast::AssertionSet & have, const ast::OpenVarSet & open )
-		: parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ), 
+		: parent( 0 ), expr(), cost( Cost::zero ), env( env ), need( need ), have( have ),
 		  open( open ), nextArg( 0 ), tupleStart( 0 ), nextExpl( 0 ), explAlt( 0 ) {}
-		
+
 		ArgPack(
-			std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env, 
-			ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open, 
-			unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero, 
+			std::size_t parent, const ast::Expr * expr, ast::TypeEnvironment && env,
+			ast::AssertionSet && need, ast::AssertionSet && have, ast::OpenVarSet && open,
+			unsigned nextArg, unsigned tupleStart = 0, Cost cost = Cost::zero,
 			unsigned nextExpl = 0, unsigned explAlt = 0 )
 		: parent(parent), expr( expr ), cost( cost ), env( move( env ) ), need( move( need ) ),
 		  have( move( have ) ), open( move( open ) ), nextArg( nextArg ), tupleStart( tupleStart ),
 		  nextExpl( nextExpl ), explAlt( explAlt ) {}
-		
+
 		ArgPack(
-			const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need, 
+			const ArgPack & o, ast::TypeEnvironment && env, ast::AssertionSet && need,
 			ast::AssertionSet && have, ast::OpenVarSet && open, unsigned nextArg, Cost added )
-		: parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ), 
-		  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ), 
+		: parent( o.parent ), expr( o.expr ), cost( o.cost + added ), env( move( env ) ),
+		  need( move( need ) ), have( move( have ) ), open( move( open ) ), nextArg( nextArg ),
 		  tupleStart( o.tupleStart ), nextExpl( 0 ), explAlt( 0 ) {}
-		
+
 		/// true if this pack is in the middle of an exploded argument
 		bool hasExpl() const { return nextExpl > 0; }
@@ -286,5 +287,5 @@
 			return args[ nextArg-1 ][ explAlt ];
 		}
-		
+
 		/// Ends a tuple expression, consolidating the appropriate args
 		void endTuple( const std::vector< ArgPack > & packs ) {
@@ -307,8 +308,8 @@
 
 	/// Instantiates an argument to match a parameter, returns false if no matching results left
-	bool instantiateArgument( 
-		const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args, 
-		std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab, 
-		unsigned nTuples = 0 
+	bool instantiateArgument(
+		const ast::Type * paramType, const ast::Init * init, const ExplodedArgs_new & args,
+		std::vector< ArgPack > & results, std::size_t & genStart, const ast::SymbolTable & symtab,
+		unsigned nTuples = 0
 	) {
 		if ( auto tupleType = dynamic_cast< const ast::TupleType * >( paramType ) ) {
@@ -318,5 +319,5 @@
 				// xxx - dropping initializer changes behaviour from previous, but seems correct
 				// ^^^ need to handle the case where a tuple has a default argument
-				if ( ! instantiateArgument( 
+				if ( ! instantiateArgument(
 					type, nullptr, args, results, genStart, symtab, nTuples ) ) return false;
 				nTuples = 0;
@@ -329,5 +330,5 @@
 		} else if ( const ast::TypeInstType * ttype = Tuples::isTtype( paramType ) ) {
 			// paramType is a ttype, consumes all remaining arguments
-			
+
 			// completed tuples; will be spliced to end of results to finish
 			std::vector< ArgPack > finalResults{};
@@ -342,5 +343,5 @@
 				for ( std::size_t i = genStart; i < genEnd; ++i ) {
 					unsigned nextArg = results[i].nextArg;
-					
+
 					// use next element of exploded tuple if present
 					if ( results[i].hasExpl() ) {
@@ -352,5 +353,5 @@
 						results.emplace_back(
 							i, expl.exprs[ results[i].nextExpl ], copy( results[i].env ),
-							copy( results[i].need ), copy( results[i].have ), 
+							copy( results[i].need ), copy( results[i].have ),
 							copy( results[i].open ), nextArg, nTuples, Cost::zero, nextExpl,
 							results[i].explAlt );
@@ -370,7 +371,5 @@
 							// push empty tuple expression
 							newResult.parent = i;
-							std::vector< ast::ptr< ast::Expr > > emptyList;
-							newResult.expr = 
-								new ast::TupleExpr{ CodeLocation{}, move( emptyList ) };
+							newResult.expr = new ast::TupleExpr{ CodeLocation{}, {} };
 							argType = newResult.expr->result;
 						} else {
@@ -400,8 +399,8 @@
 
 						// check unification for ttype before adding to final
-						if ( 
-							unify( 
+						if (
+							unify(
 								ttype, argType, newResult.env, newResult.need, newResult.have,
-								newResult.open, symtab ) 
+								newResult.open, symtab )
 						) {
 							finalResults.emplace_back( move( newResult ) );
@@ -424,7 +423,7 @@
 						if ( expl.exprs.empty() ) {
 							results.emplace_back(
-								results[i], move( env ), copy( results[i].need ), 
+								results[i], move( env ), copy( results[i].need ),
 								copy( results[i].have ), move( open ), nextArg + 1, expl.cost );
-							
+
 							continue;
 						}
@@ -432,6 +431,6 @@
 						// add new result
 						results.emplace_back(
-							i, expl.exprs.front(), move( env ), copy( results[i].need ), 
-							copy( results[i].have ), move( open ), nextArg + 1, nTuples, 
+							i, expl.exprs.front(), move( env ), copy( results[i].need ),
+							copy( results[i].have ), move( open ), nextArg + 1, nTuples,
 							expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 					}
@@ -479,5 +478,5 @@
 
 					results.emplace_back(
-						i, expr, move( env ), move( need ), move( have ), move( open ), nextArg, 
+						i, expr, move( env ), move( need ), move( have ), move( open ), nextArg,
 						nTuples, Cost::zero, nextExpl, results[i].explAlt );
 				}
@@ -495,5 +494,5 @@
 					if ( unify( paramType, cnst->result, env, need, have, open, symtab ) ) {
 						results.emplace_back(
-							i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ), 
+							i, new ast::DefaultArgExpr{ cnst->location, cnst }, move( env ),
 							move( need ), move( have ), move( open ), nextArg, nTuples );
 					}
@@ -517,7 +516,7 @@
 				if ( expl.exprs.empty() ) {
 					results.emplace_back(
-						results[i], move( env ), move( need ), move( have ), move( open ), 
+						results[i], move( env ), move( need ), move( have ), move( open ),
 						nextArg + 1, expl.cost );
-					
+
 					continue;
 				}
@@ -539,5 +538,5 @@
 					// add new result
 					results.emplace_back(
-						i, expr, move( env ), move( need ), move( have ), move( open ), 
+						i, expr, move( env ), move( need ), move( have ), move( open ),
 						nextArg + 1, nTuples, expl.cost, expl.exprs.size() == 1 ? 0 : 1, j );
 				}
@@ -548,23 +547,23 @@
 		genStart = genEnd;
 
-		return genEnd != results.size();
+		return genEnd != results.size();  // were any new results added?
 	}
 
 	/// Generate a cast expression from `arg` to `toType`
-	const ast::Expr * restructureCast( 
+	const ast::Expr * restructureCast(
 		ast::ptr< ast::Expr > & arg, const ast::Type * toType, ast::GeneratedFlag isGenerated = ast::GeneratedCast
 	) {
-		if ( 
-			arg->result->size() > 1 
-			&& ! toType->isVoid() 
-			&& ! dynamic_cast< const ast::ReferenceType * >( toType ) 
+		if (
+			arg->result->size() > 1
+			&& ! toType->isVoid()
+			&& ! dynamic_cast< const ast::ReferenceType * >( toType )
 		) {
-			// Argument is a tuple and the target type is neither void nor a reference. Cast each 
-			// member of the tuple to its corresponding target type, producing the tuple of those 
-			// cast expressions. If there are more components of the tuple than components in the 
-			// target type, then excess components do not come out in the result expression (but 
+			// Argument is a tuple and the target type is neither void nor a reference. Cast each
+			// member of the tuple to its corresponding target type, producing the tuple of those
+			// cast expressions. If there are more components of the tuple than components in the
+			// target type, then excess components do not come out in the result expression (but
 			// UniqueExpr ensures that the side effects will still be produced)
 			if ( Tuples::maybeImpureIgnoreUnique( arg ) ) {
-				// expressions which may contain side effects require a single unique instance of 
+				// expressions which may contain side effects require a single unique instance of
 				// the expression
 				arg = new ast::UniqueExpr{ arg->location, arg };
@@ -574,5 +573,5 @@
 				// cast each component
 				ast::ptr< ast::Expr > idx = new ast::TupleIndexExpr{ arg->location, arg, i };
-				components.emplace_back( 
+				components.emplace_back(
 					restructureCast( idx, toType->getComponent( i ), isGenerated ) );
 			}
@@ -594,15 +593,31 @@
 
 	/// Actually visits expressions to find their candidate interpretations
-	struct Finder final : public ast::WithShortCircuiting {
+	class Finder final : public ast::WithShortCircuiting {
+		const ast::SymbolTable & symtab;
+	public:
+		static size_t traceId;
 		CandidateFinder & selfFinder;
-		const ast::SymbolTable & symtab;
 		CandidateList & candidates;
 		const ast::TypeEnvironment & tenv;
 		ast::ptr< ast::Type > & targetType;
 
+		enum Errors {
+			NotFound,
+			NoMatch,
+			ArgsToFew,
+			ArgsToMany,
+			RetsToFew,
+			RetsToMany,
+			NoReason
+		};
+
+		struct {
+			Errors code = NotFound;
+		} reason;
+
 		Finder( CandidateFinder & f )
-		: selfFinder( f ), symtab( f.symtab ), candidates( f.candidates ), tenv( f.env ), 
+		: symtab( f.localSyms ), selfFinder( f ), candidates( f.candidates ), tenv( f.env ),
 		  targetType( f.targetType ) {}
-		
+
 		void previsit( const ast::Node * ) { visit_children = false; }
 
@@ -611,4 +626,5 @@
 		void addCandidate( Args &&... args ) {
 			candidates.emplace_back( new Candidate{ std::forward<Args>( args )... } );
+			reason.code = NoReason;
 		}
 
@@ -639,9 +655,9 @@
 
 		/// Completes a function candidate with arguments located
-		void validateFunctionCandidate( 
-			const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results, 
-			CandidateList & out 
+		void validateFunctionCandidate(
+			const CandidateRef & func, ArgPack & result, const std::vector< ArgPack > & results,
+			CandidateList & out
 		) {
-			ast::ApplicationExpr * appExpr = 
+			ast::ApplicationExpr * appExpr =
 				new ast::ApplicationExpr{ func->expr->location, func->expr };
 			// sum cost and accumulate arguments
@@ -657,5 +673,5 @@
 			appExpr->args = move( vargs );
 			// build and validate new candidate
-			auto newCand = 
+			auto newCand =
 				std::make_shared<Candidate>( appExpr, result.env, result.open, result.need, cost );
 			PRINT(
@@ -669,5 +685,5 @@
 		/// Builds a list of candidates for a function, storing them in out
 		void makeFunctionCandidates(
-			const CandidateRef & func, const ast::FunctionType * funcType, 
+			const CandidateRef & func, const ast::FunctionType * funcType,
 			const ExplodedArgs_new & args, CandidateList & out
 		) {
@@ -676,6 +692,6 @@
 			ast::TypeEnvironment funcEnv{ func->env };
 			makeUnifiableVars( funcType, funcOpen, funcNeed );
-			// add all type variables as open variables now so that those not used in the parameter 
-			// list are still considered open
+			// add all type variables as open variables now so that those not used in the
+			// parameter list are still considered open
 			funcEnv.add( funcType->forall );
 
@@ -683,6 +699,6 @@
 				// attempt to narrow based on expected target type
 				const ast::Type * returnType = funcType->returns.front()->get_type();
-				if ( ! unify( 
-					returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab ) 
+				if ( ! unify(
+					returnType, targetType, funcEnv, funcNeed, funcHave, funcOpen, symtab )
 				) {
 					// unification failed, do not pursue this candidate
@@ -698,7 +714,7 @@
 			for ( const ast::DeclWithType * param : funcType->params ) {
 				auto obj = strict_dynamic_cast< const ast::ObjectDecl * >( param );
-				// Try adding the arguments corresponding to the current parameter to the existing 
+				// Try adding the arguments corresponding to the current parameter to the existing
 				// matches
-				if ( ! instantiateArgument( 
+				if ( ! instantiateArgument(
 					obj->type, obj->init, args, results, genStart, symtab ) ) return;
 			}
@@ -750,6 +766,6 @@
 							if ( expl.exprs.empty() ) {
 								results.emplace_back(
-									results[i], move( env ), copy( results[i].need ), 
-									copy( results[i].have ), move( open ), nextArg + 1, 
+									results[i], move( env ), copy( results[i].need ),
+									copy( results[i].have ), move( open ), nextArg + 1,
 									expl.cost );
 
@@ -760,5 +776,5 @@
 							results.emplace_back(
 								i, expl.exprs.front(), move( env ), copy( results[i].need ),
-								copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost, 
+								copy( results[i].have ), move( open ), nextArg + 1, 0, expl.cost,
 								expl.exprs.size() == 1 ? 0 : 1, j );
 						}
@@ -780,11 +796,11 @@
 		/// Adds implicit struct-conversions to the alternative list
 		void addAnonConversions( const CandidateRef & cand ) {
-			// adds anonymous member interpretations whenever an aggregate value type is seen. 
-			// it's okay for the aggregate expression to have reference type -- cast it to the 
+			// adds anonymous member interpretations whenever an aggregate value type is seen.
+			// it's okay for the aggregate expression to have reference type -- cast it to the
 			// base type to treat the aggregate as the referenced value
 			ast::ptr< ast::Expr > aggrExpr( cand->expr );
 			ast::ptr< ast::Type > & aggrType = aggrExpr.get_and_mutate()->result;
 			cand->env.apply( aggrType );
-			
+
 			if ( aggrType.as< ast::ReferenceType >() ) {
 				aggrExpr = new ast::CastExpr{ aggrExpr, aggrType->stripReferences() };
@@ -799,13 +815,13 @@
 
 		/// Adds aggregate member interpretations
-		void addAggMembers( 
-			const ast::ReferenceToType * aggrInst, const ast::Expr * expr, 
-			const Candidate & cand, const Cost & addedCost, const std::string & name 
+		void addAggMembers(
+			const ast::ReferenceToType * aggrInst, const ast::Expr * expr,
+			const Candidate & cand, const Cost & addedCost, const std::string & name
 		) {
 			for ( const ast::Decl * decl : aggrInst->lookup( name ) ) {
 				auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( decl );
-				CandidateRef newCand = std::make_shared<Candidate>( 
+				CandidateRef newCand = std::make_shared<Candidate>(
 					cand, new ast::MemberExpr{ expr->location, dwt, expr }, addedCost );
-				// add anonymous member interpretations whenever an aggregate value type is seen 
+				// add anonymous member interpretations whenever an aggregate value type is seen
 				// as a member expression
 				addAnonConversions( newCand );
@@ -815,15 +831,15 @@
 
 		/// Adds tuple member interpretations
-		void addTupleMembers( 
-			const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand, 
-			const Cost & addedCost, const ast::Expr * member 
+		void addTupleMembers(
+			const ast::TupleType * tupleType, const ast::Expr * expr, const Candidate & cand,
+			const Cost & addedCost, const ast::Expr * member
 		) {
 			if ( auto constantExpr = dynamic_cast< const ast::ConstantExpr * >( member ) ) {
-				// get the value of the constant expression as an int, must be between 0 and the 
+				// get the value of the constant expression as an int, must be between 0 and the
 				// length of the tuple to have meaning
 				long long val = constantExpr->intValue();
 				if ( val >= 0 && (unsigned long long)val < tupleType->size() ) {
 					addCandidate(
-						cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val }, 
+						cand, new ast::TupleIndexExpr{ expr->location, expr, (unsigned)val },
 						addedCost );
 				}
@@ -837,7 +853,9 @@
 			if ( funcFinder.candidates.empty() ) return;
 
-			std::vector< CandidateFinder > argCandidates = 
+			reason.code = NoMatch;
+
+			std::vector< CandidateFinder > argCandidates =
 				selfFinder.findSubExprs( untypedExpr->args );
-			
+
 			// take care of possible tuple assignments
 			// if not tuple assignment, handled as normal function call
@@ -877,15 +895,15 @@
 						if ( auto function = pointer->base.as< ast::FunctionType >() ) {
 							CandidateRef newFunc{ new Candidate{ *func } };
-							newFunc->expr = 
+							newFunc->expr =
 								referenceToRvalueConversion( newFunc->expr, newFunc->cost );
 							makeFunctionCandidates( newFunc, function, argExpansions, found );
 						}
-					} else if ( 
-						auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult ) 
+					} else if (
+						auto inst = dynamic_cast< const ast::TypeInstType * >( funcResult )
 					) {
 						if ( const ast::EqvClass * clz = func->env.lookup( inst->name ) ) {
 							if ( auto function = clz->bound.as< ast::FunctionType >() ) {
 								CandidateRef newFunc{ new Candidate{ *func } };
-								newFunc->expr = 
+								newFunc->expr =
 									referenceToRvalueConversion( newFunc->expr, newFunc->cost );
 								makeFunctionCandidates( newFunc, function, argExpansions, found );
@@ -901,5 +919,5 @@
 				std::vector< ExplodedArg > funcE;
 				funcE.reserve( funcFinder.candidates.size() );
-				for ( const CandidateRef & func : funcFinder ) { 
+				for ( const CandidateRef & func : funcFinder ) {
 					funcE.emplace_back( *func, symtab );
 				}
@@ -913,5 +931,5 @@
 							if ( auto function = pointer->base.as< ast::FunctionType >() ) {
 								CandidateRef newOp{ new Candidate{ *op} };
-								newOp->expr = 
+								newOp->expr =
 									referenceToRvalueConversion( newOp->expr, newOp->cost );
 								makeFunctionCandidates( newOp, function, argExpansions, found );
@@ -922,5 +940,5 @@
 			}
 
-			// Implement SFINAE; resolution errors are only errors if there aren't any non-error 
+			// Implement SFINAE; resolution errors are only errors if there aren't any non-error
 			// candidates
 			if ( found.empty() && ! errors.isEmpty() ) { throw errors; }
@@ -934,5 +952,5 @@
 					auto pointer = appExpr->func->result.strict_as< ast::PointerType >();
 					auto function = pointer->base.strict_as< ast::FunctionType >();
-					
+
 					std::cerr << "Case +++++++++++++ " << appExpr->func << std::endl;
 					std::cerr << "parameters are:" << std::endl;
@@ -957,6 +975,6 @@
 			promoteCvtCost( winners );
 
-			// function may return a struct/union value, in which case we need to add candidates 
-			// for implicit conversions to each of the anonymous members, which must happen after 
+			// function may return a struct/union value, in which case we need to add candidates
+			// for implicit conversions to each of the anonymous members, which must happen after
 			// `findMinCost`, since anon conversions are never the cheapest
 			for ( const CandidateRef & c : winners ) {
@@ -966,5 +984,5 @@
 
 			if ( candidates.empty() && targetType && ! targetType->isVoid() ) {
-				// If resolution is unsuccessful with a target type, try again without, since it 
+				// If resolution is unsuccessful with a target type, try again without, since it
 				// will sometimes succeed when it wouldn't with a target type binding.
 				// For example:
@@ -983,5 +1001,5 @@
 		/// true if expression is an lvalue
 		static bool isLvalue( const ast::Expr * x ) {
-			return x->result && ( x->result->is_lvalue() || x->result.as< ast::ReferenceType >() );
+			return x->result && ( x->get_lvalue() || x->result.as< ast::ReferenceType >() );
 		}
 
@@ -989,4 +1007,9 @@
 			CandidateFinder finder{ symtab, tenv };
 			finder.find( addressExpr->arg );
+
+			if( finder.candidates.empty() ) return;
+
+			reason.code = NoMatch;
+
 			for ( CandidateRef & r : finder.candidates ) {
 				if ( ! isLvalue( r->expr ) ) continue;
@@ -1009,4 +1032,6 @@
 			finder.find( castExpr->arg, ResolvMode::withAdjustment() );
 
+			if( !finder.candidates.empty() ) reason.code = NoMatch;
+
 			CandidateList matches;
 			for ( CandidateRef & cand : finder.candidates ) {
@@ -1016,7 +1041,7 @@
 				cand->env.extractOpenVars( open );
 
-				// It is possible that a cast can throw away some values in a multiply-valued 
-				// expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the 
-				// subexpression results that are cast directly. The candidate is invalid if it 
+				// It is possible that a cast can throw away some values in a multiply-valued
+				// expression, e.g. cast-to-void, one value to zero. Figure out the prefix of the
+				// subexpression results that are cast directly. The candidate is invalid if it
 				// has fewer results than there are types to cast to.
 				int discardedValues = cand->expr->result->size() - toType->size();
@@ -1025,5 +1050,6 @@
 				// unification run for side-effects
 				unify( toType, cand->expr->result, cand->env, need, have, open, symtab );
-				Cost thisCost = castCost( cand->expr->result, toType, symtab, cand->env );
+				Cost thisCost = castCost( cand->expr->result, toType, cand->expr->get_lvalue(),
+						symtab, cand->env );
 				PRINT(
 					std::cerr << "working on cast with result: " << toType << std::endl;
@@ -1037,7 +1063,7 @@
 					// count one safe conversion for each value that is thrown away
 					thisCost.incSafe( discardedValues );
-					CandidateRef newCand = std::make_shared<Candidate>( 
-						restructureCast( cand->expr, toType, castExpr->isGenerated ), 
-						copy( cand->env ), move( open ), move( need ), cand->cost, 
+					CandidateRef newCand = std::make_shared<Candidate>(
+						restructureCast( cand->expr, toType, castExpr->isGenerated ),
+						copy( cand->env ), move( open ), move( need ), cand->cost,
 						cand->cost + thisCost );
 					inferParameters( newCand, matches );
@@ -1057,6 +1083,6 @@
 			finder.find( castExpr->arg, ResolvMode::withoutPrune() );
 			for ( CandidateRef & r : finder.candidates ) {
-				addCandidate( 
-					*r, 
+				addCandidate(
+					*r,
 					new ast::VirtualCastExpr{ castExpr->location, r->expr, castExpr->result } );
 			}
@@ -1067,5 +1093,5 @@
 			aggFinder.find( memberExpr->aggregate, ResolvMode::withAdjustment() );
 			for ( CandidateRef & agg : aggFinder.candidates ) {
-				// it's okay for the aggregate expression to have reference type -- cast it to the 
+				// it's okay for the aggregate expression to have reference type -- cast it to the
 				// base type to treat the aggregate as the referenced value
 				Cost addedCost = Cost::zero;
@@ -1074,8 +1100,8 @@
 				// find member of the given type
 				if ( auto structInst = agg->expr->result.as< ast::StructInstType >() ) {
-					addAggMembers( 
+					addAggMembers(
 						structInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
 				} else if ( auto unionInst = agg->expr->result.as< ast::UnionInstType >() ) {
-					addAggMembers( 
+					addAggMembers(
 						unionInst, agg->expr, *agg, addedCost, getMemberName( memberExpr ) );
 				} else if ( auto tupleType = agg->expr->result.as< ast::TupleType >() ) {
@@ -1092,4 +1118,8 @@
 			std::vector< ast::SymbolTable::IdData > declList = symtab.lookupId( nameExpr->name );
 			PRINT( std::cerr << "nameExpr is " << nameExpr->name << std::endl; )
+			if( declList.empty() ) return;
+
+			reason.code = NoMatch;
+
 			for ( auto & data : declList ) {
 				Cost cost = Cost::zero;
@@ -1097,5 +1127,5 @@
 
 				CandidateRef newCand = std::make_shared<Candidate>(
-					newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero, 
+					newExpr, copy( tenv ), ast::OpenVarSet{}, ast::AssertionSet{}, Cost::zero,
 					cost );
 				PRINT(
@@ -1107,8 +1137,8 @@
 					std::cerr << std::endl;
 				)
-				newCand->expr = ast::mutate_field( 
-					newCand->expr.get(), &ast::Expr::result, 
+				newCand->expr = ast::mutate_field(
+					newCand->expr.get(), &ast::Expr::result,
 					renameTyVars( newCand->expr->result ) );
-				// add anonymous member interpretations whenever an aggregate value type is seen 
+				// add anonymous member interpretations whenever an aggregate value type is seen
 				// as a name expression
 				addAnonConversions( newCand );
@@ -1120,5 +1150,5 @@
 			// not sufficient to just pass `variableExpr` here, type might have changed since
 			// creation
-			addCandidate( 
+			addCandidate(
 				new ast::VariableExpr{ variableExpr->location, variableExpr->var }, tenv );
 		}
@@ -1130,7 +1160,7 @@
 		void postvisit( const ast::SizeofExpr * sizeofExpr ) {
 			if ( sizeofExpr->type ) {
-				addCandidate( 
-					new ast::SizeofExpr{ 
-						sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) }, 
+				addCandidate(
+					new ast::SizeofExpr{
+						sizeofExpr->location, resolveTypeof( sizeofExpr->type, symtab ) },
 					tenv );
 			} else {
@@ -1141,5 +1171,5 @@
 				CandidateList winners = findMinCost( finder.candidates );
 				if ( winners.size() != 1 ) {
-					SemanticError( 
+					SemanticError(
 						sizeofExpr->expr.get(), "Ambiguous expression in sizeof operand: " );
 				}
@@ -1154,7 +1184,7 @@
 		void postvisit( const ast::AlignofExpr * alignofExpr ) {
 			if ( alignofExpr->type ) {
-				addCandidate( 
-					new ast::AlignofExpr{ 
-						alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) }, 
+				addCandidate(
+					new ast::AlignofExpr{
+						alignofExpr->location, resolveTypeof( alignofExpr->type, symtab ) },
 					tenv );
 			} else {
@@ -1165,5 +1195,5 @@
 				CandidateList winners = findMinCost( finder.candidates );
 				if ( winners.size() != 1 ) {
-					SemanticError( 
+					SemanticError(
 						alignofExpr->expr.get(), "Ambiguous expression in alignof operand: " );
 				}
@@ -1172,5 +1202,5 @@
 				choice->expr = referenceToRvalueConversion( choice->expr, choice->cost );
 				choice->cost = Cost::zero;
-				addCandidate( 
+				addCandidate(
 					*choice, new ast::AlignofExpr{ alignofExpr->location, choice->expr } );
 			}
@@ -1185,5 +1215,5 @@
 			for ( const ast::Decl * member : aggInst->lookup( offsetofExpr->member ) ) {
 				auto dwt = strict_dynamic_cast< const ast::DeclWithType * >( member );
-				addCandidate( 
+				addCandidate(
 					new ast::OffsetofExpr{ offsetofExpr->location, aggInst, dwt }, tenv );
 			}
@@ -1206,4 +1236,6 @@
 			finder2.find( logicalExpr->arg2, ResolvMode::withAdjustment() );
 			if ( finder2.candidates.empty() ) return;
+
+			reason.code = NoMatch;
 
 			for ( const CandidateRef & r1 : finder1.candidates ) {
@@ -1218,5 +1250,5 @@
 
 					addCandidate(
-						new ast::LogicalExpr{ 
+						new ast::LogicalExpr{
 							logicalExpr->location, r1->expr, r2->expr, logicalExpr->isAnd },
 						move( env ), move( open ), move( need ), r1->cost + r2->cost );
@@ -1240,4 +1272,6 @@
 			finder3.find( conditionalExpr->arg3, ResolvMode::withAdjustment() );
 			if ( finder3.candidates.empty() ) return;
+
+			reason.code = NoMatch;
 
 			for ( const CandidateRef & r1 : finder1.candidates ) {
@@ -1256,19 +1290,19 @@
 						ast::AssertionSet have;
 
-						// unify true and false results, then infer parameters to produce new 
+						// unify true and false results, then infer parameters to produce new
 						// candidates
 						ast::ptr< ast::Type > common;
-						if ( 
-							unify( 
-								r2->expr->result, r3->expr->result, env, need, have, open, symtab, 
-								common ) 
+						if (
+							unify(
+								r2->expr->result, r3->expr->result, env, need, have, open, symtab,
+								common )
 						) {
 							// generate typed expression
-							ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{ 
+							ast::ConditionalExpr * newExpr = new ast::ConditionalExpr{
 								conditionalExpr->location, r1->expr, r2->expr, r3->expr };
 							newExpr->result = common ? common : r2->expr->result;
 							// convert both options to result type
 							Cost cost = r1->cost + r2->cost + r3->cost;
-							newExpr->arg2 = computeExpressionConversionCost( 
+							newExpr->arg2 = computeExpressionConversionCost(
 								newExpr->arg2, newExpr->result, symtab, env, cost );
 							newExpr->arg3 = computeExpressionConversionCost(
@@ -1287,5 +1321,5 @@
 			ast::TypeEnvironment env{ tenv };
 			ast::ptr< ast::Expr > arg1 = resolveInVoidContext( commaExpr->arg1, symtab, env );
-			
+
 			CandidateFinder finder2{ symtab, env };
 			finder2.find( commaExpr->arg2, ResolvMode::withAdjustment() );
@@ -1317,4 +1351,6 @@
 			finder2.find( rangeExpr->high, ResolvMode::withAdjustment() );
 			if ( finder2.candidates.empty() ) return;
+
+			reason.code = NoMatch;
 
 			for ( const CandidateRef & r1 : finder1.candidates ) {
@@ -1330,16 +1366,16 @@
 
 					ast::ptr< ast::Type > common;
-					if ( 
-						unify( 
-							r1->expr->result, r2->expr->result, env, need, have, open, symtab, 
-							common ) 
+					if (
+						unify(
+							r1->expr->result, r2->expr->result, env, need, have, open, symtab,
+							common )
 					) {
 						// generate new expression
-						ast::RangeExpr * newExpr = 
+						ast::RangeExpr * newExpr =
 							new ast::RangeExpr{ rangeExpr->location, r1->expr, r2->expr };
 						newExpr->result = common ? common : r1->expr->result;
 						// add candidate
 						CandidateRef newCand = std::make_shared<Candidate>(
-							newExpr, move( env ), move( open ), move( need ), 
+							newExpr, move( env ), move( open ), move( need ),
 							r1->cost + r2->cost );
 						inferParameters( newCand, candidates );
@@ -1350,5 +1386,5 @@
 
 		void postvisit( const ast::UntypedTupleExpr * tupleExpr ) {
-			std::vector< CandidateFinder > subCandidates = 
+			std::vector< CandidateFinder > subCandidates =
 				selfFinder.findSubExprs( tupleExpr->exprs );
 			std::vector< CandidateList > possibilities;
@@ -1370,5 +1406,5 @@
 
 				addCandidate(
-					new ast::TupleExpr{ tupleExpr->location, move( exprs ) }, 
+					new ast::TupleExpr{ tupleExpr->location, move( exprs ) },
 					move( env ), move( open ), move( need ), sumCost( subs ) );
 			}
@@ -1412,10 +1448,12 @@
 				toType = SymTab::validateType( initExpr->location, toType, symtab );
 				toType = adjustExprType( toType, tenv, symtab );
-				// The call to find must occur inside this loop, otherwise polymorphic return 
-				// types are not bound to the initialization type, since return type variables are 
-				// only open for the duration of resolving the UntypedExpr. 
+				// The call to find must occur inside this loop, otherwise polymorphic return
+				// types are not bound to the initialization type, since return type variables are
+				// only open for the duration of resolving the UntypedExpr.
 				CandidateFinder finder{ symtab, tenv, toType };
 				finder.find( initExpr->expr, ResolvMode::withAdjustment() );
 				for ( CandidateRef & cand : finder.candidates ) {
+					if(reason.code == NotFound) reason.code = NoMatch;
+
 					ast::TypeEnvironment env{ cand->env };
 					ast::AssertionSet need( cand->need.begin(), cand->need.end() ), have;
@@ -1426,7 +1464,7 @@
 					)
 
-					// It is possible that a cast can throw away some values in a multiply-valued 
-					// expression, e.g. cast-to-void, one value to zero. Figure out the prefix of 
-					// the subexpression results that are cast directly. The candidate is invalid 
+					// It is possible that a cast can throw away some values in a multiply-valued
+					// expression, e.g. cast-to-void, one value to zero. Figure out the prefix of
+					// the subexpression results that are cast directly. The candidate is invalid
 					// if it has fewer results than there are types to cast to.
 					int discardedValues = cand->expr->result->size() - toType->size();
@@ -1435,14 +1473,15 @@
 					// unification run for side-effects
 					unify( toType, cand->expr->result, env, need, have, open, symtab );
-					Cost thisCost = castCost( cand->expr->result, toType, symtab, env );
-					
+					Cost thisCost = computeConversionCost( cand->expr->result, toType, cand->expr->get_lvalue(),
+							symtab, env );
+
 					if ( thisCost != Cost::infinity ) {
 						// count one safe conversion for each value that is thrown away
 						thisCost.incSafe( discardedValues );
-						CandidateRef newCand = std::make_shared<Candidate>( 
-							new ast::InitExpr{ 
-								initExpr->location, restructureCast( cand->expr, toType ), 
-								initAlt.designation }, 
-							copy( cand->env ), move( open ), move( need ), cand->cost, thisCost );
+						CandidateRef newCand = std::make_shared<Candidate>(
+							new ast::InitExpr{
+								initExpr->location, restructureCast( cand->expr, toType ),
+								initAlt.designation },
+							move(env), move( open ), move( need ), cand->cost, thisCost );
 						inferParameters( newCand, matches );
 					}
@@ -1469,5 +1508,6 @@
 	};
 
-	/// Prunes a list of candidates down to those that have the minimum conversion cost for a given 
+	// size_t Finder::traceId = Stats::Heap::new_stacktrace_id("Finder");
+	/// Prunes a list of candidates down to those that have the minimum conversion cost for a given
 	/// return type. Skips ambiguous candidates.
 	CandidateList pruneCandidates( CandidateList & candidates ) {
@@ -1486,4 +1526,5 @@
 			{
 				ast::ptr< ast::Type > newType = candidate->expr->result;
+				assertf(candidate->expr->result, "Result of expression %p for candidate is null", candidate->expr.get());
 				candidate->env.apply( newType );
 				mangleName = Mangle::mangle( newType );
@@ -1494,5 +1535,5 @@
 				if ( candidate->cost < found->second.candidate->cost ) {
 					PRINT(
-						std::cerr << "cost " << candidate->cost << " beats " 
+						std::cerr << "cost " << candidate->cost << " beats "
 							<< found->second.candidate->cost << std::endl;
 					)
@@ -1500,6 +1541,6 @@
 					found->second = PruneStruct{ candidate };
 				} else if ( candidate->cost == found->second.candidate->cost ) {
-					// if one of the candidates contains a deleted identifier, can pick the other, 
-					// since deleted expressions should not be ambiguous if there is another option 
+					// if one of the candidates contains a deleted identifier, can pick the other,
+					// since deleted expressions should not be ambiguous if there is another option
 					// that is at least as good
 					if ( findDeletedExpr( candidate->expr ) ) {
@@ -1515,5 +1556,5 @@
 				} else {
 					PRINT(
-						std::cerr << "cost " << candidate->cost << " loses to " 
+						std::cerr << "cost " << candidate->cost << " loses to "
 							<< found->second.candidate->cost << std::endl;
 					)
@@ -1530,10 +1571,10 @@
 
 			CandidateRef cand = target.second.candidate;
-			
+
 			ast::ptr< ast::Type > newResult = cand->expr->result;
 			cand->env.applyFree( newResult );
 			cand->expr = ast::mutate_field(
 				cand->expr.get(), &ast::Expr::result, move( newResult ) );
-			
+
 			out.emplace_back( cand );
 		}
@@ -1549,5 +1590,17 @@
 
 	if ( mode.failFast && candidates.empty() ) {
-		SemanticError( expr, "No reasonable alternatives for expression " );
+		switch(finder.core.reason.code) {
+		case Finder::NotFound:
+			{ SemanticError( expr, "No alternatives for expression " ); break; }
+		case Finder::NoMatch:
+			{ SemanticError( expr, "Invalid application of existing declaration(s) in expression " ); break; }
+		case Finder::ArgsToFew:
+		case Finder::ArgsToMany:
+		case Finder::RetsToFew:
+		case Finder::RetsToMany:
+		case Finder::NoReason:
+		default:
+			{ SemanticError( expr->location, "No reasonable alternatives for expression : reasons unkown" ); }
+		}
 	}
 
@@ -1558,5 +1611,5 @@
 		std::vector< std::string > errors;
 		for ( CandidateRef & candidate : candidates ) {
-			satisfyAssertions( candidate, symtab, satisfied, errors );
+			satisfyAssertions( candidate, localSyms, satisfied, errors );
 		}
 
@@ -1583,5 +1636,5 @@
 
 		CandidateList pruned = pruneCandidates( candidates );
-		
+
 		if ( mode.failFast && pruned.empty() ) {
 			std::ostringstream stream;
@@ -1602,16 +1655,16 @@
 		)
 		PRINT(
-			std::cerr << "there are " << candidates.size() << " alternatives after elimination" 
+			std::cerr << "there are " << candidates.size() << " alternatives after elimination"
 				<< std::endl;
 		)
 	}
 
-	// adjust types after pruning so that types substituted by pruneAlternatives are correctly 
+	// adjust types after pruning so that types substituted by pruneAlternatives are correctly
 	// adjusted
 	if ( mode.adjust ) {
 		for ( CandidateRef & r : candidates ) {
-			r->expr = ast::mutate_field( 
-				r->expr.get(), &ast::Expr::result, 
-				adjustExprType( r->expr->result, r->env, symtab ) );
+			r->expr = ast::mutate_field(
+				r->expr.get(), &ast::Expr::result,
+				adjustExprType( r->expr->result, r->env, localSyms ) );
 		}
 	}
@@ -1625,13 +1678,13 @@
 }
 
-std::vector< CandidateFinder > CandidateFinder::findSubExprs( 
-	const std::vector< ast::ptr< ast::Expr > > & xs 
+std::vector< CandidateFinder > CandidateFinder::findSubExprs(
+	const std::vector< ast::ptr< ast::Expr > > & xs
 ) {
 	std::vector< CandidateFinder > out;
 
 	for ( const auto & x : xs ) {
-		out.emplace_back( symtab, env );
+		out.emplace_back( localSyms, env );
 		out.back().find( x, ResolvMode::withAdjustment() );
-		
+
 		PRINT(
 			std::cerr << "findSubExprs" << std::endl;
Index: src/ResolvExpr/CandidateFinder.hpp
===================================================================
--- src/ResolvExpr/CandidateFinder.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/CandidateFinder.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Wed Jun 5 14:30:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Wed Jun 5 14:30:00 2019
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Oct  1  9:51:00 2019
+// Update Count     : 2
 //
 
@@ -28,12 +28,12 @@
 struct CandidateFinder {
 	CandidateList candidates;          ///< List of candidate resolutions
-	const ast::SymbolTable & symtab;   ///< Symbol table to lookup candidates
+	const ast::SymbolTable & localSyms;   ///< Symbol table to lookup candidates
 	const ast::TypeEnvironment & env;  ///< Substitutions performed in this resolution
 	ast::ptr< ast::Type > targetType;  ///< Target type for resolution
 
-	CandidateFinder( 
-		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env, 
+	CandidateFinder(
+		const ast::SymbolTable & syms, const ast::TypeEnvironment & env,
 		const ast::Type * tt = nullptr )
-	: candidates(), symtab( symtab ), env( env ), targetType( tt ) {}
+	: candidates(), localSyms( syms ), env( env ), targetType( tt ) {}
 
 	/// Fill candidates with feasible resolutions for `expr`
@@ -49,5 +49,5 @@
 	iterator begin() { return candidates.begin(); }
 	const_iterator begin() const { return candidates.begin(); }
-	
+
 	iterator end() { return candidates.end(); }
 	const_iterator end() const { return candidates.end(); }
@@ -55,7 +55,7 @@
 
 /// Computes conversion cost between two types
-Cost computeConversionCost( 
-	const ast::Type * argType, const ast::Type * paramType, const ast::SymbolTable & symtab, 
-	const ast::TypeEnvironment & env );
+Cost computeConversionCost(
+	const ast::Type * argType, const ast::Type * paramType, bool argIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/CastCost.cc
===================================================================
--- src/ResolvExpr/CastCost.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/CastCost.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 06:57:43 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Aug  8 16:12:00 2019
-// Update Count     : 8
+// Last Modified On : Tue Oct  4 15:00:00 2019
+// Update Count     : 9
 //
 
@@ -142,7 +142,7 @@
 
 		CastCost_new(
-			const ast::Type * dst, const ast::SymbolTable & symtab,
+			const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
 			const ast::TypeEnvironment & env, CostCalculation costFunc )
-		: ConversionCost_new( dst, symtab, env, costFunc ) {}
+		: ConversionCost_new( dst, srcIsLvalue, symtab, env, costFunc ) {}
 
 		void postvisit( const ast::BasicType * basicType ) {
@@ -152,5 +152,5 @@
 				cost = Cost::unsafe;
 			} else {
-				cost = conversionCost( basicType, dst, symtab, env );
+				cost = conversionCost( basicType, dst, srcIsLvalue, symtab, env );
 			}
 		}
@@ -183,9 +183,21 @@
 		}
 	};
+
+	#warning For overload resolution between the two versions.
+	int localPtrsCastable(const ast::Type * t1, const ast::Type * t2,
+			const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) {
+		return ptrsCastable( t1, t2, symtab, env );
+	}
+	Cost localCastCost(
+		const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+	) { return castCost( src, dst, srcIsLvalue, symtab, env ); }
 } // anonymous namespace
 
+
+
 Cost castCost(
-	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-	const ast::TypeEnvironment & env
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
 ) {
 	if ( auto typeInst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
@@ -193,5 +205,5 @@
 			// check cast cost against bound type, if present
 			if ( eqvClass->bound ) {
-				return castCost( src, eqvClass->bound, symtab, env );
+				return castCost( src, eqvClass->bound, srcIsLvalue, symtab, env );
 			} else {
 				return Cost::infinity;
@@ -201,5 +213,5 @@
 			auto type = strict_dynamic_cast< const ast::TypeDecl * >( named );
 			if ( type->base ) {
-				return castCost( src, type->base, symtab, env ) + Cost::safe;
+				return castCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
 			}
 		}
@@ -224,19 +236,11 @@
 		#warning cast on ptrsCastable artifact of having two functions, remove when port done
 		return convertToReferenceCost(
-			src, refType, symtab, env,
-			( int (*)(
-				const ast::Type *, const ast::Type *, const ast::SymbolTable &,
-				const ast::TypeEnvironment & )
-			) ptrsCastable );
+			src, refType, srcIsLvalue, symtab, env, localPtrsCastable );
 	} else {
 		#warning cast on castCost artifact of having two functions, remove when port done
-		ast::Pass< CastCost_new > converter{
-			dst, symtab, env,
-			( Cost (*)(
-				const ast::Type *, const ast::Type *, const ast::SymbolTable &,
-				const ast::TypeEnvironment & )
-			) castCost };
+		ast::Pass< CastCost_new > converter(
+			dst, srcIsLvalue, symtab, env, localCastCost );
 		src->accept( converter );
-		return converter.pass.cost;
+		return converter.core.cost;
 	}
 }
Index: src/ResolvExpr/CommonType.cc
===================================================================
--- src/ResolvExpr/CommonType.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/CommonType.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -666,4 +666,5 @@
 		const ast::OpenVarSet & open;
 	public:
+		static size_t traceId;
 		ast::ptr< ast::Type > result;
 
@@ -893,4 +894,5 @@
 	};
 
+	// size_t CommonType_new::traceId = Stats::Heap::new_stacktrace_id("CommonType_new");
 	namespace {
 		ast::ptr< ast::Type > handleReference(
@@ -939,5 +941,5 @@
 			ast::ptr< ast::Type > result;
 			const ast::ReferenceType * ref1 = type1.as< ast::ReferenceType >();
-			const ast::ReferenceType * ref2 = type1.as< ast::ReferenceType >();
+			const ast::ReferenceType * ref2 = type2.as< ast::ReferenceType >();
 
 			if ( depth1 > depth2 ) {
@@ -966,5 +968,5 @@
 		ast::Pass<CommonType_new> visitor{ type2, widen, symtab, env, open };
 		type1->accept( visitor );
-		ast::ptr< ast::Type > result = visitor.pass.result;
+		ast::ptr< ast::Type > result = visitor.core.result;
 
 		// handling for opaque type declarations (?)
Index: src/ResolvExpr/ConversionCost.cc
===================================================================
--- src/ResolvExpr/ConversionCost.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/ConversionCost.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -481,24 +481,24 @@
 	}
 
-static int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
-		const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
-	return ptrsAssignable( t1, t2, env );
-}
-
-// TODO: This is used for overload resolution. It might be able to be dropped once the old system
-// is removed.
-static Cost localConversionCost(
-	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-	const ast::TypeEnvironment & env
-) { return conversionCost( src, dst, symtab, env ); }
+namespace {
+	# warning For overload resolution between the two versions.
+	int localPtrsAssignable(const ast::Type * t1, const ast::Type * t2,
+			const ast::SymbolTable &, const ast::TypeEnvironment & env ) {
+		return ptrsAssignable( t1, t2, env );
+	}
+	Cost localConversionCost(
+		const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
+	) { return conversionCost( src, dst, srcIsLvalue, symtab, env ); }
+}
 
 Cost conversionCost(
-	const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-	const ast::TypeEnvironment & env
+	const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+	const ast::SymbolTable & symtab, const ast::TypeEnvironment & env
 ) {
 	if ( const ast::TypeInstType * inst = dynamic_cast< const ast::TypeInstType * >( dst ) ) {
 		if ( const ast::EqvClass * eqv = env.lookup( inst->name ) ) {
 			if ( eqv->bound ) {
-				return conversionCost(src, eqv->bound, symtab, env );
+				return conversionCost(src, eqv->bound, srcIsLvalue, symtab, env );
 			} else {
 				return Cost::infinity;
@@ -508,5 +508,5 @@
 			assertf( type, "Unexpected typedef." );
 			if ( type->base ) {
-				return conversionCost( src, type->base, symtab, env ) + Cost::safe;
+				return conversionCost( src, type->base, srcIsLvalue, symtab, env ) + Cost::safe;
 			}
 		}
@@ -518,19 +518,19 @@
 	} else if ( const ast::ReferenceType * refType =
 			 dynamic_cast< const ast::ReferenceType * >( dst ) ) {
-		return convertToReferenceCost( src, refType, symtab, env, localPtrsAssignable );
+		return convertToReferenceCost( src, refType, srcIsLvalue, symtab, env, localPtrsAssignable );
 	} else {
-		ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
+		ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
 		src->accept( converter );
-		return converter.pass.cost;
-	}
-}
-
-static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst,
+		return converter.core.cost;
+	}
+}
+
+static Cost convertToReferenceCost( const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
 		int diff, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
-		NumCostCalculation func ) {
+		PtrsCalculation func ) {
 	if ( 0 < diff ) {
 		Cost cost = convertToReferenceCost(
-			strict_dynamic_cast< const ast::ReferenceType * >( src )->base,
-			dst, (diff - 1), symtab, env, func );
+			strict_dynamic_cast< const ast::ReferenceType * >( src )->base, dst,
+			srcIsLvalue, (diff - 1), symtab, env, func );
 		cost.incReference();
 		return cost;
@@ -538,5 +538,5 @@
 		Cost cost = convertToReferenceCost(
 			src, strict_dynamic_cast< const ast::ReferenceType * >( dst )->base,
-			(diff + 1), symtab, env, func );
+			srcIsLvalue, (diff + 1), symtab, env, func );
 		cost.incReference();
 		return cost;
@@ -563,7 +563,7 @@
 			}
 		} else {
-			ast::Pass<ConversionCost_new> converter( dst, symtab, env, localConversionCost );
+			ast::Pass<ConversionCost_new> converter( dst, srcIsLvalue, symtab, env, localConversionCost );
 			src->accept( converter );
-			return converter.pass.cost;
+			return converter.core.cost;
 		}
 	} else {
@@ -572,5 +572,5 @@
 		assert( dstAsRef );
 		if ( typesCompatibleIgnoreQualifiers( src, dstAsRef->base, symtab, env ) ) {
-			if ( src->is_lvalue() ) {
+			if ( srcIsLvalue ) {
 				if ( src->qualifiers == dstAsRef->base->qualifiers ) {
 					return Cost::reference;
@@ -591,8 +591,8 @@
 
 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dst,
-	    const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
-		NumCostCalculation func ) {
+		bool srcIsLvalue, const ast::SymbolTable & symtab, const ast::TypeEnvironment & env,
+		PtrsCalculation func ) {
 	int sdepth = src->referenceDepth(), ddepth = dst->referenceDepth();
-	return convertToReferenceCost( src, dst, sdepth - ddepth, symtab, env, func );
+	return convertToReferenceCost( src, dst, srcIsLvalue, sdepth - ddepth, symtab, env, func );
 }
 
@@ -651,5 +651,5 @@
 	assert( nullptr == dynamic_cast< const ast::ReferenceType * >( dst ) );
 
-	cost = costCalc( refType->base, dst, symtab, env );
+	cost = costCalc( refType->base, dst, srcIsLvalue, symtab, env );
 	if ( refType->base->qualifiers == dst->qualifiers ) {
 		cost.incReference();
@@ -667,6 +667,6 @@
 void ConversionCost_new::postvisit( const ast::EnumInstType * enumInstType ) {
 	(void)enumInstType;
-	static const ast::BasicType integer( ast::BasicType::SignedInt );
-	cost = costCalc( &integer, dst, symtab, env );
+	static ast::ptr<ast::BasicType> integer = { new ast::BasicType( ast::BasicType::SignedInt ) };
+	cost = costCalc( integer, dst, srcIsLvalue, symtab, env );
 	if ( cost < Cost::unsafe ) {
 		cost.incSafe();
@@ -680,5 +680,5 @@
 void ConversionCost_new::postvisit( const ast::TypeInstType * typeInstType ) {
 	if ( const ast::EqvClass * eqv = env.lookup( typeInstType->name ) ) {
-		cost = costCalc( eqv->bound, dst, symtab, env );
+		cost = costCalc( eqv->bound, dst, srcIsLvalue, symtab, env );
 	} else if ( const ast::TypeInstType * dstAsInst =
 			dynamic_cast< const ast::TypeInstType * >( dst ) ) {
@@ -690,5 +690,5 @@
 		assertf( type, "Unexpected typedef.");
 		if ( type->base ) {
-			cost = costCalc( type->base, dst, symtab, env ) + Cost::safe;
+			cost = costCalc( type->base, dst, srcIsLvalue, symtab, env ) + Cost::safe;
 		}
 	}
@@ -703,5 +703,5 @@
 		auto dstEnd = dstAsTuple->types.end();
 		while ( srcIt != srcEnd && dstIt != dstEnd ) {
-			Cost newCost = costCalc( * srcIt++, * dstIt++, symtab, env );
+			Cost newCost = costCalc( * srcIt++, * dstIt++, srcIsLvalue, symtab, env );
 			if ( newCost == Cost::infinity ) {
 				return;
@@ -738,4 +738,8 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
+	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
+		cost = Cost::zero;
+		// +1 for zero_t ->, +1 for disambiguation
+		cost.incSafe( maxIntCost + 2 );
 	}
 }
@@ -755,10 +759,7 @@
 			cost.incSign( signMatrix[ ast::BasicType::SignedInt ][ dstAsBasic->kind ] );
 		}
-	} else if ( dynamic_cast< const ast::PointerType * >( dst ) ) {
-		cost = Cost::zero;
-		cost.incSafe( maxIntCost + 2 );
-	}
-}
-
+	}
+}
+// size_t ConversionCost_new::traceId = Stats::Heap::new_stacktrace_id("ConversionCost");
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/ConversionCost.h
===================================================================
--- src/ResolvExpr/ConversionCost.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/ConversionCost.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -72,7 +72,7 @@
 
 // Some function pointer types, differ in return type.
-using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *,
+using CostCalculation = std::function<Cost(const ast::Type *, const ast::Type *, bool,
 	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
-using NumCostCalculation = std::function<int(const ast::Type *, const ast::Type *,
+using PtrsCalculation = std::function<int(const ast::Type *, const ast::Type *,
 	const ast::SymbolTable &, const ast::TypeEnvironment &)>;
 
@@ -81,13 +81,16 @@
 protected:
 	const ast::Type * dst;
+	bool srcIsLvalue;
 	const ast::SymbolTable & symtab;
 	const ast::TypeEnvironment & env;
 	CostCalculation costCalc;
 public:
+	static size_t traceId;
 	Cost cost;
 
-	ConversionCost_new( const ast::Type * dst, const ast::SymbolTable & symtab,
+	ConversionCost_new( const ast::Type * dst, bool srcIsLvalue, const ast::SymbolTable & symtab,
 			const ast::TypeEnvironment & env, CostCalculation costCalc ) :
-		dst( dst ), symtab( symtab ), env( env ), costCalc( costCalc ), cost( Cost::infinity )
+		dst( dst ), srcIsLvalue( srcIsLvalue ), symtab( symtab ), env( env ),
+		costCalc( costCalc ), cost( Cost::infinity )
 	{}
 
@@ -110,5 +113,6 @@
 
 Cost convertToReferenceCost( const ast::Type * src, const ast::ReferenceType * dest,
-	const ast::SymbolTable & indexer, const ast::TypeEnvironment & env, NumCostCalculation func );
+	bool srcIsLvalue, const ast::SymbolTable & indexer, const ast::TypeEnvironment & env,
+	PtrsCalculation func );
 
 } // namespace ResolvExpr
Index: src/ResolvExpr/CurrentObject.cc
===================================================================
--- src/ResolvExpr/CurrentObject.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/CurrentObject.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -21,8 +21,10 @@
 #include <string>                      // for string, operator<<, allocator
 
+#include "AST/Copy.hpp"                // for shallowCopy
 #include "AST/Expr.hpp"                // for InitAlternative
 #include "AST/GenericSubstitution.hpp" // for genericSubstitution
 #include "AST/Init.hpp"                // for Designation
 #include "AST/Node.hpp"                // for readonly
+#include "AST/Print.hpp"                // for readonly
 #include "AST/Type.hpp"
 #include "Common/Indenter.h"           // for Indenter, operator<<
@@ -596,6 +598,6 @@
 		SimpleIterator( const CodeLocation & loc, const Type * t ) : location( loc ), type( t ) {}
 
-		void setPosition( 
-			std::deque< ptr< Expr > >::const_iterator begin, 
+		void setPosition(
+			std::deque< ptr< Expr > >::const_iterator begin,
 			std::deque< ptr< Expr > >::const_iterator end
 		) override {
@@ -637,5 +639,5 @@
 			auto res = eval(expr);
 			if ( ! res.second ) {
-				SemanticError( location, 
+				SemanticError( location,
 					toString("Array designator must be a constant expression: ", expr ) );
 			}
@@ -644,5 +646,5 @@
 
 	public:
-		ArrayIterator( const CodeLocation & loc, const ArrayType * at ) 
+		ArrayIterator( const CodeLocation & loc, const ArrayType * at )
 		: location( loc ), array( at ), base( at->base ) {
 			PRINT( std::cerr << "Creating array iterator: " << at << std::endl; )
@@ -655,6 +657,6 @@
 
 		void setPosition( const Expr * expr ) {
-			// need to permit integer-constant-expressions, including: integer constants, 
-			// enumeration constants, character constants, sizeof expressions, alignof expressions, 
+			// need to permit integer-constant-expressions, including: integer constants,
+			// enumeration constants, character constants, sizeof expressions, alignof expressions,
 			// cast expressions
 			if ( auto constExpr = dynamic_cast< const ConstantExpr * >( expr ) ) {
@@ -662,22 +664,22 @@
 					index = constExpr->intValue();
 				} catch ( SemanticErrorException & ) {
-					SemanticError( expr, 
+					SemanticError( expr,
 						"Constant expression of non-integral type in array designator: " );
 				}
 			} else if ( auto castExpr = dynamic_cast< const CastExpr * >( expr ) ) {
 				setPosition( castExpr->arg );
-			} else if ( 
-				dynamic_cast< const SizeofExpr * >( expr ) 
-				|| dynamic_cast< const AlignofExpr * >( expr ) 
+			} else if (
+				dynamic_cast< const SizeofExpr * >( expr )
+				|| dynamic_cast< const AlignofExpr * >( expr )
 			) {
 				index = 0;
 			} else {
-				assertf( false, 
+				assertf( false,
 					"bad designator given to ArrayIterator: %s", toString( expr ).c_str() );
 			}
 		}
 
-		void setPosition( 
-			std::deque< ptr< Expr > >::const_iterator begin, 
+		void setPosition(
+			std::deque< ptr< Expr > >::const_iterator begin,
 			std::deque< ptr< Expr > >::const_iterator end
 		) override {
@@ -758,8 +760,8 @@
 		}
 
-		AggregateIterator( 
-			const CodeLocation & loc, const std::string k, const std::string & n, const Type * i, 
+		AggregateIterator(
+			const CodeLocation & loc, const std::string k, const std::string & n, const Type * i,
 			const MemberList & ms )
-		: location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ), 
+		: location( loc ), kind( k ), name( n ), inst( i ), members( ms ), curMember( ms.begin() ),
 		  sub( genericSubstitution( i ) ) {
 			PRINT( std::cerr << "Creating " << kind << "(" << name << ")"; )
@@ -768,6 +770,6 @@
 
 	public:
-		void setPosition( 
-			std::deque< ptr< Expr > >::const_iterator begin, 
+		void setPosition(
+			std::deque< ptr< Expr > >::const_iterator begin,
 			std::deque< ptr< Expr > >::const_iterator end
 		) final {
@@ -786,8 +788,8 @@
 					return;
 				}
-				assertf( false, 
+				assertf( false,
 					"could not find member in %s: %s", kind.c_str(), toString( varExpr ).c_str() );
 			} else {
-				assertf( false, 
+				assertf( false,
 					"bad designator given to %s: %s", kind.c_str(), toString( *begin ).c_str() );
 			}
@@ -803,4 +805,5 @@
 						new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
 					// need to substitute for generic types so that casts are to concrete types
+					alt.type = shallowCopy(alt.type.get());
 					PRINT( std::cerr << "  type is: " << alt.type; )
 					sub.apply( alt.type ); // also apply to designation??
@@ -842,5 +845,5 @@
 				for ( InitAlternative & alt : ret ) {
 					PRINT( std::cerr << "iterating and adding designators" << std::endl; )
-					alt.designation.get_and_mutate()->designators.emplace_front( 
+					alt.designation.get_and_mutate()->designators.emplace_front(
 						new VariableExpr{ location, curMember->strict_as< ObjectDecl >() } );
 				}
@@ -897,7 +900,7 @@
 	class TupleIterator final : public AggregateIterator {
 	public:
-		TupleIterator( const CodeLocation & loc, const TupleType * inst ) 
-		: AggregateIterator( 
-			loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members 
+		TupleIterator( const CodeLocation & loc, const TupleType * inst )
+		: AggregateIterator(
+			loc, "TupleIterator", toString("Tuple", inst->size()), inst, inst->members
 		) {}
 
@@ -926,7 +929,7 @@
 				return new UnionIterator{ loc, uit };
 			} else {
-				assertf( 
-					dynamic_cast< const EnumInstType * >( aggr ) 
-						|| dynamic_cast< const TypeInstType * >( aggr ), 
+				assertf(
+					dynamic_cast< const EnumInstType * >( type )
+						|| dynamic_cast< const TypeInstType * >( type ),
 					"Encountered unhandled ReferenceToType in createMemberIterator: %s",
 						toString( type ).c_str() );
@@ -949,5 +952,5 @@
 		using DesignatorChain = std::deque< ptr< Expr > >;
 		PRINT( std::cerr << "___findNext" << std::endl; )
-		
+
 		// find all the d's
 		std::vector< DesignatorChain > desigAlts{ {} }, newDesigAlts;
@@ -1013,5 +1016,5 @@
 		// set new designators
 		assertf( ! objStack.empty(), "empty object stack when setting designation" );
-		Designation * actualDesignation = 
+		Designation * actualDesignation =
 			new Designation{ designation->location, DesignatorChain{d} };
 		objStack.back()->setPosition( d ); // destroys d
Index: src/ResolvExpr/PolyCost.cc
===================================================================
--- src/ResolvExpr/PolyCost.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/PolyCost.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -58,11 +58,12 @@
 
 // TODO: When the old PolyCost is torn out get rid of the _new suffix.
-struct PolyCost_new {
+class PolyCost_new {
+	const ast::SymbolTable &symtab;
+public:
 	int result;
-	const ast::SymbolTable &symtab;
 	const ast::TypeEnvironment &env_;
 
-	PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) :
-		result( 0 ), symtab( symtab ), env_( env ) {}
+	PolyCost_new( const ast::SymbolTable & symtab, const ast::TypeEnvironment & env ) 
+	: symtab( symtab ), result( 0 ), env_( env ) {}
 
 	void previsit( const ast::TypeInstType * type ) {
@@ -86,5 +87,5 @@
 	ast::Pass<PolyCost_new> costing( symtab, env );
 	type->accept( costing );
-	return costing.pass.result;
+	return costing.core.result;
 }
 
Index: src/ResolvExpr/PtrsAssignable.cc
===================================================================
--- src/ResolvExpr/PtrsAssignable.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/PtrsAssignable.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -155,5 +155,5 @@
 		ast::Pass<PtrsAssignable_new> visitor( dst, env );
 		src->accept( visitor );
-		return visitor.pass.result;
+		return visitor.core.result;
 	}
 
Index: src/ResolvExpr/PtrsCastable.cc
===================================================================
--- src/ResolvExpr/PtrsCastable.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/PtrsCastable.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -293,5 +293,5 @@
 		ast::Pass< PtrsCastable_new > ptrs{ dst, env, symtab };
 		src->accept( ptrs );
-		return ptrs.pass.result;
+		return ptrs.core.result;
 	}
 }
Index: src/ResolvExpr/RenameVars.cc
===================================================================
--- src/ResolvExpr/RenameVars.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/RenameVars.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -19,4 +19,5 @@
 #include <utility>                 // for pair
 
+#include "AST/ForallSubstitutionTable.hpp"
 #include "AST/Pass.hpp"
 #include "AST/Type.hpp"
@@ -30,4 +31,6 @@
 #include "SynTree/Visitor.h"       // for acceptAll, maybeAccept
 
+#include "AST/Copy.hpp"
+
 namespace ResolvExpr {
 
@@ -37,6 +40,7 @@
 		int resetCount = 0;
 		ScopedMap< std::string, std::string > nameMap;
+	public:
+		ast::ForallSubstitutionTable subs;
 
-	public:
 		void reset() {
 			level = 0;
@@ -44,8 +48,6 @@
 		}
 
-		using mapConstIterator = ScopedMap< std::string, std::string >::const_iterator;
-
 		void rename( TypeInstType * type ) {
-			mapConstIterator it = nameMap.find( type->name );
+			auto it = nameMap.find( type->name );
 			if ( it != nameMap.end() ) {
 				type->name = it->second;
@@ -65,7 +67,6 @@
 					// ditto for assertion names, the next level in
 					level++;
-					// acceptAll( td->assertions, *this );
-				} // for
-			} // if
+				}
+			}
 		}
 
@@ -77,10 +78,16 @@
 
 		const ast::TypeInstType * rename( const ast::TypeInstType * type ) {
-			mapConstIterator it = nameMap.find( type->name );
+			// re-linking of base type handled by WithForallSubstitutor
+
+			// rename
+			auto it = nameMap.find( type->name );
 			if ( it != nameMap.end() ) {
-				ast::TypeInstType * mutType = ast::mutate( type );
-				mutType->name = it->second;
-	            type = mutType;
+				// unconditionally mutate because map will *always* have different name,
+				// if this mutates, will *always* have been mutated by ForallSubstitutor above
+				ast::TypeInstType * mut = ast::mutate( type );
+				mut->name = it->second;
+	            type = mut;
 			}
+
 			return type;
 		}
@@ -88,29 +95,32 @@
 		template<typename NodeT>
 		const NodeT * openLevel( const NodeT * type ) {
-			if ( !type->forall.empty() ) {
-				nameMap.beginScope();
-				// Load new names from this forall clause and perform renaming.
-				NodeT * mutType = ast::mutate( type );
-				for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
-					std::ostringstream output;
-					output << "_" << resetCount << "_" << level << "_" << td->name;
-					std::string newname( output.str() );
-					nameMap[ td->name ] = newname;
-					++level;
+			if ( type->forall.empty() ) return type;
 
-					ast::TypeDecl * decl = ast::mutate( td.get() );
-					decl->name = newname;
-					td = decl;
-				}
+			nameMap.beginScope();
+
+			// Load new names from this forall clause and perform renaming.
+			NodeT * mutType = ast::mutate( type );
+			assert( type == mutType && "mutated type must be unique from ForallSubstitutor" );
+			for ( ast::ptr< ast::TypeDecl > & td : mutType->forall ) {
+				std::ostringstream output;
+				output << "_" << resetCount << "_" << level << "_" << td->name;
+				std::string newname =  output.str();
+				nameMap[ td->name ] = newname;
+				++level;
+
+				ast::TypeDecl * mutDecl = ast::mutate( td.get() );
+				assert( td == mutDecl && "mutated decl must be unique from ForallSubstitutor" );
+				mutDecl->name = newname;
+				// assertion above means `td = mutDecl;` is unnecessary
 			}
+			// assertion above means `type = mutType;` is unnecessary
+
 			return type;
 		}
 
-		template<typename NodeT>
-		const NodeT * closeLevel( const NodeT * type ) {
-			if ( !type->forall.empty() ) {
-				nameMap.endScope();
-			}
-			return type;
+		void closeLevel( const ast::ParameterizedType * type ) {
+			if ( type->forall.empty() ) return;
+
+			nameMap.endScope();
 		}
 	};
@@ -119,5 +129,5 @@
 	RenamingData renaming;
 
-	struct RenameVars {
+	struct RenameVars_old {
 		void previsit( TypeInstType * instType ) {
 			renaming.openLevel( (Type*)instType );
@@ -130,4 +140,9 @@
 			renaming.closeLevel( type );
 		}
+	};
+
+	struct RenameVars_new /*: public ast::WithForallSubstitutor*/ {
+		#warning when old RenameVars goes away, replace hack below with global pass inheriting from WithForallSubstitutor
+		ast::ForallSubstitutionTable & subs = renaming.subs;
 
 		const ast::FunctionType * previsit( const ast::FunctionType * type ) {
@@ -146,6 +161,6 @@
 			return renaming.rename( renaming.openLevel( type ) );
 		}
-		const ast::ParameterizedType * postvisit( const ast::ParameterizedType * type ) {
-			return renaming.closeLevel( type );
+		void postvisit( const ast::ParameterizedType * type ) {
+			renaming.closeLevel( type );
 		}
 	};
@@ -154,11 +169,13 @@
 
 void renameTyVars( Type * t ) {
-	PassVisitor<RenameVars> renamer;
+	PassVisitor<RenameVars_old> renamer;
 	t->accept( renamer );
 }
 
 const ast::Type * renameTyVars( const ast::Type * t ) {
-	ast::Pass<RenameVars> renamer;
-	return t->accept( renamer );
+	ast::Type *tc = ast::deepCopy(t);
+	ast::Pass<RenameVars_new> renamer;
+//	return t->accept( renamer );
+	return tc->accept( renamer );
 }
 
Index: src/ResolvExpr/ResolveTypeof.cc
===================================================================
--- src/ResolvExpr/ResolveTypeof.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/ResolveTypeof.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -99,16 +99,16 @@
 			// replace basetypeof(<enum>) by int
 			if ( dynamic_cast<EnumInstType*>(newType) ) {
-				Type* newerType = 
-					new BasicType{ newType->get_qualifiers(), BasicType::SignedInt, 
+				Type* newerType =
+					new BasicType{ newType->get_qualifiers(), BasicType::SignedInt,
 					newType->attributes };
 				delete newType;
 				newType = newerType;
 			}
-			newType->get_qualifiers().val 
+			newType->get_qualifiers().val
 				= ( newType->get_qualifiers().val & ~Type::Qualifiers::Mask ) | oldQuals;
 		} else {
 			newType->get_qualifiers().val |= oldQuals;
 		}
-		
+
 		return newType;
 	}
@@ -120,7 +120,7 @@
 		ResolveTypeof_new( const ast::SymbolTable & syms ) : localSymtab( syms ) {}
 
-		void premutate( const ast::TypeofType * ) { visit_children = false; }
+		void previsit( const ast::TypeofType * ) { visit_children = false; }
 
-		const ast::Type * postmutate( const ast::TypeofType * typeofType ) {
+		const ast::Type * postvisit( const ast::TypeofType * typeofType ) {
 			// pass on null expression
 			if ( ! typeofType->expr ) return typeofType;
@@ -133,5 +133,5 @@
 				// typeof wrapping expression
 				ast::TypeEnvironment dummy;
-				ast::ptr< ast::Expr > newExpr = 
+				ast::ptr< ast::Expr > newExpr =
 					resolveInVoidContext( typeofType->expr, localSymtab, dummy );
 				assert( newExpr->result && ! newExpr->result->isVoid() );
@@ -143,9 +143,9 @@
 				// replace basetypeof(<enum>) by int
 				if ( newType.as< ast::EnumInstType >() ) {
-					newType = new ast::BasicType{ 
+					newType = new ast::BasicType{
 						ast::BasicType::SignedInt, newType->qualifiers, copy(newType->attributes) };
 				}
-				reset_qualifiers( 
-					newType, 
+				reset_qualifiers(
+					newType,
 					( newType->qualifiers & ~ast::CV::EquivQualifiers ) | typeofType->qualifiers );
 			} else {
@@ -153,5 +153,5 @@
 			}
 
-			return newType;
+			return newType.release();
 		}
 	};
Index: src/ResolvExpr/Resolver.cc
===================================================================
--- src/ResolvExpr/Resolver.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/Resolver.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -982,5 +982,5 @@
 		ast::Pass<DeleteFinder_new> finder;
 		expr->accept( finder );
-		return finder.pass.delExpr;
+		return finder.core.delExpr;
 	}
 
@@ -1072,7 +1072,7 @@
 		/// Strips extraneous casts out of an expression
 		struct StripCasts_new final {
-			const ast::Expr * postmutate( const ast::CastExpr * castExpr ) {
+			const ast::Expr * postvisit( const ast::CastExpr * castExpr ) {
 				if (
-					castExpr->isGenerated
+					castExpr->isGenerated == ast::GeneratedCast
 					&& typesCompatible( castExpr->arg->result, castExpr->result )
 				) {
@@ -1128,5 +1128,5 @@
 
 		// set up and resolve expression cast to void
-		ast::CastExpr * untyped = new ast::CastExpr{ expr };
+		ast::ptr< ast::CastExpr > untyped = new ast::CastExpr{ expr };
 		CandidateRef choice = findUnfinishedKindExpression(
 			untyped, symtab, "", anyCandidate, ResolvMode::withAdjustment() );
@@ -1236,4 +1236,5 @@
 
 	public:
+		static size_t traceId;
 		Resolver_new() = default;
 		Resolver_new( const ast::SymbolTable & syms ) { symtab = syms; }
@@ -1266,8 +1267,8 @@
 		const ast::ConstructorInit * previsit( const ast::ConstructorInit * );
 	};
-
-	void resolve( std::list< ast::ptr<ast::Decl> >& translationUnit ) {
-		ast::Pass< Resolver_new > resolver;
-		accept_all( translationUnit, resolver );
+	// size_t Resolver_new::traceId = Stats::Heap::new_stacktrace_id("Resolver");
+
+	void resolve( std::list< ast::ptr< ast::Decl > >& translationUnit ) {
+		ast::Pass< Resolver_new >::run( translationUnit );
 	}
 
@@ -1299,24 +1300,27 @@
 		// default value expressions have an environment which shouldn't be there and trips up
 		// later passes.
-		ast::ptr< ast::FunctionDecl > ret = functionDecl;
-		for ( unsigned i = 0; i < functionDecl->type->params.size(); ++i ) {
-			const ast::ptr<ast::DeclWithType> & d = functionDecl->type->params[i];
-
-			if ( const ast::ObjectDecl * obj = d.as< ast::ObjectDecl >() ) {
+		assert( functionDecl->unique() );
+		ast::FunctionType * mutType = mutate( functionDecl->type.get() );
+
+		for ( unsigned i = 0 ; i < mutType->params.size() ; ++i ) {
+			if ( const ast::ObjectDecl * obj = mutType->params[i].as< ast::ObjectDecl >() ) {
 				if ( const ast::SingleInit * init = obj->init.as< ast::SingleInit >() ) {
 					if ( init->value->env == nullptr ) continue;
 					// clone initializer minus the initializer environment
-					ast::chain_mutate( ret )
-						( &ast::FunctionDecl::type )
-							( &ast::FunctionType::params )[i]
-								( &ast::ObjectDecl::init )
-									( &ast::SingleInit::value )->env = nullptr;
-
-					assert( functionDecl != ret.get() || functionDecl->unique() );
-					assert( ! ret->type->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env );
+					auto mutParam = mutate( mutType->params[i].strict_as< ast::ObjectDecl >() );
+					auto mutInit = mutate( mutParam->init.strict_as< ast::SingleInit >() );
+					auto mutValue = mutate( mutInit->value.get() );
+
+					mutValue->env = nullptr;
+					mutInit->value = mutValue;
+					mutParam->init = mutInit;
+					mutType->params[i] = mutParam;
+
+					assert( ! mutType->params[i].strict_as< ast::ObjectDecl >()->init.strict_as< ast::SingleInit >()->value->env);
 				}
 			}
 		}
-		return ret.get();
+		mutate_field(functionDecl, &ast::FunctionDecl::type, mutType);
+		return functionDecl;
 	}
 
@@ -1341,5 +1345,5 @@
 		// in case we decide to allow nested enums
 		GuardValue( inEnumDecl );
-		inEnumDecl = false;
+		inEnumDecl = true;
 	}
 
Index: src/ResolvExpr/SatisfyAssertions.cpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.cpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/SatisfyAssertions.cpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -9,7 +9,7 @@
 // Author           : Aaron B. Moss
 // Created On       : Mon Jun 10 17:45:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Mon Jun 10 17:45:00 2019
-// Update Count     : 1
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Oct  1 13:56:00 2019
+// Update Count     : 2
 //
 
@@ -188,5 +188,5 @@
 
 				matches.emplace_back( 
-					cdata, adjType, std::move( newEnv ), std::move( newNeed ), std::move( have ), 
+					cdata, adjType, std::move( newEnv ), std::move( have ), std::move( newNeed ),
 					std::move( newOpen ), crntResnSlot );
 			}
@@ -229,15 +229,18 @@
 		InferMatcher( InferCache & inferred ) : inferred( inferred ) {}
 
-		const ast::Expr * postmutate( const ast::Expr * expr ) {
+		const ast::Expr * postvisit( const ast::Expr * expr ) {
 			// Skip if no slots to find
-			if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
-
+			if ( !expr->inferred.hasSlots() ) return expr;
+			// if ( expr->inferred.mode != ast::Expr::InferUnion::Slots ) return expr;
+			std::vector<UniqueId> missingSlots;
 			// find inferred parameters for resolution slots
-			ast::InferredParams newInferred;
+			ast::InferredParams * newInferred = new ast::InferredParams();
 			for ( UniqueId slot : expr->inferred.resnSlots() ) {
 				// fail if no matching assertions found
 				auto it = inferred.find( slot );
 				if ( it == inferred.end() ) {
-					assert(!"missing assertion");
+					std::cerr << "missing assertion " << slot << std::endl;
+					missingSlots.push_back(slot);
+					continue;
 				}
 
@@ -245,6 +248,6 @@
 				for ( auto & entry : it->second ) {
 					// recurse on inferParams of resolved expressions
-					entry.second.expr = postmutate( entry.second.expr );
-					auto res = newInferred.emplace( entry );
+					entry.second.expr = postvisit( entry.second.expr );
+					auto res = newInferred->emplace( entry );
 					assert( res.second && "all assertions newly placed" );
 				}
@@ -252,5 +255,6 @@
 
 			ast::Expr * ret = mutate( expr );
-			ret->inferred.set_inferParams( std::move( newInferred ) );
+			ret->inferred.set_inferParams( newInferred );
+			if (!missingSlots.empty()) ret->inferred.resnSlots() = missingSlots;
 			return ret;
 		}
@@ -299,6 +303,6 @@
 			Cost cost;
 
-			OutType( 
-				const ast::TypeEnvironment & e, const ast::OpenVarSet & o, 
+			OutType(
+				const ast::TypeEnvironment & e, const ast::OpenVarSet & o,
 				const std::vector< DeferRef > & as, const ast::SymbolTable & symtab )
 			: env( e ), open( o ), assns( as ), cost( Cost::zero ) {
@@ -306,9 +310,9 @@
 				for ( const DeferRef & assn : assns ) {
 					// compute conversion cost from satisfying decl to assertion
-					cost += computeConversionCost( 
-						assn.match.adjType, assn.decl->get_type(), symtab, env );
-					
+					cost += computeConversionCost(
+						assn.match.adjType, assn.decl->get_type(), false, symtab, env );
+
 					// mark vars+specialization on function-type assertions
-					const ast::FunctionType * func = 
+					const ast::FunctionType * func =
 						GenPoly::getFunctionType( assn.match.cdata.id->get_type() );
 					if ( ! func ) continue;
@@ -317,7 +321,7 @@
 						cost.decSpec( specCost( param->get_type() ) );
 					}
-					
+
 					cost.incVar( func->forall.size() );
-					
+
 					for ( const ast::TypeDecl * td : func->forall ) {
 						cost.decSpec( td->assertions.size() );
@@ -329,6 +333,6 @@
 		};
 
-		CandidateEnvMerger( 
-			const ast::TypeEnvironment & env, const ast::OpenVarSet & open, 
+		CandidateEnvMerger(
+			const ast::TypeEnvironment & env, const ast::OpenVarSet & open,
 			const ast::SymbolTable & syms )
 		: crnt(), envs{ env }, opens{ open }, symtab( syms ) {}
Index: src/ResolvExpr/SatisfyAssertions.hpp
===================================================================
--- src/ResolvExpr/SatisfyAssertions.hpp	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/SatisfyAssertions.hpp	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -28,6 +28,6 @@
 
 /// Recursively satisfies all assertions provided in a candidate; returns true if succeeds
-void satisfyAssertions( 
-	CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out, 
+void satisfyAssertions(
+	CandidateRef & cand, const ast::SymbolTable & symtab, CandidateList & out,
 	std::vector<std::string> & errors );
 
Index: src/ResolvExpr/SpecCost.cc
===================================================================
--- src/ResolvExpr/SpecCost.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/SpecCost.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,8 +10,9 @@
 // Created On       : Tue Oct 02 15:50:00 2018
 // Last Modified By : Andrew Beach
-// Last Modified On : Wed Jun 19 10:43:00 2019
-// Update Count     : 2
-//
-
+// Last Modified On : Wed Jul  3 11:07:00 2019
+// Update Count     : 3
+//
+
+#include <cassert>
 #include <limits>
 #include <list>
@@ -129,4 +130,12 @@
 			typename std::add_pointer<ast::Type const *(typename T::value_type const &)>::type;
 
+		#warning Should use a standard maybe_accept
+		void maybe_accept( ast::Type const * type ) {
+			if ( type ) {
+				auto node = type->accept( *visitor );
+				assert( node == nullptr || node == type );
+			}
+		}
+
 		// Update the minimum to the new lowest non-none value.
 		template<typename T>
@@ -134,5 +143,5 @@
 			for ( const auto & node : list ) {
 				count = -1;
-				mapper( node )->accept( *visitor );
+				maybe_accept( mapper( node ) );
 				if ( count != -1 && count < minimum ) minimum = count;
 			}
@@ -208,6 +217,6 @@
 	}
 	ast::Pass<SpecCounter> counter;
-	type->accept( *counter.pass.visitor );
-	return counter.pass.get_count();
+	type->accept( counter );
+	return counter.core.get_count();
 }
 
Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/Unify.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -25,7 +25,9 @@
 #include <vector>
 
+#include "AST/Copy.hpp"
 #include "AST/Decl.hpp"
 #include "AST/Node.hpp"
 #include "AST/Pass.hpp"
+#include "AST/Print.hpp"
 #include "AST/Type.hpp"
 #include "AST/TypeEnvironment.hpp"
@@ -135,6 +137,5 @@
 		findOpenVars( newSecond, open, closed, need, have, FirstOpen );
 
-		return unifyExact(
-			newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
+		return unifyExact(newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
 	}
 
@@ -148,13 +149,5 @@
 		newFirst->get_qualifiers() = Type::Qualifiers();
 		newSecond->get_qualifiers() = Type::Qualifiers();
-///   std::cerr << "first is ";
-///   first->print( std::cerr );
-///   std::cerr << std::endl << "second is ";
-///   second->print( std::cerr );
-///   std::cerr << std::endl << "newFirst is ";
-///   newFirst->print( std::cerr );
-///   std::cerr << std::endl << "newSecond is ";
-///   newSecond->print( std::cerr );
-///   std::cerr << std::endl;
+
 		bool result = unifyExact( newFirst, newSecond, newEnv, needAssertions, haveAssertions, openVars, WidenMode( false, false ), indexer );
 		delete newFirst;
@@ -170,12 +163,18 @@
 		ast::AssertionSet need, have;
 
-		ast::ptr<ast::Type> newFirst{ first }, newSecond{ second };
-		env.apply( newFirst );
-		env.apply( newSecond );
-		reset_qualifiers( newFirst );
-		reset_qualifiers( newSecond );
+		ast::Type * newFirst  = shallowCopy( first  );
+		ast::Type * newSecond = shallowCopy( second );
+		newFirst ->qualifiers = {};
+		newSecond->qualifiers = {};
+		ast::ptr< ast::Type > t1_(newFirst );
+		ast::ptr< ast::Type > t2_(newSecond);
+
+		ast::ptr< ast::Type > subFirst = env.apply(newFirst).node;
+		ast::ptr< ast::Type > subSecond = env.apply(newSecond).node;
 
 		return unifyExact(
-			newFirst, newSecond, newEnv, need, have, open, noWiden(), symtab );
+			subFirst,
+			subSecond,
+			newEnv, need, have, open, noWiden(), symtab );
 	}
 
@@ -326,12 +325,6 @@
 
 	void markAssertionSet( AssertionSet &assertions, DeclarationWithType *assert ) {
-///   std::cerr << "assertion set is" << std::endl;
-///   printAssertionSet( assertions, std::cerr, 8 );
-///   std::cerr << "looking for ";
-///   assert->print( std::cerr );
-///   std::cerr << std::endl;
 		AssertionSet::iterator i = assertions.find( assert );
 		if ( i != assertions.end() ) {
-///     std::cerr << "found it!" << std::endl;
 			i->second.isUsed = true;
 		} // if
@@ -709,4 +702,5 @@
 		const ast::SymbolTable & symtab;
 	public:
+		static size_t traceId;
 		bool result;
 
@@ -797,6 +791,9 @@
 			for ( const ast::DeclWithType * d : src ) {
 				ast::Pass<TtypeExpander_new> expander{ env };
-				d = d->accept( expander );
-				auto types = flatten( d->get_type() );
+				// TtypeExpander pass is impure (may mutate nodes in place)
+				// need to make nodes shared to prevent accidental mutation
+				ast::ptr<ast::DeclWithType> dc = d;
+				dc = dc->accept( expander );
+				auto types = flatten( dc->get_type() );
 				for ( ast::ptr< ast::Type > & t : types ) {
 					// outermost const, volatile, _Atomic qualifiers in parameters should not play
@@ -807,5 +804,5 @@
 					// requirements than a non-mutex function
 					remove_qualifiers( t, ast::CV::Const | ast::CV::Volatile | ast::CV::Atomic );
-					dst.emplace_back( new ast::ObjectDecl{ d->location, "", t } );
+					dst.emplace_back( new ast::ObjectDecl{ dc->location, "", t } );
 				}
 			}
@@ -943,9 +940,11 @@
 
 	private:
-		template< typename RefType >
-		const RefType * handleRefType( const RefType * inst, const ast::Type * other ) {
+		// Returns: other, cast as XInstType
+		// Assigns this->result: whether types are compatible (up to generic parameters)
+		template< typename XInstType >
+		const XInstType * handleRefType( const XInstType * inst, const ast::Type * other ) {
 			// check that the other type is compatible and named the same
-			auto otherInst = dynamic_cast< const RefType * >( other );
-			result = otherInst && inst->name == otherInst->name;
+			auto otherInst = dynamic_cast< const XInstType * >( other );
+			this->result = otherInst && inst->name == otherInst->name;
 			return otherInst;
 		}
@@ -968,13 +967,13 @@
 		}
 
-		template< typename RefType >
-		void handleGenericRefType( const RefType * inst, const ast::Type * other ) {
+		template< typename XInstType >
+		void handleGenericRefType( const XInstType * inst, const ast::Type * other ) {
 			// check that other type is compatible and named the same
-			const RefType * inst2 = handleRefType( inst, other );
-			if ( ! inst2 ) return;
+			const XInstType * otherInst = handleRefType( inst, other );
+			if ( ! this->result ) return;
 
 			// check that parameters of types unify, if any
 			const std::vector< ast::ptr< ast::Expr > > & params = inst->params;
-			const std::vector< ast::ptr< ast::Expr > > & params2 = inst2->params;
+			const std::vector< ast::ptr< ast::Expr > > & params2 = otherInst->params;
 
 			auto it = params.begin();
@@ -1114,6 +1113,9 @@
 
 			ast::Pass<TtypeExpander_new> expander{ tenv };
-			const ast::Type * flat = tuple->accept( expander );
-			const ast::Type * flat2 = tuple2->accept( expander );
+
+			ast::ptr<ast::TupleType> tuplec = tuple;
+			ast::ptr<ast::TupleType> tuple2c = tuple2;
+			const ast::Type * flat = tuplec->accept( expander );
+			const ast::Type * flat2 = tuple2c->accept( expander );
 
 			auto types = flatten( flat );
@@ -1140,4 +1142,5 @@
 	};
 
+	// size_t Unify_new::traceId = Stats::Heap::new_stacktrace_id("Unify_new");
 	bool unify(
 			const ast::ptr<ast::Type> & type1, const ast::ptr<ast::Type> & type2,
@@ -1188,5 +1191,5 @@
 			ast::Pass<Unify_new> comparator{ type2, env, need, have, open, widen, symtab };
 			type1->accept( comparator );
-			return comparator.pass.result;
+			return comparator.core.result;
 		}
 	}
@@ -1202,15 +1205,16 @@
 		// force t1 and t2 to be cloned if their qualifiers must be stripped, so that type1 and
 		// type2 are left unchanged; calling convention forces type{1,2}->strong_ref >= 1
-		ast::ptr<ast::Type> t1{ type1 }, t2{ type2 };
-		reset_qualifiers( t1 );
-		reset_qualifiers( t2 );
+		ast::Type * t1 = shallowCopy(type1.get());
+		ast::Type * t2 = shallowCopy(type2.get());
+		t1->qualifiers = {};
+		t2->qualifiers = {};
+		ast::ptr< ast::Type > t1_(t1);
+		ast::ptr< ast::Type > t2_(t2);
 
 		if ( unifyExact( t1, t2, env, need, have, open, widen, symtab ) ) {
-			t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
-
 			// if exact unification on unqualified types, try to merge qualifiers
 			if ( q1 == q2 || ( ( q1 > q2 || widen.first ) && ( q2 > q1 || widen.second ) ) ) {
-				common = type1;
-				reset_qualifiers( common, q1 | q2 );
+				t1->qualifiers = q1 | q2;
+				common = t1;
 				return true;
 			} else {
@@ -1219,8 +1223,8 @@
 
 		} else if (( common = commonType( t1, t2, widen, symtab, env, open ) )) {
-			t1 = nullptr; t2 = nullptr; // release t1, t2 to avoid spurious clones
-
 			// no exact unification, but common type
-			reset_qualifiers( common, q1 | q2 );
+			auto c = shallowCopy(common.get());
+			c->qualifiers = q1 | q2;
+			common = c;
 			return true;
 		} else {
Index: src/ResolvExpr/typeops.h
===================================================================
--- src/ResolvExpr/typeops.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/ResolvExpr/typeops.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Sun May 17 07:28:22 2015
 // Last Modified By : Andrew Beach
-// Last Modified On : Thu Aug  8 16:36:00 2019
-// Update Count     : 5
+// Last Modified On : Tue Oct  1 09:45:00 2019
+// Update Count     : 6
 //
 
@@ -83,6 +83,6 @@
 		const SymTab::Indexer & indexer, const TypeEnvironment & env );
 	Cost castCost(
-		const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-		const ast::TypeEnvironment & env );
+		const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
 
 	// in ConversionCost.cc
@@ -90,6 +90,6 @@
 		const SymTab::Indexer & indexer, const TypeEnvironment & env );
 	Cost conversionCost(
-		const ast::Type * src, const ast::Type * dst, const ast::SymbolTable & symtab,
-		const ast::TypeEnvironment & env );
+		const ast::Type * src, const ast::Type * dst, bool srcIsLvalue,
+		const ast::SymbolTable & symtab, const ast::TypeEnvironment & env );
 
 	// in AlternativeFinder.cc
Index: src/SymTab/Autogen.h
===================================================================
--- src/SymTab/Autogen.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SymTab/Autogen.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -21,4 +21,5 @@
 
 #include "AST/Decl.hpp"
+#include "AST/Eval.hpp"
 #include "AST/Expr.hpp"
 #include "AST/Init.hpp"
@@ -265,5 +266,6 @@
 		}
 
-		ast::ptr< ast::Expr > begin, end, cmp, update;
+		ast::ptr< ast::Expr > begin, end;
+		std::string cmp, update;
 
 		if ( forward ) {
@@ -271,14 +273,13 @@
 			begin = ast::ConstantExpr::from_int( loc, 0 );
 			end = array->dimension;
-			cmp = new ast::NameExpr{ loc, "?<?" };
-			update = new ast::NameExpr{ loc, "++?" };
+			cmp = "?<?";
+			update = "++?";
 		} else {
 			// generate: for ( int i = N-1; i >= 0; --i )
-			begin = new ast::UntypedExpr{ 
-				loc, new ast::NameExpr{ loc, "?-?" }, 
-				{ array->dimension, ast::ConstantExpr::from_int( loc, 1 ) } };
+			begin = ast::call( 
+				loc, "?-?", array->dimension, ast::ConstantExpr::from_int( loc, 1 ) );
 			end = ast::ConstantExpr::from_int( loc, 0 );
-			cmp = new ast::NameExpr{ loc, "?>=?" };
-			update = new ast::NameExpr{ loc, "--?" };
+			cmp = "?>=?";
+			update = "--?";
 		}
 
@@ -286,18 +287,15 @@
 			loc, indexName.newName(), new ast::BasicType{ ast::BasicType::SignedInt }, 
 			new ast::SingleInit{ loc, begin } };
-		
-		ast::ptr< ast::Expr > cond = new ast::UntypedExpr{
-			loc, cmp, { new ast::VariableExpr{ loc, index }, end } };
-		
-		ast::ptr< ast::Expr > inc = new ast::UntypedExpr{
-			loc, update, { new ast::VariableExpr{ loc, index } } };
-		
-		ast::ptr< ast::Expr > dstIndex = new ast::UntypedExpr{
-			loc, new ast::NameExpr{ loc, "?[?]" }, 
-			{ dstParam, new ast::VariableExpr{ loc, index } } };
+		ast::ptr< ast::Expr > indexVar = new ast::VariableExpr{ loc, index };
+		
+		ast::ptr< ast::Expr > cond = ast::call( loc, cmp, indexVar, end );
+		
+		ast::ptr< ast::Expr > inc = ast::call( loc, update, indexVar );
+		
+		ast::ptr< ast::Expr > dstIndex = ast::call( loc, "?[?]", dstParam, indexVar );
 		
 		// srcParam must keep track of the array indices to build the source parameter and/or 
 		// array list initializer
-		srcParam.addArrayIndex( new ast::VariableExpr{ loc, index }, array->dimension );
+		srcParam.addArrayIndex( indexVar, array->dimension );
 
 		// for stmt's body, eventually containing call
@@ -385,5 +383,5 @@
 		if ( isUnnamedBitfield( obj ) ) return {};
 
-		ast::ptr< ast::Type > addCast = nullptr;
+		ast::ptr< ast::Type > addCast;
 		if ( (fname == "?{}" || fname == "^?{}") && ( ! obj || ( obj && ! obj->bitfieldWidth ) ) ) {
 			assert( dstParam->result );
Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SymTab/FixFunction.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -106,7 +106,7 @@
 		bool isVoid = false;
 
-		void premutate( const ast::FunctionDecl * ) { visit_children = false; }
+		void previsit( const ast::FunctionDecl * ) { visit_children = false; }
 
-		const ast::DeclWithType * postmutate( const ast::FunctionDecl * func ) {
+		const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
 			return new ast::ObjectDecl{ 
 				func->location, func->name, new ast::PointerType{ func->type }, nullptr, 
@@ -114,7 +114,7 @@
 		}
 
-		void premutate( const ast::ArrayType * ) { visit_children = false; }
+		void previsit( const ast::ArrayType * ) { visit_children = false; }
 
-		const ast::Type * postmutate( const ast::ArrayType * array ) {
+		const ast::Type * postvisit( const ast::ArrayType * array ) {
 			return new ast::PointerType{ 
 				array->base, array->dimension, array->isVarLen, array->isStatic, 
@@ -122,17 +122,17 @@
 		}
 
-		void premutate( const ast::VoidType * ) { isVoid = true; }
+		void previsit( const ast::VoidType * ) { isVoid = true; }
 
-		void premutate( const ast::BasicType * ) { visit_children = false; }
-		void premutate( const ast::PointerType * ) { visit_children = false; }
-		void premutate( const ast::StructInstType * ) { visit_children = false; }
-		void premutate( const ast::UnionInstType * ) { visit_children = false; }
-		void premutate( const ast::EnumInstType * ) { visit_children = false; }
-		void premutate( const ast::TraitInstType * ) { visit_children = false; }
-		void premutate( const ast::TypeInstType * ) { visit_children = false; }
-		void premutate( const ast::TupleType * ) { visit_children = false; }
-		void premutate( const ast::VarArgsType * ) { visit_children = false; }
-		void premutate( const ast::ZeroType * ) { visit_children = false; }
-		void premutate( const ast::OneType * ) { visit_children = false; }
+		void previsit( const ast::BasicType * ) { visit_children = false; }
+		void previsit( const ast::PointerType * ) { visit_children = false; }
+		void previsit( const ast::StructInstType * ) { visit_children = false; }
+		void previsit( const ast::UnionInstType * ) { visit_children = false; }
+		void previsit( const ast::EnumInstType * ) { visit_children = false; }
+		void previsit( const ast::TraitInstType * ) { visit_children = false; }
+		void previsit( const ast::TypeInstType * ) { visit_children = false; }
+		void previsit( const ast::TupleType * ) { visit_children = false; }
+		void previsit( const ast::VarArgsType * ) { visit_children = false; }
+		void previsit( const ast::ZeroType * ) { visit_children = false; }
+		void previsit( const ast::OneType * ) { visit_children = false; }
 	};
 } // anonymous namespace
@@ -141,5 +141,5 @@
 	ast::Pass< FixFunction_new > fixer;
 	dwt = dwt->accept( fixer );
-	isVoid |= fixer.pass.isVoid;
+	isVoid |= fixer.core.isVoid;
 	return dwt;
 }
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SymTab/Mangler.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -447,5 +447,5 @@
 		ast::Pass<Mangler_new> mangler( mode );
 		maybeAccept( decl, mangler );
-		return mangler.pass.get_mangleName();
+		return mangler.core.get_mangleName();
 	}
 
@@ -691,5 +691,5 @@
 								mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums );
 							assert->accept( sub_mangler );
-							assertionNames.push_back( sub_mangler.pass.get_mangleName() );
+							assertionNames.push_back( sub_mangler.core.get_mangleName() );
 							acount++;
 						} // for
Index: src/SynTree/ApplicationExpr.cc
===================================================================
--- src/SynTree/ApplicationExpr.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SynTree/ApplicationExpr.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -34,9 +34,9 @@
 
 ParamEntry::ParamEntry( const ParamEntry &other ) :
-		decl( other.decl ), declptr( maybeClone( other.declptr ) ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
+		decl( other.decl ), declptr( other.declptr ), actualType( maybeClone( other.actualType ) ), formalType( maybeClone( other.formalType ) ), expr( maybeClone( other.expr ) ) {
 }
 
 ParamEntry::~ParamEntry() {
-	delete declptr;
+	// delete declptr;
 	delete actualType;
 	delete formalType;
Index: src/SynTree/Expression.cc
===================================================================
--- src/SynTree/Expression.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SynTree/Expression.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -69,4 +69,10 @@
 void Expression::print( std::ostream & os, Indenter indent ) const {
 	printInferParams( inferParams, os, indent+1, 0 );
+
+	if ( result ) {
+		os << std::endl << indent << "with resolved type:" << std::endl;
+		os << (indent+1);
+		result->print( os, indent+1 );
+	}
 
 	if ( env ) {
Index: src/SynTree/Statement.h
===================================================================
--- src/SynTree/Statement.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/SynTree/Statement.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -518,5 +518,5 @@
 class ImplicitCtorDtorStmt : public Statement {
   public:
-	// Non-owned pointer to the constructor/destructor statement
+	// the constructor/destructor call statement; owned here for a while, eventually transferred elsewhere
 	Statement * callStmt;
 
Index: src/Tuples/Explode.cc
===================================================================
--- src/Tuples/Explode.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Tuples/Explode.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -129,5 +129,4 @@
 			for ( const ast::Expr * expr : tupleExpr->exprs ) {
 				exprs.emplace_back( applyCast( expr, false ) );
-				//exprs.emplace_back( ast::ptr< ast::Expr >( applyCast( expr, false ) ) );
 			}
 			if ( first ) {
@@ -148,5 +147,5 @@
 	}
 
-	const ast::Expr * postmutate( const ast::UniqueExpr * node ) {
+	const ast::Expr * postvisit( const ast::UniqueExpr * node ) {
 		// move cast into unique expr so that the unique expr has type T& rather than
 		// type T. In particular, this transformation helps with generating the
@@ -162,10 +161,10 @@
 			castAdded = false;
 			const ast::Type * newType = getReferenceBase( newNode->result );
-			return new ast::CastExpr{ newNode->location, node, newType };
+			return new ast::CastExpr{ newNode->location, newNode, newType };
 		}
 		return newNode;
 	}
 
-	const ast::Expr * postmutate( const ast::TupleIndexExpr * tupleExpr ) {
+	const ast::Expr * postvisit( const ast::TupleIndexExpr * tupleExpr ) {
 		// tuple index expr needs to be rebuilt to ensure that the type of the
 		// field is consistent with the type of the tuple expr, since the field
@@ -180,5 +179,5 @@
 	ast::Pass<CastExploderCore> exploder;
 	expr = expr->accept( exploder );
-	if ( ! exploder.pass.foundUniqueExpr ) {
+	if ( ! exploder.core.foundUniqueExpr ) {
 		expr = new ast::CastExpr{ expr, new ast::ReferenceType{ expr->result } };
 	}
Index: src/Tuples/Explode.h
===================================================================
--- src/Tuples/Explode.h	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Tuples/Explode.h	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -210,5 +210,5 @@
 			}
 			// Cast a reference away to a value-type to allow further explosion.
-			if ( dynamic_cast< const ast::ReferenceType *>( local->result.get() ) ) {
+			if ( local->result.as< ast::ReferenceType >() ) {
 				local = new ast::CastExpr{ local, tupleType };
 			}
@@ -220,5 +220,4 @@
 				// delete idx;
 			}
-			// delete local;
 		}
 	} else {
Index: src/Tuples/TupleAssignment.cc
===================================================================
--- src/Tuples/TupleAssignment.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Tuples/TupleAssignment.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -465,5 +465,5 @@
 					// resolve ctor/dtor for the new object
 					ast::ptr< ast::Init > ctorInit = ResolvExpr::resolveCtorInit(
-							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.symtab );
+							InitTweak::genCtorInit( location, ret ), spotter.crntFinder.localSyms );
 					// remove environments from subexpressions of stmtExpr
 					ast::Pass< EnvRemover > rm{ env };
@@ -504,6 +504,7 @@
 
 			std::vector< ast::ptr< ast::Expr > > match() override {
-				static UniqueName lhsNamer( "__massassign_L" );
-				static UniqueName rhsNamer( "__massassign_R" );
+				// temporary workaround for new and old ast to coexist and avoid name collision
+				static UniqueName lhsNamer( "__massassign_Ln" );
+				static UniqueName rhsNamer( "__massassign_Rn" );
 				// empty tuple case falls into this matcher
 				assert( lhs.empty() ? rhs.empty() : rhs.size() <= 1 );
@@ -534,6 +535,7 @@
 
 			std::vector< ast::ptr< ast::Expr > > match() override {
-				static UniqueName lhsNamer( "__multassign_L" );
-				static UniqueName rhsNamer( "__multassign_R" );
+				// temporary workaround for new and old ast to coexist and avoid name collision
+				static UniqueName lhsNamer( "__multassign_Ln" );
+				static UniqueName rhsNamer( "__multassign_Rn" );
 
 				if ( lhs.size() != rhs.size() ) return {};
@@ -560,5 +562,5 @@
 					// resolve the cast expression so that rhsCand return type is bound by the cast
 					// type as needed, and transfer the resulting environment
-					ResolvExpr::CandidateFinder finder{ spotter.crntFinder.symtab, env };
+					ResolvExpr::CandidateFinder finder{ spotter.crntFinder.localSyms, env };
 					finder.find( rhsCand->expr, ResolvExpr::ResolvMode::withAdjustment() );
 					assert( finder.candidates.size() == 1 );
@@ -609,5 +611,5 @@
 					// explode the LHS so that each field of a tuple-valued expr is assigned
 					ResolvExpr::CandidateList lhs;
-					explode( *lhsCand, crntFinder.symtab, back_inserter(lhs), true );
+					explode( *lhsCand, crntFinder.localSyms, back_inserter(lhs), true );
 					for ( ResolvExpr::CandidateRef & cand : lhs ) {
 						// each LHS value must be a reference - some come in with a cast, if not
@@ -629,5 +631,5 @@
 							if ( isTuple( rhsCand->expr ) ) {
 								// multiple assignment
-								explode( *rhsCand, crntFinder.symtab, back_inserter(rhs), true );
+								explode( *rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
 								matcher.reset(
 									new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -648,5 +650,5 @@
 							// multiple assignment
 							ResolvExpr::CandidateList rhs;
-							explode( rhsCand, crntFinder.symtab, back_inserter(rhs), true );
+							explode( rhsCand, crntFinder.localSyms, back_inserter(rhs), true );
 							matcher.reset(
 								new MultipleAssignMatcher{ *this, expr->location, lhs, rhs } );
@@ -678,5 +680,5 @@
 				)
 
-				ResolvExpr::CandidateFinder finder{ crntFinder.symtab, matcher->env };
+				ResolvExpr::CandidateFinder finder{ crntFinder.localSyms, matcher->env };
 
 				try {
Index: src/Tuples/TupleExpansion.cc
===================================================================
--- src/Tuples/TupleExpansion.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Tuples/TupleExpansion.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -323,5 +323,5 @@
 		std::vector<ast::ptr<ast::Type>> types;
 		ast::CV::Qualifiers quals{
-			ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict | ast::CV::Lvalue |
+			ast::CV::Const | ast::CV::Volatile | ast::CV::Restrict |
 			ast::CV::Atomic | ast::CV::Mutex };
 
Index: src/Tuples/Tuples.cc
===================================================================
--- src/Tuples/Tuples.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/Tuples/Tuples.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -43,4 +43,5 @@
 	};
 	struct ImpurityDetectorIgnoreUnique : public ImpurityDetector {
+		using ImpurityDetector::previsit;
 		void previsit( ast::UniqueExpr const * ) {
 			visit_children = false;
@@ -52,5 +53,5 @@
 		ast::Pass<Detector> detector;
 		expr->accept( detector );
-		return detector.pass.maybeImpure;
+		return detector.core.maybeImpure;
 	}
 } // namespace
Index: src/config.h.in
===================================================================
--- src/config.h.in	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/config.h.in	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -27,4 +27,8 @@
 /* Location of cfa install. */
 #undef CFA_PREFIX
+
+/* Sets whether or not to use the new-ast, this is adefault value and can be
+   overrided by --old-ast and --new-ast */
+#undef CFA_USE_NEW_AST
 
 /* Major.Minor */
Index: src/main.cc
===================================================================
--- src/main.cc	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ src/main.cc	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -31,5 +31,5 @@
 using namespace std;
 
-
+#include "AST/Convert.hpp"
 #include "CompilationState.h"
 #include "../config.h"                      // for CFA_LIBDIR
@@ -340,5 +340,12 @@
 		} // if
 
-		PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
+		if( useNewAST) {
+			auto transUnit = convert( move( translationUnit ) );
+			PASS( "Resolve", ResolvExpr::resolve( transUnit ) );
+			translationUnit = convert( move( transUnit ) );
+		} else {
+			PASS( "Resolve", ResolvExpr::resolve( translationUnit ) );
+		}
+
 		if ( exprp ) {
 			dump( translationUnit );
@@ -458,4 +465,6 @@
 	{ "prototypes", no_argument, nullptr, 'p' },
 	{ "deterministic-out", no_argument, nullptr, 'd' },
+	{ "old-ast", no_argument, nullptr, 'O'},
+	{ "new-ast", no_argument, nullptr, 'A'},
 	{ "print", required_argument, nullptr, 'P' },
 	{ "prelude-dir", required_argument, nullptr, PreludeDir },
@@ -479,4 +488,6 @@
 	"generate prototypes for prelude functions",		// -p
 	"don't print output that isn't deterministic",        // -d
+	"Use the old-ast",                                    // -O
+	"Use the new-ast",                                    // -A
 	"print",                                              // -P
 	"<directory> prelude directory for debug/nodebug",	// no flag
@@ -584,5 +595,11 @@
 			break;
 		  case 'd':                                     // don't print non-deterministic output
-		    deterministic_output = true;
+			deterministic_output = true;
+			break;
+		  case 'O':                                     // don't print non-deterministic output
+			useNewAST = false;
+			break;
+		  case 'A':                                     // don't print non-deterministic output
+			useNewAST = true;
 			break;
 		  case 'P':										// print options
Index: tests/.expect/alloc-ERROR.txt
===================================================================
--- tests/.expect/alloc-ERROR.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/alloc-ERROR.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -16,4 +16,6 @@
           Name: stp
 
+      with resolved type:
+        unsigned long int
 
 
@@ -28,4 +30,6 @@
     Name: stp
     constant expression (10 10: signed int)
+    with resolved type:
+      signed int
 
 
Index: tests/.expect/castError.txt
===================================================================
--- tests/.expect/castError.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/castError.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -3,4 +3,6 @@
   Name: f
 ... to:
+  char
+with resolved type:
   char Alternatives are:
 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
@@ -9,5 +11,12 @@
       ... returning nothing
 
+      with resolved type:
+        pointer to function
+          accepting unspecified arguments
+        ... returning nothing
+
     ... to:
+      char
+    with resolved type:
       char
   (types:
@@ -18,5 +27,9 @@
 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
       Variable Expression: f: double
+      with resolved type:
+        double
     ... to:
+      char
+    with resolved type:
       char
   (types:
@@ -27,5 +40,9 @@
 Cost ( 1, 0, 0, 0, 0, 0, 0 ): Explicit Cast of:
       Variable Expression: f: signed int
+      with resolved type:
+        signed int
     ... to:
+      char
+    with resolved type:
       char
   (types:
@@ -39,11 +56,23 @@
   Comma Expression:
     constant expression (3 3: signed int)
+    with resolved type:
+      signed int
     Name: v
-... to: nothing Alternatives are:
+... to: nothing
+with resolved type:
+  void  Alternatives are:
 Cost ( 0, 0, 2, 0, 0, 0, 0 ): Generated Cast of:
       Comma Expression:
         constant expression (3 3: signed int)
+        with resolved type:
+          signed int
         Variable Expression: v: unsigned char
+        with resolved type:
+          unsigned char
+      with resolved type:
+        unsigned char
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -54,6 +83,14 @@
       Comma Expression:
         constant expression (3 3: signed int)
+        with resolved type:
+          signed int
         Variable Expression: v: signed short int
+        with resolved type:
+          signed short int
+      with resolved type:
+        signed short int
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -69,2 +106,7 @@
     char
 
+with resolved type:
+  instance of struct S with body 1
+  ... with parameters
+    char
+
Index: tests/.expect/declarationSpecifier.x64.txt
===================================================================
--- tests/.expect/declarationSpecifier.x64.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/declarationSpecifier.x64.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1129,7 +1129,22 @@
 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
 static inline signed int invoke_main(signed int argc, char **argv, char **envp);
+signed int _X13cfa_args_argci_1;
+char **_X13cfa_args_argvPPc_1;
+char **_X13cfa_args_envpPPc_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
     {
+        ((void)(_X13cfa_args_argci_1=_X4argci_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
+    }
+
+    {
         signed int _tmp_cp_ret4;
         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
Index: tests/.expect/declarationSpecifier.x86.txt
===================================================================
--- tests/.expect/declarationSpecifier.x86.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/declarationSpecifier.x86.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1129,7 +1129,22 @@
 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
 static inline signed int invoke_main(signed int argc, char **argv, char **envp);
+signed int _X13cfa_args_argci_1;
+char **_X13cfa_args_argvPPc_1;
+char **_X13cfa_args_envpPPc_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
     {
+        ((void)(_X13cfa_args_argci_1=_X4argci_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
+    }
+
+    {
         signed int _tmp_cp_ret4;
         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
Index: tests/.expect/gccExtensions.x64.txt
===================================================================
--- tests/.expect/gccExtensions.x64.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/gccExtensions.x64.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -321,7 +321,22 @@
 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
 static inline signed int invoke_main(signed int argc, char **argv, char **envp);
+signed int _X13cfa_args_argci_1;
+char **_X13cfa_args_argvPPc_1;
+char **_X13cfa_args_envpPPc_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
     {
+        ((void)(_X13cfa_args_argci_1=_X4argci_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
+    }
+
+    {
         signed int _tmp_cp_ret4;
         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
Index: tests/.expect/gccExtensions.x86.txt
===================================================================
--- tests/.expect/gccExtensions.x86.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/gccExtensions.x86.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -299,7 +299,22 @@
 static inline int invoke_main(int argc, char* argv[], char* envp[]) { (void)argc; (void)argv; (void)envp; return _X4mainFi_iPPKc__1((signed int )argc, (const char **)argv); }
 static inline signed int invoke_main(signed int argc, char **argv, char **envp);
+signed int _X13cfa_args_argci_1;
+char **_X13cfa_args_argvPPc_1;
+char **_X13cfa_args_envpPPc_1;
 signed int main(signed int _X4argci_1, char **_X4argvPPc_1, char **_X4envpPPc_1){
     __attribute__ ((unused)) signed int _X12_retval_maini_1;
     {
+        ((void)(_X13cfa_args_argci_1=_X4argci_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_argvPPc_1=_X4argvPPc_1));
+    }
+
+    {
+        ((void)(_X13cfa_args_envpPPc_1=_X4envpPPc_1));
+    }
+
+    {
         signed int _tmp_cp_ret4;
         ((void)(_X12_retval_maini_1=(((void)(_tmp_cp_ret4=invoke_main(_X4argci_1, _X4argvPPc_1, _X4envpPPc_1))) , _tmp_cp_ret4)) /* ?{} */);
Index: tests/.expect/init1.txt
===================================================================
--- tests/.expect/init1.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/init1.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -11,4 +11,6 @@
 ... to:
   reference to signed int
+with resolved type:
+  reference to signed int
 init1.cfa:97:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?{}
@@ -16,5 +18,9 @@
   Generated Cast of:
     Variable Expression: _retval_f_py: pointer to signed int
+    with resolved type:
+      pointer to signed int
   ... to:
+    reference to pointer to signed int
+  with resolved type:
     reference to pointer to signed int
   Name: px
@@ -24,4 +30,6 @@
 ... to:
   reference to float
+with resolved type:
+  reference to float
 init1.cfa:107:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?{}
@@ -29,5 +37,9 @@
   Generated Cast of:
     Variable Expression: _retval_f_py2: pointer to float
+    with resolved type:
+      pointer to float
   ... to:
+    reference to pointer to float
+  with resolved type:
     reference to pointer to float
   Name: cpx
@@ -37,4 +49,6 @@
 ... to:
   reference to instance of type T (not function type)
+with resolved type:
+  reference to instance of type T (not function type)
 init1.cfa:118:1 error: No reasonable alternatives for expression Applying untyped:
   Name: ?{}
@@ -42,5 +56,9 @@
   Generated Cast of:
     Variable Expression: _retval_anycvt: pointer to instance of type T (not function type)
+    with resolved type:
+      pointer to instance of type T (not function type)
   ... to:
+    reference to pointer to instance of type T (not function type)
+  with resolved type:
     reference to pointer to instance of type T (not function type)
   Name: s
Index: tests/.expect/minmax.txt
===================================================================
--- tests/.expect/minmax.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/.expect/minmax.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1,8 +1,8 @@
 char			z a	min a
-signed int		4 3	min 3
+signed int		4 -3	min -3
 unsigned int		4 3	min 3
-signed long int		4 3	min 3
+signed long int		4 -3	min -3
 unsigned long int	4 3	min 3
-signed long long int	4 3	min 3
+signed long long int	4 -3	min -3
 unsigned long long int	4 3	min 3
 float			4. 3.1	min 3.1
@@ -11,9 +11,9 @@
 
 char			z a	max z
-signed int		4 3	max 4
+signed int		4 -3	max 4
 unsigned int		4 3	max 4
-signed long int		4 3	max 4
+signed long int		4 -3	max 4
 unsigned long int	4 3	max 4
-signed long long int	4 3	max 4
+signed long long int	4 -3	max 4
 unsigned long long int	4 3	max 4
 float			4. 3.1	max 4.
Index: tests/Makefile.am
===================================================================
--- tests/Makefile.am	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/Makefile.am	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -163,4 +163,11 @@
 	$(CFACOMPILETEST) -DERR2 -c -fsyntax-only -o $(abspath ${@})
 
+# Exception Tests
+# Test with libcfathread; it changes how storage works.
+
+exceptions/%-threads : exceptions/%.cfa $(CFACCBIN)
+	$(CFACOMPILETEST) -include exceptions/with-threads.hfa -c -o $(abspath ${@}).o
+	$(CFACCLOCAL) $($(shell echo "${@}_FLAGSLD" | sed 's/-\|\//_/g')) $(abspath ${@}).o -o $(abspath ${@})
+
 #------------------------------------------------------------------------------
 # Other targets
Index: tests/alloc.cfa
===================================================================
--- tests/alloc.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/alloc.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed Feb  3 07:56:22 2016
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Apr  6 21:08:23 2020
-// Update Count     : 428
+// Last Modified On : Fri Aug 14 16:59:59 2020
+// Update Count     : 430
 //
 
@@ -90,5 +90,5 @@
 	// do not free
 
-	ip1 = alloc_set( 2 * dim, ip );						// CFA array alloc, fill
+	ip1 = alloc_set( 2 * dim, ip, 2 * dim );				// CFA array alloc, fill
 	printf( "CFA array alloc, fill from array\n" );
 	for ( i; 2 * dim ) { printf( "%#x %#x, ", ip[i], ip1[i] ); }
@@ -288,5 +288,5 @@
 	// do not free
 
-	stp1 = alloc_align_set( Alignment, dim, stp );		// CFA array memalign, fill
+	stp1 = alloc_align_set( Alignment, dim, stp, dim );	// CFA array memalign, fill
 	assert( (uintptr_t)stp % Alignment == 0 );
 	printf( "CFA array alloc_align, fill array\n" );
Index: tests/errors/.expect/completeType.x64.txt
===================================================================
--- tests/errors/.expect/completeType.x64.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/errors/.expect/completeType.x64.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -6,5 +6,7 @@
     Name: x
 
-... to: nothing Alternatives are:
+... to: nothing
+with resolved type:
+  void  Alternatives are:
 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
       Application of
@@ -20,8 +22,26 @@
 
 
+        with resolved type:
+          pointer to forall
+            _90_4_DT: data type
+            function
+          ... with parameters
+            intrinsic pointer to instance of type _90_4_DT (not function type)
+          ... returning
+            _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
+            ... with attributes:
+              Attribute with name: unused
+
+
       ... to arguments
         Variable Expression: x: pointer to instance of struct A with body 0
-
+        with resolved type:
+          pointer to instance of struct A with body 0
+
+      with resolved type:
+        reference to instance of struct A with body 0
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -43,8 +63,26 @@
 
 
+        with resolved type:
+          pointer to forall
+            _90_4_DT: data type
+            function
+          ... with parameters
+            intrinsic pointer to instance of type _90_4_DT (not function type)
+          ... returning
+            _retval__operator_deref: reference to instance of type _90_4_DT (not function type)
+            ... with attributes:
+              Attribute with name: unused
+
+
       ... to arguments
         Variable Expression: x: pointer to instance of struct B with body 1
-
+        with resolved type:
+          pointer to instance of struct B with body 1
+
+      with resolved type:
+        reference to instance of struct B with body 1
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -121,7 +159,47 @@
             ... returning nothing
 
+            with resolved type:
+              pointer to forall
+                _109_0_T: sized data type
+                ... with assertions
+                  ?=?: pointer to function
+                  ... with parameters
+                    reference to instance of type _109_0_T (not function type)
+                    instance of type _109_0_T (not function type)
+                  ... returning
+                    _retval__operator_assign: instance of type _109_0_T (not function type)
+                    ... with attributes:
+                      Attribute with name: unused
+
+
+                  ?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _109_0_T (not function type)
+                  ... returning nothing
+
+                  ?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _109_0_T (not function type)
+                    instance of type _109_0_T (not function type)
+                  ... returning nothing
+
+                  ^?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _109_0_T (not function type)
+                  ... returning nothing
+
+
+                function
+              ... with parameters
+                pointer to instance of type _109_0_T (not function type)
+              ... returning nothing
+
           ... to arguments
             Variable Expression: z: pointer to instance of type T (not function type)
-
+            with resolved type:
+              pointer to instance of type T (not function type)
+
+          with resolved type:
+            void 
         (types:
           void 
Index: tests/errors/.expect/completeType.x86.txt
===================================================================
--- tests/errors/.expect/completeType.x86.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/errors/.expect/completeType.x86.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -6,5 +6,7 @@
     Name: x
 
-... to: nothing Alternatives are:
+... to: nothing
+with resolved type:
+  void  Alternatives are:
 Cost ( 0, 1, 2, 0, 1, -1, 0 ): Generated Cast of:
       Application of
@@ -20,8 +22,26 @@
 
 
+        with resolved type:
+          pointer to forall
+            _89_4_DT: data type
+            function
+          ... with parameters
+            intrinsic pointer to instance of type _89_4_DT (not function type)
+          ... returning
+            _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
+            ... with attributes:
+              Attribute with name: unused
+
+
       ... to arguments
         Variable Expression: x: pointer to instance of struct A with body 0
-
+        with resolved type:
+          pointer to instance of struct A with body 0
+
+      with resolved type:
+        reference to instance of struct A with body 0
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -43,8 +63,26 @@
 
 
+        with resolved type:
+          pointer to forall
+            _89_4_DT: data type
+            function
+          ... with parameters
+            intrinsic pointer to instance of type _89_4_DT (not function type)
+          ... returning
+            _retval__operator_deref: reference to instance of type _89_4_DT (not function type)
+            ... with attributes:
+              Attribute with name: unused
+
+
       ... to arguments
         Variable Expression: x: pointer to instance of struct B with body 1
-
+        with resolved type:
+          pointer to instance of struct B with body 1
+
+      with resolved type:
+        reference to instance of struct B with body 1
     ... to: nothing
+    with resolved type:
+      void 
   (types:
     void 
@@ -121,7 +159,47 @@
             ... returning nothing
 
+            with resolved type:
+              pointer to forall
+                _108_0_T: sized data type
+                ... with assertions
+                  ?=?: pointer to function
+                  ... with parameters
+                    reference to instance of type _108_0_T (not function type)
+                    instance of type _108_0_T (not function type)
+                  ... returning
+                    _retval__operator_assign: instance of type _108_0_T (not function type)
+                    ... with attributes:
+                      Attribute with name: unused
+
+
+                  ?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _108_0_T (not function type)
+                  ... returning nothing
+
+                  ?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _108_0_T (not function type)
+                    instance of type _108_0_T (not function type)
+                  ... returning nothing
+
+                  ^?{}: pointer to function
+                  ... with parameters
+                    reference to instance of type _108_0_T (not function type)
+                  ... returning nothing
+
+
+                function
+              ... with parameters
+                pointer to instance of type _108_0_T (not function type)
+              ... returning nothing
+
           ... to arguments
             Variable Expression: z: pointer to instance of type T (not function type)
-
+            with resolved type:
+              pointer to instance of type T (not function type)
+
+          with resolved type:
+            void 
         (types:
           void 
Index: tests/exceptions/.expect/conditional-threads.txt
===================================================================
--- tests/exceptions/.expect/conditional-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/conditional-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,2 @@
+Caught num_error: expected=2 actual=2.
+Caught num_error: expected=2 actual=2.
Index: tests/exceptions/.expect/defaults-threads.txt
===================================================================
--- tests/exceptions/.expect/defaults-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/defaults-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,10 @@
+Should be printed.
+jump catch handler.
+jump default handler.
+Catch unhandled_exception.
+cross terminate throw
+cross terminate default
+cross terminate catch
+cross resume throw
+cross resume default
+cross resume catch
Index: tests/exceptions/.expect/finally-threads.txt
===================================================================
--- tests/exceptions/.expect/finally-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/finally-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,21 @@
+termination throw
+finally during unwind
+Exiting: termination inner finally
+termination catch
+finally after catch
+Exiting: termination outer finally
+
+resumption throw
+resumption catch
+finally after resume
+Exiting: resumption inner finally
+finally after catch
+Exiting: resumption outer finally
+
+walking out of try
+walking through finally
+Exiting: walking finally
+
+jumping out of try
+jumping through finally
+Exiting: jumping finally
Index: tests/exceptions/.expect/resume-threads.txt
===================================================================
--- tests/exceptions/.expect/resume-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/resume-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,36 @@
+simple throw
+simple catch
+Exiting: simple catch clause
+end of try clause
+Exiting: simple try clause
+
+catch-all
+
+throwing child exception
+inner parent match
+
+caught yin as yin
+
+rethrow inner try
+caught throw, will rethrow
+Exiting: rethrowing catch clause
+caught rethrow
+Exiting: rethrow catch clause
+Exiting: rethrow inner try
+
+caught yin, will throw yang
+caught yang
+
+throwing first exception
+caught first exception
+throwing second exception
+caught second exception
+recaught first exception
+
+inner catch
+inner catch
+outer catch
+
+throw
+rethrow
+handle
Index: tests/exceptions/.expect/terminate-threads.txt
===================================================================
--- tests/exceptions/.expect/terminate-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/terminate-threads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,34 @@
+simple throw
+Exiting: simple try clause
+simple catch
+Exiting: simple catch clause
+
+catch-all
+
+throwing child exception
+inner parent match
+
+caught yin as yin
+
+rethrow inner try
+Exiting: rethrow inner try
+caught throw, will rethrow
+Exiting: rethrowing catch clause
+caught rethrow
+Exiting: rethrow catch clause
+
+caught yin, will throw yang
+caught yang
+
+throwing first exception
+caught first exception
+throwing second exception
+caught second exception
+recaught first exception
+
+inner catch
+outer catch
+
+throw
+rethrow
+handle
Index: tests/exceptions/.expect/trash.txt
===================================================================
--- tests/exceptions/.expect/trash.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/.expect/trash.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,2 @@
+inner yang
+outer yin
Index: tests/exceptions/terminate.cfa
===================================================================
--- tests/exceptions/terminate.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/exceptions/terminate.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -142,3 +142,2 @@
 	}
 }
-
Index: tests/exceptions/trash.cfa
===================================================================
--- tests/exceptions/trash.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/trash.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,27 @@
+// Make sure throw-catch during unwind does not trash internal data.
+
+#include <exception.hfa>
+#include <stdio.h>
+
+TRIVIAL_EXCEPTION(yin);
+TRIVIAL_EXCEPTION(yang);
+
+int main(int argc, char * argv[]) {
+	try {
+		try {
+			throw (yin){};
+		} finally {
+			try {
+				throw (yang){};
+			} catch (yin *) {
+				printf("inner yin\n");
+			} catch (yang *) {
+				printf("inner yang\n");
+			}
+		}
+	} catch (yin *) {
+		printf("outer yin\n");
+	} catch (yang *) {
+		printf("outer yang\n");
+	}
+}
Index: tests/exceptions/with-threads.hfa
===================================================================
--- tests/exceptions/with-threads.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/exceptions/with-threads.hfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,8 @@
+// Header used to force linking with libcfathread.
+
+// I know its "with threads" but a coroutine is enough to bring it all in.
+#include <coroutine.hfa>
+
+coroutine DummyCoroutine {};
+
+DummyCoroutine ignored_dummy_coroutine;
Index: tests/heap.cfa
===================================================================
--- tests/heap.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/heap.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Tue Nov  6 17:54:56 2018
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Aug  4 06:36:17 2020
-// Update Count     : 56
+// Last Modified On : Sun Aug  9 08:05:16 2020
+// Update Count     : 57
 // 
 
@@ -232,14 +232,11 @@
 		size_t s = i + default_mmap_start();			// cross over point
 		char * area = (char *)calloc( 1, s );
-// 		if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
 		if ( area[0] != '\0' || area[s - 1] != '\0' ||
 			 area[malloc_size( area ) - 1] != '\0' ||
-			 ! malloc_zero_fill( area ) ) //abort( "calloc/realloc/free corrupt storage3" );
-			printf( "C %zd %d %d %d %d\n", s, area[0] != '\0', area[s - 1] != '\0', area[malloc_size( area ) - 1] != '\0', ! malloc_zero_fill( area ) );
+			 ! malloc_zero_fill( area ) ) abort( "calloc/realloc/free corrupt storage3" );
 
 		// Do not start this loop index at 0 because realloc of 0 bytes frees the storage.
 		for ( r; i ~ 256 * 1024 ~ 26 ) {				// start at initial memory request
 			area = (char *)realloc( area, r );			// attempt to reuse storage
-// 			if ( area == 0p ) abort( "calloc/realloc/free out of memory" );
 			if ( area[0] != '\0' || area[r - 1] != '\0' ||
 				 area[malloc_size( area ) - 1] != '\0' ||
@@ -255,5 +252,4 @@
 		// initial N byte allocation
 		char * area = (char *)memalign( a, amount );	// aligned N-byte allocation
-// 		if ( area == 0p ) abort( "memalign/realloc/free out of memory" ); // no storage ?
 		//sout | alignments[a] | area;
 		if ( (size_t)area % a != 0 || malloc_alignment( area ) != a ) { // check for initial alignment
Index: tests/linking/.expect/exception-nothreads.txt
===================================================================
--- tests/linking/.expect/exception-nothreads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/linking/.expect/exception-nothreads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,1 @@
+no threads
Index: tests/linking/.expect/exception-withthreads.txt
===================================================================
--- tests/linking/.expect/exception-withthreads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/linking/.expect/exception-withthreads.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,1 @@
+with threads
Index: tests/linking/exception-nothreads.cfa
===================================================================
--- tests/linking/exception-nothreads.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/linking/exception-nothreads.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,33 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// exception-nothreads.cfa --
+//
+// Author           : Andrew Beach
+// Created On       : Thr 13 16:12:00 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Thr 13 16:49:00 2020
+// Update Count     : 0
+//
+
+#include <stdlib.hfa>
+#include <exception.hfa>
+
+TRIVIAL_EXCEPTION(ping);
+
+int main(void) {
+	try {
+		throwResume (ping){};
+	} catchResume (ping *) {
+		printf("%s threads\n", threading_enabled() ? "with" : "no");
+	}
+	return 0;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa nothreads.cfa" //
+// End: //
Index: tests/linking/exception-withthreads.cfa
===================================================================
--- tests/linking/exception-withthreads.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/linking/exception-withthreads.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,34 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// exception-withthreads.cfa --
+//
+// Author           : Andrew Beach
+// Created On       : Thr 13 16:12:00 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri 14 11:20:00 2020
+// Update Count     : 0
+//
+
+#include <stdlib.hfa>
+#include <exception.hfa>
+#include "../exceptions/with-threads.hfa"
+
+TRIVIAL_EXCEPTION(ping);
+
+int main(void) {
+	try {
+		throwResume (ping){};
+	} catchResume (ping *) {
+		printf("%s threads\n", threading_enabled() ? "with" : "no");
+	}
+	return 0;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa nothreads.cfa" //
+// End: //
Index: tests/linking/withthreads.cfa
===================================================================
--- tests/linking/withthreads.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/linking/withthreads.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -5,5 +5,5 @@
 // file "LICENCE" distributed with Cforall.
 //
-// nothreads.cfa --
+// withthreads.cfa --
 //
 // Author           : Thierry Delisle
Index: tests/literals.cfa
===================================================================
--- tests/literals.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/literals.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Sat Sep  9 16:34:38 2017
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb 12 08:07:39 2019
-// Update Count     : 224
+// Last Modified On : Thu Aug 20 13:51:12 2020
+// Update Count     : 225
 //
 
@@ -214,9 +214,9 @@
 	-01234567_l8;  -01234567_l16;  -01234567_l32;  -01234567_l64;  -01234567_l8u;  -01234567_ul16;  -01234567_l32u;  -01234567_ul64;
 
-#ifdef __LP64__ // 64-bit processor
+#if defined( __SIZEOF_INT128__ )
 	01234567_l128;   01234567_ul128;
 	+01234567_l128;  +01234567_ul128;
 	-01234567_l128;  -01234567_ul128;
-#endif // __LP64__
+#endif // __SIZEOF_INT128__
 
 	// decimal
@@ -225,9 +225,11 @@
 	-1234567890L8;  -1234567890L16;  -1234567890l32;  -1234567890l64;  -1234567890UL8;  -1234567890L16U;  -1234567890Ul32;  -1234567890l64u;
 
-#ifdef __LP64__ // 64-bit processor
+#if defined( __SIZEOF_INT128__ )
 	1234567890l128;   1234567890l128u;
 	+1234567890l128;  +1234567890l128u;
 	-1234567890l128;  -1234567890l128u;
-#endif // __LP64__
+    1234567890123456789_L128u; 1234567890123456789_L128u;
+	18446708753438544741_l64u; 18446708753438544741_Ul64;
+#endif // __SIZEOF_INT128__
 
 	// hexadecimal
Index: tests/minmax.cfa
===================================================================
--- tests/minmax.cfa	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/minmax.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -10,6 +10,6 @@
 // Created On       : Wed May 27 17:56:53 2015
 // Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Dec  4 21:45:31 2018
-// Update Count     : 52
+// Last Modified On : Sat Aug 15 08:28:01 2020
+// Update Count     : 54
 //
 
@@ -23,9 +23,9 @@
 
 	sout | "char\t\t\t"					| 'z' | ' ' | 'a' | "\tmin " | min( 'z', 'a' );
-	sout | "signed int\t\t"				| 4 | 3 | "\tmin" | min( 4, 3 );
+	sout | "signed int\t\t"				| 4 | -3 | "\tmin" | min( 4, -3 );
 	sout | "unsigned int\t\t"			| 4u | 3u | "\tmin" | min( 4u, 3u );
-	sout | "signed long int\t\t" 		| 4l | 3l | "\tmin" | min( 4l, 3l );
+	sout | "signed long int\t\t" 		| 4l | -3l | "\tmin" | min( 4l, -3l );
 	sout | "unsigned long int\t" 		| 4ul | 3ul | "\tmin" | min( 4ul, 3ul );
-	sout | "signed long long int\t"		| 4ll | 3ll | "\tmin" | min( 4ll, 3ll );
+	sout | "signed long long int\t"		| 4ll | -3ll | "\tmin" | min( 4ll, -3ll );
 	sout | "unsigned long long int\t"	| 4ull | 3ull | "\tmin" | min( 4ull, 3ull );
 	sout | "float\t\t\t" 				| 4.0f | 3.1f | "\tmin" | min( 4.0f, 3.1f );
@@ -36,9 +36,9 @@
 
 	sout | "char\t\t\t"					| 'z' | ' ' | 'a' | "\tmax " | max( 'z', 'a' );
-	sout | "signed int\t\t"				| 4 | 3 | "\tmax" | max( 4, 3 );
+	sout | "signed int\t\t"				| 4 | -3 | "\tmax" | max( 4, -3 );
 	sout | "unsigned int\t\t"			| 4u | 3u | "\tmax" | max( 4u, 3u );
-	sout | "signed long int\t\t" 		| 4l | 3l | "\tmax" | max( 4l, 3l );
+	sout | "signed long int\t\t" 		| 4l | -3l | "\tmax" | max( 4l, -3l );
 	sout | "unsigned long int\t" 		| 4ul | 3ul | "\tmax" | max( 4ul, 3ul );
-	sout | "signed long long int\t"		| 4ll | 3ll | "\tmax" | max( 4ll, 3ll );
+	sout | "signed long long int\t"		| 4ll | -3ll | "\tmax" | max( 4ll, -3ll );
 	sout | "unsigned long long int\t"	| 4ull | 3ull | "\tmax" | max( 4ull, 3ull );
 	sout | "float\t\t\t" 				| 4.0f | 3.1f | "\tmax" | max( 4.0f, 3.1f );
Index: tests/pybin/tools.py
===================================================================
--- tests/pybin/tools.py	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/pybin/tools.py	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -246,5 +246,5 @@
 # transform path to canonical form
 def canonical_path(path):
-	abspath = os.path.abspath(__main__.__file__)
+	abspath = os.path.abspath(os.path.realpath(__main__.__file__))
 	dname = os.path.dirname(abspath)
 	return os.path.join(dname, os.path.normpath(path) )
Index: tests/raii/.expect/ctor-autogen-ERR1.txt
===================================================================
--- tests/raii/.expect/ctor-autogen-ERR1.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/raii/.expect/ctor-autogen-ERR1.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -7,4 +7,11 @@
         x: signed int
       ... returning nothing
+
+      with resolved type:
+        function
+        ... with parameters
+          _dst: reference to instance of struct Managed with body 1
+          x: signed int
+        ... returning nothing
 
       ... deleted by: ?{}: function
@@ -26,4 +33,15 @@
 
 
+              with resolved type:
+                pointer to function
+                ... with parameters
+                  intrinsic reference to signed int
+                  intrinsic signed int
+                ... returning
+                  _retval__operator_assign: signed int
+                  ... with attributes:
+                    Attribute with name: unused
+
+
             ... to arguments
               Generated Cast of:
@@ -33,13 +51,27 @@
                   Generated Cast of:
                     Variable Expression: m: reference to instance of struct Managed with body 1
+                    with resolved type:
+                      reference to instance of struct Managed with body 1
                   ... to:
                     instance of struct Managed with body 1
+                  with resolved type:
+                    instance of struct Managed with body 1
+                with resolved type:
+                  signed int
               ... to:
+                reference to signed int
+              with resolved type:
                 reference to signed int
               Generated Cast of:
                 constant expression (0 0: zero_t)
+                with resolved type:
+                  zero_t
               ... to:
                 signed int
+              with resolved type:
+                signed int
 
+            with resolved type:
+              signed int
             ... with environment:
               Types:
@@ -50,7 +82,17 @@
     Generated Cast of:
       Variable Expression: x: instance of struct Managed with body 1
+      with resolved type:
+        instance of struct Managed with body 1
     ... to:
       reference to instance of struct Managed with body 1
+    with resolved type:
+      reference to instance of struct Managed with body 1
     constant expression (123 123: signed int)
+    with resolved type:
+      signed int
 
+  with resolved type:
+    void 
 ... to: nothing
+with resolved type:
+  void 
Index: tests/resolutionErrors.cfa
===================================================================
--- tests/resolutionErrors.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
+++ tests/resolutionErrors.cfa	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -0,0 +1,47 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// resolutionErrors.cfa --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu Nov 28 15:17:52 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+struct atype {};
+
+void noparams() {}
+void wrongparams( atype& ) {}
+void moreparams( int, int ) {}
+void fewparams( int ) {}
+void noreturn() {}
+
+void simple_calls() {
+	notexist();
+	notexistparams( 3 );
+	noparams( 3 );
+	wrongparams( 3 );
+	moreparams( 3 );
+	fewparams( 3, 3 );
+	int a = noreturn();
+
+	int notfunction;
+	notfunction(3);
+
+	atype t;
+	t.a;
+}
+
+void ctor_calls() {
+	atype a = 3;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// compile-command: "cfa resolutionErrors.cfa" //
+// End: //
Index: tests/warnings/.expect/self-assignment.txt
===================================================================
--- tests/warnings/.expect/self-assignment.txt	(revision 67ca73e71dbea21372d807389df49e401624ec3b)
+++ tests/warnings/.expect/self-assignment.txt	(revision e67a82d79e32a55496140aa883716d9123ccc7f7)
@@ -1,9 +1,17 @@
 warnings/self-assignment.cfa:29:1 warning: self assignment of expression: Generated Cast of:
   Variable Expression: j: signed int
+  with resolved type:
+    signed int
 ... to:
+  reference to signed int
+with resolved type:
   reference to signed int
 warnings/self-assignment.cfa:30:1 warning: self assignment of expression: Generated Cast of:
   Variable Expression: s: instance of struct S with body 1
+  with resolved type:
+    instance of struct S with body 1
 ... to:
+  reference to instance of struct S with body 1
+with resolved type:
   reference to instance of struct S with body 1
 warnings/self-assignment.cfa:31:1 warning: self assignment of expression: Generated Cast of:
@@ -12,5 +20,11 @@
   ... from aggregate:
     Variable Expression: s: instance of struct S with body 1
+    with resolved type:
+      instance of struct S with body 1
+  with resolved type:
+    signed int
 ... to:
+  reference to signed int
+with resolved type:
   reference to signed int
 warnings/self-assignment.cfa:32:1 warning: self assignment of expression: Generated Cast of:
@@ -22,4 +36,12 @@
     ... from aggregate:
       Variable Expression: t: instance of struct T with body 1
+      with resolved type:
+        instance of struct T with body 1
+    with resolved type:
+      instance of struct S with body 1
+  with resolved type:
+    signed int
 ... to:
   reference to signed int
+with resolved type:
+  reference to signed int
