class.c (add_method): Move slot search and insertion to ...
authorNathan Sidwell <nathan@acm.org>
Tue, 5 Sep 2017 20:13:10 +0000 (20:13 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Tue, 5 Sep 2017 20:13:10 +0000 (20:13 +0000)
* 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.

From-SVN: r251737

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/decl.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h

index 6d31718..637b788 100644 (file)
@@ -1,5 +1,15 @@
 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.        
+
        * cp-tree.h (lang_decl_base): Rename template_conv_p to
        unknown_bound_p.
        (DECL_CONV_FN_P): Don't check NULL DECL_NAME.
index 9e740db..d04c2ac 100644 (file)
@@ -1011,57 +1011,12 @@ add_method (tree type, tree method, bool via_using)
   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 via_using)
 
   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 861dfcf..da5e16b 100644 (file)
@@ -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 decl)
     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 decl)
        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 decl)
       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 f4b9ff1..eacd515 100644 (file)
@@ -1155,13 +1155,18 @@ lookup_fnfields_slot_nolazy (tree type, tree name)
     }
   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 name)
   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 94d2aaa..aa96e15 100644 (file)
@@ -322,6 +322,7 @@ extern tree lookup_arg_dependent (tree, tree, vec<tree, va_gc> *);
 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);