diff mbox

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

Message ID 20110516173938.GA779@nightcrawler
State New
Headers show

Commit Message

Nathan Froyd May 16, 2011, 5:39 p.m. UTC
On Tue, May 10, 2011 at 04:08:20PM -0400, Jason Merrill wrote:
> In general, my preference is to have diagnostics collocated with the
> tests that lead to them, and just run through the same code a second
> time if we decide that we want to give a diagnostic.  For instance,
> that's what I did in joust and synthesized_method_walk.  Saving
> information ahead of time about why we reject a particular candidate
> creates overhead that is useless in the vast majority of cases,
> since most compiles succeed.

FWIW, this is why I chose to permit NULL unification_info arguments.

Thanks for the background; I will keep the principle in mind.  IMHO, in
a case like this where we're logically printing one diagnostic (one
error and then some number of explanatory notes) keeping all the logic
for the diagnostic centralized makes more sense.

> This doesn't compile.  Were you testing a previous version of the patch?
> 
> I guess I'll stop reviewing the patch now and wait for an update.

Apologies for the mostly-not-reviewed and edited-in-the-email garbage
that I attempted to pass off as a patch.

How about this version?  Tested in the same way (g++/libstdc++), and
including an actual gcc/testsuite/ ChangeLog.

-Nathan

gcc/cp/
	PR c++/45329
	PR c++/48934
        * cp-tree.h (enum unification_result): Define.
        (struct unification_info): Define.
        (fn_type_unification): Add struct unification_info parameter.
        * pt.c (unify_success, unify_unknown): Define.
	(unify_parameter_deduction_failure): Define.
        (unify_invalid, unify_mismatch_1): Define.
        (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_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_invalid_explicit_argument): Define.
	(unify_inconsistent_template_template_parameters): Define.
        (unify): Add struct unification_info parameter.  Pass to all
        relevant calls.  Call above status functions when appropriate.
        (resolve_overloaded_unification): Likewise.
        (try_one_overload, unify): Likewise.
        (coerce_template_parms): Likewise.
        (coerce_template_parameter_pack): Likewise.
        (convert_template_argument): Likewise.
        (type_unification, type_unification_real): Likewise.
        (fn_type_unification, convert_nontype_argument): Likewise.
        (unify_pack_expansion): Likewise.
        (get_template_base, try_class_unification): Likewise.
        (get_bindings, more_specialized_fn): Pass NULL to unification
	calls.
        (get_class_bindings, do_auto_deduction): Likewise.
        * class.c (resolve_address_of_overloaded_function): Likewise.
        * call.c (enum rejection_reason_code): Add new codes.
        (struct rejection_reason): Add template_unification field.
        (template_unification_rejection): Define.
        (template_instantiation_rejection): Define.
        (invalid_copy_with_fn_template_rejection): Define.
        (add_template_candidate): Pass a struct unification_info 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/pr31434.C: Adjust.
	* g++.old-deja/g++.pt/explicit41.C: Adjust.
	* g++.old-deja/g++.pt/ptrmem6.C: Adjust.
	* g++.dg/overload/template5.C: New testcase.
	* g++.dg/template/overload12.C: New testcase.

Comments

Jason Merrill May 18, 2011, 5:45 p.m. UTC | #1
> Thanks for the background; I will keep the principle in mind.  IMHO, in
> a case like this where we're logically printing one diagnostic (one
> error and then some number of explanatory notes) keeping all the logic
> for the diagnostic centralized makes more sense.

I understand, but that means we have to create a whole data structure to 
try and preserve information about the failure, and either having to 
duplicate every possible error or give less informative messages.  I 
feel even more strongly about this after looking more closely at your patch.

> +    case ur_invalid:
> +      inform (loc,
> +             "  template argument deduction attempted with invalid input");
> +      break;

In ur_invalid cases, we should have had an earlier error message 
already, so giving an extra message here seems kind of redundant.

> +             "  types %qT and %qT differ in their qualifiers",

Let's say "...have incompatible cv-qualifiers", since some differences 
are OK.

> +      inform (loc, "  variable-sized array type %qT is not permitted",

"...is not a valid template argument"

> +      inform (loc, "  %qT is not derived from %qT",

This could be misleading, since we can also fail when the deduction is 
ambiguous.

> +      inform (loc, "  %qE is not a valid pointer-to-member of type %qT",

This needs to say "pointer-to-member constant", not just 
"pointer-to-member".

> +    case ur_parameter_deduction_failure:
> +      inform (loc, "  couldn't deduce template argument %qD", ui->u.parm);
> +      break;

It seems like you're using this both for cases where unification 
succeeded but just didn't produce template arguments for all parameters, 
and for cases where unification failed for some reason; this message 
should only apply to the first case.

>           if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
>             {
>               tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
>               tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i));
>               arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE);
>               arg = convert_template_argument (parm, arg, targs, tf_none,
>                                                i, NULL_TREE, ui);
>               if (arg == error_mark_node)
>                 return unify_parameter_deduction_failure (ui, parm);

In this case, the problem is that we tried to use the default template 
argument but it didn't work for some reason; we should say that, not 
just say we didn't deduce something, or the users will say "but there's 
a default argument!".

In this case, we should do the substitution again with 
tf_warning_or_error so the user can see what the problem actually is, 
not just say that there was some unspecified problem.

> -         return 2;
> +         return unify_parameter_deduction_failure (ui, tparm);

This seems like the only place we actually want to use 
unify_parameter_deduction_failure.

>       /* Check for mixed types and values.  */
>       if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
>            && TREE_CODE (tparm) != TYPE_DECL)
>           || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
>               && TREE_CODE (tparm) != TEMPLATE_DECL))
>         return unify_parameter_deduction_failure (ui, parm);

This is a type/template mismatch issue that deserves a more helpful 
diagnostic.

>           /* ARG must be constructed from a template class or a template
>              template parameter.  */
>           if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
>               && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
>             return unify_parameter_deduction_failure (ui, parm);

This is saying that we can't deduce a template from a non-template type.

>       /* 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 unify_parameter_deduction_failure (ui, parm);

Like with the VLA case, the problem here is deducing something that 
isn't a valid template type argument.

>         /* We haven't deduced the type of this parameter yet.  Try again
>            later.  */
>         return unify_success (ui);
>       else
>         return unify_parameter_deduction_failure (ui, parm);

Here the problem is a type mismatch between parm and arg for a non-type 
template argument.

>             /* Perhaps PARM is something like S<U> and ARG is S<int>.
>                Then, we should unify `int' and `U'.  */
>             t = arg;
>           else
>             /* There's no chance of unification succeeding.  */
>             return unify_parameter_deduction_failure (ui, parm);

This should be type_mismatch.

>     case FIELD_DECL:
>     case TEMPLATE_DECL:
>       /* Matched cases are handled by the ARG == PARM test above.  */
>       return unify_parameter_deduction_failure (ui, parm);

Another case where we should talk about the arg/parm mismatch.

> +       case rr_invalid_copy:
> +         inform (loc,
> +                 "  cannot instantiate member function templates to "
> +                 "copy class objects to their class type");

The standardese is misleading here (and is fixed in C++11); you 
certainly can instantiate a constructor template to copy an object of 
the same type.  The real problem is having a constructor taking a single 
parameter with the type of the class.

>       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.  */
>         /* FIXME: What to return here?  */
>         return (TREE_CODE (arg) == TREE_CODE (parm)
>                 && same_type_p (parm, arg)) ? 0 : 1;

unify_type_mismatch seems appropriate here.  And unify_success, of course.

>       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));

No diagnostic code here in case of mismatch?

>       idx = TEMPLATE_PARM_IDX (parm);
>       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
>
>       if (targ)
>         return !cp_tree_equal (targ, arg);

Seems like you're missing unify_inconsistency here.

> +    case ur_parameter_pack_mismatch:
> +      inform (loc, "  template parmeter %qD is not a parameter pack",
> +             ui->u.mismatch.parm);
> +      break;

This message should indicate that this is a compiler defect

>             if (coerce_template_parms (parm_parms,
>                                        full_argvec,
>                                        TYPE_TI_TEMPLATE (parm),
>                                        tf_none,
>                                        /*require_all_args=*/true,
>                                        /*use_default_args=*/false, ui)
>                 == error_mark_node)
>               return 1;

Rather than pass ui down into coerce_template_parms we should just note 
when it fails and run it again at diagnostic time.

>       converted_args
>         = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
>                                   /*require_all_args=*/false,
>                                   /*use_default_args=*/false, ui));
>       if (converted_args == error_mark_node)
>         return 1;

Here too.

>               if (TREE_CODE (arg_max) != MINUS_EXPR)
>                 return 1;

No diagnostic code here?

>     case TREE_VEC:
>       {
>         int i;
>         if (TREE_CODE (arg) != TREE_VEC)
>           return 1;
>         if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
>           return 1;

Or here?

>       /* An unresolved overload is a nondeduced context.  */
>       if (type_unknown_p (parm))
>         return 0;

And this should be unify_success.

>       if (fntype == error_mark_node)
>         return unify_substitution_failure (ui);

And this should remember the arguments so we can do the tsubst again at 
diagnostic time.

Jason
Nathan Froyd May 18, 2011, 7 p.m. UTC | #2
On 05/18/2011 01:45 PM, Jason Merrill wrote:
>> Thanks for the background; I will keep the principle in mind.  IMHO, in
>> a case like this where we're logically printing one diagnostic (one
>> error and then some number of explanatory notes) keeping all the logic
>> for the diagnostic centralized makes more sense.
> 
> I understand, but that means we have to create a whole data structure to try
> and preserve information about the failure, and either having to duplicate
> every possible error or give less informative messages.  I feel even more
> strongly about this after looking more closely at your patch.

Thank you for the review.  I'll go back and try things the way you suggest;
before I go off and do that, I've taken your comments to mean that:

- fn_type_unification/type_unification_real and associated callers should take
  a boolean `explain' parameter, which is normally false;

- failed calls to fn_type_unification should save the arguments for the call
  for future explanation;

- printing diagnostic messages should call fn_type_unification with the saved
  arguments and a true `explain' parameter.

This is similar to passing `struct unification_info' and really only involves
shuffling code from call.c into the unify_* functions in pt.c and some minor
changes to the rejection_reason code in call.c.  The only wrinkle I see is
that in cases like these:

>>           if (TREE_PURPOSE (TREE_VEC_ELT (tparms, i)))
>>             {
>>               tree parm = TREE_VALUE (TREE_VEC_ELT (tparms, i));
>>               tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i));
>>               arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE);
>>               arg = convert_template_argument (parm, arg, targs, tf_none,
>>                                                i, NULL_TREE, ui);
>>               if (arg == error_mark_node)
>>                 return unify_parameter_deduction_failure (ui, parm);
> 
> In this case, the problem is that we tried to use the default template
> argument but it didn't work for some reason; we should say that, not just say
> we didn't deduce something, or the users will say "but there's a default
> argument!".
> 
> In this case, we should do the substitution again with tf_warning_or_error so
> the user can see what the problem actually is, not just say that there was
> some unspecified problem.
>
>>             if (coerce_template_parms (parm_parms,
>>                                        full_argvec,
>>                                        TYPE_TI_TEMPLATE (parm),
>>                                        tf_none,
>>                                        /*require_all_args=*/true,
>>                                        /*use_default_args=*/false, ui)
>>                 == error_mark_node)
>>               return 1;
> 
> Rather than pass ui down into coerce_template_parms we should just note when
> it fails and run it again at diagnostic time.
> 
>>       converted_args
>>         = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
>>                                   /*require_all_args=*/false,
>>                                   /*use_default_args=*/false, ui));
>>       if (converted_args == error_mark_node)
>>         return 1;
>
> Here too.
>
>>       if (fntype == error_mark_node)
>>         return unify_substitution_failure (ui);
> 
> And this should remember the arguments so we can do the tsubst again at
> diagnostic time.

and other bits of pt.c, I'm interpreting your suggestions to mean that
tf_warning_or_error should be passed if `explain' is true.  That doesn't seem
like the best interface for diagnostics, as we'll get:

foo.cc:105:40 error: no matching function for call to bar (...)
foo.cc:105:40 note: candidates are:
bar.hh:7000:30 note: bar (...)
bar.hh:7000:30 note: [some reason]
bar.hh:4095:63 note: bar (...)
bar.hh:....... error: [some message from tf_warning_or_error code]

I'm not sure that the last location there will necessary be the same as the
one that's printed for the declaration.  I think I'll punt on that issue for
the time being until we see how the diagnostics work out.  There's also the
matter of the error vs. note diagnostic.  I think it'd be nicer to keep the
conformity of a note for all the explanations; the only way I see to do that
is something like:

- Add a tf_note flag; pass it at all appropriate call sites when explaining
  things;

- Add a tf_issue_diagnostic flag that's the union of tf_{warning,error,note};

- Change code that looks like:

  if (complain & tf_warning_or_error)
    error (<STUFF>);

  to something like:

  if (complain & tf_issue_diagnostic)
    emit_diagnostic (complain & tf_note ? DK_NOTE : DK_ERROR, <STUFF>);

  passing input_location if we're not already passing a location.

That involves a lot of code churn.  (Not a lot if you just modified the
functions above, but with this scheme, you'd have to call instantiate_template
again from the diagnostic code, and I assume you'd want to call that with
tf_note as well, which means hitting a lot more code.)  I don't see a better
way to keep the diagnostics uniform, but I might be making things too
complicated; did you have a different idea of how to implement what you were
suggesting?

-Nathan
Jason Merrill May 18, 2011, 7:48 p.m. UTC | #3
On 05/18/2011 03:00 PM, Nathan Froyd wrote:
> Thank you for the review.  I'll go back and try things the way you suggest;
> before I go off and do that, I've taken your comments to mean that:
>
> - fn_type_unification/type_unification_real and associated callers should take
>    a boolean `explain' parameter, which is normally false;
>
> - failed calls to fn_type_unification should save the arguments for the call
>    for future explanation;
>
> - printing diagnostic messages should call fn_type_unification with the saved
>    arguments and a true `explain' parameter.

Yes, that's what I had in mind.  Though I think you can reconstruct the 
arguments rather than save them.

...
> bar.hh:4095:63 note: bar (...)
> bar.hh:....... error: [some message from tf_warning_or_error code]

> I'm not sure that the last location there will necessary be the same as the
> one that's printed for the declaration.  I think I'll punt on that issue for
> the time being until we see how the diagnostics work out.  There's also the
> matter of the error vs. note diagnostic.  I think it'd be nicer to keep the
> conformity of a note for all the explanations

Nicer, yes, but I think that's a secondary concern after usefulness of 
the actual message.  In similar cases I've introduced the errors with 
another message like "%qD is implicitly deleted because the default 
definition would be ill-formed:"

Or, in this case, "deduction failed because substituting the template 
arguments would be ill-formed:"

>; the only way I see to do that
> is something like:
>
> - Add a tf_note flag; pass it at all appropriate call sites when explaining
>    things;
>
> - Add a tf_issue_diagnostic flag that's the union of tf_{warning,error,note};
>
> - Change code that looks like:
>
>    if (complain&  tf_warning_or_error)
>      error (<STUFF>);
>
>    to something like:
>
>    if (complain&  tf_issue_diagnostic)
>      emit_diagnostic (complain&  tf_note ? DK_NOTE : DK_ERROR,<STUFF>);
>
>    passing input_location if we're not already passing a location.
>
> That involves a lot of code churn.  (Not a lot if you just modified the
> functions above, but with this scheme, you'd have to call instantiate_template
> again from the diagnostic code, and I assume you'd want to call that with
> tf_note as well, which means hitting a lot more code.)  I don't see a better
> way to keep the diagnostics uniform, but I might be making things too
> complicated; did you have a different idea of how to implement what you were
> suggesting?

That all makes sense, but I'd put it in a follow-on patch.  And wrap the 
complexity in a cp_error function that takes a complain parameter and 
either gives no message, a note, or an error depending.

Jason
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 09ad4ae..f5cb7f3 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,8 @@  struct rejection_reason {
     struct conversion_info conversion;
     /* Same, but for bad argument conversions.  */
     struct conversion_info bad_conversion;
+    /* Information about template unification failures.  */
+    struct unification_info template_unification;
   } u;
 };
 
@@ -607,6 +612,28 @@  bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+template_unification_rejection (struct unification_info *ui)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_unification);
+  r->u.template_unification = *ui;
+  return r;
+}
+
+static struct rejection_reason *
+template_instantiation_rejection (void)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
+  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 *
@@ -2844,6 +2871,9 @@  add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   int i;
   tree fn;
   struct rejection_reason *reason = NULL;
+  struct unification_info ui;
+
+  ui.result = ur_unknown;
 
   /* We don't do deduction on the in-charge parameter, the VTT
      parameter or 'this'.  */
@@ -2889,14 +2919,20 @@  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, &ui);
 
   if (i != 0)
-    goto fail;
+    {
+      reason = template_unification_rejection (&ui);
+      goto fail;
+    }
 
   fn = instantiate_template (tmpl, targs, tf_none);
   if (fn == error_mark_node)
-    goto fail;
+    {
+      reason = template_instantiation_rejection ();
+      goto fail;
+    }
 
   /* In [class.copy]:
 
@@ -2925,7 +2961,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)
@@ -3088,6 +3127,107 @@  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 a candidate being rejected due to UI.  */
+
+static void
+print_template_unification_rejection (location_t loc,
+				      struct unification_info *ui)
+{
+  switch (ui->result)
+    {
+    case ur_invalid:
+      inform (loc,
+	      "  template argument deduction attempted with invalid input");
+      break;
+    case ur_unification_inconsistency:
+      inform (loc,
+	      "  deduced conflicting types for parameter %qT (%qT and %qT)",
+	      ui->u.inconsistent.template_parm,
+	      ui->u.inconsistent.earlier,
+	      ui->u.inconsistent.later);
+      break;
+    case ur_cv_qual_mismatch:
+      inform (loc,
+	      "  types %qT and %qT differ in their qualifiers",
+	      ui->u.mismatch.parm,
+	      ui->u.mismatch.arg);
+      break;
+    case ur_type_mismatch:
+      inform (loc,  "  mismatched types %qT and %qT",
+	      ui->u.mismatch.parm,
+	      ui->u.mismatch.arg);
+      break;
+    case ur_vla_arg:
+      inform (loc, "  variable-sized array type %qT is not permitted",
+	      ui->u.vla_arg.array_type);
+      break;
+    case ur_too_many_parameters:
+    case ur_too_few_parameters:
+      print_arity_information (loc, ui->u.arity.have, ui->u.arity.wanted);
+      break;
+    case ur_arg_conversion:
+      inform (loc, "  cannot convert %qE (type %qT) to type %qT",
+	      ui->u.arg_conversion.arg, ui->u.arg_conversion.from_type,
+	      ui->u.arg_conversion.to_type);
+      break;
+    case ur_no_common_base:
+      inform (loc, "  %qT is not derived from %qT",
+	      ui->u.common_base.arg, ui->u.common_base.potential_base);
+      break;
+    case ur_illformed_ptrmem_cst_expr:
+      inform (loc, "  %qE is not a valid pointer-to-member of type %qT",
+	      ui->u.illformed_ptrmem_cst.expr,
+	      ui->u.illformed_ptrmem_cst.type);
+      break;
+    case ur_parameter_deduction_failure:
+      inform (loc, "  couldn't deduce template argument %qD", ui->u.parm);
+      break;
+    case ur_substitution_failure:
+      inform (loc, "  substitution failure");
+      break;
+    case ur_invalid_explicit_arg:
+      if (DECL_P (ui->u.invalid_explicit_arg.parm)
+	  && DECL_NAME (ui->u.invalid_explicit_arg.parm))
+	inform (loc, "  invalid explicit argument for template parameter %qD",
+		ui->u.invalid_explicit_arg.parm);
+      else
+	inform (loc, " invalid explicit argument for template parameter %d",
+		ui->u.invalid_explicit_arg.parm_index + 1);
+      break;
+    case ur_inconsistent_template_template_parameters:
+      inform (loc, "  inconsistent template template parameters");
+      break;
+    case ur_parameter_pack_mismatch:
+      inform (loc, "  template parmeter %qD is not a parameter pack",
+	      ui->u.mismatch.parm);
+      break;
+    case ur_unknown:
+      /* Template deduction and instantiation fails for a multitude of
+         reasons.  In the worst case, don't print anything, as we might
+         not have caught all of the cases.  */
+      break;
+    case ur_success:
+      /* We should never see this; it means we forgot to provide a
+	 rejection reason someplace else (probably from template
+	 instantiation).  */
+      /* Fallthrough.  */
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
    is the text to print before the candidate itself.
 
@@ -3134,10 +3274,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);
@@ -3145,6 +3283,18 @@  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:
+	  print_template_unification_rejection (loc,
+						&r->u.template_unification);
+	  break;
+	case rr_template_instantiation:
+	  inform (loc, "  failed to instantiate template");
+	  break;
+	case rr_invalid_copy:
+	  inform (loc, 
+		  "  cannot instantiate member function templates to "
+		  "copy class objects to their class type");
+	  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 dc2c509..e7d629b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6515,7 +6515,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, NULL))
 	    /* Argument deduction failed.  */
 	    continue;
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index c0b5290..7dd8aa8 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5097,6 +5097,105 @@  extern tree locate_ctor				(tree);
 extern bool maybe_clone_body			(tree);
 
 /* in pt.c */
+/* Status codes for the result of unification.  */
+enum unification_result {
+  /* Unification succeeded.  */
+  ur_success = 0,
+  /* Unification failed for an unknown reason.  */
+  ur_unknown,
+  /* Failed to deduce a particular parameters.  */
+  ur_parameter_deduction_failure,
+  /* Error due to ill-formed input.  */
+  ur_invalid,
+  /* CV-qualification mismatch.  */
+  ur_cv_qual_mismatch,
+  /* Argument is a parameter pack/expansion and parm isn't.  */
+  ur_parameter_pack_mismatch,
+  /* Argument is a variable-sized array.  */
+  ur_vla_arg,
+  /* Parameter is a pointer-to-member constant, arg isn't.  */
+  ur_ptrmem_cst_mismatch,
+  /* Types of parameter and argument do not match.  */
+  ur_type_mismatch,
+  /* Parameter is a constant, arg isn't.  */
+  ur_constant_mismatch,
+  /* Parameter and argument are unequal constants.  */
+  ur_constant_unequal,
+  /* Unequal expressions.  */
+  ur_expression_unequal,
+  /* Unification of parameter packs produced inconsistencies.  */
+  ur_parameter_pack_inconsistent,
+  /* Unification of earlier parameters produced inconsistencies with
+     later ones.  */
+  ur_unification_inconsistency,
+  /* Too many parameters.  */
+  ur_too_many_parameters,
+  /* Too few parameters.  */
+  ur_too_few_parameters,
+  /* Failed argument conversion.  */
+  ur_arg_conversion,
+  ur_no_common_base,
+  ur_illformed_ptrmem_cst_expr,
+  /* Substitution failed in some way at some expression.  */
+  ur_substitution_failure,
+  /* Explicit template arguments are invalid.  */
+  ur_invalid_explicit_arg,
+  /* Template parameters that are templates cannot be deduced.  */
+  ur_inconsistent_template_template_parameters
+};
+
+/* Information gathered during the unification process.  */
+struct unification_info {
+  /* Status code.  Also indicates which member of U, below, is valid.  */
+  enum unification_result result;
+  union {
+    tree invalid;		/* For ur_invalid_*.  */
+    tree parm;			/* For generic failure.  */
+    /* For anything where we found differences between PARM and ARG.  */
+    struct {
+      tree parm;
+      tree arg;
+    } mismatch;
+    /* For inconsistent unifications.  */
+    struct {
+      tree template_parm;
+      tree earlier;
+      tree later;
+    } inconsistent;
+    /* For variably-sized array types appearing in templates.  */
+    struct {
+      tree parm;
+      tree array_type;
+    } vla_arg;
+    /* For arity issues.  */
+    struct {
+      unsigned int have;
+      unsigned int wanted;
+    } arity;
+    /* For ur_arg_conversion.  */
+    struct {
+      tree to_type;
+      tree from_type;
+      tree arg;
+    } arg_conversion;
+    /* For ur_no_common_base.  */
+    struct {
+      tree potential_base;
+      tree arg;
+    } common_base;
+    struct {
+      tree expr;
+      tree type;
+    } illformed_ptrmem_cst;
+    struct {
+      tree parm;
+      /* We ought to be able to get this from TEMPLATE_PARM_IDX
+	 (DECL_INITIAL (parm)), but parm might not be a decl.  */
+      int parm_index;
+    } invalid_explicit_arg;
+  } u;
+};
+
 extern bool check_template_shadow		(tree);
 extern tree get_innermost_template_args		(tree, int);
 extern void maybe_begin_member_template_processing (tree);
@@ -5135,7 +5234,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,
+						 struct unification_info *);
 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 e441a70..d61f3ab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -112,16 +112,19 @@  static GTY(()) VEC(tree,gc) *canonical_template_parms;
 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,
+					    struct unification_info *);
 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,
+			     struct unification_info *);
+static int unify (tree, tree, tree, tree, int, struct unification_info *);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
 static tree get_class_bindings (tree, tree, tree);
 static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
-				   bool, bool);
+				   bool, bool,
+				   struct unification_info *);
 static void tsubst_enum	(tree, tree, tree);
 static tree add_to_template_args (tree, tree);
 static tree add_outermost_template_args (tree, tree);
@@ -129,12 +132,15 @@  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,
+				  struct unification_info *ui);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree);
-static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
+static tree convert_nontype_argument (tree, tree, tsubst_flags_t,
+				      struct unification_info *);
 static tree convert_template_argument (tree, tree, tree,
-				       tsubst_flags_t, int, tree);
+				       tsubst_flags_t, int, tree,
+				       struct unification_info *);
 static int for_each_template_parm (tree, tree_fn_t, void*,
 				   struct pointer_set_t*, bool);
 static tree expand_template_argument_pack (tree);
@@ -154,7 +160,9 @@  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,
+				 struct unification_info *);
 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 +174,10 @@  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 tree get_template_base (tree, tree, tree, tree,
+			       struct unification_info *);
+static tree try_class_unification (tree, tree, tree, tree,
+				   struct unification_info *);
 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,231 @@  has_value_dependent_address (tree op)
   return false;
 }
 
+/* The next set of functions fill in their provided UI parameter (if it
+   is not NULL) with useful information about why template deduction
+   failed.  */
+
+static int
+unify_success (struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur_success;
+  return 0;
+}
+
+static int
+unify_unknown (struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur_unknown;
+  return 1;
+}
+
+static int
+unify_parameter_deduction_failure (struct unification_info *ui, tree parm)
+{
+  if (ui)
+    {
+      ui->result = ur_parameter_deduction_failure;
+      ui->u.parm = parm;
+    }
+  return 1;
+}
+
+static int
+unify_invalid (struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur_invalid;
+  return 1;
+}
+
+static int
+unify_mismatch_1 (enum unification_result ur, struct unification_info *ui,
+		  tree parm, tree arg)
+{
+  if (ui)
+    {
+      ui->result = ur;
+      ui->u.mismatch.parm = parm;
+      ui->u.mismatch.arg = arg;
+    }
+  return 1;
+}
+
+static int
+unify_cv_qual_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_cv_qual_mismatch, ui, parm, arg);
+}
+
+static int
+unify_type_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_type_mismatch, ui, parm, arg);
+}
+
+static int
+unify_parameter_pack_mismatch (struct unification_info *ui, tree parm)
+{
+  return unify_mismatch_1 (ur_parameter_pack_mismatch, ui, parm, NULL_TREE);
+}
+
+static int
+unify_ptrmem_cst_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_ptrmem_cst_mismatch, ui, parm, arg);
+}
+
+static int
+unify_constant_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_constant_mismatch, ui, parm, arg);
+}
+
+static int
+unify_constant_unequal (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_constant_unequal, ui, parm, arg);
+}
+
+static int
+unify_expression_unequal (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_expression_unequal, ui, parm, arg);
+}
+
+static int
+unify_parameter_pack_inconsistent (struct unification_info *ui, tree pack)
+{
+  if (ui)
+    {
+      ui->result = ur_parameter_pack_inconsistent;
+      ui->u.parm = pack;
+    }
+  return 1;
+}
+
+static int
+unify_inconsistency (struct unification_info *ui, tree parm,
+		     tree first, tree second)
+{
+  if (ui)
+    {
+      ui->result = ur_unification_inconsistency;
+      ui->u.inconsistent.template_parm = parm;
+      ui->u.inconsistent.earlier = first;
+      ui->u.inconsistent.later = second;
+    }
+  return 1;
+}
+
+static int
+unify_vla_arg (struct unification_info *ui, tree parm, tree arg)
+{
+  if (ui)
+    {
+      ui->result = ur_vla_arg;
+      ui->u.vla_arg.parm = parm;
+      ui->u.vla_arg.array_type = arg;
+    }
+  return 1;
+}
+
+static int
+unify_too_many_parameters (struct unification_info *ui, unsigned int have,
+			   unsigned int wanted)
+{
+  if (ui)
+    {
+      ui->result = ur_too_many_parameters;
+      ui->u.arity.have = have;
+      ui->u.arity.wanted = wanted;
+    }
+  return 1;
+}
+
+static int
+unify_too_few_parameters (struct unification_info *ui, unsigned int have,
+			  unsigned int wanted)
+{
+  if (ui)
+    {
+      ui->result = ur_too_few_parameters;
+      ui->u.arity.have = have;
+      ui->u.arity.wanted = wanted;
+    }
+  return 1;
+}
+
+static int
+unify_arg_conversion (struct unification_info *ui, tree to_type,
+		      tree from_type, tree arg)
+{
+  if (ui)
+    {
+      ui->result = ur_arg_conversion;
+      ui->u.arg_conversion.to_type = to_type;
+      ui->u.arg_conversion.from_type = from_type;
+      ui->u.arg_conversion.arg = arg;
+    }
+  return 1;
+}
+
+static int
+unify_no_common_base (struct unification_info *ui, tree parm, tree arg)
+{
+  if (ui)
+    {
+      ui->result = ur_no_common_base;
+      ui->u.common_base.potential_base = parm;
+      ui->u.common_base.arg = arg;
+    }
+  return 1;
+}
+
+static int
+unify_illformed_ptrmem_cst_expr (struct unification_info *ui,
+				 tree expr, tree type)
+{
+  if (ui)
+    {
+      ui->result = ur_illformed_ptrmem_cst_expr;
+      ui->u.illformed_ptrmem_cst.expr = expr;
+      ui->u.illformed_ptrmem_cst.type = type;
+    }
+  return 1;
+}
+
+static int
+unify_substitution_failure (struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur_substitution_failure;
+  return 1;
+}
+
+static int
+unify_invalid_explicit_argument (struct unification_info *ui, tree parm,
+				 int parm_index)
+{
+  if (ui)
+    {
+      ui->result = ur_invalid_explicit_arg;
+      ui->u.invalid_explicit_arg.parm = parm;
+      ui->u.invalid_explicit_arg.parm_index = parm_index;
+    }
+  return 1;
+}
+
+static int
+unify_inconsistent_template_template_parameters (struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur_inconsistent_template_template_parameters;
+  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
@@ -5286,7 +5521,8 @@  has_value_dependent_address (tree op)
    hacks can go away after we fix the double coercion problem.  */
 
 static tree
-convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
+convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain,
+			  struct unification_info *ui)
 {
   tree expr_type;
 
@@ -5610,7 +5846,10 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       /* [temp.arg.nontype] bullet 1 says the pointer to member
          expression must be a pointer-to-member constant.  */
       if (!check_valid_ptrmem_cst_expr (type, expr, complain))
-	return error_mark_node;
+	{
+	  unify_illformed_ptrmem_cst_expr (ui, expr, type);
+	  return error_mark_node;
+	}
 
       /* There is no way to disable standard conversions in
 	 resolve_address_of_overloaded_function (called by
@@ -5642,7 +5881,10 @@  convert_nontype_argument (tree type, tree expr, tsubst_flags_t complain)
       /* [temp.arg.nontype] bullet 1 says the pointer to member
          expression must be a pointer-to-member constant.  */
       if (!check_valid_ptrmem_cst_expr (type, expr, complain))
-	return error_mark_node;
+	{
+	  unify_illformed_ptrmem_cst_expr (ui, expr, type);
+	  return error_mark_node;
+	}
 
       expr = perform_qualification_conversions (type, expr);
       if (expr == error_mark_node)
@@ -5927,7 +6169,8 @@  convert_template_argument (tree parm,
 			   tree args,
 			   tsubst_flags_t complain,
 			   int i,
-			   tree in_decl)
+			   tree in_decl,
+			   struct unification_info *ui)
 {
   tree orig_arg;
   tree val;
@@ -6120,7 +6363,7 @@  convert_template_argument (tree parm,
 	   conversions can occur is part of determining which
 	   function template to call, or whether a given explicit
 	   argument specification is valid.  */
-	val = convert_nontype_argument (t, orig_arg, complain);
+	val = convert_nontype_argument (t, orig_arg, complain, ui);
       else
 	val = orig_arg;
 
@@ -6156,7 +6399,8 @@  coerce_template_parameter_pack (tree parms,
                                 tree new_args,
                                 int* lost,
                                 tree in_decl,
-                                tsubst_flags_t complain)
+                                tsubst_flags_t complain,
+				struct unification_info *ui)
 {
   tree parm = TREE_VEC_ELT (parms, parm_idx);
   int nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;
@@ -6238,7 +6482,7 @@  coerce_template_parameter_pack (tree parms,
       if (arg != error_mark_node)
 	arg = convert_template_argument (actual_parm, 
 					 arg, new_args, complain, parm_idx,
-					 in_decl);
+					 in_decl, ui);
       if (arg == error_mark_node)
         (*lost)++;
       TREE_VEC_ELT (packed_args, arg_idx - parm_idx) = arg; 
@@ -6281,7 +6525,8 @@  coerce_template_parms (tree parms,
 		       tree in_decl,
 		       tsubst_flags_t complain,
 		       bool require_all_args,
-		       bool use_default_args)
+		       bool use_default_args,
+		       struct unification_info *ui)
 {
   int nparms, nargs, parm_idx, arg_idx, lost = 0;
   tree inner_args;
@@ -6343,6 +6588,13 @@  coerce_template_parms (tree parms,
 	  if (in_decl)
 	    error ("provided for %q+D", in_decl);
 	}
+      else
+	{
+	  if (nargs > nparms)
+	    unify_too_many_parameters (ui, nargs, nparms);
+	  else
+	    unify_too_few_parameters (ui, nargs, nparms);
+	}
 
       return error_mark_node;
     }
@@ -6359,6 +6611,7 @@  coerce_template_parms (tree parms,
     {
       tree arg;
       tree parm;
+      int last_lost = lost;
 
       /* Get the Ith template parameter.  */
       parm = TREE_VEC_ELT (parms, parm_idx);
@@ -6383,7 +6636,7 @@  coerce_template_parms (tree parms,
 	  arg = coerce_template_parameter_pack (parms, parm_idx, args, 
 						inner_args, arg_idx,
 						new_args, &lost,
-						in_decl, complain);
+						in_decl, complain, ui);
 
           /* Store this argument.  */
           if (arg == error_mark_node)
@@ -6446,10 +6699,12 @@  coerce_template_parms (tree parms,
       else
 	arg = convert_template_argument (TREE_VALUE (parm),
 					 arg, new_args, complain, 
-                                         parm_idx, in_decl);
+                                         parm_idx, in_decl, ui);
 
       if (arg == error_mark_node)
 	lost++;
+      if (last_lost == 0 && lost)
+	unify_invalid_explicit_argument (ui, TREE_VALUE (parm), parm_idx);
       TREE_VEC_ELT (new_inner_args, arg_idx) = arg;
     }
   cp_unevaluated_operand = saved_unevaluated_operand;
@@ -6806,7 +7061,7 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
       arglist2 = coerce_template_parms (parmlist, arglist, templ,
 					complain,
 					/*require_all_args=*/true,
-					/*use_default_args=*/true);
+					/*use_default_args=*/true, NULL);
       if (arglist2 == error_mark_node
 	  || (!uses_template_parms (arglist2)
 	      && check_instantiated_args (templ, arglist2, complain)))
@@ -6879,7 +7134,7 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 					   arglist, gen_tmpl,
 					   complain,
 					   /*require_all_args=*/true,
-					   /*use_default_args=*/true);
+					   /*use_default_args=*/true, NULL);
 	      else
 		/* Outer levels should have already been coerced.  */
 		a = TMPL_ARGS_LEVEL (arglist, i);
@@ -6913,7 +7168,7 @@  lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
 				   gen_tmpl,
 				   complain,
 				   /*require_all_args=*/true,
-				   /*use_default_args=*/true);
+				   /*use_default_args=*/true, NULL);
 
       if (arglist == error_mark_node)
 	/* We were unable to bind the arguments.  */
@@ -13737,7 +13992,8 @@  fn_type_unification (tree fn,
 		     unsigned int nargs,
 		     tree return_type,
 		     unification_kind_t strict,
-		     int flags)
+		     int flags,
+		     struct unification_info *ui)
 {
   tree parms;
   tree fntype;
@@ -13772,12 +14028,12 @@  fn_type_unification (tree fn,
       bool incomplete = false;
 
       if (explicit_targs == error_mark_node)
-	return 1;
+	return unify_invalid (ui);
 
       converted_args
 	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
 				  /*require_all_args=*/false,
-				  /*use_default_args=*/false));
+				  /*use_default_args=*/false, ui));
       if (converted_args == error_mark_node)
 	return 1;
 
@@ -13840,7 +14096,7 @@  fn_type_unification (tree fn,
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
-	return 1;
+	return unify_substitution_failure (ui);
 
       /* Place the explicitly specified arguments in TARGS.  */
       for (i = NUM_TMPL_ARGS (converted_args); i--;)
@@ -13868,7 +14124,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, ui);
 
   /* Now that we have bindings for all of the template arguments,
      ensure that the arguments deduced for the template template
@@ -13894,7 +14150,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 (ui);
 
   if (result == 0)
     /* All is well so far.  Now, check:
@@ -13909,7 +14165,7 @@  fn_type_unification (tree fn,
     {
       tree substed = deduction_tsubst_fntype (fn, targs);
       if (substed == error_mark_node)
-	return 1;
+	return unify_substitution_failure (ui);
 
       /* 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
@@ -13924,7 +14180,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 (ui);
 	}
     }
 
@@ -14055,7 +14311,8 @@  type_unification_real (tree tparms,
 		       unsigned int xnargs,
 		       int subr,
 		       unification_kind_t strict,
-		       int flags)
+		       int flags,
+		       struct unification_info *ui)
 {
   tree parm, arg, arg_expr;
   int i;
@@ -14113,7 +14370,7 @@  type_unification_real (tree tparms,
       arg_expr = NULL;
 
       if (arg == error_mark_node)
-	return 1;
+	return unify_invalid (ui);
       if (arg == unknown_type_node)
 	/* We can't deduce anything from this, but we might get all the
 	   template args from other function args.  */
@@ -14139,7 +14396,7 @@  type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  return unify_arg_conversion (ui, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14155,15 +14412,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, ui))
 		continue;
 
-	      return 1;
+	      return unify_unknown (ui);
 	    }
 	  arg_expr = arg;
 	  arg = unlowered_expr_type (arg);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (ui);
 	}
 
       {
@@ -14175,7 +14432,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, ui))
+	  /* If unification failed, the recursive call will have updated
+	     UI appropriately.  */
 	  return 1;
       }
     }
@@ -14197,7 +14456,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, ui))
         return 1;
 
       /* Advance to the end of the list of parameters.  */
@@ -14207,11 +14466,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 (ui, 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 (ui, ia, count);
+    }
 
   if (!subr)
     {
@@ -14267,9 +14535,9 @@  type_unification_real (tree tparms,
 	      tree arg = TREE_PURPOSE (TREE_VEC_ELT (tparms, i));
 	      arg = tsubst_template_arg (arg, targs, tf_none, NULL_TREE);
 	      arg = convert_template_argument (parm, arg, targs, tf_none,
-					       i, NULL_TREE);
+					       i, NULL_TREE, ui);
 	      if (arg == error_mark_node)
-		return 1;
+		return unify_parameter_deduction_failure (ui, parm);
 	      else
 		{
 		  TREE_VEC_ELT (targs, i) = arg;
@@ -14303,7 +14571,7 @@  type_unification_real (tree tparms,
 	      continue;
 	    }
 
-	  return 2;
+	  return unify_parameter_deduction_failure (ui, tparm);
 	}
     }
 #ifdef ENABLE_CHECKING
@@ -14311,7 +14579,7 @@  type_unification_real (tree tparms,
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
 #endif
 
-  return 0;
+  return unify_success (ui);
 }
 
 /* Subroutine of type_unification_real.  Args are like the variables
@@ -14326,7 +14594,8 @@  resolve_overloaded_unification (tree tparms,
 				tree parm,
 				tree arg,
 				unification_kind_t strict,
-				int sub_strict)
+				int sub_strict,
+			        struct unification_info *ui)
 {
   tree tempargs = copy_node (targs);
   int good = 0;
@@ -14377,7 +14646,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, ui)
 		  && (!goodfn || !decls_match (goodfn, elem)))
 		{
 		  goodfn = elem;
@@ -14397,7 +14666,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, ui)
 	  && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg))))
 	{
 	  goodfn = OVL_CURRENT (arg);
@@ -14543,7 +14812,8 @@  try_one_overload (tree tparms,
 		  tree arg,
 		  unification_kind_t strict,
 		  int sub_strict,
-		  bool addr_p)
+		  bool addr_p,
+		  struct unification_info *ui)
 {
   int nargs;
   tree tempargs;
@@ -14573,7 +14843,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, ui))
     return 0;
 
   /* First make sure we didn't deduce anything that conflicts with
@@ -14611,7 +14881,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,
+		       struct unification_info *ui)
 {
   tree copy_of_targs;
 
@@ -14654,7 +14925,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, ui))
     return NULL_TREE;
 
   return arg;
@@ -14668,7 +14939,8 @@  try_class_unification (tree tparms, tree targs, tree parm, tree arg)
    by unify.  */
 
 static tree
-get_template_base (tree tparms, tree targs, tree parm, tree arg)
+get_template_base (tree tparms, tree targs, tree parm, tree arg,
+		   struct unification_info *ui)
 {
   tree rval = NULL_TREE;
   tree binfo;
@@ -14684,7 +14956,8 @@  get_template_base (tree tparms, tree targs, tree parm, tree arg)
      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), ui);
 
       if (r)
 	{
@@ -14785,6 +15058,12 @@  template_parm_level_and_index (tree parm, int* level, int* index)
     }
 }
 
+#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, UI)			\
+  do {									\
+    if (unify (TP, TA, P, A, S, UI))					\
+      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
@@ -14792,10 +15071,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, struct unification_info *ui)
 {
   tree parm 
     = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
@@ -14885,7 +15164,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, ui)
                         != 0)
                       return 1;
                     skip_arg_p = true;
@@ -14913,8 +15192,7 @@  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, ui);
           }
       }
 
@@ -15008,10 +15286,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 (ui, old_pack);
     }
 
-  return 0;
+  return unify_success (ui);
 }
 
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
@@ -15056,7 +15334,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,
+       struct unification_info *ui)
 {
   int idx;
   tree targ;
@@ -15071,19 +15350,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 (ui);
   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 (ui);
 
   /* 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 (ui);
 
   /* Handle init lists early, so the rest of the function can assume
      we're dealing with a type. */
@@ -15102,7 +15381,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 (ui);
 
       elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
 
@@ -15111,7 +15390,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 (ui);
 
 	  if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
 	    {
@@ -15123,8 +15402,7 @@  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, ui);
 	}
 
       /* If the std::initializer_list<T> deduction worked, replace the
@@ -15136,7 +15414,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 (ui);
     }
 
   /* Immediately reject some pairs that won't unify because of
@@ -15153,7 +15431,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 (ui, parm, arg);
 
   if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)
       && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))
@@ -15171,19 +15449,20 @@  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 (ui);
 
     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 (ui);
 
       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.  */
+	/* FIXME: What to return here?  */
 	return (TREE_CODE (arg) == TREE_CODE (parm)
 		&& same_type_p (parm, arg)) ? 0 : 1;
       idx = TEMPLATE_TYPE_IDX (parm);
@@ -15195,7 +15474,7 @@  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_parameter_deduction_failure (ui, parm);
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15203,7 +15482,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_parameter_deduction_failure (ui, parm);
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15247,7 +15526,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				       TYPE_TI_TEMPLATE (parm),
 				       tf_none,
 				       /*require_all_args=*/true,
-				       /*use_default_args=*/false)
+				       /*use_default_args=*/false, ui)
 		== error_mark_node)
 	      return 1;
 
@@ -15268,15 +15547,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 (ui, 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, ui);
 	      }
 
 	    if (parm_variadic_p
@@ -15284,7 +15563,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, ui))
 	      return 1;
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
@@ -15299,9 +15578,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 (ui);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (ui, parm, targ, arg);
 	}
       else
 	{
@@ -15311,20 +15590,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 (ui, 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 (ui);
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && same_type_p (targ, arg))
-	    return 0;
+	    return unify_success (ui);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (ui, parm, targ, arg);
 
 	  /* Make sure that ARG is not a variable-sized array.  (Note
 	     that were talking about variable-sized arrays (like
@@ -15334,7 +15613,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 (ui, parm, arg);
 
 	  /* Strip typedefs as in convert_template_argument.  */
 	  arg = strip_typedefs (arg);
@@ -15344,22 +15623,22 @@  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 (ui, 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_parameter_deduction_failure (ui, parm);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (ui);
 
     case TEMPLATE_PARM_INDEX:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (ui);
 
       if (TEMPLATE_PARM_LEVEL (parm)
 	  != template_decl_level (tparm))
@@ -15399,25 +15678,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 (ui);
       else
-	return 1;
+	return unify_parameter_deduction_failure (ui, parm);
 
       /* 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 (ui, parm);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (ui);
 
     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 (ui, parm, arg);
 
       /* Just unify the class member. It would be useless (and possibly
 	 wrong, depending on the strict flags) to unify also
@@ -15430,13 +15709,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, ui);
      }
 
     case POINTER_TYPE:
       {
 	if (TREE_CODE (arg) != POINTER_TYPE)
-	  return 1;
+	  return unify_type_mismatch (ui, parm, arg);
 
 	/* [temp.deduct.call]
 
@@ -15454,21 +15733,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, ui);
       }
 
     case REFERENCE_TYPE:
       if (TREE_CODE (arg) != REFERENCE_TYPE)
-	return 1;
+	return unify_type_mismatch (ui, parm, arg);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, ui);
 
     case ARRAY_TYPE:
       if (TREE_CODE (arg) != ARRAY_TYPE)
-	return 1;
+	return unify_type_mismatch (ui, parm, arg);
       if ((TYPE_DOMAIN (parm) == NULL_TREE)
 	  != (TYPE_DOMAIN (arg) == NULL_TREE))
-	return 1;
+	return unify_type_mismatch (ui, parm, arg);
       if (TYPE_DOMAIN (parm) != NULL_TREE)
 	{
 	  tree parm_max;
@@ -15524,11 +15803,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, ui);
 	}
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, ui);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -15538,16 +15817,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 (ui, 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 (ui, parm, arg);
 
       /* As far as unification is concerned, this wins.	 Later checks
 	 will invalidate it if necessary.  */
-      return 0;
+      return unify_success (ui);
 
       /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
       /* Type INTEGER_CST can come from ordinary constant template args.  */
@@ -15556,8 +15835,10 @@  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 (ui, parm, arg);
+      return (tree_int_cst_equal (parm, arg)
+	      ? unify_success (ui)
+	      : unify_constant_unequal (ui, parm, arg));
 
     case TREE_VEC:
       {
@@ -15567,27 +15848,27 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
 	  return 1;
 	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, ui);
+	return unify_success (ui);
       }
 
     case RECORD_TYPE:
     case UNION_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (ui, parm, arg);
 
       if (TYPE_PTRMEMFUNC_P (parm))
 	{
 	  if (!TYPE_PTRMEMFUNC_P (arg))
-	    return 1;
+	    return unify_type_mismatch (ui, parm, arg);
 
 	  return unify (tparms, targs,
 			TYPE_PTRMEMFUNC_FN_TYPE (parm),
 			TYPE_PTRMEMFUNC_FN_TYPE (arg),
-			strict);
+			strict, ui);
 	}
 
       if (CLASSTYPE_TEMPLATE_INFO (parm))
@@ -15598,7 +15879,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, ui);
 
 	      if (!t)
 		{
@@ -15611,10 +15892,11 @@  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);
+		  t = get_template_base (tparms, targs, parm, arg, ui);
 
+		  /* FIXME: Is this clobbering information in UI?  */
 		  if (!t)
-		    return 1;
+		    return unify_no_common_base (ui, parm, arg);
 		}
 	    }
 	  else if (CLASSTYPE_TEMPLATE_INFO (arg)
@@ -15625,14 +15907,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_parameter_deduction_failure (ui, parm);
 
 	  return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE);
+			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, ui);
 	}
       else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
-	return 1;
-      return 0;
+	return unify_type_mismatch (ui, parm, arg);
+      return unify_success (ui);
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -15643,7 +15925,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 (ui, parm, arg);
 
 	/* CV qualifications for methods can never be deduced, they must
 	   match exactly.  We need to check them explicitly here,
@@ -15654,11 +15936,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 (ui, 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, ui);
 
 	nargs = list_length (TYPE_ARG_TYPES (arg));
 	args = XALLOCAVEC (tree, nargs);
@@ -15670,7 +15951,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, ui);
       }
 
     case OFFSET_TYPE:
@@ -15683,11 +15964,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 (ui, 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, ui);
 
 	  /* Determine the type of the function we are unifying against. */
 	  method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
@@ -15699,28 +15980,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, ui);
 	}
 
       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 (ui, parm, arg);
+      RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+			       TYPE_OFFSET_BASETYPE (arg),
+			       UNIFY_ALLOW_NONE, ui);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict);
+		    strict, ui);
 
     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, ui);
       if (arg != integral_constant_value (parm))
-	return 1;
-      return 0;
+	return unify_constant_mismatch (ui, parm, arg);
+      return unify_success (ui);
 
     case FIELD_DECL:
     case TEMPLATE_DECL:
       /* Matched cases are handled by the ARG == PARM test above.  */
-      return 1;
+      return unify_parameter_deduction_failure (ui, parm);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15750,7 +16031,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 (ui);
 	      }
 	  }
 	  
@@ -15759,25 +16040,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 (ui, argslen, len);
+	if (argslen > len && !parm_variadic_p)
+	  return unify_too_many_parameters (ui, 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, ui);
           }
 
         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, ui);
+        return unify_success (ui);
       }
 
       break;
@@ -15787,11 +16070,11 @@  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 (ui);
 
     case ERROR_MARK:
       /* Unification fails if we hit an error node.  */
-      return 1;
+      return unify_invalid (ui);
 
     default:
       /* An unresolved overload is a nondeduced context.  */
@@ -15820,11 +16103,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 (ui, parm, arg);
       else
-	return 0;
+	return unify_success (ui);
     }
 }
+#undef RECUR_AND_CHECK_FAILURE
 
 /* Note that DECL can be defined in this translation unit, if
    required.  */
@@ -16087,10 +16371,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, NULL)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG1 is
              a pack expansion but ARG2 is not.  */
@@ -16111,10 +16396,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, NULL)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG2 is
              a pack expansion but ARG1 is not.*/
@@ -16125,8 +16411,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, NULL)
+		     == 0);
+          deduce2 = (unify (tparms2, targs2, arg2, arg1,
+			    UNIFY_ALLOW_NONE, NULL)
+		     == 0);
         }
 
       /* If we couldn't deduce arguments for tparms1 to make arg1 match
@@ -16316,7 +16606,7 @@  get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
 				 explicit_args, NULL_TREE,
 				 tf_none,
 				 /*require_all_args=*/false,
-				 /*use_default_args=*/false);
+				 /*use_default_args=*/false, NULL);
       if (converted_args == error_mark_node)
 	return NULL_TREE;
 
@@ -16340,7 +16630,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, NULL))
     return NULL_TREE;
 
   return targs;
@@ -16382,7 +16672,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, NULL))
     return NULL_TREE;
 
   for (i =  0; i < ntparms; ++i)
@@ -16619,7 +16909,7 @@  most_specialized_class (tree type, tree tmpl, tsubst_flags_t complain)
 						       partial_spec_args),
 				 tmpl, tf_none,
 				 /*require_all_args=*/true,
-				 /*use_default_args=*/true);
+				 /*use_default_args=*/true, NULL);
 
       --processing_template_decl;
 
@@ -19110,8 +19400,10 @@  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, NULL);
   if (val > 0)
     {
       if (type && type != error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
index 97ad079..231c027 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31434.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
@@ -1,5 +1,6 @@ 
 // { dg-options "-std=gnu++0x" }
 template<typename... T> int foo(const T&) // { dg-error "not expanded with|T" }
+// { dg-message "cannot convert" "overload failure" { target *-*-* } 2 }
 {
  union { T t; }; // { dg-error "not expanded with|T" }
  return t;
@@ -8,5 +9,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" "candidate note" { target *-*-* } 11 }
 }
diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C
new file mode 100644
index 0000000..5bde8b4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/template5.C
@@ -0,0 +1,17 @@ 
+// { dg-do compile }
+
+template<typename T>
+int low(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+// { dg-message "expects 3 arguments, 2 provided" "arity" { target *-*-* } 4 }
+
+template<typename T>
+int high(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+// { dg-message "expects 3 arguments, 4 provided" "arity" { target *-*-* } 8 }
+
+int test (void)
+{
+  low (5, 6);			// { dg-error "no matching function" }
+  // { dg-message "candidate" "" { target *-*-* } 13 }
+  high (5, 6, 7, 8);		// { dg-error "no matching function" }
+  // { dg-message "candidate" "" { target *-*-* } 15 }
+}
diff --git a/gcc/testsuite/g++.dg/template/overload12.C b/gcc/testsuite/g++.dg/template/overload12.C
new file mode 100644
index 0000000..d21f5f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/overload12.C
@@ -0,0 +1,19 @@ 
+// { dg-do compile }
+
+struct S {int x; int y;};
+template<typename T>
+int foo(T a, T b) {return a + b;} // { dg-message "template" }
+// { dg-message "deduced conflicting types for parameter" "deduction" { target *-*-* } 5 }
+template<typename T, typename T2>
+int foo(T a, T2& b, T2 c) {return a + b;}  // { dg-message "template" }
+// { dg-message "deduced conflicting types for parameter" "deduction" { target *-*-* } 8 }
+int foo(char*, S&); // { dg-message "foo" }
+// { dg-message "candidate expects 2 arguments, 3 provided" "arity" { target *-*-* } 10 }
+
+int foo2(int x)
+{
+  S s={1,2};
+  char c;
+  foo(c, 2, c); // { dg-error "no matching function" }
+  // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
index 560370a..56d9b44 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
@@ -1,10 +1,11 @@ 
 // { dg-do assemble  }
 template <int I>
-void f(int i);			// { dg-message "note" }
+void f(int i);			// { dg-message "void f" }
+// { dg-message "invalid explicit argument for template parameter 'I'" "argument note" { target *-*-* } 3 }
 
 void g()
 {
   int i;
   f<i>(7); // { dg-error "" } template argument 1 is invalid.
-  // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
+  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
index 85d3e73..8933038 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
@@ -13,30 +13,32 @@  public:
 };
 
 template <void (A::*)() >
-void g() {}			// { dg-message "note" }
+void g() {}			// { dg-message "void g" }
+// { dg-message "invalid explicit argument for template parameter 1" "info" { target *-*-* } 16 }
 template <int A::*>
-void h() {}			// { dg-message "note" }
+void h() {}			// { dg-message "void h" }
+// { dg-message "invalid explicit argument for template parameter 1" "info" { target *-*-* } 19 }
 
 
 int main() {
   g<&A::f>();
   h<&A::i>();
   g<&B::f>(); // { dg-error "" } 
-  // { dg-message "candidate" "candidate note" { target *-*-* } 24 }
-  h<&B::j>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 26 }
-  g<(void (A::*)()) &A::f>(); // { dg-error "" } 
+  h<&B::j>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 28 }
-  h<(int A::*) &A::i>(); // { dg-error "" } 
+  g<(void (A::*)()) &A::f>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 30 }
-  g<(void (A::*)()) &B::f>(); // { dg-error "" } 
+  h<(int A::*) &A::i>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 32 }
-  h<(int A::*) &B::j>(); // { dg-error "" } 
+  g<(void (A::*)()) &B::f>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 34 }
-  g<(void (A::*)()) 0>(); // { dg-error "" } 
+  h<(int A::*) &B::j>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 36 }
-  h<(int A::*) 0>(); // { dg-error "" } 
+  g<(void (A::*)()) 0>(); // { dg-error "" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 38 }
+  h<(int A::*) 0>(); // { dg-error "" } 
+  // { dg-message "candidate" "candidate note" { target *-*-* } 40 }
 
   return 0;
 }