diff mbox

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

Message ID 20110509224933.GR23480@codesourcery.com
State New
Headers show

Commit Message

Nathan Froyd May 9, 2011, 10:49 p.m. UTC
The patch below is an updated version of:

http://gcc.gnu.org/ml/libstdc++/2011-02/msg00009.html

with some changes:

- We now explicitly note when a candidate is rejected due to
  substitution failure.  We do not (yet) print the template parameters
  leading to rejection.

- We note when explicit template arguments are invalid.

A handful of testcases have been updated, mostly to ensure that we catch
particular failures.

Some things for future work:

- Substitution failures could be described in greater detail.  See PR
  48934 for some suggestions.

- I tried to print out the template arguments for calls with explicit
  template arguments, but discovered that such arguments get mangled
  prior to arriving at overload resolution.  It'd be nice if this didn't
  happen.

- Clearer reasons and more of them for particular cases.

Tested on x86_64-unknown-linux-gnu.  OK to commit?

-Nathan

	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, unify_failure): Define.
        (unify_invalid, unify_method_type_result): Define.
        (unify_mismatch_1): Define.
        (unify_cv_qual_mismatch): Define.
        (unify_type_mismatch): Define.
        (unify_parameter_pack_mismatch): Define.
        (unify_parameter_pack_inconsistent): Define.
        (unify_ptrmem_cst_mismatch): Define.
        (unify_pointer_mismatch): Define.
        (unify_reference_mismatch): Define.
        (unify_constant_mismatch): Define.
        (unify_constant_unequal): Define.
        (unify_expression_unequal): Define.
        (unify_inconsistency): Define.
        (unify_vla_arg): Define.
        (unify_too_many_parameters): Define.
        (unify_too_few_parameters): Define.
        (unify_arg_conversion): Define.
        (unify_no_common_base): Define.
        (unify_illformed_ptrmem_cst_expr): Define.
	(unify_substitution_failure): Define.
	(unify_invalid_explicit_argument): 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.

Comments

Jason Merrill May 10, 2011, 8:08 p.m. UTC | #1
On 05/09/2011 06:49 PM, Nathan Froyd wrote:
> The patch below is an updated version of:
>
> http://gcc.gnu.org/ml/libstdc++/2011-02/msg00009.html

Sorry I didn't respond to that message.

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.

That said, I'm not going to reject this patch over this issue, but 
please keep this principle in mind with future diagnostic improvement 
patches.

> +    case ur_invalid_arg:
> +    case ur_invalid_parm:
> +    case ur_invalid_init_list:
> +    case ur_invalid_template_parm:
> +      inform (loc, "  an error occurred during template argument deduction");

These are all cases of bailing out when we encounter an error_mark_node 
that indicates an earlier error from an ill-formed expression or 
whatever.  I don't see any reason to have separate cases for them, and 
the message is misleading; the error didn't occur during deduction, it 
occurred before we got to deduction.  We just can't do deduction on 
ill-formed inputs.

> +    case ur_type_mismatch:
> +    case ur_pointer_mismatch:
> +    case ur_reference_mismatch:
> +      inform (loc,  "  mismatched types %qT and %qT",

Why make these different?  They are all cases of the argument and 
parameter types not having the same form.

> +    case ur_expanding_pack_to_fixed_arg_list:

This is never generated anywhere.  And the message in 
coerce_template_parms is a sorry to indicate that this is a bug in G++, 
not a problem with the user's code.

> unify_failure (struct unification_info *ui, tree parm)
...
>         return unify_failure (ui);

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.

Jason
diff mbox

Patch

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3a71572..da4aeae 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,112 @@  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_arg:
+    case ur_invalid_parm:
+    case ur_invalid_init_list:
+    case ur_invalid_template_parm:
+      inform (loc, "  an error occurred during template argument deduction");
+      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:
+    case ur_pointer_mismatch:
+    case ur_reference_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_expanding_pack_to_fixed_arg_list:
+      if (TREE_CODE (ui->u.expanding_pack.arg) == EXPR_PACK_EXPANSION)
+	inform (loc, "  cannot expand %<%E%> into a fixed-length argument list",
+		ui->u.expanding_pack.arg);
+      else
+	inform (loc, "  cannot expand %<%T%> into a fixed-length argument list",
+		ui->u.expanding_pack.arg);
+      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_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_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 +3279,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 +3288,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 a67b34a..a07557b 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6487,7 +6487,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 ad298df..d82f1f9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5051,6 +5051,118 @@  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,
+  ur_failure,
+  /* Error due to invalid argument.  */
+  ur_invalid_arg,
+  /* Invalid template parameter.  */
+  ur_invalid_parm,
+  /* Invalid init list.  */
+  ur_invalid_init_list,
+  /* CV-qualification mismatch.  */
+  ur_cv_qual_mismatch,
+  /* Invalid template parameter.  */
+  ur_invalid_template_parm,
+  /* Unification resulted in a METHOD_TYPE.  */
+  ur_method_type_result,
+  /* 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 pointer, arg isn't.  */
+  ur_pointer_mismatch,
+  /* Parameter is a reference, arg isn't.  */
+  ur_reference_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_expanding_pack_to_fixed_arg_list,
+  ur_no_common_base,
+  ur_illformed_ptrmem_cst_expr,
+  ur_substitution_failure,
+  ur_invalid_explicit_arg,
+};
+
+/* 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 method_type_result;	/* For ur_method_type_result.  */
+    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_expanding_pack_to_fixed_arg_list.  */
+    struct {
+      tree arg;
+    } expanding_pack;
+    /* 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);
@@ -5089,7 +5201,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 76fc69b..251090f 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,237 @@  has_value_dependent_address (tree op)
   return false;
 }
 
+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_failure (struct unification_info *ui, tree parm)
+{
+  if (ui)
+    {
+      ui->result = ur_failure;
+      ui->u.parm = parm;
+    }
+  return 1;
+}
+
+static int
+unify_invalid (enum unification_result ur, struct unification_info *ui)
+{
+  if (ui)
+    ui->result = ur;
+  return 1;
+}
+
+static int
+unify_method_type_result (struct unification_info *ui, tree t)
+{
+  if (ui)
+    {
+      ui->result = ur_method_type_result;
+      ui->u.method_type_result = t;
+    }
+  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, tree arg)
+{
+  return unify_mismatch_1 (ur_parameter_pack_mismatch, ui, parm, arg);
+}
+
+static int
+unify_parameter_pack_inconsistent (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_parameter_pack_inconsistent, ui, parm, arg);
+}
+
+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_pointer_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_pointer_mismatch, ui, parm, arg);
+}
+
+static int
+unify_reference_mismatch (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_reference_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_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;
+}
+
 /* 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 +5527,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 +5852,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 +5887,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 +6175,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 +6369,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 +6405,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 +6488,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 +6531,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 +6594,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 +6617,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 +6642,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 +6705,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 +7067,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 +7140,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 +7174,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.  */
@@ -13685,7 +13946,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;
@@ -13725,7 +13987,7 @@  fn_type_unification (tree fn,
       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;
 
@@ -13788,7 +14050,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--;)
@@ -13816,7 +14078,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
@@ -13842,7 +14104,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_unknown (ui);
 
   if (result == 0)
     /* All is well so far.  Now, check:
@@ -13857,7 +14119,7 @@  fn_type_unification (tree fn,
     {
       tree substed = tsubst (TREE_TYPE (fn), targs, tf_none, NULL_TREE);
       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
@@ -13872,7 +14134,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);
 	}
     }
 
@@ -14003,7 +14265,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;
@@ -14061,7 +14324,7 @@  type_unification_real (tree tparms,
       arg_expr = NULL;
 
       if (arg == error_mark_node)
-	return 1;
+	return unify_invalid (ur_invalid_arg, 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.  */
@@ -14087,7 +14350,7 @@  type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  return unify_arg_conversion (ui, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14103,15 +14366,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 (ur_invalid_arg, ui);
 	}
 
       {
@@ -14123,7 +14386,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;
       }
     }
@@ -14145,7 +14410,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.  */
@@ -14155,11 +14420,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)
     {
@@ -14215,9 +14489,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_failure (ui, tparm);
 	      else
 		{
 		  TREE_VEC_ELT (targs, i) = arg;
@@ -14251,7 +14525,7 @@  type_unification_real (tree tparms,
 	      continue;
 	    }
 
-	  return 2;
+	  return unify_failure (ui, tparm);
 	}
     }
 #ifdef ENABLE_CHECKING
@@ -14259,7 +14533,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
@@ -14274,7 +14548,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;
@@ -14325,7 +14600,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;
@@ -14345,7 +14620,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);
@@ -14491,7 +14766,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;
@@ -14521,7 +14797,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
@@ -14559,7 +14835,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;
 
@@ -14602,7 +14879,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;
@@ -14616,7 +14893,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;
@@ -14632,7 +14910,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)
 	{
@@ -14733,6 +15012,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
@@ -14740,10 +15025,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);
@@ -14833,7 +15118,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;
@@ -14861,8 +15146,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);
           }
       }
 
@@ -14956,10 +15240,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, NULL_TREE, NULL_TREE);
     }
 
-  return 0;
+  return unify_success (ui);
 }
 
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
@@ -15004,7 +15288,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;
@@ -15019,19 +15304,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 (ur_invalid_arg, 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. */
@@ -15050,7 +15335,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);
 
@@ -15059,7 +15344,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 (ur_invalid_init_list, ui);
 
 	  if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
 	    {
@@ -15071,8 +15356,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
@@ -15084,7 +15368,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
@@ -15101,7 +15385,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))
@@ -15119,19 +15403,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 (ur_invalid_template_parm, 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);
@@ -15143,7 +15428,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_failure (ui);
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15151,7 +15436,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_failure (ui);
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15195,9 +15480,10 @@  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;
+	      /* FIXME: need to return something sane here.  */
+	      return unify_failure (ui);
 
 	    /* Deduce arguments T, i from TT<T> or TT<i>.
 	       We check each element of PARMVEC and ARGVEC individually
@@ -15216,15 +15502,14 @@  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_failure (ui);
 
              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
@@ -15232,8 +15517,8 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 					 parmvec, argvec,
 					 UNIFY_ALLOW_NONE,
 					 /*call_args_p=*/false,
-					 /*subr=*/false))
-	      return 1;
+					 /*subr=*/false, ui))
+	      return unify_failure (ui);
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
 
@@ -15247,9 +15532,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
 	{
@@ -15259,20 +15544,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 (ur_invalid_arg, 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
@@ -15282,7 +15567,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);
@@ -15292,27 +15577,28 @@  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 ur_parameter_pack_mismatch;
 
       /* 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_result (ui, arg);
 
       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 (ur_invalid_template_parm, ui);
 
       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.  */
+	/* FIXME: What to return here?  */
 	return !(TREE_CODE (arg) == TREE_CODE (parm)
 		 && cp_tree_equal (parm, arg));
 
@@ -15320,6 +15606,7 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
 
       if (targ)
+	/* FIXME: what's the rationale here?  */
 	return !cp_tree_equal (targ, arg);
 
       /* [temp.deduct.type] If, in the declaration of a function template
@@ -15347,25 +15634,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_failure (ui);
 
       /* 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, arg);
 
       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
@@ -15378,13 +15665,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_pointer_mismatch (ui, parm, arg);
 
 	/* [temp.deduct.call]
 
@@ -15402,21 +15689,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_reference_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;
@@ -15472,11 +15759,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:
@@ -15486,16 +15773,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.  */
@@ -15504,8 +15791,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:
       {
@@ -15515,27 +15804,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))
@@ -15546,7 +15835,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)
 		{
@@ -15559,10 +15848,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)
@@ -15573,14 +15863,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_failure (ui);
 
 	  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:
@@ -15591,7 +15881,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,
@@ -15602,11 +15892,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);
@@ -15618,7 +15907,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:
@@ -15631,11 +15920,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));
@@ -15647,28 +15936,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 ur_type_mismatch;
+      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_failure (ui);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15698,7 +15987,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);
 	      }
 	  }
 	  
@@ -15709,23 +15998,24 @@  unify (tree tparms, tree targs, tree parm, tree arg, int strict)
            a pack expression, we can't unify.  */
         if (argslen < (len - parm_variadic_p)
             || (argslen > len && !parm_variadic_p))
-          return 1;
+	  return unify_failure (ui);
 
         /* 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;
@@ -15735,11 +16025,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 (ur_invalid_parm, ui);
 
     default:
       /* An unresolved overload is a nondeduced context.  */
@@ -15768,11 +16058,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.  */
@@ -16035,10 +16326,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.  */
@@ -16059,10 +16351,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.*/
@@ -16073,8 +16366,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
@@ -16264,7 +16561,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;
 
@@ -16288,7 +16585,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;
@@ -16330,7 +16627,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)
@@ -16567,7 +16864,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;
 
@@ -19050,8 +19347,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;
 }