C++11 specified that the implicitly-declared copy constructor and assignment operator are deprecated if one of them, or the destructor, is user-provided. This patch implements that; I've recently been fixing some uses in the compiler of those deprecated copies.
Rather than bundle this into -Wdeprecated-declarations, I've introduced a new -Wdeprecated-copy so that people can turn off this specific deprecation if it causes problems for them; it certainly complains about a lot of the G++ and libstdc++ testsuite. But in this patch it's enabled by -Wall. We don't warn about elided copies from a temporary, as in that case no actual copy is occurring; this is particularly important in the context of C++17 mandatory copy elision, but makes sense under all standards. I've changed cp_warn_deprecated_use to handle all the checks for whether we actually want the warning rather than repeat them at every call site. I needed to change build_aggr_init to only set TREE_USED if the initialization has some effect so that libgomp.c++/ctor-5.C wouldn't break with an error about threadprivate after the variable has been used. The second patch is some libstdc++ changes to avoid warnings from uses of the standard library when this warning is on. More are almost certainly needed. Jonathan, how would you like me to handle this WRT the library? Check in both patches and let you follow up as needed? Hold off until you've had a chance to make the necessary library changes? Tested x86_64-pc-linux-gnu.
commit a785eb5aa4898eff68af834a08d88577bf7685d9 Author: Jason Merrill <ja...@redhat.com> Date: Tue May 15 17:42:34 2018 -0400 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. 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/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 77e183c1608..d37ab6b3e0b 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 <nat...@codesourcery.com>
diff --git a/gcc/testsuite/g++.dg/cpp0x/Wattributes1.C b/gcc/testsuite/g++.dg/cpp0x/Wattributes1.C index b0a1e864eff..0efefc65d49 100644 --- a/gcc/testsuite/g++.dg/cpp0x/Wattributes1.C +++ b/gcc/testsuite/g++.dg/cpp0x/Wattributes1.C @@ -5,4 +5,4 @@ #include <new> __attribute__((visibility("hidden")))void*operator new(std::size_t); // { dg-warning "visibility attribute ignored" } -// { dg-message "previous declaration" "" { target *-*-* } 120 } +// { dg-message "previous declaration" "" { target *-*-* } 126 } diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index 0a4eb55f611..2da499f1498 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -132,6 +132,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION allocator(const allocator& __a) throw() : __allocator_base<_Tp>(__a) { } +#if __cplusplus >= 201103L + // Avoid implicit deprecation. + allocator& operator=(const allocator&) = default; +#endif template<typename _Tp1> allocator(const allocator<_Tp1>&) throw() { } diff --git a/libstdc++-v3/include/bits/stl_deque.h b/libstdc++-v3/include/bits/stl_deque.h index 0d4390b2929..58a01c894c0 100644 --- a/libstdc++-v3/include/bits/stl_deque.h +++ b/libstdc++-v3/include/bits/stl_deque.h @@ -149,9 +149,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Deque_iterator() _GLIBCXX_NOEXCEPT : _M_cur(), _M_first(), _M_last(), _M_node() { } +#if __cplusplus < 201103L + // Conversion from iterator to const_iterator. _Deque_iterator(const iterator& __x) _GLIBCXX_NOEXCEPT : _M_cur(__x._M_cur), _M_first(__x._M_first), _M_last(__x._M_last), _M_node(__x._M_node) { } +#else + // Conversion from iterator to const_iterator. + template<typename _Iter, + typename = _Require<is_same<_Self, const_iterator>, + is_same<_Iter, iterator>>> + _Deque_iterator(const _Iter& __x) noexcept + : _M_cur(__x._M_cur), _M_first(__x._M_first), + _M_last(__x._M_last), _M_node(__x._M_node) { } + + _Deque_iterator(const _Deque_iterator&) = default; + _Deque_iterator& operator=(const _Deque_iterator&) = default; +#endif iterator _M_const_cast() const _GLIBCXX_NOEXCEPT diff --git a/libstdc++-v3/include/bits/stl_iterator.h b/libstdc++-v3/include/bits/stl_iterator.h index 750b0c0f307..71d2afb1aeb 100644 --- a/libstdc++-v3/include/bits/stl_iterator.h +++ b/libstdc++-v3/include/bits/stl_iterator.h @@ -138,6 +138,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION reverse_iterator(const reverse_iterator& __x) : current(__x.current) { } +#if __cplusplus >= 201103L + // Avoid implicit deprecation. + reverse_iterator& operator=(const reverse_iterator&) = default; +#endif + /** * A %reverse_iterator across other types can be copied if the * underlying %iterator can be converted to the type of @c current. diff --git a/libstdc++-v3/include/ext/throw_allocator.h b/libstdc++-v3/include/ext/throw_allocator.h index 5d9caa2bcae..2c7ef96025f 100644 --- a/libstdc++-v3/include/ext/throw_allocator.h +++ b/libstdc++-v3/include/ext/throw_allocator.h @@ -402,6 +402,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ struct condition_base { +#if __cplusplus >= 201103L + condition_base() = default; + + // Avoid implicit deprecation. + condition_base(const condition_base&) = default; + condition_base& operator=(const condition_base&) = default; +#endif virtual ~condition_base() { }; }; diff --git a/libstdc++-v3/include/std/stdexcept b/libstdc++-v3/include/std/stdexcept index ddc056f752f..a9748ce8f04 100644 --- a/libstdc++-v3/include/std/stdexcept +++ b/libstdc++-v3/include/std/stdexcept @@ -150,6 +150,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit domain_error(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit domain_error(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + domain_error(const domain_error&) = default; + domain_error& operator=(const domain_error&) = default; #endif virtual ~domain_error() _GLIBCXX_USE_NOEXCEPT; }; @@ -161,6 +164,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit invalid_argument(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit invalid_argument(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + invalid_argument(const invalid_argument&) = default; + invalid_argument& operator=(const invalid_argument&) = default; #endif virtual ~invalid_argument() _GLIBCXX_USE_NOEXCEPT; }; @@ -173,6 +179,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit length_error(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit length_error(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + length_error(const length_error&) = default; + length_error& operator=(const length_error&) = default; #endif virtual ~length_error() _GLIBCXX_USE_NOEXCEPT; }; @@ -185,6 +194,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit out_of_range(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit out_of_range(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + out_of_range(const out_of_range&) = default; + out_of_range& operator=(const out_of_range&) = default; #endif virtual ~out_of_range() _GLIBCXX_USE_NOEXCEPT; }; @@ -233,6 +245,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit range_error(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit range_error(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + range_error(const range_error&) = default; + range_error& operator=(const range_error&) = default; #endif virtual ~range_error() _GLIBCXX_USE_NOEXCEPT; }; @@ -244,6 +259,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit overflow_error(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit overflow_error(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + overflow_error(const overflow_error&) = default; + overflow_error& operator=(const overflow_error&) = default; #endif virtual ~overflow_error() _GLIBCXX_USE_NOEXCEPT; }; @@ -255,6 +273,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION explicit underflow_error(const string& __arg) _GLIBCXX_TXN_SAFE; #if __cplusplus >= 201103L explicit underflow_error(const char*) _GLIBCXX_TXN_SAFE; + // Avoid implicit deprecation. + underflow_error(const underflow_error&) = default; + underflow_error& operator=(const underflow_error&) = default; #endif virtual ~underflow_error() _GLIBCXX_USE_NOEXCEPT; }; diff --git a/libstdc++-v3/include/std/system_error b/libstdc++-v3/include/std/system_error index 4918ef363d8..f0ef942bcd3 100644 --- a/libstdc++-v3/include/std/system_error +++ b/libstdc++-v3/include/std/system_error @@ -364,6 +364,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : runtime_error(__what + ": " + error_code(__v, __ecat).message()), _M_code(__v, __ecat) { } +#if __cplusplus >= 201103L + // Avoid implicit deprecation. + system_error (const system_error &) = default; + system_error &operator= (const system_error &) = default; +#endif + virtual ~system_error() noexcept; const error_code& diff --git a/libstdc++-v3/libsupc++/exception.h b/libstdc++-v3/libsupc++/exception.h index 3f1111d3e4b..8975ce3d55c 100644 --- a/libstdc++-v3/libsupc++/exception.h +++ b/libstdc++-v3/libsupc++/exception.h @@ -62,6 +62,11 @@ namespace std public: exception() _GLIBCXX_USE_NOEXCEPT { } virtual ~exception() _GLIBCXX_TXN_SAFE_DYN _GLIBCXX_USE_NOEXCEPT; +#if __cplusplus >= 201103L + // Avoid implicit deprecation. + exception(const exception&) = default; + exception& operator=(const exception&) = default; +#endif /** Returns a C-style character string describing the general cause * of the current error. */ diff --git a/libstdc++-v3/libsupc++/new b/libstdc++-v3/libsupc++/new index 99c769c48d6..068f17f0d21 100644 --- a/libstdc++-v3/libsupc++/new +++ b/libstdc++-v3/libsupc++/new @@ -56,6 +56,12 @@ namespace std public: bad_alloc() throw() { } +#if __cplusplus >= 201103L + // Avoid implicit deprecation. + bad_alloc(const bad_alloc&) = default; + bad_alloc& operator=(const bad_alloc&) = default; +#endif + // This declaration is not useless: // http://gcc.gnu.org/onlinedocs/gcc-3.0.2/gcc_6.html#SEC118 virtual ~bad_alloc() throw();