OSDN Git Service

(struct function): Make frame_offset be HOST_WIDE_INT.
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index ff229ac..6a1e953 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, 93, 94, 95, 1996 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__
@@ -66,6 +68,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.
@@ -315,16 +328,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, toplevel)
+save_tree_status (p, context)
      struct function *p;
-     int toplevel;
+     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;
@@ -333,16 +350,42 @@ save_tree_status (p, toplevel)
   p->expression_obstack = expression_obstack;
   p->saveable_obstack = saveable_obstack;
   p->rtl_obstack = rtl_obstack;
+  p->inline_obstacks = inline_obstacks;
 
-  if (! toplevel)
+  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
     {
-      /* 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;
-      maybepermanent_firstobj
-       = (char *) obstack_finish (function_maybepermanent_obstack);
-    }
+      /* 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)));
+
+      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);
@@ -351,6 +394,7 @@ save_tree_status (p, toplevel)
   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;
 }
@@ -359,30 +403,27 @@ save_tree_status (p, toplevel)
    This is used after a nested function.  */
 
 void
-restore_tree_status (p, toplevel)
+restore_tree_status (p)
      struct function *p;
-     int toplevel;
 {
   all_types_permanent = p->all_types_permanent;
   momentary_stack = p->momentary_stack;
 
   obstack_free (&momentary_obstack, momentary_function_firstobj);
 
-  if (! toplevel)
-    {
-      /* 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.  */
-      obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
-    }
+  /* Free saveable storage used by the function just compiled and not
+     saved.
+
+     CAUTION: This is in function_obstack of the containing function.
+     So we must be sure that we never allocate from that obstack during
+     the compilation of a nested function if we expect it to survive
+     past the nested function's end.  */
+  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;
@@ -392,6 +433,7 @@ restore_tree_status (p, toplevel)
   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.
@@ -408,6 +450,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
@@ -535,6 +578,17 @@ permanent_allocation (function_end)
   obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
   obstack_free (&temp_decl_obstack, temp_decl_firstobj);
 
+  /* Free up the maybepermanent_obstacks for any of our nested functions
+     which were compiled at a lower level.  */
+  while (inline_obstacks)
+    {
+      struct simple_obstack_stack *current = inline_obstacks;
+      inline_obstacks = current->next;
+      obstack_free (current->obstack, 0);
+      free (current->obstack);
+      free (current);
+    }
+
   current_obstack = &permanent_obstack;
   expression_obstack = &permanent_obstack;
   rtl_obstack = saveable_obstack = &permanent_obstack;
@@ -700,7 +754,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
@@ -871,11 +925,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. 
 
@@ -1079,15 +1133,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)
@@ -1112,6 +1164,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);
@@ -1167,9 +1227,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;
@@ -1276,8 +1336,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;
@@ -1286,9 +1346,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)))
     {
@@ -1338,7 +1400,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.  */
 
@@ -1377,18 +1444,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);
@@ -1396,6 +1464,7 @@ build_complex (real, imag)
 }
 
 /* Build a newly constructed TREE_VEC node of length LEN.  */
+
 tree
 make_tree_vec (len)
      int len;
@@ -1433,6 +1502,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
@@ -1450,6 +1520,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
@@ -1474,14 +1545,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;
@@ -1521,7 +1595,7 @@ 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;
 
   high = TREE_INT_CST_HIGH (expr);
@@ -1543,6 +1617,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))
@@ -1558,6 +1633,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))
@@ -1573,6 +1649,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))
@@ -1594,7 +1671,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)
@@ -1610,7 +1687,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)
@@ -1626,7 +1703,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)
@@ -1641,7 +1718,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)
@@ -1658,7 +1735,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)
@@ -1674,6 +1754,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'.  */
@@ -1969,7 +2069,7 @@ staticp (arg)
     case FUNCTION_DECL:
       /* Nested functions aren't static, since taking their address
         involves a trampoline.  */
-      return ! FUNCTION_NEEDS_STATIC_CHAIN (arg);
+       return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
     case VAR_DECL:
       return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
 
@@ -1983,8 +2083,13 @@ staticp (arg)
     case BIT_FIELD_REF:
       return staticp (TREE_OPERAND (arg, 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
@@ -2032,10 +2137,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
@@ -2058,6 +2163,95 @@ 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;
+
+  if (expr == NULL_TREE)
+    return expr;
+
+  code = TREE_CODE (expr);
+  switch (code)
+    {
+    case SAVE_EXPR:
+      SAVE_EXPR_RTL (expr) = 0;
+      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 ();
+      break;
+
+    case CALL_EXPR:
+      CALL_EXPR_RTL (expr) = 0;
+      if (TREE_OPERAND (expr, 1)
+         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+       {
+         tree exp = TREE_OPERAND (expr, 1);
+         while (exp)
+           {
+             unsave_expr_now (TREE_VALUE (exp));
+             exp = TREE_CHAIN (exp);
+           }
+       }
+      break;
+    }
+
+  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 = tree_code_length[(int) code] - 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.
@@ -2076,6 +2270,8 @@ contains_placeholder_p (exp)
      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))
     {
@@ -2123,6 +2319,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))
@@ -2143,9 +2341,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
@@ -2155,10 +2356,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
@@ -2169,11 +2373,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;
@@ -2192,169 +2399,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
@@ -2415,10 +2501,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),
@@ -2606,13 +2692,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;
@@ -2624,7 +2711,6 @@ build1 (code, type, node)
     kind = e_kind;
 #endif
 
-  obstack = expression_obstack;
   length = sizeof (struct tree_exp);
 
   t = (tree) obstack_alloc (obstack, length);
@@ -2785,7 +2871,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)
@@ -2827,7 +2913,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))
         {
@@ -2853,62 +2939,209 @@ build_type_attribute_variant (ttype, attribute)
   return ttype;
 }
 
-/* Return a 1 if NEW_ATTR 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. */
+/* 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 (new_attr, decl, type)
-  tree new_attr;
-  tree decl;
-  tree type;
+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_MACHINE_ATTRIBUTES (decl);
+  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 (VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, new_attr))
+  if (decl != 0
+      && VALID_MACHINE_DECL_ATTRIBUTE (decl, decl_attr_list, attr_name, attr_args))
     {
-      tree attr_list;
-      int in_list = 0;
-
-      for (attr_list = decl_attr_list; 
-           attr_list;
-           attr_list = TREE_CHAIN (attr_list))
-       if (TREE_VALUE (attr_list) == new_attr)
-         in_list = 1;
+      tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
+                                   decl_attr_list);
 
-      if (! in_list)
-        decl_attr_list = tree_cons (NULL_TREE, new_attr, 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, new_attr))
+  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);
 
-      for (attr_list = type_attr_list;
-           attr_list;
-          attr_list = TREE_CHAIN (attr_list))
-       if (TREE_VALUE (attr_list) == new_attr)
-         in_list = 1;
+      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 (! in_list)
-        type_attr_list = tree_cons (NULL_TREE, new_attr, type_attr_list);
+      if (decl != 0)
+       TREE_TYPE (decl) = build_pointer_type (inner_type);
 
-      decl = build_type_attribute_variant (type, type_attr_list);
       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.
@@ -2938,7 +3171,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;
@@ -3063,12 +3296,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;
 }
@@ -3132,6 +3367,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.  */
 
@@ -3143,8 +3394,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)
@@ -3156,9 +3412,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));
 
@@ -3167,8 +3424,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;
 }
 
@@ -3182,21 +3447,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;
 }
@@ -3253,21 +3511,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);
 }
 
@@ -3366,8 +3625,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))
     {
@@ -3462,7 +3726,7 @@ 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)
@@ -3491,7 +3755,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)
@@ -3515,13 +3779,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;
 }
 
@@ -3981,8 +4248,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)
@@ -4084,7 +4352,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)
@@ -4108,7 +4376,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++)
@@ -4121,7 +4389,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')
@@ -4134,12 +4402,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)
@@ -4165,7 +4433,7 @@ get_set_constructor_bits (init, buffer, bit_size)
          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
@@ -4178,7 +4446,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)
@@ -4192,10 +4460,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)
@@ -4209,7 +4477,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++)
@@ -4219,7 +4487,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;