From 17847cffc7465c3120c33c0119a00a012b93ec2b Mon Sep 17 00:00:00 2001 From: jason Date: Fri, 18 May 2018 20:02:48 +0000 Subject: [PATCH] PR c++/58407 - deprecated implicit copy ops. 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@260381 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c-family/ChangeLog | 4 +++ gcc/c-family/c.opt | 5 +++ gcc/cp/ChangeLog | 16 +++++++++ gcc/cp/call.c | 21 ++++++++--- gcc/cp/class.c | 36 +++++++++++++++++++ gcc/cp/cp-tree.h | 3 +- gcc/cp/decl.c | 10 ++---- gcc/cp/decl2.c | 53 ++++++++++++++++++++++++++-- gcc/cp/init.c | 11 +++--- gcc/cp/method.c | 15 ++++++-- gcc/cp/tree.c | 13 ------- gcc/cp/typeck2.c | 4 +-- gcc/doc/invoke.texi | 11 +++++- gcc/testsuite/g++.dg/cpp0x/depr-copy1.C | 29 +++++++++++++++ gcc/testsuite/g++.old-deja/g++.other/warn6.C | 2 +- libitm/ChangeLog | 4 +++ libitm/beginend.cc | 5 +++ 17 files changed, 200 insertions(+), 42 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/depr-copy1.C diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 0930511da88..22c954754bf 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,7 @@ +2018-05-18 Jason Merrill + + * c.opt (Wdeprecated-copy): New flag. + 2018-05-17 Martin Liska * c-warn.c (overflow_warning): Do not use diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index c48d6dced8d..5114543c128 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -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. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index c526771f43f..e4fcffca05b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,19 @@ +2018-05-18 Jason Merrill + + 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 PR c++/85782 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 4d04785f2b9..1df4d14dfe6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -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)) diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 306ee294d8a..4960b4b5593 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -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; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index cab926028b8..b23a7c88863 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 10e3079beed..f50812f9a87 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -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 diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 126356d5de4..b6e8e077bdc 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -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 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index d9fb0ea0086..b558742abf6 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -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; } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index ef0df7eb8d9..8e7590c5dbb 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -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 diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index db81da91676..15b9697a63b 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -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 diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c index 682303ad7af..ad0774c6731 100644 --- a/gcc/cp/typeck2.c +++ b/gcc/cp/typeck2.c @@ -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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 612b97c8b0d..44b043384d9 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 index 00000000000..d33c6dc667d --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/depr-copy1.C @@ -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 } } +} diff --git a/gcc/testsuite/g++.old-deja/g++.other/warn6.C b/gcc/testsuite/g++.old-deja/g++.other/warn6.C index 4325df74baa..b48e08406de 100644 --- a/gcc/testsuite/g++.old-deja/g++.other/warn6.C +++ b/gcc/testsuite/g++.old-deja/g++.other/warn6.C @@ -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 diff --git a/libitm/ChangeLog b/libitm/ChangeLog index 1758b6a8f7f..7791d9e433f 100644 --- a/libitm/ChangeLog +++ b/libitm/ChangeLog @@ -1,3 +1,7 @@ +2018-05-17 Jason Merrill + + * beginend.cc (save): Disable -Werror=deprecated-copy. + 2018-05-02 Tom de Vries PR testsuite/85106 diff --git a/libitm/beginend.cc b/libitm/beginend.cc index 1669442580e..057d4586b37 100644 --- a/libitm/beginend.cc +++ b/libitm/beginend.cc @@ -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; -- 2.11.4.GIT