aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2018-05-18 16:02:48 -0400
committerJason Merrill <jason@gcc.gnu.org>2018-05-18 16:02:48 -0400
commitb46b715d5b838d9869f89d3594ebf7d0b7cb374c (patch)
tree5684d331d1a9d9e995bb252f9febf8e86618a0a5 /gcc/cp
parentf07c22376848e9923aa8455d2c0a059d9d0e01d5 (diff)
downloadgcc-b46b715d5b838d9869f89d3594ebf7d0b7cb374c.zip
gcc-b46b715d5b838d9869f89d3594ebf7d0b7cb374c.tar.gz
gcc-b46b715d5b838d9869f89d3594ebf7d0b7cb374c.tar.bz2
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. From-SVN: r260381
Diffstat (limited to 'gcc/cp')
-rw-r--r--gcc/cp/ChangeLog16
-rw-r--r--gcc/cp/call.c21
-rw-r--r--gcc/cp/class.c36
-rw-r--r--gcc/cp/cp-tree.h3
-rw-r--r--gcc/cp/decl.c10
-rw-r--r--gcc/cp/decl2.c53
-rw-r--r--gcc/cp/init.c11
-rw-r--r--gcc/cp/method.c15
-rw-r--r--gcc/cp/tree.c13
-rw-r--r--gcc/cp/typeck2.c4
10 files changed, 142 insertions, 40 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c526771..e4fcffc 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4d04785..1df4d14 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 306ee29..4960b4b 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 cab9260..b23a7c8 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 10e3079..f50812f 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 126356d..b6e8e07 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 d9fb0ea..b558742 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 ef0df7e..8e7590c 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 db81da9..15b9697 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 682303a..ad0774c 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