diff mbox

[c++] describe reasons for function template overload resolution failure

Message ID 20110526190429.GA6119@nightcrawler
State New
Headers show

Commit Message

Nathan Froyd May 26, 2011, 7:04 p.m. UTC
On Thu, May 26, 2011 at 11:43:07AM -0400, Jason Merrill wrote:
> On 05/25/2011 02:15 PM, Nathan Froyd wrote:
> >The patch below implements just such an idea.  The only twist is that
> >the `explain' parameter is actually a `location_t *'
> >
> >I'm not totally attached to this; it's almost too cute, and since
> >tf_warning_or_error messsages tend to be attached to the call anyway,
> >it's arguably inconsistent.
> 
> Yes, I think let's drop this bit and just use the call location.

Done.  Doing this required quite some more modifications in the
testsuite.

> Ideally, for unification failures we'd give the source location of
> the problematic argument (which we don't always have because it
> might be a plain DECL) and for substitution failures we'd give the
> source location of the expression that substitution failed on (for
> which we could adjust input_location in tsubst_*).

Yes, that would be a useful future enhancement.

Tested as before.  OK?

-Nathan

gcc/cp/
	PR c++/45329
	PR c++/48934
        * cp-tree.h (fn_type_unification): Add `bool' parameter.
        * pt.c (enum template_base_result): Define.
	(unify_success, unify_unknown): Define.
	(unify_parameter_deduction_failure): Define.
        (unify_invalid, unify_cv_qual_mismatch, unify_type_mismatch): Define.
        (unify_parameter_pack_mismatch): Define.
        (unify_parameter_pack_inconsistent): Define.
        (unify_ptrmem_cst_mismatch, unify_vla_arg): Define.
        (unify_constant_mismatch, unify_constant_unequal): Define.
        (unify_expression_unequal, unify_inconsistency): Define.
	(unify_method_type_error, unify_arity): Likewise.
        (unify_too_many_parameters, unify_too_few_parameters): Define.
        (unify_arg_conversion, unify_no_common_base): Define.
        (unify_illformed_ptrmem_cst_expr): Define.
	(unify_substitution_failure): Define.
	(unify_inconsistent_template_template_parameters): Define.
	(unify_template_deduction_failure): Define.
	(unify_template_parameter_mismatch): Define.
	(unify_template_argument_mismatch): Define.
	(deduction_tsubst_fntype): Add `complain' parameter'.  Pass it
	to tsubst.
        (unify): Add `explain_p' parameter.  Pass to all relevant calls.
	Call above status functions when appropriate.
        (resolve_overloaded_unification, try_one_overload): Likewise.
        (type_unification, type_unification_real): Likewise.
        (unify_pack_expansion): Likewise.
        (get_template_base, try_class_unification): Likewise.
        (get_bindings, more_specialized_fn): Pass false to unification
	calls.
        (get_class_bindings, do_auto_deduction): Likewise.
        (convert_nontype_argument): Likewise.
	(fn_type_unification): Likewise.  Rerun functions for diagnostics
	if necessary.
	(get_template_base): Add `explain_p' parameter and pass it to
	try_class_unification.  Return an enum template_base_result.
        * class.c (resolve_address_of_overloaded_function): Pass false to
	fn_type_unification.
        * call.c (enum rejection_reason_code): Add new codes.
        (struct rejection_reason): Add template_unification field.
	Add template_instantiation field.
        (template_unification_rejection): Define.
        (template_instantiation_rejection): Define.
        (invalid_copy_with_fn_template_rejection): Define.
        (add_template_candidate): Pass false to unify.
        Provide more rejection reasons when possible.
        (print_template_unification_rejection): Define.
        (print_arity_rejection): Define, split out from...
        (print_z_candidate): ...here.  Add cases for new rejection
	reasons.

gcc/testsuite/
	PR c++/45329
	PR c++/48934
	* g++.dg/cpp0x/lambda/lambda-ice2.C: Adjust.
	* g++.dg/cpp0x/nullptr15.C: Adjust.
	* g++.dg/cpp0x/pr31431-2.C: Adjust.
	* g++.dg/cpp0x/pr31431.C: Adjust.
	* g++.dg/cpp0x/pr31434.C: Adjust.
	* g++.dg/cpp0x/sfinae11.C: Adjust
	* g++.dg/cpp0x/temp_default2.C: Adjust.
	* g++.dg/cpp0x/trailing4.C: Adjust.
	* g++.dg/cpp0x/variadic-ex3.C: Adjust.
	* g++.dg/cpp0x/variadic-ex4.C: Adjust.
	* g++.dg/cpp0x/variadic105.C: Adjust.
	* g++.dg/cpp0x/vt-37737-2.C: Adjust.
	* g++.dg/ext/vla2.C: Adjust.
	* g++.dg/other/ptrmem10.C: Adjust.
	* g++.dg/other/ptrmem11.C: Adjust.
	* g++.dg/overload/unknown1.C: Adjust.
	* g++.dg/template/conv11.C: Adjust.
	* g++.dg/template/dependent-expr5.C: Adjust.
	* g++.dg/template/friend.C: Adjust.
	* g++.dg/template/incomplete2.C: Adjust.
	* g++.dg/template/local4.C: Adjust.
	* g++.dg/template/local6.C: Adjust.
	* g++.dg/template/operator9.C: Adjust.
	* g++.dg/template/ttp25.C: Adjust.
	* g++.dg/template/unify10.C: Adjust.
	* g++.dg/template/unify11.C: Adjust.
	* g++.dg/template/unify6.C: Adjust.
	* g++.dg/template/unify9.C: Adjust.
	* g++.dg/template/varmod1.C: Adjust.
	* g++.old-deja/g++.brendan/crash56.C: Adjust.
	* g++.old-deja/g++.pt/crash28.C: Adjust.
	* g++.old-deja/g++.pt/explicit41.C: Adjust.
	* g++.old-deja/g++.pt/explicit77.C: Adjust.
	* g++.old-deja/g++.pt/expr2.C: Adjust.
	* g++.old-deja/g++.pt/ptrmem6.C: Adjust.
	* g++.old-deja/g++.pt/spec5.C: Adjust.
	* g++.old-deja/g++.pt/spec6.C: Adjust.
	* g++.old-deja/g++.pt/unify4.C: Adjust.
	* g++.old-deja/g++.pt/unify8.C: Adjust.
	* g++.old-deja/g++.robertl/eb98.C: Adjust.
	* g++.dg/overload/template5.C: New testcase.
	* g++.dg/template/overload12.C: New testcase.

Comments

Jason Merrill May 27, 2011, 7:14 p.m. UTC | #1
On 05/26/2011 03:04 PM, Nathan Froyd wrote:

Thanks, this is looking pretty close.  A few more issues, mostly to do 
with wording of the diagnostics:

> @@ -14084,7 +14350,7 @@ fn_type_unification (tree fn,
>             sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg);
>           for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg))
>             if (!same_type_p (args[i], TREE_VALUE (sarg)))
> -             return 1;
> +             return unify_unknown (explain_p);

Here the problem is that substituting in the deduced template arguments 
didn't give us the result we were looking for; the diagnostic should 
print the substitution result and the desired result.

>               if (resolve_overloaded_unification
> -                 (tparms, targs, parm, arg, strict, sub_strict))
> +                 (tparms, targs, parm, arg, strict, sub_strict, explain_p))
>                 continue;
>
> -             return 1;
> +             return unify_unknown (explain_p);

Here the problem is that deduction is unable to resolve the address of 
an overloaded function.

> +      inform (input_location,
> +             "  template parameter %qD is not a parameter pack",
> +             parm);
> +      inform (input_location, "  please report this as a bug");

Actually, I was wrong; this isn't a bug.  14.8.2.4/8 says, "If A was 
transformed from a function parameter pack and P is not a parameter 
pack, type deduction fails."

But let's print the argument as well in this case.

> +unify_ptrmem_cst_mismatch (bool explain_p, tree parm, tree arg)
> +{
> +  if (explain_p)
> +    inform (input_location,
> +           "  mismatched pointer-to-memory constants %qE and %qE",
> +           parm, arg);

Here the problem is that arg is not a pointer-to-member constant at all 
(note also "member", not "memory").

>        if (TREE_CODE (arg) != INTEGER_CST)
> -       return 1;
> +       return unify_constant_mismatch (explain_p, parm, arg);

This could end up complaining that arg isn't constant when the problem 
is that it's the wrong kind of constant.

You might combine unify_ptrmem_cst_mismatch, unify_constant_mismatch, 
and unify_constant_unequal to just say that arg is not a constant equal 
to parm.  Or just use unify_template_argument_mismatch.

> +unify_expression_unequal (bool explain_p, tree parm, tree arg)
> +{
> +  if (explain_p)
> +    inform (input_location, "  %qE is not equal to %qE", parm, arg);

This should say "equivalent" rather than "equal".

> +           "  portions of parameter pack %qT could not be deduced",

The problem here is that portions of the pack were deduced to different 
values, like unify_inconsistency but with packs.  Let's print out the 
conflicting values.

> +           "  method type %qT is not a valid template argument", arg);

"member function type"

> +unify_too_many_parameters (bool explain_p, int have, int wanted)
> +unify_too_few_parameters (bool explain_p, int have, int wanted)

s/parameters/arguments/

>           if (strict != DEDUCE_EXACT
>               && can_convert_arg (parm, type, TYPE_P (arg) ? NULL_TREE : arg,
>                                   flags))
>             continue;
>
>           return unify_arg_conversion (explain_p, parm, type, arg);

In the DEDUCE_EXACT case, let's use unify_type_mismatch.

>       && !template_template_parm_bindings_ok_p
>            (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
>     return unify_inconsistent_template_template_parameters (explain_p);

Here the problem is that the template parameters of a template template 
argument are inconsistent with other deduced template arguments, as 
illustrated in the example just above this snippet.  Ideally here we'd 
print the parameter types of the template template argument and the 
parameter types of the template template parameter after substituting in 
the other template arguments.  I'm not going to insist on that now, but 
let's be a bit more verbose than "inconsistent template template 
parameters".

>            && TREE_CODE (tparm) != TYPE_DECL)
>           || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
>               && TREE_CODE (tparm) != TEMPLATE_DECL))
> -       return 1;
> +       return unify_template_parameter_mismatch (explain_p,
> +                                                 parm, tparm);

Looking more closely, I have no idea how this could happen.  It seems to 
hypothesize a template type parameter that isn't a type parameter, or a 
template template parameter that isn't a template template parameter. 
Let's try asserting that this can't happen.

>        converted_args
>         = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
>                                   /*require_all_args=*/false,
>                                   /*use_default_args=*/false));
>        if (converted_args == error_mark_node)
> -       return 1;
> +       {
> +         /* Run it for diagnostics.  */
> +         if (explain_p)
> +           coerce_template_parms (tparms, explicit_targs, NULL_TREE,
> +                                  tf_warning_or_error,
> +                                  /*require_all_args=*/false,
> +                                  /*use_default_args=*/false);
> +         return 1;
> +       }

Instead of calling it twice, pass different tsubst_flags depending on 
explain_p.  And the same for all the other places where you call a 
function again with tf_warning_or_error.

> +              return unify_too_few_parameters (explain_p, TREE_VEC_LENGTH (argv
> +                                              len);

Line too long.

> +  /* FIXME: Should we pass in unification information and then use that
> +     to elaborate on the error messages below?  */

Just pass in explain_p = true, and then we shouldn't need the "unable to 
deduce" message here.

Jason
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ff3dc06..c2b6502 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -430,7 +430,10 @@  enum rejection_reason_code {
   rr_none,
   rr_arity,
   rr_arg_conversion,
-  rr_bad_arg_conversion
+  rr_bad_arg_conversion,
+  rr_template_unification,
+  rr_template_instantiation,
+  rr_invalid_copy
 };
 
 struct conversion_info {
@@ -458,6 +461,24 @@  struct rejection_reason {
     struct conversion_info conversion;
     /* Same, but for bad argument conversions.  */
     struct conversion_info bad_conversion;
+    /* Information about template unification failures.  These are the
+       parameters passed to fn_type_unification.  */
+    struct {
+      tree tmpl;
+      tree explicit_targs;
+      tree targs;
+      const tree *args;
+      unsigned int nargs;
+      tree return_type;
+      unification_kind_t strict;
+      int flags;
+    } template_unification;
+    /* Information about template instantiation failures.  These are the
+       parameters passed to instantiate_template.  */
+    struct {
+      tree tmpl;
+      tree targs;
+    } template_instantiation;
   } u;
 };
 
@@ -607,6 +628,44 @@  bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
+				const tree *args, unsigned int nargs,
+				tree return_type, unification_kind_t strict,
+				int flags)
+{
+  size_t args_n_bytes = sizeof (*args) * nargs;
+  tree *args1 = (tree *) conversion_obstack_alloc (args_n_bytes);
+  struct rejection_reason *r = alloc_rejection (rr_template_unification);
+  r->u.template_unification.tmpl = tmpl;
+  r->u.template_unification.explicit_targs = explicit_targs;
+  r->u.template_unification.targs = targs;
+  /* Copy args to our own storage.  */
+  memcpy (args1, args, args_n_bytes);
+  r->u.template_unification.args = args1;
+  r->u.template_unification.nargs = nargs;
+  r->u.template_unification.return_type = return_type;
+  r->u.template_unification.strict = strict;
+  r->u.template_unification.flags = flags;
+  return r;
+}
+
+static struct rejection_reason *
+template_instantiation_rejection (tree tmpl, tree targs)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
+  r->u.template_instantiation.tmpl = tmpl;
+  r->u.template_instantiation.targs = targs;
+  return r;
+}
+
+static struct rejection_reason *
+invalid_copy_with_fn_template_rejection (void)
+{
+  struct rejection_reason *r = alloc_rejection (rr_invalid_copy);
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -2889,14 +2948,23 @@  add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   i = fn_type_unification (tmpl, explicit_targs, targs,
 			   args_without_in_chrg,
 			   nargs_without_in_chrg,
-			   return_type, strict, flags);
+			   return_type, strict, flags, false);
 
   if (i != 0)
-    goto fail;
+    {
+      reason = template_unification_rejection (tmpl, explicit_targs,
+					       targs, args_without_in_chrg,
+					       nargs_without_in_chrg,
+					       return_type, strict, flags);
+      goto fail;
+    }
 
   fn = instantiate_template (tmpl, targs, tf_none);
   if (fn == error_mark_node)
-    goto fail;
+    {
+      reason = template_instantiation_rejection (tmpl, targs);
+      goto fail;
+    }
 
   /* In [class.copy]:
 
@@ -2925,7 +2993,10 @@  add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
       tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn);
       if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)),
 				    ctype))
-	goto fail;
+	{
+	  reason = invalid_copy_with_fn_template_rejection ();
+	  goto fail;
+	}
     }
 
   if (obj != NULL_TREE)
@@ -3093,6 +3164,18 @@  print_conversion_rejection (location_t loc, struct conversion_info *info)
 	    info->n_arg+1, info->from_type, info->to_type);
 }
 
+/* Print information about a candidate with WANT parameters and we found
+   HAVE.  */
+
+static void
+print_arity_information (location_t loc, unsigned int have, unsigned int want)
+{
+  inform_n (loc, want,
+	    "  candidate expects %d argument, %d provided",
+	    "  candidate expects %d arguments, %d provided",
+	    want, have);
+}
+
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
    is the text to print before the candidate itself.
 
@@ -3139,10 +3222,8 @@  print_z_candidate (const char *msgstr, struct z_candidate *candidate)
       switch (r->code)
 	{
 	case rr_arity:
-	  inform_n (loc, r->u.arity.expected,
-		    "  candidate expects %d argument, %d provided",
-		    "  candidate expects %d arguments, %d provided",
-		    r->u.arity.expected, r->u.arity.actual);
+	  print_arity_information (loc, r->u.arity.actual,
+				   r->u.arity.expected);
 	  break;
 	case rr_arg_conversion:
 	  print_conversion_rejection (loc, &r->u.conversion);
@@ -3150,6 +3231,29 @@  print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 	case rr_bad_arg_conversion:
 	  print_conversion_rejection (loc, &r->u.bad_conversion);
 	  break;
+	case rr_template_unification:
+	  /* Re-run template unification with diagnostics.  */
+	  fn_type_unification (r->u.template_unification.tmpl,
+			       r->u.template_unification.explicit_targs,
+			       r->u.template_unification.targs,
+			       r->u.template_unification.args,
+			       r->u.template_unification.nargs,
+			       r->u.template_unification.return_type,
+			       r->u.template_unification.strict,
+			       r->u.template_unification.flags,
+			       true);
+	  break;
+	case rr_template_instantiation:
+	  /* Re-run template instantiation with diagnostics.  */
+	  instantiate_template (r->u.template_instantiation.tmpl,
+				r->u.template_instantiation.targs,
+				tf_warning_or_error);
+	  break;
+	case rr_invalid_copy:
+	  inform (loc, 
+		  "  a constructor taking a single argument of its own "
+		  "class type is invalid");
+	  break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 69627cb..3a6eb3a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6541,7 +6541,7 @@  resolve_address_of_overloaded_function (tree target_type,
 	  targs = make_tree_vec (DECL_NTPARMS (fn));
 	  if (fn_type_unification (fn, explicit_targs, targs, args, nargs,
 				   target_ret_type, DEDUCE_EXACT,
-				   LOOKUP_NORMAL))
+				   LOOKUP_NORMAL, false))
 	    /* Argument deduction failed.  */
 	    continue;
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ada01fb..8b9589b 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5129,7 +5129,8 @@  extern tree instantiate_class_template		(tree);
 extern tree instantiate_template		(tree, tree, tsubst_flags_t);
 extern int fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
-						 tree, unification_kind_t, int);
+						 tree, unification_kind_t, int,
+						 bool);
 extern void mark_decl_instantiated		(tree, int);
 extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index ab48c8f..c1e38a1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -109,13 +109,20 @@  static GTY(()) VEC(tree,gc) *canonical_template_parms;
 #define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32
 #define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64
 
+enum template_base_result {
+  tbr_incomplete_type,
+  tbr_ambiguous_baseclass,
+  tbr_success
+};
+
 static void push_access_scope (tree);
 static void pop_access_scope (tree);
 static bool resolve_overloaded_unification (tree, tree, tree, tree,
-					    unification_kind_t, int);
+					    unification_kind_t, int,
+					    bool);
 static int try_one_overload (tree, tree, tree, tree, tree,
-			     unification_kind_t, int, bool);
-static int unify (tree, tree, tree, tree, int);
+			     unification_kind_t, int, bool, bool);
+static int unify (tree, tree, tree, tree, int, bool);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
@@ -129,7 +136,8 @@  static bool check_instantiated_args (tree, tree, tsubst_flags_t);
 static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
 					     tree);
 static int type_unification_real (tree, tree, tree, const tree *,
-				  unsigned int, int, unification_kind_t, int);
+				  unsigned int, int, unification_kind_t, int,
+				  bool);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
@@ -154,7 +162,8 @@  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 void template_parm_level_and_index (tree, int*, int*);
-static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
+static int unify_pack_expansion (tree, tree, tree,
+				 tree, int, bool, bool, bool);
 static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -166,8 +175,9 @@  static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
 static bool check_specialization_scope (void);
 static tree process_partial_specialization (tree);
 static void set_current_access_from_decl (tree);
-static tree get_template_base (tree, tree, tree, tree);
-static tree try_class_unification (tree, tree, tree, tree);
+static enum template_base_result get_template_base (tree, tree, tree, tree,
+						    bool , tree *);
+static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
@@ -5265,6 +5275,233 @@  has_value_dependent_address (tree op)
   return false;
 }
 
+/* The next set of functions are used for providing helpful explanatory
+   diagnostics for failed overload resolution.  Their messages should be
+   indented by two spaces for consistency with the messages in
+   call.c  */
+
+static int
+unify_success (bool explain_p ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+unify_unknown (bool explain_p ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+unify_parameter_deduction_failure (bool explain_p, tree parm)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  couldn't deduce template parameter %qD", parm);
+  return 1;
+}
+
+static int
+unify_invalid (bool explain_p ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+unify_cv_qual_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  types %qT and %qT have incompatible cv-qualifiers",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_type_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  mismatched types %qT and %qT", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_mismatch (bool explain_p, tree parm)
+{
+  if (explain_p)
+    {
+      inform (input_location,
+	      "  template parameter %qD is not a parameter pack",
+	      parm);
+      inform (input_location, "  please report this as a bug");
+      gcc_unreachable ();
+    }
+  return 1;
+}
+
+static int
+unify_ptrmem_cst_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  mismatched pointer-to-memory constants %qE and %qE",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_constant_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  %qE is a constant and %qE is not",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_constant_unequal (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  %qE is not equal to %qE", parm, arg);
+  return 1;
+}
+
+static int
+unify_expression_unequal (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  %qE is not equal to %qE", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_inconsistent (bool explain_p,
+				   tree pack)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  portions of parameter pack %qT could not be deduced",
+	    pack);
+  return 1;
+}
+
+static int
+unify_inconsistency (bool explain_p, tree parm, tree first, tree second)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  deduced conflicting types for parameter %qT (%qT and %qT)",
+	    parm, first, second);
+  return 1;
+}
+
+static int
+unify_vla_arg (bool explain_p, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  variable-sized array type %qT is not "
+	    "a valid template argument",
+	    arg);
+  return 1;
+}
+
+static int
+unify_method_type_error (bool explain_p, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  method type %qT is not a valid template argument", arg);
+  return 1;
+}
+
+static int
+unify_arity (bool explain_p, int have, int wanted)
+{
+  if (explain_p)
+    inform_n (input_location, wanted,
+	      "  candidate expects %d argument, %d provided",
+	      "  candidate expects %d arguments, %d provided",
+	      wanted, have);
+  return 1;
+}
+
+static int
+unify_too_many_parameters (bool explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_too_few_parameters (bool explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_arg_conversion (bool explain_p, tree to_type,
+		      tree from_type, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  cannot convert %qE (type %qT) to type %qT",
+	    arg, from_type, to_type);
+  return 1;
+}
+
+static int
+unify_no_common_base (bool explain_p, enum template_base_result r,
+		      tree parm, tree arg)
+{
+  if (explain_p)
+    switch (r)
+      {
+      case tbr_ambiguous_baseclass:
+	inform (input_location, "  %qT is an ambiguous base class of %qT",
+		arg, parm);
+	break;
+      default:
+	inform (input_location, "  %qT is not derived from %qT", arg, parm);
+	break;
+      }
+  return 1;
+}
+
+static int
+unify_inconsistent_template_template_parameters (bool explain_p)
+{
+  if (explain_p)
+    inform (input_location, "  inconsistent template template parameters");
+  return 1;
+}
+
+static int
+unify_template_deduction_failure (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  can't deduce a template for %qT from non-template type %qT",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_template_parameter_mismatch (bool explain_p, tree parm, tree tparm)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template parameter %qT does not match %qD", tparm, parm);
+  return 1;
+}
+
+static int
+unify_template_argument_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template argument %qE does not match %qD", arg, parm);
+  return 1;
+}
+
 /* Attempt to convert the non-type template parameter EXPR to the
    indicated TYPE.  If the conversion is successful, return the
    converted value.  If the conversion is unsuccessful, return
@@ -13608,7 +13845,7 @@  static GTY((param_is (spec_entry))) htab_t current_deduction_htab;
    0.5% of compile time.  */
 
 static tree
-deduction_tsubst_fntype (tree fn, tree targs)
+deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
 {
   unsigned i;
   spec_entry **slot;
@@ -13678,7 +13915,7 @@  deduction_tsubst_fntype (tree fn, tree targs)
       VEC_safe_push (spec_entry, gc, current_deduction_vec, &elt);
     }
 
-  r = tsubst (fntype, targs, tf_none, NULL_TREE);
+  r = tsubst (fntype, targs, complain, NULL_TREE);
 
   /* After doing the substitution, make sure we didn't hit it again.  Note
      that we might have switched to a hash table during tsubst.  */
@@ -13891,7 +14128,8 @@  fn_type_unification (tree fn,
 		     unsigned int nargs,
 		     tree return_type,
 		     unification_kind_t strict,
-		     int flags)
+		     int flags,
+		     bool explain_p)
 {
   tree parms;
   tree fntype;
@@ -13926,14 +14164,22 @@  fn_type_unification (tree fn,
       bool incomplete = false;
 
       if (explicit_targs == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       converted_args
 	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
 				  /*require_all_args=*/false,
 				  /*use_default_args=*/false));
       if (converted_args == error_mark_node)
-	return 1;
+	{
+	  /* Run it for diagnostics.  */
+	  if (explain_p)
+	    coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+				   tf_warning_or_error,
+				   /*require_all_args=*/false,
+				   /*use_default_args=*/false);
+	  return 1;
+	}
 
       /* Substitute the explicit args into the function type.  This is
 	 necessary so that, for instance, explicitly declared function
@@ -13991,12 +14237,23 @@  fn_type_unification (tree fn,
 
       processing_template_decl += incomplete;
       push_deduction_access_scope (fn);
-      fntype = deduction_tsubst_fntype (fn, converted_args);
+      fntype = deduction_tsubst_fntype (fn, converted_args, tf_none);
       pop_deduction_access_scope (fn);
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
-	return 1;
+	{
+	  if (explain_p)
+	    {
+	      processing_template_decl += incomplete;
+	      push_deduction_access_scope (fn);
+	      deduction_tsubst_fntype (fn, converted_args,
+				       tf_warning_or_error);
+	      pop_deduction_access_scope (fn);
+	      processing_template_decl -= incomplete;
+	    }
+	  return 1;
+	}
 
       /* Place the explicitly specified arguments in TARGS.  */
       for (i = NUM_TMPL_ARGS (converted_args); i--;)
@@ -14024,7 +14281,7 @@  fn_type_unification (tree fn,
      event.  */
   result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
 				  targs, parms, args, nargs, /*subr=*/0,
-				  strict, flags);
+				  strict, flags, explain_p);
 
   /* Now that we have bindings for all of the template arguments,
      ensure that the arguments deduced for the template template
@@ -14050,7 +14307,7 @@  fn_type_unification (tree fn,
   if (result == 0
       && !template_template_parm_bindings_ok_p 
            (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
-    return 1;
+    return unify_inconsistent_template_template_parameters (explain_p);
 
   if (result == 0)
     /* All is well so far.  Now, check:
@@ -14065,10 +14322,19 @@  fn_type_unification (tree fn,
     {
       tree substed;
       push_deduction_access_scope (fn);
-      substed = deduction_tsubst_fntype (fn, targs);
+      substed = deduction_tsubst_fntype (fn, targs, tf_none);
       pop_deduction_access_scope (fn);
       if (substed == error_mark_node)
-	return 1;
+	{
+	  if (explain_p)
+	    {
+	      push_deduction_access_scope (fn);
+	      deduction_tsubst_fntype (fn, targs,
+				       tf_warning_or_error);
+	      pop_deduction_access_scope (fn);
+	    }
+	  return 1;
+	}
 
       /* If we're looking for an exact match, check that what we got
 	 is indeed an exact match.  It might not be if some template
@@ -14083,7 +14349,7 @@  fn_type_unification (tree fn,
 	    sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg);
 	  for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg))
 	    if (!same_type_p (args[i], TREE_VALUE (sarg)))
-	      return 1;
+	      return unify_unknown (explain_p);
 	}
     }
 
@@ -14214,7 +14480,8 @@  type_unification_real (tree tparms,
 		       unsigned int xnargs,
 		       int subr,
 		       unification_kind_t strict,
-		       int flags)
+		       int flags,
+		       bool explain_p)
 {
   tree parm, arg, arg_expr;
   int i;
@@ -14285,7 +14552,7 @@  type_unification_real (tree tparms,
       arg_expr = NULL;
 
       if (arg == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
       if (arg == unknown_type_node)
 	/* We can't deduce anything from this, but we might get all the
 	   template args from other function args.  */
@@ -14311,7 +14578,7 @@  type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  return unify_arg_conversion (explain_p, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14327,15 +14594,15 @@  type_unification_real (tree tparms,
 		 function templates and at most one of a set of
 		 overloaded functions provides a unique match.  */
 	      if (resolve_overloaded_unification
-		  (tparms, targs, parm, arg, strict, sub_strict))
+		  (tparms, targs, parm, arg, strict, sub_strict, explain_p))
 		continue;
 
-	      return 1;
+	      return unify_unknown (explain_p);
 	    }
 	  arg_expr = arg;
 	  arg = unlowered_expr_type (arg);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 	}
 
       {
@@ -14347,7 +14614,9 @@  type_unification_real (tree tparms,
 
 	if (arg == init_list_type_node && arg_expr)
 	  arg = arg_expr;
-	if (unify (tparms, targs, parm, arg, arg_strict))
+	if (unify (tparms, targs, parm, arg, arg_strict, explain_p))
+	  /* If unification failed, the recursive call will have updated
+	     UI appropriately.  */
 	  return 1;
       }
     }
@@ -14369,7 +14638,7 @@  type_unification_real (tree tparms,
       /* Copy the parameter into parmvec.  */
       TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
       if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
-                                /*call_args_p=*/true, /*subr=*/subr))
+                                /*call_args_p=*/true, /*subr=*/subr, explain_p))
         return 1;
 
       /* Advance to the end of the list of parameters.  */
@@ -14379,11 +14648,20 @@  type_unification_real (tree tparms,
   /* Fail if we've reached the end of the parm list, and more args
      are present, and the parm list isn't variadic.  */
   if (ia < nargs && parms == void_list_node)
-    return 1;
+    return unify_too_many_parameters (explain_p, nargs, ia);
   /* Fail if parms are left and they don't have default values.  */
   if (parms && parms != void_list_node
       && TREE_PURPOSE (parms) == NULL_TREE)
-    return 1;
+    {
+      unsigned int count = nargs;
+      tree p = parms;
+      while (p && p != void_list_node)
+	{
+	  count++;
+	  p = TREE_CHAIN (p);
+	}
+      return unify_too_few_parameters (explain_p, ia, count);
+    }
 
   if (!subr)
     {
@@ -14441,7 +14719,14 @@  type_unification_real (tree tparms,
 	      arg = convert_template_argument (parm, arg, targs, tf_none,
 					       i, NULL_TREE);
 	      if (arg == error_mark_node)
-		return 1;
+		{
+		  /* Give the user an informative error message.  */
+		  if (explain_p)
+		    convert_template_argument (parm, arg, targs,
+					       tf_warning_or_error,
+					       i, NULL_TREE);
+		  return 1;
+		}
 	      else
 		{
 		  TREE_VEC_ELT (targs, i) = arg;
@@ -14475,7 +14760,7 @@  type_unification_real (tree tparms,
 	      continue;
 	    }
 
-	  return 2;
+	  return unify_parameter_deduction_failure (explain_p, tparm);
 	}
     }
 #ifdef ENABLE_CHECKING
@@ -14483,7 +14768,7 @@  type_unification_real (tree tparms,
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
 #endif
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Subroutine of type_unification_real.  Args are like the variables
@@ -14498,7 +14783,8 @@  resolve_overloaded_unification (tree tparms,
 				tree parm,
 				tree arg,
 				unification_kind_t strict,
-				int sub_strict)
+				int sub_strict,
+			        bool explain_p)
 {
   tree tempargs = copy_node (targs);
   int good = 0;
@@ -14549,7 +14835,7 @@  resolve_overloaded_unification (tree tparms,
 	    {
 	      elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);
 	      if (try_one_overload (tparms, targs, tempargs, parm,
-				    elem, strict, sub_strict, addr_p)
+				    elem, strict, sub_strict, addr_p, explain_p)
 		  && (!goodfn || !decls_match (goodfn, elem)))
 		{
 		  goodfn = elem;
@@ -14569,7 +14855,7 @@  resolve_overloaded_unification (tree tparms,
     for (; arg; arg = OVL_NEXT (arg))
       if (try_one_overload (tparms, targs, tempargs, parm,
 			    TREE_TYPE (OVL_CURRENT (arg)),
-			    strict, sub_strict, addr_p)
+			    strict, sub_strict, addr_p, explain_p)
 	  && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg))))
 	{
 	  goodfn = OVL_CURRENT (arg);
@@ -14715,7 +15001,8 @@  try_one_overload (tree tparms,
 		  tree arg,
 		  unification_kind_t strict,
 		  int sub_strict,
-		  bool addr_p)
+		  bool addr_p,
+		  bool explain_p)
 {
   int nargs;
   tree tempargs;
@@ -14745,7 +15032,7 @@  try_one_overload (tree tparms,
   nargs = TREE_VEC_LENGTH (targs);
   tempargs = make_tree_vec (nargs);
 
-  if (unify (tparms, tempargs, parm, arg, sub_strict) != 0)
+  if (unify (tparms, tempargs, parm, arg, sub_strict, explain_p))
     return 0;
 
   /* First make sure we didn't deduce anything that conflicts with
@@ -14783,7 +15070,8 @@  try_one_overload (tree tparms,
    TARGS are as for unify.  */
 
 static tree
-try_class_unification (tree tparms, tree targs, tree parm, tree arg)
+try_class_unification (tree tparms, tree targs, tree parm, tree arg,
+		       bool explain_p)
 {
   tree copy_of_targs;
 
@@ -14826,7 +15114,7 @@  try_class_unification (tree tparms, tree targs, tree parm, tree arg)
 
   /* If unification failed, we're done.  */
   if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
-	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE))
+	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p))
     return NULL_TREE;
 
   return arg;
@@ -14839,8 +15127,9 @@  try_class_unification (tree tparms, tree targs, tree parm, tree arg)
    a partial specialization, as well as a plain template type.  Used
    by unify.  */
 
-static tree
-get_template_base (tree tparms, tree targs, tree parm, tree arg)
+static enum template_base_result
+get_template_base (tree tparms, tree targs, tree parm, tree arg,
+		   bool explain_p, tree *result)
 {
   tree rval = NULL_TREE;
   tree binfo;
@@ -14849,14 +15138,18 @@  get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
   binfo = TYPE_BINFO (complete_type (arg));
   if (!binfo)
-    /* The type could not be completed.  */
-    return NULL_TREE;
+    {
+      /* The type could not be completed.  */
+      *result = NULL_TREE;
+      return tbr_incomplete_type;
+    }
 
   /* Walk in inheritance graph order.  The search order is not
      important, and this avoids multiple walks of virtual bases.  */
   for (binfo = TREE_CHAIN (binfo); binfo; binfo = TREE_CHAIN (binfo))
     {
-      tree r = try_class_unification (tparms, targs, parm, BINFO_TYPE (binfo));
+      tree r = try_class_unification (tparms, targs, parm,
+				      BINFO_TYPE (binfo), explain_p);
 
       if (r)
 	{
@@ -14869,13 +15162,17 @@  get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
 	     applies.  */
 	  if (rval && !same_type_p (r, rval))
-	    return NULL_TREE;
+	    {
+	      *result = NULL_TREE;
+	      return tbr_ambiguous_baseclass;
+	    }
 
 	  rval = r;
 	}
     }
 
-  return rval;
+  *result = rval;
+  return tbr_success;
 }
 
 /* Returns the level of DECL, which declares a template parameter.  */
@@ -14957,6 +15254,12 @@  template_parm_level_and_index (tree parm, int* level, int* index)
     }
 }
 
+#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP)			\
+  do {									\
+    if (unify (TP, TA, P, A, S, EP))					\
+      return 1;								\
+  } while (0);
+
 /* Unifies the remaining arguments in PACKED_ARGS with the pack
    expansion at the end of PACKED_PARMS. Returns 0 if the type
    deduction succeeds, 1 otherwise. STRICT is the same as in
@@ -14964,10 +15267,10 @@  template_parm_level_and_index (tree parm, int* level, int* index)
    call argument list. We'll need to adjust the arguments to make them
    types. SUBR tells us if this is from a recursive call to
    type_unification_real.  */
-int
+static int
 unify_pack_expansion (tree tparms, tree targs, tree packed_parms, 
                       tree packed_args, int strict, bool call_args_p,
-                      bool subr)
+                      bool subr, bool explain_p)
 {
   tree parm 
     = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
@@ -15057,7 +15360,7 @@  unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
                     if (resolve_overloaded_unification
                         (tparms, targs, parm, arg,
 			 (unification_kind_t) strict,
-			 sub_strict)
+			 sub_strict, explain_p)
                         != 0)
                       return 1;
                     skip_arg_p = true;
@@ -15085,8 +15388,8 @@  unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	    /* For deduction from an init-list we need the actual list.  */
 	    if (arg_expr && BRACE_ENCLOSED_INITIALIZER_P (arg_expr))
 	      arg = arg_expr;
-            if (unify (tparms, targs, parm, arg, arg_strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs, parm, arg, arg_strict,
+				     explain_p);
           }
       }
 
@@ -15180,10 +15483,10 @@  unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
       else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
                                     new_args))
         /* Inconsistent unification of this parameter pack.  */
-        return 1;
+        return unify_parameter_pack_inconsistent (explain_p, old_pack);
     }
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
@@ -15228,7 +15531,8 @@  unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
        qualified at this point.  */
 
 static int
-unify (tree tparms, tree targs, tree parm, tree arg, int strict)
+unify (tree tparms, tree targs, tree parm, tree arg, int strict,
+       bool explain_p)
 {
   int idx;
   tree targ;
@@ -15243,19 +15547,19 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     parm = TREE_OPERAND (parm, 0);
 
   if (arg == error_mark_node)
-    return 1;
+    return unify_invalid (explain_p);
   if (arg == unknown_type_node
       || arg == init_list_type_node)
     /* We can't deduce anything from this, but we might get all the
        template args from other function args.  */
-    return 0;
+    return unify_success (explain_p);
 
   /* If PARM uses template parameters, then we can't bail out here,
      even if ARG == PARM, since we won't record unifications for the
      template parameters.  We might need them if we're trying to
      figure out which of two things is more specialized.  */
   if (arg == parm && !uses_template_parms (parm))
-    return 0;
+    return unify_success (explain_p);
 
   /* Handle init lists early, so the rest of the function can assume
      we're dealing with a type. */
@@ -15274,7 +15578,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	/* We can only deduce from an initializer list argument if the
 	   parameter is std::initializer_list; otherwise this is a
 	   non-deduced context. */
-	return 0;
+	return unify_success (explain_p);
 
       elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
 
@@ -15283,7 +15587,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  int elt_strict = strict;
 
 	  if (elt == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
 	    {
@@ -15295,8 +15599,8 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	      elt = type;
 	    }
 
-	  if (unify (tparms, targs, elttype, elt, elt_strict))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, elttype, elt, elt_strict,
+				   explain_p);
 	}
 
       /* If the std::initializer_list<T> deduction worked, replace the
@@ -15308,7 +15612,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  targ = listify (targ);
 	  TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
 	}
-      return 0;
+      return unify_success (explain_p);
     }
 
   /* Immediately reject some pairs that won't unify because of
@@ -15325,7 +15629,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 is more specialized, for example.  */
       && TREE_CODE (arg) != TEMPLATE_TYPE_PARM
       && !check_cv_quals_for_unify (strict_in, arg, parm))
-    return 1;
+    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
   if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)
       && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))
@@ -15343,21 +15647,26 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       /* In a type which contains a nested-name-specifier, template
 	 argument values cannot be deduced for template parameters used
 	 within the nested-name-specifier.  */
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_TYPE_LEVEL (parm)
 	  != template_decl_level (tparm))
 	/* The PARM is not one we're trying to unify.  Just check
 	   to see if it matches ARG.  */
-	return (TREE_CODE (arg) == TREE_CODE (parm)
-		&& same_type_p (parm, arg)) ? 0 : 1;
+	{
+	  if (TREE_CODE (arg) == TREE_CODE (parm)
+	      && same_type_p (parm, arg))
+	    return unify_success (explain_p);
+	  else
+	    return unify_type_mismatch (explain_p, parm, arg);
+	}
       idx = TEMPLATE_TYPE_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
@@ -15367,7 +15676,8 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	   && TREE_CODE (tparm) != TYPE_DECL)
 	  || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
 	      && TREE_CODE (tparm) != TEMPLATE_DECL))
-	return 1;
+	return unify_template_parameter_mismatch (explain_p,
+						  parm, tparm);
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15375,7 +15685,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     template parameter.  */
 	  if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
 	      && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
-	    return 1;
+	    return unify_template_deduction_failure (explain_p, parm, arg);
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15421,7 +15731,16 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				       /*require_all_args=*/true,
 				       /*use_default_args=*/false)
 		== error_mark_node)
-	      return 1;
+	      {
+		/* Run it for diagnostics.  */
+		if (explain_p)
+		  coerce_template_parms (parm_parms, full_argvec,
+					 TYPE_TI_TEMPLATE (parm),
+					 tf_warning_or_error,
+					 /*require_all_args=*/true,
+					 /*use_default_args=*/false);
+		return 1;
+	      }
 
 	    /* Deduce arguments T, i from TT<T> or TT<i>.
 	       We check each element of PARMVEC and ARGVEC individually
@@ -15440,15 +15759,15 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
               parm_variadic_p = 1;
             
             if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
-              return 1;
+              return unify_too_few_parameters (explain_p, TREE_VEC_LENGTH (argvec),
+					       len);
 
              for (i = 0; i < len - parm_variadic_p; ++i)
 	      {
-		if (unify (tparms, targs,
-			   TREE_VEC_ELT (parmvec, i),
-			   TREE_VEC_ELT (argvec, i),
-			   UNIFY_ALLOW_NONE))
-		  return 1;
+		RECUR_AND_CHECK_FAILURE (tparms, targs,
+					 TREE_VEC_ELT (parmvec, i),
+					 TREE_VEC_ELT (argvec, i),
+					 UNIFY_ALLOW_NONE, explain_p);
 	      }
 
 	    if (parm_variadic_p
@@ -15456,7 +15775,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 					 parmvec, argvec,
 					 UNIFY_ALLOW_NONE,
 					 /*call_args_p=*/false,
-					 /*subr=*/false))
+					 /*subr=*/false, explain_p))
 	      return 1;
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
@@ -15471,9 +15790,9 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && template_args_equal (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 	}
       else
 	{
@@ -15483,20 +15802,20 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     that binds `const int' to `T'.  */
 	  if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL,
 					 arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
 	  /* Consider the case where ARG is `const volatile int' and
 	     PARM is `const T'.  Then, T should be `volatile int'.  */
 	  arg = cp_build_qualified_type_real
 	    (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && same_type_p (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 
 	  /* Make sure that ARG is not a variable-sized array.  (Note
 	     that were talking about variable-sized arrays (like
@@ -15506,7 +15825,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     instantiation.  Besides, such types are not allowed in
 	     ISO C++, so we can do as we please here.  */
 	  if (variably_modified_type_p (arg, NULL_TREE))
-	    return 1;
+	    return unify_vla_arg (explain_p, arg);
 
 	  /* Strip typedefs as in convert_template_argument.  */
 	  arg = strip_typedefs (arg);
@@ -15516,35 +15835,45 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !template_parameter_pack_p (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm);
 
       /* If the argument deduction results is a METHOD_TYPE,
          then there is a problem.
          METHOD_TYPE doesn't map to any real C++ type the result of
 	 the deduction can not be of that type.  */
       if (TREE_CODE (arg) == METHOD_TYPE)
-	return 1;
+	return unify_method_type_error (explain_p, arg);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_PARM_INDEX:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_PARM_LEVEL (parm)
 	  != template_decl_level (tparm))
-	/* The PARM is not one we're trying to unify.  Just check
-	   to see if it matches ARG.  */
-	return !(TREE_CODE (arg) == TREE_CODE (parm)
-		 && cp_tree_equal (parm, arg));
+	{
+	  /* The PARM is not one we're trying to unify.  Just check
+	     to see if it matches ARG.  */
+	  int result = !(TREE_CODE (arg) == TREE_CODE (parm)
+			 && cp_tree_equal (parm, arg));
+	  if (result)
+	    unify_template_parameter_mismatch (explain_p, parm, tparm);
+	  return result;
+	}
 
       idx = TEMPLATE_PARM_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
 
       if (targ)
-	return !cp_tree_equal (targ, arg);
+	{
+	  int x = !cp_tree_equal (targ, arg);
+	  if (x)
+	    unify_inconsistency (explain_p, parm, targ, arg);
+	  return x;
+	}
 
       /* [temp.deduct.type] If, in the declaration of a function template
 	 with a non-type template-parameter, the non-type
@@ -15571,25 +15900,25 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       else if (uses_template_parms (tparm))
 	/* We haven't deduced the type of this parameter yet.  Try again
 	   later.  */
-	return 0;
+	return unify_success (explain_p);
       else
-	return 1;
+	return unify_type_mismatch (explain_p, tparm, arg);
 
       /* If ARG is a parameter pack or an expansion, we cannot unify
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case PTRMEM_CST:
      {
 	/* A pointer-to-member constant can be unified only with
 	 another constant.  */
       if (TREE_CODE (arg) != PTRMEM_CST)
-	return 1;
+	return unify_ptrmem_cst_mismatch (explain_p, parm, arg);
 
       /* Just unify the class member. It would be useless (and possibly
 	 wrong, depending on the strict flags) to unify also
@@ -15602,13 +15931,13 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	 Unification of &A::x and &B::x must succeed.  */
       return unify (tparms, targs, PTRMEM_CST_MEMBER (parm),
-		    PTRMEM_CST_MEMBER (arg), strict);
+		    PTRMEM_CST_MEMBER (arg), strict, explain_p);
      }
 
     case POINTER_TYPE:
       {
 	if (TREE_CODE (arg) != POINTER_TYPE)
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* [temp.deduct.call]
 
@@ -15626,21 +15955,21 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  strict |= (strict_in & UNIFY_ALLOW_DERIVED);
 
 	return unify (tparms, targs, TREE_TYPE (parm),
-		      TREE_TYPE (arg), strict);
+		      TREE_TYPE (arg), strict, explain_p);
       }
 
     case REFERENCE_TYPE:
       if (TREE_CODE (arg) != REFERENCE_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case ARRAY_TYPE:
       if (TREE_CODE (arg) != ARRAY_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if ((TYPE_DOMAIN (parm) == NULL_TREE)
 	  != (TYPE_DOMAIN (arg) == NULL_TREE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if (TYPE_DOMAIN (parm) != NULL_TREE)
 	{
 	  tree parm_max;
@@ -15679,7 +16008,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
                 Here, the type of the ARG will be "int [g(i)]", and
                 may be a SAVE_EXPR, etc.  */
 	      if (TREE_CODE (arg_max) != MINUS_EXPR)
-		return 1;
+		return unify_vla_arg (explain_p, arg);
 	      arg_max = TREE_OPERAND (arg_max, 0);
 	    }
 
@@ -15696,11 +16025,11 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				   arg_max,
 				   integer_one_node);
 
-	  if (unify (tparms, targs, parm_max, arg_max, UNIFY_ALLOW_INTEGER))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, parm_max, arg_max,
+				   UNIFY_ALLOW_INTEGER, explain_p);
 	}
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -15710,16 +16039,16 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case ENUMERAL_TYPE:
     case VOID_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* We have already checked cv-qualification at the top of the
 	 function.  */
       if (!same_type_ignoring_top_level_qualifiers_p (arg, parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* As far as unification is concerned, this wins.	 Later checks
 	 will invalidate it if necessary.  */
-      return 0;
+      return unify_success (explain_p);
 
       /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
       /* Type INTEGER_CST can come from ordinary constant template args.  */
@@ -15728,38 +16057,41 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	arg = TREE_OPERAND (arg, 0);
 
       if (TREE_CODE (arg) != INTEGER_CST)
-	return 1;
-      return !tree_int_cst_equal (parm, arg);
+	return unify_constant_mismatch (explain_p, parm, arg);
+      return (tree_int_cst_equal (parm, arg)
+	      ? unify_success (explain_p)
+	      : unify_constant_unequal (explain_p, parm, arg));
 
     case TREE_VEC:
       {
 	int i;
 	if (TREE_CODE (arg) != TREE_VEC)
-	  return 1;
+	  return unify_template_argument_mismatch (explain_p, parm, arg);
 	if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
-	  return 1;
+	  return unify_arity (explain_p, TREE_VEC_LENGTH (arg),
+			      TREE_VEC_LENGTH (parm));
 	for (i = 0; i < TREE_VEC_LENGTH (parm); ++i)
-	  if (unify (tparms, targs,
-		     TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
-		     UNIFY_ALLOW_NONE))
-	    return 1;
-	return 0;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs,
+				   TREE_VEC_ELT (parm, i),
+				   TREE_VEC_ELT (arg, i),
+				   UNIFY_ALLOW_NONE, explain_p);
+	return unify_success (explain_p);
       }
 
     case RECORD_TYPE:
     case UNION_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       if (TYPE_PTRMEMFUNC_P (parm))
 	{
 	  if (!TYPE_PTRMEMFUNC_P (arg))
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs,
 			TYPE_PTRMEMFUNC_FN_TYPE (parm),
 			TYPE_PTRMEMFUNC_FN_TYPE (arg),
-			strict);
+			strict, explain_p);
 	}
 
       if (CLASSTYPE_TEMPLATE_INFO (parm))
@@ -15770,7 +16102,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    {
 	      /* First, we try to unify the PARM and ARG directly.  */
 	      t = try_class_unification (tparms, targs,
-					 parm, arg);
+					 parm, arg, explain_p);
 
 	      if (!t)
 		{
@@ -15783,10 +16115,12 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		       a class of the form template-id, A can be a
 		       pointer to a derived class pointed to by the
 		       deduced A.  */
-		  t = get_template_base (tparms, targs, parm, arg);
+		  enum template_base_result r;
+		  r = get_template_base (tparms, targs, parm, arg,
+					 explain_p, &t);
 
 		  if (!t)
-		    return 1;
+		    return unify_no_common_base (explain_p, r, parm, arg);
 		}
 	    }
 	  else if (CLASSTYPE_TEMPLATE_INFO (arg)
@@ -15797,14 +16131,14 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    t = arg;
 	  else
 	    /* There's no chance of unification succeeding.  */
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE);
+			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p);
 	}
       else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
-	return 1;
-      return 0;
+	return unify_type_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -15815,7 +16149,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	unsigned int i;
 
 	if (TREE_CODE (arg) != TREE_CODE (parm))
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* CV qualifications for methods can never be deduced, they must
 	   match exactly.  We need to check them explicitly here,
@@ -15826,11 +16160,10 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		(UNIFY_ALLOW_NONE,
 		 class_of_this_parm (arg),
 		 class_of_this_parm (parm))))
-	  return 1;
+	  return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	if (unify (tparms, targs, TREE_TYPE (parm),
-		   TREE_TYPE (arg), UNIFY_ALLOW_NONE))
-	  return 1;
+	RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm),
+				 TREE_TYPE (arg), UNIFY_ALLOW_NONE, explain_p);
 
 	nargs = list_length (TYPE_ARG_TYPES (arg));
 	args = XALLOCAVEC (tree, nargs);
@@ -15842,7 +16175,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
 				      args, nargs, 1, DEDUCE_EXACT,
-				      LOOKUP_NORMAL);
+				      LOOKUP_NORMAL, explain_p);
       }
 
     case OFFSET_TYPE:
@@ -15855,11 +16188,11 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Check top-level cv qualifiers */
 	  if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	  if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		     TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+				   TYPE_PTRMEMFUNC_OBJECT_TYPE (arg),
+				   UNIFY_ALLOW_NONE, explain_p);
 
 	  /* Determine the type of the function we are unifying against. */
 	  method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
@@ -15871,28 +16204,28 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     implicit object parameter and place them on the function
 	     type to be restored later. */
 	  fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type));
-	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict);
+	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, explain_p);
 	}
 
       if (TREE_CODE (arg) != OFFSET_TYPE)
-	return 1;
-      if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		 TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
+      RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+			       TYPE_OFFSET_BASETYPE (arg),
+			       UNIFY_ALLOW_NONE, explain_p);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict);
+		    strict, explain_p);
 
     case CONST_DECL:
       if (DECL_TEMPLATE_PARM_P (parm))
-	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict);
+	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict, explain_p);
       if (arg != integral_constant_value (parm))
-	return 1;
-      return 0;
+	return unify_constant_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case FIELD_DECL:
     case TEMPLATE_DECL:
       /* Matched cases are handled by the ARG == PARM test above.  */
-      return 1;
+      return unify_template_argument_mismatch (explain_p, parm, arg);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15922,7 +16255,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		  /* Since there is something following the pack
 		     expansion, we cannot unify this template argument
 		     list.  */
-		  return 0;
+		  return unify_success (explain_p);
 	      }
 	  }
 	  
@@ -15931,25 +16264,27 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
            (not counting the pack expression at the end), or we have
            too many arguments for a parameter list that doesn't end in
            a pack expression, we can't unify.  */
-        if (argslen < (len - parm_variadic_p)
-            || (argslen > len && !parm_variadic_p))
-          return 1;
+        if (argslen < (len - parm_variadic_p))
+	  return unify_too_few_parameters (explain_p, argslen, len);
+	if (argslen > len && !parm_variadic_p)
+	  return unify_too_many_parameters (explain_p, argslen, len);
 
         /* Unify all of the parameters that precede the (optional)
            pack expression.  */
         for (i = 0; i < len - parm_variadic_p; ++i)
           {
-            if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
-                       TREE_VEC_ELT (packed_args, i), strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs,
+				     TREE_VEC_ELT (packed_parms, i),
+				     TREE_VEC_ELT (packed_args, i),
+				     strict, explain_p);
           }
 
         if (parm_variadic_p)
           return unify_pack_expansion (tparms, targs, 
                                        packed_parms, packed_args,
                                        strict, /*call_args_p=*/false,
-                                       /*subr=*/false);
-        return 0;
+                                       /*subr=*/false, explain_p);
+        return unify_success (explain_p);
       }
 
       break;
@@ -15959,16 +16294,16 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case UNDERLYING_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
 	 or UNDERLYING_TYPE nodes.  */
-      return 0;
+      return unify_success (explain_p);
 
     case ERROR_MARK:
       /* Unification fails if we hit an error node.  */
-      return 1;
+      return unify_invalid (explain_p);
 
     default:
       /* An unresolved overload is a nondeduced context.  */
       if (type_unknown_p (parm))
-	return 0;
+	return unify_success (explain_p);
       gcc_assert (EXPR_P (parm));
 
       /* We must be looking at an expression.  This can happen with
@@ -15992,11 +16327,12 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
       if (!uses_template_parms (parm)
 	  && !template_args_equal (parm, arg))
-	return 1;
+	return unify_expression_unequal (explain_p, parm, arg);
       else
-	return 0;
+	return unify_success (explain_p);
     }
 }
+#undef RECUR_AND_CHECK_FAILURE
 
 /* Note that DECL can be defined in this translation unit, if
    required.  */
@@ -16259,10 +16595,11 @@  more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec, 
+          deduce1 = (unify_pack_expansion (tparms1, targs1, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/false)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG1 is
              a pack expansion but ARG2 is not.  */
@@ -16283,10 +16620,11 @@  more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec, 
+          deduce2 = (unify_pack_expansion (tparms2, targs2, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/false)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG2 is
              a pack expansion but ARG1 is not.*/
@@ -16297,8 +16635,12 @@  more_specialized_fn (tree pat1, tree pat2, int len)
         {
           /* The normal case, where neither argument is a pack
              expansion.  */
-          deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
-          deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+          deduce1 = (unify (tparms1, targs1, arg1, arg2,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/false)
+		     == 0);
+          deduce2 = (unify (tparms2, targs2, arg2, arg1,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/false)
+		     == 0);
         }
 
       /* If we couldn't deduce arguments for tparms1 to make arg1 match
@@ -16512,7 +16854,7 @@  get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
 			   args, ix,
 			   (check_rettype || DECL_CONV_FN_P (fn)
 			    ? TREE_TYPE (decl_type) : NULL_TREE),
-			   DEDUCE_EXACT, LOOKUP_NORMAL))
+			   DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false))
     return NULL_TREE;
 
   return targs;
@@ -16554,7 +16896,7 @@  get_class_bindings (tree tparms, tree spec_args, tree args)
   if (unify (tparms, deduced_args,
 	     INNERMOST_TEMPLATE_ARGS (spec_args),
 	     INNERMOST_TEMPLATE_ARGS (args),
-	     UNIFY_ALLOW_NONE))
+	     UNIFY_ALLOW_NONE, /*explain_p=*/false))
     return NULL_TREE;
 
   for (i =  0; i < ntparms; ++i)
@@ -19289,8 +19631,11 @@  do_auto_deduction (tree type, tree init, tree auto_node)
   targs = make_tree_vec (1);
   TREE_VEC_ELT (tparms, 0)
     = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
+  /* FIXME: Should we pass in unification information and then use that
+     to elaborate on the error messages below?  */
   val = type_unification_real (tparms, targs, parms, args, 1, 0,
-			       DEDUCE_CALL, LOOKUP_NORMAL);
+			       DEDUCE_CALL, LOOKUP_NORMAL,
+			       /*explain_p=*/false);
   if (val > 0)
     {
       if (type && type != error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
index 352137a..120dfaa 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
@@ -9,8 +9,9 @@  decltype(F()) run(F f) // { dg-message "note" }
 
 int main()
 {
-  auto l = []() { return 5; };
+  auto l = []() { return 5; }; // { dg-error "lambda closure type" }
 
   run(l); // { dg-error "no match" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 14 }
+  // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 14 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr15.C b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
index e02fd55..af661ec 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
@@ -17,10 +17,10 @@  void test_g()
   // Deduction to nullptr_t, no deduction to pointer type
   //
   g(nullptr);               // { dg-error "no matching function for call to " }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 19 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 19 }
   type_equal<float*>(g((float*)nullptr));
   decltype(nullptr) mynull = 0;
   g(mynull);                // { dg-error "no matching function for call to " }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 23 }
   type_equal<float*>(g((float*)mynull));
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
index 15efbc5..0764939 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
@@ -4,5 +4,5 @@  template<typename, typename..., typename> void foo(); // { dg-message "note" }
 void bar()
 {
   foo<int>(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431.C b/gcc/testsuite/g++.dg/cpp0x/pr31431.C
index 36f341f..afd3237 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31431.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31431.C
@@ -4,5 +4,5 @@  template<typename..., typename> void foo(); // { dg-message "note" }
 void bar()
 {
   foo<int>(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
index 97ad079..5478616 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31434.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
@@ -8,5 +8,5 @@  template<typename... T> int foo(const T&) // { dg-error "not expanded with|T" }
 void bar()
 {
   foo(0); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|cannot convert)" "candidate note" { target *-*-* } 10 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
index a3ffc34..a525566 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
@@ -50,7 +50,7 @@  int main()
   static_assert(  noexcept( f2(y) ), "OK." );
   // static_assert(  noexcept( f3(y) ), "shall be ill-formed(OK)." );
 
-  static_assert(  noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" }
-  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
-  static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" }
+  static_assert(  noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" }
+  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "(no match|could not convert)" }
+  static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
index fa2bb6a..dab1650 100644
--- a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
@@ -8,7 +8,7 @@  void g()
   f(1, 'c'); // f<int,char>(1,'c') 
   f(1); // f<int,double>(1,0) 
   f(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   f<int>(); // f<int,double>(0,0) 
   f<int,char>(); // f<int,char>(0,0) 
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing4.C b/gcc/testsuite/g++.dg/cpp0x/trailing4.C
index d67b3b6..8d4baa9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/trailing4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing4.C
@@ -8,5 +8,5 @@  auto f(T,U) -> decltype(T() + U())
 template<class T> void g(T){}	// { dg-message "note" }
 
 int main() { g(f); }		// { dg-error "no matching function" }
-// { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+// { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
index bd97305..018eaa3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
@@ -4,8 +4,8 @@  void g()
 { 
   int i = f<int>(5.6);
   int j = f(5.6);         // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
   f<void>(f<int, bool>);
   f<void>(f<int>);        // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 9 }
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
index 5bf2116..0a777c4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
@@ -8,6 +8,6 @@  void g()
   f<int>("aa",3.0); // Y is deduced to be char*, and 
                     // Z is deduced to be double 
   f("aa",3.0); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   f2<char, short, int, long>(); // okay
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic105.C b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
index 24d7e15..2729b31 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic105.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
@@ -21,4 +21,5 @@  struct call_sum {
 int main() {
   // This shouldn't be an error; this is bug 35722.
   reverse<call_sum>(1,2);	// { dg-bogus "no match" "" { xfail *-*-* } }
+  // { dg-message "sorry, unimplemented" "candidate explanation" { target *-*-* } 23 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C b/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
index 2ff7e5b..5514259 100644
--- a/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
@@ -4,7 +4,7 @@  template<class U, class... T>
 void f()			// { dg-message "note" }
 {
   f<T...>(); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
 
 template<>
diff --git a/gcc/testsuite/g++.dg/ext/vla2.C b/gcc/testsuite/g++.dg/ext/vla2.C
index f6a9deb..3e83c8b 100644
--- a/gcc/testsuite/g++.dg/ext/vla2.C
+++ b/gcc/testsuite/g++.dg/ext/vla2.C
@@ -15,5 +15,5 @@  void bar(int i)
   char d[i] ;
   
   begin(d);  // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+  // { dg-message "(candidate|valid template argument)" "candidate note" { target *-*-* } 17 }
 }
diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C
index bc386ed..a17df7f 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem10.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem10.C
@@ -13,7 +13,7 @@  template <class C>
 static void
 bar(C *c, void (C::*m) ())
 {
-  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun)" }
+  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
 }
 
diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C
index 119cbb0..e73164e 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem11.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem11.C
@@ -14,7 +14,7 @@  template <typename T>
 int
 bar(int T::* p)
 {
-  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member)" }
+  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
 }
 
diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C
new file mode 100644
index 0000000..b1dc65e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/template5.C
@@ -0,0 +1,15 @@ 
+// { dg-do compile }
+
+template<typename T>
+int low(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+
+template<typename T>
+int high(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+
+int test (void)
+{
+  low (5, 6);			// { dg-error "no matching function" }
+  // { dg-message "(candidate|3 arguments, 2 provided)" "" { target *-*-* } 11 }
+  high (5, 6, 7, 8);		// { dg-error "no matching function" }
+  // { dg-message "(candidate|3 arguments, 4 provided)" "" { target *-*-* } 13 }
+}
diff --git a/gcc/testsuite/g++.dg/overload/unknown1.C b/gcc/testsuite/g++.dg/overload/unknown1.C
index 935f8d4..128c434 100644
--- a/gcc/testsuite/g++.dg/overload/unknown1.C
+++ b/gcc/testsuite/g++.dg/overload/unknown1.C
@@ -6,5 +6,5 @@  template <typename T> void bar(T f); // { dg-message "note" }
 
 void baz() {
   bar(foo); // { dg-error "<unresolved overloaded function type>" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/conv11.C b/gcc/testsuite/g++.dg/template/conv11.C
index 57d06af..f08e756 100644
--- a/gcc/testsuite/g++.dg/template/conv11.C
+++ b/gcc/testsuite/g++.dg/template/conv11.C
@@ -7,5 +7,5 @@  struct A
 int main()
 {
   A().operator int();		// { dg-error "operator int" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 9 }
 }
diff --git a/gcc/testsuite/g++.dg/template/dependent-expr5.C b/gcc/testsuite/g++.dg/template/dependent-expr5.C
index 1e850cd..af0dfb9 100644
--- a/gcc/testsuite/g++.dg/template/dependent-expr5.C
+++ b/gcc/testsuite/g++.dg/template/dependent-expr5.C
@@ -40,12 +40,12 @@  struct foo {
       bind (&bar::baikt);
 
       bind (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 42 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 42 }
       bind (&foo::barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 44 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 44 }
 
       bindm (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 47 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 47 }
       bindm (&foo::barf);
 
       bindn (&barf);
@@ -53,15 +53,15 @@  struct foo {
 
       bindb (&barf);
       bindb (&foo::barf); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 55 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 55 }
 
       bind (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 58 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 58 }
       bind (&bar::bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 60 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 60 }
 
       bindm (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 63 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 63 }
       bindm (&bar::bark);
 
       bindn (&bark);
@@ -69,7 +69,7 @@  struct foo {
 
       bindb (&bark);
       bindb (&bar::bark); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 71 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 71 }
     }
   };
 
@@ -92,12 +92,12 @@  struct foo {
       bind (&barT::baikt);
 
       bind (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 94 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 94 }
       bind (&foo::barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 96 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 96 }
 
       bindm (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 99 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 99 }
       bindm (&foo::barf);
 
       bindn (&barf);
@@ -105,15 +105,15 @@  struct foo {
 
       bindb (&barf);
       bindb (&foo::barf); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 107 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 107 }
 
       bind (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 110 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 110 }
       bind (&barT::bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 112 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 112 }
 
       bindm (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 115 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 115 }
       bindm (&barT::bark);
 
       bindn (&bark);
@@ -121,7 +121,7 @@  struct foo {
 
       bindb (&bark);
       bindb (&barT::bark); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 123 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 123 }
     }
   };
 
diff --git a/gcc/testsuite/g++.dg/template/friend.C b/gcc/testsuite/g++.dg/template/friend.C
index 44cbce9..e315a1a 100644
--- a/gcc/testsuite/g++.dg/template/friend.C
+++ b/gcc/testsuite/g++.dg/template/friend.C
@@ -26,5 +26,5 @@  int main()
 {
   s<int>::t y;
   cout << y; // { dg-error "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 28 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 28 }
 }
diff --git a/gcc/testsuite/g++.dg/template/incomplete2.C b/gcc/testsuite/g++.dg/template/incomplete2.C
index d86ea06..b855569 100644
--- a/gcc/testsuite/g++.dg/template/incomplete2.C
+++ b/gcc/testsuite/g++.dg/template/incomplete2.C
@@ -9,6 +9,6 @@  A a;  // { dg-error "incomplete type" }
 
 void bar()
 {
-  foo<a>();  // { dg-error "no matching function" }
+  foo<a>();  // { dg-error "(no matching function|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 12 }
 }
diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C
index 9a03c9a..d842076 100644
--- a/gcc/testsuite/g++.dg/template/local4.C
+++ b/gcc/testsuite/g++.dg/template/local4.C
@@ -5,6 +5,6 @@  template <typename T> void foo() {} // { dg-message "note" }
 
 int main () {
   struct S {};
-  foo<S> (); // { dg-error "match" } 
+  foo<S> (); // { dg-error "(match|template argument for|trying to instantiate)" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/local6.C b/gcc/testsuite/g++.dg/template/local6.C
index 4a87177..972da84 100644
--- a/gcc/testsuite/g++.dg/template/local6.C
+++ b/gcc/testsuite/g++.dg/template/local6.C
@@ -5,7 +5,7 @@  template <class T> struct PCVector2 // { dg-message "note" }
     PCVector2<T> operator- (const PCVector2<T> &ov) const 
 	{ 
 	  return PCVector2<T>(ov.xFIELD, ov.yFIELD); // { dg-error "matching" }
-	  // { dg-message "candidate" "candidate note" { target *-*-* } 7 }
+	  // { dg-message "(candidate|expects 1 argument, 2 provided|cannot convert)" "candidate note" { target *-*-* } 7 }
 	}
 
     T xFIELD, yFIELD;
diff --git a/gcc/testsuite/g++.dg/template/operator9.C b/gcc/testsuite/g++.dg/template/operator9.C
index 35be778..46eef0a 100644
--- a/gcc/testsuite/g++.dg/template/operator9.C
+++ b/gcc/testsuite/g++.dg/template/operator9.C
@@ -5,6 +5,6 @@  template<operator+> void foo(); // { dg-error "before|non-function|template" }
 void bar()
 {
   foo();                        // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 7 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 7 }
 }
  
diff --git a/gcc/testsuite/g++.dg/template/overload12.C b/gcc/testsuite/g++.dg/template/overload12.C
new file mode 100644
index 0000000..656dcae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/overload12.C
@@ -0,0 +1,17 @@ 
+// { dg-do compile }
+
+struct S {int x; int y;};
+template<typename T>
+int foo(T a, T b) {return a + b;} // { dg-message "template" }
+template<typename T, typename T2>
+int foo(T a, T2& b, T2 c) {return a + b;}  // { dg-message "template" }
+int foo(char*, S&); // { dg-message "foo" }
+// { dg-message "candidate expects 2 arguments, 3 provided" "arity" { target *-*-* } 8 }
+
+int foo2(int x)
+{
+  S s={1,2};
+  char c;
+  foo(c, 2, c); // { dg-error "no matching function" }
+  // { dg-message "(candidate|deduced conflicting types for)" "candidate note" { target *-*-* } 15 }
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp25.C b/gcc/testsuite/g++.dg/template/ttp25.C
index 861d187..4cf3b24 100644
--- a/gcc/testsuite/g++.dg/template/ttp25.C
+++ b/gcc/testsuite/g++.dg/template/ttp25.C
@@ -18,12 +18,12 @@  void f4(T, C<5>);		// { dg-message "note" }
 template<int N> struct X {};
 void g() {
   f1(5l, X<5>()); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 20 }
+  // { dg-message "(candidate|inconsistent template)" "candidate note" { target *-*-* } 20 }
   f2(X<5>(), 5);
   f3(X<5>(), 5l); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
+  // { dg-message "(candidate|inconsistent template)" "candidate note" { target *-*-* } 23 }
   f4(5, X<5>());
   f4(5l, X<5>()); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 26 }
+  // { dg-message "(candidate|inconsistent template)" "candidate note" { target *-*-* } 26 }
   f4((short)5, X<5>());
 }
diff --git a/gcc/testsuite/g++.dg/template/unify10.C b/gcc/testsuite/g++.dg/template/unify10.C
index 8dc434b..7f2fd53 100644
--- a/gcc/testsuite/g++.dg/template/unify10.C
+++ b/gcc/testsuite/g++.dg/template/unify10.C
@@ -26,34 +26,34 @@  void cvFunction(void (CLASS::* method)() const volatile) {} // { dg-message "not
 int main() {
   mFunction(&MyClass::mMethod);
   mFunction(&MyClass::cMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 28 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 28 }
   mFunction(&MyClass::vMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 30 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 30 }
   mFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 32 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 32 }
 
   cFunction(&MyClass::mMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 35 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 35 }
   cFunction(&MyClass::cMethod);
   cFunction(&MyClass::vMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 38 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 38 }
   cFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 40 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 40 }
 
   vFunction(&MyClass::mMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 43 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 43 }
   vFunction(&MyClass::cMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 45 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 45 }
   vFunction(&MyClass::vMethod);
   vFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 48 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 48 }
 
   cvFunction(&MyClass::mMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 51 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 51 }
   cvFunction(&MyClass::cMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 53 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 53 }
   cvFunction(&MyClass::vMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 55 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 55 }
   cvFunction(&MyClass::cvMethod);
 
   return 0;
diff --git a/gcc/testsuite/g++.dg/template/unify11.C b/gcc/testsuite/g++.dg/template/unify11.C
index ed6b31c..25606dc 100644
--- a/gcc/testsuite/g++.dg/template/unify11.C
+++ b/gcc/testsuite/g++.dg/template/unify11.C
@@ -20,7 +20,7 @@  struct B
     C (U t)
     {
       A a;
-      A b = foo (this, a, t); // { dg-error "no matching function" }
+      A b = foo (this, a, t); // { dg-error "(no matching function|is not a)" }
       // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
     }
   } c;
diff --git a/gcc/testsuite/g++.dg/template/unify6.C b/gcc/testsuite/g++.dg/template/unify6.C
index b12ecb2..551c96e 100644
--- a/gcc/testsuite/g++.dg/template/unify6.C
+++ b/gcc/testsuite/g++.dg/template/unify6.C
@@ -19,5 +19,5 @@  void Bar ()
   Foo3 (&Baz);
 
   Foo3 (&Baz, &Baz); // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 21 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 21 }
 }
diff --git a/gcc/testsuite/g++.dg/template/unify7.C b/gcc/testsuite/g++.dg/template/unify7.C
index 2bfa563..88d9fd9 100644
--- a/gcc/testsuite/g++.dg/template/unify7.C
+++ b/gcc/testsuite/g++.dg/template/unify7.C
@@ -11,5 +11,5 @@  int main()
 {
   Foo (f);
   Baz (f); // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 13 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 13 }
 }
diff --git a/gcc/testsuite/g++.dg/template/unify9.C b/gcc/testsuite/g++.dg/template/unify9.C
index 40f6b92..f06f83a 100644
--- a/gcc/testsuite/g++.dg/template/unify9.C
+++ b/gcc/testsuite/g++.dg/template/unify9.C
@@ -14,5 +14,5 @@  const X *x;
  
 int main () { 
   f (*x, &X::g);  // {  dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 16 }
 } 
diff --git a/gcc/testsuite/g++.dg/template/varmod1.C b/gcc/testsuite/g++.dg/template/varmod1.C
index 6ae78d9..4ba1104 100644
--- a/gcc/testsuite/g++.dg/template/varmod1.C
+++ b/gcc/testsuite/g++.dg/template/varmod1.C
@@ -7,5 +7,5 @@  void bar()
   int i;
   int A[i][i]; 
   foo(A); // { dg-error "" } 
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|not a valid template argument)" "candidate note" { target *-*-* } 9 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
index a22615d..e3bff80 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
@@ -278,7 +278,7 @@  SetLD<T>::remove(const T& item)
     Vix x;
     for (first(x); 0 != x && this->REMOVE_CURRENT != a; next(x, a))
 	a = operator()(x) == item ? this->REMOVE_CURRENT: this->NORMAL; // { dg-error "" } .*
-    // { dg-message "candidate" "candidate note" { target *-*-* } 280 }
+    // { dg-message "(candidate|not derived from)" "candidate note" { target *-*-* } 280 }
 }
 template<class T>
 bool
@@ -287,7 +287,7 @@  SetLD<T>::contains(const T& item) const
     Vix x;
     for (first(x); 0 != x; next(x)) {
 	if (operator()(x) == item)// { dg-error "" } .*
-	  // { dg-message "candidate" "candidate note" { target *-*-* } 289 }
+	  // { dg-message "(candidate|not derived from)" "candidate note" { target *-*-* } 289 }
 	    return TRUE;
     }
     return FALSE;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash28.C b/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
index 2cfed93..81ed85a 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
@@ -11,5 +11,5 @@  void f(unsigned int n) {
   int x[n];
 
   asize(x); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 13 }
+  // { dg-message "(candidate|not a valid template argument)" "candidate note" { target *-*-* } 13 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
index 560370a..c27d131 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
@@ -1,6 +1,6 @@ 
 // { dg-do assemble  }
 template <int I>
-void f(int i);			// { dg-message "note" }
+void f(int i);			// { dg-message "void f" }
 
 void g()
 {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
index 1213a15..b97c1cd 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
@@ -15,5 +15,5 @@  void g() {
   
   f<0>(s0, s2);
   f(s0, s2); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+  // { dg-message "(candidate|deduced conflicting types|ambiguous base class)" "candidate note" { target *-*-* } 17 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr2.C b/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
index 0dcc65f..06d22d5 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
@@ -9,5 +9,5 @@  void foo(S<J + 2>);		// { dg-message "note" }
 void bar()
 {
   foo(S<3>()); // { dg-error "" } no way to deduce J from this.
-  // { dg-message "candidate" "candidate note" { target *-*-* } 11 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 11 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
index 85d3e73..8802e98 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
@@ -13,9 +13,9 @@  public:
 };
 
 template <void (A::*)() >
-void g() {}			// { dg-message "note" }
+void g() {}			// { dg-message "void g" }
 template <int A::*>
-void h() {}			// { dg-message "note" }
+void h() {}			// { dg-message "void h" }
 
 
 int main() {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec5.C b/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
index df7112a..96e8cf9 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
@@ -14,9 +14,9 @@  template void g(int i, int j);
 void h()
 {
   f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 16 }
   g(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 18 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 18 }
 }
 
 
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec6.C b/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
index fc19c3c..b8f6673 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
@@ -25,9 +25,9 @@  void h()
 {
   S1 s1;
   s1.f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 27 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 27 }
 
   S2<char> s2;
   s2.f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 31 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 31 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify4.C b/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
index 6dd9961..9285b21 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
@@ -8,6 +8,6 @@  int
 main ()
 {
   f (g);			// { dg-error "" } ambiguous unification
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify8.C b/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
index 3209260..3a86d97 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
@@ -16,6 +16,6 @@  void Foo (float);     // { dg-message "note" } candidate
 void baz (int **p1)
 {
   Foo (p1);   // { dg-error "match" } no such function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 18 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 18 }
   Bar (p1);   // OK
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
index c562031..410a336 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
@@ -15,5 +15,5 @@ 
     void f()
     {
       extent(b);  // { dg-error "" } no matching function
-      // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+      // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 17 }
     }