OSDN Git Service

PR c++/11105
authormmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Jun 2003 16:58:19 +0000 (16:58 +0000)
committermmitchel <mmitchel@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 17 Jun 2003 16:58:19 +0000 (16:58 +0000)
* cp-tree.h (DECL_CONV_FN_TYPE): New method.
* mangle.c (struct globals): Remove internal_mangling_p.
(write_unqualified_name): Use DECL_CONV_FN_TYPE.
(write_template_parm): Don't write out the level number.
(conv_type_names): New variable.
(hash_type): New function.
(compare_type): Likewise.
(mangle_conv_op_name_for_type): Don't try to mangle conversion
operator names.
* search.c (lookup_conversion_operator): New function.
(lookup_fnfields_1): Use it.

PR c++/11105
* g++.dg/abi/conv1.C: Remove it.
* g++.dg/template/conv7.C: New test.
* g++.dg/template/conv8.C: Likewise.
* g++.old-deja/g++.ext/pretty2.C: Do not test __FUNCTION__ for a
conversion operator.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@68095 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/mangle.c
gcc/cp/search.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/abi/conv1.C [deleted file]
gcc/testsuite/g++.dg/template/conv7.C [new file with mode: 0644]
gcc/testsuite/g++.dg/template/conv8.C [new file with mode: 0644]
gcc/testsuite/g++.old-deja/g++.ext/pretty2.C

index 63eb324..a3585fc 100644 (file)
@@ -1,3 +1,18 @@
+2003-06-17  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/11105
+       * cp-tree.h (DECL_CONV_FN_TYPE): New method.
+       * mangle.c (struct globals): Remove internal_mangling_p.
+       (write_unqualified_name): Use DECL_CONV_FN_TYPE.
+       (write_template_parm): Don't write out the level number.
+       (conv_type_names): New variable.
+       (hash_type): New function.
+       (compare_type): Likewise.
+       (mangle_conv_op_name_for_type): Don't try to mangle conversion
+       operator names.
+       * search.c (lookup_conversion_operator): New function.
+       (lookup_fnfields_1): Use it.
+
 2003-06-17  Andreas Jaeger  <aj@suse.de>
 
        * except.c: Remove duplicate declaration of push_eh_cleanup.
index 6ed177e..aeae231 100644 (file)
@@ -1856,6 +1856,11 @@ struct lang_decl GTY(())
 #define DECL_CONV_FN_P(NODE) \
   (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)))
 
+/* If FN is a conversion operator, the type to which it converts.
+   Otherwise, NULL_TREE.  */
+#define DECL_CONV_FN_TYPE(FN) \
+  (DECL_CONV_FN_P (FN) ? TREE_TYPE (DECL_NAME (FN)) : NULL_TREE)
+
 /* Nonzero if NODE, which is a TEMPLATE_DECL, is a template
    conversion operator to a type dependent on the innermost template
    args.  */
index c0d31ba..4c53662 100644 (file)
@@ -102,11 +102,6 @@ static struct globals
   /* The entity that is being mangled.  */
   tree entity;
 
-  /* We are mangling an internal symbol. It is important to keep those
-     involving template parmeters distinct by distinguishing their level
-     and, for non-type parms, their type.  */
-  bool internal_mangling_p;
-
   /* True if the mangling will be different in a future version of the
      ABI.  */
   bool need_abi_warning;
@@ -1006,7 +1001,7 @@ write_unqualified_name (const tree decl)
          type = TREE_TYPE (fn_type);
        }
       else
-       type = TREE_TYPE (DECL_NAME (decl));
+       type = DECL_CONV_FN_TYPE (decl);
       write_conversion_operator_name (type);
     }
   else if (DECL_OVERLOADED_OPERATOR_P (decl))
@@ -2250,15 +2245,6 @@ write_template_param (const tree parm)
   if (parm_index > 0)
     write_unsigned_number (parm_index - 1);
   write_char ('_');
-  if (G.internal_mangling_p)
-    {
-      if (parm_level > 0)
-       write_unsigned_number (parm_level - 1);
-      write_char ('_');
-      if (parm_type)
-       write_type (parm_type);
-      write_char ('_');
-    }
 }
 
 /*  <template-template-param>
@@ -2600,6 +2586,28 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
   return get_identifier (result);
 }
 
+/* This hash table maps TYPEs to the IDENTIFIER for a conversion
+   operator to TYPE.  The nodes are TREE_LISTs whose TREE_PURPOSE is
+   the TYPE and whose TREE_VALUE is the IDENTIFIER.  */
+
+static GTY ((param_is (union tree_node))) htab_t conv_type_names;
+
+/* Hash a node (VAL1) in the table.  */
+
+static hashval_t
+hash_type (const void *val)
+{
+  return htab_hash_pointer (TREE_PURPOSE (*((tree *) val)));
+}
+
+/* Compare VAL1 (a node in the table) with VAL2 (a TYPE).  */
+
+static int
+compare_type (const void *val1, const void *val2)
+{
+  return TREE_PURPOSE ((tree) val1) == (tree) val2;
+}
+
 /* Return an identifier for the mangled unqualified name for a
    conversion operator to TYPE.  This mangling is not specified by the
    ABI spec; it is only used internally.  */
@@ -2607,33 +2615,22 @@ mangle_thunk (tree fn_decl, const int this_adjusting, tree fixed_offset,
 tree
 mangle_conv_op_name_for_type (const tree type)
 {
+  void **slot;
   tree identifier;
-  const char *mangled_type;
-  char *op_name;
+  char buffer[64];
 
-  /* Build the internal mangling for TYPE.  */
-  G.internal_mangling_p = true;
-  mangled_type = mangle_type_string (type);
-  G.internal_mangling_p = false;
-  
-  /* Allocate a temporary buffer for the complete name.  */
-  op_name = concat ("operator ", mangled_type, NULL);
-  /* Find or create an identifier.  */
-  identifier = get_identifier (op_name);
-  /* Done with the temporary buffer.  */
-  free (op_name);
-
-  /* It had better be a unique mangling for the type.  */
-  if (IDENTIFIER_TYPENAME_P (identifier)
-      && !same_type_p (type, TREE_TYPE (identifier)))
-    {
-      /* In G++ 3.2, the name mangling scheme was ambiguous.  In later
-        versions of the ABI, this problem has been fixed.  */
-      if (abi_version_at_least (2))
-       abort ();
-      error ("due to a defect in the G++ 3.2 ABI, G++ has assigned the "
-            "same mangled name to two different types");
-    }
+  if (conv_type_names == NULL) 
+    conv_type_names = htab_create_ggc (31, &hash_type, &compare_type, NULL);
+
+  slot = htab_find_slot_with_hash (conv_type_names, type, 
+                                  htab_hash_pointer (type), INSERT);
+  if (*slot)
+    return TREE_VALUE ((tree) *slot);
+
+  /* Create a unique name corresponding to TYPE.  */
+  sprintf (buffer, "operator %d\n", htab_elements (conv_type_names));
+  identifier = get_identifier (buffer);
+  *slot = build_tree_list (type, identifier);
   
   /* Set bits on the identifier so we know later it's a conversion.  */
   IDENTIFIER_OPNAME_P (identifier) = 1;
index 0cc769e..3df6f73 100644 (file)
@@ -1338,99 +1338,144 @@ lookup_fnfields (tree xbasetype, tree name, int protect)
   return rval;
 }
 
+/* Return the index in the CLASSTYPE_METHOD_VEC for CLASS_TYPE
+   corresponding to "operator TYPE ()", or -1 if there is no such
+   operator.  Only CLASS_TYPE itself is searched; this routine does
+   not scan the base classes of CLASS_TYPE.  */
+
+static int
+lookup_conversion_operator (tree class_type, tree type)
+{
+  int pass;
+  int i;
+
+  tree methods = CLASSTYPE_METHOD_VEC (class_type);
+
+  for (pass = 0; pass < 2; ++pass)
+    for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
+        i < TREE_VEC_LENGTH (methods);
+        ++i)
+      {
+       tree fn = TREE_VEC_ELT (methods, i);
+       /* The size of the vector may have some unused slots at the
+          end.  */
+       if (!fn)
+         break;
+
+       /* All the conversion operators come near the beginning of the
+          class.  Therefore, if FN is not a conversion operator, there
+          is no matching conversion operator in CLASS_TYPE.  */
+       fn = OVL_CURRENT (fn);
+       if (!DECL_CONV_FN_P (fn))
+         break;
+       
+       if (pass == 0)
+         {
+           /* On the first pass we only consider exact matches.  If
+              the types match, this slot is the one where the right
+              conversion operators can be found.  */
+           if (TREE_CODE (fn) != TEMPLATE_DECL
+               && same_type_p (DECL_CONV_FN_TYPE (fn), type))
+             return i;
+         }
+       else
+         {
+           /* On the second pass we look for template conversion
+              operators.  It may be possible to instantiate the
+              template to get the type desired.  All of the template
+              conversion operators share a slot.  By looking for
+              templates second we ensure that specializations are
+              preferred over templates.  */
+           if (TREE_CODE (fn) == TEMPLATE_DECL)
+             return i;
+         }
+      }
+
+  return -1;
+}
+
 /* TYPE is a class type. Return the index of the fields within
    the method vector with name NAME, or -1 is no such field exists.  */
 
 int
 lookup_fnfields_1 (tree type, tree name)
 {
-  tree method_vec = (CLASS_TYPE_P (type)
-                    ? CLASSTYPE_METHOD_VEC (type)
-                    : NULL_TREE);
+  tree method_vec;
+  tree *methods;
+  tree tmp;
+  int i;
+  int len;
 
-  if (method_vec != 0)
-    {
-      register int i;
-      register tree *methods = &TREE_VEC_ELT (method_vec, 0);
-      int len = TREE_VEC_LENGTH (method_vec);
-      tree tmp;
+  if (!CLASS_TYPE_P (type))
+    return -1;
 
-#ifdef GATHER_STATISTICS
-      n_calls_lookup_fnfields_1++;
-#endif /* GATHER_STATISTICS */
+  method_vec = CLASSTYPE_METHOD_VEC (type);
+
+  if (!method_vec)
+    return -1;
+
+  methods = &TREE_VEC_ELT (method_vec, 0);
+  len = TREE_VEC_LENGTH (method_vec);
 
-      /* Constructors are first...  */
-      if (name == ctor_identifier)
-       return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] 
-               ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
-      /* and destructors are second.  */
-      if (name == dtor_identifier)
-       return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
-               ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
-
-      for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
-          i < len && methods[i]; 
-          ++i)
-       {
 #ifdef GATHER_STATISTICS
-         n_outer_fields_searched++;
+  n_calls_lookup_fnfields_1++;
 #endif /* GATHER_STATISTICS */
 
-         tmp = OVL_CURRENT (methods[i]);
-         if (DECL_NAME (tmp) == name)
-           return i;
-
-         /* If the type is complete and we're past the conversion ops,
-            switch to binary search.  */
-         if (! DECL_CONV_FN_P (tmp)
-             && COMPLETE_TYPE_P (type))
-           {
-             int lo = i + 1, hi = len;
+  /* Constructors are first...  */
+  if (name == ctor_identifier)
+    return (methods[CLASSTYPE_CONSTRUCTOR_SLOT] 
+           ? CLASSTYPE_CONSTRUCTOR_SLOT : -1);
+  /* and destructors are second.  */
+  if (name == dtor_identifier)
+    return (methods[CLASSTYPE_DESTRUCTOR_SLOT]
+           ? CLASSTYPE_DESTRUCTOR_SLOT : -1);
+  if (IDENTIFIER_TYPENAME_P (name))
+    return lookup_conversion_operator (type, TREE_TYPE (name));
+
+  /* Skip the conversion operators.  */
+  i = CLASSTYPE_FIRST_CONVERSION_SLOT;
+  while (i < len && methods[i] && DECL_CONV_FN_P (OVL_CURRENT (methods[i])))
+    i++;
+
+  /* If the type is complete, use binary search.  */
+  if (COMPLETE_TYPE_P (type))
+    {
+      int lo = i;
+      int hi = len;
 
-             while (lo < hi)
-               {
-                 i = (lo + hi) / 2;
+      while (lo < hi)
+       {
+         i = (lo + hi) / 2;
 
 #ifdef GATHER_STATISTICS
-                 n_outer_fields_searched++;
+         n_outer_fields_searched++;
 #endif /* GATHER_STATISTICS */
 
-                 tmp = methods[i];
-                 /* This slot may be empty; we allocate more slots
-                    than we need.  In that case, the entry we're
-                    looking for is closer to the beginning of the
-                    list. */
-                 if (tmp)
-                   tmp = DECL_NAME (OVL_CURRENT (tmp));
-                 if (!tmp || tmp > name)
-                   hi = i;
-                 else if (tmp < name)
-                   lo = i + 1;
-                 else
-                   return i;
-               }
-             break;
-           }
-       }
-
-      /* If we didn't find it, it might have been a template
-        conversion operator to a templated type.  If there are any,
-        such template conversion operators will all be overloaded on
-        the first conversion slot.  (Note that we don't look for this
-        case above so that we will always find specializations
-        first.)  */
-      if (IDENTIFIER_TYPENAME_P (name)) 
-       {
-         i = CLASSTYPE_FIRST_CONVERSION_SLOT;
-         if (i < len && methods[i])
-           {
-             tmp = OVL_CURRENT (methods[i]);
-             if (TREE_CODE (tmp) == TEMPLATE_DECL
-                 && DECL_TEMPLATE_CONV_FN_P (tmp))
-               return i;
-           }
+         tmp = methods[i];
+         /* This slot may be empty; we allocate more slots than we
+            need.  In that case, the entry we're looking for is
+            closer to the beginning of the list. */
+         if (tmp)
+           tmp = DECL_NAME (OVL_CURRENT (tmp));
+         if (!tmp || tmp > name)
+           hi = i;
+         else if (tmp < name)
+           lo = i + 1;
+         else
+           return i;
        }
     }
+  else
+    for (; i < len && methods[i]; ++i)
+      {
+#ifdef GATHER_STATISTICS
+       n_outer_fields_searched++;
+#endif /* GATHER_STATISTICS */
+       
+       tmp = OVL_CURRENT (methods[i]);
+       if (DECL_NAME (tmp) == name)
+         return i;
+      }
 
   return -1;
 }
index 8a2b084..9c1fcd2 100644 (file)
@@ -1,3 +1,12 @@
+2003-06-17  Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/11105
+       * g++.dg/abi/conv1.C: Remove it.
+       * g++.dg/template/conv7.C: New test.
+       * g++.dg/template/conv8.C: Likewise.
+       * g++.old-deja/g++.ext/pretty2.C: Do not test __FUNCTION__ for a
+       conversion operator.
+
 2003-06-17  Janis Johnson  <janis187@us.ibm.com>
 
        * gcc.dg/compat/compat-common.h (DEBUG_INIT): New.
diff --git a/gcc/testsuite/g++.dg/abi/conv1.C b/gcc/testsuite/g++.dg/abi/conv1.C
deleted file mode 100644 (file)
index fdedea2..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-// { dg-options "-fabi-version=1" }
-
-template<class T1>
-struct A {
-  typedef typename T1::X X;
-  operator X() const;
-};
-
-template <class T0, class T1 >
-struct B {
-  typedef typename T1::X X;
-  operator X() const; // { dg-error "" }
-};
diff --git a/gcc/testsuite/g++.dg/template/conv7.C b/gcc/testsuite/g++.dg/template/conv7.C
new file mode 100644 (file)
index 0000000..86758b3
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-options "-fabi-version=0" }
+
+template <typename T> struct S {
+    struct I{};
+    operator I* ();
+};
+
+template <typename T> struct S2 : S<T> {
+    operator typename S<T>::I* ();
+};
+
+template struct S2<int>;
diff --git a/gcc/testsuite/g++.dg/template/conv8.C b/gcc/testsuite/g++.dg/template/conv8.C
new file mode 100644 (file)
index 0000000..96f3b98
--- /dev/null
@@ -0,0 +1,12 @@
+// { dg-options "-fabi-version=1" }
+
+template <typename T> struct S {
+    struct I{};
+    operator I* ();
+};
+
+template <typename T> struct S2 : S<T> {
+    operator typename S<T>::I* ();
+};
+
+template struct S2<int>;
index 834ffa5..c309dc8 100644 (file)
@@ -1,5 +1,5 @@
 // { dg-do run  }
-// Copyright (C) 1999, 2000 Free Software Foundation, Inc.
+// Copyright (C) 1999, 2000, 2003 Free Software Foundation, Inc.
 // Contributed by Nathan Sidwell 21 Nov 1999 <nathan@acm.org>
 
 // make sure __FUNCTION__ and __PRETTY_FUNCTION__ work in member functions
@@ -68,8 +68,6 @@ X::operator int ()
   printf ("__FUNCTION__ %s\n", function);
   printf ("__PRETTY_FUNCTION__ %s\n", pretty);
   
-  if (strcmp (function, "operator i"))
-    bad = true;
   if (strcmp (pretty, "X::operator int()"))
     bad = true;
   return 0;