386BSD 0.1 development
authorWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 6 Aug 1990 04:31:37 +0000 (20:31 -0800)
committerWilliam F. Jolitz <wjolitz@soda.berkeley.edu>
Mon, 6 Aug 1990 04:31:37 +0000 (20:31 -0800)
Work on file usr/src/usr.bin/g++/cc1plus/cplus-method.c

Co-Authored-By: Lynne Greer Jolitz <ljolitz@cardio.ucsf.edu>
Synthesized-from: 386BSD-0.1

usr/src/usr.bin/g++/cc1plus/cplus-method.c [new file with mode: 0644]

diff --git a/usr/src/usr.bin/g++/cc1plus/cplus-method.c b/usr/src/usr.bin/g++/cc1plus/cplus-method.c
new file mode 100644 (file)
index 0000000..70b1941
--- /dev/null
@@ -0,0 +1,2504 @@
+/* Handle the hair of processing (but not expanding) inline functions.
+   Also manage function and varaible name overloading.
+   Copyright (C) 1987 Free Software Foundation, Inc.
+   Contributed by Michael Tiemann (tiemann@mcc.com)
+
+   This file is part of GNU CC.
+   
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 1, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+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.  */
+
+
+/* Handle method declarations.  */
+#include <stdio.h>
+#include "config.h"
+#include "tree.h"
+#include "cplus-tree.h"
+#include "assert.h"
+
+/* TREE_LIST of the current inline functions that need to be
+   processed.  */
+struct pending_inline *pending_inlines;
+
+# define MAX_INLINE_BUF_SIZE 8188
+# define OB_INIT() (inline_bufp = inline_buffer)
+# define OB_PUTC(C) (*inline_bufp++ = (C))
+# define OB_PUTC2(C1,C2) (OB_PUTC (C1), OB_PUTC (C2))
+# define OB_PUTS(S) (strcpy (inline_bufp, S), inline_bufp += sizeof (S) - 1)
+# define OB_PUTCP(S) (strcpy (inline_bufp, S), inline_bufp += strlen (S))
+# define OB_FINISH() (*inline_bufp++ = '\0')
+
+/* Counter to help build parameter names in case they were omitted.  */
+static int dummy_name;
+static int in_parmlist;
+/* Just a pointer into INLINE_BUFFER.  */
+static char *inline_bufp;
+/* Also a pointer into INLINE_BUFFER.  This points to a safe place to
+   cut back to if we assign it 0, in case of error.  */
+static char *inline_errp;
+static char *inline_buffer;
+static void dump_type (), dump_decl ();
+static void dump_init (), dump_unary_op (), dump_binary_op ();
+
+tree wrapper_name, wrapper_pred_name, anti_wrapper_name;
+
+#ifdef NO_AUTO_OVERLOAD
+int is_overloaded ();
+#endif
+
+void
+init_method ()
+{
+  char buf[sizeof (ANTI_WRAPPER_NAME_FORMAT) + 8];
+  sprintf (buf, WRAPPER_NAME_FORMAT, "");
+  wrapper_name = get_identifier (buf);
+  sprintf (buf, WRAPPER_PRED_NAME_FORMAT, "");
+  wrapper_pred_name = get_identifier (buf);
+  sprintf (buf, ANTI_WRAPPER_NAME_FORMAT, "");
+  anti_wrapper_name = get_identifier (buf);
+}
+
+/* Return a pointer to the end of the new text in INLINE_BUFFER.
+   We cannot use `fatal' or `error' in here because that
+   might cause an infinite loop.  */
+static char *
+new_text_len (s)
+     char *s;
+{
+  while (*s++) ;
+
+  if (s >= inline_buffer + MAX_INLINE_BUF_SIZE)
+    {
+      fprintf (stderr, "recompile c++ with larger MAX_INLINE_BUF_SIZE (%d)", MAX_INLINE_BUF_SIZE);
+      abort ();
+    }
+  return s - 1;
+}
+
+/* Check that we have not overflowed INLINE_BUFFER.
+   We cannot use `fatal' or `error' in here because that
+   might cause an infinite loop.  */
+static void
+check_text_len (s)
+     char *s;
+{
+  if (s >= inline_buffer + MAX_INLINE_BUF_SIZE)
+    {
+      fprintf (stderr, "recompile c++ with larger MAX_INLINE_BUF_SIZE (%d)", MAX_INLINE_BUF_SIZE);
+      abort ();
+    }
+}
+
+tree
+make_anon_parm_name ()
+{
+  char buf[32];
+
+  sprintf (buf, ANON_PARMNAME_FORMAT, dummy_name++);
+  return get_identifier (buf);
+}
+
+void
+clear_anon_parm_name ()
+{
+  /* recycle these names.  */
+  dummy_name = 0;
+}
+
+static void
+dump_readonly_or_volatile (t)
+     tree t;
+{
+  if (TREE_READONLY (t))
+    OB_PUTS ("const ");
+  if (TREE_VOLATILE (t))
+    OB_PUTS ("volatile ");
+}
+
+static void
+dump_type_prefix (t, p)
+     tree t;
+     int *p;
+{
+  int old_p = 0;
+  int print_struct = 1;
+  tree name;
+
+  if (t == NULL_TREE)
+    return;
+
+  switch (TREE_CODE (t))
+    {
+    case ERROR_MARK:
+      sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++);
+      break;
+
+    case UNKNOWN_TYPE:
+      OB_PUTS ("<unknown type>");
+      return;
+
+    case TREE_LIST:
+      dump_type (TREE_VALUE (t), &old_p);
+      if (TREE_CHAIN (t))
+       {
+         if (TREE_CHAIN (t) != void_list_node)
+           {
+             OB_PUTC (',');
+             dump_type (TREE_CHAIN (t), &old_p);
+           }
+       }
+      else OB_PUTS ("...");
+      return;
+
+    case POINTER_TYPE:
+      *p += 1;
+      dump_type_prefix (TREE_TYPE (t), p);
+      while (*p)
+       {
+         OB_PUTC ('*');
+         *p -= 1;
+       }
+      if (TREE_READONLY (t))
+       OB_PUTS ("const ");
+      if (TREE_VOLATILE (t))
+       OB_PUTS ("volatile ");
+      return;
+
+    case OFFSET_TYPE:
+      {
+       tree type = TREE_TYPE (t);
+       if (TREE_CODE (type) == FUNCTION_TYPE)
+         {
+           type = TREE_TYPE (type);
+           if (in_parmlist)
+             OB_PUTS ("auto ");
+         }
+
+       dump_type_prefix (type, &old_p);
+
+       OB_PUTC ('(');
+       dump_type (TYPE_OFFSET_BASETYPE (t), &old_p);
+       OB_PUTC2 (':', ':');
+       while (*p)
+         {
+           OB_PUTC ('*');
+           *p -= 1;
+         }
+       if (TREE_READONLY (t) | TREE_VOLATILE (t))
+         dump_readonly_or_volatile (t);
+       return;
+      }
+
+    case METHOD_TYPE:
+      {
+       tree type = TREE_TYPE (t);
+       if (in_parmlist)
+         OB_PUTS ("auto ");
+
+       dump_type_prefix (type, &old_p);
+
+       OB_PUTC ('(');
+       dump_type (TYPE_METHOD_BASETYPE (t), &old_p);
+       OB_PUTC2 (':', ':');
+       while (*p)
+         {
+           OB_PUTC ('*');
+           *p -= 1;
+         }
+       if (TREE_READONLY (t) | TREE_VOLATILE (t))
+         dump_readonly_or_volatile (t);
+       return;
+      }
+
+    case REFERENCE_TYPE:
+      dump_type_prefix (TREE_TYPE (t), p);
+      OB_PUTC ('&');
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      return;
+
+    case ARRAY_TYPE:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      dump_type_prefix (TREE_TYPE (t), p);
+      return;
+
+    case FUNCTION_TYPE:
+      if (in_parmlist)
+       OB_PUTS ("auto ");
+      dump_type_prefix (TREE_TYPE (t), &old_p);
+      OB_PUTC ('(');
+      while (*p)
+       {
+         OB_PUTC ('*');
+         *p -= 1;
+       }
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      return;
+
+    case IDENTIFIER_NODE:
+      sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t));
+      break;
+
+    case RECORD_TYPE:
+      if (TREE_READONLY (t))
+       OB_PUTS ("const ");
+      if (TREE_VOLATILE (t))
+       OB_PUTS ("volatile ");
+      if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
+       print_struct = 0;
+      name = TYPE_NAME (t);
+      if (TREE_CODE (name) == TYPE_DECL)
+       name = DECL_NAME (name);
+      if (print_struct)
+       sprintf (inline_bufp, "struct %s ", IDENTIFIER_POINTER (name));
+      else
+       sprintf (inline_bufp, "class %s ", IDENTIFIER_POINTER (name));
+      break;
+
+    case UNION_TYPE:
+      if (TREE_READONLY (t))
+       OB_PUTS ("const ");
+      if (TREE_VOLATILE (t))
+       OB_PUTS ("volatile ");
+      name = TYPE_NAME (t);
+      if (TREE_CODE (name) == TYPE_DECL)
+       name = DECL_NAME (name);
+      sprintf (inline_bufp, "union %s ", IDENTIFIER_POINTER (name));
+      break;
+
+    case ENUMERAL_TYPE:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      name = TYPE_NAME (t);
+      if (TREE_CODE (name) == TYPE_DECL)
+       name = DECL_NAME (name);
+      sprintf (inline_bufp, "enum %s ", IDENTIFIER_POINTER (name));
+      break;
+
+    case TYPE_DECL:
+      if (TREE_READONLY (t))
+       OB_PUTS ("const ");
+      if (TREE_VOLATILE (t))
+       OB_PUTS ("volatile ");
+      sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t)));
+      break;
+
+    case INTEGER_TYPE:
+      /* Normally, `unsigned' is part of the deal.  Not so if it comes
+        with `const' or `volatile'.  */
+      if (TREE_UNSIGNED (t)
+         && (TREE_READONLY (t) || TREE_VOLATILE (t)))
+       OB_PUTS ("unsigned ");
+      /* fall through.  */
+    case REAL_TYPE:
+    case VOID_TYPE:
+      if (TREE_READONLY (t))
+       OB_PUTS ("const ");
+      if (TREE_VOLATILE (t))
+       OB_PUTS ("volatile ");
+      sprintf (inline_bufp, "%s ", TYPE_NAME_STRING (t));
+      break;
+
+    default:
+      abort ();
+    }
+  inline_bufp = new_text_len (inline_bufp);
+}
+
+static void
+dump_type_suffix (t, p)
+     tree t;
+     int *p;
+{
+  int old_p = 0;
+
+  if (t == NULL_TREE)
+    return;
+
+  switch (TREE_CODE (t))
+    {
+    case ERROR_MARK:
+      sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++);
+      break;
+
+    case UNKNOWN_TYPE:
+      return;
+
+    case POINTER_TYPE:
+      dump_type_suffix (TREE_TYPE (t), p);
+      return;
+
+    case OFFSET_TYPE:
+      {
+       tree type = TREE_TYPE (t);
+
+       OB_PUTC (')');
+       if (TREE_CODE (type) == FUNCTION_TYPE)
+         {
+#if 0
+           tree next_arg = TREE_CHAIN (TYPE_ARG_TYPES (type));
+           OB_PUTC ('(');
+           if (next_arg)
+             {
+               if (next_arg != void_list_node)
+                 {
+                   in_parmlist++;
+                   dump_type (next_arg, &old_p);
+                   in_parmlist--;
+                 }
+             }
+           else OB_PUTS ("...");
+           OB_PUTC (')');
+           dump_type_suffix (TREE_TYPE (type), p);
+#else
+           abort ();
+#endif
+         }
+       return;
+      }
+
+    case METHOD_TYPE:
+      {
+       tree next_arg;
+       OB_PUTC (')');
+       next_arg = TREE_CHAIN (TYPE_ARG_TYPES (t));
+       OB_PUTC ('(');
+       if (next_arg)
+         {
+           if (next_arg != void_list_node)
+             {
+               in_parmlist++;
+               dump_type (next_arg, &old_p);
+               in_parmlist--;
+             }
+         }
+       else OB_PUTS ("...");
+       OB_PUTC (')');
+       dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (t))));
+       dump_type_suffix (TREE_TYPE (t), p);
+       return;
+      }
+
+    case REFERENCE_TYPE:
+      dump_type_suffix (TREE_TYPE (t), p);
+      return;
+
+    case ARRAY_TYPE:
+      dump_type_suffix (TREE_TYPE (t), p);
+      OB_PUTC2 ('[', ']');
+      return;
+
+    case FUNCTION_TYPE:
+      OB_PUTC2 (')', '(');
+      if (TYPE_ARG_TYPES (t) && TYPE_ARG_TYPES (t) != void_list_node)
+       {
+         in_parmlist++;
+         dump_type (TYPE_ARG_TYPES (t), &old_p);
+         in_parmlist--;
+       }
+      OB_PUTC (')');
+      dump_type_suffix (TREE_TYPE (t), p);
+      return;
+
+    case IDENTIFIER_NODE:
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case ENUMERAL_TYPE:
+    case TYPE_DECL:
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+    case VOID_TYPE:
+      return;
+
+    default:
+      abort ();
+    }
+  inline_bufp = new_text_len (inline_bufp);
+}
+
+static void
+dump_type (t, p)
+     tree t;
+     int *p;
+{
+  int old_p = 0;
+  int print_struct = 1;
+
+  if (t == NULL_TREE)
+    return;
+
+  switch (TREE_CODE (t))
+    {
+    case ERROR_MARK:
+      sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++);
+      break;
+
+    case UNKNOWN_TYPE:
+      OB_PUTS ("<unknown type>");
+      return;
+
+    case TREE_LIST:
+      dump_type (TREE_VALUE (t), &old_p);
+      if (TREE_CHAIN (t))
+       {
+         if (TREE_CHAIN (t) != void_list_node)
+           {
+             OB_PUTC (',');
+             dump_type (TREE_CHAIN (t), &old_p);
+           }
+       }
+      else OB_PUTS ("...");
+      return;
+
+    case POINTER_TYPE:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      *p += 1;
+      dump_type (TREE_TYPE (t), p);
+      while (*p)
+       {
+         OB_PUTC ('*');
+         *p -= 1;
+       }
+      return;
+
+    case REFERENCE_TYPE:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      dump_type (TREE_TYPE (t), p);
+      OB_PUTC ('&');
+      return;
+
+    case ARRAY_TYPE:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      dump_type (TREE_TYPE (t), p);
+      OB_PUTC2 ('[', ']');
+      return;
+
+    case OFFSET_TYPE:
+    case METHOD_TYPE:
+    case FUNCTION_TYPE:
+      dump_type_prefix (t, p);
+      dump_type_suffix (t, p);
+      return;
+
+    case IDENTIFIER_NODE:
+      sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t));
+      break;
+
+    case RECORD_TYPE:
+      {
+       if (TREE_READONLY (t) | TREE_VOLATILE (t))
+         dump_readonly_or_volatile (t);
+       if (TYPE_LANG_SPECIFIC (t) && CLASSTYPE_DECLARED_CLASS (t))
+         print_struct = 0;
+       t = TYPE_NAME (t);
+       if (TREE_CODE (t) == TYPE_DECL)
+         t = DECL_NAME (t);
+       if (print_struct)
+         sprintf (inline_bufp, "struct %s ", IDENTIFIER_POINTER (t));
+       else
+         sprintf (inline_bufp, "class %s ", IDENTIFIER_POINTER (t));
+       break;
+      }
+
+    case UNION_TYPE:
+      {
+       if (TREE_READONLY (t) | TREE_VOLATILE (t))
+         dump_readonly_or_volatile (t);
+       t = TYPE_NAME (t);
+       if (TREE_CODE (t) == TYPE_DECL)
+         t = DECL_NAME (t);
+       sprintf (inline_bufp, "union %s ", IDENTIFIER_POINTER (t));
+      }
+      break;
+
+    case ENUMERAL_TYPE:
+      {
+       if (TREE_READONLY (t) | TREE_VOLATILE (t))
+         dump_readonly_or_volatile (t);
+       t = TYPE_NAME (t);
+       if (TREE_CODE (t) == TYPE_DECL)
+         t = DECL_NAME (t);
+       sprintf (inline_bufp, "enum %s ", IDENTIFIER_POINTER (t));
+      }
+      break;
+
+    case TYPE_DECL:
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t)));
+      break;
+
+    case INTEGER_TYPE:
+      /* Normally, `unsigned' is part of the deal.  Not so if it comes
+        with `const' or `volatile'.  */
+      if (TREE_READONLY (t) | TREE_VOLATILE (t))
+       dump_readonly_or_volatile (t);
+      if (TREE_UNSIGNED (t)
+         && (TREE_READONLY (t) | TREE_VOLATILE (t)))
+       OB_PUTS ("unsigned ");
+      /* fall through.  */
+    case REAL_TYPE:
+    case VOID_TYPE:
+      sprintf (inline_bufp, "%s ", TYPE_NAME_STRING (t));
+      break;
+
+    default:
+      abort ();
+    }
+  inline_bufp = new_text_len (inline_bufp);
+}
+
+static void
+dump_decl (t)
+     tree t;
+{
+  int p = 0;
+
+  if (t == NULL_TREE)
+    return;
+
+  switch (TREE_CODE (t))
+    {
+    case ERROR_MARK:
+      strcpy (inline_bufp, " /* decl error */ ");
+      break;
+
+    case PARM_DECL:
+      dump_type_prefix (TREE_TYPE (t), &p);
+      if (DECL_NAME (t))
+       dump_decl (DECL_NAME (t));
+      else
+       {
+         sprintf (inline_bufp, ANON_PARMNAME_FORMAT, dummy_name++);
+         break;
+       }
+      dump_type_suffix (TREE_TYPE (t), &p);
+      return;
+
+    case CALL_EXPR:
+      dump_decl (TREE_OPERAND (t, 0));
+      OB_PUTC ('(');
+      in_parmlist++;
+      dump_decl (TREE_OPERAND (t, 1));
+      in_parmlist--;
+      t = tree_last (TYPE_ARG_TYPES (TREE_TYPE (t)));
+      if (!t || t != void_list_node)
+       OB_PUTS ("...");
+      OB_PUTC (')');
+      return;
+
+    case ARRAY_REF:
+      dump_decl (TREE_OPERAND (t, 0));
+      OB_PUTC ('[');
+      dump_decl (TREE_OPERAND (t, 1));
+      OB_PUTC (']');
+      return;
+
+    case TYPE_DECL:
+      sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (DECL_NAME (t)));
+      break;
+
+    case TYPE_EXPR:
+      abort ();
+      break;
+
+    case IDENTIFIER_NODE:
+      if (OPERATOR_NAME_P (t))
+       sprintf (inline_bufp, "operator %s ", operator_name_string (t));
+      else if (OPERATOR_TYPENAME_P (t))
+       {
+         OB_PUTS ("operator ");
+         dump_type (TREE_TYPE (t), &p);
+         return;
+       }
+      else
+       sprintf (inline_bufp, "%s ", IDENTIFIER_POINTER (t));
+      break;
+
+    case BIT_NOT_EXPR:
+      OB_PUTC2 ('~', ' ');
+      dump_decl (TREE_OPERAND (t, 0));
+      return;
+
+    case SCOPE_REF:
+      sprintf (inline_bufp, "%s :: ", IDENTIFIER_POINTER (TREE_OPERAND (t, 0)));
+      inline_bufp += sizeof ("%s :: ") + IDENTIFIER_LENGTH (TREE_OPERAND (t, 0));
+      dump_decl (TREE_OPERAND (t, 1));
+      return;
+
+    case INDIRECT_REF:
+      OB_PUTC ('*');
+      dump_decl (TREE_OPERAND (t, 0));
+      return;
+
+    case ADDR_EXPR:
+      OB_PUTC ('&');
+      dump_decl (TREE_OPERAND (t, 0));
+      return;
+
+    default:
+      abort ();
+    }
+  inline_bufp = new_text_len (inline_bufp);
+}
+
+static void
+dump_init_list (l)
+     tree l;
+{
+  while (l)
+    {
+      dump_init (TREE_VALUE (l));
+      if (TREE_CHAIN (l))
+       OB_PUTC (',');
+      l = TREE_CHAIN (l);
+    }
+}
+
+static void
+dump_init (t)
+     tree t;
+{
+  int dummy;
+
+  switch (TREE_CODE (t))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+      sprintf (inline_bufp, " %s ", IDENTIFIER_POINTER (DECL_NAME (t)));
+      break;
+
+    case FUNCTION_DECL:
+      {
+       tree name = DECL_NAME (t);
+
+       if (DESTRUCTOR_NAME_P (name))
+         sprintf (inline_bufp, " ~%s ",
+                  IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t)));
+       else if (OPERATOR_NAME_P (name))
+         sprintf (inline_bufp, "operator %s ", operator_name_string (name));
+       else if (OPERATOR_TYPENAME_P (name))
+         {
+           dummy = 0;
+           OB_PUTS ("operator ");
+           dump_type (TREE_TYPE (name), &dummy);
+         }
+#if 0
+       else if (WRAPPER_NAME_P (name))
+         sprintf (inline_bufp, " ()%s ",
+                  IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t)));
+       else if (WRAPPER_PRED_NAME_P (name))
+         sprintf (inline_bufp, " ()?%s ",
+                  IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t)));
+       else if (ANTI_WRAPPER_NAME_P (name))
+         sprintf (inline_bufp, " ~()%s ",
+                  IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t)));
+#endif
+       else sprintf (inline_bufp, " %s ",
+                     IDENTIFIER_POINTER (DECL_ORIGINAL_NAME (t)));
+      }
+      break;
+
+    case CONST_DECL:
+      dummy = 0;
+      OB_PUTC2 ('(', '(');
+      dump_type (TREE_TYPE (t), &dummy);
+      OB_PUTC (')');
+      dump_init (DECL_INITIAL (t));
+      OB_PUTC (')');
+      return;
+
+    case INTEGER_CST:
+      sprintf (inline_bufp, " %d ", TREE_INT_CST_LOW (t));
+      break;
+
+    case REAL_CST:
+      sprintf (inline_bufp, " %g ", TREE_REAL_CST (t));
+      break;
+
+    case STRING_CST:
+      {
+       char *p = TREE_STRING_POINTER (t);
+       int len = TREE_STRING_LENGTH (t) - 1;
+       int i;
+
+       check_text_len (inline_bufp + len + 2);
+       OB_PUTC ('\"');
+       for (i = 0; i < len; i++)
+         {
+           register char c = p[i];
+           if (c == '\"' || c == '\\')
+             OB_PUTC ('\\');
+           if (c >= ' ' && c < 0177)
+             OB_PUTC (c);
+           else
+             {
+               sprintf (inline_bufp, "\\%03o", c);
+               inline_bufp = new_text_len (inline_bufp);
+             }
+         }
+       OB_PUTC ('\"');
+      }
+      return;
+
+    case COMPOUND_EXPR:
+      dump_binary_op (",", t, 1);
+      break;
+
+    case COND_EXPR:
+      OB_PUTC ('(');
+      dump_init (TREE_OPERAND (t, 0));
+      OB_PUTS (" ? ");
+      dump_init (TREE_OPERAND (t, 1));
+      OB_PUTS (" : ");
+      dump_init (TREE_OPERAND (t, 2));
+      OB_PUTC (')');
+      return;
+
+    case SAVE_EXPR:
+      if (TREE_HAS_CONSTRUCTOR (t))
+       {
+         dummy = 0;
+         OB_PUTS ("new ");
+         dump_type (TREE_TYPE (TREE_TYPE (t)), &dummy);
+         PARM_DECL_EXPR (t) = 1;
+       }
+      else
+       {
+         sorry ("operand of SAVE_EXPR not understood");
+         *inline_errp = '\0';
+         inline_bufp = inline_errp + 1;
+       }
+      return;
+
+    case NEW_EXPR:
+      strcpy (inline_bufp, TYPE_NAME_STRING (TREE_TYPE (t)));
+      inline_bufp = new_text_len (inline_bufp);
+      OB_PUTC ('(');
+      dump_init_list (TREE_CHAIN (TREE_OPERAND (t, 1)));
+      OB_PUTC (')');
+      return;
+
+    case CALL_EXPR:
+      OB_PUTC ('(');
+      dump_init (TREE_OPERAND (t, 0));
+      dump_init_list (TREE_OPERAND (t, 1));
+      OB_PUTC (')');
+      return;
+
+    case MODIFY_EXPR:
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+    case TRUNC_DIV_EXPR:
+    case TRUNC_MOD_EXPR:
+    case MIN_EXPR:
+    case MAX_EXPR:
+    case LSHIFT_EXPR:
+    case RSHIFT_EXPR:
+    case BIT_IOR_EXPR:
+    case BIT_XOR_EXPR:
+    case BIT_AND_EXPR:
+    case BIT_ANDTC_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case EQ_EXPR:
+    case NE_EXPR:
+      dump_binary_op (opname_tab[(int) TREE_CODE (t)], t,
+                     strlen (opname_tab[(int) TREE_CODE (t)]));
+      return;
+
+    case CEIL_DIV_EXPR:
+    case FLOOR_DIV_EXPR:
+    case ROUND_DIV_EXPR:
+      dump_binary_op ("/", t, 1);
+      return;
+
+    case CEIL_MOD_EXPR:
+    case FLOOR_MOD_EXPR:
+    case ROUND_MOD_EXPR:
+      dump_binary_op ("%", t, 1);
+      return;
+
+    case COMPONENT_REF:
+      dump_binary_op (".", t, 1);
+      return;
+
+    case CONVERT_EXPR:
+      dump_unary_op ("+", t, 1);
+      return;
+
+    case ADDR_EXPR:
+      if (TREE_CODE (TREE_OPERAND (t, 0)) == FUNCTION_DECL
+         || TREE_CODE (TREE_OPERAND (t, 0)) == STRING_CST)
+       dump_init (TREE_OPERAND (t, 0));
+      else
+       dump_unary_op ("&", t, 1);
+      return;
+
+    case INDIRECT_REF:
+      dump_unary_op ("*", t, 1);
+      return;
+
+    case NEGATE_EXPR:
+    case BIT_NOT_EXPR:
+    case TRUTH_NOT_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+      dump_unary_op (opname_tab [(int)TREE_CODE (t)], t,
+                    strlen (opname_tab[(int) TREE_CODE (t)]));
+      return;
+
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      OB_PUTC ('(');
+      dump_init (TREE_OPERAND (t, 0));
+      OB_PUTCP (opname_tab[(int)TREE_CODE (t)]);
+      OB_PUTC (')');
+      return;
+
+    case NOP_EXPR:
+      dummy = 0;
+      OB_PUTC2 ('(', '(');
+      dump_type (TREE_TYPE (t), &dummy);
+      OB_PUTC (')');
+      dump_init (TREE_OPERAND (t, 0));
+      OB_PUTC (')');
+      return;
+
+    case CONSTRUCTOR:
+      OB_PUTC ('{');
+      dump_init_list (CONSTRUCTOR_ELTS (t));
+      OB_PUTC ('}');
+      return;
+
+      /*  This list is incomplete, but should suffice for now.
+         It is very important that `sorry' does not call
+         `report_error_function'.  That could cause an infinite loop.  */
+    default:
+      sorry ("that operation not supported for default parameters");
+
+      /* fall through to ERROR_MARK...  */
+    case ERROR_MARK:
+      *inline_errp = '\0';
+      inline_bufp = inline_errp + 1;
+      return;
+    }
+  inline_bufp = new_text_len (inline_bufp);
+}
+
+static void
+dump_binary_op (opstring, t, len)
+     char *opstring;
+     tree t;
+     int len;
+{
+  OB_PUTC ('(');
+  dump_init (TREE_OPERAND (t, 0));
+  sprintf (inline_bufp, " %s ", opstring);
+  inline_bufp += len + 2;
+  dump_init (TREE_OPERAND (t, 1));
+  OB_PUTC (')');
+  check_text_len (inline_bufp);
+}
+
+static void
+dump_unary_op (opstring, t, len)
+     char *opstring;
+     tree t;
+     int len;
+{
+  OB_PUTC ('(');
+  sprintf (inline_bufp, " %s ", opstring);
+  inline_bufp += len + 2;
+  dump_init (TREE_OPERAND (t, 0));
+  OB_PUTC (')');
+  check_text_len (inline_bufp);
+}
+
+#ifdef DO_METHODS_THE_OLD_WAY
+/* Process the currently pending inline function definitions.
+   This entails:
+   (1) Creating a temporary file which contains return type,
+       delarator name, and argment names and types of the
+       function to be inlined.
+   (2) Reading that file into a buffer which can then be
+       made to look line another piece of inline code to
+       process, stuffing that on the top of the inline
+       stack, then letting the lexer and parser read from those
+       two.
+*/
+
+static struct pending_inline *
+stash_inline_prefix (cname, field)
+     tree cname, field;
+{
+  extern int lineno;
+  struct pending_inline *t;
+  tree name, fndecl, fntype;
+  int p = 0;
+  inline_buffer = (char *)alloca (MAX_INLINE_BUF_SIZE + 4);
+  dummy_name = 0;
+
+  name = DECL_ORIGINAL_NAME (field);
+  /* We still don't do friends right.  */
+  fndecl = field;
+  fntype = TREE_TYPE (fndecl);
+
+  if (TREE_INLINE (fndecl))
+    strcpy (inline_buffer, "inline ");
+  else
+    strcpy (inline_buffer, "static ");
+  inline_bufp = inline_buffer + strlen (inline_buffer);
+  if (! OPERATOR_TYPENAME_P (name))
+    dump_type_prefix (TREE_TYPE (fntype), &p);
+  if (TREE_CODE (fntype) == METHOD_TYPE)
+    {
+      dump_type (cname, &p);
+      inline_bufp[-1] = ':';
+      *inline_bufp++ = ':';
+      if (DESTRUCTOR_NAME_P (DECL_NAME (fndecl)))
+       OB_PUTC ('~');
+#if 0
+      else if (WRAPPER_NAME_P (DECL_NAME (fndecl)))
+       OB_PUTC2 ('(', ')');
+      else if (WRAPPER_PRED_NAME_P (DECL_NAME (fndecl)))
+       OB_PUTS ("()?");
+      else if (ANTI_WRAPPER_NAME_P (DECL_NAME (fndecl)))
+       OB_PUTS ("~()");
+#endif
+    }
+  dump_decl (name);
+  OB_PUTC ('(');
+  if (! DESTRUCTOR_NAME_P (DECL_NAME (fndecl)))
+    {
+      tree parmlist = DECL_ARGUMENTS (fndecl);
+      tree typelist = TYPE_ARG_TYPES (fntype);
+
+      if (TREE_CODE (field) == FIELD_DECL)
+       {
+         parmlist = TREE_CHAIN (parmlist);
+         typelist = TREE_CHAIN (typelist);
+       }
+
+      in_parmlist++;
+      while (parmlist)
+       {
+         dump_decl (parmlist);
+#if 0
+         if (TREE_PURPOSE (typelist))
+           {
+             inline_errp = inline_bufp;
+             OB_PUTS (" = (");
+             dump_init (TREE_PURPOSE (typelist));
+             OB_PUTC (')');
+             if (*inline_errp == '\0')
+               inline_bufp = inline_errp;
+           }
+#endif
+         if (TREE_CHAIN (parmlist))
+           OB_PUTC (',');
+         parmlist = TREE_CHAIN (parmlist);
+         typelist = TREE_CHAIN (typelist);
+       }
+      in_parmlist--;
+      if (!typelist || typelist != void_list_node)
+       OB_PUTS ("...");
+    }
+  OB_PUTC (')');
+
+  if (! OPERATOR_TYPENAME_P (name))
+    dump_type_suffix (TREE_TYPE (fntype), &p);
+  if (TREE_CODE (fntype) == METHOD_TYPE)
+    dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))));
+  {
+    extern tree value_identifier;
+
+    if (DECL_RESULT (fndecl) != value_identifier)
+      {
+       tree result = DECL_RESULT (fndecl);
+
+       OB_PUTS ("return ");
+       OB_PUTS (IDENTIFIER_POINTER (DECL_NAME (result)));
+       if (DECL_INITIAL (result))
+         {
+           OB_PUTC ('=');
+           dump_init (DECL_INITIAL (result));
+           OB_PUTC (';');
+         }
+      }
+  }
+  OB_FINISH ();
+  check_text_len (inline_bufp);
+
+  t = (struct pending_inline *)xmalloc (sizeof (struct pending_inline));
+  t->len = inline_bufp - inline_buffer;
+  t->buf = (char *)xmalloc (t->len);
+  bcopy (inline_buffer, t->buf, t->len);
+  t->lineno = lineno;
+  t->filename = input_filename;
+  t->token = 0;
+  return t;
+}
+#endif
+
+#define OVERLOAD_MAX_LEN 1024
+
+/* Pretty printing for announce_function.  If BUF is nonzero, then
+   the text is written there.  The buffer is assued to be of size
+   OVERLOAD_MAX_LEN.  CNAME is the name of the class that FNDECL
+   belongs to, if we could not figure that out from FNDECL
+   itself.  FNDECL is the declaration of the function we
+   are interested in seeing.  PRINT_RET_TYPE_P is non-zero if
+   we should print the type that this function returns.  */
+char *
+fndecl_as_string (buf, cname, fndecl, print_ret_type_p)
+     char *buf;
+     tree cname, fndecl;
+     int print_ret_type_p;
+{
+  tree name = DECL_NAME (fndecl);
+  tree fntype = TREE_TYPE (fndecl);
+  tree parmtypes = TYPE_ARG_TYPES (fntype);
+  int p = 0;
+  int spaces = 0;
+
+  inline_buffer = buf;
+  OB_INIT ();
+
+  if (DECL_STATIC_FUNCTION_P (fndecl))
+    cname = TYPE_NAME (DECL_STATIC_CONTEXT (fndecl));
+  else if (! cname && TREE_CODE (fntype) == METHOD_TYPE)
+    cname = TYPE_NAME (TYPE_METHOD_BASETYPE (fntype));
+
+  if (print_ret_type_p && ! OPERATOR_TYPENAME_P (name))
+    dump_type_prefix (TREE_TYPE (fntype), &p);
+  if (DECL_STATIC_FUNCTION_P (fndecl))
+      OB_PUTS ("static ");
+    
+  if (cname)
+    {
+      dump_type (cname, &p);
+      inline_bufp[-1] = ':';
+      *inline_bufp++ = ':';
+      if (TREE_CODE (fntype) == METHOD_TYPE && parmtypes)
+       parmtypes = TREE_CHAIN (parmtypes);
+      if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl))
+       parmtypes = TREE_CHAIN (parmtypes);
+    }
+
+  if (DESTRUCTOR_NAME_P (name))
+    {
+      OB_PUTC ('~');
+      parmtypes = TREE_CHAIN (parmtypes);
+      dump_decl (DECL_ORIGINAL_NAME (fndecl));
+    }
+  else if (OPERATOR_NAME_P (name))
+    {
+      sprintf (inline_bufp, "operator %s ", operator_name_string (name));
+      inline_bufp += strlen (inline_bufp);
+    }
+  else if (OPERATOR_TYPENAME_P (name))
+    {
+      /* This cannot use the hack that the operator's return
+        type is stashed off of its name because it may be
+        used for error reporting.  In the case of conflicting
+        declarations, both will have the same name, yet
+        the types will be different, hence the TREE_TYPE field
+        of the first name will be clobbered by the second.  */
+      OB_PUTS ("operator ");
+      dump_type (TREE_TYPE (TREE_TYPE (fndecl)), &p);
+    }
+  else if (DECL_CONSTRUCTOR_P (fndecl))
+    {
+#ifdef SOS
+      if (TYPE_DYNAMIC (TREE_TYPE (TREE_TYPE (DECL_ORIGINAL_NAME (fndecl)))))
+       {
+         OB_PUTS ("dynamic ");
+         parmtypes = TREE_CHAIN (parmtypes);
+       }
+#endif
+      dump_decl (DECL_ORIGINAL_NAME (fndecl));
+      /* Skip past "in_charge" identifier.  */
+      if (TYPE_USES_VIRTUAL_BASECLASSES (TREE_TYPE (cname)))
+       parmtypes = TREE_CHAIN (parmtypes);
+    }
+  else
+    {
+#if 0
+      if (WRAPPER_NAME_P (name))
+       OB_PUTC2 ('(', ')');
+      if (WRAPPER_PRED_NAME_P (name))
+       OB_PUTS ("()?");
+      else if (ANTI_WRAPPER_NAME_P (name))
+       OB_PUTS ("~()");
+#endif
+      dump_decl (DECL_ORIGINAL_NAME (fndecl));
+    }
+
+  OB_PUTC ('(');
+  if (parmtypes)
+    {
+      in_parmlist++;
+      if (parmtypes != void_list_node)
+       spaces = 2;
+      while (parmtypes && parmtypes != void_list_node)
+       {
+         dump_type (TREE_VALUE (parmtypes), &p);
+         while (inline_bufp[-1] == ' ')
+           inline_bufp--;
+         if (TREE_PURPOSE (parmtypes))
+           {
+             inline_errp = inline_bufp;
+             OB_PUTS (" (= ");
+             dump_init (TREE_PURPOSE (parmtypes));
+             OB_PUTC (')');
+           }
+         OB_PUTC2 (',', ' ');
+         parmtypes = TREE_CHAIN (parmtypes);
+       }
+      in_parmlist--;
+    }
+  
+  if (parmtypes)
+    inline_bufp -= spaces;
+  else
+    OB_PUTS ("...");
+
+  OB_PUTC (')');
+
+  if (print_ret_type_p && ! OPERATOR_TYPENAME_P (name))
+    dump_type_suffix (TREE_TYPE (fntype), &p);
+
+  if (TREE_CODE (fntype) == METHOD_TYPE)
+    dump_readonly_or_volatile (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (fntype))));
+
+  OB_FINISH ();
+  check_text_len (inline_bufp);
+  
+  if (strlen (buf) >= OVERLOAD_MAX_LEN)
+    {
+      fprintf (stderr, "fndecl_as_string returns something too large");
+      abort ();
+    }
+  return buf;
+}
+
+#ifdef FIELD_XREF
+
+char *
+type_as_string (buf, typ)
+     char *buf;
+     tree typ;
+{
+  int p = 0;
+  int spaces = 0;
+
+  inline_buffer = buf;
+  OB_INIT ();
+
+  dump_type(typ,&p);
+
+  OB_FINISH ();
+
+  return buf;
+}
+
+#endif
+
+/* Move inline function defintions out of structure so that they
+   can be processed normally.  CNAME is the name of the class
+   we are working from, METHOD_LIST is the list of method lists
+   of the structure.  We delete friend methods here, after
+   saving away their inline function definitions (if any).  */
+
+/* Subroutine of `do_inline_function_hair'.  */
+static void
+prepare_inline (cname, fndecl)
+     tree cname, fndecl;
+{
+  if (DECL_PENDING_INLINE_INFO (fndecl))
+    {
+      struct pending_inline *t1, *t2;
+      tree args;
+
+      t2 = DECL_PENDING_INLINE_INFO (fndecl);
+      t2->next = pending_inlines;
+      t2->fndecl = fndecl;
+      args = DECL_ARGUMENTS (fndecl);
+      while (args)
+       {
+         DECL_CONTEXT (args) = fndecl;
+         args = TREE_CHAIN (args);
+       }
+#ifdef DO_METHODS_THE_OLD_WAY
+      t1 = stash_inline_prefix (cname, methods);
+      t1->next = t2;
+#else
+      t1 = t2;
+#endif
+      pending_inlines = t1;
+
+      /* Allow this decl to be seen in global scope */
+      IDENTIFIER_GLOBAL_VALUE (DECL_NAME (fndecl)) = fndecl;
+    }
+}
+
+void
+do_inline_function_hair (type, friend_list)
+     tree type, friend_list;
+{
+  tree cname = DECL_NAME (TYPE_NAME (type));
+  tree method_vec = CLASSTYPE_METHOD_VEC (type);
+  if (method_vec != 0)
+    {
+      tree *methods = &TREE_VEC_ELT (method_vec, 0);
+      tree *end = TREE_VEC_END (method_vec);
+      while (methods != end)
+       {
+         /* Do inline member functions.  */
+         tree method = *methods;
+         while (method)
+           {
+             prepare_inline (cname, method);
+             method = TREE_CHAIN (method);
+           }
+         methods++;
+       }
+    }
+  while (friend_list)
+    {
+      prepare_inline (NULL_TREE, TREE_VALUE (friend_list));
+      friend_list = TREE_CHAIN (friend_list);
+    }
+}
+\f
+/* Report a 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, err_name)
+     struct candidate *cp;
+     tree parmtypes;
+     char *name_kind, *err_name;
+{
+  char buf[OVERLOAD_MAX_LEN];
+  int i = cp->u.bad_arg;
+  tree ttf, tta;
+
+  if (i == -3)
+    {
+      if (TREE_READONLY (TREE_TYPE (TREE_VALUE (parmtypes))))
+       error ("call to const %s `%s' with non-const object", name_kind, err_name);
+      else
+       error ("call to non-const %s `%s' with const object", name_kind, err_name);
+      return;
+    }
+  if (i == -2)
+    {
+      error ("too few arguments for %s `%s'", name_kind, err_name);
+      return;
+    }
+  else if (i == -1)
+    {
+      error ("too many arguments for %s `%s'", name_kind, err_name);
+      return;
+    }
+  if (i == 0)
+    {
+      if (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE)
+       {
+         /* Happens when we have an ambiguous base class.  */
+         assert (get_base_type (DECL_CONTEXT (cp->function), TREE_TYPE (TREE_TYPE (TREE_VALUE (parmtypes))), 1) == error_mark_node);
+         return;
+       }
+    }
+  ttf = TYPE_ARG_TYPES (TREE_TYPE (cp->function));
+  tta = parmtypes;
+
+  while (i-- > 0)
+    {
+      ttf = TREE_CHAIN (ttf);
+      tta = TREE_CHAIN (tta);
+    }
+  fndecl_as_string (buf, 0, cp->function, 0);
+  inline_bufp = inline_buffer + strlen (inline_buffer) + 1;
+  inline_buffer = inline_bufp;
+
+  /* Reset `i' so that type printing routines do the right thing.  */
+  if (tta)
+    {
+      enum tree_code code = TREE_CODE (TREE_TYPE (TREE_VALUE (tta)));
+      if (code == ERROR_MARK)
+       OB_PUTS ("(failed type instatiation)");
+      else
+       {
+         i = (code == FUNCTION_TYPE || code == METHOD_TYPE);
+         dump_type (TREE_TYPE (TREE_VALUE (tta)), &i);
+       }
+    }
+  else OB_PUTS ("void");
+
+  OB_FINISH ();
+  sprintf (inline_bufp, "bad argument %d for function `%s' (type was %s)",
+          cp->u.bad_arg - (TREE_CODE (TREE_TYPE (cp->function)) == METHOD_TYPE), buf, inline_buffer);
+  strcpy (buf, inline_bufp);
+  error (buf);
+}
+\f
+/* Here is where overload code starts.  */
+
+#define OVERLOAD_MAX_LEN 1024
+
+/* Array of types seen so far in top-level call to `build_overload_name'.
+   Allocated and deallocated by caller.  */
+static tree *typevec;
+
+/* Number of types interned by `build_overload_name' so far.  */
+static int maxtype;
+
+/* Number of occurances of last type seen.  */
+static int nrepeats;
+
+/* Nonzero if we should not try folding parameter types.  */
+static int nofold;
+
+#define ALLOCATE_TYPEVEC(PARMTYPES) \
+  do { maxtype = 0, nrepeats = 0; \
+       typevec = (tree *)alloca (list_length (PARMTYPES) * sizeof (tree)); } while (0)
+
+#define DEALLOCATE_TYPEVEC(PARMTYPES) \
+  do { tree t = (PARMTYPES); \
+       while (t) { TREE_USED (TREE_VALUE (t)) = 0; t = TREE_CHAIN (t); } \
+  } while (0)
+
+/* Code to concatenate an asciified integer to a string,
+   and return the end of the string.  */
+static
+#ifdef __GNUC__
+__inline
+#endif
+char *
+icat (s, i)
+     char *s;
+     int i;
+{
+  if (i < 10)
+    {
+      *s++ = '0' + i;
+      return s;
+    }
+  s = icat (s, i / 10);
+  *s++ = '0' + (i % 10);
+  return s;
+}
+
+static
+#ifdef __GNUC__
+__inline
+#endif
+char *
+flush_repeats (s, type)
+     char *s;
+     tree type;
+{
+  int tindex = 0;
+  char *rval;
+
+  while (typevec[tindex] != type)
+    tindex++;
+
+  if (nrepeats > 1)
+    {
+      *s++ = 'N';
+      s = icat (s, nrepeats);
+      if (nrepeats > 9)
+       *s++ = '_';
+    }
+  else
+    *s++ = 'T';
+  nrepeats = 0;
+  rval = icat (s, tindex);
+  if (tindex > 9)
+    *rval++ = '_';
+  return rval;
+}
+
+/* Given a list of parameters in PARMS, and a buffer in TEXT, of
+   length LEN bytes, create an unambiguous overload string. Should
+   distinguish any type that C (or C++) can distinguish. I.e.,
+   pointers to functions are treated correctly.
+
+   Caller must deal with whether a final `e' goes on the end or not.
+
+   Any default conversions must take place before this function
+   is called.  */
+
+static char *
+build_overload_name (parmtypes, text, text_end)
+     tree parmtypes;
+     char *text, *text_end;
+{
+  char *textp = text;
+  int just_one;
+  tree parmtype;
+
+  if (just_one = (TREE_CODE (parmtypes) != TREE_LIST))
+    {
+      parmtype = parmtypes;
+      goto only_one;
+    }
+
+  while (parmtypes)
+    {
+      if (text_end - text < 4)
+       fatal ("Out of string space in build_overload_name!");
+      parmtype = TREE_VALUE (parmtypes);
+
+    only_one:
+
+      if (! nofold)
+       {
+         if (! just_one)
+           /* Every argument gets counted.  */
+           typevec[maxtype++] = parmtype;
+
+         if (TREE_USED (parmtype))
+           {
+             if (! just_one && parmtype == typevec[maxtype-2])
+               nrepeats++;
+             else
+               {
+                 if (nrepeats)
+                   textp = flush_repeats (textp, parmtype);
+                 if (! just_one && TREE_CHAIN (parmtypes)
+                     && parmtype == TREE_VALUE (TREE_CHAIN (parmtypes)))
+                   nrepeats++;
+                 else
+                   {
+                     int tindex = 0;
+
+                     while (typevec[tindex] != parmtype)
+                       tindex++;
+                     *textp++ = 'T';
+                     textp = icat (textp, tindex);
+                     if (tindex > 9)
+                       *textp++ = '_';
+                   }
+               }
+             goto next;
+           }
+         if (nrepeats)
+           textp = flush_repeats (textp, 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)))
+           TREE_USED (parmtype) = 1;
+       }
+
+      if (TREE_READONLY (parmtype))
+       *textp++ = 'C';
+      if (TREE_CODE (parmtype) == INTEGER_TYPE && TREE_UNSIGNED (parmtype))
+       *textp++ = 'U';
+      if (TREE_VOLATILE (parmtype))
+       *textp++ = 'V';
+
+      switch (TREE_CODE (parmtype))
+       {
+       case OFFSET_TYPE:
+         *textp++ = 'O';
+         textp = build_overload_name (TYPE_OFFSET_BASETYPE (parmtype), textp, text_end);
+         *textp++ = '_';
+         textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end);
+         break;
+
+       case REFERENCE_TYPE:
+         *textp++ = 'R';
+         goto more;
+
+       case ARRAY_TYPE:
+#ifdef PARM_CAN_BE_ARRAY_TYPE
+         {
+           tree length;
+
+           *textp++ = 'A';
+           length = array_type_nelts (parmtype);
+           if (TREE_CODE (length) == INTEGER_CST)
+             textp = icat (textp, TREE_INT_CST_LOW (length));
+           *textp++ = '_';
+           goto more;
+         }
+#else
+         *textp++ = 'P';
+         goto more;
+#endif
+
+       case POINTER_TYPE:
+         *textp++ = 'P';
+       more:
+         textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end);
+         break;
+
+       case FUNCTION_TYPE:
+       case METHOD_TYPE:
+         {
+           tree firstarg = TYPE_ARG_TYPES (parmtype);
+           /* Otherwise have to implement reentrant typevecs,
+              unmark and remark types, etc.  */
+           int old_nofold = nofold;
+           nofold = 1;
+
+           if (nrepeats)
+             textp = flush_repeats (textp, typevec[maxtype-1]);
+
+           /* @@ It may be possible to pass a function type in
+              which is not preceded by a 'P'.  */
+           if (TREE_CODE (parmtype) == FUNCTION_TYPE)
+             {
+               *textp++ = 'F';
+               if (firstarg == NULL_TREE)
+                 *textp++ = 'e';
+               else if (firstarg == void_list_node)
+                 *textp++ = 'v';
+               else
+                 textp = build_overload_name (firstarg, textp, text_end);
+             }
+           else
+             {
+               int constp = TREE_READONLY (TREE_TYPE (TREE_VALUE (firstarg)));
+               int volatilep = TREE_VOLATILE (TREE_TYPE (TREE_VALUE (firstarg)));
+               *textp++ = 'M';
+               firstarg = TREE_CHAIN (firstarg);
+
+               textp = build_overload_name (TYPE_METHOD_BASETYPE (parmtype), textp, text_end);
+               if (constp)
+                 *textp++ = 'C';
+               if (volatilep)
+                 *textp++ = 'V';
+
+               /* For cfront 2.0 compatability.  */
+               *textp++ = 'F';
+
+               if (firstarg == NULL_TREE)
+                 *textp++ = 'e';
+               else if (firstarg == void_list_node)
+                 *textp++ = 'v';
+               else
+                 textp = build_overload_name (firstarg, textp, text_end);
+             }
+
+           /* Separate args from return type.  */
+           *textp++ = '_';
+           textp = build_overload_name (TREE_TYPE (parmtype), textp, text_end);
+           nofold = old_nofold;
+           break;
+         }
+
+       case INTEGER_TYPE:
+         parmtype = TYPE_MAIN_VARIANT (parmtype);
+         switch (TYPE_MODE (parmtype))
+           {
+           case TImode:
+             if (parmtype == long_integer_type_node
+                 || parmtype == long_unsigned_type_node)
+               *textp++ = 'l';
+             else
+               *textp++ = 'q';
+             break;
+           case DImode:
+             if (parmtype == long_integer_type_node
+                 || parmtype == long_unsigned_type_node)
+               *textp++ = 'l';
+             else if (parmtype == integer_type_node
+                      || parmtype == unsigned_type_node)
+               *textp++ = 'i';
+             else if (parmtype == short_integer_type_node
+                      || parmtype == short_unsigned_type_node)
+               *textp++ = 's';
+             else
+               *textp++ = 'x';
+             break;
+           case SImode:
+             if (parmtype == long_integer_type_node
+                 || parmtype == long_unsigned_type_node)
+               *textp++ = 'l';
+             else if (parmtype == short_integer_type_node
+                      || parmtype == short_unsigned_type_node)
+               *textp++ = 's';
+             else
+               *textp++ = 'i';
+             break;
+           case HImode:
+             if (parmtype == integer_type_node
+                 || parmtype == unsigned_type_node)
+               *textp++ = 'i';
+             else
+               *textp++ = 's';
+             break;
+           case QImode:
+             *textp++ = 'c';
+             break;
+           default:
+             abort ();
+           }
+         break;
+
+       case REAL_TYPE:
+         parmtype = TYPE_MAIN_VARIANT (parmtype);
+         if (parmtype == long_double_type_node)
+           *textp++ = 'r';
+         else if (parmtype == double_type_node)
+           *textp++ = 'd';
+         else if (parmtype == float_type_node)
+           *textp++ = 'f';
+         else abort ();
+         break;
+
+       case VOID_TYPE:
+         if (! just_one)
+           {
+#if 0
+             extern tree void_list_node;
+
+             /* See if anybody is wasting memory.  */
+             assert (parmtypes == void_list_node);
+#endif
+             /* This is the end of a parameter list.  */
+             *textp = '\0';
+             return textp;
+           }
+         *textp++ = 'v';
+         break;
+
+       case ERROR_MARK:        /* not right, but nothing is anyway */
+         break;
+
+         /* have to do these */
+       case UNION_TYPE:
+       case RECORD_TYPE:
+         if (! just_one)
+           /* Make this type signature look incompatible
+              with AT&T.  */
+           *textp++ = 'G';
+         goto common;
+       case ENUMERAL_TYPE:
+       common:
+         {
+           tree name = TYPE_NAME (parmtype);
+           if (TREE_CODE (name) == TYPE_DECL)
+             name = DECL_NAME (name);
+           assert (TREE_CODE (name) == IDENTIFIER_NODE);
+           textp = icat (textp, IDENTIFIER_LENGTH (name));
+           strcpy (textp, IDENTIFIER_POINTER (name));
+           textp += IDENTIFIER_LENGTH (name);
+           break;
+         }
+
+       case UNKNOWN_TYPE:
+         /* This will take some work.  */
+         *textp++ = '?';
+         break;
+
+       default:
+         abort ();
+       }
+
+    next:
+      if (just_one) break;
+      parmtypes = TREE_CHAIN (parmtypes);
+    }
+  if (! just_one)
+    {
+      if (nrepeats)
+       textp = flush_repeats (textp, typevec[maxtype-1]);
+
+      /* To get here, parms must end with `...'. */
+      *textp++ = 'e';
+    }
+
+  *textp = '\0';
+  return textp;
+}
+\f
+/* Change the name of a function definition so that it may be
+   overloaded. NAME is the name of the function to overload,
+   PARMS is the parameter list (which determines what name the
+   final function obtains).
+
+   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 (name, parms, for_method)
+     char *name;
+     tree parms;
+     int for_method;
+{
+  int tmp;
+  char tname[OVERLOAD_MAX_LEN];
+
+  if (for_method == 2)
+    /* We can divine that this is a constructor,
+       and figure out its name without any extra encoding.  */
+    tmp = 0;
+  else
+    {
+      strcpy (tname, name);
+      tmp = strlen (tname);
+    }
+  tname[tmp++] = '_';
+  tname[tmp++] = '_';
+  if (for_method)
+    {
+#if 0
+      /* We can get away without doing this.  */
+      tname[tmp++] = 'M';
+#endif
+      parms = temp_tree_cons (NULL_TREE, TREE_TYPE (TREE_VALUE (parms)), TREE_CHAIN (parms));
+    }
+  else
+    tname[tmp++] = 'F';
+
+  if (parms == NULL_TREE)
+    tname[tmp++] = 'e', tname[tmp] = '\0';
+  else if (parms == void_list_node)
+    tname[tmp++] = 'v', tname[tmp] = '\0';
+  else
+    {
+      ALLOCATE_TYPEVEC (parms);
+      nofold = 0;
+      if (for_method)
+       {
+         tmp = build_overload_name (TREE_VALUE (parms), tname+tmp, &tname[OVERLOAD_MAX_LEN]) - tname;
+
+#ifndef LONGERNAMES
+         typevec[maxtype++] = TREE_VALUE (parms);
+         TREE_USED (TREE_VALUE (parms)) = 1;
+#endif
+
+         if (TREE_CHAIN (parms))
+           build_overload_name (TREE_CHAIN (parms), tname+tmp, &tname[OVERLOAD_MAX_LEN]);
+         else
+           {
+             tname[tmp++] = 'e';
+             tname[tmp] = '\0';
+           }
+       }
+      else
+       build_overload_name (parms, tname+tmp, &tname[OVERLOAD_MAX_LEN]);
+      DEALLOCATE_TYPEVEC (parms);
+    }
+  return get_identifier (tname);
+}
+
+/* Build an overload name for the type expression TYPE.  */
+tree
+build_typename_overload (type)
+     tree type;
+{
+  char tname[OVERLOAD_MAX_LEN];
+  int i = sizeof (OPERATOR_TYPENAME_FORMAT) - 1;
+  sprintf (tname, OPERATOR_TYPENAME_FORMAT);
+#if 0
+  /* We can get away without doing this--it really gets
+     overloaded later.  */
+  tname[i++] = '_';
+  tname[i++] = '_';
+  tname[i++] = 'M';
+#endif
+  nofold = 1;
+  build_overload_name (type, tname + i, &tname[OVERLOAD_MAX_LEN]);
+  return get_identifier (tname);
+}
+
+/* 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 redundanly 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
+    abort ();
+#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;
+{
+  /* @@ */
+  return (TREE_OVERLOADED (name)
+         && (! IDENTIFIER_CLASS_VALUE (name) || current_class_type == 0)
+         && ! IDENTIFIER_LOCAL_VALUE (name));
+}
+#endif
+\f
+/* Given a tree_code CODE, and some arguments (at least one),
+   attempt to use an overloaded operator on the arguments.
+
+   For unary operators, only the first argument need be checked.
+   For binary operators, both arguments may need to be checked.
+
+   Member functions can convert class references to class pointers,
+   for one-level deep indirection.  More than that is not supported.
+   Operators [](), ()(), and ->() must be member functions.
+
+   We call function call building calls with nonzero complain if
+   they are our only hope.  This is true when we see a vanilla operator
+   applied to something of aggregate type.  If this fails, we are free to
+   return `error_mark_node', because we will have reported the error.
+
+   Operators NEW and DELETE overload in funny ways: operator new takes
+   a single `size' parameter, and operator delete takes a pointer to the
+   storage being deleted.  When overloading these operators, success is
+   assumed.  If there is a failure, report an error message and return
+   `error_mark_node'.  */
+
+/* NOSTRICT */
+tree
+build_opfncall (code, flags, xarg1, xarg2, arg3)
+     enum tree_code code;
+     tree xarg1, xarg2;
+     tree arg3;
+{
+  tree rval = 0;
+  tree arg1, arg2;
+  tree type1, type2, fnname;
+  tree fields1 = 0, parms = 0;
+  tree global_fn;
+  int try_second;
+  int binary_is_unary;
+
+  if (xarg1 == error_mark_node)
+    return error_mark_node;
+
+  if (code == COND_EXPR)
+    {
+      if (TREE_CODE (xarg2) == ERROR_MARK
+         || TREE_CODE (arg3) == ERROR_MARK)
+       return error_mark_node;
+    }
+  if (code == COMPONENT_REF)
+    if (TREE_CODE (TREE_TYPE (xarg1)) == POINTER_TYPE)
+      return rval;
+
+  /* First, see if we can work with the first argument */
+  type1 = TREE_TYPE (xarg1);
+
+  /* Some tree codes have length > 1, but we really only want to
+     overload them if their first argument has a user defined type.  */
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+      code = POSTINCREMENT_EXPR;
+      binary_is_unary = 1;
+      try_second = 0;
+      break;
+
+    case POSTDECREMENT_EXPR:
+      code = PREDECREMENT_EXPR;
+      binary_is_unary = 1;
+      try_second = 0;
+      break;
+
+    case PREDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+    case COMPONENT_REF:
+      binary_is_unary = 1;
+      try_second = 0;
+      break;
+
+      /* ARRAY_REFs and CALL_EXPRs must overload successfully.
+        If they do not, return error_mark_node instead of NULL_TREE.  */
+    case ARRAY_REF:
+      if (xarg2 == error_mark_node)
+       return error_mark_node;
+    case CALL_EXPR:
+      rval = error_mark_node;
+      binary_is_unary = 0;
+      try_second = 0;
+      break;
+
+    case NEW_EXPR:
+      {
+       /* For operators `new' (`delete'), only check visibility
+          if we are in a constructor (destructor), and we are
+          allocating for that constructor's (destructor's) type.  */
+
+       fnname = get_identifier (OPERATOR_NEW_FORMAT);
+       if (flags & LOOKUP_GLOBAL)
+         return build_overload_call (fnname, tree_cons (NULL_TREE, xarg2, arg3),
+                                     flags & LOOKUP_COMPLAIN, 0);
+
+       if (current_function_decl == NULL_TREE
+           || !DECL_CONSTRUCTOR_P (current_function_decl)
+           || current_class_type != TYPE_MAIN_VARIANT (type1))
+         flags = LOOKUP_COMPLAIN;
+       rval = build_method_call (build1 (NOP_EXPR, xarg1, error_mark_node),
+                                 fnname, tree_cons (NULL_TREE, xarg2, arg3),
+                                 NULL_TREE, flags);
+       if (rval == error_mark_node)
+         /* User might declare fancy operator new, but invoke it
+            like standard one.  */
+         return rval;
+
+       TREE_TYPE (rval) = xarg1;
+       TREE_CALLS_NEW (rval) = 1;
+       return rval;
+      }
+      break;
+
+    case DELETE_EXPR:
+      {
+       /* See comment above.  */
+
+       fnname = get_identifier (OPERATOR_DELETE_FORMAT);
+       if (flags & LOOKUP_GLOBAL)
+         return build_overload_call (fnname, build_tree_list (NULL_TREE, xarg1),
+                                     flags & LOOKUP_COMPLAIN, 0);
+
+       if (current_function_decl == NULL_TREE
+           || !DESTRUCTOR_NAME_P (DECL_NAME (current_function_decl))
+           || current_class_type != TYPE_MAIN_VARIANT (type1))
+         flags = LOOKUP_COMPLAIN;
+       rval = build_method_call (build1 (NOP_EXPR, TREE_TYPE (xarg1), error_mark_node),
+                                 fnname, build_tree_list (NULL_TREE, xarg1),
+                                 NULL_TREE, flags);
+       /* This happens when the user mis-declares `operator delete'.
+          Should now be impossible.  */
+       assert (rval != error_mark_node);
+       TREE_TYPE (rval) = void_type_node;
+       return rval;
+      }
+      break;
+
+    default:
+      binary_is_unary = 0;
+      try_second = tree_code_length [(int) code] == 2;
+      if (xarg2 == error_mark_node)
+       return error_mark_node;
+      break;
+    }
+
+  if (try_second && xarg2 == error_mark_node)
+    return error_mark_node;
+
+  /* What ever it was, we do not know how to deal with it.  */
+  if (type1 == NULL_TREE)
+    return rval;
+
+  if (TREE_CODE (type1) == OFFSET_TYPE)
+    type1 = TREE_TYPE (type1);
+
+  if (TREE_CODE (type1) == REFERENCE_TYPE)
+    {
+      arg1 = convert_from_reference (xarg1);
+      type1 = TREE_TYPE (arg1);
+    }
+  else
+    {
+      arg1 = xarg1;
+    }
+
+  if (!IS_AGGR_TYPE (type1))
+    {
+      /* Try to fail. First, fail if unary */
+      if (! try_second)
+       return rval;
+      /* Second, see if second argument is non-aggregate. */
+      type2 = TREE_TYPE (xarg2);
+      if (TREE_CODE (type2) == OFFSET_TYPE)
+       type2 = TREE_TYPE (type2);
+      if (TREE_CODE (type2) == REFERENCE_TYPE)
+       {
+         arg2 = convert_from_reference (xarg2);
+         type2 = TREE_TYPE (arg2);
+       }
+      else
+       {
+         arg2 = xarg2;
+       }
+
+      if (!IS_AGGR_TYPE (type2))
+       return rval;
+      try_second = 0;
+    }
+
+  if (try_second)
+    {
+      /* First arg may succeed; see whether second should.  */
+      type2 = TREE_TYPE (xarg2);
+      if (TREE_CODE (type2) == OFFSET_TYPE)
+       type2 = TREE_TYPE (type2);
+      if (TREE_CODE (type2) == REFERENCE_TYPE)
+       {
+         arg2 = convert_from_reference (xarg2);
+         type2 = TREE_TYPE (arg2);
+       }
+      else
+       {
+         arg2 = xarg2;
+       }
+
+      if (! IS_AGGR_TYPE (type2))
+       try_second = 0;
+    }
+
+  if (type1 == unknown_type_node
+      || (try_second && TREE_TYPE (xarg2) == unknown_type_node))
+    {
+      /* This will not be implemented in the forseeable future.  */
+      return rval;
+    }
+
+  if (code == MODIFY_EXPR)
+    {
+      tree op_id = build_opid (MODIFY_EXPR, arg3);
+      fnname = build_operator_fnname (&op_id, 0, 2);
+    }
+  else
+    {
+      tree op_id = build_opid (0, code);
+      if (binary_is_unary)
+       fnname = build_operator_fnname (&op_id, 0, 1);
+      else
+       fnname = build_operator_fnname (&op_id, 0,
+                                       tree_code_length [(int) code]);
+    }
+
+  global_fn = IDENTIFIER_GLOBAL_VALUE (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,
+     but would rather a normal operator be called on a type-converted
+     argument.  */
+
+  if (IS_AGGR_TYPE (type1))
+    fields1 = lookup_fnfields (CLASSTYPE_AS_LIST (type1), fnname, 0);
+
+  if (fields1 == NULL_TREE && global_fn == NULL_TREE)
+    return rval;
+
+  /* If RVAL winds up being `error_mark_node', we will return
+     that... There is no way that normal semantics of these
+     operators will succeed.  */
+
+  /* This argument may be an uncommited OFFSET_REF.  This is
+     the case for example when dealing with static class members
+     which are referenced from their class name rather than
+     from a class instance.  */
+  if (TREE_CODE (xarg1) == OFFSET_REF
+      && TREE_CODE (TREE_OPERAND (xarg1, 1)) == VAR_DECL)
+    xarg1 = TREE_OPERAND (xarg1, 1);
+  if (try_second && xarg2 && TREE_CODE (xarg2) == OFFSET_REF
+      && TREE_CODE (TREE_OPERAND (xarg2, 1)) == VAR_DECL)
+    xarg2 = TREE_OPERAND (xarg2, 1);
+
+  if (global_fn)
+    flags |= LOOKUP_GLOBAL;
+
+  if (code == CALL_EXPR)
+    {
+      /* This can only be a member function.  */
+      return build_method_call (xarg1, fnname, xarg2,
+                               NULL_TREE, LOOKUP_NORMAL);
+    }
+  else if (tree_code_length[(int) code] == 1 || binary_is_unary)
+    {
+      parms = NULL_TREE;
+      rval = build_method_call (xarg1, fnname, NULL_TREE, NULL_TREE, flags);
+    }
+  else if (code == COND_EXPR)
+    {
+      parms = tree_cons (0, xarg2, build_tree_list (0, arg3));
+      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
+    }
+  else if (code == METHOD_CALL_EXPR)
+    {
+      /* must be a member function.  */
+      parms = tree_cons (NULL_TREE, xarg2, arg3);
+      return build_method_call (xarg1, fnname, parms, NULL_TREE, LOOKUP_NORMAL);
+    }
+  else if (fields1)
+    {
+      parms = build_tree_list (NULL_TREE, xarg2);
+      rval = build_method_call (xarg1, fnname, parms, NULL_TREE, flags);
+    }
+  else
+    {
+      parms = tree_cons (NULL_TREE, xarg1,
+                        build_tree_list (NULL_TREE, xarg2));
+      rval = build_overload_call (fnname, parms, flags & LOOKUP_COMPLAIN, 0);
+    }
+
+  /* If we did not win, do not lose yet, since type conversion may work.  */
+  if (TREE_CODE (rval) == ERROR_MARK)
+    {
+      if (flags & LOOKUP_COMPLAIN)
+       return rval;
+      return 0;
+    }
+
+  return rval;
+}
+\f
+/* This function takes an identifier, ID, and attempts to figure out what
+   it means. There are a number of possible scenarios, presented in increasing
+   order of hair:
+
+   1) not in a class's scope
+   2) in class's scope, member name of the class's method
+   3) in class's scope, but not a member name of the class
+   4) in class's scope, member name of a class's variable
+
+   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.
+
+   Values which are declared as being of REFERENCE_TYPE are
+   automatically dereferenced here (as a hack to make the
+   compiler faster).  */
+
+tree
+hack_identifier (value, name, yychar)
+     tree value, name;
+{
+  tree type;
+
+  if (TREE_CODE (value) == ERROR_MARK)
+    {
+      if (current_class_name)
+       {
+         tree fields = lookup_fnfields (CLASSTYPE_AS_LIST (current_class_type), name, 0);
+         if (fields)
+           {
+             fields = TREE_VALUE (fields);
+             assert (TREE_CODE (fields) == FUNCTION_DECL);
+             if (TREE_CHAIN (fields) == NULL_TREE)
+               {
+                 warning ("methods cannot be converted to function pointers");
+                 return fields;
+               }
+             else
+               {
+                 error ("ambiguous request for method pointer `%s'",
+                        IDENTIFIER_POINTER (name));
+                 return error_mark_node;
+               }
+           }
+       }
+      if (flag_labels_ok && IDENTIFIER_LABEL_VALUE (name))
+       {
+         return IDENTIFIER_LABEL_VALUE (name);
+       }
+      return error_mark_node;
+    }
+
+  type = TREE_TYPE (value);
+  if (TREE_NONLOCAL (value))
+    {
+      if (TREE_CODE (value) == FIELD_DECL)
+       {
+         if (current_class_decl == 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
+               && (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;
+           }
+         /* 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);
+       }
+      if (DECL_CONTEXT (value) != current_class_type
+         && (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == CONST_DECL))
+       {
+         tree path;
+         enum visibility_type visibility;
+
+         get_base_distance (DECL_CONTEXT (value), current_class_type, 0, &path);
+         visibility = compute_visibility (path, value);
+         if (visibility != visibility_public)
+           {
+             if (TREE_CODE (value) == VAR_DECL)
+               error ("static member `%s' is from private base class",
+                      IDENTIFIER_POINTER (name));
+             else
+               error ("enum `%s' is from private base class",
+                      IDENTIFIER_POINTER (name));
+             return error_mark_node;
+           }
+       }
+      else if (TREE_CODE (value) == TREE_LIST && type == 0)
+       {
+         error ("request for member `%s' is ambiguous in multiple inheritance lattice",
+                IDENTIFIER_POINTER (name));
+         return error_mark_node;
+       }
+
+      return value;
+    }
+
+  if (! TREE_USED (value))
+    {
+      if (TREE_EXTERNAL (value))
+       assemble_external (value);
+      TREE_USED (value) = 1;
+    }
+  if (TREE_CODE (type) == REFERENCE_TYPE)
+    {
+      assert (TREE_CODE (value) == VAR_DECL || TREE_CODE (value) == PARM_DECL
+             || TREE_CODE (value) == RESULT_DECL);
+      if (DECL_REFERENCE_SLOT (value))
+       return DECL_REFERENCE_SLOT (value);
+    }
+  return value;
+}
+
+tree
+hack_operator (op)
+     tree op;
+{
+  if (op == NULL_TREE)
+    return error_mark_node;
+
+  if (TREE_CODE (op) != TYPE_EXPR)
+    return grokopexpr (&op, NULL_TREE, 0, 0, 0);
+
+  return op;
+}
+
+/* NONWRAPPER is nonzero if this call is not to be wrapped.
+   TYPE is the type that the wrapper belongs to (in case
+   it should be non-virtual).
+   DECL is the function will will be (not be) wrapped.  */
+tree
+hack_wrapper (nonwrapper, type, decl)
+     int nonwrapper;
+     tree type, decl;
+{
+  if (type == NULL_TREE || is_aggr_typedef (type, 1))
+    {
+      if (type)
+       type = TREE_TYPE (type);
+
+      switch (nonwrapper)
+       {
+       case 0:
+         return build_nt (WRAPPER_EXPR, type, decl);
+       case 1:
+         return build_nt (ANTI_WRAPPER_EXPR, type, decl);
+       case 2:
+         return build_nt (WRAPPER_EXPR, type,
+                          build_nt (COND_EXPR, decl, NULL_TREE, NULL_TREE));
+       default:
+         assert (0 <= nonwrapper && nonwrapper <= 2);
+       }
+    }
+  return error_mark_node;
+}
+\f
+/* Return an IDENTIFIER which can be used as a name for
+   anonymous structs and unions.  */
+tree
+make_anon_name ()
+{
+  static int cnt = 0;
+  char buf[32];
+
+  sprintf (buf, ANON_AGGRNAME_FORMAT, cnt++);
+  return get_identifier (buf);
+}
+\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;
+
+  assert (IS_AGGR_TYPE (TREE_TYPE (of)));
+  assert (TREE_CODE (component) == TYPE_EXPR);
+
+  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);
+         if (TREE_OPERAND (tmp, 0)
+             && TREE_OPERAND (tmp, 0) != void_list_node)
+           {
+             error ("operator <typename> requires empty parameter list");
+             TREE_OPERAND (tmp, 0) = NULL_TREE;
+           }
+         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)
+           return build_method_call (of, name, NULL_TREE, NULL_TREE, flags);
+         else if (of)
+           {
+             tree this_this;
+
+             if (current_class_decl == NULL_TREE)
+               {
+                 error ("object required for `operator <typename>' call");
+                 return error_mark_node;
+               }
+
+             this_this = convert_pointer_to (TREE_TYPE (of), current_class_decl);
+             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);
+
+         error ("object required for `operator <typename>' call");
+         return error_mark_node;
+
+       case INDIRECT_REF:
+       case ADDR_EXPR:
+       case ARRAY_REF:
+         break;
+
+       case SCOPE_REF:
+         assert (cname == 0);
+         cname = TREE_OPERAND (tmp, 0);
+         tmp = TREE_OPERAND (tmp, 1);
+         break;
+
+       default:
+         abort ();
+       }
+      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 assert (cname == DECL_NAME (of));
+    }
+
+  if (of)
+    {
+      tree this_this;
+
+      if (current_class_decl == NULL_TREE)
+       {
+         error ("object required for `operator <typename>' call");
+         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);
+
+  error ("object required for `operator <typename>' member reference");
+  return error_mark_node;
+}