PR c++/58407 - deprecated implicit copy ops.
authorJason Merrill <jason@redhat.com>
Fri, 18 May 2018 20:02:48 +0000 (16:02 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 18 May 2018 20:02:48 +0000 (16:02 -0400)
gcc/c-family/
* c.opt (Wdeprecated-copy): New flag.
gcc/cp/
* call.c (build_over_call): Warn about deprecated trivial fns.
* class.c (classtype_has_user_copy_or_dtor): New.
(type_build_ctor_call): Check TREE_DEPRECATED.
(type_build_dtor_call): Likewise.
* decl2.c (cp_warn_deprecated_use): Move from tree.c.
Add checks.  Return bool.  Handle -Wdeprecated-copy.
(mark_used): Use it.
* decl.c (grokdeclarator): Remove redundant checks.
* typeck2.c (build_functional_cast): Likewise.
* method.c (lazily_declare_fn): Mark deprecated copy ops.
* init.c (build_aggr_init): Only set TREE_USED if there are
side-effects.
libitm/
* beginend.cc (save): Disable -Werror=deprecated-copy.

From-SVN: r260381

17 files changed:
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/method.c
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/doc/invoke.texi
gcc/testsuite/g++.dg/cpp0x/depr-copy1.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.other/warn6.C
libitm/ChangeLog
libitm/beginend.cc

index 0930511..22c9547 100644 (file)
@@ -1,3 +1,7 @@
+2018-05-18  Jason Merrill  <jason@redhat.com>
+
+       * c.opt (Wdeprecated-copy): New flag.
+
 2018-05-17  Martin Liska  <mliska@suse.cz>
 
        * c-warn.c (overflow_warning): Do not use
index c48d6dc..5114543 100644 (file)
@@ -464,6 +464,11 @@ Wdeprecated
 C C++ ObjC ObjC++ CPP(cpp_warn_deprecated) CppReason(CPP_W_DEPRECATED) Var(warn_deprecated) Init(1) Warning
 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)
+Mark implicitly-declared copy operations as deprecated if the class has a
+user-provided copy operation or destructor.
+
 Wdesignated-init
 C ObjC Var(warn_designated_init) Init(1) Warning
 Warn about positional initialization of structs requiring designated initializers.
index c526771..e4fcffc 100644 (file)
@@ -1,3 +1,19 @@
+2018-05-18  Jason Merrill  <jason@redhat.com>
+
+       PR c++/58407 - deprecated implicit copy ops.
+       * call.c (build_over_call): Warn about deprecated trivial fns.
+       * class.c (classtype_has_user_copy_or_dtor): New.
+       (type_build_ctor_call): Check TREE_DEPRECATED.
+       (type_build_dtor_call): Likewise.
+       * decl2.c (cp_warn_deprecated_use): Move from tree.c.
+       Add checks.  Return bool.  Handle -Wdeprecated-copy.
+       (mark_used): Use it.
+       * decl.c (grokdeclarator): Remove redundant checks.
+       * typeck2.c (build_functional_cast): Likewise.
+       * method.c (lazily_declare_fn): Mark deprecated copy ops.
+       * init.c (build_aggr_init): Only set TREE_USED if there are
+       side-effects.
+
 2018-05-18  Cesar Philippidis  <cesar@codesourcery.com>
 
        PR c++/85782
index 4d04785..1df4d14 100644 (file)
@@ -8168,21 +8168,30 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
                    /* See unsafe_copy_elision_p.  */
                    || DECL_BASE_CONSTRUCTOR_P (fn));
 
-      /* [class.copy]: the copy constructor is implicitly defined even if
-        the implementation elided its use.  */
-      if (!trivial && !force_elide)
+      fa = argarray[0];
+      bool unsafe = unsafe_copy_elision_p (fa, arg);
+      bool eliding_temp = (TREE_CODE (arg) == TARGET_EXPR && !unsafe);
+
+      /* [class.copy]: the copy constructor is implicitly defined even if the
+        implementation elided its use.  But don't warn about deprecation when
+        eliding a temporary, as then no copy is actually performed.  */
+      warning_sentinel s (warn_deprecated_copy, eliding_temp);
+      if (force_elide)
+       /* The language says this isn't called.  */;
+      else if (!trivial)
        {
          if (!mark_used (fn, complain) && !(complain & tf_error))
            return error_mark_node;
          already_used = true;
        }
+      else
+       cp_warn_deprecated_use (fn, complain);
 
       /* If we're creating a temp and we already have one, don't create a
         new one.  If we're not creating a temp but we get one, use
         INIT_EXPR to collapse the temp into our target.  Otherwise, if the
         ctor is trivial, do a bitwise copy with a simple TARGET_EXPR for a
         temp or an INIT_EXPR otherwise.  */
-      fa = argarray[0];
       if (is_dummy_object (fa))
        {
          if (TREE_CODE (arg) == TARGET_EXPR)
@@ -8191,7 +8200,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
            return force_target_expr (DECL_CONTEXT (fn), arg, complain);
        }
       else if ((trivial || TREE_CODE (arg) == TARGET_EXPR)
-              && !unsafe_copy_elision_p (fa, arg))
+              && !unsafe)
        {
          tree to = cp_stabilize_reference (cp_build_fold_indirect_ref (fa));
 
@@ -8241,6 +8250,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
           TREE_NO_WARNING (val) = 1;
        }
 
+      cp_warn_deprecated_use (fn, complain);
+
       return val;
     }
   else if (trivial_fn_p (fn))
index 306ee29..4960b4b 100644 (file)
@@ -5171,6 +5171,40 @@ classtype_has_move_assign_or_move_ctor_p (tree t, bool user_p)
   return false;
 }
 
+/* If T, a class, has a user-provided copy constructor, copy assignment
+   operator, or destructor, returns that function.  Otherwise, null.  */
+
+tree
+classtype_has_user_copy_or_dtor (tree t)
+{
+  if (!CLASSTYPE_LAZY_COPY_CTOR (t))
+    for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (t)); iter; ++iter)
+      {
+       tree fn = *iter;
+       if (user_provided_p (fn) && copy_fn_p (fn))
+         return fn;
+      }
+
+  if (!CLASSTYPE_LAZY_COPY_ASSIGN (t))
+    for (ovl_iterator iter (get_class_binding_direct
+                           (t, assign_op_identifier));
+        iter; ++iter)
+      {
+       tree fn = *iter;
+       if (user_provided_p (fn) && copy_fn_p (fn))
+         return fn;
+      }
+
+  if (!CLASSTYPE_LAZY_DESTRUCTOR (t))
+    {
+      tree fn = CLASSTYPE_DESTRUCTOR (t);
+      if (user_provided_p (fn))
+       return fn;
+    }
+
+  return NULL_TREE;
+}
+
 /* Nonzero if we need to build up a constructor call when initializing an
    object of this class, either because it has a user-declared constructor
    or because it doesn't have a default constructor (so we need to give an
@@ -5201,6 +5235,7 @@ type_build_ctor_call (tree t)
     {
       tree fn = *iter;
       if (!DECL_ARTIFICIAL (fn)
+         || TREE_DEPRECATED (fn)
          || DECL_DELETED_FN (fn))
        return true;
     }
@@ -5228,6 +5263,7 @@ type_build_dtor_call (tree t)
     {
       tree fn = *iter;
       if (!DECL_ARTIFICIAL (fn)
+         || TREE_DEPRECATED (fn)
          || DECL_DELETED_FN (fn))
        return true;
     }
index cab9260..b23a7c8 100644 (file)
@@ -6103,6 +6103,7 @@ extern bool is_std_init_list                      (tree);
 extern bool is_list_ctor                       (tree);
 extern void validate_conversion_obstack                (void);
 extern void mark_versions_used                 (tree);
+extern bool cp_warn_deprecated_use             (tree, tsubst_flags_t = tf_warning_or_error);
 extern tree get_function_version_dispatcher    (tree);
 
 /* in class.c */
@@ -6164,6 +6165,7 @@ extern bool trivial_default_constructor_is_constexpr (tree);
 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 tree classtype_has_user_copy_or_dtor    (tree);
 extern bool type_build_ctor_call               (tree);
 extern bool type_build_dtor_call               (tree);
 extern void explain_non_literal_class          (tree);
@@ -7157,7 +7159,6 @@ extern tree cxx_copy_lang_qualifiers              (const_tree, const_tree);
 
 extern void cxx_print_statistics               (void);
 extern bool maybe_warn_zero_as_null_pointer_constant (tree, location_t);
-extern void cp_warn_deprecated_use             (tree);
 
 /* in ptree.c */
 extern void cxx_print_xnode                    (FILE *, tree, int);
index 10e3079..f50812f 100644 (file)
@@ -10388,18 +10388,12 @@ grokdeclarator (const cp_declarator *declarator,
       type = NULL_TREE;
       type_was_error_mark_node = true;
     }
-  /* If the entire declaration is itself tagged as deprecated then
-     suppress reports of deprecated items.  */
-  if (type && TREE_DEPRECATED (type)
-      && deprecated_state != DEPRECATED_SUPPRESS)
-    cp_warn_deprecated_use (type);
+  cp_warn_deprecated_use (type);
   if (type && TREE_CODE (type) == TYPE_DECL)
     {
       typedef_decl = type;
       type = TREE_TYPE (typedef_decl);
-      if (TREE_DEPRECATED (type)
-         && DECL_ARTIFICIAL (typedef_decl)
-         && deprecated_state != DEPRECATED_SUPPRESS)
+      if (DECL_ARTIFICIAL (typedef_decl))
        cp_warn_deprecated_use (type);
     }
   /* No type at all: default to `int', and set DEFAULTED_INT
index 126356d..b6e8e07 100644 (file)
@@ -5173,6 +5173,55 @@ maybe_instantiate_decl (tree decl)
     }
 }
 
+/* Maybe warn if DECL is deprecated, subject to COMPLAIN.  Returns whether or
+   not a warning was emitted.  */
+
+bool
+cp_warn_deprecated_use (tree decl, tsubst_flags_t complain)
+{
+  if (!(complain & tf_warning) || !decl
+      || deprecated_state == DEPRECATED_SUPPRESS)
+    return false;
+
+  if (!TREE_DEPRECATED (decl))
+    {
+      /* Perhaps this is a deprecated typedef.  */
+      if (TYPE_P (decl) && TYPE_NAME (decl))
+       decl = TYPE_NAME (decl);
+
+      if (!TREE_DEPRECATED (decl))
+       return false;
+    }
+
+  /* Don't warn within members of a deprecated type.  */
+  if (TYPE_P (decl)
+      && currently_open_class (decl))
+    return false;
+
+  bool warned = false;
+  if (cxx_dialect >= cxx11
+      && DECL_P (decl)
+      && DECL_ARTIFICIAL (decl)
+      && DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)
+      && copy_fn_p (decl))
+    {
+      warned = warning (OPT_Wdeprecated_copy,
+                       "implicitly-declared %qD is deprecated", decl);
+      if (warned)
+       {
+         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);
+       }
+    }
+  else
+    warned = warn_deprecated_use (decl, NULL_TREE);
+
+  return warned;
+}
+
 /* Mark DECL (either a _DECL or a BASELINK) as "used" in the program.
    If DECL is a specialization or implicitly declared class member,
    generate the actual definition.  Return false if something goes
@@ -5237,9 +5286,7 @@ mark_used (tree decl, tsubst_flags_t complain)
       return false;
     }
 
-  if (TREE_DEPRECATED (decl) && (complain & tf_warning)
-      && deprecated_state != DEPRECATED_SUPPRESS)
-    warn_deprecated_use (decl, NULL_TREE);
+  cp_warn_deprecated_use (decl, complain);
 
   /* We can only check DECL_ODR_USED on variables or functions with
      DECL_LANG_SPECIFIC set, and these are also the only decls that we
index d9fb0ea..b558742 100644 (file)
@@ -1733,11 +1733,6 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
       && !DIRECT_LIST_INIT_P (init))
     flags |= LOOKUP_ONLYCONVERTING;
 
-  if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
-      && !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (type)))
-    /* Just know that we've seen something for this node.  */
-    TREE_USED (exp) = 1;
-
   is_global = begin_init_stmts (&stmt_expr, &compound_stmt);
   destroy_temps = stmts_are_full_exprs_p ();
   current_stmt_tree ()->stmts_are_full_exprs_p = 0;
@@ -1748,6 +1743,12 @@ build_aggr_init (tree exp, tree init, int flags, tsubst_flags_t complain)
   TREE_READONLY (exp) = was_const;
   TREE_THIS_VOLATILE (exp) = was_volatile;
 
+  if ((VAR_P (exp) || TREE_CODE (exp) == PARM_DECL)
+      && TREE_SIDE_EFFECTS (stmt_expr)
+      && !lookup_attribute ("warn_unused", TYPE_ATTRIBUTES (type)))
+    /* Just know that we've seen something for this node.  */
+    TREE_USED (exp) = 1;
+
   return stmt_expr;
 }
 
index ef0df7e..8e7590c 100644 (file)
@@ -2394,8 +2394,19 @@ lazily_declare_fn (special_function_kind sfk, tree type)
      move assignment operator, the implicitly declared copy constructor is
      defined as deleted.... */
   if ((sfk == sfk_copy_assignment || sfk == sfk_copy_constructor)
-      && classtype_has_move_assign_or_move_ctor_p (type, true))
-    DECL_DELETED_FN (fn) = true;
+      && cxx_dialect >= cxx11)
+    {
+      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))
+       /* 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
+          assignment operator as defaulted is deprecated if the class has a
+          user-declared copy constructor or a user-declared destructor (15.4,
+          15.8).  */
+       TREE_DEPRECATED (fn) = true;
+    }
 
   /* Destructors and assignment operators may be virtual.  */
   if (sfk == sfk_destructor
index db81da9..15b9697 100644 (file)
@@ -5398,19 +5398,6 @@ cp_tree_code_length (enum tree_code code)
     }
 }
 
-/* Wrapper around warn_deprecated_use that doesn't warn for
-   current_class_type.  */
-
-void
-cp_warn_deprecated_use (tree node)
-{
-  if (TYPE_P (node)
-      && current_class_type
-      && TYPE_MAIN_VARIANT (node) == current_class_type)
-    return;
-  warn_deprecated_use (node, NULL_TREE);
-}
-
 /* Implement -Wzero_as_null_pointer_constant.  Return true if the
    conditions for the warning hold, false otherwise.  */
 bool
index 682303a..ad0774c 100644 (file)
@@ -2064,9 +2064,7 @@ build_functional_cast (tree exp, tree parms, tsubst_flags_t complain)
     {
       type = TREE_TYPE (exp);
 
-      if (complain & tf_warning
-         && TREE_DEPRECATED (type)
-         && DECL_ARTIFICIAL (exp))
+      if (DECL_ARTIFICIAL (exp))
        cp_warn_deprecated_use (type);
     }
   else
index 612b97c..44b0433 100644 (file)
@@ -213,7 +213,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  -Wliteral-suffix  -Wmultiple-inheritance @gol
+-Wdelete-non-virtual-dtor -Wdeprecated-copy  -Wliteral-suffix @gol
+-Wmultiple-inheritance @gol
 -Wnamespaces  -Wnarrowing @gol
 -Wnoexcept  -Wnoexcept-type  -Wclass-memaccess @gol
 -Wnon-virtual-dtor  -Wreorder  -Wregister @gol
@@ -2900,6 +2901,14 @@ an instance of a derived class through a pointer to a base class if the
 base class does not have a virtual destructor.  This warning is enabled
 by @option{-Wall}.
 
+@item -Wdeprecated-copy @r{(C++ and Objective-C++ only)}
+@opindex Wdeprecated-copy
+@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}.
+
 @item -Wliteral-suffix @r{(C++ and Objective-C++ only)}
 @opindex Wliteral-suffix
 @opindex Wno-literal-suffix
diff --git a/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C b/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C
new file mode 100644 (file)
index 0000000..d33c6dc
--- /dev/null
@@ -0,0 +1,29 @@
+/* [depr.impldec] 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 assignment
+   operator as defaulted is deprecated if the class has a user-declared copy
+   constructor or a user-declared destructor (15.4, 15.8). In a future revision
+   of this International Standard, these implicit definitions could become
+   deleted (11.4).  */
+
+// { dg-additional-options -Wdeprecated-copy }
+
+struct X
+{
+  X();
+  X(const X&);
+};
+struct A
+{
+  X x;
+  ~A();
+};
+
+void f(bool b)
+{
+  A a;
+  if (b)
+    throw A();                 // Don't warn about elided copy
+  A a2 = A();                  // Here either.
+  A a3 (a);                    // { dg-warning "deprecated" "" { target c++11 } }
+}
index 4325df7..b48e084 100644 (file)
@@ -1,5 +1,5 @@
 // { dg-do assemble  }
-// { dg-options "-W -Wall" }
+// { dg-options "-W -Wall -Wno-deprecated-copy" }
 
 // Copyright (C) 2001 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 2 Mar 2001 <nathan@codesourcery.com>
index 1758b6a..7791d9e 100644 (file)
@@ -1,3 +1,7 @@
+2018-05-17  Jason Merrill  <jason@redhat.com>
+
+       * beginend.cc (save): Disable -Werror=deprecated-copy.
+
 2018-05-02  Tom de Vries  <tom@codesourcery.com>
 
        PR testsuite/85106
index 1669442..057d458 100644 (file)
@@ -431,7 +431,12 @@ GTM::gtm_transaction_cp::save(gtm_thread* tx)
   // Save everything that we might have to restore on restarts or aborts.
   jb = tx->jb;
   undolog_size = tx->undolog.size();
+
+  /* FIXME!  Assignment of an aatree like alloc_actions is unsafe; if either
+   *this or *tx is destroyed, the other ends up pointing to a freed node.  */
+#pragma GCC diagnostic warning "-Wdeprecated-copy"
   alloc_actions = tx->alloc_actions;
+
   user_actions_size = tx->user_actions.size();
   id = tx->id;
   prop = tx->prop;