+/* Given two function templates PAT1 and PAT2, return:
+
+ 1 if PAT1 is more specialized than PAT2 as described in [temp.func.order].
+ -1 if PAT2 is more specialized than PAT1.
+ 0 if neither is more specialized.
+
+ LEN indicates the number of parameters we should consider
+ (defaulted parameters should not be considered).
+
+ The 1998 std underspecified function template partial ordering, and
+ DR214 addresses the issue. We take pairs of arguments, one from
+ each of the templates, and deduce them against each other. One of
+ the templates will be more specialized if all the *other*
+ template's arguments deduce against its arguments and at least one
+ of its arguments *does* *not* deduce against the other template's
+ corresponding argument. Deduction is done as for class templates.
+ The arguments used in deduction have reference and top level cv
+ qualifiers removed. Iff both arguments were originally reference
+ types *and* deduction succeeds in both directions, the template
+ with the more cv-qualified argument wins for that pairing (if
+ neither is more cv-qualified, they both are equal). Unlike regular
+ deduction, after all the arguments have been deduced in this way,
+ we do *not* verify the deduced template argument values can be
+ substituted into non-deduced contexts, nor do we have to verify
+ that all template arguments have been deduced. */
+
+int
+more_specialized_fn (tree pat1, tree pat2, int len)
+{
+ tree decl1 = DECL_TEMPLATE_RESULT (pat1);
+ tree decl2 = DECL_TEMPLATE_RESULT (pat2);
+ tree targs1 = make_tree_vec (DECL_NTPARMS (pat1));
+ tree targs2 = make_tree_vec (DECL_NTPARMS (pat2));
+ tree tparms1 = DECL_INNERMOST_TEMPLATE_PARMS (pat1);
+ tree tparms2 = DECL_INNERMOST_TEMPLATE_PARMS (pat2);
+ tree args1 = TYPE_ARG_TYPES (TREE_TYPE (decl1));
+ tree args2 = TYPE_ARG_TYPES (TREE_TYPE (decl2));
+ int better1 = 0;
+ int better2 = 0;
+
+ /* Remove the this parameter from non-static member functions. If
+ one is a non-static member function and the other is not a static
+ member function, remove the first parameter from that function
+ also. This situation occurs for operator functions where we
+ locate both a member function (with this pointer) and non-member
+ operator (with explicit first operand). */
+ if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl1))
+ {
+ len--; /* LEN is the number of significant arguments for DECL1 */
+ args1 = TREE_CHAIN (args1);
+ if (!DECL_STATIC_FUNCTION_P (decl2))
+ args2 = TREE_CHAIN (args2);
+ }
+ else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl2))
+ {
+ args2 = TREE_CHAIN (args2);
+ if (!DECL_STATIC_FUNCTION_P (decl1))
+ {
+ len--;
+ args1 = TREE_CHAIN (args1);
+ }
+ }
+
+ /* If only one is a conversion operator, they are unordered. */
+ if (DECL_CONV_FN_P (decl1) != DECL_CONV_FN_P (decl2))
+ return 0;
+
+ /* Consider the return type for a conversion function */
+ if (DECL_CONV_FN_P (decl1))
+ {
+ args1 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl1)), args1);
+ args2 = tree_cons (NULL_TREE, TREE_TYPE (TREE_TYPE (decl2)), args2);
+ len++;
+ }
+
+ processing_template_decl++;
+
+ while (len--)
+ {
+ tree arg1 = TREE_VALUE (args1);
+ tree arg2 = TREE_VALUE (args2);
+ int deduce1, deduce2;
+ int quals1 = -1;
+ int quals2 = -1;
+
+ if (TREE_CODE (arg1) == REFERENCE_TYPE)
+ {
+ arg1 = TREE_TYPE (arg1);
+ quals1 = cp_type_quals (arg1);
+ }
+
+ if (TREE_CODE (arg2) == REFERENCE_TYPE)
+ {
+ arg2 = TREE_TYPE (arg2);
+ quals2 = cp_type_quals (arg2);
+ }
+
+ if ((quals1 < 0) != (quals2 < 0))
+ {
+ /* Only of the args is a reference, see if we should apply
+ array/function pointer decay to it. This is not part of
+ DR214, but is, IMHO, consistent with the deduction rules
+ for the function call itself, and with our earlier
+ implementation of the underspecified partial ordering
+ rules. (nathan). */
+ if (quals1 >= 0)
+ {
+ switch (TREE_CODE (arg1))
+ {
+ case ARRAY_TYPE:
+ arg1 = TREE_TYPE (arg1);
+ /* FALLTHROUGH. */
+ case FUNCTION_TYPE:
+ arg1 = build_pointer_type (arg1);
+ break;
+
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (TREE_CODE (arg2))
+ {
+ case ARRAY_TYPE:
+ arg2 = TREE_TYPE (arg2);
+ /* FALLTHROUGH. */
+ case FUNCTION_TYPE:
+ arg2 = build_pointer_type (arg2);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ arg1 = TYPE_MAIN_VARIANT (arg1);
+ arg2 = TYPE_MAIN_VARIANT (arg2);
+
+ deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
+ deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);