OSDN Git Service

* Make-lang.in (stmp-f2c.h): Don't configure the runtime
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index d754194..6812aa4 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 1988, 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 92-96, 1997 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 
 /* This file contains the low level primitives for operating on tree nodes,
@@ -36,15 +37,24 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "config.h"
 #include "flags.h"
 #include "tree.h"
+#include "except.h"
 #include "function.h"
 #include "obstack.h"
 #ifdef __STDC__
-#include "gstdarg.h"
+#include <stdarg.h>
 #else
-#include "gvarargs.h"
+#include <varargs.h>
 #endif
 #include <stdio.h>
 
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#ifdef NEED_DECLARATION_FREE
+extern void free PROTO((void *));
+#endif
+
 #define obstack_chunk_alloc xmalloc
 #define obstack_chunk_free free
 
@@ -66,6 +76,17 @@ 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;
+
+/* 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.
@@ -257,10 +278,13 @@ static int next_decl_uid;
 /* Unique id for next type created.  */
 static int next_type_uid = 1;
 
+/* Here is how primitive or already-canonicalized types' hash
+   codes are made.  */
+#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
+
 extern char *mode_name[];
 
 void gcc_obstack_init ();
-static tree stabilize_reference_1 ();
 \f
 /* Init the principal obstacks.  */
 
@@ -288,7 +312,7 @@ init_obstacks ()
   rtl_obstack = saveable_obstack = &permanent_obstack;
 
   /* Init the hash table of identifiers.  */
-  bzero (hash_table, sizeof hash_table);
+  bzero ((char *) hash_table, sizeof hash_table);
 }
 
 void
@@ -312,15 +336,20 @@ gcc_obstack_init (obstack)
 }
 
 /* Save all variables describing the current status into the structure *P.
-   This is used before starting a nested function.  */
+   This is used before starting a nested function.
+
+   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)
+save_tree_status (p, context)
      struct function *p;
+     tree context;
 {
   p->all_types_permanent = all_types_permanent;
   p->momentary_stack = momentary_stack;
   p->maybepermanent_firstobj = maybepermanent_firstobj;
+  p->temporary_firstobj = temporary_firstobj;
   p->momentary_firstobj = momentary_firstobj;
   p->momentary_function_firstobj = momentary_function_firstobj;
   p->function_obstack = function_obstack;
@@ -329,11 +358,42 @@ save_tree_status (p)
   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;
+       }
+
+      current = ((struct simple_obstack_stack *)
+                xmalloc (sizeof (struct simple_obstack_stack)));
 
-  /* 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;
+      current->obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
+      function_maybepermanent_obstack = current->obstack;
+      gcc_obstack_init (function_maybepermanent_obstack);
+
+      current->next = *head;
+      *head = current;
+    }      
+
+  maybepermanent_firstobj
+    = (char *) obstack_finish (function_maybepermanent_obstack);
 
   function_obstack = (struct obstack *) xmalloc (sizeof (struct obstack));
   gcc_obstack_init (function_obstack);
@@ -342,10 +402,9 @@ save_tree_status (p)
   expression_obstack = &permanent_obstack;
   rtl_obstack = saveable_obstack = &permanent_obstack;
 
+  temporary_firstobj = (char *) obstack_alloc (&temporary_obstack, 0);
   momentary_firstobj = (char *) obstack_finish (&momentary_obstack);
   momentary_function_firstobj = momentary_firstobj;
-  maybepermanent_firstobj
-    = (char *) obstack_finish (function_maybepermanent_obstack);
 }
 
 /* Restore all variables describing the current status from the structure *P.
@@ -363,15 +422,16 @@ restore_tree_status (p)
   /* 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.  */
+     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.  */
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
 
   obstack_free (function_obstack, 0);
   free (function_obstack);
 
+  temporary_firstobj = p->temporary_firstobj;
   momentary_firstobj = p->momentary_firstobj;
   momentary_function_firstobj = p->momentary_function_firstobj;
   maybepermanent_firstobj = p->maybepermanent_firstobj;
@@ -381,6 +441,7 @@ restore_tree_status (p)
   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.
@@ -397,6 +458,7 @@ 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
@@ -515,12 +577,26 @@ permanent_allocation (function_end)
   /* Free up previous temporary obstack data */
   obstack_free (&temporary_obstack, temporary_firstobj);
   if (function_end)
-    obstack_free (&momentary_obstack, momentary_function_firstobj);
+    {
+      obstack_free (&momentary_obstack, momentary_function_firstobj);
+      momentary_firstobj = momentary_function_firstobj;
+    }
   else
     obstack_free (&momentary_obstack, momentary_firstobj);
-  obstack_free (&maybepermanent_obstack, maybepermanent_firstobj);
+  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;
@@ -628,6 +704,16 @@ savealloc (size)
 {
   return (char *) obstack_alloc (saveable_obstack, size);
 }
+
+/* Allocate SIZE bytes in the expression obstack
+   and return a pointer to them.  */
+
+char *
+expralloc (size)
+     int size;
+{
+  return (char *) obstack_alloc (expression_obstack, size);
+}
 \f
 /* Print out which obstack an object is in.  */
 
@@ -686,7 +772,7 @@ print_obstack_name (object, file, prefix)
       obstack_name = "temp_decl_obstack";
     }
 
-  /* Check to see if the object is in the free area of the obstack. */
+  /* Check to see if the object is in the free area of the obstack.  */
   if (obstack != NULL)
     {
       if (object >= obstack->next_free
@@ -737,6 +823,15 @@ push_momentary ()
   expression_obstack = &momentary_obstack;
 }
 
+/* Set things up so the next clear_momentary will only clear memory
+   past our present position in momentary_obstack.  */
+
+void
+preserve_momentary ()
+{
+  momentary_stack->base = (char *) obstack_base (&momentary_obstack);
+}
+
 /* Free all the storage in the current momentary-allocation level.
    In C, this happens at the end of each statement.  */
 
@@ -808,11 +903,11 @@ init_tree_codes ()
   tree_code_type = (char **) xmalloc (sizeof (standard_tree_code_type));
   tree_code_length = (int *) xmalloc (sizeof (standard_tree_code_length));
   tree_code_name = (char **) xmalloc (sizeof (standard_tree_code_name));
-  bcopy (standard_tree_code_type, tree_code_type,
+  bcopy ((char *) standard_tree_code_type, (char *) tree_code_type,
         sizeof (standard_tree_code_type));
-  bcopy (standard_tree_code_length, tree_code_length,
+  bcopy ((char *) standard_tree_code_length, (char *) tree_code_length,
         sizeof (standard_tree_code_length));
-  bcopy (standard_tree_code_name, tree_code_name,
+  bcopy ((char *) standard_tree_code_name, (char *) tree_code_name,
         sizeof (standard_tree_code_name));
 }
 
@@ -848,11 +943,11 @@ make_node (code)
       /* PARM_DECLs go on the context of the parent. If this is a nested
         function, then we must allocate the PARM_DECL on the parent's
         obstack, so that they will live to the end of the parent's
-        closing brace.  This is neccesary in case we try to inline the
+        closing brace.  This is necessary in case we try to inline the
         function into its parent.
 
         PARM_DECLs of top-level functions do not have this problem.  However,
-        we allocate them where we put the FUNCTION_DECL for languauges such as
+        we allocate them where we put the FUNCTION_DECL for languages such as
         Ada that need to consult some flags in the PARM_DECLs of the function
         when calling it. 
 
@@ -999,6 +1094,10 @@ make_node (code)
       TYPE_ALIGN (t) = 1;
       TYPE_MAIN_VARIANT (t) = t;
       TYPE_OBSTACK (t) = obstack;
+      TYPE_ATTRIBUTES (t) = NULL_TREE;
+#ifdef SET_DEFAULT_TYPE_ATTRIBUTES
+      SET_DEFAULT_TYPE_ATTRIBUTES (t);
+#endif
       break;
 
     case 'c':
@@ -1052,15 +1151,13 @@ copy_node (node)
         for REAL_CST, since the number of words is machine-dependent due
         to varying size and alignment of `double'.  */
       if (code == INTEGER_CST)
-        {
-          length = sizeof (struct tree_int_cst);
-          break;
-        }
+       length = sizeof (struct tree_int_cst);
       else if (code == REAL_CST)
-       {
-         length = sizeof (struct tree_real_cst);
-         break;
-       }
+       length = sizeof (struct tree_real_cst);
+      else
+       length = (sizeof (struct tree_common)
+                 + tree_code_length[(int) code] * sizeof (char *));
+      break;
 
     case 'x':  /* something random, like an identifier.  */
       length = sizeof (struct tree_common)
@@ -1078,6 +1175,7 @@ copy_node (node)
     ((char *) t)[i] = ((char *) node)[i];
 
   TREE_CHAIN (t) = 0;
+  TREE_ASM_WRITTEN (t) = 0;
 
   if (TREE_CODE_CLASS (code) == 'd')
     DECL_UID (t) = next_decl_uid++;
@@ -1085,6 +1183,14 @@ copy_node (node)
     {
       TYPE_UID (t) = next_type_uid++;
       TYPE_OBSTACK (t) = current_obstack;
+
+      /* The following is so that the debug code for
+        the copy is different from the original type.
+        The two statements usually duplicate each other
+        (because they clear fields of the same union),
+        but the optimizer should catch that.  */
+      TYPE_SYMTAB_POINTER (t) = 0;
+      TYPE_SYMTAB_ADDRESS (t) = 0;
     }
 
   TREE_PERMANENT (t) = (current_obstack == &permanent_obstack);
@@ -1140,9 +1246,9 @@ get_identifier (text)
     hash_len = id_clash_len;
 
   /* Compute hash code */
-  hi = hash_len * 613 + (unsigned)text[0];
+  hi = hash_len * 613 + (unsigned) text[0];
   for (i = 1; i < hash_len; i += 2)
-    hi = ((hi * 613) + (unsigned)(text[i]));
+    hi = ((hi * 613) + (unsigned) (text[i]));
 
   hi &= (1 << HASHBITS) - 1;
   hi %= MAX_HASH_TABLE;
@@ -1181,6 +1287,45 @@ get_identifier (text)
   return idp;                  /* <-- return if created */
 }
 
+/* If an identifier with the name TEXT (a null-terminated string) has
+   previously been referred to, return that node; otherwise return
+   NULL_TREE.  */
+
+tree
+maybe_get_identifier (text)
+     register char *text;
+{
+  register int hi;
+  register int i;
+  register tree idp;
+  register int len, hash_len;
+
+  /* Compute length of text in len.  */
+  for (len = 0; text[len]; len++);
+
+  /* Decide how much of that length to hash on */
+  hash_len = len;
+  if (warn_id_clash && len > id_clash_len)
+    hash_len = id_clash_len;
+
+  /* Compute hash code */
+  hi = hash_len * 613 + (unsigned) text[0];
+  for (i = 1; i < hash_len; i += 2)
+    hi = ((hi * 613) + (unsigned) (text[i]));
+
+  hi &= (1 << HASHBITS) - 1;
+  hi %= MAX_HASH_TABLE;
+  
+  /* Search table for identifier */
+  for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
+    if (IDENTIFIER_LENGTH (idp) == len
+       && IDENTIFIER_POINTER (idp)[0] == text[0]
+       && !bcmp (IDENTIFIER_POINTER (idp), text, len))
+      return idp;              /* <-- return if found */
+
+  return NULL_TREE;
+}
+
 /* Enable warnings on similar identifiers (if requested).
    Done after the built-in identifiers are created.  */
 
@@ -1228,16 +1373,18 @@ build_real (type, d)
      REAL_VALUE_TYPE d;
 {
   tree v;
+  int overflow = 0;
 
   /* Check for valid float value for this type on this target machine;
      if not, can print error message and store a valid value in D.  */
 #ifdef CHECK_FLOAT_VALUE
-  CHECK_FLOAT_VALUE (TYPE_MODE (type), d);
+  CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
 #endif
 
   v = make_node (REAL_CST);
   TREE_TYPE (v) = type;
   TREE_REAL_CST (v) = d;
+  TREE_OVERFLOW (v) = TREE_CONSTANT_OVERFLOW (v) = overflow;
   return v;
 }
 
@@ -1247,8 +1394,8 @@ build_real (type, d)
 #if !defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC)
 
 REAL_VALUE_TYPE
-real_value_from_int_cst (i)
-     tree i;
+real_value_from_int_cst (type, i)
+     tree type, i;
 {
   REAL_VALUE_TYPE d;
   REAL_VALUE_TYPE e;
@@ -1257,9 +1404,11 @@ real_value_from_int_cst (i)
 
 #ifdef REAL_ARITHMETIC
   if (! TREE_UNSIGNED (TREE_TYPE (i)))
-    REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i));
+    REAL_VALUE_FROM_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i),
+                        TYPE_MODE (type));
   else
-    REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i), TREE_INT_CST_HIGH (i));
+    REAL_VALUE_FROM_UNSIGNED_INT (d, TREE_INT_CST_LOW (i),
+                                 TREE_INT_CST_HIGH (i), TYPE_MODE (type));
 #else /* not REAL_ARITHMETIC */
   if (TREE_INT_CST_HIGH (i) < 0 && ! TREE_UNSIGNED (TREE_TYPE (i)))
     {
@@ -1309,7 +1458,12 @@ build_real_from_int_cst (type, i)
 
   set_float_handler (float_error);
 
-  d = REAL_VALUE_TRUNCATE (TYPE_MODE (type), real_value_from_int_cst (i));
+#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.  */
 
@@ -1348,18 +1502,19 @@ build_string (len, str)
 
 /* Return a newly constructed COMPLEX_CST node whose value is
    specified by the real and imaginary parts REAL and IMAG.
-   Both REAL and IMAG should be constant nodes.
-   The TREE_TYPE is not initialized.  */
+   Both REAL and IMAG should be constant nodes.  TYPE, if specified,
+   will be the type of the COMPLEX_CST; otherwise a new type will be made.  */
 
 tree
-build_complex (real, imag)
+build_complex (type, real, imag)
+     tree type;
      tree real, imag;
 {
   register tree t = make_node (COMPLEX_CST);
 
   TREE_REALPART (t) = real;
   TREE_IMAGPART (t) = imag;
-  TREE_TYPE (t) = build_complex_type (TREE_TYPE (real));
+  TREE_TYPE (t) = type ? type : build_complex_type (TREE_TYPE (real));
   TREE_OVERFLOW (t) = TREE_OVERFLOW (real) | TREE_OVERFLOW (imag);
   TREE_CONSTANT_OVERFLOW (t)
     = TREE_CONSTANT_OVERFLOW (real) | TREE_CONSTANT_OVERFLOW (imag);
@@ -1367,6 +1522,7 @@ build_complex (real, imag)
 }
 
 /* Build a newly constructed TREE_VEC node of length LEN.  */
+
 tree
 make_tree_vec (len)
      int len;
@@ -1394,7 +1550,8 @@ make_tree_vec (len)
   return t;
 }
 \f
-/* Return 1 if EXPR is the integer constant zero.  */
+/* Return 1 if EXPR is the integer constant zero or a complex constant
+   of zero.  */
 
 int
 integer_zerop (expr)
@@ -1402,12 +1559,17 @@ integer_zerop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == INTEGER_CST
-         && TREE_INT_CST_LOW (expr) == 0
-         && TREE_INT_CST_HIGH (expr) == 0);
+  return ((TREE_CODE (expr) == INTEGER_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && TREE_INT_CST_LOW (expr) == 0
+          && TREE_INT_CST_HIGH (expr) == 0)
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && integer_zerop (TREE_REALPART (expr))
+             && integer_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is the integer constant one.  */
+/* Return 1 if EXPR is the integer constant one or the corresponding
+   complex constant.  */
 
 int
 integer_onep (expr)
@@ -1415,13 +1577,17 @@ integer_onep (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == INTEGER_CST
-         && TREE_INT_CST_LOW (expr) == 1
-         && TREE_INT_CST_HIGH (expr) == 0);
+  return ((TREE_CODE (expr) == INTEGER_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && TREE_INT_CST_LOW (expr) == 1
+          && TREE_INT_CST_HIGH (expr) == 0)
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && integer_onep (TREE_REALPART (expr))
+             && integer_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is an integer containing all 1's
-   in as much precision as it contains.  */
+/* Return 1 if EXPR is an integer containing all 1's in as much precision as
+   it contains.  Likewise for the corresponding complex constant.  */
 
 int
 integer_all_onesp (expr)
@@ -1432,14 +1598,22 @@ integer_all_onesp (expr)
 
   STRIP_NOPS (expr);
 
-  if (TREE_CODE (expr) != INTEGER_CST)
+  if (TREE_CODE (expr) == COMPLEX_CST
+      && integer_all_onesp (TREE_REALPART (expr))
+      && integer_zerop (TREE_IMAGPART (expr)))
+    return 1;
+
+  else if (TREE_CODE (expr) != INTEGER_CST
+          || TREE_CONSTANT_OVERFLOW (expr))
     return 0;
 
   uns = TREE_UNSIGNED (TREE_TYPE (expr));
   if (!uns)
     return TREE_INT_CST_LOW (expr) == -1 && TREE_INT_CST_HIGH (expr) == -1;
 
-  prec = TYPE_PRECISION (TREE_TYPE (expr));
+  /* Note that using TYPE_PRECISION here is wrong.  We care about the
+     actual bits, not the (arbitrary) range of the type.  */
+  prec = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (expr)));
   if (prec >= HOST_BITS_PER_WIDE_INT)
     {
       int high_value, shift_amount;
@@ -1470,16 +1644,38 @@ int
 integer_pow2p (expr)
      tree expr;
 {
+  int prec;
   HOST_WIDE_INT high, low;
 
   STRIP_NOPS (expr);
 
-  if (TREE_CODE (expr) != INTEGER_CST)
+  if (TREE_CODE (expr) == COMPLEX_CST
+      && integer_pow2p (TREE_REALPART (expr))
+      && integer_zerop (TREE_IMAGPART (expr)))
+    return 1;
+
+  if (TREE_CODE (expr) != INTEGER_CST || TREE_CONSTANT_OVERFLOW (expr))
     return 0;
 
+  prec = (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+         ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
   high = TREE_INT_CST_HIGH (expr);
   low = TREE_INT_CST_LOW (expr);
 
+  /* First clear all bits that are beyond the type's precision in case
+     we've been sign extended.  */
+
+  if (prec == 2 * HOST_BITS_PER_WIDE_INT)
+    ;
+  else if (prec > HOST_BITS_PER_WIDE_INT)
+    high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+  else
+    {
+      high = 0;
+      if (prec < HOST_BITS_PER_WIDE_INT)
+       low &= ~((HOST_WIDE_INT) (-1) << prec);
+    }
+
   if (high == 0 && low == 0)
     return 0;
 
@@ -1487,6 +1683,45 @@ integer_pow2p (expr)
          || (low == 0 && (high & (high - 1)) == 0));
 }
 
+/* Return the power of two represented by a tree node known to be a
+   power of two.  */
+
+int
+tree_log2 (expr)
+     tree expr;
+{
+  int prec;
+  HOST_WIDE_INT high, low;
+
+  STRIP_NOPS (expr);
+
+  if (TREE_CODE (expr) == COMPLEX_CST)
+    return tree_log2 (TREE_REALPART (expr));
+
+  prec = (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+         ? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
+
+  high = TREE_INT_CST_HIGH (expr);
+  low = TREE_INT_CST_LOW (expr);
+
+  /* First clear all bits that are beyond the type's precision in case
+     we've been sign extended.  */
+
+  if (prec == 2 * HOST_BITS_PER_WIDE_INT)
+    ;
+  else if (prec > HOST_BITS_PER_WIDE_INT)
+    high &= ~((HOST_WIDE_INT) (-1) << (prec - HOST_BITS_PER_WIDE_INT));
+  else
+    {
+      high = 0;
+      if (prec < HOST_BITS_PER_WIDE_INT)
+       low &= ~((HOST_WIDE_INT) (-1) << prec);
+    }
+
+  return (high != 0 ? HOST_BITS_PER_WIDE_INT + exact_log2 (high)
+         :  exact_log2 (low));
+}
+
 /* Return 1 if EXPR is the real constant zero.  */
 
 int
@@ -1495,11 +1730,15 @@ real_zerop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0));
+  return ((TREE_CODE (expr) == REAL_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst0))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_zerop (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
-/* Return 1 if EXPR is the real constant one.  */
+/* Return 1 if EXPR is the real constant one in real or complex form.  */
 
 int
 real_onep (expr)
@@ -1507,8 +1746,12 @@ real_onep (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1));
+  return ((TREE_CODE (expr) == REAL_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst1))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_onep (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
 /* Return 1 if EXPR is the real constant two.  */
@@ -1519,8 +1762,12 @@ real_twop (expr)
 {
   STRIP_NOPS (expr);
 
-  return (TREE_CODE (expr) == REAL_CST
-         && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2));
+  return ((TREE_CODE (expr) == REAL_CST
+          && ! TREE_CONSTANT_OVERFLOW (expr)
+          && REAL_VALUES_EQUAL (TREE_REAL_CST (expr), dconst2))
+         || (TREE_CODE (expr) == COMPLEX_CST
+             && real_twop (TREE_REALPART (expr))
+             && real_zerop (TREE_IMAGPART (expr))));
 }
 
 /* Nonzero if EXP is a constant or a cast of a constant.  */
@@ -1538,7 +1785,7 @@ really_constant_p (exp)
 }
 \f
 /* Return first list element whose TREE_VALUE is ELEM.
-   Return 0 if ELEM is not it LIST.  */
+   Return 0 if ELEM is not in LIST.  */
 
 tree
 value_member (elem, list)
@@ -1554,7 +1801,7 @@ value_member (elem, list)
 }
 
 /* Return first list element whose TREE_PURPOSE is ELEM.
-   Return 0 if ELEM is not it LIST.  */
+   Return 0 if ELEM is not in LIST.  */
 
 tree
 purpose_member (elem, list)
@@ -1570,7 +1817,7 @@ purpose_member (elem, list)
 }
 
 /* Return first list element whose BINFO_TYPE is ELEM.
-   Return 0 if ELEM is not it LIST.  */
+   Return 0 if ELEM is not in LIST.  */
 
 tree
 binfo_member (elem, list)
@@ -1601,6 +1848,46 @@ chain_member (elem, chain)
   return 0;
 }
 
+/* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
+   chain CHAIN.  */
+/* ??? This function was added for machine specific attributes but is no
+   longer used.  It could be deleted if we could confirm all front ends
+   don't use it.  */
+
+int
+chain_member_value (elem, chain)
+     tree elem, chain;
+{
+  while (chain)
+    {
+      if (elem == TREE_VALUE (chain))
+       return 1;
+      chain = TREE_CHAIN (chain);
+    }
+
+  return 0;
+}
+
+/* Return nonzero if ELEM is equal to TREE_PURPOSE (CHAIN)
+   for any piece of chain CHAIN.  */
+/* ??? This function was added for machine specific attributes but is no
+   longer used.  It could be deleted if we could confirm all front ends
+   don't use it.  */
+
+int
+chain_member_purpose (elem, chain)
+     tree elem, chain;
+{
+  while (chain)
+    {
+      if (elem == TREE_PURPOSE (chain))
+       return 1;
+      chain = TREE_CHAIN (chain);
+    }
+
+  return 0;
+}
+
 /* Return the length of a chain of nodes chained through TREE_CHAIN.
    We expect a null pointer to mark the end of the chain.
    This is the Lisp primitive `length'.  */
@@ -1725,6 +2012,20 @@ build_decl_list (parm, value)
   return node;
 }
 
+/* Similar, but build on the expression_obstack.  */
+
+tree
+build_expr_list (parm, value)
+     tree parm, value;
+{
+  register tree node;
+  register struct obstack *ambient_obstack = current_obstack;
+  current_obstack = expression_obstack;
+  node = build_tree_list (parm, value);
+  current_obstack = ambient_obstack;
+  return node;
+}
+
 /* Return a newly created TREE_LIST node whose
    purpose and value fields are PARM and VALUE
    and whose TREE_CHAIN is CHAIN.  */
@@ -1771,6 +2072,20 @@ decl_tree_cons (purpose, value, chain)
   return node;
 }
 
+/* Similar, but build on the expression_obstack.  */
+
+tree
+expr_tree_cons (purpose, value, chain)
+     tree purpose, value, chain;
+{
+  register tree node;
+  register struct obstack *ambient_obstack = current_obstack;
+  current_obstack = expression_obstack;
+  node = tree_cons (purpose, value, chain);
+  current_obstack = ambient_obstack;
+  return node;
+}
+
 /* Same as `tree_cons' but make a permanent object.  */
 
 tree
@@ -1869,19 +2184,49 @@ int_size_in_bytes (type)
 }
 \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.  */
+   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.  */
 
 tree
 array_type_nelts (type)
      tree type;
 {
-  tree index_type = TYPE_DOMAIN (type);
+  tree index_type, min, max;
 
-  return (integer_zerop (TYPE_MIN_VALUE (index_type))
-         ? TYPE_MAX_VALUE (index_type)
-         : fold (build (MINUS_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)),
-                        TYPE_MAX_VALUE (index_type),
-                        TYPE_MIN_VALUE (index_type))));
+  /* If they did it with unspecified bounds, then we should have already
+     given an error about it before we got here.  */
+  if (! TYPE_DOMAIN (type))
+    return error_mark_node;
+
+  index_type = TYPE_DOMAIN (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)));
 }
 \f
 /* Return nonzero if arg is static -- a reference to an object in
@@ -1893,8 +2238,11 @@ staticp (arg)
 {
   switch (TREE_CODE (arg))
     {
-    case VAR_DECL:
     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);
+    case VAR_DECL:
       return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
 
     case CONSTRUCTOR:
@@ -1903,12 +2251,22 @@ staticp (arg)
     case STRING_CST:
       return 1;
 
+      /* If we are referencing a bitfield, we can't evaluate an
+        ADDR_EXPR at compile time and so it isn't a constant.  */
     case COMPONENT_REF:
+      return (! DECL_BIT_FIELD (TREE_OPERAND (arg, 1))
+             && staticp (TREE_OPERAND (arg, 0)));
+
     case BIT_FIELD_REF:
-      return staticp (TREE_OPERAND (arg, 0));
+      return 0;
 
+#if 0
+       /* This case is technically correct, but results in setting
+         TREE_CONSTANT on ADDR_EXPRs that cannot be evaluated at
+         compile time.  */
     case INDIRECT_REF:
       return TREE_CONSTANT (TREE_OPERAND (arg, 0));
+#endif
 
     case ARRAY_REF:
       if (TREE_CODE (TYPE_SIZE (TREE_TYPE (arg))) == INTEGER_CST
@@ -1956,10 +2314,10 @@ save_expr (expr)
      fact (i.e. this allows further folding, and direct checks for constants).
      However, a read-only object that has side effects cannot be bypassed.
      Since it is no problem to reevaluate literals, we just return the 
-     literal node. */
+     literal node.  */
 
   if (TREE_CONSTANT (t) || (TREE_READONLY (t) && ! TREE_SIDE_EFFECTS (t))
-      || TREE_CODE (t) == SAVE_EXPR)
+      || TREE_CODE (t) == SAVE_EXPR || TREE_CODE (t) == ERROR_MARK)
     return t;
 
   /* If T contains a PLACEHOLDER_EXPR, we must evaluate it each time, since
@@ -1982,53 +2340,165 @@ save_expr (expr)
   TREE_SIDE_EFFECTS (t) = 1;
   return t;
 }
+
+/* Arrange for an expression to be expanded multiple independent
+   times.  This is useful for cleanup actions, as the backend can
+   expand them multiple times in different places.  */
+
+tree
+unsave_expr (expr)
+     tree expr;
+{
+  tree t;
+
+  /* If this is already protected, no sense in protecting it again.  */
+  if (TREE_CODE (expr) == UNSAVE_EXPR)
+    return expr;
+
+  t = build1 (UNSAVE_EXPR, TREE_TYPE (expr), expr);
+  TREE_SIDE_EFFECTS (t) = TREE_SIDE_EFFECTS (expr);
+  return t;
+}
+
+/* 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;
+{
+  enum tree_code code;
+  register int i;
+  int first_rtl;
+
+  if (expr == NULL_TREE)
+    return expr;
+
+  code = TREE_CODE (expr);
+  first_rtl = tree_code_length [(int) code];
+  switch (code)
+    {
+    case SAVE_EXPR:
+      SAVE_EXPR_RTL (expr) = 0;
+      first_rtl = 2;
+      break;
+
+    case TARGET_EXPR:
+      TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3);
+      TREE_OPERAND (expr, 3) = NULL_TREE;
+      break;
+      
+    case RTL_EXPR:
+      /* I don't yet know how to emit a sequence multiple times.  */
+      if (RTL_EXPR_SEQUENCE (expr) != 0)
+       abort ();
+      first_rtl = 0;
+      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);
+           }
+       }
+      first_rtl = 2;
+      break;
+
+    case WITH_CLEANUP_EXPR:
+      /* Should be defined to be 2.  */
+      first_rtl = 1;
+      break;
+
+    case METHOD_CALL_EXPR:
+      first_rtl = 3;
+      break;
+    }
+
+  switch (TREE_CODE_CLASS (code))
+    {
+    case 'c':  /* a constant */
+    case 't':  /* a type node */
+    case 'x':  /* something random, like an identifier or an ERROR_MARK.  */
+    case 'd':  /* A decl node */
+    case 'b':  /* A block node */
+      return expr;
+
+    case 'e':  /* an expression */
+    case 'r':  /* a reference */
+    case 's':  /* an expression with side effects */
+    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;
+
+    default:
+      abort ();
+    }
+}
 \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.
-
-   Note that we only allow such expressions within simple arithmetic
-   or a COND_EXPR.  */
+   or offset that depends on a field within a record.  */
 
 int
 contains_placeholder_p (exp)
      tree exp;
 {
   register enum tree_code code = TREE_CODE (exp);
-  tree inner;
 
   /* If we have a WITH_RECORD_EXPR, it "cancels" any PLACEHOLDER_EXPR
      in it since it is supplying a value for it.  */
   if (code == WITH_RECORD_EXPR)
     return 0;
+  else if (code == PLACEHOLDER_EXPR)
+    return 1;
 
   switch (TREE_CODE_CLASS (code))
     {
     case 'r':
-      for (inner = TREE_OPERAND (exp, 0);
-          TREE_CODE_CLASS (TREE_CODE (inner)) == 'r';
-          inner = TREE_OPERAND (inner, 0))
-       ;
-      return TREE_CODE (inner) == PLACEHOLDER_EXPR;
+      /* Don't look at any PLACEHOLDER_EXPRs that might be in index or bit
+        position computations since they will be converted into a
+        WITH_RECORD_EXPR involving the reference, which will assume
+        here will be valid.  */
+      return contains_placeholder_p (TREE_OPERAND (exp, 0));
 
     case '1':
     case '2':  case '<':
     case 'e':
+      switch (code)
+       {
+       case COMPOUND_EXPR:
+         /* Ignoring the first operand isn't quite right, but works best. */
+         return contains_placeholder_p (TREE_OPERAND (exp, 1));
+
+       case RTL_EXPR:
+       case CONSTRUCTOR:
+         return 0;
+
+       case COND_EXPR:
+         return (contains_placeholder_p (TREE_OPERAND (exp, 0))
+                 || contains_placeholder_p (TREE_OPERAND (exp, 1))
+                 || contains_placeholder_p (TREE_OPERAND (exp, 2)));
+
+       case SAVE_EXPR:
+          return (SAVE_EXPR_RTL (exp) == 0
+                  && contains_placeholder_p (TREE_OPERAND (exp, 0)));
+       }
+
       switch (tree_code_length[(int) code])
        {
        case 1:
          return contains_placeholder_p (TREE_OPERAND (exp, 0));
        case 2:
-         return (code != RTL_EXPR
-                 && code != CONSTRUCTOR
-                 && ! (code == SAVE_EXPR && SAVE_EXPR_RTL (exp) != 0)
-                 && code != WITH_RECORD_EXPR
-                 && (contains_placeholder_p (TREE_OPERAND (exp, 0))
-                     || contains_placeholder_p (TREE_OPERAND (exp, 1))));
-       case 3:
-         return (code == COND_EXPR
-                 && (contains_placeholder_p (TREE_OPERAND (exp, 0))
-                     || contains_placeholder_p (TREE_OPERAND (exp, 1))
-                     || contains_placeholder_p (TREE_OPERAND (exp, 2))));
+         return (contains_placeholder_p (TREE_OPERAND (exp, 0))
+                 || contains_placeholder_p (TREE_OPERAND (exp, 1)));
        }
     }
 
@@ -2047,6 +2517,8 @@ substitute_in_expr (exp, f, r)
      tree r;
 {
   enum tree_code code = TREE_CODE (exp);
+  tree op0, op1, op2;
+  tree new = 0;
   tree inner;
 
   switch (TREE_CODE_CLASS (code))
@@ -2067,9 +2539,12 @@ substitute_in_expr (exp, f, r)
       switch (tree_code_length[(int) code])
        {
        case 1:
-         return fold (build1 (code, TREE_TYPE (exp),
-                              substitute_in_expr (TREE_OPERAND (exp, 0),
-                                                  f, r)));
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         if (op0 == TREE_OPERAND (exp, 0))
+           return exp;
+         
+         new = fold (build1 (code, TREE_TYPE (exp), op0));
+         break;
 
        case 2:
          /* An RTL_EXPR cannot contain a PLACEHOLDER_EXPR; a CONSTRUCTOR
@@ -2079,10 +2554,13 @@ substitute_in_expr (exp, f, r)
          else if (code == CONSTRUCTOR)
            abort ();
 
-         return fold (build (code, TREE_TYPE (exp),
-                             substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 1),
-                                                 f, r)));
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+         if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
+           return exp;
+
+         new = fold (build (code, TREE_TYPE (exp), op0, op1));
+         break;
 
        case 3:
          /* It cannot be that anything inside a SAVE_EXPR contains a
@@ -2093,11 +2571,14 @@ substitute_in_expr (exp, f, r)
          if (code != COND_EXPR)
            abort ();
 
-         return fold (build (code, TREE_TYPE (exp),
-                             substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 1), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 2),
-                                                 f, r)));
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+         op2 = substitute_in_expr (TREE_OPERAND (exp, 2), f, r);
+         if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+             && op2 == TREE_OPERAND (exp, 2))
+           return exp;
+
+         new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
        }
 
       break;
@@ -2116,169 +2597,48 @@ substitute_in_expr (exp, f, r)
              && TREE_OPERAND (exp, 1) == f)
            return r;
 
-         return fold (build (code, TREE_TYPE (exp),
-                             substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
-                             TREE_OPERAND (exp, 1)));
-       case BIT_FIELD_REF:
-         return fold (build (code, TREE_TYPE (exp),
-                             substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 1), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 2), f, r)));
-       case INDIRECT_REF:
-       case BUFFER_REF:
-         return fold (build1 (code, TREE_TYPE (exp),
-                              substitute_in_expr (TREE_OPERAND (exp, 0),
-                                                f, r)));
-       case OFFSET_REF:
-         return fold (build (code, TREE_TYPE (exp),
-                             substitute_in_expr (TREE_OPERAND (exp, 0), f, r),
-                             substitute_in_expr (TREE_OPERAND (exp, 1), f, r)));
-       }
-    }
+         /* If this expression hasn't been completed let, leave it 
+            alone.  */
+         if (TREE_CODE (inner) == PLACEHOLDER_EXPR
+             && TREE_TYPE (inner) == 0)
+           return exp;
 
-  /* If it wasn't one of the cases we handle, give up.  */
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         if (op0 == TREE_OPERAND (exp, 0))
+           return exp;
 
-  abort ();
-}
-\f
-/* Given a type T, a FIELD_DECL F, and a replacement value R,
-   return a new type with all size expressions that contain F
-   updated by replacing F with R.  */
+         new = fold (build (code, TREE_TYPE (exp), op0,
+                            TREE_OPERAND (exp, 1)));
+         break;
 
-tree
-substitute_in_type (t, f, r)
-     tree t, f, r;
-{
-  switch (TREE_CODE (t))
-    {
-    case POINTER_TYPE:
-    case VOID_TYPE:
-      return t;
-    case INTEGER_TYPE:
-    case ENUMERAL_TYPE:
-    case BOOLEAN_TYPE:
-    case CHAR_TYPE:
-      if ((TREE_CODE (TYPE_MIN_VALUE (t)) != INTEGER_CST
-          && contains_placeholder_p (TYPE_MIN_VALUE (t)))
-         || (TREE_CODE (TYPE_MAX_VALUE (t)) != INTEGER_CST
-             && contains_placeholder_p (TYPE_MAX_VALUE (t))))
-       return build_range_type (t,
-                                substitute_in_expr (TYPE_MIN_VALUE (t), f, r),
-                                substitute_in_expr (TYPE_MAX_VALUE (t), f, r));
-      return t;
+       case BIT_FIELD_REF:
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         op1 = substitute_in_expr (TREE_OPERAND (exp, 1), f, r);
+         op2 = substitute_in_expr (TREE_OPERAND (exp, 2), f, r);
+         if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
+             && op2 == TREE_OPERAND (exp, 2))
+           return exp;
 
-    case REAL_TYPE:
-      if ((TYPE_MIN_VALUE (t) != 0
-          && TREE_CODE (TYPE_MIN_VALUE (t)) != REAL_CST
-          && contains_placeholder_p (TYPE_MIN_VALUE (t)))
-         || (TYPE_MAX_VALUE (t) != 0
-             && TREE_CODE (TYPE_MAX_VALUE (t)) != REAL_CST
-             && contains_placeholder_p (TYPE_MAX_VALUE (t))))
-       {
-         t = build_type_copy (t);
+         new = fold (build (code, TREE_TYPE (exp), op0, op1, op2));
+         break;
 
-         if (TYPE_MIN_VALUE (t))
-           TYPE_MIN_VALUE (t) = substitute_in_expr (TYPE_MIN_VALUE (t), f, r);
-         if (TYPE_MAX_VALUE (t))
-           TYPE_MAX_VALUE (t) = substitute_in_expr (TYPE_MAX_VALUE (t), f, r);
-       }
-      return t;
+       case INDIRECT_REF:
+       case BUFFER_REF:
+         op0 = substitute_in_expr (TREE_OPERAND (exp, 0), f, r);
+         if (op0 == TREE_OPERAND (exp, 0))
+           return exp;
 
-    case COMPLEX_TYPE:
-      return build_complex_type (substitute_in_type (TREE_TYPE (t), f, r));
-
-    case OFFSET_TYPE:
-    case METHOD_TYPE:
-    case REFERENCE_TYPE:
-    case FILE_TYPE:
-    case SET_TYPE:
-    case FUNCTION_TYPE:
-    case LANG_TYPE:
-      /* Don't know how to do these yet.  */
-      abort ();
+         new = fold (build1 (code, TREE_TYPE (exp), op0));
+         break;
+       }
+    }
 
-    case ARRAY_TYPE:
-      t = build_array_type (substitute_in_type (TREE_TYPE (t), f, r),
-                           substitute_in_type (TYPE_DOMAIN (t), f, r));
-      TYPE_SIZE (t) = 0;
-      layout_type (t);
-      return t;
+  /* If it wasn't one of the cases we handle, give up.  */
+  if (new == 0)
+    abort ();
 
-    case RECORD_TYPE:
-    case UNION_TYPE:
-    case QUAL_UNION_TYPE:
-      {
-       tree new = copy_node (t);
-       tree field;
-       tree last_field = 0;
-
-       /* Start out with no fields, make new fields, and chain them
-          in.  */
-
-       TYPE_FIELDS (new) = 0;
-       TYPE_SIZE (new) = 0;
-
-       for (field = TYPE_FIELDS (t); field;
-            field = TREE_CHAIN (field))
-         {
-           tree new_field = copy_node (field);
-
-           TREE_TYPE (new_field)
-             = substitute_in_type (TREE_TYPE (new_field), f, r);
-
-           /* If this is an anonymous field and the type of this field is
-              a UNION_TYPE or RECORD_TYPE with no elements, ignore it.  If
-              the type just has one element, treat that as the field. 
-              But don't do this if we are processing a QUAL_UNION_TYPE.  */
-           if (TREE_CODE (t) != QUAL_UNION_TYPE && DECL_NAME (new_field) == 0
-               && (TREE_CODE (TREE_TYPE (new_field)) == UNION_TYPE
-                   || TREE_CODE (TREE_TYPE (new_field)) == RECORD_TYPE))
-             {
-               if (TYPE_FIELDS (TREE_TYPE (new_field)) == 0)
-                 continue;
-
-               if (TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (new_field))) == 0)
-                 new_field = TYPE_FIELDS (TREE_TYPE (new_field));
-             }
-
-           DECL_CONTEXT (new_field) = new;
-           DECL_SIZE (new_field) = 0;
-
-           if (TREE_CODE (t) == QUAL_UNION_TYPE)
-             {
-               /* Do the substitution inside the qualifier and if we find
-                  that this field will not be present, omit it.  */
-               DECL_QUALIFIER (new_field)
-                 = substitute_in_expr (DECL_QUALIFIER (field), f, r);
-               if (integer_zerop (DECL_QUALIFIER (new_field)))
-                 continue;
-             }
-
-           if (last_field == 0)
-             TYPE_FIELDS (new) = new_field;
-           else
-             TREE_CHAIN (last_field) = new_field;
-
-           last_field = new_field;
-
-           /* If this is a qualified type and this field will always be
-              present, we are done.  */
-           if (TREE_CODE (t) == QUAL_UNION_TYPE
-               && integer_onep (DECL_QUALIFIER (new_field)))
-             break;
-         }
-
-       /* If this used to be a qualified union type, but we now know what
-          field will be present, make this a normal union.  */
-       if (TREE_CODE (new) == QUAL_UNION_TYPE
-           && (TYPE_FIELDS (new) == 0
-               || integer_onep (DECL_QUALIFIER (TYPE_FIELDS (new)))))
-         TREE_SET_CODE (new, UNION_TYPE);
-
-       layout_type (new);
-       return new;
-      }
-    }
+  TREE_READONLY (new) = TREE_READONLY (exp);
+  return new;
 }
 \f
 /* Stabilize a reference so that we can use it any number of times
@@ -2338,6 +2698,20 @@ stabilize_reference (ref)
                         stabilize_reference_1 (TREE_OPERAND (ref, 1)));
       break;
 
+    case COMPOUND_EXPR:
+      /* We cannot wrap the first expression in a SAVE_EXPR, as then
+        it wouldn't be ignored.  This matters when dealing with
+        volatiles.  */
+      return stabilize_reference_1 (ref);
+
+    case RTL_EXPR:
+      result = build1 (INDIRECT_REF, TREE_TYPE (ref),
+                      save_expr (build1 (ADDR_EXPR,
+                                         build_pointer_type (TREE_TYPE (ref)),
+                                         ref)));
+      break;
+
+
       /* If arg isn't a kind of lvalue we recognize, make no change.
         Caller should recognize the error for an invalid lvalue.  */
     default:
@@ -2369,12 +2743,11 @@ stabilize_reference (ref)
    operator should be allowed, and that cse should take care of coalescing
    multiple utterances of the same expression should that prove fruitful.  */
 
-static tree
+tree
 stabilize_reference_1 (e)
      tree e;
 {
   register tree result;
-  register int length;
   register enum tree_code code = TREE_CODE (e);
 
   /* We cannot ignore const expressions because it might be a reference
@@ -2517,13 +2890,14 @@ build VPROTO((enum tree_code code, tree tt, ...))
 /* Same as above, but only builds for unary operators.
    Saves lions share of calls to `build'; cuts down use
    of varargs, which is expensive for RISC machines.  */
+
 tree
 build1 (code, type, node)
      enum tree_code code;
      tree type;
      tree node;
 {
-  register struct obstack *obstack = current_obstack;
+  register struct obstack *obstack = expression_obstack;
   register int i, length;
   register tree_node_kind kind;
   register tree t;
@@ -2535,7 +2909,6 @@ build1 (code, type, node)
     kind = e_kind;
 #endif
 
-  obstack = expression_obstack;
   length = sizeof (struct tree_exp);
 
   t = (tree) obstack_alloc (obstack, length);
@@ -2572,7 +2945,7 @@ build1 (code, type, node)
    or even garbage if their values do not matter.  */
 
 tree
-build_nt VPROTO((register enum tree_code code, ...))
+build_nt VPROTO((enum tree_code code, ...))
 {
 #ifndef __STDC__
   enum tree_code code;
@@ -2602,7 +2975,7 @@ build_nt VPROTO((register enum tree_code code, ...))
    on the temp_decl_obstack, regardless.  */
 
 tree
-build_parse_node VPROTO((register enum tree_code code, ...))
+build_parse_node VPROTO((enum tree_code code, ...))
 {
 #ifndef __STDC__
   enum tree_code code;
@@ -2695,6 +3068,279 @@ build_block (vars, tags, subblocks, supercontext, chain)
   return block;
 }
 \f
+/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
+   is ATTRIBUTE.  */
+
+tree
+build_decl_attribute_variant (ddecl, attribute)
+     tree ddecl, attribute;
+{
+  DECL_MACHINE_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_variant (ttype, attribute)
+     tree 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);
+
+      ntype = copy_node (ttype);
+      current_obstack = ambient_obstack;
+
+      TYPE_POINTER_TO (ntype) = 0;
+      TYPE_REFERENCE_TO (ntype) = 0;
+      TYPE_ATTRIBUTES (ntype) = 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;
+
+      hashcode = TYPE_HASH (TREE_CODE (ntype))
+                + TYPE_HASH (TREE_TYPE (ntype))
+                + attribute_hash_list (attribute);
+
+      switch (TREE_CODE (ntype))
+        {
+         case FUNCTION_TYPE:
+           hashcode += TYPE_HASH (TYPE_ARG_TYPES (ntype));
+           break;
+         case ARRAY_TYPE:
+           hashcode += TYPE_HASH (TYPE_DOMAIN (ntype));
+           break;
+         case INTEGER_TYPE:
+           hashcode += TYPE_HASH (TYPE_MAX_VALUE (ntype));
+           break;
+         case REAL_TYPE:
+           hashcode += TYPE_HASH (TYPE_PRECISION (ntype));
+           break;
+        }
+
+      ntype = type_hash_canon (hashcode, ntype);
+      ttype = build_type_variant (ntype, TYPE_READONLY (ttype),
+                                 TYPE_VOLATILE (ttype));
+    }
+
+  return ttype;
+}
+
+/* Return a 1 if ATTR_NAME and ATTR_ARGS is valid for either declaration DECL
+   or type TYPE and 0 otherwise.  Validity is determined the configuration
+   macros VALID_MACHINE_DECL_ATTRIBUTE and VALID_MACHINE_TYPE_ATTRIBUTE.  */
+
+int
+valid_machine_attribute (attr_name, attr_args, decl, type)
+     tree attr_name, attr_args;
+     tree decl;
+     tree type;
+{
+  int valid = 0;
+  tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
+  tree type_attr_list = TYPE_ATTRIBUTES (type);
+
+  if (TREE_CODE (attr_name) != IDENTIFIER_NODE)
+    abort ();
+
+#ifdef VALID_MACHINE_DECL_ATTRIBUTE
+  if (decl != 0
+      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name, attr_args))
+    {
+      tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+                                   decl_attr_list);
+
+      if (attr != NULL_TREE)
+       {
+         /* Override existing arguments.  Declarations are unique so we can
+            modify this in place.  */
+         TREE_VALUE (attr) = attr_args;
+       }
+      else
+       {
+         decl_attr_list = tree_cons (attr_name, attr_args, decl_attr_list);
+         decl = build_decl_attribute_variant (decl, decl_attr_list);
+       }
+
+      valid = 1;
+    }
+#endif
+
+#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
+  if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name, attr_args))
+    {
+      tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+                                   type_attr_list);
+
+      if (attr != NULL_TREE)
+       {
+         /* Override existing arguments.
+            ??? This currently works since attribute arguments are not
+            included in `attribute_hash_list'.  Something more complicated
+            may be needed in the future.  */
+         TREE_VALUE (attr) = attr_args;
+       }
+      else
+       {
+         type_attr_list = tree_cons (attr_name, attr_args, type_attr_list);
+         type = build_type_attribute_variant (type, type_attr_list);
+       }
+      if (decl != 0)
+       TREE_TYPE (decl) = type;
+      valid = 1;
+    }
+
+  /* Handle putting a type attribute on pointer-to-function-type by putting
+     the attribute on the function type.  */
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
+          && VALID_MACHINE_TYPE_ATTRIBUTE (TREE_TYPE (type), type_attr_list,
+                                           attr_name, attr_args))
+    {
+      tree inner_type = TREE_TYPE (type);
+      tree inner_attr_list = TYPE_ATTRIBUTES (inner_type);
+      tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+                                   type_attr_list);
+
+      if (attr != NULL_TREE)
+       TREE_VALUE (attr) = attr_args;
+      else
+       {
+         inner_attr_list = tree_cons (attr_name, attr_args, inner_attr_list);
+         inner_type = build_type_attribute_variant (inner_type,
+                                                    inner_attr_list);
+       }
+
+      if (decl != 0)
+       TREE_TYPE (decl) = build_pointer_type (inner_type);
+
+      valid = 1;
+    }
+#endif
+
+  return valid;
+}
+
+/* Return non-zero if IDENT is a valid name for attribute ATTR,
+   or zero if not.
+
+   We try both `text' and `__text__', ATTR may be either one.  */
+/* ??? It might be a reasonable simplification to require ATTR to be only
+   `text'.  One might then also require attribute lists to be stored in
+   their canonicalized form.  */
+
+int
+is_attribute_p (attr, ident)
+     char *attr;
+     tree ident;
+{
+  int ident_len, attr_len;
+  char *p;
+
+  if (TREE_CODE (ident) != IDENTIFIER_NODE)
+    return 0;
+
+  if (strcmp (attr, IDENTIFIER_POINTER (ident)) == 0)
+    return 1;
+
+  p = IDENTIFIER_POINTER (ident);
+  ident_len = strlen (p);
+  attr_len = strlen (attr);
+
+  /* If ATTR is `__text__', IDENT must be `text'; and vice versa.  */
+  if (attr[0] == '_')
+    {
+      if (attr[1] != '_'
+         || attr[attr_len - 2] != '_'
+         || attr[attr_len - 1] != '_')
+       abort ();
+      if (ident_len == attr_len - 4
+         && strncmp (attr + 2, p, attr_len - 4) == 0)
+       return 1;
+    }
+  else
+    {
+      if (ident_len == attr_len + 4
+         && p[0] == '_' && p[1] == '_'
+         && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
+         && strncmp (attr, p + 2, attr_len) == 0)
+       return 1;
+    }
+
+  return 0;
+}
+
+/* Given an attribute name and a list of attributes, return a pointer to the
+   attribute's list element if the attribute is part of the list, or NULL_TREE
+   if not found.  */
+
+tree
+lookup_attribute (attr_name, list)
+     char *attr_name;
+     tree list;
+{
+  tree l;
+
+  for (l = list; l; l = TREE_CHAIN (l))
+    {
+      if (TREE_CODE (TREE_PURPOSE (l)) != IDENTIFIER_NODE)
+       abort ();
+      if (is_attribute_p (attr_name, TREE_PURPOSE (l)))
+       return l;
+    }
+
+  return NULL_TREE;
+}
+
+/* Return an attribute list that is the union of a1 and a2.  */
+
+tree
+merge_attributes (a1, a2)
+     register tree a1, a2;
+{
+  tree attributes;
+
+  /* Either one unset?  Take the set one.  */
+
+  if (! (attributes = a1))
+    attributes = a2;
+
+  /* One that completely contains the other?  Take it.  */
+
+  else if (a2 && ! attribute_list_contained (a1, a2))
+    if (attribute_list_contained (a2, a1))
+      attributes = a2;
+    else
+      {
+       /* Pick the longest list, and hang on the other list.  */
+       /* ??? For the moment we punt on the issue of attrs with args.  */
+
+       if (list_length (a1) < list_length (a2))
+         attributes = a2, a2 = a1;
+
+       for (; a2; a2 = TREE_CHAIN (a2))
+         if (lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (a2)),
+                               attributes) == NULL_TREE)
+           {
+             a1 = copy_node (a2);
+             TREE_CHAIN (a1) = attributes;
+             attributes = a1;
+           }
+      }
+  return attributes;
+}
+\f
 /* Return a type like TYPE except that its TYPE_READONLY is CONSTP
    and its TYPE_VOLATILE is VOLATILEP.
 
@@ -2719,19 +3365,14 @@ build_type_variant (type, constp, volatilep)
   constp = !!constp;
   volatilep = !!volatilep;
 
-  /* If not generating auxiliary info, 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.
+  /* 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.  */
 
-     We don't do this in the case where we are generating aux info because
-     in that case we want each typedef names to get it's own distinct type
-     node, even if the type of this new typedef is the same as some other
-     (existing) type.  */
-
-  if (!flag_gen_aux_info)
-    for (t = TYPE_MAIN_VARIANT(type); t; t = TYPE_NEXT_VARIANT (t))
-      if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t))
-        return t;
+  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))
+      return t;
 
   /* We need a new one.  */
 
@@ -2742,34 +3383,6 @@ build_type_variant (type, constp, volatilep)
   return t;
 }
 
-/* Give TYPE a new main variant: NEW_MAIN.
-   This is the right thing to do only when something else
-   about TYPE is modified in place.  */
-
-tree
-change_main_variant (type, new_main)
-     tree type, new_main;
-{
-  tree t;
-  tree omain = TYPE_MAIN_VARIANT (type);
-
-  /* Remove TYPE from the TYPE_NEXT_VARIANT chain of its main variant.  */
-  if (TYPE_NEXT_VARIANT (omain) == type)
-    TYPE_NEXT_VARIANT (omain) = TYPE_NEXT_VARIANT (type);
-  else
-    for (t = TYPE_NEXT_VARIANT (omain); t && TYPE_NEXT_VARIANT (t);
-        t = TYPE_NEXT_VARIANT (t))
-      if (TYPE_NEXT_VARIANT (t) == type)
-       {
-         TYPE_NEXT_VARIANT (t) = TYPE_NEXT_VARIANT (type);
-         break;
-       }
-
-  TYPE_MAIN_VARIANT (type) = new_main;
-  TYPE_NEXT_VARIANT (type) = TYPE_NEXT_VARIANT (new_main);
-  TYPE_NEXT_VARIANT (new_main) = type;
-}
-
 /* Create a new variant of TYPE, equivalent but distinct.
    This is so the caller can modify it.  */
 
@@ -2817,10 +3430,6 @@ struct type_hash
 #define TYPE_HASH_SIZE 59
 struct type_hash *type_hash_table[TYPE_HASH_SIZE];
 
-/* Here is how primitive or already-canonicalized types' hash
-   codes are made.  */
-#define TYPE_HASH(TYPE) ((HOST_WIDE_INT) (TYPE) & 0777777)
-
 /* 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.  */
@@ -2849,18 +3458,22 @@ type_hash_lookup (hashcode, type)
     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_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
            || tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
                                   TYPE_MAX_VALUE (type)))
        && (TYPE_MIN_VALUE (h->type) == TYPE_MIN_VALUE (type)
            || tree_int_cst_equal (TYPE_MIN_VALUE (h->type),
                                   TYPE_MIN_VALUE (type)))
+       /* Note that TYPE_DOMAIN is TYPE_ARG_TYPES for FUNCTION_TYPE.  */
        && (TYPE_DOMAIN (h->type) == TYPE_DOMAIN (type)
            || (TYPE_DOMAIN (h->type)
                && TREE_CODE (TYPE_DOMAIN (h->type)) == TREE_LIST
                && TYPE_DOMAIN (type)
                && TREE_CODE (TYPE_DOMAIN (type)) == TREE_LIST
-               && type_list_equal (TYPE_DOMAIN (h->type), TYPE_DOMAIN (type)))))
+               && type_list_equal (TYPE_DOMAIN (h->type),
+                                   TYPE_DOMAIN (type)))))
       return h->type;
   return 0;
 }
@@ -2924,6 +3537,76 @@ type_hash_canon (hashcode, type)
   return type;
 }
 
+/* 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.  */
+
+int
+attribute_hash_list (list)
+     tree list;
+{
+  register int hashcode;
+  register tree tail;
+  for (hashcode = 0, tail = list; tail; tail = TREE_CHAIN (tail))
+    /* ??? Do we want to add in TREE_VALUE too? */
+    hashcode += TYPE_HASH (TREE_PURPOSE (tail));
+  return hashcode;
+}
+
+/* Given two lists of attributes, return true if list l2 is
+   equivalent to l1.  */
+
+int
+attribute_list_equal (l1, l2)
+     tree l1, l2;
+{
+   return attribute_list_contained (l1, l2)
+         && attribute_list_contained (l2, l1);
+}
+
+/* Given two lists of attributes, return true if list L2 is
+   completely contained within L1.  */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+   must be used to show these elements are equivalent (which they are).  */
+/* ??? It's not clear that attributes with arguments will always be handled
+   correctly.  */
+
+int
+attribute_list_contained (l1, l2)
+     tree l1, l2;
+{
+  register tree t1, t2;
+
+  /* First check the obvious, maybe the lists are identical.  */
+  if (l1 == l2)
+     return 1;
+
+  /* Maybe the lists are similar.  */
+  for (t1 = l1, t2 = l2;
+       t1 && t2
+        && TREE_PURPOSE (t1) == TREE_PURPOSE (t2)
+        && TREE_VALUE (t1) == TREE_VALUE (t2);
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2));
+
+  /* Maybe the lists are equal.  */
+  if (t1 == 0 && t2 == 0)
+     return 1;
+
+  for (; t2; t2 = TREE_CHAIN (t2))
+    {
+      tree attr
+       = lookup_attribute (IDENTIFIER_POINTER (TREE_PURPOSE (t2)), l1);
+
+      if (attr == NULL_TREE)
+       return 0;
+      if (simple_cst_equal (TREE_VALUE (t2), TREE_VALUE (attr)) != 1)
+       return 0;
+    }
+
+  return 1;
+}
+
 /* Given two lists of types
    (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
    return 1 if the lists contain the same types in the same order.
@@ -2934,19 +3617,14 @@ type_list_equal (l1, l2)
      tree l1, l2;
 {
   register tree t1, t2;
+
   for (t1 = l1, t2 = l2; t1 && t2; t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-    {
-      if (TREE_VALUE (t1) != TREE_VALUE (t2))
-       return 0;
-      if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2))
-       {
-         int cmp = simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2));
-         if (cmp < 0)
-           abort ();
-         if (cmp == 0)
-           return 0;
-       }
-    }
+    if (TREE_VALUE (t1) != TREE_VALUE (t2)
+       || (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)
+           && ! (1 == simple_cst_equal (TREE_PURPOSE (t1), TREE_PURPOSE (t2))
+                 && (TREE_TYPE (TREE_PURPOSE (t1))
+                     == TREE_TYPE (TREE_PURPOSE (t2))))))
+      return 0;
 
   return t1 == t2;
 }
@@ -2985,21 +3663,40 @@ tree_int_cst_lt (t1, t2)
   return INT_CST_LT_UNSIGNED (t1, t2);
 }
 
-/* Compare two constructor-element-type constants.  */
+/* Return an indication of the sign of the integer constant T.
+   The return value is -1 if T < 0, 0 if T == 0, and 1 if T > 0.
+   Note that -1 will never be returned it T's type is unsigned.  */
+
+int
+tree_int_cst_sgn (t)
+     tree t;
+{
+  if (TREE_INT_CST_LOW (t) == 0 && TREE_INT_CST_HIGH (t) == 0)
+    return 0;
+  else if (TREE_UNSIGNED (TREE_TYPE (t)))
+    return 1;
+  else if (TREE_INT_CST_HIGH (t) < 0)
+    return -1;
+  else
+    return 1;
+}
+
+/* Compare two constructor-element-type constants.  Return 1 if the lists
+   are known to be equal; otherwise return 0.  */
+
 int
 simple_cst_list_equal (l1, l2)
      tree l1, l2;
 {
   while (l1 != NULL_TREE && l2 != NULL_TREE)
     {
-      int cmp = simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2));
-      if (cmp < 0)
-       abort ();
-      if (cmp == 0)
+      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
        return 0;
+
       l1 = TREE_CHAIN (l1);
       l2 = TREE_CHAIN (l2);
     }
+
   return (l1 == l2);
 }
 
@@ -3098,8 +3795,13 @@ simple_cst_equal (t1, t2)
       return 0;
     }
 
-  /* This general rule works for most tree codes.
-     All exceptions should be handled above.  */
+  /* This general rule works for most tree codes.  All exceptions should be
+     handled above.  If this is a language-specific tree code, we can't
+     trust what might be in the operand, so say we don't know
+     the situation.  */
+  if ((int) code1
+      >= sizeof standard_tree_code_type / sizeof standard_tree_code_type[0])
+    return -1;
 
   switch (TREE_CODE_CLASS (code1))
     {
@@ -3168,10 +3870,14 @@ build_index_type (maxval)
      tree maxval;
 {
   register tree itype = make_node (INTEGER_TYPE);
+
   TYPE_PRECISION (itype) = TYPE_PRECISION (sizetype);
-  TYPE_MIN_VALUE (itype) = build_int_2 (0, 0);
-  TREE_TYPE (TYPE_MIN_VALUE (itype)) = sizetype;
+  TYPE_MIN_VALUE (itype) = size_zero_node;
+
+  push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
   TYPE_MAX_VALUE (itype) = convert (sizetype, maxval);
+  pop_obstacks ();
+
   TYPE_MODE (itype) = TYPE_MODE (sizetype);
   TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
   TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
@@ -3194,19 +3900,24 @@ build_index_type (maxval)
 /* Create a range of some discrete type TYPE (an INTEGER_TYPE,
    ENUMERAL_TYPE, BOOLEAN_TYPE, or CHAR_TYPE), with
    low bound LOWVAL and high bound HIGHVAL.
-   if TYPE==NULL_TREE, sizetype is used. */
+   if TYPE==NULL_TREE, sizetype is used.  */
 
 tree
 build_range_type (type, lowval, highval)
      tree type, lowval, highval;
 {
   register tree itype = make_node (INTEGER_TYPE);
+
   TREE_TYPE (itype) = type;
   if (type == NULL_TREE)
     type = sizetype;
-  TYPE_PRECISION (itype) = TYPE_PRECISION (type);
+
+  push_obstacks (TYPE_OBSTACK (itype), TYPE_OBSTACK (itype));
   TYPE_MIN_VALUE (itype) = convert (type, lowval);
   TYPE_MAX_VALUE (itype) = convert (type, highval);
+  pop_obstacks ();
+
+  TYPE_PRECISION (itype) = TYPE_PRECISION (type);
   TYPE_MODE (itype) = TYPE_MODE (type);
   TYPE_SIZE (itype) = TYPE_SIZE (type);
   TYPE_ALIGN (itype) = TYPE_ALIGN (type);
@@ -3223,7 +3934,7 @@ build_range_type (type, lowval, highval)
 }
 
 /* Just like build_index_type, but takes lowval and highval instead
-   of just highval (maxval). */
+   of just highval (maxval).  */
 
 tree
 build_index_2_type (lowval,highval)
@@ -3247,13 +3958,16 @@ index_type_equal (itype1, itype2)
     {
       if (TYPE_PRECISION (itype1) != TYPE_PRECISION (itype2)
          || TYPE_MODE (itype1) != TYPE_MODE (itype2)
-         || ! simple_cst_equal (TYPE_SIZE (itype1), TYPE_SIZE (itype2))
+         || simple_cst_equal (TYPE_SIZE (itype1), TYPE_SIZE (itype2)) != 1
          || TYPE_ALIGN (itype1) != TYPE_ALIGN (itype2))
        return 0;
-      if (simple_cst_equal (TYPE_MIN_VALUE (itype1), TYPE_MIN_VALUE (itype2))
-         && simple_cst_equal (TYPE_MAX_VALUE (itype1), TYPE_MAX_VALUE (itype2)))
+      if (1 == simple_cst_equal (TYPE_MIN_VALUE (itype1),
+                                TYPE_MIN_VALUE (itype2))
+         && 1 == simple_cst_equal (TYPE_MAX_VALUE (itype1),
+                                   TYPE_MAX_VALUE (itype2)))
        return 1;
     }
+
   return 0;
 }
 
@@ -3291,15 +4005,6 @@ build_array_type (elt_type, index_type)
   hashcode = TYPE_HASH (elt_type) + TYPE_HASH (index_type);
   t = type_hash_canon (hashcode, t);
 
-#if 0 /* This led to crashes, because it could put a temporary node
-        on the TYPE_NEXT_VARIANT chain of a permanent one.  */
-  /* The main variant of an array type should always
-     be an array whose element type is the main variant.  */
-  if (elt_type != TYPE_MAIN_VARIANT (elt_type))
-    change_main_variant (t, build_array_type (TYPE_MAIN_VARIANT (elt_type),
-                                             index_type));
-#endif
-
   if (TYPE_SIZE (t) == 0)
     layout_type (t);
   return t;
@@ -3546,7 +4251,9 @@ get_unwidened (op, for_type)
 
   if (TREE_CODE (op) == COMPONENT_REF
       /* Since type_for_size always gives an integer type.  */
-      && TREE_CODE (type) != REAL_TYPE)
+      && TREE_CODE (type) != REAL_TYPE
+      /* Don't crash if field not layed out yet.  */
+      && DECL_SIZE (TREE_OPERAND (op, 1)) != 0)
     {
       unsigned innerprec = TREE_INT_CST_LOW (DECL_SIZE (TREE_OPERAND (op, 1)));
       type = type_for_size (innerprec, TREE_UNSIGNED (TREE_OPERAND (op, 1)));
@@ -3685,12 +4392,18 @@ int_fits_type_p (c, type)
     return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
               && INT_CST_LT_UNSIGNED (TYPE_MAX_VALUE (type), c))
            && ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
-                 && INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type))));
+                 && INT_CST_LT_UNSIGNED (c, TYPE_MIN_VALUE (type)))
+           /* Negative ints never fit unsigned types.  */
+           && ! (TREE_INT_CST_HIGH (c) < 0
+                 && ! TREE_UNSIGNED (TREE_TYPE (c))));
   else
     return (! (TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST
               && INT_CST_LT (TYPE_MAX_VALUE (type), c))
            && ! (TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST
-                 && INT_CST_LT (c, TYPE_MIN_VALUE (type))));
+                 && INT_CST_LT (c, TYPE_MIN_VALUE (type)))
+           /* Unsigned ints with top bit set never fit signed types.  */
+           && ! (TREE_INT_CST_HIGH (c) < 0
+                 && TREE_UNSIGNED (TREE_TYPE (c))));
 }
 
 /* Return the innermost context enclosing DECL that is
@@ -3713,7 +4426,8 @@ decl_function_context (decl)
   while (context && TREE_CODE (context) != FUNCTION_DECL)
     {
       if (TREE_CODE (context) == RECORD_TYPE
-         || TREE_CODE (context) == UNION_TYPE)
+         || TREE_CODE (context) == UNION_TYPE
+         || TREE_CODE (context) == QUAL_UNION_TYPE)
        context = TYPE_CONTEXT (context);
       else if (TREE_CODE (context) == TYPE_DECL)
        context = DECL_CONTEXT (context);
@@ -3816,7 +4530,7 @@ dump_tree_statistics ()
 extern char * first_global_object_name;
 
 /* If KIND=='I', return a suitable global initializer (constructor) name.
-   If KIND=='D', return a suitable global clean-up (destructor) name. */
+   If KIND=='D', return a suitable global clean-up (destructor) name.  */
 
 tree
 get_file_function_name (kind)
@@ -3840,7 +4554,7 @@ get_file_function_name (kind)
      constraints).  -- Raeburn@MIT.EDU, 10 Jan 1990.  */
   sprintf (buf, FILE_FUNCTION_FORMAT, p);
 
-  /* Don't need to pull wierd characters out of global names.  */
+  /* Don't need to pull weird characters out of global names.  */
   if (p != first_global_object_name)
     {
       for (p = buf+11; *p; p++)
@@ -3853,7 +4567,7 @@ get_file_function_name (kind)
 #ifndef NO_DOLLAR_IN_LABEL     /* this for `$'; unlikely, but... -- kr */
               || *p == '$'
 #endif
-#ifndef NO_DOT_IN_LABEL                /* this for `.'; unlikely, but... */
+#ifndef NO_DOT_IN_LABEL                /* this for `.'; unlikely, but...  */
               || *p == '.'
 #endif
               || (*p >= 'A' && *p <= 'Z')
@@ -3865,3 +4579,100 @@ get_file_function_name (kind)
 
   return get_identifier (buf);
 }
+\f
+/* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
+   The result is placed in BUFFER (which has length BIT_SIZE),
+   with one bit in each char ('\000' or '\001').
+
+   If the constructor is constant, NULL_TREE is returned.
+   Otherwise, a TREE_LIST of the non-constant elements is emitted.  */
+
+tree
+get_set_constructor_bits (init, buffer, bit_size)
+     tree init;
+     char *buffer;
+     int bit_size;
+{
+  int i;
+  tree vals;
+  HOST_WIDE_INT domain_min
+    = TREE_INT_CST_LOW (TYPE_MIN_VALUE (TYPE_DOMAIN (TREE_TYPE (init))));
+  tree non_const_bits = NULL_TREE;
+  for (i = 0; i < bit_size; i++)
+    buffer[i] = 0;
+
+  for (vals = TREE_OPERAND (init, 1); 
+       vals != NULL_TREE; vals = TREE_CHAIN (vals))
+    {
+      if (TREE_CODE (TREE_VALUE (vals)) != INTEGER_CST
+         || (TREE_PURPOSE (vals) != NULL_TREE
+             && TREE_CODE (TREE_PURPOSE (vals)) != INTEGER_CST))
+       non_const_bits
+         = tree_cons (TREE_PURPOSE (vals), TREE_VALUE (vals), non_const_bits);
+      else if (TREE_PURPOSE (vals) != NULL_TREE)
+       {
+         /* Set a range of bits to ones.  */
+         HOST_WIDE_INT lo_index
+           = TREE_INT_CST_LOW (TREE_PURPOSE (vals)) - domain_min;
+         HOST_WIDE_INT hi_index
+           = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+         if (lo_index < 0 || lo_index >= bit_size
+           || hi_index < 0 || hi_index >= bit_size)
+           abort ();
+         for ( ; lo_index <= hi_index; lo_index++)
+           buffer[lo_index] = 1;
+       }
+      else
+       {
+         /* Set a single bit to one.  */
+         HOST_WIDE_INT index
+           = TREE_INT_CST_LOW (TREE_VALUE (vals)) - domain_min;
+         if (index < 0 || index >= bit_size)
+           {
+             error ("invalid initializer for bit string");
+             return NULL_TREE;
+           }
+         buffer[index] = 1;
+       }
+    }
+  return non_const_bits;
+}
+
+/* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
+   The result is placed in BUFFER (which is an array of bytes).
+   If the constructor is constant, NULL_TREE is returned.
+   Otherwise, a TREE_LIST of the non-constant elements is emitted.  */
+
+tree
+get_set_constructor_bytes (init, buffer, wd_size)
+     tree init;
+     unsigned char *buffer;
+     int wd_size;
+{
+  int i;
+  tree vals = TREE_OPERAND (init, 1);
+  int set_word_size = BITS_PER_UNIT;
+  int bit_size = wd_size * set_word_size;
+  int bit_pos = 0;
+  unsigned char *bytep = buffer;
+  char *bit_buffer = (char *) alloca(bit_size);
+  tree non_const_bits = get_set_constructor_bits (init, bit_buffer, bit_size);
+
+  for (i = 0; i < wd_size; i++)
+    buffer[i] = 0;
+
+  for (i = 0; i < bit_size; i++)
+    {
+      if (bit_buffer[i])
+       {
+         if (BYTES_BIG_ENDIAN)
+           *bytep |= (1 << (set_word_size - 1 - bit_pos));
+         else
+           *bytep |= 1 << bit_pos;
+       }
+      bit_pos++;
+      if (bit_pos >= set_word_size)
+       bit_pos = 0, bytep++;
+    }
+  return non_const_bits;
+}