Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision 0bd3faf870391e5ed803287ec0b3c696cfde22b2)
+++ src/SymTab/FixFunction.cc	(revision b0845f9b0a749d876b30f395469f2acd02d5d886)
@@ -26,45 +26,47 @@
 
 namespace {
-	struct FixFunction final : public ast::WithShortCircuiting {
-		bool isVoid = false;
 
-		void previsit( const ast::FunctionDecl * ) { visit_children = false; }
+struct FixFunction final : public ast::WithShortCircuiting {
+	bool isVoid = 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::FunctionDecl * ) { visit_children = false; }
 
-		void previsit( const ast::ArrayType * ) { 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 ) };
+	}
 
-		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::ArrayType * ) { visit_children = false; }
 
-		void previsit( const ast::FunctionType * ) { 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 };
+	}
 
-		const ast::Type * postvisit( const ast::FunctionType * type ) {
-			return new ast::PointerType( type );
-		}
+	void previsit( const ast::FunctionType * ) { visit_children = false; }
 
-		void previsit( const ast::VoidType * ) { isVoid = true; }
+	const ast::Type * postvisit( const ast::FunctionType * type ) {
+		return new ast::PointerType( type );
+	}
 
-		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; }
-	};
+	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
 
Index: src/SymTab/FixFunction.h
===================================================================
--- src/SymTab/FixFunction.h	(revision 0bd3faf870391e5ed803287ec0b3c696cfde22b2)
+++ src/SymTab/FixFunction.h	(revision b0845f9b0a749d876b30f395469f2acd02d5d886)
@@ -22,8 +22,10 @@
 
 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 );
+
+/// 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
 
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision 0bd3faf870391e5ed803287ec0b3c696cfde22b2)
+++ src/SymTab/Mangler.cc	(revision b0845f9b0a749d876b30f395469f2acd02d5d886)
@@ -28,329 +28,323 @@
 
 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 );
-
-			/// 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
-	} // namespace
-
-	std::string mangle( const ast::Node * decl, Mangle::Mode mode ) {
-		return ast::Pass<Mangler>::read( decl, mode );
-	}
-
-	namespace {
-		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;
-			} // if
-			mangleName += Encoding::manglePrefix;
-			const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( decl->name );
-			if ( opInfo ) {
-				mangleName += std::to_string( opInfo->outputName.size() ) + opInfo->outputName;
-			} else {
-				mangleName += std::to_string( decl->name.size() ) + decl->name;
-			} // if
-			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" );
-				} // if
+
+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 );
+
+	/// 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::BasicType::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;
+}
+
+// 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() );
 			}
-			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::BasicType::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 );
-			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 );
-			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 );
-			} // if
-		}
-
-		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;
-		}
-
-		// 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;
-			} // for
-		}
-
-		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", SymTab::Mangler::Encoding::typeVariables[decl->kind].c_str() );
-					} // switch
-					varNums[ decl->name ] = std::make_pair( nextVarNum, (int)decl->kind );
-				} // for
-				for ( auto & assert : funcType->assertions ) {
-					assertionNames.push_back( ast::Pass<Mangler>::read(
-						assert->var.get(),
-						mangleOverridable, typeMode, mangleGenericParams, nextVarNum, varNums ) );
-					acount++;
-				} // for
-				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
-			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
-				if ( type->is_volatile() ) {
-					mangleName += Encoding::qualifiers.at( ast::CV::Volatile );
-				} // if
-				// Removed due to restrict not affecting function compatibility in GCC
-				// if ( type->get_isRestrict() ) {
-				// 	mangleName += "E";
-				// } // if
-				if ( type->is_atomic() ) {
-					mangleName += Encoding::qualifiers.at( ast::CV::Atomic );
-				} // if
-			}
-			if ( type->is_mutex() ) {
-				mangleName += Encoding::qualifiers.at( ast::CV::Mutex );
-			} // if
-			if ( inFunctionType ) {
-				// turn off inFunctionType so that types can be differentiated for nested qualifiers
-				GuardValue( inFunctionType );
-				inFunctionType = false;
-			}
-		}
-	}	// namespace
+			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
 
Index: src/SymTab/Mangler.h
===================================================================
--- src/SymTab/Mangler.h	(revision 0bd3faf870391e5ed803287ec0b3c696cfde22b2)
+++ src/SymTab/Mangler.h	(revision b0845f9b0a749d876b30f395469f2acd02d5d886)
@@ -34,71 +34,66 @@
 }
 
-namespace SymTab {
-	namespace Mangler {
-		namespace Encoding {
-			extern const std::string manglePrefix;
-			extern const std::string basicTypes[];
-			extern const std::map<int, std::string> qualifiers;
+namespace Mangle {
 
-			extern const std::string void_t;
-			extern const std::string zero;
-			extern const std::string one;
+/// Bitflags for mangle Mode:
+enum {
+	NoOverrideable  = 1 << 0,
+	Type            = 1 << 1,
+	NoGenericParams = 1 << 2
+};
 
-			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;
+/// 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;
 		};
-	} // Mangler
-} // SymTab
-
-namespace Mangle {
-	/// Bitflags for mangle modes
-	enum {
-		NoOverrideable  = 1 << 0,
-		Type            = 1 << 1,
-		NoGenericParams = 1 << 2
 	};
 
-	/// Bitflag type for mangler modes
-	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) {}
+};
 
-		constexpr mangle_flags( unsigned int val ) : val(val) {}
-	};
+using Mode = bitfield<mangle_flags>;
 
-	using Mode = bitfield<mangle_flags>;
+/// Mangle declaration name.
+std::string mangle( const ast::Node * decl, Mode mode = {} );
 
-	/// 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 } );
+}
 
-	/// 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;
 
-	namespace Encoding {
-		using namespace SymTab::Mangler::Encoding;
-	};
+	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;
+}
+
 }
 
Index: src/SymTab/ManglerCommon.cc
===================================================================
--- src/SymTab/ManglerCommon.cc	(revision 0bd3faf870391e5ed803287ec0b3c696cfde22b2)
+++ src/SymTab/ManglerCommon.cc	(revision b0845f9b0a749d876b30f395469f2acd02d5d886)
@@ -19,109 +19,111 @@
 #include "AST/Type.hpp"
 
-namespace SymTab {
-	namespace Mangler {
-		namespace Encoding {
-			const std::string manglePrefix = "_X";
+namespace Mangle {
 
-			// GENERATED START, DO NOT EDIT
-			// GENERATED BY BasicTypes-gen.cc
-			// 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::BasicType::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::BasicType::NUMBER_OF_BASIC_TYPES,
-				"Each basic type kind should have a corresponding mangler letter"
-			);
+namespace Encoding {
 
-			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 manglePrefix = "_X";
 
-			const std::string void_t = "v";
-			const std::string zero = "Z";
-			const std::string one = "O";
+// GENERATED START, DO NOT EDIT
+// GENERATED BY BasicTypes-gen.cc
+// 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::BasicType::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::BasicType::NUMBER_OF_BASIC_TYPES,
+	"Each basic type kind should have a corresponding mangler letter"
+);
 
-			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::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 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 void_t = "v";
+const std::string zero = "Z";
+const std::string one = "O";
 
-			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 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 autogen = "autogen__";
-			const std::string intrinsic = "intrinsic__";
-		} // namespace Encoding
-	} // namespace Mangler
-} // namespace SymTab
+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
