diff mbox series

C++ PATCH for c++/88136, -Wdeprecated-copy too noisy

Message ID CADzB+2nxjBAaig10w3-1sZEvAZpTMgWFPeSpF8EWknyzzx_x-Q@mail.gmail.com
State New
Headers show
Series C++ PATCH for c++/88136, -Wdeprecated-copy too noisy | expand

Commit Message

Jason Merrill Dec. 6, 2018, 9:11 p.m. UTC
-Wdeprecated-copy does find some real bugs, but it also complains
about a lot of reasonable code for which the implicitly declared copy
ctor/op= are fine oven though the class has a user-defined destructor:
this situation is only problematic if the destructor releases
resources held in one of the non-static data members.

So, this patch reins it in somewhat: first by moving from -Wall to
-Wextra, and then also only complaining if the other copy op is
user-declared.  The old behavior can be explicitly requested with
-Wdeprecated-copy-dtor.

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

Comments

Ville Voutilainen Dec. 8, 2018, 4:46 p.m. UTC | #1
On Thu, 6 Dec 2018 at 23:12, Jason Merrill <jason@redhat.com> wrote:
>
> -Wdeprecated-copy does find some real bugs, but it also complains
> about a lot of reasonable code for which the implicitly declared copy
> ctor/op= are fine oven though the class has a user-defined destructor:
> this situation is only problematic if the destructor releases
> resources held in one of the non-static data members.
>
> So, this patch reins it in somewhat: first by moving from -Wall to
> -Wextra, and then also only complaining if the other copy op is
> user-declared.  The old behavior can be explicitly requested with
> -Wdeprecated-copy-dtor.

Hmm.

g++ -c -pipe -O2 -fPIC -std=c++1z -fvisibility=hidden
-fvisibility-inlines-hidden -ffunction-sections -fdata-sections
-fno-exceptions -Wall -W -Wvla -Wdate-time -Wshift-overflow=2
-Wduplicated-cond -Wno-stringop-overflow -Werror -Wno-error=cpp
-Wno-error=deprecated-declarations -Wno-error=strict-overflow
-Wno-error=implicit-fallthrough -D_REENTRANT
-DQT_VERSION_STR='"5.12.0"' -DQT_VERSION_MAJOR=5 -DQT_VERSION_MINOR=12
-DQT_VERSION_PATCH=0 -DQT_BOOTSTRAPPED -DQT_NO_CAST_TO_ASCII
-DQT_NO_FOREACH -DQT_NO_CAST_FROM_ASCII
-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT -DQT_BUILD_BOOTSTRAP_LIB
-DQT_BUILDING_QT -DQT_ASCII_CAST_WARNINGS -DQT_MOC_COMPAT
-DQT_USE_QSTRINGBUILDER -DQT_DEPRECATED_WARNINGS
-DQT_DISABLE_DEPRECATED_BEFORE=0x050000 -DQT_NO_EXCEPTIONS
-D_LARGEFILE64_SOURCE -D_LARGEFILE_SOURCE -DQT_NO_DEBUG
-I/home/vivoutil/kuutti/qt5-5.12/qtbase/src/tools/bootstrap -I.
-I../../../include -I../../../include/QtCore
-I../../../include/QtCore/5.12.0
-I../../../include/QtCore/5.12.0/QtCore -I../../../include/QtXml
-I../../../include/QtXml/5.12.0 -I../../../include/QtXml/5.12.0/QtXml
-I/home/vivoutil/kuutti/qt5-5.12/qtbase/mkspecs/linux-g++ -o
.obj/qglobal.o /home/vivoutil/kuutti/qt5-5.12/qtbase/src/corelib/global/qglobal.cpp
In file included from ../../../include/QtCore/qvariant.h:1,
                 from
../../../include/QtCore/5.12.0/QtCore/private/../../../../../../../qtbase/src/corelib/tools/qlocale_p.h:58,
                 from
../../../include/QtCore/5.12.0/QtCore/private/../../../../../../../qtbase/src/corelib/tools/qlocale_tools_p.h:54,
                 from
../../../include/QtCore/5.12.0/QtCore/private/qlocale_tools_p.h:1,
                 from
/home/vivoutil/kuutti/qt5-5.12/qtbase/src/corelib/global/qglobal.cpp:52:
../../../include/QtCore/../../../../qtbase/src/corelib/kernel/qvariant.h:
In constructor ‘QVariant::QVariant(QVariant&&)’:
../../../include/QtCore/../../../../qtbase/src/corelib/kernel/qvariant.h:273:25:
error: implicitly-declared ‘constexpr QVariant::Private&
QVariant::Private::operator=(const QVariant::Private&)’ is deprecated
[-Werror=deprecated-copy]
  273 |     { other.d = Private(); }
      |                         ^
../../../include/QtCore/../../../../qtbase/src/corelib/kernel/qvariant.h:399:16:
note: because ‘QVariant::Private’ has user-provided
‘QVariant::Private::Private(const QVariant::Private&)’
  399 |         inline Private(const Private &other) Q_DECL_NOTHROW
      |                ^~~~~~~
cc1plus: all warnings being treated as errors

That doesn't have -Wextra. Yet the -Wdeprecated-copy still triggers.
Jakub Jelinek Dec. 8, 2018, 4:58 p.m. UTC | #2
On Sat, Dec 08, 2018 at 06:46:27PM +0200, Ville Voutilainen wrote:
> On Thu, 6 Dec 2018 at 23:12, Jason Merrill <jason@redhat.com> wrote:
> >
> > -Wdeprecated-copy does find some real bugs, but it also complains
> > about a lot of reasonable code for which the implicitly declared copy
> > ctor/op= are fine oven though the class has a user-defined destructor:
> > this situation is only problematic if the destructor releases
> > resources held in one of the non-static data members.
> >
> > So, this patch reins it in somewhat: first by moving from -Wall to
> > -Wextra, and then also only complaining if the other copy op is
> > user-declared.  The old behavior can be explicitly requested with
> > -Wdeprecated-copy-dtor.
> 
> Hmm.
> 
> g++ -c -pipe -O2 -fPIC -std=c++1z -fvisibility=hidden
> -fvisibility-inlines-hidden -ffunction-sections -fdata-sections
> -fno-exceptions -Wall -W -Wvla -Wdate-time -Wshift-overflow=2

-W is an alias to -Wextra.

> That doesn't have -Wextra. Yet the -Wdeprecated-copy still triggers.

	Jakub
Ville Voutilainen Dec. 8, 2018, 5:17 p.m. UTC | #3
On Sat, 8 Dec 2018 at 18:58, Jakub Jelinek <jakub@redhat.com> wrote:
> > g++ -c -pipe -O2 -fPIC -std=c++1z -fvisibility=hidden
> > -fvisibility-inlines-hidden -ffunction-sections -fdata-sections
> > -fno-exceptions -Wall -W -Wvla -Wdate-time -Wshift-overflow=2
>
> -W is an alias to -Wextra.

Yeah. Jason, I seem to have code that user-provides a copy constructor
(seemingly for no particular reason),
doesn't bother declaring a copy assignment operator, and still breaks
magnificently. :) There is no bug
in it; the assignment works as expected, so that's a false positive. I
am going to suggest taking this warning
out of -Wextra and making it completely separate for GCC 9.
Jason Merrill Dec. 8, 2018, 5:53 p.m. UTC | #4
On Sat, Dec 8, 2018 at 12:17 PM Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> On Sat, 8 Dec 2018 at 18:58, Jakub Jelinek <jakub@redhat.com> wrote:
> > > g++ -c -pipe -O2 -fPIC -std=c++1z -fvisibility=hidden
> > > -fvisibility-inlines-hidden -ffunction-sections -fdata-sections
> > > -fno-exceptions -Wall -W -Wvla -Wdate-time -Wshift-overflow=2
> >
> > -W is an alias to -Wextra.
>
> Yeah. Jason, I seem to have code that user-provides a copy constructor (seemingly for no particular reason),
> doesn't bother declaring a copy assignment operator, and still breaks magnificently. :) There is no bug
> in it; the assignment works as expected, so that's a false positive. I am going to suggest taking this warning
> out of -Wextra and making it completely separate for GCC 9.

The documented policy for -Wall is,

     This enables all the warnings about constructions that some users
     consider questionable, and that are easy to avoid (or modify to
     prevent the warning), even in conjunction with macros.
...
     Note that some warning flags are not implied by '-Wall'.  Some of
     them warn about constructions that users generally do not consider
     questionable, but which occasionally you might wish to check for;
     others warn about constructions that are necessary or hard to avoid
     in some cases, and there is no simple way to modify the code to
     suppress the warning.

It seems to me that this warning qualifies for -Wall under these
guidelines.  Providing a copy constructor without a matching
assignment operator is definitely suspect; the false positive only
comes in because, as you say, there was no good reason to provide the
copy constructor for Private.  And it's easy to avoid the warning by
declaring a defaulted assignment operator, if ABI concerns preclude
removing the constructor.

New compiler releases will usually include new warnings that require
some code modification to accommodate.  Why is this one particularly
problematic?

Jason
Ville Voutilainen Dec. 8, 2018, 6:05 p.m. UTC | #5
On Sat, 8 Dec 2018 at 19:53, Jason Merrill <jason@redhat.com> wrote:
> The documented policy for -Wall is,
>
>      This enables all the warnings about constructions that some users
>      consider questionable, and that are easy to avoid (or modify to
>      prevent the warning), even in conjunction with macros.
> ...
>      Note that some warning flags are not implied by '-Wall'.  Some of
>      them warn about constructions that users generally do not consider
>      questionable, but which occasionally you might wish to check for;
>      others warn about constructions that are necessary or hard to avoid
>      in some cases, and there is no simple way to modify the code to
>      suppress the warning.
>
> It seems to me that this warning qualifies for -Wall under these
> guidelines.  Providing a copy constructor without a matching
> assignment operator is definitely suspect; the false positive only
> comes in because, as you say, there was no good reason to provide the
> copy constructor for Private.  And it's easy to avoid the warning by
> declaring a defaulted assignment operator, if ABI concerns preclude
> removing the constructor.
>
> New compiler releases will usually include new warnings that require
> some code modification to accommodate.  Why is this one particularly
> problematic?

I don't think it's any more problematic than any other warning that
introduces new errors for fools that build with -Wall and -Werror.
But considering that those errors are false positives, and that
turning them off will in some cases require writing boiler-plate
(defaulted assignments), I would merely prefer having another release
round to get fixes for my codebase out in the wild.
Ville Voutilainen Dec. 8, 2018, 6:32 p.m. UTC | #6
On Sat, 8 Dec 2018 at 20:05, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:

> > New compiler releases will usually include new warnings that require
> > some code modification to accommodate.  Why is this one particularly
> > problematic?
>
> I don't think it's any more problematic than any other warning that
> introduces new errors for fools that build with -Wall and -Werror.
> But considering that those errors are false positives, and that
> turning them off will in some cases require writing boiler-plate
> (defaulted assignments), I would merely prefer having another release
> round to get fixes for my codebase out in the wild.

For what it's worth, I find it unfortunate that this deprecation and
its resulting warnings end up
making the decision on whether a "rule of 5" must be followed; correct
code needs to be adjusted
to cope with a fairly stylistic matter, with false positives and all.

I'll vote with my feet:

diff --git a/mkspecs/features/qt_common.prf b/mkspecs/features/qt_common.prf
index 4ad9946..3ba7eff 100644
--- a/mkspecs/features/qt_common.prf
+++ b/mkspecs/features/qt_common.prf
@@ -89,6 +89,8 @@ clang {
     greaterThan(QT_GCC_MAJOR_VERSION, 5): QMAKE_CXXFLAGS_WARN_ON +=
-Wshift-overflow=2 -Wduplicated-cond
     # GCC 7 has a lot of false positives relating to this, so disable
completely
     greaterThan(QT_GCC_MAJOR_VERSION, 6): QMAKE_CXXFLAGS_WARN_ON +=
-Wno-stringop-overflow
+    # GCC 9 has a lot of false positives relating to this, so disable
completely
+    greaterThan(QT_GCC_MAJOR_VERSION, 8): QMAKE_CXXFLAGS_WARN_ON +=
-Wno-deprecated-copy
 }
Jason Merrill Dec. 12, 2018, 2:52 p.m. UTC | #7
On Sat, Dec 8, 2018 at 1:33 PM Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> On Sat, 8 Dec 2018 at 20:05, Ville Voutilainen
> <ville.voutilainen@gmail.com> wrote:
>
> > > New compiler releases will usually include new warnings that require
> > > some code modification to accommodate.  Why is this one particularly
> > > problematic?
> >
> > I don't think it's any more problematic than any other warning that
> > introduces new errors for fools that build with -Wall and -Werror.
> > But considering that those errors are false positives, and that
> > turning them off will in some cases require writing boiler-plate
> > (defaulted assignments), I would merely prefer having another release
> > round to get fixes for my codebase out in the wild.
>
> For what it's worth, I find it unfortunate that this deprecation and its resulting warnings end up
> making the decision on whether a "rule of 5" must be followed; correct code needs to be adjusted
> to cope with a fairly stylistic matter, with false positives and all.

I don't see it as a stylistic matter.  If you need a user-provided
copy constructor to get proper copy semantics for a class, you almost
certainly need the same thing for copy assignment.  This was too noisy
for destructors, for which it's fairly common to define a virtual
destructor just to make a class polymorphic, not because there are
significant destruction semantics.  But I don't see a similar argument
for copy constructors: in your example, there was no need for
QVariant::Private to define a copy constructor, and that seems like a
situation where a warning is reasonable, even if the code is in fact
correct.

Jason
Ville Voutilainen Dec. 12, 2018, 3:30 p.m. UTC | #8
On Wed, 12 Dec 2018 at 16:52, Jason Merrill <jason@redhat.com> wrote:

> > For what it's worth, I find it unfortunate that this deprecation and its resulting warnings end up
> > making the decision on whether a "rule of 5" must be followed; correct code needs to be adjusted
> > to cope with a fairly stylistic matter, with false positives and all.
>
> I don't see it as a stylistic matter.  If you need a user-provided
> copy constructor to get proper copy semantics for a class, you almost
> certainly need the same thing for copy assignment.  This was too noisy
> for destructors, for which it's fairly common to define a virtual
> destructor just to make a class polymorphic, not because there are
> significant destruction semantics.  But I don't see a similar argument
> for copy constructors: in your example, there was no need for
> QVariant::Private to define a copy constructor, and that seems like a
> situation where a warning is reasonable, even if the code is in fact
> correct.

I have other cases where the compiler warns besides QVariant::Private.
I don't have a good grasp of what
those cases are like, yet, because I'll look at those warnings some
time later, possibly next year. :)
Thus I don't have any idea whether there are practical cases where the
copy constructor allocates but the assignment
can just blast bits, although I find that rather plausible. (Side
note: disabling warnings in Qt is painful; it's
not really more or less painful than doing code changes and regtesting
those on all platforms; that's not your
problem, though.)
diff mbox series

Patch

commit c37377416dcbf21c6b9f6c7b83fd8f9587b0a517
Author: Jason Merrill <jason@redhat.com>
Date:   Wed Nov 21 18:04:02 2018 -0500

            PR c++/88136 - -Wdeprecated-copy false positives
    
    Deprecating the copy operations because the class has a user-provided
    destructor turns out to have too many false positives; this patch adjusts
    -Wdeprecated-copy to only deprecate if the other copy operation is
    user-provided.  To get the earlier behavior, people can explicitly request
    it with -Wdeprecated-copy-dtor.
    
    gcc/c-family/
            * c.opt (Wdeprecated-copy-dtor): New.
            (Wdeprecated-copy): Move to -Wextra.
    gcc/cp/
            * class.c (classtype_has_depr_implicit_copy): Rename from
            classtype_has_user_copy_or_dtor.
            * method.c (lazily_declare_fn): Adjust.
            * decl2.c (cp_warn_deprecated_use): Refer to -Wdeprecated-copy-dtor
            if deprecation is due to a destructor.

diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 3b6912ea1cc..98c1a748329 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -228,7 +228,8 @@  in the following sections.
 -fvisibility-ms-compat @gol
 -fext-numeric-literals @gol
 -Wabi=@var{n}  -Wabi-tag  -Wconversion-null  -Wctor-dtor-privacy @gol
--Wdelete-non-virtual-dtor  -Wdeprecated-copy  -Wliteral-suffix @gol
+-Wdelete-non-virtual-dtor  -Wdeprecated-copy  -Wdeprecated-copy-dtor @gol
+-Wliteral-suffix @gol
 -Wmultiple-inheritance  -Wno-init-list-lifetime @gol
 -Wnamespaces  -Wnarrowing @gol
 -Wpessimizing-move  -Wredundant-move @gol
@@ -3000,8 +3001,10 @@  by @option{-Wall}.
 @opindex Wno-deprecated-copy
 Warn that the implicit declaration of a copy constructor or copy
 assignment operator is deprecated if the class has a user-provided
-copy constructor, copy assignment operator, or destructor, in C++11
-and up.  This warning is enabled by @option{-Wall}.
+copy constructor or copy assignment operator, in C++11 and up.  This
+warning is enabled by @option{-Wextra}.  With
+@option{-Wdeprecated-copy-dtor}, also deprecate if the class has a
+user-provided destructor.
 
 @item -Wno-init-list-lifetime @r{(C++ and Objective-C++ only)}
 @opindex Winit-list-lifetime
@@ -4407,6 +4410,7 @@  name is still supported, but the newer name is more descriptive.)
 
 @gccoptlist{-Wclobbered  @gol
 -Wcast-function-type  @gol
+-Wdeprecated-copy @r{(C++ only)} @gol
 -Wempty-body  @gol
 -Wignored-qualifiers @gol
 -Wimplicit-fallthrough=3 @gol
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 6f88a1013d6..07ff1c84f96 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -481,7 +481,12 @@  C C++ ObjC ObjC++ CPP(cpp_warn_deprecated) CppReason(CPP_W_DEPRECATED) Var(warn_
 Warn if a deprecated compiler feature, class, method, or field is used.
 
 Wdeprecated-copy
-C++ ObjC++ Var(warn_deprecated_copy) Warning LangEnabledBy(C++ ObjC++, Wall)
+C++ ObjC++ Var(warn_deprecated_copy) Warning LangEnabledBy(C++ ObjC++, Wextra)
+Mark implicitly-declared copy operations as deprecated if the class has a
+user-provided copy operation.
+
+Wdeprecated-copy-dtor
+C++ ObjC++ Var(warn_deprecated_copy, 2) Warning
 Mark implicitly-declared copy operations as deprecated if the class has a
 user-provided copy operation or destructor.
 
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 111a123bb34..886abeaa3f9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6272,7 +6272,7 @@  extern bool type_has_constexpr_default_constructor (tree);
 extern bool type_has_virtual_destructor		(tree);
 extern bool classtype_has_move_assign_or_move_ctor_p (tree, bool user_declared);
 extern bool classtype_has_non_deleted_move_ctor (tree);
-extern tree classtype_has_user_copy_or_dtor	(tree);
+extern tree classtype_has_depr_implicit_copy	(tree);
 extern bool type_build_ctor_call		(tree);
 extern bool type_build_dtor_call		(tree);
 extern void explain_non_literal_class		(tree);
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 57261511a90..9c175f85cf6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5233,7 +5233,7 @@  classtype_has_non_deleted_move_ctor (tree t)
    operator, or destructor, returns that function.  Otherwise, null.  */
 
 tree
-classtype_has_user_copy_or_dtor (tree t)
+classtype_has_depr_implicit_copy (tree t)
 {
   if (!CLASSTYPE_LAZY_COPY_CTOR (t))
     for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 79abdaebe86..44e6ef379ed 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -5275,18 +5275,23 @@  cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
       && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
       && copy_fn_p (decl))
     {
-      auto_diagnostic_group d;
-      /* Don't warn about system library classes (c++/86342).  */
-      if (!DECL_IN_SYSTEM_HEADER (decl))
-	warned = warning (OPT_Wdeprecated_copy,
-			  "implicitly-declared %qD is deprecated", decl);
-      if (warned)
+      if (warn_deprecated_copy
+	  /* Don't warn about system library classes (c++/86342).  */
+	  && (!DECL_IN_SYSTEM_HEADER (decl)
+	      || global_dc->dc_warn_system_headers))
 	{
+	  auto_diagnostic_group d;
 	  tree ctx = DECL_CONTEXT (decl);
-	  tree other = classtype_has_user_copy_or_dtor (ctx);
-	  inform (DECL_SOURCE_LOCATION (other),
-		  "because %qT has user-provided %qD",
-		  ctx, other);
+	  tree other = classtype_has_depr_implicit_copy (ctx);
+	  int opt = (DECL_DESTRUCTOR_P (other)
+		     ? OPT_Wdeprecated_copy_dtor
+		     : OPT_Wdeprecated_copy);
+	  warned = warning (opt, "implicitly-declared %qD is deprecated",
+			    decl);
+	  if (warned)
+	    inform (DECL_SOURCE_LOCATION (other),
+		    "because %qT has user-provided %qD",
+		    ctx, other);
 	}
     }
   else
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index 936dad42122..fd023e20053 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -2380,7 +2380,7 @@  lazily_declare_fn (special_function_kind sfk, tree type)
     {
       if (classtype_has_move_assign_or_move_ctor_p (type, true))
 	DECL_DELETED_FN (fn) = true;
-      else if (classtype_has_user_copy_or_dtor (type))
+      else if (classtype_has_depr_implicit_copy (type))
 	/* The implicit definition of a copy constructor as defaulted is
 	   deprecated if the class has a user-declared copy assignment operator
 	   or a user-declared destructor. The implicit definition of a copy
diff --git a/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C b/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C
index d33c6dc667d..bbb81303925 100644
--- a/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C
@@ -6,7 +6,7 @@ 
    of this International Standard, these implicit definitions could become
    deleted (11.4).  */
 
-// { dg-additional-options -Wdeprecated-copy }
+// { dg-additional-options -Wdeprecated-copy-dtor }
 
 struct X
 {