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

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

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

Yes, that would be a useful future enhancement.

Tested as before.  OK?

-Nathan

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

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

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


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