Re: C++ PATCH for c++/50500 (DR 1082, implicitly declared copy in class with move)

2011-11-01 Thread Jason Merrill

On 10/29/2011 05:07 PM, Eric Botcazou wrote:

DR 1082 changed the rules for implicitly declared copy constructors and
assignment operators in the presence of move ctor/op= such that if
either move operation is present, instead of being suppressed the copy
operations will still be declared, but as deleted.


We have detected a side effect of this change by means of -fdump-ada-spec:
implicit copy assignment operators are now generated in simple cases where
they were not previously generated, for example:


Oops, thanks.  Fixed thus.

commit 06151eabf195163c8885da36abae67ab60cf1978
Author: Jason Merrill ja...@redhat.com
Date:   Mon Oct 31 16:57:17 2011 -0400

	PR c++/50500
	DR 1082
	* search.c (lookup_fnfields_idx_nolazy): Split out from...
	(lookup_fnfields_1): ...here.
	(lookup_fnfields_slot_nolazy): Use it.
	* cp-tree.h: Declare it.
	* class.c (type_has_move_assign): Use it.
	(type_has_user_declared_move_assign): Likewise.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index a014d25..41d182a 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -4485,7 +4485,7 @@ type_has_move_assign (tree t)
   lazily_declare_fn (sfk_move_assignment, t);
 }
 
-  for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
+  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
fns; fns = OVL_NEXT (fns))
 if (move_fn_p (OVL_CURRENT (fns)))
   return true;
@@ -4530,7 +4530,7 @@ type_has_user_declared_move_assign (tree t)
   if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
 return false;
 
-  for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
+  for (fns = lookup_fnfields_slot_nolazy (t, ansi_assopname (NOP_EXPR));
fns; fns = OVL_NEXT (fns))
 {
   tree fn = OVL_CURRENT (fns);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 7ff1491..ac42e0e 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -5328,6 +5328,7 @@ extern tree lookup_field_1			(tree, tree, bool);
 extern tree lookup_field			(tree, tree, int, bool);
 extern int lookup_fnfields_1			(tree, tree);
 extern tree lookup_fnfields_slot		(tree, tree);
+extern tree lookup_fnfields_slot_nolazy		(tree, tree);
 extern int class_method_index_for_fn		(tree, tree);
 extern tree lookup_fnfields			(tree, tree, int);
 extern tree lookup_member			(tree, tree, int, bool);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 97f593c..5f60eee 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -1335,10 +1335,11 @@ lookup_conversion_operator (tree class_type, tree type)
 }
 
 /* TYPE is a class type. Return the index of the fields within
-   the method vector with name NAME, or -1 if no such field exists.  */
+   the method vector with name NAME, or -1 if no such field exists.
+   Does not lazily declare implicitly-declared member functions.  */
 
-int
-lookup_fnfields_1 (tree type, tree name)
+static int
+lookup_fnfields_idx_nolazy (tree type, tree name)
 {
   VEC(tree,gc) *method_vec;
   tree fn;
@@ -1348,34 +1349,6 @@ lookup_fnfields_1 (tree type, tree name)
   if (!CLASS_TYPE_P (type))
 return -1;
 
-  if (COMPLETE_TYPE_P (type))
-{
-  if ((name == ctor_identifier
-	   || name == base_ctor_identifier
-	   || name == complete_ctor_identifier))
-	{
-	  if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
-	lazily_declare_fn (sfk_constructor, type);
-	  if (CLASSTYPE_LAZY_COPY_CTOR (type))
-	lazily_declare_fn (sfk_copy_constructor, type);
-	  if (CLASSTYPE_LAZY_MOVE_CTOR (type))
-	lazily_declare_fn (sfk_move_constructor, type);
-	}
-  else if (name == ansi_assopname (NOP_EXPR))
-	{
-	  if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
-	lazily_declare_fn (sfk_copy_assignment, type);
-	  if (CLASSTYPE_LAZY_MOVE_ASSIGN (type))
-	lazily_declare_fn (sfk_move_assignment, type);
-	}
-  else if ((name == dtor_identifier
-		|| name == base_dtor_identifier
-		|| name == complete_dtor_identifier
-		|| name == deleting_dtor_identifier)
-	CLASSTYPE_LAZY_DESTRUCTOR (type))
-	lazily_declare_fn (sfk_destructor, type);
-}
-
   method_vec = CLASSTYPE_METHOD_VEC (type);
   if (!method_vec)
 return -1;
@@ -1445,6 +1418,46 @@ lookup_fnfields_1 (tree type, tree name)
   return -1;
 }
 
+/* TYPE is a class type. Return the index of the fields within
+   the method vector with name NAME, or -1 if no such field exists.  */
+
+int
+lookup_fnfields_1 (tree type, tree name)
+{
+  if (!CLASS_TYPE_P (type))
+return -1;
+
+  if (COMPLETE_TYPE_P (type))
+{
+  if ((name == ctor_identifier
+	   || name == base_ctor_identifier
+	   || name == complete_ctor_identifier))
+	{
+	  if (CLASSTYPE_LAZY_DEFAULT_CTOR (type))
+	lazily_declare_fn (sfk_constructor, type);
+	  if (CLASSTYPE_LAZY_COPY_CTOR (type))
+	lazily_declare_fn (sfk_copy_constructor, type);
+	  if (CLASSTYPE_LAZY_MOVE_CTOR (type))
+	lazily_declare_fn (sfk_move_constructor, type);
+	}
+  else if (name == ansi_assopname (NOP_EXPR))
+	{
+	  if (CLASSTYPE_LAZY_COPY_ASSIGN (type))
+	

Re: C++ PATCH for c++/50500 (DR 1082, implicitly declared copy in class with move)

2011-10-29 Thread Eric Botcazou
 DR 1082 changed the rules for implicitly declared copy constructors and
 assignment operators in the presence of move ctor/op= such that if
 either move operation is present, instead of being suppressed the copy
 operations will still be declared, but as deleted.

We have detected a side effect of this change by means of -fdump-ada-spec: 
implicit copy assignment operators are now generated in simple cases where 
they were not previously generated, for example:

templateclass T, class U class Generic_Array
{
  Generic_Array();
  void mf(T t, U u);
};

template class Generic_Arraychar, int;  // explicit instantiation


This is because, during the call to lazily_declare_fn on sfk_copy_constructor, 
the new code:

  /* [class.copy]/8 If the class definition declares a move constructor or
 move assignment operator, the implicitly declared copy constructor is
 defined as deleted */
  if ((sfk == sfk_copy_assignment
   || sfk == sfk_copy_constructor)
   (type_has_user_declared_move_constructor (type)
  || type_has_user_declared_move_assign (type)))
DECL_DELETED_FN (fn) = true;

is invoked, and type_has_user_declared_move_assign has the side effect of 
causing lazily_declare_fn to be called on sfk_copy_assignment through the call 
to lookup_fnfields_slot:

bool
type_has_user_declared_move_assign (tree t)
{
  tree fns;

  if (CLASSTYPE_LAZY_MOVE_ASSIGN (t))
return false;

  for (fns = lookup_fnfields_slot (t, ansi_assopname (NOP_EXPR));
   fns; fns = OVL_NEXT (fns))
{
  tree fn = OVL_CURRENT (fns);
  if (move_fn_p (fn)  !DECL_ARTIFICIAL (fn))
return true;
}

  return false;
}


Is that expected?

-- 
Eric Botcazou