This patch adds a new warning -Wclass-conversion that is on by default, and
warns about conversion functions converting a class to the wrong type.  This
was under the -Wconversion umbrella, but we should warn about this by default.

It also makes the warning print the types in question.

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-09-19  Marek Polacek  <pola...@redhat.com>

        Add -Wclass-conversion.
        * c.opt (Wclass-conversion): New.

        * decl.c (grok_op_properties): Change a warning from -Wconversion to
        -Wclass-conversion.  Make it print the types.

        * doc/invoke.texi: Document -Wclass-conversion.

        * g++.dg/conversion/op4.C: Add dg-warning.
        * g++.dg/warn/Wclass-conversion1.C: New test.
        * g++.dg/warn/Wclass-conversion2.C: New test.
        * g++.dg/warn/Wconversion5.C: Remove file.
        * g++.dg/warn/conversion-function-1.C: Use -Wno-class-converison.
        * g++.old-deja/g++.bugs/900215_01.C: Adjust dg-warning.
        * g++.old-deja/g++.jason/conversion5.C: Likewise.

diff --git gcc/c-family/c.opt gcc/c-family/c.opt
index 092ec940d86..ea863f71e34 100644
--- gcc/c-family/c.opt
+++ gcc/c-family/c.opt
@@ -850,6 +850,10 @@ Wnon-template-friend
 C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning
 Warn when non-templatized friend functions are declared within a template.
 
+Wclass-conversion
+C++ ObjC++ Var(warn_class_conversion) Init(1) Warning
+Warn about user-defined conversions converting a class to the wrong type.
+
 Wclass-memaccess
 C++ ObjC++ Var(warn_class_memaccess) Warning LangEnabledBy(C++ ObjC++, Wall)
 Warn for unsafe raw memory writes to objects of class types.
diff --git gcc/cp/decl.c gcc/cp/decl.c
index 503b433cbd1..2d9d56ef6e1 100644
--- gcc/cp/decl.c
+++ gcc/cp/decl.c
@@ -13544,7 +13544,7 @@ grok_op_properties (tree decl, bool complain)
   /* Warn about conversion operators that will never be used.  */
   if (IDENTIFIER_CONV_OP_P (name)
       && ! DECL_TEMPLATE_INFO (decl)
-      && warn_conversion)
+      && warn_class_conversion)
     {
       tree t = TREE_TYPE (name);
       int ref = TYPE_REF_P (t);
@@ -13553,27 +13553,29 @@ grok_op_properties (tree decl, bool complain)
        t = TYPE_MAIN_VARIANT (TREE_TYPE (t));
 
       if (VOID_TYPE_P (t))
-       warning_at (loc, OPT_Wconversion, "conversion to void "
-                   "will never use a type conversion operator");
+       warning_at (loc, OPT_Wclass_conversion, "converting %qT to %<void%> "
+                   "will never use a type conversion operator", class_type);
       else if (class_type)
        {
          if (same_type_ignoring_top_level_qualifiers_p (t, class_type))
-           warning_at (loc, OPT_Wconversion,
+           warning_at (loc, OPT_Wclass_conversion,
                        ref
-                       ? G_("conversion to a reference to the same type "
+                       ? G_("converting %qT to a reference to the same type "
                             "will never use a type conversion operator")
-                       : G_("conversion to the same type "
-                            "will never use a type conversion operator"));
+                       : G_("converting %qT to the same type "
+                            "will never use a type conversion operator"),
+                       class_type);
          /* Don't force t to be complete here.  */
          else if (MAYBE_CLASS_TYPE_P (t)
                   && COMPLETE_TYPE_P (t)
                   && DERIVED_FROM_P (t, class_type))
-           warning_at (loc, OPT_Wconversion,
+           warning_at (loc, OPT_Wclass_conversion,
                        ref
-                       ? G_("conversion to a reference to a base class "
-                            "will never use a type conversion operator")
-                       : G_("conversion to a base class "
-                            "will never use a type conversion operator"));
+                       ? G_("converting %qT to a reference to a base class "
+                            "%qT will never use a type conversion operator")
+                       : G_("converting %qT to a base class %qT "
+                            "will never use a type conversion operator"),
+                       class_type, t);
        }
     }
 
diff --git gcc/doc/invoke.texi gcc/doc/invoke.texi
index 685c211e176..26f7031498d 100644
--- gcc/doc/invoke.texi
+++ gcc/doc/invoke.texi
@@ -237,6 +237,7 @@ in the following sections.
 -Weffc++  -Wstrict-null-sentinel  -Wtemplates @gol
 -Wno-non-template-friend  -Wold-style-cast @gol
 -Woverloaded-virtual  -Wno-pmf-conversions @gol
+-Wno-class-conversion  -Wno-terminate @gol
 -Wsign-promo  -Wvirtual-inheritance}
 
 @item Objective-C and Objective-C++ Language Options
@@ -3367,6 +3368,13 @@ use the STL.  One may also use using directives and 
qualified names.
 @opindex Wno-terminate
 Disable the warning about a throw-expression that will immediately
 result in a call to @code{terminate}.
+
+@item -Wno-class-conversion @r{(C++ and Objective-C++ only)}
+@opindex Wno-class-conversion
+@opindex Wclass-conversion
+Disable the warning about user-defined conversions converting a class to
+the wrong type, such as having a conversion function converting an
+object to the same type, to a base class of that type, or to void.
 @end table
 
 @node Objective-C and Objective-C++ Dialect Options
diff --git gcc/testsuite/g++.dg/conversion/op4.C 
gcc/testsuite/g++.dg/conversion/op4.C
index cb99a380b43..3fb850cb825 100644
--- gcc/testsuite/g++.dg/conversion/op4.C
+++ gcc/testsuite/g++.dg/conversion/op4.C
@@ -4,7 +4,7 @@
 struct X {
   int x;
   X (int i = 0) : x (i) {}
-  operator X& (void) const {
+  operator X& (void) const { // { dg-warning "will never use" }
     return *(new X);
   }
 };
diff --git gcc/testsuite/g++.dg/warn/Wclass-conversion1.C 
gcc/testsuite/g++.dg/warn/Wclass-conversion1.C
index e69de29bb2d..2599a53dbeb 100644
--- gcc/testsuite/g++.dg/warn/Wclass-conversion1.C
+++ gcc/testsuite/g++.dg/warn/Wclass-conversion1.C
@@ -0,0 +1,19 @@
+// PR c++/87357
+// { dg-do compile }
+
+struct B { };
+
+struct X : public B {
+  operator X(); // { dg-warning "3:converting .X. to the same type will never 
use a type conversion operator" }
+  operator X&(); // { dg-warning "3:converting .X. to a reference to the same 
type will never use a type conversion operator" }
+  operator X() const; // { dg-warning "3:converting .X. to the same type will 
never use a type conversion operator" }
+  operator const X(); // { dg-warning "3:converting .X. to the same type will 
never use a type conversion operator" }
+
+  operator B(); // { dg-warning "3:converting .X. to a base class .B. will 
never use a type conversion operator" }
+  operator B&(); // { dg-warning "3:converting .X. to a reference to a base 
class .B. will never use a type conversion operator" }
+  operator B() const; // { dg-warning "3:converting .X. to a base class .B. 
will never use a type conversion operator" }
+  operator const B(); // { dg-warning "3:converting .X. to a base class .const 
B. will never use a type conversion operator" }
+
+  operator void(); // { dg-warning "3:converting .X. to .void. will never use 
a type conversion operator" }
+  operator void() const; // { dg-warning "3:converting .X. to .void. will 
never use a type conversion operator" }
+};
diff --git gcc/testsuite/g++.dg/warn/Wclass-conversion2.C 
gcc/testsuite/g++.dg/warn/Wclass-conversion2.C
index e69de29bb2d..b6919f0bfea 100644
--- gcc/testsuite/g++.dg/warn/Wclass-conversion2.C
+++ gcc/testsuite/g++.dg/warn/Wclass-conversion2.C
@@ -0,0 +1,20 @@
+// PR c++/87357
+// { dg-do compile }
+// { dg-options "-Wno-class-conversion" }
+
+struct B { };
+
+struct X : public B {
+  operator X(); // { dg-bogus "3:converting .X. to the same type will never 
use a type conversion operator" }
+  operator X&(); // { dg-bogus "3:converting .X. to a reference to the same 
type will never use a type conversion operator" }
+  operator X() const; // { dg-bogus "3:converting .X. to the same type will 
never use a type conversion operator" }
+  operator const X(); // { dg-bogus "3:converting .X. to the same type will 
never use a type conversion operator" }
+
+  operator B(); // { dg-bogus "3:converting .X. to a base class .B. will never 
use a type conversion operator" }
+  operator B&(); // { dg-bogus "3:converting .X. to a reference to a base 
class .B. will never use a type conversion operator" }
+  operator B() const; // { dg-bogus "3:converting .X. to a base class .B. will 
never use a type conversion operator" }
+  operator const B(); // { dg-bogus "3:converting .X. to a base class .const 
B. will never use a type conversion operator" }
+
+  operator void(); // { dg-bogus "3:converting .X. to .void. will never use a 
type conversion operator" }
+  operator void() const; // { dg-bogus "3:converting .X. to .void. will never 
use a type conversion operator" }
+};
diff --git gcc/testsuite/g++.dg/warn/Wconversion5.C 
gcc/testsuite/g++.dg/warn/Wconversion5.C
deleted file mode 100644
index 00b1ddab188..00000000000
--- gcc/testsuite/g++.dg/warn/Wconversion5.C
+++ /dev/null
@@ -1,20 +0,0 @@
-// PR c++/87357
-// { dg-do compile }
-// { dg-options "-Wconversion" }
-
-struct B { };
-
-struct X : public B {
-  operator X(); // { dg-warning "3:conversion to the same type will never use 
a type conversion operator" }
-  operator X&(); // { dg-warning "3:conversion to a reference to the same type 
will never use a type conversion operator" }
-  operator X() const; // { dg-warning "3:conversion to the same type will 
never use a type conversion operator" }
-  operator const X(); // { dg-warning "3:conversion to the same type will 
never use a type conversion operator" }
-
-  operator B(); // { dg-warning "3:conversion to a base class will never use a 
type conversion operator" }
-  operator B&(); // { dg-warning "3:conversion to a reference to a base class 
will never use a type conversion operator" }
-  operator B() const; // { dg-warning "3:conversion to a base class will never 
use a type conversion operator" }
-  operator const B(); // { dg-warning "3:conversion to a base class will never 
use a type conversion operator" }
-
-  operator void(); // { dg-warning "3:conversion to void will never use a type 
conversion operator" }
-  operator void() const; // { dg-warning "3:conversion to void will never use 
a type conversion operator" }
-};
diff --git gcc/testsuite/g++.dg/warn/conversion-function-1.C 
gcc/testsuite/g++.dg/warn/conversion-function-1.C
index 878011cf328..890719b3477 100644
--- gcc/testsuite/g++.dg/warn/conversion-function-1.C
+++ gcc/testsuite/g++.dg/warn/conversion-function-1.C
@@ -1,6 +1,6 @@
 // Copyright (C) 2003 Free Software Foundation
 // Contributed by Gabriel Dos Reis <g...@integrable-solutions.net>
-// { dg-options "-Wno-conversion" }
+// { dg-options "-Wno-class-conversion" }
 
 struct A {
    operator A&();
diff --git gcc/testsuite/g++.old-deja/g++.bugs/900215_01.C 
gcc/testsuite/g++.old-deja/g++.bugs/900215_01.C
index 0cd9b321e3e..fd075685cec 100644
--- gcc/testsuite/g++.old-deja/g++.bugs/900215_01.C
+++ gcc/testsuite/g++.old-deja/g++.bugs/900215_01.C
@@ -24,7 +24,7 @@
 
 struct struct0 {
 
-  operator void ();  // { dg-warning "3:conversion to void will never use a 
type conversion operator" }
+  operator void ();  // { dg-warning "3:converting .struct0. to .void. will 
never use a type conversion operator" }
 };
 
 int exit_status = 1;
diff --git gcc/testsuite/g++.old-deja/g++.jason/conversion5.C 
gcc/testsuite/g++.old-deja/g++.jason/conversion5.C
index a9531a6d209..7f04de48378 100644
--- gcc/testsuite/g++.old-deja/g++.jason/conversion5.C
+++ gcc/testsuite/g++.old-deja/g++.jason/conversion5.C
@@ -3,7 +3,7 @@
 struct A { };
 struct B: public A {
   A a;
-  operator A () { return a; }  // { dg-warning "3:conversion to a base class 
will never use a type conversion operator" }
+  operator A () { return a; }  // { dg-warning "3:converting .B. to a base 
class .A. will never use a type conversion operator" }
 };
 void f (const A&);
 void g()

Reply via email to