diff mbox

Improved diagnostics for casts and enums

Message ID tkrat.817619ca3943d33b@netcologne.de
State New
Headers show

Commit Message

Volker Reichelt April 27, 2017, 7:29 a.m. UTC
Hi,

the following two patches aim at improving GCC's diagnostics to help
the user to get rid of old-style casts. While old-style pointer casts
are really bad and need to be weeded out quickly, old-style casts between
arithmetic types are IMHO much more tolerable. The patches allow to
easily distinguish between those situations.

The first patch for cp_parser_cast_expression in parser.c just adds
the target type of the cast to the diagnostic (like in
maybe_warn_about_useless_cast in typeck.c).

The second patch for type_to_string in error.c tackles the problem
that the name of a type doesn't tell you if you have a class or just
a simple enum. Similar to adding "{aka 'int'}" to types that
are essentially integers, this patch adds "{enum}" to all
enumeration types (and adjusts two testcases accordingly).

Bootstrapped and regtested on x86_64-pc-linux-gnu.

OK for trunk (as two patches or as one)?

Regards,
Volker


2017-04-27  Volker Reichelt  <v.reichelt@netcologne.de>

	* parser.c (cp_parser_cast_expression): Add target type of cast to
	diagnostic.

===================================================================

Comments

Nathan Sidwell April 27, 2017, 11:38 a.m. UTC | #1
On 04/27/2017 03:29 AM, Volker Reichelt wrote:
> Hi,
> 
> the following two patches aim at improving GCC's diagnostics to help
> the user to get rid of old-style casts. While old-style pointer casts
> are really bad and need to be weeded out quickly, old-style casts between
> arithmetic types are IMHO much more tolerable. The patches allow to
> easily distinguish between those situations.
> 
> The first patch for cp_parser_cast_expression in parser.c just adds
> the target type of the cast to the diagnostic (like in
> maybe_warn_about_useless_cast in typeck.c).
> 
> The second patch for type_to_string in error.c tackles the problem
> that the name of a type doesn't tell you if you have a class or just
> a simple enum. Similar to adding "{aka 'int'}" to types that
> are essentially integers, this patch adds "{enum}" to all
> enumeration types (and adjusts two testcases accordingly).
> 
> Bootstrapped and regtested on x86_64-pc-linux-gnu.
> 
> OK for trunk (as two patches or as one)?

ok.  One commit is fine.

nathan
Martin Sebor April 27, 2017, 3:55 p.m. UTC | #2
On 04/27/2017 01:29 AM, Volker Reichelt wrote:
> Hi,
>
> the following two patches aim at improving GCC's diagnostics to help
> the user to get rid of old-style casts. While old-style pointer casts
> are really bad and need to be weeded out quickly, old-style casts between
> arithmetic types are IMHO much more tolerable. The patches allow to
> easily distinguish between those situations.

FWIW, it can be most helpful to include this sort of detail (and
similar) in diagnostics.  In the case of the C-style cast, besides
mentioning the type of the result, it might be even more helpful
to mention the type of the operand because unlike that of the
result, its type is not apparent from the cast itself.

>
> The first patch for cp_parser_cast_expression in parser.c just adds
> the target type of the cast to the diagnostic (like in
> maybe_warn_about_useless_cast in typeck.c).
>
> The second patch for type_to_string in error.c tackles the problem
> that the name of a type doesn't tell you if you have a class or just
> a simple enum. Similar to adding "{aka 'int'}" to types that
> are essentially integers, this patch adds "{enum}" to all
> enumeration types (and adjusts two testcases accordingly).

In the C front end %qT prints 'enum E' for an argument of
an enumerated type.  Is there some significance to having
the C++ front end print 'E { enum }' or can C++ be made
consistent?

Martin
Volker Reichelt April 28, 2017, 7:47 a.m. UTC | #3
On 27 Apr, Martin Sebor wrote:
> On 04/27/2017 01:29 AM, Volker Reichelt wrote:
>> Hi,
>>
>> the following two patches aim at improving GCC's diagnostics to help
>> the user to get rid of old-style casts. While old-style pointer casts
>> are really bad and need to be weeded out quickly, old-style casts between
>> arithmetic types are IMHO much more tolerable. The patches allow to
>> easily distinguish between those situations.
> 
> FWIW, it can be most helpful to include this sort of detail (and
> similar) in diagnostics.  In the case of the C-style cast, besides
> mentioning the type of the result, it might be even more helpful
> to mention the type of the operand because unlike that of the
> result, its type is not apparent from the cast itself.

In this particular case the operand is evaluated after the warning
message. So I couldn't include it in the message without fiddling
around with the logic. I was also afraid that the warning message would
become too long.

>> The first patch for cp_parser_cast_expression in parser.c just adds
>> the target type of the cast to the diagnostic (like in
>> maybe_warn_about_useless_cast in typeck.c).
>>
>> The second patch for type_to_string in error.c tackles the problem
>> that the name of a type doesn't tell you if you have a class or just
>> a simple enum. Similar to adding "{aka 'int'}" to types that
>> are essentially integers, this patch adds "{enum}" to all
>> enumeration types (and adjusts two testcases accordingly).
> 
> In the C front end %qT prints 'enum E' for an argument of
> an enumerated type.  Is there some significance to having
> the C++ front end print 'E { enum }' or can C++ be made
> consistent?
>
> Martin

Ah, good point! I was so focused on the '{aka ...}' thing that I didn't
see the obvious: I should have used %q#T instead of just %qT to get
the enum prefix with the type. Unfortunately, I already committed the
patch after Nathan's OK before seeing your message.

I'll prepare another patch this weekend to revert my error.c changes and
use %q#T for the warnings about old-style and useless casts mentioned
above.

Another thought just crossed my mind: Other users might find an
enum/class prefix helpful for different warnings. Right now they
would have to modify the compile to use %q#T instead of %qT.
Would it make sense to add a compiler option that sets the verbose
flag for cp_printer unconditionally? Or am I just unaware of existing
functionality?

Regards,
Volker
diff mbox

Patch

Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 247283)
+++ gcc/cp/parser.c	(working copy)
@@ -8763,7 +8763,8 @@ 
 		  && !in_system_header_at (input_location)
 		  && !VOID_TYPE_P (type)
 		  && current_lang_name != lang_name_c)
-		warning (OPT_Wold_style_cast, "use of old-style cast");
+		warning (OPT_Wold_style_cast,
+			 "use of old-style cast to %qT", type);
 
 	      /* Only type conversions to integral or enumeration types
 		 can be used in constant-expressions.  */
===================================================================

2017-04-27  Volker Reichelt  <v.reichelt@netcologne.de>

	* error.c (type_to_string): Add '{enum}' suffix to enumeration types.

Index: gcc/cp/error.c
===================================================================
--- gcc/cp/error.c	(revision 247283)
+++ gcc/cp/error.c	(working copy)
@@ -3134,6 +3134,10 @@ 
       if (len == aka_len && memcmp (p, p+aka_start, len) == 0)
 	p[len] = '\0';
     }
+
+  if (typ && TYPE_P (typ) && TREE_CODE (typ) == ENUMERAL_TYPE)
+    pp_string (cxx_pp, M_(" {enum}"));
+
   return pp_ggc_formatted_text (cxx_pp);
 }
 
===================================================================

2017-04-27  Volker Reichelt  <v.reichelt@netcologne.de>

	* g++.dg/cpp1z/direct-enum-init1.C: Adjust for more verbose enum
	diagnostics.
	* g++.dg/warn/pr12242.C: Likewise.

Index: gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C
===================================================================
--- gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C	(revision 247283)
+++ gcc/testsuite/g++.dg/cpp1z/direct-enum-init1.C	(working copy)
@@ -17,67 +17,67 @@ 
 void
 foo ()
 {
-  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
-  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
   C c1 { s };
-  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
-  D d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
+  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D {enum}'" }
+  D d2 { t };		// { dg-error "cannot convert 'T' to 'D {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
-  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
-  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D {enum}' in initialization" "" { target c++14_down } }
+  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D {enum}' in initialization" "" { target c++14_down } }
   D d5 { D(l) };
-  D d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
-  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  D d6 { G };		// { dg-error "cannot convert 'A {enum}' to 'D {enum}' in initialization" "" { target c++14_down } }
+  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
-  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" }
+  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
 
-  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
-  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target c++14_down } }
+  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
-  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
-  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' for argument" }
+  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E {enum}'" }
+  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
-  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" }
+  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
     ;
-  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B {enum}' in initialization" "" { target c++14_down } }
     ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
-  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
-  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
-  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B {enum}'" "" { target c++14_down } }
+  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
-  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
-  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
-  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
 }
 
 struct U
 {
-  U () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
-  U (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
+  U (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
   U (float) : e({ 6 }) {}// { dg-error "list-initializer for non-class type must not be parenthesized" }
-			// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target *-*-* } .-1 }
+			// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target *-*-* } .-1 }
   E e;
 };
 
 struct W
 {
-  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
-  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
-  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } }
+  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
+  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-1 }
-  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" }
+  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" }
 };
 
 template <int N>
@@ -84,54 +84,54 @@ 
 void
 foo2 ()
 {
-  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
-  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  A a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+  B b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
   C c1 { s };
-  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
-  D d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
+  D d1 { D(t) };	// { dg-error "invalid cast from type 'T' to type 'D {enum}'" }
+  D d2 { t };		// { dg-error "cannot convert 'T' to 'D {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
-  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
-  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  D d3 { 9 };		// { dg-error "cannot convert 'int' to 'D {enum}' in initialization" "" { target c++14_down } }
+  D d4 { l };		// { dg-error "cannot convert 'long int' to 'D {enum}' in initialization" "" { target c++14_down } }
   D d5 { D(l) };
-  D d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
-  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  D d6 { G };		// { dg-error "cannot convert 'A {enum}' to 'D {enum}' in initialization" "" { target c++14_down } }
+  E e1 { 5 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  E e2 { -1 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  E e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  E e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
-  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
-  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
-  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  B b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" }
+  C c2 = { C { 8 } };	// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  D *d7 = new D { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target c++14_down } }
+  E *e5 = new E { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
-  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
-  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  bar ({ 10 });		// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' for argument" }
+  bar (E { 9 });	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  V v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E {enum}'" }
+  V v2 = { E { 12 } };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  V v3 = { E { 5.0 } };	// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
-  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  V v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" }
+  if (B b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
     ;
-  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+  if (B b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B {enum}' in initialization" "" { target c++14_down } }
     ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
-  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
-  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
-  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  C c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  B b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B {enum}'" "" { target c++14_down } }
+  B b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
-  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+  C c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
-  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
-  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  C c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  C c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
 }
 
 template <int N>
 struct U2
 {
-  U2 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
-  U2 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U2 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
+  U2 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
   U2 (float) : e({ 6 }) {}
   E e;
@@ -140,11 +140,11 @@ 
 template <int N>
 struct W2
 {
-  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
-  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
-  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
+  A a { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" "" { target *-*-* } .-2 }
+  B b { 6 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } .-3 }
+  C c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C {enum}' in initialization" "" { target c++14_down } .-4 }
 			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
-  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+  D d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target *-*-* } .-6 }
 };
 
 template <typename H, typename I, typename J, typename K, typename L, typename M>
@@ -152,54 +152,54 @@ 
 foo3 ()
 {
   void bar3 (L);
-  H a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" }
-  I b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  H a1 { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+  I b1 { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
   J c1 { s };
-  K d1 { K(t) };	// { dg-error "invalid cast from type 'T' to type 'D'" }
-  K d2 { t };		// { dg-error "cannot convert 'T' to 'D' in initialization" "" { target c++14_down } }
-			// { dg-error "invalid cast from type 'T' to type 'D'" "" { target c++1z } .-1 }
-  K d3 { 9 };		// { dg-error "cannot convert 'int' to 'D' in initialization" "" { target c++14_down } }
-  K d4 { l };		// { dg-error "cannot convert 'long int' to 'D' in initialization" "" { target c++14_down } }
+  K d1 { K(t) };	// { dg-error "invalid cast from type 'T' to type 'D {enum}'" }
+  K d2 { t };		// { dg-error "cannot convert 'T' to 'D {enum}' in initialization" "" { target c++14_down } }
+			// { dg-error "invalid cast from type 'T' to type 'D {enum}'" "" { target c++1z } .-1 }
+  K d3 { 9 };		// { dg-error "cannot convert 'int' to 'D {enum}' in initialization" "" { target c++14_down } }
+  K d4 { l };		// { dg-error "cannot convert 'long int' to 'D {enum}' in initialization" "" { target c++14_down } }
   K d5 { K(l) };
-  K d6 { G };		// { dg-error "cannot convert 'A' to 'D' in initialization" "" { target c++14_down } }
-  L e1 { 5 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  L e2 { -1 };		// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
+  K d6 { G };		// { dg-error "cannot convert 'A {enum}' to 'D {enum}' in initialization" "" { target c++14_down } }
+  L e1 { 5 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  L e2 { -1 };		// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-1' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  L e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  L e3 { 5.0 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  L e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  L e4 { 5.2 };		// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.\[0-9]*e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  I b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B'" }
-  J c2 = { J { 8 } };	// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
-  K *d7 = new K { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target c++14_down } }
-  L *e5 = new L { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  I b2 = { 7 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" }
+  J c2 = { J { 8 } };	// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  K *d7 = new K { 9 };	// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target c++14_down } }
+  L *e5 = new L { -4 };	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '-4' from 'int' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  bar3 ({ 10 });	// { dg-error "cannot convert \[^\n\r]* to 'E' for argument" }
-  bar3 (E { 9 });	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  M v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E'" }
-  M v2 = { L { 12 } };	// { dg-error "cannot convert 'int' to 'E' in initialization" "" { target c++14_down } }
-  M v3 = { L { 5.0 } };	// { dg-error "cannot convert 'double' to 'E' in initialization" "" { target c++14_down } }
+  bar3 ({ 10 });	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' for argument" }
+  bar3 (E { 9 });	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  M v1 = { { 11 } };	// { dg-error "braces around scalar initializer for type 'E {enum}'" }
+  M v2 = { L { 12 } };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" "" { target c++14_down } }
+  M v3 = { L { 5.0 } };	// { dg-error "cannot convert 'double' to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
-  M v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E' in initialization" }
-  if (I b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  M v4 = { 13 };	// { dg-error "cannot convert 'int' to 'E {enum}' in initialization" }
+  if (I b3 { 5 })	// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
     ;
-  if (I b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B' in initialization" "" { target c++14_down } }
+  if (I b4 { 4.0 })	// { dg-error "cannot convert 'double' to 'B {enum}' in initialization" "" { target c++14_down } }
     ;			// { dg-error "narrowing conversion of '4.0e.0' from 'double' to 'short int' inside" "" { target c++1z } .-1 }
-  J c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C' in initialization" "" { target c++14_down } }
-  I b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B'" "" { target c++14_down } }
-  I b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } }
+  J c3 { 8L };		// { dg-error "cannot convert 'long int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  I b4 {short (c + 5)};	// { dg-error "invalid conversion from 'short int' to 'B {enum}'" "" { target c++14_down } }
+  I b5 {c + 5};		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of \[^\n\r]* from 'int' to 'short int' inside" "" { target c++1z } .-1 }
-  J c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C' in initialization" "" { target c++14_down } }
+  J c4 { ll };		// { dg-error "cannot convert 'long long int' to 'C {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of 'll' from 'long long int' to 'int' inside" "" { target c++1z } .-1 }
-  J c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C' in initialization" "" { target c++14_down } }
-  J c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C' in initialization" "" { target c++14_down } }
+  J c5 {short (c + 5)};	// { dg-error "cannot convert 'short int' to 'C {enum}' in initialization" "" { target c++14_down } }
+  J c6 {c + 5};		// { dg-error "cannot convert 'int' to 'C {enum}' in initialization" "" { target c++14_down } }
 }
 
 template <typename L>
 struct U3
 {
-  U3 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
-  U3 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E' in initialization" "" { target c++14_down } }
+  U3 () : e { 5 } {}	// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
+  U3 (int) : e { 5.0 } {}// { dg-error "cannot convert \[^\n\r]* to 'E {enum}' in initialization" "" { target c++14_down } }
 			// { dg-error "narrowing conversion of '5.0e.0' from 'double' to 'unsigned char' inside" "" { target c++1z } .-1 }
   U3 (float) : e({ 6 }) {}
   L e;
@@ -208,11 +208,11 @@ 
 template <typename H, typename I, typename J, typename K>
 struct W3
 {
-  H a { 5 };		// { dg-error "invalid conversion from 'int' to 'A'" "" { target *-*-* } .-2 }
-  I b { 6 };		// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-3 }
-  J c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-4 }
+  H a { 5 };		// { dg-error "invalid conversion from 'int' to 'A {enum}'" "" { target *-*-* } .-2 }
+  I b { 6 };		// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } .-3 }
+  J c { 3.0f };		// { dg-error "cannot convert \[^\n\r]* to 'C {enum}' in initialization" "" { target c++14_down } .-4 }
 			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-5 }
-  K d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-6 }
+  K d = { 7 };		// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target *-*-* } .-6 }
 };
 
 void
@@ -221,17 +221,17 @@ 
   foo2<0> ();
   U2<0> u20;
   U2<1> u21 (5);
-  W2<0> w2;		// { dg-error "invalid conversion from 'int' to 'A'" }
-			// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
-			// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
+  W2<0> w2;		// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+			// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } .-1 }
+			// { dg-error "cannot convert \[^\n\r]* to 'C {enum}' in initialization" "" { target c++14_down } .-2 }
 			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
-			// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+			// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target *-*-* } .-4 }
   foo3<A, B, C, D, E, V> ();
   U3<E> u30;
   U3<E> u31 (5);
-  W3<A, B, C, D> w3;	// { dg-error "invalid conversion from 'int' to 'A'" }
-			// { dg-error "invalid conversion from 'int' to 'B'" "" { target c++14_down } .-1 }
-			// { dg-error "cannot convert \[^\n\r]* to 'C' in initialization" "" { target c++14_down } .-2 }
+  W3<A, B, C, D> w3;	// { dg-error "invalid conversion from 'int' to 'A {enum}'" }
+			// { dg-error "invalid conversion from 'int' to 'B {enum}'" "" { target c++14_down } .-1 }
+			// { dg-error "cannot convert \[^\n\r]* to 'C {enum}' in initialization" "" { target c++14_down } .-2 }
 			// { dg-error "narrowing conversion of '3.0e.0f' from 'float' to 'int' inside" "" { target c++1z } .-3 }
-			// { dg-error "cannot convert \[^\n\r]* to 'D' in initialization" "" { target *-*-* } .-4 }
+			// { dg-error "cannot convert \[^\n\r]* to 'D {enum}' in initialization" "" { target *-*-* } .-4 }
 }
Index: gcc/testsuite/g++.dg/warn/pr12242.C
===================================================================
--- gcc/testsuite/g++.dg/warn/pr12242.C	(revision 247283)
+++ gcc/testsuite/g++.dg/warn/pr12242.C	(working copy)
@@ -10,14 +10,14 @@ 
   X x;
   Y y;
   
-  x = 10;  // { dg-warning "invalid conversion from .int. to .X." "invalid" }
+  x = 10;  // { dg-warning "invalid conversion from .int. to .X {enum}." "invalid" }
            // { dg-warning "unspecified" "unspecified" { target *-*-* } .-1 }
-  x = 1;   // { dg-warning "invalid conversion from .int. to .X." }
-  x = C;   // { dg-error "cannot convert .Y. to .X. in assignment" }  
-  x = D;   // { dg-error "cannot convert .Y. to .X. in assignment" }  
-  y = A;   // { dg-error "cannot convert .X. to .Y. in assignment" }  
-  x = y;   // { dg-error "cannot convert .Y. to .X. in assignment" }  
-  x = i;   // { dg-warning "invalid conversion from .int. to .X."  }
+  x = 1;   // { dg-warning "invalid conversion from .int. to .X {enum}." }
+  x = C;   // { dg-error "cannot convert .Y {enum}. to .X {enum}. in assignment" }  
+  x = D;   // { dg-error "cannot convert .Y {enum}. to .X {enum}. in assignment" }  
+  y = A;   // { dg-error "cannot convert .X {enum}. to .Y {enum}. in assignment" }  
+  x = y;   // { dg-error "cannot convert .Y {enum}. to .X {enum}. in assignment" }  
+  x = i;   // { dg-warning "invalid conversion from .int. to .X {enum}."  }
 }
 
 void foo ()