Index: src/ResolvExpr/Unify.cc
===================================================================
--- src/ResolvExpr/Unify.cc	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/ResolvExpr/Unify.cc	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -563,4 +563,8 @@
 			flatten( dcl->get_type(), back_inserter( types ) );
 			for ( Type * t : types ) {
+				// outermost const, volatile, _Atomic qualifiers in parameters should not play a role in the unification of function types, since they do not determine whether a function is callable.
+				// Note: MUST consider at least mutex qualifier, since functions can be overloaded on outermost mutex and a mutex function has different requirements than a non-mutex function.
+				t->get_qualifiers() -= Type::Qualifiers(Type::Const | Type::Volatile | Type::Atomic);
+
 				dst.push_back( new ObjectDecl( "", Type::StorageClasses(), LinkageSpec::C, nullptr, t, nullptr ) );
 			}
@@ -580,7 +584,7 @@
 
 			// sizes don't have to match if ttypes are involved; need to be more precise wrt where the ttype is to prevent errors
-			if ( (flatFunc->get_parameters().size() == flatOther->get_parameters().size() && flatFunc->get_returnVals().size() == flatOther->get_returnVals().size()) || flatFunc->isTtype() || flatOther->isTtype() ) {
-				if ( unifyDeclList( flatFunc->get_parameters().begin(), flatFunc->get_parameters().end(), flatOther->get_parameters().begin(), flatOther->get_parameters().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
-					if ( unifyDeclList( flatFunc->get_returnVals().begin(), flatFunc->get_returnVals().end(), flatOther->get_returnVals().begin(), flatOther->get_returnVals().end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+			if ( (flatFunc->parameters.size() == flatOther->parameters.size() && flatFunc->returnVals.size() == flatOther->returnVals.size()) || flatFunc->isTtype() || flatOther->isTtype() ) {
+				if ( unifyDeclList( flatFunc->parameters.begin(), flatFunc->parameters.end(), flatOther->parameters.begin(), flatOther->parameters.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
+					if ( unifyDeclList( flatFunc->returnVals.begin(), flatFunc->returnVals.end(), flatOther->returnVals.begin(), flatOther->returnVals.end(), env, needAssertions, haveAssertions, openVars, indexer ) ) {
 
 						// the original types must be used in mark assertions, since pointer comparisons are used
@@ -599,5 +603,5 @@
 		// check that other type is compatible and named the same
 		RefType *otherStruct = dynamic_cast< RefType* >( other );
-		result = otherStruct && inst->get_name() == otherStruct->get_name();
+		result = otherStruct && inst->name == otherStruct->name;
 	}
 
@@ -608,6 +612,6 @@
 		if ( ! result ) return;
 		// Check that parameters of types unify, if any
-		std::list< Expression* > params = inst->get_parameters();
-		std::list< Expression* > otherParams = ((RefType*)other)->get_parameters();
+		std::list< Expression* > params = inst->parameters;
+		std::list< Expression* > otherParams = ((RefType*)other)->parameters;
 
 		std::list< Expression* >::const_iterator it = params.begin(), jt = otherParams.begin();
Index: src/SymTab/FixFunction.cc
===================================================================
--- src/SymTab/FixFunction.cc	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/SymTab/FixFunction.cc	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -36,4 +36,8 @@
 	}
 
+	// xxx - this passes on void[], e.g.
+	//   void foo(void [10]);
+	// does not cause an error
+
 	Type * FixFunction::postmutate(ArrayType *arrayType) {
 		// need to recursively mutate the base type in order for multi-dimensional arrays to work.
@@ -62,4 +66,10 @@
 	void FixFunction::premutate(ZeroType *) { visit_children = false; }
 	void FixFunction::premutate(OneType *) { visit_children = false; }
+
+	bool fixFunction( DeclarationWithType *& dwt ) {
+		PassVisitor<FixFunction> fixer;
+		dwt = dwt->acceptMutator( fixer );
+		return fixer.pass.isVoid;
+	}
 } // namespace SymTab
 
Index: src/SymTab/FixFunction.h
===================================================================
--- src/SymTab/FixFunction.h	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/SymTab/FixFunction.h	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -47,4 +47,6 @@
 		bool isVoid;
 	};
+
+	bool fixFunction( DeclarationWithType *& );
 } // namespace SymTab
 
Index: src/SymTab/Mangler.cc
===================================================================
--- src/SymTab/Mangler.cc	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/SymTab/Mangler.cc	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -37,5 +37,5 @@
 			struct Mangler : public WithShortCircuiting, public WithVisitorRef<Mangler> {
 				Mangler( bool mangleOverridable, bool typeMode, bool mangleGenericParams );
-				Mangler( const Mangler & );
+				Mangler( const Mangler & ) = delete;
 
 				void previsit( BaseSyntaxNode * ) { visit_children = false; }
Index: src/SymTab/Validate.cc
===================================================================
--- src/SymTab/Validate.cc	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/SymTab/Validate.cc	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -351,31 +351,22 @@
 	namespace {
 		template< typename DWTList >
-		void fixFunctionList( DWTList & dwts, FunctionType * func ) {
-			// the only case in which "void" is valid is where it is the only one in the list; then it should be removed
-			// entirely. other fix ups are handled by the FixFunction class
-			typedef typename DWTList::iterator DWTIterator;
-			DWTIterator begin( dwts.begin() ), end( dwts.end() );
-			if ( begin == end ) return;
-			PassVisitor<FixFunction> fixer;
-			DWTIterator i = begin;
-			*i = (*i)->acceptMutator( fixer );
-			if ( fixer.pass.isVoid ) {
-				DWTIterator j = i;
-				++i;
-				delete *j;
-				dwts.erase( j );
-				if ( i != end ) {
-					throw SemanticError( "invalid type void in function type ", func );
-				} // if
-			} else {
-				++i;
-				for ( ; i != end; ++i ) {
-					PassVisitor<FixFunction> fixer;
-					*i = (*i)->acceptMutator( fixer );
-					if ( fixer.pass.isVoid ) {
-						throw SemanticError( "invalid type void in function type ", func );
-					} // if
-				} // for
-			} // if
+		void fixFunctionList( DWTList & dwts, bool isVarArgs, FunctionType * func ) {
+			auto nvals = dwts.size();
+			bool containsVoid = false;
+			for ( auto & dwt : dwts ) {
+				// fix each DWT and record whether a void was found
+				containsVoid |= fixFunction( dwt );
+			}
+
+			// the only case in which "void" is valid is where it is the only one in the list
+			if ( containsVoid && ( nvals > 1 || isVarArgs ) ) {
+				throw SemanticError( "invalid type void in function type ", func );
+			}
+
+			// one void is the only thing in the list; remove it.
+			if ( containsVoid ) {
+				delete dwts.front();
+				dwts.clear();
+			}
 		}
 	}
@@ -383,6 +374,6 @@
 	void EnumAndPointerDecay::previsit( FunctionType *func ) {
 		// Fix up parameters and return types
-		fixFunctionList( func->get_parameters(), func );
-		fixFunctionList( func->get_returnVals(), func );
+		fixFunctionList( func->parameters, func->isVarArgs, func );
+		fixFunctionList( func->returnVals, false, func );
 	}
 
@@ -626,7 +617,6 @@
 			// apply FixFunction to every assertion to check for invalid void type
 			for ( DeclarationWithType *& assertion : type->assertions ) {
-				PassVisitor<FixFunction> fixer;
-				assertion = assertion->acceptMutator( fixer );
-				if ( fixer.pass.isVoid ) {
+				bool isVoid = fixFunction( assertion );
+				if ( isVoid ) {
 					throw SemanticError( "invalid type void in assertion of function ", node );
 				} // if
Index: src/tests/tuple/tupleVariadic.c
===================================================================
--- src/tests/tuple/tupleVariadic.c	(revision ff2d113903704b0fb3779974f5c980298b4c87c6)
+++ src/tests/tuple/tupleVariadic.c	(revision 7a052e3412f2d7ad0010af394762a950f3f989e7)
@@ -95,4 +95,7 @@
 }
 
+forall(ttype T | { void foo(T); }) void bar(T x) {}
+void foo(int) {}
+
 int main() {
 	array * x0 = new();
@@ -117,4 +120,10 @@
 	func(3, 2.0, 111, 4.145);
 	printf("finished func\n");
+
+	{
+		// T = [const int] -- this ensures that void(*)(int) satisfies void(*)(const int)
+		const int x;
+		bar(x);
+	}
 }
 
