OSDN Git Service

(struct function): Make frame_offset be HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / cp / method.c
index 16dead8..c7e3a87 100644 (file)
@@ -1,6 +1,6 @@
 /* Handle the hair of processing (but not expanding) inline functions.
    Also manage function and variable name overloading.
-   Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92, 93, 94, 95, 1996 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
    This file is part of GNU CC.
@@ -17,7 +17,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 #ifndef PARM_CAN_BE_ARRAY_TYPE
@@ -59,10 +60,7 @@ static char *scratch_firstobj;
                 IDENTIFIER_LENGTH (ID)))
 # define OB_PUTCP(S) (obstack_grow (&scratch_obstack, (S), strlen (S)))
 # define OB_FINISH() (obstack_1grow (&scratch_obstack, '\0'))
-
-#ifdef NO_AUTO_OVERLOAD
-int is_overloaded ();
-#endif
+# define OB_LAST() (obstack_next_free (&scratch_obstack)[-1])
 
 void
 init_method ()
@@ -89,10 +87,12 @@ do_inline_function_hair (type, friend_list)
 
   if (method && TREE_CODE (method) == TREE_VEC)
     {
-      if (TREE_VEC_ELT (method, 0))
+      if (TREE_VEC_ELT (method, 1))
+       method = TREE_VEC_ELT (method, 1);
+      else if (TREE_VEC_ELT (method, 0))
        method = TREE_VEC_ELT (method, 0);
       else
-       method = TREE_VEC_ELT (method, 1);
+       method = TREE_VEC_ELT (method, 2);
     }
 
   while (method)
@@ -135,7 +135,8 @@ do_inline_function_hair (type, friend_list)
            }
 
          /* Allow this decl to be seen in global scope */
-         IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (fndecl)) = fndecl;
+         if (! current_function_decl)
+           IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (fndecl)) = fndecl;
        }
 
       friend_list = TREE_CHAIN (friend_list);
@@ -144,6 +145,7 @@ do_inline_function_hair (type, friend_list)
 \f
 /* Report an argument type mismatch between the best declared function
    we could find and the current argument list that we have.  */
+
 void
 report_type_mismatch (cp, parmtypes, name_kind)
      struct candidate *cp;
@@ -162,14 +164,6 @@ report_type_mismatch (cp, parmtypes, name_kind)
                cp->function);
       return;
 
-    case -3:
-      if (TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))))
-       cp_error ("call to const %s `%#D' with non-const object", name_kind,
-                 cp->function);
-      else
-       cp_error ("call to non-const %s `%#D' with const object", name_kind,
-                 cp->function);
-      return;
     case -2:
       cp_error ("too few arguments for %s `%#D'", name_kind, cp->function);
       return;
@@ -177,14 +171,20 @@ report_type_mismatch (cp, parmtypes, name_kind)
       cp_error ("too many arguments for %s `%#D'", name_kind, cp->function);
       return;
     case 0:
-      if (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
-       {
-         /* Happens when we have an ambiguous base class.  */
-         my_friendly_assert (get_binfo (DECL_CLASS_CONTEXT (cp->function),
-                            TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))), 1) == error_mark_node,
-                             241);
-         return;
-       }
+      if (TREE_CODE (TREE_TYPE (cp->function)) != METHOD_TYPE)
+       break;
+    case -3:
+      /* Happens when the implicit object parameter is rejected.  */
+      my_friendly_assert (! TYPE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))),
+                         241);
+      if (TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))))
+         && ! TYPE_VOLATILE (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (cp->function))))))
+       cp_error ("call to non-volatile %s `%#D' with volatile object",
+                 name_kind, cp->function);
+      else
+       cp_error ("call to non-const %s `%#D' with const object",
+                 name_kind, cp->function);
+      return;
     }
 
   ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
@@ -254,6 +254,7 @@ static int nofold;
   } while (0)
 
 /* Code to concatenate an asciified integer to a string.  */
+
 static
 #ifdef __GNUC__
 __inline
@@ -312,22 +313,89 @@ flush_repeats (type)
     OB_PUTC ('_');
 }
 
+static int numeric_output_need_bar;
 static void build_overload_identifier ();
 
 static void
-build_overload_nested_name (context)
-     tree context;
+build_overload_nested_name (decl)
+     tree decl;
 {
-  /* We use DECL_NAME here, because pushtag now sets the DECL_ASSEMBLER_NAME.  */
-  tree name = DECL_NAME (context);
-  if (DECL_CONTEXT (context))
+  if (DECL_CONTEXT (decl))
     {
-      context = DECL_CONTEXT (context);
+      tree context = DECL_CONTEXT (decl);
       if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-       context = TYPE_NAME (context);
+       context = TYPE_MAIN_DECL (context);
       build_overload_nested_name (context);
     }
-  build_overload_identifier (name);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      tree name = DECL_ASSEMBLER_NAME (decl);
+      char *label;
+      extern int var_labelno;
+
+      ASM_FORMAT_PRIVATE_NAME (label, IDENTIFIER_POINTER (name), var_labelno);
+      var_labelno++;
+
+      if (numeric_output_need_bar)
+       {
+         OB_PUTC ('_');
+         numeric_output_need_bar = 0;
+       }
+      icat (strlen (label));
+      OB_PUTCP (label);
+    }
+  else                         /* TYPE_DECL */
+    build_overload_identifier (decl);
+}
+
+/* Encoding for an INTEGER_CST value.  */
+
+static void
+build_overload_int (value)
+     tree value;
+{
+  if (TREE_CODE (value) == TEMPLATE_CONST_PARM)
+    {
+      OB_PUTC ('Y');
+      if (TEMPLATE_CONST_IDX (value) > 9)
+       OB_PUTC ('_');
+      icat (TEMPLATE_CONST_IDX (value)); 
+      if (TEMPLATE_CONST_IDX (value) > 9)
+       OB_PUTC ('_');
+      return;
+    }
+  else if (processing_template_decl
+          && TREE_CODE (value) != INTEGER_CST)
+    /* We don't ever want this output, but it's inconvenient not to
+       be able to build the string.  This should cause assembler
+       errors we'll notice.  */
+    {
+      static int n;
+      sprintf (digit_buffer, " *%d", n++);
+      OB_PUTCP (digit_buffer);
+      return;
+    }
+
+  my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
+  if (TYPE_PRECISION (TREE_TYPE (value)) == 2 * HOST_BITS_PER_WIDE_INT)
+    {
+      if (tree_int_cst_lt (value, integer_zero_node))
+       {
+         OB_PUTC ('m');
+         value = build_int_2 (~ TREE_INT_CST_LOW (value),
+                              - TREE_INT_CST_HIGH (value));
+       }
+      if (TREE_INT_CST_HIGH (value)
+         != (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1)))
+       {
+         /* need to print a DImode value in decimal */
+         sorry ("conversion of long long as PT parameter");
+       }
+      /* else fall through to print in smaller mode */
+    }
+  /* Wordsize or smaller */
+  icat (TREE_INT_CST_LOW (value));
 }
 
 static void
@@ -339,30 +407,37 @@ build_overload_value (type, value)
     value = TREE_OPERAND (value, 0);
   my_friendly_assert (TREE_CODE (type) == PARM_DECL, 242);
   type = TREE_TYPE (type);
+
+  if (numeric_output_need_bar)
+    {
+      OB_PUTC ('_');
+      numeric_output_need_bar = 0;
+    }
+
+  if (TREE_CODE (type) == POINTER_TYPE
+      && TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
+    {
+      /* Handle a pointer to data member as a template instantiation
+        parameter, boy, what fun!  */
+      type = integer_type_node;
+      if (TREE_CODE (value) != INTEGER_CST)
+       {
+         sorry ("unknown pointer to member constant");
+         return;
+       }
+    }
+
+  if (TYPE_PTRMEMFUNC_P (type))
+    type = TYPE_PTRMEMFUNC_FN_TYPE (type);
+
   switch (TREE_CODE (type))
     {
     case INTEGER_TYPE:
     case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
       {
-       my_friendly_assert (TREE_CODE (value) == INTEGER_CST, 243);
-       if (TYPE_PRECISION (value) == 2 * HOST_BITS_PER_WIDE_INT)
-         {
-           if (tree_int_cst_lt (value, integer_zero_node))
-             {
-               OB_PUTC ('m');
-               value = build_int_2 (~ TREE_INT_CST_LOW (value),
-                                    - TREE_INT_CST_HIGH (value));
-             }
-           if (TREE_INT_CST_HIGH (value)
-               != (TREE_INT_CST_LOW (value) >> (HOST_BITS_PER_WIDE_INT - 1)))
-             {
-               /* need to print a DImode value in decimal */
-               sorry ("conversion of long long as PT parameter");
-             }
-           /* else fall through to print in smaller mode */
-         }
-       /* Wordsize or smaller */
-       icat (TREE_INT_CST_LOW (value));
+       build_overload_int (value);
+       numeric_output_need_bar = 1;
        return;
       }
 #ifndef REAL_IS_NOT_DOUBLE
@@ -409,21 +484,69 @@ build_overload_value (type, value)
              }
          }
        OB_PUTCP (digit_buffer);
+       numeric_output_need_bar = 1;
        return;
       }
 #endif
     case POINTER_TYPE:
+      if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE
+         && TREE_CODE (value) != ADDR_EXPR)
+       {
+         if (TREE_CODE (value) == CONSTRUCTOR)
+           {
+             /* This is dangerous code, crack built up pointer to members.  */
+             tree args = CONSTRUCTOR_ELTS (value);
+             tree a1 = TREE_VALUE (args);
+             tree a2 = TREE_VALUE (TREE_CHAIN (args));
+             tree a3 = CONSTRUCTOR_ELTS (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args))));
+             a3 = TREE_VALUE (a3);
+             STRIP_NOPS (a3);
+             if (TREE_CODE (a1) == INTEGER_CST
+                 && TREE_CODE (a2) == INTEGER_CST)
+               {
+                 build_overload_int (a1);
+                 OB_PUTC ('_');
+                 build_overload_int (a2);
+                 OB_PUTC ('_');
+                 if (TREE_CODE (a3) == ADDR_EXPR)
+                   {
+                     a3 = TREE_OPERAND (a3, 0);
+                     if (TREE_CODE (a3) == FUNCTION_DECL)
+                       {
+                         numeric_output_need_bar = 0;
+                         build_overload_identifier (DECL_ASSEMBLER_NAME (a3));
+                         return;
+                       }
+                   }
+                 else if (TREE_CODE (a3) == INTEGER_CST)
+                   {
+                     OB_PUTC ('i');
+                     build_overload_int (a3);
+                     numeric_output_need_bar = 1;
+                     return;
+                   }
+               }
+           }
+         sorry ("template instantiation with pointer to method that is too complex");
+         return;
+       }
+      if (TREE_CODE (value) == INTEGER_CST)
+       {
+         build_overload_int (value);
+         numeric_output_need_bar = 1;
+         return;
+       }
       value = TREE_OPERAND (value, 0);
       if (TREE_CODE (value) == VAR_DECL)
        {
          my_friendly_assert (DECL_NAME (value) != 0, 245);
-         build_overload_identifier (DECL_NAME (value));
+         build_overload_identifier (DECL_ASSEMBLER_NAME (value));
          return;
        }
       else if (TREE_CODE (value) == FUNCTION_DECL)
        {
          my_friendly_assert (DECL_NAME (value) != 0, 246);
-         build_overload_identifier (DECL_NAME (value));
+         build_overload_identifier (DECL_ASSEMBLER_NAME (value));
          return;
        }
       else
@@ -441,11 +564,14 @@ static void
 build_overload_identifier (name)
      tree name;
 {
-  if (IDENTIFIER_TEMPLATE (name))
+  if (TREE_CODE (name) == TYPE_DECL
+      && IS_AGGR_TYPE (TREE_TYPE (name))
+      && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name))
+      && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name))))
     {
       tree template, parmlist, arglist, tname;
       int i, nparms;
-      template = IDENTIFIER_TEMPLATE (name);
+      template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
       arglist = TREE_VALUE (template);
       template = TREE_PURPOSE (template);
       tname = DECL_NAME (template);
@@ -457,9 +583,9 @@ build_overload_identifier (name)
       icat (nparms);
       for (i = 0; i < nparms; i++)
        {
-         tree parm = TREE_VEC_ELT (parmlist, i);
+         tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
          tree arg = TREE_VEC_ELT (arglist, i);
-         if (TREE_CODE (parm) == IDENTIFIER_NODE)
+         if (TREE_CODE (parm) == TYPE_DECL)
            {
              /* This parameter is a type.  */
              OB_PUTC ('Z');
@@ -467,6 +593,8 @@ build_overload_identifier (name)
            }
          else
            {
+             parm = tsubst (parm, &TREE_VEC_ELT (arglist, 0),
+                            TREE_VEC_LENGTH (arglist), NULL_TREE);
              /* It's a PARM_DECL.  */
              build_overload_name (TREE_TYPE (parm), 0, 0);
              build_overload_value (parm, arg);
@@ -475,6 +603,13 @@ build_overload_identifier (name)
     }
   else
     {
+      if (TREE_CODE (name) == TYPE_DECL)
+       name = DECL_NAME (name);
+      if (numeric_output_need_bar)
+       {
+         OB_PUTC ('_');
+         numeric_output_need_bar = 0;
+       }
       icat (IDENTIFIER_LENGTH (name));
       OB_PUTID (name);
     }
@@ -501,6 +636,7 @@ build_overload_name (parmtypes, begin, end)
   tree parmtype;
 
   if (begin) OB_INIT ();
+  numeric_output_need_bar = 0;
 
   if ((just_one = (TREE_CODE (parmtypes) != TREE_LIST)))
     {
@@ -514,44 +650,37 @@ build_overload_name (parmtypes, begin, end)
 
     only_one:
 
-      if (! nofold)
+      if (! nofold && ! just_one)
        {
-         if (! just_one)
-           /* Every argument gets counted.  */
-           typevec[maxtype++] = parmtype;
+         /* Every argument gets counted.  */
+         typevec[maxtype++] = parmtype;
 
-         if (TREE_USED (parmtype))
+         if (TREE_USED (parmtype) && parmtype == typevec[maxtype-2])
            {
-             if (! just_one && parmtype == typevec[maxtype-2])
-               nrepeats++;
-             else
-               {
-                 if (nrepeats)
-                   flush_repeats (parmtype);
-                 if (! just_one && TREE_CHAIN (parmtypes)
-                     && parmtype == TREE_VALUE (TREE_CHAIN (parmtypes)))
-                   nrepeats++;
-                 else
-                   {
-                     int tindex = 0;
-
-                     while (typevec[tindex] != parmtype)
-                       tindex++;
-                     OB_PUTC ('T');
-                     icat (tindex);
-                     if (tindex > 9)
-                       OB_PUTC ('_');
-                   }
-               }
+             nrepeats++;
              goto next;
            }
+
          if (nrepeats)
            flush_repeats (typevec[maxtype-2]);
-         if (! just_one
-             /* Only cache types which take more than one character.  */
-             && (parmtype != TYPE_MAIN_VARIANT (parmtype)
-                 || (TREE_CODE (parmtype) != INTEGER_TYPE
-                     && TREE_CODE (parmtype) != REAL_TYPE)))
+
+         if (TREE_USED (parmtype))
+           {
+#if 0
+             /* We can turn this on at some point when we want
+                improved symbol mangling.  */
+             nrepeats++;
+#else
+             /* This is bug compatible with 2.7.x  */
+             flush_repeats (parmtype);
+#endif
+             goto next;
+           }
+
+         /* Only cache types which take more than one character.  */
+         if (parmtype != TYPE_MAIN_VARIANT (parmtype)
+             || (TREE_CODE (parmtype) != INTEGER_TYPE
+                 && TREE_CODE (parmtype) != REAL_TYPE))
            TREE_USED (parmtype) = 1;
        }
 
@@ -586,10 +715,7 @@ build_overload_name (parmtypes, begin, end)
 
            OB_PUTC ('A');
            if (TYPE_DOMAIN (parmtype) == NULL_TREE)
-             {
-               error ("parameter type with unspecified array bounds invalid");
-               icat (1);
-             }
+             error ("pointer or reference to array of unknown bound in parm type");
            else
              {
                length = array_type_nelts (parmtype);
@@ -700,6 +826,10 @@ build_overload_name (parmtypes, begin, end)
            my_friendly_abort (73);
          break;
 
+       case BOOLEAN_TYPE:
+         OB_PUTC ('b');
+         break;
+
        case REAL_TYPE:
          parmtype = TYPE_MAIN_VARIANT (parmtype);
          if (parmtype == long_double_type_node)
@@ -747,6 +877,13 @@ build_overload_name (parmtypes, begin, end)
            if (TREE_CODE (name) == TYPE_DECL)
              {
                tree context = name;
+
+               /* If DECL_ASSEMBLER_NAME has been set properly, use it.  */
+               if (DECL_ASSEMBLER_NAME (context) != DECL_NAME (context))
+                 {
+                   OB_PUTID (DECL_ASSEMBLER_NAME (context));
+                   break;
+                 }
                while (DECL_CONTEXT (context))
                  {
                    i += 1;
@@ -765,10 +902,11 @@ build_overload_name (parmtypes, begin, end)
                icat (i);
                if (i > 9)
                  OB_PUTC ('_');
-               build_overload_nested_name (TYPE_NAME (parmtype));
+               numeric_output_need_bar = 0;
+               build_overload_nested_name (TYPE_MAIN_DECL (parmtype));
              }
-           else
-             build_overload_identifier (name);
+           else              
+             build_overload_identifier (TYPE_MAIN_DECL (parmtype));
            break;
          }
 
@@ -778,8 +916,15 @@ build_overload_name (parmtypes, begin, end)
          break;
 
        case TEMPLATE_TYPE_PARM:
-       case TEMPLATE_CONST_PARM:
-        case UNINSTANTIATED_P_TYPE:
+         OB_PUTC ('X');
+         if (TEMPLATE_TYPE_IDX (parmtype) > 9)
+           OB_PUTC ('_');
+         icat (TEMPLATE_TYPE_IDX (parmtype)); 
+         if (TEMPLATE_TYPE_IDX (parmtype) > 9)
+           OB_PUTC ('_');
+         break;
+           
+       case TYPENAME_TYPE:
          /* We don't ever want this output, but it's inconvenient not to
             be able to build the string.  This should cause assembler
             errors we'll notice.  */
@@ -803,28 +948,25 @@ build_overload_name (parmtypes, begin, end)
       if (nrepeats)
        flush_repeats (typevec[maxtype-1]);
 
-      /* To get here, parms must end with `...'. */
+      /* To get here, parms must end with `...'.  */
       OB_PUTC ('e');
     }
 
   if (end) OB_FINISH ();
   return (char *)obstack_base (&scratch_obstack);
 }
-\f
-/* Generate an identifier that encodes the (ANSI) exception TYPE. */
-
-/* This should be part of `ansi_opname', or at least be defined by the std.  */
-#define EXCEPTION_NAME_PREFIX "__ex"
-#define EXCEPTION_NAME_LENGTH 4
 
 tree
-cplus_exception_name (type)
-     tree type;
+build_static_name (basetype, name)
+  tree basetype, name;
 {
-  OB_INIT ();
-  OB_PUTS (EXCEPTION_NAME_PREFIX);
-  return get_identifier (build_overload_name (type, 0, 1));
-}
+  char *basename  = build_overload_name (basetype, 1, 1);
+  char *buf = (char *) alloca (IDENTIFIER_LENGTH (name)
+                              + sizeof (STATIC_NAME_FORMAT)
+                              + strlen (basename));
+  sprintf (buf, STATIC_NAME_FORMAT, basename, IDENTIFIER_POINTER (name));
+  return get_identifier (buf);
+}  
 \f
 /* Change the name of a function definition so that it may be
    overloaded. NAME is the name of the function to overload,
@@ -834,6 +976,7 @@ cplus_exception_name (type)
    FOR_METHOD is 1 if this overload is being performed
    for a method, rather than a function type.  It is 2 if
    this overload is being performed for a constructor.  */
+
 tree
 build_decl_overload (dname, parms, for_method)
      tree dname;
@@ -845,18 +988,17 @@ build_decl_overload (dname, parms, for_method)
   /* member operators new and delete look like methods at this point.  */
   if (! for_method && parms != NULL_TREE && TREE_CODE (parms) == TREE_LIST)
     {
-      if (TREE_VALUE (parms) == sizetype
-         && TREE_CHAIN (parms) == void_list_node)
+      if (dname == ansi_opname[(int) DELETE_EXPR])
+       return get_identifier ("__builtin_delete");
+      else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
+       return get_identifier ("__builtin_vec_delete");
+      else if (TREE_CHAIN (parms) == void_list_node)
        {
          if (dname == ansi_opname[(int) NEW_EXPR])
            return get_identifier ("__builtin_new");
          else if (dname == ansi_opname[(int) VEC_NEW_EXPR])
            return get_identifier ("__builtin_vec_new");
        }
-      else if (dname == ansi_opname[(int) DELETE_EXPR])
-       return get_identifier ("__builtin_delete");
-      else if (dname == ansi_opname[(int) VEC_DELETE_EXPR])
-       return get_identifier ("__builtin_vec_delete");
     }
 
   OB_INIT ();
@@ -919,6 +1061,7 @@ build_decl_overload (dname, parms, for_method)
 }
 
 /* Build an overload name for the type expression TYPE.  */
+
 tree
 build_typename_overload (type)
      tree type;
@@ -931,106 +1074,36 @@ build_typename_overload (type)
   build_overload_name (type, 0, 1);
   id = get_identifier (obstack_base (&scratch_obstack));
   IDENTIFIER_OPNAME_P (id) = 1;
+#if 0
   IDENTIFIER_GLOBAL_VALUE (id) = TYPE_NAME (type);
+#endif
   TREE_TYPE (id) = type;
   return id;
 }
 
-#ifndef NO_DOLLAR_IN_LABEL
-#define T_DESC_FORMAT "TD$"
-#define I_DESC_FORMAT "ID$"
-#define M_DESC_FORMAT "MD$"
-#else
-#if !defined(NO_DOT_IN_LABEL)
-#define T_DESC_FORMAT "TD."
-#define I_DESC_FORMAT "ID."
-#define M_DESC_FORMAT "MD."
-#else
-#define T_DESC_FORMAT "__t_desc_"
-#define I_DESC_FORMAT "__i_desc_"
-#define M_DESC_FORMAT "__m_desc_"
-#endif
-#endif
-
-/* Build an overload name for the type expression TYPE.  */
 tree
-build_t_desc_overload (type)
-     tree type;
+build_overload_with_type (name, type)
+     tree name, type;
 {
   OB_INIT ();
-  OB_PUTS (T_DESC_FORMAT);
+  OB_PUTID (name);
   nofold = 1;
 
-#if 0
-  /* Use a different format if the type isn't defined yet.  */
-  if (TYPE_SIZE (type) == NULL_TREE)
-    {
-      char *p;
-      int changed;
-
-      for (p = tname; *p; p++)
-       if (isupper (*p))
-         {
-           changed = 1;
-           *p = tolower (*p);
-         }
-      /* If there's no change, we have an inappropriate T_DESC_FORMAT.  */
-      my_friendly_assert (changed != 0, 249);
-    }
-#endif
-
   build_overload_name (type, 0, 1);
   return get_identifier (obstack_base (&scratch_obstack));
 }
 
-/* Top-level interface to explicit overload requests. Allow NAME
-   to be overloaded. Error if NAME is already declared for the current
-   scope. Warning if function is redundantly overloaded. */
-
-void
-declare_overloaded (name)
-     tree name;
-{
-#ifdef NO_AUTO_OVERLOAD
-  if (is_overloaded (name))
-    warning ("function `%s' already declared overloaded",
-            IDENTIFIER_POINTER (name));
-  else if (IDENTIFIER_GLOBAL_VALUE (name))
-    error ("overloading function `%s' that is already defined",
-          IDENTIFIER_POINTER (name));
-  else
-    {
-      TREE_OVERLOADED (name) = 1;
-      IDENTIFIER_GLOBAL_VALUE (name) = build_tree_list (name, NULL_TREE);
-      TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (name)) = unknown_type_node;
-    }
-#else
-  if (current_lang_name == lang_name_cplusplus)
-    {
-      if (0)
-       warning ("functions are implicitly overloaded in C++");
-    }
-  else if (current_lang_name == lang_name_c)
-    error ("overloading function `%s' cannot be done in C language context");
-  else
-    my_friendly_abort (76);
-#endif
-}
-
-#ifdef NO_AUTO_OVERLOAD
-/* Check to see if NAME is overloaded. For first approximation,
-   check to see if its TREE_OVERLOADED is set.  This is used on
-   IDENTIFIER nodes.  */
-int
-is_overloaded (name)
-     tree name;
+tree
+get_id_2 (name, name2)
+     char *name;
+     tree name2;
 {
-  /* @@ */
-  return (TREE_OVERLOADED (name)
-         && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
-         && ! IDENTIFIER_LOCAL_VALUE (name));
+  OB_INIT ();
+  OB_PUTCP (name);
+  OB_PUTID (name2);
+  OB_FINISH ();
+  return get_identifier (obstack_base (&scratch_obstack));
 }
-#endif
 \f
 /* Given a tree_code CODE, and some arguments (at least one),
    attempt to use an overloaded operator on the arguments.
@@ -1069,6 +1142,9 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
   int try_second;
   int binary_is_unary;
 
+  if (flag_ansi_overloading)
+    return build_new_op (code, flags, xarg1, xarg2, arg3);
+
   if (xarg1 == error_mark_node)
     return error_mark_node;
 
@@ -1115,8 +1191,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
        tree args = tree_cons (NULL_TREE, xarg2, arg3);
        fnname = ansi_opname[(int) code];
        if (flags & LOOKUP_GLOBAL)
-         return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN,
-                                     (struct candidate *)0);
+         return build_overload_call (fnname, args, flags & LOOKUP_COMPLAIN);
 
        rval = build_method_call
          (build_indirect_ref (build1 (NOP_EXPR, xarg1, error_mark_node),
@@ -1140,20 +1215,37 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
        if (flags & LOOKUP_GLOBAL)
          return build_overload_call (fnname,
                                      build_tree_list (NULL_TREE, xarg1),
-                                     flags & LOOKUP_COMPLAIN,
-                                     (struct candidate *)0);
+                                     flags & LOOKUP_COMPLAIN);
+       arg1 = TREE_TYPE (xarg1);
+
+       /* This handles the case where we're trying to delete
+          X (*a)[10];
+          a=new X[5][10];
+          delete[] a; */
+          
+       if (TREE_CODE (TREE_TYPE (arg1)) == ARRAY_TYPE)
+         {
+           /* Strip off the pointer and the array.  */
+           arg1 = TREE_TYPE (TREE_TYPE (arg1));
+
+           while (TREE_CODE (arg1) == ARRAY_TYPE)
+               arg1 = (TREE_TYPE (arg1));
+
+           arg1 = build_pointer_type (arg1);
+         }
 
        rval = build_method_call
-         (build_indirect_ref (build1 (NOP_EXPR, TREE_TYPE (xarg1),
+         (build_indirect_ref (build1 (NOP_EXPR, arg1,
                                       error_mark_node),
                               NULL_PTR),
           fnname, tree_cons (NULL_TREE, xarg1,
                               build_tree_list (NULL_TREE, xarg2)),
           NULL_TREE, flags);
-       /* This happens when the user mis-declares `operator delete'.
-          Should now be impossible.  */
+#if 0
+       /* This can happen when operator delete is protected.  */
        my_friendly_assert (rval != error_mark_node, 250);
        TREE_TYPE (rval) = void_type_node;
+#endif
        return rval;
       }
       break;
@@ -1191,7 +1283,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
       /* Try to fail. First, fail if unary */
       if (! try_second)
        return rval;
-      /* Second, see if second argument is non-aggregate. */
+      /* Second, see if second argument is non-aggregate.  */
       type2 = TREE_TYPE (xarg2);
       if (TREE_CODE (type2) == OFFSET_TYPE)
        type2 = TREE_TYPE (type2);
@@ -1242,7 +1334,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
   else
     fnname = ansi_opname[(int) code];
 
-  global_fn = IDENTIFIER_GLOBAL_VALUE (fnname);
+  global_fn = lookup_name_nonclass (fnname);
 
   /* This is the last point where we will accept failure.  This
      may be too eager if we wish an overloaded operator not to match,
@@ -1265,7 +1357,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
 
              /* Look for an `operator++ (int)'.  If they didn't have
                 one, then we fall back to the old way of doing things.  */
-             for (t = TREE_VALUE (fields1); t ; t = TREE_CHAIN (t))
+             for (t = TREE_VALUE (fields1); t ; t = DECL_CHAIN (t))
                {
                  t2 = TYPE_ARG_TYPES (TREE_TYPE (t));
                  if (TREE_CHAIN (t2) != NULL_TREE
@@ -1281,13 +1373,9 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
                  char *op = POSTINCREMENT_EXPR ? "++" : "--";
 
                  /* There's probably a LOT of code in the world that
-                    relies upon this old behavior.  So we'll only give this
-                    warning when we've been given -pedantic.  A few
-                    releases after 2.4, we'll convert this to be a pedwarn
-                    or something else more appropriate.  */
-                 if (pedantic)
-                   warning ("no `operator%s (int)' declared for postfix `%s'",
-                            op, op);
+                    relies upon this old behavior.  */
+                 pedwarn ("no `operator%s (int)' declared for postfix `%s', using prefix operator instead",
+                          op, op);
                  xarg2 = NULL_TREE;
                  binary_is_unary = 1;
                }
@@ -1329,7 +1417,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
     }
   else if (code == COND_EXPR)
     {
-      parms = tree_cons (0, xarg2, build_tree_list (NULL_TREE, arg3));
+      parms = tree_cons (NULL_TREE, xarg2, build_tree_list (NULL_TREE, arg3));
       rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
     }
   else if (code == METHOD_CALL_EXPR)
@@ -1348,8 +1436,7 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
     {
       parms = tree_cons (NULL_TREE, xarg1,
                         build_tree_list (NULL_TREE, xarg2));
-      rval = build_overload_call (fnname, parms, flags,
-                                 (struct candidate *)0);
+      rval = build_overload_call (fnname, parms, flags);
     }
 
   return rval;
@@ -1366,7 +1453,6 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
 
    NAME is $1 from the bison rule. It is an IDENTIFIER_NODE.
    VALUE is $$ from the bison rule. It is the value returned by lookup_name ($1)
-   yychar is the pending input character (suitably encoded :-).
 
    As a last ditch, try to look up the name as a label and return that
    address.
@@ -1376,11 +1462,10 @@ build_opfncall (code, flags, xarg1, xarg2, arg3)
    compiler faster).  */
 
 tree
-hack_identifier (value, name, yychar)
+hack_identifier (value, name)
      tree value, name;
-     int yychar;
 {
-  tree type;
+  tree type, context;
 
   if (TREE_CODE (value) == ERROR_MARK)
     {
@@ -1418,51 +1503,59 @@ hack_identifier (value, name, yychar)
   type = TREE_TYPE (value);
   if (TREE_CODE (value) == FIELD_DECL)
     {
-      if (current_class_decl == NULL_TREE)
+      if (current_class_ptr == NULL_TREE)
        {
          error ("request for member `%s' in static member function",
                 IDENTIFIER_POINTER (DECL_NAME (value)));
          return error_mark_node;
        }
-      TREE_USED (current_class_decl) = 1;
-      if (yychar == '(')
-       if (! ((TYPE_LANG_SPECIFIC (type)
-               && TYPE_OVERLOADS_CALL_EXPR (type))
-              || (TREE_CODE (type) == REFERENCE_TYPE
-                  && TYPE_LANG_SPECIFIC (TREE_TYPE (type))
-                  && TYPE_OVERLOADS_CALL_EXPR (TREE_TYPE (type))))
-           && TREE_CODE (type) != FUNCTION_TYPE
-           && TREE_CODE (type) != METHOD_TYPE
-           && !TYPE_PTRMEMFUNC_P (type)
-           && (TREE_CODE (type) != POINTER_TYPE
-               || (TREE_CODE (TREE_TYPE (type)) != FUNCTION_TYPE
-                   && TREE_CODE (TREE_TYPE (type)) != METHOD_TYPE)))
-         {
-           error ("component `%s' is not a method",
-                  IDENTIFIER_POINTER (name));
-           return error_mark_node;
-         }
+      TREE_USED (current_class_ptr) = 1;
+
       /* Mark so that if we are in a constructor, and then find that
         this field was initialized by a base initializer,
         we can emit an error message.  */
       TREE_USED (value) = 1;
-      return build_component_ref (C_C_D, name, 0, 1);
+      value = build_component_ref (current_class_ref, name, NULL_TREE, 1);
     }
+  else if (really_overloaded_fn (value))
+    {
+#if 0
+      tree t = get_first_fn (value);
+      for (; t; t = DECL_CHAIN (t))
+       {
+         if (TREE_CODE (t) == TEMPLATE_DECL)
+           continue;
 
-  if (TREE_CODE (value) == TREE_LIST)
+         assemble_external (t);
+         TREE_USED (t) = 1;
+       }
+#endif
+    }
+  else if (TREE_CODE (value) == TREE_LIST)
     {
+      /* Ambiguous reference to base members, possibly other cases?.  */
       tree t = value;
       while (t && TREE_CODE (t) == TREE_LIST)
        {
-         assemble_external (TREE_VALUE (t));
-         TREE_USED (t) = 1;
+         mark_used (TREE_VALUE (t));
          t = TREE_CHAIN (t);
        }
     }
   else
+    mark_used (value);
+
+  if (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL)
     {
-      assemble_external (value);
-      TREE_USED (value) = 1;
+      tree context = decl_function_context (value);
+      if (context != NULL_TREE && context != current_function_decl
+         && ! TREE_STATIC (value))
+       {
+         cp_error ("use of %s from containing function",
+                     (TREE_CODE (value) == VAR_DECL
+                      ? "`auto' variable" : "parameter"));
+         cp_error_at ("  `%#D' declared here", value);
+         value = error_mark_node;
+       }
     }
 
   if (TREE_CODE_CLASS (TREE_CODE (value)) == 'd' && DECL_NONLOCAL (value))
@@ -1470,8 +1563,7 @@ hack_identifier (value, name, yychar)
       if (DECL_LANG_SPECIFIC (value)
          && DECL_CLASS_CONTEXT (value) != current_class_type)
        {
-         tree path;
-         enum access_type access;
+         tree path, access;
          register tree context
            = (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value))
              ? DECL_CLASS_CONTEXT (value)
@@ -1481,7 +1573,7 @@ hack_identifier (value, name, yychar)
          if (path)
            {
              access = compute_access (path, value);
-             if (access != access_public)
+             if (access != access_public_node)
                {
                  if (TREE_CODE (value) == VAR_DECL)
                    error ("static member `%s' is %s",
@@ -1509,151 +1601,12 @@ hack_identifier (value, name, yychar)
       return value;
     }
 
-  if (TREE_CODE (type) == REFERENCE_TYPE)
-    {
-      my_friendly_assert (TREE_CODE (value) == VAR_DECL
-                         || TREE_CODE (value) == PARM_DECL
-                         || TREE_CODE (value) == RESULT_DECL, 252);
-      if (DECL_REFERENCE_SLOT (value))
-       return DECL_REFERENCE_SLOT (value);
-    }
+  if (TREE_CODE (type) == REFERENCE_TYPE && ! processing_template_decl)
+    value = convert_from_reference (value);
   return value;
 }
 
 \f
-/* Given an object OF, and a type conversion operator COMPONENT
-   build a call to the conversion operator, if a call is requested,
-   or return the address (as a pointer to member function) if one is not.
-
-   OF can be a TYPE_DECL or any kind of datum that would normally
-   be passed to `build_component_ref'.  It may also be NULL_TREE,
-   in which case `current_class_type' and `current_class_decl'
-   provide default values.
-
-   BASETYPE_PATH, if non-null, is the path of basetypes
-   to go through before we get the the instance of interest.
-
-   PROTECT says whether we apply C++ scoping rules or not.  */
-tree
-build_component_type_expr (of, component, basetype_path, protect)
-     tree of, component, basetype_path;
-     int protect;
-{
-  tree cname = NULL_TREE;
-  tree tmp, last;
-  tree name;
-  int flags = protect ? LOOKUP_NORMAL : LOOKUP_COMPLAIN;
-
-  if (of)
-    my_friendly_assert (IS_AGGR_TYPE (TREE_TYPE (of)), 253);
-  my_friendly_assert (TREE_CODE (component) == TYPE_EXPR, 254);
-
-  tmp = TREE_OPERAND (component, 0);
-  last = NULL_TREE;
-
-  while (tmp)
-    {
-      switch (TREE_CODE (tmp))
-       {
-       case CALL_EXPR:
-         if (last)
-           TREE_OPERAND (last, 0) = TREE_OPERAND (tmp, 0);
-         else
-           TREE_OPERAND (component, 0) = TREE_OPERAND (tmp, 0);
-
-         last = groktypename (build_tree_list (TREE_TYPE (component),
-                                               TREE_OPERAND (component, 0)));
-         name = build_typename_overload (last);
-         TREE_TYPE (name) = last;
-
-         if (TREE_OPERAND (tmp, 0)
-             && TREE_OPERAND (tmp, 0) != void_list_node)
-           {
-             cp_error ("`operator %T' requires empty parameter list", last);
-             TREE_OPERAND (tmp, 0) = NULL_TREE;
-           }
-
-         if (of && TREE_CODE (of) != TYPE_DECL)
-           return build_method_call (of, name, NULL_TREE, NULL_TREE, flags);
-         else if (of)
-           {
-             tree this_this;
-
-             if (current_class_decl == NULL_TREE)
-               {
-                 cp_error ("object required for `operator %T' call",
-                           TREE_TYPE (name));
-                 return error_mark_node;
-               }
-
-             this_this = convert_pointer_to (TREE_TYPE (of),
-                                             current_class_decl);
-             this_this = build_indirect_ref (this_this, NULL_PTR);
-             return build_method_call (this_this, name, NULL_TREE,
-                                       NULL_TREE, flags | LOOKUP_NONVIRTUAL);
-           }
-         else if (current_class_decl)
-           return build_method_call (tmp, name, NULL_TREE, NULL_TREE, flags);
-
-         cp_error ("object required for `operator %T' call",
-                   TREE_TYPE (name));
-         return error_mark_node;
-
-       case INDIRECT_REF:
-       case ADDR_EXPR:
-       case ARRAY_REF:
-         break;
-
-       case SCOPE_REF:
-         my_friendly_assert (cname == 0, 255);
-         cname = TREE_OPERAND (tmp, 0);
-         tmp = TREE_OPERAND (tmp, 1);
-         break;
-
-       default:
-         my_friendly_abort (77);
-       }
-      last = tmp;
-      tmp = TREE_OPERAND (tmp, 0);
-    }
-
-  last = groktypename (build_tree_list (TREE_TYPE (component), TREE_OPERAND (component, 0)));
-  name = build_typename_overload (last);
-  TREE_TYPE (name) = last;
-  if (of && TREE_CODE (of) == TYPE_DECL)
-    {
-      if (cname == NULL_TREE)
-       {
-         cname = DECL_NAME (of);
-         of = NULL_TREE;
-       }
-      else my_friendly_assert (cname == DECL_NAME (of), 256);
-    }
-
-  if (of)
-    {
-      tree this_this;
-
-      if (current_class_decl == NULL_TREE)
-       {
-         cp_error ("object required for `operator %T' call",
-                   TREE_TYPE (name));
-         return error_mark_node;
-       }
-
-      this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl);
-      return build_component_ref (this_this, name, 0, protect);
-    }
-  else if (cname)
-    return build_offset_ref (cname, name);
-  else if (current_class_name)
-    return build_offset_ref (current_class_name, name);
-
-  cp_error ("object required for `operator %T' member reference",
-           TREE_TYPE (name));
-  return error_mark_node;
-}
-\f
 static char *
 thunk_printable_name (decl)
      tree decl;
@@ -1667,8 +1620,9 @@ make_thunk (function, delta)
      int delta;
 {
   char buffer[250];
-  tree thunk_fndecl;
+  tree thunk_fndecl, thunk_id;
   tree thunk;
+  char *func_name;
   static int thunk_number = 0;
   tree func_decl;
   if (TREE_CODE (function) != ADDR_EXPR)
@@ -1676,14 +1630,34 @@ make_thunk (function, delta)
   func_decl = TREE_OPERAND (function, 0);
   if (TREE_CODE (func_decl) != FUNCTION_DECL)
     abort ();
-  sprintf (buffer, "__thunk_%d_%d", -delta, thunk_number++);
-  thunk = build_decl (THUNK_DECL, get_identifier (buffer),
-                     TREE_TYPE (func_decl));
-  DECL_RESULT (thunk)
-    = build_decl (RESULT_DECL, NULL_TREE, void_type_node);
-  make_function_rtl (thunk);
-  DECL_INITIAL (thunk) = function;
-  THUNK_DELTA (thunk) = delta;
+  func_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func_decl));
+  if (delta<=0)
+    sprintf (buffer, "__thunk_%d_%s", -delta, func_name);
+  else
+    sprintf (buffer, "__thunk_n%d_%s", delta, func_name);
+  thunk_id = get_identifier (buffer);
+  thunk = IDENTIFIER_GLOBAL_VALUE (thunk_id);
+  if (thunk && TREE_CODE (thunk) != THUNK_DECL)
+    {
+      cp_error ("implementation-reserved name `%D' used", thunk_id);
+      IDENTIFIER_GLOBAL_VALUE (thunk_id) = thunk = NULL_TREE;
+    }
+  if (thunk == NULL_TREE)
+    {
+      thunk = build_decl (FUNCTION_DECL, thunk_id, TREE_TYPE (func_decl));
+      DECL_RESULT (thunk)
+       = build_decl (RESULT_DECL, 0, TYPE_MAIN_VARIANT (TREE_TYPE (vtable_entry_type)));
+      TREE_READONLY (thunk) = TYPE_READONLY (TREE_TYPE (vtable_entry_type));
+      TREE_THIS_VOLATILE (thunk) = TYPE_VOLATILE (TREE_TYPE (vtable_entry_type));
+      make_function_rtl (thunk);
+      comdat_linkage (thunk);
+      TREE_SET_CODE (thunk, THUNK_DECL);
+      DECL_INITIAL (thunk) = function;
+      THUNK_DELTA (thunk) = delta;
+      DECL_EXTERNAL (thunk) = 1;
+      /* So that finish_file can write out any thunks that need to be: */
+      pushdecl_top_level (thunk);
+    }
   return thunk;
 }
 
@@ -1692,21 +1666,21 @@ emit_thunk (thunk_fndecl)
   tree thunk_fndecl;
 {
   rtx insns;
-  char *fnname;
   char buffer[250];
   tree argp;
   struct args_size stack_args_size;
   tree function = TREE_OPERAND (DECL_INITIAL (thunk_fndecl), 0);
   int delta = THUNK_DELTA (thunk_fndecl);
+  char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
   int tem;
   int failure = 0;
-  extern int current_call_is_indirect; /* Needed for (at least) HPPA. */
+  int save_ofp;
 
-  /* Used to remember which regs we need to emit a USE rtx for. */
+  /* Used to remember which regs we need to emit a USE rtx for.  */
   rtx need_use[FIRST_PSEUDO_REGISTER];
   int need_use_count = 0;
 
-  /* rtx for the 'this' parameter. */
+  /* rtx for the 'this' parameter.  */
   rtx this_rtx = 0, this_reg_rtx = 0, fixed_this_rtx;
 
   char *(*save_decl_printable_name) () = decl_printable_name;
@@ -1716,23 +1690,41 @@ emit_thunk (thunk_fndecl)
   if (TREE_ASM_WRITTEN (thunk_fndecl))
     return;
 
+  TREE_ASM_WRITTEN (thunk_fndecl) = 1;
+
+  TREE_ADDRESSABLE (function) = 1;
+  mark_used (function);
+
   decl_printable_name = thunk_printable_name;
   if (current_function_decl)
     abort ();
   current_function_decl = thunk_fndecl;
+
+  TREE_SET_CODE (thunk_fndecl, FUNCTION_DECL);
+#ifdef ASM_OUTPUT_MI_THUNK
+  temporary_allocation ();
+  assemble_start_function (thunk_fndecl, fnname);
+  ASM_OUTPUT_MI_THUNK (asm_out_file, thunk_fndecl, delta, function);
+  assemble_end_function (thunk_fndecl, fnname);
+  permanent_allocation (1);
+#else
+  save_ofp = flag_omit_frame_pointer;
+  flag_omit_frame_pointer = 1;
   init_function_start (thunk_fndecl, input_filename, lineno);
   pushlevel (0);
   expand_start_bindings (1);
 
+  temporary_allocation ();
+
   /* Start updating where the next arg would go.  */
-  INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX);
+  INIT_CUMULATIVE_ARGS (args_so_far, TREE_TYPE (function), NULL_RTX, 0);
   stack_args_size.constant = 0;
   stack_args_size.var = 0;
   /* SETUP for possible structure return address FIXME */
 
   /* Now look through all the parameters, make sure that we
      don't clobber any registers used for parameters.
-     Also, pick up an rtx for the first "this" parameter. */
+     Also, pick up an rtx for the first "this" parameter.  */
   for (argp = TYPE_ARG_TYPES (TREE_TYPE (function));
        argp != NULL_TREE;
        argp = TREE_CHAIN (argp))
@@ -1824,8 +1816,6 @@ emit_thunk (thunk_fndecl)
   expand_end_bindings (NULL, 1, 0);
   poplevel (0, 0, 1);
 
-  TREE_ASM_WRITTEN (thunk_fndecl) = 1;
-
   /* From now on, allocate rtl in current_obstack, not in saveable_obstack.
      Note that that may have been done above, in save_for_inline_copying.
      The call to resume_temporary_allocation near the end of this function
@@ -1887,21 +1877,289 @@ emit_thunk (thunk_fndecl)
 
   /* Now turn the rtl into assembler code.  */
 
-    {
-      char *fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
-      assemble_start_function (thunk_fndecl, fnname);
-      final (insns, asm_out_file, optimize, 0);
-      assemble_end_function (thunk_fndecl, fnname);
-    };
-
- exit_rest_of_compilation:
+  assemble_start_function (thunk_fndecl, fnname);
+  final (insns, asm_out_file, optimize, 0);
+  assemble_end_function (thunk_fndecl, fnname);
 
   reload_completed = 0;
 
   /* Cancel the effect of rtl_in_current_obstack.  */
 
-  resume_temporary_allocation ();
+  permanent_allocation (1);
+  flag_omit_frame_pointer = save_ofp;
+#endif /* ASM_OUTPUT_MI_THUNK */
+  TREE_SET_CODE (thunk_fndecl, THUNK_DECL);
 
   decl_printable_name = save_decl_printable_name;
   current_function_decl = 0;
 }
+\f
+/* Code for synthesizing methods which have default semantics defined.  */
+
+/* For the anonymous union in TYPE, return the member that is at least as
+   large as the rest of the members, so we can copy it.  */
+
+static tree
+largest_union_member (type)
+     tree type;
+{
+  tree f, type_size = TYPE_SIZE (type);
+
+  for (f = TYPE_FIELDS (type); f; f = TREE_CHAIN (f))
+    if (simple_cst_equal (DECL_SIZE (f), type_size) == 1)
+      return f;
+
+  /* We should always find one.  */
+  my_friendly_abort (323);
+  return NULL_TREE;
+}
+
+/* Generate code for default X(X&) constructor.  */
+
+void
+do_build_copy_constructor (fndecl)
+     tree fndecl;
+{
+  tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
+  tree t;
+
+  clear_last_expr ();
+  push_momentary ();
+
+  if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
+    parm = TREE_CHAIN (parm);
+  parm = convert_from_reference (parm);
+
+  if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type))
+    {
+      t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
+      TREE_SIDE_EFFECTS (t) = 1;
+      cplus_expand_expr_stmt (t);
+    }
+  else
+    {
+      tree fields = TYPE_FIELDS (current_class_type);
+      int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
+      tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
+      int i;
+
+      for (t = CLASSTYPE_VBASECLASSES (current_class_type); t;
+          t = TREE_CHAIN (t))
+       {
+         tree basetype = BINFO_TYPE (t);
+         tree p = convert_to_reference
+           (build_reference_type (basetype), parm,
+            CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+         p = convert_from_reference (p);
+
+         if (p == error_mark_node)
+           cp_error ("in default copy constructor");
+         else 
+           current_base_init_list = tree_cons (basetype,
+                                               p, current_base_init_list);
+       }
+       
+      for (i = 0; i < n_bases; ++i)
+       {
+         tree p, basetype = TREE_VEC_ELT (binfos, i);
+         if (TREE_VIA_VIRTUAL (basetype))
+           continue; 
+
+         basetype = BINFO_TYPE (basetype);
+         p = convert_to_reference
+           (build_reference_type (basetype), parm,
+            CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+
+         if (p == error_mark_node) 
+           cp_error ("in default copy constructor");
+         else 
+           {
+             p = convert_from_reference (p);
+             current_base_init_list = tree_cons (basetype,
+                                                 p, current_base_init_list);
+           }
+       }
+      for (; fields; fields = TREE_CHAIN (fields))
+       {
+         tree name, init, t;
+         tree field = fields;
+
+         if (TREE_CODE (field) != FIELD_DECL)
+           continue;
+         if (DECL_NAME (field))
+           {
+             if (VFIELD_NAME_P (DECL_NAME (field)))
+               continue;
+             if (VBASE_NAME_P (DECL_NAME (field)))
+               continue;
+
+             /* True for duplicate members.  */
+             if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
+               continue;
+           }
+         else if ((t = TREE_TYPE (field)) != NULL_TREE
+                  && TREE_CODE (t) == UNION_TYPE
+                  && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+                  && TYPE_FIELDS (t) != NULL_TREE)
+           field = largest_union_member (t);
+         else
+           continue;
+
+         init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+         init = build_tree_list (NULL_TREE, init);
+
+         current_member_init_list
+           = tree_cons (DECL_NAME (field), init, current_member_init_list);
+       }
+      current_member_init_list = nreverse (current_member_init_list);
+      current_base_init_list = nreverse (current_base_init_list);
+      setup_vtbl_ptr ();
+    }
+
+  pop_momentary ();
+}
+
+void
+do_build_assign_ref (fndecl)
+     tree fndecl;
+{
+  tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
+
+  clear_last_expr ();
+  push_momentary ();
+
+  parm = convert_from_reference (parm);
+
+  if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type))
+    {
+      tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm);
+      TREE_SIDE_EFFECTS (t) = 1;
+      cplus_expand_expr_stmt (t);
+    }
+  else
+    {
+      tree fields = TYPE_FIELDS (current_class_type);
+      int n_bases = CLASSTYPE_N_BASECLASSES (current_class_type);
+      tree binfos = TYPE_BINFO_BASETYPES (current_class_type);
+      int i;
+
+      for (i = 0; i < n_bases; ++i)
+       {
+         tree basetype = BINFO_TYPE (TREE_VEC_ELT (binfos, i));
+         tree p = convert_to_reference
+           (build_reference_type (basetype), parm,
+            CONV_IMPLICIT|CONV_CONST, LOOKUP_COMPLAIN, NULL_TREE);
+         p = convert_from_reference (p);
+         p = build_member_call (basetype, ansi_opname [MODIFY_EXPR],
+                                build_tree_list (NULL_TREE, p));
+         expand_expr_stmt (p);
+       }
+      for (; fields; fields = TREE_CHAIN (fields))
+       {
+         tree comp, init, t;
+         tree field = fields;
+
+         if (TREE_CODE (field) != FIELD_DECL)
+           continue;
+
+         if (TREE_READONLY (field))
+           {
+             if (DECL_NAME (field))
+               cp_error ("non-static const member `%#D', can't use default assignment operator", field);
+             else
+               cp_error ("non-static const member in type `%T', can't use default assignment operator", current_class_type);
+             continue;
+           }
+         else if (TREE_CODE (TREE_TYPE (field)) == REFERENCE_TYPE)
+           {
+             if (DECL_NAME (field))
+               cp_error ("non-static reference member `%#D', can't use default assignment operator", field);
+             else
+               cp_error ("non-static reference member in type `%T', can't use default assignment operator", current_class_type);
+             continue;
+           }
+
+         if (DECL_NAME (field))
+           {
+             if (VFIELD_NAME_P (DECL_NAME (field)))
+               continue;
+             if (VBASE_NAME_P (DECL_NAME (field)))
+               continue;
+
+             /* True for duplicate members.  */
+             if (IDENTIFIER_CLASS_VALUE (DECL_NAME (field)) != field)
+               continue;
+           }
+         else if ((t = TREE_TYPE (field)) != NULL_TREE
+                  && TREE_CODE (t) == UNION_TYPE
+                  && ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))
+                  && TYPE_FIELDS (t) != NULL_TREE)
+           field = largest_union_member (t);
+         else
+           continue;
+
+         comp = build (COMPONENT_REF, TREE_TYPE (field), current_class_ref, field);
+         init = build (COMPONENT_REF, TREE_TYPE (field), parm, field);
+
+         expand_expr_stmt (build_modify_expr (comp, NOP_EXPR, init));
+       }
+    }
+  c_expand_return (current_class_ref);
+  pop_momentary ();
+}
+
+void
+synthesize_method (fndecl)
+     tree fndecl;
+{
+  int nested = (current_function_decl != NULL_TREE);
+  tree context = hack_decl_function_context (fndecl);
+  tree base = DECL_CLASS_CONTEXT (fndecl);
+
+  if (! context)
+    push_to_top_level ();
+  else if (nested)
+    push_cp_function_context (context);
+
+  interface_unknown = 1;
+  start_function (NULL_TREE, fndecl, NULL_TREE, 1);
+  store_parm_decls ();
+
+  if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
+    do_build_assign_ref (fndecl);
+  else if (DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (fndecl)))
+    ;
+  else
+    {
+      tree arg_chain = FUNCTION_ARG_CHAIN (fndecl);
+      if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl))
+       arg_chain = TREE_CHAIN (arg_chain);
+      if (arg_chain != void_list_node)
+       do_build_copy_constructor (fndecl);
+      else if (TYPE_NEEDS_CONSTRUCTING (current_class_type))
+       setup_vtbl_ptr ();
+    }
+
+  finish_function (lineno, 0, nested);
+
+  /* Do we really *want* to inline this function?  */
+  if (DECL_INLINE (fndecl))
+    {
+      /* Turn off DECL_INLINE for the moment so function_cannot_inline_p
+         will check our size.  */
+      DECL_INLINE (fndecl) = 0;
+
+      /* We say !at_eof because at the end of the file some of the rtl
+        for fndecl may have been allocated on the temporary obstack.
+        (The function_obstack is the temporary one if we're not in a
+        function). */
+      if ((! at_eof) && function_cannot_inline_p (fndecl) == 0)
+       DECL_INLINE (fndecl) = 1;
+    }
+
+  extract_interface_info ();
+  if (! context)
+    pop_from_top_level ();
+  else if (nested)
+    pop_cp_function_context (context);
+}