Index: src/Common/Assert.cc
===================================================================
--- src/Common/Assert.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,55 +1,0 @@
-//
-// 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.
-//
-// Assert.cc --
-//
-// Author           : Peter A. Buhr
-// Created On       : Thu Aug 18 13:26:59 2016
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Nov 20 22:57:18 2023
-// Update Count     : 11
-//
-
-#include <cstdarg>  // for va_end, va_list, va_start
-#include <cstdio>   // for fprintf, stderr, vfprintf
-#include <cstdlib>  // for abort
-
-extern const char * __progname;							// global name of running executable (argv[0])
-
-#define CFA_ASSERT_FMT "*CFA assertion error* \"%s\" from program \"%s\" in \"%s\" at line %d in file \"%s\""
-
-// called by macro assert in assert.h
-void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
-	fprintf( stderr, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
-	abort();
-}
-
-// called by macro assertf
-void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
-	fprintf( stderr, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
-	va_list args;
-	va_start( args, fmt );
-	vfprintf( stderr, fmt, args );
-	va_end( args );
-	fprintf( stderr, "\n" );
-	abort();
-}
-
-void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2)));
-void abort(const char *fmt, ... ) noexcept {
-	va_list args;
-	va_start( args, fmt );
-	vfprintf( stderr, fmt, args );
-	va_end( args );
-	fprintf( stderr, "\n" );
-	abort();
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End:  //
Index: src/Common/Assert.cpp
===================================================================
--- src/Common/Assert.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Assert.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,55 @@
+//
+// 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.
+//
+// Assert.cc --
+//
+// Author           : Peter A. Buhr
+// Created On       : Thu Aug 18 13:26:59 2016
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Nov 20 22:57:18 2023
+// Update Count     : 11
+//
+
+#include <cstdarg>  // for va_end, va_list, va_start
+#include <cstdio>   // for fprintf, stderr, vfprintf
+#include <cstdlib>  // for abort
+
+extern const char * __progname;							// global name of running executable (argv[0])
+
+#define CFA_ASSERT_FMT "*CFA assertion error* \"%s\" from program \"%s\" in \"%s\" at line %d in file \"%s\""
+
+// called by macro assert in assert.h
+void __assert_fail( const char *assertion, const char *file, unsigned int line, const char *function ) {
+	fprintf( stderr, CFA_ASSERT_FMT ".\n", assertion, __progname, function, line, file );
+	abort();
+}
+
+// called by macro assertf
+void __assert_fail_f( const char *assertion, const char *file, unsigned int line, const char *function, const char *fmt, ... ) {
+	fprintf( stderr, CFA_ASSERT_FMT ": ", assertion, __progname, function, line, file );
+	va_list args;
+	va_start( args, fmt );
+	vfprintf( stderr, fmt, args );
+	va_end( args );
+	fprintf( stderr, "\n" );
+	abort();
+}
+
+void abort(const char *fmt, ... ) noexcept __attribute__((noreturn, format(printf, 1, 2)));
+void abort(const char *fmt, ... ) noexcept {
+	va_list args;
+	va_start( args, fmt );
+	vfprintf( stderr, fmt, args );
+	va_end( args );
+	fprintf( stderr, "\n" );
+	abort();
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End:  //
Index: src/Common/CodeLocation.h
===================================================================
--- src/Common/CodeLocation.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,75 +1,0 @@
-//
-// 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.
-//
-// CodeLocation.h --
-//
-// Author           : Andrew Beach
-// Created On       : Thr Aug 17 11:23:00 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Aug 28 12:46:01 2017
-// Update Count     : 2
-//
-
-#pragma once
-
-#include <iostream>
-#include <string>
-
-struct CodeLocation {
-	int first_line = -1, first_column = -1, last_line = -1, last_column = -1;
-	std::string filename = "";
-
-	/// Create a new unset CodeLocation.
-	CodeLocation() = default;
-
-	/// Create a new CodeLocation with the given values.
-	CodeLocation( const char* filename, int lineno )
-		: first_line( lineno )
-		, filename(filename ? filename : "")
-	{}
-
-	CodeLocation( const CodeLocation& rhs ) = default;
-	CodeLocation( CodeLocation&& rhs ) = default;
-	CodeLocation& operator=( const CodeLocation & ) = default;
-	CodeLocation& operator=( CodeLocation && ) = default;
-
-	bool isSet () const {
-		return -1 != first_line;
-	}
-
-	bool isUnset () const {
-		return !isSet();
-	}
-
-	bool startsBefore( CodeLocation const & other ) const {
-		if( filename < other.filename ) return true;
-		if( filename > other.filename ) return false;
-
-		if( first_line < other.first_line ) return true;
-		if( first_line > other.first_line ) return false;
-
-		if( last_line < other.last_line ) return true;
-		return false;
-	}
-
-	bool followedBy( CodeLocation const & other, int seperation ) const {
-		return (first_line + seperation == other.first_line &&
-		        filename == other.filename);
-	}
-
-	bool operator==( CodeLocation const & other ) const {
-		return followedBy( other, 0 );
-	}
-
-	bool operator!=( CodeLocation const & other ) const {
-		return !(*this == other);
-	}
-};
-
-inline std::ostream & operator<<( std::ostream & out, const CodeLocation & location ) {
-	// Column number ":1" allows IDEs to parse the error message and position the cursor in the source text.
-	return location.isSet() ? out << location.filename << ":" << location.first_line << ":1 " : out;
-}
Index: src/Common/CodeLocation.hpp
===================================================================
--- src/Common/CodeLocation.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/CodeLocation.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,75 @@
+//
+// 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.
+//
+// CodeLocation.hpp --
+//
+// Author           : Andrew Beach
+// Created On       : Thr Aug 17 11:23:00 2017
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Aug 28 12:46:01 2017
+// Update Count     : 2
+//
+
+#pragma once
+
+#include <iostream>
+#include <string>
+
+struct CodeLocation {
+	int first_line = -1, first_column = -1, last_line = -1, last_column = -1;
+	std::string filename = "";
+
+	/// Create a new unset CodeLocation.
+	CodeLocation() = default;
+
+	/// Create a new CodeLocation with the given values.
+	CodeLocation( const char* filename, int lineno )
+		: first_line( lineno )
+		, filename(filename ? filename : "")
+	{}
+
+	CodeLocation( const CodeLocation& rhs ) = default;
+	CodeLocation( CodeLocation&& rhs ) = default;
+	CodeLocation& operator=( const CodeLocation & ) = default;
+	CodeLocation& operator=( CodeLocation && ) = default;
+
+	bool isSet () const {
+		return -1 != first_line;
+	}
+
+	bool isUnset () const {
+		return !isSet();
+	}
+
+	bool startsBefore( CodeLocation const & other ) const {
+		if( filename < other.filename ) return true;
+		if( filename > other.filename ) return false;
+
+		if( first_line < other.first_line ) return true;
+		if( first_line > other.first_line ) return false;
+
+		if( last_line < other.last_line ) return true;
+		return false;
+	}
+
+	bool followedBy( CodeLocation const & other, int seperation ) const {
+		return (first_line + seperation == other.first_line &&
+		        filename == other.filename);
+	}
+
+	bool operator==( CodeLocation const & other ) const {
+		return followedBy( other, 0 );
+	}
+
+	bool operator!=( CodeLocation const & other ) const {
+		return !(*this == other);
+	}
+};
+
+inline std::ostream & operator<<( std::ostream & out, const CodeLocation & location ) {
+	// Column number ":1" allows IDEs to parse the error message and position the cursor in the source text.
+	return location.isSet() ? out << location.filename << ":" << location.first_line << ":1 " : out;
+}
Index: src/Common/CodeLocationTools.cpp
===================================================================
--- src/Common/CodeLocationTools.cpp	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ src/Common/CodeLocationTools.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -20,5 +20,5 @@
 #include "AST/Pass.hpp"
 #include "AST/TranslationUnit.hpp"
-#include "Common/CodeLocation.h"
+#include "Common/CodeLocation.hpp"
 
 namespace {
Index: src/Common/DebugMalloc.cc
===================================================================
--- src/Common/DebugMalloc.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,71 +1,0 @@
-#if 0
-#include <dlfcn.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-bool recursion = false;
-
-static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-
-static union {
-    void *addr;
-    unsigned char bytes[sizeof(void *)];
-};
-
-struct Mallocmsg {
-    const char start[9];
-    char addr[16];
-    const char sep[3];
-    char size[16];
-    const char end[1];
-} mallocmsg = {
-    'm', 'a', 'l', 'l', 'o', 'c', ' ', '0', 'x',
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    ' ', '0', 'x',
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    '\n'
-};
-
-void * malloc( size_t size ) {
-    if ( recursion ) { write( STDERR_FILENO, "recursion\n", 10 ); abort(); }
-    recursion = true;
-    __typeof__( ::malloc ) *libc_malloc = (__typeof__( ::malloc ) *)dlsym(RTLD_NEXT, "malloc");
-    addr = (void *)size;
-    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
-    	mallocmsg.size[i] = hex[bytes[j] >> 4];
-    	mallocmsg.size[i + 1] = hex[bytes[j] & 0x0f];
-    } // for
-    addr = libc_malloc( size );
-    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
-	mallocmsg.addr[i] = hex[bytes[j] >> 4];
-	mallocmsg.addr[i + 1] = hex[bytes[j] & 0x0f];
-    } // for
-    write( STDERR_FILENO, &mallocmsg, sizeof(mallocmsg) );
-    recursion = false;
-    return addr;
-}
-
-struct Freemsg {
-    const char start[7];
-    char addr[16];
-    const char end[1];
-} freemsg = {
-    'f', 'r', 'e', 'e', ' ', '0', 'x',
-    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-    '\n'
-};
-
-void free( void * x ) {
-    if ( recursion ) { write( STDERR_FILENO, "recursion\n", 10 ); abort(); }
-    recursion = true;
-    __typeof__( ::free ) *libc_free = (__typeof__( ::free ) *)dlsym(RTLD_NEXT, "free");
-    addr = x;
-    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
-	freemsg.addr[i] = hex[bytes[j] >> 4];
-	freemsg.addr[i + 1] = hex[bytes[j] & 0x0f];
-    } // for
-    write( STDERR_FILENO, &freemsg, sizeof(freemsg) );
-    recursion = false;
-    libc_free( addr );
-}
-#endif // 0
Index: src/Common/DebugMalloc.cpp
===================================================================
--- src/Common/DebugMalloc.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/DebugMalloc.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,71 @@
+#if 0
+#include <dlfcn.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+bool recursion = false;
+
+static char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+static union {
+    void *addr;
+    unsigned char bytes[sizeof(void *)];
+};
+
+struct Mallocmsg {
+    const char start[9];
+    char addr[16];
+    const char sep[3];
+    char size[16];
+    const char end[1];
+} mallocmsg = {
+    'm', 'a', 'l', 'l', 'o', 'c', ' ', '0', 'x',
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    ' ', '0', 'x',
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    '\n'
+};
+
+void * malloc( size_t size ) {
+    if ( recursion ) { write( STDERR_FILENO, "recursion\n", 10 ); abort(); }
+    recursion = true;
+    __typeof__( ::malloc ) *libc_malloc = (__typeof__( ::malloc ) *)dlsym(RTLD_NEXT, "malloc");
+    addr = (void *)size;
+    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
+    	mallocmsg.size[i] = hex[bytes[j] >> 4];
+    	mallocmsg.size[i + 1] = hex[bytes[j] & 0x0f];
+    } // for
+    addr = libc_malloc( size );
+    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
+	mallocmsg.addr[i] = hex[bytes[j] >> 4];
+	mallocmsg.addr[i + 1] = hex[bytes[j] & 0x0f];
+    } // for
+    write( STDERR_FILENO, &mallocmsg, sizeof(mallocmsg) );
+    recursion = false;
+    return addr;
+}
+
+struct Freemsg {
+    const char start[7];
+    char addr[16];
+    const char end[1];
+} freemsg = {
+    'f', 'r', 'e', 'e', ' ', '0', 'x',
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    '\n'
+};
+
+void free( void * x ) {
+    if ( recursion ) { write( STDERR_FILENO, "recursion\n", 10 ); abort(); }
+    recursion = true;
+    __typeof__( ::free ) *libc_free = (__typeof__( ::free ) *)dlsym(RTLD_NEXT, "free");
+    addr = x;
+    for ( int i = 0, j = 7; i < 16; i += 2, j -= 1 ) {
+	freemsg.addr[i] = hex[bytes[j] >> 4];
+	freemsg.addr[i + 1] = hex[bytes[j] & 0x0f];
+    } // for
+    write( STDERR_FILENO, &freemsg, sizeof(freemsg) );
+    recursion = false;
+    libc_free( addr );
+}
+#endif // 0
Index: src/Common/DeclStats.cpp
===================================================================
--- src/Common/DeclStats.cpp	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ src/Common/DeclStats.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -19,5 +19,5 @@
 #include "AST/Pass.hpp"
 #include "AST/Print.hpp"
-#include "Common/VectorMap.h"
+#include "Common/VectorMap.hpp"
 
 #include <iostream>
Index: src/Common/ErrorObjects.h
===================================================================
--- src/Common/ErrorObjects.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,47 +1,0 @@
-//
-// 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.
-//
-// ErrorObjects.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Wed Feb 28 15:16:47 2018
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-
-#include <exception>	// for exception
-#include <iostream>	// for ostream
-#include <list>		// for list
-#include <string>		// for string
-#include <unistd.h>	// for isatty
-
-#include "CodeLocation.h"								// for CodeLocation, toString
-
-struct error {
-	CodeLocation location;
-	std::string description;
-
-	error() = default;
-	error( CodeLocation loc, const std::string & str ) : location( loc ), description( str ) {}
-};
-
-class SemanticErrorException : public std::exception {
-  public:
-	SemanticErrorException() = default;
-	SemanticErrorException( CodeLocation location, std::string error );
-	~SemanticErrorException() throw() {}
-
-	void append( SemanticErrorException & other );
-	void append( CodeLocation location, const std::string & );
-	bool isEmpty() const;
-	void print();
-  private:
-	std::list< error > errors;
-};
Index: src/Common/ErrorObjects.hpp
===================================================================
--- src/Common/ErrorObjects.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/ErrorObjects.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,47 @@
+//
+// 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.
+//
+// ErrorObjects.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Wed Feb 28 15:16:47 2018
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+
+#include <exception>	// for exception
+#include <iostream>	// for ostream
+#include <list>		// for list
+#include <string>		// for string
+#include <unistd.h>	// for isatty
+
+#include "CodeLocation.hpp"								// for CodeLocation, toString
+
+struct error {
+	CodeLocation location;
+	std::string description;
+
+	error() = default;
+	error( CodeLocation loc, const std::string & str ) : location( loc ), description( str ) {}
+};
+
+class SemanticErrorException : public std::exception {
+  public:
+	SemanticErrorException() = default;
+	SemanticErrorException( CodeLocation location, std::string error );
+	~SemanticErrorException() throw() {}
+
+	void append( SemanticErrorException & other );
+	void append( CodeLocation location, const std::string & );
+	bool isEmpty() const;
+	void print();
+  private:
+	std::list< error > errors;
+};
Index: src/Common/Eval.cc
===================================================================
--- src/Common/Eval.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,217 +1,0 @@
-//
-// 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.cc -- Evaluate parts of the ast at compile time.
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Sat Aug  6 12:11:59 2022
-// Update Count     : 119
-//
-
-#include "Eval.h"
-
-#include <utility> // for pair
-
-#include "AST/Inspect.hpp"
-#include "CodeGen/OperatorTable.h"						// access: OperatorInfo
-#include "AST/Pass.hpp"
-#include "InitTweak/InitTweak.h"
-
-struct EvalNew : public ast::WithShortCircuiting {
-	Evaluation result = { 0, true, true };
-
-	void previsit( const ast::Node * ) { visit_children = false; }
-	void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue = false; }
-
-	void postvisit( const ast::UntypedExpr * ) {
-		assertf( false, "UntypedExpr in constant expression evaluation" ); // FIX ME, resolve variable
-	}
-
-	void postvisit( const ast::ConstantExpr * expr ) {	// only handle int constants
-		result.knownValue = expr->intValue();
-		result.hasKnownValue = true;
-		result.isEvaluableInGCC = true;
-	}
-
-	void postvisit( const ast::SizeofExpr * ) {
-		result.hasKnownValue = false;
-		result.isEvaluableInGCC = true;
-	}
-
-	void postvisit( const ast::AlignofExpr * ) {
-		result.hasKnownValue = false;
-		result.isEvaluableInGCC = true;
-	}
-
-	void postvisit( const ast::OffsetofExpr * ) {
-		result.hasKnownValue = false;
-		result.isEvaluableInGCC = true;
-	}
-
-	void postvisit( const ast::LogicalExpr * expr ) {
-		Evaluation arg1, arg2;
-		arg1 = eval( expr->arg1 );
-		result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
-		if ( ! result.isEvaluableInGCC ) return;
-		arg2 = eval( expr->arg2 );
-		result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
-		if ( ! result.isEvaluableInGCC ) return;
-
-		result.hasKnownValue &= arg1.hasKnownValue;
-		result.hasKnownValue &= arg2.hasKnownValue;
-		if ( ! result.hasKnownValue ) return;
-
-		if ( expr->isAnd ) {
-			result.knownValue = arg1.knownValue && arg2.knownValue;
-		} else {
-			result.knownValue = arg1.knownValue || arg2.knownValue;
-		} // if
-	}
-
-	void postvisit( const ast::ConditionalExpr * expr ) {
-		Evaluation arg1, arg2, arg3;
-		arg1 = eval( expr->arg1 );
-		result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
-		if ( ! result.isEvaluableInGCC ) return;
-		arg2 = eval( expr->arg2 );
-		result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
-		if ( ! result.isEvaluableInGCC ) return;
-		arg3 = eval( expr->arg3 );
-		result.isEvaluableInGCC &= arg3.isEvaluableInGCC;
-		if ( ! result.isEvaluableInGCC ) return;
-
-		result.hasKnownValue &= arg1.hasKnownValue;
-		result.hasKnownValue &= arg2.hasKnownValue;
-		result.hasKnownValue &= arg3.hasKnownValue;
-		if ( ! result.hasKnownValue ) return;
-
-		result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue;
-	}
-
-	void postvisit( const ast::CastExpr * expr ) {		
-		// cfa-cc generates a cast before every constant and many other places, e.g., (int)3, 
-		// so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc
-		result = eval(expr->arg);
-	}
-
-	void postvisit( const ast::VariableExpr * expr ) {
-		result.hasKnownValue = false;
-		result.isEvaluableInGCC = false;
-		if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
-			if ( const ast::EnumDecl * decl = inst->base ) {
-				result.isEvaluableInGCC = true;
-				result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf
-			}
-		}
-	}
-
-	void postvisit( const ast::ApplicationExpr * expr ) {
-		const ast::DeclWithType * function = ast::getFunction(expr);
-		if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { 
-			result.isEvaluableInGCC = false;
-			result.hasKnownValue = false;
-			return;
-		}
-		const std::string & fname = function->name;
-		assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
-
-		if ( expr->args.size() == 1 ) {
-			// pre/postfix operators ++ and -- => assignment, which is not constant
-			Evaluation arg1;
-			arg1 = eval(expr->args.front());
-			result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
-			if ( ! result.isEvaluableInGCC ) return;
-
-			result.hasKnownValue &= arg1.hasKnownValue;
-			if ( ! result.hasKnownValue ) return;
-
-			if (fname == "+?") {
-				result.knownValue = arg1.knownValue;
-			} else if (fname == "-?") {
-				result.knownValue = -arg1.knownValue;
-			} else if (fname == "~?") {
-				result.knownValue = ~arg1.knownValue;
-			} else if (fname == "!?") {
-				result.knownValue = ! arg1.knownValue;
-			} else {
-				result.isEvaluableInGCC = false;
-				result.hasKnownValue = false;
-			} // if
-		} else { // => expr->args.size() == 2
-			// infix assignment operators => assignment, which is not constant
-			Evaluation arg1, arg2;
-			arg1 = eval(expr->args.front());
-			result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
-			if ( ! result.isEvaluableInGCC ) return;
-			arg2 = eval(expr->args.back());
-			result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
-			if ( ! result.isEvaluableInGCC ) return;
-
-			result.hasKnownValue &= arg1.hasKnownValue;
-			result.hasKnownValue &= arg2.hasKnownValue;
-			if ( ! result.hasKnownValue ) return;
-
-			if (fname == "?+?") {
-				result.knownValue = arg1.knownValue + arg2.knownValue;
-			} else if (fname == "?-?") {
-				result.knownValue = arg1.knownValue - arg2.knownValue;
-			} else if (fname == "?*?") {
-				result.knownValue = arg1.knownValue * arg2.knownValue;
-			} else if (fname == "?/?") {
-				if ( arg2.knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue;
-			} else if (fname == "?%?") {
-				if ( arg2.knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue;
-			} else if (fname == "?<<?") {
-				result.knownValue = arg1.knownValue << arg2.knownValue;
-			} else if (fname == "?>>?") {
-				result.knownValue = arg1.knownValue >> arg2.knownValue;
-			} else if (fname == "?<?") {
-				result.knownValue = arg1.knownValue < arg2.knownValue;
-			} else if (fname == "?>?") {
-				result.knownValue = arg1.knownValue > arg2.knownValue;
-			} else if (fname == "?<=?") {
-				result.knownValue = arg1.knownValue <= arg2.knownValue;
-			} else if (fname == "?>=?") {
-				result.knownValue = arg1.knownValue >= arg2.knownValue;
-			} else if (fname == "?==?") {
-				result.knownValue = arg1.knownValue == arg2.knownValue;
-			} else if (fname == "?!=?") {
-				result.knownValue = arg1.knownValue != arg2.knownValue;
-			} else if (fname == "?&?") {
-				result.knownValue = arg1.knownValue & arg2.knownValue;
-			} else if (fname == "?^?") {
-				result.knownValue = arg1.knownValue ^ arg2.knownValue;
-			} else if (fname == "?|?") {
-				result.knownValue = arg1.knownValue | arg2.knownValue;
-			} else {
-				result.isEvaluableInGCC = false;
-				result.hasKnownValue = false;
-			}
-		} // if
-		// TODO: implement other intrinsic functions
-	}
-};
-
-Evaluation eval( const ast::Expr * expr ) {
-	if ( expr ) {
-
-		return ast::Pass<EvalNew>::read(expr);
-		// Evaluation ret = ast::Pass<EvalNew>::read(expr);
-		// ret.knownValue = 777;
-		// return ret;
-
-	} else {
-		return { 0, false, false };
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/Eval.cpp
===================================================================
--- src/Common/Eval.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Eval.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,217 @@
+//
+// 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.cpp -- Evaluate parts of the ast at compile time.
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Sat Aug  6 12:11:59 2022
+// Update Count     : 119
+//
+
+#include "Eval.hpp"
+
+#include <utility> // for pair
+
+#include "AST/Inspect.hpp"
+#include "CodeGen/OperatorTable.hpp"						// access: OperatorInfo
+#include "AST/Pass.hpp"
+#include "InitTweak/InitTweak.hpp"
+
+struct EvalNew : public ast::WithShortCircuiting {
+	Evaluation result = { 0, true, true };
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+	void postvisit( const ast::Node * ) { result.isEvaluableInGCC = result.hasKnownValue = false; }
+
+	void postvisit( const ast::UntypedExpr * ) {
+		assertf( false, "UntypedExpr in constant expression evaluation" ); // FIX ME, resolve variable
+	}
+
+	void postvisit( const ast::ConstantExpr * expr ) {	// only handle int constants
+		result.knownValue = expr->intValue();
+		result.hasKnownValue = true;
+		result.isEvaluableInGCC = true;
+	}
+
+	void postvisit( const ast::SizeofExpr * ) {
+		result.hasKnownValue = false;
+		result.isEvaluableInGCC = true;
+	}
+
+	void postvisit( const ast::AlignofExpr * ) {
+		result.hasKnownValue = false;
+		result.isEvaluableInGCC = true;
+	}
+
+	void postvisit( const ast::OffsetofExpr * ) {
+		result.hasKnownValue = false;
+		result.isEvaluableInGCC = true;
+	}
+
+	void postvisit( const ast::LogicalExpr * expr ) {
+		Evaluation arg1, arg2;
+		arg1 = eval( expr->arg1 );
+		result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
+		if ( ! result.isEvaluableInGCC ) return;
+		arg2 = eval( expr->arg2 );
+		result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
+		if ( ! result.isEvaluableInGCC ) return;
+
+		result.hasKnownValue &= arg1.hasKnownValue;
+		result.hasKnownValue &= arg2.hasKnownValue;
+		if ( ! result.hasKnownValue ) return;
+
+		if ( expr->isAnd ) {
+			result.knownValue = arg1.knownValue && arg2.knownValue;
+		} else {
+			result.knownValue = arg1.knownValue || arg2.knownValue;
+		} // if
+	}
+
+	void postvisit( const ast::ConditionalExpr * expr ) {
+		Evaluation arg1, arg2, arg3;
+		arg1 = eval( expr->arg1 );
+		result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
+		if ( ! result.isEvaluableInGCC ) return;
+		arg2 = eval( expr->arg2 );
+		result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
+		if ( ! result.isEvaluableInGCC ) return;
+		arg3 = eval( expr->arg3 );
+		result.isEvaluableInGCC &= arg3.isEvaluableInGCC;
+		if ( ! result.isEvaluableInGCC ) return;
+
+		result.hasKnownValue &= arg1.hasKnownValue;
+		result.hasKnownValue &= arg2.hasKnownValue;
+		result.hasKnownValue &= arg3.hasKnownValue;
+		if ( ! result.hasKnownValue ) return;
+
+		result.knownValue = arg1.knownValue ? arg2.knownValue : arg3.knownValue;
+	}
+
+	void postvisit( const ast::CastExpr * expr ) {		
+		// cfa-cc generates a cast before every constant and many other places, e.g., (int)3, 
+		// so we must use the value from the cast argument, even though we lack any basis for evaluating wraparound effects, etc
+		result = eval(expr->arg);
+	}
+
+	void postvisit( const ast::VariableExpr * expr ) {
+		result.hasKnownValue = false;
+		result.isEvaluableInGCC = false;
+		if ( const ast::EnumInstType * inst = dynamic_cast<const ast::EnumInstType *>(expr->result.get()) ) {
+			if ( const ast::EnumDecl * decl = inst->base ) {
+				result.isEvaluableInGCC = true;
+				result.hasKnownValue = decl->valueOf( expr->var, result.knownValue ); // result.knownValue filled by valueOf
+			}
+		}
+	}
+
+	void postvisit( const ast::ApplicationExpr * expr ) {
+		const ast::DeclWithType * function = ast::getFunction(expr);
+		if ( ! function || function->linkage != ast::Linkage::Intrinsic ) { 
+			result.isEvaluableInGCC = false;
+			result.hasKnownValue = false;
+			return;
+		}
+		const std::string & fname = function->name;
+		assertf( expr->args.size() == 1 || expr->args.size() == 2, "Intrinsic function with %zd arguments: %s", expr->args.size(), fname.c_str() );
+
+		if ( expr->args.size() == 1 ) {
+			// pre/postfix operators ++ and -- => assignment, which is not constant
+			Evaluation arg1;
+			arg1 = eval(expr->args.front());
+			result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
+			if ( ! result.isEvaluableInGCC ) return;
+
+			result.hasKnownValue &= arg1.hasKnownValue;
+			if ( ! result.hasKnownValue ) return;
+
+			if (fname == "+?") {
+				result.knownValue = arg1.knownValue;
+			} else if (fname == "-?") {
+				result.knownValue = -arg1.knownValue;
+			} else if (fname == "~?") {
+				result.knownValue = ~arg1.knownValue;
+			} else if (fname == "!?") {
+				result.knownValue = ! arg1.knownValue;
+			} else {
+				result.isEvaluableInGCC = false;
+				result.hasKnownValue = false;
+			} // if
+		} else { // => expr->args.size() == 2
+			// infix assignment operators => assignment, which is not constant
+			Evaluation arg1, arg2;
+			arg1 = eval(expr->args.front());
+			result.isEvaluableInGCC &= arg1.isEvaluableInGCC;
+			if ( ! result.isEvaluableInGCC ) return;
+			arg2 = eval(expr->args.back());
+			result.isEvaluableInGCC &= arg2.isEvaluableInGCC;
+			if ( ! result.isEvaluableInGCC ) return;
+
+			result.hasKnownValue &= arg1.hasKnownValue;
+			result.hasKnownValue &= arg2.hasKnownValue;
+			if ( ! result.hasKnownValue ) return;
+
+			if (fname == "?+?") {
+				result.knownValue = arg1.knownValue + arg2.knownValue;
+			} else if (fname == "?-?") {
+				result.knownValue = arg1.knownValue - arg2.knownValue;
+			} else if (fname == "?*?") {
+				result.knownValue = arg1.knownValue * arg2.knownValue;
+			} else if (fname == "?/?") {
+				if ( arg2.knownValue ) result.knownValue = arg1.knownValue / arg2.knownValue;
+			} else if (fname == "?%?") {
+				if ( arg2.knownValue ) result.knownValue = arg1.knownValue % arg2.knownValue;
+			} else if (fname == "?<<?") {
+				result.knownValue = arg1.knownValue << arg2.knownValue;
+			} else if (fname == "?>>?") {
+				result.knownValue = arg1.knownValue >> arg2.knownValue;
+			} else if (fname == "?<?") {
+				result.knownValue = arg1.knownValue < arg2.knownValue;
+			} else if (fname == "?>?") {
+				result.knownValue = arg1.knownValue > arg2.knownValue;
+			} else if (fname == "?<=?") {
+				result.knownValue = arg1.knownValue <= arg2.knownValue;
+			} else if (fname == "?>=?") {
+				result.knownValue = arg1.knownValue >= arg2.knownValue;
+			} else if (fname == "?==?") {
+				result.knownValue = arg1.knownValue == arg2.knownValue;
+			} else if (fname == "?!=?") {
+				result.knownValue = arg1.knownValue != arg2.knownValue;
+			} else if (fname == "?&?") {
+				result.knownValue = arg1.knownValue & arg2.knownValue;
+			} else if (fname == "?^?") {
+				result.knownValue = arg1.knownValue ^ arg2.knownValue;
+			} else if (fname == "?|?") {
+				result.knownValue = arg1.knownValue | arg2.knownValue;
+			} else {
+				result.isEvaluableInGCC = false;
+				result.hasKnownValue = false;
+			}
+		} // if
+		// TODO: implement other intrinsic functions
+	}
+};
+
+Evaluation eval( const ast::Expr * expr ) {
+	if ( expr ) {
+
+		return ast::Pass<EvalNew>::read(expr);
+		// Evaluation ret = ast::Pass<EvalNew>::read(expr);
+		// ret.knownValue = 777;
+		// return ret;
+
+	} else {
+		return { 0, false, false };
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Eval.h
===================================================================
--- src/Common/Eval.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,38 +1,0 @@
-//
-// 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.h -- Evaluate parts of the ast at compile time.
-//
-// Author           : Andrew Beach
-// Created On       : Fri Feb 17 11:41:00 2023
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Feb 17 11:41:00 2023
-// Update Count     : 0
-//
-
-#pragma once
-
-#include <utility>                 // for pair
-
-class Expression;
-namespace ast {
-	class Expr;
-}
-
-struct Evaluation {
-	long long int knownValue;
-	bool hasKnownValue;
-	bool isEvaluableInGCC;
-};
-
-/// Evaluates expr as a long long int.
-Evaluation eval(const ast::Expr * expr);
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/Eval.hpp
===================================================================
--- src/Common/Eval.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Eval.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,38 @@
+//
+// 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 -- Evaluate parts of the ast at compile time.
+//
+// Author           : Andrew Beach
+// Created On       : Fri Feb 17 11:41:00 2023
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Feb 17 11:41:00 2023
+// Update Count     : 0
+//
+
+#pragma once
+
+#include <utility>                 // for pair
+
+class Expression;
+namespace ast {
+	class Expr;
+}
+
+struct Evaluation {
+	long long int knownValue;
+	bool hasKnownValue;
+	bool isEvaluableInGCC;
+};
+
+/// Evaluates expr as a long long int.
+Evaluation eval(const ast::Expr * expr);
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Examine.cc
===================================================================
--- src/Common/Examine.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,70 +1,0 @@
-//
-// 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.
-//
-// Examine.cc -- Helpers for examining AST code.
-//
-// Author           : Andrew Beach
-// Created On       : Wed Sept 2 14:02 2020
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Dec 10 10:27 2021
-// Update Count     : 1
-//
-
-#include "Common/Examine.h"
-
-#include "AST/Type.hpp"
-#include "CodeGen/OperatorTable.h"
-#include "InitTweak/InitTweak.h"
-
-namespace {
-
-// getTypeofThis but does some extra checks used in this module.
-const ast::Type * getTypeofThisSolo( const ast::FunctionDecl * func ) {
-	if ( 1 != func->params.size() ) {
-		return nullptr;
-	}
-	auto ref = func->type->params.front().as<ast::ReferenceType>();
-	return (ref) ? ref->base : nullptr;
-}
-
-}
-
-const ast::DeclWithType * isMainFor(
-		const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ) {
-	if ( "main" != func->name ) return nullptr;
-	if ( 1 != func->params.size() ) return nullptr;
-
-	auto param = func->params.front();
-
-	auto type = dynamic_cast<const ast::ReferenceType *>( param->get_type() );
-	if ( !type ) return nullptr;
-
-	auto obj = type->base.as<ast::StructInstType>();
-	if ( !obj ) return nullptr;
-
-	if ( kind != obj->base->kind ) return nullptr;
-
-	return param;
-}
-
-namespace {
-
-const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
-	if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
-	//return InitTweak::getParamThis( func )->type;
-	return getTypeofThisSolo( func );
-}
-
-}
-
-bool isDestructorFor(
-		const ast::FunctionDecl * func, const ast::StructDecl * type_decl ) {
-	if ( const ast::Type * type = getDestructorParam( func ) ) {
-		auto stype = dynamic_cast<const ast::StructInstType *>( type );
-		return stype && stype->base.get() == type_decl;
-	}
-	return false;
-}
Index: src/Common/Examine.cpp
===================================================================
--- src/Common/Examine.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Examine.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,69 @@
+//
+// 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.
+//
+// Examine.cpp -- Helpers for examining AST code.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Sept 2 14:02 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Dec 10 10:27 2021
+// Update Count     : 1
+//
+
+#include "Common/Examine.hpp"
+
+#include "AST/Type.hpp"
+#include "CodeGen/OperatorTable.hpp"
+#include "InitTweak/InitTweak.hpp"
+
+namespace {
+
+// getTypeofThis but does some extra checks used in this module.
+const ast::Type * getTypeofThisSolo( const ast::FunctionDecl * func ) {
+	if ( 1 != func->params.size() ) {
+		return nullptr;
+	}
+	auto ref = func->type->params.front().as<ast::ReferenceType>();
+	return (ref) ? ref->base : nullptr;
+}
+
+}
+
+const ast::DeclWithType * isMainFor(
+		const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind ) {
+	if ( "main" != func->name ) return nullptr;
+	if ( 1 != func->params.size() ) return nullptr;
+
+	auto param = func->params.front();
+
+	auto type = dynamic_cast<const ast::ReferenceType *>( param->get_type() );
+	if ( !type ) return nullptr;
+
+	auto obj = type->base.as<ast::StructInstType>();
+	if ( !obj ) return nullptr;
+
+	if ( kind != obj->base->kind ) return nullptr;
+
+	return param;
+}
+
+namespace {
+
+const ast::Type * getDestructorParam( const ast::FunctionDecl * func ) {
+	if ( !CodeGen::isDestructor( func->name ) ) return nullptr;
+	return getTypeofThisSolo( func );
+}
+
+}
+
+bool isDestructorFor(
+		const ast::FunctionDecl * func, const ast::StructDecl * type_decl ) {
+	if ( const ast::Type * type = getDestructorParam( func ) ) {
+		auto stype = dynamic_cast<const ast::StructInstType *>( type );
+		return stype && stype->base.get() == type_decl;
+	}
+	return false;
+}
Index: src/Common/Examine.h
===================================================================
--- src/Common/Examine.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,25 +1,0 @@
-//
-// 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.
-//
-// Examine.h -- Helpers for examining AST code.
-//
-// Author           : Andrew Beach
-// Created On       : Wed Sept 2 13:57 2020
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Dec 10 10:28 2021
-// Update Count     : 1
-//
-
-#include "AST/Decl.hpp"
-
-/// Check if this is a main function for a type of an aggregate kind.
-const ast::DeclWithType * isMainFor(
-	const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
-// Returns a pointer to the parameter if true, nullptr otherwise.
-
-/// Check if this function is a destructor for the given structure.
-bool isDestructorFor(
-	const ast::FunctionDecl * func, const ast::StructDecl * type );
Index: src/Common/Examine.hpp
===================================================================
--- src/Common/Examine.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Examine.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,25 @@
+//
+// 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.
+//
+// Examine.hpp -- Helpers for examining AST code.
+//
+// Author           : Andrew Beach
+// Created On       : Wed Sept 2 13:57 2020
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Dec 10 10:28 2021
+// Update Count     : 1
+//
+
+#include "AST/Decl.hpp"
+
+/// Check if this is a main function for a type of an aggregate kind.
+const ast::DeclWithType * isMainFor(
+	const ast::FunctionDecl * func, ast::AggregateDecl::Aggregate kind );
+// Returns a pointer to the parameter if true, nullptr otherwise.
+
+/// Check if this function is a destructor for the given structure.
+bool isDestructorFor(
+	const ast::FunctionDecl * func, const ast::StructDecl * type );
Index: src/Common/FilterCombos.h
===================================================================
--- src/Common/FilterCombos.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,103 +1,0 @@
-//
-// 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.
-//
-// FilterCombos.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Mon Jul 23 16:05:00 2018
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Mon Jul 23 16:05:00 2018
-// Update Count     : 1
-//
-
-#pragma once
-
-#include <vector>
-
-/// Type of index vector for combinations
-typedef std::vector<unsigned> Indices;
-
-/// Combo iterator that simply collects values into a vector, marking all values as valid.
-/// Prefer combos in typeops.h to use of IntoVectorComboIter with filterCombos
-/// @param T	The element type of the vector.
-template<typename T>
-class IntoVectorComboIter {
-	std::vector<T> crnt_combo;
-public:
-	/// Outputs a vector of T
-	using OutType = std::vector<T>;
-
-	/// Adds the element to the current combination, always returning true for valid.
-	bool append( const T& x ) {
-		crnt_combo.push_back( x );
-		return true;
-	}
-
-	/// Removes the last element of the current combination.
-	void backtrack() { crnt_combo.pop_back(); }
-
-	/// Returns a copy of the current combination.
-	OutType finalize() { return crnt_combo; }
-};
-
-/// Filters combinations from qs by the given combo iterator. If the iterator rejects some prefix 
-/// of a combination, it will not accept any combination with that prefix.
-/// qs should not be empty
-template<typename Q, typename ComboIter>
-auto filterCombos( const std::vector<Q>& qs, ComboIter&& iter )
-		-> std::vector<typename ComboIter::OutType> {
-    unsigned n = qs.size();  // number of queues to combine
-
-	std::vector<typename ComboIter::OutType> out;  // filtered output
-	for ( auto& q : qs ) if ( q.empty() ) return out;  // return empty if any empty queue
-
-	Indices inds;
-	inds.reserve( n );
-	inds.push_back( 0 );
-
-	while (true) {
-		unsigned i = inds.size() - 1;
-
-		// iterate or keep successful match
-		if ( iter.append( qs[i][inds.back()] ) ) {
-			if ( i + 1 == n ) {
-				// keep successful match of entire combination and continue iterating final place
-				out.push_back( iter.finalize() );
-				iter.backtrack();
-			} else {
-				// try to extend successful prefix
-				inds.push_back( 0 );
-				continue;
-			}
-		}
-
-		// move to next combo
-		++inds.back();
-		if ( inds.back() < qs[i].size() ) continue;
-		
-		// Otherwise done with the current row.
-		// At this point, an invalid prefix is stored in inds and iter is in a state looking at 
-		// all but the final value in inds. Now backtrack to next prefix:
-		inds.pop_back();
-		while ( ! inds.empty() ) {
-			// try the next value at the previous index
-			++inds.back();
-			iter.backtrack();
-			if ( inds.back() < qs[inds.size()-1].size() ) break;
-			// if the previous index is finished, backtrack out
-			inds.pop_back();
-		}
-
-		// Done if backtracked the entire array
-		if ( inds.empty() ) return out;
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/FilterCombos.hpp
===================================================================
--- src/Common/FilterCombos.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/FilterCombos.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,103 @@
+//
+// 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.
+//
+// FilterCombos.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Mon Jul 23 16:05:00 2018
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Mon Jul 23 16:05:00 2018
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <vector>
+
+/// Type of index vector for combinations
+typedef std::vector<unsigned> Indices;
+
+/// Combo iterator that simply collects values into a vector, marking all values as valid.
+/// Prefer combos in typeops.h to use of IntoVectorComboIter with filterCombos
+/// @param T	The element type of the vector.
+template<typename T>
+class IntoVectorComboIter {
+	std::vector<T> crnt_combo;
+public:
+	/// Outputs a vector of T
+	using OutType = std::vector<T>;
+
+	/// Adds the element to the current combination, always returning true for valid.
+	bool append( const T& x ) {
+		crnt_combo.push_back( x );
+		return true;
+	}
+
+	/// Removes the last element of the current combination.
+	void backtrack() { crnt_combo.pop_back(); }
+
+	/// Returns a copy of the current combination.
+	OutType finalize() { return crnt_combo; }
+};
+
+/// Filters combinations from qs by the given combo iterator. If the iterator rejects some prefix 
+/// of a combination, it will not accept any combination with that prefix.
+/// qs should not be empty
+template<typename Q, typename ComboIter>
+auto filterCombos( const std::vector<Q>& qs, ComboIter&& iter )
+		-> std::vector<typename ComboIter::OutType> {
+    unsigned n = qs.size();  // number of queues to combine
+
+	std::vector<typename ComboIter::OutType> out;  // filtered output
+	for ( auto& q : qs ) if ( q.empty() ) return out;  // return empty if any empty queue
+
+	Indices inds;
+	inds.reserve( n );
+	inds.push_back( 0 );
+
+	while (true) {
+		unsigned i = inds.size() - 1;
+
+		// iterate or keep successful match
+		if ( iter.append( qs[i][inds.back()] ) ) {
+			if ( i + 1 == n ) {
+				// keep successful match of entire combination and continue iterating final place
+				out.push_back( iter.finalize() );
+				iter.backtrack();
+			} else {
+				// try to extend successful prefix
+				inds.push_back( 0 );
+				continue;
+			}
+		}
+
+		// move to next combo
+		++inds.back();
+		if ( inds.back() < qs[i].size() ) continue;
+		
+		// Otherwise done with the current row.
+		// At this point, an invalid prefix is stored in inds and iter is in a state looking at 
+		// all but the final value in inds. Now backtrack to next prefix:
+		inds.pop_back();
+		while ( ! inds.empty() ) {
+			// try the next value at the previous index
+			++inds.back();
+			iter.backtrack();
+			if ( inds.back() < qs[inds.size()-1].size() ) break;
+			// if the previous index is finished, backtrack out
+			inds.pop_back();
+		}
+
+		// Done if backtracked the entire array
+		if ( inds.empty() ) return out;
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Indenter.cc
===================================================================
--- src/Common/Indenter.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,24 +1,0 @@
-//
-// 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.
-//
-// Indenter.cc --
-//
-// Author           : Andrew Beach
-// Created On       : Fri May 13 14:03:00 2022
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri May 13 14:03:00 2022
-// Update Count     : 0
-//
-
-#include "Indenter.h"
-
-unsigned Indenter::tabsize = 2;
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/Indenter.cpp
===================================================================
--- src/Common/Indenter.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Indenter.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,24 @@
+//
+// 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.
+//
+// Indenter.cpp --
+//
+// Author           : Andrew Beach
+// Created On       : Fri May 13 14:03:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri May 13 14:03:00 2022
+// Update Count     : 0
+//
+
+#include "Indenter.hpp"
+
+unsigned Indenter::tabsize = 2;
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Indenter.h
===================================================================
--- src/Common/Indenter.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,39 +1,0 @@
-//
-// 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.
-//
-// Indenter.h --
-//
-// Author           : Rob Schluntz
-// Created On       : Fri Jun 30 16:55:23 2017
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri May 13 14:10:00 2022
-// Update Count     : 2
-//
-
-#pragma once
-
-#include <ostream>
-
-struct Indenter {
-	static unsigned tabsize;  ///< default number of spaces in one level of indentation
-
-	unsigned int indent;      ///< number of spaces to indent
-	unsigned int amt;         ///< spaces in one level of indentation
-
-	Indenter( unsigned int indent = 0, unsigned int amt = tabsize )
-	: indent( indent ), amt( amt ) {}
-
-	Indenter & operator+=(int nlevels) { indent += nlevels; return *this; }
-	Indenter & operator-=(int nlevels) { indent -= nlevels; return *this; }
-	Indenter operator+(int nlevels) { Indenter indenter = *this; return indenter += nlevels; }
-	Indenter operator-(int nlevels) { Indenter indenter = *this; return indenter -= nlevels; }
-	Indenter & operator++() { return *this += 1; }
-	Indenter & operator--() { return *this -= 1; }
-};
-
-inline std::ostream & operator<<( std::ostream & out, const Indenter & indent ) {
-	return out << std::string(indent.indent * indent.amt, ' ');
-}
Index: src/Common/Indenter.hpp
===================================================================
--- src/Common/Indenter.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Indenter.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,39 @@
+//
+// 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.
+//
+// Indenter.hpp --
+//
+// Author           : Rob Schluntz
+// Created On       : Fri Jun 30 16:55:23 2017
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri May 13 14:10:00 2022
+// Update Count     : 2
+//
+
+#pragma once
+
+#include <ostream>
+
+struct Indenter {
+	static unsigned tabsize;  ///< default number of spaces in one level of indentation
+
+	unsigned int indent;      ///< number of spaces to indent
+	unsigned int amt;         ///< spaces in one level of indentation
+
+	Indenter( unsigned int indent = 0, unsigned int amt = tabsize )
+	: indent( indent ), amt( amt ) {}
+
+	Indenter & operator+=(int nlevels) { indent += nlevels; return *this; }
+	Indenter & operator-=(int nlevels) { indent -= nlevels; return *this; }
+	Indenter operator+(int nlevels) { Indenter indenter = *this; return indenter += nlevels; }
+	Indenter operator-(int nlevels) { Indenter indenter = *this; return indenter -= nlevels; }
+	Indenter & operator++() { return *this += 1; }
+	Indenter & operator--() { return *this -= 1; }
+};
+
+inline std::ostream & operator<<( std::ostream & out, const Indenter & indent ) {
+	return out << std::string(indent.indent * indent.amt, ' ');
+}
Index: src/Common/PersistentMap.h
===================================================================
--- src/Common/PersistentMap.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,292 +1,0 @@
-//
-// 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.
-//
-// PersistentMap.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Thu Mar  7 15:50:00 2019
-// Last Modified By : Aaron B. Moss
-// Last Modified On : Thu Mar  7 15:50:00 2019
-// Update Count     : 1
-//
-
-#pragma once
-
-#include <cassert>        // for assertf
-#include <cstddef>        // for size_t
-#include <functional>     // for hash, equal_to
-#include <memory>         // for shared_ptr, enable_shared_from_this, make_shared
-#include <unordered_map>  // for unordered_map
-#include <utility>        // for forward, move
-
-/// Wraps a hash table in a persistent data structure, using a technique based
-/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find
-/// Data Structure"
-
-template<typename Key, typename Val,
-		typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
-class PersistentMap
-	: public std::enable_shared_from_this<PersistentMap<Key, Val, Hash, Eq>> {
-public:
-	/// Type of this class
-	using Self = PersistentMap<Key, Val, Hash, Eq>;
-	/// Type of pointer to this class
-	using Ptr = std::shared_ptr<Self>;
-
-	/// Types of version nodes
-	enum Mode {
-		BASE,  ///< Root node of version tree
-		REM,   ///< Key removal node
-		INS,   ///< Key update node
-		UPD    ///< Key update node
-	};
-
-private:
-	using Base = std::unordered_map<Key, Val, Hash, Eq>;
-
-	/// Insertion/update node
-	struct Ins {
-		Ptr base;  ///< Modified map
-		Key key;   ///< Key inserted
-		Val val;   ///< Value stored
-
-		template<typename P, typename K, typename V>
-		Ins(P&& p, K&& k, V&& v)
-		: base(std::forward<P>(p)), key(std::forward<K>(k)), val(std::forward<V>(v)) {}
-	};
-
-	/// Removal node
-	struct Rem {
-		Ptr base;  ///< Modified map
-		Key key;   ///< Key removed
-
-		template<typename P, typename K>
-		Rem(P&& p, K&& k) : base(std::forward<P>(p)), key(std::forward<K>(k)) {}
-	};
-
-	/// Underlying storage
-	union Data {
-		char def;
-		Base base;
-		Ins ins;
-		Rem rem;
-
-		Data() : def('\0') {}
-		~Data() {}
-	} data;
-
-	/// Type of node
-	mutable Mode mode;
-
-	/// get mutable reference as T
-	template<typename T>
-	T& as() { return reinterpret_cast<T&>(data); }
-
-	/// get const reference as T
-	template<typename T>
-	const T& as() const { return reinterpret_cast<const T&>(data); }
-
-	/// get rvalue reference as T
-	template<typename T>
-	T&& take_as() { return std::move(as<T>()); }
-
-	/// initialize as T
-	template<typename T, typename... Args>
-	void init( Args&&... args ) {
-		new( &as<T>() ) T { std::forward<Args>(args)... };
-	}
-
-	/// reset as current mode
-	void reset() {
-		switch( mode ) {
-			case BASE:          as<Base>().~Base(); break;
-			case REM:           as<Rem>().~Rem();   break;
-			case INS: case UPD: as<Ins>().~Ins();   break;
-		}
-	}
-
-	/// reset as base
-	void reset_as_base() {
-		as<Base>().~Base();
-	}
-
-public:
-	using key_type = typename Base::key_type;
-	using mapped_type = typename Base::mapped_type;
-	using value_type = typename Base::value_type;
-	using size_type = typename Base::size_type;
-	using difference_type = typename Base::difference_type;
-	using iterator = typename Base::const_iterator;
-
-	PersistentMap() : data(), mode(BASE) { init<Base>(); }
-
-	PersistentMap( Base&& b ) : data(), mode(BASE) { init<Base>(std::move(b)); }
-
-	PersistentMap( const Self& o ) = delete;
-
-	Self& operator= ( const Self& o ) = delete;
-
-	~PersistentMap() { reset(); }
-
-	/// Create a pointer to a new, empty persistent map
-	static Ptr new_ptr() { return std::make_shared<Self>(); }
-
-	/// reroot persistent map at current node
-	void reroot() const {
-		// recursive base case
-		if ( mode == BASE ) return;
-
-		// reroot base
-		Self* mut_this = const_cast<Self*>(this);
-		Ptr base = ( mode == REM ) ? mut_this->as<Rem>().base : mut_this->as<Ins>().base;
-		base->reroot();
-
-		// remove map from base
-		Base base_map = base->template take_as<Base>();
-		base->reset_as_base();
-
-		// switch base to inverse of self and mutate base map
-		switch ( mode ) {
-			case REM: {
-				Rem& self = mut_this->as<Rem>();
-				auto it = base_map.find( self.key );
-
-				base->template init<Ins>(
-						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
-				base->mode = INS;
-
-				base_map.erase( it );
-				break;
-			}
-			case INS: {
-				Ins& self = mut_this->as<Ins>();
-
-				base->template init<Rem>( mut_this->shared_from_this(), self.key );
-				base->mode = REM;
-
-				base_map.emplace( std::move(self.key), std::move(self.val) );
-				break;
-			}
-			case UPD: {
-				Ins& self = mut_this->as<Ins>();
-				auto it = base_map.find( self.key );
-
-				base->template init<Ins>(
-						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
-				base->mode = UPD;
-
-				it->second = std::move(self.val);
-				break;
-			}
-			case BASE: assertf(false, "unreachable"); break;
-		}
-
-		// set base map into self
-		mut_this->reset();
-		mut_this->init<Base>( std::move(base_map) );
-		mode = BASE;
-	}
-
-private:
-	/// the base after rerooting at the current node
-	const Base& rerooted() const {
-		reroot();
-		return as<Base>();
-	}
-
-public:
-	/// true iff the map is empty
-	bool empty() const { return rerooted().empty(); }
-
-	/// number of entries in map
-	size_type size() const { return rerooted().size(); }
-
-	/// begin iterator for map; may be invalidated by calls to non-iteration functions
-	/// or functions on other maps in the same tree
-	iterator begin() const { return rerooted().begin(); }
-
-	/// end iterator for map; may be invalidated by calls to non-iteration functions
-	/// or functions on other maps in the same tree
-	iterator end() const { return rerooted().end(); }
-
-	/// underlying map iterator for value
-	iterator find(const Key& k) const { return rerooted().find( k ); }
-
-	/// check if value is present
-	size_type count(const Key& k) const { return rerooted().count( k ); }
-
-	/// get value; undefined behaviour if not present
-	const Val& get(const Key& k) const {
-		const Base& self = rerooted();
-		auto it = self.find( k );
-		return it->second;
-	}
-
-	/// get value; returns default if not present
-	template<typename V>
-	Val get_or_default(const Key& k, V&& d) const {
-		const Base& self = rerooted();
-		auto it = self.find( k );
-		if ( it == self.end() ) return d;
-		else return it->second;
-	}
-
-	/// set value, storing new map in output variable
-	template<typename K, typename V>
-	Ptr set(K&& k, V&& v) {
-		reroot();
-
-		// transfer map to new node
-		Ptr ret = std::make_shared<Self>( take_as<Base>() );
-		reset_as_base();
-		Base& base_map = ret->template as<Base>();
-
-		// check if this is update or insert
-		auto it = base_map.find( k );
-		if ( it == base_map.end() ) {
-			// set self to REM node and insert into base
-			init<Rem>( ret, k );
-			mode = REM;
-
-			base_map.emplace_hint( it, std::forward<K>(k), std::forward<V>(v) );
-		} else {
-			// set self to UPD node and modify base
-			init<Ins>( ret, std::forward<K>(k), std::move(it->second) );
-			mode = UPD;
-
-			it->second = std::forward<V>(v);
-		}
-
-		return ret;
-	}
-
-	/// remove value, storing new map in output variable; does nothing if key not in map
-	Ptr erase(const Key& k) {
-		reroot();
-
-		// exit early if key does not exist in map
-		if ( ! as<Base>().count( k ) ) return this->shared_from_this();
-
-		// transfer map to new node
-		Ptr ret = std::make_shared<Self>( take_as<Base>() );
-		reset_as_base();
-		Base& base_map = ret->template as<Base>();
-
-		// set self to INS node and remove from base
-		init<Ins>( ret, k, base_map[k] );
-		mode = INS;
-
-		base_map.erase( k );
-
-		return ret;
-	}
-};
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/PersistentMap.hpp
===================================================================
--- src/Common/PersistentMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/PersistentMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,292 @@
+//
+// 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.
+//
+// PersistentMap.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Thu Mar  7 15:50:00 2019
+// Last Modified By : Aaron B. Moss
+// Last Modified On : Thu Mar  7 15:50:00 2019
+// Update Count     : 1
+//
+
+#pragma once
+
+#include <cassert>        // for assertf
+#include <cstddef>        // for size_t
+#include <functional>     // for hash, equal_to
+#include <memory>         // for shared_ptr, enable_shared_from_this, make_shared
+#include <unordered_map>  // for unordered_map
+#include <utility>        // for forward, move
+
+/// Wraps a hash table in a persistent data structure, using a technique based
+/// on the persistent array in Conchon & Filliatre "A Persistent Union-Find
+/// Data Structure"
+
+template<typename Key, typename Val,
+		typename Hash = std::hash<Key>, typename Eq = std::equal_to<Key>>
+class PersistentMap
+	: public std::enable_shared_from_this<PersistentMap<Key, Val, Hash, Eq>> {
+public:
+	/// Type of this class
+	using Self = PersistentMap<Key, Val, Hash, Eq>;
+	/// Type of pointer to this class
+	using Ptr = std::shared_ptr<Self>;
+
+	/// Types of version nodes
+	enum Mode {
+		BASE,  ///< Root node of version tree
+		REM,   ///< Key removal node
+		INS,   ///< Key update node
+		UPD    ///< Key update node
+	};
+
+private:
+	using Base = std::unordered_map<Key, Val, Hash, Eq>;
+
+	/// Insertion/update node
+	struct Ins {
+		Ptr base;  ///< Modified map
+		Key key;   ///< Key inserted
+		Val val;   ///< Value stored
+
+		template<typename P, typename K, typename V>
+		Ins(P&& p, K&& k, V&& v)
+		: base(std::forward<P>(p)), key(std::forward<K>(k)), val(std::forward<V>(v)) {}
+	};
+
+	/// Removal node
+	struct Rem {
+		Ptr base;  ///< Modified map
+		Key key;   ///< Key removed
+
+		template<typename P, typename K>
+		Rem(P&& p, K&& k) : base(std::forward<P>(p)), key(std::forward<K>(k)) {}
+	};
+
+	/// Underlying storage
+	union Data {
+		char def;
+		Base base;
+		Ins ins;
+		Rem rem;
+
+		Data() : def('\0') {}
+		~Data() {}
+	} data;
+
+	/// Type of node
+	mutable Mode mode;
+
+	/// get mutable reference as T
+	template<typename T>
+	T& as() { return reinterpret_cast<T&>(data); }
+
+	/// get const reference as T
+	template<typename T>
+	const T& as() const { return reinterpret_cast<const T&>(data); }
+
+	/// get rvalue reference as T
+	template<typename T>
+	T&& take_as() { return std::move(as<T>()); }
+
+	/// initialize as T
+	template<typename T, typename... Args>
+	void init( Args&&... args ) {
+		new( &as<T>() ) T { std::forward<Args>(args)... };
+	}
+
+	/// reset as current mode
+	void reset() {
+		switch( mode ) {
+			case BASE:          as<Base>().~Base(); break;
+			case REM:           as<Rem>().~Rem();   break;
+			case INS: case UPD: as<Ins>().~Ins();   break;
+		}
+	}
+
+	/// reset as base
+	void reset_as_base() {
+		as<Base>().~Base();
+	}
+
+public:
+	using key_type = typename Base::key_type;
+	using mapped_type = typename Base::mapped_type;
+	using value_type = typename Base::value_type;
+	using size_type = typename Base::size_type;
+	using difference_type = typename Base::difference_type;
+	using iterator = typename Base::const_iterator;
+
+	PersistentMap() : data(), mode(BASE) { init<Base>(); }
+
+	PersistentMap( Base&& b ) : data(), mode(BASE) { init<Base>(std::move(b)); }
+
+	PersistentMap( const Self& o ) = delete;
+
+	Self& operator= ( const Self& o ) = delete;
+
+	~PersistentMap() { reset(); }
+
+	/// Create a pointer to a new, empty persistent map
+	static Ptr new_ptr() { return std::make_shared<Self>(); }
+
+	/// reroot persistent map at current node
+	void reroot() const {
+		// recursive base case
+		if ( mode == BASE ) return;
+
+		// reroot base
+		Self* mut_this = const_cast<Self*>(this);
+		Ptr base = ( mode == REM ) ? mut_this->as<Rem>().base : mut_this->as<Ins>().base;
+		base->reroot();
+
+		// remove map from base
+		Base base_map = base->template take_as<Base>();
+		base->reset_as_base();
+
+		// switch base to inverse of self and mutate base map
+		switch ( mode ) {
+			case REM: {
+				Rem& self = mut_this->as<Rem>();
+				auto it = base_map.find( self.key );
+
+				base->template init<Ins>(
+						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
+				base->mode = INS;
+
+				base_map.erase( it );
+				break;
+			}
+			case INS: {
+				Ins& self = mut_this->as<Ins>();
+
+				base->template init<Rem>( mut_this->shared_from_this(), self.key );
+				base->mode = REM;
+
+				base_map.emplace( std::move(self.key), std::move(self.val) );
+				break;
+			}
+			case UPD: {
+				Ins& self = mut_this->as<Ins>();
+				auto it = base_map.find( self.key );
+
+				base->template init<Ins>(
+						mut_this->shared_from_this(), std::move(self.key), std::move(it->second) );
+				base->mode = UPD;
+
+				it->second = std::move(self.val);
+				break;
+			}
+			case BASE: assertf(false, "unreachable"); break;
+		}
+
+		// set base map into self
+		mut_this->reset();
+		mut_this->init<Base>( std::move(base_map) );
+		mode = BASE;
+	}
+
+private:
+	/// the base after rerooting at the current node
+	const Base& rerooted() const {
+		reroot();
+		return as<Base>();
+	}
+
+public:
+	/// true iff the map is empty
+	bool empty() const { return rerooted().empty(); }
+
+	/// number of entries in map
+	size_type size() const { return rerooted().size(); }
+
+	/// begin iterator for map; may be invalidated by calls to non-iteration functions
+	/// or functions on other maps in the same tree
+	iterator begin() const { return rerooted().begin(); }
+
+	/// end iterator for map; may be invalidated by calls to non-iteration functions
+	/// or functions on other maps in the same tree
+	iterator end() const { return rerooted().end(); }
+
+	/// underlying map iterator for value
+	iterator find(const Key& k) const { return rerooted().find( k ); }
+
+	/// check if value is present
+	size_type count(const Key& k) const { return rerooted().count( k ); }
+
+	/// get value; undefined behaviour if not present
+	const Val& get(const Key& k) const {
+		const Base& self = rerooted();
+		auto it = self.find( k );
+		return it->second;
+	}
+
+	/// get value; returns default if not present
+	template<typename V>
+	Val get_or_default(const Key& k, V&& d) const {
+		const Base& self = rerooted();
+		auto it = self.find( k );
+		if ( it == self.end() ) return d;
+		else return it->second;
+	}
+
+	/// set value, storing new map in output variable
+	template<typename K, typename V>
+	Ptr set(K&& k, V&& v) {
+		reroot();
+
+		// transfer map to new node
+		Ptr ret = std::make_shared<Self>( take_as<Base>() );
+		reset_as_base();
+		Base& base_map = ret->template as<Base>();
+
+		// check if this is update or insert
+		auto it = base_map.find( k );
+		if ( it == base_map.end() ) {
+			// set self to REM node and insert into base
+			init<Rem>( ret, k );
+			mode = REM;
+
+			base_map.emplace_hint( it, std::forward<K>(k), std::forward<V>(v) );
+		} else {
+			// set self to UPD node and modify base
+			init<Ins>( ret, std::forward<K>(k), std::move(it->second) );
+			mode = UPD;
+
+			it->second = std::forward<V>(v);
+		}
+
+		return ret;
+	}
+
+	/// remove value, storing new map in output variable; does nothing if key not in map
+	Ptr erase(const Key& k) {
+		reroot();
+
+		// exit early if key does not exist in map
+		if ( ! as<Base>().count( k ) ) return this->shared_from_this();
+
+		// transfer map to new node
+		Ptr ret = std::make_shared<Self>( take_as<Base>() );
+		reset_as_base();
+		Base& base_map = ret->template as<Base>();
+
+		// set self to INS node and remove from base
+		init<Ins>( ret, k, base_map[k] );
+		mode = INS;
+
+		base_map.erase( k );
+
+		return ret;
+	}
+};
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/ResolvProtoDump.cpp
===================================================================
--- src/Common/ResolvProtoDump.cpp	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ src/Common/ResolvProtoDump.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -26,5 +26,5 @@
 #include "AST/TranslationUnit.hpp"
 #include "AST/Type.hpp"
-#include "CodeGen/OperatorTable.h"
+#include "CodeGen/OperatorTable.hpp"
 
 namespace {
Index: src/Common/ScopedMap.h
===================================================================
--- src/Common/ScopedMap.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,357 +1,0 @@
-//
-// 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.
-//
-// ScopedMap.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Wed Dec 2 11:37:00 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Feb 15 08:41:28 2022
-// Update Count     : 5
-//
-
-#pragma once
-
-#include <cassert>
-#include <iterator>
-#include <map>
-#include <utility>
-#include <vector>
-
-/// Default (empty) ScopedMap note type
-struct EmptyNote {};
-
-/// A map where the items are placed into nested scopes;
-/// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward.
-/// Scopes may be annotated with a value; the annotation defaults to empty
-template<typename Key, typename Value, typename Note = EmptyNote>
-class ScopedMap {
-	typedef std::map< Key, Value > MapType;
-	struct Scope {
-		MapType map;
-		Note note;
-
-		template<typename N>
-		Scope(N && n) : map(), note(std::forward<N>(n)) {}
-
-		Scope() = default;
-		Scope(const Scope &) = default;
-		Scope(Scope &&) = default;
-		Scope & operator= (const Scope &) = default;
-		Scope & operator= (Scope &&) = default;
-	};
-	typedef std::vector< Scope > ScopeList;
-
-	/// Scoped list of maps.
-	ScopeList scopes;
-public:
-	typedef typename MapType::key_type key_type;
-	typedef typename MapType::mapped_type mapped_type;
-	typedef typename MapType::value_type value_type;
-	typedef typename ScopeList::size_type size_type;
-	typedef typename ScopeList::difference_type difference_type;
-	typedef typename MapType::reference reference;
-	typedef typename MapType::const_reference const_reference;
-	typedef typename MapType::pointer pointer;
-	typedef typename MapType::const_pointer const_pointer;
-
-	// Both iterator types are complete bidrectional iterators, see below.
-	class iterator;
-	class const_iterator;
-
-	/// Starts a new scope
-	void beginScope() {
-		scopes.emplace_back();
-	}
-
-	// Starts a new scope with the given note
-	template<typename N>
-	void beginScope( N && n ) {
-		scopes.emplace_back( std::forward<N>(n) );
-	}
-
-	/// Ends a scope; invalidates any iterators pointing to elements of that scope
-	void endScope() {
-		scopes.pop_back();
-		assert( ! scopes.empty() );
-	}
-
-	/// Default constructor initializes with one scope
-	ScopedMap() : scopes() { beginScope(); }
-
-	/// Constructs with a given note on the outermost scope
-	template<typename N>
-	ScopedMap( N && n ) : scopes() { beginScope(std::forward<N>(n)); }
-
-	iterator begin() { return iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
-	const_iterator begin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
-	const_iterator cbegin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
-	iterator end() { return iterator(scopes, scopes[0].map.end(), 0); }
-	const_iterator end() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
-	const_iterator cend() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
-
-	/// Gets the index of the current scope (counted from 1)
-	size_type currentScope() const { return scopes.size() - 1; }
-
-	/// 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; }
-
-	/// Finds the given key in the outermost scope it occurs; returns end() for none such
-	iterator find( const Key & key ) {
-		for ( size_type i = scopes.size() - 1; ; --i ) {
-			typename MapType::iterator val = scopes[i].map.find( key );
-			if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
-			if ( i == 0 ) break;
-		}
-		return end();
-	}
-	const_iterator find( const Key & key ) const {
-			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->find( key ) );
-	}
-
-	/// Finds the given key in the provided scope; returns end() for none such
-	iterator findAt( size_type scope, const Key & key ) {
-		typename MapType::iterator val = scopes[scope].map.find( key );
-		if ( val != scopes[scope].map.end() ) return iterator( scopes, val, scope );
-		return end();
-	}
-	const_iterator findAt( size_type scope, const Key & key ) const {
-		return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findAt( scope, key ) );
-	}
-
-	/// Finds the given key in the outermost scope inside the given scope where it occurs
-	iterator findNext( const_iterator & it, const Key & key ) {
-		if ( it.level == 0 ) return end();
-		for ( size_type i = it.level - 1; ; --i ) {
-			typename MapType::iterator val = scopes[i].map.find( key );
-			if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
-			if ( i == 0 ) break;
-		}
-		return end();
-	}
-	const_iterator findNext( const_iterator & it, const Key & key ) const {
-			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findNext( it, key ) );
-	}
-
-	/// Inserts the given key-value pair into the outermost scope
-	template< typename value_type_t >
-	std::pair< iterator, bool > insert( value_type_t && value ) {
-		std::pair< typename MapType::iterator, bool > res = scopes.back().map.insert( std::forward<value_type_t>( value ) );
-		return std::make_pair( iterator(scopes, std::move( res.first ), scopes.size()-1), std::move( res.second ) );
-	}
-
-	template< typename value_t >
-	std::pair< iterator, bool > insert( const Key & key, value_t && value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
-
-	template< typename value_type_t >
-	std::pair< iterator, bool > insertAt( size_type scope, value_type_t && value ) {
-		std::pair< typename MapType::iterator, bool > res = scopes.at(scope).map.insert( std::forward<value_type_t>( value ) );
-		return std::make_pair( iterator(scopes, std::move( res.first ), scope), std::move( res.second ) );
-	}
-
-	template< typename value_t >
-	std::pair< iterator, bool > insertAt( size_type scope, const Key & key, value_t && value ) {
-		return insertAt( scope, std::make_pair( key, std::forward<value_t>( value ) ) );
-	}
-
-	Value & operator[] ( const Key & key ) {
-		iterator slot = find( key );
-		if ( slot != end() ) return slot->second;
-		return insert( key, Value() ).first->second;
-	}
-
-	/// Erases element with key in the innermost scope that has it.
-	size_type erase( const Key & key ) {
-		for ( auto it = scopes.rbegin() ; it != scopes.rend() ; ++it ) {
-			size_type i = it->map.erase( key );
-			if ( 0 != i ) return i;
-		}
-		return 0;
-	}
-
-	size_type count( const Key & key ) const {
-		size_type c = 0;
-		auto it = find( key );
-		auto end = cend();
-
-		while(it != end) {
-			c++;
-			it = findNext(it, key);
-		}
-
-		return c;
-	}
-
-	bool contains( const Key & key ) const {
-		return find( key ) != cend();
-	}
-};
-
-template<typename Key, typename Value, typename Note>
-class ScopedMap<Key, Value, Note>::iterator :
-		public std::iterator< std::bidirectional_iterator_tag, value_type > {
-	friend class ScopedMap;
-	friend class const_iterator;
-	typedef typename MapType::iterator wrapped_iterator;
-	typedef typename ScopeList::size_type size_type;
-
-	/// Checks if this iterator points to a valid item
-	bool is_valid() const {
-		return it != (*scopes)[level].map.end();
-	}
-
-	/// Increments on invalid
-	iterator & next_valid() {
-		if ( ! is_valid() ) { ++(*this); }
-		return *this;
-	}
-
-	/// Decrements on invalid
-	iterator & prev_valid() {
-		if ( ! is_valid() ) { --(*this); }
-		return *this;
-	}
-
-	iterator(ScopeList & _scopes, const wrapped_iterator & _it, size_type inLevel)
-		: scopes(&_scopes), it(_it), level(inLevel) {}
-public:
-	iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
-	iterator & operator= (const iterator & that) {
-		scopes = that.scopes; level = that.level; it = that.it;
-		return *this;
-	}
-
-	reference operator* () { return *it; }
-	pointer operator-> () const { return it.operator->(); }
-
-	iterator & operator++ () {
-		if ( it == (*scopes)[level].map.end() ) {
-			if ( level == 0 ) return *this;
-			--level;
-			it = (*scopes)[level].map.begin();
-		} else {
-			++it;
-		}
-		return next_valid();
-	}
-	iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
-
-	iterator & operator-- () {
-		// may fail if this is the begin iterator; allowed by STL spec
-		if ( it == (*scopes)[level].map.begin() ) {
-			++level;
-			it = (*scopes)[level].map.end();
-		}
-		--it;
-		return prev_valid();
-	}
-	iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
-
-	bool operator== (const iterator & that) const {
-		return scopes == that.scopes && level == that.level && it == that.it;
-	}
-	bool operator!= (const iterator & that) const { return !( *this == that ); }
-
-	size_type get_level() const { return level; }
-
-	Note & get_note() { return (*scopes)[level].note; }
-	const Note & get_note() const { return (*scopes)[level].note; }
-
-private:
-	ScopeList *scopes;
-	wrapped_iterator it;
-	size_type level;
-};
-
-template<typename Key, typename Value, typename Note>
-class ScopedMap<Key, Value, Note>::const_iterator :
-		public std::iterator< std::bidirectional_iterator_tag, value_type > {
-	friend class ScopedMap;
-	typedef typename ScopedMap::MapType::iterator wrapped_iterator;
-	typedef typename ScopedMap::MapType::const_iterator wrapped_const_iterator;
-	typedef typename ScopedMap::ScopeList scope_list;
-	typedef typename scope_list::size_type size_type;
-
-	/// Checks if this iterator points to a valid item
-	bool is_valid() const {
-		return it != (*scopes)[level].map.end();
-	}
-
-	/// Increments on invalid
-	const_iterator & next_valid() {
-		if ( ! is_valid() ) { ++(*this); }
-		return *this;
-	}
-
-	/// Decrements on invalid
-	const_iterator & prev_valid() {
-		if ( ! is_valid() ) { --(*this); }
-		return *this;
-	}
-
-	const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
-		: scopes(&_scopes), it(_it), level(inLevel) {}
-public:
-	const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
-	const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
-	const_iterator & operator= (const iterator & that) {
-		scopes = that.scopes; level = that.level; it = that.it;
-		return *this;
-	}
-	const_iterator & operator= (const const_iterator & that) {
-		scopes = that.scopes; level = that.level; it = that.it;
-		return *this;
-	}
-
-	const_reference operator* () { return *it; }
-	const_pointer operator-> () { return it.operator->(); }
-
-	const_iterator & operator++ () {
-		if ( it == (*scopes)[level].map.end() ) {
-			if ( level == 0 ) return *this;
-			--level;
-			it = (*scopes)[level].map.begin();
-		} else {
-			++it;
-		}
-		return next_valid();
-	}
-	const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
-
-	const_iterator & operator-- () {
-		// may fail if this is the begin iterator; allowed by STL spec
-		if ( it == (*scopes)[level].map.begin() ) {
-			++level;
-			it = (*scopes)[level].map.end();
-		}
-		--it;
-		return prev_valid();
-	}
-	const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
-
-	bool operator== (const const_iterator & that) const {
-		return scopes == that.scopes && level == that.level && it == that.it;
-	}
-	bool operator!= (const const_iterator & that) const { return !( *this == that ); }
-
-	size_type get_level() const { return level; }
-
-	const Note & get_note() const { return (*scopes)[level].note; }
-
-private:
-	scope_list const *scopes;
-	wrapped_const_iterator it;
-	size_type level;
-};
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/ScopedMap.hpp
===================================================================
--- src/Common/ScopedMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/ScopedMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,357 @@
+//
+// 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.
+//
+// ScopedMap.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed Dec 2 11:37:00 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Feb 15 08:41:28 2022
+// Update Count     : 5
+//
+
+#pragma once
+
+#include <cassert>
+#include <iterator>
+#include <map>
+#include <utility>
+#include <vector>
+
+/// Default (empty) ScopedMap note type
+struct EmptyNote {};
+
+/// A map where the items are placed into nested scopes;
+/// inserted items are placed into the innermost scope, lookup looks from the innermost scope outward.
+/// Scopes may be annotated with a value; the annotation defaults to empty
+template<typename Key, typename Value, typename Note = EmptyNote>
+class ScopedMap {
+	typedef std::map< Key, Value > MapType;
+	struct Scope {
+		MapType map;
+		Note note;
+
+		template<typename N>
+		Scope(N && n) : map(), note(std::forward<N>(n)) {}
+
+		Scope() = default;
+		Scope(const Scope &) = default;
+		Scope(Scope &&) = default;
+		Scope & operator= (const Scope &) = default;
+		Scope & operator= (Scope &&) = default;
+	};
+	typedef std::vector< Scope > ScopeList;
+
+	/// Scoped list of maps.
+	ScopeList scopes;
+public:
+	typedef typename MapType::key_type key_type;
+	typedef typename MapType::mapped_type mapped_type;
+	typedef typename MapType::value_type value_type;
+	typedef typename ScopeList::size_type size_type;
+	typedef typename ScopeList::difference_type difference_type;
+	typedef typename MapType::reference reference;
+	typedef typename MapType::const_reference const_reference;
+	typedef typename MapType::pointer pointer;
+	typedef typename MapType::const_pointer const_pointer;
+
+	// Both iterator types are complete bidrectional iterators, see below.
+	class iterator;
+	class const_iterator;
+
+	/// Starts a new scope
+	void beginScope() {
+		scopes.emplace_back();
+	}
+
+	// Starts a new scope with the given note
+	template<typename N>
+	void beginScope( N && n ) {
+		scopes.emplace_back( std::forward<N>(n) );
+	}
+
+	/// Ends a scope; invalidates any iterators pointing to elements of that scope
+	void endScope() {
+		scopes.pop_back();
+		assert( ! scopes.empty() );
+	}
+
+	/// Default constructor initializes with one scope
+	ScopedMap() : scopes() { beginScope(); }
+
+	/// Constructs with a given note on the outermost scope
+	template<typename N>
+	ScopedMap( N && n ) : scopes() { beginScope(std::forward<N>(n)); }
+
+	iterator begin() { return iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
+	const_iterator begin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
+	const_iterator cbegin() const { return const_iterator(scopes, scopes.back().map.begin(), currentScope()).next_valid(); }
+	iterator end() { return iterator(scopes, scopes[0].map.end(), 0); }
+	const_iterator end() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
+	const_iterator cend() const { return const_iterator(scopes, scopes[0].map.end(), 0); }
+
+	/// Gets the index of the current scope (counted from 1)
+	size_type currentScope() const { return scopes.size() - 1; }
+
+	/// 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; }
+
+	/// Finds the given key in the outermost scope it occurs; returns end() for none such
+	iterator find( const Key & key ) {
+		for ( size_type i = scopes.size() - 1; ; --i ) {
+			typename MapType::iterator val = scopes[i].map.find( key );
+			if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
+			if ( i == 0 ) break;
+		}
+		return end();
+	}
+	const_iterator find( const Key & key ) const {
+			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->find( key ) );
+	}
+
+	/// Finds the given key in the provided scope; returns end() for none such
+	iterator findAt( size_type scope, const Key & key ) {
+		typename MapType::iterator val = scopes[scope].map.find( key );
+		if ( val != scopes[scope].map.end() ) return iterator( scopes, val, scope );
+		return end();
+	}
+	const_iterator findAt( size_type scope, const Key & key ) const {
+		return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findAt( scope, key ) );
+	}
+
+	/// Finds the given key in the outermost scope inside the given scope where it occurs
+	iterator findNext( const_iterator & it, const Key & key ) {
+		if ( it.level == 0 ) return end();
+		for ( size_type i = it.level - 1; ; --i ) {
+			typename MapType::iterator val = scopes[i].map.find( key );
+			if ( val != scopes[i].map.end() ) return iterator( scopes, val, i );
+			if ( i == 0 ) break;
+		}
+		return end();
+	}
+	const_iterator findNext( const_iterator & it, const Key & key ) const {
+			return const_iterator( const_cast< ScopedMap< Key, Value, Note >* >(this)->findNext( it, key ) );
+	}
+
+	/// Inserts the given key-value pair into the outermost scope
+	template< typename value_type_t >
+	std::pair< iterator, bool > insert( value_type_t && value ) {
+		std::pair< typename MapType::iterator, bool > res = scopes.back().map.insert( std::forward<value_type_t>( value ) );
+		return std::make_pair( iterator(scopes, std::move( res.first ), scopes.size()-1), std::move( res.second ) );
+	}
+
+	template< typename value_t >
+	std::pair< iterator, bool > insert( const Key & key, value_t && value ) { return insert( std::make_pair( key, std::forward<value_t>( value ) ) ); }
+
+	template< typename value_type_t >
+	std::pair< iterator, bool > insertAt( size_type scope, value_type_t && value ) {
+		std::pair< typename MapType::iterator, bool > res = scopes.at(scope).map.insert( std::forward<value_type_t>( value ) );
+		return std::make_pair( iterator(scopes, std::move( res.first ), scope), std::move( res.second ) );
+	}
+
+	template< typename value_t >
+	std::pair< iterator, bool > insertAt( size_type scope, const Key & key, value_t && value ) {
+		return insertAt( scope, std::make_pair( key, std::forward<value_t>( value ) ) );
+	}
+
+	Value & operator[] ( const Key & key ) {
+		iterator slot = find( key );
+		if ( slot != end() ) return slot->second;
+		return insert( key, Value() ).first->second;
+	}
+
+	/// Erases element with key in the innermost scope that has it.
+	size_type erase( const Key & key ) {
+		for ( auto it = scopes.rbegin() ; it != scopes.rend() ; ++it ) {
+			size_type i = it->map.erase( key );
+			if ( 0 != i ) return i;
+		}
+		return 0;
+	}
+
+	size_type count( const Key & key ) const {
+		size_type c = 0;
+		auto it = find( key );
+		auto end = cend();
+
+		while(it != end) {
+			c++;
+			it = findNext(it, key);
+		}
+
+		return c;
+	}
+
+	bool contains( const Key & key ) const {
+		return find( key ) != cend();
+	}
+};
+
+template<typename Key, typename Value, typename Note>
+class ScopedMap<Key, Value, Note>::iterator :
+		public std::iterator< std::bidirectional_iterator_tag, value_type > {
+	friend class ScopedMap;
+	friend class const_iterator;
+	typedef typename MapType::iterator wrapped_iterator;
+	typedef typename ScopeList::size_type size_type;
+
+	/// Checks if this iterator points to a valid item
+	bool is_valid() const {
+		return it != (*scopes)[level].map.end();
+	}
+
+	/// Increments on invalid
+	iterator & next_valid() {
+		if ( ! is_valid() ) { ++(*this); }
+		return *this;
+	}
+
+	/// Decrements on invalid
+	iterator & prev_valid() {
+		if ( ! is_valid() ) { --(*this); }
+		return *this;
+	}
+
+	iterator(ScopeList & _scopes, const wrapped_iterator & _it, size_type inLevel)
+		: scopes(&_scopes), it(_it), level(inLevel) {}
+public:
+	iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+	iterator & operator= (const iterator & that) {
+		scopes = that.scopes; level = that.level; it = that.it;
+		return *this;
+	}
+
+	reference operator* () { return *it; }
+	pointer operator-> () const { return it.operator->(); }
+
+	iterator & operator++ () {
+		if ( it == (*scopes)[level].map.end() ) {
+			if ( level == 0 ) return *this;
+			--level;
+			it = (*scopes)[level].map.begin();
+		} else {
+			++it;
+		}
+		return next_valid();
+	}
+	iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
+
+	iterator & operator-- () {
+		// may fail if this is the begin iterator; allowed by STL spec
+		if ( it == (*scopes)[level].map.begin() ) {
+			++level;
+			it = (*scopes)[level].map.end();
+		}
+		--it;
+		return prev_valid();
+	}
+	iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
+
+	bool operator== (const iterator & that) const {
+		return scopes == that.scopes && level == that.level && it == that.it;
+	}
+	bool operator!= (const iterator & that) const { return !( *this == that ); }
+
+	size_type get_level() const { return level; }
+
+	Note & get_note() { return (*scopes)[level].note; }
+	const Note & get_note() const { return (*scopes)[level].note; }
+
+private:
+	ScopeList *scopes;
+	wrapped_iterator it;
+	size_type level;
+};
+
+template<typename Key, typename Value, typename Note>
+class ScopedMap<Key, Value, Note>::const_iterator :
+		public std::iterator< std::bidirectional_iterator_tag, value_type > {
+	friend class ScopedMap;
+	typedef typename ScopedMap::MapType::iterator wrapped_iterator;
+	typedef typename ScopedMap::MapType::const_iterator wrapped_const_iterator;
+	typedef typename ScopedMap::ScopeList scope_list;
+	typedef typename scope_list::size_type size_type;
+
+	/// Checks if this iterator points to a valid item
+	bool is_valid() const {
+		return it != (*scopes)[level].map.end();
+	}
+
+	/// Increments on invalid
+	const_iterator & next_valid() {
+		if ( ! is_valid() ) { ++(*this); }
+		return *this;
+	}
+
+	/// Decrements on invalid
+	const_iterator & prev_valid() {
+		if ( ! is_valid() ) { --(*this); }
+		return *this;
+	}
+
+	const_iterator(scope_list const & _scopes, const wrapped_const_iterator & _it, size_type inLevel)
+		: scopes(&_scopes), it(_it), level(inLevel) {}
+public:
+	const_iterator(const iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+	const_iterator(const const_iterator & that) : scopes(that.scopes), it(that.it), level(that.level) {}
+	const_iterator & operator= (const iterator & that) {
+		scopes = that.scopes; level = that.level; it = that.it;
+		return *this;
+	}
+	const_iterator & operator= (const const_iterator & that) {
+		scopes = that.scopes; level = that.level; it = that.it;
+		return *this;
+	}
+
+	const_reference operator* () { return *it; }
+	const_pointer operator-> () { return it.operator->(); }
+
+	const_iterator & operator++ () {
+		if ( it == (*scopes)[level].map.end() ) {
+			if ( level == 0 ) return *this;
+			--level;
+			it = (*scopes)[level].map.begin();
+		} else {
+			++it;
+		}
+		return next_valid();
+	}
+	const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
+
+	const_iterator & operator-- () {
+		// may fail if this is the begin iterator; allowed by STL spec
+		if ( it == (*scopes)[level].map.begin() ) {
+			++level;
+			it = (*scopes)[level].map.end();
+		}
+		--it;
+		return prev_valid();
+	}
+	const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
+
+	bool operator== (const const_iterator & that) const {
+		return scopes == that.scopes && level == that.level && it == that.it;
+	}
+	bool operator!= (const const_iterator & that) const { return !( *this == that ); }
+
+	size_type get_level() const { return level; }
+
+	const Note & get_note() const { return (*scopes)[level].note; }
+
+private:
+	scope_list const *scopes;
+	wrapped_const_iterator it;
+	size_type level;
+};
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/SemanticError.cc
===================================================================
--- src/Common/SemanticError.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,195 +1,0 @@
-//
-// 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.
-//
-// SemanticError.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 13:45:28 2023
-// Update Count     : 34
-//
-
-#include <cstdarg>
-#include <cstdio>										// for fileno, stderr
-#include <cstring>
-#include <unistd.h>										// for isatty
-#include <iostream>										// for basic_ostream, operator<<, ostream
-#include <list>											// for list, _List_iterator
-#include <string>										// for string, operator<<, operator+, to_string
-#include <vector>
-
-using namespace std;
-
-#include "Common/utility.h"								// for to_string, CodeLocation (ptr only)
-#include "SemanticError.h"
-
-//-----------------------------------------------------------------------------
-// Severity Handling
-vector<Severity> & get_severities() {
-	static vector<Severity> severities;
-	if(severities.empty()) {
-		severities.reserve((size_t)Warning::NUMBER_OF_WARNINGS);
-		for ( const auto w : WarningFormats ) {
-			severities.push_back( w.default_severity );
-		} // for
-	}
-	return severities;
-}
-
-void SemanticWarning_SuppressAll() {
-	for( auto & s : get_severities() ) {
-		s = Severity::Suppress;
-	}
-}
-
-void SemanticWarning_EnableAll() {
-	for( auto & s : get_severities() ) {
-		s = Severity::Warn;
-	}
-}
-
-void SemanticWarning_WarningAsError() {
-	for( auto & s : get_severities() ) {
-		if(s == Severity::Warn) s = Severity::Error;
-	}
-}
-
-void SemanticWarning_Set(const char * const name, Severity s) {
-	size_t idx = 0;
-	for ( const auto & w : WarningFormats ) {
-		if ( strcmp( name, w.name ) == 0 ) {
-			get_severities()[idx] = s;
-			break;
-		}
-		idx++;
-	}
-}
-
-//-----------------------------------------------------------------------------
-// Semantic Error
-
-bool SemanticErrorThrow = false;
-
-SemanticErrorException::SemanticErrorException( CodeLocation location, string error ) {
-	append( location, error );
-}
-
-void SemanticErrorException::append( SemanticErrorException &other ) {
-	errors.splice( errors.end(), other.errors );
-}
-
-void SemanticErrorException::append( CodeLocation location, const string & msg ) {
-	errors.emplace_back( location, msg );
-}
-
-bool SemanticErrorException::isEmpty() const {
-	return errors.empty();
-}
-
-void SemanticErrorException::print() {
-//	using to_string;
-
-	errors.sort([](const error & lhs, const error & rhs) -> bool {
-		if(lhs.location.startsBefore(rhs.location)) return true;
-		if(rhs.location.startsBefore(lhs.location)) return false;
-
-		return lhs.description < rhs.description;
-	});
-
-	for( auto err : errors ) {
-		cerr << ErrorHelpers::bold() << err.location << ErrorHelpers::error_str() << ErrorHelpers::reset_font() << err.description << endl;
-	}
-}
-
-void SemanticError( CodeLocation location, const char * fmt, ... ) {
-	char msg[2048];										// worst-case error-message buffer
-	va_list args;
-	va_start( args, fmt );
-	vsnprintf( msg, sizeof(msg), fmt, args );			// always null terminated, but may be truncated
-	va_end( args );
-
-	SemanticErrorThrow = true;
-	throw SemanticErrorException( location, msg );		// convert msg to string
-}
-
-void SemanticWarning( CodeLocation location, Warning warning, ... ) {
-	Severity severity = get_severities()[(int)warning];
-
-	switch ( severity ) {
-	case Severity::Suppress :
-		break;
-	case Severity::Warn :
-	case Severity::Error :
-		{
-			char msg[2048];								// worst-case error-message buffer
-			va_list args;
-			va_start( args, warning );
-			vsnprintf( msg, sizeof(msg), WarningFormats[(int)warning].message, args ); // always null terminated, but may be truncated
-			va_end( args );
-
-			if ( severity == Severity::Warn ) {
-				cerr << ErrorHelpers::bold() << location << ErrorHelpers::warning_str() << ErrorHelpers::reset_font() << msg << endl;
-			} else {
-				SemanticError( location, string( msg ) );
-			}
-		}
-		break;
-	case Severity::Critical :
-		assertf(false, "Critical errors not implemented yet");
-		break;
-	}
-}
-
-//-----------------------------------------------------------------------------
-// Helpers
-namespace ErrorHelpers {
-	Colors colors = Colors::Auto;
-
-	static inline bool with_colors() {
-		return colors == Colors::Auto ? isatty( STDERR_FILENO ) : bool(colors);
-	}
-
-	const string & error_str() {
-		static string str = with_colors() ? "\e[31merror:\e[39m " : "error: ";
-		return str;
-	}
-
-	const string & warning_str() {
-		static string str = with_colors() ? "\e[95mwarning:\e[39m " : "warning: ";
-		return str;
-	}
-
-	const string & bold_ttycode() {
-		static string str = with_colors() ? "\e[1m" : "";
-		return str;
-	}
-
-	const string & reset_font_ttycode() {
-		static string str = with_colors() ? "\e[0m" : "";
-		return str;
-	}
-
-	string make_bold( const string & str ) {
-		return bold_ttycode() + str + reset_font_ttycode();
-	}
-
-	ostream & operator<<(ostream & os, bold) {
-		os << bold_ttycode();
-		return os;
-	}
-
-	ostream & operator<<(ostream & os, reset_font) {
-		os << reset_font_ttycode();
-		return os;
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/SemanticError.cpp
===================================================================
--- src/Common/SemanticError.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/SemanticError.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,196 @@
+//
+// 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.
+//
+// SemanticError.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Dec 14 13:45:28 2023
+// Update Count     : 34
+//
+
+#include "SemanticError.hpp"
+
+#include <cstdarg>
+#include <cstdio>										// for fileno, stderr
+#include <cstring>
+#include <unistd.h>										// for isatty
+#include <iostream>										// for basic_ostream, operator<<, ostream
+#include <list>											// for list, _List_iterator
+#include <string>										// for string, operator<<, operator+, to_string
+#include <vector>
+
+#include "Common/Utility.hpp"							// for to_string, CodeLocation (ptr only)
+
+using namespace std;
+
+//-----------------------------------------------------------------------------
+// Severity Handling
+vector<Severity> & get_severities() {
+	static vector<Severity> severities;
+	if(severities.empty()) {
+		severities.reserve((size_t)Warning::NUMBER_OF_WARNINGS);
+		for ( const auto w : WarningFormats ) {
+			severities.push_back( w.default_severity );
+		} // for
+	}
+	return severities;
+}
+
+void SemanticWarning_SuppressAll() {
+	for( auto & s : get_severities() ) {
+		s = Severity::Suppress;
+	}
+}
+
+void SemanticWarning_EnableAll() {
+	for( auto & s : get_severities() ) {
+		s = Severity::Warn;
+	}
+}
+
+void SemanticWarning_WarningAsError() {
+	for( auto & s : get_severities() ) {
+		if(s == Severity::Warn) s = Severity::Error;
+	}
+}
+
+void SemanticWarning_Set(const char * const name, Severity s) {
+	size_t idx = 0;
+	for ( const auto & w : WarningFormats ) {
+		if ( strcmp( name, w.name ) == 0 ) {
+			get_severities()[idx] = s;
+			break;
+		}
+		idx++;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Semantic Error
+
+bool SemanticErrorThrow = false;
+
+SemanticErrorException::SemanticErrorException( CodeLocation location, string error ) {
+	append( location, error );
+}
+
+void SemanticErrorException::append( SemanticErrorException &other ) {
+	errors.splice( errors.end(), other.errors );
+}
+
+void SemanticErrorException::append( CodeLocation location, const string & msg ) {
+	errors.emplace_back( location, msg );
+}
+
+bool SemanticErrorException::isEmpty() const {
+	return errors.empty();
+}
+
+void SemanticErrorException::print() {
+//	using to_string;
+
+	errors.sort([](const error & lhs, const error & rhs) -> bool {
+		if(lhs.location.startsBefore(rhs.location)) return true;
+		if(rhs.location.startsBefore(lhs.location)) return false;
+
+		return lhs.description < rhs.description;
+	});
+
+	for( auto err : errors ) {
+		cerr << ErrorHelpers::bold() << err.location << ErrorHelpers::error_str() << ErrorHelpers::reset_font() << err.description << endl;
+	}
+}
+
+void SemanticError( CodeLocation location, const char * fmt, ... ) {
+	char msg[2048];										// worst-case error-message buffer
+	va_list args;
+	va_start( args, fmt );
+	vsnprintf( msg, sizeof(msg), fmt, args );			// always null terminated, but may be truncated
+	va_end( args );
+
+	SemanticErrorThrow = true;
+	throw SemanticErrorException( location, msg );		// convert msg to string
+}
+
+void SemanticWarning( CodeLocation location, Warning warning, ... ) {
+	Severity severity = get_severities()[(int)warning];
+
+	switch ( severity ) {
+	case Severity::Suppress :
+		break;
+	case Severity::Warn :
+	case Severity::Error :
+		{
+			char msg[2048];								// worst-case error-message buffer
+			va_list args;
+			va_start( args, warning );
+			vsnprintf( msg, sizeof(msg), WarningFormats[(int)warning].message, args ); // always null terminated, but may be truncated
+			va_end( args );
+
+			if ( severity == Severity::Warn ) {
+				cerr << ErrorHelpers::bold() << location << ErrorHelpers::warning_str() << ErrorHelpers::reset_font() << msg << endl;
+			} else {
+				SemanticError( location, string( msg ) );
+			}
+		}
+		break;
+	case Severity::Critical :
+		assertf(false, "Critical errors not implemented yet");
+		break;
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Helpers
+namespace ErrorHelpers {
+	Colors colors = Colors::Auto;
+
+	static inline bool with_colors() {
+		return colors == Colors::Auto ? isatty( STDERR_FILENO ) : bool(colors);
+	}
+
+	const string & error_str() {
+		static string str = with_colors() ? "\e[31merror:\e[39m " : "error: ";
+		return str;
+	}
+
+	const string & warning_str() {
+		static string str = with_colors() ? "\e[95mwarning:\e[39m " : "warning: ";
+		return str;
+	}
+
+	const string & bold_ttycode() {
+		static string str = with_colors() ? "\e[1m" : "";
+		return str;
+	}
+
+	const string & reset_font_ttycode() {
+		static string str = with_colors() ? "\e[0m" : "";
+		return str;
+	}
+
+	string make_bold( const string & str ) {
+		return bold_ttycode() + str + reset_font_ttycode();
+	}
+
+	ostream & operator<<(ostream & os, bold) {
+		os << bold_ttycode();
+		return os;
+	}
+
+	ostream & operator<<(ostream & os, reset_font) {
+		os << reset_font_ttycode();
+		return os;
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/SemanticError.h
===================================================================
--- src/Common/SemanticError.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,133 +1,0 @@
-//
-// 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.
-//
-// SemanticError.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Thu Dec 14 13:48:07 2023
-// Update Count     : 72
-//
-
-#pragma once
-
-#include "ErrorObjects.h"
-#include "AST/Node.hpp"
-#include "AST/ParseNode.hpp"
-#include <cstring>
-
-//-----------------------------------------------------------------------------
-// Errors
-
-extern bool SemanticErrorThrow;
-
-__attribute__((noreturn, format(printf, 2, 3))) void SemanticError( CodeLocation location, const char fmt[], ... );
-
-__attribute__((noreturn)) static inline void SemanticError( CodeLocation location, std::string error ) {
-	SemanticErrorThrow = true;
-	throw SemanticErrorException( location, error );
-}
-
-__attribute__((noreturn)) static inline void SemanticError( const ast::ParseNode * obj, const std::string & error ) {
-	SemanticError( obj->location, toString( error, obj ) );
-}
-
-__attribute__((noreturn)) static inline void SemanticError( CodeLocation location, const ast::Node * obj, const std::string & error ) {
-	SemanticError( location, toString( error, obj ) );
-}
-
-//-----------------------------------------------------------------------------
-// Warnings
-
-enum class Severity {
-	Suppress,
-	Warn,
-	Error,
-	Critical
-};
-
-struct WarningData {
-	const char * const name;
-	const Severity default_severity;
-	const char * const message;
-};
-
-constexpr WarningData WarningFormats[] = {
-	{"self-assign"              , Severity::Warn, "self assignment of expression: %s"                          },
-	{"reference-conversion"     , Severity::Warn, "rvalue to reference conversion of rvalue: %s"               },
-	{"qualifiers-zero_t-one_t"  , Severity::Warn, "questionable use of type qualifier(s) with %s"              },
-	{"aggregate-forward-decl"   , Severity::Warn, "forward declaration of nested aggregate: %s"                },
-	{"superfluous-decl"         , Severity::Warn, "declaration does not allocate storage: %s"                  },
-	{"superfluous-else"         , Severity::Warn, "else clause never executed for empty loop conditional"      },
-	{"gcc-attributes"           , Severity::Warn, "invalid attribute: %s"                                      },
-	{"c++-like-copy"            , Severity::Warn, "Constructor from reference is not a valid copy constructor" },
-	{"depreciated-trait-syntax" , Severity::Warn, "trait type-parameters are now specified using the forall clause" },
-};
-
-enum class Warning {
-	SelfAssignment,
-	RvalueToReferenceConversion,
-	BadQualifiersZeroOne,
-	AggrForwardDecl,
-	SuperfluousDecl,
-	SuperfluousElse,
-	GccAttributes,
-	CppCopy,
-	DeprecTraitSyntax,
-	NUMBER_OF_WARNINGS, // MUST be last warning
-};
-
-static_assert(
-	(sizeof(WarningFormats) / sizeof(WarningFormats[0])) == ((unsigned long)Warning::NUMBER_OF_WARNINGS),
-	"Each warning format should have a corresponding warning enum value"
-);
-
-void SemanticWarning( CodeLocation loc, Warning warn, ... );
-
-void SemanticWarning_SuppressAll();
-void SemanticWarning_EnableAll();
-void SemanticWarning_WarningAsError();
-void SemanticWarning_Set(const char * const name, Severity s);
-
-// SKULLDUGGERY: cfa.cc is built before SemanticError.cc but needs this routine.
-static inline bool SemanticWarning_Exist(const char * const name) {
-	for ( const auto & w : WarningFormats ) {
-		if ( std::strcmp( name, w.name ) == 0 ) return true;
-	}
-	return false;
-}
-
-//-----------------------------------------------------------------------------
-// Helpers
-namespace ErrorHelpers {
-	enum class Colors {
-		Never = false,
-		Always = true,
-		Auto,
-	};
-
-	extern Colors colors;
-
-	const std::string & error_str();
-	const std::string & warning_str();
-	const std::string & bold_ttycode();
-	const std::string & reset_font_ttycode();
-
-	std::string make_bold( const std::string & str );
-
-	struct bold {};
-	std::ostream & operator<<(std::ostream & os, bold);
-
-	struct reset_font {};
-	std::ostream & operator<<(std::ostream & os, reset_font);
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/SemanticError.hpp
===================================================================
--- src/Common/SemanticError.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/SemanticError.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -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.
+//
+// SemanticError.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Thu Dec 14 13:48:07 2023
+// Update Count     : 72
+//
+
+#pragma once
+
+#include "ErrorObjects.hpp"
+#include "AST/Node.hpp"
+#include "AST/ParseNode.hpp"
+#include <cstring>
+
+//-----------------------------------------------------------------------------
+// Errors
+
+extern bool SemanticErrorThrow;
+
+__attribute__((noreturn, format(printf, 2, 3))) void SemanticError( CodeLocation location, const char fmt[], ... );
+
+__attribute__((noreturn)) static inline void SemanticError( CodeLocation location, std::string error ) {
+	SemanticErrorThrow = true;
+	throw SemanticErrorException( location, error );
+}
+
+__attribute__((noreturn)) static inline void SemanticError( const ast::ParseNode * obj, const std::string & error ) {
+	SemanticError( obj->location, toString( error, obj ) );
+}
+
+__attribute__((noreturn)) static inline void SemanticError( CodeLocation location, const ast::Node * obj, const std::string & error ) {
+	SemanticError( location, toString( error, obj ) );
+}
+
+//-----------------------------------------------------------------------------
+// Warnings
+
+enum class Severity {
+	Suppress,
+	Warn,
+	Error,
+	Critical
+};
+
+struct WarningData {
+	const char * const name;
+	const Severity default_severity;
+	const char * const message;
+};
+
+constexpr WarningData WarningFormats[] = {
+	{"self-assign"              , Severity::Warn, "self assignment of expression: %s"                          },
+	{"reference-conversion"     , Severity::Warn, "rvalue to reference conversion of rvalue: %s"               },
+	{"qualifiers-zero_t-one_t"  , Severity::Warn, "questionable use of type qualifier(s) with %s"              },
+	{"aggregate-forward-decl"   , Severity::Warn, "forward declaration of nested aggregate: %s"                },
+	{"superfluous-decl"         , Severity::Warn, "declaration does not allocate storage: %s"                  },
+	{"superfluous-else"         , Severity::Warn, "else clause never executed for empty loop conditional"      },
+	{"gcc-attributes"           , Severity::Warn, "invalid attribute: %s"                                      },
+	{"c++-like-copy"            , Severity::Warn, "Constructor from reference is not a valid copy constructor" },
+	{"depreciated-trait-syntax" , Severity::Warn, "trait type-parameters are now specified using the forall clause" },
+};
+
+enum class Warning {
+	SelfAssignment,
+	RvalueToReferenceConversion,
+	BadQualifiersZeroOne,
+	AggrForwardDecl,
+	SuperfluousDecl,
+	SuperfluousElse,
+	GccAttributes,
+	CppCopy,
+	DeprecTraitSyntax,
+	NUMBER_OF_WARNINGS, // MUST be last warning
+};
+
+static_assert(
+	(sizeof(WarningFormats) / sizeof(WarningFormats[0])) == ((unsigned long)Warning::NUMBER_OF_WARNINGS),
+	"Each warning format should have a corresponding warning enum value"
+);
+
+void SemanticWarning( CodeLocation loc, Warning warn, ... );
+
+void SemanticWarning_SuppressAll();
+void SemanticWarning_EnableAll();
+void SemanticWarning_WarningAsError();
+void SemanticWarning_Set(const char * const name, Severity s);
+
+// SKULLDUGGERY: cfa.cc is built before SemanticError.cc but needs this routine.
+static inline bool SemanticWarning_Exist(const char * const name) {
+	for ( const auto & w : WarningFormats ) {
+		if ( std::strcmp( name, w.name ) == 0 ) return true;
+	}
+	return false;
+}
+
+//-----------------------------------------------------------------------------
+// Helpers
+namespace ErrorHelpers {
+	enum class Colors {
+		Never = false,
+		Always = true,
+		Auto,
+	};
+
+	extern Colors colors;
+
+	const std::string & error_str();
+	const std::string & warning_str();
+	const std::string & bold_ttycode();
+	const std::string & reset_font_ttycode();
+
+	std::string make_bold( const std::string & str );
+
+	struct bold {};
+	std::ostream & operator<<(std::ostream & os, bold);
+
+	struct reset_font {};
+	std::ostream & operator<<(std::ostream & os, reset_font);
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Stats.h
===================================================================
--- src/Common/Stats.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,49 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Stats.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Thu Feb 28 11::27:10 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-// Entry point for compiler analytics.
-/*
-The compiler currently supports 3 times of analytics:
-	 - generic counters
-	 - heap statistics
-	 - timiing statistics
-
-These can be enabled using the --stats option, to which a comma seperated list of options can be passed.
-For more details see Stats.cc
-
-Counters:
-	The counters are a generic tree of counters that print in a 2-column output format.
-	They can count maximums, averages, totals, etc.
-
-	Currently all counters are under the same enable block, this could be changed if needed.
-
-Heap:
-	Measures the total calls malloc and free as the peak number of allocations per pass
-
-Timing:
-	Comming soon
-*/
-
-
-#include "Common/Stats/Counter.h"
-#include "Common/Stats/Heap.h"
-#include "Common/Stats/Time.h"
-
-namespace Stats {
-	void parse_params(const char * const params);
-	void print();
-}
Index: src/Common/Stats.hpp
===================================================================
--- src/Common/Stats.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,49 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Stats.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu Feb 28 11::27:10 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+// Entry point for compiler analytics.
+/*
+The compiler currently supports 3 times of analytics:
+	 - generic counters
+	 - heap statistics
+	 - timiing statistics
+
+These can be enabled using the --stats option, to which a comma seperated list of options can be passed.
+For more details see Stats.cc
+
+Counters:
+	The counters are a generic tree of counters that print in a 2-column output format.
+	They can count maximums, averages, totals, etc.
+
+	Currently all counters are under the same enable block, this could be changed if needed.
+
+Heap:
+	Measures the total calls malloc and free as the peak number of allocations per pass
+
+Timing:
+	Comming soon
+*/
+
+
+#include "Common/Stats/Counter.hpp"
+#include "Common/Stats/Heap.hpp"
+#include "Common/Stats/Time.hpp"
+
+namespace Stats {
+	void parse_params(const char * const params);
+	void print();
+}
Index: src/Common/Stats/Base.h
===================================================================
--- src/Common/Stats/Base.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,86 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Heap.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Fri Mar 03 14:53:53 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-#include <cstdint>
-#include <iostream>
-
-namespace Stats {
-	namespace Base {
-		class TreeImpl;
-
-		struct TreeTop {
-			TreeImpl * head = nullptr;
-			TreeImpl * tail = nullptr;
-
-			inline void append(TreeImpl * node);
-		};
-
-		template<typename func_t>
-		void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy = false);
-
-		class TreeImpl {
-		public:
-			virtual void print(std::ostream &) = 0;
-
-			const char * const name;
-			TreeImpl(const char * const name) : name(name) {}
-
-		protected:
-			virtual ~TreeImpl() = default;
-
-			TreeImpl * next = nullptr;
-			TreeTop children;
-
-			friend struct TreeTop;
-
-			template<typename func_t>
-			friend void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy);
-		};
-
-		void TreeTop::append(TreeImpl * node) {
-			if(!head) { head = node; }
-			else      { tail->next = node;}
-			tail = node;
-		}
-
-		template<typename func_t>
-		inline void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy) {
-			auto it = range.head;
-			while(it) {
-				auto next = it->next;
-				func(it, level);
-				ForAll(it->children, level + 1, func);
-				if(destroy) delete it;
-				it = next;
-			}
-		}
-
-		template<TreeTop & top>
-		class Tree : public TreeImpl {
-		public:
-			Tree(const char * const name) : TreeImpl{name} {
-				top.append(this);
-			}
-
-			Tree(const char * const name, Tree * parent) : TreeImpl{name} {
-				parent->children.append(this);
-			}
-		protected:
-			virtual ~Tree() = default;
-		};
-	}
-}
Index: src/Common/Stats/Base.hpp
===================================================================
--- src/Common/Stats/Base.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Base.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,86 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Heap.h --
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 03 14:53:53 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+
+namespace Stats {
+	namespace Base {
+		class TreeImpl;
+
+		struct TreeTop {
+			TreeImpl * head = nullptr;
+			TreeImpl * tail = nullptr;
+
+			inline void append(TreeImpl * node);
+		};
+
+		template<typename func_t>
+		void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy = false);
+
+		class TreeImpl {
+		public:
+			virtual void print(std::ostream &) = 0;
+
+			const char * const name;
+			TreeImpl(const char * const name) : name(name) {}
+
+		protected:
+			virtual ~TreeImpl() = default;
+
+			TreeImpl * next = nullptr;
+			TreeTop children;
+
+			friend struct TreeTop;
+
+			template<typename func_t>
+			friend void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy);
+		};
+
+		void TreeTop::append(TreeImpl * node) {
+			if(!head) { head = node; }
+			else      { tail->next = node;}
+			tail = node;
+		}
+
+		template<typename func_t>
+		inline void ForAll(TreeTop & range, std::size_t level, func_t func, bool destroy) {
+			auto it = range.head;
+			while(it) {
+				auto next = it->next;
+				func(it, level);
+				ForAll(it->children, level + 1, func);
+				if(destroy) delete it;
+				it = next;
+			}
+		}
+
+		template<TreeTop & top>
+		class Tree : public TreeImpl {
+		public:
+			Tree(const char * const name) : TreeImpl{name} {
+				top.append(this);
+			}
+
+			Tree(const char * const name, Tree * parent) : TreeImpl{name} {
+				parent->children.append(this);
+			}
+		protected:
+			virtual ~Tree() = default;
+		};
+	}
+}
Index: src/Common/Stats/Counter.cc
===================================================================
--- src/Common/Stats/Counter.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,58 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Counter.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Thu Feb 28 13::27:10 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#include "Counter.h"
-
-#include <algorithm>
-#include <cstring>
-#include <functional>
-#include <iomanip>
-
-namespace Stats {
-	namespace Counters {
-		void print() {
-			if(!top.head) return;
-			size_t nc = 0;
-			Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
-				nc = std::max(nc, (4 * level) + std::strlen(node->name));
-			});
-
-			const char * const title = "Counter Statistic";
-			size_t nct = nc + 14;
-			std::cerr << std::string(nct, '=') << std::endl;
-			std::cerr << std::string((nct - std::strlen(title)) / 2, ' ');
-			std::cerr << title << std::endl;
-			std::cerr << std::string(nct, '-') << std::endl;
-
-
-			Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
-				std::cerr << std::string(level * 4, ' ');
-				std::cerr << node->name;
-				std::cerr << std::string(nc - ((level * 4) + std::strlen(node->name)), ' ');
-				std::cerr << " | ";
-				std::cerr << std::setw(9);
-				node->print(std::cerr);
-				std::cerr << " |";
-				std::cerr << '\n';
-			}, true);
-
-			std::cerr << std::string(nct, '-') << std::endl;
-		}
-
-		Base::TreeTop top;
-
-		extern bool enabled;
-	}
-}
Index: src/Common/Stats/Counter.cpp
===================================================================
--- src/Common/Stats/Counter.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Counter.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,58 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Counter.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu Feb 28 13::27:10 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Counter.hpp"
+
+#include <algorithm>
+#include <cstring>
+#include <functional>
+#include <iomanip>
+
+namespace Stats {
+	namespace Counters {
+		void print() {
+			if(!top.head) return;
+			size_t nc = 0;
+			Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
+				nc = std::max(nc, (4 * level) + std::strlen(node->name));
+			});
+
+			const char * const title = "Counter Statistic";
+			size_t nct = nc + 14;
+			std::cerr << std::string(nct, '=') << std::endl;
+			std::cerr << std::string((nct - std::strlen(title)) / 2, ' ');
+			std::cerr << title << std::endl;
+			std::cerr << std::string(nct, '-') << std::endl;
+
+
+			Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
+				std::cerr << std::string(level * 4, ' ');
+				std::cerr << node->name;
+				std::cerr << std::string(nc - ((level * 4) + std::strlen(node->name)), ' ');
+				std::cerr << " | ";
+				std::cerr << std::setw(9);
+				node->print(std::cerr);
+				std::cerr << " |";
+				std::cerr << '\n';
+			}, true);
+
+			std::cerr << std::string(nct, '-') << std::endl;
+		}
+
+		Base::TreeTop top;
+
+		extern bool enabled;
+	}
+}
Index: src/Common/Stats/Counter.h
===================================================================
--- src/Common/Stats/Counter.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,146 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Counter.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Thu Feb 28 12::05:10 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-#include <cstdint>
-#include <iostream>
-
-#include "Common/Stats/Base.h"
-
-#if defined( NO_STATISTICS )
-	#define NO_COUNTER_STATISTICS
-#endif
-
-namespace Stats {
-	namespace Counters {
-# 		if defined(NO_COUNTERS_STATISTICS)
-
-			static inline void print() {}
-
-			class CounterGroup {
-			public:
-			};
-
-			class SimpleCounter {
-			public:
-				inline void operator++() {}
-				inline void operator++(int) {}
-				inline void operator+=(size_t) {}
-			};
-
-			template<typename T>
-			class AverageCounter {
-			public:
-				inline void push(T value) {}
-			};
-
-			template<typename T>
-			class MaxCounter {
-			public:
-				inline void push(T value) {}
-			};
-
-			template<typename counter_t>
-			counter_t * build(const char * const name) {
-				return nullptr;
-			}
-
-			template<typename counter_t>
-			counter_t * build(const char * const name, Base::Tree<top> * parent) {
-					return nullptr;
-			}
-#		else
-			extern bool enabled;
-
-			extern Base::TreeTop top;
-
-			class CounterGroup : public Base::Tree<top> {
-			public:
-				CounterGroup(const char * const name ) : Base::Tree<top>(name) {}
-				CounterGroup(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent) {}
-
-				virtual void print(std::ostream & os) override { os << ""; }
-			protected:
-				virtual ~CounterGroup() = default;
-			};
-
-			class SimpleCounter : public Base::Tree<top> {
-			public:
-				SimpleCounter(const char * const name ) : Base::Tree<top>(name) {}
-				SimpleCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent) {}
-
-				virtual void print(std::ostream & os) override { os << count; }
-
-				inline void operator++()             { if(!enabled) return; count++;        }
-				inline void operator++(int)          { if(!enabled) return; count++;        }
-				inline void operator+=(size_t value) { if(!enabled) return; count += value; }
-
-			protected:
-				virtual ~SimpleCounter() = default;
-
-			private:
-				size_t count = 0;
-			};
-
-			template<typename T>
-			class AverageCounter : public Base::Tree<top> {
-			public:
-				AverageCounter(const char * const name ) : Base::Tree<top>(name), sum{} {}
-				AverageCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent), sum{} {}
-
-				virtual void print(std::ostream & os) { os << sum / count; }
-
-				inline void push(T value) { if(!enabled) return; sum += value; count++; }
-
-			protected:
-				virtual ~AverageCounter() = default;
-
-			private:
-				T sum;
-				size_t count = 1;
-			};
-
-			template<typename T>
-			class MaxCounter : public Base::Tree<top> {
-			public:
-				MaxCounter(const char * const name ) : Base::Tree<top>(name), max{} {}
-				MaxCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent), max{} {}
-
-				virtual void print(std::ostream & os) { os << max; }
-
-				inline void push(T value) { if(!enabled) return; max = std::max(max, value); }
-
-			protected:
-				virtual ~MaxCounter() = default;
-
-			private:
-				T max;
-			};
-
-			template<typename counter_t>
-			counter_t * build(const char * const name) {
-				if(!enabled) return nullptr;
-				return new counter_t(name);
-			}
-
-			template<typename counter_t>
-			counter_t * build(const char * const name, Base::Tree<top> * parent) {
-				if(!enabled) return nullptr;
-				return new counter_t(name, parent);
-			}
-#		endif
-	}
-}
Index: src/Common/Stats/Counter.hpp
===================================================================
--- src/Common/Stats/Counter.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Counter.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,146 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Counter.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu Feb 28 12::05:10 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+
+#include "Common/Stats/Base.hpp"
+
+#if defined( NO_STATISTICS )
+	#define NO_COUNTER_STATISTICS
+#endif
+
+namespace Stats {
+	namespace Counters {
+# 		if defined(NO_COUNTERS_STATISTICS)
+
+			static inline void print() {}
+
+			class CounterGroup {
+			public:
+			};
+
+			class SimpleCounter {
+			public:
+				inline void operator++() {}
+				inline void operator++(int) {}
+				inline void operator+=(size_t) {}
+			};
+
+			template<typename T>
+			class AverageCounter {
+			public:
+				inline void push(T value) {}
+			};
+
+			template<typename T>
+			class MaxCounter {
+			public:
+				inline void push(T value) {}
+			};
+
+			template<typename counter_t>
+			counter_t * build(const char * const name) {
+				return nullptr;
+			}
+
+			template<typename counter_t>
+			counter_t * build(const char * const name, Base::Tree<top> * parent) {
+					return nullptr;
+			}
+#		else
+			extern bool enabled;
+
+			extern Base::TreeTop top;
+
+			class CounterGroup : public Base::Tree<top> {
+			public:
+				CounterGroup(const char * const name ) : Base::Tree<top>(name) {}
+				CounterGroup(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent) {}
+
+				virtual void print(std::ostream & os) override { os << ""; }
+			protected:
+				virtual ~CounterGroup() = default;
+			};
+
+			class SimpleCounter : public Base::Tree<top> {
+			public:
+				SimpleCounter(const char * const name ) : Base::Tree<top>(name) {}
+				SimpleCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent) {}
+
+				virtual void print(std::ostream & os) override { os << count; }
+
+				inline void operator++()             { if(!enabled) return; count++;        }
+				inline void operator++(int)          { if(!enabled) return; count++;        }
+				inline void operator+=(size_t value) { if(!enabled) return; count += value; }
+
+			protected:
+				virtual ~SimpleCounter() = default;
+
+			private:
+				size_t count = 0;
+			};
+
+			template<typename T>
+			class AverageCounter : public Base::Tree<top> {
+			public:
+				AverageCounter(const char * const name ) : Base::Tree<top>(name), sum{} {}
+				AverageCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent), sum{} {}
+
+				virtual void print(std::ostream & os) { os << sum / count; }
+
+				inline void push(T value) { if(!enabled) return; sum += value; count++; }
+
+			protected:
+				virtual ~AverageCounter() = default;
+
+			private:
+				T sum;
+				size_t count = 1;
+			};
+
+			template<typename T>
+			class MaxCounter : public Base::Tree<top> {
+			public:
+				MaxCounter(const char * const name ) : Base::Tree<top>(name), max{} {}
+				MaxCounter(const char * const name, Base::Tree<top> * parent) : Base::Tree<top>(name, parent), max{} {}
+
+				virtual void print(std::ostream & os) { os << max; }
+
+				inline void push(T value) { if(!enabled) return; max = std::max(max, value); }
+
+			protected:
+				virtual ~MaxCounter() = default;
+
+			private:
+				T max;
+			};
+
+			template<typename counter_t>
+			counter_t * build(const char * const name) {
+				if(!enabled) return nullptr;
+				return new counter_t(name);
+			}
+
+			template<typename counter_t>
+			counter_t * build(const char * const name, Base::Tree<top> * parent) {
+				if(!enabled) return nullptr;
+				return new counter_t(name, parent);
+			}
+#		endif
+	}
+}
Index: src/Common/Stats/Heap.cc
===================================================================
--- src/Common/Stats/Heap.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,272 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Heap.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Thu May  3 16:16:10 2018
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri May  4 17:27:31 2018
-// Update Count     : 28
-//
-
-#include <cassert>
-#include <cmath>
-#include <cstddef>
-#include <cstring>
-#include <iomanip>
-#include <iostream>
-
-#if defined(__has_feature)
-	#if __has_feature(address_sanitizer)
-		#define NO_HEAP_STATISTICS
-	# endif
-#endif
-
-#if defined( NO_STATISTICS ) || defined( TCMALLOC ) || defined(__SANITIZE_ADDRESS__)
-	#if !defined(NO_HEAP_STATISTICS)
-		#define NO_HEAP_STATISTICS
-	#endif
-#endif
-
-namespace Stats {
-	namespace Heap {
-#if defined( NO_HEAP_STATISTICS )
-		void newPass( const char * const ) {}
-
-		void print() {}
-#else
-		extern bool enabled;
-
-		struct StatBlock {
-			const char * name  = nullptr;	///< Name of this pass
-			size_t mallocs     = 0;			///< Allocations in this pass
-			size_t frees       = 0;			///< Frees in this pass
-			size_t n_allocs    = 0;			///< Current number of live allocations
-			size_t peak_allocs = 0;			///< Peak number of live allocations this pass
-		};
-
-		StatBlock    passes[100] = {{ "Pre-Parse", 0, 0, 0, 0 }};
-		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 ) {
-			passes[passes_cnt].name    = name;
-			passes[passes_cnt].mallocs = 0;
-			passes[passes_cnt].frees   = 0;
-			passes[passes_cnt].n_allocs
-				= passes[passes_cnt].peak_allocs
-				= passes[passes_cnt-1].n_allocs;
-			passes_cnt++;
-
-			assertf(passes_cnt < passes_size, "Too many passes for Stats::Heap, increase the size of the array in Heap.cc");
-		}
-
-		void print(size_t value, size_t total) {
-			std::cerr << std::setw(12) << value;
-			std::cerr << "(" << std::setw(3);
-			std::cerr << (value == 0 ? 0 : value * 100 / total);
-			std::cerr << "%) | ";
-		}
-
-		void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees, size_t overall_peak) {
-			std::cerr << std::setw(nc) << stat.name;
-			std::cerr << " | ";
-
-			print(stat.mallocs,     total_mallocs);
-			print(stat.frees,       total_frees  );
-			print(stat.peak_allocs, overall_peak );
-			std::cerr << "\n";
-		}
-
-		void print(char c, size_t nc) {
-			for(size_t i = 0; i < nc; i++) {
-				std::cerr << c;
-			}
-			std::cerr << '\n';
-		}
-
-		void print() {
-			if(!enabled) return;
-
-			size_t nc = 0;
-			size_t total_mallocs = 0;
-			size_t total_frees   = 0;
-			size_t overall_peak  = 0;
-			for(size_t i = 0; i < passes_cnt; i++) {
-				nc = std::max(nc, std::strlen(passes[i].name));
-				total_mallocs += passes[i].mallocs;
-				total_frees   += passes[i].frees;
-				overall_peak = std::max(overall_peak, passes[i].peak_allocs);
-			}
-			size_t nct = nc + 65;
-
-			const char * const title = "Heap Usage Statistic";
-			print('=', nct);
-			for(size_t i = 0; i < (nct - std::strlen(title)) / 2; i++) std::cerr << ' ';
-			std::cerr << title << std::endl;
-			print('-', nct);
-			std::cerr << std::setw(nc) << "Pass";
-			std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
-
-			print('-', nct);
-			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);
-			print({"Sum", total_mallocs, total_frees, 0, overall_peak},
-				nc, total_mallocs, total_frees, overall_peak);
-
-		}
-
-#include <stdarg.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <signal.h>
-		extern "C" {
-#include <dlfcn.h>
-#include <execinfo.h>
-		}
-
-	//=============================================================================================
-	// Interposing helpers
-	//=============================================================================================
-
-		typedef void (* generic_fptr_t)(void);
-		generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
-			const char * error;
-
-			static void * library;
-			if ( ! library ) {
-#				if defined( RTLD_NEXT )
-					library = RTLD_NEXT;
-#				else
-					// missing RTLD_NEXT => must hard-code library name, assuming libstdc++
-					library = dlopen( "libc.so.6", RTLD_LAZY );
-					error = dlerror();
-					if ( error ) {
-						std::cerr << "interpose_symbol : failed to open libc, " << error << std::endl;
-						abort();
-					}
-#				endif // RTLD_NEXT
-			} // if
-
-			generic_fptr_t fptr;
-
-#			if defined( _GNU_SOURCE )
-				if ( version ) {
-					fptr = (generic_fptr_t)dlvsym( library, symbol, version );
-				} else {
-					fptr = (generic_fptr_t)dlsym( library, symbol );
-				}
-#			else
-				fptr = (generic_fptr_t)dlsym( library, symbol );
-#			endif // _GNU_SOURCE
-
-			error = dlerror();
-			if ( error ) {
-				std::cerr << "interpose_symbol : internal error, " << error << std::endl;
-				abort();
-			}
-
-			return fptr;
-		}
-
-		extern "C" {
-			void * malloc( size_t size ) __attribute__((malloc));
-			void * malloc( size_t size ) {
-				static auto __malloc = reinterpret_cast<void * (*)(size_t)>(interpose_symbol( "malloc", nullptr ));
-				if( enabled && passes_cnt > 0 ) {
-					passes[passes_cnt - 1].mallocs++;
-					passes[passes_cnt - 1].n_allocs++;
-					passes[passes_cnt - 1].peak_allocs
-						= 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 );
-			}
-
-			void free( void * ptr ) {
-				static auto __free = reinterpret_cast<void   (*)(void *)>(interpose_symbol( "free", nullptr ));
-				if( enabled && passes_cnt > 0 ) {
-					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 );
-			}
-
-			void * calloc( size_t nelem, size_t size ) {
-				static auto __calloc = reinterpret_cast<void * (*)(size_t, size_t)>(interpose_symbol( "calloc", nullptr ));
-				if( enabled && passes_cnt > 0 ) {
-					passes[passes_cnt - 1].mallocs++;
-					passes[passes_cnt - 1].n_allocs++;
-					passes[passes_cnt - 1].peak_allocs
-						= 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 );
-			}
-
-			void * realloc( void * ptr, size_t size ) {
-				static auto __realloc = reinterpret_cast<void * (*)(void *, size_t)>(interpose_symbol( "realloc", nullptr ));
-				void * s = __realloc( ptr, size );
-				if ( enabled && s != ptr && passes_cnt > 0 ) {			// did realloc get new storage ?
-					passes[passes_cnt - 1].mallocs++;
-					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;
-			}
-		}
-#endif
-	}
-}
Index: src/Common/Stats/Heap.cpp
===================================================================
--- src/Common/Stats/Heap.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Heap.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,272 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Heap.cc --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu May  3 16:16:10 2018
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri May  4 17:27:31 2018
+// Update Count     : 28
+//
+
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <iomanip>
+#include <iostream>
+
+#if defined(__has_feature)
+	#if __has_feature(address_sanitizer)
+		#define NO_HEAP_STATISTICS
+	# endif
+#endif
+
+#if defined( NO_STATISTICS ) || defined( TCMALLOC ) || defined(__SANITIZE_ADDRESS__)
+	#if !defined(NO_HEAP_STATISTICS)
+		#define NO_HEAP_STATISTICS
+	#endif
+#endif
+
+namespace Stats {
+	namespace Heap {
+#if defined( NO_HEAP_STATISTICS )
+		void newPass( const char * const ) {}
+
+		void print() {}
+#else
+		extern bool enabled;
+
+		struct StatBlock {
+			const char * name  = nullptr;	///< Name of this pass
+			size_t mallocs     = 0;			///< Allocations in this pass
+			size_t frees       = 0;			///< Frees in this pass
+			size_t n_allocs    = 0;			///< Current number of live allocations
+			size_t peak_allocs = 0;			///< Peak number of live allocations this pass
+		};
+
+		StatBlock    passes[100] = {{ "Pre-Parse", 0, 0, 0, 0 }};
+		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 ) {
+			passes[passes_cnt].name    = name;
+			passes[passes_cnt].mallocs = 0;
+			passes[passes_cnt].frees   = 0;
+			passes[passes_cnt].n_allocs
+				= passes[passes_cnt].peak_allocs
+				= passes[passes_cnt-1].n_allocs;
+			passes_cnt++;
+
+			assertf(passes_cnt < passes_size, "Too many passes for Stats::Heap, increase the size of the array in Heap.cc");
+		}
+
+		void print(size_t value, size_t total) {
+			std::cerr << std::setw(12) << value;
+			std::cerr << "(" << std::setw(3);
+			std::cerr << (value == 0 ? 0 : value * 100 / total);
+			std::cerr << "%) | ";
+		}
+
+		void print(const StatBlock& stat, size_t nc, size_t total_mallocs, size_t total_frees, size_t overall_peak) {
+			std::cerr << std::setw(nc) << stat.name;
+			std::cerr << " | ";
+
+			print(stat.mallocs,     total_mallocs);
+			print(stat.frees,       total_frees  );
+			print(stat.peak_allocs, overall_peak );
+			std::cerr << "\n";
+		}
+
+		void print(char c, size_t nc) {
+			for(size_t i = 0; i < nc; i++) {
+				std::cerr << c;
+			}
+			std::cerr << '\n';
+		}
+
+		void print() {
+			if(!enabled) return;
+
+			size_t nc = 0;
+			size_t total_mallocs = 0;
+			size_t total_frees   = 0;
+			size_t overall_peak  = 0;
+			for(size_t i = 0; i < passes_cnt; i++) {
+				nc = std::max(nc, std::strlen(passes[i].name));
+				total_mallocs += passes[i].mallocs;
+				total_frees   += passes[i].frees;
+				overall_peak = std::max(overall_peak, passes[i].peak_allocs);
+			}
+			size_t nct = nc + 65;
+
+			const char * const title = "Heap Usage Statistic";
+			print('=', nct);
+			for(size_t i = 0; i < (nct - std::strlen(title)) / 2; i++) std::cerr << ' ';
+			std::cerr << title << std::endl;
+			print('-', nct);
+			std::cerr << std::setw(nc) << "Pass";
+			std::cerr << " |       Malloc Count |         Free Count |        Peak Allocs |" << std::endl;
+
+			print('-', nct);
+			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);
+			print({"Sum", total_mallocs, total_frees, 0, overall_peak},
+				nc, total_mallocs, total_frees, overall_peak);
+
+		}
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+		extern "C" {
+#include <dlfcn.h>
+#include <execinfo.h>
+		}
+
+	//=============================================================================================
+	// Interposing helpers
+	//=============================================================================================
+
+		typedef void (* generic_fptr_t)(void);
+		generic_fptr_t interpose_symbol( const char * symbol, const char * version ) {
+			const char * error;
+
+			static void * library;
+			if ( ! library ) {
+#				if defined( RTLD_NEXT )
+					library = RTLD_NEXT;
+#				else
+					// missing RTLD_NEXT => must hard-code library name, assuming libstdc++
+					library = dlopen( "libc.so.6", RTLD_LAZY );
+					error = dlerror();
+					if ( error ) {
+						std::cerr << "interpose_symbol : failed to open libc, " << error << std::endl;
+						abort();
+					}
+#				endif // RTLD_NEXT
+			} // if
+
+			generic_fptr_t fptr;
+
+#			if defined( _GNU_SOURCE )
+				if ( version ) {
+					fptr = (generic_fptr_t)dlvsym( library, symbol, version );
+				} else {
+					fptr = (generic_fptr_t)dlsym( library, symbol );
+				}
+#			else
+				fptr = (generic_fptr_t)dlsym( library, symbol );
+#			endif // _GNU_SOURCE
+
+			error = dlerror();
+			if ( error ) {
+				std::cerr << "interpose_symbol : internal error, " << error << std::endl;
+				abort();
+			}
+
+			return fptr;
+		}
+
+		extern "C" {
+			void * malloc( size_t size ) __attribute__((malloc));
+			void * malloc( size_t size ) {
+				static auto __malloc = reinterpret_cast<void * (*)(size_t)>(interpose_symbol( "malloc", nullptr ));
+				if( enabled && passes_cnt > 0 ) {
+					passes[passes_cnt - 1].mallocs++;
+					passes[passes_cnt - 1].n_allocs++;
+					passes[passes_cnt - 1].peak_allocs
+						= 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 );
+			}
+
+			void free( void * ptr ) {
+				static auto __free = reinterpret_cast<void   (*)(void *)>(interpose_symbol( "free", nullptr ));
+				if( enabled && passes_cnt > 0 ) {
+					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 );
+			}
+
+			void * calloc( size_t nelem, size_t size ) {
+				static auto __calloc = reinterpret_cast<void * (*)(size_t, size_t)>(interpose_symbol( "calloc", nullptr ));
+				if( enabled && passes_cnt > 0 ) {
+					passes[passes_cnt - 1].mallocs++;
+					passes[passes_cnt - 1].n_allocs++;
+					passes[passes_cnt - 1].peak_allocs
+						= 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 );
+			}
+
+			void * realloc( void * ptr, size_t size ) {
+				static auto __realloc = reinterpret_cast<void * (*)(void *, size_t)>(interpose_symbol( "realloc", nullptr ));
+				void * s = __realloc( ptr, size );
+				if ( enabled && s != ptr && passes_cnt > 0 ) {			// did realloc get new storage ?
+					passes[passes_cnt - 1].mallocs++;
+					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;
+			}
+		}
+#endif
+	}
+}
Index: src/Common/Stats/Heap.h
===================================================================
--- src/Common/Stats/Heap.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,27 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Heap.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Thu May  3 16:16:10 2018
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri May  4 14:34:08 2018
-// Update Count     : 3
-//
-
-#pragma once
-
-namespace Stats {
-	namespace Heap {
-		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/Common/Stats/Heap.hpp
===================================================================
--- src/Common/Stats/Heap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Heap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,27 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2018 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Heap.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Thu May  3 16:16:10 2018
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri May  4 14:34:08 2018
+// Update Count     : 3
+//
+
+#pragma once
+
+namespace Stats {
+	namespace Heap {
+		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/Common/Stats/ResolveTime.cc
===================================================================
--- src/Common/Stats/ResolveTime.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,67 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ResolveTime.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Wed Sep 16 15:45:51 2020
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#include "ResolveTime.h"
-
-#include <fstream>
-#include <iomanip>
-
-#include "AST/Fwd.hpp"
-#include "AST/Expr.hpp"
-#include "AST/Print.hpp"
-#include "AST/Type.hpp"
-
-namespace Stats {
-	namespace ResolveTime {
-		static inline long long rdtscl(void) {
-			#if defined( __i386 ) || defined( __x86_64 )
-				unsigned int lo, hi;
-				__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
-				return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
-			#elif defined( __aarch64__ )
-				int64_t value;
-				asm volatile("mrs %0, cntvct_el0" : "=r"(value));
-				return value;
-			#else
-				#error unknown hardware architecture
-			#endif
-		}
-
-		extern bool enabled;
-		bool started = false;
-		long long before;
-		std::ostream & out = std::cout;
-
-		void start( const ast::Expr * expr ) {
-			if(enabled) {
-				assert(!started);
-				started = true;
-
-				out << expr->location << " : ";
-
-				before = rdtscl();
-			}
-		}
-		void stop() {
-			if(enabled) {
-				assert(started);
-				auto after = rdtscl();
-				out << (after - before) << std::endl;
-
-				started = false;
-			}
-		}
-	};
-};
Index: src/Common/Stats/ResolveTime.cpp
===================================================================
--- src/Common/Stats/ResolveTime.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/ResolveTime.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,67 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolveTime.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Wed Sep 16 15:45:51 2020
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "ResolveTime.hpp"
+
+#include <fstream>
+#include <iomanip>
+
+#include "AST/Fwd.hpp"
+#include "AST/Expr.hpp"
+#include "AST/Print.hpp"
+#include "AST/Type.hpp"
+
+namespace Stats {
+	namespace ResolveTime {
+		static inline long long rdtscl(void) {
+			#if defined( __i386 ) || defined( __x86_64 )
+				unsigned int lo, hi;
+				__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+				return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
+			#elif defined( __aarch64__ )
+				int64_t value;
+				asm volatile("mrs %0, cntvct_el0" : "=r"(value));
+				return value;
+			#else
+				#error unknown hardware architecture
+			#endif
+		}
+
+		extern bool enabled;
+		bool started = false;
+		long long before;
+		std::ostream & out = std::cout;
+
+		void start( const ast::Expr * expr ) {
+			if(enabled) {
+				assert(!started);
+				started = true;
+
+				out << expr->location << " : ";
+
+				before = rdtscl();
+			}
+		}
+		void stop() {
+			if(enabled) {
+				assert(started);
+				auto after = rdtscl();
+				out << (after - before) << std::endl;
+
+				started = false;
+			}
+		}
+	};
+};
Index: src/Common/Stats/ResolveTime.h
===================================================================
--- src/Common/Stats/ResolveTime.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,38 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// ResolveTime.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Wed Sep 16 15:45:51 2020
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-#include "Common/Stats/Base.h"
-
-#if defined( NO_STATISTICS )
-	#define NO_RESOLVE_TIME_STATISTICS
-#endif
-
-namespace ast {
-	class Expr;
-}
-
-namespace Stats {
-	namespace ResolveTime {
-		#if defined(NO_RESOLVE_TIME_STATISTICS)
-			void start( const ast::Expr * ) {}
-			void stop() {}
-		#else
-			void start( const ast::Expr * );
-			void stop();
-		#endif
-	};
-};
Index: src/Common/Stats/ResolveTime.hpp
===================================================================
--- src/Common/Stats/ResolveTime.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/ResolveTime.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,38 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// ResolveTime.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Wed Sep 16 15:45:51 2020
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include "Common/Stats/Base.hpp"
+
+#if defined( NO_STATISTICS )
+	#define NO_RESOLVE_TIME_STATISTICS
+#endif
+
+namespace ast {
+	class Expr;
+}
+
+namespace Stats {
+	namespace ResolveTime {
+		#if defined(NO_RESOLVE_TIME_STATISTICS)
+			void start( const ast::Expr * ) {}
+			void stop() {}
+		#else
+			void start( const ast::Expr * );
+			void stop();
+		#endif
+	};
+};
Index: src/Common/Stats/Stats.cc
===================================================================
--- src/Common/Stats/Stats.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,91 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Stats.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Fri Mar 01 15:45:08 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#include <iostream>
-#include <sstream>
-#include <string>
-
-
-namespace Stats {
-	namespace Counters {
-		bool enabled = false;
-		void print();
-	}
-
-	namespace Heap {
-		bool enabled = false;
-		void print();
-	}
-
-	namespace Time {
-		bool enabled = false;
-		void print();
-	}
-
-	namespace ResolveTime {
-		bool enabled = false;
-	}
-
-	struct {
-		const char * const opt;
-		bool & enabled;
-	}
-	statistics[] = {
-		{ "counters", Counters::enabled },
-		{ "heap"    , Heap::enabled },
-		{ "time"    , Time::enabled },
-		{ "resolve" , ResolveTime::enabled },
-	};
-
-	void set_param(std::string & param) {
-		if(param == "all") {
-			for(auto & stat : statistics) {
-				stat.enabled = true;
-			}
-			return;
-		}
-
-		if(param == "none") {
-			for(auto & stat : statistics) {
-				stat.enabled = false;
-			}
-			return;
-		}
-
-		for(auto & stat : statistics) {
-			if(stat.opt == param) {
-				stat.enabled = true;
-				return;
-			}
-		}
-
-		std::cerr << "Ignoring unknown statistic " << param << std::endl;
-	}
-
-	void parse_params(const char * const params) {
-		std::stringstream ss(params);
-		while(ss.good()) {
-			std::string substr;
-			getline( ss, substr, ',' );
-			set_param(substr);
-		}
-	}
-
-	void print() {
-		Counters::print();
-		Heap::print();
-		Time::print();
-	}
-}
Index: src/Common/Stats/Stats.cpp
===================================================================
--- src/Common/Stats/Stats.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Stats.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,91 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Stats.cc --
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 01 15:45:08 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include <iostream>
+#include <sstream>
+#include <string>
+
+
+namespace Stats {
+	namespace Counters {
+		bool enabled = false;
+		void print();
+	}
+
+	namespace Heap {
+		bool enabled = false;
+		void print();
+	}
+
+	namespace Time {
+		bool enabled = false;
+		void print();
+	}
+
+	namespace ResolveTime {
+		bool enabled = false;
+	}
+
+	struct {
+		const char * const opt;
+		bool & enabled;
+	}
+	statistics[] = {
+		{ "counters", Counters::enabled },
+		{ "heap"    , Heap::enabled },
+		{ "time"    , Time::enabled },
+		{ "resolve" , ResolveTime::enabled },
+	};
+
+	void set_param(std::string & param) {
+		if(param == "all") {
+			for(auto & stat : statistics) {
+				stat.enabled = true;
+			}
+			return;
+		}
+
+		if(param == "none") {
+			for(auto & stat : statistics) {
+				stat.enabled = false;
+			}
+			return;
+		}
+
+		for(auto & stat : statistics) {
+			if(stat.opt == param) {
+				stat.enabled = true;
+				return;
+			}
+		}
+
+		std::cerr << "Ignoring unknown statistic " << param << std::endl;
+	}
+
+	void parse_params(const char * const params) {
+		std::stringstream ss(params);
+		while(ss.good()) {
+			std::string substr;
+			getline( ss, substr, ',' );
+			set_param(substr);
+		}
+	}
+
+	void print() {
+		Counters::print();
+		Heap::print();
+		Time::print();
+	}
+}
Index: src/Common/Stats/Time.cc
===================================================================
--- src/Common/Stats/Time.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,199 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Time.cc --
-//
-// Author           : Thierry Delisle
-// Created On       : Mon Mar 04 15:16:07 2019
-// Last Modified By :
-// Last Modified On :
-// Update Count     :
-//
-
-#include "Time.h"
-
-#include <cassert>
-#include <chrono>
-#include <cstdint>
-#include <cstring>
-#include <iostream>
-#include <iomanip>
-#include <stack>
-
-namespace Stats {
-	namespace Time {
-#		if !defined(NO_TIME_STATISTICS)
-			extern bool enabled;
-
-			Base::TreeTop top;
-
-			typedef  std::chrono::time_point<std::chrono::high_resolution_clock> point_t;
-			std::chrono::duration<double> total;
-
-			point_t global_begin;
-
-			int prevl = 0;
-			int currl = 0;
-
-			template<typename T>
-			static inline std::ostream & operator<<(std::ostream & os, const std::chrono::duration<T> & dd) {
-				auto d = std::chrono::duration_cast<std::chrono::milliseconds>(dd);
-				auto minutes = std::chrono::duration_cast<std::chrono::minutes>(d);
-				auto seconds = std::chrono::duration_cast<std::chrono::seconds>(d % std::chrono::minutes(1));
-				auto millis  = std::chrono::duration_cast<std::chrono::milliseconds>(d % std::chrono::seconds(1));
-
-				bool zmin = minutes == minutes.zero();
-				bool zsec = seconds == seconds.zero();
-				bool zmil = millis  == millis .zero();
-
-				if(!zmin) {
-					os << std::setw(4) << minutes.count() << "m";
-				} else {
-					os << std::string(5, ' ');
-				}
-
-				if(!zmin || !zsec) {
-					if(!zmin) os << std::setfill('0');
-					os << std::setw(2) << seconds.count() << "s";
-				} else {
-					os << std::string(3, ' ');
-				}
-				os << std::setfill(' ');
-
-				if(!zmin || !zsec || !zmil) {
-					if(!zmin || !zsec) os << std::setfill('0');
-					os << std::setw(3) << millis .count();
-				} else {
-					os << std::string(4, ' ');
-				}
-				os << std::setfill(' ');
-
-				return os;
-			}
-
-			class TimerNode : public Base::Tree<top> {
-			public:
-				TimerNode(const char * const name )
-					: Base::Tree<top>(name)
-				{}
-
-				TimerNode(const char * const name, Base::Tree<top> * parent)
-					: Base::Tree<top>(name, parent)
-
-				{}
-
-				virtual void print(std::ostream & os) override {
-					if(currl > prevl) {
-						parents.push(last);
-					}
-					for(auto lvl = prevl - currl; lvl > 0; lvl--) {
-						parents.pop();
-					}
-					last = end - begin;
-
-					assert(finished);
-					std::chrono::duration<double> diff = end - begin;
-					os << diff << " | ";
-					if(parents.empty()) {
-						os << "     N/A | ";
-					} else {
-						os << std::setw(7) << std::setprecision(0);
-						os << size_t(100.0 * diff.count() / parents.top().count()) << "% | ";
-					}
-					os << std::setw(5) << std::setprecision(0);
-					os << size_t(100.0 * diff.count() / total.count()) << "% ";
-				}
-
-				void start() {
-					begin = std::chrono::high_resolution_clock::now();
-				}
-
-				void finish() {
-					end = std::chrono::high_resolution_clock::now();
-					finished = true;
-				}
-
-			protected:
-				virtual ~TimerNode() = default;
-
-			private:
-				bool finished = false;
-
-				point_t begin;
-				point_t end;
-
-				static std::chrono::duration<double> last;
-				static std::stack<std::chrono::duration<double>> parents;
-			};
-
-			std::stack<TimerNode *> nodes;
-
-			std::chrono::duration<double> TimerNode::last;
-			std::stack<std::chrono::duration<double>> TimerNode::parents;
-
-			void StartGlobal() {
-				global_begin = std::chrono::high_resolution_clock::now();
-			}
-
-			void StartBlock(const char * const name) {
-				if(!enabled) return;
-				auto node = nodes.empty()
-					? new TimerNode(name)
-					: new TimerNode(name, nodes.top());
-
-				nodes.push(node);
-				node->start();
-			}
-
-			void StopBlock() {
-				if(!enabled) return;
-				nodes.top()->finish();
-				nodes.pop();
-			}
-
-			void print() {
-				if(!top.head) return;
-				auto global_end = std::chrono::high_resolution_clock::now();
-				total = global_end - global_begin;
-
-				size_t nc = 0;
-				Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
-					nc = std::max(nc, (4 * level) + std::strlen(node->name));
-				});
-
-				size_t nct = nc + 37;
-				std::cerr << std::string(nct, '=') << std::endl;
-				const char * const title = "Timing Results";
-				std::cerr << std::string((nct - std::strlen(title)) / 2, ' ');
-				std::cerr << title << std::endl;
-				std::cerr << std::string(nct, '-') << std::endl;
-				std::cerr << "Location";
-				std::cerr << std::string(nc - (std::strlen("Location")), ' ');
-				std::cerr << " | ";
-				std::cerr << "       Time | ";
-				std::cerr << "% parent | ";
-				std::cerr << "% total |" << std::endl;
-				std::cerr << std::string(nct, '-') << std::endl;
-
-				Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
-					currl = level;
-					std::cerr << std::string(level * 4, ' ');
-					std::cerr << node->name;
-					std::cerr << std::string(nc - ((level * 4) + std::strlen(node->name)), ' ');
-					std::cerr << " | ";
-					node->print(std::cerr);
-					std::cerr << " |";
-					std::cerr << '\n';
-					prevl = level;
-				}, true);
-
-				std::cerr << std::string(nct, '-') << std::endl;
-				std::cerr << "Total " << total << std::endl;
-				std::cerr << std::string(nct, '-') << std::endl;
-			}
-#		endif
-	}
-}
Index: src/Common/Stats/Time.cpp
===================================================================
--- src/Common/Stats/Time.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Time.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,199 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Time.cpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Mon Mar 04 15:16:07 2019
+// Last Modified By :
+// Last Modified On :
+// Update Count     :
+//
+
+#include "Time.hpp"
+
+#include <cassert>
+#include <chrono>
+#include <cstdint>
+#include <cstring>
+#include <iostream>
+#include <iomanip>
+#include <stack>
+
+namespace Stats {
+	namespace Time {
+#		if !defined(NO_TIME_STATISTICS)
+			extern bool enabled;
+
+			Base::TreeTop top;
+
+			typedef  std::chrono::time_point<std::chrono::high_resolution_clock> point_t;
+			std::chrono::duration<double> total;
+
+			point_t global_begin;
+
+			int prevl = 0;
+			int currl = 0;
+
+			template<typename T>
+			static inline std::ostream & operator<<(std::ostream & os, const std::chrono::duration<T> & dd) {
+				auto d = std::chrono::duration_cast<std::chrono::milliseconds>(dd);
+				auto minutes = std::chrono::duration_cast<std::chrono::minutes>(d);
+				auto seconds = std::chrono::duration_cast<std::chrono::seconds>(d % std::chrono::minutes(1));
+				auto millis  = std::chrono::duration_cast<std::chrono::milliseconds>(d % std::chrono::seconds(1));
+
+				bool zmin = minutes == minutes.zero();
+				bool zsec = seconds == seconds.zero();
+				bool zmil = millis  == millis .zero();
+
+				if(!zmin) {
+					os << std::setw(4) << minutes.count() << "m";
+				} else {
+					os << std::string(5, ' ');
+				}
+
+				if(!zmin || !zsec) {
+					if(!zmin) os << std::setfill('0');
+					os << std::setw(2) << seconds.count() << "s";
+				} else {
+					os << std::string(3, ' ');
+				}
+				os << std::setfill(' ');
+
+				if(!zmin || !zsec || !zmil) {
+					if(!zmin || !zsec) os << std::setfill('0');
+					os << std::setw(3) << millis .count();
+				} else {
+					os << std::string(4, ' ');
+				}
+				os << std::setfill(' ');
+
+				return os;
+			}
+
+			class TimerNode : public Base::Tree<top> {
+			public:
+				TimerNode(const char * const name )
+					: Base::Tree<top>(name)
+				{}
+
+				TimerNode(const char * const name, Base::Tree<top> * parent)
+					: Base::Tree<top>(name, parent)
+
+				{}
+
+				virtual void print(std::ostream & os) override {
+					if(currl > prevl) {
+						parents.push(last);
+					}
+					for(auto lvl = prevl - currl; lvl > 0; lvl--) {
+						parents.pop();
+					}
+					last = end - begin;
+
+					assert(finished);
+					std::chrono::duration<double> diff = end - begin;
+					os << diff << " | ";
+					if(parents.empty()) {
+						os << "     N/A | ";
+					} else {
+						os << std::setw(7) << std::setprecision(0);
+						os << size_t(100.0 * diff.count() / parents.top().count()) << "% | ";
+					}
+					os << std::setw(5) << std::setprecision(0);
+					os << size_t(100.0 * diff.count() / total.count()) << "% ";
+				}
+
+				void start() {
+					begin = std::chrono::high_resolution_clock::now();
+				}
+
+				void finish() {
+					end = std::chrono::high_resolution_clock::now();
+					finished = true;
+				}
+
+			protected:
+				virtual ~TimerNode() = default;
+
+			private:
+				bool finished = false;
+
+				point_t begin;
+				point_t end;
+
+				static std::chrono::duration<double> last;
+				static std::stack<std::chrono::duration<double>> parents;
+			};
+
+			std::stack<TimerNode *> nodes;
+
+			std::chrono::duration<double> TimerNode::last;
+			std::stack<std::chrono::duration<double>> TimerNode::parents;
+
+			void StartGlobal() {
+				global_begin = std::chrono::high_resolution_clock::now();
+			}
+
+			void StartBlock(const char * const name) {
+				if(!enabled) return;
+				auto node = nodes.empty()
+					? new TimerNode(name)
+					: new TimerNode(name, nodes.top());
+
+				nodes.push(node);
+				node->start();
+			}
+
+			void StopBlock() {
+				if(!enabled) return;
+				nodes.top()->finish();
+				nodes.pop();
+			}
+
+			void print() {
+				if(!top.head) return;
+				auto global_end = std::chrono::high_resolution_clock::now();
+				total = global_end - global_begin;
+
+				size_t nc = 0;
+				Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
+					nc = std::max(nc, (4 * level) + std::strlen(node->name));
+				});
+
+				size_t nct = nc + 37;
+				std::cerr << std::string(nct, '=') << std::endl;
+				const char * const title = "Timing Results";
+				std::cerr << std::string((nct - std::strlen(title)) / 2, ' ');
+				std::cerr << title << std::endl;
+				std::cerr << std::string(nct, '-') << std::endl;
+				std::cerr << "Location";
+				std::cerr << std::string(nc - (std::strlen("Location")), ' ');
+				std::cerr << " | ";
+				std::cerr << "       Time | ";
+				std::cerr << "% parent | ";
+				std::cerr << "% total |" << std::endl;
+				std::cerr << std::string(nct, '-') << std::endl;
+
+				Base::ForAll(top, 0, [&](Base::TreeImpl * node, size_t level) {
+					currl = level;
+					std::cerr << std::string(level * 4, ' ');
+					std::cerr << node->name;
+					std::cerr << std::string(nc - ((level * 4) + std::strlen(node->name)), ' ');
+					std::cerr << " | ";
+					node->print(std::cerr);
+					std::cerr << " |";
+					std::cerr << '\n';
+					prevl = level;
+				}, true);
+
+				std::cerr << std::string(nct, '-') << std::endl;
+				std::cerr << "Total " << total << std::endl;
+				std::cerr << std::string(nct, '-') << std::endl;
+			}
+#		endif
+	}
+}
Index: src/Common/Stats/Time.h
===================================================================
--- src/Common/Stats/Time.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,76 +1,0 @@
-//
-// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
-//
-// The contents of this file are covered under the licence agreement in the
-// file "LICENCE" distributed with Cforall.
-//
-// Time.h --
-//
-// Author           : Thierry Delisle
-// Created On       : Fri Mar 01 15:14:11 2019
-// Last Modified By : Andrew Beach
-// Last Modified On :
-// Update Count     :
-//
-
-#pragma once
-
-#include "Common/Stats/Base.h"
-
-#if defined( NO_STATISTICS )
-	#define NO_TIME_STATISTICS
-#endif
-
-namespace Stats {
-	namespace Time {
-#		if defined(NO_TIME_STATISTICS)
-			inline void StartGlobal() {}
-
-			inline void StartBlock(const char * const) {}
-			inline void StopBlock() {}
-
-			inline void print() {}
-
-			struct BlockGuard {
-				BlockGuard(const char * const) {}
-				~BlockGuard() {}
-			};
-
-			template<typename func_t>
-			inline void TimeBlock(const char *, func_t f) {
-				f();
-			}
-
-			template<typename ret_t = void, typename func_t, typename... arg_t>
-			inline ret_t TimeCall(
-					const char *, func_t func, arg_t&&... arg) {
-				return func(std::forward<arg_t>(arg)...);
-			}
-#		else
-			void StartGlobal();
-
-			void StartBlock(const char * const name);
-			void StopBlock();
-
-			void print();
-
-			struct BlockGuard {
-				BlockGuard(const char * const name ) { StartBlock(name); }
-				~BlockGuard() { StopBlock(); }
-			};
-
-			template<typename func_t>
-			inline void TimeBlock(const char * name, func_t func) {
-				BlockGuard guard(name);
-				func();
-			}
-
-			template<typename ret_t = void, typename func_t, typename... arg_t>
-			inline ret_t TimeCall(
-					const char * name, func_t func, arg_t&&... arg) {
-				BlockGuard guard(name);
-				return func(std::forward<arg_t>(arg)...);
-			}
-#		endif
-	}
-}
Index: src/Common/Stats/Time.hpp
===================================================================
--- src/Common/Stats/Time.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Stats/Time.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,76 @@
+//
+// Cforall Version 1.0.0 Copyright (C) 2019 University of Waterloo
+//
+// The contents of this file are covered under the licence agreement in the
+// file "LICENCE" distributed with Cforall.
+//
+// Time.hpp --
+//
+// Author           : Thierry Delisle
+// Created On       : Fri Mar 01 15:14:11 2019
+// Last Modified By : Andrew Beach
+// Last Modified On :
+// Update Count     :
+//
+
+#pragma once
+
+#include "Common/Stats/Base.hpp"
+
+#if defined( NO_STATISTICS )
+	#define NO_TIME_STATISTICS
+#endif
+
+namespace Stats {
+	namespace Time {
+#		if defined(NO_TIME_STATISTICS)
+			inline void StartGlobal() {}
+
+			inline void StartBlock(const char * const) {}
+			inline void StopBlock() {}
+
+			inline void print() {}
+
+			struct BlockGuard {
+				BlockGuard(const char * const) {}
+				~BlockGuard() {}
+			};
+
+			template<typename func_t>
+			inline void TimeBlock(const char *, func_t f) {
+				f();
+			}
+
+			template<typename ret_t = void, typename func_t, typename... arg_t>
+			inline ret_t TimeCall(
+					const char *, func_t func, arg_t&&... arg) {
+				return func(std::forward<arg_t>(arg)...);
+			}
+#		else
+			void StartGlobal();
+
+			void StartBlock(const char * const name);
+			void StopBlock();
+
+			void print();
+
+			struct BlockGuard {
+				BlockGuard(const char * const name ) { StartBlock(name); }
+				~BlockGuard() { StopBlock(); }
+			};
+
+			template<typename func_t>
+			inline void TimeBlock(const char * name, func_t func) {
+				BlockGuard guard(name);
+				func();
+			}
+
+			template<typename ret_t = void, typename func_t, typename... arg_t>
+			inline ret_t TimeCall(
+					const char * name, func_t func, arg_t&&... arg) {
+				BlockGuard guard(name);
+				return func(std::forward<arg_t>(arg)...);
+			}
+#		endif
+	}
+}
Index: src/Common/UniqueName.cc
===================================================================
--- src/Common/UniqueName.cc	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,31 +1,0 @@
-//
-// 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.
-//
-// UniqueName.cc -- Create a unique variants of a base name with a counter.
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Nov  7 15:04:00 2023
-// Update Count     : 4
-//
-
-#include "UniqueName.h"
-
-#include "Common/ToString.hpp"
-
-UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) {
-}
-
-std::string UniqueName::newName( const std::string &additional ) {
-	return toString( base, additional, count++ );
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/UniqueName.cpp
===================================================================
--- src/Common/UniqueName.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/UniqueName.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,31 @@
+//
+// 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.
+//
+// UniqueName.cpp -- Create a unique variants of a base name with a counter.
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Nov  7 15:04:00 2023
+// Update Count     : 4
+//
+
+#include "UniqueName.hpp"
+
+#include "Common/ToString.hpp"
+
+UniqueName::UniqueName( const std::string &base ) : base( base ), count( 0 ) {
+}
+
+std::string UniqueName::newName( const std::string &additional ) {
+	return toString( base, additional, count++ );
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/UniqueName.h
===================================================================
--- src/Common/UniqueName.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,33 +1,0 @@
-//
-// 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.
-//
-// UniqueName.h -- Create a unique variants of a base name with a counter.
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Nov  7 15:00:00 2023
-// Update Count     : 3
-//
-
-#pragma once
-
-#include <string>
-
-class UniqueName {
-public:
-	UniqueName( const std::string &base );
-	std::string newName( const std::string &additional = "" );
-private:
-	std::string base;
-	int count;
-};
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/UniqueName.hpp
===================================================================
--- src/Common/UniqueName.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/UniqueName.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -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.
+//
+// UniqueName.hpp -- Create a unique variants of a base name with a counter.
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Nov  7 15:00:00 2023
+// Update Count     : 3
+//
+
+#pragma once
+
+#include <string>
+
+class UniqueName {
+public:
+	UniqueName( const std::string &base );
+	std::string newName( const std::string &additional = "" );
+private:
+	std::string base;
+	int count;
+};
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/Utility.hpp
===================================================================
--- src/Common/Utility.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/Utility.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,117 @@
+//
+// 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.
+//
+// Utility.hpp -- General utilities used across the compiler.
+//
+// Author           : Richard C. Bilson
+// Created On       : Mon May 18 07:44:20 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Wed Jan 17 14:40:00 2024
+// Update Count     : 54
+//
+
+#pragma once
+
+#include <cassert>
+#include <algorithm>
+#include <list>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+/// partner to move that copies any copyable type
+template<typename T>
+T copy( const T & x ) { return x; }
+
+/// Splice src onto the end of dst, clearing src
+template< typename T >
+void splice( std::vector< T > & dst, std::vector< T > & src ) {
+	dst.reserve( dst.size() + src.size() );
+	for ( T & x : src ) { dst.emplace_back( std::move( x ) ); }
+	src.clear();
+}
+
+/// Splice src onto the begining of dst, clearing src
+template< typename T >
+void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) {
+	splice( src, dst );
+	dst.swap( src );
+}
+
+/// Remove elements that match pred from the container.
+template<typename Container, typename Pred>
+void erase_if( Container & cont, Pred && pred ) {
+	auto keep_end = std::remove_if( cont.begin(), cont.end(), pred );
+	cont.erase( keep_end, cont.end() );
+}
+
+// determines if pref is a prefix of str
+static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
+	if ( pref.size() > str.size() ) return false;
+	return pref == str.substr(start, pref.size());
+}
+
+// -----------------------------------------------------------------------------
+// RAII object to regulate "save and restore" behaviour, e.g.
+// void Foo::bar() {
+//   ValueGuard<int> guard(var); // var is a member of type Foo
+//   var = ...;
+// } // var's original value is restored
+template< typename T >
+struct ValueGuard {
+	T old;
+	T& ref;
+
+	ValueGuard(T& inRef) : old(inRef), ref(inRef) {}
+	~ValueGuard() { ref = old; }
+};
+
+template< typename T >
+struct ValueGuardPtr {
+	T old;
+	T* ref;
+
+	ValueGuardPtr(T * inRef) : old( inRef ? *inRef : T() ), ref(inRef) {}
+	ValueGuardPtr(const ValueGuardPtr& other) = delete;
+	ValueGuardPtr(ValueGuardPtr&& other) : old(other.old), ref(other.ref) { other.ref = nullptr; }
+	~ValueGuardPtr() { if( ref ) *ref = old; }
+};
+
+template< typename aT >
+struct FuncGuard {
+	aT m_after;
+
+	template< typename bT >
+	FuncGuard( bT before, aT after ) : m_after( after ) {
+		before();
+	}
+
+	~FuncGuard() {
+		m_after();
+	}
+};
+
+template< typename bT, typename aT >
+FuncGuard<aT> makeFuncGuard( bT && before, aT && after ) {
+	return FuncGuard<aT>( std::forward<bT>(before), std::forward<aT>(after) );
+}
+
+template< typename T >
+struct ValueGuardPtr< std::list< T > > {
+	std::list< T > old;
+	std::list< T >* ref;
+
+	ValueGuardPtr( std::list< T > * inRef) : old(), ref(inRef) {
+		if( ref ) { swap( *ref, old ); }
+	}
+	~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } }
+};
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/VectorMap.h
===================================================================
--- src/Common/VectorMap.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,248 +1,0 @@
-//
-// 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.
-//
-// VectorMap.h --
-//
-// Author           : Aaron B. Moss
-// Created On       : Wed Feb  1 16:55:00 2017
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Fri Jul 21 22:19:29 2017
-// Update Count     : 2
-//
-
-#pragma once
-
-#include <iterator>
-#include <utility>
-#include <vector>
-
-/// Maps integers from a contiguous range to T's
-template<typename T>
-class VectorMap {
-	std::vector<T> data;
-
-public:
-	typedef typename std::vector<T>::size_type size_type;
-	typedef size_type key_type;
-	typedef T mapped_type;
-	typedef std::pair<size_type, T&> value_type;
-	typedef std::pair<size_type, const T&> const_value_type;
-	typedef typename std::vector<T>::difference_type difference_type;
-	typedef const value_type& reference;
-	typedef const const_value_type& const_reference;
-	typedef const value_type* pointer;
-	typedef const const_value_type* const_pointer;
-
-	class iterator : public std::iterator<
-			std::random_access_iterator_tag,
-			value_type, difference_type, pointer, reference > {
-		friend class VectorMap;
-		friend class const_iterator;
-
-		value_type data;
-
-		iterator(size_type i, std::vector<T>& v) : data(i, v[i]) {}
-	public:
-		iterator(const iterator& that) : data(that.data) {}
-		iterator& operator= (const iterator& that) {
-			new(&data) value_type{ that.data };
-			return *this;
-		}
-
-		reference operator* () { return data; }
-		pointer operator-> () { return &data; }
-
-		iterator& operator++ () {
-			// SHENANIGANS: relies on pair<unsigned, T&> having a trivial destructor and
-			// vector<T> having contiguous layout
-			new(&data) value_type{ (data.first + 1), *(&data.second + 1) };
-			return *this;
-		}
-		iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
-
-		iterator& operator-- () {
-			// SHENANIGANS: same reasons as operator++
-			new(&data) value_type{ (data.first - 1), *(&data.second - 1) };
-			return *this;
-		}
-		iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
-
-		iterator& operator+= (difference_type i) {
-			// SHENANIGANS: same reasons as operator++
-			new(&data) value_type{ (data.first + i), *(&data.second + i) };
-			return *this;
-		}
-
-		iterator operator+ (difference_type i) const { iterator tmp = *this; return tmp += i; }
-
-		iterator& operator-= (difference_type i) {
-			// SHENANIGANS: same reasons as operator++
-			new(&data) value_type{ (data.first - i), *(&data.second - i) };
-			return *this;
-		}
-
-		iterator operator- (difference_type i) const { iterator tmp = *this; return tmp -= i; }
-
-		difference_type operator- (const iterator& o) const { return data.first - o.data.first; }
-
-		value_type operator[] (difference_type i) const {
-			// SHENANIGANS: same reasons as operator++
-			return value_type{ (data.first + i), *(&data.second + i) };
-		}
-
-		bool operator== (const iterator& o) const {
-			return data.first == o.data.first && &data.second == &o.data.second;
-		}
-
-		bool operator!= (const iterator& that) const { return !(*this == that); }
-
-		bool operator< (const iterator& o) const { return data.first < o.data.first; }
-
-		bool operator> (const iterator& o) const { return data.first > o.data.first; }
-
-		bool operator<= (const iterator& o) const { return data.first <= o.data.first; }
-
-		bool operator>= (const iterator& o) const { return data.first >= o.data.first; }
-	};
-
-	class const_iterator : public std::iterator<
-			std::bidirectional_iterator_tag,
-			const_value_type, difference_type, const_pointer, const_reference > {
-		friend class VectorMap;
-		const_value_type data;
-
-		const_iterator(size_type i, const std::vector<T>& v) : data(i, v[i]) {}
-	public:
-		const_iterator(const iterator& that) : data(that.data) {}
-		const_iterator(const const_iterator& that) : data(that.data) {}
-		const_iterator& operator= (const iterator& that) {
-			new(&data) const_value_type{ that.data };
-			return *this;
-		}
-		const_iterator& operator= (const const_iterator& that) {
-			new(&data) const_value_type{ that.data };
-			return *this;
-		}
-
-		const_reference operator* () { return data; }
-		const_pointer operator-> () { return &data; }
-
-		const_iterator& operator++ () {
-			// SHENANIGANS: same reasons as iterator::operator++
-			new(&data) const_value_type{ (data.first + 1), *(&data.second + 1) };
-			return *this;
-		}
-		const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
-
-		const_iterator& operator-- () {
-			// SHENANIGANS: same reasons as iterator::operator++
-			new(&data) const_value_type{ (data.first - 1), *(&data.second - 1) };
-			return *this;
-		}
-		const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
-
-		const_iterator& operator+= (difference_type i) {
-			// SHENANIGANS: same reasons as iterator::operator++
-			new(&data) const_value_type{ (data.first + i), *(&data.second + i) };
-			return *this;
-		}
-
-		const_iterator operator+ (difference_type i) const {
-			const_iterator tmp = *this; return tmp += i;
-		}
-
-		const_iterator& operator-= (difference_type i) {
-			// SHENANIGANS: same reasons as iterator::operator++
-			new(&data) const_value_type{ (data.first - i), *(&data.second - i) };
-			return *this;
-		}
-
-		const_iterator operator- (difference_type i) const {
-			const_iterator tmp = *this; return tmp -= i;
-		}
-
-		difference_type operator- (const const_iterator& o) const {
-			return data.first - o.data.first;
-		}
-
-		const_value_type operator[] (difference_type i) const {
-			// SHENANIGANS: same reasons as iterator::operator++
-			return const_value_type{ (data.first + i), *(&data.second + i) };
-		}
-
-		bool operator== (const const_iterator& o) const {
-			return data.first == o.data.first && &data.second == &o.data.second;
-		}
-
-		bool operator!= (const const_iterator& that) const { return !(*this == that); }
-
-		bool operator< (const const_iterator& o) const { return data.first < o.data.first; }
-
-		bool operator> (const const_iterator& o) const { return data.first > o.data.first; }
-
-		bool operator<= (const const_iterator& o) const { return data.first <= o.data.first; }
-
-		bool operator>= (const const_iterator& o) const { return data.first >= o.data.first; }
-	};
-
-	/// Reserve space for n elements
-	void reserve(size_type n) {
-		if ( n > data.size() ) { data.insert( data.end(), n - data.size(), T{} ); }
-	}
-
-	/// Unsafe access; no bounds checking
-	T& operator[] (size_type i) { return data[i]; }
-	const T& operator[] (size_type i) const { return data[i]; }
-
-	/// Safe access; will insert new values if needed
-	T& at(size_type i) {
-		reserve(i+1);
-		return data[i];
-	}
-
-	/// Number of stored values
-	unsigned size() const { return data.size(); }
-
-	/// No stored values
-	bool empty() const { return data.empty(); }
-
-	/// Empties the map
-	void clear() { data.clear(); }
-
-	/// Returns 1 if element in map, 0 otherwise
-	size_type count( size_type i ) const { return i < size() ? 1 : 0; }
-
-	iterator begin() { return iterator{ 0, data }; }
-	const_iterator begin() const { return const_iterator{ 0, data }; }
-	const_iterator cbegin() const { return const_iterator{ 0, data }; }
-
-	iterator end() { return iterator{ data.size(), data }; }
-	const_iterator end() const { return const_iterator{ data.size(), data }; }
-	const_iterator cend() const { return const_iterator{ data.size(), data }; }
-
-	iterator find( size_type i ) { return i < size() ? iterator{ i, data } : end(); }
-	const_iterator find( size_type i ) const { return i < size() ? const_iterator{ i, data } : end(); }
-};
-
-template<typename T>
-typename VectorMap<T>::iterator operator+(
-		typename VectorMap<T>::difference_type i,
-		const typename VectorMap<T>::iterator& it) {
-	return it + i;
-}
-
-template<typename T>
-typename VectorMap<T>::const_iterator operator+(
-		typename VectorMap<T>::difference_type i,
-		const typename VectorMap<T>::const_iterator& it) {
-	return it + i;
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/Common/VectorMap.hpp
===================================================================
--- src/Common/VectorMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/Common/VectorMap.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,248 @@
+//
+// 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.
+//
+// VectorMap.hpp --
+//
+// Author           : Aaron B. Moss
+// Created On       : Wed Feb  1 16:55:00 2017
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Fri Jul 21 22:19:29 2017
+// Update Count     : 2
+//
+
+#pragma once
+
+#include <iterator>
+#include <utility>
+#include <vector>
+
+/// Maps integers from a contiguous range to T's
+template<typename T>
+class VectorMap {
+	std::vector<T> data;
+
+public:
+	typedef typename std::vector<T>::size_type size_type;
+	typedef size_type key_type;
+	typedef T mapped_type;
+	typedef std::pair<size_type, T&> value_type;
+	typedef std::pair<size_type, const T&> const_value_type;
+	typedef typename std::vector<T>::difference_type difference_type;
+	typedef const value_type& reference;
+	typedef const const_value_type& const_reference;
+	typedef const value_type* pointer;
+	typedef const const_value_type* const_pointer;
+
+	class iterator : public std::iterator<
+			std::random_access_iterator_tag,
+			value_type, difference_type, pointer, reference > {
+		friend class VectorMap;
+		friend class const_iterator;
+
+		value_type data;
+
+		iterator(size_type i, std::vector<T>& v) : data(i, v[i]) {}
+	public:
+		iterator(const iterator& that) : data(that.data) {}
+		iterator& operator= (const iterator& that) {
+			new(&data) value_type{ that.data };
+			return *this;
+		}
+
+		reference operator* () { return data; }
+		pointer operator-> () { return &data; }
+
+		iterator& operator++ () {
+			// SHENANIGANS: relies on pair<unsigned, T&> having a trivial destructor and
+			// vector<T> having contiguous layout
+			new(&data) value_type{ (data.first + 1), *(&data.second + 1) };
+			return *this;
+		}
+		iterator operator++ (int) { iterator tmp = *this; ++(*this); return tmp; }
+
+		iterator& operator-- () {
+			// SHENANIGANS: same reasons as operator++
+			new(&data) value_type{ (data.first - 1), *(&data.second - 1) };
+			return *this;
+		}
+		iterator operator-- (int) { iterator tmp = *this; --(*this); return tmp; }
+
+		iterator& operator+= (difference_type i) {
+			// SHENANIGANS: same reasons as operator++
+			new(&data) value_type{ (data.first + i), *(&data.second + i) };
+			return *this;
+		}
+
+		iterator operator+ (difference_type i) const { iterator tmp = *this; return tmp += i; }
+
+		iterator& operator-= (difference_type i) {
+			// SHENANIGANS: same reasons as operator++
+			new(&data) value_type{ (data.first - i), *(&data.second - i) };
+			return *this;
+		}
+
+		iterator operator- (difference_type i) const { iterator tmp = *this; return tmp -= i; }
+
+		difference_type operator- (const iterator& o) const { return data.first - o.data.first; }
+
+		value_type operator[] (difference_type i) const {
+			// SHENANIGANS: same reasons as operator++
+			return value_type{ (data.first + i), *(&data.second + i) };
+		}
+
+		bool operator== (const iterator& o) const {
+			return data.first == o.data.first && &data.second == &o.data.second;
+		}
+
+		bool operator!= (const iterator& that) const { return !(*this == that); }
+
+		bool operator< (const iterator& o) const { return data.first < o.data.first; }
+
+		bool operator> (const iterator& o) const { return data.first > o.data.first; }
+
+		bool operator<= (const iterator& o) const { return data.first <= o.data.first; }
+
+		bool operator>= (const iterator& o) const { return data.first >= o.data.first; }
+	};
+
+	class const_iterator : public std::iterator<
+			std::bidirectional_iterator_tag,
+			const_value_type, difference_type, const_pointer, const_reference > {
+		friend class VectorMap;
+		const_value_type data;
+
+		const_iterator(size_type i, const std::vector<T>& v) : data(i, v[i]) {}
+	public:
+		const_iterator(const iterator& that) : data(that.data) {}
+		const_iterator(const const_iterator& that) : data(that.data) {}
+		const_iterator& operator= (const iterator& that) {
+			new(&data) const_value_type{ that.data };
+			return *this;
+		}
+		const_iterator& operator= (const const_iterator& that) {
+			new(&data) const_value_type{ that.data };
+			return *this;
+		}
+
+		const_reference operator* () { return data; }
+		const_pointer operator-> () { return &data; }
+
+		const_iterator& operator++ () {
+			// SHENANIGANS: same reasons as iterator::operator++
+			new(&data) const_value_type{ (data.first + 1), *(&data.second + 1) };
+			return *this;
+		}
+		const_iterator operator++ (int) { const_iterator tmp = *this; ++(*this); return tmp; }
+
+		const_iterator& operator-- () {
+			// SHENANIGANS: same reasons as iterator::operator++
+			new(&data) const_value_type{ (data.first - 1), *(&data.second - 1) };
+			return *this;
+		}
+		const_iterator operator-- (int) { const_iterator tmp = *this; --(*this); return tmp; }
+
+		const_iterator& operator+= (difference_type i) {
+			// SHENANIGANS: same reasons as iterator::operator++
+			new(&data) const_value_type{ (data.first + i), *(&data.second + i) };
+			return *this;
+		}
+
+		const_iterator operator+ (difference_type i) const {
+			const_iterator tmp = *this; return tmp += i;
+		}
+
+		const_iterator& operator-= (difference_type i) {
+			// SHENANIGANS: same reasons as iterator::operator++
+			new(&data) const_value_type{ (data.first - i), *(&data.second - i) };
+			return *this;
+		}
+
+		const_iterator operator- (difference_type i) const {
+			const_iterator tmp = *this; return tmp -= i;
+		}
+
+		difference_type operator- (const const_iterator& o) const {
+			return data.first - o.data.first;
+		}
+
+		const_value_type operator[] (difference_type i) const {
+			// SHENANIGANS: same reasons as iterator::operator++
+			return const_value_type{ (data.first + i), *(&data.second + i) };
+		}
+
+		bool operator== (const const_iterator& o) const {
+			return data.first == o.data.first && &data.second == &o.data.second;
+		}
+
+		bool operator!= (const const_iterator& that) const { return !(*this == that); }
+
+		bool operator< (const const_iterator& o) const { return data.first < o.data.first; }
+
+		bool operator> (const const_iterator& o) const { return data.first > o.data.first; }
+
+		bool operator<= (const const_iterator& o) const { return data.first <= o.data.first; }
+
+		bool operator>= (const const_iterator& o) const { return data.first >= o.data.first; }
+	};
+
+	/// Reserve space for n elements
+	void reserve(size_type n) {
+		if ( n > data.size() ) { data.insert( data.end(), n - data.size(), T{} ); }
+	}
+
+	/// Unsafe access; no bounds checking
+	T& operator[] (size_type i) { return data[i]; }
+	const T& operator[] (size_type i) const { return data[i]; }
+
+	/// Safe access; will insert new values if needed
+	T& at(size_type i) {
+		reserve(i+1);
+		return data[i];
+	}
+
+	/// Number of stored values
+	unsigned size() const { return data.size(); }
+
+	/// No stored values
+	bool empty() const { return data.empty(); }
+
+	/// Empties the map
+	void clear() { data.clear(); }
+
+	/// Returns 1 if element in map, 0 otherwise
+	size_type count( size_type i ) const { return i < size() ? 1 : 0; }
+
+	iterator begin() { return iterator{ 0, data }; }
+	const_iterator begin() const { return const_iterator{ 0, data }; }
+	const_iterator cbegin() const { return const_iterator{ 0, data }; }
+
+	iterator end() { return iterator{ data.size(), data }; }
+	const_iterator end() const { return const_iterator{ data.size(), data }; }
+	const_iterator cend() const { return const_iterator{ data.size(), data }; }
+
+	iterator find( size_type i ) { return i < size() ? iterator{ i, data } : end(); }
+	const_iterator find( size_type i ) const { return i < size() ? const_iterator{ i, data } : end(); }
+};
+
+template<typename T>
+typename VectorMap<T>::iterator operator+(
+		typename VectorMap<T>::difference_type i,
+		const typename VectorMap<T>::iterator& it) {
+	return it + i;
+}
+
+template<typename T>
+typename VectorMap<T>::const_iterator operator+(
+		typename VectorMap<T>::difference_type i,
+		const typename VectorMap<T>::const_iterator& it) {
+	return it + i;
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/Common/module.mk
===================================================================
--- src/Common/module.mk	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ src/Common/module.mk	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,44 +16,44 @@
 
 SRC_COMMON = \
-	Common/Assert.cc \
-	Common/CodeLocation.h \
+	Common/Assert.cpp \
+	Common/CodeLocation.hpp \
 	Common/CodeLocationTools.hpp \
 	Common/CodeLocationTools.cpp \
 	Common/DeclStats.hpp \
 	Common/DeclStats.cpp \
-	Common/ErrorObjects.h \
-	Common/Eval.cc \
-	Common/Eval.h \
-	Common/Examine.cc \
-	Common/Examine.h \
-	Common/FilterCombos.h \
-	Common/Indenter.h \
-	Common/Indenter.cc \
+	Common/ErrorObjects.hpp \
+	Common/Eval.cpp \
+	Common/Eval.hpp \
+	Common/Examine.cpp \
+	Common/Examine.hpp \
+	Common/FilterCombos.hpp \
+	Common/Indenter.hpp \
+	Common/Indenter.cpp \
 	Common/Iterate.hpp \
-	Common/PersistentMap.h \
+	Common/PersistentMap.hpp \
 	Common/ResolvProtoDump.hpp \
 	Common/ResolvProtoDump.cpp \
-	Common/ScopedMap.h \
-	Common/SemanticError.cc \
-	Common/SemanticError.h \
-	Common/Stats.h \
-	Common/Stats/Base.h \
-	Common/Stats/Counter.cc \
-	Common/Stats/Counter.h \
-	Common/Stats/Heap.cc \
-	Common/Stats/Heap.h \
-	Common/Stats/ResolveTime.cc \
-	Common/Stats/ResolveTime.h \
-	Common/Stats/Stats.cc \
-	Common/Stats/Time.cc \
-	Common/Stats/Time.h \
+	Common/ScopedMap.hpp \
+	Common/SemanticError.cpp \
+	Common/SemanticError.hpp \
+	Common/Stats.hpp \
+	Common/Stats/Base.hpp \
+	Common/Stats/Counter.cpp \
+	Common/Stats/Counter.hpp \
+	Common/Stats/Heap.cpp \
+	Common/Stats/Heap.hpp \
+	Common/Stats/ResolveTime.cpp \
+	Common/Stats/ResolveTime.hpp \
+	Common/Stats/Stats.cpp \
+	Common/Stats/Time.cpp \
+	Common/Stats/Time.hpp \
 	Common/ToString.hpp \
-	Common/UniqueName.cc \
-	Common/UniqueName.h \
-	Common/utility.h \
-	Common/VectorMap.h
+	Common/UniqueName.cpp \
+	Common/UniqueName.hpp \
+	Common/utility.hpp \
+	Common/VectorMap.hpp
 
 SRC += $(SRC_COMMON) \
-	Common/DebugMalloc.cc
+	Common/DebugMalloc.cpp
 
 SRCDEMANGLE += $(SRC_COMMON)
Index: src/Common/utility.h
===================================================================
--- src/Common/utility.h	(revision fc1a3e283512526d1ddc12898c7c5fa33f0ddeaf)
+++ 	(revision )
@@ -1,117 +1,0 @@
-//
-// 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.
-//
-// utility.h -- General utilities used across the compiler.
-//
-// Author           : Richard C. Bilson
-// Created On       : Mon May 18 07:44:20 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Wed Jan 17 14:40:00 2024
-// Update Count     : 54
-//
-
-#pragma once
-
-#include <cassert>
-#include <algorithm>
-#include <list>
-#include <string>
-#include <type_traits>
-#include <vector>
-
-/// partner to move that copies any copyable type
-template<typename T>
-T copy( const T & x ) { return x; }
-
-/// Splice src onto the end of dst, clearing src
-template< typename T >
-void splice( std::vector< T > & dst, std::vector< T > & src ) {
-	dst.reserve( dst.size() + src.size() );
-	for ( T & x : src ) { dst.emplace_back( std::move( x ) ); }
-	src.clear();
-}
-
-/// Splice src onto the begining of dst, clearing src
-template< typename T >
-void spliceBegin( std::vector< T > & dst, std::vector< T > & src ) {
-	splice( src, dst );
-	dst.swap( src );
-}
-
-/// Remove elements that match pred from the container.
-template<typename Container, typename Pred>
-void erase_if( Container & cont, Pred && pred ) {
-	auto keep_end = std::remove_if( cont.begin(), cont.end(), pred );
-	cont.erase( keep_end, cont.end() );
-}
-
-// determines if pref is a prefix of str
-static inline bool isPrefix( const std::string & str, const std::string & pref, unsigned int start = 0 ) {
-	if ( pref.size() > str.size() ) return false;
-	return pref == str.substr(start, pref.size());
-}
-
-// -----------------------------------------------------------------------------
-// RAII object to regulate "save and restore" behaviour, e.g.
-// void Foo::bar() {
-//   ValueGuard<int> guard(var); // var is a member of type Foo
-//   var = ...;
-// } // var's original value is restored
-template< typename T >
-struct ValueGuard {
-	T old;
-	T& ref;
-
-	ValueGuard(T& inRef) : old(inRef), ref(inRef) {}
-	~ValueGuard() { ref = old; }
-};
-
-template< typename T >
-struct ValueGuardPtr {
-	T old;
-	T* ref;
-
-	ValueGuardPtr(T * inRef) : old( inRef ? *inRef : T() ), ref(inRef) {}
-	ValueGuardPtr(const ValueGuardPtr& other) = delete;
-	ValueGuardPtr(ValueGuardPtr&& other) : old(other.old), ref(other.ref) { other.ref = nullptr; }
-	~ValueGuardPtr() { if( ref ) *ref = old; }
-};
-
-template< typename aT >
-struct FuncGuard {
-	aT m_after;
-
-	template< typename bT >
-	FuncGuard( bT before, aT after ) : m_after( after ) {
-		before();
-	}
-
-	~FuncGuard() {
-		m_after();
-	}
-};
-
-template< typename bT, typename aT >
-FuncGuard<aT> makeFuncGuard( bT && before, aT && after ) {
-	return FuncGuard<aT>( std::forward<bT>(before), std::forward<aT>(after) );
-}
-
-template< typename T >
-struct ValueGuardPtr< std::list< T > > {
-	std::list< T > old;
-	std::list< T >* ref;
-
-	ValueGuardPtr( std::list< T > * inRef) : old(), ref(inRef) {
-		if( ref ) { swap( *ref, old ); }
-	}
-	~ValueGuardPtr() { if( ref ) { swap( *ref, old ); } }
-};
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
