OSDN Git Service

2002-09-25 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / mangle.c
index 6736d1e..c7bd312 100644 (file)
@@ -1,5 +1,5 @@
-/* Name mangling for the new standard C++ ABI.
-   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+/* Name mangling for the 3.0 C++ ABI.
+   Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc.
    Written by Alex Samuel <sameul@codesourcery.com>
 
    This file is part of GNU CC.
@@ -51,6 +51,7 @@
 #include "system.h"
 #include "tree.h"
 #include "cp-tree.h"
+#include "real.h"
 #include "obstack.h"
 #include "toplev.h"
 #include "varray.h"
 /* Macros for tracing the write_* functions.  */
 #if DEBUG_MANGLE
 # define MANGLE_TRACE(FN, INPUT) \
-  fprintf (stderr, "  %-24s: %-24s\n", FN, INPUT)
+  fprintf (stderr, "  %-24s: %-24s\n", (FN), (INPUT))
 # define MANGLE_TRACE_TREE(FN, NODE) \
   fprintf (stderr, "  %-24s: %-24s (%p)\n", \
-           FN, tree_code_name[TREE_CODE (NODE)], (void *) NODE)
+           (FN), tree_code_name[TREE_CODE (NODE)], (void *) (NODE))
 #else
 # define MANGLE_TRACE(FN, INPUT)
 # define MANGLE_TRACE_TREE(FN, NODE)
 #endif
 
-/* Non-zero if NODE is a class template-id.  We can't rely on
+/* Nonzero if NODE is a class template-id.  We can't rely on
    CLASSTYPE_USE_TEMPLATE here because of tricky bugs in the parser
    that hard to distinguish A<T> from A, where A<T> is the type as
    instantiated outside of the template, and A is the type used
@@ -93,6 +94,11 @@ static struct globals
   /* An array of the current substitution candidates, in the order
      we've seen them.  */
   varray_type substitutions;
+
+  /* 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;
 } G;
 
 /* Indices into subst_identifiers.  These are identifiers used in
@@ -115,7 +121,7 @@ static tree subst_identifiers[SUBID_MAX];
 
 /* Single-letter codes for builtin integer types, defined in
    <builtin-type>.  These are indexed by integer_type_kind values.  */
-static char
+static const char
 integer_type_codes[itk_none] =
 {
   'c',  /* itk_char */
@@ -153,6 +159,7 @@ static void write_prefix PARAMS ((tree));
 static void write_template_prefix PARAMS ((tree));
 static void write_unqualified_name PARAMS ((tree));
 static void write_source_name PARAMS ((tree));
+static int hwint_to_ascii PARAMS ((unsigned HOST_WIDE_INT, unsigned int, char *, unsigned));
 static void write_number PARAMS ((unsigned HOST_WIDE_INT, int,
                                  unsigned int));
 static void write_integer_cst PARAMS ((tree));
@@ -189,7 +196,7 @@ static inline void start_mangling PARAMS ((void));
 static inline const char *finish_mangling PARAMS ((void));
 static tree mangle_special_for_type PARAMS ((tree, const char *));
 
-/* Foreign language functions. */
+/* Foreign language functions.  */
 
 static void write_java_integer_type_codes PARAMS ((tree));
 
@@ -198,17 +205,16 @@ static void write_java_integer_type_codes PARAMS ((tree));
 #define write_char(CHAR)                                              \
   obstack_1grow (&G.name_obstack, (CHAR))
 
+/* Append a sized buffer to the end of the mangled representation.  */
+#define write_chars(CHAR, LEN)                                        \
+  obstack_grow (&G.name_obstack, (CHAR), (LEN))
+
 /* Append a NUL-terminated string to the end of the mangled
    representation.  */
 #define write_string(STRING)                                          \
   obstack_grow (&G.name_obstack, (STRING), strlen (STRING))
 
-/* Return the position at which the next character will be appended to
-   the mangled representation.  */
-#define mangled_position()                                              \
-  obstack_object_size (&G.name_obstack)
-
-/* Non-zero if NODE1 and NODE2 are both TREE_LIST nodes and have the
+/* Nonzero if NODE1 and NODE2 are both TREE_LIST nodes and have the
    same purpose (context, which may be a type) and value (template
    decl).  See write_template_prefix for more information on what this
    is used for.  */
@@ -220,15 +226,11 @@ static void write_java_integer_type_codes PARAMS ((tree));
        || TREE_PURPOSE (NODE1) == TREE_PURPOSE (NODE2))             \
    && TREE_VALUE (NODE1) == TREE_VALUE (NODE2))
 
-/* Write out a signed quantity in base 10.  */
-#define write_signed_number(NUMBER) \
-  write_number (NUMBER, /*unsigned_p=*/0, 10)
-
 /* Write out an unsigned quantity in base 10.  */
 #define write_unsigned_number(NUMBER) \
-  write_number (NUMBER, /*unsigned_p=*/1, 10)
+  write_number ((NUMBER), /*unsigned_p=*/1, 10)
 
-/* If DECL is a template instance, return non-zero and, if
+/* If DECL is a template instance, return nonzero and, if
    TEMPLATE_INFO is non-NULL, set *TEMPLATE_INFO to its template info.
    Otherwise return zero.  */
 
@@ -356,7 +358,7 @@ add_substitution (node)
            || (TYPE_P (node) 
                && TYPE_P (candidate) 
                && same_type_p (node, candidate)))
-         my_friendly_abort (20000524);
+         abort ();
       }
   }
 #endif /* ENABLE_CHECKING */
@@ -368,7 +370,7 @@ add_substitution (node)
     dump_substitution_candidates ();
 }
 
-/* Helper function for find_substitution.  Returns non-zero if NODE,
+/* Helper function for find_substitution.  Returns nonzero if NODE,
    which may be a decl or a CLASS_TYPE, is a template-id with template
    name of substitution_index[INDEX] in the ::std namespace.  */
 
@@ -401,7 +403,7 @@ is_std_substitution (node, index)
              == subst_identifiers[index]));
 }
 
-/* Helper function for find_substitution.  Returns non-zero if NODE,
+/* Helper function for find_substitution.  Returns nonzero if NODE,
    which may be a decl or a CLASS_TYPE, is the template-id
    ::std::identifier<char>, where identifier is
    substitution_index[INDEX].  */
@@ -461,7 +463,7 @@ is_std_substitution_char (node, index)
    candidates for entities appearing earlier in the same mangling
 
    If a substitution is found, write its mangled representation and
-   return non-zero.  If none is found, just return zero.  */
+   return nonzero.  If none is found, just return zero.  */
 
 static int
 find_substitution (node)
@@ -504,7 +506,7 @@ find_substitution (node)
                 std::basic_string <char,
                                    std::char_traits<char>,
                                    std::allocator<char> > .  */
-         if (CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+         if (cp_type_quals (type) == TYPE_UNQUALIFIED
              && CLASSTYPE_USE_TEMPLATE (type))
            {
              tree args = CLASSTYPE_TI_ARGS (type);
@@ -530,7 +532,7 @@ find_substitution (node)
 
   /* Check for basic_{i,o,io}stream.  */
   if (TYPE_P (node)
-      && CP_TYPE_QUALS (type) == TYPE_UNQUALIFIED
+      && cp_type_quals (type) == TYPE_UNQUALIFIED
       && CLASS_TYPE_P (type)
       && CLASSTYPE_USE_TEMPLATE (type)
       && CLASSTYPE_TEMPLATE_INFO (type) != NULL)
@@ -573,7 +575,7 @@ find_substitution (node)
     }
 
   /* Now check the list of available substitutions for this mangling
-     operation.    */
+     operation.  */
   for (i = 0; i < size; ++i)
     {
       tree candidate = VARRAY_TREE (G.substitutions, i);
@@ -663,7 +665,7 @@ write_encoding (decl)
          ::= <nested-name>
          ::= <local-name>  
 
-   If IGNORE_LOCAL_SCOPE is non-zero, this production of <name> is
+   If IGNORE_LOCAL_SCOPE is nonzero, this production of <name> is
    called from <local-name>, which mangles the enclosing scope
    elsewhere and then uses this function to mangle just the part
    underneath the function scope.  So don't use the <local-name>
@@ -774,7 +776,7 @@ write_unscoped_name (decl)
           || TREE_CODE (context) == FUNCTION_DECL)
     write_unqualified_name (decl);
   else 
-    my_friendly_abort (20000521);
+    abort ();
 }
 
 /* <unscoped-template-name> ::= <unscoped-name>
@@ -918,7 +920,7 @@ write_template_prefix (node)
     template = CLASSTYPE_TI_TEMPLATE (type);
   else
     /* Oops, not a template.  */
-    my_friendly_abort (20000524);
+    abort ();
 
   /* For a member template, though, the template name for the
      innermost name must have all the outer template levels
@@ -977,8 +979,17 @@ write_unqualified_name (decl)
     {
       /* Conversion operator. Handle it right here.  
            <operator> ::= cv <type>  */
+      tree type;
+      if (decl_is_template_id (decl, NULL))
+       {
+         tree fn_type = get_mostly_instantiated_function_type (decl, NULL,
+                                                               NULL);
+         type = TREE_TYPE (fn_type);
+       }
+      else
+       type = TREE_TYPE (DECL_NAME (decl));
       write_string ("cv");
-      write_type (TREE_TYPE (DECL_NAME (decl)));
+      write_type (type);
     }
   else if (DECL_OVERLOADED_OPERATOR_P (decl))
     {
@@ -1013,6 +1024,38 @@ write_source_name (identifier)
   write_identifier (IDENTIFIER_POINTER (identifier));
 }
 
+/* Convert NUMBER to ascii using base BASE and generating at least
+   MIN_DIGITS characters. BUFFER points to the _end_ of the buffer
+   into which to store the characters. Returns the number of
+   characters generated (these will be layed out in advance of where
+   BUFFER points).  */
+
+static int
+hwint_to_ascii (number, base, buffer, min_digits)
+     unsigned HOST_WIDE_INT number;
+     unsigned int base;
+     char *buffer;
+     unsigned min_digits;
+{
+  static const char base_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  unsigned digits = 0;
+  
+  while (number)
+    {
+      unsigned HOST_WIDE_INT d = number / base;
+      
+      *--buffer = base_digits[number - d * base];
+      digits++;
+      number = d;
+    }
+  while (digits < min_digits)
+    {
+      *--buffer = base_digits[0];
+      digits++;
+    }
+  return digits;
+}
+
 /* Non-terminal <number>.
 
      <number> ::= [n] </decimal integer/>  */
@@ -1023,50 +1066,91 @@ write_number (number, unsigned_p, base)
      int unsigned_p;
      unsigned int base;
 {
-  static const char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-  unsigned HOST_WIDE_INT n;
-  unsigned HOST_WIDE_INT m = 1;
+  char buffer[sizeof (HOST_WIDE_INT) * 8];
+  unsigned count = 0;
 
   if (!unsigned_p && (HOST_WIDE_INT) number < 0)
     {
       write_char ('n');
       number = -((HOST_WIDE_INT) number);
     }
-  
-  /* Figure out how many digits there are.  */
-  n = number;
-  while (n >= base)
-    {
-      n /= base;
-      m *= base;
-    }
-
-  /* Write them out.  */
-  while (m > 0)
-    {
-      int digit = number / m;
-      write_char (digits[digit]);
-      number -= digit * m;
-      m /= base;
-    }
-
-  my_friendly_assert (number == 0, 20000407);
+  count = hwint_to_ascii (number, base, buffer + sizeof (buffer), 1);
+  write_chars (buffer + sizeof (buffer) - count, count);
 }
 
-/* Write out an integeral CST in decimal.  */
+/* Write out an integral CST in decimal. Most numbers are small, and
+   representable in a HOST_WIDE_INT. Occasionally we'll have numbers
+   bigger than that, which we must deal with.  */
 
 static inline void
 write_integer_cst (cst)
      tree cst;
 {
-  if (tree_int_cst_sgn (cst) >= 0) 
+  int sign = tree_int_cst_sgn (cst);
+
+  if (TREE_INT_CST_HIGH (cst) + (sign < 0))
     {
-      if (TREE_INT_CST_HIGH (cst) != 0)
-       sorry ("mangling very large integers");
-      write_unsigned_number (TREE_INT_CST_LOW (cst));
+      /* A bignum. We do this in chunks, each of which fits in a
+        HOST_WIDE_INT.  */
+      char buffer[sizeof (HOST_WIDE_INT) * 8 * 2];
+      unsigned HOST_WIDE_INT chunk;
+      unsigned chunk_digits;
+      char *ptr = buffer + sizeof (buffer);
+      unsigned count = 0;
+      tree n, base, type;
+      int done;
+
+      /* HOST_WIDE_INT must be at least 32 bits, so 10^9 is
+        representable.  */
+      chunk = 1000000000;
+      chunk_digits = 9;
+      
+      if (sizeof (HOST_WIDE_INT) >= 8)
+       {
+         /* It is at least 64 bits, so 10^18 is representable.  */
+         chunk_digits = 18;
+         chunk *= chunk;
+       }
+      
+      type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
+      base = build_int_2 (chunk, 0);
+      n = build_int_2 (TREE_INT_CST_LOW (cst), TREE_INT_CST_HIGH (cst));
+      TREE_TYPE (n) = TREE_TYPE (base) = type;
+
+      if (sign < 0)
+       {
+         write_char ('n');
+         n = fold (build1 (NEGATE_EXPR, type, n));
+       }
+      do
+       {
+         tree d = fold (build (FLOOR_DIV_EXPR, type, n, base));
+         tree tmp = fold (build (MULT_EXPR, type, d, base));
+         unsigned c;
+         
+         done = integer_zerop (d);
+         tmp = fold (build (MINUS_EXPR, type, n, tmp));
+         c = hwint_to_ascii (TREE_INT_CST_LOW (tmp), 10, ptr,
+                               done ? 1 : chunk_digits);
+         ptr -= c;
+         count += c;
+         n = d;
+       }
+      while (!done);
+      write_chars (ptr, count);
+    }
+  else 
+    {
+      /* A small num.  */
+      unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (cst);
+      
+      if (sign < 0)
+       {
+         write_char ('n');
+         low = -low;
+       }
+      write_unsigned_number (low);
     }
-  else
-    write_signed_number (tree_low_cst (cst, 0));
 }
 
 /* Non-terminal <identifier>.
@@ -1090,10 +1174,9 @@ write_identifier (identifier)
 
    Currently, allocating constructors are never used. 
 
-   We also need to provide unique mangled names (which should never be
-   exported) for the constructor that takes an in-charge parameter,
-   and for a constructor whose name is the same as its class's name.
-   We use "C*INTERNAL*" for these.  */
+   We also need to provide mangled names for the maybe-in-charge
+   constructor, so we treat it here too.  mangle_decl_string will
+   append *INTERNAL* to that, to make sure we never emit it.  */
 
 static void
 write_special_name_constructor (ctor)
@@ -1108,19 +1191,19 @@ write_special_name_constructor (ctor)
   else if (DECL_BASE_CONSTRUCTOR_P (ctor))
     write_string ("C2");
   else
-    my_friendly_abort (20001115);
+    abort ();
 }
 
 /* Handle destructor productions of non-terminal <special-name>.
-   DTOR is a denstructor FUNCTION_DECL. 
+   DTOR is a destructor FUNCTION_DECL. 
 
      <special-name> ::= D0 # deleting (in-charge) destructor
                     ::= D1 # complete object (in-charge) destructor
-                    ::= D2 # base object (not-in-charge) destructor 
+                    ::= D2 # base object (not-in-charge) destructor
 
-   We also need to provide unique mngled names for old-ABI
-   destructors, sometimes.  These should only be used internally.  We
-   use "D*INTERNAL*" for these.  */
+   We also need to provide mangled names for the maybe-incharge
+   destructor, so we treat it here too.  mangle_decl_string will
+   append *INTERNAL* to that, to make sure we never emit it.  */
 
 static void
 write_special_name_destructor (dtor)
@@ -1137,7 +1220,7 @@ write_special_name_destructor (dtor)
   else if (DECL_BASE_DESTRUCTOR_P (dtor))
     write_string ("D2");
   else
-    my_friendly_abort (20001115);
+    abort ();
 }
 
 /* Return the discriminator for ENTITY appearing inside
@@ -1154,16 +1237,17 @@ discriminator_for_local_entity (entity)
   /* Assume this is the only local entity with this name.  */
   discriminator = 0;
 
-  /* For now, we don't discriminate amongst local variables.  */
-  if (TREE_CODE (entity) != TYPE_DECL)
-    return 0;
-
-  /* Scan the list of local classes.  */
-  entity = TREE_TYPE (entity);
-  for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
-    if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
-       && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
-      ++discriminator;
+  if (DECL_DISCRIMINATOR_P (entity) && DECL_LANG_SPECIFIC (entity))
+    discriminator = DECL_DISCRIMINATOR (entity);
+  else if (TREE_CODE (entity) == TYPE_DECL)
+    {
+      /* Scan the list of local classes.  */
+      entity = TREE_TYPE (entity);
+      for (type = &VARRAY_TREE (local_classes, 0); *type != entity; ++type)
+        if (TYPE_IDENTIFIER (*type) == TYPE_IDENTIFIER (entity)
+            && TYPE_CONTEXT (*type) == TYPE_CONTEXT (entity))
+         ++discriminator;
+    }  
 
   return discriminator;
 }
@@ -1191,14 +1275,11 @@ static void
 write_discriminator (discriminator)
      int discriminator;
 {
-  /* If discriminator is zero, don't write anything.  Otherwise... */
+  /* If discriminator is zero, don't write anything.  Otherwise...  */
   if (discriminator > 0)
     {
       write_char ('_');
-      /* The number is omitted for discriminator == 1.  Beyond 1, the
-        numbering starts at 0.  */
-      if (discriminator > 1)
-       write_unsigned_number (discriminator - 2);
+      write_unsigned_number (discriminator - 1);
     }
 }
 
@@ -1260,7 +1341,7 @@ static void
 write_type (type)
      tree type;
 {
-  /* This gets set to non-zero if TYPE turns out to be a (possibly
+  /* This gets set to nonzero if TYPE turns out to be a (possibly
      CV-qualified) builtin type.  */
   int is_builtin_type = 0;
 
@@ -1278,6 +1359,11 @@ write_type (type)
        since both the qualified and uqualified types are substitution
        candidates.  */
     write_type (TYPE_MAIN_VARIANT (type));
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    /* It is important not to use the TYPE_MAIN_VARIANT of TYPE here
+       so that the cv-qualification of the element type is available
+       in write_array_type.  */
+    write_array_type (type);
   else
     {
       /* See through any typedefs.  */
@@ -1318,14 +1404,12 @@ write_type (type)
          break;
 
        case TYPENAME_TYPE:
-         /* We handle TYPENAME_TYPEs like ordinary nested names.  */
+       case UNBOUND_CLASS_TEMPLATE:
+         /* We handle TYPENAME_TYPEs and UNBOUND_CLASS_TEMPLATEs like
+            ordinary nested names.  */
          write_nested_name (TYPE_STUB_DECL (type));
          break;
 
-       case ARRAY_TYPE:
-         write_array_type (type);
-         break;
-
        case POINTER_TYPE:
          /* A pointer-to-member variable is represented by a POINTER_TYPE
             to an OFFSET_TYPE, so check for this first.  */
@@ -1368,7 +1452,7 @@ write_type (type)
          break;
 
        default:
-         my_friendly_abort (20000409);
+         abort ();
        }
     }
 
@@ -1392,19 +1476,23 @@ write_CV_qualifiers_for_type (type)
 
        "In cases where multiple order-insensitive qualifiers are
        present, they should be ordered 'K' (closest to the base type),
-       'V', 'r', and 'U' (farthest from the base type) ..."  */
+       'V', 'r', and 'U' (farthest from the base type) ..."  
+
+     Note that we do not use cp_type_quals below; given "const
+     int[3]", the "const" is emitted with the "int", not with the
+     array.  */
 
-  if (CP_TYPE_RESTRICT_P (type))
+  if (TYPE_QUALS (type) & TYPE_QUAL_RESTRICT)
     {
       write_char ('r');
       ++num_qualifiers;
     }
-  if (CP_TYPE_VOLATILE_P (type))
+  if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
     {
       write_char ('V');
       ++num_qualifiers;
     }
-  if (CP_TYPE_CONST_P (type))
+  if (TYPE_QUALS (type) & TYPE_QUAL_CONST)
     {
       write_char ('K');
       ++num_qualifiers;
@@ -1429,8 +1517,8 @@ write_CV_qualifiers_for_type (type)
                     ::= m   # unsigned long
                     ::= x   # long long, __int64
                     ::= y   # unsigned long long, __int64  
-                    ::= n   # __int128            [not supported]
-                    ::= o   # unsigned __int128   [not supported] 
+                    ::= n   # __int128
+                    ::= o   # unsigned __int128
                     ::= f   # float
                     ::= d   # double
                     ::= e   # long double, __float80 
@@ -1475,15 +1563,24 @@ write_builtin_type (type)
                write_char (integer_type_codes[itk]);
                break;
              }
-         
+
          if (itk == itk_none)
            {
-             tree t = type_for_mode (TYPE_MODE (type), TREE_UNSIGNED (type));
+             tree t = c_common_type_for_mode (TYPE_MODE (type),
+                                              TREE_UNSIGNED (type));
              if (type == t)
-               /* Couldn't find this type.  */
-               my_friendly_abort (20000408);
-             type = t;
-             goto iagain;
+               {
+                 if (TYPE_PRECISION (type) == 128)
+                   write_char (TREE_UNSIGNED (type) ? 'o' : 'n');
+                 else
+                   /* Couldn't find this type.  */
+                   abort ();
+               }
+             else
+               {
+                 type = t;
+                 goto iagain;
+               }
            }
        }
       break;
@@ -1498,11 +1595,11 @@ write_builtin_type (type)
       else if (type == long_double_type_node)
        write_char ('e');
       else
-       my_friendly_abort (20000409);
+       abort ();
       break;
 
     default:
-      my_friendly_abort (20000509);
+      abort ();
     }
 }
 
@@ -1518,6 +1615,17 @@ write_function_type (type)
 {
   MANGLE_TRACE_TREE ("function-type", type);
 
+  /* For a pointer to member function, the function type may have
+     cv-qualifiers, indicating the quals for the artificial 'this'
+     parameter.  */
+  if (TREE_CODE (type) == METHOD_TYPE)
+    {
+      /* The first parameter must be a POINTER_TYPE pointing to the
+        `this' parameter.  */
+      tree this_type = TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (type)));
+      write_CV_qualifiers_for_type (this_type);
+    }
+
   write_char ('F');
   /* We don't track whether or not a type is `extern "C"'.  Note that
      you can have an `extern "C"' function that does not have
@@ -1537,7 +1645,7 @@ write_function_type (type)
 }
 
 /* Non-terminal <bare-function-type>.  TYPE is a FUNCTION_TYPE or
-   METHOD_TYPE.  If INCLUDE_RETURN_TYPE is non-zero, the return value
+   METHOD_TYPE.  If INCLUDE_RETURN_TYPE is nonzero, the return value
    is mangled before the parameter types.  If non-NULL, DECL is
    FUNCTION_DECL for the function whose type is being emitted.
 
@@ -1562,7 +1670,7 @@ write_bare_function_type (type, include_return_type_p, decl)
 }
 
 /* Write the mangled representation of a method parameter list of
-   types given in PARM_TYPES.  If METHOD_P is non-zero, the function is 
+   types given in PARM_TYPES.  If METHOD_P is nonzero, the function is
    considered a non-static method, and the this parameter is omitted.
    If non-NULL, DECL is the FUNCTION_DECL for the function whose
    parameters are being emitted.  */
@@ -1692,7 +1800,17 @@ write_expression (expr)
       code = TREE_CODE (expr);
     }
 
-  /* Handle template parameters. */
+  /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
+     is converted (via qualification conversions) to another
+     type.  */
+  while (TREE_CODE (expr) == NOP_EXPR
+        || TREE_CODE (expr) == NON_LVALUE_EXPR)
+    {
+      expr = TREE_OPERAND (expr, 0);
+      code = TREE_CODE (expr);
+    }
+
+  /* Handle template parameters.  */
   if (code == TEMPLATE_TYPE_PARM 
       || code == TEMPLATE_TEMPLATE_PARM
       || code == BOUND_TEMPLATE_TEMPLATE_PARM
@@ -1707,19 +1825,16 @@ write_expression (expr)
       write_mangled_name (expr);
       write_char ('E');
     }
+  else if (TREE_CODE (expr) == SIZEOF_EXPR 
+          && TYPE_P (TREE_OPERAND (expr, 0)))
+    {
+      write_string ("st");
+      write_type (TREE_OPERAND (expr, 0));
+    }
   else
     {
       int i;
 
-      /* Skip NOP_EXPRs.  They can occur when (say) a pointer argument
-        is converted (via qualification conversions) to another
-        type.  */
-      while (TREE_CODE (expr) == NOP_EXPR)
-       {
-         expr = TREE_OPERAND (expr, 0);
-         code = TREE_CODE (expr);
-       }
-
       /* When we bind a variable or function to a non-type template
         argument with reference type, we create an ADDR_EXPR to show
         the fact that the entity's address has been taken.  But, we
@@ -1741,18 +1856,33 @@ write_expression (expr)
       /* If it wasn't any of those, recursively expand the expression.  */
       write_string (operator_name_info[(int) code].mangled_name);
 
-      /* Handle pointers-to-members specially.  */
-      if (code == SCOPE_REF)
+      switch (code)
        {
+       case CAST_EXPR:
+         write_type (TREE_TYPE (expr));
+         write_expression (TREE_VALUE (TREE_OPERAND (expr, 0)));
+         break;
+
+       case STATIC_CAST_EXPR:
+       case CONST_CAST_EXPR:
+         write_type (TREE_TYPE (expr));
+         write_expression (TREE_OPERAND (expr, 0));
+         break;
+
+         
+       /* Handle pointers-to-members specially.  */
+       case SCOPE_REF:
          write_type (TREE_OPERAND (expr, 0));
          if (TREE_CODE (TREE_OPERAND (expr, 1)) == IDENTIFIER_NODE)
            write_source_name (TREE_OPERAND (expr, 1));
          else
            write_encoding (TREE_OPERAND (expr, 1));
+         break;
+
+       default:
+         for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
+           write_expression (TREE_OPERAND (expr, i));
        }
-      else
-       for (i = 0; i < TREE_CODE_LENGTH (code); ++i)
-         write_expression (TREE_OPERAND (expr, i));
     }
 }
 
@@ -1786,7 +1916,7 @@ write_template_arg_literal (value)
          else if (value == boolean_true_node)
            write_unsigned_number (1);
          else 
-           my_friendly_abort (20000412);
+           abort ();
        }
       else
        write_integer_cst (value);
@@ -1811,7 +1941,7 @@ write_template_arg_literal (value)
 #endif
     }
   else
-    my_friendly_abort (20000412);
+    abort ();
 
   write_char ('E');
 }
@@ -1938,13 +2068,22 @@ write_pointer_to_member_type (type)
    TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
    TEMPLATE_PARM_INDEX.
 
-     <template-param> ::= T </parameter/ number> _  */
+     <template-param> ::= T </parameter/ number> _
+
+   If we are internally mangling then we distinguish level and, for
+   non-type parms, type too. The mangling appends
+   
+     </level/ number> _ </non-type type/ type> _
+
+   This is used by mangle_conv_op_name_for_type.  */
 
 static void
 write_template_param (parm)
      tree parm;
 {
   int parm_index;
+  int parm_level;
+  tree parm_type = NULL_TREE;
 
   MANGLE_TRACE_TREE ("template-parm", parm);
 
@@ -1954,14 +2093,17 @@ write_template_param (parm)
     case TEMPLATE_TEMPLATE_PARM:
     case BOUND_TEMPLATE_TEMPLATE_PARM:
       parm_index = TEMPLATE_TYPE_IDX (parm);
+      parm_level = TEMPLATE_TYPE_LEVEL (parm);
       break;
 
     case TEMPLATE_PARM_INDEX:
       parm_index = TEMPLATE_PARM_IDX (parm);
+      parm_level = TEMPLATE_PARM_LEVEL (parm);
+      parm_type = TREE_TYPE (TEMPLATE_PARM_DECL (parm));
       break;
 
     default:
-      my_friendly_abort (20000523);
+      abort ();
     }
 
   write_char ('T');
@@ -1970,6 +2112,15 @@ write_template_param (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>
@@ -2022,6 +2173,7 @@ write_substitution (seq_id)
 static inline void
 start_mangling ()
 {
+  VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
   obstack_free (&G.name_obstack, obstack_base (&G.name_obstack));
 }
 
@@ -2031,7 +2183,7 @@ static inline const char *
 finish_mangling ()
 {
   /* Clear all the substitutions.  */
-  VARRAY_POP_ALL (G.substitutions);
+  G.substitutions = 0;
 
   /* Null-terminate the string.  */
   write_char ('\0');
@@ -2045,7 +2197,6 @@ void
 init_mangle ()
 {
   gcc_obstack_init (&G.name_obstack);
-  VARRAY_TREE_INIT (G.substitutions, 1, "mangling substitutions");
 
   /* Cache these identifiers for quick comparison when checking for
      standard substitutions.  */
@@ -2069,6 +2220,17 @@ mangle_decl_string (decl)
 
   if (TREE_CODE (decl) == TYPE_DECL)
     write_type (TREE_TYPE (decl));
+  else if (/* The names of `extern "C"' functions are not mangled.  */
+          (DECL_EXTERN_C_FUNCTION_P (decl)
+           /* But overloaded operator names *are* mangled.  */
+           && !DECL_OVERLOADED_OPERATOR_P (decl))
+          /* The names of global variables aren't mangled either.  */
+          || (TREE_CODE (decl) == VAR_DECL
+              && CP_DECL_CONTEXT (decl) == global_namespace)
+          /* And neither are `extern "C"' variables.  */
+          || (TREE_CODE (decl) == VAR_DECL
+              && DECL_EXTERN_C_P (decl)))
+    write_string (IDENTIFIER_POINTER (DECL_NAME (decl)));
   else
     {
       write_mangled_name (decl);
@@ -2089,11 +2251,13 @@ mangle_decl_string (decl)
 
 /* Create an identifier for the external mangled name of DECL.  */
 
-tree
+void
 mangle_decl (decl)
      tree decl;
 {
-  return get_identifier (mangle_decl_string (decl));
+  tree id = get_identifier (mangle_decl_string (decl));
+
+  SET_DECL_ASSEMBLER_NAME (decl, id);
 }
 
 /* Generate the mangled representation of TYPE.  */
@@ -2283,19 +2447,26 @@ mangle_conv_op_name_for_type (type)
      tree type;
 {
   tree identifier;
+  const char *mangled_type;
+  char *op_name;
 
-  /* Build the mangling for TYPE.  */
-  const char *mangled_type = mangle_type_string (type);
+  /* 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.  */
-  char *op_name = (char *) xmalloc (strlen ("operator ") 
-                                   + strlen (mangled_type) + 1);
-  /* Assemble the mangling.  */
-  strcpy (op_name, "operator ");
-  strcat (op_name, mangled_type);
+  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.  */
+  my_friendly_assert (!IDENTIFIER_TYPENAME_P (identifier)
+                     || same_type_p (type, TREE_TYPE (identifier)),
+                     20011230);
+  
   /* Set bits on the identifier so we know later it's a conversion.  */
   IDENTIFIER_OPNAME_P (identifier) = 1;
   IDENTIFIER_TYPENAME_P (identifier) = 1;
@@ -2315,10 +2486,28 @@ mangle_guard_variable (variable)
 {
   start_mangling ();
   write_string ("_ZGV");
-  write_name (variable, /*ignore_local_scope=*/0);
+  if (strncmp (IDENTIFIER_POINTER (DECL_NAME (variable)), "_ZGR", 4) == 0)
+    /* The name of a guard variable for a reference temporary should refer
+       to the reference, not the temporary.  */
+    write_string (IDENTIFIER_POINTER (DECL_NAME (variable)) + 4);
+  else
+    write_name (variable, /*ignore_local_scope=*/0);
   return get_identifier (finish_mangling ());
 }
 
+/* Return an identifier for the name of a temporary variable used to
+   initialize a static reference.  This isn't part of the ABI, but we might
+   as well call them something readable.  */
+
+tree
+mangle_ref_init_variable (variable)
+     tree variable;
+{
+  start_mangling ();
+  write_string ("_ZGR");
+  write_name (variable, /*ignore_local_scope=*/0);
+  return get_identifier (finish_mangling ());
+}
 \f
 
 /* Foreign language type mangling section.  */
@@ -2342,6 +2531,6 @@ write_java_integer_type_codes (type)
   else if (type == java_boolean_type_node)
     write_char ('b');
   else
-    my_friendly_abort (20001207);
+    abort ();
 }