diff mbox

C++ PATCHes to improve overload resolution diagnostics

Message ID 53739E0F.6050806@redhat.com
State New
Headers show

Commit Message

Jason Merrill May 14, 2014, 4:47 p.m. UTC
When I was working on DR 1571, I noticed that our diagnostics weren't 
very helpful for reference bindings (BZ 20332/21631) so I set out to 
treat lvalue/rvalue mismatches and cv-qual loss as a bad conversion 
rather than no conversion.  As I worked on that I kept noticing other 
things that I could tweak to improve diagnostics:

We now explain what's wrong with near matches in overload resolution. 
As a result, I've changed to saying "candidate:" before every candidate 
to help users recognize when we're printing a new candidate rather than 
explanation of what was wrong with the previous one.

We now get information about near-matches even with -pedantic.

If we see ambiguous valid candidates, the diagnostic won't mention 
near-matches.  If we see a template candidate and ambiguous near-valid 
candidates, we will print all the candidates.

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

Comments

Jakub Jelinek May 15, 2014, 6:30 a.m. UTC | #1
On Wed, May 14, 2014 at 12:47:11PM -0400, Jason Merrill wrote:
> commit f770db5dce4328b831d3c3e50322366f3e7b927a
> Author: jason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
> Date:   Tue May 13 21:10:03 2014 +0000
> 
>     	* call.c (print_error_for_call_failure): Say "no match" rather
>     	than "ambiguous" if there were no strict matches.
>     	(build_new_method_call_1): Likewise.

I'm seeing recent:
+FAIL: obj-c++.dg/exceptions-3.mm -fgnu-runtime  (test for warnings, line 72)
+FAIL: obj-c++.dg/exceptions-5.mm -fgnu-runtime  (test for warnings, line 72)
regression, the /* { dg-message "candidates" "" { target *-*-* } 72 } */
doesn't match any longer, can it be related to this patch?

	Jakub
Manuel López-Ibáñez May 15, 2014, 10:34 a.m. UTC | #2
On 14 May 2014 18:47, Jason Merrill <jason@redhat.com> wrote:
> When I was working on DR 1571, I noticed that our diagnostics weren't very
> helpful for reference bindings (BZ 20332/21631) so I set out to treat
> lvalue/rvalue mismatches and cv-qual loss as a bad conversion rather than no
> conversion.  As I worked on that I kept noticing other things that I could
> tweak to improve diagnostics:
>
> We now explain what's wrong with near matches in overload resolution. As a
> result, I've changed to saying "candidate:" before every candidate to help
> users recognize when we're printing a new candidate rather than explanation
> of what was wrong with the previous one.
>
> We now get information about near-matches even with -pedantic.
>
> If we see ambiguous valid candidates, the diagnostic won't mention
> near-matches.  If we see a template candidate and ambiguous near-valid
> candidates, we will print all the candidates.
>
> Tested x86_64-pc-linux-gnu, applying to trunk.

This looks great. One minor nit: In this hunk, what is input_location
pointing at and why is that better than loc?

@@ -3195,18 +3217,37 @@ equal_functions (tree fn1, tree fn2)
 static void
 print_conversion_rejection (location_t loc, struct conversion_info *info)
 {
+  tree from = info->from;
+  if (!TYPE_P (from))
+    from = lvalue_type (from);
   if (info->n_arg == -1)
-    /* Conversion of implicit `this' argument failed.  */
-    inform (loc, "  no known conversion for implicit "
-        "%<this%> parameter from %qT to %qT",
-        info->from_type, info->to_type);
+    {
+      /* Conversion of implicit `this' argument failed.  */
+      if (!TYPE_P (info->from))
+    /* A bad conversion for 'this' must be discarding cv-quals.  */
+    inform (input_location, "  passing %qT as %<this%> "
+        "argument discards qualifiers",
+        from);
+      else
+    inform (loc, "  no known conversion for implicit "
+        "%<this%> parameter from %qT to %qT",
+        from, info->to_type);
+    }
+  else if (!TYPE_P (info->from))
+    {
+      if (info->n_arg >= 0)
+    inform (loc, "  conversion of argument %d would be ill-formed:",
+        info->n_arg+1);
+      perform_implicit_conversion (info->to_type, info->from,
+                   tf_warning_or_error);
+    }
   else if (info->n_arg == -2)
     /* Conversion of conversion function return value failed.  */
     inform (loc, "  no known conversion from %qT to %qT",
-        info->from_type, info->to_type);
+        from, info->to_type);
   else
     inform (loc, "  no known conversion for argument %d from %qT to %qT",
-        info->n_arg+1, info->from_type, info->to_type);
+        info->n_arg+1, from, info->to_type);


And too few spaces around '+'.

Also, are there other qualifiers of 'this' besides 'const'?

Cheers,

Manuel.
Jason Merrill May 15, 2014, 12:01 p.m. UTC | #3
On 05/15/2014 06:34 AM, Manuel López-Ibáñez wrote:
> This looks great. One minor nit: In this hunk, what is input_location
> pointing at and why is that better than loc?

Oops, cut/paste error, thanks.

> Also, are there other qualifiers of 'this' besides 'const'?

An object can also be 'volatile'.

Jason
diff mbox

Patch

commit fbe3c5abf8d5baabca24ceb579d5991c91693e08
Author: Jason Merrill <jason@redhat.com>
Date:   Tue Apr 15 10:46:04 2014 -0400

    	PR c++/20332
    	PR c++/21631
    	* call.c (reference_binding): Treat lvalue/rvalue mismatch and
    	dropped cv-quals as a bad conversion.
    	(convert_like_real) [ck_ref_bind]: Explain them.
    	(compare_ics): Check badness before stripping reference
    	bindings.  Handle comparing bad reference bindings.
    	* typeck.c (comp_cv_qualification): Add overload that just takes
    	integers.
    	* cp-tree.h: Declare it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 1d9a15c..23fad8f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1540,15 +1540,11 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
      [8.5.3/5 dcl.init.ref] is changed to also require direct bindings for
      const and rvalue references to rvalues of compatible class type.
      We should also do direct bindings for non-class xvalues.  */
-  if (compatible_p
-      && (is_lvalue
-	  || (((CP_TYPE_CONST_NON_VOLATILE_P (to)
-		&& !(flags & LOOKUP_NO_RVAL_BIND))
-	       || TYPE_REF_IS_RVALUE (rto))
-	      && (gl_kind
-		  || (!(flags & LOOKUP_NO_TEMP_BIND)
-		      && (CLASS_TYPE_P (from)
-			  || TREE_CODE (from) == ARRAY_TYPE))))))
+  if (related_p
+      && (gl_kind
+	  || (!(flags & LOOKUP_NO_TEMP_BIND)
+	      && (CLASS_TYPE_P (from)
+		  || TREE_CODE (from) == ARRAY_TYPE))))
     {
       /* [dcl.init.ref]
 
@@ -1603,6 +1599,16 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
           && !(flags & LOOKUP_PREFER_RVALUE))
 	conv->bad_p = true;
 
+      /* Nor the reverse.  */
+      if (!is_lvalue && !TYPE_REF_IS_RVALUE (rto)
+	  && (!CP_TYPE_CONST_NON_VOLATILE_P (to)
+	      || (flags & LOOKUP_NO_RVAL_BIND))
+	  && TREE_CODE (to) != FUNCTION_TYPE)
+	conv->bad_p = true;
+
+      if (!compatible_p)
+	conv->bad_p = true;
+
       return conv;
     }
   /* [class.conv.fct] A conversion function is never used to convert a
@@ -1647,24 +1653,6 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
      difference in top-level cv-qualification is subsumed by the
      initialization itself and does not constitute a conversion.  */
 
-  /* [dcl.init.ref]
-
-     Otherwise, the reference shall be an lvalue reference to a
-     non-volatile const type, or the reference shall be an rvalue
-     reference.  */
-  if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
-    return NULL;
-
-  /* [dcl.init.ref]
-
-     Otherwise, a temporary of type "cv1 T1" is created and
-     initialized from the initializer expression using the rules for a
-     non-reference copy initialization.  If T1 is reference-related to
-     T2, cv1 must be the same cv-qualification as, or greater
-     cv-qualification than, cv2; otherwise, the program is ill-formed.  */
-  if (related_p && !at_least_as_qualified_p (to, from))
-    return NULL;
-
   /* We're generating a temporary now, but don't bind any more in the
      conversion (specifically, don't slice the temporary returned by a
      conversion operator).  */
@@ -1710,6 +1698,24 @@  reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags,
   conv->need_temporary_p = true;
   conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto);
 
+  /* [dcl.init.ref]
+
+     Otherwise, the reference shall be an lvalue reference to a
+     non-volatile const type, or the reference shall be an rvalue
+     reference.  */
+  if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
+    conv->bad_p = true;
+
+  /* [dcl.init.ref]
+
+     Otherwise, a temporary of type "cv1 T1" is created and
+     initialized from the initializer expression using the rules for a
+     non-reference copy initialization.  If T1 is reference-related to
+     T2, cv1 must be the same cv-qualification as, or greater
+     cv-qualification than, cv2; otherwise, the program is ill-formed.  */
+  if (related_p && !at_least_as_qualified_p (to, from))
+    conv->bad_p = true;
+
   return conv;
 }
 
@@ -6334,12 +6340,20 @@  convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
 	if (convs->bad_p && !next_conversion (convs)->bad_p)
 	  {
-	    gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
-			&& (real_lvalue_p (expr)
-			    || next_conversion(convs)->kind == ck_rvalue));
-
-	    error_at (loc, "cannot bind %qT lvalue to %qT",
-		      TREE_TYPE (expr), totype);
+	    tree extype = TREE_TYPE (expr);
+	    if (TYPE_REF_IS_RVALUE (ref_type)
+		&& real_lvalue_p (expr))
+	      error_at (loc, "cannot bind %qT lvalue to %qT",
+			extype, totype);
+	    else if (!TYPE_REF_IS_RVALUE (ref_type) && !real_lvalue_p (expr)
+		     && !CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (ref_type)))
+	      error_at (loc, "invalid initialization of non-const reference of "
+			"type %qT from an rvalue of type %qT", totype, extype);
+	    else if (!reference_compatible_p (TREE_TYPE (totype), extype))
+	      error_at (loc, "binding %qT to reference of type %qT "
+			"discards qualifiers", extype, totype);
+	    else
+	      gcc_unreachable ();
 	    maybe_print_user_conv_context (convs);
 	    if (fn)
 	      inform (input_location,
@@ -8230,6 +8244,12 @@  compare_ics (conversion *ics1, conversion *ics2)
   conversion *ref_conv1;
   conversion *ref_conv2;
 
+  /* Compare badness before stripping the reference conversion.  */
+  if (ics1->bad_p > ics2->bad_p)
+    return -1;
+  else if (ics1->bad_p < ics2->bad_p)
+    return 1;
+
   /* Handle implicit object parameters.  */
   maybe_handle_implicit_object (&ics1);
   maybe_handle_implicit_object (&ics2);
@@ -8258,31 +8278,19 @@  compare_ics (conversion *ics1, conversion *ics2)
      --a user-defined conversion sequence (_over.ics.user_) is a
        better conversion sequence than an ellipsis conversion sequence
        (_over.ics.ellipsis_).  */
-  rank1 = CONVERSION_RANK (ics1);
-  rank2 = CONVERSION_RANK (ics2);
+  /* Use BAD_CONVERSION_RANK because we already checked for a badness
+     mismatch.  If both ICS are bad, we try to make a decision based on
+     what would have happened if they'd been good.  This is not an
+     extension, we'll still give an error when we build up the call; this
+     just helps us give a more helpful error message.  */
+  rank1 = BAD_CONVERSION_RANK (ics1);
+  rank2 = BAD_CONVERSION_RANK (ics2);
 
   if (rank1 > rank2)
     return -1;
   else if (rank1 < rank2)
     return 1;
 
-  if (rank1 == cr_bad)
-    {
-      /* Both ICS are bad.  We try to make a decision based on what would
-	 have happened if they'd been good.  This is not an extension,
-	 we'll still give an error when we build up the call; this just
-	 helps us give a more helpful error message.  */
-      rank1 = BAD_CONVERSION_RANK (ics1);
-      rank2 = BAD_CONVERSION_RANK (ics2);
-
-      if (rank1 > rank2)
-	return -1;
-      else if (rank1 < rank2)
-	return 1;
-
-      /* We couldn't make up our minds; try to figure it out below.  */
-    }
-
   if (ics1->ellipsis_p)
     /* Both conversions are ellipsis conversions.  */
     return 0;
@@ -8602,13 +8610,30 @@  compare_ics (conversion *ics1, conversion *ics2)
 	      || (TYPE_REF_IS_RVALUE (ref_conv1->type)
 		  != TYPE_REF_IS_RVALUE (ref_conv2->type))))
 	{
+	  if (ref_conv1->bad_p
+	      && !same_type_p (TREE_TYPE (ref_conv1->type),
+			       TREE_TYPE (ref_conv2->type)))
+	    /* Don't prefer a bad conversion that drops cv-quals to a bad
+	       conversion with the wrong rvalueness.  */
+	    return 0;
 	  return (ref_conv1->rvaluedness_matches_p
 		  - ref_conv2->rvaluedness_matches_p);
 	}
 
       if (same_type_ignoring_top_level_qualifiers_p (to_type1, to_type2))
-	return comp_cv_qualification (TREE_TYPE (ref_conv2->type),
-				      TREE_TYPE (ref_conv1->type));
+	{
+	  int q1 = cp_type_quals (TREE_TYPE (ref_conv1->type));
+	  int q2 = cp_type_quals (TREE_TYPE (ref_conv2->type));
+	  if (ref_conv1->bad_p)
+	    {
+	      /* Prefer the one that drops fewer cv-quals.  */
+	      tree ftype = next_conversion (ref_conv1)->type;
+	      int fquals = cp_type_quals (ftype);
+	      q1 ^= fquals;
+	      q2 ^= fquals;
+	    }
+	  return comp_cv_qualification (q2, q1);
+	}
     }
 
   /* Neither conversion sequence is better than the other.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index ed8d099..f3788a7 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6034,6 +6034,7 @@  extern bool comptypes				(tree, tree, int);
 extern bool same_type_ignoring_top_level_qualifiers_p (tree, tree);
 extern bool compparms				(const_tree, const_tree);
 extern int comp_cv_qualification		(const_tree, const_tree);
+extern int comp_cv_qualification		(int, int);
 extern int comp_cv_qual_signature		(tree, tree);
 extern tree cxx_sizeof_or_alignof_expr		(tree, enum tree_code, bool);
 extern tree cxx_sizeof_or_alignof_type		(tree, enum tree_code, bool);
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index b933b96..7420da4 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1452,11 +1452,8 @@  at_least_as_qualified_p (const_tree type1, const_tree type2)
    more cv-qualified that TYPE1, and 0 otherwise.  */
 
 int
-comp_cv_qualification (const_tree type1, const_tree type2)
+comp_cv_qualification (int q1, int q2)
 {
-  int q1 = cp_type_quals (type1);
-  int q2 = cp_type_quals (type2);
-
   if (q1 == q2)
     return 0;
 
@@ -1468,6 +1465,14 @@  comp_cv_qualification (const_tree type1, const_tree type2)
   return 0;
 }
 
+int
+comp_cv_qualification (const_tree type1, const_tree type2)
+{
+  int q1 = cp_type_quals (type1);
+  int q2 = cp_type_quals (type2);
+  return comp_cv_qualification (q1, q2);
+}
+
 /* Returns 1 if the cv-qualification signature of TYPE1 is a proper
    subset of the cv-qualification signature of TYPE2, and the types
    are similar.  Returns -1 if the other way 'round, and 0 otherwise.  */
diff --git a/gcc/testsuite/g++.dg/conversion/op4.C b/gcc/testsuite/g++.dg/conversion/op4.C
index 7ef4b6a..cb99a38 100644
--- a/gcc/testsuite/g++.dg/conversion/op4.C
+++ b/gcc/testsuite/g++.dg/conversion/op4.C
@@ -9,11 +9,11 @@  struct X {
   }
 };
 
-void add_one (X & ref) { /* { dg-message "in passing argument" } */
+void add_one (X & ref) { /* { dg-message "argument" } */
   ++ ref.x;
 }
 
 void foo() {
   X const a (2);
-  add_one(a); /* { dg-error "invalid initialization of reference of type" } */
+  add_one(a); /* { dg-error "discards qualifiers" } */
 }
diff --git a/gcc/testsuite/g++.dg/cpp0x/diag2.C b/gcc/testsuite/g++.dg/cpp0x/diag2.C
new file mode 100644
index 0000000..0d01b1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/diag2.C
@@ -0,0 +1,19 @@ 
+// { dg-do compile { target c++11 } }
+
+struct A {};
+
+// We shouldn't arbitarily choose which of these is better.
+void f (A&);
+void f (const A&&);
+
+// But do prefer the lvalue overload here.
+void g (A&);
+void g (A&&);
+int main()
+{
+  const A a;
+  f(a);				// { dg-error "no match" }
+  // { dg-error "qualifiers" "" { target *-*-* } 15 }
+  // { dg-error "lvalue" "" { target *-*-* } 15 }
+  g(a);				// { dg-error "qualifiers" }
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/overloadn.C b/gcc/testsuite/g++.dg/cpp0x/overloadn.C
index 16c39a9..243f83b 100644
--- a/gcc/testsuite/g++.dg/cpp0x/overloadn.C
+++ b/gcc/testsuite/g++.dg/cpp0x/overloadn.C
@@ -543,9 +543,9 @@  void ucr1111(const S&&) {}
 
 int main()
 {
-  l0001(l); // { dg-error "lvalue" }
-  l0010(l); // { dg-error "lvalue" }
-  l0011(l); // { dg-error "lvalue" }
+  l0001(l); // { dg-error "" }
+  l0010(l); // { dg-error "" }
+  l0011(l); // { dg-error "" }
   l0100(l);
   l0101(l);
   l0110(l);
@@ -564,8 +564,8 @@  int main()
   cl0101(cl);
   cl0110(cl);
   cl0111(cl);
-  cl1001(cl); // { dg-error "lvalue" }
-  cl1011(cl); // { dg-error "lvalue" }
+  cl1001(cl); // { dg-error "" }
+  cl1011(cl); // { dg-error "" }
   cl1100(cl);
   cl1101(cl);
   cl1110(cl);
@@ -617,8 +617,8 @@  int main()
   ncl0101(ncl);
   ncl0110(ncl);
   ncl0111(ncl);
-  ncl1001(ncl); // { dg-error "lvalue" }
-  ncl1011(ncl); // { dg-error "lvalue" }
+  ncl1001(ncl); // { dg-error "" }
+  ncl1011(ncl); // { dg-error "" }
   ncl1100(ncl);
   ncl1101(ncl);
   ncl1110(ncl);
@@ -644,8 +644,8 @@  int main()
   ncr0101(ncr);
   ncr0110(ncr);
   ncr0111(ncr);
-  ncr1001(ncr); // { dg-error "lvalue" }
-  ncr1011(ncr); // { dg-error "lvalue" }
+  ncr1001(ncr); // { dg-error "" }
+  ncr1011(ncr); // { dg-error "" }
   ncr1100(ncr);
   ncr1101(ncr);
   ncr1110(ncr);
@@ -671,8 +671,8 @@  int main()
   ucl0101(ucl());
   ucl0110(ucl());
   ucl0111(ucl());
-  ucl1001(ucl()); // { dg-error "lvalue" }
-  ucl1011(ucl()); // { dg-error "lvalue" }
+  ucl1001(ucl()); // { dg-error "" }
+  ucl1011(ucl()); // { dg-error "" }
   ucl1100(ucl());
   ucl1101(ucl());
   ucl1110(ucl());
diff --git a/gcc/testsuite/g++.dg/diagnostic/ref1.C b/gcc/testsuite/g++.dg/diagnostic/ref1.C
new file mode 100644
index 0000000..36368de
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ref1.C
@@ -0,0 +1,7 @@ 
+// PR c++/20332
+
+struct bar {};
+void foo1() {
+  bar& b = bar();		// { dg-error "rvalue" }
+}
+void foo(bar& b = bar()) {}	// { dg-error "rvalue" }
diff --git a/gcc/testsuite/g++.dg/diagnostic/ref2.C b/gcc/testsuite/g++.dg/diagnostic/ref2.C
new file mode 100644
index 0000000..ded35e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/diagnostic/ref2.C
@@ -0,0 +1,9 @@ 
+// PR c++/21631
+
+int f(int&);
+int f();
+
+int g(void)
+{
+  return f(1);			// { dg-error "rvalue" }
+}
diff --git a/gcc/testsuite/g++.dg/expr/cond9.C b/gcc/testsuite/g++.dg/expr/cond9.C
index e71a84b..b344c1f 100644
--- a/gcc/testsuite/g++.dg/expr/cond9.C
+++ b/gcc/testsuite/g++.dg/expr/cond9.C
@@ -1,10 +1,10 @@ 
 // PR c++/27666
 
 struct A { // { dg-message "A" }
-  A(int); // { dg-message "A" }
+  A(int);
 };
 
 void foo(volatile A a) { 
-  1 ? a : 0; // { dg-error "match|temporary" }
-  1 ? 0 : a; // { dg-error "match|temporary" }
+  1 ? a : 0; // { dg-error "qualifiers|lvalue|no match" }
+  1 ? 0 : a; // { dg-error "qualifiers|lvalue|no match" }
 } 
diff --git a/gcc/testsuite/g++.dg/init/synth2.C b/gcc/testsuite/g++.dg/init/synth2.C
index 9e8a08a..cc6cce0 100644
--- a/gcc/testsuite/g++.dg/init/synth2.C
+++ b/gcc/testsuite/g++.dg/init/synth2.C
@@ -1,7 +1,7 @@ 
 // PR c++/34180
 
 struct G {
-  G();				// { dg-message "" "candidate" }
+  G();
   G(G&);			// { dg-message "" "candidate" }
 };
 
diff --git a/gcc/testsuite/g++.dg/lookup/two-stage4.C b/gcc/testsuite/g++.dg/lookup/two-stage4.C
index bbb44af..7d97109 100644
--- a/gcc/testsuite/g++.dg/lookup/two-stage4.C
+++ b/gcc/testsuite/g++.dg/lookup/two-stage4.C
@@ -3,15 +3,15 @@ 
 
 template<class T> struct wrap {};
 
-template<typename T> bool& operator==(wrap<T>, wrap<T>);
+template<typename T> bool operator==(wrap<T>, wrap<T>);
 
 template<typename T>
 void g(T, wrap<wrap<int> > x)
 {
-  bool& b = x == x; // { dg-bogus "invalid initialization of reference" "" { xfail *-*-*} }
+  bool b = x == x; // { dg-bogus "" "" { xfail *-*-* } }
 }
 
-template<typename T> int& operator==(wrap<wrap<T> >, wrap<wrap<T> >);
+template<typename T> void operator==(wrap<wrap<T> >, wrap<wrap<T> >);
 
 void h()
 {
diff --git a/gcc/testsuite/g++.dg/overload/arg3.C b/gcc/testsuite/g++.dg/overload/arg3.C
index b4fd2b7..1684fcc 100644
--- a/gcc/testsuite/g++.dg/overload/arg3.C
+++ b/gcc/testsuite/g++.dg/overload/arg3.C
@@ -10,7 +10,7 @@  struct A {};
 
 struct B : A
 {
-  B(int); // { dg-message "B::B|no known conversion" "" }
+  B(int);
   B(B&);  // { dg-message "note" "" }
 };
 
@@ -18,5 +18,5 @@  void foo(B);			// { dg-message "initializing" }
 
 void bar()
 {
-  foo(0); // { dg-error "no matching function" "no matching" }
+  foo(0); // { dg-error "" }
 }
diff --git a/gcc/testsuite/g++.dg/overload/conv-op1.C b/gcc/testsuite/g++.dg/overload/conv-op1.C
index 6a63cba..cd8d9f4 100644
--- a/gcc/testsuite/g++.dg/overload/conv-op1.C
+++ b/gcc/testsuite/g++.dg/overload/conv-op1.C
@@ -11,7 +11,7 @@  void f()
 {
   const int i = 42;
   A()(i);			// { dg-message "<conversion>" }
+  // { dg-error "qualifiers" "" { target *-*-* } 13 }
 }
 
 // { dg-prune-output "no match" }
-// { dg-prune-output "candidate" }
diff --git a/gcc/testsuite/g++.dg/overload/copy1.C b/gcc/testsuite/g++.dg/overload/copy1.C
index f776a06..5c7922f 100644
--- a/gcc/testsuite/g++.dg/overload/copy1.C
+++ b/gcc/testsuite/g++.dg/overload/copy1.C
@@ -4,7 +4,7 @@  struct A;
 
 struct B
 {
-  B (A const &);		// { dg-message "note" }
+  B (A const &);
   B (B &);			// { dg-message "note" }
 };
 
@@ -16,5 +16,5 @@  struct A
 B
 f (B const& b)
 {
-  return b;			// { dg-error "matching" "matching" }
+  return b;			// { dg-error "" }
 }
diff --git a/gcc/testsuite/g++.dg/overload/volatile1.C b/gcc/testsuite/g++.dg/overload/volatile1.C
index 29f649f..0426b8f 100644
--- a/gcc/testsuite/g++.dg/overload/volatile1.C
+++ b/gcc/testsuite/g++.dg/overload/volatile1.C
@@ -1,5 +1,4 @@ 
 // PR c++/48118
-// { dg-prune-output "note" }
 
 struct A { };
 
@@ -9,6 +8,6 @@  void (*g)(A);
 int main()
 {
   volatile A a;
-  f(a);				// { dg-error "no match" }
-  g(a);				// { dg-error "no match" }
+  f(a);				// { dg-error "" }
+  g(a);				// { dg-error "" }
 }
diff --git a/gcc/testsuite/g++.dg/rtti/dyncast6.C b/gcc/testsuite/g++.dg/rtti/dyncast6.C
index a6329e9..bfbf511 100644
--- a/gcc/testsuite/g++.dg/rtti/dyncast6.C
+++ b/gcc/testsuite/g++.dg/rtti/dyncast6.C
@@ -38,19 +38,19 @@  void r()
   B b;
 
   A& a1 = dynamic_cast<A&>(b);
-  A& a2 = dynamic_cast<const A&>(b);                // { dg-error "invalid" }
-  A& a3 = dynamic_cast<volatile A&>(b);             // { dg-error "invalid" }
-  A& a4 = dynamic_cast<const volatile A&>(b);       // { dg-error "invalid" }
+  A& a2 = dynamic_cast<const A&>(b);                // { dg-error "" }
+  A& a3 = dynamic_cast<volatile A&>(b);             // { dg-error "" }
+  A& a4 = dynamic_cast<const volatile A&>(b);       // { dg-error "" }
 
   const A& ca1 = dynamic_cast<A&>(b);
   const A& ca2 = dynamic_cast<const A&>(b);
-  const A& ca3 = dynamic_cast<volatile A&>(b);       // { dg-error "invalid" }
-  const A& ca4 = dynamic_cast<const volatile A&>(b); // { dg-error "invalid" }
+  const A& ca3 = dynamic_cast<volatile A&>(b);       // { dg-error "" }
+  const A& ca4 = dynamic_cast<const volatile A&>(b); // { dg-error "" }
 
   volatile A& va1 = dynamic_cast<A&>(b);
-  volatile A& va2 = dynamic_cast<const A&>(b);       // { dg-error "invalid" }
+  volatile A& va2 = dynamic_cast<const A&>(b);       // { dg-error "" }
   volatile A& va3 = dynamic_cast<volatile A&>(b);
-  volatile A& va4 = dynamic_cast<const volatile A&>(b);// { dg-error "invalid" }
+  volatile A& va4 = dynamic_cast<const volatile A&>(b);// { dg-error "" }
 
   const volatile A& cva1 = dynamic_cast<A&>(b);
   const volatile A& cva2 = dynamic_cast<const A&>(b);
diff --git a/gcc/testsuite/g++.dg/template/copy1.C b/gcc/testsuite/g++.dg/template/copy1.C
index 6f5fa00..bf5a37c 100644
--- a/gcc/testsuite/g++.dg/template/copy1.C
+++ b/gcc/testsuite/g++.dg/template/copy1.C
@@ -6,9 +6,9 @@ 
 
 struct A
 {
-  A(A&); // { dg-message "note" }
-  template <class T> A(T); 	// { dg-message "note" }
+  A(A&);			// { dg-message "A::A" }
+  template <class T> A(T); 	// { dg-message "A::A" }
 };
 
-A a = 0; // { dg-error "no matching function" }
+A a = 0; // { dg-error "" }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.benjamin/15800-1.C b/gcc/testsuite/g++.old-deja/g++.benjamin/15800-1.C
index 88d829d..5f2fe10 100644
--- a/gcc/testsuite/g++.old-deja/g++.benjamin/15800-1.C
+++ b/gcc/testsuite/g++.old-deja/g++.benjamin/15800-1.C
@@ -12,6 +12,6 @@  extern panama dig();
 
 void foo() {
    panama obj;
-   obj = dig(); // { dg-error "no match" }
+   obj = dig(); // { dg-error "rvalue" }
 }
 
diff --git a/gcc/testsuite/g++.old-deja/g++.brendan/cvt3.C b/gcc/testsuite/g++.old-deja/g++.brendan/cvt3.C
index 79b0013..71c6866 100644
--- a/gcc/testsuite/g++.old-deja/g++.brendan/cvt3.C
+++ b/gcc/testsuite/g++.old-deja/g++.brendan/cvt3.C
@@ -44,5 +44,5 @@  public:
 void
 foo (bar yylval, bar *yyvsp)
 {
-  nnyacc::assign(yylval.valueList, yyvsp[0].valueList);// { dg-error "no matching" } 
+  nnyacc::assign(yylval.valueList, yyvsp[0].valueList);// { dg-error "no matching|rvalue" } 
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.bugs/900514_03.C b/gcc/testsuite/g++.old-deja/g++.bugs/900514_03.C
index 64223a4..0d3cb9b 100644
--- a/gcc/testsuite/g++.old-deja/g++.bugs/900514_03.C
+++ b/gcc/testsuite/g++.old-deja/g++.bugs/900514_03.C
@@ -71,8 +71,8 @@  void t_1_assignment ()
   t_1_st_1 t_1_st_1_obj1;
   t_1_st_1 t_1_st_1_obj2;
 
-  t_1_st_1_obj0 = t_1_st_0_obj0;			// { dg-error "no match" } 
-  t_1_st_1_obj1 = t_1_st_1 (t_1_st_0_obj0);		// { dg-error "no match" } 
+  t_1_st_1_obj0 = t_1_st_0_obj0;			// { dg-error "no match|conversion" } 
+  t_1_st_1_obj1 = t_1_st_1 (t_1_st_0_obj0);		// { dg-error "no match|rvalue" } 
 }
 
 void t_1_local_init ()
diff --git a/gcc/testsuite/g++.old-deja/g++.eh/ctor1.C b/gcc/testsuite/g++.old-deja/g++.eh/ctor1.C
index 898f9e2..9b4adaf 100644
--- a/gcc/testsuite/g++.old-deja/g++.eh/ctor1.C
+++ b/gcc/testsuite/g++.old-deja/g++.eh/ctor1.C
@@ -1,7 +1,7 @@ 
 // { dg-do assemble  }
 struct A
 {
-  A();				// { dg-message "A::A|candidate expects" } candidate
+  A();
   A(A&);			// { dg-message "A::A|no known conversion" } referenced below
 };
 
@@ -10,7 +10,7 @@  main ()
 {
   try
     {
-      throw A();		// { dg-error "no matching" "match" } can't copy
+      throw A();		// { dg-error "rvalue" "" } can't copy
 // { dg-error "thrown expression" "expr" { target *-*-* } 13 }
     }
   catch (...) { }
diff --git a/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C b/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C
index efd09fd..e557384 100644
--- a/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C
+++ b/gcc/testsuite/g++.old-deja/g++.jason/temporary2.C
@@ -2,7 +2,7 @@ 
 class X // Indentation has been done so to see the similarities.
 {
 public:
-  X() {}		  // { dg-message "note" } referenced below
+  X() {}
          X(X& x) {x.i=7;} // { dg-message "note" } Both functions modify the
   void bar(X& x) {x.i=7;} // { dg-message "note" } reference parameter x.
   int i;
@@ -12,6 +12,6 @@  X foo() { X x; return x; }
 
 int main() 
 {
-  X   x(foo()); // { dg-error "no match" } Compiler doesn't warn about temporary reference.
-  x.bar(foo()); // { dg-error "no match" } The same mistake is warned about in this case.
+  X   x(foo()); // { dg-error "rvalue" } Compiler doesn't warn about temporary reference.
+  x.bar(foo()); // { dg-error "rvalue" } The same mistake is warned about in this case.
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/cvt20.C b/gcc/testsuite/g++.old-deja/g++.law/cvt20.C
index 9389a10..f5c703b 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/cvt20.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/cvt20.C
@@ -9,7 +9,7 @@ 
 
 // Compiles fine with Sun CC 2.1
 
-void f(char *& x) // { dg-message "passing argument" }
+void f(const char *& x) // { dg-message "argument" }
 {
   x++;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/enum4.C b/gcc/testsuite/g++.old-deja/g++.law/enum4.C
index 2c36010..363f114 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/enum4.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/enum4.C
@@ -24,6 +24,6 @@  int main()
   Enum e = enumerator1;
   Struct s;
   int x = funct(e+1);// { dg-error "invalid" }
-  int y = s.getI(e+1);// { dg-error "match|conv" }
+  int y = s.getI(e+1);// { dg-error "invalid" }
   return x+y;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/init8.C b/gcc/testsuite/g++.old-deja/g++.law/init8.C
index 5ed619b..829dd9b 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/init8.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/init8.C
@@ -8,7 +8,7 @@ 
 
 
 const int ic = 1;
-void f(int& arg)  // { dg-message "passing argument 1" }
+void f(int& arg)  // { dg-message "argument 1" }
 {
         if (arg) ;
 }
@@ -16,7 +16,7 @@  const int& icr = ic;
 
 int main(void)
 {
-  f(icr);   // { dg-error "invalid initialization" }
+  f(icr);   // { dg-error "const" }
 
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.law/operators9.C b/gcc/testsuite/g++.old-deja/g++.law/operators9.C
index 6c37163..8d5b686d 100644
--- a/gcc/testsuite/g++.old-deja/g++.law/operators9.C
+++ b/gcc/testsuite/g++.old-deja/g++.law/operators9.C
@@ -16,5 +16,5 @@  public:
 void
 test(B &b1, const B &b2)
 {
-        b1 = b2;// { dg-error "match" }
+        b1 = b2;// { dg-error "const" }
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/net8.C b/gcc/testsuite/g++.old-deja/g++.mike/net8.C
index d1f6864..6c2cd7f 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/net8.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/net8.C
@@ -11,14 +11,14 @@  public:
   int bar;
 };
 
-void func(Base&);			// { dg-message "passing argument 1" } 
+void func(Base&);			// { dg-message "argument 1" }
 
 void func2(const Derived& d) {
-  func(d);				// { dg-error "invalid initialization" }
+  func(d);				// { dg-error "" }
 }
 
 void
-foo (int& a)				// { dg-message "in passing argument 1" } 
+foo (int& a)				// { dg-message "argument 1" }
 {
 }
 
@@ -27,6 +27,6 @@  int main ()
   int b;
   const int*const a = &b;
   *a = 10;				// { dg-error "read-only location" }
-  foo (*a);				// { dg-error "invalid initialization" }
+  foo (*a);				// { dg-error "qualifiers" }
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p1989.C b/gcc/testsuite/g++.old-deja/g++.mike/p1989.C
index 05b8b1c..376d1f5 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p1989.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p1989.C
@@ -196,7 +196,7 @@  Pix
 List_DLS<T>::search(const T& item) const
 {
     for (Pix x=this->first(); 0 != x; this->next(x)) {
-	if (item == this->operator()(x)) // { dg-error "match" } const subversion
+	if (item == this->operator()(x)) // { dg-error "qualifiers" } const subversion
 	    return x;
     }
     return 0;
@@ -485,8 +485,8 @@  class STRLIdentifier {
     char buf[10];
 };
 
-extern int operator==(vertex<STRLIdentifier*>&, vertex<STRLIdentifier*>&); // { dg-message "note" } const subversion
-extern int operator==(STRLIdentifier&, STRLIdentifier&); // { dg-message "note" } fn ref in err msg
+extern int operator==(vertex<STRLIdentifier*>&, vertex<STRLIdentifier*>&); // { dg-message "argument 1" } const subversion
+extern int operator==(STRLIdentifier&, STRLIdentifier&);
 
 extern int x(List_DLSp<STRLIdentifier *>);
 
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p2431.C b/gcc/testsuite/g++.old-deja/g++.mike/p2431.C
index bc272af..8a7ede6 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p2431.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p2431.C
@@ -18,6 +18,6 @@  class C
 	C()
 	{
 		B	b;
-		A a = b;// { dg-error "match" } 
+		A a = b;// { dg-error "rvalue" }
 	}
 };
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p438.C b/gcc/testsuite/g++.old-deja/g++.mike/p438.C
index 1975ebf..18f9267 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p438.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p438.C
@@ -19,5 +19,5 @@  void C::test() const
 {
    D d;
 
-   d.a(*this);	// { dg-error "match" } *this is const, so should get error
+   d.a(*this);	// { dg-error "const" } *this is const, so should get error
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p701.C b/gcc/testsuite/g++.old-deja/g++.mike/p701.C
index 8e9a345..99ef1f4 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p701.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p701.C
@@ -7,7 +7,7 @@  extern "C"
 }
 
 
-void Munge(int& x) 	// { dg-message "passing argument 1" }
+void Munge(int& x) 	// { dg-message "argument 1" }
 {
    x = 2;
 }
@@ -24,7 +24,7 @@  class A
 void
 A::Safe() const 
 {
-   Munge(i);	        // { dg-error "invalid initialization" }
+   Munge(i);	        // { dg-error "const" }
 }
 
 int main()
diff --git a/gcc/testsuite/g++.old-deja/g++.other/crash24.C b/gcc/testsuite/g++.old-deja/g++.other/crash24.C
index d2581f0..a4d655a 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/crash24.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/crash24.C
@@ -12,7 +12,7 @@  class foo {
 static void iteratorTest(const foo &x)
 {
    foo::const_iterator i = x.begin();		// { dg-error "incomplete type" "incomplete type" } 
-   // { dg-error "no matching|const foo" "no matching" { target *-*-* } 14 }
+   // { dg-error "const foo" "" { target *-*-* } 14 }
    for (; i; ++i)
       *i;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.other/volatile1.C b/gcc/testsuite/g++.old-deja/g++.other/volatile1.C
index 5c58728..7d818fb 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/volatile1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/volatile1.C
@@ -15,6 +15,6 @@  ret_v_f_class()
 int main(void)
 {
   volatile f_class vf;
-  0 ? ret_v_f_class() : vf;	// { dg-error "match" } can't copy volatile lvalue
+  0 ? ret_v_f_class() : vf;	// { dg-error "volatile" } can't copy volatile lvalue
   return 0;
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/auto_ptr.C b/gcc/testsuite/g++.old-deja/g++.pt/auto_ptr.C
index 08af5fb..4a363a2 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/auto_ptr.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/auto_ptr.C
@@ -11,7 +11,7 @@  template<typename X> struct auto_ptr {
    explicit auto_ptr(X* p =0) throw() : px(p) {}
    auto_ptr(auto_ptr& r) throw() : px(r.release()) {} // { dg-message "note" } candidate
    template<typename Y>
-      auto_ptr(auto_ptr<Y>& r) throw() : px(r.release()) {}// { dg-message "note" } candidate
+      auto_ptr(auto_ptr<Y>& r) throw() : px(r.release()) {}
 
    auto_ptr& operator=(auto_ptr& r) throw() { 
       reset(r.release()); 
@@ -30,7 +30,7 @@  template<typename X> struct auto_ptr {
    X* release() throw() { X* p=px; px=0; return p; }
    void reset(X* p=0) throw() { if (px != p) delete px, px = p; }
 
-   auto_ptr(auto_ptr_ref<X> r) throw() : px(r.py) {} // { dg-message "note" } 
+   auto_ptr(auto_ptr_ref<X> r) throw() : px(r.py) {}
    template<typename Y> operator auto_ptr_ref<Y>() throw() {
       return auto_ptr_ref<Y>(release()); 
    }
@@ -51,5 +51,5 @@  int main() {
     auto_ptr<Derived> y(f());
     x = y;
     g(f());
-    h(f());			// { dg-error "match" "match" } no usable copy ctor
+    h(f());			// { dg-error "rvalue" "" } no usable copy ctor
 }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/t05.C b/gcc/testsuite/g++.old-deja/g++.pt/t05.C
index 71fe958..f1eda15 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/t05.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/t05.C
@@ -1,9 +1,9 @@ 
 // { dg-do assemble  }
 
-template <class A> class B {    // { dg-message "note" } 
+template <class A> class B {
   A a;                          
  public:
   B(A&aa);			// { dg-message "note" }
   ~B();
 };
-static B<int> b_int (3);	// { dg-error "no matching function" } 
+static B<int> b_int (3);	// { dg-error "no match|rvalue" }
diff --git a/libstdc++-v3/testsuite/20_util/forward/1_neg.cc b/libstdc++-v3/testsuite/20_util/forward/1_neg.cc
index 06f7bcb..f34fc8a 100644
--- a/libstdc++-v3/testsuite/20_util/forward/1_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/forward/1_neg.cc
@@ -28,7 +28,7 @@  template<class T, class A1, class A2>
   factory(A1&& a1, A2&& a2)
   {
     return std::shared_ptr<T>(new T(std::forward<A1>(a1),
-				    std::forward<A2>(a2))); // { dg-error "no matching function" }
+				    std::forward<A2>(a2))); // { dg-error "rvalue" }
   }
 
 struct A