OSDN Git Service

* Make-lang.in (stmp-f2c.h): Don't configure the runtime
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index 689003e..6812aa4 100644 (file)
@@ -1,5 +1,5 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
-   Copyright (C) 1987, 88, 92, 93, 94, 1995 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,6 +37,7 @@ 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__
@@ -45,6 +47,14 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #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
 
@@ -339,6 +349,7 @@ save_tree_status (p, 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;
@@ -391,6 +402,7 @@ save_tree_status (p, context)
   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;
 }
@@ -419,6 +431,7 @@ restore_tree_status (p)
   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;
@@ -691,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.  */
 
@@ -749,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
@@ -920,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. 
 
@@ -1128,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)
@@ -1154,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++;
@@ -1161,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);
@@ -1216,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;
@@ -1257,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.  */
 
@@ -1325,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;
@@ -1335,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)))
     {
@@ -1387,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.  */
 
@@ -1426,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);
@@ -1445,6 +1522,7 @@ build_complex (real, imag)
 }
 
 /* Build a newly constructed TREE_VEC node of length LEN.  */
+
 tree
 make_tree_vec (len)
      int len;
@@ -1482,6 +1560,7 @@ integer_zerop (expr)
   STRIP_NOPS (expr);
 
   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
@@ -1499,6 +1578,7 @@ integer_onep (expr)
   STRIP_NOPS (expr);
 
   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
@@ -1523,14 +1603,17 @@ integer_all_onesp (expr)
       && integer_zerop (TREE_IMAGPART (expr)))
     return 1;
 
-  else if (TREE_CODE (expr) != INTEGER_CST)
+  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;
@@ -1561,6 +1644,7 @@ int
 integer_pow2p (expr)
      tree expr;
 {
+  int prec;
   HOST_WIDE_INT high, low;
 
   STRIP_NOPS (expr);
@@ -1570,12 +1654,28 @@ integer_pow2p (expr)
       && integer_zerop (TREE_IMAGPART (expr)))
     return 1;
 
-  if (TREE_CODE (expr) != INTEGER_CST)
+  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;
 
@@ -1583,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
@@ -1592,6 +1731,7 @@ real_zerop (expr)
   STRIP_NOPS (expr);
 
   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))
@@ -1607,6 +1747,7 @@ real_onep (expr)
   STRIP_NOPS (expr);
 
   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))
@@ -1622,6 +1763,7 @@ real_twop (expr)
   STRIP_NOPS (expr);
 
   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))
@@ -1643,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)
@@ -1659,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)
@@ -1675,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)
@@ -1690,7 +1832,7 @@ binfo_member (elem, list)
   return NULL_TREE;
 }
 
-/* Return nonzero if ELEM is part of the chain CHAIN. */
+/* Return nonzero if ELEM is part of the chain CHAIN.  */
 
 int
 chain_member (elem, chain)
@@ -1707,7 +1849,10 @@ chain_member (elem, chain)
 }
 
 /* Return nonzero if ELEM is equal to TREE_VALUE (CHAIN) for any piece of
-   chain CHAIN. */
+   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)
@@ -1723,6 +1868,26 @@ chain_member_value (elem, 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'.  */
@@ -1847,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.  */
@@ -1893,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
@@ -1991,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;
+
+  /* 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 (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))));
+  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
@@ -2018,7 +2241,7 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-       return decl_function_context (arg) == 0;
+       return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
     case VAR_DECL:
       return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
 
@@ -2028,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
@@ -2081,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
@@ -2107,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)));
        }
     }
 
@@ -2172,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))
@@ -2192,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
@@ -2204,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
@@ -2218,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;
@@ -2241,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
@@ -2464,10 +2699,10 @@ stabilize_reference (ref)
       break;
 
     case COMPOUND_EXPR:
-      result = build_nt (COMPOUND_EXPR,
-                        stabilize_reference_1 (TREE_OPERAND (ref, 0)),
-                        stabilize_reference (TREE_OPERAND (ref, 1)));
-      break;
+      /* 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),
@@ -2655,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;
@@ -2673,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);
@@ -2834,7 +3069,7 @@ build_block (vars, tags, subblocks, supercontext, chain)
 }
 \f
 /* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
-   is ATTRIBUTE. */
+   is ATTRIBUTE.  */
 
 tree
 build_decl_attribute_variant (ddecl, attribute)
@@ -2876,7 +3111,7 @@ build_type_attribute_variant (ttype, attribute)
 
       hashcode = TYPE_HASH (TREE_CODE (ntype))
                 + TYPE_HASH (TREE_TYPE (ntype))
-                + type_hash_list (attribute);
+                + attribute_hash_list (attribute);
 
       switch (TREE_CODE (ntype))
         {
@@ -2904,7 +3139,7 @@ build_type_attribute_variant (ttype, attribute)
 
 /* 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. */
+   macros VALID_MACHINE_DECL_ATTRIBUTE and VALID_MACHINE_TYPE_ATTRIBUTE.  */
 
 int
 valid_machine_attribute (attr_name, attr_args, decl, type)
@@ -2916,55 +3151,195 @@ valid_machine_attribute (attr_name, attr_args, decl, type)
   tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
   tree type_attr_list = TYPE_ATTRIBUTES (type);
 
-  /* For now, we don't support args.  */
-  if (attr_args != 0)
-    return 0;
+  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))
+      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name, attr_args))
     {
-      tree attr_list;
-      int in_list = 0;
+      tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+                                   decl_attr_list);
 
-      for (attr_list = decl_attr_list; 
-           attr_list;
-           attr_list = TREE_CHAIN (attr_list))
-       if (TREE_VALUE (attr_list) == attr_name)
-         in_list = 1;
-
-      if (! in_list)
-        decl_attr_list = tree_cons (NULL_TREE, 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);
+       }
 
-      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))
+  if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name, attr_args))
     {
-      tree attr_list;
-      int in_list = 0;
+      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;
+    }
 
-      for (attr_list = type_attr_list;
-           attr_list;
-          attr_list = TREE_CHAIN (attr_list))
-       if (TREE_VALUE (attr_list) == attr_name)
-         in_list = 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 (! in_list)
-        type_attr_list = tree_cons (NULL_TREE, 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);
+       }
 
-      type = build_type_attribute_variant (type, type_attr_list);
       if (decl != 0)
-       TREE_TYPE (decl) = type;
+       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.
@@ -2994,7 +3369,7 @@ build_type_variant (type, constp, volatilep)
      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))
+  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;
@@ -3008,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.  */
-
-void
-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.  */
 
@@ -3119,12 +3466,14 @@ type_hash_lookup (hashcode, 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;
 }
@@ -3188,6 +3537,22 @@ 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.  */
 
@@ -3199,8 +3564,13 @@ attribute_list_equal (l1, l2)
          && attribute_list_contained (l2, l1);
 }
 
-/* Given two lists of attributes, return true if list l2 is
-   completely contained within 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)
@@ -3212,9 +3582,10 @@ attribute_list_contained (l1, l2)
   if (l1 == l2)
      return 1;
 
-  /* Then check the obvious, maybe the lists are similar.  */
+  /* 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));
 
@@ -3223,8 +3594,16 @@ attribute_list_contained (l1, l2)
      return 1;
 
   for (; t2; t2 = TREE_CHAIN (t2))
-     if (!value_member (l1, 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;
 }
 
@@ -3238,21 +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
-             || TREE_TYPE (TREE_PURPOSE (t1))
-                != TREE_TYPE (TREE_PURPOSE (t2)))
-           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;
 }
@@ -3309,21 +3681,22 @@ tree_int_cst_sgn (t)
     return 1;
 }
 
-/* Compare two constructor-element-type constants.  */
+/* 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);
 }
 
@@ -3422,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))
     {
@@ -3492,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);
@@ -3518,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);
@@ -3547,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)
@@ -3571,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;
 }
 
@@ -3615,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;
@@ -3870,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)));
@@ -4009,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
@@ -4037,8 +4426,9 @@ decl_function_context (decl)
   while (context && TREE_CODE (context) != FUNCTION_DECL)
     {
       if (TREE_CODE (context) == RECORD_TYPE
-         || TREE_CODE (context) == UNION_TYPE)
-       context = NULL_TREE;
+         || 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);
       else if (TREE_CODE (context) == BLOCK)
@@ -4140,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)
@@ -4164,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++)
@@ -4177,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')
@@ -4190,12 +4580,12 @@ get_file_function_name (kind)
   return get_identifier (buf);
 }
 \f
-/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+/* 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. */
+   Otherwise, a TREE_LIST of the non-constant elements is emitted.  */
 
 tree
 get_set_constructor_bits (init, buffer, bit_size)
@@ -4217,11 +4607,11 @@ get_set_constructor_bits (init, buffer, bit_size)
       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);
+       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. */
+         /* 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
@@ -4234,7 +4624,7 @@ get_set_constructor_bits (init, buffer, bit_size)
        }
       else
        {
-         /* Set a single bit to one. */
+         /* 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)
@@ -4248,10 +4638,10 @@ get_set_constructor_bits (init, buffer, bit_size)
   return non_const_bits;
 }
 
-/* Expand (the constant part of) a SET_TYPE CONTRUCTOR node.
+/* 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. */
+   Otherwise, a TREE_LIST of the non-constant elements is emitted.  */
 
 tree
 get_set_constructor_bytes (init, buffer, wd_size)
@@ -4265,7 +4655,7 @@ get_set_constructor_bytes (init, buffer, wd_size)
   int bit_size = wd_size * set_word_size;
   int bit_pos = 0;
   unsigned char *bytep = buffer;
-  char *bit_buffer = (char*)alloca(bit_size);
+  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++)
@@ -4275,7 +4665,7 @@ get_set_constructor_bytes (init, buffer, wd_size)
     {
       if (bit_buffer[i])
        {
-         if (BITS_BIG_ENDIAN)
+         if (BYTES_BIG_ENDIAN)
            *bytep |= (1 << (set_word_size - 1 - bit_pos));
          else
            *bytep |= 1 << bit_pos;