tree.c (decl_function_context): Handle virtual functions.
[gcc.git] / gcc / tree.c
index ff608db5360a84a1323f4cb30908d206c144b8e2..78ea4cf976a7a9d3d5cedafca27adf9ab6a98a46 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -34,21 +34,21 @@ Boston, MA 02111-1307, USA.  */
    by all passes of the compiler.  */
 
 #include "config.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
 #include "system.h"
-#include <setjmp.h>
 #include "flags.h"
 #include "tree.h"
-#include "except.h"
+#include "tm_p.h"
 #include "function.h"
 #include "obstack.h"
+#include "toplev.h"
+#include "ggc.h"
 
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
+/* obstack.[ch] explicitly declined to prototype this. */
+extern int _obstack_allocated_p PROTO ((struct obstack *h, PTR obj));
+
+static void unsave_expr_now_r PROTO ((tree));
 
 /* Tree nodes of permanent duration are allocated in this obstack.
    They are the identifier nodes, and everything outside of
@@ -68,21 +68,6 @@ struct obstack *function_maybepermanent_obstack;
 
 struct obstack maybepermanent_obstack;
 
-/* This is a list of function_maybepermanent_obstacks for top-level inline
-   functions that are compiled in the middle of compiling other functions.  */
-
-struct simple_obstack_stack *toplev_inline_obstacks;
-
-/* Former elements of toplev_inline_obstacks that have been recycled.  */
-
-struct simple_obstack_stack *extra_inline_obstacks;
-
-/* This is a list of function_maybepermanent_obstacks for inline functions
-   nested in the current function that were compiled in the middle of
-   compiling other functions.  */
-
-struct simple_obstack_stack *inline_obstacks;
-
 /* The contents of the current function definition are allocated
    in this obstack, and all are freed at the end of the function.
    For top-level functions, this is temporary_obstack.
@@ -197,7 +182,7 @@ int tree_code_length[MAX_TREE_CODES] = {
    Used for printing out the tree and error messages.  */
 #define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
 
-char *tree_code_name[MAX_TREE_CODES] = {
+const char *tree_code_name[MAX_TREE_CODES] = {
 #include "tree.def"
 };
 #undef DEFTREECODE
@@ -227,7 +212,7 @@ int tree_node_counts[(int)all_kinds];
 int tree_node_sizes[(int)all_kinds];
 int id_string_size = 0;
 
-char *tree_node_kind_names[] = {
+static const char * const tree_node_kind_names[] = {
   "decls",
   "types",
   "blocks",
@@ -258,13 +243,56 @@ static int next_decl_uid;
 /* Unique id for next type created.  */
 static int next_type_uid = 1;
 
+/* The language-specific function for alias analysis.  If NULL, the
+   language does not do any special alias analysis.  */
+int (*lang_get_alias_set) PROTO((tree));
+
 /* Here is how primitive or already-canonicalized types' hash
    codes are made.  */
 #define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
 
-extern char *mode_name[];
+/* Each hash table slot is a bucket containing a chain
+   of these structures.  */
+
+struct type_hash
+{
+  struct type_hash *next;      /* Next structure in the bucket.  */
+  int hashcode;                        /* Hash code of this type.  */
+  tree type;                   /* The type recorded here.  */
+};
+
+/* Now here is the hash table.  When recording a type, it is added
+   to the slot whose index is the hash code mod the table size.
+   Note that the hash table is used for several kinds of types
+   (function types, array types and array index range types, for now).
+   While all these live in the same table, they are completely independent,
+   and the hash code is computed differently for each of these.  */
 
-void gcc_obstack_init ();
+#define TYPE_HASH_SIZE 59
+struct type_hash *type_hash_table[TYPE_HASH_SIZE];
+
+static void set_type_quals PROTO((tree, int));
+static void append_random_chars PROTO((char *));
+static void build_real_from_int_cst_1 PROTO((PTR));
+static void mark_type_hash PROTO ((void *));
+static void fix_sizetype PROTO ((tree));
+
+/* If non-null, these are language-specific helper functions for
+   unsave_expr_now.  If present, LANG_UNSAVE is called before its
+   argument (an UNSAVE_EXPR) is to be unsaved, and all other
+   processing in unsave_expr_now is aborted.  LANG_UNSAVE_EXPR_NOW is
+   called from unsave_expr_1 for language-specific tree codes.  */
+void (*lang_unsave) PROTO((tree *));
+void (*lang_unsave_expr_now) PROTO((tree));
+
+/* The string used as a placeholder instead of a source file name for
+   built-in tree nodes.  The variable, which is dynamically allocated,
+   should be used; the macro is only used to initialize it.  */
+
+static char *built_in_filename;
+#define BUILT_IN_FILENAME ("<built-in>")
+\f
+tree global_trees[TI_MAX];
 \f
 /* Init the principal obstacks.  */
 
@@ -293,6 +321,12 @@ init_obstacks ()
 
   /* Init the hash table of identifiers.  */
   bzero ((char *) hash_table, sizeof hash_table);
+
+  ggc_add_tree_root (hash_table, MAX_HASH_TABLE);
+  ggc_add_root (type_hash_table, TYPE_HASH_SIZE, 
+               sizeof(struct type_hash *),
+               mark_type_hash);
+  ggc_add_tree_root (global_trees, TI_MAX);
 }
 
 void
@@ -311,20 +345,22 @@ gcc_obstack_init (obstack)
 #define OBSTACK_CHUNK_FREE free
 #endif
   _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
-                 (void *(*) ()) OBSTACK_CHUNK_ALLOC,
-                 (void (*) ()) OBSTACK_CHUNK_FREE);
+                 (void *(*) PROTO ((long))) OBSTACK_CHUNK_ALLOC,
+                 (void (*) PROTO ((void *))) OBSTACK_CHUNK_FREE);
 }
 
-/* Save all variables describing the current status into the structure *P.
-   This is used before starting a nested function.
+/* Save all variables describing the current status into the structure
+   *P.  This function is called whenever we start compiling one
+   function in the midst of compiling another.  For example, when
+   compiling a nested function, or, in C++, a template instantiation
+   that is required by the function we are currently compiling.
 
    CONTEXT is the decl_function_context for the function we're about to
    compile; if it isn't current_function_decl, we have to play some games.  */
 
 void
-save_tree_status (p, context)
+save_tree_status (p)
      struct function *p;
-     tree context;
 {
   p->all_types_permanent = all_types_permanent;
   p->momentary_stack = momentary_stack;
@@ -338,50 +374,10 @@ save_tree_status (p, context)
   p->expression_obstack = expression_obstack;
   p->saveable_obstack = saveable_obstack;
   p->rtl_obstack = rtl_obstack;
-  p->inline_obstacks = inline_obstacks;
-
-  if (context == current_function_decl)
-    /* Objects that need to be saved in this function can be in the nonsaved
-       obstack of the enclosing function since they can't possibly be needed
-       once it has returned.  */
-    function_maybepermanent_obstack = function_obstack;
-  else
-    {
-      /* We're compiling a function which isn't nested in the current
-         function.  We need to create a new maybepermanent_obstack for this
-         function, since it can't go onto any of the existing obstacks.  */
-      struct simple_obstack_stack **head;
-      struct simple_obstack_stack *current;
-
-      if (context == NULL_TREE)
-       head = &toplev_inline_obstacks;
-      else
-       {
-         struct function *f = find_function_data (context);
-         head = &f->inline_obstacks;
-       }
-
-      if (context == NULL_TREE && extra_inline_obstacks)
-       {
-         current = extra_inline_obstacks;
-         extra_inline_obstacks = current->next;
-       }
-      else
-       {
-         current = ((struct simple_obstack_stack *)
-                    xmalloc (sizeof (struct simple_obstack_stack)));
-
-         current->obstack
-           = (struct obstack *) xmalloc (sizeof (struct obstack));
-         gcc_obstack_init (current->obstack);
-       }
-
-      function_maybepermanent_obstack = current->obstack;
-
-      current->next = *head;
-      *head = current;
-    }      
 
+  function_maybepermanent_obstack
+    = (struct obstack *) xmalloc (sizeof (struct obstack));
+  gcc_obstack_init (function_maybepermanent_obstack);
   maybepermanent_firstobj
     = (char *) obstack_finish (function_maybepermanent_obstack);
 
@@ -401,9 +397,8 @@ save_tree_status (p, context)
    This is used after a nested function.  */
 
 void
-restore_tree_status (p, context)
+restore_tree_status (p)
      struct function *p;
-     tree context;
 {
   all_types_permanent = p->all_types_permanent;
   momentary_stack = p->momentary_stack;
@@ -411,41 +406,18 @@ restore_tree_status (p, context)
   obstack_free (&momentary_obstack, momentary_function_firstobj);
 
   /* Free saveable storage used by the function just compiled and not
-     saved.
-
-     CAUTION: This is in function_obstack of the containing function.
-     So we must be sure that we never allocate from that obstack during
-     the compilation of a nested function if we expect it to survive
-     past the nested function's end.  */
+     saved.  */
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
-
-  /* If we were compiling a toplevel function, we can free this space now.  */
-  if (context == NULL_TREE)
+  if (obstack_empty_p (function_maybepermanent_obstack))
     {
-      obstack_free (&temporary_obstack, temporary_firstobj);
-      obstack_free (&momentary_obstack, momentary_function_firstobj);
+      obstack_free (function_maybepermanent_obstack, NULL);
+      free (function_maybepermanent_obstack);
     }
 
-  /* If we were compiling a toplevel function that we don't actually want
-     to save anything from, return the obstack to the pool.  */
-  if (context == NULL_TREE
-      && obstack_empty_p (function_maybepermanent_obstack))
-    {
-      struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
-
-      if ((*p) != NULL)
-       {
-         while ((*p)->obstack != function_maybepermanent_obstack)
-           p = &((*p)->next);
-         current = *p;
-         *p = current->next;
-
-         current->next = extra_inline_obstacks;
-         extra_inline_obstacks = current;
-       }
-    }
+  obstack_free (&temporary_obstack, temporary_firstobj);
+  obstack_free (&momentary_obstack, momentary_function_firstobj);
 
-  obstack_free (function_obstack, 0);
+  obstack_free (function_obstack, NULL);
   free (function_obstack);
 
   temporary_firstobj = p->temporary_firstobj;
@@ -458,7 +430,6 @@ restore_tree_status (p, context)
   expression_obstack = p->expression_obstack;
   saveable_obstack = p->saveable_obstack;
   rtl_obstack = p->rtl_obstack;
-  inline_obstacks = p->inline_obstacks;
 }
 \f
 /* Start allocating on the temporary (per function) obstack.
@@ -475,7 +446,6 @@ temporary_allocation ()
   expression_obstack = function_obstack;
   rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
   momentary_stack = 0;
-  inline_obstacks = 0;
 }
 
 /* Start allocating on the permanent obstack but don't
@@ -522,8 +492,9 @@ void
 push_obstacks (current, saveable)
      struct obstack *current, *saveable;
 {
-  struct obstack_stack *p
-    = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+  struct obstack_stack *p;
+
+  p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
                                              (sizeof (struct obstack_stack)));
 
   p->current = current_obstack;
@@ -543,8 +514,9 @@ push_obstacks (current, saveable)
 void
 push_obstacks_nochange ()
 {
-  struct obstack_stack *p
-    = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+  struct obstack_stack *p;
+  
+  p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
                                              (sizeof (struct obstack_stack)));
 
   p->current = current_obstack;
@@ -560,7 +532,9 @@ push_obstacks_nochange ()
 void
 pop_obstacks ()
 {
-  struct obstack_stack *p = obstack_stack;
+  struct obstack_stack *p;
+
+  p = obstack_stack;
   obstack_stack = p->next;
 
   current_obstack = p->current;
@@ -603,17 +577,6 @@ permanent_allocation (function_end)
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
   obstack_free (&temp_decl_obstack, temp_decl_firstobj);
 
-  /* Free up the maybepermanent_obstacks for any of our nested functions
-     which were compiled at a lower level.  */
-  while (inline_obstacks)
-    {
-      struct simple_obstack_stack *current = inline_obstacks;
-      inline_obstacks = current->next;
-      obstack_free (current->obstack, 0);
-      free (current->obstack);
-      free (current);
-    }
-
   current_obstack = &permanent_obstack;
   expression_obstack = &permanent_obstack;
   rtl_obstack = saveable_obstack = &permanent_obstack;
@@ -738,10 +701,10 @@ void
 print_obstack_name (object, file, prefix)
      char *object;
      FILE *file;
-     char *prefix;
+     const char *prefix;
 {
   struct obstack *obstack = NULL;
-  char *obstack_name = NULL;
+  const char *obstack_name = NULL;
   struct function *p;
 
   for (p = outer_function_chain; p; p = p->next)
@@ -917,7 +880,9 @@ resume_momentary (yes)
 void
 init_tree_codes ()
 {
-  
+  built_in_filename = 
+    ggc_alloc_string (BUILT_IN_FILENAME, sizeof (BUILT_IN_FILENAME));
+  ggc_add_string_root (&built_in_filename, 1);
 }
 
 /* Return a newly allocated node of code CODE.
@@ -933,9 +898,8 @@ make_node (code)
 {
   register tree t;
   register int type = TREE_CODE_CLASS (code);
-  register int length;
+  register int length = 0;
   register struct obstack *obstack = current_obstack;
-  register int i;
 #ifdef GATHER_STATISTICS
   register tree_node_kind kind;
 #endif
@@ -1065,20 +1029,19 @@ make_node (code)
       abort ();
     }
 
-  t = (tree) obstack_alloc (obstack, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    {
+      t = (tree) obstack_alloc (obstack, length);
+      memset ((PTR) t, 0, length);
+    }
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)kind]++;
   tree_node_sizes[(int)kind] += length;
 #endif
 
-  /* Clear a word at a time.  */
-  for (i = (length / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) t)[i] = 0;
-  /* Clear any extra bytes.  */
-  for (i = length / sizeof (int) * sizeof (int); i < length; i++)
-    ((char *) t)[i] = 0;
-
   TREE_SET_CODE (t, code);
   if (obstack == &permanent_obstack)
     TREE_PERMANENT (t) = 1;
@@ -1096,8 +1059,12 @@ make_node (code)
       DECL_IN_SYSTEM_HEADER (t)
        = in_system_header && (obstack == &permanent_obstack);
       DECL_SOURCE_LINE (t) = lineno;
-      DECL_SOURCE_FILE (t) = (input_filename) ? input_filename : "<built-in>";
+      DECL_SOURCE_FILE (t) = 
+       (input_filename) ? input_filename : built_in_filename;
       DECL_UID (t) = next_decl_uid++;
+      /* Note that we have not yet computed the alias set for this
+        declaration.  */
+      DECL_POINTER_ALIAS_SET (t) = -1;
       break;
 
     case 't':
@@ -1109,18 +1076,60 @@ make_node (code)
 #ifdef SET_DEFAULT_TYPE_ATTRIBUTES
       SET_DEFAULT_TYPE_ATTRIBUTES (t);
 #endif
+      /* Note that we have not yet computed the alias set for this
+        type.  */
+      TYPE_ALIAS_SET (t) = -1;
       break;
 
     case 'c':
       TREE_CONSTANT (t) = 1;
       break;
+
+    case 'e':
+      switch (code)
+       {
+       case INIT_EXPR:
+       case MODIFY_EXPR:
+       case VA_ARG_EXPR:
+       case RTL_EXPR:
+       case PREDECREMENT_EXPR:
+       case PREINCREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+         /* All of these have side-effects, no matter what their
+            operands are.  */
+         TREE_SIDE_EFFECTS (t) = 1;
+         break;
+         
+       default:
+         break;
+       }
+      break;
     }
 
   return t;
 }
+
+/* A front-end can reset this to an appropriate function if types need
+   special handling.  */
+
+tree (*make_lang_type_fn) PROTO((enum tree_code)) = make_node;
+
+/* Return a new type (with the indicated CODE), doing whatever
+   language-specific processing is required.  */
+
+tree 
+make_lang_type (code)
+     enum tree_code code;
+{
+  return (*make_lang_type_fn) (code);
+}
 \f
-/* Return a new node with the same contents as NODE
-   except that its TREE_CHAIN is zero and it has a fresh uid.  */
+/* Return a new node with the same contents as NODE except that its
+   TREE_CHAIN is zero and it has a fresh uid.  Unlike make_node, this
+   function always performs the allocation on the CURRENT_OBSTACK;
+   it's up to the caller to pick the right obstack before calling this
+   function.  */
 
 tree
 copy_node (node)
@@ -1129,7 +1138,6 @@ copy_node (node)
   register tree t;
   register enum tree_code code = TREE_CODE (node);
   register int length = 0;
-  register int i;
 
   switch (TREE_CODE_CLASS (code))
     {
@@ -1177,17 +1185,13 @@ copy_node (node)
        length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
     }
 
-  t = (tree) obstack_alloc (current_obstack, length);
-
-  for (i = (length / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) t)[i] = ((int *) node)[i];
-  /* Clear any extra bytes.  */
-  for (i = length / sizeof (int) * sizeof (int); i < length; i++)
-    ((char *) t)[i] = ((char *) node)[i];
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    t = (tree) obstack_alloc (current_obstack, length);
+  memcpy (t, node, length);
 
-  /* EXPR_WITH_FILE_LOCATION must keep filename info stored in TREE_CHAIN */
-  if (TREE_CODE (node) != EXPR_WITH_FILE_LOCATION)
-    TREE_CHAIN (t) = 0;
+  TREE_CHAIN (t) = 0;
   TREE_ASM_WRITTEN (t) = 0;
 
   if (TREE_CODE_CLASS (code) == 'd')
@@ -1243,7 +1247,7 @@ copy_list (list)
 
 tree
 get_identifier (text)
-     register char *text;
+     register const char *text;
 {
   register int hi;
   register int i;
@@ -1251,11 +1255,11 @@ get_identifier (text)
   register int len, hash_len;
 
   /* Compute length of text in len.  */
-  for (len = 0; text[len]; len++);
+  len = strlen (text);
 
   /* Decide how much of that length to hash on */
   hash_len = len;
-  if (warn_id_clash && len > id_clash_len)
+  if (warn_id_clash && (unsigned)len > id_clash_len)
     hash_len = id_clash_len;
 
   /* Compute hash code */
@@ -1274,7 +1278,7 @@ get_identifier (text)
       return idp;              /* <-- return if found */
 
   /* Not found; optionally warn about a similar identifier */
-  if (warn_id_clash && do_identifier_warnings && len >= id_clash_len)
+  if (warn_id_clash && do_identifier_warnings && (unsigned)len >= id_clash_len)
     for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
       if (!strncmp (IDENTIFIER_POINTER (idp), text, id_clash_len))
        {
@@ -1293,7 +1297,10 @@ get_identifier (text)
   id_string_size += len;
 #endif
 
-  IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
+  if (ggc_p)
+    IDENTIFIER_POINTER (idp) = ggc_alloc_string (text, len);
+  else
+    IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
 
   TREE_CHAIN (idp) = hash_table[hi];
   hash_table[hi] = idp;
@@ -1306,7 +1313,7 @@ get_identifier (text)
 
 tree
 maybe_get_identifier (text)
-     register char *text;
+     register const char *text;
 {
   register int hi;
   register int i;
@@ -1314,11 +1321,11 @@ maybe_get_identifier (text)
   register int len, hash_len;
 
   /* Compute length of text in len.  */
-  for (len = 0; text[len]; len++);
+  len = strlen (text);
 
   /* Decide how much of that length to hash on */
   hash_len = len;
-  if (warn_id_clash && len > id_clash_len)
+  if (warn_id_clash && (unsigned)len > id_clash_len)
     hash_len = id_clash_len;
 
   /* Compute hash code */
@@ -1449,6 +1456,29 @@ real_value_from_int_cst (type, i)
   return d;
 }
 
+struct brfic_args
+{
+  /* Input */
+  tree type, i;
+  /* Output */
+  REAL_VALUE_TYPE d;
+};
+
+static void
+build_real_from_int_cst_1 (data)
+  PTR data;
+{
+  struct brfic_args * args = (struct brfic_args *) data;
+  
+#ifdef REAL_ARITHMETIC
+  args->d = real_value_from_int_cst (args->type, args->i);
+#else
+  args->d =
+    REAL_VALUE_TRUNCATE (TYPE_MODE (args->type),
+                        real_value_from_int_cst (args->type, args->i));
+#endif
+}
+
 /* This function can't be implemented if we can't do arithmetic
    on the float representation.  */
 
@@ -1460,32 +1490,29 @@ build_real_from_int_cst (type, i)
   tree v;
   int overflow = TREE_OVERFLOW (i);
   REAL_VALUE_TYPE d;
-  jmp_buf float_error;
+  struct brfic_args args;
 
   v = make_node (REAL_CST);
   TREE_TYPE (v) = type;
 
-  if (setjmp (float_error))
+  /* Setup input for build_real_from_int_cst_1() */
+  args.type = type;
+  args.i = i;
+
+  if (do_float_handler (build_real_from_int_cst_1, (PTR) &args))
+    {
+      /* Receive output from build_real_from_int_cst_1() */
+      d = args.d;
+    }
+  else
     {
+      /* We got an exception from build_real_from_int_cst_1() */
       d = dconst0;
       overflow = 1;
-      goto got_it;
     }
-
-  set_float_handler (float_error);
-
-#ifdef REAL_ARITHMETIC
-  d = real_value_from_int_cst (type, i);
-#else
-  d = REAL_VALUE_TRUNCATE (TYPE_MODE (type),
-                          real_value_from_int_cst (type, i));
-#endif
-
+  
   /* Check for valid float value for this type on this target machine.  */
 
- got_it:
-  set_float_handler (NULL_PTR);
-
 #ifdef CHECK_FLOAT_VALUE
   CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
 #endif
@@ -1504,7 +1531,7 @@ build_real_from_int_cst (type, i)
 tree
 build_string (len, str)
      int len;
-     char *str;
+     const char *str;
 {
   /* Put the string in saveable_obstack since it will be placed in the RTL
      for an "asm" statement and will also be kept around a while if
@@ -1512,7 +1539,10 @@ build_string (len, str)
 
   register tree s = make_node (STRING_CST);
   TREE_STRING_LENGTH (s) = len;
-  TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+  if (ggc_p)
+    TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
+  else
+    TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
   return s;
 }
 
@@ -1546,17 +1576,19 @@ make_tree_vec (len)
   register tree t;
   register int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
   register struct obstack *obstack = current_obstack;
-  register int i;
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)vec_kind]++;
   tree_node_sizes[(int)vec_kind] += length;
 #endif
 
-  t = (tree) obstack_alloc (obstack, length);
-
-  for (i = (length / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) t)[i] = 0;
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    {
+      t = (tree) obstack_alloc (obstack, length);
+      bzero ((PTR) t, length);
+    }
 
   TREE_SET_CODE (t, TREE_VEC);
   TREE_VEC_LENGTH (t) = len;
@@ -1933,14 +1965,18 @@ chainon (op1, op2)
   if (op1)
     {
       register tree t1;
+#ifdef ENABLE_CHECKING
       register tree t2;
+#endif
 
       for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
        ;
       TREE_CHAIN (t1) = op2;
+#ifdef ENABLE_CHECKING
       for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
         if (t2 == t1)
           abort ();  /* Circularity created.  */
+#endif
       return op1;
     }
   else return op2;
@@ -2053,15 +2089,21 @@ tree_cons (purpose, value, chain)
 #if 0
   register tree node = make_node (TREE_LIST);
 #else
-  register int i;
-  register tree node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+  register tree node;
+
+  if (ggc_p)
+    node = ggc_alloc_tree (sizeof (struct tree_list));
+  else
+    {
+      node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+      memset (node, 0, sizeof (struct tree_common));
+    }
+
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)x_kind]++;
   tree_node_sizes[(int)x_kind] += sizeof (struct tree_list);
 #endif
 
-  for (i = (sizeof (struct tree_common) / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) node)[i] = 0;
 
   TREE_SET_CODE (node, TREE_LIST);
   if (current_obstack == &permanent_obstack)
@@ -2161,16 +2203,17 @@ size_in_bytes (type)
 
   if (type == error_mark_node)
     return integer_zero_node;
+
   type = TYPE_MAIN_VARIANT (type);
-  if (TYPE_SIZE (type) == 0)
+  t = TYPE_SIZE_UNIT (type);
+  if (t == 0)
     {
       incomplete_type_error (NULL_TREE, type);
       return integer_zero_node;
     }
-  t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
-                 size_int (BITS_PER_UNIT));
   if (TREE_CODE (t) == INTEGER_CST)
     force_fit_type (t, 0);
+
   return t;
 }
 
@@ -2187,26 +2230,17 @@ int_size_in_bytes (type)
     return 0;
 
   type = TYPE_MAIN_VARIANT (type);
-  if (TYPE_SIZE (type) == 0
-      || TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
-    return -1;
-
-  if (TREE_INT_CST_HIGH (TYPE_SIZE (type)) == 0)
-    return ((TREE_INT_CST_LOW (TYPE_SIZE (type)) + BITS_PER_UNIT - 1)
-         / BITS_PER_UNIT);
-
-  t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type), size_int (BITS_PER_UNIT));
-  if (TREE_CODE (t) != INTEGER_CST || TREE_INT_CST_HIGH (t) != 0)
+  t = TYPE_SIZE_UNIT (type);
+  if (t == 0
+      || TREE_CODE (t) != INTEGER_CST
+      || TREE_INT_CST_HIGH (t) != 0)
     return -1;
 
   return TREE_INT_CST_LOW (t);
 }
 \f
 /* Return, as a tree node, the number of elements for TYPE (which is an
-   ARRAY_TYPE) minus one. This counts only elements of the top array.
-
-   Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup
-   action, they would get unsaved.  */
+   ARRAY_TYPE) minus one. This counts only elements of the top array.  */
 
 tree
 array_type_nelts (type)
@@ -2223,26 +2257,6 @@ array_type_nelts (type)
   min = TYPE_MIN_VALUE (index_type);
   max = TYPE_MAX_VALUE (index_type);
 
-  if (! TREE_CONSTANT (min))
-    {
-      STRIP_NOPS (min);
-      if (TREE_CODE (min) == SAVE_EXPR)
-       min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (min));
-      else
-       min = TYPE_MIN_VALUE (index_type);
-    }
-
-  if (! TREE_CONSTANT (max))
-    {
-      STRIP_NOPS (max);
-      if (TREE_CODE (max) == SAVE_EXPR)
-       max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (max));
-      else
-       max = TYPE_MAX_VALUE (index_type);
-    }
-
   return (integer_zerop (min)
          ? max
          : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
@@ -2260,9 +2274,12 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-       return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
+       return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+              && ! DECL_NON_ADDR_CONST_P (arg);
+
     case VAR_DECL:
-      return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
+      return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+             && ! DECL_NON_ADDR_CONST_P (arg);
 
     case CONSTRUCTOR:
       return TREE_STATIC (arg);
@@ -2391,6 +2408,7 @@ first_rtl_op (code)
     {
     case SAVE_EXPR:
       return 2;
+    case GOTO_SUBROUTINE_EXPR:
     case RTL_EXPR:
       return 0;
     case CALL_EXPR:
@@ -2405,26 +2423,18 @@ first_rtl_op (code)
     }
 }
 
-/* Modify a tree in place so that all the evaluate only once things
-   are cleared out.  Return the EXPR given.  */
+/* Perform any modifications to EXPR required when it is unsaved.  Does
+   not recurse into EXPR's subtrees.  */
 
-tree
-unsave_expr_now (expr)
+void
+unsave_expr_1 (expr)
      tree expr;
 {
-  enum tree_code code;
-  register int i;
-  int first_rtl;
-
-  if (expr == NULL_TREE)
-    return expr;
-
-  code = TREE_CODE (expr);
-  first_rtl = first_rtl_op (code);
-  switch (code)
+  switch (TREE_CODE (expr))
     {
     case SAVE_EXPR:
-      SAVE_EXPR_RTL (expr) = 0;
+      if (!SAVE_EXPR_PERSISTENT_P (expr))
+       SAVE_EXPR_RTL (expr) = 0;
       break;
 
     case TARGET_EXPR:
@@ -2434,28 +2444,48 @@ unsave_expr_now (expr)
       
     case RTL_EXPR:
       /* I don't yet know how to emit a sequence multiple times.  */
-      if (RTL_EXPR_SEQUENCE (expr) != 0)
+      if (RTL_EXPR_SEQUENCE (expr))
        abort ();
       break;
 
     case CALL_EXPR:
       CALL_EXPR_RTL (expr) = 0;
-      if (TREE_OPERAND (expr, 1)
-         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
-       {
-         tree exp = TREE_OPERAND (expr, 1);
-         while (exp)
-           {
-             unsave_expr_now (TREE_VALUE (exp));
-             exp = TREE_CHAIN (exp);
-           }
-       }
       break;
 
     default:
+      if (lang_unsave_expr_now)
+       (*lang_unsave_expr_now) (expr);
       break;
     }
+}
+
+/* Helper function for unsave_expr_now.  */
 
+static void
+unsave_expr_now_r (expr)
+     tree expr;
+{
+  enum tree_code code;
+
+  /* There's nothing to do for NULL_TREE.  */
+  if (!expr)
+    return;
+
+  unsave_expr_1 (expr);
+
+  code = TREE_CODE (expr);
+  if (code == CALL_EXPR 
+      && TREE_OPERAND (expr, 1)
+      && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+    {
+      tree exp = TREE_OPERAND (expr, 1);
+      while (exp)
+       {
+         unsave_expr_now_r (TREE_VALUE (exp));
+         exp = TREE_CHAIN (exp);
+       }
+    }
   switch (TREE_CODE_CLASS (code))
     {
     case 'c':  /* a constant */
@@ -2463,7 +2493,7 @@ unsave_expr_now (expr)
     case 'x':  /* something random, like an identifier or an ERROR_MARK.  */
     case 'd':  /* A decl node */
     case 'b':  /* A block node */
-      return expr;
+      break;
 
     case 'e':  /* an expression */
     case 'r':  /* a reference */
@@ -2471,14 +2501,33 @@ unsave_expr_now (expr)
     case '<':  /* a comparison expression */
     case '2':  /* a binary arithmetic expression */
     case '1':  /* a unary arithmetic expression */
-      for (i = first_rtl - 1; i >= 0; i--)
-       unsave_expr_now (TREE_OPERAND (expr, i));
-      return expr;
+      {
+       int i;
+       
+       for (i = first_rtl_op (code) - 1; i >= 0; i--)
+         unsave_expr_now_r (TREE_OPERAND (expr, i));
+      }
+      break;
 
     default:
       abort ();
     }
 }
+
+/* Modify a tree in place so that all the evaluate only once things
+   are cleared out.  Return the EXPR given.  */
+
+tree
+unsave_expr_now (expr)
+     tree expr;
+{
+  if (lang_unsave)
+    (*lang_unsave) (&expr);
+  else
+    unsave_expr_now_r (expr);
+
+  return expr;
+}
 \f
 /* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
    or offset that depends on a field within a record.  */
@@ -2584,6 +2633,7 @@ has_cleanups (exp)
   switch (TREE_CODE (exp))
     {
     case TARGET_EXPR:
+    case GOTO_SUBROUTINE_EXPR:
     case WITH_CLEANUP_EXPR:
       return 1;
 
@@ -2974,7 +3024,7 @@ stabilize_reference_1 (e)
 tree
 build VPROTO((enum tree_code code, tree tt, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
   tree tt;
 #endif
@@ -2982,10 +3032,11 @@ build VPROTO((enum tree_code code, tree tt, ...))
   register tree t;
   register int length;
   register int i;
+  int fro;
 
   VA_START (p, tt);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum tree_code);
   tt = va_arg (p, tree);
 #endif
@@ -2994,6 +3045,12 @@ build VPROTO((enum tree_code code, tree tt, ...))
   length = tree_code_length[(int) code];
   TREE_TYPE (t) = tt;
 
+  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_RAISED for
+     the result based on those same flags for the arguments.  But, if
+     the arguments aren't really even `tree' expressions, we shouldn't
+     be trying to do this.  */
+  fro = first_rtl_op (code);
+
   if (length == 2)
     {
       /* This is equivalent to the loop below, but faster.  */
@@ -3001,11 +3058,20 @@ build VPROTO((enum tree_code code, tree tt, ...))
       register tree arg1 = va_arg (p, tree);
       TREE_OPERAND (t, 0) = arg0;
       TREE_OPERAND (t, 1) = arg1;
-      if ((arg0 && TREE_SIDE_EFFECTS (arg0))
-         || (arg1 && TREE_SIDE_EFFECTS (arg1)))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t)
-       = (arg0 && TREE_RAISES (arg0)) || (arg1 && TREE_RAISES (arg1));
+      if (arg0 && fro > 0)
+       {
+         if (TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+         if (TREE_RAISES (arg0))
+           TREE_RAISES (t) = 1;
+       }
+      if (arg1 && fro > 1)
+       {
+         if (TREE_SIDE_EFFECTS (arg1))
+           TREE_SIDE_EFFECTS (t) = 1;
+         if (TREE_RAISES (arg1))
+           TREE_RAISES (t) = 1;
+       }
     }
   else if (length == 1)
     {
@@ -3015,9 +3081,12 @@ build VPROTO((enum tree_code code, tree tt, ...))
       if (TREE_CODE_CLASS (code) != 's')
        abort ();
       TREE_OPERAND (t, 0) = arg0;
-      if (arg0 && TREE_SIDE_EFFECTS (arg0))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+      if (fro > 0)
+       {
+         if (arg0 && TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+         TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+       }
     }
   else
     {
@@ -3025,7 +3094,7 @@ build VPROTO((enum tree_code code, tree tt, ...))
        {
          register tree operand = va_arg (p, tree);
          TREE_OPERAND (t, i) = operand;
-         if (operand)
+         if (operand && fro > i)
            {
              if (TREE_SIDE_EFFECTS (operand))
                TREE_SIDE_EFFECTS (t) = 1;
@@ -3049,7 +3118,7 @@ build1 (code, type, node)
      tree node;
 {
   register struct obstack *obstack = expression_obstack;
-  register int i, length;
+  register int length;
 #ifdef GATHER_STATISTICS
   register tree_node_kind kind;
 #endif
@@ -3064,16 +3133,19 @@ build1 (code, type, node)
 
   length = sizeof (struct tree_exp);
 
-  t = (tree) obstack_alloc (obstack, length);
+  if (ggc_p)
+    t = ggc_alloc_tree (length);
+  else
+    {
+      t = (tree) obstack_alloc (obstack, length);
+      memset ((PTR) t, 0, length);
+    }
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)kind]++;
   tree_node_sizes[(int)kind] += length;
 #endif
 
-  for (i = (length / sizeof (int)) - 1; i >= 0; i--)
-    ((int *) t)[i] = 0;
-
   TREE_TYPE (t) = type;
   TREE_SET_CODE (t, code);
 
@@ -3081,7 +3153,7 @@ build1 (code, type, node)
     TREE_PERMANENT (t) = 1;
 
   TREE_OPERAND (t, 0) = node;
-  if (node)
+  if (node && first_rtl_op (code) != 0)
     {
       if (TREE_SIDE_EFFECTS (node))
        TREE_SIDE_EFFECTS (t) = 1;
@@ -3089,6 +3161,25 @@ build1 (code, type, node)
        TREE_RAISES (t) = 1;
     }
 
+  switch (code)
+    {
+    case INIT_EXPR:
+    case MODIFY_EXPR:
+    case VA_ARG_EXPR:
+    case RTL_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      /* All of these have side-effects, no matter what their
+        operands are.  */
+      TREE_SIDE_EFFECTS (t) = 1;
+      break;
+         
+    default:
+      break;
+    }
+
   return t;
 }
 
@@ -3100,7 +3191,7 @@ build1 (code, type, node)
 tree
 build_nt VPROTO((enum tree_code code, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
 #endif
   va_list p;
@@ -3110,7 +3201,7 @@ build_nt VPROTO((enum tree_code code, ...))
 
   VA_START (p, code);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum tree_code);
 #endif
 
@@ -3130,7 +3221,7 @@ build_nt VPROTO((enum tree_code code, ...))
 tree
 build_parse_node VPROTO((enum tree_code code, ...))
 {
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   enum tree_code code;
 #endif
   register struct obstack *ambient_obstack = expression_obstack;
@@ -3141,7 +3232,7 @@ build_parse_node VPROTO((enum tree_code code, ...))
 
   VA_START (p, code);
 
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
   code = va_arg (p, enum tree_code);
 #endif
 
@@ -3214,7 +3305,6 @@ build_block (vars, tags, subblocks, supercontext, chain)
 {
   register tree block = make_node (BLOCK);
   BLOCK_VARS (block) = vars;
-  BLOCK_TYPE_TAGS (block) = tags;
   BLOCK_SUBBLOCKS (block) = subblocks;
   BLOCK_SUPERCONTEXT (block) = supercontext;
   BLOCK_CHAIN (block) = chain;
@@ -3229,10 +3319,10 @@ build_block (vars, tags, subblocks, supercontext, chain)
 tree
 build_expr_wfl (node, file, line, col)
      tree node;
-     char *file;
+     const char *file;
      int line, col;
 {
-  static char *last_file = 0;
+  static const char *last_file = 0;
   static tree  last_filenode = NULL_TREE;
   register tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
 
@@ -3275,14 +3365,10 @@ build_type_attribute_variant (ttype, attribute)
   if ( ! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
     {
       register int hashcode;
-      register struct obstack *ambient_obstack = current_obstack;
       tree ntype;
 
-      if (ambient_obstack != &permanent_obstack)
-        current_obstack = TYPE_OBSTACK (ttype);
-
+      push_obstacks (TYPE_OBSTACK (ttype), TYPE_OBSTACK (ttype));
       ntype = copy_node (ttype);
-      current_obstack = ambient_obstack;
 
       TYPE_POINTER_TO (ntype) = 0;
       TYPE_REFERENCE_TO (ntype) = 0;
@@ -3291,7 +3377,7 @@ build_type_attribute_variant (ttype, attribute)
       /* Create a new main variant of TYPE.  */
       TYPE_MAIN_VARIANT (ntype) = ntype;
       TYPE_NEXT_VARIANT (ntype) = 0;
-      TYPE_READONLY (ntype) = TYPE_VOLATILE (ntype) = 0;
+      set_type_quals (ntype, TYPE_UNQUALIFIED);
 
       hashcode = TYPE_HASH (TREE_CODE (ntype))
                 + TYPE_HASH (TREE_TYPE (ntype))
@@ -3316,8 +3402,8 @@ build_type_attribute_variant (ttype, attribute)
         }
 
       ntype = type_hash_canon (hashcode, ntype);
-      ttype = build_type_variant (ntype, TYPE_READONLY (ttype),
-                                 TYPE_VOLATILE (ttype));
+      ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
+      pop_obstacks ();
     }
 
   return ttype;
@@ -3329,11 +3415,12 @@ build_type_attribute_variant (ttype, attribute)
 
 int
 valid_machine_attribute (attr_name, attr_args, decl, type)
-     tree attr_name, attr_args;
-     tree decl;
-     tree type;
+  tree attr_name;
+  tree attr_args ATTRIBUTE_UNUSED;
+  tree decl ATTRIBUTE_UNUSED;
+  tree type ATTRIBUTE_UNUSED;
 {
-  int valid = 0;
+  int validated = 0;
 #ifdef VALID_MACHINE_DECL_ATTRIBUTE
   tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
 #endif
@@ -3363,12 +3450,15 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
          decl = build_decl_attribute_variant (decl, decl_attr_list);
        }
 
-      valid = 1;
+      validated = 1;
     }
 #endif
 
 #ifdef VALID_MACHINE_TYPE_ATTRIBUTE
-  if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name, attr_args))
+  if (validated)
+    /* Don't apply the attribute to both the decl and the type.  */;
+  else if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name,
+                                        attr_args))
     {
       tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
                                    type_attr_list);
@@ -3383,12 +3473,18 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
        }
       else
        {
+         /* If this is part of a declaration, create a type variant,
+            otherwise, this is part of a type definition, so add it 
+            to the base type.  */
          type_attr_list = tree_cons (attr_name, attr_args, type_attr_list);
-         type = build_type_attribute_variant (type, type_attr_list);
+         if (decl != 0)
+           type = build_type_attribute_variant (type, type_attr_list);
+         else
+           TYPE_ATTRIBUTES (type) = type_attr_list;
        }
       if (decl != 0)
        TREE_TYPE (decl) = type;
-      valid = 1;
+      validated = 1;
     }
 
   /* Handle putting a type attribute on pointer-to-function-type by putting
@@ -3414,12 +3510,19 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
 
       if (decl != 0)
        TREE_TYPE (decl) = build_pointer_type (inner_type);
+      else
+       {
+         /* Clear TYPE_POINTER_TO for the old inner type, since
+            `type' won't be pointing to it anymore.  */
+         TYPE_POINTER_TO (TREE_TYPE (type)) = NULL_TREE;
+         TREE_TYPE (type) = inner_type;
+       }
 
-      valid = 1;
+      validated = 1;
     }
 #endif
 
-  return valid;
+  return validated;
 }
 
 /* Return non-zero if IDENT is a valid name for attribute ATTR,
@@ -3432,7 +3535,7 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
 
 int
 is_attribute_p (attr, ident)
-     char *attr;
+     const char *attr;
      tree ident;
 {
   int ident_len, attr_len;
@@ -3477,7 +3580,7 @@ is_attribute_p (attr, ident)
 
 tree
 lookup_attribute (attr_name, list)
-     char *attr_name;
+     const char *attr_name;
      tree list;
 {
   tree l;
@@ -3563,45 +3666,44 @@ merge_machine_decl_attributes (olddecl, newdecl)
 #endif
 }
 \f
-/* Return a type like TYPE except that its TYPE_READONLY is CONSTP
-   and its TYPE_VOLATILE is VOLATILEP.
+/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
+   of the various TYPE_QUAL values.  */
 
-   Such variant types already made are recorded so that duplicates
-   are not made.
+static void
+set_type_quals (type, type_quals)
+     tree type;
+     int  type_quals;
+{
+  TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
+  TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
+  TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
+}
 
-   A variant types should never be used as the type of an expression.
-   Always copy the variant information into the TREE_READONLY
-   and TREE_THIS_VOLATILE of the expression, and then give the expression
-   as its type the "main variant", the variant whose TYPE_READONLY
-   and TYPE_VOLATILE are zero.  Use TYPE_MAIN_VARIANT to find the
-   main variant.  */
+/* Given a type node TYPE and a TYPE_QUALIFIER_SET, return a type for
+   the same kind of data as TYPE describes.  Variants point to the
+   "main variant" (which has no qualifiers set) via TYPE_MAIN_VARIANT,
+   and it points to a chain of other variants so that duplicate
+   variants are never made.  Only main variants should ever appear as
+   types of expressions.  */
 
 tree
-build_type_variant (type, constp, volatilep)
+build_qualified_type (type, type_quals)
      tree type;
-     int constp, volatilep;
+     int type_quals;
 {
   register tree t;
-
-  /* Treat any nonzero argument as 1.  */
-  constp = !!constp;
-  volatilep = !!volatilep;
-
+  
   /* Search the chain of variants to see if there is already one there just
      like the one we need to have.  If so, use that existing one.  We must
      preserve the TYPE_NAME, since there is code that depends on this.  */
 
   for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
-    if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t)
-       && TYPE_NAME (t) == TYPE_NAME (type))
+    if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type))
       return t;
 
   /* We need a new one.  */
-
   t = build_type_copy (type);
-  TYPE_READONLY (t) = constp;
-  TYPE_VOLATILE (t) = volatilep;
-
+  set_type_quals (t, type_quals);
   return t;
 }
 
@@ -3632,26 +3734,6 @@ build_type_copy (type)
 /* Hashing of types so that we don't make duplicates.
    The entry point is `type_hash_canon'.  */
 
-/* Each hash table slot is a bucket containing a chain
-   of these structures.  */
-
-struct type_hash
-{
-  struct type_hash *next;      /* Next structure in the bucket.  */
-  int hashcode;                        /* Hash code of this type.  */
-  tree type;                   /* The type recorded here.  */
-};
-
-/* Now here is the hash table.  When recording a type, it is added
-   to the slot whose index is the hash code mod the table size.
-   Note that the hash table is used for several kinds of types
-   (function types, array types and array index range types, for now).
-   While all these live in the same table, they are completely independent,
-   and the hash code is computed differently for each of these.  */
-
-#define TYPE_HASH_SIZE 59
-struct type_hash *type_hash_table[TYPE_HASH_SIZE];
-
 /* Compute a hash code for a list of types (chain of TREE_LIST nodes
    with types in the TREE_VALUE slots), by adding the hash codes
    of the individual types.  */
@@ -3676,12 +3758,18 @@ type_hash_lookup (hashcode, type)
      tree type;
 {
   register struct type_hash *h;
+
+  /* The TYPE_ALIGN field of a type is set by layout_type(), so we
+     must call that routine before comparing TYPE_ALIGNs. */
+  layout_type (type);
+
   for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
     if (h->hashcode == hashcode
        && TREE_CODE (h->type) == TREE_CODE (type)
        && TREE_TYPE (h->type) == TREE_TYPE (type)
         && attribute_list_equal (TYPE_ATTRIBUTES (h->type),
                                   TYPE_ATTRIBUTES (type))
+       && TYPE_ALIGN (h->type) == TYPE_ALIGN (type)
        && (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
            || tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
                                   TYPE_MAX_VALUE (type)))
@@ -3710,7 +3798,7 @@ type_hash_add (hashcode, type)
 {
   register struct type_hash *h;
 
-  h = (struct type_hash *) oballoc (sizeof (struct type_hash));
+  h = (struct type_hash *) permalloc (sizeof (struct type_hash));
   h->hashcode = hashcode;
   h->type = type;
   h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];
@@ -3744,7 +3832,8 @@ type_hash_canon (hashcode, type)
   t1 = type_hash_lookup (hashcode, type);
   if (t1 != 0)
     {
-      obstack_free (TYPE_OBSTACK (type), type);
+      if (!ggc_p)
+       obstack_free (TYPE_OBSTACK (type), type);
 #ifdef GATHER_STATISTICS
       tree_node_counts[(int)t_kind]--;
       tree_node_sizes[(int)t_kind] -= sizeof (struct tree_type);
@@ -3753,12 +3842,27 @@ type_hash_canon (hashcode, type)
     }
 
   /* If this is a permanent type, record it for later reuse.  */
-  if (TREE_PERMANENT (type))
+  if (ggc_p || TREE_PERMANENT (type))
     type_hash_add (hashcode, type);
 
   return type;
 }
 
+/* Mark ARG (which is really a struct type_hash **) for GC.  */
+
+static void
+mark_type_hash (arg)
+     void *arg;
+{
+  struct type_hash *t = *(struct type_hash **) arg;
+
+  while (t)
+    {
+      ggc_mark_tree (t->type);
+      t = t->next;
+    }
+}
+
 /* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
    with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
    by adding the hash codes of the individual attributes.  */
@@ -3944,10 +4048,13 @@ simple_cst_equal (t1, t2)
   code2 = TREE_CODE (t2);
 
   if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
-    if (code2 == NOP_EXPR || code2 == CONVERT_EXPR || code2 == NON_LVALUE_EXPR)
-      return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
-    else
-      return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
+    {
+      if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
+         || code2 == NON_LVALUE_EXPR)
+       return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+      else
+       return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
+    }
   else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
           || code2 == NON_LVALUE_EXPR)
     return simple_cst_equal (t1, TREE_OPERAND (t2, 0));
@@ -3970,7 +4077,10 @@ simple_cst_equal (t1, t2)
                  TREE_STRING_LENGTH (t1));
 
     case CONSTRUCTOR:
-      abort ();
+      if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2))
+       return 1;
+      else
+       abort ();
 
     case SAVE_EXPR:
       return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
@@ -4110,6 +4220,7 @@ build_index_type (maxval)
 
   TYPE_MODE (itype) = TYPE_MODE (sizetype);
   TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
+  TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
   TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
   if (TREE_CODE (maxval) == INTEGER_CST)
     {
@@ -4150,6 +4261,7 @@ build_range_type (type, lowval, highval)
   TYPE_PRECISION (itype) = TYPE_PRECISION (type);
   TYPE_MODE (itype) = TYPE_MODE (type);
   TYPE_SIZE (itype) = TYPE_SIZE (type);
+  TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
   TYPE_ALIGN (itype) = TYPE_ALIGN (type);
   if (TREE_CODE (lowval) == INTEGER_CST)
     {
@@ -4246,6 +4358,21 @@ build_array_type (elt_type, index_type)
   return t;
 }
 
+/* Return the TYPE of the elements comprising
+   the innermost dimension of ARRAY.  */
+
+tree
+get_inner_array_type (array)
+    tree array;
+{
+  tree type = TREE_TYPE (array);
+
+  while (TREE_CODE (type) == ARRAY_TYPE)
+    type = TREE_TYPE (type);
+
+  return type;
+}
+
 /* Construct, lay out and return
    the type of functions returning type VALUE_TYPE
    given arguments of types ARG_TYPES.
@@ -4386,8 +4513,7 @@ build_complex_type (component_type)
   t = make_node (COMPLEX_TYPE);
 
   TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
-  TYPE_VOLATILE (t) = TYPE_VOLATILE (component_type);
-  TYPE_READONLY (t) = TYPE_READONLY (component_type);
+  set_type_quals (t, TYPE_QUALS (component_type));
 
   /* If we already have such a type, use the old one and free this one.  */
   hashcode = TYPE_HASH (component_type);
@@ -4396,6 +4522,40 @@ build_complex_type (component_type)
   if (TYPE_SIZE (t) == 0)
     layout_type (t);
 
+  /* If we are writing Dwarf2 output we need to create a name,
+     since complex is a fundamental type.  */
+  if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
+    {
+      const char *name;
+      if (component_type == char_type_node)
+       name = "complex char";
+      else if (component_type == signed_char_type_node)
+       name = "complex signed char";
+      else if (component_type == unsigned_char_type_node)
+       name = "complex unsigned char";
+      else if (component_type == short_integer_type_node)
+       name = "complex short int";
+      else if (component_type == short_unsigned_type_node)
+       name = "complex short unsigned int";
+      else if (component_type == integer_type_node)
+       name = "complex int";
+      else if (component_type == unsigned_type_node)
+       name = "complex unsigned int";
+      else if (component_type == long_integer_type_node)
+       name = "complex long int";
+      else if (component_type == long_unsigned_type_node)
+       name = "complex long unsigned int";
+      else if (component_type == long_long_integer_type_node)
+       name = "complex long long int";
+      else if (component_type == long_long_unsigned_type_node)
+       name = "complex long long unsigned int";
+      else
+       name = (char *)0;
+
+      if (name)
+       TYPE_NAME (t) = get_identifier (name);
+    }
+
   return t;
 }
 \f
@@ -4428,8 +4588,6 @@ get_unwidened (op, for_type)
      tree for_type;
 {
   /* Set UNS initially if converting OP to FOR_TYPE is a zero-extension.  */
-  /* TYPE_PRECISION is safe in place of type_precision since
-     pointer types are not allowed.  */
   register tree type = TREE_TYPE (op);
   register unsigned final_prec
     = TYPE_PRECISION (for_type != 0 ? for_type : type);
@@ -4595,21 +4753,6 @@ get_narrower (op, unsignedp_ptr)
   return win;
 }
 \f
-/* Return the precision of a type, for arithmetic purposes.
-   Supports all types on which arithmetic is possible
-   (including pointer types).
-   It's not clear yet what will be right for complex types.  */
-
-int
-type_precision (type)
-     register tree type;
-{
-  return ((TREE_CODE (type) == INTEGER_TYPE
-          || TREE_CODE (type) == ENUMERAL_TYPE
-          || TREE_CODE (type) == REAL_TYPE)
-         ? TYPE_PRECISION (type) : POINTER_SIZE);
-}
-
 /* Nonzero if integer constant C has a value that is permissible
    for type TYPE (an INTEGER_TYPE).  */
 
@@ -4635,6 +4778,16 @@ int_fits_type_p (c, type)
                  && TREE_UNSIGNED (TREE_TYPE (c))));
 }
 
+/* Given a DECL or TYPE, return the scope in which it was declared, or
+   NUL_TREE if there is no containing scope.  */
+
+tree
+get_containing_scope (t)
+     tree t;
+{
+  return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
+}
+
 /* Return the innermost context enclosing DECL that is
    a FUNCTION_DECL, or zero if none.  */
 
@@ -4649,20 +4802,24 @@ decl_function_context (decl)
 
   if (TREE_CODE (decl) == SAVE_EXPR)
     context = SAVE_EXPR_CONTEXT (decl);
+  /* C++ virtual functions use DECL_CONTEXT for the class of the vtable
+     where we look up the function at runtime.  Such functions always take
+     a first argument of type 'pointer to real context'.
+
+     C++ should really be fixed to use DECL_CONTEXT for the real context,
+     and use something else for the "virtual context".  */
+  else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
+    context = TYPE_MAIN_VARIANT
+      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
   else
     context = DECL_CONTEXT (decl);
 
   while (context && TREE_CODE (context) != FUNCTION_DECL)
     {
-      if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-       context = TYPE_CONTEXT (context);
-      else if (TREE_CODE_CLASS (TREE_CODE (context)) == 'd')
-       context = DECL_CONTEXT (context);
-      else if (TREE_CODE (context) == BLOCK)
+      if (TREE_CODE (context) == BLOCK)
        context = BLOCK_SUPERCONTEXT (context);
-      else
-       /* Unhandled CONTEXT !?  */
-       abort ();
+      else 
+       context = get_containing_scope (context);
     }
 
   return context;
@@ -4696,37 +4853,40 @@ decl_type_context (decl)
   return NULL_TREE;
 }
 
-/* Print debugging information about the size of the
-   toplev_inline_obstacks.  */
+/* CALL is a CALL_EXPR.  Return the declaration for the function
+   called, or NULL_TREE if the called function cannot be 
+   determined.  */
 
-void
-print_inline_obstack_statistics ()
+tree
+get_callee_fndecl (call)
+     tree call;
 {
-  struct simple_obstack_stack *current = toplev_inline_obstacks;
-  int n_obstacks = 0;
-  int n_alloc = 0;
-  int n_chunks = 0;
+  tree addr;
 
-  for (; current; current = current->next, ++n_obstacks)
-    {
-      struct obstack *o = current->obstack;
-      struct _obstack_chunk *chunk = o->chunk;
+  /* It's invalid to call this function with anything but a
+     CALL_EXPR.  */
+  if (TREE_CODE (call) != CALL_EXPR)
+    abort ();
 
-      n_alloc += o->next_free - chunk->contents;
-      chunk = chunk->prev;
-      ++n_chunks;
-      for (; chunk; chunk = chunk->prev, ++n_chunks)
-       n_alloc += chunk->limit - &chunk->contents[0];
-    }
-  fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
-          n_obstacks, n_alloc, n_chunks);
+  /* The first operand to the CALL is the address of the function
+     called.  */
+  addr = TREE_OPERAND (call, 0);
+
+  /* If the address is just `&f' for some function `f', then we know
+     that `f' is being called.  */
+  if (TREE_CODE (addr) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
+    return TREE_OPERAND (addr, 0);
+
+  /* We couldn't figure out what was being called.  */
+  return NULL_TREE;
 }
 
 /* Print debugging information about the obstack O, named STR.  */
 
 void
 print_obstack_statistics (str, o)
-     char *str;
+     const char *str;
      struct obstack *o;
 {
   struct _obstack_chunk *chunk = o->chunk;
@@ -4780,54 +4940,116 @@ dump_tree_statistics ()
   print_obstack_statistics ("temporary_obstack", &temporary_obstack);
   print_obstack_statistics ("momentary_obstack", &momentary_obstack);
   print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
-  print_inline_obstack_statistics ();
   print_lang_statistics ();
 }
 \f
 #define FILE_FUNCTION_PREFIX_LEN 9
 
 #ifndef NO_DOLLAR_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_$D$%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_$%s$%s"
 #else /* NO_DOLLAR_IN_LABEL */
 #ifndef NO_DOT_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_.D.%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_.%s.%s"
 #else /* NO_DOT_IN_LABEL */
-#define FILE_FUNCTION_FORMAT "_GLOBAL__D_%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
 #endif /* NO_DOT_IN_LABEL */
 #endif /* NO_DOLLAR_IN_LABEL */
 
 extern char * first_global_object_name;
+extern char * weak_global_object_name;
 
-/* If KIND=='I', return a suitable global initializer (constructor) name.
-   If KIND=='D', return a suitable global clean-up (destructor) name.  */
+/* Appends 6 random characters to TEMPLATE to (hopefully) avoid name
+   clashes in cases where we can't reliably choose a unique name.
+
+   Derived from mkstemp.c in libiberty.  */
+
+static void
+append_random_chars (template)
+     char *template;
+{
+  static const char letters[]
+    = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+  static unsigned HOST_WIDE_INT value;
+  unsigned HOST_WIDE_INT v;
+
+#ifdef HAVE_GETTIMEOFDAY
+  struct timeval tv;
+#endif
+
+  template += strlen (template);
+
+#ifdef HAVE_GETTIMEOFDAY
+  /* Get some more or less random data.  */
+  gettimeofday (&tv, NULL);
+  value += ((unsigned HOST_WIDE_INT) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
+#else
+  value += getpid ();
+#endif
+
+  v = value;
+
+  /* Fill in the random bits.  */
+  template[0] = letters[v % 62];
+  v /= 62;
+  template[1] = letters[v % 62];
+  v /= 62;
+  template[2] = letters[v % 62];
+  v /= 62;
+  template[3] = letters[v % 62];
+  v /= 62;
+  template[4] = letters[v % 62];
+  v /= 62;
+  template[5] = letters[v % 62];
+
+  template[6] = '\0';
+}
+
+/* Generate a name for a function unique to this translation unit.
+   TYPE is some string to identify the purpose of this function to the
+   linker or collect2.  */
 
 tree
-get_file_function_name (kind)
-     int kind;
+get_file_function_name_long (type)
+     const char *type;
 {
   char *buf;
   register char *p;
 
   if (first_global_object_name)
     p = first_global_object_name;
-  else if (main_input_filename)
-    p = main_input_filename;
   else
-    p = input_filename;
+    {
+      /* We don't have anything that we know to be unique to this translation
+        unit, so use what we do have and throw in some randomness.  */
+
+      const char *name = weak_global_object_name;
+      const char *file = main_input_filename;
 
-  buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p));
+      if (! name)
+       name = "";
+      if (! file)
+       file = input_filename;
+
+      p = (char *) alloca (7 + strlen (name) + strlen (file));
+
+      sprintf (p, "%s%s", name, file);
+      append_random_chars (p);
+    }
+
+  buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
+                        + strlen (type));
 
   /* Set up the name of the file-level functions we may need.  */
   /* Use a global object (which is already required to be unique over
      the program) rather than the file name (which imposes extra
      constraints).  -- Raeburn@MIT.EDU, 10 Jan 1990.  */
-  sprintf (buf, FILE_FUNCTION_FORMAT, p);
+  sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
 
   /* Don't need to pull weird characters out of global names.  */
   if (p != first_global_object_name)
     {
       for (p = buf+11; *p; p++)
-       if (! ((*p >= '0' && *p <= '9')
+       if (! ( ISDIGIT(*p)
 #if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
 #ifndef ASM_IDENTIFY_GCC       /* this is required if `.' is invalid -- k. raeburn */
               || *p == '.'
@@ -4839,15 +5061,28 @@ get_file_function_name (kind)
 #ifndef NO_DOT_IN_LABEL                /* this for `.'; unlikely, but...  */
               || *p == '.'
 #endif
-              || (*p >= 'A' && *p <= 'Z')
-              || (*p >= 'a' && *p <= 'z')))
+              || ISUPPER(*p)
+              || ISLOWER(*p)))
          *p = '_';
     }
 
-  buf[FILE_FUNCTION_PREFIX_LEN] = kind;
-
   return get_identifier (buf);
 }
+
+/* If KIND=='I', return a suitable global initializer (constructor) name.
+   If KIND=='D', return a suitable global clean-up (destructor) name.  */
+
+tree
+get_file_function_name (kind)
+     int kind;
+{
+  char p[2];
+  p[0] = kind;
+  p[1] = 0;
+
+  return get_file_function_name_long (p);
+}
+
 \f
 /* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
    The result is placed in BUFFER (which has length BIT_SIZE),
@@ -4944,3 +5179,246 @@ get_set_constructor_bytes (init, buffer, wd_size)
     }
   return non_const_bits;
 }
+\f
+#if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
+/* Complain that the tree code of NODE does not match the expected CODE.
+   FILE, LINE, and FUNCTION are of the caller.  */
+void
+tree_check_failed (node, code, file, line, function)
+     const tree node;
+     enum tree_code code;
+     const char *file;
+     int line;
+     const char *function;
+{
+  error ("Tree check: expected %s, have %s",
+        tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+  fancy_abort (file, line, function);
+}
+
+/* Similar to above, except that we check for a class of tree
+   code, given in CL.  */
+void
+tree_class_check_failed (node, cl, file, line, function)
+     const tree node;
+     char cl;
+     const char *file;
+     int line;
+     const char *function;
+{
+  error ("Tree check: expected class '%c', have '%c' (%s)",
+        cl, TREE_CODE_CLASS (TREE_CODE (node)),
+        tree_code_name[TREE_CODE (node)]);
+  fancy_abort (file, line, function);
+}
+
+#endif /* ENABLE_CHECKING */
+
+/* Return the alias set for T, which may be either a type or an
+   expression.  */
+
+int
+get_alias_set (t)
+     tree t;
+{
+  if (!flag_strict_aliasing || !lang_get_alias_set)
+    /* If we're not doing any lanaguage-specific alias analysis, just
+       assume everything aliases everything else.  */
+    return 0;
+  else
+    return (*lang_get_alias_set) (t);
+}
+
+/* Return a brand-new alias set.  */
+
+int
+new_alias_set ()
+{
+  static int last_alias_set;
+  if (flag_strict_aliasing)
+    return ++last_alias_set;
+  else
+    return 0;
+}
+\f
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* Create nodes for all integer types (and error_mark_node) using the sizes
+   of C datatypes.  The caller should call set_sizetype soon after calling
+   this function to select one of the types as sizetype.  */
+   
+void
+build_common_tree_nodes (signed_char)
+     int signed_char;
+{
+  error_mark_node = make_node (ERROR_MARK);
+  TREE_TYPE (error_mark_node) = error_mark_node;
+
+  /* Define both `signed char' and `unsigned char'.  */
+  signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+  unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+
+  /* Define `char', which is like either `signed char' or `unsigned char'
+     but not the same as either.  */
+  char_type_node
+    = (signed_char
+       ? make_signed_type (CHAR_TYPE_SIZE)
+       : make_unsigned_type (CHAR_TYPE_SIZE));
+
+  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+  integer_type_node = make_signed_type (INT_TYPE_SIZE);
+  /* Define an unsigned integer first.  make_unsigned_type and make_signed_type
+     both call set_sizetype for the first type that we create, and we want this
+     to be large enough to hold the sizes of various types until we switch to
+     the real sizetype.  */
+  unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+  long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+  long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+  long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+  long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+
+  intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
+  intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
+  intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
+  intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
+  intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+
+  unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+  unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
+  unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
+  unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
+  unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+}
+
+/* For type TYPE, fill in the proper type for TYPE_SIZE and
+   TYPE_SIZE_UNIT.  */
+static void
+fix_sizetype (type)
+     tree type;
+{
+  TREE_TYPE (TYPE_SIZE (type)) = bitsizetype;
+  TREE_TYPE (TYPE_SIZE_UNIT (type)) = sizetype;
+}
+
+/* Call this function after calling build_common_tree_nodes and set_sizetype.
+   It will fix the previously made nodes to have proper references to
+   sizetype, and it will create several other common tree nodes.  */
+void
+build_common_tree_nodes_2 (short_double)
+     int short_double;
+{
+  fix_sizetype (signed_char_type_node);
+  fix_sizetype (unsigned_char_type_node);
+  fix_sizetype (char_type_node);
+  fix_sizetype (short_integer_type_node);
+  fix_sizetype (short_unsigned_type_node);
+  fix_sizetype (integer_type_node);
+  fix_sizetype (unsigned_type_node);
+  fix_sizetype (long_unsigned_type_node);
+  fix_sizetype (long_integer_type_node);
+  fix_sizetype (long_long_integer_type_node);
+  fix_sizetype (long_long_unsigned_type_node);
+
+  fix_sizetype (intQI_type_node);
+  fix_sizetype (intHI_type_node);
+  fix_sizetype (intSI_type_node);
+  fix_sizetype (intDI_type_node);
+  fix_sizetype (intTI_type_node);
+  fix_sizetype (unsigned_intQI_type_node);
+  fix_sizetype (unsigned_intHI_type_node);
+  fix_sizetype (unsigned_intSI_type_node);
+  fix_sizetype (unsigned_intDI_type_node);
+  fix_sizetype (unsigned_intTI_type_node);
+
+  integer_zero_node = build_int_2 (0, 0);
+  TREE_TYPE (integer_zero_node) = integer_type_node;
+  integer_one_node = build_int_2 (1, 0);
+  TREE_TYPE (integer_one_node) = integer_type_node;
+
+  size_zero_node = build_int_2 (0, 0);
+  TREE_TYPE (size_zero_node) = sizetype;
+  size_one_node = build_int_2 (1, 0);
+  TREE_TYPE (size_one_node) = sizetype;
+
+  void_type_node = make_node (VOID_TYPE);
+  layout_type (void_type_node);        /* Uses size_zero_node */
+  /* We are not going to have real types in C with less than byte alignment,
+     so we might as well not have any types that claim to have it.  */
+  TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+
+  null_pointer_node = build_int_2 (0, 0);
+  TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+  layout_type (TREE_TYPE (null_pointer_node));
+
+  ptr_type_node = build_pointer_type (void_type_node);
+  const_ptr_type_node
+    = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+
+  float_type_node = make_node (REAL_TYPE);
+  TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+  layout_type (float_type_node);
+
+  double_type_node = make_node (REAL_TYPE);
+  if (short_double)
+    TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
+  else
+    TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+  layout_type (double_type_node);
+
+  long_double_type_node = make_node (REAL_TYPE);
+  TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+  layout_type (long_double_type_node);
+
+  complex_integer_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_integer_type_node) = integer_type_node;
+  layout_type (complex_integer_type_node);
+
+  complex_float_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_float_type_node) = float_type_node;
+  layout_type (complex_float_type_node);
+
+  complex_double_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_double_type_node) = double_type_node;
+  layout_type (complex_double_type_node);
+
+  complex_long_double_type_node = make_node (COMPLEX_TYPE);
+  TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+  layout_type (complex_long_double_type_node);
+
+#ifdef BUILD_VA_LIST_TYPE
+  BUILD_VA_LIST_TYPE(va_list_type_node);
+#else
+  va_list_type_node = ptr_type_node;
+#endif
+}