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()