Conversion operators have a special name
authorNathan Sidwell <nathan@acm.org>
Fri, 25 Aug 2017 11:37:10 +0000 (11:37 +0000)
committerNathan Sidwell <nathan@gcc.gnu.org>
Fri, 25 Aug 2017 11:37:10 +0000 (11:37 +0000)
Conversion operators have a special name
* cp-tree.h (CPTI_CONV_OP_MARKER, CPTI_CONV_OP_IDENTIFIER): New.
(conv_op_marker, conv_op_identifier): New.
(CLASSTYPE_FIRST_CONVERSION_SLOT): Delete.
* decl.c (initialize_predefined_identifiers): Add
conv_op_identifier.
(cxx_init_decl_processing): Create conv_op_marker.
* decl2.c (check_classfn): Lookup conv-ops by name.
* class.c (add_method): Use conv_op_identifier & conv_op_marker.
(resort_type_method_vec): Don't skip conv-ops.
(finish_struct_methods, warn_hidden): Likewise.
* name-lookup.h (lookup_all_conversions): Delete.
* name-lookup.c (lookup_conversion_operator): Replace with ...
(extract_conversion_operator): ... this.
(lookup_fnfields_slot_nolazy): Find conv-ops by name.
(lookup_all_conversions): Delete.
* pt.c (check_explicit_specialization): Find conv-ops by name.
* search.c (lookup_conversions_r): Likewise.

From-SVN: r251348

gcc/cp/ChangeLog
gcc/cp/class.c
gcc/cp/cp-tree.h
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/cp/pt.c
gcc/cp/search.c

index 92ecf91a23ea39c0fedb7d8a16f715cb3b4e4469..3557e4881dcdc78065ecf7149f1ef5a5d94d16cf 100644 (file)
@@ -1,3 +1,24 @@
+2017-08-25  Nathan Sidwell  <nathan@acm.org>
+
+       Conversion operators have a special name
+       * cp-tree.h (CPTI_CONV_OP_MARKER, CPTI_CONV_OP_IDENTIFIER): New.
+       (conv_op_marker, conv_op_identifier): New.
+       (CLASSTYPE_FIRST_CONVERSION_SLOT): Delete.
+       * decl.c (initialize_predefined_identifiers): Add
+       conv_op_identifier.
+       (cxx_init_decl_processing): Create conv_op_marker.
+       * decl2.c (check_classfn): Lookup conv-ops by name.
+       * class.c (add_method): Use conv_op_identifier & conv_op_marker.
+       (resort_type_method_vec): Don't skip conv-ops.
+       (finish_struct_methods, warn_hidden): Likewise.
+       * name-lookup.h (lookup_all_conversions): Delete.
+       * name-lookup.c (lookup_conversion_operator): Replace with ...
+       (extract_conversion_operator): ... this.
+       (lookup_fnfields_slot_nolazy): Find conv-ops by name.
+       (lookup_all_conversions): Delete.
+       * pt.c (check_explicit_specialization): Find conv-ops by name.
+       * search.c (lookup_conversions_r): Likewise.
+
 2017-08-24  Nathan Sidwell  <nathan@acm.org>
 
        Conversion operators kept on single overload set
index a08ce89c66e7442a714fb6de2aa8db1389218836..fc37bd8aa9c8e0085068fdfe453a6e7308d67b46 100644 (file)
@@ -1017,9 +1017,6 @@ add_method (tree type, tree method, bool via_using)
   if (method == error_mark_node)
     return false;
 
-  bool complete_p = COMPLETE_TYPE_P (type);
-  bool conv_p = DECL_CONV_FN_P (method);
-
   vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (type);
   if (!method_vec)
     {
@@ -1032,32 +1029,45 @@ add_method (tree type, tree method, bool via_using)
   grok_special_member_properties (method);
 
   bool insert_p = true;
-  unsigned slot;
-  tree m;
+  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.  */
-  for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT;
-       vec_safe_iterate (method_vec, slot, &m);
-       ++slot)
+  unsigned slot;
+  tree m;
+  for (slot = 0; vec_safe_iterate (method_vec, slot, &m); ++slot)
     {
-      m = OVL_FIRST (m);
-      if (conv_p)
-       {
-         if (DECL_CONV_FN_P (m))
-           insert_p = false;
-         break;
-       }
-      if (DECL_NAME (m) == DECL_NAME (method))
+      m = DECL_NAME (OVL_FIRST (m));
+      if (m == method_name)
        {
          insert_p = false;
          break;
        }
-      if (complete_p
-         && !DECL_CONV_FN_P (m)
-         && DECL_NAME (m) > DECL_NAME (method))
+      if (complete_p && m > method_name)
        break;
     }
   tree current_fns = insert_p ? NULL_TREE : (*method_vec)[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.  */
@@ -1206,7 +1216,12 @@ 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;
+    {
+      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)))
     push_class_level_binding (DECL_NAME (method), current_fns);
 
@@ -2294,23 +2309,10 @@ resort_type_method_vec (void* obj,
 {
   if (vec<tree, va_gc> *method_vec = (vec<tree, va_gc> *) obj)
     {
-      int len = method_vec->length ();
-      int slot;
-
-      /* The type conversion ops have to live at the front of the vec, so we
-        can't sort them.  */
-      for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT;
-          slot < len; slot++)
-       if (!DECL_CONV_FN_P (OVL_FIRST ((*method_vec)[slot])))
-         break;
-
-      if (len > slot + 1)
-       {
-         resort_data.new_value = new_value;
-         resort_data.cookie = cookie;
-         qsort (method_vec->address () + slot, len - slot, sizeof (tree),
-                resort_method_name_cmp);
-       }
+      resort_data.new_value = new_value;
+      resort_data.cookie = cookie;
+      qsort (method_vec->address (), method_vec->length (), sizeof (tree),
+            resort_method_name_cmp);
     }
 }
 
@@ -2323,15 +2325,10 @@ resort_type_method_vec (void* obj,
 static void
 finish_struct_methods (tree t)
 {
-  vec<tree, va_gc> *method_vec;
-  int slot, len;
-
-  method_vec = CLASSTYPE_METHOD_VEC (t);
+  vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (t);
   if (!method_vec)
     return;
 
-  len = method_vec->length ();
-
   /* Clear DECL_IN_AGGR_P for all functions.  */
   for (tree fn = TYPE_FIELDS (t); fn; fn = DECL_CHAIN (fn))
     if (DECL_DECLARES_FUNCTION_P (fn))
@@ -2341,17 +2338,8 @@ finish_struct_methods (tree t)
      no methods, then some public defaults are generated.  */
   maybe_warn_about_overly_private_class (t);
 
-  /* The type conversion ops have to live at the front of the vec, so we
-     can't sort them.  */
-  tree fn_fields;
-  for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT;
-       method_vec->iterate (slot, &fn_fields);
-       ++slot)
-    if (!DECL_CONV_FN_P (OVL_FIRST (fn_fields)))
-      break;
-  if (len - slot > 1)
-    qsort (method_vec->address () + slot,
-          len-slot, sizeof (tree), method_name_cmp);
+  qsort (method_vec->address (), method_vec->length (),
+        sizeof (tree), method_name_cmp);
 }
 
 /* Make BINFO's vtable have N entries, including RTTI entries,
@@ -3000,12 +2988,9 @@ warn_hidden (tree t)
 {
   vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (t);
   tree fns;
-  size_t i;
 
   /* We go through each separately named virtual function.  */
-  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
-       vec_safe_iterate (method_vec, i, &fns);
-       ++i)
+  for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i)
     {
       tree fndecl;
       tree base_binfo;
index b915bd9603fb92ac94ba9c82ef465c56a5d85ceb..d04c00cf4cf90a98a8eb712075a7bc58e42b630d 100644 (file)
@@ -125,6 +125,7 @@ enum cp_tree_index
     CPTI_TYPE_INFO_PTR_TYPE,
     CPTI_ABORT_FNDECL,
     CPTI_AGGR_TAG,
+    CPTI_CONV_OP_MARKER,
 
     CPTI_CTOR_IDENTIFIER,
     CPTI_COMPLETE_CTOR_IDENTIFIER,
@@ -133,6 +134,7 @@ enum cp_tree_index
     CPTI_COMPLETE_DTOR_IDENTIFIER,
     CPTI_BASE_DTOR_IDENTIFIER,
     CPTI_DELETING_DTOR_IDENTIFIER,
+    CPTI_CONV_OP_IDENTIFIER,
     CPTI_DELTA_IDENTIFIER,
     CPTI_IN_CHARGE_IDENTIFIER,
     CPTI_VTT_PARM_IDENTIFIER,
@@ -199,6 +201,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define global_type_node               cp_global_trees[CPTI_GLOBAL_TYPE]
 #define const_type_info_type_node      cp_global_trees[CPTI_CONST_TYPE_INFO_TYPE]
 #define type_info_ptr_type             cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE]
+#define conv_op_marker                 cp_global_trees[CPTI_CONV_OP_MARKER]
 #define abort_fndecl                   cp_global_trees[CPTI_ABORT_FNDECL]
 #define current_aggr                   cp_global_trees[CPTI_AGGR_TAG]
 #define nullptr_node                   cp_global_trees[CPTI_NULLPTR]
@@ -239,6 +242,10 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 /* The name of a destructor that destroys virtual base classes, and
    then deletes the entire object.  */
 #define deleting_dtor_identifier       cp_global_trees[CPTI_DELETING_DTOR_IDENTIFIER]
+/* The name used for conversion operators -- but note that actual
+   conversion functions use special identifiers outside the identifier
+   table.  */
+#define conv_op_identifier             cp_global_trees[CPTI_CONV_OP_IDENTIFIER]
 
 /* The name of the identifier used internally to represent operator CODE.  */
 #define cp_operator_id(CODE) \
@@ -2148,10 +2155,6 @@ struct GTY(()) lang_type {
    and the RECORD_TYPE for the class template otherwise.  */
 #define CLASSTYPE_DECL_LIST(NODE) (LANG_TYPE_CLASS_CHECK (NODE)->decl_list)
 
-/* The first slot in the CLASSTYPE_METHOD_VEC where conversion
-   operators can appear.  */
-#define CLASSTYPE_FIRST_CONVERSION_SLOT 0
-
 /* A FUNCTION_DECL or OVERLOAD for the constructors for NODE.  These
    are the constructors that take an in-charge parameter.  */
 #define CLASSTYPE_CONSTRUCTORS(NODE) \
index a9d72c0f30d168f147c177a235d3a2f1f508e032..bd6926a486a9f8ad458457a37c1c79ffc4f094b4 100644 (file)
@@ -3979,6 +3979,7 @@ initialize_predefined_identifiers (void)
     {"__dt_base ", &base_dtor_identifier, cik_dtor},
     {"__dt_comp ", &complete_dtor_identifier, cik_dtor},
     {"__dt_del ", &deleting_dtor_identifier, cik_dtor},
+    {"__conv_op ", &conv_op_identifier, cik_conv_op},
     {"__in_chrg", &in_charge_identifier, cik_normal},
     {"this", &this_identifier, cik_normal},
     {"__delta", &delta_identifier, cik_normal},
@@ -4072,6 +4073,13 @@ 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
index 66d206ea851b351307814be01968e84458e190f4..0f828b57396365684ce06ca5a6a6c91b899ffe58 100644 (file)
@@ -664,7 +664,7 @@ check_classfn (tree ctype, tree function, tree template_parms)
       else
        {
          if (DECL_CONV_FN_P (function))
-           fns = lookup_all_conversions (ctype);
+           fns = lookup_fnfields_slot (ctype, conv_op_identifier);
 
          error_at (DECL_SOURCE_LOCATION (function),
                    "no declaration matches %q#D", function);
index 3d69e1d1c2eb09c9f1a41215c6873f7c1475bdb4..df29331b95db55f5c6f0ccae9bf7317f86a719ea 100644 (file)
@@ -1089,37 +1089,27 @@ lookup_arg_dependent (tree name, tree fns, vec<tree, va_gc> *args)
   return fns;
 }
 
-/* Return the conversion operators in CLASS_TYPE corresponding to
-   "operator TYPE ()".  Only CLASS_TYPE itself is searched; this
-   routine does not scan the base classes of CLASS_TYPE.  */
+/* FNS is an overload set of conversion functions.  Return the
+   overloads converting to TYPE.  */
 
 static tree
-lookup_conversion_operator (tree class_type, tree type)
+extract_conversion_operator (tree fns, tree type)
 {
   tree convs = NULL_TREE;
+  tree tpls = NULL_TREE;
 
-  if (TYPE_HAS_CONVERSION (class_type))
+  for (ovl_iterator iter (fns); iter; ++iter)
     {
-      tree fns = NULL_TREE;
-      tree tpls = NULL_TREE;
-      vec<tree, va_gc> *methods = CLASSTYPE_METHOD_VEC (class_type);
+      if (same_type_p (DECL_CONV_FN_TYPE (*iter), type))
+       convs = lookup_add (*iter, convs);
 
-      vec_safe_iterate (methods, CLASSTYPE_FIRST_CONVERSION_SLOT, &fns);
-      if (fns && !DECL_CONV_FN_P (OVL_FIRST (fns)))
-       fns = NULL_TREE;
-      for (ovl_iterator iter (fns); iter; ++iter)
-       {
-         if (same_type_p (DECL_CONV_FN_TYPE (*iter), type))
-           convs = lookup_add (*iter, convs);
-
-         if (TREE_CODE (*iter) == TEMPLATE_DECL)
-           tpls = lookup_add (*iter, tpls);
-       }
-
-      if (!convs)
-       convs = tpls;
+      if (TREE_CODE (*iter) == TEMPLATE_DECL)
+       tpls = lookup_add (*iter, tpls);
     }
 
+  if (!convs)
+    convs = tpls;
+
   return convs;
 }
 
@@ -1134,48 +1124,56 @@ lookup_fnfields_slot_nolazy (tree type, tree name)
   if (!method_vec)
     return NULL_TREE;
 
-  if (IDENTIFIER_CONV_OP_P (name))
-    return lookup_conversion_operator (type, TREE_TYPE (name));
-
-  /* Skip the conversion operators.  */
-  int i;
+  /* Conversion operators can only be found by the marker conversion
+     operator name.  */
+  bool conv_op = IDENTIFIER_CONV_OP_P (name);
+  tree lookup = conv_op ? conv_op_identifier : name;
+  tree val = NULL_TREE;
   tree fns;
-  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT;
-       vec_safe_iterate (method_vec, i, &fns);
-       ++i)
-    if (!DECL_CONV_FN_P (OVL_FIRST (fns)))
-      break;
 
   /* If the type is complete, use binary search.  */
   if (COMPLETE_TYPE_P (type))
     {
-      int lo;
-      int hi;
-
-      lo = i;
-      hi = method_vec->length ();
+      int lo = 0;
+      int hi = method_vec->length ();
       while (lo < hi)
        {
-         i = (lo + hi) / 2;
+         int i = (lo + hi) / 2;
 
          fns = (*method_vec)[i];
          tree fn_name = OVL_NAME (fns);
-         if (fn_name > name)
+         if (fn_name > lookup)
            hi = i;
-         else if (fn_name < name)
+         else if (fn_name < lookup)
            lo = i + 1;
          else
-           return fns;
+           {
+             val = fns;
+             break;
+           }
        }
     }
   else
-    for (; vec_safe_iterate (method_vec, i, &fns); ++i)
+    for (int i = 0; vec_safe_iterate (method_vec, i, &fns); ++i)
       {
-       if (OVL_NAME (fns) == name)
-         return fns;
+       if (OVL_NAME (fns) == lookup)
+         {
+           val = fns;
+           break;
+         }
       }
 
-  return NULL_TREE;
+  /* Extract the conversion operators asked for, unless the general
+     conversion operator was requested.   */
+  if (val && conv_op)
+    {
+      gcc_checking_assert (OVL_FUNCTION (val) == conv_op_marker);
+      val = OVL_CHAIN (val);
+      if (tree type = TREE_TYPE (name))
+       val = extract_conversion_operator (val, type);
+    }
+
+  return val;
 }
 
 /* Do a 1-level search for NAME as a member of TYPE.  The caller must
@@ -1314,30 +1312,6 @@ lookup_fnfields_slot (tree type, tree name)
   return lookup_fnfields_slot_nolazy (type, name);
 }
 
-/* Collect all the conversion operators of KLASS.  */
-
-tree
-lookup_all_conversions (tree klass)
-{
-  tree lkp = NULL_TREE;
-
-  if (vec<tree, va_gc> *methods = CLASSTYPE_METHOD_VEC (klass))
-    {
-      tree ovl;
-      for (int idx = CLASSTYPE_FIRST_CONVERSION_SLOT;
-          methods->iterate (idx, &ovl); ++idx)
-       {
-         if (!DECL_CONV_FN_P (OVL_FIRST (ovl)))
-           /* There are no more conversion functions.  */
-           break;
-
-         lkp = lookup_add (ovl, lkp);
-       }
-    }
-
-  return lkp;
-}
-
 /* Compute the chain index of a binding_entry given the HASH value of its
    name and the total COUNT of chains.  COUNT is assumed to be a power
    of 2.  */
index 1f671479fecc2e490f165b66e714a6c9acd626a1..99f9b9bb45d2d0ff63cc227b37575df13cff7162 100644 (file)
@@ -322,7 +322,6 @@ 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 lookup_all_conversions             (tree);
 extern tree innermost_non_namespace_value (tree);
 extern cxx_binding *outer_binding (tree, cxx_binding *, bool);
 extern void cp_emit_debug_info_for_using (tree, tree);
index 8d816c732447553d2fb062c7795169d2d081ed6f..564ffb05f28849126da8a7af442f103aa5365de6 100644 (file)
@@ -2894,16 +2894,13 @@ check_explicit_specialization (tree declarator,
              name = DECL_NAME (decl);
            }
 
-         tree fns = NULL_TREE;
-         if (DECL_CONV_FN_P (decl))
-           /* For a type-conversion operator, we cannot do a
-              name-based lookup.  We might be looking for `operator
-              int' which will be a specialization of `operator T'.
-              Grab all the conversion operators, and then select from
-              them.  */
-           fns = lookup_all_conversions (ctype);
-         else
-           fns = lookup_fnfields_slot_nolazy (ctype, name);
+         /* For a type-conversion operator, We might be looking for
+            `operator int' which will be a specialization of
+            `operator T'.  Grab all the conversion operators, and
+            then select from them.  */
+         tree fns = lookup_fnfields_slot_nolazy (ctype,
+                                                 IDENTIFIER_CONV_OP_P (name)
+                                                 ? conv_op_identifier : name);
 
          if (fns == NULL_TREE)
            {
index 31f4dd66b9f416eb408c43b1839d6a19647b9930..266d8dd36d6e3678475b59207b6acb05835a3a3a 100644 (file)
@@ -2370,12 +2370,8 @@ lookup_conversions_r (tree binfo, int virtual_depth, int virtualness,
     virtual_depth++;
 
   /* First, locate the unhidden ones at this level.  */
-  vec<tree, va_gc> *method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
-  tree conv = NULL_TREE;
-  vec_safe_iterate (method_vec, CLASSTYPE_FIRST_CONVERSION_SLOT, &conv);
-  if (conv && !DECL_CONV_FN_P (OVL_FIRST (conv)))
-    conv = NULL_TREE;
-
+  tree conv = lookup_fnfields_slot_nolazy (BINFO_TYPE (binfo),
+                                          conv_op_identifier);
   for (ovl_iterator iter (conv); iter; ++iter)
     {
       tree fn = *iter;