OSDN Git Service

* c-common.c (unsigned_conversion_warning, convert_and_check,
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 3e1c0df..04cd3c4 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
-   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,17 +30,33 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "expr.h"
 #include "c-common.h"
-#include "defaults.h"
-#include "tm_p.h"
-#include "intl.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
 #define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node)
 
+/* We let tm.h override the types used here, to handle trivial differences
+   such as the choice of unsigned int or long unsigned int for size_t.
+   When machines start needing nontrivial differences in the size type,
+   it would be best to do something here to figure out automatically
+   from other information what type to use.  */
+
+#ifndef SIZE_TYPE
+#define SIZE_TYPE "long unsigned int"
+#endif
+
+#ifndef WCHAR_TYPE
+#define WCHAR_TYPE "int"
+#endif
+
 #ifndef PTRDIFF_TYPE
 #define PTRDIFF_TYPE "long int"
 #endif
@@ -65,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.
 
@@ -141,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_name_decl_node;
+       tree pretty_function_name_decl_node;
+       tree c99_function_name_decl_node;
 
-       tree function_id_node;
-       tree pretty_function_id_node;
-       tree func_id_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;
@@ -172,40 +193,26 @@ int flag_no_builtin;
 
 int flag_no_nonansi_builtin;
 
-/* If non-NULL, dump the tree structure for the entire translation
-   unit to this file.  */
-
-const char *flag_dump_translation_unit;
-
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Nonzero means give `double' the same size as `float'.  */
 
-int warn_format;
+int flag_short_double;
 
-/* Warn about Y2K problems with strftime formats.  */
+/* Nonzero means give `wchar_t' the same size as `short'.  */
 
-int warn_format_y2k;
-
-/* Warn about excess arguments to formats.  */
-
-int warn_format_extra_args;
-
-/* Warn about non-literal format arguments.  */
-
-int warn_format_nonliteral;
-
-/* Warn about possible security problems with calls to format functions.  */
-
-int warn_format_security;
+int flag_short_wchar;
 
 /* 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.  */
@@ -215,30 +222,32 @@ 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? */
+};
 
-enum format_type { printf_format_type, scanf_format_type,
-                  strftime_format_type };
+/* 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 void record_function_format     PARAMS ((tree, tree, enum format_type,
-                                                int, int));
-static void record_international_format        PARAMS ((tree, tree, int));
-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
    statements seen up to the if keyword, as well as the line number
@@ -263,28 +272,32 @@ static int if_stack_space = 0;
 static int if_stack_pointer = 0;
 
 /* 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);
 
@@ -350,3090 +363,337 @@ c_finish_else ()
   RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
-/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__.  */
-
-void
-declare_function_name ()
-{
-  const char *name, *printable_name;
+/* Begin an if-statement.  Returns a newly created IF_STMT if
+   appropriate.
 
-  if (current_function_decl == NULL)
-    {
-      name = "";
-      printable_name = "top level";
-    }
-  else
-    {
-      /* 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);
+   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.  */
 
-      /* 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);
-    }
-  
-  (*make_fname_decl) (function_id_node, name, 0);
-  (*make_fname_decl) (pretty_function_id_node, printable_name, 1);
+tree
+c_begin_if_stmt ()
+{
+  tree r;
+  r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
+  return r;
 }
 
-/* Given a chain of STRING_CST nodes,
-   concatenate them into one STRING_CST
-   and give it a suitable array-of-chars data type.  */
+/* 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
-combine_strings (strings)
-     tree strings;
+c_begin_while_stmt ()
 {
-  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;
-
-  if (TREE_CHAIN (strings))
-    {
-      /* More than one in the chain, so concatenate.  */
-      register char *p, *q;
-
-      /* 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))
-       {
-         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 r;
+  r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
+  return r;
+}
 
-      /* 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;
+void
+c_finish_while_stmt_cond (cond, while_stmt)
+     tree while_stmt;
+     tree cond;
+{
+  WHILE_COND (while_stmt) = cond;
+}
 
-      p = alloca (length);
+/* Push current bindings for the function name VAR_DECLS.  */
 
-      /* 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.  */
+void
+start_fname_decls ()
+{
+  unsigned ix;
+  tree saved = NULL_TREE;
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    {
+      tree decl = *fname_vars[ix].decl;
 
-      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)
+      if (decl)
        {
-         int i;
-         for (i = 0; i < wchar_bytes; i++)
-           *q++ = 0;
+         saved = tree_cons (decl, build_int_2 (ix, 0), saved);
+         *fname_vars[ix].decl = NULL_TREE;
        }
-      else
-       *q = 0;
-
-      value = build_string (length, p);
-    }
-  else
-    {
-      value = strings;
-      length = TREE_STRING_LENGTH (value);
-      if (TREE_TYPE (value) == wchar_array_type_node)
-       wide_flag = 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);
+}
 
-  /* Compute the number of elements, for the array type.  */
-  nchars = wide_flag ? length / wchar_bytes : length;
+/* 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.  */
 
-  if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
-    pedwarn ("string length `%d' is greater than the minimum length `%d' ISO C%d is required to support",
-            nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
+void
+finish_fname_decls ()
+{
+  unsigned ix;
+  tree body = NULL_TREE;
+  tree stack = saved_function_name_decls;
 
-  /* Create the array type for the string constant.
-     -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))
+  for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack))
+    body = chainon (TREE_VALUE (stack), body);
+  
+  if (body)
     {
-      tree elements
-       = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
-                             1, 0);
-      TREE_TYPE (value)
-       = build_array_type (elements,
-                           build_index_type (build_int_2 (nchars - 1, 0)));
+      /* 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;
     }
-  else
-    TREE_TYPE (value)
-      = build_array_type (wide_flag ? wchar_type_node : char_type_node,
-                         build_index_type (build_int_2 (nchars - 1, 0)));
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    *fname_vars[ix].decl = NULL_TREE;
+  
+  if (stack)
+    {
+      /* We had saved values, restore them.  */
+      tree saved;
 
-  TREE_CONSTANT (value) = 1;
-  TREE_READONLY (value) = ! flag_writable_strings;
-  TREE_STATIC (value) = 1;
-  return value;
+      for (saved = TREE_PURPOSE (stack); saved; saved = TREE_CHAIN (saved))
+       {
+         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;
 }
-\f
-/* To speed up processing of attributes, we maintain an array of
-   IDENTIFIER_NODES and the corresponding attribute types.  */
-
-/* Array to hold attribute information.  */
 
-static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
+/* Return the text name of the current function, suitable prettified
+   by PRETTY_P.  */
 
-static int attrtab_idx = 0;
-
-/* Add an entry to the attribute table above.  */
-
-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;
+const char *
+fname_as_string (pretty_p)
+     int pretty_p;
 {
-  char buf[100];
-
-  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;
-
-  sprintf (buf, "__%s__", string);
-
-  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;
+  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;
 }
 
-/* Initialize attribute table.  */
+/* Return the text name of the current function, formatted as
+   required by the supplied RID value.  */
 
-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);
-}
-\f
-/* Default implementation of valid_lang_attribute, below.  By default, there
-   are no language-specific attributes.  */
-
-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;
+const char *
+fname_string (rid)
+     unsigned rid;
 {
-  return 0;
+  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);
 }
 
-/* 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.  */
-
-int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree))
-     = default_valid_lang_attribute;
+/* 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.  */
 
-/* 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.  */
-
-void
-decl_attributes (node, attributes, prefix_attributes)
-     tree node, attributes, prefix_attributes;
+tree
+fname_decl (rid, id)
+     unsigned rid;
+     tree id;
 {
-  tree decl = 0, type = 0;
-  int is_type = 0;
-  tree a;
+  unsigned ix;
+  tree decl = NULL_TREE;
 
-  if (attrtab_idx == 0)
-    init_attributes ();
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    if (fname_vars[ix].rid == rid)
+      break;
 
-  if (DECL_P (node))
+  decl = *fname_vars[ix].decl;
+  if (!decl)
     {
-      decl = node;
-      type = TREE_TYPE (decl);
-      is_type = TREE_CODE (node) == TYPE_DECL;
+      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;
     }
-  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
+  if (!ix && !current_function_decl)
+    pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
+  
+  return decl;
+}
 
-#ifdef INSERT_ATTRIBUTES
-  INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
-#endif
+/* Given a chain of STRING_CST nodes,
+   concatenate them into one STRING_CST
+   and give it a suitable array-of-chars data type.  */
 
-  attributes = chainon (prefix_attributes, attributes);
+tree
+combine_strings (strings)
+     tree strings;
+{
+  tree value, t;
+  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;
 
-  for (a = attributes; a; a = TREE_CHAIN (a))
+  if (TREE_CHAIN (strings))
     {
-      tree name = TREE_PURPOSE (a);
-      tree args = TREE_VALUE (a);
-      int i;
-      enum attrs id;
-
-      for (i = 0; i < attrtab_idx; i++)
-       if (attrtab[i].name == name)
-         break;
-
-      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)
-       {
-         error ("wrong number of arguments specified for `%s' attribute",
-                IDENTIFIER_POINTER (name));
-         continue;
-       }
+      /* More than one in the chain, so concatenate.  */
+      char *p, *q;
 
-      id = attrtab[i].id;
-      switch (id)
+      /* 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))
        {
-       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;
-
-       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;
-
-       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;
-
-       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;
-
-       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;
-
-
-       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;
-
-       case A_CONSTRUCTOR:
-         if (TREE_CODE (decl) == FUNCTION_DECL
-             && TREE_CODE (type) == FUNCTION_TYPE
-             && decl_function_context (decl) == 0)
+         if (TREE_TYPE (t) == wchar_array_type_node)
            {
-             DECL_STATIC_CONSTRUCTOR (decl) = 1;
-             TREE_USED (decl) = 1;
+             wide_length += (TREE_STRING_LENGTH (t) - wchar_bytes);
+             wide_flag = 1;
            }
          else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       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;
+             length += (TREE_STRING_LENGTH (t) - 1);
+             if (C_ARTIFICIAL_STRING_P (t) && !in_system_header)
+               warning ("concatenation of string literals with __FUNCTION__ is deprecated.  This feature will be removed in future"); 
            }
-         else
-           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
-         break;
-
-       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);
-
-                 strcpy (newp, &p[2]);
-                 newp[len - 4] = '\0';
-                 p = newp;
-               }
-
-             /* 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;
-
-       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;
-
-       case A_ALIGNED:
-         {
-           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;
-             }
-         }
-         break;
-
-       case A_FORMAT:
-         {
-           tree format_type_id = TREE_VALUE (args);
-           tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
-           tree first_arg_num_expr
-             = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
-           unsigned HOST_WIDE_INT format_num, first_arg_num;
-           enum format_type format_type;
-           tree argument;
-           unsigned int arg_num;
-
-           if (TREE_CODE (decl) != FUNCTION_DECL)
-             {
-               error_with_decl (decl,
-                        "argument format specified for non-function `%s'");
-               continue;
-             }
-
-           if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
-             {
-               error ("unrecognized format specifier");
-               continue;
-             }
-           else
-             {
-               const char *p = IDENTIFIER_POINTER (format_type_id);
-
-               if (!strcmp (p, "printf") || !strcmp (p, "__printf__"))
-                 format_type = printf_format_type;
-               else if (!strcmp (p, "scanf") || !strcmp (p, "__scanf__"))
-                 format_type = scanf_format_type;
-               else if (!strcmp (p, "strftime")
-                        || !strcmp (p, "__strftime__"))
-                 format_type = strftime_format_type;
-               else
-                 {
-                   warning ("`%s' is an unrecognized format function type", p);
-                   continue;
-                 }
-             }
-
-           /* Strip any conversions from the string index and first arg number
-              and verify they are constants.  */
-           while (TREE_CODE (format_num_expr) == NOP_EXPR
-                  || TREE_CODE (format_num_expr) == CONVERT_EXPR
-                  || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
-             format_num_expr = TREE_OPERAND (format_num_expr, 0);
-
-           while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
-                  || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
-                  || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
-             first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
-
-           if (TREE_CODE (format_num_expr) != INTEGER_CST
-               || TREE_INT_CST_HIGH (format_num_expr) != 0
-               || TREE_CODE (first_arg_num_expr) != INTEGER_CST
-               || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
-             {
-               error ("format string has invalid operand number");
-               continue;
-             }
-
-           format_num = TREE_INT_CST_LOW (format_num_expr);
-           first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
-           if (first_arg_num != 0 && first_arg_num <= format_num)
-             {
-               error ("format string arg follows the args to be formatted");
-               continue;
-             }
-
-           /* If a parameter list is specified, verify that the format_num
-              argument is actually a string, in case the format attribute
-              is in error.  */
-           argument = TYPE_ARG_TYPES (type);
-           if (argument)
-             {
-               for (arg_num = 1; argument != 0 && arg_num != format_num;
-                    ++arg_num, argument = TREE_CHAIN (argument))
-                 ;
-
-               if (! argument
-                   || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
-                 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
-                     != char_type_node))
-                 {
-                   error ("format string arg not a string type");
-                   continue;
-                 }
-
-               else if (first_arg_num != 0)
-                 {
-                   /* Verify that first_arg_num points to the last arg,
-                      the ...  */
-                   while (argument)
-                     arg_num++, argument = TREE_CHAIN (argument);
-
-                   if (arg_num != first_arg_num)
-                     {
-                       error ("args to be formatted is not '...'");
-                       continue;
-                     }
-                 }
-             }
-
-           if (format_type == strftime_format_type && first_arg_num != 0)
-             {
-               error ("strftime formats cannot format arguments");
-               continue;
-             }
-
-           record_function_format (DECL_NAME (decl),
-                                   DECL_ASSEMBLER_NAME (decl),
-                                   format_type, format_num, first_arg_num);
-           break;
-         }
-
-       case A_FORMAT_ARG:
-         {
-           tree format_num_expr = TREE_VALUE (args);
-           unsigned HOST_WIDE_INT format_num;
-           unsigned int arg_num;
-           tree argument;
-
-           if (TREE_CODE (decl) != FUNCTION_DECL)
-             {
-               error_with_decl (decl,
-                        "argument format specified for non-function `%s'");
-               continue;
-             }
-
-           /* Strip any conversions from the first arg number and verify it
-              is a constant.  */
-           while (TREE_CODE (format_num_expr) == NOP_EXPR
-                  || TREE_CODE (format_num_expr) == CONVERT_EXPR
-                  || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
-             format_num_expr = TREE_OPERAND (format_num_expr, 0);
-
-           if (TREE_CODE (format_num_expr) != INTEGER_CST
-               || TREE_INT_CST_HIGH (format_num_expr) != 0)
-             {
-               error ("format string has invalid operand number");
-               continue;
-             }
-
-           format_num = TREE_INT_CST_LOW (format_num_expr);
-
-           /* If a parameter list is specified, verify that the format_num
-              argument is actually a string, in case the format attribute
-              is in error.  */
-           argument = TYPE_ARG_TYPES (type);
-           if (argument)
-             {
-               for (arg_num = 1; argument != 0 && arg_num != format_num;
-                    ++arg_num, argument = TREE_CHAIN (argument))
-                 ;
-
-               if (! argument
-                   || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
-                 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
-                     != char_type_node))
-                 {
-                   error ("format string arg not a string type");
-                   continue;
-                 }
-             }
-
-           if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE
-               || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl))))
-                   != char_type_node))
-             {
-               error ("function does not return string type");
-               continue;
-             }
-
-           record_international_format (DECL_NAME (decl),
-                                        DECL_ASSEMBLER_NAME (decl),
-                                        format_num);
-           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;
-       }
-    }
-}
-
-/* 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.  */
-
-void
-split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
-     tree specs_attrs;
-     tree *declspecs, *prefix_attributes;
-{
-  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;
-    }
-
-  /* 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;
-      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)
-    {
-      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 (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);
-       }
-    }
-
-  /* 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.  */
-
-tree
-strip_attrs (specs_attrs)
-     tree specs_attrs;
-{
-  tree specs, attrs;
-
-  split_specs_attrs (specs_attrs, &specs, &attrs);
-
-  while (attrs)
-    {
-      warning ("`%s' attribute ignored",
-              IDENTIFIER_POINTER (TREE_PURPOSE (attrs)));
-      attrs = TREE_CHAIN (attrs);
-    }
-
-  return specs;
-}
-\f
-/* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against
-   a parameter list.  */
-
-/* The meaningfully distinct length modifiers for format checking recognised
-   by GCC.  */
-enum format_lengths
-{
-  FMT_LEN_none,
-  FMT_LEN_hh,
-  FMT_LEN_h,
-  FMT_LEN_l,
-  FMT_LEN_ll,
-  FMT_LEN_L,
-  FMT_LEN_z,
-  FMT_LEN_t,
-  FMT_LEN_j,
-  FMT_LEN_MAX
-};
-
-
-/* The standard versions in which various format features appeared.  */
-enum format_std_version
-{
-  STD_C89,
-  STD_C94,
-  STD_C9L, /* C99, but treat as C89 if -Wno-long-long.  */
-  STD_C99,
-  STD_EXT
-};
-
-/* The C standard version C++ is treated as equivalent to
-   or inheriting from, for the purpose of format features supported.  */
-#define CPLUSPLUS_STD_VER      STD_C89
-/* The C standard version we are checking formats against when pedantic.  */
-#define C_STD_VER              (c_language == clk_cplusplus              \
-                                ? CPLUSPLUS_STD_VER                      \
-                                : (flag_isoc99                           \
-                                   ? STD_C99                             \
-                                   : (flag_isoc94 ? STD_C94 : STD_C89)))
-/* The name to give to the standard version we are warning about when
-   pedantic.  FEATURE_VER is the version in which the feature warned out
-   appeared, which is higher than C_STD_VER.  */
-#define C_STD_NAME(FEATURE_VER) (c_language == clk_cplusplus   \
-                                ? "ISO C++"                    \
-                                : ((FEATURE_VER) == STD_EXT    \
-                                   ? "ISO C"                   \
-                                   : "ISO C89"))
-/* Adjust a C standard version, which may be STD_C9L, to account for
-   -Wno-long-long.  Returns other standard versions unchanged.  */
-#define ADJ_STD(VER)           ((int)((VER) == STD_C9L                       \
-                                      ? (warn_long_long ? STD_C99 : STD_C89) \
-                                      : (VER)))
-
-/* Flags that may apply to a particular kind of format checked by GCC.  */
-enum
-{
-  /* This format converts arguments of types determined by the
-     format string.  */
-  FMT_FLAG_ARG_CONVERT = 1,
-  /* The scanf allocation 'a' kludge applies to this format kind.  */
-  FMT_FLAG_SCANF_A_KLUDGE = 2,
-  /* A % during parsing a specifier is allowed to be a modified % rather
-     that indicating the format is broken and we are out-of-sync.  */
-  FMT_FLAG_FANCY_PERCENT_OK = 4,
-  /* With $ operand numbers, it is OK to reference the same argument more
-     than once.  */
-  FMT_FLAG_DOLLAR_MULTIPLE = 8
-  /* Not included here: details of whether width or precision may occur
-     (controlled by width_char and precision_char); details of whether
-     '*' can be used for these (width_type and precision_type); details
-     of whether length modifiers can occur (length_char_specs); details
-     of when $ operand numbers are allowed (always, for the formats
-     supported, if arguments are converted).  */
-};
-
-
-/* Structure describing a length modifier supported in format checking, and
-   possibly a doubled version such as "hh".  */
-typedef struct
-{
-  /* Name of the single-character length modifier.  */
-  const char *name;
-  /* Index into a format_char_info.types array.  */
-  enum format_lengths index;
-  /* Standard version this length appears in.  */
-  enum format_std_version std;
-  /* Same, if the modifier can be repeated, or NULL if it can't.  */
-  const char *double_name;
-  enum format_lengths double_index;
-  enum format_std_version double_std;
-} format_length_info;
-
-
-/* Structure desribing the combination of a conversion specifier
-   (or a set of specifiers which act identically) and a length modifier.  */
-typedef struct
-{
-  /* The standard version this combination of length and type appeared in.
-     This is only relevant if greater than those for length and type
-     individually; otherwise it is ignored.  */
-  enum format_std_version std;
-  /* The name to use for the type, if different from that generated internally
-     (e.g., "signed size_t").  */
-  const char *name;
-  /* The type itself.  */
-  tree *type;
-} format_type_detail;
-
-
-/* Macros to fill out tables of these.  */
-#define BADLEN { 0, NULL, NULL }
-#define NOLENGTHS      { BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN, BADLEN }
-
-
-/* Structure desribing a format conversion specifier (or a set of specifiers
-   which act identically), and the length modifiers used with it.  */
-typedef struct
-{
-  const char *format_chars;
-  int pointer_count;
-  enum format_std_version std;
-  /* Types accepted for each length modifier.  */
-  format_type_detail types[FMT_LEN_MAX];
-  /* List of other modifier characters allowed with these specifiers.
-     This lists flags, and additionally "w" for width, "p" for precision,
-     "a" for scanf "a" allocation extension (not applicable in C99 mode),
-     "*" for scanf suppression, and "E" and "O" for those strftime
-     modifiers.  */
-  const char *flag_chars;
-  /* List of additional flags describing these conversion specifiers.
-     "c" for generic character pointers being allowed, "2" for strftime
-     two digit year formats, "3" for strftime formats giving two digit
-     years in some locales, "4" for "2" which becomes "3" with an "E" modifier,
-     "o" if use of strftime "O" is a GNU extension beyond C99,
-     "W" if the argument is a pointer which is dereferenced and written into,
-     "R" if the argument is a pointer which is dereferenced and read from,
-     "i" for printf integer formats where the '0' flag is ignored with
-     precision, and "[" for the starting character of a scanf scanset.  */
-  const char *flags2;
-} format_char_info;
-
-
-/* Structure describing a flag accepted by some kind of format.  */
-typedef struct
-{
-  /* The flag character in question (0 for end of array).  */
-  int flag_char;
-  /* Zero if this entry describes the flag character in general, or a
-     non-zero character that may be found in flags2 if it describes the
-     flag when used with certain formats only.  If the latter, only
-     the first such entry found that applies to the current conversion
-     specifier is used; the values of `name' and `long_name' it supplies
-     will be used, if non-NULL and the standard version is higher than
-     the unpredicated one, for any pedantic warning.  For example, 'o'
-     for strftime formats (meaning 'O' is an extension over C99).  */
-  int predicate;
-  /* The name to use for this flag in diagnostic messages.  For example,
-     N_("`0' flag"), N_("field width").  */
-  const char *name;
-  /* Long name for this flag in diagnostic messages; currently only used for
-     "ISO C does not support ...".  For example, N_("the `I' printf flag").  */
-  const char *long_name;
-  /* The standard version in which it appeared.  */
-  enum format_std_version std;
-} format_flag_spec;
-
-
-/* Structure describing a combination of flags that is bad for some kind
-   of format.  */
-typedef struct
-{
-  /* The first flag character in question (0 for end of array).  */
-  int flag_char1;
-  /* The second flag character.  */
-  int flag_char2;
-  /* Non-zero if the message should say that the first flag is ignored with
-     the second, zero if the combination should simply be objected to.  */
-  int ignored;
-  /* Zero if this entry applies whenever this flag combination occurs,
-     a non-zero character from flags2 if it only applies in some
-     circumstances (e.g. 'i' for printf formats ignoring 0 with precision).  */
-  int predicate;
-} format_flag_pair;
-
-
-/* Structure describing a particular kind of format processed by GCC.  */
-typedef struct
-{
-  /* The name of this kind of format, for use in diagnostics.  */
-  const char *name;
-  /* Specifications of the length modifiers accepted; possibly NULL.  */
-  const format_length_info *length_char_specs;
-  /* Details of the conversion specification characters accepted.  */
-  const format_char_info *conversion_specs;
-  /* String listing the flag characters that are accepted.  */
-  const char *flag_chars;
-  /* String listing modifier characters (strftime) accepted.  May be NULL.  */
-  const char *modifier_chars;
-  /* Details of the flag characters, including pseudo-flags.  */
-  const format_flag_spec *flag_specs;
-  /* Details of bad combinations of flags.  */
-  const format_flag_pair *bad_flag_pairs;
-  /* Flags applicable to this kind of format.  */
-  int flags;
-  /* Flag character to treat a width as, or 0 if width not used.  */
-  int width_char;
-  /* Flag character to treat a precision as, or 0 if precision not used.  */
-  int precision_char;
-  /* If a flag character has the effect of suppressing the conversion of
-     an argument ('*' in scanf), that flag character, otherwise 0.  */
-  int suppression_char;
-  /* Flag character to treat a length modifier as (ignored if length
-     modifiers not used).  Need not be placed in flag_chars for conversion
-     specifiers, but is used to check for bad combinations such as length
-     modifier with assignment suppression in scanf.  */
-  int length_code_char;
-  /* Pointer to type of argument expected if '*' is used for a width,
-     or NULL if '*' not used for widths.  */
-  tree *width_type;
-  /* Pointer to type of argument expected if '*' is used for a precision,
-     or NULL if '*' not used for precisions.  */
-  tree *precision_type;
-} format_kind_info;
-
-
-/* Structure describing details of a type expected in format checking,
-   and the type to check against it.  */
-typedef struct format_wanted_type
-{
-  /* The type wanted.  */
-  tree wanted_type;
-  /* The name of this type to use in diagnostics.  */
-  const char *wanted_type_name;
-  /* The level of indirection through pointers at which this type occurs.  */
-  int pointer_count;
-  /* Whether, when pointer_count is 1, to allow any character type when
-     pedantic, rather than just the character or void type specified.  */
-  int char_lenient_flag;
-  /* Whether the argument, dereferenced once, is written into and so the
-     argument must not be a pointer to a const-qualified type.  */
-  int writing_in_flag;
-  /* Whether the argument, dereferenced once, is read from and so
-     must not be a NULL pointer.  */
-  int reading_from_flag;
-  /* If warnings should be of the form "field precision is not type int",
-     the name to use (in this case "field precision"), otherwise NULL,
-     for "%s format, %s arg" type messages.  If (in an extension), this
-     is a pointer type, wanted_type_name should be set to include the
-     terminating '*' characters of the type name to give a correct
-     message.  */
-  const char *name;
-  /* The actual parameter to check against the wanted type.  */
-  tree param;
-  /* The argument number of that parameter.  */
-  int arg_num;
-  /* The next type to check for this format conversion, or NULL if none.  */
-  struct format_wanted_type *next;
-} format_wanted_type;
-
-
-static const format_length_info printf_length_specs[] =
-{
-  { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
-  { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
-  { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
-  { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
-  { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
-  { "Z", FMT_LEN_z, STD_EXT, NULL, 0, 0 },
-  { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
-  { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
-  { NULL, 0, 0, NULL, 0, 0 }
-};
-
-
-/* This differs from printf_length_specs only in that "Z" is not accepted.  */
-static const format_length_info scanf_length_specs[] =
-{
-  { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
-  { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C9L },
-  { "q", FMT_LEN_ll, STD_EXT, NULL, 0, 0 },
-  { "L", FMT_LEN_L, STD_C89, NULL, 0, 0 },
-  { "z", FMT_LEN_z, STD_C99, NULL, 0, 0 },
-  { "t", FMT_LEN_t, STD_C99, NULL, 0, 0 },
-  { "j", FMT_LEN_j, STD_C99, NULL, 0, 0 },
-  { NULL, 0, 0, NULL, 0, 0 }
-};
-
-
-static const format_flag_spec printf_flag_specs[] =
-{
-  { ' ',  0, N_("` ' flag"),        N_("the ` ' printf flag"),              STD_C89 },
-  { '+',  0, N_("`+' flag"),        N_("the `+' printf flag"),              STD_C89 },
-  { '#',  0, N_("`#' flag"),        N_("the `#' printf flag"),              STD_C89 },
-  { '0',  0, N_("`0' flag"),        N_("the `0' printf flag"),              STD_C89 },
-  { '-',  0, N_("`-' flag"),        N_("the `-' printf flag"),              STD_C89 },
-  { '\'', 0, N_("`'' flag"),        N_("the `'' printf flag"),              STD_EXT },
-  { 'I',  0, N_("`I' flag"),        N_("the `I' printf flag"),              STD_EXT },
-  { 'w',  0, N_("field width"),     N_("field width in printf format"),     STD_C89 },
-  { 'p',  0, N_("precision"),       N_("precision in printf format"),       STD_C89 },
-  { 'L',  0, N_("length modifier"), N_("length modifier in printf format"), STD_C89 },
-  { 0, 0, NULL, NULL, 0 }
-};
-
-
-static const format_flag_pair printf_flag_pairs[] =
-{
-  { ' ', '+', 1, 0   },
-  { '0', '-', 1, 0   },
-  { '0', 'p', 1, 'i' },
-  { 0, 0, 0, 0 }
-};
-
-
-static const format_flag_spec scanf_flag_specs[] =
-{
-  { '*',  0, N_("assignment suppression"), N_("assignment suppression"),          STD_C89 },
-  { 'a',  0, N_("`a' flag"),               N_("the `a' scanf flag"),              STD_EXT },
-  { 'w',  0, N_("field width"),            N_("field width in scanf format"),     STD_C89 },
-  { 'L',  0, N_("length modifier"),        N_("length modifier in scanf format"), STD_C89 },
-  { '\'', 0, N_("`'' flag"),               N_("the `'' scanf flag"),              STD_EXT },
-  { 'I',  0, N_("`I' flag"),               N_("the `I' scanf flag"),              STD_EXT },
-  { 0, 0, NULL, NULL, 0 }
-};
-
-
-static const format_flag_pair scanf_flag_pairs[] =
-{
-  { '*', 'L', 0, 0 },
-  { 0, 0, 0, 0 }
-};
-
-
-static const format_flag_spec strftime_flag_specs[] =
-{
-  { '_', 0,   N_("`_' flag"),     N_("the `_' strftime flag"),          STD_EXT },
-  { '-', 0,   N_("`-' flag"),     N_("the `-' strftime flag"),          STD_EXT },
-  { '0', 0,   N_("`0' flag"),     N_("the `0' strftime flag"),          STD_EXT },
-  { '^', 0,   N_("`^' flag"),     N_("the `^' strftime flag"),          STD_EXT },
-  { '#', 0,   N_("`#' flag"),     N_("the `#' strftime flag"),          STD_EXT },
-  { 'w', 0,   N_("field width"),  N_("field width in strftime format"), STD_EXT },
-  { 'E', 0,   N_("`E' modifier"), N_("the `E' strftime modifier"),      STD_C99 },
-  { 'O', 0,   N_("`O' modifier"), N_("the `O' strftime modifier"),      STD_C99 },
-  { 'O', 'o', NULL,               N_("the `O' modifier"),               STD_EXT },
-  { 0, 0, NULL, NULL, 0 }
-};
-
-
-static const format_flag_pair strftime_flag_pairs[] =
-{
-  { 'E', 'O', 0, 0 },
-  { '_', '-', 0, 0 },
-  { '_', '0', 0, 0 },
-  { '-', '0', 0, 0 },
-  { '^', '#', 0, 0 },
-  { 0, 0, 0, 0 }
-};
-
-
-#define T_I    &integer_type_node
-#define T89_I  { STD_C89, NULL, T_I }
-#define T99_I  { STD_C99, NULL, T_I }
-#define T_L    &long_integer_type_node
-#define T89_L  { STD_C89, NULL, T_L }
-#define T_LL   &long_long_integer_type_node
-#define T9L_LL { STD_C9L, NULL, T_LL }
-#define TEX_LL { STD_EXT, NULL, T_LL }
-#define T_S    &short_integer_type_node
-#define T89_S  { STD_C89, NULL, T_S }
-#define T_UI   &unsigned_type_node
-#define T89_UI { STD_C89, NULL, T_UI }
-#define T99_UI { STD_C99, NULL, T_UI }
-#define T_UL   &long_unsigned_type_node
-#define T89_UL { STD_C89, NULL, T_UL }
-#define T_ULL  &long_long_unsigned_type_node
-#define T9L_ULL        { STD_C9L, NULL, T_ULL }
-#define TEX_ULL        { STD_EXT, NULL, T_ULL }
-#define T_US   &short_unsigned_type_node
-#define T89_US { STD_C89, NULL, T_US }
-#define T_F    &float_type_node
-#define T89_F  { STD_C89, NULL, T_F }
-#define T99_F  { STD_C99, NULL, T_F }
-#define T_D    &double_type_node
-#define T89_D  { STD_C89, NULL, T_D }
-#define T99_D  { STD_C99, NULL, T_D }
-#define T_LD   &long_double_type_node
-#define T89_LD { STD_C89, NULL, T_LD }
-#define T99_LD { STD_C99, NULL, T_LD }
-#define T_C    &char_type_node
-#define T89_C  { STD_C89, NULL, T_C }
-#define T_SC   &signed_char_type_node
-#define T99_SC { STD_C99, NULL, T_SC }
-#define T_UC   &unsigned_char_type_node
-#define T99_UC { STD_C99, NULL, T_UC }
-#define T_V    &void_type_node
-#define T89_V  { STD_C89, NULL, T_V }
-#define T_W    &wchar_type_node
-#define T94_W  { STD_C94, "wchar_t", T_W }
-#define TEX_W  { STD_EXT, "wchar_t", T_W }
-#define T_WI   &wint_type_node
-#define T94_WI { STD_C94, "wint_t", T_WI }
-#define TEX_WI { STD_EXT, "wint_t", T_WI }
-#define T_ST    &c_size_type_node
-#define T99_ST { STD_C99, "size_t", T_ST }
-#define T_SST   &signed_size_type_node
-#define T99_SST        { STD_C99, "signed size_t", T_SST }
-#define T_PD    &ptrdiff_type_node
-#define T99_PD { STD_C99, "ptrdiff_t", T_PD }
-#define T_UPD   &unsigned_ptrdiff_type_node
-#define T99_UPD        { STD_C99, "unsigned ptrdiff_t", T_UPD }
-#define T_IM    &intmax_type_node
-#define T99_IM { STD_C99, "intmax_t", T_IM }
-#define T_UIM   &uintmax_type_node
-#define T99_UIM        { STD_C99, "uintmax_t", T_UIM }
-
-static const format_char_info print_char_table[] =
-{
-  /* C89 conversion specifiers.  */
-  { "di",  0, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "-wp0 +'I", "i"  },
-  { "oxX", 0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0#",    "i"  },
-  { "u",   0, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0'I",   "i"  },
-  { "fgG", 0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", ""   },
-  { "eE",  0, STD_C89, { T89_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  ""   },
-  { "c",   0, STD_C89, { T89_I,   BADLEN,  BADLEN,  T94_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       ""   },
-  { "s",   1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "cR" },
-  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       "c"  },
-  { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, "",         "W"  },
-  /* C99 conversion specifiers.  */
-  { "F",   0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#'", ""   },
-  { "aA",  0, STD_C99, { T99_D,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "-wp0 +#",  ""   },
-  /* X/Open conversion specifiers.  */
-  { "C",   0, STD_EXT, { TEX_WI,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-w",       ""   },
-  { "S",   1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      "R"  },
-  /* GNU conversion specifiers.  */
-  { "m",   0, STD_EXT, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp",      ""   },
-  { NULL,  0, 0, NOLENGTHS, NULL, NULL }
-};
-
-static const format_char_info scan_char_table[] =
-{
-  /* C89 conversion specifiers.  */
-  { "di",    1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "*w'I", "W"   },
-  { "u",     1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "*w'I", "W"   },
-  { "oxX",   1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T9L_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "*w",   "W"   },
-  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w'",  "W"   },
-  { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "cW"  },
-  { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "cW"  },
-  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "cW[" },
-  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "W"   },
-  { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T9L_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, "",     "W"   },
-  /* C99 conversion specifiers.  */
-  { "FaA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w'",  "W"   },
-  /* X/Open conversion specifiers.  */
-  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w",   "W"   },
-  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw",  "W"   },
-  { NULL, 0, 0, NOLENGTHS, NULL, NULL }
-};
-
-static format_char_info time_char_table[] =
-{
-  /* C89 conversion specifiers.  */
-  { "ABZab",           0, STD_C89, NOLENGTHS, "^#",     ""   },
-  { "cx",              0, STD_C89, NOLENGTHS, "E",      "3"  },
-  { "HIMSUWdmw",       0, STD_C89, NOLENGTHS, "-_0Ow",  ""   },
-  { "j",               0, STD_C89, NOLENGTHS, "-_0Ow",  "o"  },
-  { "p",               0, STD_C89, NOLENGTHS, "#",      ""   },
-  { "X",               0, STD_C89, NOLENGTHS, "E",      ""   },
-  { "y",               0, STD_C89, NOLENGTHS, "EO-_0w", "4"  },
-  { "Y",               0, STD_C89, NOLENGTHS, "-_0EOw", "o"  },
-  { "%",               0, STD_C89, NOLENGTHS, "",       ""   },
-  /* C99 conversion specifiers.  */
-  { "C",               0, STD_C99, NOLENGTHS, "-_0EOw", "o"  },
-  { "D",               0, STD_C99, NOLENGTHS, "",       "2"  },
-  { "eVu",             0, STD_C99, NOLENGTHS, "-_0Ow",  ""   },
-  { "FRTnrt",          0, STD_C99, NOLENGTHS, "",       ""   },
-  { "g",               0, STD_C99, NOLENGTHS, "O-_0w",  "2o" },
-  { "G",               0, STD_C99, NOLENGTHS, "-_0Ow",  "o"  },
-  { "h",               0, STD_C99, NOLENGTHS, "^#",     ""   },
-  { "z",               0, STD_C99, NOLENGTHS, "O",      "o"  },
-  /* GNU conversion specifiers.  */
-  { "kls",             0, STD_EXT, NOLENGTHS, "-_0Ow",  ""   },
-  { "P",               0, STD_EXT, NOLENGTHS, "",       ""   },
-  { NULL,              0, 0, NOLENGTHS, NULL, NULL }
-};
-
-
-/* This must be in the same order as enum format_type.  */
-static const format_kind_info format_types[] =
-{
-  { "printf",   printf_length_specs, print_char_table, " +#0-'I", NULL, 
-    printf_flag_specs, printf_flag_pairs,
-    FMT_FLAG_ARG_CONVERT|FMT_FLAG_DOLLAR_MULTIPLE, 'w', 'p', 0, 'L',
-    &integer_type_node, &integer_type_node
-  },
-  { "scanf",    scanf_length_specs,  scan_char_table,  "*'I", NULL, 
-    scanf_flag_specs, scanf_flag_pairs,
-    FMT_FLAG_ARG_CONVERT|FMT_FLAG_SCANF_A_KLUDGE, 'w', 0, '*', 'L',
-    NULL, NULL
-  },
-  { "strftime", NULL,                time_char_table,  "_-0^#", "EO",
-    strftime_flag_specs, strftime_flag_pairs,
-    FMT_FLAG_FANCY_PERCENT_OK, 'w', 0, 0, 0,
-    NULL, NULL
-  }
-};
-
-
-typedef struct function_format_info
-{
-  struct function_format_info *next;  /* next structure on the list */
-  tree name;                   /* identifier such as "printf" */
-  tree assembler_name;         /* optional mangled identifier (for C++) */
-  enum format_type format_type;        /* type of format (printf, scanf, etc.) */
-  int format_num;              /* number of format argument */
-  int first_arg_num;           /* number of first arg (zero for varargs) */
-} function_format_info;
-
-static function_format_info *function_format_list = NULL;
-
-typedef struct international_format_info
-{
-  struct international_format_info *next;  /* next structure on the list */
-  tree name;                   /* identifier such as "gettext" */
-  tree assembler_name;         /* optional mangled identifier (for C++) */
-  int format_num;              /* number of format argument */
-} international_format_info;
-
-static international_format_info *international_format_list = NULL;
-
-/* Structure detailing the results of checking a format function call
-   where the format expression may be a conditional expression with
-   many leaves resulting from nested conditional expressions.  */
-typedef struct
-{
-  /* Number of leaves of the format argument that could not be checked
-     as they were not string literals.  */
-  int number_non_literal;
-  /* Number of leaves of the format argument that were null pointers or
-     string literals, but had extra format arguments.  */
-  int number_extra_args;
-  /* Number of leaves of the format argument that were null pointers or
-     string literals, but had extra format arguments and used $ operand
-     numbers.  */
-  int number_dollar_extra_args;
-  /* Number of leaves of the format argument that were wide string
-     literals.  */
-  int number_wide;
-  /* Number of leaves of the format argument that were empty strings.  */
-  int number_empty;
-  /* Number of leaves of the format argument that were unterminated
-     strings.  */
-  int number_unterminated;
-  /* Number of leaves of the format argument that were not counted above.  */
-  int number_other;
-} format_check_results;
-
-static void check_format_info  PARAMS ((int *, function_format_info *, tree));
-static void check_format_info_recurse PARAMS ((int *, format_check_results *,
-                                              function_format_info *, tree,
-                                              tree, int));
-static void check_format_info_main PARAMS ((int *, format_check_results *,
-                                           function_format_info *,
-                                           const char *, int, tree, int));
-static void status_warning PARAMS ((int *, const char *, ...))
-     ATTRIBUTE_PRINTF_2;
-
-static void init_dollar_format_checking                PARAMS ((int, tree));
-static int maybe_read_dollar_number            PARAMS ((int *, const char **, int,
-                                                        tree, tree *,
-                                                        const format_kind_info *));
-static void finish_dollar_format_checking      PARAMS ((int *, format_check_results *));
-
-static const format_flag_spec *get_flag_spec   PARAMS ((const format_flag_spec *,
-                                                        int, const char *));
-
-static void check_format_types PARAMS ((int *, format_wanted_type *));
-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));
-
-/* Initialize the table of functions to perform format checking on.
-   The ISO C functions are always checked (whether <stdio.h> is
-   included or not), since it is common to call printf without
-   including <stdio.h>.  There shouldn't be a problem with this,
-   since ISO C reserves these function names whether you include the
-   header file or not.  In any case, the checking is harmless.  With
-   -ffreestanding, these default attributes are disabled, and must be
-   specified manually if desired.
-
-   Also initialize the name of function that modify the format string for
-   internationalization purposes.  */
-
-void
-init_function_format_info ()
-{
-  if (flag_hosted)
-    {
-      /* Functions from ISO/IEC 9899:1990.  */
-      record_function_format (get_identifier ("printf"), NULL_TREE,
-                             printf_format_type, 1, 2);
-      record_function_format (get_identifier ("__builtin_printf"), NULL_TREE,
-                             printf_format_type, 1, 2);
-      record_function_format (get_identifier ("fprintf"), NULL_TREE,
-                             printf_format_type, 2, 3);
-      record_function_format (get_identifier ("sprintf"), NULL_TREE,
-                             printf_format_type, 2, 3);
-      record_function_format (get_identifier ("scanf"), NULL_TREE,
-                             scanf_format_type, 1, 2);
-      record_function_format (get_identifier ("fscanf"), NULL_TREE,
-                             scanf_format_type, 2, 3);
-      record_function_format (get_identifier ("sscanf"), NULL_TREE,
-                             scanf_format_type, 2, 3);
-      record_function_format (get_identifier ("vprintf"), NULL_TREE,
-                             printf_format_type, 1, 0);
-      record_function_format (get_identifier ("vfprintf"), NULL_TREE,
-                             printf_format_type, 2, 0);
-      record_function_format (get_identifier ("vsprintf"), NULL_TREE,
-                             printf_format_type, 2, 0);
-      record_function_format (get_identifier ("strftime"), NULL_TREE,
-                             strftime_format_type, 3, 0);
-    }
-
-  if (flag_hosted && flag_isoc99)
-    {
-      /* ISO C99 adds the snprintf and vscanf family functions.  */
-      record_function_format (get_identifier ("snprintf"), NULL_TREE,
-                             printf_format_type, 3, 4);
-      record_function_format (get_identifier ("vsnprintf"), NULL_TREE,
-                             printf_format_type, 3, 0);
-      record_function_format (get_identifier ("vscanf"), NULL_TREE,
-                             scanf_format_type, 1, 0);
-      record_function_format (get_identifier ("vfscanf"), NULL_TREE,
-                             scanf_format_type, 2, 0);
-      record_function_format (get_identifier ("vsscanf"), NULL_TREE,
-                             scanf_format_type, 2, 0);
-    }
-
-  if (flag_hosted && flag_noniso_default_format_attributes)
-    {
-      /* Uniforum/GNU gettext functions, not in ISO C.  */
-      record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
-      record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
-      record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
-    }
-}
-
-/* Record information for argument format checking.  FUNCTION_IDENT is
-   the identifier node for the name of the function to check (its decl
-   need not exist yet).
-   FORMAT_TYPE specifies the type of format checking.  FORMAT_NUM is the number
-   of the argument which is the format control string (starting from 1).
-   FIRST_ARG_NUM is the number of the first actual argument to check
-   against the format string, or zero if no checking is not be done
-   (e.g. for varargs such as vfprintf).  */
-
-static void
-record_function_format (name, assembler_name, format_type,
-                       format_num, first_arg_num)
-      tree name;
-      tree assembler_name;
-      enum format_type format_type;
-      int format_num;
-      int first_arg_num;
-{
-  function_format_info *info;
-
-  /* Re-use existing structure if it's there.  */
-
-  for (info = function_format_list; info; info = info->next)
-    {
-      if (info->name == name && info->assembler_name == assembler_name)
-       break;
-    }
-  if (! info)
-    {
-      info = (function_format_info *) xmalloc (sizeof (function_format_info));
-      info->next = function_format_list;
-      function_format_list = info;
-
-      info->name = name;
-      info->assembler_name = assembler_name;
-    }
-
-  info->format_type = format_type;
-  info->format_num = format_num;
-  info->first_arg_num = first_arg_num;
-}
-
-/* Record information for the names of function that modify the format
-   argument to format functions.  FUNCTION_IDENT is the identifier node for
-   the name of the function (its decl need not exist yet) and FORMAT_NUM is
-   the number of the argument which is the format control string (starting
-   from 1).  */
-
-static void
-record_international_format (name, assembler_name, format_num)
-      tree name;
-      tree assembler_name;
-      int format_num;
-{
-  international_format_info *info;
-
-  /* Re-use existing structure if it's there.  */
-
-  for (info = international_format_list; info; info = info->next)
-    {
-      if (info->name == name && info->assembler_name == assembler_name)
-       break;
-    }
-
-  if (! info)
-    {
-      info
-       = (international_format_info *)
-         xmalloc (sizeof (international_format_info));
-      info->next = international_format_list;
-      international_format_list = info;
-
-      info->name = name;
-      info->assembler_name = assembler_name;
-    }
-
-  info->format_num = format_num;
-}
-\f
-/* Check the argument list of a call to printf, scanf, etc.
-   NAME is the function identifier.
-   ASSEMBLER_NAME is the function's assembler identifier.
-   (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.)
-   PARAMS is the list of argument values.  Also, if -Wmissing-format-attribute,
-   warn for calls to vprintf or vscanf in functions with no such format
-   attribute themselves.  */
-
-void
-check_function_format (status, name, assembler_name, params)
-     int *status;
-     tree name;
-     tree assembler_name;
-     tree params;
-{
-  function_format_info *info;
-
-  /* See if this function is a format function.  */
-  for (info = function_format_list; info; info = info->next)
-    {
-      if (info->assembler_name
-         ? (info->assembler_name == assembler_name)
-         : (info->name == name))
-       {
-         /* Yup; check it.  */
-         check_format_info (status, info, params);
-         if (warn_missing_format_attribute && info->first_arg_num == 0
-             && (format_types[info->format_type].flags & FMT_FLAG_ARG_CONVERT))
-           {
-             function_format_info *info2;
-             for (info2 = function_format_list; info2; info2 = info2->next)
-               if ((info2->assembler_name
-                    ? (info2->assembler_name == DECL_ASSEMBLER_NAME (current_function_decl))
-                    : (info2->name == DECL_NAME (current_function_decl)))
-                   && info2->format_type == info->format_type)
-                 break;
-             if (info2 == NULL)
-               {
-                 /* Check if the current function has a parameter to which
-                    the format attribute could be attached; if not, it
-                    can't be a candidate for a format attribute, despite
-                    the vprintf-like or vscanf-like call.  */
-                 tree args;
-                 for (args = DECL_ARGUMENTS (current_function_decl);
-                      args != 0;
-                      args = TREE_CHAIN (args))
-                   {
-                     if (TREE_CODE (TREE_TYPE (args)) == POINTER_TYPE
-                         && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (args)))
-                             == char_type_node))
-                       break;
-                   }
-                 if (args != 0)
-                   warning ("function might be possible candidate for `%s' format attribute",
-                            format_types[info->format_type].name);
-               }
-           }
-         break;
-       }
-    }
-}
-
-/* This function replaces `warning' inside the printf format checking
-   functions.  If the `status' parameter is non-NULL, then it is
-   dereferenced and set to 1 whenever a warning is caught.  Otherwise
-   it warns as usual by replicating the innards of the warning
-   function from diagnostic.c.  */
-static void
-status_warning VPARAMS ((int *status, const char *msgid, ...))
-{
-#ifndef ANSI_PROTOTYPES
-  int *status;
-  const char *msgid;
-#endif
-  va_list ap;
-  diagnostic_context dc;
-
-  VA_START (ap, msgid);
-
-#ifndef ANSI_PROTOTYPES
-  status = va_arg (ap, int *);
-  msgid = va_arg (ap, const char *);
-#endif
-
-  if (status)
-    *status = 1;
-  else
-    {
-      /* This duplicates the warning function behavior.  */
-      set_diagnostic_context
-       (&dc, msgid, &ap, input_filename, lineno, /* warn = */ 1);
-      report_diagnostic (&dc);
-    }
-
-  va_end (ap);
-}
-
-/* Variables used by the checking of $ operand number formats.  */
-static char *dollar_arguments_used = NULL;
-static int dollar_arguments_alloc = 0;
-static int dollar_arguments_count;
-static int dollar_first_arg_num;
-static int dollar_max_arg_used;
-static int dollar_format_warned;
-
-/* Initialize the checking for a format string that may contain $
-   parameter number specifications; we will need to keep track of whether
-   each parameter has been used.  FIRST_ARG_NUM is the number of the first
-   argument that is a parameter to the format, or 0 for a vprintf-style
-   function; PARAMS is the list of arguments starting at this argument.  */
-
-static void
-init_dollar_format_checking (first_arg_num, params)
-     int first_arg_num;
-     tree params;
-{
-  dollar_first_arg_num = first_arg_num;
-  dollar_arguments_count = 0;
-  dollar_max_arg_used = 0;
-  dollar_format_warned = 0;
-  if (first_arg_num > 0)
-    {
-      while (params)
-       {
-         dollar_arguments_count++;
-         params = TREE_CHAIN (params);
-       }
-    }
-  if (dollar_arguments_alloc < dollar_arguments_count)
-    {
-      if (dollar_arguments_used)
-       free (dollar_arguments_used);
-      dollar_arguments_alloc = dollar_arguments_count;
-      dollar_arguments_used = xmalloc (dollar_arguments_alloc);
-    }
-  if (dollar_arguments_alloc)
-    memset (dollar_arguments_used, 0, dollar_arguments_alloc);
-}
-
-
-/* Look for a decimal number followed by a $ in *FORMAT.  If DOLLAR_NEEDED
-   is set, it is an error if one is not found; otherwise, it is OK.  If
-   such a number is found, check whether it is within range and mark that
-   numbered operand as being used for later checking.  Returns the operand
-   number if found and within range, zero if no such number was found and
-   this is OK, or -1 on error.  PARAMS points to the first operand of the
-   format; PARAM_PTR is made to point to the parameter referred to.  If
-   a $ format is found, *FORMAT is updated to point just after it.  */
-
-static int
-maybe_read_dollar_number (status, format, dollar_needed, params, param_ptr,
-                         fki)
-     int *status;
-     const char **format;
-     int dollar_needed;
-     tree params;
-     tree *param_ptr;
-     const format_kind_info *fki;
-{
-  int argnum;
-  int overflow_flag;
-  const char *fcp = *format;
-  if (*fcp < '0' || *fcp > '9')
-    {
-      if (dollar_needed)
-       {
-         status_warning (status, "missing $ operand number in format");
-         return -1;
-       }
-      else
-       return 0;
-    }
-  argnum = 0;
-  overflow_flag = 0;
-  while (*fcp >= '0' && *fcp <= '9')
-    {
-      int nargnum;
-      nargnum = 10 * argnum + (*fcp - '0');
-      if (nargnum < 0 || nargnum / 10 != argnum)
-       overflow_flag = 1;
-      argnum = nargnum;
-      fcp++;
-    }
-  if (*fcp != '$')
-    {
-      if (dollar_needed)
-       {
-         status_warning (status, "missing $ operand number in format");
-         return -1;
-       }
-      else
-       return 0;
-    }
-  *format = fcp + 1;
-  if (pedantic && !dollar_format_warned)
-    {
-      status_warning (status,
-                     "%s does not support %%n$ operand number formats",
-                     C_STD_NAME (STD_EXT));
-      dollar_format_warned = 1;
-    }
-  if (overflow_flag || argnum == 0
-      || (dollar_first_arg_num && argnum > dollar_arguments_count))
-    {
-      status_warning (status, "operand number out of range in format");
-      return -1;
-    }
-  if (argnum > dollar_max_arg_used)
-    dollar_max_arg_used = argnum;
-  /* For vprintf-style functions we may need to allocate more memory to
-     track which arguments are used.  */
-  while (dollar_arguments_alloc < dollar_max_arg_used)
-    {
-      int nalloc;
-      nalloc = 2 * dollar_arguments_alloc + 16;
-      dollar_arguments_used = xrealloc (dollar_arguments_used, nalloc);
-      memset (dollar_arguments_used + dollar_arguments_alloc, 0,
-             nalloc - dollar_arguments_alloc);
-      dollar_arguments_alloc = nalloc;
-    }
-  if (!(fki->flags & FMT_FLAG_DOLLAR_MULTIPLE)
-      && dollar_arguments_used[argnum - 1] == 1)
-    {
-      dollar_arguments_used[argnum - 1] = 2;
-      status_warning (status,
-                     "format argument %d used more than once in %s format",
-                     argnum, fki->name);
-    }
-  else
-    dollar_arguments_used[argnum - 1] = 1;
-  if (dollar_first_arg_num)
-    {
-      int i;
-      *param_ptr = params;
-      for (i = 1; i < argnum && *param_ptr != 0; i++)
-       *param_ptr = TREE_CHAIN (*param_ptr);
-
-      if (*param_ptr == 0)
-       {
-         /* This case shouldn't be caught here.  */
-         abort ();
-       }
-    }
-  else
-    *param_ptr = 0;
-  return argnum;
-}
-
-
-/* Finish the checking for a format string that used $ operand number formats
-   instead of non-$ formats.  We check for unused operands before used ones
-   (a serious error, since the implementation of the format function
-   can't know what types to pass to va_arg to find the later arguments).
-   and for unused operands at the end of the format (if we know how many
-   arguments the format had, so not for vprintf).  If there were operand
-   numbers out of range on a non-vprintf-style format, we won't have reached
-   here.  */
-
-static void
-finish_dollar_format_checking (status, res)
-     int *status;
-     format_check_results *res;
-{
-  int i;
-  for (i = 0; i < dollar_max_arg_used; i++)
-    {
-      if (!dollar_arguments_used[i])
-       status_warning (status, "format argument %d unused before used argument %d in $-style format",
-                i + 1, dollar_max_arg_used);
-    }
-  if (dollar_first_arg_num && dollar_max_arg_used < dollar_arguments_count)
-    {
-      res->number_other--;
-      res->number_dollar_extra_args++;
-    }
-}
-
-
-/* Retrieve the specification for a format flag.  SPEC contains the
-   specifications for format flags for the applicable kind of format.
-   FLAG is the flag in question.  If PREDICATES is NULL, the basic
-   spec for that flag must be retrieved and this function aborts if
-   it cannot be found.  If PREDICATES is not NULL, it is a string listing
-   possible predicates for the spec entry; if an entry predicated on any
-   of these is found, it is returned, otherwise NULL is returned.  */
-
-static const format_flag_spec *
-get_flag_spec (spec, flag, predicates)
-     const format_flag_spec *spec;
-     int flag;
-     const char *predicates;
-{
-  int i;
-  for (i = 0; spec[i].flag_char != 0; i++)
-    {
-      if (spec[i].flag_char != flag)
-       continue;
-      if (predicates != NULL)
-       {
-         if (spec[i].predicate != 0
-             && strchr (predicates, spec[i].predicate) != 0)
-           return &spec[i];
-       }
-      else if (spec[i].predicate == 0)
-       return &spec[i];
-    }
-  if (predicates == NULL)
-    abort ();
-  else
-    return NULL;
-}
-
-
-/* Check the argument list of a call to printf, scanf, etc.
-   INFO points to the function_format_info structure.
-   PARAMS is the list of argument values.  */
-
-static void
-check_format_info (status, info, params)
-     int *status;
-     function_format_info *info;
-     tree params;
-{
-  int arg_num;
-  tree format_tree;
-  format_check_results res;
-  /* Skip to format argument.  If the argument isn't available, there's
-     no work for us to do; prototype checking will catch the problem.  */
-  for (arg_num = 1; ; ++arg_num)
-    {
-      if (params == 0)
-       return;
-      if (arg_num == info->format_num)
-       break;
-      params = TREE_CHAIN (params);
-    }
-  format_tree = TREE_VALUE (params);
-  params = TREE_CHAIN (params);
-  if (format_tree == 0)
-    return;
-
-  res.number_non_literal = 0;
-  res.number_extra_args = 0;
-  res.number_dollar_extra_args = 0;
-  res.number_wide = 0;
-  res.number_empty = 0;
-  res.number_unterminated = 0;
-  res.number_other = 0;
-
-  check_format_info_recurse (status, &res, info, format_tree, params, arg_num);
-
-  if (res.number_non_literal > 0)
-    {
-      /* Functions taking a va_list normally pass a non-literal format
-        string.  These functions typically are declared with
-        first_arg_num == 0, so avoid warning in those cases.  */
-      if (!(format_types[info->format_type].flags & FMT_FLAG_ARG_CONVERT))
-       {
-         /* For strftime-like formats, warn for not checking the format
-            string; but there are no arguments to check.  */
-         if (warn_format_nonliteral)
-           status_warning (status, "format not a string literal, format string not checked");
-       }
-      else if (info->first_arg_num != 0)
-       {
-         /* If there are no arguments for the format at all, we may have
-            printf (foo) which is likely to be a security hole.  */
-         while (arg_num + 1 < info->first_arg_num)
-           {
-             if (params == 0)
-               break;
-             params = TREE_CHAIN (params);
-             ++arg_num;
-           }
-         if (params == 0 && (warn_format_nonliteral || warn_format_security))
-           status_warning (status, "format not a string literal and no format arguments");
-         else if (warn_format_nonliteral)
-           status_warning (status, "format not a string literal, argument types not checked");
-       }
-    }
-
-  /* If there were extra arguments to the format, normally warn.  However,
-     the standard does say extra arguments are ignored, so in the specific
-     case where we have multiple leaves (conditional expressions or
-     ngettext) allow extra arguments if at least one leaf didn't have extra
-     arguments, but was otherwise OK (either non-literal or checked OK).
-     If the format is an empty string, this should be counted similarly to the
-     case of extra format arguments.  */
-  if (res.number_extra_args > 0 && res.number_non_literal == 0
-      && res.number_other == 0 && warn_format_extra_args)
-    status_warning (status, "too many arguments for format");
-  if (res.number_dollar_extra_args > 0 && res.number_non_literal == 0
-      && res.number_other == 0 && warn_format_extra_args)
-    status_warning (status, "unused arguments in $-style format");
-  if (res.number_empty > 0 && res.number_non_literal == 0
-      && res.number_other == 0)
-    status_warning (status, "zero-length format string");
-
-  if (res.number_wide > 0)
-    status_warning (status, "format is a wide character string");
-
-  if (res.number_unterminated > 0)
-    status_warning (status, "unterminated format string");
-}
-
-
-/* Recursively check a call to a format function.  FORMAT_TREE is the
-   format parameter, which may be a conditional expression in which
-   both halves should be checked.  ARG_NUM is the number of the
-   format argument; PARAMS points just after it in the argument list.  */
-
-static void
-check_format_info_recurse (status, res, info, format_tree, params, arg_num)
-     int *status;
-     format_check_results *res;
-     function_format_info *info;
-     tree format_tree;
-     tree params;
-     int arg_num;
-{
-  int format_length;
-  const char *format_chars;
-  tree array_size = 0;
-  tree array_init;
-
-  if (TREE_CODE (format_tree) == NOP_EXPR)
-    {
-      /* Strip coercion.  */
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 0), params,
-                                arg_num);
-      return;
-    }
-
-  if (TREE_CODE (format_tree) == CALL_EXPR
-      && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR
-      && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0))
-         == FUNCTION_DECL))
-    {
-      tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0);
-
-      /* See if this is a call to a known internationalization function
-        that modifies the format arg.  */
-      international_format_info *iinfo;
-
-      for (iinfo = international_format_list; iinfo; iinfo = iinfo->next)
-       if (iinfo->assembler_name
-           ? (iinfo->assembler_name == DECL_ASSEMBLER_NAME (function))
-           : (iinfo->name == DECL_NAME (function)))
-         {
-           tree inner_args;
-           int i;
-
-           for (inner_args = TREE_OPERAND (format_tree, 1), i = 1;
-                inner_args != 0;
-                inner_args = TREE_CHAIN (inner_args), i++)
-             if (i == iinfo->format_num)
-               {
-                 /* FIXME: with Marc Espie's __attribute__((nonnull))
-                    patch in GCC, we will have chained attributes,
-                    and be able to handle functions like ngettext
-                    with multiple format_arg attributes properly.  */
-                 check_format_info_recurse (status, res, info,
-                                            TREE_VALUE (inner_args), params,
-                                            arg_num);
-                 return;
-               }
-         }
-    }
-
-  if (TREE_CODE (format_tree) == COND_EXPR)
-    {
-      /* Check both halves of the conditional expression.  */
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 1), params,
-                                arg_num);
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 2), params,
-                                arg_num);
-      return;
-    }
-
-  if (integer_zerop (format_tree))
-    {
-      /* FIXME: this warning should go away once Marc Espie's
-        __attribute__((nonnull)) patch is in.  Instead, checking for
-        nonnull attributes should probably change this function to act
-        specially if info == NULL and add a res->number_null entry for
-        that case, or maybe add a function pointer to be called at
-        the end instead of hardcoding check_format_info_main.  */
-      status_warning (status, "null format string");
-
-      /* Skip to first argument to check, so we can see if this format
-        has any arguments (it shouldn't).  */
-      while (arg_num + 1 < info->first_arg_num)
-       {
-         if (params == 0)
-           return;
-         params = TREE_CHAIN (params);
-         ++arg_num;
-       }
-
-      if (params == 0)
-       res->number_other++;
-      else
-       res->number_extra_args++;
-
-      return;
-    }
-
-  if (TREE_CODE (format_tree) != ADDR_EXPR)
-    {
-      res->number_non_literal++;
-      return;
-    }
-  format_tree = TREE_OPERAND (format_tree, 0);
-  if (TREE_CODE (format_tree) == VAR_DECL
-      && TREE_CODE (TREE_TYPE (format_tree)) == ARRAY_TYPE
-      && (array_init = decl_constant_value (format_tree)) != format_tree
-      && TREE_CODE (array_init) == STRING_CST)
-    {
-      /* Extract the string constant initializer.  Note that this may include
-        a trailing NUL character that is not in the array (e.g.
-        const char a[3] = "foo";).  */
-      array_size = DECL_SIZE_UNIT (format_tree);
-      format_tree = array_init;
-    }
-  if (TREE_CODE (format_tree) != STRING_CST)
-    {
-      res->number_non_literal++;
-      return;
-    }
-  if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (format_tree))) != char_type_node)
-    {
-      res->number_wide++;
-      return;
-    }
-  format_chars = TREE_STRING_POINTER (format_tree);
-  format_length = TREE_STRING_LENGTH (format_tree);
-  if (array_size != 0)
-    {
-      /* Variable length arrays can't be initialized.  */
-      if (TREE_CODE (array_size) != INTEGER_CST)
-       abort ();
-      if (host_integerp (array_size, 0))
-       {
-         HOST_WIDE_INT array_size_value = TREE_INT_CST_LOW (array_size);
-         if (array_size_value > 0
-             && array_size_value == (int) array_size_value
-             && format_length > array_size_value)
-           format_length = array_size_value;
-       }
-    }
-  if (format_length < 1)
-    {
-      res->number_unterminated++;
-      return;
-    }
-  if (format_length == 1)
-    {
-      res->number_empty++;
-      return;
-    }
-  if (format_chars[--format_length] != 0)
-    {
-      res->number_unterminated++;
-      return;
-    }
-
-  /* Skip to first argument to check.  */
-  while (arg_num + 1 < info->first_arg_num)
-    {
-      if (params == 0)
-       return;
-      params = TREE_CHAIN (params);
-      ++arg_num;
-    }
-  /* Provisionally increment res->number_other; check_format_info_main
-     will decrement it if it finds there are extra arguments, but this way
-     need not adjust it for every return.  */
-  res->number_other++;
-  check_format_info_main (status, res, info, format_chars, format_length,
-                         params, arg_num);
-}
-
-
-/* Do the main part of checking a call to a format function.  FORMAT_CHARS
-   is the NUL-terminated format string (which at this point may contain
-   internal NUL characters); FORMAT_LENGTH is its length (excluding the
-   terminating NUL character).  ARG_NUM is one less than the number of
-   the first format argument to check; PARAMS points to that format
-   argument in the list of arguments.  */
-
-static void
-check_format_info_main (status, res, info, format_chars, format_length,
-                       params, arg_num)
-     int *status;
-     format_check_results *res;
-     function_format_info *info;
-     const char *format_chars;
-     int format_length;
-     tree params;
-     int arg_num;
-{
-  const char *orig_format_chars = format_chars;
-  tree first_fillin_param = params;
-
-  const format_kind_info *fki = &format_types[info->format_type];
-  const format_flag_spec *flag_specs = fki->flag_specs;
-  const format_flag_pair *bad_flag_pairs = fki->bad_flag_pairs;
-
-  /* -1 if no conversions taking an operand have been found; 0 if one has
-     and it didn't use $; 1 if $ formats are in use.  */
-  int has_operand_number = -1;
-
-  init_dollar_format_checking (info->first_arg_num, first_fillin_param);
-
-  while (1)
-    {
-      int i;
-      int suppressed = FALSE;
-      const char *length_chars = NULL;
-      enum format_lengths length_chars_val = FMT_LEN_none;
-      enum format_std_version length_chars_std = STD_C89;
-      int format_char;
-      tree cur_param;
-      tree wanted_type;
-      int main_arg_num = 0;
-      tree main_arg_params = 0;
-      enum format_std_version wanted_type_std;
-      const char *wanted_type_name;
-      format_wanted_type width_wanted_type;
-      format_wanted_type precision_wanted_type;
-      format_wanted_type main_wanted_type;
-      format_wanted_type *first_wanted_type = NULL;
-      format_wanted_type *last_wanted_type = NULL;
-      const format_length_info *fli = NULL;
-      const format_char_info *fci = NULL;
-      char flag_chars[256];
-      int aflag = 0;
-      if (*format_chars == 0)
-       {
-         if (format_chars - orig_format_chars != format_length)
-           status_warning (status, "embedded `\\0' in format");
-         if (info->first_arg_num != 0 && params != 0
-             && has_operand_number <= 0)
-           {
-             res->number_other--;
-             res->number_extra_args++;
-           }
-         if (has_operand_number > 0)
-           finish_dollar_format_checking (status, res);
-         return;
-       }
-      if (*format_chars++ != '%')
-       continue;
-      if (*format_chars == 0)
-       {
-         status_warning (status, "spurious trailing `%%' in format");
-         continue;
-       }
-      if (*format_chars == '%')
-       {
-         ++format_chars;
-         continue;
-       }
-      flag_chars[0] = 0;
-
-      if ((fki->flags & FMT_FLAG_ARG_CONVERT) && has_operand_number != 0)
-       {
-         /* Possibly read a $ operand number at the start of the format.
-            If one was previously used, one is required here.  If one
-            is not used here, we can't immediately conclude this is a
-            format without them, since it could be printf %m or scanf %*.  */
-         int opnum;
-         opnum = maybe_read_dollar_number (status, &format_chars, 0,
-                                           first_fillin_param,
-                                           &main_arg_params, fki);
-         if (opnum == -1)
-           return;
-         else if (opnum > 0)
-           {
-             has_operand_number = 1;
-             main_arg_num = opnum + info->first_arg_num - 1;
-           }
-       }
-
-      /* Read any format flags, but do not yet validate them beyond removing
-        duplicates, since in general validation depends on the rest of
-        the format.  */
-      while (*format_chars != 0
-            && strchr (fki->flag_chars, *format_chars) != 0)
-       {
-         if (strchr (flag_chars, *format_chars) != 0)
-           {
-             const format_flag_spec *s = get_flag_spec (flag_specs,
-                                                        *format_chars, NULL);
-             status_warning (status, "repeated %s in format", _(s->name));
-           }
-         else
-           {
-             i = strlen (flag_chars);
-             flag_chars[i++] = *format_chars;
-             flag_chars[i] = 0;
-           }
-         ++format_chars;
-       }
-
-      /* Read any format width, possibly * or *m$.  */
-      if (fki->width_char != 0)
-       {
-         if (fki->width_type != NULL && *format_chars == '*')
-           {
-             i = strlen (flag_chars);
-             flag_chars[i++] = fki->width_char;
-             flag_chars[i] = 0;
-             /* "...a field width...may be indicated by an asterisk.
-                In this case, an int argument supplies the field width..."  */
-             ++format_chars;
-             if (params == 0)
-               {
-                 status_warning (status, "too few arguments for format");
-                 return;
-               }
-             if (has_operand_number != 0)
-               {
-                 int opnum;
-                 opnum = maybe_read_dollar_number (status, &format_chars,
-                                                   has_operand_number == 1,
-                                                   first_fillin_param,
-                                                   &params, fki);
-                 if (opnum == -1)
-                   return;
-                 else if (opnum > 0)
-                   {
-                     has_operand_number = 1;
-                     arg_num = opnum + info->first_arg_num - 1;
-                   }
-                 else
-                   has_operand_number = 0;
-               }
-             if (info->first_arg_num != 0)
-               {
-                 cur_param = TREE_VALUE (params);
-                 if (has_operand_number <= 0)
-                   {
-                     params = TREE_CHAIN (params);
-                     ++arg_num;
-                   }
-                 width_wanted_type.wanted_type = *fki->width_type;
-                 width_wanted_type.wanted_type_name = NULL;
-                 width_wanted_type.pointer_count = 0;
-                 width_wanted_type.char_lenient_flag = 0;
-                 width_wanted_type.writing_in_flag = 0;
-                 width_wanted_type.reading_from_flag = 0;
-                 width_wanted_type.name = _("field width");
-                 width_wanted_type.param = cur_param;
-                 width_wanted_type.arg_num = arg_num;
-                 width_wanted_type.next = NULL;
-                 if (last_wanted_type != 0)
-                   last_wanted_type->next = &width_wanted_type;
-                 if (first_wanted_type == 0)
-                   first_wanted_type = &width_wanted_type;
-                 last_wanted_type = &width_wanted_type;
-               }
-           }
-         else
-           {
-             /* Possibly read a numeric width.  If the width is zero,
-                we complain; for scanf this is bad according to the
-                standard, and for printf and strftime it cannot occur
-                because 0 is a flag.  */
-             int non_zero_width_char = FALSE;
-             int found_width = FALSE;
-             while (ISDIGIT (*format_chars))
-               {
-                 found_width = TRUE;
-                 if (*format_chars != '0')
-                   non_zero_width_char = TRUE;
-                 ++format_chars;
-               }
-             if (found_width && !non_zero_width_char)
-               status_warning (status, "zero width in %s format",
-                               fki->name);
-             if (found_width)
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = fki->width_char;
-                 flag_chars[i] = 0;
-               }
-           }
-       }
-
-      /* Read any format precision, possibly * or *m$.  */
-      if (fki->precision_char != 0 && *format_chars == '.')
-       {
-         ++format_chars;
-         i = strlen (flag_chars);
-         flag_chars[i++] = fki->precision_char;
-         flag_chars[i] = 0;
-         if (fki->precision_type != NULL && *format_chars == '*')
-           {
-             /* "...a...precision...may be indicated by an asterisk.
-                In this case, an int argument supplies the...precision."  */
-             ++format_chars;
-             if (has_operand_number != 0)
-               {
-                 int opnum;
-                 opnum = maybe_read_dollar_number (status, &format_chars,
-                                                   has_operand_number == 1,
-                                                   first_fillin_param,
-                                                   &params, fki);
-                 if (opnum == -1)
-                   return;
-                 else if (opnum > 0)
-                   {
-                     has_operand_number = 1;
-                     arg_num = opnum + info->first_arg_num - 1;
-                   }
-                 else
-                   has_operand_number = 0;
-               }
-             if (info->first_arg_num != 0)
-               {
-                 if (params == 0)
-                   {
-                     status_warning (status, "too few arguments for format");
-                     return;
-                   }
-                 cur_param = TREE_VALUE (params);
-                 if (has_operand_number <= 0)
-                   {
-                     params = TREE_CHAIN (params);
-                     ++arg_num;
-                   }
-                 precision_wanted_type.wanted_type = *fki->precision_type;
-                 precision_wanted_type.wanted_type_name = NULL;
-                 precision_wanted_type.pointer_count = 0;
-                 precision_wanted_type.char_lenient_flag = 0;
-                 precision_wanted_type.writing_in_flag = 0;
-                 precision_wanted_type.reading_from_flag = 0;
-                 precision_wanted_type.name = _("field precision");
-                 precision_wanted_type.param = cur_param;
-                 precision_wanted_type.arg_num = arg_num;
-                 precision_wanted_type.next = NULL;
-                 if (last_wanted_type != 0)
-                   last_wanted_type->next = &precision_wanted_type;
-                 if (first_wanted_type == 0)
-                   first_wanted_type = &precision_wanted_type;
-                 last_wanted_type = &precision_wanted_type;
-               }
-           }
-         else
-           {
-             while (ISDIGIT (*format_chars))
-               ++format_chars;
-           }
-       }
-
-      /* Read any length modifier, if this kind of format has them.  */
-      fli = fki->length_char_specs;
-      length_chars = NULL;
-      length_chars_val = FMT_LEN_none;
-      length_chars_std = STD_C89;
-      if (fli)
-       {
-         while (fli->name != 0 && fli->name[0] != *format_chars)
-           fli++;
-         if (fli->name != 0)
-           {
-             format_chars++;
-             if (fli->double_name != 0 && fli->name[0] == *format_chars)
-               {
-                 format_chars++;
-                 length_chars = fli->double_name;
-                 length_chars_val = fli->double_index;
-                 length_chars_std = fli->double_std;
-               }
-             else
-               {
-                 length_chars = fli->name;
-                 length_chars_val = fli->index;
-                 length_chars_std = fli->std;
-               }
-             i = strlen (flag_chars);
-             flag_chars[i++] = fki->length_code_char;
-             flag_chars[i] = 0;
-           }
-         if (pedantic)
-           {
-             /* Warn if the length modifier is non-standard.  */
-             if (ADJ_STD (length_chars_std) > C_STD_VER)
-               status_warning (status, "%s does not support the `%s' %s length modifier",
-                               C_STD_NAME (length_chars_std), length_chars,
-                               fki->name);
-           }
-       }
-
-      /* Read any modifier (strftime E/O).  */
-      if (fki->modifier_chars != NULL)
-       {
-         while (*format_chars != 0
-                && strchr (fki->modifier_chars, *format_chars) != 0)
-           {
-             if (strchr (flag_chars, *format_chars) != 0)
-               {
-                 const format_flag_spec *s = get_flag_spec (flag_specs,
-                                                            *format_chars, NULL);
-                 status_warning (status, "repeated %s in format", _(s->name));
-               }
-             else
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = *format_chars;
-                 flag_chars[i] = 0;
-               }
-             ++format_chars;
-           }
-       }
-
-      /* Handle the scanf allocation kludge.  */
-      if (fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
-       {
-         if (*format_chars == 'a' && !flag_isoc99)
-           {
-             if (format_chars[1] == 's' || format_chars[1] == 'S'
-                 || format_chars[1] == '[')
-               {
-                 /* `a' is used as a flag.  */
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = 'a';
-                 flag_chars[i] = 0;
-                 format_chars++;
-               }
-           }
-       }
-
-      format_char = *format_chars;
-      if (format_char == 0
-         || (!(fki->flags & FMT_FLAG_FANCY_PERCENT_OK) && format_char == '%'))
-       {
-         status_warning (status, "conversion lacks type at end of format");
-         continue;
-       }
-      format_chars++;
-      fci = fki->conversion_specs;
-      while (fci->format_chars != 0
-            && strchr (fci->format_chars, format_char) == 0)
-         ++fci;
-      if (fci->format_chars == 0)
-       {
-          if (ISGRAPH(format_char))
-           status_warning (status, "unknown conversion type character `%c' in format",
-                    format_char);
-         else
-           status_warning (status, "unknown conversion type character 0x%x in format",
-                    format_char);
-         continue;
-       }
-      if (pedantic)
-       {
-         if (ADJ_STD (fci->std) > C_STD_VER)
-           status_warning (status, "%s does not support the `%%%c' %s format",
-                           C_STD_NAME (fci->std), format_char, fki->name);
-       }
-
-      /* Validate the individual flags used, removing any that are invalid.  */
-      {
-       int d = 0;
-       for (i = 0; flag_chars[i] != 0; i++)
-         {
-           const format_flag_spec *s = get_flag_spec (flag_specs,
-                                                      flag_chars[i], NULL);
-           flag_chars[i - d] = flag_chars[i];
-           if (flag_chars[i] == fki->length_code_char)
-             continue;
-           if (strchr (fci->flag_chars, flag_chars[i]) == 0)
-             {
-               status_warning (status, "%s used with `%%%c' %s format",
-                               _(s->name), format_char, fki->name);
-               d++;
-               continue;
-             }
-           if (pedantic)
-             {
-               const format_flag_spec *t;
-               if (ADJ_STD (s->std) > C_STD_VER)
-                 status_warning (status, "%s does not support %s",
-                                 C_STD_NAME (s->std), _(s->long_name));
-               t = get_flag_spec (flag_specs, flag_chars[i], fci->flags2);
-               if (t != NULL && ADJ_STD (t->std) > ADJ_STD (s->std))
-                 {
-                   const char *long_name = (t->long_name != NULL
-                                            ? t->long_name
-                                            : s->long_name);
-                   if (ADJ_STD (t->std) > C_STD_VER)
-                     status_warning (status, "%s does not support %s with the `%%%c' %s format",
-                                     C_STD_NAME (t->std), _(long_name),
-                                     format_char, fki->name);
-                 }
-             }
-         }
-       flag_chars[i - d] = 0;
-      }
-
-      if ((fki->flags & FMT_FLAG_SCANF_A_KLUDGE)
-         && strchr (flag_chars, 'a') != 0)
-       aflag = 1;
-
-      if (fki->suppression_char
-         && strchr (flag_chars, fki->suppression_char) != 0)
-       suppressed = 1;
-
-      /* Validate the pairs of flags used.  */
-      for (i = 0; bad_flag_pairs[i].flag_char1 != 0; i++)
-       {
-         const format_flag_spec *s, *t;
-         if (strchr (flag_chars, bad_flag_pairs[i].flag_char1) == 0)
-           continue;
-         if (strchr (flag_chars, bad_flag_pairs[i].flag_char2) == 0)
-           continue;
-         if (bad_flag_pairs[i].predicate != 0
-             && strchr (fci->flags2, bad_flag_pairs[i].predicate) == 0)
-           continue;
-         s = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char1, NULL);
-         t = get_flag_spec (flag_specs, bad_flag_pairs[i].flag_char2, NULL);
-         if (bad_flag_pairs[i].ignored)
-           {
-             if (bad_flag_pairs[i].predicate != 0)
-               status_warning (status, "%s ignored with %s and `%%%c' %s format",
-                               _(s->name), _(t->name), format_char,
-                               fki->name);
-             else
-               status_warning (status, "%s ignored with %s in %s format",
-                               _(s->name), _(t->name), fki->name);
-           }
-         else
-           {
-             if (bad_flag_pairs[i].predicate != 0)
-               status_warning (status, "use of %s and %s together with `%%%c' %s format",
-                               _(s->name), _(t->name), format_char,
-                               fki->name);
-             else
-               status_warning (status, "use of %s and %s together in %s format",
-                               _(s->name), _(t->name), fki->name);
-           }
-       }
-
-      /* Give Y2K warnings.  */
-      if (warn_format_y2k)
-       {
-         int y2k_level = 0;
-         if (strchr (fci->flags2, '4') != 0)
-           if (strchr (flag_chars, 'E') != 0)
-             y2k_level = 3;
-           else
-             y2k_level = 2;
-         else if (strchr (fci->flags2, '3') != 0)
-           y2k_level = 3;
-         else if (strchr (fci->flags2, '2') != 0)
-           y2k_level = 2;
-         if (y2k_level == 3)
-           status_warning (status, "`%%%c' yields only last 2 digits of year in some locales",
-                           format_char);
-         else if (y2k_level == 2)
-           status_warning (status, "`%%%c' yields only last 2 digits of year", format_char);
-       }
-
-      if (strchr (fci->flags2, '[') != 0)
-       {
-         /* Skip over scan set, in case it happens to have '%' in it.  */
-         if (*format_chars == '^')
-           ++format_chars;
-         /* Find closing bracket; if one is hit immediately, then
-            it's part of the scan set rather than a terminator.  */
-         if (*format_chars == ']')
-           ++format_chars;
-         while (*format_chars && *format_chars != ']')
-           ++format_chars;
-         if (*format_chars != ']')
-           /* The end of the format string was reached.  */
-           status_warning (status, "no closing `]' for `%%[' format");
-       }
-
-      wanted_type = 0;
-      wanted_type_name = 0;
-      if (fki->flags & FMT_FLAG_ARG_CONVERT)
-       {
-         wanted_type = (fci->types[length_chars_val].type
-                        ? *fci->types[length_chars_val].type : 0);
-         wanted_type_name = fci->types[length_chars_val].name;
-         wanted_type_std = fci->types[length_chars_val].std;
-         if (wanted_type == 0)
-           {
-             status_warning (status, "use of `%s' length modifier with `%c' type character",
-                             length_chars, format_char);
-             /* Heuristic: skip one argument when an invalid length/type
-                combination is encountered.  */
-             arg_num++;
-             if (params == 0)
-               {
-                 status_warning (status, "too few arguments for format");
-                 return;
-               }
-             params = TREE_CHAIN (params);
-             continue;
-           }
-         else if (pedantic
-                  /* Warn if non-standard, provided it is more non-standard
-                     than the length and type characters that may already
-                     have been warned for.  */
-                  && ADJ_STD (wanted_type_std) > ADJ_STD (length_chars_std)
-                  && ADJ_STD (wanted_type_std) > ADJ_STD (fci->std))
-           {
-             if (ADJ_STD (wanted_type_std) > C_STD_VER)
-               status_warning (status, "%s does not support the `%%%s%c' %s format",
-                               C_STD_NAME (wanted_type_std), length_chars,
-                               format_char, fki->name);
-           }
-       }
-
-      /* Finally. . .check type of argument against desired type!  */
-      if (info->first_arg_num == 0)
-       continue;
-      if ((fci->pointer_count == 0 && wanted_type == void_type_node)
-         || suppressed)
-       {
-         if (main_arg_num != 0)
-           {
-             if (suppressed)
-               status_warning (status, "operand number specified with suppressed assignment");
-             else
-               status_warning (status, "operand number specified for format taking no argument");
-           }
-       }
-      else
-       {
-         if (main_arg_num != 0)
-           {
-             arg_num = main_arg_num;
-             params = main_arg_params;
-           }
-         else
-           {
-             ++arg_num;
-             if (has_operand_number > 0)
-               {
-                 status_warning (status, "missing $ operand number in format");
-                 return;
-               }
-             else
-               has_operand_number = 0;
-             if (params == 0)
-               {
-                 status_warning (status, "too few arguments for format");
-                 return;
-               }
-           }
-         cur_param = TREE_VALUE (params);
-         params = TREE_CHAIN (params);
-         main_wanted_type.wanted_type = wanted_type;
-         main_wanted_type.wanted_type_name = wanted_type_name;
-         main_wanted_type.pointer_count = fci->pointer_count + aflag;
-         main_wanted_type.char_lenient_flag = 0;
-         if (strchr (fci->flags2, 'c') != 0)
-           main_wanted_type.char_lenient_flag = 1;
-         main_wanted_type.writing_in_flag = 0;
-         main_wanted_type.reading_from_flag = 0;
-         if (aflag)
-           main_wanted_type.writing_in_flag = 1;
-         else
-           {
-             if (strchr (fci->flags2, 'W') != 0)
-               main_wanted_type.writing_in_flag = 1;
-             if (strchr (fci->flags2, 'R') != 0)
-               main_wanted_type.reading_from_flag = 1;
-           }
-         main_wanted_type.name = NULL;
-         main_wanted_type.param = cur_param;
-         main_wanted_type.arg_num = arg_num;
-         main_wanted_type.next = NULL;
-         if (last_wanted_type != 0)
-           last_wanted_type->next = &main_wanted_type;
-         if (first_wanted_type == 0)
-           first_wanted_type = &main_wanted_type;
-         last_wanted_type = &main_wanted_type;
-       }
-
-      if (first_wanted_type != 0)
-       check_format_types (status, first_wanted_type);
-
-    }
-}
+       }
 
+      /* 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;
 
-/* Check the argument types from a single format conversion (possibly
-   including width and precision arguments).  */
-static void
-check_format_types (status, types)
-     int *status;
-     format_wanted_type *types;
-{
-  for (; types != 0; types = types->next)
-    {
-      tree cur_param;
-      tree cur_type;
-      tree orig_cur_type;
-      tree wanted_type;
-      tree promoted_type;
-      int arg_num;
-      int i;
-      int char_type_flag;
-      cur_param = types->param;
-      cur_type = TREE_TYPE (cur_param);
-      if (cur_type == error_mark_node)
-       continue;
-      char_type_flag = 0;
-      wanted_type = types->wanted_type;
-      arg_num = types->arg_num;
-
-      /* The following should not occur here.  */
-      if (wanted_type == 0)
-       abort ();
-      if (wanted_type == void_type_node && types->pointer_count == 0)
-       abort ();
-
-      if (types->pointer_count == 0)
-       {
-         promoted_type = simple_type_promotes_to (wanted_type);
-         if (promoted_type != NULL_TREE)
-           wanted_type = promoted_type;
-       }
+      p = alloca (length);
 
-      STRIP_NOPS (cur_param);
+      /* 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.  */
 
-      /* Check the types of any additional pointer arguments
-        that precede the "real" argument.  */
-      for (i = 0; i < types->pointer_count; ++i)
+      q = p;
+      for (t = strings; t; t = TREE_CHAIN (t))
        {
-         if (TREE_CODE (cur_type) == POINTER_TYPE)
+         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)
            {
-             cur_type = TREE_TYPE (cur_type);
-             if (cur_type == error_mark_node)
-               break;
-
-             /* Check for writing through a NULL pointer.  */
-             if (types->writing_in_flag
-                 && i == 0
-                 && cur_param != 0
-                 && integer_zerop (cur_param))
-               status_warning (status,
-                               "writing through null pointer (arg %d)",
-                               arg_num);
-
-             /* Check for reading through a NULL pointer.  */
-             if (types->reading_from_flag
-                 && i == 0
-                 && cur_param != 0
-                 && integer_zerop (cur_param))
-               status_warning (status,
-                               "reading through null pointer (arg %d)",
-                               arg_num);
-
-             if (cur_param != 0 && TREE_CODE (cur_param) == ADDR_EXPR)
-               cur_param = TREE_OPERAND (cur_param, 0);
-             else
-               cur_param = 0;
-
-             /* See if this is an attempt to write into a const type with
-                scanf or with printf "%n".  Note: the writing in happens
-                at the first indirection only, if for example
-                void * const * is passed to scanf %p; passing
-                const void ** is simply passing an incompatible type.  */
-             if (types->writing_in_flag
-                 && i == 0
-                 && (TYPE_READONLY (cur_type)
-                     || (cur_param != 0
-                         && (TREE_CODE_CLASS (TREE_CODE (cur_param)) == 'c'
-                             || (DECL_P (cur_param)
-                                 && TREE_READONLY (cur_param))))))
-               status_warning (status, "writing into constant object (arg %d)", arg_num);
-
-             /* If there are extra type qualifiers beyond the first
-                indirection, then this makes the types technically
-                incompatible.  */
-             if (i > 0
-                 && pedantic
-                 && (TYPE_READONLY (cur_type)
-                     || TYPE_VOLATILE (cur_type)
-                     || TYPE_RESTRICT (cur_type)))
-               status_warning (status, "extra type qualifiers in format argument (arg %d)",
-                        arg_num);
-
+             memcpy (q, TREE_STRING_POINTER (t), len);
+             q += len;
            }
          else
            {
-             if (types->pointer_count == 1)
-               status_warning (status, "format argument is not a pointer (arg %d)", arg_num);
-             else
-               status_warning (status, "format argument is not a pointer to a pointer (arg %d)", arg_num);
-             break;
+             int i, j;
+             for (i = 0; i < len; i++)
+               {
+                 if (BYTES_BIG_ENDIAN)
+                   {
+                     for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
+                       *q++ = 0;
+                     *q++ = TREE_STRING_POINTER (t)[i];
+                   }
+                 else
+                   {
+                     *q++ = TREE_STRING_POINTER (t)[i];
+                     for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
+                       *q++ = 0;
+                   }
+               }
            }
        }
+      if (wide_flag)
+       {
+         int i;
+         for (i = 0; i < wchar_bytes; i++)
+           *q++ = 0;
+       }
+      else
+       *q = 0;
 
-      if (i < types->pointer_count)
-       continue;
-
-      orig_cur_type = cur_type;
-      cur_type = TYPE_MAIN_VARIANT (cur_type);
-
-      /* Check whether the argument type is a character type.  This leniency
-        only applies to certain formats, flagged with 'c'.
-      */
-      if (types->char_lenient_flag)
-       char_type_flag = (cur_type == char_type_node
-                         || cur_type == signed_char_type_node
-                         || cur_type == unsigned_char_type_node);
-
-      /* Check the type of the "real" argument, if there's a type we want.  */
-      if (wanted_type == cur_type)
-       continue;
-      /* If we want `void *', allow any pointer type.
-        (Anything else would already have got a warning.)
-        With -pedantic, only allow pointers to void and to character
-        types.  */
-      if (wanted_type == void_type_node
-         && (!pedantic || (i == 1 && char_type_flag)))
-       continue;
-      /* Don't warn about differences merely in signedness, unless
-        -pedantic.  With -pedantic, warn if the type is a pointer
-        target and not a character type, and for character types at
-        a second level of indirection.  */
-      if (TREE_CODE (wanted_type) == INTEGER_TYPE
-         && TREE_CODE (cur_type) == INTEGER_TYPE
-         && (! pedantic || i == 0 || (i == 1 && char_type_flag))
-         && (TREE_UNSIGNED (wanted_type)
-             ? wanted_type == unsigned_type (cur_type)
-             : wanted_type == signed_type (cur_type)))
-       continue;
-      /* Likewise, "signed char", "unsigned char" and "char" are
-        equivalent but the above test won't consider them equivalent.  */
-      if (wanted_type == char_type_node
-         && (! pedantic || i < 2)
-         && char_type_flag)
-       continue;
-      /* Now we have a type mismatch.  */
-      {
-       register const char *this;
-       register const char *that;
-
-       this = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (wanted_type)));
-       that = 0;
-       if (TYPE_NAME (orig_cur_type) != 0
-           && TREE_CODE (orig_cur_type) != INTEGER_TYPE
-           && !(TREE_CODE (orig_cur_type) == POINTER_TYPE
-                && TREE_CODE (TREE_TYPE (orig_cur_type)) == INTEGER_TYPE))
-         {
-           if (TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL
-               && DECL_NAME (TYPE_NAME (orig_cur_type)) != 0)
-             that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
-           else
-             that = IDENTIFIER_POINTER (TYPE_NAME (orig_cur_type));
-         }
-
-       /* A nameless type can't possibly match what the format wants.
-          So there will be a warning for it.
-          Make up a string to describe vaguely what it is.  */
-       if (that == 0)
-         {
-           if (TREE_CODE (orig_cur_type) == POINTER_TYPE)
-             that = "pointer";
-           else
-             that = "different type";
-         }
-
-       /* Make the warning better in case of mismatch of int vs long.  */
-       if (TREE_CODE (orig_cur_type) == INTEGER_TYPE
-           && TREE_CODE (wanted_type) == INTEGER_TYPE
-           && TYPE_PRECISION (orig_cur_type) == TYPE_PRECISION (wanted_type)
-           && TYPE_NAME (orig_cur_type) != 0
-           && TREE_CODE (TYPE_NAME (orig_cur_type)) == TYPE_DECL)
-         that = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (orig_cur_type)));
-
-       if (strcmp (this, that) != 0)
-         {
-           /* There may be a better name for the format, e.g. size_t,
-              but we should allow for programs with a perverse typedef
-              making size_t something other than what the compiler
-              thinks.  */
-           if (types->wanted_type_name != 0
-               && strcmp (types->wanted_type_name, that) != 0)
-             this = types->wanted_type_name;
-           if (types->name != 0)
-             status_warning (status, "%s is not type %s (arg %d)", types->name, this,
-                      arg_num);
-           else
-             status_warning (status, "%s format, %s arg (arg %d)", this, that, arg_num);
-         }
-      }
+      value = build_string (length, p);
+    }
+  else
+    {
+      value = strings;
+      length = TREE_STRING_LENGTH (value);
+      if (TREE_TYPE (value) == wchar_array_type_node)
+       wide_flag = 1;
     }
-}
 
-/* Set format warning options according to a -Wformat=n option.  */
+  /* Compute the number of elements, for the array type.  */
+  nchars = wide_flag ? length / wchar_bytes : length;
 
-void
-set_Wformat (setting)
-     int setting;
-{
-  warn_format = setting;
-  warn_format_y2k = setting;
-  warn_format_extra_args = setting;
-  if (setting != 1)
+  if (pedantic && nchars - 1 > nchars_max && c_language == clk_c)
+    pedwarn ("string length `%d' is greater than the length `%d' ISO C%d compilers are required to support",
+            nchars - 1, nchars_max, flag_isoc99 ? 99 : 89);
+
+  /* Create the array type for the string constant.
+     -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_writable_strings)
     {
-      warn_format_nonliteral = setting;
-      warn_format_security = setting;
+      tree elements
+       = build_type_variant (wide_flag ? wchar_type_node : char_type_node,
+                             1, 0);
+      TREE_TYPE (value)
+       = build_array_type (elements,
+                           build_index_type (build_int_2 (nchars - 1, 0)));
     }
+  else
+    TREE_TYPE (value)
+      = build_array_type (wide_flag ? wchar_type_node : char_type_node,
+                         build_index_type (build_int_2 (nchars - 1, 0)));
+
+  TREE_CONSTANT (value) = 1;
+  TREE_READONLY (value) = ! flag_writable_strings;
+  TREE_STATIC (value) = 1;
+  return value;
 }
 \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, 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.
@@ -3445,6 +705,7 @@ constant_expression_warning (value)
      tree value;
 {
   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");
@@ -3479,6 +740,12 @@ overflow_warning (value)
       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");
+    }
 }
 
 /* Print a warning if a large constant is truncated to unsigned,
@@ -3490,13 +757,15 @@ void
 unsigned_conversion_warning (result, operand)
      tree result, operand;
 {
+  tree type = TREE_TYPE (result);
+
   if (TREE_CODE (operand) == INTEGER_CST
-      && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
-      && TREE_UNSIGNED (TREE_TYPE (result))
+      && TREE_CODE (type) == INTEGER_TYPE
+      && TREE_UNSIGNED (type)
       && skip_evaluation == 0
-      && !int_fits_type_p (operand, TREE_TYPE (result)))
+      && !int_fits_type_p (operand, type))
     {
-      if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
+      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)
@@ -3504,6 +773,20 @@ unsigned_conversion_warning (result, operand)
     }
 }
 
+/* Nonzero if constant C has a value that is permissible
+   for type TYPE (an INTEGER_TYPE).  */
+
+static int
+constant_fits_type_p (c, type)
+     tree c, type;
+{
+  if (TREE_CODE (c) == INTEGER_CST)
+    return int_fits_type_p (c, type);
+
+  c = convert (type, c);
+  return !TREE_OVERFLOW (c);
+}     
+
 /* 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.  */
@@ -3531,7 +814,8 @@ convert_and_check (type, expr)
               don't warn unless pedantic.  */
            if ((pedantic
                 || TREE_UNSIGNED (type)
-                || ! int_fits_type_p (expr, unsigned_type (type)))
+                || ! constant_fits_type_p (expr,
+                                           c_common_unsigned_type (type)))
                && skip_evaluation == 0)
              warning ("overflow in implicit constant conversion");
        }
@@ -3704,7 +988,7 @@ warn_for_collisions (list)
     }
 }
 
-/* Return nonzero if X is a tree that can be verified by the sequence poitn
+/* Return nonzero if X is a tree that can be verified by the sequence point
    warnings.  */
 static int
 warning_candidate_p (x)
@@ -3748,6 +1032,11 @@ verify_tree (x, pbefore_sp, pno_sp, writer)
   enum tree_code code;
   char class;
 
+  /* X may be NULL if it is the operand of an empty statement expression
+     ({ }).  */
+  if (x == NULL)
+    return;
+
  restart:
   code = TREE_CODE (x);
   class = TREE_CODE_CLASS (code);
@@ -3956,7 +1245,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);
 
@@ -4015,7 +1305,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;
 {
@@ -4059,7 +1349,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;
 {
@@ -4082,16 +1372,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
@@ -4115,24 +1405,40 @@ 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 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;
+       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);
@@ -4161,13 +1467,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);
@@ -4196,14 +1502,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;
 {
@@ -4225,6 +1531,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
@@ -4264,7 +1584,7 @@ void
 binary_op_error (code)
      enum tree_code code;
 {
-  register const char *opname;
+  const char *opname;
 
   switch (code)
     {
@@ -4343,7 +1663,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;
@@ -4376,8 +1696,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;
@@ -4438,19 +1758,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);
@@ -4547,7 +1868,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
              default:
                break;
              }
-         type = unsigned_type (type);
+         type = c_common_unsigned_type (type);
        }
 
       if (!max_gt && !unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
@@ -4599,15 +1920,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
     {
@@ -4630,7 +1955,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;
@@ -4639,7 +1964,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;
@@ -4668,6 +1993,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.
 
@@ -4731,7 +2157,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)))
@@ -4788,10 +2214,15 @@ truthvalue_conversion (expr)
       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:
@@ -4893,41 +2324,26 @@ 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;
-
+  
+  /* We know nothing about vector types */
+  if (TREE_CODE (t) == VECTOR_TYPE)
+    return 0;          
+  
   /* Permit type-punning when accessing a union, provided the access
      is directly through the union.  For example, this code does not
      permit taking the address of a union member and then storing
@@ -4957,7 +2373,7 @@ lang_get_alias_set (t)
      variant as canonical.  */
   if (TREE_CODE (t) == INTEGER_TYPE && TREE_UNSIGNED (t))
     {
-      tree t1 = signed_type (t);
+      tree t1 = c_common_signed_type (t);
 
       /* t1 == t can happen for boolean nodes which are always unsigned.  */
       if (t1 != t)
@@ -4974,7 +2390,7 @@ lang_get_alias_set (t)
 
         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++
+        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.
@@ -4984,7 +2400,7 @@ lang_get_alias_set (t)
 
             int *ip;
             int **ipp = &ip;
-            const int* const* cipp = &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
@@ -4994,13 +2410,102 @@ lang_get_alias_set (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;
 
   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
+/* Give the specifications for the format attributes, used by C and all
+   descendents.  */
+
+static const struct attribute_spec c_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 }
+};
 
 /* Build tree nodes and builtin functions common to both C and C++ language
    frontends.  */
@@ -5008,34 +2513,198 @@ lang_get_alias_set (t)
 void
 c_common_nodes_and_builtins ()
 {
-  tree temp;
-  tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree bzero_ftype, bcmp_ftype, puts_ftype, printf_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, sizet_ftype_any;
-  tree double_ftype_double, double_ftype_double_double;
-  tree float_ftype_float, ldouble_ftype_ldouble;
-  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;
+  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;
 
+  /* We must initialize this before any builtin functions (which might have
+     attributes) are declared.  (c_common_init is too late.)  */
+  format_attribute_table = c_format_attribute_table;
+
+  /* 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));
+
+  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_type_variant (char_type_node, 1, 0));
+    = 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)));
@@ -5048,16 +2717,19 @@ c_common_nodes_and_builtins ()
   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);
+  unsigned_ptrdiff_type_node = c_common_unsigned_type (ptrdiff_type_node);
 
-  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_va_list"),
+                va_list_type_node));
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
-                       ptrdiff_type_node));
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("__builtin_ptrdiff_t"),
+                ptrdiff_type_node));
 
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
-                       sizetype));
+  (*lang_hooks.decls.pushdecl)
+    (build_decl (TYPE_DECL, get_identifier ("__builtin_size_t"),
+                sizetype));
 
   if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
     {
@@ -5070,481 +2742,196 @@ c_common_nodes_and_builtins ()
       va_list_ref_type_node = build_reference_type (va_list_type_node);
     }
  
-  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);
-
-  sizet_ftype_any = build_function_type (sizetype, NULL_TREE);
-  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));
-
-  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;
-
-  /* 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,
+#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));
 
-  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 just to mark it as non-returning.  */
-  builtin_function_2 (NULL_PTR, "_exit", NULL_TREE, void_ftype_int,
+#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 ("__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_LABS, BUILT_IN_NORMAL, 0, 0, 0);
-  builtin_function_2 ("__builtin_llabs", "llabs",
-                     longlong_ftype_longlong, longlong_ftype_longlong,
-                     BUILT_IN_LLABS, BUILT_IN_NORMAL, 0, !flag_isoc99, 0);
-  builtin_function_2 ("__builtin_imaxabs", "imaxabs",
-                     intmax_ftype_intmax, intmax_ftype_intmax,
-                     BUILT_IN_IMAXABS, 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);
-  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);
-  /* We declare these without argument so that the initial declaration
-     for these identifiers is a builtin.  That allows us to redeclare
-     them later with argument without worrying about the explicit
-     declarations in stdio.h being taken as the initial declaration.
-     Also, save the _DECL for these so we can use them later.  */
-  built_in_decls[BUILT_IN_FWRITE] =
-    builtin_function ("__builtin_fwrite", sizet_ftype_any,
-                     BUILT_IN_FWRITE, BUILT_IN_NORMAL, "fwrite");
-  built_in_decls[BUILT_IN_FPUTC] =
-    builtin_function_2 ("__builtin_fputc", "fputc",
-                       int_ftype_any, int_ftype_any,
-                       BUILT_IN_FPUTC, BUILT_IN_NORMAL, 1, 0, 0);
-  built_in_decls[BUILT_IN_FPUTS] =
-    builtin_function_2 ("__builtin_fputs", "fputs",
-                       int_ftype_any, int_ftype_any,
-                       BUILT_IN_FPUTS, BUILT_IN_NORMAL, 1, 0, 0);
+  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_PTR, "abort",
+  builtin_function_2 (NULL, "abort",
                      NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? void_ftype : void_ftype_any),
+                                 ? builtin_types[BT_FN_VOID]
+                                 : builtin_types[BT_FN_VOID_VAR]),
                      0, NOT_BUILT_IN, 0, 0, 1);
 
-  builtin_function_2 (NULL_PTR, "exit",
+  builtin_function_2 (NULL, "exit",
                      NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? void_ftype_int : void_ftype_any),
+                                 ? builtin_types[BT_FN_VOID_INT]
+                                 : builtin_types[BT_FN_VOID_VAR]),
                      0, NOT_BUILT_IN, 0, 0, 1);
 
-#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
+  main_identifier_node = get_identifier ("main");
+
+  /* ??? 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;
+}
+
+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 *));
 
-  main_identifier_node = get_identifier ("main");
+/* Disable a built-in function specified by -fno-builtin-NAME.  If NAME
+   begins with "__builtin_", give an error.  */
 
-  /* ??? 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;
+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;
+    }
 }
 
-tree
-build_va_arg (expr, type)
-     tree expr, type;
+
+/* Return true if the built-in function NAME has been disabled, false
+   otherwise.  */
+
+static bool
+builtin_function_disabled_p (name)
+     const char *name;
 {
-  return build1 (VA_ARG_EXPR, type, expr);
+  disabled_builtin *p;
+  for (p = disabled_builtins; p != NULL; p = p->next)
+    {
+      if (strcmp (name, p->name) == 0)
+       return true;
+    }
+  return false;
 }
 
 
@@ -5581,16 +2968,17 @@ builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
   if (builtin_name != 0)
     {
       bdecl = builtin_function (builtin_name, builtin_type, function_code,
-                               class, library_name_p ? name : NULL_PTR);
+                               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 && !(nonansi_p && flag_no_nonansi_builtin))
+  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_PTR);
+      decl = builtin_function (name, type, function_code, class, NULL);
       if (nonansi_p)
        DECL_BUILT_IN_NONANSI (decl) = 1;
       if (noreturn_p)
@@ -5602,6 +2990,37 @@ builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
   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;
+    }
+}
+
 /* 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
@@ -5616,13 +3035,11 @@ simple_type_promotes_to (type)
   if (TYPE_MAIN_VARIANT (type) == float_type_node)
     return double_type_node;
 
-  if (C_PROMOTING_INTEGER_TYPE_P (type))
+  if (c_promoting_integer_type_p (type))
     {
-      /* Traditionally, unsignedness is preserved in default promotions.
-         Also preserve unsignedness if not really getting any wider.  */
+      /* Preserve unsignedness if not really getting any wider.  */
       if (TREE_UNSIGNED (type)
-          && (flag_traditional
-              || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+          && (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
         return unsigned_type_node;
       return integer_type_node;
     }
@@ -5637,10 +3054,10 @@ int
 self_promoting_args_p (parms)
      tree parms;
 {
-  register tree t;
+  tree t;
   for (t = parms; t; t = TREE_CHAIN (t))
     {
-      register tree type = TREE_VALUE (t);
+      tree type = TREE_VALUE (t);
 
       if (TREE_CHAIN (t) == 0 && type != void_type_node)
        return 0;
@@ -5651,7 +3068,7 @@ self_promoting_args_p (parms)
       if (TYPE_MAIN_VARIANT (type) == float_type_node)
        return 0;
 
-      if (C_PROMOTING_INTEGER_TYPE_P (type))
+      if (c_promoting_integer_type_p (type))
        return 0;
     }
   return 1;
@@ -5670,6 +3087,81 @@ strip_array_types (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.  */
@@ -5682,8 +3174,6 @@ tree
 expand_tree_builtin (function, params, coerced_params)
      tree function, params, coerced_params;
 {
-  enum tree_code code;
-
   if (DECL_BUILT_IN_CLASS (function) != BUILT_IN_NORMAL)
     return NULL_TREE;
 
@@ -5694,77 +3184,50 @@ expand_tree_builtin (function, params, coerced_params)
     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:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNLE_EXPR;
-      else
-       code = LE_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNLE_EXPR, LE_EXPR);
 
     case BUILT_IN_ISGREATEREQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNLT_EXPR;
-      else
-       code = LT_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNLT_EXPR, LT_EXPR);
 
     case BUILT_IN_ISLESS:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGE_EXPR;
-      else
-       code = GE_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNGE_EXPR, GE_EXPR);
 
     case BUILT_IN_ISLESSEQUAL:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNGT_EXPR;
-      else
-       code = GT_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNGT_EXPR, GT_EXPR);
 
     case BUILT_IN_ISLESSGREATER:
-      if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
-       code = UNEQ_EXPR;
-      else
-       code = EQ_EXPR;
-      goto unordered_cmp;
+      return expand_unordered_cmp (function, params, UNEQ_EXPR, EQ_EXPR);
 
     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;
+      return expand_unordered_cmp (function, params, UNORDERED_EXPR, NOP_EXPR);
 
     default:
       break;
@@ -5781,6 +3244,7 @@ statement_code_p (code)
 {
   switch (code)
     {
+    case CLEANUP_STMT:
     case EXPR_STMT:
     case COMPOUND_STMT:
     case DECL_STMT:
@@ -5796,6 +3260,7 @@ statement_code_p (code)
     case GOTO_STMT:
     case LABEL_STMT:
     case ASM_STMT:
+    case FILE_STMT:
     case CASE_LABEL:
       return 1;
 
@@ -5806,7 +3271,7 @@ statement_code_p (code)
     }
 }
 
-/* Walk the statemen tree, rooted at *tp.  Apply FUNC to all the
+/* 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
@@ -5852,25 +3317,25 @@ walk_stmt_tree (tp, func, data)
   if (result)
     return result;
 
-  /* 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;
-
   /* 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;
 
-  /* 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));
+  /* 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.  */
@@ -6056,6 +3521,39 @@ c_add_case_label (cases, cond, low_value, high_value)
   return case_label;
 }
 
+/* Finish an expression taking the address of LABEL.  Returns an
+   expression for the address.  */
+
+tree 
+finish_label_address_expr (label)
+     tree label;
+{
+  tree result;
+
+  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");
+    }
+
+  label = lookup_label (label);
+  if (label == NULL_TREE)
+    result = null_pointer_node;
+  else
+    {
+      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.  */
+    }
+
+  return result;
+}
+
 /* 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.  */
@@ -6074,9 +3572,8 @@ mark_stmt_tree (p)
 
 void
 c_mark_lang_decl (c)
-     struct c_lang_decl *c;
+     struct c_lang_decl *c ATTRIBUTE_UNUSED;
 {
-  ggc_mark_tree (c->saved_tree);
 }
 
 /* Mark F for GC.  */
@@ -6099,7 +3596,7 @@ c_expand_expr (exp, target, tmode, modifier)
      tree exp;
      rtx target;
      enum machine_mode tmode;
-     enum expand_modifier modifier;
+     int modifier;  /* Actually enum_modifier.  */
 {
   switch (TREE_CODE (exp))
     {
@@ -6107,6 +3604,7 @@ c_expand_expr (exp, target, tmode, modifier)
       {
        tree rtl_expr;
        rtx result;
+       bool preserve_result = false;
 
        /* Since expand_expr_stmt calls free_temp_slots after every
           expression statement, we must call push_temp_slots here.
@@ -6115,9 +3613,42 @@ c_expand_expr (exp, target, tmode, modifier)
           STMT_EXPR.  */
        push_temp_slots ();
        rtl_expr = expand_start_stmt_expr ();
+
+       /* 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);
+
+           while (TREE_CHAIN (last))
+             {
+               expr = last;
+               last = TREE_CHAIN (last);
+             }
+
+           if (TREE_CODE (last) == SCOPE_STMT
+               && TREE_CODE (expr) == EXPR_STMT)
+             {
+               TREE_ADDRESSABLE (expr) = 1;
+               preserve_result = true;
+             }
+         }
+
        expand_stmt (STMT_EXPR_STMT (exp));
        expand_end_stmt_expr (rtl_expr);
+
        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);
+         }
+
        pop_temp_slots ();
        return result;
       }
@@ -6133,10 +3664,19 @@ c_expand_expr (exp, target, tmode, modifier)
                == BUILT_IN_FRONTEND))
          return c_expand_builtin (exp, target, tmode, modifier);
        else
-         abort();
+         abort ();
       }
       break;
 
+    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);
+      }
+
     default:
       abort ();
     }
@@ -6176,65 +3716,29 @@ c_safe_from_p (target, exp)
 /* Hook used by unsafe_for_reeval to handle language-specific tree codes.  */
 
 int
-c_unsafe_for_reeval (exp)
+c_common_unsafe_for_reeval (exp)
      tree exp;
 {
-  /* Statement expressions may not be reevaluated.  */
-  if (TREE_CODE (exp) == STMT_EXPR)
+  /* 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;
 }
 
-/* Tree code classes. */
+/* Hook used by staticp to handle language-specific tree codes.  */
 
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
-
-static char c_tree_code_type[] = {
-  'x',
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Table indexed by tree code giving number of expression
-   operands beyond the fixed part of the node structure.
-   Not used for types or decls.  */
-
-#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) LENGTH,
-
-static int c_tree_code_length[] = {
-  0,
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Names of tree components.
-   Used for printing out the tree and error messages.  */
-#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-
-static const char *c_tree_code_name[] = {
-  "@@dummy",
-#include "c-common.def"
-};
-#undef DEFTREECODE
-
-/* Adds the tree codes specific to the C front end to the list of all
-   tree codes. */
-
-void
-add_c_tree_codes ()
+int
+c_staticp (exp)
+     tree exp;
 {
-  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;
+  if (TREE_CODE (exp) == COMPOUND_LITERAL_EXPR
+      && TREE_STATIC (COMPOUND_LITERAL_EXPR_DECL (exp)))
+    return 1;
+  return 0;
 }
 
 #define CALLED_AS_BUILT_IN(NODE) \
@@ -6265,7 +3769,28 @@ c_expand_builtin (exp, target, tmode, modifier)
     {
     case BUILT_IN_PRINTF:
       target = c_expand_builtin_printf (arglist, target, tmode,
-                                       modifier, ignore);
+                                       modifier, ignore, /*unlocked=*/ 0);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_PRINTF_UNLOCKED:
+      target = c_expand_builtin_printf (arglist, target, tmode,
+                                       modifier, ignore, /*unlocked=*/ 1);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_FPRINTF:
+      target = c_expand_builtin_fprintf (arglist, target, tmode,
+                                        modifier, ignore, /*unlocked=*/ 0);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_FPRINTF_UNLOCKED:
+      target = c_expand_builtin_fprintf (arglist, target, tmode,
+                                        modifier, ignore, /*unlocked=*/ 1);
       if (target)
        return target;
       break;
@@ -6282,56 +3807,67 @@ c_expand_builtin (exp, target, tmode, modifier)
 
 /* Check an arglist to *printf for problems.  The arglist should start
    at the format specifier, with the remaining arguments immediately
-   following it. */
+   following it.  */
 static int
 is_valid_printf_arglist (arglist)
-  tree arglist;
+     tree arglist;
 {
-  /* Save this value so we can restore it later. */
+  /* Save this value so we can restore it later.  */
   const int SAVE_pedantic = pedantic;
   int diagnostic_occurred = 0;
+  tree attrs;
 
   /* 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);
-
-  /* Restore the value of `pedantic'. */
+  /* 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;
 
   /* If calling `check_function_format_ptr' produces a warning, we
-     return false, otherwise we return true. */
+     return false, otherwise we return true.  */
   return ! diagnostic_occurred;
 }
 
 /* If the arguments passed to printf are suitable for optimizations,
-   we attempt to transform the call. */
+   we attempt to transform the call.  */
 static rtx
-c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
+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 = built_in_decls[BUILT_IN_PUTCHAR],
-    fn_puts = built_in_decls[BUILT_IN_PUTS];
+  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;
 
   /* If the return value is used, or the replacement _DECL isn't
-     initialized, don't do the transformation. */
+     initialized, don't do the transformation.  */
   if (!ignore || !fn_putchar || !fn_puts)
     return 0;
 
-  /* Verify the required arguments in the original call. */
+  /* 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. */
+  /* Check the specifier vs. the parameters.  */
   if (!is_valid_printf_arglist (arglist))
     return 0;
   
@@ -6347,13 +3883,13 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
   
   /* OK!  We can attempt optimization.  */
 
-  /* If the format specifier was "%s\n", call __builtin_puts(arg2). */
+  /* 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). */
+  /* If the format specifier was "%c", call __builtin_putchar (arg2).  */
   else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
     {
       arglist = TREE_CHAIN (arglist);
@@ -6361,7 +3897,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
     }
   else
     {
-     /* We can't handle anything else with % args or %% ... yet. */
+      /* We can't handle anything else with % args or %% ... yet.  */
       if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
        return 0;
       
@@ -6372,7 +3908,7 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
         {
          /* Given printf("c"), (where c is any one character,)
              convert "c"[0] to an int and pass that to the replacement
-             function. */
+             function.  */
          arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
          arglist = build_tree_list (NULL_TREE, arglist);
          
@@ -6407,6 +3943,89 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
                      (ignore ? const0_rtx : target),
                      tmode, modifier);
 }
+
+/* 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;
+{
+  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;
+
+  /* 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 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)
+    {
+      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 the format specifier was "%c", call __builtin_fputc (arg3, arg1).  */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      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;
+    }
+  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 boolean expression ARG, return a tree representing an increment
@@ -6448,3 +4067,184 @@ boolean_increment (code, arg)
   TREE_SIDE_EFFECTS (val) = 1;
   return val;
 }
+\f
+/* Handle C and C++ default attributes.  */
+
+enum built_in_attribute
+{
+#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
+};
+
+static tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
+
+/* Common initialization before parsing options.  */
+void
+c_common_init_options (lang)
+     enum c_language_kind lang;
+{
+  c_language = lang;
+  parse_in = cpp_create_reader (lang == clk_c ? CLK_GNUC89:
+                               lang == clk_cplusplus ? CLK_GNUCXX: CLK_OBJC);
+
+  /* Mark as "unspecified" (see c_common_post_options).  */
+  flag_bounds_check = -1;
+}
+
+/* Post-switch processing.  */
+void
+c_common_post_options ()
+{
+  cpp_post_options (parse_in);
+
+  /* Save no-inline information we may clobber below.  */
+  flag_really_no_inline = flag_no_inline;
+
+  flag_inline_trees = 1;
+
+  /* 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)
+    {
+      if (!flag_no_inline)
+       flag_no_inline = 1;
+      if (flag_inline_functions)
+       {
+         flag_inline_trees = 2;
+         flag_inline_functions = 0;
+       }
+    }
+
+  /* If still "unspecified", make it match -fbounded-pointers.  */
+  if (flag_bounds_check == -1)
+    flag_bounds_check = flag_bounded_pointers;
+
+  /* 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");
+}
+
+/* Front end initialization common to C, ObjC and C++.  */
+const char *
+c_common_init (filename)
+     const char *filename;
+{
+  /* NULL is passed up to toplev.c and we exit quickly.  */
+  if (flag_preprocess_only)
+    {
+      cpp_preprocess_file (parse_in);
+      return NULL;
+    }
+
+  /* Do this before initializing pragmas, as then cpplib's hash table
+     has been set up.  */
+  filename = init_c_lex (filename);
+
+  init_pragma ();
+
+  if (!c_attrs_initialized)
+    c_init_attributes ();
+
+  return filename;
+}
+
+/* Common finish hook for the C, ObjC and C++ front ends.  */
+void
+c_common_finish ()
+{
+  cpp_finish (parse_in);
+
+  /* For performance, avoid tearing down cpplib's internal structures.
+     Call cpp_errors () instead of cpp_destroy ().  */
+  errorcount += cpp_errors (parse_in);
+}
+
+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;
+}
+
+/* Depending on the name of DECL, apply default attributes to it.  */
+
+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
+}
+
+/* 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");
+}
+