Index: src/SymTab/Demangle.cc
===================================================================
--- src/SymTab/Demangle.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,330 +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.
-//
-// Demangle.cc -- Convert a mangled name into a human readable name.
-//
-// Author           : Rob Schluntz
-// Created On       : Thu Jul 19 12:52:41 2018
-// Last Modified By : Andrew Beach
-// Last Modified On : Mon Nov  6 15:59:00 2023
-// Update Count     : 12
-//
-
-#include <algorithm>
-#include <sstream>
-
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "CodeGen/GenType.h"
-#include "CodeGen/OperatorTable.h"
-#include "Common/utility.h"								// isPrefix
-#include "Mangler.h"
-
-#define DEBUG
-#ifdef DEBUG
-#define PRINT(x) x
-#else
-#define PRINT(x) {}
-#endif
-
-namespace Mangle {
-
-namespace {
-
-struct Demangler {
-private:
-	std::string str;
-	size_t index = 0;
-	using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>;
-	std::vector<std::pair<std::string, Parser>> parsers;
-public:
-	Demangler( const std::string & str );
-
-	bool done() const { return str.size() <= index; }
-	char cur() const { assert( !done() ); return str[index]; }
-	bool expect( char ch ) { return str[index++] == ch; }
-
-	bool isPrefix( const std::string & pref );
-	bool extractNumber( size_t & out );
-	bool extractName( std::string & out );
-	bool stripMangleName( std::string & name );
-
-	ast::Type * parseFunction( ast::CV::Qualifiers tq );
-	ast::Type * parseTuple( ast::CV::Qualifiers tq );
-	ast::Type * parsePointer( ast::CV::Qualifiers tq );
-	ast::Type * parseArray( ast::CV::Qualifiers tq );
-	ast::Type * parseStruct( ast::CV::Qualifiers tq );
-	ast::Type * parseUnion( ast::CV::Qualifiers tq );
-	ast::Type * parseEnum( ast::CV::Qualifiers tq );
-	ast::Type * parseType( ast::CV::Qualifiers tq );
-	ast::Type * parseZero( ast::CV::Qualifiers tq );
-	ast::Type * parseOne( ast::CV::Qualifiers tq );
-
-	ast::Type * parseType();
-	bool parse( std::string & name, ast::Type *& type );
-};
-
-Demangler::Demangler(const std::string & str) : str(str) {
-	for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
-		parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) {
-			PRINT( std::cerr << "basic type: " << k << std::endl; )
-			return new ast::BasicType( (ast::BasicType::Kind)k, tq );
-		});
-	}
-
-	for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) {
-		static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
-		static_assert(
-			sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
-			"Each type variable kind should have a demangle name prefix"
-		);
-		parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * {
-			PRINT( std::cerr << "type variable type: " << k << std::endl; )
-			size_t N;
-			if (!extractNumber(N)) return nullptr;
-			return new ast::TypeInstType(
-				toString(typeVariableNames[k], N),
-				(ast::TypeDecl::Kind)k,
-				tq );
-		});
-	}
-
-	parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); });
-	parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); });
-	parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); });
-	parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); });
-	parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); });
-	parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); });
-	parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); });
-	parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); });
-	parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); });
-	parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); });
-	parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); });
-}
-
-bool Demangler::extractNumber( size_t & out ) {
-	std::stringstream numss;
-	if ( str.size() <= index ) return false;
-	while ( isdigit( str[index] ) ) {
-		numss << str[index];
-		++index;
-		if ( str.size() == index ) break;
-	}
-	if ( !(numss >> out) ) return false;
-	PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
-	return true;
-}
-
-bool Demangler::extractName( std::string & out ) {
-	size_t len;
-	if ( !extractNumber(len) ) return false;
-	if ( str.size() < index + len ) return false;
-	out = str.substr( index, len );
-	index += len;
-	PRINT( std::cerr << "extractName success: " << out << std::endl; )
-	return true;
-}
-
-bool Demangler::isPrefix( const std::string & pref ) {
-	// Wraps the utility isPrefix function.
-	if ( ::isPrefix( str, pref, index ) ) {
-		index += pref.size();
-		return true;
-	}
-	return false;
-}
-
-// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
-bool Demangler::stripMangleName( std::string & name ) {
-	PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
-	if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
-	if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false;
-
-	if (!extractName(name)) return false;
-
-	// Find bounds for type.
-	PRINT( std::cerr << index << " " << str.size() << std::endl; )
-	PRINT( std::cerr << "[");
-	while (isdigit(str.back())) {
-		PRINT(std::cerr << ".");
-		str.pop_back();
-		if (str.size() <= index) return false;
-	}
-	PRINT( std::cerr << "]" << std::endl );
-	if (str.back() != '_') return false;
-	str.pop_back();
-	PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; )
-	return index < str.size();
-}
-
-ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "function..." << std::endl; )
-	if ( done() ) return nullptr;
-	ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq );
-	std::unique_ptr<ast::Type> manager( ftype );
-	ast::Type * retVal = parseType();
-	if ( !retVal ) return nullptr;
-	PRINT( std::cerr << "with return type: " << retVal << std::endl; )
-	ftype->returns.emplace_back( retVal );
-	if ( done() || !expect('_') ) return nullptr;
-	while ( !done() ) {
-		PRINT( std::cerr << "got ch: " << cur() << std::endl; )
-		if ( cur() == '_' ) return manager.release();
-		ast::Type * param = parseType();
-		if ( !param ) return nullptr;
-		PRINT( std::cerr << "with parameter : " << param << std::endl; )
-		ftype->params.emplace_back( param );
-	}
-	return nullptr;
-}
-
-ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "tuple..." << std::endl; )
-	std::vector<ast::ptr<ast::Type>> types;
-	size_t ncomponents;
-	if ( !extractNumber(ncomponents) ) return nullptr;
-	for ( size_t i = 0; i < ncomponents; ++i ) {
-		if ( done() ) return nullptr;
-		PRINT( std::cerr << "got ch: " << cur() << std::endl; )
-		ast::Type * t = parseType();
-		if ( !t ) return nullptr;
-		PRINT( std::cerr << "with type : " << t << std::endl; )
-		types.push_back( t );
-	}
-	return new ast::TupleType( std::move( types ), tq );
-}
-
-ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "pointer..." << std::endl; )
-	ast::Type * t = parseType();
-	if ( !t ) return nullptr;
-	return new ast::PointerType( t, tq );
-}
-
-ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "array..." << std::endl; )
-	size_t length;
-	if ( !extractNumber(length) ) return nullptr;
-	ast::Type * t = parseType();
-	if ( !t ) return nullptr;
-	return new ast::ArrayType(
-		t,
-		ast::ConstantExpr::from_ulong( CodeLocation(), length ),
-		ast::FixedLen,
-		ast::DynamicDim,
-		tq );
-}
-
-ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "struct..." << std::endl; )
-	std::string name;
-	if ( !extractName(name) ) return nullptr;
-	return new ast::StructInstType( name, tq );
-}
-
-ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "union..." << std::endl; )
-	std::string name;
-	if ( !extractName(name) ) return nullptr;
-	return new ast::UnionInstType( name, tq );
-}
-
-ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "enum..." << std::endl; )
-	std::string name;
-	if ( !extractName(name) ) return nullptr;
-	return new ast::EnumInstType( name, tq );
-}
-
-ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) {
-	PRINT( std::cerr << "type..." << std::endl; )
-	std::string name;
-	if ( !extractName(name) ) return nullptr;
-	PRINT( std::cerr << "typename..." << name << std::endl; )
-	return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq );
-}
-
-ast::Type * Demangler::parseType() {
-	if (done()) return nullptr;
-
-	if (isPrefix(Encoding::forall)) {
-		PRINT( std::cerr << "polymorphic with..." << std::endl; )
-		size_t dcount, fcount, vcount, acount;
-		if ( !extractNumber(dcount) ) return nullptr;
-		PRINT( std::cerr << dcount << " dtypes" << std::endl; )
-		if ( !expect('_') ) return nullptr;
-		if ( !extractNumber(fcount) ) return nullptr;
-		PRINT( std::cerr << fcount << " ftypes" << std::endl; )
-		if ( !expect('_')) return nullptr;
-		if ( !extractNumber(vcount)) return nullptr;
-		PRINT( std::cerr << vcount << " ttypes" << std::endl; )
-		if ( !expect('_') ) return nullptr;
-		if ( !extractNumber(acount) ) return nullptr;
-		PRINT( std::cerr << acount << " assertions" << std::endl; )
-		if ( !expect('_') ) return nullptr;
-		for ( size_t i = 0 ; i < acount ; ++i ) {
-			// TODO: need to recursively parse assertions, but for now just return nullptr so that
-			// demangler does not crash if there are assertions
-			return nullptr;
-		}
-		if ( !expect('_') ) return nullptr;
-	}
-
-	ast::CV::Qualifiers tq;
-	while (true) {
-		auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
-			return isPrefix(val.second);
-		});
-		if (qual == Encoding::qualifiers.end()) break;
-		tq |= qual->first;
-	}
-
-	// Find the correct type parser and then apply it.
-	auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) {
-		return isPrefix(p.first);
-	});
-	assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index);
-	ast::Type * ret = iter->second(tq);
-	if ( !ret ) return nullptr;
-	return ret;
-}
-
-bool Demangler::parse( std::string & name, ast::Type *& type) {
-	if ( !stripMangleName(name) ) return false;
-	PRINT( std::cerr << "stripped name: " << name << std::endl; )
-	ast::Type * t = parseType();
-	if ( !t ) return false;
-	type = t;
-	return true;
-}
-
-std::string demangle( const std::string & mangleName ) {
-	using namespace CodeGen;
-	Demangler demangler( mangleName );
-	std::string name;
-	ast::Type * type = nullptr;
-	if ( !demangler.parse( name, type ) ) return mangleName;
-	ast::readonly<ast::Type> roType = type;
-	if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName;
-	return genType( type, name, Options( false, false, false, false ) );
-}
-
-} // namespace
-
-} // namespace Mangle
-
-extern "C" {
-	char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
-		const std::string & demangleName = Mangle::demangle(mangleName);
-		return strdup(demangleName.c_str());
-	}
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/Demangle.cpp
===================================================================
--- src/SymTab/Demangle.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/Demangle.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,330 @@
+//
+// 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.
+//
+// Demangle.cpp -- Convert a mangled name into a human readable name.
+//
+// Author           : Rob Schluntz
+// Created On       : Thu Jul 19 12:52:41 2018
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Nov  6 15:59:00 2023
+// Update Count     : 12
+//
+
+#include <algorithm>
+#include <sstream>
+
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "CodeGen/GenType.hpp"
+#include "CodeGen/OperatorTable.hpp"
+#include "Common/utility.hpp"								// isPrefix
+#include "Mangler.hpp"
+
+#define DEBUG
+#ifdef DEBUG
+#define PRINT(x) x
+#else
+#define PRINT(x) {}
+#endif
+
+namespace Mangle {
+
+namespace {
+
+struct Demangler {
+private:
+	std::string str;
+	size_t index = 0;
+	using Parser = std::function<ast::Type * ( ast::CV::Qualifiers )>;
+	std::vector<std::pair<std::string, Parser>> parsers;
+public:
+	Demangler( const std::string & str );
+
+	bool done() const { return str.size() <= index; }
+	char cur() const { assert( !done() ); return str[index]; }
+	bool expect( char ch ) { return str[index++] == ch; }
+
+	bool isPrefix( const std::string & pref );
+	bool extractNumber( size_t & out );
+	bool extractName( std::string & out );
+	bool stripMangleName( std::string & name );
+
+	ast::Type * parseFunction( ast::CV::Qualifiers tq );
+	ast::Type * parseTuple( ast::CV::Qualifiers tq );
+	ast::Type * parsePointer( ast::CV::Qualifiers tq );
+	ast::Type * parseArray( ast::CV::Qualifiers tq );
+	ast::Type * parseStruct( ast::CV::Qualifiers tq );
+	ast::Type * parseUnion( ast::CV::Qualifiers tq );
+	ast::Type * parseEnum( ast::CV::Qualifiers tq );
+	ast::Type * parseType( ast::CV::Qualifiers tq );
+	ast::Type * parseZero( ast::CV::Qualifiers tq );
+	ast::Type * parseOne( ast::CV::Qualifiers tq );
+
+	ast::Type * parseType();
+	bool parse( std::string & name, ast::Type *& type );
+};
+
+Demangler::Demangler(const std::string & str) : str(str) {
+	for (size_t k = 0; k < ast::BasicType::NUMBER_OF_BASIC_TYPES; ++k) {
+		parsers.emplace_back(Encoding::basicTypes[k], [k]( ast::CV::Qualifiers tq ) {
+			PRINT( std::cerr << "basic type: " << k << std::endl; )
+			return new ast::BasicType( (ast::BasicType::Kind)k, tq );
+		});
+	}
+
+	for (size_t k = 0; k < ast::TypeDecl::NUMBER_OF_KINDS; ++k) {
+		static const std::string typeVariableNames[] = { "DT", "DST", "OT", "FT", "TT", "ALT", };
+		static_assert(
+			sizeof(typeVariableNames)/sizeof(typeVariableNames[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
+			"Each type variable kind should have a demangle name prefix"
+		);
+		parsers.emplace_back(Encoding::typeVariables[k], [k, this]( ast::CV::Qualifiers tq ) -> ast::TypeInstType * {
+			PRINT( std::cerr << "type variable type: " << k << std::endl; )
+			size_t N;
+			if (!extractNumber(N)) return nullptr;
+			return new ast::TypeInstType(
+				toString(typeVariableNames[k], N),
+				(ast::TypeDecl::Kind)k,
+				tq );
+		});
+	}
+
+	parsers.emplace_back(Encoding::void_t, [this]( ast::CV::Qualifiers tq ) { return new ast::VoidType(tq); });
+	parsers.emplace_back(Encoding::function, [this]( ast::CV::Qualifiers tq ) { return parseFunction(tq); });
+	parsers.emplace_back(Encoding::pointer, [this]( ast::CV::Qualifiers tq ) { return parsePointer(tq); });
+	parsers.emplace_back(Encoding::array, [this]( ast::CV::Qualifiers tq ) { return parseArray(tq); });
+	parsers.emplace_back(Encoding::tuple, [this]( ast::CV::Qualifiers tq ) { return parseTuple(tq); });
+	parsers.emplace_back(Encoding::struct_t, [this]( ast::CV::Qualifiers tq ) { return parseStruct(tq); });
+	parsers.emplace_back(Encoding::union_t, [this]( ast::CV::Qualifiers tq ) { return parseUnion(tq); });
+	parsers.emplace_back(Encoding::enum_t, [this]( ast::CV::Qualifiers tq ) { return parseEnum(tq); });
+	parsers.emplace_back(Encoding::type, [this]( ast::CV::Qualifiers tq ) { return parseType(tq); });
+	parsers.emplace_back(Encoding::zero, []( ast::CV::Qualifiers tq ) { return new ast::ZeroType(tq); });
+	parsers.emplace_back(Encoding::one, []( ast::CV::Qualifiers tq ) { return new ast::OneType(tq); });
+}
+
+bool Demangler::extractNumber( size_t & out ) {
+	std::stringstream numss;
+	if ( str.size() <= index ) return false;
+	while ( isdigit( str[index] ) ) {
+		numss << str[index];
+		++index;
+		if ( str.size() == index ) break;
+	}
+	if ( !(numss >> out) ) return false;
+	PRINT( std::cerr << "extractNumber success: " << out << std::endl; )
+	return true;
+}
+
+bool Demangler::extractName( std::string & out ) {
+	size_t len;
+	if ( !extractNumber(len) ) return false;
+	if ( str.size() < index + len ) return false;
+	out = str.substr( index, len );
+	index += len;
+	PRINT( std::cerr << "extractName success: " << out << std::endl; )
+	return true;
+}
+
+bool Demangler::isPrefix( const std::string & pref ) {
+	// Wraps the utility isPrefix function.
+	if ( ::isPrefix( str, pref, index ) ) {
+		index += pref.size();
+		return true;
+	}
+	return false;
+}
+
+// strips __NAME__cfa__TYPE_N, where N is [0-9]+: returns str is a match is found, returns empty string otherwise
+bool Demangler::stripMangleName( std::string & name ) {
+	PRINT( std::cerr << "====== " << str.size() << " " << str << std::endl; )
+	if (str.size() < 2+Encoding::manglePrefix.size()) return false; // +2 for at least _1 suffix
+	if ( !isPrefix(Encoding::manglePrefix) || !isdigit(str.back() ) ) return false;
+
+	if (!extractName(name)) return false;
+
+	// Find bounds for type.
+	PRINT( std::cerr << index << " " << str.size() << std::endl; )
+	PRINT( std::cerr << "[");
+	while (isdigit(str.back())) {
+		PRINT(std::cerr << ".");
+		str.pop_back();
+		if (str.size() <= index) return false;
+	}
+	PRINT( std::cerr << "]" << std::endl );
+	if (str.back() != '_') return false;
+	str.pop_back();
+	PRINT( std::cerr << str.size() << " " << name << " " << str.substr(index) << std::endl; )
+	return index < str.size();
+}
+
+ast::Type * Demangler::parseFunction( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "function..." << std::endl; )
+	if ( done() ) return nullptr;
+	ast::FunctionType * ftype = new ast::FunctionType( ast::FixedArgs, tq );
+	std::unique_ptr<ast::Type> manager( ftype );
+	ast::Type * retVal = parseType();
+	if ( !retVal ) return nullptr;
+	PRINT( std::cerr << "with return type: " << retVal << std::endl; )
+	ftype->returns.emplace_back( retVal );
+	if ( done() || !expect('_') ) return nullptr;
+	while ( !done() ) {
+		PRINT( std::cerr << "got ch: " << cur() << std::endl; )
+		if ( cur() == '_' ) return manager.release();
+		ast::Type * param = parseType();
+		if ( !param ) return nullptr;
+		PRINT( std::cerr << "with parameter : " << param << std::endl; )
+		ftype->params.emplace_back( param );
+	}
+	return nullptr;
+}
+
+ast::Type * Demangler::parseTuple( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "tuple..." << std::endl; )
+	std::vector<ast::ptr<ast::Type>> types;
+	size_t ncomponents;
+	if ( !extractNumber(ncomponents) ) return nullptr;
+	for ( size_t i = 0; i < ncomponents; ++i ) {
+		if ( done() ) return nullptr;
+		PRINT( std::cerr << "got ch: " << cur() << std::endl; )
+		ast::Type * t = parseType();
+		if ( !t ) return nullptr;
+		PRINT( std::cerr << "with type : " << t << std::endl; )
+		types.push_back( t );
+	}
+	return new ast::TupleType( std::move( types ), tq );
+}
+
+ast::Type * Demangler::parsePointer( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "pointer..." << std::endl; )
+	ast::Type * t = parseType();
+	if ( !t ) return nullptr;
+	return new ast::PointerType( t, tq );
+}
+
+ast::Type * Demangler::parseArray( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "array..." << std::endl; )
+	size_t length;
+	if ( !extractNumber(length) ) return nullptr;
+	ast::Type * t = parseType();
+	if ( !t ) return nullptr;
+	return new ast::ArrayType(
+		t,
+		ast::ConstantExpr::from_ulong( CodeLocation(), length ),
+		ast::FixedLen,
+		ast::DynamicDim,
+		tq );
+}
+
+ast::Type * Demangler::parseStruct( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "struct..." << std::endl; )
+	std::string name;
+	if ( !extractName(name) ) return nullptr;
+	return new ast::StructInstType( name, tq );
+}
+
+ast::Type * Demangler::parseUnion( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "union..." << std::endl; )
+	std::string name;
+	if ( !extractName(name) ) return nullptr;
+	return new ast::UnionInstType( name, tq );
+}
+
+ast::Type * Demangler::parseEnum( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "enum..." << std::endl; )
+	std::string name;
+	if ( !extractName(name) ) return nullptr;
+	return new ast::EnumInstType( name, tq );
+}
+
+ast::Type * Demangler::parseType( ast::CV::Qualifiers tq ) {
+	PRINT( std::cerr << "type..." << std::endl; )
+	std::string name;
+	if ( !extractName(name) ) return nullptr;
+	PRINT( std::cerr << "typename..." << name << std::endl; )
+	return new ast::TypeInstType( name, ast::TypeDecl::Dtype, tq );
+}
+
+ast::Type * Demangler::parseType() {
+	if (done()) return nullptr;
+
+	if (isPrefix(Encoding::forall)) {
+		PRINT( std::cerr << "polymorphic with..." << std::endl; )
+		size_t dcount, fcount, vcount, acount;
+		if ( !extractNumber(dcount) ) return nullptr;
+		PRINT( std::cerr << dcount << " dtypes" << std::endl; )
+		if ( !expect('_') ) return nullptr;
+		if ( !extractNumber(fcount) ) return nullptr;
+		PRINT( std::cerr << fcount << " ftypes" << std::endl; )
+		if ( !expect('_')) return nullptr;
+		if ( !extractNumber(vcount)) return nullptr;
+		PRINT( std::cerr << vcount << " ttypes" << std::endl; )
+		if ( !expect('_') ) return nullptr;
+		if ( !extractNumber(acount) ) return nullptr;
+		PRINT( std::cerr << acount << " assertions" << std::endl; )
+		if ( !expect('_') ) return nullptr;
+		for ( size_t i = 0 ; i < acount ; ++i ) {
+			// TODO: need to recursively parse assertions, but for now just return nullptr so that
+			// demangler does not crash if there are assertions
+			return nullptr;
+		}
+		if ( !expect('_') ) return nullptr;
+	}
+
+	ast::CV::Qualifiers tq;
+	while (true) {
+		auto qual = std::find_if(Encoding::qualifiers.begin(), Encoding::qualifiers.end(), [this](decltype(Encoding::qualifiers)::value_type val) {
+			return isPrefix(val.second);
+		});
+		if (qual == Encoding::qualifiers.end()) break;
+		tq |= qual->first;
+	}
+
+	// Find the correct type parser and then apply it.
+	auto iter = std::find_if(parsers.begin(), parsers.end(), [this](std::pair<std::string, Parser> & p) {
+		return isPrefix(p.first);
+	});
+	assertf(iter != parsers.end(), "Unhandled type letter: %c at index: %zd", cur(), index);
+	ast::Type * ret = iter->second(tq);
+	if ( !ret ) return nullptr;
+	return ret;
+}
+
+bool Demangler::parse( std::string & name, ast::Type *& type) {
+	if ( !stripMangleName(name) ) return false;
+	PRINT( std::cerr << "stripped name: " << name << std::endl; )
+	ast::Type * t = parseType();
+	if ( !t ) return false;
+	type = t;
+	return true;
+}
+
+std::string demangle( const std::string & mangleName ) {
+	using namespace CodeGen;
+	Demangler demangler( mangleName );
+	std::string name;
+	ast::Type * type = nullptr;
+	if ( !demangler.parse( name, type ) ) return mangleName;
+	ast::readonly<ast::Type> roType = type;
+	if ( auto info = operatorLookupByOutput( name ) ) name = info->inputName;
+	return genType( type, name, Options( false, false, false, false ) );
+}
+
+} // namespace
+
+} // namespace Mangle
+
+extern "C" {
+	char * cforall_demangle(const char * mangleName, int option __attribute__((unused))) {
+		const std::string & demangleName = Mangle::demangle(mangleName);
+		return strdup(demangleName.c_str());
+	}
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/Demangle.h
===================================================================
--- src/SymTab/Demangle.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,28 +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.
-//
-// Demangle.h -- Convert a mangled name into a human readable name.
-//
-// Author           : Andrew Beach
-// Created On       : Fri May 13 10:11:00 2022
-// Last Modified By : Andrew Beach
-// Last Modified On : Mon Nov  6 15:48:00 2023
-// Update Count     : 1
-//
-
-#pragma once
-
-extern "C" {
-	/// Main interface to the demangler as a utility.
-	/// Caller must free the returned string.
-	char * cforall_demangle(const char *, int);
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/Demangle.hpp
===================================================================
--- src/SymTab/Demangle.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/Demangle.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,28 @@
+//
+// 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.
+//
+// Demangle.hpp -- Convert a mangled name into a human readable name.
+//
+// Author           : Andrew Beach
+// Created On       : Fri May 13 10:11:00 2022
+// Last Modified By : Andrew Beach
+// Last Modified On : Mon Nov  6 15:48:00 2023
+// Update Count     : 1
+//
+
+#pragma once
+
+extern "C" {
+	/// Main interface to the demangler as a utility.
+	/// Caller must free the returned string.
+	char * cforall_demangle(const char *, int);
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,93 +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.
-//
-// FixFunction.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 16:19:49 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Tue Jul 12 14:28:00 2022
-// Update Count     : 7
-//
-
-#include "FixFunction.h"
-
-#include <list>                   // for list
-
-#include "AST/Decl.hpp"
-#include "AST/Pass.hpp"
-#include "AST/Type.hpp"
-#include "Common/utility.h"       // for copy
-
-namespace SymTab {
-
-namespace {
-
-struct FixFunction final : public ast::WithShortCircuiting {
-	bool isVoid = false;
-
-	void previsit( const ast::FunctionDecl * ) { visit_children = false; }
-
-	const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
-		// Cannot handle cases with asserions.
-		assert( func->assertions.empty() );
-		return new ast::ObjectDecl{
-			func->location, func->name, new ast::PointerType( func->type ), nullptr,
-			func->storage, func->linkage, nullptr, copy( func->attributes ) };
-	}
-
-	void previsit( const ast::ArrayType * ) { visit_children = false; }
-
-	const ast::Type * postvisit( const ast::ArrayType * array ) {
-		return new ast::PointerType{
-			array->base, array->dimension, array->isVarLen, array->isStatic,
-			array->qualifiers };
-	}
-
-	void previsit( const ast::FunctionType * ) { visit_children = false; }
-
-	const ast::Type * postvisit( const ast::FunctionType * type ) {
-		return new ast::PointerType( type );
-	}
-
-	void previsit( const ast::VoidType * ) { isVoid = true; }
-
-	void previsit( const ast::BasicType * ) { visit_children = false; }
-	void previsit( const ast::PointerType * ) { visit_children = false; }
-	void previsit( const ast::StructInstType * ) { visit_children = false; }
-	void previsit( const ast::UnionInstType * ) { visit_children = false; }
-	void previsit( const ast::EnumInstType * ) { visit_children = false; }
-	void previsit( const ast::TraitInstType * ) { visit_children = false; }
-	void previsit( const ast::TypeInstType * ) { visit_children = false; }
-	void previsit( const ast::TupleType * ) { visit_children = false; }
-	void previsit( const ast::VarArgsType * ) { visit_children = false; }
-	void previsit( const ast::ZeroType * ) { visit_children = false; }
-	void previsit( const ast::OneType * ) { visit_children = false; }
-};
-
-} // anonymous namespace
-
-const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) {
-	ast::Pass< FixFunction > fixer;
-	dwt = dwt->accept( fixer );
-	isVoid |= fixer.core.isVoid;
-	return dwt;
-}
-
-const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) {
-	ast::Pass< FixFunction > fixer;
-	type = type->accept( fixer );
-	isVoid |= fixer.core.isVoid;
-	return type;
-}
-
-} // namespace SymTab
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/FixFunction.cpp
===================================================================
--- src/SymTab/FixFunction.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/FixFunction.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,93 @@
+//
+// 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.
+//
+// FixFunction.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 16:19:49 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Tue Jul 12 14:28:00 2022
+// Update Count     : 7
+//
+
+#include "FixFunction.hpp"
+
+#include <list>                   // for list
+
+#include "AST/Decl.hpp"
+#include "AST/Pass.hpp"
+#include "AST/Type.hpp"
+#include "Common/Utility.hpp"     // for copy
+
+namespace SymTab {
+
+namespace {
+
+struct FixFunction final : public ast::WithShortCircuiting {
+	bool isVoid = false;
+
+	void previsit( const ast::FunctionDecl * ) { visit_children = false; }
+
+	const ast::DeclWithType * postvisit( const ast::FunctionDecl * func ) {
+		// Cannot handle cases with asserions.
+		assert( func->assertions.empty() );
+		return new ast::ObjectDecl{
+			func->location, func->name, new ast::PointerType( func->type ), nullptr,
+			func->storage, func->linkage, nullptr, copy( func->attributes ) };
+	}
+
+	void previsit( const ast::ArrayType * ) { visit_children = false; }
+
+	const ast::Type * postvisit( const ast::ArrayType * array ) {
+		return new ast::PointerType{
+			array->base, array->dimension, array->isVarLen, array->isStatic,
+			array->qualifiers };
+	}
+
+	void previsit( const ast::FunctionType * ) { visit_children = false; }
+
+	const ast::Type * postvisit( const ast::FunctionType * type ) {
+		return new ast::PointerType( type );
+	}
+
+	void previsit( const ast::VoidType * ) { isVoid = true; }
+
+	void previsit( const ast::BasicType * ) { visit_children = false; }
+	void previsit( const ast::PointerType * ) { visit_children = false; }
+	void previsit( const ast::StructInstType * ) { visit_children = false; }
+	void previsit( const ast::UnionInstType * ) { visit_children = false; }
+	void previsit( const ast::EnumInstType * ) { visit_children = false; }
+	void previsit( const ast::TraitInstType * ) { visit_children = false; }
+	void previsit( const ast::TypeInstType * ) { visit_children = false; }
+	void previsit( const ast::TupleType * ) { visit_children = false; }
+	void previsit( const ast::VarArgsType * ) { visit_children = false; }
+	void previsit( const ast::ZeroType * ) { visit_children = false; }
+	void previsit( const ast::OneType * ) { visit_children = false; }
+};
+
+} // anonymous namespace
+
+const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid ) {
+	ast::Pass< FixFunction > fixer;
+	dwt = dwt->accept( fixer );
+	isVoid |= fixer.core.isVoid;
+	return dwt;
+}
+
+const ast::Type * fixFunction( const ast::Type * type, bool & isVoid ) {
+	ast::Pass< FixFunction > fixer;
+	type = type->accept( fixer );
+	isVoid |= fixer.core.isVoid;
+	return type;
+}
+
+} // namespace SymTab
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/FixFunction.h
===================================================================
--- src/SymTab/FixFunction.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,36 +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.
-//
-// FixFunction.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 17:02:08 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Tue Jul 12 14:19:00 2022
-// Update Count     : 5
-//
-
-#pragma once
-
-namespace ast {
-	class DeclWithType;
-	class Type;
-}
-
-namespace SymTab {
-
-/// Returns declaration with function and array types replaced by equivalent pointer types.
-/// Sets isVoid to true if type is void.
-const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
-const ast::Type * fixFunction( const ast::Type * type, bool & isVoid );
-
-} // namespace SymTab
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/FixFunction.hpp
===================================================================
--- src/SymTab/FixFunction.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/FixFunction.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,36 @@
+//
+// 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.
+//
+// FixFunction.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 17:02:08 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Tue Jul 12 14:19:00 2022
+// Update Count     : 5
+//
+
+#pragma once
+
+namespace ast {
+	class DeclWithType;
+	class Type;
+}
+
+namespace SymTab {
+
+/// Returns declaration with function and array types replaced by equivalent pointer types.
+/// Sets isVoid to true if type is void.
+const ast::DeclWithType * fixFunction( const ast::DeclWithType * dwt, bool & isVoid );
+const ast::Type * fixFunction( const ast::Type * type, bool & isVoid );
+
+} // namespace SymTab
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/GenImplicitCall.cpp
===================================================================
--- src/SymTab/GenImplicitCall.cpp	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ src/SymTab/GenImplicitCall.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -23,7 +23,7 @@
 #include "AST/Stmt.hpp"                  // for ExprStmt
 #include "AST/Type.hpp"                  // for ArrayType, BasicType, ...
-#include "CodeGen/OperatorTable.h"       // for isCtorDtor
-#include "Common/UniqueName.h"           // for UniqueName
-#include "Common/utility.h"              // for splice
+#include "CodeGen/OperatorTable.hpp"     // for isCtorDtor
+#include "Common/UniqueName.hpp"         // for UniqueName
+#include "Common/Utility.hpp"            // for splice
 
 namespace SymTab {
Index: src/SymTab/GenImplicitCall.hpp
===================================================================
--- src/SymTab/GenImplicitCall.hpp	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ src/SymTab/GenImplicitCall.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,5 +16,5 @@
 #pragma once
 
-#include "InitTweak/InitTweak.h"  // for InitExpander
+#include "InitTweak/InitTweak.hpp"  // for InitExpander
 
 namespace SymTab {
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,374 +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.
-//
-// Mangler.cc --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 21:40:29 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Fri Oct 21 16:18:00 2022
-// Update Count     : 75
-//
-#include "Mangler.h"
-
-#include <algorithm>                     // for copy, transform
-#include <cassert>                       // for assert, assertf
-#include <functional>                    // for const_mem_fun_t, mem_fun
-#include <iterator>                      // for ostream_iterator, back_insert_ite...
-#include <list>                          // for _List_iterator, list, _List_const...
-#include <string>                        // for string, char_traits, operator<<
-
-#include "AST/Pass.hpp"
-#include "CodeGen/OperatorTable.h"       // for OperatorInfo, operatorLookup
-#include "Common/ToString.hpp"           // for toCString
-#include "Common/SemanticError.h"        // for SemanticError
-
-namespace Mangle {
-
-namespace {
-
-/// Mangles names to a unique C identifier.
-struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
-	Mangler( Mangle::Mode mode );
-	Mangler( const Mangler & ) = delete;
-
-	void previsit( const ast::Node * ) { visit_children = false; }
-
-	void postvisit( const ast::ObjectDecl * declaration );
-	void postvisit( const ast::FunctionDecl * declaration );
-	void postvisit( const ast::TypeDecl * declaration );
-
-	void postvisit( const ast::VoidType * voidType );
-	void postvisit( const ast::BasicType * basicType );
-	void postvisit( const ast::PointerType * pointerType );
-	void postvisit( const ast::ArrayType * arrayType );
-	void postvisit( const ast::ReferenceType * refType );
-	void postvisit( const ast::FunctionType * functionType );
-	void postvisit( const ast::StructInstType * aggregateUseType );
-	void postvisit( const ast::UnionInstType * aggregateUseType );
-	void postvisit( const ast::EnumInstType * aggregateUseType );
-	void postvisit( const ast::TypeInstType * aggregateUseType );
-	void postvisit( const ast::TraitInstType * inst );
-	void postvisit( const ast::TupleType * tupleType );
-	void postvisit( const ast::VarArgsType * varArgsType );
-	void postvisit( const ast::ZeroType * zeroType );
-	void postvisit( const ast::OneType * oneType );
-	void postvisit( const ast::QualifiedType * qualType );
-	void postvisit( const ast::EnumAttrType * posType );
-
-	/// The result is the current constructed mangled name.
-	std::string result() const { return mangleName; }
-private:
-	std::string mangleName;         ///< Mangled name being constructed
-	typedef std::map< std::string, std::pair< int, int > > VarMapType;
-	VarMapType varNums;             ///< Map of type variables to indices
-	int nextVarNum;                 ///< Next type variable index
-	bool isTopLevel;                ///< Is the Mangler at the top level
-	bool mangleOverridable;         ///< Specially mangle overridable built-in methods
-	bool typeMode;                  ///< Produce a unique mangled name for a type
-	bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
-	bool inFunctionType = false;    ///< Include type qualifiers if false.
-	bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
-
-private:
-	Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
-		int nextVarNum, const VarMapType& varNums );
-	friend class ast::Pass<Mangler>;
-
-private:
-	void mangleDecl( const ast::DeclWithType *declaration );
-	void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
-
-	void printQualifiers( const ast::Type *type );
-}; // Mangler
-
-Mangler::Mangler( Mangle::Mode mode )
-	: nextVarNum( 0 ), isTopLevel( true ),
-	mangleOverridable  ( ! mode.no_overrideable   ),
-	typeMode           (   mode.type              ),
-	mangleGenericParams( ! mode.no_generic_params ) {}
-
-Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
-	int nextVarNum, const VarMapType& varNums )
-	: varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
-	mangleOverridable( mangleOverridable ), typeMode( typeMode ),
-	mangleGenericParams( mangleGenericParams ) {}
-
-void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
-	bool wasTopLevel = isTopLevel;
-	if ( isTopLevel ) {
-		varNums.clear();
-		nextVarNum = 0;
-		isTopLevel = false;
-	}
-	mangleName += Encoding::manglePrefix;
-	if ( auto opInfo = CodeGen::operatorLookup( decl->name ) ) {
-		mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
-	} else {
-		mangleName += std::to_string( decl->name.size() ) + decl->name;
-	}
-	decl->get_type()->accept( *visitor );
-	if ( mangleOverridable && decl->linkage.is_overrideable ) {
-		// want to be able to override autogenerated and intrinsic routines,
-		// so they need a different name mangling
-		if ( decl->linkage == ast::Linkage::AutoGen ) {
-			mangleName += Encoding::autogen;
-		} else if ( decl->linkage == ast::Linkage::Intrinsic ) {
-			mangleName += Encoding::intrinsic;
-		} else {
-			// if we add another kind of overridable function, this has to change
-			assert( false && "unknown overrideable linkage" );
-		}
-	}
-	isTopLevel = wasTopLevel;
-}
-
-void Mangler::postvisit( const ast::ObjectDecl * decl ) {
-	mangleDecl( decl );
-}
-
-void Mangler::postvisit( const ast::FunctionDecl * decl ) {
-	mangleDecl( decl );
-}
-
-void Mangler::postvisit( const ast::VoidType * voidType ) {
-	printQualifiers( voidType );
-	mangleName += Encoding::void_t;
-}
-
-void Mangler::postvisit( const ast::BasicType * basicType ) {
-	printQualifiers( basicType );
-	assertf( basicType->kind < ast::BasicKind::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
-	mangleName += Encoding::basicTypes[ basicType->kind ];
-}
-
-void Mangler::postvisit( const ast::PointerType * pointerType ) {
-	printQualifiers( pointerType );
-	// Mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers.
-	if ( !pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
-	maybe_accept( pointerType->base.get(), *visitor );
-}
-
-void Mangler::postvisit( const ast::ArrayType * arrayType ) {
-	// TODO: encode dimension
-	printQualifiers( arrayType );
-	mangleName += Encoding::array + "0";
-	arrayType->base->accept( *visitor );
-}
-
-void Mangler::postvisit( const ast::ReferenceType * refType ) {
-	// Don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
-	// Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
-	// by pretending every reference type is a function parameter.
-	GuardValue( inFunctionType ) = true;
-	printQualifiers( refType );
-	refType->base->accept( *visitor );
-}
-
-void Mangler::postvisit( const ast::FunctionType * functionType ) {
-	printQualifiers( functionType );
-	mangleName += Encoding::function;
-	// Turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
-	// since qualifiers on outermost parameter type do not differentiate function types, e.g.,
-	// void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different.
-	GuardValue( inFunctionType ) = true;
-	if (functionType->returns.empty()) mangleName += Encoding::void_t;
-	else accept_each( functionType->returns, *visitor );
-	mangleName += "_";
-	accept_each( functionType->params, *visitor );
-	mangleName += "_";
-}
-
-void Mangler::mangleRef(
-		const ast::BaseInstType * refType, const std::string & prefix ) {
-	printQualifiers( refType );
-
-	mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
-
-	if ( mangleGenericParams && ! refType->params.empty() ) {
-		mangleName += "_";
-		for ( const ast::Expr * param : refType->params ) {
-			auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
-			assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
-			paramType->type->accept( *visitor );
-		}
-		mangleName += "_";
-	}
-}
-
-void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
-	mangleRef( aggregateUseType, Encoding::struct_t );
-}
-
-void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
-	mangleRef( aggregateUseType, Encoding::union_t );
-}
-
-void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
-	mangleRef( aggregateUseType, Encoding::enum_t );
-}
-
-void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
-	VarMapType::iterator varNum = varNums.find( typeInst->name );
-	if ( varNum == varNums.end() ) {
-		mangleRef( typeInst, Encoding::type );
-	} else {
-		printQualifiers( typeInst );
-		// Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
-		//   forall(dtype T) void f(T);
-		//   forall(dtype S) void f(S);
-		// are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
-		// are first found and prefixing with the appropriate encoding for the type class.
-		assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
-		mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
-	}
-}
-
-void Mangler::postvisit( const ast::TraitInstType * inst ) {
-	printQualifiers( inst );
-	mangleName += std::to_string( inst->name.size() ) + inst->name;
-}
-
-void Mangler::postvisit( const ast::TupleType * tupleType ) {
-	printQualifiers( tupleType );
-	mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
-	accept_each( tupleType->types, *visitor );
-}
-
-void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
-	printQualifiers( varArgsType );
-	static const std::string vargs = "__builtin_va_list";
-	mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
-}
-
-void Mangler::postvisit( const ast::ZeroType * ) {
-	mangleName += Encoding::zero;
-}
-
-void Mangler::postvisit( const ast::OneType * ) {
-	mangleName += Encoding::one;
-}
-
-void Mangler::postvisit( const ast::QualifiedType * qualType ) {
-	bool inqual = inQualifiedType;
-	if ( !inqual ) {
-		// N marks the start of a qualified type.
-		inQualifiedType = true;
-		mangleName += Encoding::qualifiedTypeStart;
-	}
-	qualType->parent->accept( *visitor );
-	qualType->child->accept( *visitor );
-	if ( !inqual ) {
-		// E marks the end of a qualified type.
-		inQualifiedType = false;
-		mangleName += Encoding::qualifiedTypeEnd;
-	}
-}
-
-void Mangler::postvisit( const ast::TypeDecl * decl ) {
-	// TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
-	// fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
-	// Note: The current scheme may already work correctly for this case, I have not thought about this deeply
-	// and the case has not yet come up in practice. Alternatively, if not then this code can be removed
-	// aside from the assert false.
-	assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
-	assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
-	mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
-}
-
-void Mangler::postvisit( const ast::EnumAttrType * enumAttr ) {
-	postvisit( enumAttr->instance );
-	// mangleName += "_pos";
-	switch ( enumAttr->attr )
-	{
-		case ast::EnumAttribute::Label:
-			mangleName += "_label_";
-			break;
-		case ast::EnumAttribute::Posn:
-			mangleName += "_posn_";
-			break;
-		case ast::EnumAttribute::Value:
-			mangleName += "_value_";
-			break;
-	}
-
-}
-
-// For debugging:
-__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
-	for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
-		os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
-	}
-}
-
-void Mangler::printQualifiers( const ast::Type * type ) {
-	// Skip if not including qualifiers:
-	if ( typeMode ) return;
-	auto funcType = dynamic_cast<const ast::FunctionType *>( type );
-	if ( funcType && !funcType->forall.empty() ) {
-		std::list< std::string > assertionNames;
-		int dcount = 0, fcount = 0, vcount = 0, acount = 0;
-		mangleName += Encoding::forall;
-		for ( auto & decl : funcType->forall ) {
-			switch ( decl->kind ) {
-			case ast::TypeDecl::Dtype:
-				dcount++;
-				break;
-			case ast::TypeDecl::Ftype:
-				fcount++;
-				break;
-			case ast::TypeDecl::Ttype:
-				vcount++;
-				break;
-			default:
-				assertf( false, "unimplemented kind for type variable %s", Encoding::typeVariables[decl->kind].c_str() );
-			}
-			varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
-		}
-		for ( auto & assert : funcType->assertions ) {
-			assertionNames.push_back( ast::Pass<Mangler>::read(
-				assert->var.get(),
-				mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
-			acount++;
-		}
-		mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
-		for ( const auto & a : assertionNames ) mangleName += a;
-		mangleName += "_";
-	}
-	if ( !inFunctionType ) {
-		// These qualifiers do not distinguish the outermost type of a function parameter.
-		if ( type->is_const() ) {
-			mangleName += Encoding::qualifiers.at( ast::CV::Const );
-		}
-		if ( type->is_volatile() ) {
-			mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
-		}
-		if ( type->is_atomic() ) {
-			mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
-		}
-	}
-	if ( type->is_mutex() ) {
-		mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
-	}
-	if ( inFunctionType ) {
-		// Turn off inFunctionType so that types can be differentiated for nested qualifiers.
-		GuardValue( inFunctionType ) = false;
-	}
-}
-
-} // namespace
-
-std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
-	return ast::Pass<Mangler>::read( decl, mode );
-}
-
-} // namespace Mangle
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/Mangler.cpp
===================================================================
--- src/SymTab/Mangler.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/Mangler.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,374 @@
+//
+// 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.
+//
+// Mangler.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 21:40:29 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Fri Oct 21 16:18:00 2022
+// Update Count     : 75
+//
+#include "Mangler.hpp"
+
+#include <algorithm>                     // for copy, transform
+#include <cassert>                       // for assert, assertf
+#include <functional>                    // for const_mem_fun_t, mem_fun
+#include <iterator>                      // for ostream_iterator, back_insert_ite...
+#include <list>                          // for _List_iterator, list, _List_const...
+#include <string>                        // for string, char_traits, operator<<
+
+#include "AST/Pass.hpp"
+#include "CodeGen/OperatorTable.hpp"     // for OperatorInfo, operatorLookup
+#include "Common/ToString.hpp"           // for toCString
+#include "Common/SemanticError.hpp"      // for SemanticError
+
+namespace Mangle {
+
+namespace {
+
+/// Mangles names to a unique C identifier.
+struct Mangler : public ast::WithShortCircuiting, public ast::WithVisitorRef<Mangler>, public ast::WithGuards {
+	Mangler( Mangle::Mode mode );
+	Mangler( const Mangler & ) = delete;
+
+	void previsit( const ast::Node * ) { visit_children = false; }
+
+	void postvisit( const ast::ObjectDecl * declaration );
+	void postvisit( const ast::FunctionDecl * declaration );
+	void postvisit( const ast::TypeDecl * declaration );
+
+	void postvisit( const ast::VoidType * voidType );
+	void postvisit( const ast::BasicType * basicType );
+	void postvisit( const ast::PointerType * pointerType );
+	void postvisit( const ast::ArrayType * arrayType );
+	void postvisit( const ast::ReferenceType * refType );
+	void postvisit( const ast::FunctionType * functionType );
+	void postvisit( const ast::StructInstType * aggregateUseType );
+	void postvisit( const ast::UnionInstType * aggregateUseType );
+	void postvisit( const ast::EnumInstType * aggregateUseType );
+	void postvisit( const ast::TypeInstType * aggregateUseType );
+	void postvisit( const ast::TraitInstType * inst );
+	void postvisit( const ast::TupleType * tupleType );
+	void postvisit( const ast::VarArgsType * varArgsType );
+	void postvisit( const ast::ZeroType * zeroType );
+	void postvisit( const ast::OneType * oneType );
+	void postvisit( const ast::QualifiedType * qualType );
+	void postvisit( const ast::EnumAttrType * posType );
+
+	/// The result is the current constructed mangled name.
+	std::string result() const { return mangleName; }
+private:
+	std::string mangleName;         ///< Mangled name being constructed
+	typedef std::map< std::string, std::pair< int, int > > VarMapType;
+	VarMapType varNums;             ///< Map of type variables to indices
+	int nextVarNum;                 ///< Next type variable index
+	bool isTopLevel;                ///< Is the Mangler at the top level
+	bool mangleOverridable;         ///< Specially mangle overridable built-in methods
+	bool typeMode;                  ///< Produce a unique mangled name for a type
+	bool mangleGenericParams;       ///< Include generic parameters in name mangling if true
+	bool inFunctionType = false;    ///< Include type qualifiers if false.
+	bool inQualifiedType = false;   ///< Add start/end delimiters around qualified type
+
+private:
+	Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
+		int nextVarNum, const VarMapType& varNums );
+	friend class ast::Pass<Mangler>;
+
+private:
+	void mangleDecl( const ast::DeclWithType *declaration );
+	void mangleRef( const ast::BaseInstType *refType, const std::string & prefix );
+
+	void printQualifiers( const ast::Type *type );
+}; // Mangler
+
+Mangler::Mangler( Mangle::Mode mode )
+	: nextVarNum( 0 ), isTopLevel( true ),
+	mangleOverridable  ( ! mode.no_overrideable   ),
+	typeMode           (   mode.type              ),
+	mangleGenericParams( ! mode.no_generic_params ) {}
+
+Mangler::Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams,
+	int nextVarNum, const VarMapType& varNums )
+	: varNums( varNums ), nextVarNum( nextVarNum ), isTopLevel( false ),
+	mangleOverridable( mangleOverridable ), typeMode( typeMode ),
+	mangleGenericParams( mangleGenericParams ) {}
+
+void Mangler::mangleDecl( const ast::DeclWithType * decl ) {
+	bool wasTopLevel = isTopLevel;
+	if ( isTopLevel ) {
+		varNums.clear();
+		nextVarNum = 0;
+		isTopLevel = false;
+	}
+	mangleName += Encoding::manglePrefix;
+	if ( auto opInfo = CodeGen::operatorLookup( decl->name ) ) {
+		mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
+	} else {
+		mangleName += std::to_string( decl->name.size() ) + decl->name;
+	}
+	decl->get_type()->accept( *visitor );
+	if ( mangleOverridable && decl->linkage.is_overrideable ) {
+		// want to be able to override autogenerated and intrinsic routines,
+		// so they need a different name mangling
+		if ( decl->linkage == ast::Linkage::AutoGen ) {
+			mangleName += Encoding::autogen;
+		} else if ( decl->linkage == ast::Linkage::Intrinsic ) {
+			mangleName += Encoding::intrinsic;
+		} else {
+			// if we add another kind of overridable function, this has to change
+			assert( false && "unknown overrideable linkage" );
+		}
+	}
+	isTopLevel = wasTopLevel;
+}
+
+void Mangler::postvisit( const ast::ObjectDecl * decl ) {
+	mangleDecl( decl );
+}
+
+void Mangler::postvisit( const ast::FunctionDecl * decl ) {
+	mangleDecl( decl );
+}
+
+void Mangler::postvisit( const ast::VoidType * voidType ) {
+	printQualifiers( voidType );
+	mangleName += Encoding::void_t;
+}
+
+void Mangler::postvisit( const ast::BasicType * basicType ) {
+	printQualifiers( basicType );
+	assertf( basicType->kind < ast::BasicKind::NUMBER_OF_BASIC_TYPES, "Unhandled basic type: %d", basicType->kind );
+	mangleName += Encoding::basicTypes[ basicType->kind ];
+}
+
+void Mangler::postvisit( const ast::PointerType * pointerType ) {
+	printQualifiers( pointerType );
+	// Mangle void (*f)() and void f() to the same name to prevent overloading on functions and function pointers.
+	if ( !pointerType->base.as<ast::FunctionType>() ) mangleName += Encoding::pointer;
+	maybe_accept( pointerType->base.get(), *visitor );
+}
+
+void Mangler::postvisit( const ast::ArrayType * arrayType ) {
+	// TODO: encode dimension
+	printQualifiers( arrayType );
+	mangleName += Encoding::array + "0";
+	arrayType->base->accept( *visitor );
+}
+
+void Mangler::postvisit( const ast::ReferenceType * refType ) {
+	// Don't print prefix (e.g. 'R') for reference types so that references and non-references do not overload.
+	// Further, do not print the qualifiers for a reference type (but do run printQualifers because of TypeDecls, etc.),
+	// by pretending every reference type is a function parameter.
+	GuardValue( inFunctionType ) = true;
+	printQualifiers( refType );
+	refType->base->accept( *visitor );
+}
+
+void Mangler::postvisit( const ast::FunctionType * functionType ) {
+	printQualifiers( functionType );
+	mangleName += Encoding::function;
+	// Turn on inFunctionType so that printQualifiers does not print most qualifiers for function parameters,
+	// since qualifiers on outermost parameter type do not differentiate function types, e.g.,
+	// void (*)(const int) and void (*)(int) are the same type, but void (*)(const int *) and void (*)(int *) are different.
+	GuardValue( inFunctionType ) = true;
+	if (functionType->returns.empty()) mangleName += Encoding::void_t;
+	else accept_each( functionType->returns, *visitor );
+	mangleName += "_";
+	accept_each( functionType->params, *visitor );
+	mangleName += "_";
+}
+
+void Mangler::mangleRef(
+		const ast::BaseInstType * refType, const std::string & prefix ) {
+	printQualifiers( refType );
+
+	mangleName += prefix + std::to_string( refType->name.length() ) + refType->name;
+
+	if ( mangleGenericParams && ! refType->params.empty() ) {
+		mangleName += "_";
+		for ( const ast::Expr * param : refType->params ) {
+			auto paramType = dynamic_cast< const ast::TypeExpr * >( param );
+			assertf(paramType, "Aggregate parameters should be type expressions: %s", toCString(param));
+			paramType->type->accept( *visitor );
+		}
+		mangleName += "_";
+	}
+}
+
+void Mangler::postvisit( const ast::StructInstType * aggregateUseType ) {
+	mangleRef( aggregateUseType, Encoding::struct_t );
+}
+
+void Mangler::postvisit( const ast::UnionInstType * aggregateUseType ) {
+	mangleRef( aggregateUseType, Encoding::union_t );
+}
+
+void Mangler::postvisit( const ast::EnumInstType * aggregateUseType ) {
+	mangleRef( aggregateUseType, Encoding::enum_t );
+}
+
+void Mangler::postvisit( const ast::TypeInstType * typeInst ) {
+	VarMapType::iterator varNum = varNums.find( typeInst->name );
+	if ( varNum == varNums.end() ) {
+		mangleRef( typeInst, Encoding::type );
+	} else {
+		printQualifiers( typeInst );
+		// Note: Can't use name here, since type variable names do not actually disambiguate a function, e.g.
+		//   forall(dtype T) void f(T);
+		//   forall(dtype S) void f(S);
+		// are equivalent and should mangle the same way. This is accomplished by numbering the type variables when they
+		// are first found and prefixing with the appropriate encoding for the type class.
+		assertf( varNum->second.second < ast::TypeDecl::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", varNum->second.second );
+		mangleName += Encoding::typeVariables[varNum->second.second] + std::to_string( varNum->second.first );
+	}
+}
+
+void Mangler::postvisit( const ast::TraitInstType * inst ) {
+	printQualifiers( inst );
+	mangleName += std::to_string( inst->name.size() ) + inst->name;
+}
+
+void Mangler::postvisit( const ast::TupleType * tupleType ) {
+	printQualifiers( tupleType );
+	mangleName += Encoding::tuple + std::to_string( tupleType->types.size() );
+	accept_each( tupleType->types, *visitor );
+}
+
+void Mangler::postvisit( const ast::VarArgsType * varArgsType ) {
+	printQualifiers( varArgsType );
+	static const std::string vargs = "__builtin_va_list";
+	mangleName += Encoding::type + std::to_string( vargs.size() ) + vargs;
+}
+
+void Mangler::postvisit( const ast::ZeroType * ) {
+	mangleName += Encoding::zero;
+}
+
+void Mangler::postvisit( const ast::OneType * ) {
+	mangleName += Encoding::one;
+}
+
+void Mangler::postvisit( const ast::QualifiedType * qualType ) {
+	bool inqual = inQualifiedType;
+	if ( !inqual ) {
+		// N marks the start of a qualified type.
+		inQualifiedType = true;
+		mangleName += Encoding::qualifiedTypeStart;
+	}
+	qualType->parent->accept( *visitor );
+	qualType->child->accept( *visitor );
+	if ( !inqual ) {
+		// E marks the end of a qualified type.
+		inQualifiedType = false;
+		mangleName += Encoding::qualifiedTypeEnd;
+	}
+}
+
+void Mangler::postvisit( const ast::TypeDecl * decl ) {
+	// TODO: is there any case where mangling a TypeDecl makes sense? If so, this code needs to be
+	// fixed to ensure that two TypeDecls mangle to the same name when they are the same type and vice versa.
+	// Note: The current scheme may already work correctly for this case, I have not thought about this deeply
+	// and the case has not yet come up in practice. Alternatively, if not then this code can be removed
+	// aside from the assert false.
+	assertf(false, "Mangler should not visit typedecl: %s", toCString(decl));
+	assertf( decl->kind < ast::TypeDecl::Kind::NUMBER_OF_KINDS, "Unhandled type variable kind: %d", decl->kind );
+	mangleName += Encoding::typeVariables[ decl->kind ] + std::to_string( decl->name.length() ) + decl->name;
+}
+
+void Mangler::postvisit( const ast::EnumAttrType * enumAttr ) {
+	postvisit( enumAttr->instance );
+	// mangleName += "_pos";
+	switch ( enumAttr->attr )
+	{
+		case ast::EnumAttribute::Label:
+			mangleName += "_label_";
+			break;
+		case ast::EnumAttribute::Posn:
+			mangleName += "_posn_";
+			break;
+		case ast::EnumAttribute::Value:
+			mangleName += "_value_";
+			break;
+	}
+
+}
+
+// For debugging:
+__attribute__((unused)) void printVarMap( const std::map< std::string, std::pair< int, int > > &varMap, std::ostream &os ) {
+	for ( std::map< std::string, std::pair< int, int > >::const_iterator i = varMap.begin(); i != varMap.end(); ++i ) {
+		os << i->first << "(" << i->second.first << "/" << i->second.second << ")" << std::endl;
+	}
+}
+
+void Mangler::printQualifiers( const ast::Type * type ) {
+	// Skip if not including qualifiers:
+	if ( typeMode ) return;
+	auto funcType = dynamic_cast<const ast::FunctionType *>( type );
+	if ( funcType && !funcType->forall.empty() ) {
+		std::list< std::string > assertionNames;
+		int dcount = 0, fcount = 0, vcount = 0, acount = 0;
+		mangleName += Encoding::forall;
+		for ( auto & decl : funcType->forall ) {
+			switch ( decl->kind ) {
+			case ast::TypeDecl::Dtype:
+				dcount++;
+				break;
+			case ast::TypeDecl::Ftype:
+				fcount++;
+				break;
+			case ast::TypeDecl::Ttype:
+				vcount++;
+				break;
+			default:
+				assertf( false, "unimplemented kind for type variable %s", Encoding::typeVariables[decl->kind].c_str() );
+			}
+			varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
+		}
+		for ( auto & assert : funcType->assertions ) {
+			assertionNames.push_back( ast::Pass<Mangler>::read(
+				assert->var.get(),
+				mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
+			acount++;
+		}
+		mangleName += std::to_string( dcount ) + "_" + std::to_string( fcount ) + "_" + std::to_string( vcount ) + "_" + std::to_string( acount ) + "_";
+		for ( const auto & a : assertionNames ) mangleName += a;
+		mangleName += "_";
+	}
+	if ( !inFunctionType ) {
+		// These qualifiers do not distinguish the outermost type of a function parameter.
+		if ( type->is_const() ) {
+			mangleName += Encoding::qualifiers.at( ast::CV::Const );
+		}
+		if ( type->is_volatile() ) {
+			mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
+		}
+		if ( type->is_atomic() ) {
+			mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
+		}
+	}
+	if ( type->is_mutex() ) {
+		mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
+	}
+	if ( inFunctionType ) {
+		// Turn off inFunctionType so that types can be differentiated for nested qualifiers.
+		GuardValue( inFunctionType ) = false;
+	}
+}
+
+} // namespace
+
+std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
+	return ast::Pass<Mangler>::read( decl, mode );
+}
+
+} // namespace Mangle
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,104 +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.
-//
-// Mangler.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 21:44:03 2015
-// Last Modified By : Andrew Beach
-// Last Modified On : Thu Oct 27 11:58:00 2022
-// Update Count     : 16
-//
-
-#pragma once
-
-#include <map>                // for map, map<>::value_compare
-#include <sstream>            // for ostringstream
-#include <string>             // for string
-#include <utility>            // for pair
-
-#include "AST/Bitfield.hpp"
-
-// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
-// The CFA name mangling scheme is based closely on the itanium C++ name mangling scheme, with the following key differences:
-// * Variable names are also mangled to include type information, not just functions
-// * CFA does not have template expansion, so the rules for function specialization do not apply.
-// * CFA instead has to handle type parameters and assertion parameters.
-// * Currently name compression is not implemented.
-
-namespace ast {
-	class Node;
-}
-
-namespace Mangle {
-
-/// Bitflags for mangle Mode:
-enum {
-	NoOverrideable  = 1 << 0,
-	Type            = 1 << 1,
-	NoGenericParams = 1 << 2
-};
-
-/// Bitflag type for mangle Mode:
-struct mangle_flags {
-	union {
-		unsigned int val;
-		struct {
-			bool no_overrideable   : 1;
-			bool type              : 1;
-			bool no_generic_params : 1;
-		};
-	};
-
-	constexpr mangle_flags( unsigned int val ) : val(val) {}
-};
-
-using Mode = bitfield<mangle_flags>;
-
-/// Mangle declaration name.
-std::string mangle( const ast::Node * decl, Mode mode = {} );
-
-/// Most common mangle configuration for types.
-static inline std::string mangleType( const ast::Node * type ) {
-	return mangle( type, { NoOverrideable | Type } );
-}
-
-/// The substrings used in name mangling and demangling.
-namespace Encoding {
-	extern const std::string manglePrefix;
-	extern const std::string basicTypes[];
-	extern const std::map<int, std::string> qualifiers;
-
-	extern const std::string void_t;
-	extern const std::string zero;
-	extern const std::string one;
-
-	extern const std::string function;
-	extern const std::string tuple;
-	extern const std::string pointer;
-	extern const std::string array;
-	extern const std::string qualifiedTypeStart;
-	extern const std::string qualifiedTypeEnd;
-
-	extern const std::string forall;
-	extern const std::string typeVariables[];
-
-	extern const std::string struct_t;
-	extern const std::string union_t;
-	extern const std::string enum_t;
-	extern const std::string type;
-
-	extern const std::string autogen;
-	extern const std::string intrinsic;
-}
-
-}
-
-// Local Variables: //
-// tab-width: 4 //
-// mode: c++ //
-// compile-command: "make install" //
-// End: //
Index: src/SymTab/Mangler.hpp
===================================================================
--- src/SymTab/Mangler.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/Mangler.hpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,104 @@
+//
+// 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.
+//
+// Mangler.hpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 21:44:03 2015
+// Last Modified By : Andrew Beach
+// Last Modified On : Thu Oct 27 11:58:00 2022
+// Update Count     : 16
+//
+
+#pragma once
+
+#include <map>                // for map, map<>::value_compare
+#include <sstream>            // for ostringstream
+#include <string>             // for string
+#include <utility>            // for pair
+
+#include "AST/Bitfield.hpp"
+
+// https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling
+// The CFA name mangling scheme is based closely on the itanium C++ name mangling scheme, with the following key differences:
+// * Variable names are also mangled to include type information, not just functions
+// * CFA does not have template expansion, so the rules for function specialization do not apply.
+// * CFA instead has to handle type parameters and assertion parameters.
+// * Currently name compression is not implemented.
+
+namespace ast {
+	class Node;
+}
+
+namespace Mangle {
+
+/// Bitflags for mangle Mode:
+enum {
+	NoOverrideable  = 1 << 0,
+	Type            = 1 << 1,
+	NoGenericParams = 1 << 2
+};
+
+/// Bitflag type for mangle Mode:
+struct mangle_flags {
+	union {
+		unsigned int val;
+		struct {
+			bool no_overrideable   : 1;
+			bool type              : 1;
+			bool no_generic_params : 1;
+		};
+	};
+
+	constexpr mangle_flags( unsigned int val ) : val(val) {}
+};
+
+using Mode = bitfield<mangle_flags>;
+
+/// Mangle declaration name.
+std::string mangle( const ast::Node * decl, Mode mode = {} );
+
+/// Most common mangle configuration for types.
+static inline std::string mangleType( const ast::Node * type ) {
+	return mangle( type, { NoOverrideable | Type } );
+}
+
+/// The substrings used in name mangling and demangling.
+namespace Encoding {
+	extern const std::string manglePrefix;
+	extern const std::string basicTypes[];
+	extern const std::map<int, std::string> qualifiers;
+
+	extern const std::string void_t;
+	extern const std::string zero;
+	extern const std::string one;
+
+	extern const std::string function;
+	extern const std::string tuple;
+	extern const std::string pointer;
+	extern const std::string array;
+	extern const std::string qualifiedTypeStart;
+	extern const std::string qualifiedTypeEnd;
+
+	extern const std::string forall;
+	extern const std::string typeVariables[];
+
+	extern const std::string struct_t;
+	extern const std::string union_t;
+	extern const std::string enum_t;
+	extern const std::string type;
+
+	extern const std::string autogen;
+	extern const std::string intrinsic;
+}
+
+}
+
+// Local Variables: //
+// tab-width: 4 //
+// mode: c++ //
+// compile-command: "make install" //
+// End: //
Index: src/SymTab/ManglerCommon.cc
===================================================================
--- src/SymTab/ManglerCommon.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,129 +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.
-//
-// Mangler.h --
-//
-// Author           : Richard C. Bilson
-// Created On       : Sun May 17 21:44:03 2015
-// Last Modified By : Peter A. Buhr
-// Last Modified On : Mon Jan 11 21:23:10 2021
-// Update Count     : 29
-//
-
-#include "Mangler.h"
-
-#include "AST/Decl.hpp"
-#include "AST/Type.hpp"
-
-namespace Mangle {
-
-namespace Encoding {
-
-const std::string manglePrefix = "_X";
-
-// GENERATED START, DO NOT EDIT
-// GENERATED BY BasicTypes-gen.cpp
-// NOTES ON MANGLING:
-// * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems.
-// * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble.
-// * Mangling for non-standard complex types is by best guess
-// * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above.
-// * unused mangling identifiers:
-//   - "z" ellipsis
-//   - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)
-//   - "De" IEEE 754r 128-bit decimal floating point
-//   - "Df" IEEE 754r 32-bit decimal floating point
-//   - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)
-//   - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)
-//   - "Di" char32_t
-//   - "Ds" char16_t
-const std::string basicTypes[ast::BasicKind::NUMBER_OF_BASIC_TYPES] = {
-	"b",        // _Bool
-	"c",        // char
-	"a",        // signed char
-	"h",        // unsigned char
-	"s",        // signed short int
-	"t",        // unsigned short int
-	"i",        // signed int
-	"j",        // unsigned int
-	"l",        // signed long int
-	"m",        // unsigned long int
-	"x",        // signed long long int
-	"y",        // unsigned long long int
-	"n",        // __int128
-	"o",        // unsigned __int128
-	"DF16_",    // _Float16
-	"CDF16_",   // _Float16 _Complex
-	"DF32_",    // _Float32
-	"CDF32_",   // _Float32 _Complex
-	"f",        // float
-	"Cf",       // float _Complex
-	"DF32x_",   // _Float32x
-	"CDF32x_",  // _Float32x _Complex
-	"DF64_",    // _Float64
-	"CDF64_",   // _Float64 _Complex
-	"d",        // double
-	"Cd",       // double _Complex
-	"DF64x_",   // _Float64x
-	"CDF64x_",  // _Float64x _Complex
-	"Dq",       // __float80
-	"DF128_",   // _Float128
-	"CDF128_",  // _Float128 _Complex
-	"g",        // __float128
-	"e",        // long double
-	"Ce",       // long double _Complex
-	"DF128x_",  // _Float128x
-	"CDF128x_", // _Float128x _Complex
-}; // basicTypes
-// GENERATED END
-static_assert(
-	sizeof(basicTypes) / sizeof(basicTypes[0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES,
-	"Each basic type kind should have a corresponding mangler letter"
-);
-
-const std::map<int, std::string> qualifiers = {
-	{ ast::CV::Const, "K" },
-	{ ast::CV::Volatile, "V" },
-	{ ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
-	{ ast::CV::Mutex, "X" },
-};
-
-const std::string void_t = "v";
-const std::string zero = "Z";
-const std::string one = "O";
-
-const std::string function = "F";
-const std::string tuple = "T";
-const std::string pointer = "P";
-const std::string array = "A";
-const std::string qualifiedTypeStart = "N";
-const std::string qualifiedTypeEnd = "E";
-
-const std::string forall = "Q";
-const std::string typeVariables[] = {
-	"BD", // dtype
-	"BDS", // dtype + sized
-	"BO", // otype
-	"BF", // ftype
-	"BT", // ttype
-	"BAL", // array length type
-};
-static_assert(
-	sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
-	"Each type variable kind should have a corresponding mangler prefix"
-);
-
-const std::string struct_t = "S";
-const std::string union_t = "U";
-const std::string enum_t = "M";
-const std::string type = "Y";
-
-const std::string autogen = "autogen__";
-const std::string intrinsic = "intrinsic__";
-
-} // namespace Encoding
-
-} // namespace Mangle
Index: src/SymTab/ManglerCommon.cpp
===================================================================
--- src/SymTab/ManglerCommon.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/ManglerCommon.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,129 @@
+//
+// 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.
+//
+// ManglerCommon.cpp --
+//
+// Author           : Richard C. Bilson
+// Created On       : Sun May 17 21:44:03 2015
+// Last Modified By : Peter A. Buhr
+// Last Modified On : Mon Jan 11 21:23:10 2021
+// Update Count     : 29
+//
+
+#include "Mangler.hpp"
+
+#include "AST/Decl.hpp"
+#include "AST/Type.hpp"
+
+namespace Mangle {
+
+namespace Encoding {
+
+const std::string manglePrefix = "_X";
+
+// GENERATED START, DO NOT EDIT
+// GENERATED BY BasicTypes-gen.cpp
+// NOTES ON MANGLING:
+// * Itanium spec says that Float80 encodes to "e" (like LongDouble), but the distinct lengths cause resolution problems.
+// * Float128 is supposed to encode to "g", but I wanted it to mangle equal to LongDouble.
+// * Mangling for non-standard complex types is by best guess
+// * _FloatN is supposed to encode as "DF"N"_"; modified for same reason as above.
+// * unused mangling identifiers:
+//   - "z" ellipsis
+//   - "Dd" IEEE 754r 64-bit decimal floating point (borrowed for _Float32x)
+//   - "De" IEEE 754r 128-bit decimal floating point
+//   - "Df" IEEE 754r 32-bit decimal floating point
+//   - "Dh" IEEE 754r 16-bit decimal floating point (borrowed for _Float16)
+//   - "DF"N"_" ISO/IEC TS 18661 N-bit binary floating point (_FloatN)
+//   - "Di" char32_t
+//   - "Ds" char16_t
+const std::string basicTypes[ast::BasicKind::NUMBER_OF_BASIC_TYPES] = {
+	"b",        // _Bool
+	"c",        // char
+	"a",        // signed char
+	"h",        // unsigned char
+	"s",        // signed short int
+	"t",        // unsigned short int
+	"i",        // signed int
+	"j",        // unsigned int
+	"l",        // signed long int
+	"m",        // unsigned long int
+	"x",        // signed long long int
+	"y",        // unsigned long long int
+	"n",        // __int128
+	"o",        // unsigned __int128
+	"DF16_",    // _Float16
+	"CDF16_",   // _Float16 _Complex
+	"DF32_",    // _Float32
+	"CDF32_",   // _Float32 _Complex
+	"f",        // float
+	"Cf",       // float _Complex
+	"DF32x_",   // _Float32x
+	"CDF32x_",  // _Float32x _Complex
+	"DF64_",    // _Float64
+	"CDF64_",   // _Float64 _Complex
+	"d",        // double
+	"Cd",       // double _Complex
+	"DF64x_",   // _Float64x
+	"CDF64x_",  // _Float64x _Complex
+	"Dq",       // __float80
+	"DF128_",   // _Float128
+	"CDF128_",  // _Float128 _Complex
+	"g",        // __float128
+	"e",        // long double
+	"Ce",       // long double _Complex
+	"DF128x_",  // _Float128x
+	"CDF128x_", // _Float128x _Complex
+}; // basicTypes
+// GENERATED END
+static_assert(
+	sizeof(basicTypes) / sizeof(basicTypes[0]) == ast::BasicKind::NUMBER_OF_BASIC_TYPES,
+	"Each basic type kind should have a corresponding mangler letter"
+);
+
+const std::map<int, std::string> qualifiers = {
+	{ ast::CV::Const, "K" },
+	{ ast::CV::Volatile, "V" },
+	{ ast::CV::Atomic, "DA" }, // A is array, so need something unique for atmoic. For now, go with multiletter DA
+	{ ast::CV::Mutex, "X" },
+};
+
+const std::string void_t = "v";
+const std::string zero = "Z";
+const std::string one = "O";
+
+const std::string function = "F";
+const std::string tuple = "T";
+const std::string pointer = "P";
+const std::string array = "A";
+const std::string qualifiedTypeStart = "N";
+const std::string qualifiedTypeEnd = "E";
+
+const std::string forall = "Q";
+const std::string typeVariables[] = {
+	"BD", // dtype
+	"BDS", // dtype + sized
+	"BO", // otype
+	"BF", // ftype
+	"BT", // ttype
+	"BAL", // array length type
+};
+static_assert(
+	sizeof(typeVariables) / sizeof(typeVariables[0]) == ast::TypeDecl::NUMBER_OF_KINDS,
+	"Each type variable kind should have a corresponding mangler prefix"
+);
+
+const std::string struct_t = "S";
+const std::string union_t = "U";
+const std::string enum_t = "M";
+const std::string type = "Y";
+
+const std::string autogen = "autogen__";
+const std::string intrinsic = "intrinsic__";
+
+} // namespace Encoding
+
+} // namespace Mangle
Index: src/SymTab/demangler.cc
===================================================================
--- src/SymTab/demangler.cc	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ 	(revision )
@@ -1,25 +1,0 @@
-#include "Demangle.h"
-#include <iostream>
-#include <fstream>
-
-void demangleAndPrint(const std::string & mangleName) {
-	char * demangleName = cforall_demangle(mangleName.c_str(), 0);
-	std::cout << mangleName << " => " << demangleName << std::endl;
-	free(demangleName);
-}
-
-int main(int argc, char * argv[]) {
-	char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt";
-	std::ifstream in(fileName);
-
-	std::string line;
-	while (std::getline(in, line)) {
-		if (line.empty()) {
-			std::cout << "=================================" << std::endl;
-		} else if (line[0] == '#') {
-			continue;
-		} else {
-			demangleAndPrint(line);
-		}
-	}
-}
Index: src/SymTab/demangler.cpp
===================================================================
--- src/SymTab/demangler.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
+++ src/SymTab/demangler.cpp	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -0,0 +1,25 @@
+#include "Demangle.hpp"
+#include <iostream>
+#include <fstream>
+
+void demangleAndPrint(const std::string & mangleName) {
+	char * demangleName = cforall_demangle(mangleName.c_str(), 0);
+	std::cout << mangleName << " => " << demangleName << std::endl;
+	free(demangleName);
+}
+
+int main(int argc, char * argv[]) {
+	char const * fileName = (1 < argc) ? argv[1] : "in-demangle.txt";
+	std::ifstream in(fileName);
+
+	std::string line;
+	while (std::getline(in, line)) {
+		if (line.empty()) {
+			std::cout << "=================================" << std::endl;
+		} else if (line[0] == '#') {
+			continue;
+		} else {
+			demangleAndPrint(line);
+		}
+	}
+}
Index: src/SymTab/module.mk
===================================================================
--- src/SymTab/module.mk	(revision b2ea0cddcfd03f2242eda9e8d588f2ce92daf9a7)
+++ src/SymTab/module.mk	(revision c92bdcc6ef9bc5c1b005f67d1c9f428bb8bd2b4c)
@@ -16,15 +16,15 @@
 
 SRC_SYMTAB = \
-	SymTab/FixFunction.cc \
-	SymTab/FixFunction.h \
+	SymTab/FixFunction.cpp \
+	SymTab/FixFunction.hpp \
 	SymTab/GenImplicitCall.cpp \
 	SymTab/GenImplicitCall.hpp \
-	SymTab/Mangler.cc \
-	SymTab/ManglerCommon.cc \
-	SymTab/Mangler.h
+	SymTab/Mangler.cpp \
+	SymTab/ManglerCommon.cpp \
+	SymTab/Mangler.hpp
 
 SRC += $(SRC_SYMTAB)
 
 SRCDEMANGLE += $(SRC_SYMTAB) \
-	SymTab/Demangle.cc \
-	SymTab/Demangle.h
+	SymTab/Demangle.cpp \
+	SymTab/Demangle.hpp
