OSDN Git Service

* rs6000.md (abssi2_nopower): Convert to define_insn_and_split.
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 5d3510c..f009cd6 100644 (file)
@@ -1,23 +1,23 @@
 /* Subroutines shared by all languages that are variants of C.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002 Free Software Foundation, Inc.
 
-This file is part of GNU CC.
+This file is part of GCC.
 
-GNU CC is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2, or (at your option) any later
+version.
 
-GNU CC is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+along with GCC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -30,9 +30,14 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "expr.h"
 #include "c-common.h"
+#include "tree-inline.h"
+#include "diagnostic.h"
 #include "tm_p.h"
 #include "obstack.h"
+#include "c-lex.h"
 #include "cpplib.h"
+#include "target.h"
+#include "langhooks.h"
 cpp_reader *parse_in;          /* Declared in c-lex.h.  */
 
 #undef WCHAR_TYPE_SIZE
@@ -76,6 +81,10 @@ cpp_reader *parse_in;                /* Declared in c-lex.h.  */
                        : "long long unsigned int"))
 #endif
 
+/* The variant of the C language being processed.  */
+
+enum c_language_kind c_language;
+
 /* The following symbols are subsumed in the c_global_trees array, and
    listed here individually for documentation purposes.
 
@@ -152,28 +161,29 @@ cpp_reader *parse_in;             /* Declared in c-lex.h.  */
 
        tree default_function_type;
 
-   Function types `int (int)', etc.
-
-       tree int_ftype_int;
-       tree void_ftype;
-       tree void_ftype_ptr;
-       tree int_ftype_int;
-       tree ptr_ftype_sizetype;
-
    A VOID_TYPE node, packaged in a TREE_LIST.
 
        tree void_list_node;
 
-  The identifiers __FUNCTION__, __PRETTY_FUNCTION__, and __func__.
+  The lazily created VAR_DECLs for __FUNCTION__, __PRETTY_FUNCTION__,
+  and __func__. (C doesn't generate __FUNCTION__ and__PRETTY_FUNCTION__
+  VAR_DECLS, but C++ does.)
 
-       tree function_id_node;
-       tree pretty_function_id_node;
-       tree func_id_node;
+       tree function_name_decl_node;
+       tree pretty_function_name_decl_node;
+       tree c99_function_name_decl_node;
+
+  Stack of nested function name VAR_DECLs.
+  
+       tree saved_function_name_decls;
 
 */
 
 tree c_global_trees[CTI_MAX];
 
+/* Nonzero if prepreprocessing only.  */
+int flag_preprocess_only;
+
 /* Nonzero means don't recognize the non-ANSI builtin functions.  */
 
 int flag_no_builtin;
@@ -191,20 +201,18 @@ int flag_short_double;
 
 int flag_short_wchar;
 
-/* If non-NULL, dump the tree structure for the entire translation
-   unit to this file.  */
-
-const char *flag_dump_translation_unit;
-
 /* Nonzero means warn about possible violations of sequence point rules.  */
 
 int warn_sequence_point;
 
+/* Nonzero means to warn about compile-time division by zero.  */
+int warn_div_by_zero = 1;
+
 /* The elements of `ridpointers' are identifier nodes for the reserved
    type names and storage classes.  It is indexed by a RID_... value.  */
 tree *ridpointers;
 
-tree (*make_fname_decl)                PARAMS ((tree, const char *, int));
+tree (*make_fname_decl)                PARAMS ((tree, int));
 
 /* If non-NULL, the address of a language-specific function that
    returns 1 for language-specific statement codes.  */
@@ -214,24 +222,31 @@ int (*lang_statement_code_p)           PARAMS ((enum tree_code));
    any action required right before expand_function_end is called.  */
 void (*lang_expand_function_end)       PARAMS ((void));
 
-/* If this variable is defined to a non-NULL value, it will be called
-   after the file has been completely parsed.  */
-void (*back_end_hook) PARAMS ((tree));
-
 /* Nonzero means the expression being parsed will never be evaluated.
    This is a count, since unevaluated expressions can nest.  */
 int skip_evaluation;
 
-enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
-           A_NO_CHECK_MEMORY_USAGE, A_NO_INSTRUMENT_FUNCTION,
-           A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
-           A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
-           A_NO_LIMIT_STACK, A_PURE};
+/* Information about how a function name is generated.  */
+struct fname_var_t
+{
+  tree *const decl;    /* pointer to the VAR_DECL.  */
+  const unsigned rid;  /* RID number for the identifier.  */
+  const int pretty;    /* How pretty is it? */
+};
+
+/* The three ways of getting then name of the current function.  */
+
+const struct fname_var_t fname_vars[] =
+{
+  /* C99 compliant __func__, must be first.  */
+  {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0},
+  /* GCC __FUNCTION__ compliant.  */
+  {&function_name_decl_node, RID_FUNCTION_NAME, 0},
+  /* GCC __PRETTY_FUNCTION__ compliant.  */
+  {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1},
+  {NULL, 0, 0},
+};
 
-static void add_attribute              PARAMS ((enum attrs, const char *,
-                                                int, int, int));
-static void init_attributes            PARAMS ((void));
-static int default_valid_lang_attribute PARAMS ((tree, tree, tree, tree));
 static int constant_fits_type_p                PARAMS ((tree, tree));
 
 /* Keep a stack of if statements.  We record the number of compound
@@ -256,29 +271,160 @@ static int if_stack_space = 0;
 /* Stack pointer.  */
 static int if_stack_pointer = 0;
 
+static tree handle_packed_attribute    PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_nocommon_attribute  PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_common_attribute    PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_noreturn_attribute  PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_noinline_attribute  PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_always_inline_attribute PARAMS ((tree *, tree, tree, int,
+                                                   bool *));
+static tree handle_used_attribute      PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_unused_attribute    PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_const_attribute     PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_transparent_union_attribute PARAMS ((tree *, tree, tree,
+                                                       int, bool *));
+static tree handle_constructor_attribute PARAMS ((tree *, tree, tree, int,
+                                                 bool *));
+static tree handle_destructor_attribute PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_mode_attribute      PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_section_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_aligned_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_weak_attribute      PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_alias_attribute     PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_visibility_attribute        PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
+                                                            tree, int,
+                                                            bool *));
+static tree handle_malloc_attribute    PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int,
+                                                    bool *));
+static tree handle_pure_attribute      PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_deprecated_attribute        PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
+                                                 bool *));
+static tree vector_size_helper PARAMS ((tree, tree));
+
+/* Table of machine-independent attributes common to all C-like languages.  */
+const struct attribute_spec c_common_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "packed",                 0, 0, false, false, false,
+                             handle_packed_attribute },
+  { "nocommon",               0, 0, true,  false, false,
+                             handle_nocommon_attribute },
+  { "common",                 0, 0, true,  false, false,
+                             handle_common_attribute },
+  /* FIXME: logically, noreturn attributes should be listed as
+     "false, true, true" and apply to function types.  But implementing this
+     would require all the places in the compiler that use TREE_THIS_VOLATILE
+     on a decl to identify non-returning functions to be located and fixed
+     to check the function type instead.  */
+  { "noreturn",               0, 0, true,  false, false,
+                             handle_noreturn_attribute },
+  { "volatile",               0, 0, true,  false, false,
+                             handle_noreturn_attribute },
+  { "noinline",               0, 0, true,  false, false,
+                             handle_noinline_attribute },
+  { "always_inline",          0, 0, true,  false, false,
+                             handle_always_inline_attribute },
+  { "used",                   0, 0, true,  false, false,
+                             handle_used_attribute },
+  { "unused",                 0, 0, false, false, false,
+                             handle_unused_attribute },
+  /* The same comments as for noreturn attributes apply to const ones.  */
+  { "const",                  0, 0, true,  false, false,
+                             handle_const_attribute },
+  { "transparent_union",      0, 0, false, false, false,
+                             handle_transparent_union_attribute },
+  { "constructor",            0, 0, true,  false, false,
+                             handle_constructor_attribute },
+  { "destructor",             0, 0, true,  false, false,
+                             handle_destructor_attribute },
+  { "mode",                   1, 1, false,  true, false,
+                             handle_mode_attribute },
+  { "section",                1, 1, true,  false, false,
+                             handle_section_attribute },
+  { "aligned",                0, 1, false, false, false,
+                             handle_aligned_attribute },
+  { "weak",                   0, 0, true,  false, false,
+                             handle_weak_attribute },
+  { "alias",                  1, 1, true,  false, false,
+                             handle_alias_attribute },
+  { "no_instrument_function", 0, 0, true,  false, false,
+                             handle_no_instrument_function_attribute },
+  { "malloc",                 0, 0, true,  false, false,
+                             handle_malloc_attribute },
+  { "no_stack_limit",         0, 0, true,  false, false,
+                             handle_no_limit_stack_attribute },
+  { "pure",                   0, 0, true,  false, false,
+                             handle_pure_attribute },
+  { "deprecated",             0, 0, false, false, false,
+                             handle_deprecated_attribute },
+  { "vector_size",           1, 1, false, true, false,
+                             handle_vector_size_attribute },
+  { "visibility",            1, 1, true,  false, false,
+                             handle_visibility_attribute },
+  { NULL,                     0, 0, false, false, false, NULL }
+};
+
+/* Give the specifications for the format attributes, used by C and all
+   descendents.  */
+
+const struct attribute_spec c_common_format_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+  { "format",                 3, 3, false, true,  true,
+                             handle_format_attribute },
+  { "format_arg",             1, 1, false, true,  true,
+                             handle_format_arg_attribute },
+  { NULL,                     0, 0, false, false, false, NULL }
+};
+
 /* Record the start of an if-then, and record the start of it
-   for ambiguous else detection.  */
+   for ambiguous else detection.
+
+   COND is the condition for the if-then statement.
+
+   IF_STMT is the statement node that has already been created for
+   this if-then statement.  It is created before parsing the
+   condition to keep line number information accurate.  */
 
 void
-c_expand_start_cond (cond, compstmt_count)
+c_expand_start_cond (cond, compstmt_count, if_stmt)
      tree cond;
      int compstmt_count;
+     tree if_stmt;
 {
-  tree if_stmt;
-
   /* Make sure there is enough space on the stack.  */
   if (if_stack_space == 0)
     {
       if_stack_space = 10;
-      if_stack = (if_elt *)xmalloc (10 * sizeof (if_elt));
+      if_stack = (if_elt *) xmalloc (10 * sizeof (if_elt));
     }
   else if (if_stack_space == if_stack_pointer)
     {
       if_stack_space += 10;
-      if_stack = (if_elt *)xrealloc (if_stack, if_stack_space * sizeof (if_elt));
+      if_stack = (if_elt *) xrealloc (if_stack, if_stack_space * sizeof (if_elt));
     }
 
-  if_stmt = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
   IF_COND (if_stmt) = cond;
   add_stmt (if_stmt);
 
@@ -344,124 +490,210 @@ c_finish_else ()
   RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
-/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__.  */
+/* Begin an if-statement.  Returns a newly created IF_STMT if
+   appropriate.
+
+   Unlike the C++ front-end, we do not call add_stmt here; it is
+   probably safe to do so, but I am not very familiar with this
+   code so I am being extra careful not to change its behavior
+   beyond what is strictly necessary for correctness.  */
+
+tree
+c_begin_if_stmt ()
+{
+  tree r;
+  r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+  return r;
+}
+
+/* Begin a while statement.  Returns a newly created WHILE_STMT if
+   appropriate.
+
+   Unlike the C++ front-end, we do not call add_stmt here; it is
+   probably safe to do so, but I am not very familiar with this
+   code so I am being extra careful not to change its behavior
+   beyond what is strictly necessary for correctness.  */
+
+tree
+c_begin_while_stmt ()
+{
+  tree r;
+  r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
+  return r;
+}
 
 void
-declare_function_name ()
+c_finish_while_stmt_cond (cond, while_stmt)
+     tree while_stmt;
+     tree cond;
 {
-  const char *name, *printable_name;
+  WHILE_COND (while_stmt) = cond;
+}
 
-  if (current_function_decl == NULL)
-    {
-      name = "";
-      printable_name = "top level";
-    }
-  else
+/* Push current bindings for the function name VAR_DECLS.  */
+
+void
+start_fname_decls ()
+{
+  unsigned ix;
+  tree saved = NULL_TREE;
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
     {
-      /* Allow functions to be nameless (such as artificial ones).  */
-      if (DECL_NAME (current_function_decl))
-        name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
-      else
-       name = "";
-      printable_name = (*decl_printable_name) (current_function_decl, 2);
+      tree decl = *fname_vars[ix].decl;
 
-      /* ISO C99 defines __func__, which is a variable, not a string
-        constant, and which is not a defined symbol at file scope.  */
-      (*make_fname_decl) (func_id_node, name, 0);
+      if (decl)
+       {
+         saved = tree_cons (decl, build_int_2 (ix, 0), saved);
+         *fname_vars[ix].decl = NULL_TREE;
+       }
     }
-  
-  (*make_fname_decl) (function_id_node, name, 0);
-  (*make_fname_decl) (pretty_function_id_node, printable_name, 1);
+  if (saved || saved_function_name_decls)
+    /* Normally they'll have been NULL, so only push if we've got a
+       stack, or they are non-NULL.  */
+    saved_function_name_decls = tree_cons (saved, NULL_TREE,
+                                          saved_function_name_decls);
 }
 
-/* Given a chain of STRING_CST nodes,
-   concatenate them into one STRING_CST
-   and give it a suitable array-of-chars data type.  */
+/* Finish up the current bindings, adding them into the
+   current function's statement tree. This is done by wrapping the
+   function's body in a COMPOUND_STMT containing these decls too. This
+   must be done _before_ finish_stmt_tree is called. If there is no
+   current function, we must be at file scope and no statements are
+   involved. Pop the previous bindings.  */
 
-tree
-combine_strings (strings)
-     tree strings;
+void
+finish_fname_decls ()
 {
-  register tree value, t;
-  register int length = 1;
-  int wide_length = 0;
-  int wide_flag = 0;
-  int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
-  int nchars;
-  const int nchars_max = flag_isoc99 ? 4095 : 509;
+  unsigned ix;
+  tree body = NULL_TREE;
+  tree stack = saved_function_name_decls;
 
-  if (TREE_CHAIN (strings))
+  for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack))
+    body = chainon (TREE_VALUE (stack), body);
+  
+  if (body)
+    {
+      /* They were called into existence, so add to statement tree.  */
+      body = chainon (body,
+                     TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)));
+      body = build_stmt (COMPOUND_STMT, body);
+      
+      COMPOUND_STMT_NO_SCOPE (body) = 1;
+      TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)) = body;
+    }
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    *fname_vars[ix].decl = NULL_TREE;
+  
+  if (stack)
     {
-      /* More than one in the chain, so concatenate.  */
-      register char *p, *q;
+      /* We had saved values, restore them.  */
+      tree saved;
 
-      /* Don't include the \0 at the end of each substring,
-        except for the last one.
-        Count wide strings and ordinary strings separately.  */
-      for (t = strings; t; t = TREE_CHAIN (t))
+      for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved))
        {
-         if (TREE_TYPE (t) == wchar_array_type_node)
-           {
-             wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
-             wide_flag = 1;
-           }
-         else
-           length += (TREE_STRING_LENGTH (t) - 1);
+         tree decl = TREE_PURPOSE (saved);
+         unsigned ix = TREE_INT_CST_LOW (TREE_VALUE (saved));
+         
+         *fname_vars[ix].decl = decl;
        }
+      stack = TREE_CHAIN (stack);
+    }
+  saved_function_name_decls = stack;
+}
 
-      /* If anything is wide, the non-wides will be converted,
-        which makes them take more space.  */
-      if (wide_flag)
-       length = length * wchar_bytes + wide_length;
+/* Return the text name of the current function, suitable prettified
+   by PRETTY_P.  */
 
-      p = alloca (length);
+const char *
+fname_as_string (pretty_p)
+     int pretty_p;
+{
+  const char *name = NULL;
+  
+  if (pretty_p)
+    name = (current_function_decl
+           ? (*lang_hooks.decl_printable_name) (current_function_decl, 2)
+           : "top level");
+  else if (current_function_decl && DECL_NAME (current_function_decl))
+    name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
+  else
+    name = "";
+  return name;
+}
 
-      /* Copy the individual strings into the new combined string.
-        If the combined string is wide, convert the chars to ints
-        for any individual strings that are not wide.  */
+/* Return the text name of the current function, formatted as
+   required by the supplied RID value.  */
 
-      q = p;
-      for (t = strings; t; t = TREE_CHAIN (t))
-       {
-         int len = (TREE_STRING_LENGTH (t)
-                    - ((TREE_TYPE (t) == wchar_array_type_node)
-                       ? wchar_bytes : 1));
-         if ((TREE_TYPE (t) == wchar_array_type_node) == wide_flag)
-           {
-             memcpy (q, TREE_STRING_POINTER (t), len);
-             q += len;
-           }
-         else
-           {
-             int i;
-             for (i = 0; i < len; i++)
-               {
-                 if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT)
-                   ((short *) q)[i] = TREE_STRING_POINTER (t)[i];
-                 else
-                   ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
-               }
-             q += len * wchar_bytes;
-           }
-       }
-      if (wide_flag)
-       {
-         int i;
-         for (i = 0; i < wchar_bytes; i++)
-           *q++ = 0;
-       }
-      else
-       *q = 0;
+const char *
+fname_string (rid)
+     unsigned rid;
+{
+  unsigned ix;
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    if (fname_vars[ix].rid == rid)
+      break;
+  return fname_as_string (fname_vars[ix].pretty);
+}
 
-      value = build_string (length, p);
-    }
-  else
+/* Return the VAR_DECL for a const char array naming the current
+   function. If the VAR_DECL has not yet been created, create it
+   now. RID indicates how it should be formatted and IDENTIFIER_NODE
+   ID is its name (unfortunately C and C++ hold the RID values of
+   keywords in different places, so we can't derive RID from ID in
+   this language independent code.  */
+
+tree
+fname_decl (rid, id)
+     unsigned rid;
+     tree id;
+{
+  unsigned ix;
+  tree decl = NULL_TREE;
+
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    if (fname_vars[ix].rid == rid)
+      break;
+
+  decl = *fname_vars[ix].decl;
+  if (!decl)
     {
-      value = strings;
-      length = TREE_STRING_LENGTH (value);
-      if (TREE_TYPE (value) == wchar_array_type_node)
-       wide_flag = 1;
+      tree saved_last_tree = last_tree;
+      
+      decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
+      if (last_tree != saved_last_tree)
+       {
+         /* We created some statement tree for the decl. This belongs
+            at the start of the function, so remove it now and reinsert
+            it after the function is complete.  */
+         tree stmts = TREE_CHAIN (saved_last_tree);
+
+         TREE_CHAIN (saved_last_tree) = NULL_TREE;
+         last_tree = saved_last_tree;
+         saved_function_name_decls = tree_cons (decl, stmts,
+                                                saved_function_name_decls);
+       }
+      *fname_vars[ix].decl = decl;
     }
+  if (!ix && !current_function_decl)
+    pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
+  
+  return decl;
+}
+
+/* Given a STRING_CST, give it a suitable array-of-chars data type.  */
+
+tree
+fix_string_type (value)
+      tree value;
+{
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  const int wide_flag = TREE_TYPE (value) == wchar_array_type_node;
+  const int nchars_max = flag_isoc99 ? 4095 : 509;
+  int length = TREE_STRING_LENGTH (value);
+  int nchars;
 
   /* Compute the number of elements, for the array type.  */
   nchars = wide_flag ? length / wchar_bytes : length;
@@ -474,8 +706,7 @@ combine_strings (strings)
      -Wwrite-strings says make the string constant an array of const char
      so that copying it to a non-const pointer will get a warning.
      For C++, this is the standard behavior.  */
-  if (flag_const_strings
-      && (! flag_traditional  && ! flag_writable_strings))
+  if (flag_const_strings && ! flag_writable_strings)
     {
       tree elements
        = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
@@ -494,1015 +725,517 @@ combine_strings (strings)
   TREE_STATIC (value) = 1;
   return value;
 }
-\f
-/* To speed up processing of attributes, we maintain an array of
-   IDENTIFIER_NODES and the corresponding attribute types.  */
 
-/* Array to hold attribute information.  */
+/* Given a VARRAY of STRING_CST nodes, concatenate them into one
+   STRING_CST.  */
 
-static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
+tree
+combine_strings (strings)
+     varray_type strings;
+{
+  const int wchar_bytes = TYPE_PRECISION (wchar_type_node) / BITS_PER_UNIT;
+  const int nstrings = VARRAY_ACTIVE_SIZE (strings);
+  tree value, t;
+  int length = 1;
+  int wide_length = 0;
+  int wide_flag = 0;
+  int i;
+  char *p, *q;
 
-static int attrtab_idx = 0;
+  /* Don't include the \0 at the end of each substring.  Count wide
+     strings and ordinary strings separately.  */
+  for (i = 0; i < nstrings; ++i)
+    {
+      t = VARRAY_TREE (strings, i);
 
-/* Add an entry to the attribute table above.  */
+      if (TREE_TYPE (t) == wchar_array_type_node)
+       {
+         wide_length += TREE_STRING_LENGTH (t) - wchar_bytes;
+         wide_flag = 1;
+       }
+      else
+       {
+         length += (TREE_STRING_LENGTH (t) - 1);
+         if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
+           warning ("concatenation of string literals with __FUNCTION__ is deprecated"); 
+       }
+    }
 
-static void
-add_attribute (id, string, min_len, max_len, decl_req)
-     enum attrs id;
-     const char *string;
-     int min_len, max_len;
-     int decl_req;
-{
-  char buf[100];
+  /* If anything is wide, the non-wides will be converted,
+     which makes them take more space.  */
+  if (wide_flag)
+    length = length * wchar_bytes + wide_length;
 
-  attrtab[attrtab_idx].id = id;
-  attrtab[attrtab_idx].name = get_identifier (string);
-  attrtab[attrtab_idx].min = min_len;
-  attrtab[attrtab_idx].max = max_len;
-  attrtab[attrtab_idx++].decl_req = decl_req;
+  p = xmalloc (length);
 
-  sprintf (buf, "__%s__", string);
+  /* Copy the individual strings into the new combined string.
+     If the combined string is wide, convert the chars to ints
+     for any individual strings that are not wide.  */
 
-  attrtab[attrtab_idx].id = id;
-  attrtab[attrtab_idx].name = get_identifier (buf);
-  attrtab[attrtab_idx].min = min_len;
-  attrtab[attrtab_idx].max = max_len;
-  attrtab[attrtab_idx++].decl_req = decl_req;
-}
+  q = p;
+  for (i = 0; i < nstrings; ++i)
+    {
+      int len, this_wide;
 
-/* Initialize attribute table.  */
+      t = VARRAY_TREE (strings, i);
+      this_wide = TREE_TYPE (t) == wchar_array_type_node;
+      len = TREE_STRING_LENGTH (t) - (this_wide ? wchar_bytes : 1);
+      if (this_wide == wide_flag)
+       {
+         memcpy (q, TREE_STRING_POINTER (t), len);
+         q += len;
+       }
+      else
+       {
+         const int nzeros = (WCHAR_TYPE_SIZE / BITS_PER_UNIT) - 1;
+         int j, k;
 
-static void
-init_attributes ()
-{
-  add_attribute (A_PACKED, "packed", 0, 0, 0);
-  add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
-  add_attribute (A_COMMON, "common", 0, 0, 1);
-  add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
-  add_attribute (A_NORETURN, "volatile", 0, 0, 1);
-  add_attribute (A_UNUSED, "unused", 0, 0, 0);
-  add_attribute (A_CONST, "const", 0, 0, 1);
-  add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
-  add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
-  add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1);
-  add_attribute (A_MODE, "mode", 1, 1, 1);
-  add_attribute (A_SECTION, "section", 1, 1, 1);
-  add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
-  add_attribute (A_FORMAT, "format", 3, 3, 1);
-  add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
-  add_attribute (A_WEAK, "weak", 0, 0, 1);
-  add_attribute (A_ALIAS, "alias", 1, 1, 1);
-  add_attribute (A_NO_INSTRUMENT_FUNCTION, "no_instrument_function", 0, 0, 1);
-  add_attribute (A_NO_CHECK_MEMORY_USAGE, "no_check_memory_usage", 0, 0, 1);
-  add_attribute (A_MALLOC, "malloc", 0, 0, 1);
-  add_attribute (A_NO_LIMIT_STACK, "no_stack_limit", 0, 0, 1);
-  add_attribute (A_PURE, "pure", 0, 0, 1);
+         if (BYTES_BIG_ENDIAN)
+           {
+             for (k = 0; k < len; k++)
+               {
+                 for (j = 0; j < nzeros; j++)
+                   *q++ = 0;
+                 *q++ = TREE_STRING_POINTER (t)[k];
+               }
+           }
+         else
+           {
+             for (k = 0; k < len; k++)
+               {
+                 *q++ = TREE_STRING_POINTER (t)[k];
+                 for (j = 0; j < nzeros; j++)
+                   *q++ = 0;
+               }
+           }
+       }
+    }
+
+  /* Nul terminate the string.  */
+  if (wide_flag)
+    {
+      for (i = 0; i < wchar_bytes; i++)
+       *q++ = 0;
+    }
+  else
+    *q = 0;
+
+  value = build_string (length, p);
+  free (p);
+
+  if (wide_flag)
+    TREE_TYPE (value) = wchar_array_type_node;
+  else
+    TREE_TYPE (value) = char_array_type_node;
+
+  return value;
 }
 \f
-/* Default implementation of valid_lang_attribute, below.  By default, there
-   are no language-specific attributes.  */
+static int is_valid_printf_arglist PARAMS ((tree));
+static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
+static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
+                                           enum expand_modifier, int, int));
+static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
+                                            enum expand_modifier, int, int));
+\f
+/* Print a warning if a constant expression had overflow in folding.
+   Invoke this function on every expression that the language
+   requires to be a constant expression.
+   Note the ANSI C standard says it is erroneous for a
+   constant expression to overflow.  */
 
-static int
-default_valid_lang_attribute (attr_name, attr_args, decl, type)
-  tree attr_name ATTRIBUTE_UNUSED;
-  tree attr_args ATTRIBUTE_UNUSED;
-  tree decl ATTRIBUTE_UNUSED;
-  tree type ATTRIBUTE_UNUSED;
+void
+constant_expression_warning (value)
+     tree value;
 {
-  return 0;
+  if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
+       || TREE_CODE (value) == VECTOR_CST
+       || TREE_CODE (value) == COMPLEX_CST)
+      && TREE_CONSTANT_OVERFLOW (value) && pedantic)
+    pedwarn ("overflow in constant expression");
 }
 
-/* Return a 1 if ATTR_NAME and ATTR_ARGS denote a valid language-specific
-   attribute for either declaration DECL or type TYPE and 0 otherwise.  */
+/* Print a warning if an expression had overflow in folding.
+   Invoke this function on every expression that
+   (1) appears in the source code, and
+   (2) might be a constant expression that overflowed, and
+   (3) is not already checked by convert_and_check;
+   however, do not invoke this function on operands of explicit casts.  */
 
-int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree))
-     = default_valid_lang_attribute;
+void
+overflow_warning (value)
+     tree value;
+{
+  if ((TREE_CODE (value) == INTEGER_CST
+       || (TREE_CODE (value) == COMPLEX_CST
+          && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
+      && TREE_OVERFLOW (value))
+    {
+      TREE_OVERFLOW (value) = 0;
+      if (skip_evaluation == 0)
+       warning ("integer overflow in expression");
+    }
+  else if ((TREE_CODE (value) == REAL_CST
+           || (TREE_CODE (value) == COMPLEX_CST
+               && TREE_CODE (TREE_REALPART (value)) == REAL_CST))
+          && TREE_OVERFLOW (value))
+    {
+      TREE_OVERFLOW (value) = 0;
+      if (skip_evaluation == 0)
+       warning ("floating point overflow in expression");
+    }
+  else if (TREE_CODE (value) == VECTOR_CST && TREE_OVERFLOW (value))
+    {
+      TREE_OVERFLOW (value) = 0;
+      if (skip_evaluation == 0)
+       warning ("vector overflow in expression");
+    }
+}
 
-/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
-   and install them in NODE, which is either a DECL (including a TYPE_DECL)
-   or a TYPE.  PREFIX_ATTRIBUTES can appear after the declaration specifiers
-   and declaration modifiers but before the declaration proper.  */
+/* Print a warning if a large constant is truncated to unsigned,
+   or if -Wconversion is used and a constant < 0 is converted to unsigned.
+   Invoke this function on every expression that might be implicitly
+   converted to an unsigned type.  */
 
 void
-decl_attributes (node, attributes, prefix_attributes)
-     tree node, attributes, prefix_attributes;
+unsigned_conversion_warning (result, operand)
+     tree result, operand;
 {
-  tree decl = 0, type = 0;
-  int is_type = 0;
-  tree a;
-
-  if (attrtab_idx == 0)
-    init_attributes ();
+  tree type = TREE_TYPE (result);
 
-  if (DECL_P (node))
+  if (TREE_CODE (operand) == INTEGER_CST
+      && TREE_CODE (type) == INTEGER_TYPE
+      && TREE_UNSIGNED (type)
+      && skip_evaluation == 0
+      && !int_fits_type_p (operand, type))
     {
-      decl = node;
-      type = TREE_TYPE (decl);
-      is_type = TREE_CODE (node) == TYPE_DECL;
+      if (!int_fits_type_p (operand, c_common_signed_type (type)))
+       /* This detects cases like converting -129 or 256 to unsigned char.  */
+       warning ("large integer implicitly truncated to unsigned type");
+      else if (warn_conversion)
+       warning ("negative integer implicitly converted to unsigned type");
     }
-  else if (TYPE_P (node))
-    type = node, is_type = 1;
-
-#ifdef PRAGMA_INSERT_ATTRIBUTES
-  /* If the code in c-pragma.c wants to insert some attributes then
-     allow it to do so.  Do this before allowing machine back ends to
-     insert attributes, so that they have the opportunity to override
-     anything done here.  */
-  PRAGMA_INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
-#endif
+}
 
-#ifdef INSERT_ATTRIBUTES
-  INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
-#endif
+/* Nonzero if constant C has a value that is permissible
+   for type TYPE (an INTEGER_TYPE).  */
 
-  attributes = chainon (prefix_attributes, attributes);
+static int
+constant_fits_type_p (c, type)
+     tree c, type;
+{
+  if (TREE_CODE (c) == INTEGER_CST)
+    return int_fits_type_p (c, type);
 
-  for (a = attributes; a; a = TREE_CHAIN (a))
-    {
-      tree name = TREE_PURPOSE (a);
-      tree args = TREE_VALUE (a);
-      int i;
-      enum attrs id;
+  c = convert (type, c);
+  return !TREE_OVERFLOW (c);
+}     
 
-      for (i = 0; i < attrtab_idx; i++)
-       if (attrtab[i].name == name)
-         break;
+/* Convert EXPR to TYPE, warning about conversion problems with constants.
+   Invoke this function on every expression that is converted implicitly,
+   i.e. because of language rules and not because of an explicit cast.  */
 
-      if (i == attrtab_idx)
-       {
-         if (! valid_machine_attribute (name, args, decl, type)
-             && ! (* valid_lang_attribute) (name, args, decl, type))
-           warning ("`%s' attribute directive ignored",
-                    IDENTIFIER_POINTER (name));
-         else if (decl != 0)
-           type = TREE_TYPE (decl);
-         continue;
-       }
-      else if (attrtab[i].decl_req && decl == 0)
-       {
-         warning ("`%s' attribute does not apply to types",
-                  IDENTIFIER_POINTER (name));
-         continue;
-       }
-      else if (list_length (args) < attrtab[i].min
-              || list_length (args) > attrtab[i].max)
+tree
+convert_and_check (type, expr)
+     tree type, expr;
+{
+  tree t = convert (type, expr);
+  if (TREE_CODE (t) == INTEGER_CST)
+    {
+      if (TREE_OVERFLOW (t))
        {
-         error ("wrong number of arguments specified for `%s' attribute",
-                IDENTIFIER_POINTER (name));
-         continue;
-       }
+         TREE_OVERFLOW (t) = 0;
 
-      id = attrtab[i].id;
-      switch (id)
-       {
-       case A_PACKED:
-         if (is_type)
-           TYPE_PACKED (type) = 1;
-         else if (TREE_CODE (decl) == FIELD_DECL)
-           DECL_PACKED (decl) = 1;
-         /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
-            used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_NOCOMMON:
-         if (TREE_CODE (decl) == VAR_DECL)
-           DECL_COMMON (decl) = 0;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_COMMON:
-         if (TREE_CODE (decl) == VAR_DECL)
-           DECL_COMMON (decl) = 1;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_NORETURN:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           TREE_THIS_VOLATILE (decl) = 1;
-         else if (TREE_CODE (type) == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-           TREE_TYPE (decl) = type
-             = build_pointer_type
-               (build_type_variant (TREE_TYPE (type),
-                                    TREE_READONLY (TREE_TYPE (type)), 1));
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+         /* Do not diagnose overflow in a constant expression merely
+            because a conversion overflowed.  */
+         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
 
-       case A_MALLOC:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           DECL_IS_MALLOC (decl) = 1;
-         /* ??? TODO: Support types.  */
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+         /* No warning for converting 0x80000000 to int.  */
+         if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
+               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+               && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
+           /* If EXPR fits in the unsigned version of TYPE,
+              don't warn unless pedantic.  */
+           if ((pedantic
+                || TREE_UNSIGNED (type)
+                || ! constant_fits_type_p (expr,
+                                           c_common_unsigned_type (type)))
+               && skip_evaluation == 0)
+             warning ("overflow in implicit constant conversion");
+       }
+      else
+       unsigned_conversion_warning (t, expr);
+    }
+  return t;
+}
+\f
+/* A node in a list that describes references to variables (EXPR), which are
+   either read accesses if WRITER is zero, or write accesses, in which case
+   WRITER is the parent of EXPR.  */
+struct tlist
+{
+  struct tlist *next;
+  tree expr, writer;
+};
 
-       case A_UNUSED:
-         if (is_type)
-           if (decl)
-             TREE_USED (decl) = 1;
-           else
-             TREE_USED (type) = 1;
-         else if (TREE_CODE (decl) == PARM_DECL
-                  || TREE_CODE (decl) == VAR_DECL
-                  || TREE_CODE (decl) == FUNCTION_DECL
-                  || TREE_CODE (decl) == LABEL_DECL)
-           TREE_USED (decl) = 1;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Used to implement a cache the results of a call to verify_tree.  We only
+   use this for SAVE_EXPRs.  */
+struct tlist_cache
+{
+  struct tlist_cache *next;
+  struct tlist *cache_before_sp;
+  struct tlist *cache_after_sp;
+  tree expr;
+};
 
-       case A_CONST:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           TREE_READONLY (decl) = 1;
-         else if (TREE_CODE (type) == POINTER_TYPE
-                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-           TREE_TYPE (decl) = type
-             = build_pointer_type
-               (build_type_variant (TREE_TYPE (type), 1,
-                                    TREE_THIS_VOLATILE (TREE_TYPE (type))));
-         else
-           warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Obstack to use when allocating tlist structures, and corresponding
+   firstobj.  */
+static struct obstack tlist_obstack;
+static char *tlist_firstobj = 0;
 
-       case A_PURE:
-         if (TREE_CODE (decl) == FUNCTION_DECL)
-           DECL_IS_PURE (decl) = 1;
-         /* ??? TODO: Support types.  */
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Keep track of the identifiers we've warned about, so we can avoid duplicate
+   warnings.  */
+static struct tlist *warned_ids;
+/* SAVE_EXPRs need special treatment.  We process them only once and then
+   cache the results.  */
+static struct tlist_cache *save_expr_cache;
 
+static void add_tlist PARAMS ((struct tlist **, struct tlist *, tree, int));
+static void merge_tlist PARAMS ((struct tlist **, struct tlist *, int));
+static void verify_tree PARAMS ((tree, struct tlist **, struct tlist **, tree));
+static int warning_candidate_p PARAMS ((tree));
+static void warn_for_collisions PARAMS ((struct tlist *));
+static void warn_for_collisions_1 PARAMS ((tree, tree, struct tlist *, int));
+static struct tlist *new_tlist PARAMS ((struct tlist *, tree, tree));
+static void verify_sequence_points PARAMS ((tree));
 
-       case A_T_UNION:
-         if (is_type
-             && TREE_CODE (type) == UNION_TYPE
-             && (decl == 0
-                 || (TYPE_FIELDS (type) != 0
-                     && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
-           TYPE_TRANSPARENT_UNION (type) = 1;
-         else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
-                  && TREE_CODE (type) == UNION_TYPE
-                  && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
-           DECL_TRANSPARENT_UNION (decl) = 1;
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Create a new struct tlist and fill in its fields.  */
+static struct tlist *
+new_tlist (next, t, writer)
+     struct tlist *next;
+     tree t;
+     tree writer;
+{
+  struct tlist *l;
+  l = (struct tlist *) obstack_alloc (&tlist_obstack, sizeof *l);
+  l->next = next;
+  l->expr = t;
+  l->writer = writer;
+  return l;
+}
 
-       case A_CONSTRUCTOR:
-         if (TREE_CODE (decl) == FUNCTION_DECL
-             && TREE_CODE (type) == FUNCTION_TYPE
-             && decl_function_context (decl) == 0)
-           {
-             DECL_STATIC_CONSTRUCTOR (decl) = 1;
-             TREE_USED (decl) = 1;
-           }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+/* Add duplicates of the nodes found in ADD to the list *TO.  If EXCLUDE_WRITER
+   is nonnull, we ignore any node we find which has a writer equal to it.  */
 
-       case A_DESTRUCTOR:
-         if (TREE_CODE (decl) == FUNCTION_DECL
-             && TREE_CODE (type) == FUNCTION_TYPE
-             && decl_function_context (decl) == 0)
-           {
-             DECL_STATIC_DESTRUCTOR (decl) = 1;
-             TREE_USED (decl) = 1;
-           }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
+static void
+add_tlist (to, add, exclude_writer, copy)
+     struct tlist **to;
+     struct tlist *add;
+     tree exclude_writer;
+     int copy;
+{
+  while (add)
+    {
+      struct tlist *next = add->next;
+      if (! copy)
+       add->next = *to;
+      if (! exclude_writer || add->writer != exclude_writer)
+       *to = copy ? new_tlist (*to, add->expr, add->writer) : add;
+      add = next;
+    }
+}
 
-       case A_MODE:
-         if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         else
-           {
-             int j;
-             const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
-             int len = strlen (p);
-             enum machine_mode mode = VOIDmode;
-             tree typefm;
-
-             if (len > 4 && p[0] == '_' && p[1] == '_'
-                 && p[len - 1] == '_' && p[len - 2] == '_')
-               {
-                 char *newp = (char *) alloca (len - 1);
+/* Merge the nodes of ADD into TO.  This merging process is done so that for
+   each variable that already exists in TO, no new node is added; however if
+   there is a write access recorded in ADD, and an occurrence on TO is only
+   a read access, then the occurrence in TO will be modified to record the
+   write.  */
 
-                 strcpy (newp, &p[2]);
-                 newp[len - 4] = '\0';
-                 p = newp;
-               }
+static void
+merge_tlist (to, add, copy)
+     struct tlist **to;
+     struct tlist *add;
+     int copy;
+{
+  struct tlist **end = to;
 
-             /* Give this decl a type with the specified mode.
-                First check for the special modes.  */
-             if (! strcmp (p, "byte"))
-               mode = byte_mode;
-             else if (!strcmp (p, "word"))
-               mode = word_mode;
-             else if (! strcmp (p, "pointer"))
-               mode = ptr_mode;
-             else
-               for (j = 0; j < NUM_MACHINE_MODES; j++)
-                 if (!strcmp (p, GET_MODE_NAME (j)))
-                   mode = (enum machine_mode) j;
-
-             if (mode == VOIDmode)
-               error ("unknown machine mode `%s'", p);
-             else if (0 == (typefm = type_for_mode (mode,
-                                                    TREE_UNSIGNED (type))))
-               error ("no data type for mode `%s'", p);
-             else
-               {
-                 if (TYPE_PRECISION (typefm) > (TREE_UNSIGNED (type)
-                                                ? TYPE_PRECISION(uintmax_type_node)
-                                                : TYPE_PRECISION(intmax_type_node))
-                     && pedantic)
-                   pedwarn ("type with more precision than %s",
-                            TREE_UNSIGNED (type) ? "uintmax_t" : "intmax_t");
-                 TREE_TYPE (decl) = type = typefm;
-                 DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0;
-                 layout_decl (decl, 0);
-               }
-           }
-         break;
+  while (*end)
+    end = &(*end)->next;
 
-       case A_SECTION:
-#ifdef ASM_OUTPUT_SECTION_NAME
-         if ((TREE_CODE (decl) == FUNCTION_DECL
-              || TREE_CODE (decl) == VAR_DECL)
-             && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
-           {
-             if (TREE_CODE (decl) == VAR_DECL
-                 && current_function_decl != NULL_TREE
-                 && ! TREE_STATIC (decl))
-               error_with_decl (decl,
-                 "section attribute cannot be specified for local variables");
-             /* The decl may have already been given a section attribute from
-                a previous declaration.  Ensure they match.  */
-             else if (DECL_SECTION_NAME (decl) != NULL_TREE
-                      && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
-                                 TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
-               error_with_decl (node,
-                                "section of `%s' conflicts with previous declaration");
-             else
-               DECL_SECTION_NAME (decl) = TREE_VALUE (args);
-           }
-         else
-           error_with_decl (node,
-                          "section attribute not allowed for `%s'");
-#else
-         error_with_decl (node,
-                 "section attributes are not supported for this target");
-#endif
-         break;
+  while (add)
+    {
+      int found = 0;
+      struct tlist *tmp2;
+      struct tlist *next = add->next;
 
-       case A_ALIGNED:
+      for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
+       if (tmp2->expr == add->expr)
          {
-           tree align_expr
-             = (args ? TREE_VALUE (args)
-                : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
-           int i;
-
-           /* Strip any NOPs of any kind.  */
-           while (TREE_CODE (align_expr) == NOP_EXPR
-                  || TREE_CODE (align_expr) == CONVERT_EXPR
-                  || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
-             align_expr = TREE_OPERAND (align_expr, 0);
-
-           if (TREE_CODE (align_expr) != INTEGER_CST)
-             {
-               error ("requested alignment is not a constant");
-               continue;
-             }
-
-           if ((i = tree_log2 (align_expr)) == -1)
-             error ("requested alignment is not a power of 2");
-           else if (i > HOST_BITS_PER_INT - 2)
-             error ("requested alignment is too large");
-           else if (is_type)
-             {
-               /* If we have a TYPE_DECL, then copy the type, so that we
-                  don't accidentally modify a builtin type.  See pushdecl.  */
-               if (decl && TREE_TYPE (decl) != error_mark_node
-                   && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
-                 {
-                   tree tt = TREE_TYPE (decl);
-                   DECL_ORIGINAL_TYPE (decl) = tt;
-                   tt = build_type_copy (tt);
-                   TYPE_NAME (tt) = decl;
-                   TREE_USED (tt) = TREE_USED (decl);
-                   TREE_TYPE (decl) = tt;
-                   type = tt;
-                 }
-
-               TYPE_ALIGN (type) = (1 << i) * BITS_PER_UNIT;
-               TYPE_USER_ALIGN (type) = 1;
-             }
-           else if (TREE_CODE (decl) != VAR_DECL
-                    && TREE_CODE (decl) != FIELD_DECL)
-             error_with_decl (decl,
-                              "alignment may not be specified for `%s'");
-           else
-             {
-               DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
-               DECL_USER_ALIGN (decl) = 1;
-             }
+           found = 1;
+           if (! tmp2->writer)
+             tmp2->writer = add->writer;
          }
-         break;
-
-       case A_FORMAT:
-         decl_handle_format_attribute (decl, args);
-         break;
-
-       case A_FORMAT_ARG:
-         decl_handle_format_arg_attribute (decl, args);
-         break;
-
-       case A_WEAK:
-         declare_weak (decl);
-         break;
-
-       case A_ALIAS:
-         if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
-             || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
-           error_with_decl (decl,
-                            "`%s' defined both normally and as an alias");
-         else if (decl_function_context (decl) == 0)
-           {
-             tree id;
-
-             id = TREE_VALUE (args);
-             if (TREE_CODE (id) != STRING_CST)
-               {
-                 error ("alias arg not a string");
-                 break;
-               }
-             id = get_identifier (TREE_STRING_POINTER (id));
-             /* This counts as a use of the object pointed to.  */
-             TREE_USED (id) = 1;
-
-             if (TREE_CODE (decl) == FUNCTION_DECL)
-               DECL_INITIAL (decl) = error_mark_node;
-             else
-               DECL_EXTERNAL (decl) = 0;
-             assemble_alias (decl, id);
-           }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       case A_NO_CHECK_MEMORY_USAGE:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
-           {
-             error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
-           }
-         else if (DECL_INITIAL (decl))
-           {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
-           }
-         else
-           DECL_NO_CHECK_MEMORY_USAGE (decl) = 1;
-         break;
-
-       case A_NO_INSTRUMENT_FUNCTION:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
-           {
-             error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
-           }
-         else if (DECL_INITIAL (decl))
-           {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
-           }
-         else
-           DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
-         break;
-
-        case A_NO_LIMIT_STACK:
-         if (TREE_CODE (decl) != FUNCTION_DECL)
-           {
-             error_with_decl (decl,
-                              "`%s' attribute applies only to functions",
-                              IDENTIFIER_POINTER (name));
-           }
-         else if (DECL_INITIAL (decl))
-           {
-             error_with_decl (decl,
-                              "can't set `%s' attribute after definition",
-                              IDENTIFIER_POINTER (name));
-           }
-         else
-           DECL_NO_LIMIT_STACK (decl) = 1;
-         break;
+      if (! found)
+       {
+         *end = copy ? add : new_tlist (NULL, add->expr, add->writer);
+         end = &(*end)->next;
+         *end = 0;
        }
+      add = next;
     }
 }
 
-/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
-   lists.  SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
-
-   The head of the declspec list is stored in DECLSPECS.
-   The head of the attribute list is stored in PREFIX_ATTRIBUTES.
-
-   Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
-   the list elements.  We drop the containing TREE_LIST nodes and link the
-   resulting attributes together the way decl_attributes expects them.  */
+/* WRITTEN is a variable, WRITER is its parent.  Warn if any of the variable
+   references in list LIST conflict with it, excluding reads if ONLY writers
+   is nonzero.  */
 
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
-     tree specs_attrs;
-     tree *declspecs, *prefix_attributes;
+static void
+warn_for_collisions_1 (written, writer, list, only_writes)
+     tree written, writer;
+     struct tlist *list;
+     int only_writes;
 {
-  tree t, s, a, next, specs, attrs;
-
-  /* This can happen after an __extension__ in pedantic mode.  */
-  if (specs_attrs != NULL_TREE 
-      && TREE_CODE (specs_attrs) == INTEGER_CST)
-    {
-      *declspecs = NULL_TREE;
-      *prefix_attributes = NULL_TREE;
-      return;
-    }
+  struct tlist *tmp;
 
-  /* This can happen in c++ (eg: decl: typespec initdecls ';').  */
-  if (specs_attrs != NULL_TREE
-      && TREE_CODE (specs_attrs) != TREE_LIST)
-    {
-      *declspecs = specs_attrs;
-      *prefix_attributes = NULL_TREE;
+  /* Avoid duplicate warnings.  */
+  for (tmp = warned_ids; tmp; tmp = tmp->next)
+    if (tmp->expr == written)
       return;
-    }
-
-  /* Remember to keep the lists in the same order, element-wise.  */
 
-  specs = s = NULL_TREE;
-  attrs = a = NULL_TREE;
-  for (t = specs_attrs; t; t = next)
+  while (list)
     {
-      next = TREE_CHAIN (t);
-      /* Declspecs have a non-NULL TREE_VALUE.  */
-      if (TREE_VALUE (t) != NULL_TREE)
-       {
-         if (specs == NULL_TREE)
-           specs = s = t;
-         else
-           {
-             TREE_CHAIN (s) = t;
-             s = t;
-           }
-       }
-      else
+      if (list->expr == written
+         && list->writer != writer
+         && (! only_writes || list->writer))
        {
-         if (attrs == NULL_TREE)
-           attrs = a = TREE_PURPOSE (t);
-         else
-           {
-             TREE_CHAIN (a) = TREE_PURPOSE (t);
-             a = TREE_PURPOSE (t);
-           }
-         /* More attrs can be linked here, move A to the end.  */
-         while (TREE_CHAIN (a) != NULL_TREE)
-           a = TREE_CHAIN (a);
+         warned_ids = new_tlist (warned_ids, written, NULL_TREE);
+         warning ("operation on `%s' may be undefined",
+                  IDENTIFIER_POINTER (DECL_NAME (list->expr)));
        }
+      list = list->next;
     }
-
-  /* Terminate the lists.  */
-  if (s != NULL_TREE)
-    TREE_CHAIN (s) = NULL_TREE;
-  if (a != NULL_TREE)
-    TREE_CHAIN (a) = NULL_TREE;
-
-  /* All done.  */
-  *declspecs = specs;
-  *prefix_attributes = attrs;
 }
 
-/* Strip attributes from SPECS_ATTRS, a list of declspecs and attributes.
-   This function is used by the parser when a rule will accept attributes
-   in a particular position, but we don't want to support that just yet.
-
-   A warning is issued for every ignored attribute.  */
+/* Given a list LIST of references to variables, find whether any of these
+   can cause conflicts due to missing sequence points.  */
 
-tree
-strip_attrs (specs_attrs)
-     tree specs_attrs;
+static void
+warn_for_collisions (list)
+     struct tlist *list;
 {
-  tree specs, attrs;
-
-  split_specs_attrs (specs_attrs, &specs, &attrs);
-
-  while (attrs)
+  struct tlist *tmp;
+  
+  for (tmp = list; tmp; tmp = tmp->next)
     {
-      warning ("`%s' attribute ignored",
-              IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
-      attrs = TREE_CHAIN (attrs);
+      if (tmp->writer)
+       warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0);
     }
-
-  return specs;
-}
-\f
-static int is_valid_printf_arglist PARAMS ((tree));
-static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
-static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
-                                           enum expand_modifier, int));
-static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
-                                            enum expand_modifier, int));
-\f
-/* Print a warning if a constant expression had overflow in folding.
-   Invoke this function on every expression that the language
-   requires to be a constant expression.
-   Note the ANSI C standard says it is erroneous for a
-   constant expression to overflow.  */
-
-void
-constant_expression_warning (value)
-     tree value;
-{
-  if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
-       || TREE_CODE (value) == COMPLEX_CST)
-      && TREE_CONSTANT_OVERFLOW (value) && pedantic)
-    pedwarn ("overflow in constant expression");
 }
 
-/* Print a warning if an expression had overflow in folding.
-   Invoke this function on every expression that
-   (1) appears in the source code, and
-   (2) might be a constant expression that overflowed, and
-   (3) is not already checked by convert_and_check;
-   however, do not invoke this function on operands of explicit casts.  */
-
-void
-overflow_warning (value)
-     tree value;
+/* Return nonzero if X is a tree that can be verified by the sequence point
+   warnings.  */
+static int
+warning_candidate_p (x)
+     tree x;
 {
-  if ((TREE_CODE (value) == INTEGER_CST
-       || (TREE_CODE (value) == COMPLEX_CST
-          && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
-      && TREE_OVERFLOW (value))
-    {
-      TREE_OVERFLOW (value) = 0;
-      if (skip_evaluation == 0)
-       warning ("integer overflow in expression");
-    }
-  else if ((TREE_CODE (value) == REAL_CST
-           || (TREE_CODE (value) == COMPLEX_CST
-               && TREE_CODE (TREE_REALPART (value)) == REAL_CST))
-          && TREE_OVERFLOW (value))
-    {
-      TREE_OVERFLOW (value) = 0;
-      if (skip_evaluation == 0)
-       warning ("floating point overflow in expression");
-    }
+  return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
 }
 
-/* Print a warning if a large constant is truncated to unsigned,
-   or if -Wconversion is used and a constant < 0 is converted to unsigned.
-   Invoke this function on every expression that might be implicitly
-   converted to an unsigned type.  */
+/* Walk the tree X, and record accesses to variables.  If X is written by the
+   parent tree, WRITER is the parent.
+   We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP.  If this
+   expression or its only operand forces a sequence point, then everything up
+   to the sequence point is stored in PBEFORE_SP.  Everything else gets stored
+   in PNO_SP.
+   Once we return, we will have emitted warnings if any subexpression before
+   such a sequence point could be undefined.  On a higher level, however, the
+   sequence point may not be relevant, and we'll merge the two lists.
 
-void
-unsigned_conversion_warning (result, operand)
-     tree result, operand;
-{
-  if (TREE_CODE (operand) == INTEGER_CST
-      && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
-      && TREE_UNSIGNED (TREE_TYPE (result))
-      && skip_evaluation == 0
-      && !int_fits_type_p (operand, TREE_TYPE (result)))
-    {
-      if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
-       /* This detects cases like converting -129 or 256 to unsigned char.  */
-       warning ("large integer implicitly truncated to unsigned type");
-      else if (warn_conversion)
-       warning ("negative integer implicitly converted to unsigned type");
-    }
-}
+   Example: (b++, a) + b;
+   The call that processes the COMPOUND_EXPR will store the increment of B
+   in PBEFORE_SP, and the use of A in PNO_SP.  The higher-level call that
+   processes the PLUS_EXPR will need to merge the two lists so that
+   eventually, all accesses end up on the same list (and we'll warn about the
+   unordered subexpressions b++ and b.
 
-/* Nonzero if constant C has a value that is permissible
-   for type TYPE (an INTEGER_TYPE).  */
+   A note on merging.  If we modify the former example so that our expression
+   becomes
+     (b++, b) + a
+   care must be taken not simply to add all three expressions into the final
+   PNO_SP list.  The function merge_tlist takes care of that by merging the
+   before-SP list of the COMPOUND_EXPR into its after-SP list in a special
+   way, so that no more than one access to B is recorded.  */
 
-static int
-constant_fits_type_p (c, type)
-     tree c, type;
+static void
+verify_tree (x, pbefore_sp, pno_sp, writer)
+     tree x;
+     struct tlist **pbefore_sp, **pno_sp;
+     tree writer;
 {
-  if (TREE_CODE (c) == INTEGER_CST)
-    return int_fits_type_p (c, type);
+  struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
+  enum tree_code code;
+  char class;
 
-  c = convert (type, c);
-  return !TREE_OVERFLOW (c);
-}     
+  /* X may be NULL if it is the operand of an empty statement expression
+     ({ }).  */
+  if (x == NULL)
+    return;
 
-/* Convert EXPR to TYPE, warning about conversion problems with constants.
-   Invoke this function on every expression that is converted implicitly,
-   i.e. because of language rules and not because of an explicit cast.  */
+ restart:
+  code = TREE_CODE (x);
+  class = TREE_CODE_CLASS (code);
 
-tree
-convert_and_check (type, expr)
-     tree type, expr;
-{
-  tree t = convert (type, expr);
-  if (TREE_CODE (t) == INTEGER_CST)
+  if (warning_candidate_p (x))
     {
-      if (TREE_OVERFLOW (t))
-       {
-         TREE_OVERFLOW (t) = 0;
-
-         /* Do not diagnose overflow in a constant expression merely
-            because a conversion overflowed.  */
-         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
-
-         /* No warning for converting 0x80000000 to int.  */
-         if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
-               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
-               && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
-           /* If EXPR fits in the unsigned version of TYPE,
-              don't warn unless pedantic.  */
-           if ((pedantic
-                || TREE_UNSIGNED (type)
-                || ! constant_fits_type_p (expr, unsigned_type (type)))
-               && skip_evaluation == 0)
-             warning ("overflow in implicit constant conversion");
-       }
-      else
-       unsigned_conversion_warning (t, expr);
+      *pno_sp = new_tlist (*pno_sp, x, writer);
+      return;
     }
-  return t;
-}
-\f
-/* A node in a list that describes references to variables (EXPR), which are
-   either read accesses if WRITER is zero, or write accesses, in which case
-   WRITER is the parent of EXPR.  */
-struct tlist
-{
-  struct tlist *next;
-  tree expr, writer;
-};
 
-/* Used to implement a cache the results of a call to verify_tree.  We only
-   use this for SAVE_EXPRs.  */
-struct tlist_cache
-{
-  struct tlist_cache *next;
-  struct tlist *cache_before_sp;
-  struct tlist *cache_after_sp;
-  tree expr;
-};
+  switch (code)
+    {
+    case CONSTRUCTOR:
+      return;
 
-/* Obstack to use when allocating tlist structures, and corresponding
-   firstobj.  */
-static struct obstack tlist_obstack;
-static char *tlist_firstobj = 0;
+    case COMPOUND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      tmp_before = tmp_nosp = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_nosp, 0);
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      return;
 
-/* Keep track of the identifiers we've warned about, so we can avoid duplicate
-   warnings.  */
-static struct tlist *warned_ids;
-/* SAVE_EXPRs need special treatment.  We process them only once and then
-   cache the results.  */
-static struct tlist_cache *save_expr_cache;
+    case COND_EXPR:
+      tmp_before = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_list2, 1);
 
-static void add_tlist PARAMS ((struct tlist **, struct tlist *, tree, int));
-static void merge_tlist PARAMS ((struct tlist **, struct tlist *, int));
-static void verify_tree PARAMS ((tree, struct tlist **, struct tlist **, tree));
-static int warning_candidate_p PARAMS ((tree));
-static void warn_for_collisions PARAMS ((struct tlist *));
-static void warn_for_collisions_1 PARAMS ((tree, tree, struct tlist *, int));
-static struct tlist *new_tlist PARAMS ((struct tlist *, tree, tree));
-static void verify_sequence_points PARAMS ((tree));
+      tmp_list3 = tmp_nosp = 0;
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
 
-/* Create a new struct tlist and fill in its fields.  */
-static struct tlist *
-new_tlist (next, t, writer)
-     struct tlist *next;
-     tree t;
-     tree writer;
-{
-  struct tlist *l;
-  l = (struct tlist *) obstack_alloc (&tlist_obstack, sizeof *l);
-  l->next = next;
-  l->expr = t;
-  l->writer = writer;
-  return l;
-}
+      tmp_list3 = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      /* Rather than add both tmp_nosp and tmp_list2, we have to merge the
+        two first, to avoid warning for (a ? b++ : b++).  */
+      merge_tlist (&tmp_nosp, tmp_list2, 0);
+      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+      return;
 
-/* Add duplicates of the nodes found in ADD to the list *TO.  If EXCLUDE_WRITER
-   is nonnull, we ignore any node we find which has a writer equal to it.  */
-
-static void
-add_tlist (to, add, exclude_writer, copy)
-     struct tlist **to;
-     struct tlist *add;
-     tree exclude_writer;
-     int copy;
-{
-  while (add)
-    {
-      struct tlist *next = add->next;
-      if (! copy)
-       add->next = *to;
-      if (! exclude_writer || add->writer != exclude_writer)
-       *to = copy ? new_tlist (*to, add->expr, add->writer) : add;
-      add = next;
-    }
-}
-
-/* Merge the nodes of ADD into TO.  This merging process is done so that for
-   each variable that already exists in TO, no new node is added; however if
-   there is a write access recorded in ADD, and an occurrence on TO is only
-   a read access, then the occurrence in TO will be modified to record the
-   write.  */
-
-static void
-merge_tlist (to, add, copy)
-     struct tlist **to;
-     struct tlist *add;
-     int copy;
-{
-  struct tlist **end = to;
-
-  while (*end)
-    end = &(*end)->next;
-
-  while (add)
-    {
-      int found = 0;
-      struct tlist *tmp2;
-      struct tlist *next = add->next;
-
-      for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
-       if (tmp2->expr == add->expr)
-         {
-           found = 1;
-           if (! tmp2->writer)
-             tmp2->writer = add->writer;
-         }
-      if (! found)
-       {
-         *end = copy ? add : new_tlist (NULL, add->expr, add->writer);
-         end = &(*end)->next;
-         *end = 0;
-       }
-      add = next;
-    }
-}
-
-/* WRITTEN is a variable, WRITER is its parent.  Warn if any of the variable
-   references in list LIST conflict with it, excluding reads if ONLY writers
-   is nonzero.  */
-
-static void
-warn_for_collisions_1 (written, writer, list, only_writes)
-     tree written, writer;
-     struct tlist *list;
-     int only_writes;
-{
-  struct tlist *tmp;
-
-  /* Avoid duplicate warnings.  */
-  for (tmp = warned_ids; tmp; tmp = tmp->next)
-    if (tmp->expr == written)
-      return;
-
-  while (list)
-    {
-      if (list->expr == written
-         && list->writer != writer
-         && (! only_writes || list->writer))
-       {
-         warned_ids = new_tlist (warned_ids, written, NULL_TREE);
-         warning ("operation on `%s' may be undefined",
-                  IDENTIFIER_POINTER (DECL_NAME (list->expr)));
-       }
-      list = list->next;
-    }
-}
-
-/* Given a list LIST of references to variables, find whether any of these
-   can cause conflicts due to missing sequence points.  */
-
-static void
-warn_for_collisions (list)
-     struct tlist *list;
-{
-  struct tlist *tmp;
-  
-  for (tmp = list; tmp; tmp = tmp->next)
-    {
-      if (tmp->writer)
-       warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0);
-    }
-}
-
-/* Return nonzero if X is a tree that can be verified by the sequence poitn
-   warnings.  */
-static int
-warning_candidate_p (x)
-     tree x;
-{
-  return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
-}
-
-/* Walk the tree X, and record accesses to variables.  If X is written by the
-   parent tree, WRITER is the parent.
-   We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP.  If this
-   expression or its only operand forces a sequence point, then everything up
-   to the sequence point is stored in PBEFORE_SP.  Everything else gets stored
-   in PNO_SP.
-   Once we return, we will have emitted warnings if any subexpression before
-   such a sequence point could be undefined.  On a higher level, however, the
-   sequence point may not be relevant, and we'll merge the two lists.
-
-   Example: (b++, a) + b;
-   The call that processes the COMPOUND_EXPR will store the increment of B
-   in PBEFORE_SP, and the use of A in PNO_SP.  The higher-level call that
-   processes the PLUS_EXPR will need to merge the two lists so that
-   eventually, all accesses end up on the same list (and we'll warn about the
-   unordered subexpressions b++ and b.
-
-   A note on merging.  If we modify the former example so that our expression
-   becomes
-     (b++, b) + a
-   care must be taken not simply to add all three expressions into the final
-   PNO_SP list.  The function merge_tlist takes care of that by merging the
-   before-SP list of the COMPOUND_EXPR into its after-SP list in a special
-   way, so that no more than one access to B is recorded.  */
-
-static void
-verify_tree (x, pbefore_sp, pno_sp, writer)
-     tree x;
-     struct tlist **pbefore_sp, **pno_sp;
-     tree writer;
-{
-  struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
-  enum tree_code code;
-  char class;
-
- restart:
-  code = TREE_CODE (x);
-  class = TREE_CODE_CLASS (code);
-
-  if (warning_candidate_p (x))
-    {
-      *pno_sp = new_tlist (*pno_sp, x, writer);
-      return;
-    }
-
-  switch (code)
-    {
-    case CONSTRUCTOR:
-      return;
-
-    case COMPOUND_EXPR:
-    case TRUTH_ANDIF_EXPR:
-    case TRUTH_ORIF_EXPR:
-      tmp_before = tmp_nosp = tmp_list3 = 0;
-      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
-      warn_for_collisions (tmp_nosp);
-      merge_tlist (pbefore_sp, tmp_before, 0);
-      merge_tlist (pbefore_sp, tmp_nosp, 0);
-      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE);
-      merge_tlist (pbefore_sp, tmp_list3, 0);
-      return;
-
-    case COND_EXPR:
-      tmp_before = tmp_list2 = 0;
-      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE);
-      warn_for_collisions (tmp_list2);
-      merge_tlist (pbefore_sp, tmp_before, 0);
-      merge_tlist (pbefore_sp, tmp_list2, 1);
-
-      tmp_list3 = tmp_nosp = 0;
-      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE);
-      warn_for_collisions (tmp_nosp);
-      merge_tlist (pbefore_sp, tmp_list3, 0);
-
-      tmp_list3 = tmp_list2 = 0;
-      verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE);
-      warn_for_collisions (tmp_list2);
-      merge_tlist (pbefore_sp, tmp_list3, 0);
-      /* Rather than add both tmp_nosp and tmp_list2, we have to merge the
-        two first, to avoid warning for (a ? b++ : b++).  */
-      merge_tlist (&tmp_nosp, tmp_list2, 0);
-      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
-      return;
-
-    case PREDECREMENT_EXPR:
-    case PREINCREMENT_EXPR:
-    case POSTDECREMENT_EXPR:
-    case POSTINCREMENT_EXPR:
-      verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x);
-      return;
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x);
+      return;
 
     case MODIFY_EXPR:
       tmp_before = tmp_nosp = tmp_list3 = 0;
@@ -1656,7 +1389,8 @@ c_expand_expr_stmt (expr)
 {
   /* Do default conversion if safe and possibly important,
      in case within ({...}).  */
-  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE && lvalue_p (expr))
+  if ((TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+       && (flag_isoc99 || lvalue_p (expr)))
       || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
     expr = default_conversion (expr);
 
@@ -1715,7 +1449,7 @@ check_case_value (value)
    that is unsigned if UNSIGNEDP is nonzero, otherwise signed.  */
 
 tree
-type_for_size (bits, unsignedp)
+c_common_type_for_size (bits, unsignedp)
      unsigned bits;
      int unsignedp;
 {
@@ -1759,7 +1493,7 @@ type_for_size (bits, unsignedp)
    then UNSIGNEDP selects between signed and unsigned types.  */
 
 tree
-type_for_mode (mode, unsignedp)
+c_common_type_for_mode (mode, unsignedp)
      enum machine_mode mode;
      int unsignedp;
 {
@@ -1782,16 +1516,16 @@ type_for_mode (mode, unsignedp)
     return unsignedp ? widest_unsigned_literal_type_node
                      : widest_integer_literal_type_node;
 
-  if (mode == TYPE_MODE (intQI_type_node))
+  if (mode == QImode)
     return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
 
-  if (mode == TYPE_MODE (intHI_type_node))
+  if (mode == HImode)
     return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
 
-  if (mode == TYPE_MODE (intSI_type_node))
+  if (mode == SImode)
     return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
 
-  if (mode == TYPE_MODE (intDI_type_node))
+  if (mode == DImode)
     return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
 
 #if HOST_BITS_PER_WIDE_INT >= 64
@@ -1815,24 +1549,44 @@ type_for_mode (mode, unsignedp)
     return build_pointer_type (integer_type_node);
 
 #ifdef VECTOR_MODE_SUPPORTED_P
-  if (mode == TYPE_MODE (V4SF_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
-    return V4SF_type_node;
-  if (mode == TYPE_MODE (V4SI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
-    return V4SI_type_node;
-  if (mode == TYPE_MODE (V2SI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
-    return V2SI_type_node;
-  if (mode == TYPE_MODE (V4HI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
-    return V4HI_type_node;
-  if (mode == TYPE_MODE (V8QI_type_node) && VECTOR_MODE_SUPPORTED_P (mode))
-    return V8QI_type_node;
+  if (VECTOR_MODE_SUPPORTED_P (mode))
+    {
+      switch (mode)
+       {
+       case V16QImode:
+         return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node;
+       case V8HImode:
+         return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node;
+       case V4SImode:
+         return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node;
+       case V2DImode:
+         return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node;
+       case V2SImode:
+         return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node;
+       case V4HImode:
+         return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node;
+       case V8QImode:
+         return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node;
+       case V16SFmode:
+         return V16SF_type_node;
+       case V4SFmode:
+         return V4SF_type_node;
+       case V2SFmode:
+         return V2SF_type_node;
+       case V2DFmode:
+         return V2DF_type_node;
+       default:
+         break;
+       }
+    }
 #endif
 
   return 0;
 }
 
-/* Return an unsigned type the same as TYPE in other respects. */
+/* Return an unsigned type the same as TYPE in other respects.  */
 tree
-unsigned_type (type)
+c_common_unsigned_type (type)
      tree type;
 {
   tree type1 = TYPE_MAIN_VARIANT (type);
@@ -1861,13 +1615,13 @@ unsigned_type (type)
   if (type1 == intQI_type_node)
     return unsigned_intQI_type_node;
 
-  return signed_or_unsigned_type (1, type);
+  return c_common_signed_or_unsigned_type (1, type);
 }
 
 /* Return a signed type the same as TYPE in other respects.  */
 
 tree
-signed_type (type)
+c_common_signed_type (type)
      tree type;
 {
   tree type1 = TYPE_MAIN_VARIANT (type);
@@ -1896,14 +1650,14 @@ signed_type (type)
   if (type1 == unsigned_intQI_type_node)
     return intQI_type_node;
 
-  return signed_or_unsigned_type (0, type);
+  return c_common_signed_or_unsigned_type (0, type);
 }
 
 /* Return a type the same as TYPE except unsigned or
    signed according to UNSIGNEDP.  */
 
 tree
-signed_or_unsigned_type (unsignedp, type)
+c_common_signed_or_unsigned_type (unsignedp, type)
      int unsignedp;
      tree type;
 {
@@ -1925,6 +1679,20 @@ signed_or_unsigned_type (unsignedp, type)
   if (TYPE_PRECISION (type) == TYPE_PRECISION (widest_integer_literal_type_node))
     return (unsignedp ? widest_unsigned_literal_type_node
            : widest_integer_literal_type_node);
+
+#if HOST_BITS_PER_WIDE_INT >= 64
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (intTI_type_node))
+    return unsignedp ? unsigned_intTI_type_node : intTI_type_node;
+#endif
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (intDI_type_node))
+    return unsignedp ? unsigned_intDI_type_node : intDI_type_node;
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (intSI_type_node))
+    return unsignedp ? unsigned_intSI_type_node : intSI_type_node;
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (intHI_type_node))
+    return unsignedp ? unsigned_intHI_type_node : intHI_type_node;
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (intQI_type_node))
+    return unsignedp ? unsigned_intQI_type_node : intQI_type_node;
+
   return type;
 }
 \f
@@ -1957,14 +1725,15 @@ min_precision (value, unsignedp)
   return log + 1 + ! unsignedp;
 }
 \f
-/* Print an error message for invalid operands to arith operation CODE.
-   NOP_EXPR is used as a special case (see truthvalue_conversion).  */
+/* Print an error message for invalid operands to arith operation
+   CODE.  NOP_EXPR is used as a special case (see
+   c_common_truthvalue_conversion).  */
 
 void
 binary_op_error (code)
      enum tree_code code;
 {
-  register const char *opname;
+  const char *opname;
 
   switch (code)
     {
@@ -2043,7 +1812,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
      tree *restype_ptr;
      enum tree_code *rescode_ptr;
 {
-  register tree type;
+  tree type;
   tree op0 = *op0_ptr;
   tree op1 = *op1_ptr;
   int unsignedp0, unsignedp1;
@@ -2076,8 +1845,8 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
   if (TREE_CONSTANT (primop0)
       && ! integer_zerop (primop1) && ! real_zerop (primop1))
     {
-      register tree tem = primop0;
-      register int temi = unsignedp0;
+      tree tem = primop0;
+      int temi = unsignedp0;
       primop0 = primop1;
       primop1 = tem;
       tem = op0;
@@ -2138,19 +1907,20 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
       int unsignedp = TREE_UNSIGNED (*restype_ptr);
       tree val;
 
-      type = signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0));
+      type = c_common_signed_or_unsigned_type (unsignedp0,
+                                              TREE_TYPE (primop0));
 
       /* If TYPE is an enumeration, then we need to get its min/max
         values from it's underlying integral type, not the enumerated
         type itself.  */
       if (TREE_CODE (type) == ENUMERAL_TYPE)
-       type = type_for_size (TYPE_PRECISION (type), unsignedp0);
+       type = c_common_type_for_size (TYPE_PRECISION (type), unsignedp0);
 
       maxval = TYPE_MAX_VALUE (type);
       minval = TYPE_MIN_VALUE (type);
 
       if (unsignedp && !unsignedp0)
-       *restype_ptr = signed_type (*restype_ptr);
+       *restype_ptr = c_common_signed_type (*restype_ptr);
 
       if (TREE_TYPE (primop1) != *restype_ptr)
        primop1 = convert (*restype_ptr, primop1);
@@ -2247,22 +2017,11 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
              default:
                break;
              }
-         type = unsigned_type (type);
-       }
-
-      if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
-       {
-         /* This is the case of (char)x >?< 0x80, which people used to use
-            expecting old C compilers to change the 0x80 into -0x80.  */
-         if (val == boolean_false_node)
-           warning ("comparison is always false due to limited range of data type");
-         if (val == boolean_true_node)
-           warning ("comparison is always true due to limited range of data type");
+         type = c_common_unsigned_type (type);
        }
 
-      if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
+      if (TREE_CODE (primop0) != INTEGER_CST)
        {
-         /* This is the case of (unsigned char)x >?< -1 or < 0.  */
          if (val == boolean_false_node)
            warning ("comparison is always false due to limited range of data type");
          if (val == boolean_true_node)
@@ -2299,15 +2058,19 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
           && TYPE_PRECISION (TREE_TYPE (primop1)) < TYPE_PRECISION (*restype_ptr))
     {
       type = common_type (TREE_TYPE (primop0), TREE_TYPE (primop1));
-      type = signed_or_unsigned_type (unsignedp0
-                                     || TREE_UNSIGNED (*restype_ptr),
-                                     type);
+      type = c_common_signed_or_unsigned_type (unsignedp0
+                                              || TREE_UNSIGNED (*restype_ptr),
+                                              type);
       /* Make sure shorter operand is extended the right way
         to match the longer operand.  */
-      primop0 = convert (signed_or_unsigned_type (unsignedp0, TREE_TYPE (primop0)),
-                        primop0);
-      primop1 = convert (signed_or_unsigned_type (unsignedp1, TREE_TYPE (primop1)),
-                        primop1);
+      primop0
+       = convert (c_common_signed_or_unsigned_type (unsignedp0,
+                                                    TREE_TYPE (primop0)),
+                  primop0);
+      primop1
+       = convert (c_common_signed_or_unsigned_type (unsignedp1,
+                                                    TREE_TYPE (primop1)),
+                  primop1);
     }
   else
     {
@@ -2330,7 +2093,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
                 so suppress the warning.  */
              if (extra_warnings && !in_system_header
                  && ! (TREE_CODE (primop0) == INTEGER_CST
-                       && ! TREE_OVERFLOW (convert (signed_type (type),
+                       && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
                                                     primop0))))
                warning ("comparison of unsigned expression >= 0 is always true");
              value = boolean_true_node;
@@ -2339,7 +2102,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
            case LT_EXPR:
              if (extra_warnings && !in_system_header
                  && ! (TREE_CODE (primop0) == INTEGER_CST
-                       && ! TREE_OVERFLOW (convert (signed_type (type),
+                       && ! TREE_OVERFLOW (convert (c_common_signed_type (type),
                                                     primop0))))
                warning ("comparison of unsigned expression < 0 is always false");
              value = boolean_false_node;
@@ -2368,6 +2131,107 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
   return 0;
 }
 \f
+/* Return a tree for the sum or difference (RESULTCODE says which)
+   of pointer PTROP and integer INTOP.  */
+
+tree
+pointer_int_sum (resultcode, ptrop, intop)
+     enum tree_code resultcode;
+     tree ptrop, intop;
+{
+  tree size_exp;
+
+  tree result;
+  tree folded;
+
+  /* The result is a pointer of the same type that is being added.  */
+
+  tree result_type = TREE_TYPE (ptrop);
+
+  if (TREE_CODE (TREE_TYPE (result_type)) == VOID_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer of type `void *' used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == FUNCTION_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to a function used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == METHOD_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to member function used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else if (TREE_CODE (TREE_TYPE (result_type)) == OFFSET_TYPE)
+    {
+      if (pedantic || warn_pointer_arith)
+       pedwarn ("pointer to a member used in arithmetic");
+      size_exp = integer_one_node;
+    }
+  else
+    size_exp = size_in_bytes (TREE_TYPE (result_type));
+
+  /* If what we are about to multiply by the size of the elements
+     contains a constant term, apply distributive law
+     and multiply that constant term separately.
+     This helps produce common subexpressions.  */
+
+  if ((TREE_CODE (intop) == PLUS_EXPR || TREE_CODE (intop) == MINUS_EXPR)
+      && ! TREE_CONSTANT (intop)
+      && TREE_CONSTANT (TREE_OPERAND (intop, 1))
+      && TREE_CONSTANT (size_exp)
+      /* If the constant comes from pointer subtraction,
+        skip this optimization--it would cause an error.  */
+      && TREE_CODE (TREE_TYPE (TREE_OPERAND (intop, 0))) == INTEGER_TYPE
+      /* If the constant is unsigned, and smaller than the pointer size,
+        then we must skip this optimization.  This is because it could cause
+        an overflow error if the constant is negative but INTOP is not.  */
+      && (! TREE_UNSIGNED (TREE_TYPE (intop))
+         || (TYPE_PRECISION (TREE_TYPE (intop))
+             == TYPE_PRECISION (TREE_TYPE (ptrop)))))
+    {
+      enum tree_code subcode = resultcode;
+      tree int_type = TREE_TYPE (intop);
+      if (TREE_CODE (intop) == MINUS_EXPR)
+       subcode = (subcode == PLUS_EXPR ? MINUS_EXPR : PLUS_EXPR);
+      /* Convert both subexpression types to the type of intop,
+        because weird cases involving pointer arithmetic
+        can result in a sum or difference with different type args.  */
+      ptrop = build_binary_op (subcode, ptrop,
+                              convert (int_type, TREE_OPERAND (intop, 1)), 1);
+      intop = convert (int_type, TREE_OPERAND (intop, 0));
+    }
+
+  /* Convert the integer argument to a type the same size as sizetype
+     so the multiply won't overflow spuriously.  */
+
+  if (TYPE_PRECISION (TREE_TYPE (intop)) != TYPE_PRECISION (sizetype)
+      || TREE_UNSIGNED (TREE_TYPE (intop)) != TREE_UNSIGNED (sizetype))
+    intop = convert (c_common_type_for_size (TYPE_PRECISION (sizetype), 
+                                            TREE_UNSIGNED (sizetype)), intop);
+
+  /* Replace the integer argument with a suitable product by the object size.
+     Do this multiplication as signed, then convert to the appropriate
+     pointer type (actually unsigned integral).  */
+
+  intop = convert (result_type,
+                  build_binary_op (MULT_EXPR, intop,
+                                   convert (TREE_TYPE (intop), size_exp), 1));
+
+  /* Create the sum or difference.  */
+
+  result = build (resultcode, result_type, ptrop, intop);
+
+  folded = fold (result);
+  if (folded == result)
+    TREE_CONSTANT (folded) = TREE_CONSTANT (ptrop) & TREE_CONSTANT (intop);
+  return folded;
+}
+\f
 /* Prepare expr to be an argument of a TRUTH_NOT_EXPR,
    or validate its data type for an `if' or `while' statement or ?..: exp.
 
@@ -2380,7 +2244,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
    The resulting type should always be `boolean_type_node'.  */
 
 tree
-truthvalue_conversion (expr)
+c_common_truthvalue_conversion (expr)
      tree expr;
 {
   if (TREE_CODE (expr) == ERROR_MARK)
@@ -2431,7 +2295,7 @@ truthvalue_conversion (expr)
       return real_zerop (expr) ? boolean_false_node : boolean_true_node;
 
     case ADDR_EXPR:
-      /* If we are taking the address of a external decl, it might be zero
+      /* If we are taking the address of an external decl, it might be zero
         if it is weak, so we cannot optimize.  */
       if (DECL_P (TREE_OPERAND (expr, 0))
          && DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
@@ -2446,8 +2310,8 @@ truthvalue_conversion (expr)
     case COMPLEX_EXPR:
       return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
                               ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
-                             truthvalue_conversion (TREE_OPERAND (expr, 0)),
-                             truthvalue_conversion (TREE_OPERAND (expr, 1)),
+               c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+               c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
                              0);
 
     case NEGATE_EXPR:
@@ -2455,7 +2319,7 @@ truthvalue_conversion (expr)
     case FLOAT_EXPR:
     case FFS_EXPR:
       /* These don't change whether an object is non-zero or zero.  */
-      return truthvalue_conversion (TREE_OPERAND (expr, 0));
+      return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
 
     case LROTATE_EXPR:
     case RROTATE_EXPR:
@@ -2463,15 +2327,15 @@ truthvalue_conversion (expr)
         we can't ignore them if their second arg has side-effects.  */
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
        return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1),
-                     truthvalue_conversion (TREE_OPERAND (expr, 0)));
+                     c_common_truthvalue_conversion (TREE_OPERAND (expr, 0)));
       else
-       return truthvalue_conversion (TREE_OPERAND (expr, 0));
+       return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
 
     case COND_EXPR:
       /* Distribute the conversion into the arms of a COND_EXPR.  */
       return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
-                         truthvalue_conversion (TREE_OPERAND (expr, 1)),
-                         truthvalue_conversion (TREE_OPERAND (expr, 2))));
+               c_common_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+               c_common_truthvalue_conversion (TREE_OPERAND (expr, 2))));
 
     case CONVERT_EXPR:
       /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
@@ -2484,14 +2348,19 @@ truthvalue_conversion (expr)
       /* If this is widening the argument, we can ignore it.  */
       if (TYPE_PRECISION (TREE_TYPE (expr))
          >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
-       return truthvalue_conversion (TREE_OPERAND (expr, 0));
+       return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
       break;
 
     case MINUS_EXPR:
-      /* With IEEE arithmetic, x - x may not equal 0, so we can't optimize
-        this case.  */
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
-         && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
+      /* Perhaps reduce (x - y) != 0 to (x != y).  The expressions
+        aren't guaranteed to the be same for modes that can represent
+        infinity, since if x and y are both +infinity, or both
+        -infinity, then x - y is not a number.
+
+        Note that this transformation is safe when x or y is NaN.
+        (x - y) is then NaN, and both (x - y) != 0 and x != y will
+        be false.  */
+      if (HONOR_INFINITIES (TYPE_MODE (TREE_TYPE (TREE_OPERAND (expr, 0)))))
        break;
       /* fall through...  */
     case BIT_XOR_EXPR:
@@ -2524,12 +2393,12 @@ truthvalue_conversion (expr)
 
   if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
     {
-      tree tem = save_expr (expr);
+      tree t = save_expr (expr);
       return (build_binary_op
              ((TREE_SIDE_EFFECTS (expr)
                ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
-              truthvalue_conversion (build_unary_op (REALPART_EXPR, tem, 0)),
-              truthvalue_conversion (build_unary_op (IMAGPART_EXPR, tem, 0)),
+       c_common_truthvalue_conversion (build_unary_op (REALPART_EXPR, t, 0)),
+       c_common_truthvalue_conversion (build_unary_op (IMAGPART_EXPR, t, 0)),
               0));
     }
 
@@ -2593,37 +2462,18 @@ c_apply_type_quals_to_decl (type_quals, decl)
          || !C_TYPE_OBJECT_OR_INCOMPLETE_P (TREE_TYPE (TREE_TYPE (decl))))
        error ("invalid use of `restrict'");
       else if (flag_strict_aliasing)
-       {
-         /* No two restricted pointers can point at the same thing.
-            However, a restricted pointer can point at the same thing
-            as an unrestricted pointer, if that unrestricted pointer
-            is based on the restricted pointer.  So, we make the
-            alias set for the restricted pointer a subset of the
-            alias set for the type pointed to by the type of the
-            decl.  */
-
-         HOST_WIDE_INT pointed_to_alias_set
-           = get_alias_set (TREE_TYPE (TREE_TYPE (decl)));
-
-         if (pointed_to_alias_set == 0)
-           /* It's not legal to make a subset of alias set zero.  */
-           ;
-         else
-           {
-             DECL_POINTER_ALIAS_SET (decl) = new_alias_set ();
-             record_alias_subset  (pointed_to_alias_set,
-                                   DECL_POINTER_ALIAS_SET (decl));
-           }
-       }
+       /* Indicate we need to make a unique alias set for this pointer.
+          We can't do it here because it might be pointing to an
+          incomplete type.  */
+       DECL_POINTER_ALIAS_SET (decl) = -2;
     }
 }
 
-
 /* Return the typed-based alias set for T, which may be an expression
    or a type.  Return -1 if we don't do anything special.  */
 
 HOST_WIDE_INT
-lang_get_alias_set (t)
+c_common_get_alias_set (t)
      tree t;
 {
   tree u;
@@ -2645,1861 +2495,2927 @@ lang_get_alias_set (t)
        && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
       return 0;
 
-  /* If this is a char *, the ANSI C standard says it can alias
-     anything.  Note that all references need do this.  */
-  if (TREE_CODE_CLASS (TREE_CODE (t)) == 'r'
-      && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
-      && TYPE_PRECISION (TREE_TYPE (t)) == TYPE_PRECISION (char_type_node))
-    return 0;
+  /* If this is a char *, the ANSI C standard says it can alias
+     anything.  Note that all references need do this.  */
+  if (TREE_CODE_CLASS (TREE_CODE (t)) == 'r'
+      && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
+      && TYPE_PRECISION (TREE_TYPE (t)) == TYPE_PRECISION (char_type_node))
+    return 0;
+
+  /* That's all the expressions we handle specially.  */
+  if (! TYPE_P (t))
+    return -1;
+
+  /* The C standard specifically allows aliasing between signed and
+     unsigned variants of the same type.  We treat the signed
+     variant as canonical.  */
+  if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t))
+    {
+      tree t1 = c_common_signed_type (t);
+
+      /* t1 == t can happen for boolean nodes which are always unsigned.  */
+      if (t1 != t)
+       return get_alias_set (t1);
+    }
+  else if (POINTER_TYPE_P (t))
+    {
+      tree t1;
+
+      /* Unfortunately, there is no canonical form of a pointer type.
+        In particular, if we have `typedef int I', then `int *', and
+        `I *' are different types.  So, we have to pick a canonical
+        representative.  We do this below.
+
+        Technically, this approach is actually more conservative that
+        it needs to be.  In particular, `const int *' and `int *'
+        should be in different alias sets, according to the C and C++
+        standard, since their types are not the same, and so,
+        technically, an `int **' and `const int **' cannot point at
+        the same thing.
+
+         But, the standard is wrong.  In particular, this code is
+        legal C++:
+
+            int *ip;
+            int **ipp = &ip;
+            const int* const* cipp = &ipp;
+
+         And, it doesn't make sense for that to be legal unless you
+        can dereference IPP and CIPP.  So, we ignore cv-qualifiers on
+        the pointed-to types.  This issue has been reported to the
+        C++ committee.  */
+      t1 = build_type_no_quals (t);
+      if (t1 != t)
+       return get_alias_set (t1);
+    }
+
+  return -1;
+}
+\f
+/* Implement the __alignof keyword: Return the minimum required
+   alignment of TYPE, measured in bytes.  */
+
+tree
+c_alignof (type)
+     tree type;
+{
+  enum tree_code code = TREE_CODE (type);
+  tree t;
+
+  /* In C++, sizeof applies to the referent.  Handle alignof the same way.  */
+  if (code == REFERENCE_TYPE)
+    {
+      type = TREE_TYPE (type);
+      code = TREE_CODE (type);
+    }
+
+  if (code == FUNCTION_TYPE)
+    t = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+  else if (code == VOID_TYPE || code == ERROR_MARK)
+    t = size_one_node;
+  else if (!COMPLETE_TYPE_P (type))
+    {
+      error ("__alignof__ applied to an incomplete type");
+      t = size_zero_node;
+    }
+  else
+    t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+
+  return fold (build1 (NOP_EXPR, c_size_type_node, t));
+}
+
+/* Implement the __alignof keyword: Return the minimum required
+   alignment of EXPR, measured in bytes.  For VAR_DECL's and
+   FIELD_DECL's return DECL_ALIGN (which can be set from an
+   "aligned" __attribute__ specification).  */
+
+tree
+c_alignof_expr (expr)
+     tree expr;
+{
+  tree t;
+
+  if (TREE_CODE (expr) == VAR_DECL)
+    t = size_int (DECL_ALIGN (expr) / BITS_PER_UNIT);
+  else if (TREE_CODE (expr) == COMPONENT_REF
+          && DECL_C_BIT_FIELD (TREE_OPERAND (expr, 1)))
+    {
+      error ("`__alignof' applied to a bit-field");
+      t = size_one_node;
+    }
+  else if (TREE_CODE (expr) == COMPONENT_REF
+          && TREE_CODE (TREE_OPERAND (expr, 1)) == FIELD_DECL)
+    t = size_int (DECL_ALIGN (TREE_OPERAND (expr, 1)) / BITS_PER_UNIT);
+  else if (TREE_CODE (expr) == INDIRECT_REF)
+    {
+      tree t = TREE_OPERAND (expr, 0);
+      tree best = t;
+      int bestalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
+      while (TREE_CODE (t) == NOP_EXPR
+            && TREE_CODE (TREE_TYPE (TREE_OPERAND (t, 0))) == POINTER_TYPE)
+       {
+         int thisalign;
+
+         t = TREE_OPERAND (t, 0);
+         thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
+         if (thisalign > bestalign)
+           best = t, bestalign = thisalign;
+       }
+      return c_alignof (TREE_TYPE (TREE_TYPE (best)));
+    }
+  else
+    return c_alignof (TREE_TYPE (expr));
+
+  return fold (build1 (NOP_EXPR, c_size_type_node, t));
+}
+\f
+/* Build tree nodes and builtin functions common to both C and C++ language
+   frontends.  */
+
+void
+c_common_nodes_and_builtins ()
+{
+  enum builtin_type 
+  {
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_POINTER_TYPE
+    BT_LAST
+  };
+
+  typedef enum builtin_type builtin_type;
+
+  tree builtin_types[(int) BT_LAST];
+  int wchar_type_size;
+  tree array_domain_type;
+  tree va_list_ref_type_node;
+  tree va_list_arg_type_node;
+
+  /* Define `int' and `char' first so that dbx will output them first.  */
+  record_builtin_type (RID_INT, NULL, integer_type_node);
+  record_builtin_type (RID_CHAR, "char", char_type_node);
+
+  /* `signed' is the same as `int'.  FIXME: the declarations of "signed",
+     "unsigned long", "long long unsigned" and "unsigned short" were in C++
+     but not C.  Are the conditionals here needed?  */
+  if (c_language == clk_cplusplus)
+    record_builtin_type (RID_SIGNED, NULL, integer_type_node);
+  record_builtin_type (RID_LONG, "long int", long_integer_type_node);
+  record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node);
+  record_builtin_type (RID_MAX, "long unsigned int",
+                      long_unsigned_type_node);
+  if (c_language == clk_cplusplus)
+    record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node);
+  record_builtin_type (RID_MAX, "long long int",
+                      long_long_integer_type_node);
+  record_builtin_type (RID_MAX, "long long unsigned int",
+                      long_long_unsigned_type_node);
+  if (c_language == clk_cplusplus)
+    record_builtin_type (RID_MAX, "long long unsigned",
+                        long_long_unsigned_type_node);
+  record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
+  record_builtin_type (RID_MAX, "short unsigned int",
+                      short_unsigned_type_node);
+  if (c_language == clk_cplusplus)
+    record_builtin_type (RID_MAX, "unsigned short",
+                        short_unsigned_type_node);
+
+  /* Define both `signed char' and `unsigned char'.  */
+  record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
+  record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node);
+
+  /* These are types that c_common_type_for_size and
+     c_common_type_for_mode use.  */
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           intQI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           intHI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           intSI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                           get_identifier ("__int128_t"),
+                                           intTI_type_node));
+#endif
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           unsigned_intQI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           unsigned_intHI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           unsigned_intSI_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           unsigned_intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                           get_identifier ("__uint128_t"),
+                                           unsigned_intTI_type_node));
+#endif
+
+  /* Create the widest literal types.  */
+  widest_integer_literal_type_node
+    = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           widest_integer_literal_type_node));
+
+  widest_unsigned_literal_type_node
+    = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL, NULL_TREE,
+                                           widest_unsigned_literal_type_node));
+
+  /* `unsigned long' is the standard type for sizeof.
+     Note that stddef.h uses `unsigned long',
+     and this must agree, even if long and int are the same size.  */
+  c_size_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
+  signed_size_type_node = c_common_signed_type (c_size_type_node);
+  set_sizetype (c_size_type_node);
+
+  build_common_tree_nodes_2 (flag_short_double);
+
+  record_builtin_type (RID_FLOAT, NULL, float_type_node);
+  record_builtin_type (RID_DOUBLE, NULL, double_type_node);
+  record_builtin_type (RID_MAX, "long double", long_double_type_node);
+
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                           get_identifier ("complex int"),
+                                           complex_integer_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                           get_identifier ("complex float"),
+                                           complex_float_type_node));
+  (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                           get_identifier ("complex double"),
+                                           complex_double_type_node));
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+                complex_long_double_type_node));
+
+  /* Types which are common to the fortran compiler and libf2c.  When
+     changing these, you also need to be concerned with f/com.h.  */
+
+  if (TYPE_PRECISION (float_type_node)
+      == TYPE_PRECISION (long_integer_type_node))
+    {
+      g77_integer_type_node = long_integer_type_node;
+      g77_uinteger_type_node = long_unsigned_type_node;
+    }
+  else if (TYPE_PRECISION (float_type_node)
+          == TYPE_PRECISION (integer_type_node))
+    {
+      g77_integer_type_node = integer_type_node;
+      g77_uinteger_type_node = unsigned_type_node;
+    }
+  else
+    g77_integer_type_node = g77_uinteger_type_node = NULL_TREE;
+
+  if (g77_integer_type_node != NULL_TREE)
+    {
+      (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                               get_identifier ("__g77_integer"),
+                                               g77_integer_type_node));
+      (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                               get_identifier ("__g77_uinteger"),
+                                               g77_uinteger_type_node));
+    }
+
+  if (TYPE_PRECISION (float_type_node) * 2
+      == TYPE_PRECISION (long_integer_type_node))
+    {
+      g77_longint_type_node = long_integer_type_node;
+      g77_ulongint_type_node = long_unsigned_type_node;
+    }
+  else if (TYPE_PRECISION (float_type_node) * 2
+          == TYPE_PRECISION (long_long_integer_type_node))
+    {
+      g77_longint_type_node = long_long_integer_type_node;
+      g77_ulongint_type_node = long_long_unsigned_type_node;
+    }
+  else
+    g77_longint_type_node = g77_ulongint_type_node = NULL_TREE;
+
+  if (g77_longint_type_node != NULL_TREE)
+    {
+      (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                               get_identifier ("__g77_longint"),
+                                               g77_longint_type_node));
+      (*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
+                                               get_identifier ("__g77_ulongint"),
+                                               g77_ulongint_type_node));
+    }
+
+  record_builtin_type (RID_VOID, NULL, void_type_node);
+
+  void_zero_node = build_int_2 (0, 0);
+  TREE_TYPE (void_zero_node) = void_type_node;
+
+  void_list_node = build_void_list_node ();
+
+  /* Make a type to be the domain of a few array types
+     whose domains don't really matter.
+     200 is small enough that it always fits in size_t
+     and large enough that it can hold most function names for the
+     initializations of __FUNCTION__ and __PRETTY_FUNCTION__.  */
+  array_domain_type = build_index_type (size_int (200));
+
+  /* Make a type for arrays of characters.
+     With luck nothing will ever really depend on the length of this
+     array type.  */
+  char_array_type_node
+    = build_array_type (char_type_node, array_domain_type);
+
+  /* Likewise for arrays of ints.  */
+  int_array_type_node
+    = build_array_type (integer_type_node, array_domain_type);
+
+  string_type_node = build_pointer_type (char_type_node);
+  const_string_type_node
+    = build_pointer_type (build_qualified_type
+                         (char_type_node, TYPE_QUAL_CONST));
+
+  (*targetm.init_builtins) ();
+
+  /* This is special for C++ so functions can be overloaded.  */
+  wchar_type_node = get_identifier (flag_short_wchar
+                                   ? "short unsigned int"
+                                   : WCHAR_TYPE);
+  wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
+  wchar_type_size = TYPE_PRECISION (wchar_type_node);
+  if (c_language == clk_cplusplus)
+    {
+      if (TREE_UNSIGNED (wchar_type_node))
+       wchar_type_node = make_unsigned_type (wchar_type_size);
+      else
+       wchar_type_node = make_signed_type (wchar_type_size);
+      record_builtin_type (RID_WCHAR, "wchar_t", wchar_type_node);
+    }
+  else
+    {
+      signed_wchar_type_node = c_common_signed_type (wchar_type_node);
+      unsigned_wchar_type_node = c_common_unsigned_type (wchar_type_node);
+    }
+
+  /* This is for wide string constants.  */
+  wchar_array_type_node
+    = build_array_type (wchar_type_node, array_domain_type);
+
+  wint_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE)));
+
+  intmax_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (INTMAX_TYPE)));
+  uintmax_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE)));
+
+  default_function_type = build_function_type (integer_type_node, NULL_TREE);
+  ptrdiff_type_node
+    = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
+  unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
+
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
+                va_list_type_node));
+
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
+                ptrdiff_type_node));
+
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
+                sizetype));
+
+  if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+    {
+      va_list_arg_type_node = va_list_ref_type_node =
+       build_pointer_type (TREE_TYPE (va_list_type_node));
+    }
+  else
+    {
+      va_list_arg_type_node = va_list_type_node;
+      va_list_ref_type_node = build_reference_type (va_list_type_node);
+    }
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+  builtin_types[(int) ENUM] = VALUE;
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN)              \
+  builtin_types[(int) ENUM]                            \
+    = build_function_type (builtin_types[(int) RETURN],        \
+                          void_list_node);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1)                                \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN],                        \
+                          tree_cons (NULL_TREE,                        \
+                                     builtin_types[(int) ARG1],        \
+                                     void_list_node));
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2)  \
+  builtin_types[(int) ENUM]                            \
+    = build_function_type                              \
+      (builtin_types[(int) RETURN],                    \
+       tree_cons (NULL_TREE,                           \
+                 builtin_types[(int) ARG1],            \
+                 tree_cons (NULL_TREE,                 \
+                            builtin_types[(int) ARG2], \
+                            void_list_node)));
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3)             \
+  builtin_types[(int) ENUM]                                             \
+    = build_function_type                                               \
+      (builtin_types[(int) RETURN],                                     \
+       tree_cons (NULL_TREE,                                            \
+                 builtin_types[(int) ARG1],                             \
+                 tree_cons (NULL_TREE,                                  \
+                            builtin_types[(int) ARG2],                  \
+                            tree_cons (NULL_TREE,                       \
+                                       builtin_types[(int) ARG3],       \
+                                       void_list_node))));
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4)      \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type                                              \
+      (builtin_types[(int) RETURN],                                    \
+       tree_cons (NULL_TREE,                                           \
+                 builtin_types[(int) ARG1],                            \
+                 tree_cons (NULL_TREE,                                 \
+                            builtin_types[(int) ARG2],                 \
+                            tree_cons                                  \
+                            (NULL_TREE,                                \
+                             builtin_types[(int) ARG3],                \
+                             tree_cons (NULL_TREE,                     \
+                                        builtin_types[(int) ARG4],     \
+                                        void_list_node)))));
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN)                          \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN], NULL_TREE);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1)                     \
+   builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN],                 \
+                          tree_cons (NULL_TREE,                         \
+                                     builtin_types[(int) ARG1],         \
+                                     NULL_TREE));
+
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2)      \
+   builtin_types[(int) ENUM]                                   \
+    = build_function_type                                      \
+      (builtin_types[(int) RETURN],                            \
+       tree_cons (NULL_TREE,                                   \
+                 builtin_types[(int) ARG1],                    \
+                 tree_cons (NULL_TREE,                         \
+                            builtin_types[(int) ARG2],         \
+                            NULL_TREE)));
+#define DEF_POINTER_TYPE(ENUM, TYPE)                   \
+  builtin_types[(int) ENUM]                            \
+    = build_pointer_type (builtin_types[(int) TYPE]);
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_POINTER_TYPE
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS,                                 \
+                    TYPE, LIBTYPE, BOTH_P, FALLBACK_P, NONANSI_P)      \
+  if (NAME)                                                            \
+    {                                                                  \
+      tree decl;                                                       \
+                                                                       \
+      if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0)    \
+       abort ();                                                       \
+                                                                       \
+      if (!BOTH_P)                                                     \
+       decl = builtin_function (NAME, builtin_types[TYPE], ENUM,       \
+                                CLASS,                                 \
+                                (FALLBACK_P                            \
+                                 ? (NAME + strlen ("__builtin_"))      \
+                                 : NULL));                             \
+      else                                                             \
+       decl = builtin_function_2 (NAME,                                \
+                                  NAME + strlen ("__builtin_"),        \
+                                  builtin_types[TYPE],                 \
+                                  builtin_types[LIBTYPE],              \
+                                  ENUM,                                \
+                                  CLASS,                               \
+                                  FALLBACK_P,                          \
+                                  NONANSI_P,                           \
+                                  /*noreturn_p=*/0);                   \
+                                                                       \
+      built_in_decls[(int) ENUM] = decl;                               \
+    }                                                                  
+#include "builtins.def"
+#undef DEF_BUILTIN
+
+  /* Declare _exit and _Exit just to mark them as non-returning.  */
+  builtin_function_2 (NULL, "_exit", NULL_TREE, 
+                     builtin_types[BT_FN_VOID_INT],
+                     0, NOT_BUILT_IN, 0, 1, 1);
+  builtin_function_2 (NULL, "_Exit", NULL_TREE, 
+                     builtin_types[BT_FN_VOID_INT],
+                     0, NOT_BUILT_IN, 0, !flag_isoc99, 1);
+
+  /* Declare these functions non-returning
+     to avoid spurious "control drops through" warnings.  */
+  builtin_function_2 (NULL, "abort",
+                     NULL_TREE, ((c_language == clk_cplusplus)
+                                 ? builtin_types[BT_FN_VOID]
+                                 : builtin_types[BT_FN_VOID_VAR]),
+                     0, NOT_BUILT_IN, 0, 0, 1);
+
+  builtin_function_2 (NULL, "exit",
+                     NULL_TREE, ((c_language == clk_cplusplus)
+                                 ? builtin_types[BT_FN_VOID_INT]
+                                 : builtin_types[BT_FN_VOID_VAR]),
+                     0, NOT_BUILT_IN, 0, 0, 1);
+
+  main_identifier_node = get_identifier ("main");
+}
+
+tree
+build_va_arg (expr, type)
+     tree expr, type;
+{
+  return build1 (VA_ARG_EXPR, type, expr);
+}
+
+
+/* Linked list of disabled built-in functions.  */
+
+typedef struct disabled_builtin
+{
+  const char *name;
+  struct disabled_builtin *next;
+} disabled_builtin;
+static disabled_builtin *disabled_builtins = NULL;
+
+static bool builtin_function_disabled_p PARAMS ((const char *));
+
+/* Disable a built-in function specified by -fno-builtin-NAME.  If NAME
+   begins with "__builtin_", give an error.  */
+
+void
+disable_builtin_function (name)
+     const char *name;
+{
+  if (strncmp (name, "__builtin_", strlen ("__builtin_")) == 0)
+    error ("cannot disable built-in function `%s'", name);
+  else
+    {
+      disabled_builtin *new = xmalloc (sizeof (disabled_builtin));
+      new->name = name;
+      new->next = disabled_builtins;
+      disabled_builtins = new;
+    }
+}
+
+
+/* Return true if the built-in function NAME has been disabled, false
+   otherwise.  */
+
+static bool
+builtin_function_disabled_p (name)
+     const char *name;
+{
+  disabled_builtin *p;
+  for (p = disabled_builtins; p != NULL; p = p->next)
+    {
+      if (strcmp (name, p->name) == 0)
+       return true;
+    }
+  return false;
+}
+
+
+/* Possibly define a builtin function with one or two names.  BUILTIN_NAME
+   is an __builtin_-prefixed name; NAME is the ordinary name; one or both
+   of these may be NULL (though both being NULL is useless).
+   BUILTIN_TYPE is the type of the __builtin_-prefixed function;
+   TYPE is the type of the function with the ordinary name.  These
+   may differ if the ordinary name is declared with a looser type to avoid
+   conflicts with headers.  FUNCTION_CODE and CLASS are as for
+   builtin_function.  If LIBRARY_NAME_P is nonzero, NAME is passed as
+   the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME.
+   If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name; if
+   NORETURN_P is nonzero, the function is marked as non-returning.
+   Returns the declaration of BUILTIN_NAME, if any, otherwise
+   the declaration of NAME.  Does not declare NAME if flag_no_builtin,
+   or if NONANSI_P and flag_no_nonansi_builtin.  */
+
+static tree
+builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
+                   class, library_name_p, nonansi_p, noreturn_p)
+     const char *builtin_name;
+     const char *name;
+     tree builtin_type;
+     tree type;
+     int function_code;
+     enum built_in_class class;
+     int library_name_p;
+     int nonansi_p;
+     int noreturn_p;
+{
+  tree bdecl = NULL_TREE;
+  tree decl = NULL_TREE;
+  if (builtin_name != 0)
+    {
+      bdecl = builtin_function (builtin_name, builtin_type, function_code,
+                               class, library_name_p ? name : NULL);
+      if (noreturn_p)
+       {
+         TREE_THIS_VOLATILE (bdecl) = 1;
+         TREE_SIDE_EFFECTS (bdecl) = 1;
+       }
+    }
+  if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
+      && !(nonansi_p && flag_no_nonansi_builtin))
+    {
+      decl = builtin_function (name, type, function_code, class, NULL);
+      if (nonansi_p)
+       DECL_BUILT_IN_NONANSI (decl) = 1;
+      if (noreturn_p)
+       {
+         TREE_THIS_VOLATILE (decl) = 1;
+         TREE_SIDE_EFFECTS (decl) = 1;
+       }
+    }
+  return (bdecl != 0 ? bdecl : decl);
+}
+\f
+/* Nonzero if the type T promotes to int.  This is (nearly) the
+   integral promotions defined in ISO C99 6.3.1.1/2.  */
+
+bool
+c_promoting_integer_type_p (t)
+     tree t;
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+      return (TYPE_MAIN_VARIANT (t) == char_type_node
+             || TYPE_MAIN_VARIANT (t) == signed_char_type_node
+             || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node
+             || TYPE_MAIN_VARIANT (t) == short_integer_type_node
+             || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node
+             || TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node));
+
+    case ENUMERAL_TYPE:
+      /* ??? Technically all enumerations not larger than an int
+        promote to an int.  But this is used along code paths
+        that only want to notice a size change.  */
+      return TYPE_PRECISION (t) < TYPE_PRECISION (integer_type_node);
+
+    case BOOLEAN_TYPE:
+      return 1;
+
+    default:
+      return 0;
+    }
+}
+
+/* Return 1 if PARMS specifies a fixed number of parameters
+   and none of their types is affected by default promotions.  */
+
+int
+self_promoting_args_p (parms)
+     tree parms;
+{
+  tree t;
+  for (t = parms; t; t = TREE_CHAIN (t))
+    {
+      tree type = TREE_VALUE (t);
+
+      if (TREE_CHAIN (t) == 0 && type != void_type_node)
+       return 0;
+
+      if (type == 0)
+       return 0;
+
+      if (TYPE_MAIN_VARIANT (type) == float_type_node)
+       return 0;
+
+      if (c_promoting_integer_type_p (type))
+       return 0;
+    }
+  return 1;
+}
+
+/* Recursively examines the array elements of TYPE, until a non-array
+   element type is found.  */
+
+tree
+strip_array_types (type)
+     tree type;
+{
+  while (TREE_CODE (type) == ARRAY_TYPE)
+    type = TREE_TYPE (type);
+
+  return type;
+}
+
+static tree expand_unordered_cmp PARAMS ((tree, tree, enum tree_code,
+                                         enum tree_code));
+
+/* Expand a call to an unordered comparison function such as
+   __builtin_isgreater().  FUNCTION is the function's declaration and
+   PARAMS a list of the values passed.  For __builtin_isunordered(),
+   UNORDERED_CODE is UNORDERED_EXPR and ORDERED_CODE is NOP_EXPR.  In
+   other cases, UNORDERED_CODE and ORDERED_CODE are comparison codes
+   that give the opposite of the desired result.  UNORDERED_CODE is
+   used for modes that can hold NaNs and ORDERED_CODE is used for the
+   rest.  */
+
+static tree
+expand_unordered_cmp (function, params, unordered_code, ordered_code)
+     tree function, params;
+     enum tree_code unordered_code, ordered_code;
+{
+  tree arg0, arg1, type;
+  enum tree_code code0, code1;
+
+  /* Check that we have exactly two arguments.  */
+  if (params == 0 || TREE_CHAIN (params) == 0)
+    {
+      error ("too few arguments to function `%s'",
+            IDENTIFIER_POINTER (DECL_NAME (function)));
+      return error_mark_node;
+    }
+  else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
+    {
+      error ("too many arguments to function `%s'",
+            IDENTIFIER_POINTER (DECL_NAME (function)));
+      return error_mark_node;
+    }
+
+  arg0 = TREE_VALUE (params);
+  arg1 = TREE_VALUE (TREE_CHAIN (params));
+
+  code0 = TREE_CODE (TREE_TYPE (arg0));
+  code1 = TREE_CODE (TREE_TYPE (arg1));
+
+  /* Make sure that the arguments have a common type of REAL.  */
+  type = 0;
+  if ((code0 == INTEGER_TYPE || code0 == REAL_TYPE)
+      && (code1 == INTEGER_TYPE || code1 == REAL_TYPE))
+    type = common_type (TREE_TYPE (arg0), TREE_TYPE (arg1));
+
+  if (type == 0 || TREE_CODE (type) != REAL_TYPE)
+    {
+      error ("non-floating-point argument to function `%s'",
+            IDENTIFIER_POINTER (DECL_NAME (function)));
+      return error_mark_node;
+    }
+
+  if (unordered_code == UNORDERED_EXPR)
+    {
+      if (MODE_HAS_NANS (TYPE_MODE (type)))
+       return build_binary_op (unordered_code,
+                               convert (type, arg0),
+                               convert (type, arg1),
+                               0);
+      else
+       return integer_zero_node;
+    }
+
+  return build_unary_op (TRUTH_NOT_EXPR,
+                        build_binary_op (MODE_HAS_NANS (TYPE_MODE (type))
+                                         ? unordered_code
+                                         : ordered_code,
+                                         convert (type, arg0),
+                                         convert (type, arg1),
+                                         0),
+                        0);
+}
+
+
+/* Recognize certain built-in functions so we can make tree-codes
+   other than CALL_EXPR.  We do this when it enables fold-const.c
+   to do something useful.  */
+/* ??? By rights this should go in builtins.c, but only C and C++
+   implement build_{binary,unary}_op.  Not exactly sure what bits
+   of functionality are actually needed from those functions, or
+   where the similar functionality exists in the other front ends.  */
+
+tree
+expand_tree_builtin (function, params, coerced_params)
+     tree function, params, coerced_params;
+{
+  if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
+    return NULL_TREE;
+
+  switch (DECL_FUNCTION_CODE (function))
+    {
+    case BUILT_IN_ABS:
+    case BUILT_IN_LABS:
+    case BUILT_IN_LLABS:
+    case BUILT_IN_IMAXABS:
+    case BUILT_IN_FABS:
+    case BUILT_IN_FABSL:
+    case BUILT_IN_FABSF:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_CONJ:
+    case BUILT_IN_CONJF:
+    case BUILT_IN_CONJL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_CREAL:
+    case BUILT_IN_CREALF:
+    case BUILT_IN_CREALL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (REALPART_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_CIMAG:
+    case BUILT_IN_CIMAGF:
+    case BUILT_IN_CIMAGL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_ISGREATER:
+      return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
+
+    case BUILT_IN_ISGREATEREQUAL:
+      return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
+
+    case BUILT_IN_ISLESS:
+      return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
+
+    case BUILT_IN_ISLESSEQUAL:
+      return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
+
+    case BUILT_IN_ISLESSGREATER:
+      return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
+
+    case BUILT_IN_ISUNORDERED:
+      return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
+
+    default:
+      break;
+    }
+
+  return NULL_TREE;
+}
+
+/* Returns non-zero if CODE is the code for a statement.  */
+
+int
+statement_code_p (code)
+     enum tree_code code;
+{
+  switch (code)
+    {
+    case CLEANUP_STMT:
+    case EXPR_STMT:
+    case COMPOUND_STMT:
+    case DECL_STMT:
+    case IF_STMT:
+    case FOR_STMT:
+    case WHILE_STMT:
+    case DO_STMT:
+    case RETURN_STMT:
+    case BREAK_STMT:
+    case CONTINUE_STMT:
+    case SCOPE_STMT:
+    case SWITCH_STMT:
+    case GOTO_STMT:
+    case LABEL_STMT:
+    case ASM_STMT:
+    case FILE_STMT:
+    case CASE_LABEL:
+      return 1;
+
+    default:
+      if (lang_statement_code_p)
+       return (*lang_statement_code_p) (code);
+      return 0;
+    }
+}
+
+/* Walk the statement tree, rooted at *tp.  Apply FUNC to all the
+   sub-trees of *TP in a pre-order traversal.  FUNC is called with the
+   DATA and the address of each sub-tree.  If FUNC returns a non-NULL
+   value, the traversal is aborted, and the value returned by FUNC is
+   returned.  If FUNC sets WALK_SUBTREES to zero, then the subtrees of
+   the node being visited are not walked.
+
+   We don't need a without_duplicates variant of this one because the
+   statement tree is a tree, not a graph.  */
+
+tree 
+walk_stmt_tree (tp, func, data)
+     tree *tp;
+     walk_tree_fn func;
+     void *data;
+{
+  enum tree_code code;
+  int walk_subtrees;
+  tree result;
+  int i, len;
+
+#define WALK_SUBTREE(NODE)                             \
+  do                                                   \
+    {                                                  \
+      result = walk_stmt_tree (&(NODE), func, data);   \
+      if (result)                                      \
+       return result;                                  \
+    }                                                  \
+  while (0)
+
+  /* Skip empty subtrees.  */
+  if (!*tp)
+    return NULL_TREE;
+
+  /* Skip subtrees below non-statement nodes.  */
+  if (!statement_code_p (TREE_CODE (*tp)))
+    return NULL_TREE;
+
+  /* Call the function.  */
+  walk_subtrees = 1;
+  result = (*func) (tp, &walk_subtrees, data);
+
+  /* If we found something, return it.  */
+  if (result)
+    return result;
+
+  /* FUNC may have modified the tree, recheck that we're looking at a
+     statement node.  */
+  code = TREE_CODE (*tp);
+  if (!statement_code_p (code))
+    return NULL_TREE;
+
+  /* Visit the subtrees unless FUNC decided that there was nothing
+     interesting below this point in the tree.  */
+  if (walk_subtrees)
+    {
+      /* Walk over all the sub-trees of this operand.  Statement nodes
+        never contain RTL, and we needn't worry about TARGET_EXPRs.  */
+      len = TREE_CODE_LENGTH (code);
+
+      /* Go through the subtrees.  We need to do this in forward order so
+        that the scope of a FOR_EXPR is handled properly.  */
+      for (i = 0; i < len; ++i)
+       WALK_SUBTREE (TREE_OPERAND (*tp, i));
+    }
+
+  /* Finally visit the chain.  This can be tail-recursion optimized if
+     we write it this way.  */
+  return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
+
+#undef WALK_SUBTREE
+}
+
+/* Used to compare case labels.  K1 and K2 are actually tree nodes
+   representing case labels, or NULL_TREE for a `default' label.
+   Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
+   K2, and 0 if K1 and K2 are equal.  */
+
+int
+case_compare (k1, k2)
+     splay_tree_key k1;
+     splay_tree_key k2;
+{
+  /* Consider a NULL key (such as arises with a `default' label) to be
+     smaller than anything else.  */
+  if (!k1)
+    return k2 ? -1 : 0;
+  else if (!k2)
+    return k1 ? 1 : 0;
+
+  return tree_int_cst_compare ((tree) k1, (tree) k2);
+}
+
+/* Process a case label for the range LOW_VALUE ... HIGH_VALUE.  If
+   LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is
+   actually a `default' label.  If only HIGH_VALUE is NULL_TREE, then
+   case label was declared using the usual C/C++ syntax, rather than
+   the GNU case range extension.  CASES is a tree containing all the
+   case ranges processed so far; COND is the condition for the
+   switch-statement itself.  Returns the CASE_LABEL created, or
+   ERROR_MARK_NODE if no CASE_LABEL is created.  */
+
+tree
+c_add_case_label (cases, cond, low_value, high_value)
+     splay_tree cases;
+     tree cond;
+     tree low_value;
+     tree high_value;
+{
+  tree type;
+  tree label;
+  tree case_label;
+  splay_tree_node node;
+
+  /* Create the LABEL_DECL itself.  */
+  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
+  DECL_CONTEXT (label) = current_function_decl;
+
+  /* If there was an error processing the switch condition, bail now
+     before we get more confused.  */
+  if (!cond || cond == error_mark_node)
+    {
+      /* Add a label anyhow so that the back-end doesn't think that
+        the beginning of the switch is unreachable.  */
+      if (!cases->root)
+       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+      return error_mark_node;
+    }
+
+  if ((low_value && TREE_TYPE (low_value) 
+       && POINTER_TYPE_P (TREE_TYPE (low_value))) 
+      || (high_value && TREE_TYPE (high_value)
+         && POINTER_TYPE_P (TREE_TYPE (high_value))))
+    error ("pointers are not permitted as case values");
+
+  /* Case ranges are a GNU extension.  */
+  if (high_value && pedantic)
+    {
+      if (c_language == clk_cplusplus)
+       pedwarn ("ISO C++ forbids range expressions in switch statements");
+      else
+       pedwarn ("ISO C forbids range expressions in switch statements");
+    }
+
+  type = TREE_TYPE (cond);
+  if (low_value)
+    {
+      low_value = check_case_value (low_value);
+      low_value = convert_and_check (type, low_value);
+    }
+  if (high_value)
+    {
+      high_value = check_case_value (high_value);
+      high_value = convert_and_check (type, high_value);
+    }
+
+  /* If an error has occurred, bail out now.  */
+  if (low_value == error_mark_node || high_value == error_mark_node)
+    {
+      if (!cases->root)
+       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+      return error_mark_node;
+    }
+
+  /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
+     really a case range, even though it was written that way.  Remove
+     the HIGH_VALUE to simplify later processing.  */
+  if (tree_int_cst_equal (low_value, high_value))
+    high_value = NULL_TREE;
+  if (low_value && high_value 
+      && !tree_int_cst_lt (low_value, high_value)) 
+    warning ("empty range specified");
+
+  /* Look up the LOW_VALUE in the table of case labels we already
+     have.  */
+  node = splay_tree_lookup (cases, (splay_tree_key) low_value);
+  /* If there was not an exact match, check for overlapping ranges.
+     There's no need to do this if there's no LOW_VALUE or HIGH_VALUE;
+     that's a `default' label and the only overlap is an exact match.  */
+  if (!node && (low_value || high_value))
+    {
+      splay_tree_node low_bound;
+      splay_tree_node high_bound;
+
+      /* Even though there wasn't an exact match, there might be an
+        overlap between this case range and another case range.
+        Since we've (inductively) not allowed any overlapping case
+        ranges, we simply need to find the greatest low case label
+        that is smaller that LOW_VALUE, and the smallest low case
+        label that is greater than LOW_VALUE.  If there is an overlap
+        it will occur in one of these two ranges.  */
+      low_bound = splay_tree_predecessor (cases,
+                                         (splay_tree_key) low_value);
+      high_bound = splay_tree_successor (cases,
+                                        (splay_tree_key) low_value);
+
+      /* Check to see if the LOW_BOUND overlaps.  It is smaller than
+        the LOW_VALUE, so there is no need to check unless the
+        LOW_BOUND is in fact itself a case range.  */
+      if (low_bound
+         && CASE_HIGH ((tree) low_bound->value)
+         && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value),
+                                   low_value) >= 0)
+       node = low_bound;
+      /* Check to see if the HIGH_BOUND overlaps.  The low end of that
+        range is bigger than the low end of the current range, so we
+        are only interested if the current range is a real range, and
+        not an ordinary case label.  */
+      else if (high_bound 
+              && high_value
+              && (tree_int_cst_compare ((tree) high_bound->key,
+                                        high_value)
+                  <= 0))
+       node = high_bound;
+    }
+  /* If there was an overlap, issue an error.  */
+  if (node)
+    {
+      tree duplicate = CASE_LABEL_DECL ((tree) node->value);
+
+      if (high_value)
+       {
+         error ("duplicate (or overlapping) case value");
+         error_with_decl (duplicate, 
+                          "this is the first entry overlapping that value");
+       }
+      else if (low_value)
+       {
+         error ("duplicate case value") ;
+         error_with_decl (duplicate, "previously used here");
+       }
+      else
+       {
+         error ("multiple default labels in one switch");
+         error_with_decl (duplicate, "this is the first default label");
+       }
+      if (!cases->root)
+       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+    }
+
+  /* Add a CASE_LABEL to the statement-tree.  */
+  case_label = add_stmt (build_case_label (low_value, high_value, label));
+  /* Register this case label in the splay tree.  */
+  splay_tree_insert (cases, 
+                    (splay_tree_key) low_value,
+                    (splay_tree_value) case_label);
+
+  return case_label;
+}
 
-  /* That's all the expressions we handle specially.  */
-  if (! TYPE_P (t))
-    return -1;
+/* Finish an expression taking the address of LABEL.  Returns an
+   expression for the address.  */
 
-  /* The C standard specifically allows aliasing between signed and
-     unsigned variants of the same type.  We treat the signed
-     variant as canonical.  */
-  if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t))
-    {
-      tree t1 = signed_type (t);
+tree 
+finish_label_address_expr (label)
+     tree label;
+{
+  tree result;
 
-      /* t1 == t can happen for boolean nodes which are always unsigned.  */
-      if (t1 != t)
-       return get_alias_set (t1);
+  if (pedantic)
+    {
+      if (c_language == clk_cplusplus)
+       pedwarn ("ISO C++ forbids taking the address of a label");
+      else
+       pedwarn ("ISO C forbids taking the address of a label");
     }
-  else if (POINTER_TYPE_P (t))
+
+  label = lookup_label (label);
+  if (label == NULL_TREE)
+    result = null_pointer_node;
+  else
     {
-      tree t1;
+      TREE_USED (label) = 1;
+      result = build1 (ADDR_EXPR, ptr_type_node, label);
+      TREE_CONSTANT (result) = 1;
+      /* The current function in not necessarily uninlinable.
+        Computed gotos are incompatible with inlining, but the value
+        here could be used only in a diagnostic, for example.  */
+    }
 
-      /* Unfortunately, there is no canonical form of a pointer type.
-        In particular, if we have `typedef int I', then `int *', and
-        `I *' are different types.  So, we have to pick a canonical
-        representative.  We do this below.
+  return result;
+}
 
-        Technically, this approach is actually more conservative that
-        it needs to be.  In particular, `const int *' and `int *'
-        chould be in different alias sets, according to the C and C++
-        standard, since their types are not the same, and so,
-        technically, an `int **' and `const int **' cannot point at
-        the same thing.
+/* Mark P (a stmt_tree) for GC.  The use of a `void *' for the
+   parameter allows this function to be used as a GC-marking
+   function.  */
 
-         But, the standard is wrong.  In particular, this code is
-        legal C++:
+void
+mark_stmt_tree (p)
+     void *p;
+{
+  stmt_tree st = (stmt_tree) p;
 
-            int *ip;
-            int **ipp = &ip;
-            const int* const* cipp = &ip;
+  ggc_mark_tree (st->x_last_stmt);
+  ggc_mark_tree (st->x_last_expr_type);
+}
 
-         And, it doesn't make sense for that to be legal unless you
-        can dereference IPP and CIPP.  So, we ignore cv-qualifiers on
-        the pointed-to types.  This issue has been reported to the
-        C++ committee.  */
-      t1 = build_type_no_quals (t);
-      if (t1 != t)
-       return get_alias_set (t1);
-    }
-  /* It's not yet safe to use alias sets for classes in C++ because
-     the TYPE_FIELDs list for a class doesn't mention base classes.  */
-  else if (c_language == clk_cplusplus && AGGREGATE_TYPE_P (t))
-    return 0;
+/* Mark LD for GC.  */
 
-  return -1;
+void
+c_mark_lang_decl (c)
+     struct c_lang_decl *c ATTRIBUTE_UNUSED;
+{
 }
 
-/* Build tree nodes and builtin functions common to both C and C++ language
-   frontends.  */
+/* Mark F for GC.  */
 
 void
-c_common_nodes_and_builtins ()
+mark_c_language_function (f)
+     struct language_function *f;
 {
-  int wchar_type_size;
-  tree array_domain_type;
-  tree temp;
-  tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree bzero_ftype, bcmp_ftype, puts_ftype, printf_ftype;
-  tree fputs_ftype, fputc_ftype, fwrite_ftype, fprintf_ftype;
-  tree endlink, int_endlink, double_endlink, unsigned_endlink;
-  tree cstring_endlink, sizetype_endlink;
-  tree ptr_ftype, ptr_ftype_unsigned;
-  tree void_ftype_any, void_ftype_int, int_ftype_any;
-  tree double_ftype_double, double_ftype_double_double;
-  tree float_ftype_float, ldouble_ftype_ldouble;
-  tree cfloat_ftype_cfloat, cdouble_ftype_cdouble, cldouble_ftype_cldouble;
-  tree float_ftype_cfloat, double_ftype_cdouble, ldouble_ftype_cldouble;
-  tree int_ftype_cptr_cptr_sizet, sizet_ftype_cstring_cstring;
-  tree int_ftype_cstring_cstring, string_ftype_string_cstring;
-  tree string_ftype_cstring_int, string_ftype_cstring_cstring;
-  tree string_ftype_string_cstring_sizet, int_ftype_cstring_cstring_sizet;
-  tree long_ftype_long;
-  tree longlong_ftype_longlong;
-  tree intmax_ftype_intmax;
-  /* Either char* or void*.  */
-  tree traditional_ptr_type_node;
-  /* Either const char* or const void*.  */
-  tree traditional_cptr_type_node;
-  tree traditional_len_type_node;
-  tree traditional_len_endlink;
-  tree va_list_ref_type_node;
-  tree va_list_arg_type_node;
-
-  /* Define `int' and `char' first so that dbx will output them first.  */
-  record_builtin_type (RID_INT, NULL_PTR, integer_type_node);
-  record_builtin_type (RID_CHAR, "char", char_type_node);
+  if (!f)
+    return;
 
-  /* `signed' is the same as `int'.  FIXME: the declarations of "signed",
-     "unsigned long", "long long unsigned" and "unsigned short" were in C++
-     but not C.  Are the conditionals here needed?  */
-  if (c_language == clk_cplusplus)
-    record_builtin_type (RID_SIGNED, NULL_PTR, integer_type_node);
-  record_builtin_type (RID_LONG, "long int", long_integer_type_node);
-  record_builtin_type (RID_UNSIGNED, "unsigned int", unsigned_type_node);
-  record_builtin_type (RID_MAX, "long unsigned int",
-                      long_unsigned_type_node);
-  if (c_language == clk_cplusplus)
-    record_builtin_type (RID_MAX, "unsigned long", long_unsigned_type_node);
-  record_builtin_type (RID_MAX, "long long int",
-                      long_long_integer_type_node);
-  record_builtin_type (RID_MAX, "long long unsigned int",
-                      long_long_unsigned_type_node);
-  if (c_language == clk_cplusplus)
-    record_builtin_type (RID_MAX, "long long unsigned",
-                        long_long_unsigned_type_node);
-  record_builtin_type (RID_SHORT, "short int", short_integer_type_node);
-  record_builtin_type (RID_MAX, "short unsigned int",
-                      short_unsigned_type_node);
-  if (c_language == clk_cplusplus)
-    record_builtin_type (RID_MAX, "unsigned short",
-                        short_unsigned_type_node);
+  mark_stmt_tree (&f->x_stmt_tree);
+  ggc_mark_tree (f->x_scope_stmt_stack);
+}
 
-  /* Define both `signed char' and `unsigned char'.  */
-  record_builtin_type (RID_MAX, "signed char", signed_char_type_node);
-  record_builtin_type (RID_MAX, "unsigned char", unsigned_char_type_node);
+/* Hook used by expand_expr to expand language-specific tree codes.  */
 
-  /* These are types that type_for_size and type_for_mode use.  */
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
-#if HOST_BITS_PER_WIDE_INT >= 64
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
-#endif
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
-#if HOST_BITS_PER_WIDE_INT >= 64
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
-#endif
+rtx
+c_expand_expr (exp, target, tmode, modifier)
+     tree exp;
+     rtx target;
+     enum machine_mode tmode;
+     int modifier;  /* Actually enum_modifier.  */
+{
+  switch (TREE_CODE (exp))
+    {
+    case STMT_EXPR:
+      {
+       tree rtl_expr;
+       rtx result;
+       bool preserve_result = false;
 
-  /* Create the widest literal types.  */
-  widest_integer_literal_type_node
-    = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
-                       widest_integer_literal_type_node));
+       /* Since expand_expr_stmt calls free_temp_slots after every
+          expression statement, we must call push_temp_slots here.
+          Otherwise, any temporaries in use now would be considered
+          out-of-scope after the first EXPR_STMT from within the
+          STMT_EXPR.  */
+       push_temp_slots ();
+       rtl_expr = expand_start_stmt_expr (!STMT_EXPR_NO_SCOPE (exp));
 
-  widest_unsigned_literal_type_node
-    = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
-  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
-                       widest_unsigned_literal_type_node));
+       /* If we want the result of this expression, find the last
+           EXPR_STMT in the COMPOUND_STMT and mark it as addressable.  */
+       if (target != const0_rtx
+           && TREE_CODE (STMT_EXPR_STMT (exp)) == COMPOUND_STMT
+           && TREE_CODE (COMPOUND_BODY (STMT_EXPR_STMT (exp))) == SCOPE_STMT)
+         {
+           tree expr = COMPOUND_BODY (STMT_EXPR_STMT (exp));
+           tree last = TREE_CHAIN (expr);
 
-  /* `unsigned long' is the standard type for sizeof.
-     Note that stddef.h uses `unsigned long',
-     and this must agree, even if long and int are the same size.  */
-  c_size_type_node =
-    TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
-  signed_size_type_node = signed_type (c_size_type_node);
-  if (flag_traditional)
-    c_size_type_node = signed_size_type_node;
-  set_sizetype (c_size_type_node);
+           while (TREE_CHAIN (last))
+             {
+               expr = last;
+               last = TREE_CHAIN (last);
+             }
 
-  build_common_tree_nodes_2 (flag_short_double);
+           if (TREE_CODE (last) == SCOPE_STMT
+               && TREE_CODE (expr) == EXPR_STMT)
+             {
+               TREE_ADDRESSABLE (expr) = 1;
+               preserve_result = true;
+             }
+         }
 
-  record_builtin_type (RID_FLOAT, NULL_PTR, float_type_node);
-  record_builtin_type (RID_DOUBLE, NULL_PTR, double_type_node);
-  record_builtin_type (RID_MAX, "long double", long_double_type_node);
+       expand_stmt (STMT_EXPR_STMT (exp));
+       expand_end_stmt_expr (rtl_expr);
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
-                       complex_integer_type_node));
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
-                       complex_float_type_node));
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
-                       complex_double_type_node));
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
-                       complex_long_double_type_node));
+       result = expand_expr (rtl_expr, target, tmode, modifier);
+       if (preserve_result && GET_CODE (result) == MEM)
+         {
+           if (GET_MODE (result) != BLKmode)
+             result = copy_to_reg (result);
+           else
+             preserve_temp_slots (result);
+         }
 
-  record_builtin_type (RID_VOID, NULL_PTR, void_type_node);
+       /* If the statment-expression does not have a scope, then the
+          new temporaries we created within it must live beyond the
+          statement-expression.  */
+       if (STMT_EXPR_NO_SCOPE (exp))
+         preserve_temp_slots (NULL_RTX);
 
-  void_list_node = build_void_list_node ();
+       pop_temp_slots ();
+       return result;
+      }
+      break;
+      
+    case CALL_EXPR:
+      {
+       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+           && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == FUNCTION_DECL)
+           && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+           && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == BUILT_IN_FRONTEND))
+         return c_expand_builtin (exp, target, tmode, modifier);
+       else
+         abort ();
+      }
+      break;
 
-  /* Make a type to be the domain of a few array types
-     whose domains don't really matter.
-     200 is small enough that it always fits in size_t
-     and large enough that it can hold most function names for the
-     initializations of __FUNCTION__ and __PRETTY_FUNCTION__.  */
-  array_domain_type = build_index_type (size_int (200));
+    case COMPOUND_LITERAL_EXPR:
+      {
+       /* Initialize the anonymous variable declared in the compound
+          literal, then return the variable.  */
+       tree decl = COMPOUND_LITERAL_EXPR_DECL (exp);
+       emit_local_var (decl);
+       return expand_expr (decl, target, tmode, modifier);
+      }
 
-  /* Make a type for arrays of characters.
-     With luck nothing will ever really depend on the length of this
-     array type.  */
-  char_array_type_node
-    = build_array_type (char_type_node, array_domain_type);
+    default:
+      abort ();
+    }
 
-  /* Likewise for arrays of ints.  */
-  int_array_type_node
-    = build_array_type (integer_type_node, array_domain_type);
+  abort ();
+  return NULL;
+}
 
-#ifdef MD_INIT_BUILTINS
-  MD_INIT_BUILTINS;
-#endif
+/* Hook used by safe_from_p to handle language-specific tree codes.  */
 
-  /* This is special for C++ so functions can be overloaded.  */
-  wchar_type_node = get_identifier (flag_short_wchar
-                                   ? "short unsigned int"
-                                   : WCHAR_TYPE);
-  wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
-  wchar_type_size = TYPE_PRECISION (wchar_type_node);
-  if (c_language == clk_cplusplus)
-    {
-      if (TREE_UNSIGNED (wchar_type_node))
-       wchar_type_node = make_unsigned_type (wchar_type_size);
-      else
-       wchar_type_node = make_signed_type (wchar_type_size);
-      record_builtin_type (RID_WCHAR, "wchar_t", wchar_type_node);
-    }
-  else
+int
+c_safe_from_p (target, exp)
+     rtx target;
+     tree exp;
+{
+  /* We can see statements here when processing the body of a
+     statement-expression.  For a declaration statement declaring a
+     variable, look at the variable's initializer.  */
+  if (TREE_CODE (exp) == DECL_STMT) 
     {
-      signed_wchar_type_node = signed_type (wchar_type_node);
-      unsigned_wchar_type_node = unsigned_type (wchar_type_node);
+      tree decl = DECL_STMT_DECL (exp);
+
+      if (TREE_CODE (decl) == VAR_DECL
+         && DECL_INITIAL (decl)
+         && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0))
+       return 0;
     }
 
-  /* This is for wide string constants.  */
-  wchar_array_type_node
-    = build_array_type (wchar_type_node, array_domain_type);
+  /* For any statement, we must follow the statement-chain.  */
+  if (statement_code_p (TREE_CODE (exp)) && TREE_CHAIN (exp))
+    return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0);
+
+  /* Assume everything else is safe.  */
+  return 1;
+}
+
+/* Hook used by unsafe_for_reeval to handle language-specific tree codes.  */
+
+int
+c_common_unsafe_for_reeval (exp)
+     tree exp;
+{
+  /* Statement expressions may not be reevaluated, likewise compound
+     literals.  */
+  if (TREE_CODE (exp) == STMT_EXPR
+      || TREE_CODE (exp) == COMPOUND_LITERAL_EXPR)
+    return 2;
+
+  /* Walk all other expressions.  */
+  return -1;
+}
+
+/* Hook used by staticp to handle language-specific tree codes.  */
 
-  string_type_node = build_pointer_type (char_type_node);
-  const_string_type_node
-    = build_pointer_type (build_type_variant (char_type_node, 1, 0));
+int
+c_staticp (exp)
+     tree exp;
+{
+  if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+      && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
+    return 1;
+  return 0;
+}
 
-  wint_type_node =
-    TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE)));
+#define CALLED_AS_BUILT_IN(NODE) \
+   (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
 
-  intmax_type_node =
-    TREE_TYPE (identifier_global_value (get_identifier (INTMAX_TYPE)));
-  uintmax_type_node =
-    TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE)));
+static rtx
+c_expand_builtin (exp, target, tmode, modifier)
+     tree exp;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+{
+  tree type = TREE_TYPE (exp);
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  enum tree_code code = TREE_CODE (exp);
+  const int ignore = (target == const0_rtx
+                     || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
+                          || code == CONVERT_EXPR || code == REFERENCE_EXPR
+                          || code == COND_EXPR)
+                         && TREE_CODE (type) == VOID_TYPE));
 
-  default_function_type = build_function_type (integer_type_node, NULL_TREE);
-  ptrdiff_type_node
-    = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
-  unsigned_ptrdiff_type_node = unsigned_type (ptrdiff_type_node);
+  if (! optimize && ! CALLED_AS_BUILT_IN (fndecl))
+    return expand_call (exp, target, ignore);
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
-                       va_list_type_node));
+  switch (fcode)
+    {
+    case BUILT_IN_PRINTF:
+      target = c_expand_builtin_printf (arglist, target, tmode,
+                                       modifier, ignore, /*unlocked=*/ 0);
+      if (target)
+       return target;
+      break;
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
-                       ptrdiff_type_node));
+    case BUILT_IN_PRINTF_UNLOCKED:
+      target = c_expand_builtin_printf (arglist, target, tmode,
+                                       modifier, ignore, /*unlocked=*/ 1);
+      if (target)
+       return target;
+      break;
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
-                       sizetype));
+    case BUILT_IN_FPRINTF:
+      target = c_expand_builtin_fprintf (arglist, target, tmode,
+                                        modifier, ignore, /*unlocked=*/ 0);
+      if (target)
+       return target;
+      break;
 
-  if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
-    {
-      va_list_arg_type_node = va_list_ref_type_node =
-       build_pointer_type (TREE_TYPE (va_list_type_node));
-    }
-  else
-    {
-      va_list_arg_type_node = va_list_type_node;
-      va_list_ref_type_node = build_reference_type (va_list_type_node);
+    case BUILT_IN_FPRINTF_UNLOCKED:
+      target = c_expand_builtin_fprintf (arglist, target, tmode,
+                                        modifier, ignore, /*unlocked=*/ 1);
+      if (target)
+       return target;
+      break;
+
+    default:                   /* just do library call, if unknown builtin */
+      error ("built-in function `%s' not currently supported",
+            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
     }
-  endlink = void_list_node;
-  int_endlink = tree_cons (NULL_TREE, integer_type_node, endlink);
-  double_endlink = tree_cons (NULL_TREE, double_type_node, endlink);
-  unsigned_endlink = tree_cons (NULL_TREE, unsigned_type_node, endlink);
-  cstring_endlink = tree_cons (NULL_TREE, const_string_type_node, endlink);
-
-  ptr_ftype = build_function_type (ptr_type_node, NULL_TREE);
-  ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink);
-  sizetype_endlink = tree_cons (NULL_TREE, TYPE_DOMAIN (sizetype), endlink);
-  /* We realloc here because sizetype could be int or unsigned.  S'ok.  */
-  ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink);
-
-  int_ftype_any = build_function_type (integer_type_node, NULL_TREE);
-  void_ftype_any = build_function_type (void_type_node, NULL_TREE);
-  void_ftype = build_function_type (void_type_node, endlink);
-  void_ftype_int = build_function_type (void_type_node, int_endlink);
-  void_ftype_ptr
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node, endlink));
-
-  float_ftype_float
-    = build_function_type (float_type_node,
-                          tree_cons (NULL_TREE, float_type_node, endlink));
-
-  double_ftype_double
-    = build_function_type (double_type_node, double_endlink);
-
-  ldouble_ftype_ldouble
-    = build_function_type (long_double_type_node,
-                          tree_cons (NULL_TREE, long_double_type_node,
-                                     endlink));
-
-  double_ftype_double_double
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node,
-                                     double_endlink));
-
-  cfloat_ftype_cfloat
-    = build_function_type (complex_float_type_node,
-                          tree_cons (NULL_TREE, complex_float_type_node,
-                                     endlink));
-  cdouble_ftype_cdouble
-    = build_function_type (complex_double_type_node,
-                          tree_cons (NULL_TREE, complex_double_type_node,
-                                     endlink));
-  cldouble_ftype_cldouble
-    = build_function_type (complex_long_double_type_node,
-                          tree_cons (NULL_TREE, complex_long_double_type_node,
-                                     endlink));
-
-  float_ftype_cfloat
-    = build_function_type (float_type_node,
-                          tree_cons (NULL_TREE, complex_float_type_node,
-                                     endlink));
-  double_ftype_cdouble
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, complex_double_type_node,
-                                     endlink));
-  ldouble_ftype_cldouble
-    = build_function_type (long_double_type_node,
-                          tree_cons (NULL_TREE, complex_long_double_type_node,
-                                     endlink));
-
-  int_ftype_int
-    = build_function_type (integer_type_node, int_endlink);
-
-  long_ftype_long
-    = build_function_type (long_integer_type_node,
-                          tree_cons (NULL_TREE, long_integer_type_node,
-                                     endlink));
-
-  longlong_ftype_longlong
-    = build_function_type (long_long_integer_type_node,
-                          tree_cons (NULL_TREE, long_long_integer_type_node,
-                                     endlink));
-
-  intmax_ftype_intmax
-    = build_function_type (intmax_type_node,
-                          tree_cons (NULL_TREE, intmax_type_node,
-                                     endlink));
-
-  int_ftype_cptr_cptr_sizet
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_ptr_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_ptr_type_node,
-                                                sizetype_endlink)));
 
-  void_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (void_zero_node) = void_type_node;
+  /* The switch statement above can drop through to cause the function
+     to be called normally.  */
+  return expand_call (exp, target, ignore);
+}
 
-  /* Prototype for strcpy/strcat.  */
-  string_ftype_string_cstring
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, string_type_node,
-                                     cstring_endlink));
-
-  /* Prototype for strncpy/strncat.  */
-  string_ftype_string_cstring_sizet
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                sizetype_endlink)));
-
-  traditional_len_type_node = ((flag_traditional && 
-                               c_language != clk_cplusplus)
-                              ? integer_type_node : sizetype);
-  traditional_len_endlink = tree_cons (NULL_TREE, traditional_len_type_node,
-                                      endlink);
-
-  /* Prototype for strcmp.  */
-  int_ftype_cstring_cstring
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     cstring_endlink));
-
-  /* Prototype for strspn/strcspn.  */
-  sizet_ftype_cstring_cstring
-    = build_function_type (c_size_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     cstring_endlink));
-
-  /* Prototype for strncmp.  */
-  int_ftype_cstring_cstring_sizet
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                sizetype_endlink)));
-
-  /* Prototype for strstr, strpbrk, etc.  */
-  string_ftype_cstring_cstring
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     cstring_endlink));
-
-  /* Prototype for strchr.  */
-  string_ftype_cstring_int
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     int_endlink));
-
-  /* Prototype for strlen.  */
-  strlen_ftype
-    = build_function_type (traditional_len_type_node, cstring_endlink);
-
-  traditional_ptr_type_node = ((flag_traditional && 
-                               c_language != clk_cplusplus)
-                              ? string_type_node : ptr_type_node);
-  traditional_cptr_type_node = ((flag_traditional && 
-                                c_language != clk_cplusplus)
-                              ? const_string_type_node : const_ptr_type_node);
-
-  /* Prototype for memcpy.  */
-  memcpy_ftype
-    = build_function_type (traditional_ptr_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, const_ptr_type_node,
-                                                sizetype_endlink)));
-
-  /* Prototype for memset.  */
-  memset_ftype
-    = build_function_type (traditional_ptr_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE, integer_type_node,
-                                                sizetype_endlink)));
-
-  /* Prototype for bzero.  */
-  bzero_ftype
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, traditional_ptr_type_node,
-                                     traditional_len_endlink));
-
-  /* Prototype for bcmp.  */
-  bcmp_ftype
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, traditional_cptr_type_node,
-                                     tree_cons (NULL_TREE,
-                                                traditional_cptr_type_node,
-                                                traditional_len_endlink)));
-
-  /* Prototype for puts.  */
-  puts_ftype
-    = build_function_type (integer_type_node, cstring_endlink);
-
-  /* Prototype for printf.  */
-  printf_ftype
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     NULL_TREE));
+/* Check an arglist to *printf for problems.  The arglist should start
+   at the format specifier, with the remaining arguments immediately
+   following it.  */
+static int
+is_valid_printf_arglist (arglist)
+     tree arglist;
+{
+  /* Save this value so we can restore it later.  */
+  const int SAVE_pedantic = pedantic;
+  int diagnostic_occurred = 0;
+  tree attrs;
 
-  /* These stdio prototypes are declared using void* in place of
-     FILE*.  They are only used for __builtin_ style calls, regular
-     style builtin prototypes omit the arguments and merge those
-     provided by stdio.h.  */
-  /* Prototype for fwrite.  */
-  fwrite_ftype
-    = build_function_type (c_size_type_node,
-                          tree_cons (NULL_TREE, const_ptr_type_node,
-                                     tree_cons (NULL_TREE, c_size_type_node,
-                                                tree_cons (NULL_TREE, c_size_type_node,
-                                                           tree_cons (NULL_TREE, ptr_type_node, endlink)))));
-
-  /* Prototype for fputc.  */
-  fputc_ftype
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, integer_type_node,
-                                     tree_cons (NULL_TREE, ptr_type_node, endlink)));
-
-  /* Prototype for fputs.  */
-  fputs_ftype
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     tree_cons (NULL_TREE, ptr_type_node, endlink)));
-
-  /* Prototype for fprintf.  */
-  fprintf_ftype
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                NULL_TREE)));
-
-  builtin_function ("__builtin_constant_p", default_function_type,
-                   BUILT_IN_CONSTANT_P, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_return_address", ptr_ftype_unsigned,
-                   BUILT_IN_RETURN_ADDRESS, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_frame_address", ptr_ftype_unsigned,
-                   BUILT_IN_FRAME_ADDRESS, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_alloca", ptr_ftype_sizetype,
-                   BUILT_IN_ALLOCA, BUILT_IN_NORMAL, "alloca");
-  builtin_function_2 ("__builtin_ffs", "ffs",
-                     int_ftype_int, int_ftype_int,
-                     BUILT_IN_FFS, BUILT_IN_NORMAL, 0, 1, 0);
-  /* Define alloca as builtin, unless SMALL_STACK.  */
-#ifndef SMALL_STACK
-  builtin_function_2 (NULL_PTR, "alloca", NULL_TREE, ptr_ftype_sizetype,
-                     BUILT_IN_ALLOCA, BUILT_IN_NORMAL, 0, 1, 0);
-#endif
-  /* Declare _exit and _Exit just to mark them as non-returning.  */
-  builtin_function_2 (NULL_PTR, "_exit", NULL_TREE, void_ftype_int,
-                     0, NOT_BUILT_IN, 0, 1, 1);
-  builtin_function_2 (NULL_PTR, "_Exit", NULL_TREE, void_ftype_int,
-                     0, NOT_BUILT_IN, 0, !flag_isoc99, 1);
+  /* Set this to a known value so the user setting won't affect code
+     generation.  */
+  pedantic = 1;
+  /* Check to make sure there are no format specifier errors.  */
+  attrs = tree_cons (get_identifier ("format"),
+                    tree_cons (NULL_TREE,
+                               get_identifier ("printf"),
+                               tree_cons (NULL_TREE,
+                                          integer_one_node,
+                                          tree_cons (NULL_TREE,
+                                                     build_int_2 (2, 0),
+                                                     NULL_TREE))),
+                    NULL_TREE);
+  check_function_format (&diagnostic_occurred, attrs, arglist);
+
+  /* Restore the value of `pedantic'.  */
+  pedantic = SAVE_pedantic;
 
-  builtin_function_2 ("__builtin_index", "index",
-                     string_ftype_cstring_int, string_ftype_cstring_int,
-                     BUILT_IN_INDEX, BUILT_IN_NORMAL, 1, 1, 0);
-  builtin_function_2 ("__builtin_rindex", "rindex",
-                     string_ftype_cstring_int, string_ftype_cstring_int,
-                     BUILT_IN_RINDEX, BUILT_IN_NORMAL, 1, 1, 0);
-
-  /* The system prototypes for these functions have many
-     variations, so don't specify parameters to avoid conflicts.
-     The expand_* functions check the argument types anyway.  */
-  builtin_function_2 ("__builtin_bzero", "bzero",
-                     bzero_ftype, void_ftype_any,
-                     BUILT_IN_BZERO, BUILT_IN_NORMAL, 1, 1, 0);
-  builtin_function_2 ("__builtin_bcmp", "bcmp",
-                     bcmp_ftype, int_ftype_any,
-                     BUILT_IN_BCMP, BUILT_IN_NORMAL, 1, 1, 0);
-
-  builtin_function_2 ("__builtin_abs", "abs",
-                     int_ftype_int, int_ftype_int,
-                     BUILT_IN_ABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_fabsf", "fabsf",
-                     float_ftype_float, float_ftype_float,
-                     BUILT_IN_FABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_fabs", "fabs",
-                     double_ftype_double, double_ftype_double,
-                     BUILT_IN_FABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_fabsl", "fabsl",
-                     ldouble_ftype_ldouble, ldouble_ftype_ldouble,
-                     BUILT_IN_FABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_labs", "labs",
-                     long_ftype_long, long_ftype_long,
-                     BUILT_IN_ABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_llabs", "llabs",
-                     longlong_ftype_longlong, longlong_ftype_longlong,
-                     BUILT_IN_ABS, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_imaxabs", "imaxabs",
-                     intmax_ftype_intmax, intmax_ftype_intmax,
-                     BUILT_IN_ABS, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-
-  builtin_function ("__builtin_saveregs", ptr_ftype, BUILT_IN_SAVEREGS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_classify_type", default_function_type,
-                   BUILT_IN_CLASSIFY_TYPE, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_next_arg", ptr_ftype, BUILT_IN_NEXT_ARG,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_args_info", int_ftype_int, BUILT_IN_ARGS_INFO,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_setjmp",
-                   build_function_type (integer_type_node,
-                                        tree_cons (NULL_TREE, ptr_type_node,
-                                                   endlink)),
-                   BUILT_IN_SETJMP, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_longjmp",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE, ptr_type_node,
-                                                   int_endlink)),
-                   BUILT_IN_LONGJMP, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_trap", void_ftype, BUILT_IN_TRAP,
-                   BUILT_IN_NORMAL, NULL_PTR);
-
-  /* ISO C99 IEEE Unordered compares.  */
-  builtin_function ("__builtin_isgreater", default_function_type,
-                   BUILT_IN_ISGREATER, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_isgreaterequal", default_function_type,
-                   BUILT_IN_ISGREATEREQUAL, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_isless", default_function_type,
-                   BUILT_IN_ISLESS, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_islessequal", default_function_type,
-                   BUILT_IN_ISLESSEQUAL, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_islessgreater", default_function_type,
-                   BUILT_IN_ISLESSGREATER, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_isunordered", default_function_type,
-                   BUILT_IN_ISUNORDERED, BUILT_IN_NORMAL, NULL_PTR);
-
-  /* Untyped call and return.  */
-  builtin_function ("__builtin_apply_args", ptr_ftype,
-                   BUILT_IN_APPLY_ARGS, BUILT_IN_NORMAL, NULL_PTR);
-
-  temp = tree_cons (NULL_TREE,
-                   build_pointer_type (build_function_type (void_type_node,
-                                                            NULL_TREE)),
-                   tree_cons (NULL_TREE, ptr_type_node, sizetype_endlink));
-  builtin_function ("__builtin_apply",
-                   build_function_type (ptr_type_node, temp),
-                   BUILT_IN_APPLY, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_return", void_ftype_ptr,
-                   BUILT_IN_RETURN, BUILT_IN_NORMAL, NULL_PTR);
-
-  /* Support for varargs.h and stdarg.h.  */
-  builtin_function ("__builtin_varargs_start",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   va_list_ref_type_node,
-                                                   endlink)),
-                   BUILT_IN_VARARGS_START, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_stdarg_start",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   va_list_ref_type_node,
-                                                   NULL_TREE)),
-                   BUILT_IN_STDARG_START, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_va_end",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   va_list_ref_type_node,
-                                                   endlink)),
-                   BUILT_IN_VA_END, BUILT_IN_NORMAL, NULL_PTR);
-
-  builtin_function ("__builtin_va_copy",
-                   build_function_type (void_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   va_list_ref_type_node,
-                                                   tree_cons (NULL_TREE,
-                                                     va_list_arg_type_node,
-                                                     endlink))),
-                   BUILT_IN_VA_COPY, BUILT_IN_NORMAL, NULL_PTR);
-
-  /* ??? Ought to be `T __builtin_expect(T, T)' for any type T.  */
-  builtin_function ("__builtin_expect",
-                   build_function_type (long_integer_type_node,
-                                        tree_cons (NULL_TREE,
-                                                   long_integer_type_node,
-                                                   tree_cons (NULL_TREE,
-                                                       long_integer_type_node,
-                                                       endlink))),
-                   BUILT_IN_EXPECT, BUILT_IN_NORMAL, NULL_PTR);
-
-  /* Currently under experimentation.  */
-  builtin_function_2 ("__builtin_memcpy", "memcpy",
-                     memcpy_ftype, memcpy_ftype,
-                     BUILT_IN_MEMCPY, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_memcmp", "memcmp",
-                     int_ftype_cptr_cptr_sizet, int_ftype_cptr_cptr_sizet,
-                     BUILT_IN_MEMCMP, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_memset", "memset",
-                     memset_ftype, memset_ftype,
-                     BUILT_IN_MEMSET, BUILT_IN_NORMAL, 1, 0, 0);
-  built_in_decls[BUILT_IN_STRCMP] =
-    builtin_function_2 ("__builtin_strcmp", "strcmp",
-                       int_ftype_cstring_cstring, int_ftype_cstring_cstring,
-                       BUILT_IN_STRCMP, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strncmp", "strncmp",
-                     int_ftype_cstring_cstring_sizet,
-                     int_ftype_cstring_cstring_sizet,
-                     BUILT_IN_STRNCMP, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strstr", "strstr",
-                     string_ftype_cstring_cstring, string_ftype_cstring_cstring,
-                     BUILT_IN_STRSTR, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strpbrk", "strpbrk",
-                     string_ftype_cstring_cstring, string_ftype_cstring_cstring,
-                     BUILT_IN_STRPBRK, BUILT_IN_NORMAL, 1, 0, 0);
-  built_in_decls[BUILT_IN_STRCHR] =
-    builtin_function_2 ("__builtin_strchr", "strchr",
-                       string_ftype_cstring_int, string_ftype_cstring_int,
-                       BUILT_IN_STRCHR, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strrchr", "strrchr",
-                     string_ftype_cstring_int, string_ftype_cstring_int,
-                     BUILT_IN_STRRCHR, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strcpy", "strcpy",
-                     string_ftype_string_cstring, string_ftype_string_cstring,
-                     BUILT_IN_STRCPY, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strncpy", "strncpy",
-                     string_ftype_string_cstring_sizet,
-                     string_ftype_string_cstring_sizet,
-                     BUILT_IN_STRNCPY, BUILT_IN_NORMAL, 1, 0, 0);
-  built_in_decls[BUILT_IN_STRCAT] =
-    builtin_function_2 ("__builtin_strcat", "strcat",
-                       string_ftype_string_cstring,
-                       string_ftype_string_cstring,
-                       BUILT_IN_STRCAT, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strncat", "strncat",
-                     string_ftype_string_cstring_sizet,
-                     string_ftype_string_cstring_sizet,
-                     BUILT_IN_STRNCAT, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strspn", "strspn",
-                     sizet_ftype_cstring_cstring, sizet_ftype_cstring_cstring,
-                     BUILT_IN_STRSPN, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_strcspn", "strcspn",
-                     sizet_ftype_cstring_cstring, sizet_ftype_cstring_cstring,
-                     BUILT_IN_STRCSPN, BUILT_IN_NORMAL, 1, 0, 0);
-  built_in_decls[BUILT_IN_STRLEN] =
-    builtin_function_2 ("__builtin_strlen", "strlen",
-                       strlen_ftype, strlen_ftype,
-                       BUILT_IN_STRLEN, BUILT_IN_NORMAL, 1, 0, 0);
-
-  builtin_function_2 ("__builtin_sqrtf", "sqrtf",
-                     float_ftype_float, float_ftype_float,
-                     BUILT_IN_FSQRT, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_fsqrt", "sqrt",
-                     double_ftype_double, double_ftype_double,
-                     BUILT_IN_FSQRT, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_sqrtl", "sqrtl",
-                     ldouble_ftype_ldouble, ldouble_ftype_ldouble,
-                     BUILT_IN_FSQRT, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_sinf", "sinf",
-                     float_ftype_float, float_ftype_float,
-                     BUILT_IN_SIN, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_sin", "sin",
-                     double_ftype_double, double_ftype_double,
-                     BUILT_IN_SIN, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_sinl", "sinl",
-                     ldouble_ftype_ldouble, ldouble_ftype_ldouble,
-                     BUILT_IN_SIN, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_cosf", "cosf",
-                     float_ftype_float, float_ftype_float,
-                     BUILT_IN_COS, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_cos", "cos",
-                     double_ftype_double, double_ftype_double,
-                     BUILT_IN_COS, BUILT_IN_NORMAL, 1, 0, 0);
-  builtin_function_2 ("__builtin_cosl", "cosl",
-                     ldouble_ftype_ldouble, ldouble_ftype_ldouble,
-                     BUILT_IN_COS, BUILT_IN_NORMAL, 1, 0, 0);
-
-  /* ISO C99 complex arithmetic functions.  */
-  builtin_function_2 ("__builtin_conjf", "conjf",
-                     cfloat_ftype_cfloat, cfloat_ftype_cfloat,
-                     BUILT_IN_CONJ, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_conj", "conj",
-                     cdouble_ftype_cdouble, cdouble_ftype_cdouble,
-                     BUILT_IN_CONJ, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_conjl", "conjl",
-                     cldouble_ftype_cldouble, cldouble_ftype_cldouble,
-                     BUILT_IN_CONJ, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_crealf", "crealf",
-                     float_ftype_cfloat, float_ftype_cfloat,
-                     BUILT_IN_CREAL, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_creal", "creal",
-                     double_ftype_cdouble, double_ftype_cdouble,
-                     BUILT_IN_CREAL, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_creall", "creall",
-                     ldouble_ftype_cldouble, ldouble_ftype_cldouble,
-                     BUILT_IN_CREAL, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_cimagf", "cimagf",
-                     float_ftype_cfloat, float_ftype_cfloat,
-                     BUILT_IN_CIMAG, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_cimag", "cimag",
-                     double_ftype_cdouble, double_ftype_cdouble,
-                     BUILT_IN_CIMAG, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_cimagl", "cimagl",
-                     ldouble_ftype_cldouble, ldouble_ftype_cldouble,
-                     BUILT_IN_CIMAG, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-
-  built_in_decls[BUILT_IN_PUTCHAR] =
-    builtin_function ("__builtin_putchar", int_ftype_int,
-                     BUILT_IN_PUTCHAR, BUILT_IN_NORMAL, "putchar");
-  built_in_decls[BUILT_IN_PUTS] =
-    builtin_function ("__builtin_puts", puts_ftype,
-                     BUILT_IN_PUTS, BUILT_IN_NORMAL, "puts");
-  builtin_function_2 ("__builtin_printf", "printf",
-                     printf_ftype, printf_ftype,
-                     BUILT_IN_PRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
-  builtin_function_2 ("__builtin_fprintf", "fprintf",
-                     fprintf_ftype, fprintf_ftype,
-                     BUILT_IN_FPRINTF, BUILT_IN_FRONTEND, 1, 0, 0);
-  built_in_decls[BUILT_IN_FWRITE] =
-    builtin_function ("__builtin_fwrite", fwrite_ftype,
-                     BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite");
-  built_in_decls[BUILT_IN_FPUTC] =
-    builtin_function ("__builtin_fputc", fputc_ftype,
-                     BUILT_IN_FPUTC, BUILT_IN_NORMAL, "fputc");
-  /* Declare the __builtin_ style with arguments and the regular style
-     without them.  We rely on stdio.h to supply the arguments for the
-     regular style declaration since we had to use void* instead of
-     FILE* in the __builtin_ prototype supplied here.  */
-  built_in_decls[BUILT_IN_FPUTS] =
-    builtin_function_2 ("__builtin_fputs", "fputs",
-                       fputs_ftype, int_ftype_any,
-                       BUILT_IN_FPUTS, BUILT_IN_NORMAL, 1, 0, 0);
+  /* If calling `check_function_format_ptr' produces a warning, we
+     return false, otherwise we return true.  */
+  return ! diagnostic_occurred;
+}
 
-  /* Declare these functions non-returning
-     to avoid spurious "control drops through" warnings.  */
-  builtin_function_2 (NULL_PTR, "abort",
-                     NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? void_ftype : void_ftype_any),
-                     0, NOT_BUILT_IN, 0, 0, 1);
+/* If the arguments passed to printf are suitable for optimizations,
+   we attempt to transform the call.  */
+static rtx
+c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
+     tree arglist;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+     int ignore;
+     int unlocked;
+{
+  tree fn_putchar = unlocked ?
+    built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : built_in_decls[BUILT_IN_PUTCHAR];
+  tree fn_puts = unlocked ?
+    built_in_decls[BUILT_IN_PUTS_UNLOCKED] : built_in_decls[BUILT_IN_PUTS];
+  tree fn, format_arg, stripped_string;
 
-  builtin_function_2 (NULL_PTR, "exit",
-                     NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? void_ftype_int : void_ftype_any),
-                     0, NOT_BUILT_IN, 0, 0, 1);
+  /* If the return value is used, or the replacement _DECL isn't
+     initialized, don't do the transformation.  */
+  if (!ignore || !fn_putchar || !fn_puts)
+    return 0;
 
-#if 0
-  /* Support for these has not been written in either expand_builtin
-     or build_function_call.  */
-  builtin_function ("__builtin_div", default_ftype, BUILT_IN_DIV,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_ldiv", default_ftype, BUILT_IN_LDIV,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_ffloor", double_ftype_double, BUILT_IN_FFLOOR,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_fceil", double_ftype_double, BUILT_IN_FCEIL,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_fmod", double_ftype_double_double,
-                   BUILT_IN_FMOD, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_frem", double_ftype_double_double,
-                   BUILT_IN_FREM, BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
-                   BUILT_IN_NORMAL, NULL_PTR);
-#endif
+  /* Verify the required arguments in the original call.  */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
+    return 0;
+  
+  /* Check the specifier vs. the parameters.  */
+  if (!is_valid_printf_arglist (arglist))
+    return 0;
+  
+  format_arg = TREE_VALUE (arglist);
+  stripped_string = format_arg;
+  STRIP_NOPS (stripped_string);
+  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
+    stripped_string = TREE_OPERAND (stripped_string, 0);
 
-  main_identifier_node = get_identifier ("main");
+  /* If the format specifier isn't a STRING_CST, punt.  */
+  if (TREE_CODE (stripped_string) != STRING_CST)
+    return 0;
+  
+  /* OK!  We can attempt optimization.  */
 
-  /* ??? Perhaps there's a better place to do this.  But it is related
-     to __builtin_va_arg, so it isn't that off-the-wall.  */
-  lang_type_promotes_to = simple_type_promotes_to;
+  /* If the format specifier was "%s\n", call __builtin_puts(arg2).  */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_puts;
+    }
+  /* If the format specifier was "%c", call __builtin_putchar (arg2).  */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_putchar;
+    }
+  else
+    {
+      /* We can't handle anything else with % args or %% ... yet.  */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+       return 0;
+      
+      /* If the resulting constant string has a length of 1, call
+         putchar.  Note, TREE_STRING_LENGTH includes the terminating
+         NULL in its count.  */
+      if (TREE_STRING_LENGTH (stripped_string) == 2)
+        {
+         /* Given printf("c"), (where c is any one character,)
+             convert "c"[0] to an int and pass that to the replacement
+             function.  */
+         arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+         arglist = build_tree_list (NULL_TREE, arglist);
+         
+         fn = fn_putchar;
+        }
+      /* If the resulting constant was "string\n", call
+         __builtin_puts("string").  Ensure "string" has at least one
+         character besides the trailing \n.  Note, TREE_STRING_LENGTH
+         includes the terminating NULL in its count.  */
+      else if (TREE_STRING_LENGTH (stripped_string) > 2
+              && TREE_STRING_POINTER (stripped_string)
+              [TREE_STRING_LENGTH (stripped_string) - 2] == '\n')
+        {
+         /* Create a NULL-terminated string that's one char shorter
+            than the original, stripping off the trailing '\n'.  */
+         const int newlen = TREE_STRING_LENGTH (stripped_string) - 1;
+         char *newstr = (char *) alloca (newlen);
+         memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
+         newstr[newlen - 1] = 0;
+         
+         arglist = fix_string_type (build_string (newlen, newstr));
+         arglist = build_tree_list (NULL_TREE, arglist);
+         fn = fn_puts;
+       }
+      else
+       /* We'd like to arrange to call fputs(string) here, but we
+           need stdout and don't have a way to get it ... yet.  */
+       return 0;
+    }
+  
+  return expand_expr (build_function_call (fn, arglist),
+                     (ignore ? const0_rtx : target),
+                     tmode, modifier);
 }
 
-tree
-build_va_arg (expr, type)
-     tree expr, type;
+/* If the arguments passed to fprintf are suitable for optimizations,
+   we attempt to transform the call.  */
+static rtx
+c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore, unlocked)
+     tree arglist;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+     int ignore;
+     int unlocked;
 {
-  return build1 (VA_ARG_EXPR, type, expr);
-}
+  tree fn_fputc = unlocked ?
+    built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : built_in_decls[BUILT_IN_FPUTC];
+  tree fn_fputs = unlocked ?
+    built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : built_in_decls[BUILT_IN_FPUTS];
+  tree fn, format_arg, stripped_string;
 
+  /* If the return value is used, or the replacement _DECL isn't
+     initialized, don't do the transformation.  */
+  if (!ignore || !fn_fputc || !fn_fputs)
+    return 0;
 
-/* Possibly define a builtin function with one or two names.  BUILTIN_NAME
-   is an __builtin_-prefixed name; NAME is the ordinary name; one or both
-   of these may be NULL (though both being NULL is useless).
-   BUILTIN_TYPE is the type of the __builtin_-prefixed function;
-   TYPE is the type of the function with the ordinary name.  These
-   may differ if the ordinary name is declared with a looser type to avoid
-   conflicts with headers.  FUNCTION_CODE and CLASS are as for
-   builtin_function.  If LIBRARY_NAME_P is nonzero, NAME is passed as
-   the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME.
-   If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name; if
-   NORETURN_P is nonzero, the function is marked as non-returning.
-   Returns the declaration of BUILTIN_NAME, if any, otherwise
-   the declaration of NAME.  Does not declare NAME if flag_no_builtin,
-   or if NONANSI_P and flag_no_nonansi_builtin.  */
+  /* Verify the required arguments in the original call.  */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
+      || (TREE_CHAIN (arglist) == 0)
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) !=
+         POINTER_TYPE))
+    return 0;
+  
+  /* Check the specifier vs. the parameters.  */
+  if (!is_valid_printf_arglist (TREE_CHAIN (arglist)))
+    return 0;
+  
+  format_arg = TREE_VALUE (TREE_CHAIN (arglist));
+  stripped_string = format_arg;
+  STRIP_NOPS (stripped_string);
+  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
+    stripped_string = TREE_OPERAND (stripped_string, 0);
 
-static tree
-builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
-                   class, library_name_p, nonansi_p, noreturn_p)
-     const char *builtin_name;
-     const char *name;
-     tree builtin_type;
-     tree type;
-     int function_code;
-     enum built_in_class class;
-     int library_name_p;
-     int nonansi_p;
-     int noreturn_p;
-{
-  tree bdecl = NULL_TREE;
-  tree decl = NULL_TREE;
-  if (builtin_name != 0)
+  /* If the format specifier isn't a STRING_CST, punt.  */
+  if (TREE_CODE (stripped_string) != STRING_CST)
+    return 0;
+  
+  /* OK!  We can attempt optimization.  */
+
+  /* If the format specifier was "%s", call __builtin_fputs(arg3, arg1).  */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
     {
-      bdecl = builtin_function (builtin_name, builtin_type, function_code,
-                               class, library_name_p ? name : NULL_PTR);
-      if (noreturn_p)
-       {
-         TREE_THIS_VOLATILE (bdecl) = 1;
-         TREE_SIDE_EFFECTS (bdecl) = 1;
-       }
+      tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
+      arglist = tree_cons (NULL_TREE,
+                          TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
+                          newarglist);
+      fn = fn_fputs;
     }
-  if (name != 0 && !flag_no_builtin && !(nonansi_p && flag_no_nonansi_builtin))
+  /* If the format specifier was "%c", call __builtin_fputc (arg3, arg1).  */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
     {
-      decl = builtin_function (name, type, function_code, class, NULL_PTR);
-      if (nonansi_p)
-       DECL_BUILT_IN_NONANSI (decl) = 1;
-      if (noreturn_p)
-       {
-         TREE_THIS_VOLATILE (decl) = 1;
-         TREE_SIDE_EFFECTS (decl) = 1;
-       }
+      tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
+      arglist = tree_cons (NULL_TREE,
+                          TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
+                          newarglist);
+      fn = fn_fputc;
     }
-  return (bdecl != 0 ? bdecl : decl);
+  else
+    {
+      /* We can't handle anything else with % args or %% ... yet.  */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+       return 0;
+      
+      /* When "string" doesn't contain %, replace all cases of
+         fprintf(stream,string) with fputs(string,stream).  The fputs
+         builtin will take take of special cases like length==1.  */
+      arglist = tree_cons (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)),
+                          build_tree_list (NULL_TREE, TREE_VALUE (arglist)));
+      fn = fn_fputs;
+    }
+  
+  return expand_expr (build_function_call (fn, arglist),
+                     (ignore ? const0_rtx : target),
+                     tmode, modifier);
 }
 \f
-/* Given a type, apply default promotions wrt unnamed function arguments
-   and return the new type.  Return NULL_TREE if no change.  */
-/* ??? There is a function of the same name in the C++ front end that
-   does something similar, but is more thorough and does not return NULL
-   if no change.  We could perhaps share code, but it would make the
-   self_promoting_type property harder to identify.  */
 
+/* Given a boolean expression ARG, return a tree representing an increment
+   or decrement (as indicated by CODE) of ARG.  The front end must check for
+   invalid cases (e.g., decrement in C++).  */
 tree
-simple_type_promotes_to (type)
-     tree type;
+boolean_increment (code, arg)
+     enum tree_code code;
+     tree arg;
 {
-  if (TYPE_MAIN_VARIANT (type) == float_type_node)
-    return double_type_node;
-
-  if (C_PROMOTING_INTEGER_TYPE_P (type))
+  tree val;
+  tree true_res = (c_language == clk_cplusplus
+                  ? boolean_true_node
+                  : c_bool_true_node);
+  arg = stabilize_reference (arg);
+  switch (code)
     {
-      /* Traditionally, unsignedness is preserved in default promotions.
-         Also preserve unsignedness if not really getting any wider.  */
-      if (TREE_UNSIGNED (type)
-          && (flag_traditional
-              || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
-        return unsigned_type_node;
-      return integer_type_node;
+    case PREINCREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+      break;
+    case POSTINCREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+      arg = save_expr (arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+      break;
+    case PREDECREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+      break;
+    case POSTDECREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+      arg = save_expr (arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+      break;
+    default:
+      abort ();
     }
-
-  return NULL_TREE;
+  TREE_SIDE_EFFECTS (val) = 1;
+  return val;
 }
+\f
+/* Handle C and C++ default attributes.  */
 
-/* Return 1 if PARMS specifies a fixed number of parameters
-   and none of their types is affected by default promotions.  */
-
-int
-self_promoting_args_p (parms)
-     tree parms;
+enum built_in_attribute
 {
-  register tree t;
-  for (t = parms; t; t = TREE_CHAIN (t))
-    {
-      register tree type = TREE_VALUE (t);
-
-      if (TREE_CHAIN (t) == 0 && type != void_type_node)
-       return 0;
-
-      if (type == 0)
-       return 0;
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum.  */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+  ATTR_LAST
+};
 
-      if (TYPE_MAIN_VARIANT (type) == float_type_node)
-       return 0;
+static tree built_in_attributes[(int) ATTR_LAST];
 
-      if (C_PROMOTING_INTEGER_TYPE_P (type))
-       return 0;
-    }
-  return 1;
-}
+static bool c_attrs_initialized = false;
 
-/* Recursively examines the array elements of TYPE, until a non-array
-   element type is found.  */
+static void c_init_attributes PARAMS ((void));
 
-tree
-strip_array_types (type)
-     tree type;
+/* Common initialization before parsing options.  */
+void
+c_common_init_options (lang)
+     enum c_language_kind lang;
 {
-  while (TREE_CODE (type) == ARRAY_TYPE)
-    type = TREE_TYPE (type);
+  c_language = lang;
+  parse_in = cpp_create_reader (lang == clk_c ? CLK_GNUC89:
+                               lang == clk_cplusplus ? CLK_GNUCXX: CLK_OBJC);
 
-  return type;
+  /* Mark as "unspecified" (see c_common_post_options).  */
+  flag_bounds_check = -1;
 }
 
-/* Recognize certain built-in functions so we can make tree-codes
-   other than CALL_EXPR.  We do this when it enables fold-const.c
-   to do something useful.  */
-/* ??? By rights this should go in builtins.c, but only C and C++
-   implement build_{binary,unary}_op.  Not exactly sure what bits
-   of functionality are actually needed from those functions, or
-   where the similar functionality exists in the other front ends.  */
-
-tree
-expand_tree_builtin (function, params, coerced_params)
-     tree function, params, coerced_params;
+/* Post-switch processing.  */
+void
+c_common_post_options ()
 {
-  enum tree_code code;
+  cpp_post_options (parse_in);
 
-  if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
-    return NULL_TREE;
+  flag_inline_trees = 1;
 
-  switch (DECL_FUNCTION_CODE (function))
+  /* Use tree inlining if possible.  Function instrumentation is only
+     done in the RTL level, so we disable tree inlining.  */
+  if (! flag_instrument_function_entry_exit)
     {
-    case BUILT_IN_ABS:
-    case BUILT_IN_FABS:
-      if (coerced_params == 0)
-       return integer_zero_node;
-      return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
-
-    case BUILT_IN_CONJ:
-      if (coerced_params == 0)
-       return integer_zero_node;
-      return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0);
-
-    case BUILT_IN_CREAL:
-      if (coerced_params == 0)
-       return integer_zero_node;
-      return build_unary_op (REALPART_EXPR, TREE_VALUE (coerced_params), 0);
-
-    case BUILT_IN_CIMAG:
-      if (coerced_params == 0)
-       return integer_zero_node;
-      return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
-
-    case BUILT_IN_ISGREATER:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNLE_EXPR;
-      else
-       code = LE_EXPR;
-      goto unordered_cmp;
-
-    case BUILT_IN_ISGREATEREQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNLT_EXPR;
-      else
-       code = LT_EXPR;
-      goto unordered_cmp;
-
-    case BUILT_IN_ISLESS:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGE_EXPR;
-      else
-       code = GE_EXPR;
-      goto unordered_cmp;
-
-    case BUILT_IN_ISLESSEQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGT_EXPR;
-      else
-       code = GT_EXPR;
-      goto unordered_cmp;
-
-    case BUILT_IN_ISLESSGREATER:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNEQ_EXPR;
-      else
-       code = EQ_EXPR;
-      goto unordered_cmp;
-
-    case BUILT_IN_ISUNORDERED:
-      if (TARGET_FLOAT_FORMAT != IEEE_FLOAT_FORMAT)
-       return integer_zero_node;
-      code = UNORDERED_EXPR;
-      goto unordered_cmp;
-
-    unordered_cmp:
-      {
-       tree arg0, arg1;
-
-       if (params == 0
-           || TREE_CHAIN (params) == 0)
-         {
-           error ("too few arguments to function `%s'",
-                  IDENTIFIER_POINTER (DECL_NAME (function)));
-           return error_mark_node;
-         }
-       else if (TREE_CHAIN (TREE_CHAIN (params)) != 0)
-         {
-           error ("too many arguments to function `%s'",
-                  IDENTIFIER_POINTER (DECL_NAME (function)));
-           return error_mark_node;
-         }
-
-       arg0 = TREE_VALUE (params);
-       arg1 = TREE_VALUE (TREE_CHAIN (params));
-       arg0 = build_binary_op (code, arg0, arg1, 0);
-       if (code != UNORDERED_EXPR)
-         arg0 = build_unary_op (TRUTH_NOT_EXPR, arg0, 0);
-       return arg0;
-      }
-      break;
-
-    default:
-      break;
+      if (!flag_no_inline)
+       flag_no_inline = 1;
+      if (flag_inline_functions)
+       {
+         flag_inline_trees = 2;
+         flag_inline_functions = 0;
+       }
     }
 
-  return NULL_TREE;
-}
+  /* If still "unspecified", make it match -fbounded-pointers.  */
+  if (flag_bounds_check == -1)
+    flag_bounds_check = flag_bounded_pointers;
 
-/* Returns non-zero if CODE is the code for a statement.  */
+  /* Special format checking options don't work without -Wformat; warn if
+     they are used.  */
+  if (warn_format_y2k && !warn_format)
+    warning ("-Wformat-y2k ignored without -Wformat");
+  if (warn_format_extra_args && !warn_format)
+    warning ("-Wformat-extra-args ignored without -Wformat");
+  if (warn_format_nonliteral && !warn_format)
+    warning ("-Wformat-nonliteral ignored without -Wformat");
+  if (warn_format_security && !warn_format)
+    warning ("-Wformat-security ignored without -Wformat");
+  if (warn_missing_format_attribute && !warn_format)
+    warning ("-Wmissing-format-attribute ignored without -Wformat");
+}
 
-int
-statement_code_p (code)
-     enum tree_code code;
+/* Front end initialization common to C, ObjC and C++.  */
+const char *
+c_common_init (filename)
+     const char *filename;
 {
-  switch (code)
+  /* NULL is passed up to toplev.c and we exit quickly.  */
+  if (flag_preprocess_only)
     {
-    case EXPR_STMT:
-    case COMPOUND_STMT:
-    case DECL_STMT:
-    case IF_STMT:
-    case FOR_STMT:
-    case WHILE_STMT:
-    case DO_STMT:
-    case RETURN_STMT:
-    case BREAK_STMT:
-    case CONTINUE_STMT:
-    case SCOPE_STMT:
-    case SWITCH_STMT:
-    case GOTO_STMT:
-    case LABEL_STMT:
-    case ASM_STMT:
-    case CASE_LABEL:
-      return 1;
-
-    default:
-      if (lang_statement_code_p)
-       return (*lang_statement_code_p) (code);
-      return 0;
+      cpp_preprocess_file (parse_in);
+      return NULL;
     }
-}
 
-/* Walk the statemen tree, rooted at *tp.  Apply FUNC to all the
-   sub-trees of *TP in a pre-order traversal.  FUNC is called with the
-   DATA and the address of each sub-tree.  If FUNC returns a non-NULL
-   value, the traversal is aborted, and the value returned by FUNC is
-   returned.  If FUNC sets WALK_SUBTREES to zero, then the subtrees of
-   the node being visited are not walked.
+  /* Do this before initializing pragmas, as then cpplib's hash table
+     has been set up.  */
+  filename = init_c_lex (filename);
 
-   We don't need a without_duplicates variant of this one because the
-   statement tree is a tree, not a graph.  */
+  init_pragma ();
 
-tree 
-walk_stmt_tree (tp, func, data)
-     tree *tp;
-     walk_tree_fn func;
-     void *data;
-{
-  enum tree_code code;
-  int walk_subtrees;
-  tree result;
-  int i, len;
+  if (!c_attrs_initialized)
+    c_init_attributes ();
 
-#define WALK_SUBTREE(NODE)                             \
-  do                                                   \
-    {                                                  \
-      result = walk_stmt_tree (&(NODE), func, data);   \
-      if (result)                                      \
-       return result;                                  \
-    }                                                  \
-  while (0)
+  return filename;
+}
+
+/* Common finish hook for the C, ObjC and C++ front ends.  */
+void
+c_common_finish ()
+{
+  cpp_finish (parse_in);
 
-  /* Skip empty subtrees.  */
-  if (!*tp)
-    return NULL_TREE;
+  /* For performance, avoid tearing down cpplib's internal structures.
+     Call cpp_errors () instead of cpp_destroy ().  */
+  errorcount += cpp_errors (parse_in);
+}
 
-  /* Skip subtrees below non-statement nodes.  */
-  if (!statement_code_p (TREE_CODE (*tp)))
-    return NULL_TREE;
+static void
+c_init_attributes ()
+{
+  /* Fill in the built_in_attributes array.  */
+#define DEF_ATTR_NULL_TREE(ENUM)               \
+  built_in_attributes[(int) ENUM] = NULL_TREE;
+#define DEF_ATTR_INT(ENUM, VALUE)                                           \
+  built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_IDENT(ENUM, STRING)                           \
+  built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)        \
+  built_in_attributes[(int) ENUM]                      \
+    = tree_cons (built_in_attributes[(int) PURPOSE],   \
+                built_in_attributes[(int) VALUE],      \
+                built_in_attributes[(int) CHAIN]);
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No initialization needed.  */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+  ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST);
+  c_attrs_initialized = true;
+}
 
-  /* Call the function.  */
-  walk_subtrees = 1;
-  result = (*func) (tp, &walk_subtrees, data);
+/* Depending on the name of DECL, apply default attributes to it.  */
 
-  /* If we found something, return it.  */
-  if (result)
-    return result;
+void
+c_common_insert_default_attributes (decl)
+     tree decl;
+{
+  tree name = DECL_NAME (decl);
+
+  if (!c_attrs_initialized)
+    c_init_attributes ();
+
+#define DEF_ATTR_NULL_TREE(ENUM) /* Nothing needed after initialization.  */
+#define DEF_ATTR_INT(ENUM, VALUE)
+#define DEF_ATTR_IDENT(ENUM, STRING)
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE)                    \
+  if ((PREDICATE) && name == built_in_attributes[(int) NAME])  \
+    decl_attributes (&decl, built_in_attributes[(int) ATTRS],  \
+                    ATTR_FLAG_BUILT_IN);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+}
 
-  /* Even if we didn't, FUNC may have decided that there was nothing
-     interesting below this point in the tree.  */
-  if (!walk_subtrees)
-    return NULL_TREE;
+/* Output a -Wshadow warning MSGID about NAME, an IDENTIFIER_NODE, and
+   additionally give the location of the previous declaration DECL.  */
+void
+shadow_warning (msgid, name, decl)
+     const char *msgid;
+     tree name, decl;
+{
+  warning ("declaration of `%s' shadows %s", IDENTIFIER_POINTER (name), msgid);
+  warning_with_file_and_line (DECL_SOURCE_FILE (decl),
+                             DECL_SOURCE_LINE (decl),
+                             "shadowed declaration is here");
+}
 
-  /* FUNC may have modified the tree, recheck that we're looking at a
-     statement node.  */
-  code = TREE_CODE (*tp);
-  if (!statement_code_p (code))
-    return NULL_TREE;
+/* Attribute handlers common to C front ends.  */
 
-  /* Walk over all the sub-trees of this operand.  Statement nodes never
-     contain RTL, and we needn't worry about TARGET_EXPRs.  */
-  len = TREE_CODE_LENGTH (code);
+/* Handle a "packed" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-  /* Go through the subtrees.  We need to do this in forward order so
-     that the scope of a FOR_EXPR is handled properly.  */
-  for (i = 0; i < len; ++i)
-    WALK_SUBTREE (TREE_OPERAND (*tp, i));
+static tree
+handle_packed_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree *type = NULL;
+  if (DECL_P (*node))
+    {
+      if (TREE_CODE (*node) == TYPE_DECL)
+       type = &TREE_TYPE (*node);
+    }
+  else
+    type = node;
 
-  /* Finally visit the chain.  This can be tail-recursion optimized if
-     we write it this way.  */
-  return walk_stmt_tree (&TREE_CHAIN (*tp), func, data);
+  if (type)
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
+      TYPE_PACKED (*type) = 1;
+    }
+  else if (TREE_CODE (*node) == FIELD_DECL)
+    DECL_PACKED (*node) = 1;
+  /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
+     used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-#undef WALK_SUBTREE
+  return NULL_TREE;
 }
 
-/* Used to compare case labels.  K1 and K2 are actually tree nodes
-   representing case labels, or NULL_TREE for a `default' label.
-   Returns -1 if K1 is ordered before K2, -1 if K1 is ordered after
-   K2, and 0 if K1 and K2 are equal.  */
+/* Handle a "nocommon" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-int
-case_compare (k1, k2)
-     splay_tree_key k1;
-     splay_tree_key k2;
+static tree
+handle_nocommon_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  /* Consider a NULL key (such as arises with a `default' label) to be
-     smaller than anything else.  */
-  if (!k1)
-    return k2 ? -1 : 0;
-  else if (!k2)
-    return k1 ? 1 : 0;
+  if (TREE_CODE (*node) == VAR_DECL)
+    DECL_COMMON (*node) = 0;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-  return tree_int_cst_compare ((tree) k1, (tree) k2);
+  return NULL_TREE;
 }
 
-/* Process a case label for the range LOW_VALUE ... HIGH_VALUE.  If
-   LOW_VALUE and HIGH_VALUE are both NULL_TREE then this case label is
-   actually a `default' label.  If only HIGH_VALUE is NULL_TREE, then
-   case label was declared using the usual C/C++ syntax, rather than
-   the GNU case range extension.  CASES is a tree containing all the
-   case ranges processed so far; COND is the condition for the
-   switch-statement itself.  Returns the CASE_LABEL created, or
-   ERROR_MARK_NODE if no CASE_LABEL is created.  */
+/* Handle a "common" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-tree
-c_add_case_label (cases, cond, low_value, high_value)
-     splay_tree cases;
-     tree cond;
-     tree low_value;
-     tree high_value;
+static tree
+handle_common_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  tree type;
-  tree label;
-  tree case_label;
-  splay_tree_node node;
+  if (TREE_CODE (*node) == VAR_DECL)
+    DECL_COMMON (*node) = 1;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-  /* Create the LABEL_DECL itself.  */
-  label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
-  DECL_CONTEXT (label) = current_function_decl;
+  return NULL_TREE;
+}
 
-  /* If there was an error processing the switch condition, bail now
-     before we get more confused.  */
-  if (!cond || cond == error_mark_node)
+/* Handle a "noreturn" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noreturn_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_THIS_VOLATILE (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type
+       (build_type_variant (TREE_TYPE (type),
+                            TREE_READONLY (TREE_TYPE (type)), 1));
+  else
     {
-      /* Add a label anyhow so that the back-end doesn't think that
-        the beginning of the switch is unreachable.  */
-      if (!cases->root)
-       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
-      return error_mark_node;
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
 
-  if ((low_value && TREE_TYPE (low_value) 
-       && POINTER_TYPE_P (TREE_TYPE (low_value))) 
-      || (high_value && TREE_TYPE (high_value)
-         && POINTER_TYPE_P (TREE_TYPE (high_value))))
-    error ("pointers are not permitted as case values");
+  return NULL_TREE;
+}
 
-  /* Case ranges are a GNU extension.  */
-  if (high_value && pedantic)
+/* Handle a "noinline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noinline_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_UNINLINABLE (*node) = 1;
+  else
     {
-      if (c_language == clk_cplusplus)
-       pedwarn ("ISO C++ forbids range expressions in switch statements");
-      else
-       pedwarn ("ISO C forbids range expressions in switch statements");
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
 
-  type = TREE_TYPE (cond);
-  if (low_value)
+  return NULL_TREE;
+}
+
+/* Handle a "always_inline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_always_inline_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
     {
-      low_value = check_case_value (low_value);
-      low_value = convert_and_check (type, low_value);
+      /* Do nothing else, just set the attribute.  We'll get at
+        it later with lookup_attribute.  */
     }
-  if (high_value)
+  else
     {
-      high_value = check_case_value (high_value);
-      high_value = convert_and_check (type, high_value);
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
 
-  /* If an error has occurred, bail out now.  */
-  if (low_value == error_mark_node || high_value == error_mark_node)
-    {
-      if (!cases->root)
-       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
-      return error_mark_node;
-    }
+  return NULL_TREE;
+}
 
-  /* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
-     really a case range, even though it was written that way.  Remove
-     the HIGH_VALUE to simplify later processing.  */
-  if (tree_int_cst_equal (low_value, high_value))
-    high_value = NULL_TREE;
-  if (low_value && high_value 
-      && !tree_int_cst_lt (low_value, high_value)) 
-    warning ("empty range specified");
+/* Handle a "used" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-  /* Look up the LOW_VALUE in the table of case labels we already
-     have.  */
-  node = splay_tree_lookup (cases, (splay_tree_key) low_value);
-  /* If there was not an exact match, check for overlapping ranges.
-     There's no need to do this if there's no LOW_VALUE or HIGH_VALUE;
-     that's a `default' label and the only overlap is an exact match.  */
-  if (!node && (low_value || high_value))
+static tree
+handle_used_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*node))
+      = TREE_USED (*node) = 1;
+  else
     {
-      splay_tree_node low_bound;
-      splay_tree_node high_bound;
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-      /* Even though there wasn't an exact match, there might be an
-        overlap between this case range and another case range.
-        Since we've (inductively) not allowed any overlapping case
-        ranges, we simply need to find the greatest low case label
-        that is smaller that LOW_VALUE, and the smallest low case
-        label that is greater than LOW_VALUE.  If there is an overlap
-        it will occur in one of these two ranges.  */
-      low_bound = splay_tree_predecessor (cases,
-                                         (splay_tree_key) low_value);
-      high_bound = splay_tree_successor (cases,
-                                        (splay_tree_key) low_value);
+  return NULL_TREE;
+}
 
-      /* Check to see if the LOW_BOUND overlaps.  It is smaller than
-        the LOW_VALUE, so there is no need to check unless the
-        LOW_BOUND is in fact itself a case range.  */
-      if (low_bound
-         && CASE_HIGH ((tree) low_bound->value)
-         && tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value),
-                                   low_value) >= 0)
-       node = low_bound;
-      /* Check to see if the HIGH_BOUND overlaps.  The low end of that
-        range is bigger than the low end of the current range, so we
-        are only interested if the current range is a real range, and
-        not an ordinary case label.  */
-      else if (high_bound 
-              && high_value
-              && (tree_int_cst_compare ((tree) high_bound->key,
-                                        high_value)
-                  <= 0))
-       node = high_bound;
-    }
-  /* If there was an overlap, issue an error.  */
-  if (node)
-    {
-      tree duplicate = CASE_LABEL_DECL ((tree) node->value);
+/* Handle a "unused" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-      if (high_value)
-       {
-         error ("duplicate (or overlapping) case value");
-         error_with_decl (duplicate, 
-                          "this is the first entry overlapping that value");
-       }
-      else if (low_value)
-       {
-         error ("duplicate case value") ;
-         error_with_decl (duplicate, "previously used here");
-       }
+static tree
+handle_unused_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  if (DECL_P (*node))
+    {
+      tree decl = *node;
+
+      if (TREE_CODE (decl) == PARM_DECL
+         || TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == FUNCTION_DECL
+         || TREE_CODE (decl) == LABEL_DECL
+         || TREE_CODE (decl) == TYPE_DECL)
+       TREE_USED (decl) = 1;
       else
        {
-         error ("multiple default labels in one switch");
-         error_with_decl (duplicate, "this is the first default label");
+         warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         *no_add_attrs = true;
        }
-      if (!cases->root)
-       add_stmt (build_case_label (NULL_TREE, NULL_TREE, label));
+    }
+  else
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *node = build_type_copy (*node);
+      TREE_USED (*node) = 1;
     }
 
-  /* Add a CASE_LABEL to the statement-tree.  */
-  case_label = add_stmt (build_case_label (low_value, high_value, label));
-  /* Register this case label in the splay tree.  */
-  splay_tree_insert (cases, 
-                    (splay_tree_key) low_value,
-                    (splay_tree_value) case_label);
+  return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_const_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment on noreturn in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_READONLY (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+          && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type
+       (build_type_variant (TREE_TYPE (type), 1,
+                            TREE_THIS_VOLATILE (TREE_TYPE (type))));
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "transparent_union" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_transparent_union_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree decl = NULL_TREE;
+  tree *type = NULL;
+  int is_type = 0;
+
+  if (DECL_P (*node))
+    {
+      decl = *node;
+      type = &TREE_TYPE (decl);
+      is_type = TREE_CODE (*node) == TYPE_DECL;
+    }
+  else if (TYPE_P (*node))
+    type = node, is_type = 1;
+
+  if (is_type
+      && TREE_CODE (*type) == UNION_TYPE
+      && (decl == 0
+         || (TYPE_FIELDS (*type) != 0
+             && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))))
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
+      TYPE_TRANSPARENT_UNION (*type) = 1;
+    }
+  else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
+          && TREE_CODE (*type) == UNION_TYPE
+          && TYPE_MODE (*type) == DECL_MODE (TYPE_FIELDS (*type)))
+    DECL_TRANSPARENT_UNION (decl) = 1;
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-  return case_label;
+  return NULL_TREE;
 }
 
-/* Mark P (a stmt_tree) for GC.  The use of a `void *' for the
-   parameter allows this function to be used as a GC-marking
-   function.  */
+/* Handle a "constructor" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-void
-mark_stmt_tree (p)
-     void *p;
+static tree
+handle_constructor_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  stmt_tree st = (stmt_tree) p;
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
 
-  ggc_mark_tree (st->x_last_stmt);
-  ggc_mark_tree (st->x_last_expr_type);
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TREE_CODE (type) == FUNCTION_TYPE
+      && decl_function_context (decl) == 0)
+    {
+      DECL_STATIC_CONSTRUCTOR (decl) = 1;
+      TREE_USED (decl) = 1;
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
 }
 
-/* Mark LD for GC.  */
+/* Handle a "destructor" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-void
-c_mark_lang_decl (c)
-     struct c_lang_decl *c;
+static tree
+handle_destructor_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  ggc_mark_tree (c->saved_tree);
+  tree decl = *node;
+  tree type = TREE_TYPE (decl);
+
+  if (TREE_CODE (decl) == FUNCTION_DECL
+      && TREE_CODE (type) == FUNCTION_TYPE
+      && decl_function_context (decl) == 0)
+    {
+      DECL_STATIC_DESTRUCTOR (decl) = 1;
+      TREE_USED (decl) = 1;
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
 }
 
-/* Mark F for GC.  */
+/* Handle a "mode" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-void
-mark_c_language_function (f)
-     struct language_function *f;
+static tree
+handle_mode_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  if (!f)
-    return;
+  tree type = *node;
 
-  mark_stmt_tree (&f->x_stmt_tree);
-  ggc_mark_tree (f->x_scope_stmt_stack);
+  *no_add_attrs = true;
+
+  if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
+    warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+  else
+    {
+      int j;
+      const char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+      int len = strlen (p);
+      enum machine_mode mode = VOIDmode;
+      tree typefm;
+
+      if (len > 4 && p[0] == '_' && p[1] == '_'
+         && p[len - 1] == '_' && p[len - 2] == '_')
+       {
+         char *newp = (char *) alloca (len - 1);
+
+         strcpy (newp, &p[2]);
+         newp[len - 4] = '\0';
+         p = newp;
+       }
+
+      /* Change this type to have a type with the specified mode.
+        First check for the special modes.  */
+      if (! strcmp (p, "byte"))
+       mode = byte_mode;
+      else if (!strcmp (p, "word"))
+       mode = word_mode;
+      else if (! strcmp (p, "pointer"))
+       mode = ptr_mode;
+      else
+       for (j = 0; j < NUM_MACHINE_MODES; j++)
+         if (!strcmp (p, GET_MODE_NAME (j)))
+           mode = (enum machine_mode) j;
+
+      if (mode == VOIDmode)
+       error ("unknown machine mode `%s'", p);
+      else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
+                    (mode, TREE_UNSIGNED (type))))
+       error ("no data type for mode `%s'", p);
+      else
+       *node = typefm;
+        /* No need to layout the type here.  The caller should do this.  */
+    }
+
+  return NULL_TREE;
 }
 
-/* Hook used by expand_expr to expand language-specific tree codes.  */
+/* Handle a "section" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-rtx
-c_expand_expr (exp, target, tmode, modifier)
-     tree exp;
-     rtx target;
-     enum machine_mode tmode;
-     enum expand_modifier modifier;
+static tree
+handle_section_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  switch (TREE_CODE (exp))
-    {
-    case STMT_EXPR:
-      {
-       tree rtl_expr;
-       rtx result;
+  tree decl = *node;
 
-       /* Since expand_expr_stmt calls free_temp_slots after every
-          expression statement, we must call push_temp_slots here.
-          Otherwise, any temporaries in use now would be considered
-          out-of-scope after the first EXPR_STMT from within the
-          STMT_EXPR.  */
-       push_temp_slots ();
-       rtl_expr = expand_start_stmt_expr ();
-       expand_stmt (STMT_EXPR_STMT (exp));
-       expand_end_stmt_expr (rtl_expr);
-       result = expand_expr (rtl_expr, target, tmode, modifier);
-       pop_temp_slots ();
-       return result;
-      }
-      break;
-      
-    case CALL_EXPR:
-      {
-       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
-           && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-               == FUNCTION_DECL)
-           && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-           && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
-               == BUILT_IN_FRONTEND))
-         return c_expand_builtin (exp, target, tmode, modifier);
-       else
-         abort();
-      }
-      break;
+  if (targetm.have_named_sections)
+    {
+      if ((TREE_CODE (decl) == FUNCTION_DECL
+          || TREE_CODE (decl) == VAR_DECL)
+         && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+       {
+         if (TREE_CODE (decl) == VAR_DECL
+             && current_function_decl != NULL_TREE
+             && ! TREE_STATIC (decl))
+           {
+             error_with_decl (decl,
+                              "section attribute cannot be specified for local variables");
+             *no_add_attrs = true;
+           }
 
-    default:
-      abort ();
+         /* The decl may have already been given a section attribute
+            from a previous declaration.  Ensure they match.  */
+         else if (DECL_SECTION_NAME (decl) != NULL_TREE
+                  && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                             TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+           {
+             error_with_decl (*node,
+                              "section of `%s' conflicts with previous declaration");
+             *no_add_attrs = true;
+           }
+         else
+           DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+       }
+      else
+       {
+         error_with_decl (*node,
+                          "section attribute not allowed for `%s'");
+         *no_add_attrs = true;
+       }
+    }
+  else
+    {
+      error_with_decl (*node,
+                      "section attributes are not supported for this target");
+      *no_add_attrs = true;
     }
 
-  abort ();
-  return NULL;
+  return NULL_TREE;
 }
 
-/* Hook used by safe_from_p to handle language-specific tree codes.  */
+/* Handle a "aligned" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-int
-c_safe_from_p (target, exp)
-     rtx target;
-     tree exp;
+static tree
+handle_aligned_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args;
+     int flags;
+     bool *no_add_attrs;
 {
-  /* We can see statements here when processing the body of a
-     statement-expression.  For a declaration statement declaring a
-     variable, look at the variable's initializer.  */
-  if (TREE_CODE (exp) == DECL_STMT) 
+  tree decl = NULL_TREE;
+  tree *type = NULL;
+  int is_type = 0;
+  tree align_expr = (args ? TREE_VALUE (args)
+                    : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+  int i;
+
+  if (DECL_P (*node))
     {
-      tree decl = DECL_STMT_DECL (exp);
+      decl = *node;
+      type = &TREE_TYPE (decl);
+      is_type = TREE_CODE (*node) == TYPE_DECL;
+    }
+  else if (TYPE_P (*node))
+    type = node, is_type = 1;
 
-      if (TREE_CODE (decl) == VAR_DECL
-         && DECL_INITIAL (decl)
-         && !safe_from_p (target, DECL_INITIAL (decl), /*top_p=*/0))
-       return 0;
+  /* Strip any NOPs of any kind.  */
+  while (TREE_CODE (align_expr) == NOP_EXPR
+        || TREE_CODE (align_expr) == CONVERT_EXPR
+        || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
+    align_expr = TREE_OPERAND (align_expr, 0);
+
+  if (TREE_CODE (align_expr) != INTEGER_CST)
+    {
+      error ("requested alignment is not a constant");
+      *no_add_attrs = true;
     }
+  else if ((i = tree_log2 (align_expr)) == -1)
+    {
+      error ("requested alignment is not a power of 2");
+      *no_add_attrs = true;
+    }
+  else if (i > HOST_BITS_PER_INT - 2)
+    {
+      error ("requested alignment is too large");
+      *no_add_attrs = true;
+    }
+  else if (is_type)
+    {
+      /* If we have a TYPE_DECL, then copy the type, so that we
+        don't accidentally modify a builtin type.  See pushdecl.  */
+      if (decl && TREE_TYPE (decl) != error_mark_node
+         && DECL_ORIGINAL_TYPE (decl) == NULL_TREE)
+       {
+         tree tt = TREE_TYPE (decl);
+         *type = build_type_copy (*type);
+         DECL_ORIGINAL_TYPE (decl) = tt;
+         TYPE_NAME (*type) = decl;
+         TREE_USED (*type) = TREE_USED (decl);
+         TREE_TYPE (decl) = *type;
+       }
+      else if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *type = build_type_copy (*type);
 
-  /* For any statement, we must follow the statement-chain.  */
-  if (statement_code_p (TREE_CODE (exp)) && TREE_CHAIN (exp))
-    return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0);
+      TYPE_ALIGN (*type) = (1 << i) * BITS_PER_UNIT;
+      TYPE_USER_ALIGN (*type) = 1;
+    }
+  else if (TREE_CODE (decl) != VAR_DECL
+          && TREE_CODE (decl) != FIELD_DECL)
+    {
+      error_with_decl (decl,
+                      "alignment may not be specified for `%s'");
+      *no_add_attrs = true;
+    }
+  else
+    {
+      DECL_ALIGN (decl) = (1 << i) * BITS_PER_UNIT;
+      DECL_USER_ALIGN (decl) = 1;
+    }
 
-  /* Assume everything else is safe.  */
-  return 1;
+  return NULL_TREE;
 }
 
-/* Hook used by unsafe_for_reeval to handle language-specific tree codes.  */
+/* Handle a "weak" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-int
-c_unsafe_for_reeval (exp)
-     tree exp;
+static tree
+handle_weak_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs ATTRIBUTE_UNUSED;
 {
-  /* Statement expressions may not be reevaluated.  */
-  if (TREE_CODE (exp) == STMT_EXPR)
-    return 2;
+  declare_weak (*node);
 
-  /* Walk all other expressions.  */
-  return -1;
+  return NULL_TREE;
 }
 
-/* Tree code classes. */
+/* Handle an "alias" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
+static tree
+handle_alias_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
 
-static char c_tree_code_type[] = {
-  'x',
-#include "c-common.def"
-};
-#undef DEFTREECODE
+  if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+      || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
+    {
+      error_with_decl (decl,
+                      "`%s' defined both normally and as an alias");
+      *no_add_attrs = true;
+    }
+  else if (decl_function_context (decl) == 0)
+    {
+      tree id;
 
-/* Table indexed by tree code giving number of expression
-   operands beyond the fixed part of the node structure.
-   Not used for types or decls.  */
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+       {
+         error ("alias arg not a string");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      id = get_identifier (TREE_STRING_POINTER (id));
+      /* This counts as a use of the object pointed to.  */
+      TREE_USED (id) = 1;
 
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+       DECL_INITIAL (decl) = error_mark_node;
+      else
+       DECL_EXTERNAL (decl) = 0;
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-static int c_tree_code_length[] = {
-  0,
-#include "c-common.def"
-};
-#undef DEFTREECODE
+  return NULL_TREE;
+}
 
-/* Names of tree components.
-   Used for printing out the tree and error messages.  */
-#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
+/* Handle an "visibility" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-static const char *c_tree_code_name[] = {
-  "@@dummy",
-#include "c-common.def"
-};
-#undef DEFTREECODE
+static tree
+handle_visibility_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
 
-/* Adds the tree codes specific to the C front end to the list of all
-   tree codes. */
+  if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    {
+      tree id;
 
-void
-add_c_tree_codes ()
-{
-  memcpy (tree_code_type + (int) LAST_AND_UNUSED_TREE_CODE,
-         c_tree_code_type,
-         (int)LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE);
-  memcpy (tree_code_length + (int) LAST_AND_UNUSED_TREE_CODE,
-         c_tree_code_length,
-         (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (int));
-  memcpy (tree_code_name + (int) LAST_AND_UNUSED_TREE_CODE,
-         c_tree_code_name,
-         (LAST_C_TREE_CODE - (int)LAST_AND_UNUSED_TREE_CODE) * sizeof (char *));
-  lang_unsafe_for_reeval = c_unsafe_for_reeval;
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+       {
+         error ("visibility arg not a string");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      if (strcmp (TREE_STRING_POINTER (id), "hidden")
+         && strcmp (TREE_STRING_POINTER (id), "protected")
+         && strcmp (TREE_STRING_POINTER (id), "internal"))
+       {
+         error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\"");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+    }
+
+  return NULL_TREE;
 }
 
-#define CALLED_AS_BUILT_IN(NODE) \
-   (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
+/* Handle a "no_instrument_function" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-static rtx
-c_expand_builtin (exp, target, tmode, modifier)
-     tree exp;
-     rtx target;
-     enum machine_mode tmode;
-     enum expand_modifier modifier;
+static tree
+handle_no_instrument_function_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  tree type = TREE_TYPE (exp);
-  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
-  tree arglist = TREE_OPERAND (exp, 1);
-  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
-  enum tree_code code = TREE_CODE (exp);
-  const int ignore = (target == const0_rtx
-                     || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
-                          || code == CONVERT_EXPR || code == REFERENCE_EXPR
-                          || code == COND_EXPR)
-                         && TREE_CODE (type) == VOID_TYPE));
-
-  if (! optimize && ! CALLED_AS_BUILT_IN (fndecl))
-    return expand_call (exp, target, ignore);
+  tree decl = *node;
 
-  switch (fcode)
+  if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-    case BUILT_IN_PRINTF:
-      target = c_expand_builtin_printf (arglist, target, tmode,
-                                       modifier, ignore);
-      if (target)
-       return target;
-      break;
+      error_with_decl (decl,
+                      "`%s' attribute applies only to functions",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_with_decl (decl,
+                      "can't set `%s' attribute after definition",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
 
-    case BUILT_IN_FPRINTF:
-      target = c_expand_builtin_fprintf (arglist, target, tmode,
-                                        modifier, ignore);
-      if (target)
-       return target;
-      break;
+  return NULL_TREE;
+}
 
-    default:                   /* just do library call, if unknown builtin */
-      error ("built-in function `%s' not currently supported",
-            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+/* Handle a "malloc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_malloc_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_IS_MALLOC (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
     }
 
-  /* The switch statement above can drop through to cause the function
-     to be called normally.  */
-  return expand_call (exp, target, ignore);
+  return NULL_TREE;
 }
 
-/* Check an arglist to *printf for problems.  The arglist should start
-   at the format specifier, with the remaining arguments immediately
-   following it. */
-static int
-is_valid_printf_arglist (arglist)
-  tree arglist;
-{
-  /* Save this value so we can restore it later. */
-  const int SAVE_pedantic = pedantic;
-  int diagnostic_occurred = 0;
+/* Handle a "no_limit_stack" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-  /* Set this to a known value so the user setting won't affect code
-     generation.  */
-  pedantic = 1;
-  /* Check to make sure there are no format specifier errors. */
-  check_function_format (&diagnostic_occurred,
-                        maybe_get_identifier("printf"),
-                        NULL_TREE, arglist);
+static tree
+handle_no_limit_stack_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
 
-  /* Restore the value of `pedantic'. */
-  pedantic = SAVE_pedantic;
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    {
+      error_with_decl (decl,
+                      "`%s' attribute applies only to functions",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else if (DECL_INITIAL (decl))
+    {
+      error_with_decl (decl,
+                      "can't set `%s' attribute after definition",
+                      IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    DECL_NO_LIMIT_STACK (decl) = 1;
 
-  /* If calling `check_function_format_ptr' produces a warning, we
-     return false, otherwise we return true. */
-  return ! diagnostic_occurred;
+  return NULL_TREE;
 }
 
-/* If the arguments passed to printf are suitable for optimizations,
-   we attempt to transform the call. */
-static rtx
-c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
-     tree arglist;
-     rtx target;
-     enum machine_mode tmode;
-     enum expand_modifier modifier;
-     int ignore;
-{
-  tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
-    fn_puts = built_in_decls[BUILT_IN_PUTS];
-  tree fn, format_arg, stripped_string;
+/* Handle a "pure" attribute; arguments as in
+   struct attribute_spec.handler.  */
 
-  /* If the return value is used, or the replacement _DECL isn't
-     initialized, don't do the transformation. */
-  if (!ignore || !fn_putchar || !fn_puts)
-    return 0;
+static tree
+handle_pure_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_IS_PURE (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
 
-  /* Verify the required arguments in the original call. */
-  if (arglist == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
-    return 0;
-  
-  /* Check the specifier vs. the parameters. */
-  if (!is_valid_printf_arglist (arglist))
-    return 0;
-  
-  format_arg = TREE_VALUE (arglist);
-  stripped_string = format_arg;
-  STRIP_NOPS (stripped_string);
-  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
-    stripped_string = TREE_OPERAND (stripped_string, 0);
+  return NULL_TREE;
+}
 
-  /* If the format specifier isn't a STRING_CST, punt.  */
-  if (TREE_CODE (stripped_string) != STRING_CST)
-    return 0;
+/* Handle a "deprecated" attribute; arguments as in
+   struct attribute_spec.handler.  */
+   
+static tree
+handle_deprecated_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree type = NULL_TREE;
+  int warn = 0;
+  const char *what = NULL;
   
-  /* OK!  We can attempt optimization.  */
-
-  /* If the format specifier was "%s\n", call __builtin_puts(arg2). */
-  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
+  if (DECL_P (*node))
     {
-      arglist = TREE_CHAIN (arglist);
-      fn = fn_puts;
+      tree decl = *node;
+      type = TREE_TYPE (decl);
+      
+      if (TREE_CODE (decl) == TYPE_DECL
+         || TREE_CODE (decl) == PARM_DECL
+         || TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == FUNCTION_DECL
+         || TREE_CODE (decl) == FIELD_DECL)
+       TREE_DEPRECATED (decl) = 1;
+      else
+       warn = 1;
     }
-  /* If the format specifier was "%c", call __builtin_putchar (arg2). */
-  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+  else if (TYPE_P (*node))
     {
-      arglist = TREE_CHAIN (arglist);
-      fn = fn_putchar;
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *node = build_type_copy (*node);
+      TREE_DEPRECATED (*node) = 1;
+      type = *node;
     }
   else
+    warn = 1;
+  
+  if (warn)
     {
-     /* We can't handle anything else with % args or %% ... yet. */
-      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
-       return 0;
-      
-      /* If the resulting constant string has a length of 1, call
-         putchar.  Note, TREE_STRING_LENGTH includes the terminating
-         NULL in its count.  */
-      if (TREE_STRING_LENGTH (stripped_string) == 2)
-        {
-         /* Given printf("c"), (where c is any one character,)
-             convert "c"[0] to an int and pass that to the replacement
-             function. */
-         arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
-         arglist = build_tree_list (NULL_TREE, arglist);
-         
-         fn = fn_putchar;
-        }
-      /* If the resulting constant was "string\n", call
-         __builtin_puts("string").  Ensure "string" has at least one
-         character besides the trailing \n.  Note, TREE_STRING_LENGTH
-         includes the terminating NULL in its count.  */
-      else if (TREE_STRING_LENGTH (stripped_string) > 2
-              && TREE_STRING_POINTER (stripped_string)
-              [TREE_STRING_LENGTH (stripped_string) - 2] == '\n')
-        {
-         /* Create a NULL-terminated string that's one char shorter
-            than the original, stripping off the trailing '\n'.  */
-         const int newlen = TREE_STRING_LENGTH (stripped_string) - 1;
-         char *newstr = (char *) alloca (newlen);
-         memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
-         newstr[newlen - 1] = 0;
-         
-         arglist = combine_strings (build_string (newlen, newstr));
-         arglist = build_tree_list (NULL_TREE, arglist);
-         fn = fn_puts;
+      *no_add_attrs = true;
+      if (type && TYPE_NAME (type))
+       {
+         if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+           what = IDENTIFIER_POINTER (TYPE_NAME (*node));
+         else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+                  && DECL_NAME (TYPE_NAME (type)))
+           what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
        }
+      if (what)
+       warning ("`%s' attribute ignored for `%s'",
+                 IDENTIFIER_POINTER (name), what);
       else
-       /* We'd like to arrange to call fputs(string) here, but we
-           need stdout and don't have a way to get it ... yet.  */
-       return 0;
+       warning ("`%s' attribute ignored", 
+                     IDENTIFIER_POINTER (name));
     }
-  
-  return expand_expr (build_function_call (fn, arglist),
-                     (ignore ? const0_rtx : target),
-                     tmode, modifier);
+
+  return NULL_TREE;
 }
 
-/* If the arguments passed to fprintf are suitable for optimizations,
-   we attempt to transform the call. */
-static rtx
-c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore)
-     tree arglist;
-     rtx target;
-     enum machine_mode tmode;
-     enum expand_modifier modifier;
-     int ignore;
+/* Keep a list of vector type nodes we created in handle_vector_size_attribute,
+   to prevent us from duplicating type nodes unnecessarily.
+   The normal mechanism to prevent duplicates is to use type_hash_canon, but
+   since we want to distinguish types that are essentially identical (except
+   for their debug representation), we use a local list here.  */
+static tree vector_type_node_list = 0;
+
+/* Handle a "vector_size" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
 {
-  tree fn_fputc = built_in_decls[BUILT_IN_FPUTC],
-    fn_fputs = built_in_decls[BUILT_IN_FPUTS];
-  tree fn, format_arg, stripped_string;
+  unsigned HOST_WIDE_INT vecsize, nunits;
+  enum machine_mode mode, orig_mode, new_mode;
+  tree type = *node, new_type = NULL_TREE;
+  tree type_list_node;
 
-  /* If the return value is used, or the replacement _DECL isn't
-     initialized, don't do the transformation. */
-  if (!ignore || !fn_fputc || !fn_fputs)
-    return 0;
+  *no_add_attrs = true;
 
-  /* Verify the required arguments in the original call. */
-  if (arglist == 0
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
-      || (TREE_CHAIN (arglist) == 0)
-      || (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) !=
-         POINTER_TYPE))
-    return 0;
-  
-  /* Check the specifier vs. the parameters. */
-  if (!is_valid_printf_arglist (TREE_CHAIN (arglist)))
-    return 0;
-  
-  format_arg = TREE_VALUE (TREE_CHAIN (arglist));
-  stripped_string = format_arg;
-  STRIP_NOPS (stripped_string);
-  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
-    stripped_string = TREE_OPERAND (stripped_string, 0);
+  if (! host_integerp (TREE_VALUE (args), 1))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      return NULL_TREE;
+    }
 
-  /* If the format specifier isn't a STRING_CST, punt.  */
-  if (TREE_CODE (stripped_string) != STRING_CST)
-    return 0;
-  
-  /* OK!  We can attempt optimization.  */
+  /* Get the vector size (in bytes).  */
+  vecsize = tree_low_cst (TREE_VALUE (args), 1);
 
-  /* If the format specifier was "%s", call __builtin_fputs(arg3, arg1). */
-  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s") == 0)
+  /* We need to provide for vector pointers, vector arrays, and
+     functions returning vectors.  For example:
+
+       __attribute__((vector_size(16))) short *foo;
+
+     In this case, the mode is SI, but the type being modified is
+     HI, so we need to look further.  */
+
+  while (POINTER_TYPE_P (type)
+        || TREE_CODE (type) == FUNCTION_TYPE
+        || TREE_CODE (type) == ARRAY_TYPE)
+    type = TREE_TYPE (type);
+
+  /* Get the mode of the type being modified.  */
+  orig_mode = TYPE_MODE (type);
+
+  if (TREE_CODE (type) == RECORD_TYPE
+      || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
+         && GET_MODE_CLASS (orig_mode) != MODE_INT)
+      || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
     {
-      tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
-      arglist = tree_cons (NULL_TREE,
-                          TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
-                          newarglist);
-      fn = fn_fputs;
+      error ("invalid vector type for attribute `%s'",
+            IDENTIFIER_POINTER (name));
+      return NULL_TREE;
     }
-  /* If the format specifier was "%c", call __builtin_fputc (arg3, arg1). */
-  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+
+  /* Calculate how many units fit in the vector.  */
+  nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
+
+  /* Find a suitably sized vector.  */
+  new_mode = VOIDmode;
+  for (mode = GET_CLASS_NARROWEST_MODE (GET_MODE_CLASS (orig_mode) == MODE_INT
+                                       ? MODE_VECTOR_INT
+                                       : MODE_VECTOR_FLOAT);
+       mode != VOIDmode;
+       mode = GET_MODE_WIDER_MODE (mode))
+    if (vecsize == GET_MODE_SIZE (mode)
+       && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
+      {
+       new_mode = mode;
+       break;
+      }
+
+    if (new_mode == VOIDmode)
     {
-      tree newarglist = build_tree_list (NULL_TREE, TREE_VALUE (arglist));
-      arglist = tree_cons (NULL_TREE,
-                          TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))),
-                          newarglist);
-      fn = fn_fputc;
+      error ("no vector mode with the size and type specified could be found");
+      return NULL_TREE;
     }
-  else
+
+  for (type_list_node = vector_type_node_list; type_list_node;
+       type_list_node = TREE_CHAIN (type_list_node))
     {
-     /* We can't handle anything else with % args or %% ... yet. */
-      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
-       return 0;
-      
-      /* When "string" doesn't contain %, replace all cases of
-         fprintf(stream,string) with fputs(string,stream).  The fputs
-         builtin will take take of special cases like length==1.  */
-      arglist = tree_cons (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)),
-                          build_tree_list (NULL_TREE, TREE_VALUE (arglist)));
-      fn = fn_fputs;
+      tree other_type = TREE_VALUE (type_list_node);
+      tree record = TYPE_DEBUG_REPRESENTATION_TYPE (other_type);
+      tree fields = TYPE_FIELDS (record);
+      tree field_type = TREE_TYPE (fields);
+      tree array_type = TREE_TYPE (field_type);
+      if (TREE_CODE (fields) != FIELD_DECL
+         || TREE_CODE (field_type) != ARRAY_TYPE)
+       abort ();
+
+      if (TYPE_MODE (other_type) == mode && type == array_type)
+       {
+         new_type = other_type;
+         break;
+       }
     }
-  
-  return expand_expr (build_function_call (fn, arglist),
-                     (ignore ? const0_rtx : target),
-                     tmode, modifier);
-}
-\f
 
-/* Given a boolean expression ARG, return a tree representing an increment
-   or decrement (as indicated by CODE) of ARG.  The front end must check for
-   invalid cases (e.g., decrement in C++).  */
-tree
-boolean_increment (code, arg)
-     enum tree_code code;
-     tree arg;
-{
-  tree val;
-  tree true_res = (c_language == clk_cplusplus
-                  ? boolean_true_node
-                  : c_bool_true_node);
-  arg = stabilize_reference (arg);
-  switch (code)
+  if (new_type == NULL_TREE)
     {
-    case PREINCREMENT_EXPR:
-      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
-      break;
-    case POSTINCREMENT_EXPR:
-      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
-      arg = save_expr (arg);
-      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
-      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
-      break;
-    case PREDECREMENT_EXPR:
-      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
-      break;
-    case POSTDECREMENT_EXPR:
-      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
-      arg = save_expr (arg);
-      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
-      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
-      break;
-    default:
-      abort ();
+      tree index, array, rt, list_node;
+
+      new_type = (*lang_hooks.types.type_for_mode) (new_mode,
+                                                   TREE_UNSIGNED (type));
+
+      if (!new_type)
+       {
+         error ("no vector mode with the size and type specified could be found");
+         return NULL_TREE;
+       }
+
+      new_type = build_type_copy (new_type);
+
+      /* Set the debug information here, because this is the only
+        place where we know the underlying type for a vector made
+        with vector_size.  For debugging purposes we pretend a vector
+        is an array within a structure.  */
+      index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0);
+      array = build_array_type (type, build_index_type (index));
+      rt = make_node (RECORD_TYPE);
+
+      TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
+      DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
+      layout_type (rt);
+      TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt;
+
+      list_node = build_tree_list (NULL, new_type);
+      TREE_CHAIN (list_node) = vector_type_node_list;
+      vector_type_node_list = list_node;
     }
-  TREE_SIDE_EFFECTS (val) = 1;
-  return val;
+
+  /* Build back pointers if needed.  */
+  *node = vector_size_helper (*node, new_type);
+
+  return NULL_TREE;
 }
-\f
 
-/* Do the parts of lang_init common to C and C++.  */
-void
-c_common_lang_init ()
+/* HACK.  GROSS.  This is absolutely disgusting.  I wish there was a
+   better way.
+
+   If we requested a pointer to a vector, build up the pointers that
+   we stripped off while looking for the inner type.  Similarly for
+   return values from functions.
+
+   The argument "type" is the top of the chain, and "bottom" is the
+   new type which we will point to.  */
+
+static tree
+vector_size_helper (type, bottom)
+     tree type, bottom;
 {
-  /* If still "unspecified", make it match -fbounded-pointers.  */
-  if (flag_bounds_check < 0)
-    flag_bounds_check = flag_bounded_pointers;
+  tree inner, outer;
 
-  /* Special format checking options don't work without -Wformat; warn if
-     they are used.  */
-  if (warn_format_y2k && !warn_format)
-    warning ("-Wformat-y2k ignored without -Wformat");
-  if (warn_format_extra_args && !warn_format)
-    warning ("-Wformat-extra-args ignored without -Wformat");
-  if (warn_format_nonliteral && !warn_format)
-    warning ("-Wformat-nonliteral ignored without -Wformat");
-  if (warn_format_security && !warn_format)
-    warning ("-Wformat-security ignored without -Wformat");
-  if (warn_missing_format_attribute && !warn_format)
-    warning ("-Wmissing-format-attribute ignored without -Wformat");
+  if (POINTER_TYPE_P (type))
+    {
+      inner = vector_size_helper (TREE_TYPE (type), bottom);
+      outer = build_pointer_type (inner);
+    }
+  else if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      inner = vector_size_helper (TREE_TYPE (type), bottom);
+      outer = build_array_type (inner, TYPE_VALUES (type));
+    }
+  else if (TREE_CODE (type) == FUNCTION_TYPE)
+    {
+      inner = vector_size_helper (TREE_TYPE (type), bottom);
+      outer = build_function_type (inner, TYPE_VALUES (type));
+    }
+  else
+    return bottom;
+  
+  TREE_READONLY (outer) = TREE_READONLY (type);
+  TREE_THIS_VOLATILE (outer) = TREE_THIS_VOLATILE (type);
+
+  return outer;
 }