public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH,c++] describe reasons for function template overload resolution failure
@ 2011-05-10  6:36 Nathan Froyd
  2011-05-10 23:29 ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-10  6:36 UTC (permalink / raw)
  To: gcc-patches; +Cc: jason

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.

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
 \f
 /* 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;
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-10  6:36 [PATCH,c++] describe reasons for function template overload resolution failure Nathan Froyd
@ 2011-05-10 23:29 ` Jason Merrill
  2011-05-16 20:28   ` Nathan Froyd
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-10 23:29 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-10 23:29 ` Jason Merrill
@ 2011-05-16 20:28   ` Nathan Froyd
  2011-05-18 18:36     ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-16 20:28 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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.

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
 \f
 /* 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;
 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-16 20:28   ` Nathan Froyd
@ 2011-05-18 18:36     ` Jason Merrill
  2011-05-18 20:04       ` Nathan Froyd
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-18 18:36 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

> 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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-18 18:36     ` Jason Merrill
@ 2011-05-18 20:04       ` Nathan Froyd
  2011-05-18 20:34         ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-18 20:04 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-18 20:04       ` Nathan Froyd
@ 2011-05-18 20:34         ` Jason Merrill
  2011-05-25 19:40           ` Nathan Froyd
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-18 20:34 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-18 20:34         ` Jason Merrill
@ 2011-05-25 19:40           ` Nathan Froyd
  2011-05-26 16:52             ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-25 19:40 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Wed, May 18, 2011 at 03:48:41PM -0400, Jason Merrill wrote:
> 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.

The patch below implements just such an idea.  The only twist is that
the `explain' parameter is actually a `location_t *' so that when we
provide explanations that aren't produced via tf_warning_or_error
blocks, the explanations are attached to the template itself rather than
the call, as would be done with input_location.  Requests for
non-explanation are accomplished with a NULL argument.

I'm not totally attached to this; it's almost too cute, and since
tf_warning_or_error messsages tend to be attached to the call anyway,
it's arguably inconsistent.

I didn't see what you intended by "reconstructing" the arguments, so I
implemented the more straightforward saving.

The testsuite needs a little more fixing up, though surprisingly not as
much as you might think.  The oddest result is the change to
variadic105.C, where we now output a sorry during overload explanation.
But if I understand the test correctly, that is the expected result
currently.

The patch does not totally address PR 48934; we are not explaining
ourselves in all cases.  I plan to hunt this down in a followup patch
and attempt to say something intelligent.

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

-Nathan

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

gcc/testsuite/
	PR c++/45329
	PR c++/48934
	* g++.dg/cpp0x/lambda/lambda-ice2.C: Adjust.
	* g++.dg/cpp0x/pr31434.C: Adjust.
	* g++.dg/cpp0x/sfinae11.C: Adjust.
	* g++.dg/cpp0x/variadic105.C: Adjust.
	* g++.dg/other/ptrmem10.C: Adjust.
	* g++.dg/other/ptrmem11.C: Adjust.
	* g++.dg/template/incomplete2.C: Adjust.
	* g++.dg/template/local4.C: Adjust.
	* g++.dg/template/unify11.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.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index ff3dc06..9888261 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -430,7 +430,10 @@ enum rejection_reason_code {
   rr_none,
   rr_arity,
   rr_arg_conversion,
-  rr_bad_arg_conversion
+  rr_bad_arg_conversion,
+  rr_template_unification,
+  rr_template_instantiation,
+  rr_invalid_copy
 };
 
 struct conversion_info {
@@ -458,6 +461,24 @@ struct rejection_reason {
     struct conversion_info conversion;
     /* Same, but for bad argument conversions.  */
     struct conversion_info bad_conversion;
+    /* Information about template unification failures.  These are the
+       parameters passed to fn_type_unification.  */
+    struct {
+      tree tmpl;
+      tree explicit_targs;
+      tree targs;
+      const tree *args;
+      unsigned int nargs;
+      tree return_type;
+      unification_kind_t strict;
+      int flags;
+    } template_unification;
+    /* Information about template instantiation failures.  These are the
+       parameters passed to instantiate_template.  */
+    struct {
+      tree tmpl;
+      tree targs;
+    } template_instantiation;
   } u;
 };
 
@@ -607,6 +628,44 @@ bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
+				const tree *args, unsigned int nargs,
+				tree return_type, unification_kind_t strict,
+				int flags)
+{
+  size_t args_n_bytes = sizeof (*args) * nargs;
+  tree *args1 = (tree *) conversion_obstack_alloc (args_n_bytes);
+  struct rejection_reason *r = alloc_rejection (rr_template_unification);
+  r->u.template_unification.tmpl = tmpl;
+  r->u.template_unification.explicit_targs = explicit_targs;
+  r->u.template_unification.targs = targs;
+  /* Copy args to our own storage.  */
+  memcpy (args1, args, args_n_bytes);
+  r->u.template_unification.args = args1;
+  r->u.template_unification.nargs = nargs;
+  r->u.template_unification.return_type = return_type;
+  r->u.template_unification.strict = strict;
+  r->u.template_unification.flags = flags;
+  return r;
+}
+
+static struct rejection_reason *
+template_instantiation_rejection (tree tmpl, tree targs)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
+  r->u.template_instantiation.tmpl = tmpl;
+  r->u.template_instantiation.targs = targs;
+  return r;
+}
+
+static struct rejection_reason *
+invalid_copy_with_fn_template_rejection (void)
+{
+  struct rejection_reason *r = alloc_rejection (rr_invalid_copy);
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -2889,14 +2948,23 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   i = fn_type_unification (tmpl, explicit_targs, targs,
 			   args_without_in_chrg,
 			   nargs_without_in_chrg,
-			   return_type, strict, flags);
+			   return_type, strict, flags, NULL);
 
   if (i != 0)
-    goto fail;
+    {
+      reason = template_unification_rejection (tmpl, explicit_targs,
+					       targs, args_without_in_chrg,
+					       nargs_without_in_chrg,
+					       return_type, strict, flags);
+      goto fail;
+    }
 
   fn = instantiate_template (tmpl, targs, tf_none);
   if (fn == error_mark_node)
-    goto fail;
+    {
+      reason = template_instantiation_rejection (tmpl, targs);
+      goto fail;
+    }
 
   /* In [class.copy]:
 
@@ -2925,7 +2993,10 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
       tree arg_types = FUNCTION_FIRST_USER_PARMTYPE (fn);
       if (arg_types && same_type_p (TYPE_MAIN_VARIANT (TREE_VALUE (arg_types)),
 				    ctype))
-	goto fail;
+	{
+	  reason = invalid_copy_with_fn_template_rejection ();
+	  goto fail;
+	}
     }
 
   if (obj != NULL_TREE)
@@ -3093,6 +3164,18 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
 	    info->n_arg+1, info->from_type, info->to_type);
 }
 
+/* Print information about a candidate with WANT parameters and we found
+   HAVE.  */
+
+static void
+print_arity_information (location_t loc, unsigned int have, unsigned int want)
+{
+  inform_n (loc, want,
+	    "  candidate expects %d argument, %d provided",
+	    "  candidate expects %d arguments, %d provided",
+	    want, have);
+}
+
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
    is the text to print before the candidate itself.
 
@@ -3139,10 +3222,8 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate)
       switch (r->code)
 	{
 	case rr_arity:
-	  inform_n (loc, r->u.arity.expected,
-		    "  candidate expects %d argument, %d provided",
-		    "  candidate expects %d arguments, %d provided",
-		    r->u.arity.expected, r->u.arity.actual);
+	  print_arity_information (loc, r->u.arity.actual,
+				   r->u.arity.expected);
 	  break;
 	case rr_arg_conversion:
 	  print_conversion_rejection (loc, &r->u.conversion);
@@ -3150,6 +3231,29 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 	case rr_bad_arg_conversion:
 	  print_conversion_rejection (loc, &r->u.bad_conversion);
 	  break;
+	case rr_template_unification:
+	  /* Re-run template unification with diagnostics.  */
+	  fn_type_unification (r->u.template_unification.tmpl,
+			       r->u.template_unification.explicit_targs,
+			       r->u.template_unification.targs,
+			       r->u.template_unification.args,
+			       r->u.template_unification.nargs,
+			       r->u.template_unification.return_type,
+			       r->u.template_unification.strict,
+			       r->u.template_unification.flags,
+			       &loc);
+	  break;
+	case rr_template_instantiation:
+	  /* Re-run template instantiation with diagnostics.  */
+	  instantiate_template (r->u.template_instantiation.tmpl,
+				r->u.template_instantiation.targs,
+				tf_warning_or_error);
+	  break;
+	case rr_invalid_copy:
+	  inform (loc, 
+		  "  a constructor taking a single argument of its own "
+		  "class type is invalid");
+	  break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 4e52b18..d0d3363 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6527,7 +6527,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 ada01fb..d900d99 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5129,7 +5129,8 @@ extern tree instantiate_class_template		(tree);
 extern tree instantiate_template		(tree, tree, tsubst_flags_t);
 extern int fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
-						 tree, unification_kind_t, int);
+						 tree, unification_kind_t, int,
+						 location_t *);
 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 dbff91e..add205e 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -109,13 +109,20 @@ static GTY(()) VEC(tree,gc) *canonical_template_parms;
 #define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32
 #define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64
 
+enum template_base_result {
+  tbr_incomplete_type,
+  tbr_ambiguous_baseclass,
+  tbr_success
+};
+
 static void push_access_scope (tree);
 static void pop_access_scope (tree);
 static bool resolve_overloaded_unification (tree, tree, tree, tree,
-					    unification_kind_t, int);
+					    unification_kind_t, int,
+					    location_t *);
 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, location_t *);
+static int unify (tree, tree, tree, tree, int, location_t *);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
@@ -129,7 +136,8 @@ static bool check_instantiated_args (tree, tree, tsubst_flags_t);
 static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
 					     tree);
 static int type_unification_real (tree, tree, tree, const tree *,
-				  unsigned int, int, unification_kind_t, int);
+				  unsigned int, int, unification_kind_t, int,
+				  location_t *);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
@@ -154,7 +162,8 @@ static tree get_bindings (tree, tree, tree, bool);
 static int template_decl_level (tree);
 static int check_cv_quals_for_unify (int, tree, tree);
 static void template_parm_level_and_index (tree, int*, int*);
-static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
+static int unify_pack_expansion (tree, tree, tree,
+				 tree, int, bool, bool, location_t *);
 static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -166,8 +175,9 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
 static bool check_specialization_scope (void);
 static tree process_partial_specialization (tree);
 static void set_current_access_from_decl (tree);
-static tree get_template_base (tree, tree, tree, tree);
-static tree try_class_unification (tree, tree, tree, tree);
+static enum template_base_result get_template_base (tree, tree, tree, tree,
+						    location_t *, tree *);
+static tree try_class_unification (tree, tree, tree, tree, location_t *);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
@@ -5265,6 +5275,233 @@ has_value_dependent_address (tree op)
   return false;
 }
 
+/* The next set of functions are used for providing helpful explanatory
+   diagnostics for failed overload resolution.  Their messages should be
+   indented by two spaces for consistency with the messages in
+   call.c  */
+
+static int
+unify_success (location_t *explain_p ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+unify_unknown (location_t *explain_p ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+unify_parameter_deduction_failure (location_t *explain_p, tree parm)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  couldn't deduce template parameter %qD", parm);
+  return 1;
+}
+
+static int
+unify_invalid (location_t *explain_p ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+unify_cv_qual_mismatch (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  types %qT and %qT have incompatible cv-qualifiers",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_type_mismatch (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p, "  mismatched types %qT and %qT", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_mismatch (location_t *explain_p, tree parm)
+{
+  if (explain_p)
+    {
+      inform (*explain_p,
+	      "  template parameter %qD is not a parameter pack",
+	      parm);
+      inform (*explain_p, "  please report this as a bug");
+      gcc_unreachable ();
+    }
+  return 1;
+}
+
+static int
+unify_ptrmem_cst_mismatch (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  mismatched pointer-to-memory constants %qE and %qE",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_constant_mismatch (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p, "  %qE is a constant and %qE is not",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_constant_unequal (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p, "  %qE is not equal to %qE", parm, arg);
+  return 1;
+}
+
+static int
+unify_expression_unequal (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p, "  %qE is not equal to %qE", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_inconsistent (location_t *explain_p,
+				   tree pack)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  portions of parameter pack %qT could not be deduced",
+	    pack);
+  return 1;
+}
+
+static int
+unify_inconsistency (location_t *explain_p, tree parm, tree first, tree second)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  deduced conflicting types for parameter %qT (%qT and %qT)",
+	    parm, first, second);
+  return 1;
+}
+
+static int
+unify_vla_arg (location_t *explain_p, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  variable-sized array type %qT is not "
+	    "a valid template argument",
+	    arg);
+  return 1;
+}
+
+static int
+unify_method_type_error (location_t *explain_p, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  method type %qT is not a valid template argument", arg);
+  return 1;
+}
+
+static int
+unify_arity (location_t *explain_p, int have, int wanted)
+{
+  if (explain_p)
+    inform_n (*explain_p, wanted,
+	      "  candidate expects %d argument, %d provided",
+	      "  candidate expects %d arguments, %d provided",
+	      wanted, have);
+  return 1;
+}
+
+static int
+unify_too_many_parameters (location_t *explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_too_few_parameters (location_t *explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_arg_conversion (location_t *explain_p, tree to_type,
+		      tree from_type, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p, "  cannot convert %qE (type %qT) to type %qT",
+	    arg, from_type, to_type);
+  return 1;
+}
+
+static int
+unify_no_common_base (location_t *explain_p, enum template_base_result r,
+		      tree parm, tree arg)
+{
+  if (explain_p)
+    switch (r)
+      {
+      case tbr_ambiguous_baseclass:
+	inform (*explain_p, "  %qT is an ambiguous base class of %qT",
+		arg, parm);
+	break;
+      default:
+	inform (*explain_p, "  %qT is not derived from %qT", arg, parm);
+	break;
+      }
+  return 1;
+}
+
+static int
+unify_inconsistent_template_template_parameters (location_t *explain_p)
+{
+  if (explain_p)
+    inform (*explain_p, "  inconsistent template template parameters");
+  return 1;
+}
+
+static int
+unify_template_deduction_failure (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  can't deduce a template for %qT from non-template type %qT",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_template_parameter_mismatch (location_t *explain_p, tree parm, tree tparm)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  template parameter %qT does not match %qD", tparm, parm);
+  return 1;
+}
+
+static int
+unify_template_argument_mismatch (location_t *explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (*explain_p,
+	    "  template argument %qE does not match %qD", arg, parm);
+  return 1;
+}
+
 /* Attempt to convert the non-type template parameter EXPR to the
    indicated TYPE.  If the conversion is successful, return the
    converted value.  If the conversion is unsuccessful, return
@@ -13600,7 +13837,7 @@ static GTY((param_is (spec_entry))) htab_t current_deduction_htab;
    0.5% of compile time.  */
 
 static tree
-deduction_tsubst_fntype (tree fn, tree targs)
+deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
 {
   unsigned i;
   spec_entry **slot;
@@ -13670,7 +13907,7 @@ deduction_tsubst_fntype (tree fn, tree targs)
       VEC_safe_push (spec_entry, gc, current_deduction_vec, &elt);
     }
 
-  r = tsubst (fntype, targs, tf_none, NULL_TREE);
+  r = tsubst (fntype, targs, complain, NULL_TREE);
 
   /* After doing the substitution, make sure we didn't hit it again.  Note
      that we might have switched to a hash table during tsubst.  */
@@ -13859,7 +14096,8 @@ fn_type_unification (tree fn,
 		     unsigned int nargs,
 		     tree return_type,
 		     unification_kind_t strict,
-		     int flags)
+		     int flags,
+		     location_t *explain_p)
 {
   tree parms;
   tree fntype;
@@ -13894,14 +14132,22 @@ fn_type_unification (tree fn,
       bool incomplete = false;
 
       if (explicit_targs == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       converted_args
 	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
 				  /*require_all_args=*/false,
 				  /*use_default_args=*/false));
       if (converted_args == error_mark_node)
-	return 1;
+	{
+	  /* Run it for diagnostics.  */
+	  if (explain_p)
+	    coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+				   tf_warning_or_error,
+				   /*require_all_args=*/false,
+				   /*use_default_args=*/false);
+	  return 1;
+	}
 
       /* Substitute the explicit args into the function type.  This is
 	 necessary so that, for instance, explicitly declared function
@@ -13958,11 +14204,20 @@ fn_type_unification (tree fn,
         incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
 
       processing_template_decl += incomplete;
-      fntype = deduction_tsubst_fntype (fn, converted_args);
+      fntype = deduction_tsubst_fntype (fn, converted_args, tf_none);
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
-	return 1;
+	{
+	  if (explain_p)
+	    {
+	      processing_template_decl += incomplete;
+	      fntype = deduction_tsubst_fntype (fn, converted_args,
+						tf_warning_or_error);
+	      processing_template_decl -= incomplete;
+	    }
+	  return 1;
+	}
 
       /* Place the explicitly specified arguments in TARGS.  */
       for (i = NUM_TMPL_ARGS (converted_args); i--;)
@@ -13990,7 +14245,7 @@ fn_type_unification (tree fn,
      event.  */
   result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
 				  targs, parms, args, nargs, /*subr=*/0,
-				  strict, flags);
+				  strict, flags, explain_p);
 
   /* Now that we have bindings for all of the template arguments,
      ensure that the arguments deduced for the template template
@@ -14016,7 +14271,7 @@ fn_type_unification (tree fn,
   if (result == 0
       && !template_template_parm_bindings_ok_p 
            (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
-    return 1;
+    return unify_inconsistent_template_template_parameters (explain_p);
 
   if (result == 0)
     /* All is well so far.  Now, check:
@@ -14029,9 +14284,13 @@ fn_type_unification (tree fn,
        substitution results in an invalid type, as described above,
        type deduction fails.  */
     {
-      tree substed = deduction_tsubst_fntype (fn, targs);
+      tree substed = deduction_tsubst_fntype (fn, targs, tf_none);
       if (substed == error_mark_node)
-	return 1;
+	{
+	  if (explain_p)
+	    deduction_tsubst_fntype (fn, targs, tf_warning_or_error);
+	  return 1;
+	}
 
       /* If we're looking for an exact match, check that what we got
 	 is indeed an exact match.  It might not be if some template
@@ -14046,7 +14305,7 @@ fn_type_unification (tree fn,
 	    sarg = tree_cons (NULL_TREE, TREE_TYPE (substed), sarg);
 	  for (i = 0; i < nargs && sarg; ++i, sarg = TREE_CHAIN (sarg))
 	    if (!same_type_p (args[i], TREE_VALUE (sarg)))
-	      return 1;
+	      return unify_unknown (explain_p);
 	}
     }
 
@@ -14177,7 +14436,8 @@ type_unification_real (tree tparms,
 		       unsigned int xnargs,
 		       int subr,
 		       unification_kind_t strict,
-		       int flags)
+		       int flags,
+		       location_t *explain_p)
 {
   tree parm, arg, arg_expr;
   int i;
@@ -14235,7 +14495,7 @@ type_unification_real (tree tparms,
       arg_expr = NULL;
 
       if (arg == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
       if (arg == unknown_type_node)
 	/* We can't deduce anything from this, but we might get all the
 	   template args from other function args.  */
@@ -14261,7 +14521,7 @@ type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  return unify_arg_conversion (explain_p, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14277,15 +14537,15 @@ type_unification_real (tree tparms,
 		 function templates and at most one of a set of
 		 overloaded functions provides a unique match.  */
 	      if (resolve_overloaded_unification
-		  (tparms, targs, parm, arg, strict, sub_strict))
+		  (tparms, targs, parm, arg, strict, sub_strict, explain_p))
 		continue;
 
-	      return 1;
+	      return unify_unknown (explain_p);
 	    }
 	  arg_expr = arg;
 	  arg = unlowered_expr_type (arg);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 	}
 
       {
@@ -14297,7 +14557,9 @@ type_unification_real (tree tparms,
 
 	if (arg == init_list_type_node && arg_expr)
 	  arg = arg_expr;
-	if (unify (tparms, targs, parm, arg, arg_strict))
+	if (unify (tparms, targs, parm, arg, arg_strict, explain_p))
+	  /* If unification failed, the recursive call will have updated
+	     UI appropriately.  */
 	  return 1;
       }
     }
@@ -14319,7 +14581,7 @@ type_unification_real (tree tparms,
       /* Copy the parameter into parmvec.  */
       TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
       if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
-                                /*call_args_p=*/true, /*subr=*/subr))
+                                /*call_args_p=*/true, /*subr=*/subr, explain_p))
         return 1;
 
       /* Advance to the end of the list of parameters.  */
@@ -14329,11 +14591,20 @@ type_unification_real (tree tparms,
   /* Fail if we've reached the end of the parm list, and more args
      are present, and the parm list isn't variadic.  */
   if (ia < nargs && parms == void_list_node)
-    return 1;
+    return unify_too_many_parameters (explain_p, nargs, ia);
   /* Fail if parms are left and they don't have default values.  */
   if (parms && parms != void_list_node
       && TREE_PURPOSE (parms) == NULL_TREE)
-    return 1;
+    {
+      unsigned int count = nargs;
+      tree p = parms;
+      while (p && p != void_list_node)
+	{
+	  count++;
+	  p = TREE_CHAIN (p);
+	}
+      return unify_too_few_parameters (explain_p, ia, count);
+    }
 
   if (!subr)
     {
@@ -14391,7 +14662,14 @@ type_unification_real (tree tparms,
 	      arg = convert_template_argument (parm, arg, targs, tf_none,
 					       i, NULL_TREE);
 	      if (arg == error_mark_node)
-		return 1;
+		{
+		  /* Give the user an informative error message.  */
+		  if (explain_p)
+		    convert_template_argument (parm, arg, targs,
+					       tf_warning_or_error,
+					       i, NULL_TREE);
+		  return 1;
+		}
 	      else
 		{
 		  TREE_VEC_ELT (targs, i) = arg;
@@ -14425,7 +14703,7 @@ type_unification_real (tree tparms,
 	      continue;
 	    }
 
-	  return 2;
+	  return unify_parameter_deduction_failure (explain_p, tparm);
 	}
     }
 #ifdef ENABLE_CHECKING
@@ -14433,7 +14711,7 @@ type_unification_real (tree tparms,
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
 #endif
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Subroutine of type_unification_real.  Args are like the variables
@@ -14448,7 +14726,8 @@ resolve_overloaded_unification (tree tparms,
 				tree parm,
 				tree arg,
 				unification_kind_t strict,
-				int sub_strict)
+				int sub_strict,
+			        location_t *explain_p)
 {
   tree tempargs = copy_node (targs);
   int good = 0;
@@ -14499,7 +14778,7 @@ resolve_overloaded_unification (tree tparms,
 	    {
 	      elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);
 	      if (try_one_overload (tparms, targs, tempargs, parm,
-				    elem, strict, sub_strict, addr_p)
+				    elem, strict, sub_strict, addr_p, explain_p)
 		  && (!goodfn || !decls_match (goodfn, elem)))
 		{
 		  goodfn = elem;
@@ -14519,7 +14798,7 @@ resolve_overloaded_unification (tree tparms,
     for (; arg; arg = OVL_NEXT (arg))
       if (try_one_overload (tparms, targs, tempargs, parm,
 			    TREE_TYPE (OVL_CURRENT (arg)),
-			    strict, sub_strict, addr_p)
+			    strict, sub_strict, addr_p, explain_p)
 	  && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg))))
 	{
 	  goodfn = OVL_CURRENT (arg);
@@ -14665,7 +14944,8 @@ try_one_overload (tree tparms,
 		  tree arg,
 		  unification_kind_t strict,
 		  int sub_strict,
-		  bool addr_p)
+		  bool addr_p,
+		  location_t *explain_p)
 {
   int nargs;
   tree tempargs;
@@ -14695,7 +14975,7 @@ try_one_overload (tree tparms,
   nargs = TREE_VEC_LENGTH (targs);
   tempargs = make_tree_vec (nargs);
 
-  if (unify (tparms, tempargs, parm, arg, sub_strict) != 0)
+  if (unify (tparms, tempargs, parm, arg, sub_strict, explain_p))
     return 0;
 
   /* First make sure we didn't deduce anything that conflicts with
@@ -14733,7 +15013,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,
+		       location_t *explain_p)
 {
   tree copy_of_targs;
 
@@ -14776,7 +15057,7 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg)
 
   /* If unification failed, we're done.  */
   if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
-	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE))
+	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p))
     return NULL_TREE;
 
   return arg;
@@ -14789,8 +15070,9 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg)
    a partial specialization, as well as a plain template type.  Used
    by unify.  */
 
-static tree
-get_template_base (tree tparms, tree targs, tree parm, tree arg)
+static enum template_base_result
+get_template_base (tree tparms, tree targs, tree parm, tree arg,
+		   location_t *explain_p, tree *result)
 {
   tree rval = NULL_TREE;
   tree binfo;
@@ -14799,14 +15081,18 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
   binfo = TYPE_BINFO (complete_type (arg));
   if (!binfo)
-    /* The type could not be completed.  */
-    return NULL_TREE;
+    {
+      /* The type could not be completed.  */
+      *result = NULL_TREE;
+      return tbr_incomplete_type;
+    }
 
   /* Walk in inheritance graph order.  The search order is not
      important, and this avoids multiple walks of virtual bases.  */
   for (binfo = TREE_CHAIN (binfo); binfo; binfo = TREE_CHAIN (binfo))
     {
-      tree r = try_class_unification (tparms, targs, parm, BINFO_TYPE (binfo));
+      tree r = try_class_unification (tparms, targs, parm,
+				      BINFO_TYPE (binfo), explain_p);
 
       if (r)
 	{
@@ -14819,13 +15105,17 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
 	     applies.  */
 	  if (rval && !same_type_p (r, rval))
-	    return NULL_TREE;
+	    {
+	      *result = NULL_TREE;
+	      return tbr_ambiguous_baseclass;
+	    }
 
 	  rval = r;
 	}
     }
 
-  return rval;
+  *result = rval;
+  return tbr_success;
 }
 
 /* Returns the level of DECL, which declares a template parameter.  */
@@ -14907,6 +15197,12 @@ template_parm_level_and_index (tree parm, int* level, int* index)
     }
 }
 
+#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP)			\
+  do {									\
+    if (unify (TP, TA, P, A, S, EP))					\
+      return 1;								\
+  } while (0);
+
 /* Unifies the remaining arguments in PACKED_ARGS with the pack
    expansion at the end of PACKED_PARMS. Returns 0 if the type
    deduction succeeds, 1 otherwise. STRICT is the same as in
@@ -14914,10 +15210,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, location_t *explain_p)
 {
   tree parm 
     = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
@@ -15007,7 +15303,7 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
                     if (resolve_overloaded_unification
                         (tparms, targs, parm, arg,
 			 (unification_kind_t) strict,
-			 sub_strict)
+			 sub_strict, explain_p)
                         != 0)
                       return 1;
                     skip_arg_p = true;
@@ -15035,8 +15331,8 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	    /* For deduction from an init-list we need the actual list.  */
 	    if (arg_expr && BRACE_ENCLOSED_INITIALIZER_P (arg_expr))
 	      arg = arg_expr;
-            if (unify (tparms, targs, parm, arg, arg_strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs, parm, arg, arg_strict,
+				     explain_p);
           }
       }
 
@@ -15130,10 +15426,10 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
       else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
                                     new_args))
         /* Inconsistent unification of this parameter pack.  */
-        return 1;
+        return unify_parameter_pack_inconsistent (explain_p, old_pack);
     }
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
@@ -15178,7 +15474,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,
+       location_t *explain_p)
 {
   int idx;
   tree targ;
@@ -15193,19 +15490,19 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     parm = TREE_OPERAND (parm, 0);
 
   if (arg == error_mark_node)
-    return 1;
+    return unify_invalid (explain_p);
   if (arg == unknown_type_node
       || arg == init_list_type_node)
     /* We can't deduce anything from this, but we might get all the
        template args from other function args.  */
-    return 0;
+    return unify_success (explain_p);
 
   /* If PARM uses template parameters, then we can't bail out here,
      even if ARG == PARM, since we won't record unifications for the
      template parameters.  We might need them if we're trying to
      figure out which of two things is more specialized.  */
   if (arg == parm && !uses_template_parms (parm))
-    return 0;
+    return unify_success (explain_p);
 
   /* Handle init lists early, so the rest of the function can assume
      we're dealing with a type. */
@@ -15224,7 +15521,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	/* We can only deduce from an initializer list argument if the
 	   parameter is std::initializer_list; otherwise this is a
 	   non-deduced context. */
-	return 0;
+	return unify_success (explain_p);
 
       elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
 
@@ -15233,7 +15530,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  int elt_strict = strict;
 
 	  if (elt == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
 	    {
@@ -15245,8 +15542,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	      elt = type;
 	    }
 
-	  if (unify (tparms, targs, elttype, elt, elt_strict))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, elttype, elt, elt_strict,
+				   explain_p);
 	}
 
       /* If the std::initializer_list<T> deduction worked, replace the
@@ -15258,7 +15555,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  targ = listify (targ);
 	  TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
 	}
-      return 0;
+      return unify_success (explain_p);
     }
 
   /* Immediately reject some pairs that won't unify because of
@@ -15275,7 +15572,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 is more specialized, for example.  */
       && TREE_CODE (arg) != TEMPLATE_TYPE_PARM
       && !check_cv_quals_for_unify (strict_in, arg, parm))
-    return 1;
+    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
   if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)
       && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))
@@ -15293,21 +15590,26 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       /* In a type which contains a nested-name-specifier, template
 	 argument values cannot be deduced for template parameters used
 	 within the nested-name-specifier.  */
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_TYPE_LEVEL (parm)
 	  != template_decl_level (tparm))
 	/* The PARM is not one we're trying to unify.  Just check
 	   to see if it matches ARG.  */
-	return (TREE_CODE (arg) == TREE_CODE (parm)
-		&& same_type_p (parm, arg)) ? 0 : 1;
+	{
+	  if (TREE_CODE (arg) == TREE_CODE (parm)
+	      && same_type_p (parm, arg))
+	    return unify_success (explain_p);
+	  else
+	    return unify_type_mismatch (explain_p, parm, arg);
+	}
       idx = TEMPLATE_TYPE_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
@@ -15317,7 +15619,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	   && TREE_CODE (tparm) != TYPE_DECL)
 	  || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
 	      && TREE_CODE (tparm) != TEMPLATE_DECL))
-	return 1;
+	return unify_template_parameter_mismatch (explain_p,
+						  parm, tparm);
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15325,7 +15628,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     template parameter.  */
 	  if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
 	      && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
-	    return 1;
+	    return unify_template_deduction_failure (explain_p, parm, arg);
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15371,7 +15674,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				       /*require_all_args=*/true,
 				       /*use_default_args=*/false)
 		== error_mark_node)
-	      return 1;
+	      {
+		/* Run it for diagnostics.  */
+		if (explain_p)
+		  coerce_template_parms (parm_parms, full_argvec,
+					 TYPE_TI_TEMPLATE (parm),
+					 tf_warning_or_error,
+					 /*require_all_args=*/true,
+					 /*use_default_args=*/false);
+		return 1;
+	      }
 
 	    /* Deduce arguments T, i from TT<T> or TT<i>.
 	       We check each element of PARMVEC and ARGVEC individually
@@ -15390,15 +15702,15 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
               parm_variadic_p = 1;
             
             if (TREE_VEC_LENGTH (argvec) < len - parm_variadic_p)
-              return 1;
+              return unify_too_few_parameters (explain_p, TREE_VEC_LENGTH (argvec),
+					       len);
 
              for (i = 0; i < len - parm_variadic_p; ++i)
 	      {
-		if (unify (tparms, targs,
-			   TREE_VEC_ELT (parmvec, i),
-			   TREE_VEC_ELT (argvec, i),
-			   UNIFY_ALLOW_NONE))
-		  return 1;
+		RECUR_AND_CHECK_FAILURE (tparms, targs,
+					 TREE_VEC_ELT (parmvec, i),
+					 TREE_VEC_ELT (argvec, i),
+					 UNIFY_ALLOW_NONE, explain_p);
 	      }
 
 	    if (parm_variadic_p
@@ -15406,7 +15718,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 					 parmvec, argvec,
 					 UNIFY_ALLOW_NONE,
 					 /*call_args_p=*/false,
-					 /*subr=*/false))
+					 /*subr=*/false, explain_p))
 	      return 1;
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
@@ -15421,9 +15733,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && template_args_equal (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 	}
       else
 	{
@@ -15433,20 +15745,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     that binds `const int' to `T'.  */
 	  if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL,
 					 arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
 	  /* Consider the case where ARG is `const volatile int' and
 	     PARM is `const T'.  Then, T should be `volatile int'.  */
 	  arg = cp_build_qualified_type_real
 	    (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && same_type_p (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 
 	  /* Make sure that ARG is not a variable-sized array.  (Note
 	     that were talking about variable-sized arrays (like
@@ -15456,7 +15768,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     instantiation.  Besides, such types are not allowed in
 	     ISO C++, so we can do as we please here.  */
 	  if (variably_modified_type_p (arg, NULL_TREE))
-	    return 1;
+	    return unify_vla_arg (explain_p, arg);
 
 	  /* Strip typedefs as in convert_template_argument.  */
 	  arg = strip_typedefs (arg);
@@ -15466,35 +15778,45 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !template_parameter_pack_p (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm);
 
       /* If the argument deduction results is a METHOD_TYPE,
          then there is a problem.
          METHOD_TYPE doesn't map to any real C++ type the result of
 	 the deduction can not be of that type.  */
       if (TREE_CODE (arg) == METHOD_TYPE)
-	return 1;
+	return unify_method_type_error (explain_p, arg);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_PARM_INDEX:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_PARM_LEVEL (parm)
 	  != template_decl_level (tparm))
-	/* The PARM is not one we're trying to unify.  Just check
-	   to see if it matches ARG.  */
-	return !(TREE_CODE (arg) == TREE_CODE (parm)
-		 && cp_tree_equal (parm, arg));
+	{
+	  /* The PARM is not one we're trying to unify.  Just check
+	     to see if it matches ARG.  */
+	  int result = !(TREE_CODE (arg) == TREE_CODE (parm)
+			 && cp_tree_equal (parm, arg));
+	  if (result)
+	    unify_template_parameter_mismatch (explain_p, parm, tparm);
+	  return result;
+	}
 
       idx = TEMPLATE_PARM_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
 
       if (targ)
-	return !cp_tree_equal (targ, arg);
+	{
+	  int x = !cp_tree_equal (targ, arg);
+	  if (x)
+	    unify_inconsistency (explain_p, parm, targ, arg);
+	  return x;
+	}
 
       /* [temp.deduct.type] If, in the declaration of a function template
 	 with a non-type template-parameter, the non-type
@@ -15521,25 +15843,25 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       else if (uses_template_parms (tparm))
 	/* We haven't deduced the type of this parameter yet.  Try again
 	   later.  */
-	return 0;
+	return unify_success (explain_p);
       else
-	return 1;
+	return unify_type_mismatch (explain_p, tparm, arg);
 
       /* If ARG is a parameter pack or an expansion, we cannot unify
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case PTRMEM_CST:
      {
 	/* A pointer-to-member constant can be unified only with
 	 another constant.  */
       if (TREE_CODE (arg) != PTRMEM_CST)
-	return 1;
+	return unify_ptrmem_cst_mismatch (explain_p, parm, arg);
 
       /* Just unify the class member. It would be useless (and possibly
 	 wrong, depending on the strict flags) to unify also
@@ -15552,13 +15874,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	 Unification of &A::x and &B::x must succeed.  */
       return unify (tparms, targs, PTRMEM_CST_MEMBER (parm),
-		    PTRMEM_CST_MEMBER (arg), strict);
+		    PTRMEM_CST_MEMBER (arg), strict, explain_p);
      }
 
     case POINTER_TYPE:
       {
 	if (TREE_CODE (arg) != POINTER_TYPE)
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* [temp.deduct.call]
 
@@ -15576,21 +15898,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  strict |= (strict_in & UNIFY_ALLOW_DERIVED);
 
 	return unify (tparms, targs, TREE_TYPE (parm),
-		      TREE_TYPE (arg), strict);
+		      TREE_TYPE (arg), strict, explain_p);
       }
 
     case REFERENCE_TYPE:
       if (TREE_CODE (arg) != REFERENCE_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case ARRAY_TYPE:
       if (TREE_CODE (arg) != ARRAY_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if ((TYPE_DOMAIN (parm) == NULL_TREE)
 	  != (TYPE_DOMAIN (arg) == NULL_TREE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if (TYPE_DOMAIN (parm) != NULL_TREE)
 	{
 	  tree parm_max;
@@ -15629,7 +15951,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
                 Here, the type of the ARG will be "int [g(i)]", and
                 may be a SAVE_EXPR, etc.  */
 	      if (TREE_CODE (arg_max) != MINUS_EXPR)
-		return 1;
+		return unify_vla_arg (explain_p, arg);
 	      arg_max = TREE_OPERAND (arg_max, 0);
 	    }
 
@@ -15646,11 +15968,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				   arg_max,
 				   integer_one_node);
 
-	  if (unify (tparms, targs, parm_max, arg_max, UNIFY_ALLOW_INTEGER))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, parm_max, arg_max,
+				   UNIFY_ALLOW_INTEGER, explain_p);
 	}
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -15660,16 +15982,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case ENUMERAL_TYPE:
     case VOID_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* We have already checked cv-qualification at the top of the
 	 function.  */
       if (!same_type_ignoring_top_level_qualifiers_p (arg, parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* As far as unification is concerned, this wins.	 Later checks
 	 will invalidate it if necessary.  */
-      return 0;
+      return unify_success (explain_p);
 
       /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
       /* Type INTEGER_CST can come from ordinary constant template args.  */
@@ -15678,38 +16000,41 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	arg = TREE_OPERAND (arg, 0);
 
       if (TREE_CODE (arg) != INTEGER_CST)
-	return 1;
-      return !tree_int_cst_equal (parm, arg);
+	return unify_constant_mismatch (explain_p, parm, arg);
+      return (tree_int_cst_equal (parm, arg)
+	      ? unify_success (explain_p)
+	      : unify_constant_unequal (explain_p, parm, arg));
 
     case TREE_VEC:
       {
 	int i;
 	if (TREE_CODE (arg) != TREE_VEC)
-	  return 1;
+	  return unify_template_argument_mismatch (explain_p, parm, arg);
 	if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
-	  return 1;
+	  return unify_arity (explain_p, TREE_VEC_LENGTH (arg),
+			      TREE_VEC_LENGTH (parm));
 	for (i = 0; i < TREE_VEC_LENGTH (parm); ++i)
-	  if (unify (tparms, targs,
-		     TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
-		     UNIFY_ALLOW_NONE))
-	    return 1;
-	return 0;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs,
+				   TREE_VEC_ELT (parm, i),
+				   TREE_VEC_ELT (arg, i),
+				   UNIFY_ALLOW_NONE, explain_p);
+	return unify_success (explain_p);
       }
 
     case RECORD_TYPE:
     case UNION_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       if (TYPE_PTRMEMFUNC_P (parm))
 	{
 	  if (!TYPE_PTRMEMFUNC_P (arg))
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs,
 			TYPE_PTRMEMFUNC_FN_TYPE (parm),
 			TYPE_PTRMEMFUNC_FN_TYPE (arg),
-			strict);
+			strict, explain_p);
 	}
 
       if (CLASSTYPE_TEMPLATE_INFO (parm))
@@ -15720,7 +16045,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    {
 	      /* First, we try to unify the PARM and ARG directly.  */
 	      t = try_class_unification (tparms, targs,
-					 parm, arg);
+					 parm, arg, explain_p);
 
 	      if (!t)
 		{
@@ -15733,10 +16058,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		       a class of the form template-id, A can be a
 		       pointer to a derived class pointed to by the
 		       deduced A.  */
-		  t = get_template_base (tparms, targs, parm, arg);
+		  enum template_base_result r;
+		  r = get_template_base (tparms, targs, parm, arg,
+					 explain_p, &t);
 
 		  if (!t)
-		    return 1;
+		    return unify_no_common_base (explain_p, r, parm, arg);
 		}
 	    }
 	  else if (CLASSTYPE_TEMPLATE_INFO (arg)
@@ -15747,14 +16074,14 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    t = arg;
 	  else
 	    /* There's no chance of unification succeeding.  */
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE);
+			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p);
 	}
       else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
-	return 1;
-      return 0;
+	return unify_type_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -15765,7 +16092,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	unsigned int i;
 
 	if (TREE_CODE (arg) != TREE_CODE (parm))
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* CV qualifications for methods can never be deduced, they must
 	   match exactly.  We need to check them explicitly here,
@@ -15776,11 +16103,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		(UNIFY_ALLOW_NONE,
 		 class_of_this_parm (arg),
 		 class_of_this_parm (parm))))
-	  return 1;
+	  return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	if (unify (tparms, targs, TREE_TYPE (parm),
-		   TREE_TYPE (arg), UNIFY_ALLOW_NONE))
-	  return 1;
+	RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm),
+				 TREE_TYPE (arg), UNIFY_ALLOW_NONE, explain_p);
 
 	nargs = list_length (TYPE_ARG_TYPES (arg));
 	args = XALLOCAVEC (tree, nargs);
@@ -15792,7 +16118,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
 				      args, nargs, 1, DEDUCE_EXACT,
-				      LOOKUP_NORMAL);
+				      LOOKUP_NORMAL, explain_p);
       }
 
     case OFFSET_TYPE:
@@ -15805,11 +16131,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Check top-level cv qualifiers */
 	  if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	  if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		     TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+				   TYPE_PTRMEMFUNC_OBJECT_TYPE (arg),
+				   UNIFY_ALLOW_NONE, explain_p);
 
 	  /* Determine the type of the function we are unifying against. */
 	  method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
@@ -15821,28 +16147,28 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     implicit object parameter and place them on the function
 	     type to be restored later. */
 	  fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type));
-	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict);
+	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, explain_p);
 	}
 
       if (TREE_CODE (arg) != OFFSET_TYPE)
-	return 1;
-      if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		 TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
+      RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+			       TYPE_OFFSET_BASETYPE (arg),
+			       UNIFY_ALLOW_NONE, explain_p);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict);
+		    strict, explain_p);
 
     case CONST_DECL:
       if (DECL_TEMPLATE_PARM_P (parm))
-	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict);
+	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict, explain_p);
       if (arg != integral_constant_value (parm))
-	return 1;
-      return 0;
+	return unify_constant_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case FIELD_DECL:
     case TEMPLATE_DECL:
       /* Matched cases are handled by the ARG == PARM test above.  */
-      return 1;
+      return unify_template_argument_mismatch (explain_p, parm, arg);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15872,7 +16198,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		  /* Since there is something following the pack
 		     expansion, we cannot unify this template argument
 		     list.  */
-		  return 0;
+		  return unify_success (explain_p);
 	      }
 	  }
 	  
@@ -15881,25 +16207,27 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
            (not counting the pack expression at the end), or we have
            too many arguments for a parameter list that doesn't end in
            a pack expression, we can't unify.  */
-        if (argslen < (len - parm_variadic_p)
-            || (argslen > len && !parm_variadic_p))
-          return 1;
+        if (argslen < (len - parm_variadic_p))
+	  return unify_too_few_parameters (explain_p, argslen, len);
+	if (argslen > len && !parm_variadic_p)
+	  return unify_too_many_parameters (explain_p, argslen, len);
 
         /* Unify all of the parameters that precede the (optional)
            pack expression.  */
         for (i = 0; i < len - parm_variadic_p; ++i)
           {
-            if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
-                       TREE_VEC_ELT (packed_args, i), strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs,
+				     TREE_VEC_ELT (packed_parms, i),
+				     TREE_VEC_ELT (packed_args, i),
+				     strict, explain_p);
           }
 
         if (parm_variadic_p)
           return unify_pack_expansion (tparms, targs, 
                                        packed_parms, packed_args,
                                        strict, /*call_args_p=*/false,
-                                       /*subr=*/false);
-        return 0;
+                                       /*subr=*/false, explain_p);
+        return unify_success (explain_p);
       }
 
       break;
@@ -15909,16 +16237,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case UNDERLYING_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
 	 or UNDERLYING_TYPE nodes.  */
-      return 0;
+      return unify_success (explain_p);
 
     case ERROR_MARK:
       /* Unification fails if we hit an error node.  */
-      return 1;
+      return unify_invalid (explain_p);
 
     default:
       /* An unresolved overload is a nondeduced context.  */
       if (type_unknown_p (parm))
-	return 0;
+	return unify_success (explain_p);
       gcc_assert (EXPR_P (parm));
 
       /* We must be looking at an expression.  This can happen with
@@ -15942,11 +16270,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
       if (!uses_template_parms (parm)
 	  && !template_args_equal (parm, arg))
-	return 1;
+	return unify_expression_unequal (explain_p, parm, arg);
       else
-	return 0;
+	return unify_success (explain_p);
     }
 }
+#undef RECUR_AND_CHECK_FAILURE
 \f
 /* Note that DECL can be defined in this translation unit, if
    required.  */
@@ -16209,10 +16538,11 @@ more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec, 
+          deduce1 = (unify_pack_expansion (tparms1, targs1, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/NULL)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG1 is
              a pack expansion but ARG2 is not.  */
@@ -16233,10 +16563,11 @@ more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec, 
+          deduce2 = (unify_pack_expansion (tparms2, targs2, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/NULL)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG2 is
              a pack expansion but ARG1 is not.*/
@@ -16247,8 +16578,12 @@ more_specialized_fn (tree pat1, tree pat2, int len)
         {
           /* The normal case, where neither argument is a pack
              expansion.  */
-          deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
-          deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+          deduce1 = (unify (tparms1, targs1, arg1, arg2,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/NULL)
+		     == 0);
+          deduce2 = (unify (tparms2, targs2, arg2, arg1,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/NULL)
+		     == 0);
         }
 
       /* If we couldn't deduce arguments for tparms1 to make arg1 match
@@ -16462,7 +16797,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
 			   args, ix,
 			   (check_rettype || DECL_CONV_FN_P (fn)
 			    ? TREE_TYPE (decl_type) : NULL_TREE),
-			   DEDUCE_EXACT, LOOKUP_NORMAL))
+			   DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/NULL))
     return NULL_TREE;
 
   return targs;
@@ -16504,7 +16839,7 @@ get_class_bindings (tree tparms, tree spec_args, tree args)
   if (unify (tparms, deduced_args,
 	     INNERMOST_TEMPLATE_ARGS (spec_args),
 	     INNERMOST_TEMPLATE_ARGS (args),
-	     UNIFY_ALLOW_NONE))
+	     UNIFY_ALLOW_NONE, /*explain_p=*/NULL))
     return NULL_TREE;
 
   for (i =  0; i < ntparms; ++i)
@@ -19237,8 +19572,11 @@ do_auto_deduction (tree type, tree init, tree auto_node)
   targs = make_tree_vec (1);
   TREE_VEC_ELT (tparms, 0)
     = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
+  /* FIXME: Should we pass in unification information and then use that
+     to elaborate on the error messages below?  */
   val = type_unification_real (tparms, targs, parms, args, 1, 0,
-			       DEDUCE_CALL, LOOKUP_NORMAL);
+			       DEDUCE_CALL, LOOKUP_NORMAL,
+			       /*explain_p=*/NULL);
   if (val > 0)
     {
       if (type && type != error_mark_node)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
index 352137a..120dfaa 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
@@ -9,8 +9,9 @@ decltype(F()) run(F f) // { dg-message "note" }
 
 int main()
 {
-  auto l = []() { return 5; };
+  auto l = []() { return 5; }; // { dg-error "lambda closure type" }
 
   run(l); // { dg-error "no match" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 14 }
+  // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 14 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/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/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
index a3ffc34..a525566 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
@@ -50,7 +50,7 @@ int main()
   static_assert(  noexcept( f2(y) ), "OK." );
   // static_assert(  noexcept( f3(y) ), "shall be ill-formed(OK)." );
 
-  static_assert(  noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "no match" }
-  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
-  static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "no match" }
+  static_assert(  noexcept( f1(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" }
+  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "(no match|could not convert)" }
+  static_assert( !noexcept( f3(z) ), "shall be ill-formed." ); // { dg-error "(no match|no member)" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic105.C b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
index 24d7e15..2729b31 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic105.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
@@ -21,4 +21,5 @@ struct call_sum {
 int main() {
   // This shouldn't be an error; this is bug 35722.
   reverse<call_sum>(1,2);	// { dg-bogus "no match" "" { xfail *-*-* } }
+  // { dg-message "sorry, unimplemented" "candidate explanation" { target *-*-* } 23 }
 }
diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C
index bc386ed..a17df7f 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem10.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem10.C
@@ -13,7 +13,7 @@ template <class C>
 static void
 bar(C *c, void (C::*m) ())
 {
-  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun)" }
+  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
 }
 
diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C
index 119cbb0..e73164e 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem11.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem11.C
@@ -14,7 +14,7 @@ template <typename T>
 int
 bar(int T::* p)
 {
-  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member)" }
+  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
 }
 
diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C
new file mode 100644
index 0000000..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/incomplete2.C b/gcc/testsuite/g++.dg/template/incomplete2.C
index d86ea06..b855569 100644
--- a/gcc/testsuite/g++.dg/template/incomplete2.C
+++ b/gcc/testsuite/g++.dg/template/incomplete2.C
@@ -9,6 +9,6 @@ A a;  // { dg-error "incomplete type" }
 
 void bar()
 {
-  foo<a>();  // { dg-error "no matching function" }
+  foo<a>();  // { dg-error "(no matching function|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 12 }
 }
diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C
index 9a03c9a..d842076 100644
--- a/gcc/testsuite/g++.dg/template/local4.C
+++ b/gcc/testsuite/g++.dg/template/local4.C
@@ -5,6 +5,6 @@ template <typename T> void foo() {} // { dg-message "note" }
 
 int main () {
   struct S {};
-  foo<S> (); // { dg-error "match" } 
+  foo<S> (); // { dg-error "(match|template argument for|trying to instantiate)" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/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++.dg/template/unify11.C b/gcc/testsuite/g++.dg/template/unify11.C
index ed6b31c..25606dc 100644
--- a/gcc/testsuite/g++.dg/template/unify11.C
+++ b/gcc/testsuite/g++.dg/template/unify11.C
@@ -20,7 +20,7 @@ struct B
     C (U t)
     {
       A a;
-      A b = foo (this, a, t); // { dg-error "no matching function" }
+      A b = foo (this, a, t); // { dg-error "(no matching function|is not a)" }
       // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
     }
   } c;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
index 560370a..c27d131 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
@@ -1,6 +1,6 @@
 // { dg-do assemble  }
 template <int I>
-void f(int i);			// { dg-message "note" }
+void f(int i);			// { dg-message "void f" }
 
 void g()
 {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
index 85d3e73..8802e98 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
@@ -13,9 +13,9 @@ public:
 };
 
 template <void (A::*)() >
-void g() {}			// { dg-message "note" }
+void g() {}			// { dg-message "void g" }
 template <int A::*>
-void h() {}			// { dg-message "note" }
+void h() {}			// { dg-message "void h" }
 
 
 int main() {

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-25 19:40           ` Nathan Froyd
@ 2011-05-26 16:52             ` Jason Merrill
  2011-05-26 20:53               ` Nathan Froyd
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-26 16:52 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

On 05/25/2011 02:15 PM, Nathan Froyd wrote:
> The patch below implements just such an idea.  The only twist is that
> the `explain' parameter is actually a `location_t *' so that when we
> provide explanations that aren't produced via tf_warning_or_error
> blocks, the explanations are attached to the template itself rather than
> the call, as would be done with input_location.  Requests for
> non-explanation are accomplished with a NULL argument.
>
> I'm not totally attached to this; it's almost too cute, and since
> tf_warning_or_error messsages tend to be attached to the call anyway,
> it's arguably inconsistent.

Yes, I think let's drop this bit and just use the call location. 
Ideally, for unification failures we'd give the source location of the 
problematic argument (which we don't always have because it might be a 
plain DECL) and for substitution failures we'd give the source location 
of the expression that substitution failed on (for which we could adjust 
input_location in tsubst_*).

> I didn't see what you intended by "reconstructing" the arguments, so I
> implemented the more straightforward saving.

I was thinking that we could try to add the candidate again, but this is 
fine.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-26 16:52             ` Jason Merrill
@ 2011-05-26 20:53               ` Nathan Froyd
  2011-05-27 20:23                 ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-26 20:53 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

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

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

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

Yes, that would be a useful future enhancement.

Tested as before.  OK?

-Nathan

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

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

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-26 20:53               ` Nathan Froyd
@ 2011-05-27 20:23                 ` Jason Merrill
  2011-05-28  0:44                   ` Nathan Froyd
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-27 20:23 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

On 05/26/2011 03:04 PM, Nathan Froyd wrote:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

"member function type"

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

s/parameters/arguments/

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

In the DEDUCE_EXACT case, let's use unify_type_mismatch.

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

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

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

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

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

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

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

Line too long.

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

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

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-27 20:23                 ` Jason Merrill
@ 2011-05-28  0:44                   ` Nathan Froyd
  2011-05-28 14:03                     ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-05-28  0:44 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches

On Fri, May 27, 2011 at 03:14:59PM -0400, Jason Merrill wrote:
> On 05/26/2011 03:04 PM, Nathan Froyd wrote:
> 
> Thanks, this is looking pretty close.  A few more issues, mostly to
> do with wording of the diagnostics:

Thanks for all your feedback during the development of the patch.

> >       converted_args
> >        = (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
> >                                  /*require_all_args=*/false,
> >                                  /*use_default_args=*/false));
> >       if (converted_args == error_mark_node)
> >-       return 1;
> >+       {
> >+         /* Run it for diagnostics.  */
> >+         if (explain_p)
> >+           coerce_template_parms (tparms, explicit_targs, NULL_TREE,
> >+                                  tf_warning_or_error,
> >+                                  /*require_all_args=*/false,
> >+                                  /*use_default_args=*/false);
> >+         return 1;
> >+       }
> 
> Instead of calling it twice, pass different tsubst_flags depending
> on explain_p.  And the same for all the other places where you call
> a function again with tf_warning_or_error.

I knew there must have been a better way to do this. =/

I think I've addressed everything in the patch below except for:

> >+  /* FIXME: Should we pass in unification information and then use that
> >+     to elaborate on the error messages below?  */
> 
> Just pass in explain_p = true, and then we shouldn't need the
> "unable to deduce" message here.

I tried this, but for the few examples in the testsuite where it fires,
I thought the error messages were more confusing, so I left this as-is
and removed the FIXME.

Tested as before.

-Nathan

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

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

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

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-28  0:44                   ` Nathan Froyd
@ 2011-05-28 14:03                     ` Jason Merrill
  2011-07-17  7:56                       ` Jason Merrill
  0 siblings, 1 reply; 15+ messages in thread
From: Jason Merrill @ 2011-05-28 14:03 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches

On 05/27/2011 04:22 PM, Nathan Froyd wrote:
> +         /* The PARM is not one we're trying to unify.  Just check
> +            to see if it matches ARG.  */
> +         int result = !(TREE_CODE (arg) == TREE_CODE (parm)
> +                        && cp_tree_equal (parm, arg));
> +         if (result)
> +           unify_template_parameter_mismatch (explain_p, parm, tparm);

This should be unify_template_argument_mismatch (explain_p, parm, arg);

So we can drop unify_template_parameter_mismatch.

OK with that change.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-05-28 14:03                     ` Jason Merrill
@ 2011-07-17  7:56                       ` Jason Merrill
  0 siblings, 0 replies; 15+ messages in thread
From: Jason Merrill @ 2011-07-17  7:56 UTC (permalink / raw)
  To: gcc-patches

[-- Attachment #1: Type: text/plain, Size: 1021 bytes --]

On 05/27/2011 09:55 PM, Jason Merrill wrote:
> On 05/27/2011 04:22 PM, Nathan Froyd wrote:
>> + /* The PARM is not one we're trying to unify. Just check
>> + to see if it matches ARG. */
>> + int result = !(TREE_CODE (arg) == TREE_CODE (parm)
>> + && cp_tree_equal (parm, arg));
>> + if (result)
>> + unify_template_parameter_mismatch (explain_p, parm, tparm);
>
> This should be unify_template_argument_mismatch (explain_p, parm, arg);
>
> So we can drop unify_template_parameter_mismatch.
>
> OK with that change.

It seems that Nathan is no longer working on this patch, so I'm going to 
apply it myself.

The first patch is Nathan's original patch, adjusted to apply to the 
current trunk.

The second patch makes the above requested change and avoids redundant 
error messages from repeating unification.

The third patch makes some tangential adjustments to error message 
context printing that seemed like a good idea while I was looking at the 
new error messages.

Tested x86_64-pc-linux-gnu, applying to trunk.

[-- Attachment #2: 45329-1.patch --]
[-- Type: text/x-patch, Size: 92968 bytes --]

commit 8dbed75cf3439041851357f1a6a60f0ac449bec0
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jul 13 18:05:05 2011 -0400

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

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 56f3408..dc8cfe7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -434,7 +434,10 @@ enum rejection_reason_code {
   rr_arity,
   rr_explicit_conversion,
   rr_arg_conversion,
-  rr_bad_arg_conversion
+  rr_bad_arg_conversion,
+  rr_template_unification,
+  rr_template_instantiation,
+  rr_invalid_copy
 };
 
 struct conversion_info {
@@ -462,6 +465,24 @@ struct rejection_reason {
     struct conversion_info conversion;
     /* Same, but for bad argument conversions.  */
     struct conversion_info bad_conversion;
+    /* Information about template unification failures.  These are the
+       parameters passed to fn_type_unification.  */
+    struct {
+      tree tmpl;
+      tree explicit_targs;
+      tree targs;
+      const tree *args;
+      unsigned int nargs;
+      tree return_type;
+      unification_kind_t strict;
+      int flags;
+    } template_unification;
+    /* Information about template instantiation failures.  These are the
+       parameters passed to instantiate_template.  */
+    struct {
+      tree tmpl;
+      tree targs;
+    } template_instantiation;
   } u;
 };
 
@@ -622,6 +643,44 @@ explicit_conversion_rejection (tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
+				const tree *args, unsigned int nargs,
+				tree return_type, unification_kind_t strict,
+				int flags)
+{
+  size_t args_n_bytes = sizeof (*args) * nargs;
+  tree *args1 = (tree *) conversion_obstack_alloc (args_n_bytes);
+  struct rejection_reason *r = alloc_rejection (rr_template_unification);
+  r->u.template_unification.tmpl = tmpl;
+  r->u.template_unification.explicit_targs = explicit_targs;
+  r->u.template_unification.targs = targs;
+  /* Copy args to our own storage.  */
+  memcpy (args1, args, args_n_bytes);
+  r->u.template_unification.args = args1;
+  r->u.template_unification.nargs = nargs;
+  r->u.template_unification.return_type = return_type;
+  r->u.template_unification.strict = strict;
+  r->u.template_unification.flags = flags;
+  return r;
+}
+
+static struct rejection_reason *
+template_instantiation_rejection (tree tmpl, tree targs)
+{
+  struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
+  r->u.template_instantiation.tmpl = tmpl;
+  r->u.template_instantiation.targs = targs;
+  return r;
+}
+
+static struct rejection_reason *
+invalid_copy_with_fn_template_rejection (void)
+{
+  struct rejection_reason *r = alloc_rejection (rr_invalid_copy);
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -2904,14 +2963,23 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   i = fn_type_unification (tmpl, explicit_targs, targs,
 			   args_without_in_chrg,
 			   nargs_without_in_chrg,
-			   return_type, strict, flags);
+			   return_type, strict, flags, false);
 
   if (i != 0)
-    goto fail;
+    {
+      reason = template_unification_rejection (tmpl, explicit_targs,
+					       targs, args_without_in_chrg,
+					       nargs_without_in_chrg,
+					       return_type, strict, flags);
+      goto fail;
+    }
 
   fn = instantiate_template (tmpl, targs, tf_none);
   if (fn == error_mark_node)
-    goto fail;
+    {
+      reason = template_instantiation_rejection (tmpl, targs);
+      goto fail;
+    }
 
   /* In [class.copy]:
 
@@ -2940,7 +3008,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)
@@ -3108,6 +3179,18 @@ print_conversion_rejection (location_t loc, struct conversion_info *info)
 	    info->n_arg+1, info->from_type, info->to_type);
 }
 
+/* Print information about a candidate with WANT parameters and we found
+   HAVE.  */
+
+static void
+print_arity_information (location_t loc, unsigned int have, unsigned int want)
+{
+  inform_n (loc, want,
+	    "  candidate expects %d argument, %d provided",
+	    "  candidate expects %d arguments, %d provided",
+	    want, have);
+}
+
 /* Print information about one overload candidate CANDIDATE.  MSGSTR
    is the text to print before the candidate itself.
 
@@ -3154,10 +3237,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);
@@ -3171,6 +3252,29 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 		  "conversion", r->u.conversion.from_type,
 		  r->u.conversion.to_type);
 	  break;
+	case rr_template_unification:
+	  /* Re-run template unification with diagnostics.  */
+	  fn_type_unification (r->u.template_unification.tmpl,
+			       r->u.template_unification.explicit_targs,
+			       r->u.template_unification.targs,
+			       r->u.template_unification.args,
+			       r->u.template_unification.nargs,
+			       r->u.template_unification.return_type,
+			       r->u.template_unification.strict,
+			       r->u.template_unification.flags,
+			       true);
+	  break;
+	case rr_template_instantiation:
+	  /* Re-run template instantiation with diagnostics.  */
+	  instantiate_template (r->u.template_instantiation.tmpl,
+				r->u.template_instantiation.targs,
+				tf_warning_or_error);
+	  break;
+	case rr_invalid_copy:
+	  inform (loc, 
+		  "  a constructor taking a single argument of its own "
+		  "class type is invalid");
+	  break;
 	case rr_none:
 	default:
 	  /* This candidate didn't have any issues or we failed to
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 7de104d..61c1380 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6570,7 +6570,7 @@ resolve_address_of_overloaded_function (tree target_type,
 	  targs = make_tree_vec (DECL_NTPARMS (fn));
 	  if (fn_type_unification (fn, explicit_targs, targs, args, nargs,
 				   target_ret_type, DEDUCE_EXACT,
-				   LOOKUP_NORMAL))
+				   LOOKUP_NORMAL, false))
 	    /* Argument deduction failed.  */
 	    continue;
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 96d9fa8..c590585 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5161,7 +5161,8 @@ extern tree instantiate_class_template		(tree);
 extern tree instantiate_template		(tree, tree, tsubst_flags_t);
 extern int fn_type_unification			(tree, tree, tree,
 						 const tree *, unsigned int,
-						 tree, unification_kind_t, int);
+						 tree, unification_kind_t, int,
+						 bool);
 extern void mark_decl_instantiated		(tree, int);
 extern int more_specialized_fn			(tree, tree, int);
 extern void do_decl_instantiation		(tree, tree);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index d50e214..b8d25d4 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -109,15 +109,22 @@ static GTY(()) VEC(tree,gc) *canonical_template_parms;
 #define UNIFY_ALLOW_OUTER_MORE_CV_QUAL 32
 #define UNIFY_ALLOW_OUTER_LESS_CV_QUAL 64
 
+enum template_base_result {
+  tbr_incomplete_type,
+  tbr_ambiguous_baseclass,
+  tbr_success
+};
+
 static void push_access_scope (tree);
 static void pop_access_scope (tree);
 static void push_deduction_access_scope (tree);
 static void pop_deduction_access_scope (tree);
 static bool resolve_overloaded_unification (tree, tree, tree, tree,
-					    unification_kind_t, int);
+					    unification_kind_t, int,
+					    bool);
 static int try_one_overload (tree, tree, tree, tree, tree,
-			     unification_kind_t, int, bool);
-static int unify (tree, tree, tree, tree, int);
+			     unification_kind_t, int, bool, bool);
+static int unify (tree, tree, tree, tree, int, bool);
 static void add_pending_template (tree);
 static tree reopen_tinst_level (struct tinst_level *);
 static tree tsubst_initializer_list (tree, tree);
@@ -131,7 +138,8 @@ static bool check_instantiated_args (tree, tree, tsubst_flags_t);
 static int maybe_adjust_types_for_deduction (unification_kind_t, tree*, tree*,
 					     tree);
 static int type_unification_real (tree, tree, tree, const tree *,
-				  unsigned int, int, unification_kind_t, int);
+				  unsigned int, int, unification_kind_t, int,
+				  bool);
 static void note_template_header (int);
 static tree convert_nontype_argument_function (tree, tree);
 static tree convert_nontype_argument (tree, tree, tsubst_flags_t);
@@ -156,7 +164,8 @@ static tree get_bindings (tree, tree, tree, bool);
 static int template_decl_level (tree);
 static int check_cv_quals_for_unify (int, tree, tree);
 static void template_parm_level_and_index (tree, int*, int*);
-static int unify_pack_expansion (tree, tree, tree, tree, int, bool, bool);
+static int unify_pack_expansion (tree, tree, tree,
+				 tree, int, bool, bool, bool);
 static tree tsubst_template_arg (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_args (tree, tree, tsubst_flags_t, tree);
 static tree tsubst_template_parms (tree, tree, tsubst_flags_t);
@@ -168,8 +177,9 @@ static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
 static bool check_specialization_scope (void);
 static tree process_partial_specialization (tree);
 static void set_current_access_from_decl (tree);
-static tree get_template_base (tree, tree, tree, tree);
-static tree try_class_unification (tree, tree, tree, tree);
+static enum template_base_result get_template_base (tree, tree, tree, tree,
+						    bool , tree *);
+static tree try_class_unification (tree, tree, tree, tree, bool);
 static int coerce_template_template_parms (tree, tree, tsubst_flags_t,
 					   tree, tree);
 static bool template_template_parm_bindings_ok_p (tree, tree);
@@ -5267,6 +5277,220 @@ has_value_dependent_address (tree op)
   return false;
 }
 
+/* The next set of functions are used for providing helpful explanatory
+   diagnostics for failed overload resolution.  Their messages should be
+   indented by two spaces for consistency with the messages in
+   call.c  */
+
+static int
+unify_success (bool explain_p ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+static int
+unify_parameter_deduction_failure (bool explain_p, tree parm)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  couldn't deduce template parameter %qD", parm);
+  return 1;
+}
+
+static int
+unify_invalid (bool explain_p ATTRIBUTE_UNUSED)
+{
+  return 1;
+}
+
+static int
+unify_cv_qual_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  types %qT and %qT have incompatible cv-qualifiers",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_type_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  mismatched types %qT and %qT", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template parameter %qD is not a parameter pack, but "
+	    "argument %qD is",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_ptrmem_cst_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template argument %qE does not match "
+	    "pointer-to-member constant %qE",
+	    arg, parm);
+  return 1;
+}
+
+static int
+unify_expression_unequal (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  %qE is not equivalent to %qE", parm, arg);
+  return 1;
+}
+
+static int
+unify_parameter_pack_inconsistent (bool explain_p, tree old_arg, tree new_arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  inconsistent parameter pack deduction with %qT and %qT",
+	    old_arg, new_arg);
+  return 1;
+}
+
+static int
+unify_inconsistency (bool explain_p, tree parm, tree first, tree second)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  deduced conflicting types for parameter %qT (%qT and %qT)",
+	    parm, first, second);
+  return 1;
+}
+
+static int
+unify_vla_arg (bool explain_p, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  variable-sized array type %qT is not "
+	    "a valid template argument",
+	    arg);
+  return 1;
+}
+
+static int
+unify_method_type_error (bool explain_p, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  member function type %qT is not a valid template argument",
+	    arg);
+  return 1;
+}
+
+static int
+unify_arity (bool explain_p, int have, int wanted)
+{
+  if (explain_p)
+    inform_n (input_location, wanted,
+	      "  candidate expects %d argument, %d provided",
+	      "  candidate expects %d arguments, %d provided",
+	      wanted, have);
+  return 1;
+}
+
+static int
+unify_too_many_arguments (bool explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_too_few_arguments (bool explain_p, int have, int wanted)
+{
+  return unify_arity (explain_p, have, wanted);
+}
+
+static int
+unify_arg_conversion (bool explain_p, tree to_type,
+		      tree from_type, tree arg)
+{
+  if (explain_p)
+    inform (input_location, "  cannot convert %qE (type %qT) to type %qT",
+	    arg, from_type, to_type);
+  return 1;
+}
+
+static int
+unify_no_common_base (bool explain_p, enum template_base_result r,
+		      tree parm, tree arg)
+{
+  if (explain_p)
+    switch (r)
+      {
+      case tbr_ambiguous_baseclass:
+	inform (input_location, "  %qT is an ambiguous base class of %qT",
+		arg, parm);
+	break;
+      default:
+	inform (input_location, "  %qT is not derived from %qT", arg, parm);
+	break;
+      }
+  return 1;
+}
+
+static int
+unify_inconsistent_template_template_parameters (bool explain_p)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template parameters of a template template argument are "
+	    "inconsistent with other deduced template arguments");
+  return 1;
+}
+
+static int
+unify_template_deduction_failure (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  can't deduce a template for %qT from non-template type %qT",
+	    parm, arg);
+  return 1;
+}
+
+static int
+unify_template_parameter_mismatch (bool explain_p, tree parm, tree tparm)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template parameter %qT does not match %qD", tparm, parm);
+  return 1;
+}
+
+static int
+unify_template_argument_mismatch (bool explain_p, tree parm, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  template argument %qE does not match %qD", arg, parm);
+  return 1;
+}
+
+static int
+unify_overload_resolution_failure (bool explain_p, tree arg)
+{
+  if (explain_p)
+    inform (input_location,
+	    "  could not resolve address from overloaded function %qE",
+	    arg);
+  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
@@ -6550,11 +6774,13 @@ template_args_equal (tree ot, tree nt)
     return cp_tree_equal (ot, nt);
 }
 
-/* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets
-   of template arguments.  Returns 0 otherwise.  */
+/* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets of
+   template arguments.  Returns 0 otherwise, and updates OLDARG_PTR and
+   NEWARG_PTR with the offending arguments if they are non-NULL.  */
 
-int
-comp_template_args (tree oldargs, tree newargs)
+static int
+comp_template_args_with_info (tree oldargs, tree newargs,
+			      tree *oldarg_ptr, tree *newarg_ptr)
 {
   int i;
 
@@ -6567,11 +6793,26 @@ comp_template_args (tree oldargs, tree newargs)
       tree ot = TREE_VEC_ELT (oldargs, i);
 
       if (! template_args_equal (ot, nt))
-	return 0;
+	{
+	  if (oldarg_ptr != NULL)
+	    *oldarg_ptr = ot;
+	  if (newarg_ptr != NULL)
+	    *newarg_ptr = nt;
+	  return 0;
+	}
     }
   return 1;
 }
 
+/* Returns 1 iff the OLDARGS and NEWARGS are in fact identical sets
+   of template arguments.  Returns 0 otherwise.  */
+
+int
+comp_template_args (tree oldargs, tree newargs)
+{
+  return comp_template_args_with_info (oldargs, newargs, NULL, NULL);
+}
+
 static void
 add_pending_template (tree d)
 {
@@ -13724,7 +13965,7 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)
    This is, of course, not reentrant.  */
 
 static tree
-deduction_tsubst_fntype (tree fn, tree targs)
+deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
 {
   static bool excessive_deduction_depth;
   static int deduction_depth;
@@ -13748,7 +13989,7 @@ deduction_tsubst_fntype (tree fn, tree targs)
   input_location = DECL_SOURCE_LOCATION (fn);
   ++deduction_depth;
   push_deduction_access_scope (fn);
-  r = tsubst (fntype, targs, tf_none, NULL_TREE);
+  r = tsubst (fntype, targs, complain, NULL_TREE);
   pop_deduction_access_scope (fn);
   --deduction_depth;
 
@@ -13961,7 +14202,8 @@ fn_type_unification (tree fn,
 		     unsigned int nargs,
 		     tree return_type,
 		     unification_kind_t strict,
-		     int flags)
+		     int flags,
+		     bool explain_p)
 {
   tree parms;
   tree fntype;
@@ -13996,12 +14238,15 @@ fn_type_unification (tree fn,
       bool incomplete = false;
 
       if (explicit_targs == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       converted_args
-	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE, tf_none,
-				  /*require_all_args=*/false,
-				  /*use_default_args=*/false));
+	= (coerce_template_parms (tparms, explicit_targs, NULL_TREE,
+				  (explain_p
+				   ? tf_warning_or_error
+				   : tf_none),
+				   /*require_all_args=*/false,
+				   /*use_default_args=*/false));
       if (converted_args == error_mark_node)
 	return 1;
 
@@ -14060,7 +14305,10 @@ fn_type_unification (tree fn,
         incomplete = NUM_TMPL_ARGS (explicit_targs) != NUM_TMPL_ARGS (targs);
 
       processing_template_decl += incomplete;
-      fntype = deduction_tsubst_fntype (fn, converted_args);
+      fntype = deduction_tsubst_fntype (fn, converted_args,
+					(explain_p
+					 ? tf_warning_or_error
+					 : tf_none));
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
@@ -14092,7 +14340,7 @@ fn_type_unification (tree fn,
      event.  */
   result = type_unification_real (DECL_INNERMOST_TEMPLATE_PARMS (fn),
 				  targs, parms, args, nargs, /*subr=*/0,
-				  strict, flags);
+				  strict, flags, explain_p);
 
   /* Now that we have bindings for all of the template arguments,
      ensure that the arguments deduced for the template template
@@ -14118,7 +14366,7 @@ fn_type_unification (tree fn,
   if (result == 0
       && !template_template_parm_bindings_ok_p 
            (DECL_INNERMOST_TEMPLATE_PARMS (fn), targs))
-    return 1;
+    return unify_inconsistent_template_template_parameters (explain_p);
 
   if (result == 0)
     /* All is well so far.  Now, check:
@@ -14131,7 +14379,10 @@ fn_type_unification (tree fn,
        substitution results in an invalid type, as described above,
        type deduction fails.  */
     {
-      tree substed = deduction_tsubst_fntype (fn, targs);
+      tree substed = deduction_tsubst_fntype (fn, targs,
+					      (explain_p
+					       ? tf_warning_or_error
+					       : tf_none));
       if (substed == error_mark_node)
 	return 1;
 
@@ -14148,7 +14399,8 @@ 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_type_mismatch (explain_p, args[i],
+					  TREE_VALUE (sarg));
 	}
     }
 
@@ -14279,7 +14531,8 @@ type_unification_real (tree tparms,
 		       unsigned int xnargs,
 		       int subr,
 		       unification_kind_t strict,
-		       int flags)
+		       int flags,
+		       bool explain_p)
 {
   tree parm, arg, arg_expr;
   int i;
@@ -14350,7 +14603,7 @@ type_unification_real (tree tparms,
       arg_expr = NULL;
 
       if (arg == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
       if (arg == unknown_type_node)
 	/* We can't deduce anything from this, but we might get all the
 	   template args from other function args.  */
@@ -14376,7 +14629,10 @@ type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  if (strict == DEDUCE_EXACT)
+	    return unify_type_mismatch (explain_p, parm, arg);
+	  else
+	    return unify_arg_conversion (explain_p, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14392,15 +14648,15 @@ type_unification_real (tree tparms,
 		 function templates and at most one of a set of
 		 overloaded functions provides a unique match.  */
 	      if (resolve_overloaded_unification
-		  (tparms, targs, parm, arg, strict, sub_strict))
+		  (tparms, targs, parm, arg, strict, sub_strict, explain_p))
 		continue;
 
-	      return 1;
+	      return unify_overload_resolution_failure (explain_p, arg);
 	    }
 	  arg_expr = arg;
 	  arg = unlowered_expr_type (arg);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 	}
 
       {
@@ -14412,7 +14668,9 @@ type_unification_real (tree tparms,
 
 	if (arg == init_list_type_node && arg_expr)
 	  arg = arg_expr;
-	if (unify (tparms, targs, parm, arg, arg_strict))
+	if (unify (tparms, targs, parm, arg, arg_strict, explain_p))
+	  /* If unification failed, the recursive call will have updated
+	     UI appropriately.  */
 	  return 1;
       }
     }
@@ -14434,7 +14692,7 @@ type_unification_real (tree tparms,
       /* Copy the parameter into parmvec.  */
       TREE_VEC_ELT (parmvec, 0) = TREE_VALUE (parms);
       if (unify_pack_expansion (tparms, targs, parmvec, argvec, strict,
-                                /*call_args_p=*/true, /*subr=*/subr))
+                                /*call_args_p=*/true, /*subr=*/subr, explain_p))
         return 1;
 
       /* Advance to the end of the list of parameters.  */
@@ -14444,11 +14702,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_arguments (explain_p, nargs, ia);
   /* Fail if parms are left and they don't have default values.  */
   if (parms && parms != void_list_node
       && TREE_PURPOSE (parms) == NULL_TREE)
-    return 1;
+    {
+      unsigned int count = nargs;
+      tree p = parms;
+      while (p && p != void_list_node)
+	{
+	  count++;
+	  p = TREE_CHAIN (p);
+	}
+      return unify_too_few_arguments (explain_p, ia, count);
+    }
 
   if (!subr)
     {
@@ -14503,7 +14770,10 @@ type_unification_real (tree tparms,
 	      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,
+	      arg = convert_template_argument (parm, arg, targs,
+					       (explain_p
+						? tf_warning_or_error
+						: tf_none),
 					       i, NULL_TREE);
 	      if (arg == error_mark_node)
 		return 1;
@@ -14540,7 +14810,7 @@ type_unification_real (tree tparms,
 	      continue;
 	    }
 
-	  return 2;
+	  return unify_parameter_deduction_failure (explain_p, tparm);
 	}
     }
 #ifdef ENABLE_CHECKING
@@ -14548,7 +14818,7 @@ type_unification_real (tree tparms,
     SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs, TREE_VEC_LENGTH (targs));
 #endif
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Subroutine of type_unification_real.  Args are like the variables
@@ -14563,7 +14833,8 @@ resolve_overloaded_unification (tree tparms,
 				tree parm,
 				tree arg,
 				unification_kind_t strict,
-				int sub_strict)
+				int sub_strict,
+			        bool explain_p)
 {
   tree tempargs = copy_node (targs);
   int good = 0;
@@ -14615,7 +14886,7 @@ resolve_overloaded_unification (tree tparms,
 	    {
 	      elem = tsubst (TREE_TYPE (fn), subargs, tf_none, NULL_TREE);
 	      if (try_one_overload (tparms, targs, tempargs, parm,
-				    elem, strict, sub_strict, addr_p)
+				    elem, strict, sub_strict, addr_p, explain_p)
 		  && (!goodfn || !decls_match (goodfn, elem)))
 		{
 		  goodfn = elem;
@@ -14643,7 +14914,7 @@ resolve_overloaded_unification (tree tparms,
     for (; arg; arg = OVL_NEXT (arg))
       if (try_one_overload (tparms, targs, tempargs, parm,
 			    TREE_TYPE (OVL_CURRENT (arg)),
-			    strict, sub_strict, addr_p)
+			    strict, sub_strict, addr_p, explain_p)
 	  && (!goodfn || !decls_match (goodfn, OVL_CURRENT (arg))))
 	{
 	  goodfn = OVL_CURRENT (arg);
@@ -14790,7 +15061,8 @@ try_one_overload (tree tparms,
 		  tree arg,
 		  unification_kind_t strict,
 		  int sub_strict,
-		  bool addr_p)
+		  bool addr_p,
+		  bool explain_p)
 {
   int nargs;
   tree tempargs;
@@ -14820,7 +15092,7 @@ try_one_overload (tree tparms,
   nargs = TREE_VEC_LENGTH (targs);
   tempargs = make_tree_vec (nargs);
 
-  if (unify (tparms, tempargs, parm, arg, sub_strict) != 0)
+  if (unify (tparms, tempargs, parm, arg, sub_strict, explain_p))
     return 0;
 
   /* First make sure we didn't deduce anything that conflicts with
@@ -14858,7 +15130,8 @@ try_one_overload (tree tparms,
    TARGS are as for unify.  */
 
 static tree
-try_class_unification (tree tparms, tree targs, tree parm, tree arg)
+try_class_unification (tree tparms, tree targs, tree parm, tree arg,
+		       bool explain_p)
 {
   tree copy_of_targs;
 
@@ -14901,7 +15174,7 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg)
 
   /* If unification failed, we're done.  */
   if (unify (tparms, copy_of_targs, CLASSTYPE_TI_ARGS (parm),
-	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE))
+	     CLASSTYPE_TI_ARGS (arg), UNIFY_ALLOW_NONE, explain_p))
     return NULL_TREE;
 
   return arg;
@@ -14914,8 +15187,9 @@ try_class_unification (tree tparms, tree targs, tree parm, tree arg)
    a partial specialization, as well as a plain template type.  Used
    by unify.  */
 
-static tree
-get_template_base (tree tparms, tree targs, tree parm, tree arg)
+static enum template_base_result
+get_template_base (tree tparms, tree targs, tree parm, tree arg,
+		   bool explain_p, tree *result)
 {
   tree rval = NULL_TREE;
   tree binfo;
@@ -14924,14 +15198,18 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
   binfo = TYPE_BINFO (complete_type (arg));
   if (!binfo)
-    /* The type could not be completed.  */
-    return NULL_TREE;
+    {
+      /* The type could not be completed.  */
+      *result = NULL_TREE;
+      return tbr_incomplete_type;
+    }
 
   /* Walk in inheritance graph order.  The search order is not
      important, and this avoids multiple walks of virtual bases.  */
   for (binfo = TREE_CHAIN (binfo); binfo; binfo = TREE_CHAIN (binfo))
     {
-      tree r = try_class_unification (tparms, targs, parm, BINFO_TYPE (binfo));
+      tree r = try_class_unification (tparms, targs, parm,
+				      BINFO_TYPE (binfo), explain_p);
 
       if (r)
 	{
@@ -14944,13 +15222,17 @@ get_template_base (tree tparms, tree targs, tree parm, tree arg)
 
 	     applies.  */
 	  if (rval && !same_type_p (r, rval))
-	    return NULL_TREE;
+	    {
+	      *result = NULL_TREE;
+	      return tbr_ambiguous_baseclass;
+	    }
 
 	  rval = r;
 	}
     }
 
-  return rval;
+  *result = rval;
+  return tbr_success;
 }
 
 /* Returns the level of DECL, which declares a template parameter.  */
@@ -15032,6 +15314,12 @@ template_parm_level_and_index (tree parm, int* level, int* index)
     }
 }
 
+#define RECUR_AND_CHECK_FAILURE(TP, TA, P, A, S, EP)			\
+  do {									\
+    if (unify (TP, TA, P, A, S, EP))					\
+      return 1;								\
+  } while (0);
+
 /* Unifies the remaining arguments in PACKED_ARGS with the pack
    expansion at the end of PACKED_PARMS. Returns 0 if the type
    deduction succeeds, 1 otherwise. STRICT is the same as in
@@ -15039,10 +15327,10 @@ template_parm_level_and_index (tree parm, int* level, int* index)
    call argument list. We'll need to adjust the arguments to make them
    types. SUBR tells us if this is from a recursive call to
    type_unification_real.  */
-int
+static int
 unify_pack_expansion (tree tparms, tree targs, tree packed_parms, 
                       tree packed_args, int strict, bool call_args_p,
-                      bool subr)
+                      bool subr, bool explain_p)
 {
   tree parm 
     = TREE_VEC_ELT (packed_parms, TREE_VEC_LENGTH (packed_parms) - 1);
@@ -15132,7 +15420,7 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
                     if (resolve_overloaded_unification
                         (tparms, targs, parm, arg,
 			 (unification_kind_t) strict,
-			 sub_strict)
+			 sub_strict, explain_p)
                         != 0)
                       return 1;
                     skip_arg_p = true;
@@ -15160,8 +15448,8 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
 	    /* For deduction from an init-list we need the actual list.  */
 	    if (arg_expr && BRACE_ENCLOSED_INITIALIZER_P (arg_expr))
 	      arg = arg_expr;
-            if (unify (tparms, targs, parm, arg, arg_strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs, parm, arg, arg_strict,
+				     explain_p);
           }
       }
 
@@ -15252,13 +15540,21 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
           ARGUMENT_PACK_INCOMPLETE_P (old_pack) = 1;
           ARGUMENT_PACK_EXPLICIT_ARGS (old_pack) = explicit_args;
         }
-      else if (!comp_template_args (ARGUMENT_PACK_ARGS (old_pack),
-                                    new_args))
-        /* Inconsistent unification of this parameter pack.  */
-        return 1;
+      else
+	{
+	  tree bad_old_arg, bad_new_arg;
+	  tree old_args = ARGUMENT_PACK_ARGS (old_pack);
+
+	  if (!comp_template_args_with_info (old_args, new_args,
+					     &bad_old_arg, &bad_new_arg))
+	    /* Inconsistent unification of this parameter pack.  */
+	    return unify_parameter_pack_inconsistent (explain_p,
+						      bad_old_arg,
+						      bad_new_arg);
+	}
     }
 
-  return 0;
+  return unify_success (explain_p);
 }
 
 /* Deduce the value of template parameters.  TPARMS is the (innermost)
@@ -15303,7 +15599,8 @@ unify_pack_expansion (tree tparms, tree targs, tree packed_parms,
        qualified at this point.  */
 
 static int
-unify (tree tparms, tree targs, tree parm, tree arg, int strict)
+unify (tree tparms, tree targs, tree parm, tree arg, int strict,
+       bool explain_p)
 {
   int idx;
   tree targ;
@@ -15318,19 +15615,19 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     parm = TREE_OPERAND (parm, 0);
 
   if (arg == error_mark_node)
-    return 1;
+    return unify_invalid (explain_p);
   if (arg == unknown_type_node
       || arg == init_list_type_node)
     /* We can't deduce anything from this, but we might get all the
        template args from other function args.  */
-    return 0;
+    return unify_success (explain_p);
 
   /* If PARM uses template parameters, then we can't bail out here,
      even if ARG == PARM, since we won't record unifications for the
      template parameters.  We might need them if we're trying to
      figure out which of two things is more specialized.  */
   if (arg == parm && !uses_template_parms (parm))
-    return 0;
+    return unify_success (explain_p);
 
   /* Handle init lists early, so the rest of the function can assume
      we're dealing with a type. */
@@ -15349,7 +15646,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	/* We can only deduce from an initializer list argument if the
 	   parameter is std::initializer_list; otherwise this is a
 	   non-deduced context. */
-	return 0;
+	return unify_success (explain_p);
 
       elttype = TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0);
 
@@ -15358,7 +15655,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  int elt_strict = strict;
 
 	  if (elt == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  if (!BRACE_ENCLOSED_INITIALIZER_P (elt))
 	    {
@@ -15370,8 +15667,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	      elt = type;
 	    }
 
-	  if (unify (tparms, targs, elttype, elt, elt_strict))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, elttype, elt, elt_strict,
+				   explain_p);
 	}
 
       /* If the std::initializer_list<T> deduction worked, replace the
@@ -15383,7 +15680,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  targ = listify (targ);
 	  TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = targ;
 	}
-      return 0;
+      return unify_success (explain_p);
     }
 
   /* Immediately reject some pairs that won't unify because of
@@ -15400,7 +15697,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 is more specialized, for example.  */
       && TREE_CODE (arg) != TEMPLATE_TYPE_PARM
       && !check_cv_quals_for_unify (strict_in, arg, parm))
-    return 1;
+    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
   if (!(strict & UNIFY_ALLOW_OUTER_LEVEL)
       && TYPE_P (parm) && !CP_TYPE_CONST_P (parm))
@@ -15418,21 +15715,26 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       /* In a type which contains a nested-name-specifier, template
 	 argument values cannot be deduced for template parameters used
 	 within the nested-name-specifier.  */
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_TYPE_PARM:
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_TYPE_LEVEL (parm)
 	  != template_decl_level (tparm))
 	/* The PARM is not one we're trying to unify.  Just check
 	   to see if it matches ARG.  */
-	return (TREE_CODE (arg) == TREE_CODE (parm)
-		&& same_type_p (parm, arg)) ? 0 : 1;
+	{
+	  if (TREE_CODE (arg) == TREE_CODE (parm)
+	      && same_type_p (parm, arg))
+	    return unify_success (explain_p);
+	  else
+	    return unify_type_mismatch (explain_p, parm, arg);
+	}
       idx = TEMPLATE_TYPE_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
@@ -15442,7 +15744,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;
+	gcc_unreachable ();
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15450,7 +15752,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     template parameter.  */
 	  if (TREE_CODE (arg) != BOUND_TEMPLATE_TEMPLATE_PARM
 	      && !CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (arg))
-	    return 1;
+	    return unify_template_deduction_failure (explain_p, parm, arg);
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15492,7 +15794,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    if (coerce_template_parms (parm_parms,
                                        full_argvec,
 				       TYPE_TI_TEMPLATE (parm),
-				       tf_none,
+				       (explain_p
+					? tf_warning_or_error
+					: tf_none),
 				       /*require_all_args=*/true,
 				       /*use_default_args=*/false)
 		== error_mark_node)
@@ -15515,15 +15819,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_arguments (explain_p,
+					      TREE_VEC_LENGTH (argvec), len);
 
              for (i = 0; i < len - parm_variadic_p; ++i)
 	      {
-		if (unify (tparms, targs,
-			   TREE_VEC_ELT (parmvec, i),
-			   TREE_VEC_ELT (argvec, i),
-			   UNIFY_ALLOW_NONE))
-		  return 1;
+		RECUR_AND_CHECK_FAILURE (tparms, targs,
+					 TREE_VEC_ELT (parmvec, i),
+					 TREE_VEC_ELT (argvec, i),
+					 UNIFY_ALLOW_NONE, explain_p);
 	      }
 
 	    if (parm_variadic_p
@@ -15531,7 +15835,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 					 parmvec, argvec,
 					 UNIFY_ALLOW_NONE,
 					 /*call_args_p=*/false,
-					 /*subr=*/false))
+					 /*subr=*/false, explain_p))
 	      return 1;
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
@@ -15546,9 +15850,9 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && template_args_equal (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 	}
       else
 	{
@@ -15558,20 +15862,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     that binds `const int' to `T'.  */
 	  if (!check_cv_quals_for_unify (strict_in | UNIFY_ALLOW_LESS_CV_QUAL,
 					 arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
 	  /* Consider the case where ARG is `const volatile int' and
 	     PARM is `const T'.  Then, T should be `volatile int'.  */
 	  arg = cp_build_qualified_type_real
 	    (arg, cp_type_quals (arg) & ~cp_type_quals (parm), tf_none);
 	  if (arg == error_mark_node)
-	    return 1;
+	    return unify_invalid (explain_p);
 
 	  /* Simple cases: Value already set, does match or doesn't.  */
 	  if (targ != NULL_TREE && same_type_p (targ, arg))
-	    return 0;
+	    return unify_success (explain_p);
 	  else if (targ)
-	    return 1;
+	    return unify_inconsistency (explain_p, parm, targ, arg);
 
 	  /* Make sure that ARG is not a variable-sized array.  (Note
 	     that were talking about variable-sized arrays (like
@@ -15581,7 +15885,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     instantiation.  Besides, such types are not allowed in
 	     ISO C++, so we can do as we please here.  */
 	  if (variably_modified_type_p (arg, NULL_TREE))
-	    return 1;
+	    return unify_vla_arg (explain_p, arg);
 
 	  /* Strip typedefs as in convert_template_argument.  */
 	  arg = canonicalize_type_argument (arg, tf_none);
@@ -15591,35 +15895,45 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !template_parameter_pack_p (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm, arg);
 
       /* If the argument deduction results is a METHOD_TYPE,
          then there is a problem.
          METHOD_TYPE doesn't map to any real C++ type the result of
 	 the deduction can not be of that type.  */
       if (TREE_CODE (arg) == METHOD_TYPE)
-	return 1;
+	return unify_method_type_error (explain_p, arg);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case TEMPLATE_PARM_INDEX:
       tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
       if (tparm == error_mark_node)
-	return 1;
+	return unify_invalid (explain_p);
 
       if (TEMPLATE_PARM_LEVEL (parm)
 	  != template_decl_level (tparm))
-	/* The PARM is not one we're trying to unify.  Just check
-	   to see if it matches ARG.  */
-	return !(TREE_CODE (arg) == TREE_CODE (parm)
-		 && cp_tree_equal (parm, arg));
+	{
+	  /* The PARM is not one we're trying to unify.  Just check
+	     to see if it matches ARG.  */
+	  int result = !(TREE_CODE (arg) == TREE_CODE (parm)
+			 && cp_tree_equal (parm, arg));
+	  if (result)
+	    unify_template_parameter_mismatch (explain_p, parm, tparm);
+	  return result;
+	}
 
       idx = TEMPLATE_PARM_IDX (parm);
       targ = TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx);
 
       if (targ)
-	return !cp_tree_equal (targ, arg);
+	{
+	  int x = !cp_tree_equal (targ, arg);
+	  if (x)
+	    unify_inconsistency (explain_p, parm, targ, arg);
+	  return x;
+	}
 
       /* [temp.deduct.type] If, in the declaration of a function template
 	 with a non-type template-parameter, the non-type
@@ -15646,25 +15960,25 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
       else if (uses_template_parms (tparm))
 	/* We haven't deduced the type of this parameter yet.  Try again
 	   later.  */
-	return 0;
+	return unify_success (explain_p);
       else
-	return 1;
+	return unify_type_mismatch (explain_p, tparm, arg);
 
       /* If ARG is a parameter pack or an expansion, we cannot unify
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (explain_p, parm, arg);
 
       TREE_VEC_ELT (INNERMOST_TEMPLATE_ARGS (targs), idx) = arg;
-      return 0;
+      return unify_success (explain_p);
 
     case PTRMEM_CST:
      {
 	/* A pointer-to-member constant can be unified only with
 	 another constant.  */
       if (TREE_CODE (arg) != PTRMEM_CST)
-	return 1;
+	return unify_ptrmem_cst_mismatch (explain_p, parm, arg);
 
       /* Just unify the class member. It would be useless (and possibly
 	 wrong, depending on the strict flags) to unify also
@@ -15677,13 +15991,13 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	 Unification of &A::x and &B::x must succeed.  */
       return unify (tparms, targs, PTRMEM_CST_MEMBER (parm),
-		    PTRMEM_CST_MEMBER (arg), strict);
+		    PTRMEM_CST_MEMBER (arg), strict, explain_p);
      }
 
     case POINTER_TYPE:
       {
 	if (TREE_CODE (arg) != POINTER_TYPE)
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* [temp.deduct.call]
 
@@ -15701,21 +16015,21 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	  strict |= (strict_in & UNIFY_ALLOW_DERIVED);
 
 	return unify (tparms, targs, TREE_TYPE (parm),
-		      TREE_TYPE (arg), strict);
+		      TREE_TYPE (arg), strict, explain_p);
       }
 
     case REFERENCE_TYPE:
       if (TREE_CODE (arg) != REFERENCE_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case ARRAY_TYPE:
       if (TREE_CODE (arg) != ARRAY_TYPE)
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if ((TYPE_DOMAIN (parm) == NULL_TREE)
 	  != (TYPE_DOMAIN (arg) == NULL_TREE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
       if (TYPE_DOMAIN (parm) != NULL_TREE)
 	{
 	  tree parm_max;
@@ -15754,7 +16068,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
                 Here, the type of the ARG will be "int [g(i)]", and
                 may be a SAVE_EXPR, etc.  */
 	      if (TREE_CODE (arg_max) != MINUS_EXPR)
-		return 1;
+		return unify_vla_arg (explain_p, arg);
 	      arg_max = TREE_OPERAND (arg_max, 0);
 	    }
 
@@ -15771,11 +16085,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 				   arg_max,
 				   integer_one_node);
 
-	  if (unify (tparms, targs, parm_max, arg_max, UNIFY_ALLOW_INTEGER))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, parm_max, arg_max,
+				   UNIFY_ALLOW_INTEGER, explain_p);
 	}
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict & UNIFY_ALLOW_MORE_CV_QUAL);
+		    strict & UNIFY_ALLOW_MORE_CV_QUAL, explain_p);
 
     case REAL_TYPE:
     case COMPLEX_TYPE:
@@ -15785,16 +16099,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case ENUMERAL_TYPE:
     case VOID_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* We have already checked cv-qualification at the top of the
 	 function.  */
       if (!same_type_ignoring_top_level_qualifiers_p (arg, parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       /* As far as unification is concerned, this wins.	 Later checks
 	 will invalidate it if necessary.  */
-      return 0;
+      return unify_success (explain_p);
 
       /* Types INTEGER_CST and MINUS_EXPR can come from array bounds.  */
       /* Type INTEGER_CST can come from ordinary constant template args.  */
@@ -15803,38 +16117,41 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	arg = TREE_OPERAND (arg, 0);
 
       if (TREE_CODE (arg) != INTEGER_CST)
-	return 1;
-      return !tree_int_cst_equal (parm, arg);
+	return unify_template_argument_mismatch (explain_p, parm, arg);
+      return (tree_int_cst_equal (parm, arg)
+	      ? unify_success (explain_p)
+	      : unify_template_argument_mismatch (explain_p, parm, arg));
 
     case TREE_VEC:
       {
 	int i;
 	if (TREE_CODE (arg) != TREE_VEC)
-	  return 1;
+	  return unify_template_argument_mismatch (explain_p, parm, arg);
 	if (TREE_VEC_LENGTH (parm) != TREE_VEC_LENGTH (arg))
-	  return 1;
+	  return unify_arity (explain_p, TREE_VEC_LENGTH (arg),
+			      TREE_VEC_LENGTH (parm));
 	for (i = 0; i < TREE_VEC_LENGTH (parm); ++i)
-	  if (unify (tparms, targs,
-		     TREE_VEC_ELT (parm, i), TREE_VEC_ELT (arg, i),
-		     UNIFY_ALLOW_NONE))
-	    return 1;
-	return 0;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs,
+				   TREE_VEC_ELT (parm, i),
+				   TREE_VEC_ELT (arg, i),
+				   UNIFY_ALLOW_NONE, explain_p);
+	return unify_success (explain_p);
       }
 
     case RECORD_TYPE:
     case UNION_TYPE:
       if (TREE_CODE (arg) != TREE_CODE (parm))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
 
       if (TYPE_PTRMEMFUNC_P (parm))
 	{
 	  if (!TYPE_PTRMEMFUNC_P (arg))
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs,
 			TYPE_PTRMEMFUNC_FN_TYPE (parm),
 			TYPE_PTRMEMFUNC_FN_TYPE (arg),
-			strict);
+			strict, explain_p);
 	}
 
       if (CLASSTYPE_TEMPLATE_INFO (parm))
@@ -15845,7 +16162,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    {
 	      /* First, we try to unify the PARM and ARG directly.  */
 	      t = try_class_unification (tparms, targs,
-					 parm, arg);
+					 parm, arg, explain_p);
 
 	      if (!t)
 		{
@@ -15858,10 +16175,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		       a class of the form template-id, A can be a
 		       pointer to a derived class pointed to by the
 		       deduced A.  */
-		  t = get_template_base (tparms, targs, parm, arg);
+		  enum template_base_result r;
+		  r = get_template_base (tparms, targs, parm, arg,
+					 explain_p, &t);
 
 		  if (!t)
-		    return 1;
+		    return unify_no_common_base (explain_p, r, parm, arg);
 		}
 	    }
 	  else if (CLASSTYPE_TEMPLATE_INFO (arg)
@@ -15872,14 +16191,14 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	    t = arg;
 	  else
 	    /* There's no chance of unification succeeding.  */
-	    return 1;
+	    return unify_type_mismatch (explain_p, parm, arg);
 
 	  return unify (tparms, targs, CLASSTYPE_TI_ARGS (parm),
-			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE);
+			CLASSTYPE_TI_ARGS (t), UNIFY_ALLOW_NONE, explain_p);
 	}
       else if (!same_type_ignoring_top_level_qualifiers_p (parm, arg))
-	return 1;
-      return 0;
+	return unify_type_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case METHOD_TYPE:
     case FUNCTION_TYPE:
@@ -15890,7 +16209,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	unsigned int i;
 
 	if (TREE_CODE (arg) != TREE_CODE (parm))
-	  return 1;
+	  return unify_type_mismatch (explain_p, parm, arg);
 
 	/* CV qualifications for methods can never be deduced, they must
 	   match exactly.  We need to check them explicitly here,
@@ -15901,11 +16220,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		(UNIFY_ALLOW_NONE,
 		 class_of_this_parm (arg),
 		 class_of_this_parm (parm))))
-	  return 1;
+	  return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	if (unify (tparms, targs, TREE_TYPE (parm),
-		   TREE_TYPE (arg), UNIFY_ALLOW_NONE))
-	  return 1;
+	RECUR_AND_CHECK_FAILURE (tparms, targs, TREE_TYPE (parm),
+				 TREE_TYPE (arg), UNIFY_ALLOW_NONE, explain_p);
 
 	nargs = list_length (TYPE_ARG_TYPES (arg));
 	args = XALLOCAVEC (tree, nargs);
@@ -15917,7 +16235,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	return type_unification_real (tparms, targs, TYPE_ARG_TYPES (parm),
 				      args, nargs, 1, DEDUCE_EXACT,
-				      LOOKUP_NORMAL);
+				      LOOKUP_NORMAL, explain_p);
       }
 
     case OFFSET_TYPE:
@@ -15930,11 +16248,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
 	  /* Check top-level cv qualifiers */
 	  if (!check_cv_quals_for_unify (UNIFY_ALLOW_NONE, arg, parm))
-	    return 1;
+	    return unify_cv_qual_mismatch (explain_p, parm, arg);
 
-	  if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		     TYPE_PTRMEMFUNC_OBJECT_TYPE (arg), UNIFY_ALLOW_NONE))
-	    return 1;
+	  RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+				   TYPE_PTRMEMFUNC_OBJECT_TYPE (arg),
+				   UNIFY_ALLOW_NONE, explain_p);
 
 	  /* Determine the type of the function we are unifying against. */
 	  method_type = TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (arg));
@@ -15946,28 +16264,28 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	     implicit object parameter and place them on the function
 	     type to be restored later. */
 	  fntype = apply_memfn_quals (fntype, type_memfn_quals (method_type));
-	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict);
+	  return unify (tparms, targs, TREE_TYPE (parm), fntype, strict, explain_p);
 	}
 
       if (TREE_CODE (arg) != OFFSET_TYPE)
-	return 1;
-      if (unify (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
-		 TYPE_OFFSET_BASETYPE (arg), UNIFY_ALLOW_NONE))
-	return 1;
+	return unify_type_mismatch (explain_p, parm, arg);
+      RECUR_AND_CHECK_FAILURE (tparms, targs, TYPE_OFFSET_BASETYPE (parm),
+			       TYPE_OFFSET_BASETYPE (arg),
+			       UNIFY_ALLOW_NONE, explain_p);
       return unify (tparms, targs, TREE_TYPE (parm), TREE_TYPE (arg),
-		    strict);
+		    strict, explain_p);
 
     case CONST_DECL:
       if (DECL_TEMPLATE_PARM_P (parm))
-	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict);
+	return unify (tparms, targs, DECL_INITIAL (parm), arg, strict, explain_p);
       if (arg != integral_constant_value (parm))
-	return 1;
-      return 0;
+	return unify_template_argument_mismatch (explain_p, parm, arg);
+      return unify_success (explain_p);
 
     case FIELD_DECL:
     case TEMPLATE_DECL:
       /* Matched cases are handled by the ARG == PARM test above.  */
-      return 1;
+      return unify_template_argument_mismatch (explain_p, parm, arg);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15997,7 +16315,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		  /* Since there is something following the pack
 		     expansion, we cannot unify this template argument
 		     list.  */
-		  return 0;
+		  return unify_success (explain_p);
 	      }
 	  }
 	  
@@ -16006,25 +16324,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_arguments (explain_p, argslen, len);
+	if (argslen > len && !parm_variadic_p)
+	  return unify_too_many_arguments (explain_p, argslen, len);
 
         /* Unify all of the parameters that precede the (optional)
            pack expression.  */
         for (i = 0; i < len - parm_variadic_p; ++i)
           {
-            if (unify (tparms, targs, TREE_VEC_ELT (packed_parms, i),
-                       TREE_VEC_ELT (packed_args, i), strict))
-              return 1;
+	    RECUR_AND_CHECK_FAILURE (tparms, targs,
+				     TREE_VEC_ELT (packed_parms, i),
+				     TREE_VEC_ELT (packed_args, i),
+				     strict, explain_p);
           }
 
         if (parm_variadic_p)
           return unify_pack_expansion (tparms, targs, 
                                        packed_parms, packed_args,
                                        strict, /*call_args_p=*/false,
-                                       /*subr=*/false);
-        return 0;
+                                       /*subr=*/false, explain_p);
+        return unify_success (explain_p);
       }
 
       break;
@@ -16034,16 +16354,16 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case UNDERLYING_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE, DECLTYPE_TYPE,
 	 or UNDERLYING_TYPE nodes.  */
-      return 0;
+      return unify_success (explain_p);
 
     case ERROR_MARK:
       /* Unification fails if we hit an error node.  */
-      return 1;
+      return unify_invalid (explain_p);
 
     default:
       /* An unresolved overload is a nondeduced context.  */
       if (type_unknown_p (parm))
-	return 0;
+	return unify_success (explain_p);
       gcc_assert (EXPR_P (parm));
 
       /* We must be looking at an expression.  This can happen with
@@ -16067,11 +16387,12 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 
       if (!uses_template_parms (parm)
 	  && !template_args_equal (parm, arg))
-	return 1;
+	return unify_expression_unequal (explain_p, parm, arg);
       else
-	return 0;
+	return unify_success (explain_p);
     }
 }
+#undef RECUR_AND_CHECK_FAILURE
 \f
 /* Note that DECL can be defined in this translation unit, if
    required.  */
@@ -16334,10 +16655,11 @@ more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len2; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce1 = !unify_pack_expansion (tparms1, targs1, parmvec, 
+          deduce1 = (unify_pack_expansion (tparms1, targs1, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/false)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG1 is
              a pack expansion but ARG2 is not.  */
@@ -16358,10 +16680,11 @@ more_specialized_fn (tree pat1, tree pat2, int len)
           for (i = 0; i < len1; i++, ta = TREE_CHAIN (ta))
             TREE_VEC_ELT (argvec, i) = TREE_VALUE (ta);
 
-          deduce2 = !unify_pack_expansion (tparms2, targs2, parmvec, 
+          deduce2 = (unify_pack_expansion (tparms2, targs2, parmvec, 
 					   argvec, UNIFY_ALLOW_NONE, 
                                            /*call_args_p=*/false, 
-					   /*subr=*/0);
+					   /*subr=*/0, /*explain_p=*/false)
+		     == 0);
 
           /* We cannot deduce in the other direction, because ARG2 is
              a pack expansion but ARG1 is not.*/
@@ -16372,8 +16695,12 @@ more_specialized_fn (tree pat1, tree pat2, int len)
         {
           /* The normal case, where neither argument is a pack
              expansion.  */
-          deduce1 = !unify (tparms1, targs1, arg1, arg2, UNIFY_ALLOW_NONE);
-          deduce2 = !unify (tparms2, targs2, arg2, arg1, UNIFY_ALLOW_NONE);
+          deduce1 = (unify (tparms1, targs1, arg1, arg2,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/false)
+		     == 0);
+          deduce2 = (unify (tparms2, targs2, arg2, arg1,
+			    UNIFY_ALLOW_NONE, /*explain_p=*/false)
+		     == 0);
         }
 
       /* If we couldn't deduce arguments for tparms1 to make arg1 match
@@ -16587,7 +16914,7 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
 			   args, ix,
 			   (check_rettype || DECL_CONV_FN_P (fn)
 			    ? TREE_TYPE (decl_type) : NULL_TREE),
-			   DEDUCE_EXACT, LOOKUP_NORMAL))
+			   DEDUCE_EXACT, LOOKUP_NORMAL, /*explain_p=*/false))
     return NULL_TREE;
 
   return targs;
@@ -16629,7 +16956,7 @@ get_class_bindings (tree tparms, tree spec_args, tree args)
   if (unify (tparms, deduced_args,
 	     INNERMOST_TEMPLATE_ARGS (spec_args),
 	     INNERMOST_TEMPLATE_ARGS (args),
-	     UNIFY_ALLOW_NONE))
+	     UNIFY_ALLOW_NONE, /*explain_p=*/false))
     return NULL_TREE;
 
   for (i =  0; i < ntparms; ++i)
@@ -19436,7 +19763,8 @@ do_auto_deduction (tree type, tree init, tree auto_node)
   TREE_VEC_ELT (tparms, 0)
     = build_tree_list (NULL_TREE, TYPE_NAME (auto_node));
   val = type_unification_real (tparms, targs, parms, args, 1, 0,
-			       DEDUCE_CALL, LOOKUP_NORMAL);
+			       DEDUCE_CALL, LOOKUP_NORMAL,
+			       /*explain_p=*/false);
   if (val > 0)
     {
       if (processing_template_decl)
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
index 352137a..120dfaa 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
@@ -9,8 +9,9 @@ decltype(F()) run(F f) // { dg-message "note" }
 
 int main()
 {
-  auto l = []() { return 5; };
+  auto l = []() { return 5; }; // { dg-error "lambda closure type" }
 
   run(l); // { dg-error "no match" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 14 }
+  // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 14 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/nullptr15.C b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
index e02fd55..af661ec 100644
--- a/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
+++ b/gcc/testsuite/g++.dg/cpp0x/nullptr15.C
@@ -17,10 +17,10 @@ void test_g()
   // Deduction to nullptr_t, no deduction to pointer type
   //
   g(nullptr);               // { dg-error "no matching function for call to " }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 19 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 19 }
   type_equal<float*>(g((float*)nullptr));
   decltype(nullptr) mynull = 0;
   g(mynull);                // { dg-error "no matching function for call to " }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 23 }
   type_equal<float*>(g((float*)mynull));
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
index 15efbc5..0764939 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31431-2.C
@@ -4,5 +4,5 @@ template<typename, typename..., typename> void foo(); // { dg-message "note" }
 void bar()
 {
   foo<int>(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31431.C b/gcc/testsuite/g++.dg/cpp0x/pr31431.C
index 36f341f..afd3237 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31431.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31431.C
@@ -4,5 +4,5 @@ template<typename..., typename> void foo(); // { dg-message "note" }
 void bar()
 {
   foo<int>(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr31434.C b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
index 97ad079..5478616 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr31434.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr31434.C
@@ -8,5 +8,5 @@ template<typename... T> int foo(const T&) // { dg-error "not expanded with|T" }
 void bar()
 {
   foo(0); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|cannot convert)" "candidate note" { target *-*-* } 10 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
index 117b08b..e62c089 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae11.C
@@ -51,6 +51,6 @@ int main()
   // static_assert(  noexcept( f3(y) ), "shall be ill-formed(OK)." );
 
   noexcept( f1(z) );		// { dg-message "required" }
-  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match" }
+  static_assert(  noexcept( f2(z) ), "shall be ill-formed." ); // { dg-error "no match|could not convert" }
   noexcept( f3(z) );		// { dg-message "required" }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
index fa2bb6a..dab1650 100644
--- a/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/temp_default2.C
@@ -8,7 +8,7 @@ void g()
   f(1, 'c'); // f<int,char>(1,'c') 
   f(1); // f<int,double>(1,0) 
   f(); // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   f<int>(); // f<int,double>(0,0) 
   f<int,char>(); // f<int,char>(0,0) 
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/trailing4.C b/gcc/testsuite/g++.dg/cpp0x/trailing4.C
index d67b3b6..8d4baa9 100644
--- a/gcc/testsuite/g++.dg/cpp0x/trailing4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/trailing4.C
@@ -8,5 +8,5 @@ auto f(T,U) -> decltype(T() + U())
 template<class T> void g(T){}	// { dg-message "note" }
 
 int main() { g(f); }		// { dg-error "no matching function" }
-// { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+// { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
index bd97305..018eaa3 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex3.C
@@ -4,8 +4,8 @@ void g()
 { 
   int i = f<int>(5.6);
   int j = f(5.6);         // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
   f<void>(f<int, bool>);
   f<void>(f<int>);        // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 9 }
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C b/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
index 5bf2116..0a777c4 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-ex4.C
@@ -8,6 +8,6 @@ void g()
   f<int>("aa",3.0); // Y is deduced to be char*, and 
                     // Z is deduced to be double 
   f("aa",3.0); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   f2<char, short, int, long>(); // okay
 } 
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic105.C b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
index 24d7e15..2729b31 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic105.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
@@ -21,4 +21,5 @@ struct call_sum {
 int main() {
   // This shouldn't be an error; this is bug 35722.
   reverse<call_sum>(1,2);	// { dg-bogus "no match" "" { xfail *-*-* } }
+  // { dg-message "sorry, unimplemented" "candidate explanation" { target *-*-* } 23 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C b/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
index 2ff7e5b..5514259 100644
--- a/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/vt-37737-2.C
@@ -4,7 +4,7 @@ template<class U, class... T>
 void f()			// { dg-message "note" }
 {
   f<T...>(); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 6 }
 }
 
 template<>
diff --git a/gcc/testsuite/g++.dg/ext/vla2.C b/gcc/testsuite/g++.dg/ext/vla2.C
index f6a9deb..3e83c8b 100644
--- a/gcc/testsuite/g++.dg/ext/vla2.C
+++ b/gcc/testsuite/g++.dg/ext/vla2.C
@@ -15,5 +15,5 @@ void bar(int i)
   char d[i] ;
   
   begin(d);  // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+  // { dg-message "(candidate|valid template argument)" "candidate note" { target *-*-* } 17 }
 }
diff --git a/gcc/testsuite/g++.dg/other/ptrmem10.C b/gcc/testsuite/g++.dg/other/ptrmem10.C
index bc386ed..a17df7f 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem10.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem10.C
@@ -13,7 +13,7 @@ template <class C>
 static void
 bar(C *c, void (C::*m) ())
 {
-  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun)" }
+  foo<C,m>((void *)c);// { dg-error "(not a valid template arg|pointer-to-member|no matching fun|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
 }
 
diff --git a/gcc/testsuite/g++.dg/other/ptrmem11.C b/gcc/testsuite/g++.dg/other/ptrmem11.C
index 119cbb0..e73164e 100644
--- a/gcc/testsuite/g++.dg/other/ptrmem11.C
+++ b/gcc/testsuite/g++.dg/other/ptrmem11.C
@@ -14,7 +14,7 @@ template <typename T>
 int
 bar(int T::* p)
 {
-  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member)" }
+  return foo<p>(0);// { dg-error "(not a valid template arg|no matching func|pointer-to-member|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
 }
 
diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C
new file mode 100644
index 0000000..b1dc65e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/template5.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+
+template<typename T>
+int low(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+
+template<typename T>
+int high(T a, T b, T c) { return a + b + c; } // { dg-message "template" }
+
+int test (void)
+{
+  low (5, 6);			// { dg-error "no matching function" }
+  // { dg-message "(candidate|3 arguments, 2 provided)" "" { target *-*-* } 11 }
+  high (5, 6, 7, 8);		// { dg-error "no matching function" }
+  // { dg-message "(candidate|3 arguments, 4 provided)" "" { target *-*-* } 13 }
+}
diff --git a/gcc/testsuite/g++.dg/overload/unknown1.C b/gcc/testsuite/g++.dg/overload/unknown1.C
index 935f8d4..128c434 100644
--- a/gcc/testsuite/g++.dg/overload/unknown1.C
+++ b/gcc/testsuite/g++.dg/overload/unknown1.C
@@ -6,5 +6,5 @@ template <typename T> void bar(T f); // { dg-message "note" }
 
 void baz() {
   bar(foo); // { dg-error "<unresolved overloaded function type>" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/conv11.C b/gcc/testsuite/g++.dg/template/conv11.C
index 57d06af..f08e756 100644
--- a/gcc/testsuite/g++.dg/template/conv11.C
+++ b/gcc/testsuite/g++.dg/template/conv11.C
@@ -7,5 +7,5 @@ struct A
 int main()
 {
   A().operator int();		// { dg-error "operator int" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 9 }
 }
diff --git a/gcc/testsuite/g++.dg/template/dependent-expr5.C b/gcc/testsuite/g++.dg/template/dependent-expr5.C
index 1e850cd..af0dfb9 100644
--- a/gcc/testsuite/g++.dg/template/dependent-expr5.C
+++ b/gcc/testsuite/g++.dg/template/dependent-expr5.C
@@ -40,12 +40,12 @@ struct foo {
       bind (&bar::baikt);
 
       bind (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 42 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 42 }
       bind (&foo::barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 44 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 44 }
 
       bindm (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 47 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 47 }
       bindm (&foo::barf);
 
       bindn (&barf);
@@ -53,15 +53,15 @@ struct foo {
 
       bindb (&barf);
       bindb (&foo::barf); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 55 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 55 }
 
       bind (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 58 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 58 }
       bind (&bar::bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 60 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 60 }
 
       bindm (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 63 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 63 }
       bindm (&bar::bark);
 
       bindn (&bark);
@@ -69,7 +69,7 @@ struct foo {
 
       bindb (&bark);
       bindb (&bar::bark); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 71 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 71 }
     }
   };
 
@@ -92,12 +92,12 @@ struct foo {
       bind (&barT::baikt);
 
       bind (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 94 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 94 }
       bind (&foo::barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 96 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 96 }
 
       bindm (&barf); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 99 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 99 }
       bindm (&foo::barf);
 
       bindn (&barf);
@@ -105,15 +105,15 @@ struct foo {
 
       bindb (&barf);
       bindb (&foo::barf); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 107 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 107 }
 
       bind (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 110 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 110 }
       bind (&barT::bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 112 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 112 }
 
       bindm (&bark); // { dg-error "no matching function" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 115 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 115 }
       bindm (&barT::bark);
 
       bindn (&bark);
@@ -121,7 +121,7 @@ struct foo {
 
       bindb (&bark);
       bindb (&barT::bark); // { dg-error "ambiguous" }
-      // { dg-message "candidate" "candidate note" { target *-*-* } 123 }
+      // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 123 }
     }
   };
 
diff --git a/gcc/testsuite/g++.dg/template/friend.C b/gcc/testsuite/g++.dg/template/friend.C
index 44cbce9..e315a1a 100644
--- a/gcc/testsuite/g++.dg/template/friend.C
+++ b/gcc/testsuite/g++.dg/template/friend.C
@@ -26,5 +26,5 @@ int main()
 {
   s<int>::t y;
   cout << y; // { dg-error "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 28 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 28 }
 }
diff --git a/gcc/testsuite/g++.dg/template/incomplete2.C b/gcc/testsuite/g++.dg/template/incomplete2.C
index d86ea06..b855569 100644
--- a/gcc/testsuite/g++.dg/template/incomplete2.C
+++ b/gcc/testsuite/g++.dg/template/incomplete2.C
@@ -9,6 +9,6 @@ A a;  // { dg-error "incomplete type" }
 
 void bar()
 {
-  foo<a>();  // { dg-error "no matching function" }
+  foo<a>();  // { dg-error "(no matching function|could not convert)" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 12 }
 }
diff --git a/gcc/testsuite/g++.dg/template/local4.C b/gcc/testsuite/g++.dg/template/local4.C
index 9a03c9a..d842076 100644
--- a/gcc/testsuite/g++.dg/template/local4.C
+++ b/gcc/testsuite/g++.dg/template/local4.C
@@ -5,6 +5,6 @@ template <typename T> void foo() {} // { dg-message "note" }
 
 int main () {
   struct S {};
-  foo<S> (); // { dg-error "match" } 
+  foo<S> (); // { dg-error "(match|template argument for|trying to instantiate)" } 
   // { dg-message "candidate" "candidate note" { target *-*-* } 8 }
 }
diff --git a/gcc/testsuite/g++.dg/template/local6.C b/gcc/testsuite/g++.dg/template/local6.C
index 777349a..3eb828f 100644
--- a/gcc/testsuite/g++.dg/template/local6.C
+++ b/gcc/testsuite/g++.dg/template/local6.C
@@ -5,7 +5,7 @@ template <class T> struct PCVector2 // { dg-message "note" }
     PCVector2<T> operator- (const PCVector2<T> &ov) const 
 	{ 
 	  return PCVector2<T>(ov.xFIELD, ov.yFIELD); // { dg-error "matching" }
-	  // { dg-message "candidate" "candidate note" { target *-*-* } 7 }
+	  // { dg-message "(candidate|expects 1 argument, 2 provided|cannot convert)" "candidate note" { target *-*-* } 7 }
 	}
 
     T xFIELD, yFIELD;
diff --git a/gcc/testsuite/g++.dg/template/operator9.C b/gcc/testsuite/g++.dg/template/operator9.C
index 35be778..46eef0a 100644
--- a/gcc/testsuite/g++.dg/template/operator9.C
+++ b/gcc/testsuite/g++.dg/template/operator9.C
@@ -5,6 +5,6 @@ template<operator+> void foo(); // { dg-error "before|non-function|template" }
 void bar()
 {
   foo();                        // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 7 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 7 }
 }
  
diff --git a/gcc/testsuite/g++.dg/template/overload12.C b/gcc/testsuite/g++.dg/template/overload12.C
new file mode 100644
index 0000000..656dcae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/overload12.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+
+struct S {int x; int y;};
+template<typename T>
+int foo(T a, T b) {return a + b;} // { dg-message "template" }
+template<typename T, typename T2>
+int foo(T a, T2& b, T2 c) {return a + b;}  // { dg-message "template" }
+int foo(char*, S&); // { dg-message "foo" }
+// { dg-message "candidate expects 2 arguments, 3 provided" "arity" { target *-*-* } 8 }
+
+int foo2(int x)
+{
+  S s={1,2};
+  char c;
+  foo(c, 2, c); // { dg-error "no matching function" }
+  // { dg-message "(candidate|deduced conflicting types for)" "candidate note" { target *-*-* } 15 }
+}
diff --git a/gcc/testsuite/g++.dg/template/ttp25.C b/gcc/testsuite/g++.dg/template/ttp25.C
index 861d187..46762ae 100644
--- a/gcc/testsuite/g++.dg/template/ttp25.C
+++ b/gcc/testsuite/g++.dg/template/ttp25.C
@@ -18,12 +18,12 @@ void f4(T, C<5>);		// { dg-message "note" }
 template<int N> struct X {};
 void g() {
   f1(5l, X<5>()); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 20 }
+  // { dg-message "(candidate|inconsistent with)" "candidate note" { target *-*-* } 20 }
   f2(X<5>(), 5);
   f3(X<5>(), 5l); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
+  // { dg-message "(candidate|inconsistent with)" "candidate note" { target *-*-* } 23 }
   f4(5, X<5>());
   f4(5l, X<5>()); // { dg-error "no matching" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 26 }
+  // { dg-message "(candidate|inconsistent with)" "candidate note" { target *-*-* } 26 }
   f4((short)5, X<5>());
 }
diff --git a/gcc/testsuite/g++.dg/template/unify10.C b/gcc/testsuite/g++.dg/template/unify10.C
index 8dc434b..7f2fd53 100644
--- a/gcc/testsuite/g++.dg/template/unify10.C
+++ b/gcc/testsuite/g++.dg/template/unify10.C
@@ -26,34 +26,34 @@ void cvFunction(void (CLASS::* method)() const volatile) {} // { dg-message "not
 int main() {
   mFunction(&MyClass::mMethod);
   mFunction(&MyClass::cMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 28 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 28 }
   mFunction(&MyClass::vMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 30 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 30 }
   mFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 32 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 32 }
 
   cFunction(&MyClass::mMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 35 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 35 }
   cFunction(&MyClass::cMethod);
   cFunction(&MyClass::vMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 38 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 38 }
   cFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 40 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 40 }
 
   vFunction(&MyClass::mMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 43 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 43 }
   vFunction(&MyClass::cMethod);    // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 45 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 45 }
   vFunction(&MyClass::vMethod);
   vFunction(&MyClass::cvMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 48 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 48 }
 
   cvFunction(&MyClass::mMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 51 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 51 }
   cvFunction(&MyClass::cMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 53 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 53 }
   cvFunction(&MyClass::vMethod);   // { dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 55 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 55 }
   cvFunction(&MyClass::cvMethod);
 
   return 0;
diff --git a/gcc/testsuite/g++.dg/template/unify11.C b/gcc/testsuite/g++.dg/template/unify11.C
index ed6b31c..25606dc 100644
--- a/gcc/testsuite/g++.dg/template/unify11.C
+++ b/gcc/testsuite/g++.dg/template/unify11.C
@@ -20,7 +20,7 @@ struct B
     C (U t)
     {
       A a;
-      A b = foo (this, a, t); // { dg-error "no matching function" }
+      A b = foo (this, a, t); // { dg-error "(no matching function|is not a)" }
       // { dg-message "candidate" "candidate note" { target *-*-* } 23 }
     }
   } c;
diff --git a/gcc/testsuite/g++.dg/template/unify6.C b/gcc/testsuite/g++.dg/template/unify6.C
index b12ecb2..551c96e 100644
--- a/gcc/testsuite/g++.dg/template/unify6.C
+++ b/gcc/testsuite/g++.dg/template/unify6.C
@@ -19,5 +19,5 @@ void Bar ()
   Foo3 (&Baz);
 
   Foo3 (&Baz, &Baz); // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 21 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 21 }
 }
diff --git a/gcc/testsuite/g++.dg/template/unify7.C b/gcc/testsuite/g++.dg/template/unify7.C
index 2bfa563..88d9fd9 100644
--- a/gcc/testsuite/g++.dg/template/unify7.C
+++ b/gcc/testsuite/g++.dg/template/unify7.C
@@ -11,5 +11,5 @@ int main()
 {
   Foo (f);
   Baz (f); // { dg-error "no matching function" "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 13 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 13 }
 }
diff --git a/gcc/testsuite/g++.dg/template/unify9.C b/gcc/testsuite/g++.dg/template/unify9.C
index 40f6b92..f06f83a 100644
--- a/gcc/testsuite/g++.dg/template/unify9.C
+++ b/gcc/testsuite/g++.dg/template/unify9.C
@@ -14,5 +14,5 @@ const X *x;
  
 int main () { 
   f (*x, &X::g);  // {  dg-error "no matching function" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 16 }
 } 
diff --git a/gcc/testsuite/g++.dg/template/varmod1.C b/gcc/testsuite/g++.dg/template/varmod1.C
index 6ae78d9..4ba1104 100644
--- a/gcc/testsuite/g++.dg/template/varmod1.C
+++ b/gcc/testsuite/g++.dg/template/varmod1.C
@@ -7,5 +7,5 @@ void bar()
   int i;
   int A[i][i]; 
   foo(A); // { dg-error "" } 
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-message "(candidate|not a valid template argument)" "candidate note" { target *-*-* } 9 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
index a22615d..e3bff80 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/crash56.C
@@ -278,7 +278,7 @@ SetLD<T>::remove(const T& item)
     Vix x;
     for (first(x); 0 != x && this->REMOVE_CURRENT != a; next(x, a))
 	a = operator()(x) == item ? this->REMOVE_CURRENT: this->NORMAL; // { dg-error "" } .*
-    // { dg-message "candidate" "candidate note" { target *-*-* } 280 }
+    // { dg-message "(candidate|not derived from)" "candidate note" { target *-*-* } 280 }
 }
 template<class T>
 bool
@@ -287,7 +287,7 @@ SetLD<T>::contains(const T& item) const
     Vix x;
     for (first(x); 0 != x; next(x)) {
 	if (operator()(x) == item)// { dg-error "" } .*
-	  // { dg-message "candidate" "candidate note" { target *-*-* } 289 }
+	  // { dg-message "(candidate|not derived from)" "candidate note" { target *-*-* } 289 }
 	    return TRUE;
     }
     return FALSE;
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash28.C b/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
index 2cfed93..81ed85a 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash28.C
@@ -11,5 +11,5 @@ void f(unsigned int n) {
   int x[n];
 
   asize(x); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 13 }
+  // { dg-message "(candidate|not a valid template argument)" "candidate note" { target *-*-* } 13 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
index 560370a..c27d131 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit41.C
@@ -1,6 +1,6 @@
 // { dg-do assemble  }
 template <int I>
-void f(int i);			// { dg-message "note" }
+void f(int i);			// { dg-message "void f" }
 
 void g()
 {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
index 1213a15..b97c1cd 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/explicit77.C
@@ -15,5 +15,5 @@ void g() {
   
   f<0>(s0, s2);
   f(s0, s2); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+  // { dg-message "(candidate|deduced conflicting types|ambiguous base class)" "candidate note" { target *-*-* } 17 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/expr2.C b/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
index 0dcc65f..06d22d5 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/expr2.C
@@ -9,5 +9,5 @@ void foo(S<J + 2>);		// { dg-message "note" }
 void bar()
 {
   foo(S<3>()); // { dg-error "" } no way to deduce J from this.
-  // { dg-message "candidate" "candidate note" { target *-*-* } 11 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 11 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
index 85d3e73..8802e98 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/ptrmem6.C
@@ -13,9 +13,9 @@ public:
 };
 
 template <void (A::*)() >
-void g() {}			// { dg-message "note" }
+void g() {}			// { dg-message "void g" }
 template <int A::*>
-void h() {}			// { dg-message "note" }
+void h() {}			// { dg-message "void h" }
 
 
 int main() {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec5.C b/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
index df7112a..96e8cf9 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec5.C
@@ -14,9 +14,9 @@ template void g(int i, int j);
 void h()
 {
   f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 16 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 16 }
   g(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 18 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 18 }
 }
 
 
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec6.C b/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
index fc19c3c..b8f6673 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/spec6.C
@@ -25,9 +25,9 @@ void h()
 {
   S1 s1;
   s1.f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 27 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 27 }
 
   S2<char> s2;
   s2.f(3, 'c'); // { dg-error "" } no matching function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 31 }
+  // { dg-message "(candidate|deduced conflicting types)" "candidate note" { target *-*-* } 31 }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify4.C b/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
index 6dd9961..9285b21 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/unify4.C
@@ -8,6 +8,6 @@ int
 main ()
 {
   f (g);			// { dg-error "" } ambiguous unification
-  // { dg-message "candidate" "candidate note" { target *-*-* } 10 }
+  // { dg-message "(candidate|deduce template parameter)" "candidate note" { target *-*-* } 10 }
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify8.C b/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
index 3209260..3a86d97 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/unify8.C
@@ -16,6 +16,6 @@ void Foo (float);     // { dg-message "note" } candidate
 void baz (int **p1)
 {
   Foo (p1);   // { dg-error "match" } no such function
-  // { dg-message "candidate" "candidate note" { target *-*-* } 18 }
+  // { dg-message "(candidate|incompatible cv-qualifiers)" "candidate note" { target *-*-* } 18 }
   Bar (p1);   // OK
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C b/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
index c562031..410a336 100644
--- a/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
+++ b/gcc/testsuite/g++.old-deja/g++.robertl/eb98.C
@@ -15,5 +15,5 @@
     void f()
     {
       extent(b);  // { dg-error "" } no matching function
-      // { dg-message "candidate" "candidate note" { target *-*-* } 17 }
+      // { dg-message "(candidate|mismatched types)" "candidate note" { target *-*-* } 17 }
     }

[-- Attachment #3: 45329-2.patch --]
[-- Type: text/x-patch, Size: 9500 bytes --]

commit c51bed9b91dd53013feb770278a6e8c466001fa0
Author: Jason Merrill <jason@redhat.com>
Date:   Sat Jul 16 22:20:52 2011 -0400

    	* call.c (template_unification_error_rejection): Define.
    	(add_template_candidate_real): Use it if unification caused errors.
    	(print_z_candidate): Handle it.
    	* pt.c (unify_template_parameter_mismatch): Remove.
    	(unify): Use unify_expression_unequal instead.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index dc8cfe7..0279066 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -666,6 +666,12 @@ template_unification_rejection (tree tmpl, tree explicit_targs, tree targs,
 }
 
 static struct rejection_reason *
+template_unification_error_rejection (void)
+{
+  return alloc_rejection (rr_template_unification);
+}
+
+static struct rejection_reason *
 template_instantiation_rejection (tree tmpl, tree targs)
 {
   struct rejection_reason *r = alloc_rejection (rr_template_instantiation);
@@ -2918,6 +2924,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
   int i;
   tree fn;
   struct rejection_reason *reason = NULL;
+  int errs;
 
   /* We don't do deduction on the in-charge parameter, the VTT
      parameter or 'this'.  */
@@ -2960,6 +2967,7 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
     }
   gcc_assert (ia == nargs_without_in_chrg);
 
+  errs = errorcount+sorrycount;
   i = fn_type_unification (tmpl, explicit_targs, targs,
 			   args_without_in_chrg,
 			   nargs_without_in_chrg,
@@ -2967,10 +2975,14 @@ add_template_candidate_real (struct z_candidate **candidates, tree tmpl,
 
   if (i != 0)
     {
-      reason = template_unification_rejection (tmpl, explicit_targs,
-					       targs, args_without_in_chrg,
-					       nargs_without_in_chrg,
-					       return_type, strict, flags);
+      /* Don't repeat unification later if it already resulted in errors.  */
+      if (errorcount+sorrycount == errs)
+	reason = template_unification_rejection (tmpl, explicit_targs,
+						 targs, args_without_in_chrg,
+						 nargs_without_in_chrg,
+						 return_type, strict, flags);
+      else
+	reason = template_unification_error_rejection ();
       goto fail;
     }
 
@@ -3253,7 +3265,17 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate)
 		  r->u.conversion.to_type);
 	  break;
 	case rr_template_unification:
+	  /* We use template_unification_error_rejection if unification caused
+	     actual non-SFINAE errors, in which case we don't need to repeat
+	     them here.  */
+	  if (r->u.template_unification.tmpl == NULL_TREE)
+	    {
+	      inform (loc, "  substitution of deduced template arguments "
+		      "resulted in errors seen above");
+	      break;
+	    }
 	  /* Re-run template unification with diagnostics.  */
+	  inform (loc, "  template argument deduction/substitution failed:");
 	  fn_type_unification (r->u.template_unification.tmpl,
 			       r->u.template_unification.explicit_targs,
 			       r->u.template_unification.targs,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index b8d25d4..8136a99 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5464,15 +5464,6 @@ unify_template_deduction_failure (bool explain_p, tree parm, tree arg)
 }
 
 static int
-unify_template_parameter_mismatch (bool explain_p, tree parm, tree tparm)
-{
-  if (explain_p)
-    inform (input_location,
-	    "  template parameter %qT does not match %qD", tparm, parm);
-  return 1;
-}
-
-static int
 unify_template_argument_mismatch (bool explain_p, tree parm, tree arg)
 {
   if (explain_p)
@@ -15920,7 +15911,7 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict,
 	  int result = !(TREE_CODE (arg) == TREE_CODE (parm)
 			 && cp_tree_equal (parm, arg));
 	  if (result)
-	    unify_template_parameter_mismatch (explain_p, parm, tparm);
+	    unify_expression_unequal (explain_p, parm, arg);
 	  return result;
 	}
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/decltype29.C b/gcc/testsuite/g++.dg/cpp0x/decltype29.C
index 2bb79d0..70fe441 100644
--- a/gcc/testsuite/g++.dg/cpp0x/decltype29.C
+++ b/gcc/testsuite/g++.dg/cpp0x/decltype29.C
@@ -13,7 +13,7 @@ decltype (ft<F> (F()))
 ft() {}				// { dg-error "depth" }
 
 int main() {
-    ft<struct a*, 0>();		// { dg-error "no match" }
+    ft<struct a*, 0>();		// { dg-error "no match|wrong number" }
 }
 
 // { dg-prune-output "note" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/error4.C b/gcc/testsuite/g++.dg/cpp0x/error4.C
index 29a1cdd..064c2f2 100644
--- a/gcc/testsuite/g++.dg/cpp0x/error4.C
+++ b/gcc/testsuite/g++.dg/cpp0x/error4.C
@@ -10,7 +10,7 @@ struct S {
     static U get(const volatile T&);
 
   template<typename U>
-    static decltype(*declval<U>()) get(...);
+    static decltype(*declval<U>()) get(...); // { dg-error "operator*" }
 
   typedef decltype(get<T>(declval<T>())) type; // { dg-error "no match" }
 };
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
index 120dfaa..8d7d093 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice2.C
@@ -13,5 +13,5 @@ int main()
 
   run(l); // { dg-error "no match" }
   // { dg-message "candidate" "candidate note" { target *-*-* } 14 }
-  // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 14 }
+  // { dg-error "use of deleted function" "candidate explanation" { target *-*-* } 5 }
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/sfinae26.C b/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
index 5b8cdd9..42b48eb 100644
--- a/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
+++ b/gcc/testsuite/g++.dg/cpp0x/sfinae26.C
@@ -32,7 +32,7 @@ struct S {
   template<class... U,
     typename enable_if<and_<is_same<T, U>...>::value>::type*& = enabler
   >
-  S(U...){} // #
+  S(U...){}			// { dg-error "no type named 'type'" }
 };
 
 S<bool> s(0);			// { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic105.C b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
index 2729b31..66387b2 100644
--- a/gcc/testsuite/g++.dg/cpp0x/variadic105.C
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic105.C
@@ -21,5 +21,5 @@ struct call_sum {
 int main() {
   // This shouldn't be an error; this is bug 35722.
   reverse<call_sum>(1,2);	// { dg-bogus "no match" "" { xfail *-*-* } }
-  // { dg-message "sorry, unimplemented" "candidate explanation" { target *-*-* } 23 }
+  // { dg-bogus "sorry, unimplemented" "candidate explanation" { xfail *-*-* } 6 }
 }
diff --git a/gcc/testsuite/g++.dg/template/deduce3.C b/gcc/testsuite/g++.dg/template/deduce3.C
index e8a1d4e..c5d6e00 100644
--- a/gcc/testsuite/g++.dg/template/deduce3.C
+++ b/gcc/testsuite/g++.dg/template/deduce3.C
@@ -4,8 +4,8 @@ void f(int, T (*)() = 0);	// { dg-message "note" }
 void g() {
   typedef int A[2];
   f<A>(0); // { dg-error "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 6 }
+  // { dg-error "returning an array" "candidate explanation" { target *-*-* } 2 }
   typedef void F();
   f<F>(0); // { dg-error "" }
-  // { dg-message "candidate" "candidate note" { target *-*-* } 9 }
+  // { dg-error "returning a function" "candidate explanation" { target *-*-* } 2 }
 }
diff --git a/gcc/testsuite/g++.dg/template/error45.C b/gcc/testsuite/g++.dg/template/error45.C
index 454acc6..064554d 100644
--- a/gcc/testsuite/g++.dg/template/error45.C
+++ b/gcc/testsuite/g++.dg/template/error45.C
@@ -11,7 +11,7 @@ struct enable_if< true, T >
 
 template < typename T >
 struct enable_if< true, T >::type
-f( T x );
+f( T x );			// { dg-error "not a class type" }
 
 void
 g( void )
diff --git a/gcc/testsuite/g++.dg/template/ptrmem2.C b/gcc/testsuite/g++.dg/template/ptrmem2.C
index 1919047..5f03580 100644
--- a/gcc/testsuite/g++.dg/template/ptrmem2.C
+++ b/gcc/testsuite/g++.dg/template/ptrmem2.C
@@ -7,7 +7,7 @@
 
 struct A {};
 
-template <typename T> T A::* Foo (); // { dg-message "note" }
+template <typename T> T A::* Foo (); // { dg-error "reference" }
 
 void Baz ()
 {
diff --git a/gcc/testsuite/g++.dg/template/sfinae2.C b/gcc/testsuite/g++.dg/template/sfinae2.C
index e39ca6b..c9e1031 100644
--- a/gcc/testsuite/g++.dg/template/sfinae2.C
+++ b/gcc/testsuite/g++.dg/template/sfinae2.C
@@ -8,7 +8,7 @@ template<int T> struct cl {
   const static int value = T;
 };
 
-template<int I> void fn (char (*) [cl<I>::value] = 0 ); // { dg-message "note" }
+template<int I> void fn (char (*) [cl<I>::value] = 0 ); // { dg-error "zero-size array" }
 
 void foo (void)
 {
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash60.C b/gcc/testsuite/g++.old-deja/g++.pt/crash60.C
index 1aad621..747af9b 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash60.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash60.C
@@ -7,7 +7,7 @@
 template< typename SID, class SDR >
 void k( SID sid, SDR* p,
  void (SDR::*)
- ( typename SID::T ) );		// { dg-message "note" }
+ ( typename SID::T ) );		// { dg-error "no type named 'T'" }
 
 struct E { };
 struct S { void f( int ); };
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C
index 0e5c034..a6f7674 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/unify6.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/unify6.C
@@ -19,7 +19,7 @@ template<> void fn<int &>() {} // ok, specialize A
 template<> void fn<void ()>() {} // ok, specialize A
 
 // now make sure we moan when we really should
-template<class T> void foo(T const *){} // { dg-message "note" }
+template<class T> void foo(T const *){} // { dg-error "pointer to reference" }
 
 void f()
 {

[-- Attachment #4: 45329-3.patch --]
[-- Type: text/x-patch, Size: 7071 bytes --]

commit b8ce4e6d5fd01abd939817fa2b5ad2088f0e4834
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Jul 13 22:58:28 2011 -0400

    gcc/cp/
    	* pt.c (tinst_level_tick, last_template_error_tick): Replace with
    	last_error_tinst_level.
    	(push_tinst_level, pop_tinst_level): Adjust.
    	(problematic_instantiation_changed): Adjust.
    	(record_last_problematic_instantiation): Adjust.
    	* error.c (cp_print_error_function): Don't print
    	current_function_decl if we're in a template instantiation context.
    	(print_instantiation_full_context): Always print first line.
    gcc/testsuite/
    	* lib/prune.exp (prune_gcc_output): Prune "In substitution" too.

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index b16fce6..2d7c0f1 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -2784,6 +2784,10 @@ static void
 cp_print_error_function (diagnostic_context *context,
 			 diagnostic_info *diagnostic)
 {
+  /* If we are in an instantiation context, current_function_decl is likely
+     to be wrong, so just rely on print_instantiation_full_context.  */
+  if (current_instantiation ())
+    return;
   if (diagnostic_last_function_changed (context, diagnostic))
     {
       const char *old_prefix = context->printer->prefix;
@@ -2927,26 +2931,15 @@ print_instantiation_full_context (diagnostic_context *context)
 
   if (p)
     {
-      if (current_function_decl != p->decl
-	  && current_function_decl != NULL_TREE)
-	/* We can get here during the processing of some synthesized
-	   method.  Then, P->DECL will be the function that's causing
-	   the synthesis.  */
-	;
-      else
-	{
-	  if (current_function_decl == p->decl)
-	    /* Avoid redundancy with the "In function" line.  */;
-	  else
-	    pp_verbatim (context->printer,
-			 _("%s: In instantiation of %qs:\n"),
-			 LOCATION_FILE (location),
-			 decl_as_string_translate (p->decl,
-						   TFF_DECL_SPECIFIERS | TFF_RETURN_TYPE));
+      pp_verbatim (context->printer,
+		   TREE_CODE (p->decl) == TREE_LIST
+		   ? _("%s: In substitution of %qS:\n")
+		   : _("%s: In instantiation of %q#D:\n"),
+		   LOCATION_FILE (location),
+		   p->decl);
 
-	  location = p->locus;
-	  p = p->next;
-	}
+      location = p->locus;
+      p = p->next;
     }
 
   print_instantiation_partial_context (context, p, location);
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8136a99..1c2a062 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -7766,8 +7766,7 @@ extern int max_tinst_depth;
 #ifdef GATHER_STATISTICS
 int depth_reached;
 #endif
-static int tinst_level_tick;
-static int last_template_error_tick;
+static GTY(()) struct tinst_level *last_error_tinst_level;
 
 /* We're starting to instantiate D; record the template instantiation context
    for diagnostics and to restore it later.  */
@@ -7779,7 +7778,7 @@ push_tinst_level (tree d)
 
   if (tinst_depth >= max_tinst_depth)
     {
-      last_template_error_tick = tinst_level_tick;
+      last_error_tinst_level = current_tinst_level;
       if (TREE_CODE (d) == TREE_LIST)
 	error ("template instantiation depth exceeds maximum of %d (use "
 	       "-ftemplate-depth= to increase the maximum) substituting %qS",
@@ -7814,7 +7813,6 @@ push_tinst_level (tree d)
     depth_reached = tinst_depth;
 #endif
 
-  ++tinst_level_tick;
   return 1;
 }
 
@@ -7829,7 +7827,6 @@ pop_tinst_level (void)
   input_location = current_tinst_level->locus;
   current_tinst_level = current_tinst_level->next;
   --tinst_depth;
-  ++tinst_level_tick;
 }
 
 /* We're instantiating a deferred template; restore the template
@@ -13961,6 +13958,7 @@ deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
   static bool excessive_deduction_depth;
   static int deduction_depth;
   struct pending_template *old_last_pend = last_pending_template;
+  struct tinst_level *old_error_tinst = last_error_tinst_level;
 
   tree fntype = TREE_TYPE (fn);
   tree tinst;
@@ -13993,8 +13991,10 @@ deduction_tsubst_fntype (tree fn, tree targs, tsubst_flags_t complain)
     }
 
   pop_tinst_level ();
-  /* We can't free this if a pending_template entry is pointing at it.  */
-  if (last_pending_template == old_last_pend)
+  /* We can't free this if a pending_template entry or last_error_tinst_level
+     is pointing at it.  */
+  if (last_pending_template == old_last_pend
+      && last_error_tinst_level == old_error_tinst)
     ggc_free (tinst);
   return r;
 }
@@ -18564,14 +18564,14 @@ get_mostly_instantiated_function_type (tree decl)
 int
 problematic_instantiation_changed (void)
 {
-  return last_template_error_tick != tinst_level_tick;
+  return current_tinst_level != last_error_tinst_level;
 }
 
 /* Remember current template involved in diagnostics.  */
 void
 record_last_problematic_instantiation (void)
 {
-  last_template_error_tick = tinst_level_tick;
+  last_error_tinst_level = current_tinst_level;
 }
 
 struct tinst_level *
diff --git a/gcc/testsuite/lib/prune.exp b/gcc/testsuite/lib/prune.exp
index f5cbc4c..4683f93 100644
--- a/gcc/testsuite/lib/prune.exp
+++ b/gcc/testsuite/lib/prune.exp
@@ -20,7 +20,7 @@
 proc prune_gcc_output { text } {
     #send_user "Before:$text\n"
 
-    regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|program|subroutine|block-data)\[^\n\]*" $text "" text
+    regsub -all "(^|\n)(\[^\n\]*: )?In ((static member |lambda )?function|member|method|(copy )?constructor|destructor|instantiation|substitution|program|subroutine|block-data)\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*(: )?At (top level|global scope):\[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*:   (recursively )?required \[^\n\]*" $text "" text
     regsub -all "(^|\n)\[^\n\]*:   . skipping \[0-9\]* instantiation contexts \[^\n\]*" $text "" text
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc
index a56148a..a884d01 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/assign/shared_ptr_neg.cc
@@ -47,6 +47,6 @@ main()
   test01();
   return 0;
 }
-// { dg-error "In member function" "" { target *-*-* } 0 }
+// { dg-error "In instantiation" "" { target *-*-* } 0 }
 // { dg-error "cannot convert" "" { target *-*-* } 0 }
 // { dg-error "required from" "" { target *-*-* } 0 }
diff --git a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/shared_ptr_neg.cc b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/shared_ptr_neg.cc
index 8114531..ec41e5b 100644
--- a/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/shared_ptr_neg.cc
+++ b/libstdc++-v3/testsuite/tr1/2_general_utilities/shared_ptr/assign/shared_ptr_neg.cc
@@ -46,6 +46,6 @@ main()
   test01();
   return 0;
 }
-// { dg-error "In member function" "" { target *-*-* } 0 }
+// { dg-error "In instantiation" "" { target *-*-* } 0 }
 // { dg-error "cannot convert" "" { target *-*-* } 0 }
 // { dg-error "required from" "" { target *-*-* } 0 }

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [PATCH,c++] describe reasons for function template overload resolution failure
  2011-02-02 21:05 Nathan Froyd
@ 2011-02-15  3:34 ` Mark Mitchell
  0 siblings, 0 replies; 15+ messages in thread
From: Mark Mitchell @ 2011-02-15  3:34 UTC (permalink / raw)
  To: Nathan Froyd; +Cc: gcc-patches, libstdc++, jason

On 2/2/2011 1:05 PM, Nathan Froyd wrote:

> In my patch for PR 45329, diagnostics for overload resolution failure, I
> overlooked one very important class of failures: failures when dealing
> with overload candidates that are function templates.  Specifically, we
> ought to diagnose any reasons why template argument deduction failed.
> The patch below attempts to rectify that situation.  It's a bit big for
> stage 4; it'd be great if it went in to 4.6, but I expect this to go in
> for the 4.7 timeframe.  It's also not quite done, so I'd appreciate
> feedback on whether the idea and implementation are sound.

I think the idea is sound and the improved diagnostics valuable.

I do think that, though, this is 4.7 material -- it just doesn't seem
bug-fixy enough for 4.6.

> I chose to permit NULL unification_infos to be passed around; I think
> it'd be just as valid to require the unification_info to be non-NULL,
> though.

I don't have an opinion on this -- I think either way is perfectly
reasonable.  I guess, in general, requiring a non-NULL input is a bit
less error-prone, though, so I might tend that way.  A caller that
doesn't want the info can always just ignore the result...

Thank you,

-- 
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH,c++] describe reasons for function template overload resolution failure
@ 2011-02-02 21:05 Nathan Froyd
  2011-02-15  3:34 ` Mark Mitchell
  0 siblings, 1 reply; 15+ messages in thread
From: Nathan Froyd @ 2011-02-02 21:05 UTC (permalink / raw)
  To: gcc-patches, libstdc++; +Cc: jason, mark

[libstdc++@ included for wider C++ exposure]

In my patch for PR 45329, diagnostics for overload resolution failure, I
overlooked one very important class of failures: failures when dealing
with overload candidates that are function templates.  Specifically, we
ought to diagnose any reasons why template argument deduction failed.
The patch below attempts to rectify that situation.  It's a bit big for
stage 4; it'd be great if it went in to 4.6, but I expect this to go in
for the 4.7 timeframe.  It's also not quite done, so I'd appreciate
feedback on whether the idea and implementation are sound.

This patch is a simple extension of the idea from the original patch:
when we're attempting to do template argument deduction, we need to pass
around some structure ('struct unification_info' in the patch) in which
we can record success or failure, and the reason for that failure.  Once
we've got that information in hand, providing a diagnostic about the
failure reason is pretty straightforward.

As an example of what the patch provides, for the code below:

struct S {int x; int y;};
template<typename T>
int foo(T a, T b) {return a + b;}
template<typename T, typename T2>
int foo(T a, T2& b, T2 c) {return a + b;}
int foo(char*, S&);

int foo2(int x)
{
  S s={1,2};
  char c;
  foo(c, 2, c);
}

the compiler now says:

template-ex.C: In function 'int foo2(int)':
template-ex.C:12:14: error: no matching function for call to 'foo(char&, int, char&)'
template-ex.C:12:14: note: candidates are:
template-ex.C:3:17: note: template<class T> int foo(T, T)
template-ex.C:3:17: note:   deduced conflicting types for parameter 'T' ('char' and 'int')
template-ex.C:5:25: note: template<class T, class T2> int foo(T, T2&, T2)
template-ex.C:5:25: note:   deduced conflicting types for parameter 'T2' ('int' and 'char')
template-ex.C:6:5: note: int foo(char*, S&)
template-ex.C:6:5: note:   candidate expects 2 arguments, 3 provided

I chose to permit NULL unification_infos to be passed around; I think
it'd be just as valid to require the unification_info to be non-NULL,
though.

Conveniently enough, the patch causes very few testsuite regressions,
probably due to aggressive use of { dg-note "" } in the testsuite.

Comments?  Concerns?  Tricky overload cases the patch makes clearer (or
doesn't)?

-Nathan

gcc/cp/
	PR c++/45329
	* 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_template_weirdness): 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): 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/testuite/
	* g++.dg/overload/template5.C: New testcase.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 7d602b9..3f14e42 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -427,7 +427,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 {
@@ -455,6 +458,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;
 };
 
@@ -604,6 +609,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 *
@@ -2709,6 +2736,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'.  */
@@ -2754,14 +2784,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]:
 
@@ -2790,7 +2826,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)
@@ -2953,6 +2992,100 @@ 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_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.
 
@@ -2999,10 +3132,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);
@@ -3010,6 +3141,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 03951cf..4c25055 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6439,7 +6439,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 934dab8..93d6bee 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5003,6 +5003,112 @@ 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,
+  /* FIXME: placeholder until I grok template corner cases.  */
+  ur_template_weirdness
+};
+
+/* 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;
+  } u;
+};
+
 extern bool check_template_shadow		(tree);
 extern tree get_innermost_template_args		(tree, int);
 extern void maybe_begin_member_template_processing (tree);
@@ -5041,7 +5147,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 d59f32a..9b37d53 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);
@@ -5269,6 +5279,222 @@ 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_template_weirdness (struct unification_info *ui, tree parm, tree arg)
+{
+  return unify_mismatch_1 (ur_template_weirdness, 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;
+}
+
 /* 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
@@ -5290,7 +5516,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;
 
@@ -5605,7 +5832,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
@@ -5637,7 +5867,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)
@@ -5922,7 +6155,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;
@@ -6115,7 +6349,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;
 
@@ -6151,7 +6385,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;
@@ -6233,7 +6468,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; 
@@ -6276,7 +6511,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;
@@ -6378,7 +6614,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)
@@ -6441,7 +6677,7 @@ 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++;
@@ -6807,7 +7043,7 @@ lookup_template_class (tree d1,
       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)))
@@ -6880,7 +7116,7 @@ lookup_template_class (tree d1,
 					   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);
@@ -6914,7 +7150,7 @@ lookup_template_class (tree d1,
 				   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.  */
@@ -13577,7 +13813,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;
@@ -13617,7 +13854,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;
 
@@ -13679,7 +13916,8 @@ fn_type_unification (tree fn,
       processing_template_decl -= incomplete;
 
       if (fntype == error_mark_node)
-	return 1;
+	/* FIXME: this should be something different.  */
+	return unify_unknown (ui);
 
       /* Place the explicitly specified arguments in TARGS.  */
       for (i = NUM_TMPL_ARGS (converted_args); i--;)
@@ -13707,7 +13945,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);
 
   if (result == 0 && incomplete_argument_packs_p)
     {
@@ -13749,7 +13987,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:
@@ -13764,7 +14002,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_unknown (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
@@ -13779,7 +14017,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);
 	}
     }
 
@@ -13907,7 +14145,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;
@@ -13965,7 +14204,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.  */
@@ -13991,7 +14230,7 @@ type_unification_real (tree tparms,
 				  flags))
 	    continue;
 
-	  return 1;
+	  return unify_arg_conversion (ui, parm, type, arg);
 	}
 
       if (!TYPE_P (arg))
@@ -14007,15 +14246,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);
 	}
 
       {
@@ -14027,7 +14266,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;
       }
     }
@@ -14049,7 +14290,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.  */
@@ -14059,11 +14300,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)
     for (i = 0; i < ntparms; i++)
@@ -14099,9 +14349,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;
@@ -14135,14 +14385,14 @@ type_unification_real (tree tparms,
               continue;
             }
 
-	  return 2;
+	  return unify_failure (ui, tparm);
 	}
 #ifdef ENABLE_CHECKING
   if (!NON_DEFAULT_TEMPLATE_ARGS_COUNT (targs))
     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
@@ -14157,7 +14407,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;
@@ -14208,7 +14459,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;
@@ -14228,7 +14479,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);
@@ -14374,7 +14625,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;
@@ -14404,7 +14656,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
@@ -14442,7 +14694,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;
 
@@ -14485,7 +14738,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;
@@ -14499,7 +14752,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;
@@ -14515,7 +14769,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)
 	{
@@ -14616,6 +14871,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
@@ -14623,10 +14884,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);
@@ -14716,7 +14977,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;
@@ -14744,8 +15005,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);
           }
       }
 
@@ -14839,10 +15099,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)
@@ -14887,7 +15147,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;
@@ -14902,19 +15163,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. */
@@ -14933,7 +15194,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);
 
@@ -14942,7 +15203,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))
 	    {
@@ -14954,8 +15215,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
@@ -14967,7 +15227,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
@@ -14984,7 +15244,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))
@@ -15002,19 +15262,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);
@@ -15026,7 +15287,8 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 	   && TREE_CODE (tparm) != TYPE_DECL)
 	  || (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
 	      && TREE_CODE (tparm) != TEMPLATE_DECL))
-	return 1;
+	/* FIXME */
+	return unify_template_weirdness (ui, tparm, parm);
 
       if (TREE_CODE (parm) == BOUND_TEMPLATE_TEMPLATE_PARM)
 	{
@@ -15034,7 +15296,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 ur_template_weirdness;
 
 	  {
 	    tree parmvec = TYPE_TI_ARGS (parm);
@@ -15078,9 +15340,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_template_weirdness (ui, NULL_TREE, NULL_TREE);
 
 	    /* Deduce arguments T, i from TT<T> or TT<i>.
 	       We check each element of PARMVEC and ARGVEC individually
@@ -15099,15 +15362,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_template_weirdness (ui, targ, arg);
 
              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
@@ -15115,8 +15377,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_template_weirdness (ui, targ, arg);
 	  }
 	  arg = TYPE_TI_TEMPLATE (arg);
 
@@ -15130,9 +15392,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
 	{
@@ -15142,20 +15404,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
@@ -15165,7 +15427,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);
@@ -15175,27 +15437,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));
 
@@ -15203,6 +15466,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
@@ -15230,25 +15494,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_template_weirdness (ui, tparm, arg);
 
       /* If ARG is a parameter pack or an expansion, we cannot unify
 	 against it unless PARM is also a parameter pack.  */
       if ((template_parameter_pack_p (arg) || PACK_EXPANSION_P (arg))
 	  && !TEMPLATE_PARM_PARAMETER_PACK (parm))
-	return 1;
+	return unify_parameter_pack_mismatch (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
@@ -15261,13 +15525,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]
 
@@ -15285,21 +15549,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;
@@ -15355,11 +15619,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:
@@ -15369,16 +15633,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.  */
@@ -15387,8 +15651,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:
       {
@@ -15398,27 +15664,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))
@@ -15429,7 +15695,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)
 		{
@@ -15442,10 +15708,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)
@@ -15456,14 +15723,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_template_weirdness (ui, parm, arg);
 
 	  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:
@@ -15474,7 +15741,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,
@@ -15485,11 +15752,10 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
 		(UNIFY_ALLOW_NONE,
 		 TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (arg))),
 		 TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (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);
@@ -15501,7 +15767,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:
@@ -15514,11 +15780,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));
@@ -15530,28 +15796,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_template_weirdness (ui, parm, arg);
 
     case VAR_DECL:
       /* A non-type template parameter that is a variable should be a
@@ -15581,7 +15847,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);
 	      }
 	  }
 	  
@@ -15592,23 +15858,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_template_weirdness (ui, NULL_TREE, NULL_TREE);
 
         /* 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;
@@ -15617,11 +15884,11 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict)
     case DECLTYPE_TYPE:
       /* Cannot deduce anything from TYPEOF_TYPE or DECLTYPE_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:
       gcc_assert (EXPR_P (parm));
@@ -15647,11 +15914,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
 \f
 /* Note that DECL can be defined in this translation unit, if
    required.  */
@@ -15914,10 +16182,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.  */
@@ -15938,10 +16207,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.*/
@@ -15952,8 +16222,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
@@ -16143,7 +16417,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;
 
@@ -16167,7 +16441,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;
@@ -16209,7 +16483,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)
@@ -16446,7 +16720,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;
 
@@ -18910,8 +19184,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)
     {
       error ("unable to deduce %qT from %qE", type, init);
diff --git a/gcc/testsuite/g++.dg/overload/template5.C b/gcc/testsuite/g++.dg/overload/template5.C
new file mode 100644
index 0000000..263455b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/template5.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+
+template<typename T>
+int low(T a, T b, T c) { return a + b + c; } // { dg-message "expects 3 parameters, 2 provided" }
+
+template<typename T>
+int high(T a, T b, T c) { return a + b + c; } // { dg-message "expects 3 parameters, 4 provided" }
+
+int test (void)
+{
+  low (5, 6);			// { dg-error "no matching function" }
+  // { dg-message "candidate" "" { target *-*-* } 11 }
+  high (5, 6, 7, 8);		// { dg-error "no matching function" }
+  // { dg-message "candidate" "" { target *-*-* } 13 }
+}

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2011-07-17  2:30 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-05-10  6:36 [PATCH,c++] describe reasons for function template overload resolution failure Nathan Froyd
2011-05-10 23:29 ` Jason Merrill
2011-05-16 20:28   ` Nathan Froyd
2011-05-18 18:36     ` Jason Merrill
2011-05-18 20:04       ` Nathan Froyd
2011-05-18 20:34         ` Jason Merrill
2011-05-25 19:40           ` Nathan Froyd
2011-05-26 16:52             ` Jason Merrill
2011-05-26 20:53               ` Nathan Froyd
2011-05-27 20:23                 ` Jason Merrill
2011-05-28  0:44                   ` Nathan Froyd
2011-05-28 14:03                     ` Jason Merrill
2011-07-17  7:56                       ` Jason Merrill
  -- strict thread matches above, loose matches on Subject: below --
2011-02-02 21:05 Nathan Froyd
2011-02-15  3:34 ` Mark Mitchell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).