... in practice, something like the below. Paolo.
///////////////////
Index: cp/pt.c =================================================================== --- cp/pt.c (revision 214027) +++ cp/pt.c (working copy) @@ -162,7 +162,7 @@ static tree tsubst_friend_class (tree, tree); static int can_complete_type_without_circularity (tree); static tree get_bindings (tree, tree, tree, bool); static int template_decl_level (tree); -static int check_cv_quals_for_unify (int, tree, tree); +static int check_cv_quals_for_unify (int, tree, tree, bool); static void template_parm_level_and_index (tree, int*, int*); static int unify_pack_expansion (tree, tree, tree, tree, unification_kind_t, bool, bool); @@ -17279,11 +17279,16 @@ template_decl_level (tree decl) Returns nonzero iff the unification is OK on that basis. */ static int -check_cv_quals_for_unify (int strict, tree arg, tree parm) +check_cv_quals_for_unify (int strict, tree arg, tree parm, bool in_function) { int arg_quals = cp_type_quals (arg); int parm_quals = cp_type_quals (parm); + /* DR 1584: cv-qualification of a deduced function type is + ignored; see 8.3.5 [dcl.fct]. */ + if (in_function && TREE_CODE (arg) == FUNCTION_TYPE) + return 1; + if (TREE_CODE (parm) == TEMPLATE_TYPE_PARM && !(strict & UNIFY_ALLOW_OUTER_MORE_CV_QUAL)) { @@ -17644,6 +17649,8 @@ unify (tree tparms, tree targs, tree parm, tree ar tree targ; tree tparm; int strict_in = strict; + bool in_function = (TREE_TYPE (tparms) + && DECL_FUNCTION_TEMPLATE_P (TREE_TYPE (tparms))); /* I don't think this will do the right thing with respect to types. But the only case I've seen it in so far has been array bounds, where @@ -17750,7 +17757,7 @@ unify (tree tparms, tree targs, tree parm, tree ar PARM `T' for example, when computing which of two templates is more specialized, for example. */ && TREE_CODE (arg) != TEMPLATE_TYPE_PARM - && !check_cv_quals_for_unify (strict_in, arg, parm)) + && !check_cv_quals_for_unify (strict_in, arg, parm, in_function)) return unify_cv_qual_mismatch (explain_p, parm, arg); if (!(strict & UNIFY_ALLOW_OUTER_LEVEL) @@ -17927,7 +17934,7 @@ unify (tree tparms, tree targs, tree parm, tree ar If ARG is `const int' and PARM is just `T' that's OK; that binds `const int' to `T'. */ if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL, - arg, parm)) + arg, parm, in_function)) return unify_cv_qual_mismatch (explain_p, parm, arg); /* Consider the case where ARG is `const volatile int' and @@ -18273,7 +18280,7 @@ unify (tree tparms, tree targs, tree parm, tree ar && (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, class_of_this_parm (arg), - class_of_this_parm (parm)))) + class_of_this_parm (parm), in_function))) return unify_cv_qual_mismatch (explain_p, parm, arg); RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm), @@ -18298,7 +18305,8 @@ unify (tree tparms, tree targs, tree parm, tree ar if (TYPE_PTRMEMFUNC_P (arg)) { /* Check top-level cv qualifiers */ - if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm)) + if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm, + in_function)) return unify_cv_qual_mismatch (explain_p, parm, arg); RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm), Index: testsuite/g++.dg/cpp0x/pr57466.C =================================================================== --- testsuite/g++.dg/cpp0x/pr57466.C (revision 0) +++ testsuite/g++.dg/cpp0x/pr57466.C (working copy) @@ -0,0 +1,18 @@ +// PR c++/57466 +// { dg-do compile { target c++11 } } + +template<typename T> + constexpr bool + is_pointer(const T*) + { return true; } + +template<typename T> + constexpr bool + is_pointer(const T&) + { return false; } + +using F = void(); + +constexpr F* f = nullptr; + +static_assert( is_pointer(f), "function pointer is a pointer" ); Index: testsuite/g++.dg/template/pr57466.C =================================================================== --- testsuite/g++.dg/template/pr57466.C (revision 0) +++ testsuite/g++.dg/template/pr57466.C (working copy) @@ -0,0 +1,8 @@ +// DR 1584, PR c++/57466 + +template<class T> void f2(const T*); +void g2(); + +void m() { + f2(g2); // OK: cv-qualification of deduced function type ignored +} Index: testsuite/g++.dg/template/unify6.C =================================================================== --- testsuite/g++.dg/template/unify6.C (revision 214027) +++ testsuite/g++.dg/template/unify6.C (working copy) @@ -3,21 +3,20 @@ void Baz (); -template <typename T> void Foo1 (T *); // #1 -template <typename T> void Foo1 (T const *a) {a (1);} // #2 +template <typename T> void Foo1 (T *); +template <typename T> void Foo1 (T const *a) {a (1);} // { dg-error "too many arguments" } template <typename T> T const *Foo2 (T *); -template <typename T> void Foo3 (T *, T const * = 0); // { dg-message "note" } +template <typename T> void Foo3 (T *, T const * = 0); void Bar () { - Foo1 (&Baz); // #1 + Foo1 (&Baz); // { dg-message "required from here" } Foo2 (&Baz); Foo3 (&Baz); - Foo3 (&Baz, &Baz); // { dg-error "no matching function" "" } - // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 21 } + Foo3 (&Baz, &Baz); }