This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH,c++] describe reasons for function template overload resolution failure


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.
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
 
 /* 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 }
     }
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()
 {
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 }

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]