Commit 115ef7c5 by Jason Merrill Committed by Jason Merrill

re PR c++/66501 (Default move assignment does not move array members)

	PR c++/66501
	* class.c (type_has_nontrivial_assignment): New.
	* init.c (build_vec_init): Use it.
	* cp-tree.h: Declare it.
	* method.c (trivial_fn_p): Templates aren't trivial.

From-SVN: r224843
parent d4c9e7f9
2015-06-23 Jason Merrill <jason@redhat.com> 2015-06-23 Jason Merrill <jason@redhat.com>
PR c++/66501
* class.c (type_has_nontrivial_assignment): New.
* init.c (build_vec_init): Use it.
* cp-tree.h: Declare it.
* method.c (trivial_fn_p): Templates aren't trivial.
PR c++/66542 PR c++/66542
* decl.c (expand_static_init): Make sure the destructor is callable * decl.c (expand_static_init): Make sure the destructor is callable
here even if we have an initializer. here even if we have an initializer.
......
...@@ -5136,6 +5136,24 @@ type_has_non_user_provided_default_constructor (tree t) ...@@ -5136,6 +5136,24 @@ type_has_non_user_provided_default_constructor (tree t)
return false; return false;
} }
/* Return true if TYPE has some non-trivial assignment operator. */
bool
type_has_nontrivial_assignment (tree type)
{
gcc_assert (TREE_CODE (type) != ARRAY_TYPE);
if (CLASS_TYPE_P (type))
for (tree fns
= lookup_fnfields_slot_nolazy (type, ansi_assopname (NOP_EXPR));
fns; fns = OVL_NEXT (fns))
{
tree fn = OVL_CURRENT (fns);
if (!trivial_fn_p (fn))
return true;
}
return false;
}
/* TYPE is being used as a virtual base, and has a non-trivial move /* TYPE is being used as a virtual base, and has a non-trivial move
assignment. Return true if this is due to there being a user-provided assignment. Return true if this is due to there being a user-provided
move assignment in TYPE or one of its subobjects; if there isn't, then move assignment in TYPE or one of its subobjects; if there isn't, then
......
...@@ -5295,6 +5295,7 @@ extern tree in_class_defaulted_default_constructor (tree); ...@@ -5295,6 +5295,7 @@ extern tree in_class_defaulted_default_constructor (tree);
extern bool user_provided_p (tree); extern bool user_provided_p (tree);
extern bool type_has_user_provided_constructor (tree); extern bool type_has_user_provided_constructor (tree);
extern bool type_has_non_user_provided_default_constructor (tree); extern bool type_has_non_user_provided_default_constructor (tree);
extern bool type_has_nontrivial_assignment (tree);
extern bool vbase_has_user_provided_move_assign (tree); extern bool vbase_has_user_provided_move_assign (tree);
extern tree default_init_uninitialized_part (tree); extern tree default_init_uninitialized_part (tree);
extern bool trivial_default_constructor_is_constexpr (tree); extern bool trivial_default_constructor_is_constexpr (tree);
......
...@@ -3460,8 +3460,7 @@ build_vec_init (tree base, tree maxindex, tree init, ...@@ -3460,8 +3460,7 @@ build_vec_init (tree base, tree maxindex, tree init,
&& TREE_CODE (atype) == ARRAY_TYPE && TREE_CODE (atype) == ARRAY_TYPE
&& TREE_CONSTANT (maxindex) && TREE_CONSTANT (maxindex)
&& (from_array == 2 && (from_array == 2
? (!CLASS_TYPE_P (inner_elt_type) ? !type_has_nontrivial_assignment (inner_elt_type)
|| !TYPE_HAS_COMPLEX_COPY_ASSIGN (inner_elt_type))
: !TYPE_NEEDS_CONSTRUCTING (type)) : !TYPE_NEEDS_CONSTRUCTING (type))
&& ((TREE_CODE (init) == CONSTRUCTOR && ((TREE_CODE (init) == CONSTRUCTOR
/* Don't do this if the CONSTRUCTOR might contain something /* Don't do this if the CONSTRUCTOR might contain something
......
...@@ -476,6 +476,8 @@ type_set_nontrivial_flag (tree ctype, special_function_kind sfk) ...@@ -476,6 +476,8 @@ type_set_nontrivial_flag (tree ctype, special_function_kind sfk)
bool bool
trivial_fn_p (tree fn) trivial_fn_p (tree fn)
{ {
if (TREE_CODE (fn) == TEMPLATE_DECL)
return false;
if (!DECL_DEFAULTED_FN (fn)) if (!DECL_DEFAULTED_FN (fn))
return false; return false;
......
// PR c++/66501
// { dg-do run { target c++11 } }
int total_size;
struct Object
{
int size = 0;
Object () = default;
~Object () {
total_size -= size;
}
Object (const Object &) = delete;
Object & operator= (const Object &) = delete;
Object (Object && b) {
size = b.size;
b.size = 0;
}
Object & operator= (Object && b) {
if (this != & b) {
total_size -= size;
size = b.size;
b.size = 0;
}
return * this;
}
void grow () {
size ++;
total_size ++;
}
};
struct Container {
Object objects[2];
};
int main (void)
{
Container container;
// grow some objects in the container
for (auto & object : container.objects)
object.grow ();
// now empty it
container = Container ();
return total_size;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment