diff mbox series

[C++] more conversion operator changes

Message ID 6ddc1630-1b5a-56c4-7682-9fffc4505b58@acm.org
State New
Headers show
Series [C++] more conversion operator changes | expand

Commit Message

Nathan Sidwell Sept. 5, 2017, 8:17 p.m. UTC
This patch moves add_method's management of METHOD_VEC into a new 
function in name-lookup.c.  That function will create a slot, if there 
isn't one with the requested name -- we know in that case that 
add_method will succeed in adding the new method.  The one quirk is the 
IDENTIFIER_BINDING machinery, which will perform a lookup in that case, 
so we have to protect lookup_fnfields_nolazy.

I moved the TYPE_HAS_CONVERSION setting into 
grok_special_member_properties, as that seemed a more appropriate location.

Finally I gave the conversion-operator marker function a FUNCTION_TYPE. 
that stops the tree_dumping machinery from barfing, which is annoying 
inside GDB.

Applied to trunk.

nathan
diff mbox series

Patch

2017-09-05  Nathan Sidwell  <nathan@acm.org>

	* class.c (add_method): Move slot search and insertion to ...
	* name-lookup.c (get_method_slot): ... this new function.
	(lookup_fnfields_slot_nolazy): Cope with NULL slot.
	* name-lookup.h (get_method_slot): Declare.
	* decl.c (cxx_init_decl_processinng): Give conv_op_marker a more
	realistic type.
	(grok_special_member_properties): Set
	TYPE_HAS_CONVERSION. Expicitly look at DECL_NAME for specialness.
	Improve TYPE_HAS_CONSTEXPR_CTOR setting.	

Index: class.c
===================================================================
--- class.c	(revision 251724)
+++ class.c	(working copy)
@@ -1011,57 +1011,12 @@  add_method (tree type, tree method, bool
   if (method == error_mark_node)
     return false;
 
-  vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (type);
-  if (!method_vec)
-    {
-      /* Make a new method vector.  We start with 8 entries.  */
-      vec_alloc (method_vec, 8);
-      CLASSTYPE_METHOD_VEC (type) = method_vec;
-    }
-
   /* Maintain TYPE_HAS_USER_CONSTRUCTOR, etc.  */
   grok_special_member_properties (method);
 
-  bool insert_p = true;
-  tree method_name = DECL_NAME (method);
-  bool complete_p = COMPLETE_TYPE_P (type);
-  bool conv_p = IDENTIFIER_CONV_OP_P (method_name);
-
-  if (conv_p)
-    method_name = conv_op_identifier;
-
-  /* See if we already have an entry with this name.  */
-  unsigned slot;
-  tree m;
-  for (slot = 0; vec_safe_iterate (method_vec, slot, &m); ++slot)
-    {
-      m = DECL_NAME (OVL_FIRST (m));
-      if (m == method_name)
-	{
-	  insert_p = false;
-	  break;
-	}
-      if (complete_p && m > method_name)
-	break;
-    }
-  tree current_fns = insert_p ? NULL_TREE : (*method_vec)[slot];
+  tree *slot = get_method_slot (type, DECL_NAME (method));
+  tree current_fns = *slot;
 
-  tree conv_marker = NULL_TREE;
-  if (conv_p)
-    {
-      /* For conversion operators, we prepend a dummy overload
-	 pointing at conv_op_marker.  That function's DECL_NAME is
-	 conv_op_identifier, so we can use identifier equality to
-	 locate it.  */
-      if (current_fns)
-	{
-	  gcc_checking_assert (OVL_FUNCTION (current_fns) == conv_op_marker);
-	  conv_marker = current_fns;
-	  current_fns = OVL_CHAIN (current_fns);
-	}
-      else
-	conv_marker = ovl_make (conv_op_marker, NULL_TREE);
-    }
   gcc_assert (!DECL_EXTERN_C_P (method));
 
   /* Check to see if we've already got this method.  */
@@ -1209,36 +1164,11 @@  add_method (tree type, tree method, bool
 
   current_fns = ovl_insert (method, current_fns, via_using);
 
-  if (conv_p)
-    {
-      TYPE_HAS_CONVERSION (type) = 1;
-      /* Prepend the marker function.  */
-      OVL_CHAIN (conv_marker) = current_fns;
-      current_fns = conv_marker;
-    }
-  else if (!complete_p && !IDENTIFIER_CDTOR_P (DECL_NAME (method)))
+  if (!DECL_CONV_FN_P (method) && !COMPLETE_TYPE_P (type))
     push_class_level_binding (DECL_NAME (method), current_fns);
 
-  if (insert_p)
-    {
-      bool reallocated;
+  *slot = current_fns;
 
-      /* We only expect to add few methods in the COMPLETE_P case, so
-	 just make room for one more method in that case.  */
-      if (complete_p)
-	reallocated = vec_safe_reserve_exact (method_vec, 1);
-      else
-	reallocated = vec_safe_reserve (method_vec, 1);
-      if (reallocated)
-	CLASSTYPE_METHOD_VEC (type) = method_vec;
-      if (slot == method_vec->length ())
-	method_vec->quick_push (current_fns);
-      else
-	method_vec->quick_insert (slot, current_fns);
-    }
-  else
-    /* Replace the current slot.  */
-    (*method_vec)[slot] = current_fns;
   return true;
 }
 
Index: decl.c
===================================================================
--- decl.c	(revision 251722)
+++ decl.c	(working copy)
@@ -4073,13 +4073,6 @@  cxx_init_decl_processing (void)
   noexcept_deferred_spec = build_tree_list (make_node (DEFERRED_NOEXCEPT),
 					    NULL_TREE);
 
-  /* Create the conversion operator marker.  This operator's DECL_NAME
-     is in the identifier table, so we can use identifier equality to
-     find it.  This has no type and no context, so we can't
-     accidentally think it a real function.  */
-  conv_op_marker = build_lang_decl (FUNCTION_DECL, conv_op_identifier,
-				    NULL_TREE);
-
 #if 0
   record_builtin_type (RID_MAX, NULL, string_type_node);
 #endif
@@ -4094,6 +4087,12 @@  cxx_init_decl_processing (void)
   void_ftype_ptr
     = build_exception_variant (void_ftype_ptr, empty_except_spec);
 
+  /* Create the conversion operator marker.  This operator's DECL_NAME
+     is in the identifier table, so we can use identifier equality to
+     find it.  */
+  conv_op_marker = build_lang_decl (FUNCTION_DECL, conv_op_identifier,
+				    void_ftype);
+
   /* C++ extensions */
 
   unknown_type_node = make_node (LANG_TYPE);
@@ -12793,7 +12792,7 @@  grok_special_member_properties (tree dec
     return;
 
   class_type = DECL_CONTEXT (decl);
-  if (DECL_CONSTRUCTOR_P (decl))
+  if (IDENTIFIER_CTOR_P (DECL_NAME (decl)))
     {
       int ctor = copy_fn_p (decl);
 
@@ -12823,10 +12822,10 @@  grok_special_member_properties (tree dec
 	TYPE_HAS_LIST_CTOR (class_type) = 1;
 
       if (DECL_DECLARED_CONSTEXPR_P (decl)
-	  && !copy_fn_p (decl) && !move_fn_p (decl))
+	  && !ctor && !move_fn_p (decl))
 	TYPE_HAS_CONSTEXPR_CTOR (class_type) = 1;
     }
-  else if (DECL_OVERLOADED_OPERATOR_P (decl) == NOP_EXPR)
+  else if (DECL_NAME (decl) == cp_assignment_operator_id (NOP_EXPR))
     {
       /* [class.copy]
 
@@ -12847,6 +12846,9 @@  grok_special_member_properties (tree dec
       else if (move_fn_p (decl) && user_provided_p (decl))
 	TYPE_HAS_COMPLEX_MOVE_ASSIGN (class_type) = 1;
     }
+  else if (IDENTIFIER_CONV_OP_P (DECL_NAME (decl)))
+    TYPE_HAS_CONVERSION (class_type) = true;
+  
   /* Destructors are handled in check_methods.  */
 }
 
Index: name-lookup.c
===================================================================
--- name-lookup.c	(revision 251722)
+++ name-lookup.c	(working copy)
@@ -1155,13 +1155,18 @@  lookup_fnfields_slot_nolazy (tree type,
     }
   else
     for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i)
-      {
-	if (OVL_NAME (fns) == lookup)
-	  {
-	    val = fns;
-	    break;
-	  }
-      }
+      /* We can get a NULL binding during insertion of a new
+	 method name, because the identifier_binding machinery
+	 performs a lookup.  If we find such a NULL slot, that's
+	 the thing we were looking for, so we might as well bail
+	 out immediately.  */
+      if (!fns)
+	break;
+      else if (OVL_NAME (fns) == lookup)
+	{
+	  val = fns;
+	  break;
+	}
 
   /* Extract the conversion operators asked for, unless the general
      conversion operator was requested.   */
@@ -1312,6 +1317,74 @@  lookup_fnfields_slot (tree type, tree na
   return lookup_fnfields_slot_nolazy (type, name);
 }
 
+/* Find the slot containing overloads called 'NAME'.  If there is no
+   such slot, create an empty one.  KLASS might be complete at this
+   point, in which case we need to preserve ordering.  Deals with
+   conv_op marker handling.  */
+
+tree *
+get_method_slot (tree klass, tree name)
+{
+  bool complete_p = COMPLETE_TYPE_P (klass);
+  
+  vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (klass);
+  if (!method_vec)
+    {
+      vec_alloc (method_vec, 8);
+      CLASSTYPE_METHOD_VEC (klass) = method_vec;
+    }
+
+  if (IDENTIFIER_CONV_OP_P (name))
+    name = conv_op_identifier;
+
+  unsigned ix, length = method_vec->length ();
+  for (ix = 0; ix < length; ix++)
+    {
+      tree *slot = &(*method_vec)[ix];
+      tree fn_name = OVL_NAME (*slot);
+
+      if (fn_name == name)
+	{
+	  if (name == conv_op_identifier)
+	    {
+	      gcc_checking_assert (OVL_FUNCTION (*slot) == conv_op_marker);
+	      /* Skip the conv-op marker. */
+	      slot = &OVL_CHAIN (*slot);
+	    }
+	  return slot;
+	}
+
+      if (complete_p && fn_name > name)
+	break;
+    }
+
+  /* No slot found.  Create one at IX.  We know in this case that our
+     caller will succeed in adding the function.  */
+  if (complete_p)
+    {
+      /* Do exact allocation when complete, as we don't expect to add
+	 many.  */
+      vec_safe_reserve_exact (method_vec, 1);
+      method_vec->quick_insert (ix, NULL_TREE);
+    }
+  else
+    {
+      gcc_checking_assert (ix == length);
+      vec_safe_push (method_vec, NULL_TREE);
+    }
+  CLASSTYPE_METHOD_VEC (klass) = method_vec;
+
+  tree *slot = &(*method_vec)[ix];
+  if (name == conv_op_identifier)
+    {
+      /* Install the marker prefix.  */
+      *slot = ovl_make (conv_op_marker, NULL_TREE);
+      slot = &OVL_CHAIN (*slot);
+    }
+
+  return slot;
+}
+
 static struct {
   gt_pointer_operator new_value;
   void *cookie;
Index: name-lookup.h
===================================================================
--- name-lookup.h	(revision 251722)
+++ name-lookup.h	(working copy)
@@ -322,6 +322,7 @@  extern tree lookup_arg_dependent (tree,
 extern tree lookup_field_1			(tree, tree, bool);
 extern tree lookup_fnfields_slot		(tree, tree);
 extern tree lookup_fnfields_slot_nolazy		(tree, tree);
+extern tree *get_method_slot (tree klass, tree name);
 extern void resort_type_method_vec (void *, void *,
 				    gt_pointer_operator, void *);
 extern void set_class_bindings (tree);