OSDN Git Service

* optimize.c (inlinable_function_p): Allow only smaller single
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 292d946..84a9262 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
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
    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"
@@ -31,16 +31,52 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "c-common.h"
 #include "tm_p.h"
-#include "intl.h"
-
-#if USE_CPPLIB
+#include "obstack.h"
 #include "cpplib.h"
-cpp_reader  parse_in;
-#endif
+#include "target.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
+
+#ifndef WINT_TYPE
+#define WINT_TYPE "unsigned int"
+#endif
+
+#ifndef INTMAX_TYPE
+#define INTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)    \
+                    ? "int"                                    \
+                    : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
+                       ? "long int"                            \
+                       : "long long int"))
+#endif
+
+#ifndef UINTMAX_TYPE
+#define UINTMAX_TYPE ((INT_TYPE_SIZE == LONG_LONG_TYPE_SIZE)   \
+                    ? "unsigned int"                           \
+                    : ((LONG_TYPE_SIZE == LONG_LONG_TYPE_SIZE) \
+                       ? "long unsigned int"                   \
+                       : "long long unsigned int"))
+#endif
+
 /* The following symbols are subsumed in the c_global_trees array, and
    listed here individually for documentation purposes.
 
@@ -117,33 +153,52 @@ cpp_reader  parse_in;
 
        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_declnode;
+       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 means don't recognize the non-ANSI builtin functions.  */
+
+int flag_no_builtin;
+
+/* Nonzero means don't recognize the non-ANSI builtin functions.
+   -ansi sets this.  */
+
+int flag_no_nonansi_builtin;
+
+/* Nonzero means give `double' the same size as `float'.  */
+
+int flag_short_double;
+
+/* Nonzero means give `wchar_t' the same size as `short'.  */
+
+int flag_short_wchar;
+
+/* Nonzero means warn about possible violations of sequence point rules.  */
+
+int warn_sequence_point;
+
 /* 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.  */
@@ -153,6 +208,10 @@ 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;
@@ -163,16 +222,32 @@ enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
            A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS, A_MALLOC,
            A_NO_LIMIT_STACK, A_PURE};
 
-enum format_type { printf_format_type, scanf_format_type,
-                  strftime_format_type };
+/* Information about how a function name is generated.  */
+struct fname_var_t
+{
+  tree *decl;  /* pointer to the VAR_DECL.  */
+  unsigned rid;        /* RID number for the identifier.  */
+  int pretty;  /* How pretty is it? */
+};
+
+/* The three ways of getting then name of the current function.  */
+
+const struct fname_var_t fname_vars[] =
+{
+  /* C99 compliant __func__, must be first.  */
+  {&c99_function_name_decl_node, RID_C99_FUNCTION_NAME, 0},
+  /* GCC __FUNCTION__ compliant.  */
+  {&function_name_decl_node, RID_FUNCTION_NAME, 0},
+  /* GCC __PRETTY_FUNCTION__ compliant.  */
+  {&pretty_function_name_decl_node, RID_PRETTY_FUNCTION_NAME, 1},
+  {NULL, 0, 0},
+};
 
 static void add_attribute              PARAMS ((enum attrs, const char *,
                                                 int, int, int));
 static void init_attributes            PARAMS ((void));
-static 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
@@ -187,7 +262,6 @@ typedef struct
   int needs_warning;
   tree if_stmt;
 } if_elt;
-static void tfaff                      PARAMS ((void));
 
 static if_elt *if_stack;
 
@@ -285,34 +359,157 @@ c_finish_else ()
   RECHAIN_STMTS (if_stmt, ELSE_CLAUSE (if_stmt));
 }
 
-/* Make bindings for __FUNCTION__, __PRETTY_FUNCTION__, and __func__.  */
+/* Push current bindings for the function name VAR_DECLS.  */
+
+void
+start_fname_decls ()
+{
+  unsigned ix;
+  tree saved = NULL_TREE;
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    {
+      tree decl = *fname_vars[ix].decl;
+
+      if (decl)
+       {
+         saved = tree_cons (decl, build_int_2 (ix, 0), saved);
+         *fname_vars[ix].decl = NULL_TREE;
+       }
+    }
+  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);
+}
+
+/* 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.  */
 
 void
-declare_function_name ()
+finish_fname_decls ()
 {
-  const char *name, *printable_name;
+  unsigned ix;
+  tree body = NULL_TREE;
+  tree stack = saved_function_name_decls;
 
-  if (current_function_decl == NULL)
+  for (; stack && TREE_VALUE (stack); stack = TREE_CHAIN (stack))
+    body = chainon (TREE_VALUE (stack), body);
+  
+  if (body)
     {
-      name = "";
-      printable_name = "top level";
+      /* They were called into existance, 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
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    *fname_vars[ix].decl = NULL_TREE;
+  
+  if (stack)
     {
-      /* 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);
+      /* We had saved values, restore them.  */
+      tree saved;
+
+      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;
+}
+
+/* Return the text name of the current function, suitable prettified
+   by PRETTY_P.  */
+
+const char *
+fname_as_string (pretty_p)
+     int pretty_p;
+{
+  const char *name = NULL;
+  
+  if (pretty_p)
+    name = (current_function_decl
+           ? (*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;
+}
 
-      /* 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);
+/* Return the text name of the current function, formatted as
+   required by the supplied RID value.  */
+
+const char *
+fname_string (rid)
+     unsigned rid;
+{
+  unsigned ix;
+  
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    if (fname_vars[ix].rid == rid)
+      break;
+  return fname_as_string (fname_vars[ix].pretty);
+}
+
+/* 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 independant code.  */
+
+tree
+fname_decl (rid, id)
+     unsigned rid;
+     tree id;
+{
+  unsigned ix;
+  tree decl = NULL_TREE;
+
+  for (ix = 0; fname_vars[ix].decl; ix++)
+    if (fname_vars[ix].rid == rid)
+      break;
+
+  decl = *fname_vars[ix].decl;
+  if (!decl)
+    {
+      tree saved_last_tree = last_tree;
+      
+      decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
+      if (last_tree != saved_last_tree)
+       {
+         /* We created some statement tree for the decl. This belongs
+            at the start of the function, so remove it now and reinsert
+            it after the function is complete.  */
+         tree stmts = TREE_CHAIN (saved_last_tree);
+
+         TREE_CHAIN (saved_last_tree) = NULL_TREE;
+         last_tree = saved_last_tree;
+         saved_function_name_decls = tree_cons (decl, stmts,
+                                                saved_function_name_decls);
+       }
+      *fname_vars[ix].decl = decl;
     }
+  if (!ix && !current_function_decl)
+    pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
   
-  (*make_fname_decl) (function_id_node, name, 0);
-  (*make_fname_decl) (pretty_function_id_node, printable_name, 1);
+  return decl;
 }
 
 /* Given a chain of STRING_CST nodes,
@@ -355,7 +552,7 @@ combine_strings (strings)
       if (wide_flag)
        length = length * wchar_bytes + wide_length;
 
-      p = ggc_alloc_string (NULL, length);
+      p = alloca (length);
 
       /* Copy the individual strings into the new combined string.
         If the combined string is wide, convert the chars to ints
@@ -374,15 +571,22 @@ combine_strings (strings)
            }
          else
            {
-             int i;
+             int i, j;
              for (i = 0; i < len; i++)
                {
-                 if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT)
-                   ((short *) q)[i] = TREE_STRING_POINTER (t)[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
-                   ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+                   {
+                     *q++ = TREE_STRING_POINTER (t)[i];
+                     for (j=0; j<(WCHAR_TYPE_SIZE / BITS_PER_UNIT)-1; j++)
+                       *q++ = 0;
+                   }
                }
-             q += len * wchar_bytes;
            }
        }
       if (wide_flag)
@@ -394,9 +598,7 @@ combine_strings (strings)
       else
        *q = 0;
 
-      value = make_node (STRING_CST);
-      TREE_STRING_POINTER (value) = p;
-      TREE_STRING_LENGTH (value) = length;
+      value = build_string (length, p);
     }
   else
     {
@@ -409,9 +611,9 @@ combine_strings (strings)
   /* Compute the number of elements, for the array type.  */
   nchars = wide_flag ? length / wchar_bytes : length;
 
-  if (pedantic && nchars > nchars_max)
-    pedwarn ("string length `%d' is greater than the minimum length `%d' ISO C%d is required to support",
-            nchars, nchars_max, flag_isoc99 ? 99 : 89);
+  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
@@ -521,14 +723,19 @@ default_valid_lang_attribute (attr_name, attr_args, decl, type)
 int (*valid_lang_attribute) PARAMS ((tree, tree, tree, tree))
      = default_valid_lang_attribute;
 
-/* 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.  */
+/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
+   which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
+   it should be modified in place; if a TYPE, a copy should be created.
+   FLAGS gives further information, in the form of a bitwise OR of flags
+   in enum attribute_flags from c-common.h.  Depending on these flags,
+   some attributes may be returned to be applied at a later stage (for
+   example, to apply a decl attribute to the declaration rather than to
+   its type).  */
 
-void
-decl_attributes (node, attributes, prefix_attributes)
-     tree node, attributes, prefix_attributes;
+tree
+decl_attributes (node, attributes, flags)
+     tree *node, attributes;
+     int flags ATTRIBUTE_UNUSED;
 {
   tree decl = 0, type = 0;
   int is_type = 0;
@@ -537,28 +744,16 @@ decl_attributes (node, attributes, prefix_attributes)
   if (attrtab_idx == 0)
     init_attributes ();
 
-  if (DECL_P (node))
+  if (DECL_P (*node))
     {
-      decl = node;
+      decl = *node;
       type = TREE_TYPE (decl);
-      is_type = TREE_CODE (node) == TYPE_DECL;
+      is_type = TREE_CODE (*node) == TYPE_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
-
-#ifdef INSERT_ATTRIBUTES
-  INSERT_ATTRIBUTES (node, & attributes, & prefix_attributes);
-#endif
+  else if (TYPE_P (*node))
+    type = *node, is_type = 1;
 
-  attributes = chainon (prefix_attributes, attributes);
+  (*targetm.insert_attributes) (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
@@ -761,41 +956,49 @@ decl_attributes (node, attributes, prefix_attributes)
                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);
+                 if (TREE_CODE (decl) != FIELD_DECL)
+                   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 (targetm.have_named_sections)
            {
-             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");
+             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
-               DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+               error_with_decl (*node,
+                                "section attribute not allowed for `%s'");
            }
          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
+           error_with_decl (*node,
+                            "section attributes are not supported for this target");
          break;
 
        case A_ALIGNED:
@@ -853,178 +1056,12 @@ decl_attributes (node, attributes, prefix_attributes)
          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;
-                     }
-                 }
-             }
-
-           record_function_format (DECL_NAME (decl),
-                                   DECL_ASSEMBLER_NAME (decl),
-                                   format_type, format_num, first_arg_num);
-           break;
-         }
+         decl_handle_format_attribute (decl, args);
+         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;
-         }
+         decl_handle_format_arg_attribute (decl, args);
+         break;
 
        case A_WEAK:
          declare_weak (decl);
@@ -1111,6 +1148,7 @@ decl_attributes (node, attributes, prefix_attributes)
          break;
        }
     }
+  return NULL_TREE;
 }
 
 /* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
@@ -1216,1582 +1254,549 @@ strip_attrs (specs_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_C99,
-  STD_EXT
-};
-
+static int is_valid_printf_arglist PARAMS ((tree));
+static rtx c_expand_builtin PARAMS ((tree, rtx, enum machine_mode, enum expand_modifier));
+static rtx c_expand_builtin_printf PARAMS ((tree, rtx, enum machine_mode,
+                                           enum expand_modifier, int));
+static rtx c_expand_builtin_fprintf PARAMS ((tree, rtx, enum machine_mode,
+                                            enum expand_modifier, int));
+\f
+/* Print a warning if a constant expression had overflow in folding.
+   Invoke this function on every expression that the language
+   requires to be a constant expression.
+   Note the ANSI C standard says it is erroneous for a
+   constant expression to overflow.  */
 
-/* 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
+void
+constant_expression_warning (value)
+     tree value;
 {
-  /* 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 }
+  if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
+       || TREE_CODE (value) == COMPLEX_CST)
+      && TREE_CONSTANT_OVERFLOW (value) && pedantic)
+    pedwarn ("overflow in constant expression");
+}
 
+/* Print a warning if an expression had overflow in folding.
+   Invoke this function on every expression that
+   (1) appears in the source code, and
+   (2) might be a constant expression that overflowed, and
+   (3) is not already checked by convert_and_check;
+   however, do not invoke this function on operands of explicit casts.  */
 
-/* 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 options.
-     This lists flags, and additionally "w" for width, "p" for precision,
-     "c" for generic character pointers being allowed, "a" for scanf
-     "a" allocation extension (not applicable in C99 mode), "*" for
-     scanf suppression, "2" for strftime two digit year formats, "3"
-     for strftime formats giving two digit years in some locales, "E"
-     and "O" for those strftime modifiers, and "o" if use of strftime "O"
-     is a GNU extension beyond C99.  */
-  const char *flag_chars;
-} format_char_info;
-
-
-/* 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;
-} 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;
-  /* 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[] =
+void
+overflow_warning (value)
+     tree value;
 {
-  { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
-  { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C99 },
-  { "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 }
-};
+  if ((TREE_CODE (value) == INTEGER_CST
+       || (TREE_CODE (value) == COMPLEX_CST
+          && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
+      && TREE_OVERFLOW (value))
+    {
+      TREE_OVERFLOW (value) = 0;
+      if (skip_evaluation == 0)
+       warning ("integer overflow in expression");
+    }
+  else if ((TREE_CODE (value) == REAL_CST
+           || (TREE_CODE (value) == COMPLEX_CST
+               && TREE_CODE (TREE_REALPART (value)) == REAL_CST))
+          && TREE_OVERFLOW (value))
+    {
+      TREE_OVERFLOW (value) = 0;
+      if (skip_evaluation == 0)
+       warning ("floating point overflow in expression");
+    }
+}
 
+/* Print a warning if a large constant is truncated to unsigned,
+   or if -Wconversion is used and a constant < 0 is converted to unsigned.
+   Invoke this function on every expression that might be implicitly
+   converted to an unsigned type.  */
 
-/* This differs from printf_length_specs only in that "Z" is not accepted.  */
-static const format_length_info scanf_length_specs[] =
+void
+unsigned_conversion_warning (result, operand)
+     tree result, operand;
 {
-  { "h", FMT_LEN_h, STD_C89, "hh", FMT_LEN_hh, STD_C99 },
-  { "l", FMT_LEN_l, STD_C89, "ll", FMT_LEN_ll, STD_C99 },
-  { "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 }
-};
-
+  if (TREE_CODE (operand) == INTEGER_CST
+      && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
+      && TREE_UNSIGNED (TREE_TYPE (result))
+      && skip_evaluation == 0
+      && !int_fits_type_p (operand, TREE_TYPE (result)))
+    {
+      if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
+       /* This detects cases like converting -129 or 256 to unsigned char.  */
+       warning ("large integer implicitly truncated to unsigned type");
+      else if (warn_conversion)
+       warning ("negative integer implicitly converted to unsigned type");
+    }
+}
 
-#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 T99_LL { STD_C99, 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 T99_ULL        { STD_C99, 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    NULL /* intmax_t not yet implemented.  */
-#define T99_IM { STD_C99, "intmax_t", T_IM }
-#define T_UIM   NULL /* uintmax_t not yet implemented.  */
-#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_I,   T89_I,   T89_L,   T99_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "-wp0 +'I" },
-  { "oxX", 0, STD_C89, { T89_UI,  T99_UI,  T89_UI,  T89_UL,  T99_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0#"    },
-  { "u",   0, STD_C89, { T89_UI,  T99_UI,  T89_UI,  T89_UL,  T99_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "-wp0'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  }, "-wpc"     },
-  { "p",   1, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wc"      },
-  { "n",   1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T99_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, ""         },
-  /* 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"      },
-  /* GNU conversion specifiers.  */
-  { "m",   0, STD_EXT, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "-wp"      },
-  { NULL,  0, 0, NOLENGTHS, NULL }
-};
+/* Nonzero if constant C has a value that is permissible
+   for type TYPE (an INTEGER_TYPE).  */
 
-static const format_char_info scan_char_table[] =
+static int
+constant_fits_type_p (c, type)
+     tree c, type;
 {
-  /* C89 conversion specifiers.  */
-  { "di",    1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T99_LL,  TEX_LL,  T99_SST, T99_PD,  T99_IM  }, "*w"   },
-  { "ouxX",  1, STD_C89, { T89_UI,  T99_UC,  T89_US,  T89_UL,  T99_ULL, TEX_ULL, T99_ST,  T99_UPD, T99_UIM }, "*w"   },
-  { "efgEG", 1, STD_C89, { T89_F,   BADLEN,  BADLEN,  T89_D,   BADLEN,  T89_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w"   },
-  { "c",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*cw"  },
-  { "s",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*acw" },
-  { "[",     1, STD_C89, { T89_C,   BADLEN,  BADLEN,  T94_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*acw" },
-  { "p",     2, STD_C89, { T89_V,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w"   },
-  { "n",     1, STD_C89, { T89_I,   T99_SC,  T89_S,   T89_L,   T99_LL,  BADLEN,  T99_SST, T99_PD,  T99_IM  }, ""     },
-  /* C99 conversion specifiers.  */
-  { "FaA",   1, STD_C99, { T99_F,   BADLEN,  BADLEN,  T99_D,   BADLEN,  T99_LD,  BADLEN,  BADLEN,  BADLEN  }, "*w"   },
-  /* X/Open conversion specifiers.  */
-  { "C",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*w"   },
-  { "S",     1, STD_EXT, { TEX_W,   BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN,  BADLEN  }, "*aw"  },
-  { NULL, 0, 0, NOLENGTHS, NULL }
-};
+  if (TREE_CODE (c) == INTEGER_CST)
+    return int_fits_type_p (c, type);
 
-static format_char_info time_char_table[] =
-{
-  /* C89 conversion specifiers.  */
-  { "ABZab",           0, STD_C89, NOLENGTHS, "^#" },
-  { "cx",              0, STD_C89, NOLENGTHS, "3E" },
-  { "HIMSUWdmw",       0, STD_C89, NOLENGTHS, "-_0Ow" },
-  { "j",               0, STD_C89, NOLENGTHS, "-_0Oow" },
-  { "p",               0, STD_C89, NOLENGTHS, "#" },
-  { "X",               0, STD_C89, NOLENGTHS, "E" },
-  { "y",               0, STD_C89, NOLENGTHS, "2EO-_0w" },
-  { "Y",               0, STD_C89, NOLENGTHS, "-_0EOow" },
-  { "%",               0, STD_C89, NOLENGTHS, "" },
-  /* C99 conversion specifiers.  */
-  { "C",               0, STD_C99, NOLENGTHS, "-_0EOow" },
-  { "D",               0, STD_C99, NOLENGTHS, "2" },
-  { "eVu",             0, STD_C99, NOLENGTHS, "-_0Ow" },
-  { "FRTnrt",          0, STD_C99, NOLENGTHS, "" },
-  { "g",               0, STD_C99, NOLENGTHS, "2Oo-_0w" },
-  { "G",               0, STD_C99, NOLENGTHS, "-_0Oow" },
-  { "h",               0, STD_C99, NOLENGTHS, "^#" },
-  { "z",               0, STD_C99, NOLENGTHS, "Oo" },
-  /* GNU conversion specifiers.  */
-  { "kls",             0, STD_EXT, NOLENGTHS, "-_0Ow" },
-  { "P",               0, STD_EXT, NOLENGTHS, "" },
-  { NULL,              0, 0, NOLENGTHS, NULL }
-};
+  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.  */
 
-/* This must be in the same order as enum format_type.  */
-static const format_kind_info format_types[] =
+tree
+convert_and_check (type, expr)
+     tree type, expr;
 {
-  { "printf",   printf_length_specs, print_char_table },
-  { "scanf",    scanf_length_specs,  scan_char_table  },
-  { "strftime", NULL,                time_char_table  }
-};
+  tree t = convert (type, expr);
+  if (TREE_CODE (t) == INTEGER_CST)
+    {
+      if (TREE_OVERFLOW (t))
+       {
+         TREE_OVERFLOW (t) = 0;
 
+         /* Do not diagnose overflow in a constant expression merely
+            because a conversion overflowed.  */
+         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
 
-typedef struct function_format_info
+         /* No warning for converting 0x80000000 to int.  */
+         if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
+               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
+               && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
+           /* If EXPR fits in the unsigned version of TYPE,
+              don't warn unless pedantic.  */
+           if ((pedantic
+                || TREE_UNSIGNED (type)
+                || ! constant_fits_type_p (expr, unsigned_type (type)))
+               && skip_evaluation == 0)
+             warning ("overflow in implicit constant conversion");
+       }
+      else
+       unsigned_conversion_warning (t, expr);
+    }
+  return t;
+}
+\f
+/* A node in a list that describes references to variables (EXPR), which are
+   either read accesses if WRITER is zero, or write accesses, in which case
+   WRITER is the parent of EXPR.  */
+struct tlist
 {
-  struct 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;
+  struct tlist *next;
+  tree expr, writer;
+};
 
-typedef struct international_format_info
+/* Used to implement a cache the results of a call to verify_tree.  We only
+   use this for SAVE_EXPRs.  */
+struct tlist_cache
 {
-  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;
-
-static void check_format_info  PARAMS ((function_format_info *, tree));
-
-static void init_dollar_format_checking                PARAMS ((int, tree));
-static int maybe_read_dollar_number            PARAMS ((const char **, int,
-                                                        tree, tree *));
-static void finish_dollar_format_checking      PARAMS ((void));
-
-static void check_format_types PARAMS ((format_wanted_type *));
-
-/* 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.  */
+  struct tlist_cache *next;
+  struct tlist *cache_before_sp;
+  struct tlist *cache_after_sp;
+  tree expr;
+};
 
-void
-init_function_format_info ()
+/* Obstack to use when allocating tlist structures, and corresponding
+   firstobj.  */
+static struct obstack tlist_obstack;
+static char *tlist_firstobj = 0;
+
+/* Keep track of the identifiers we've warned about, so we can avoid duplicate
+   warnings.  */
+static struct tlist *warned_ids;
+/* SAVE_EXPRs need special treatment.  We process them only once and then
+   cache the results.  */
+static struct tlist_cache *save_expr_cache;
+
+static void add_tlist PARAMS ((struct tlist **, struct tlist *, tree, int));
+static void merge_tlist PARAMS ((struct tlist **, struct tlist *, int));
+static void verify_tree PARAMS ((tree, struct tlist **, struct tlist **, tree));
+static int warning_candidate_p PARAMS ((tree));
+static void warn_for_collisions PARAMS ((struct tlist *));
+static void warn_for_collisions_1 PARAMS ((tree, tree, struct tlist *, int));
+static struct tlist *new_tlist PARAMS ((struct tlist *, tree, tree));
+static void verify_sequence_points PARAMS ((tree));
+
+/* Create a new struct tlist and fill in its fields.  */
+static struct tlist *
+new_tlist (next, t, writer)
+     struct tlist *next;
+     tree t;
+     tree writer;
 {
-  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 ("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);
-    }
+  struct tlist *l;
+  l = (struct tlist *) obstack_alloc (&tlist_obstack, sizeof *l);
+  l->next = next;
+  l->expr = t;
+  l->writer = writer;
+  return l;
 }
 
-/* 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).  */
+/* Add duplicates of the nodes found in ADD to the list *TO.  If EXCLUDE_WRITER
+   is nonnull, we ignore any node we find which has a writer equal to it.  */
 
 static void
-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;
+add_tlist (to, add, exclude_writer, copy)
+     struct tlist **to;
+     struct tlist *add;
+     tree exclude_writer;
+     int copy;
 {
-  function_format_info *info;
-
-  /* Re-use existing structure if it's there.  */
-
-  for (info = function_format_list; info; info = info->next)
+  while (add)
     {
-      if (info->name == name && info->assembler_name == assembler_name)
-       break;
+      struct tlist *next = add->next;
+      if (! copy)
+       add->next = *to;
+      if (! exclude_writer || add->writer != exclude_writer)
+       *to = copy ? new_tlist (*to, add->expr, add->writer) : add;
+      add = next;
     }
-  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).  */
+/* Merge the nodes of ADD into TO.  This merging process is done so that for
+   each variable that already exists in TO, no new node is added; however if
+   there is a write access recorded in ADD, and an occurrence on TO is only
+   a read access, then the occurrence in TO will be modified to record the
+   write.  */
 
 static void
-record_international_format (name, assembler_name, format_num)
-      tree name;
-      tree assembler_name;
-      int format_num;
+merge_tlist (to, add, copy)
+     struct tlist **to;
+     struct tlist *add;
+     int copy;
 {
-  international_format_info *info;
+  struct tlist **end = to;
 
-  /* Re-use existing structure if it's there.  */
+  while (*end)
+    end = &(*end)->next;
 
-  for (info = international_format_list; info; info = info->next)
+  while (add)
     {
-      if (info->name == name && info->assembler_name == assembler_name)
-       break;
-    }
+      int found = 0;
+      struct tlist *tmp2;
+      struct tlist *next = add->next;
 
-  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;
+      for (tmp2 = *to; tmp2; tmp2 = tmp2->next)
+       if (tmp2->expr == add->expr)
+         {
+           found = 1;
+           if (! tmp2->writer)
+             tmp2->writer = add->writer;
+         }
+      if (! found)
+       {
+         *end = copy ? add : new_tlist (NULL, add->expr, add->writer);
+         end = &(*end)->next;
+         *end = 0;
+       }
+      add = next;
     }
-
-  info->format_num = format_num;
 }
 
+/* WRITTEN is a variable, WRITER is its parent.  Warn if any of the variable
+   references in list LIST conflict with it, excluding reads if ONLY writers
+   is nonzero.  */
+
 static void
-tfaff ()
+warn_for_collisions_1 (written, writer, list, only_writes)
+     tree written, writer;
+     struct tlist *list;
+     int only_writes;
 {
-  warning ("too few arguments for format");
-}
-\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.  */
+  struct tlist *tmp;
 
-void
-check_function_format (name, assembler_name, params)
-     tree name;
-     tree assembler_name;
-     tree params;
-{
-  function_format_info *info;
+  /* Avoid duplicate warnings.  */
+  for (tmp = warned_ids; tmp; tmp = tmp->next)
+    if (tmp->expr == written)
+      return;
 
-  /* See if this function is a format function.  */
-  for (info = function_format_list; info; info = info->next)
+  while (list)
     {
-      if (info->assembler_name
-         ? (info->assembler_name == assembler_name)
-         : (info->name == name))
+      if (list->expr == written
+         && list->writer != writer
+         && (! only_writes || list->writer))
        {
-         /* Yup; check it.  */
-         check_format_info (info, params);
-         break;
+         warned_ids = new_tlist (warned_ids, written, NULL_TREE);
+         warning ("operation on `%s' may be undefined",
+                  IDENTIFIER_POINTER (DECL_NAME (list->expr)));
        }
+      list = list->next;
     }
 }
 
-
-/* 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.  */
+/* Given a list LIST of references to variables, find whether any of these
+   can cause conflicts due to missing sequence points.  */
 
 static void
-init_dollar_format_checking (first_arg_num, params)
-     int first_arg_num;
-     tree params;
+warn_for_collisions (list)
+     struct tlist *list;
 {
-  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)
+  struct tlist *tmp;
+  
+  for (tmp = list; tmp; tmp = tmp->next)
     {
-      if (dollar_arguments_used)
-       free (dollar_arguments_used);
-      dollar_arguments_alloc = dollar_arguments_count;
-      dollar_arguments_used = xmalloc (dollar_arguments_alloc);
+      if (tmp->writer)
+       warn_for_collisions_1 (tmp->expr, tmp->writer, list, 0);
     }
-  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.  */
-
+/* Return nonzero if X is a tree that can be verified by the sequence poitn
+   warnings.  */
 static int
-maybe_read_dollar_number (format, dollar_needed, params, param_ptr)
-     const char **format;
-     int dollar_needed;
-     tree params;
-     tree *param_ptr;
+warning_candidate_p (x)
+     tree x;
 {
-  int argnum;
-  int overflow_flag;
-  const char *fcp = *format;
-  if (*fcp < '0' || *fcp > '9')
-    {
-      if (dollar_needed)
-       {
-         warning ("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)
-       {
-         warning ("missing $ operand number in format");
-         return -1;
-       }
-      else
-       return 0;
-    }
-  *format = fcp + 1;
-  if (pedantic && !dollar_format_warned)
-    {
-      warning ("ISO C does not support %%n$ operand number formats");
-      dollar_format_warned = 1;
-    }
-  if (overflow_flag || argnum == 0
-      || (dollar_first_arg_num && argnum > dollar_arguments_count))
-    {
-      warning ("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;
-    }
-  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;
+  return TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == PARM_DECL;
 }
 
-
-/* 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.  */
+/* Walk the tree X, and record accesses to variables.  If X is written by the
+   parent tree, WRITER is the parent.
+   We store accesses in one of the two lists: PBEFORE_SP, and PNO_SP.  If this
+   expression or its only operand forces a sequence point, then everything up
+   to the sequence point is stored in PBEFORE_SP.  Everything else gets stored
+   in PNO_SP.
+   Once we return, we will have emitted warnings if any subexpression before
+   such a sequence point could be undefined.  On a higher level, however, the
+   sequence point may not be relevant, and we'll merge the two lists.
+
+   Example: (b++, a) + b;
+   The call that processes the COMPOUND_EXPR will store the increment of B
+   in PBEFORE_SP, and the use of A in PNO_SP.  The higher-level call that
+   processes the PLUS_EXPR will need to merge the two lists so that
+   eventually, all accesses end up on the same list (and we'll warn about the
+   unordered subexpressions b++ and b.
+
+   A note on merging.  If we modify the former example so that our expression
+   becomes
+     (b++, b) + a
+   care must be taken not simply to add all three expressions into the final
+   PNO_SP list.  The function merge_tlist takes care of that by merging the
+   before-SP list of the COMPOUND_EXPR into its after-SP list in a special
+   way, so that no more than one access to B is recorded.  */
 
 static void
-finish_dollar_format_checking ()
+verify_tree (x, pbefore_sp, pno_sp, writer)
+     tree x;
+     struct tlist **pbefore_sp, **pno_sp;
+     tree writer;
 {
-  int i;
-  for (i = 0; i < dollar_max_arg_used; i++)
-    {
-      if (!dollar_arguments_used[i])
-       warning ("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)
-    warning ("unused arguments in $-style format");
-}
-
-
-/* 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.  */
+  struct tlist *tmp_before, *tmp_nosp, *tmp_list2, *tmp_list3;
+  enum tree_code code;
+  char class;
 
-static void
-check_format_info (info, params)
-     function_format_info *info;
-     tree params;
-{
-  int i;
-  int arg_num;
-  int suppressed, wide, precise;
-  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;
-  int format_length;
-  tree format_tree;
-  tree cur_param;
-  tree wanted_type;
-  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;
-  format_wanted_type *last_wanted_type;
-  tree first_fillin_param;
-  const char *format_chars;
-  const format_kind_info *fki = NULL;
-  const format_length_info *fli = NULL;
-  const format_char_info *fci = NULL;
-  char flag_chars[8];
-  /* -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;
-
-  /* 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)
+  /* X may be NULL if it is the operand of an empty statement expression
+     ({ }).  */
+  if (x == NULL)
     return;
 
-  /* We can only check the format if it's a string constant.  */
-  while (TREE_CODE (format_tree) == NOP_EXPR)
-    format_tree = TREE_OPERAND (format_tree, 0); /* strip coercion */
-
-  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 *info;
-
-      for (info = international_format_list; info; info = info->next)
-       if (info->assembler_name
-           ? (info->assembler_name == DECL_ASSEMBLER_NAME (function))
-           : (info->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 == info->format_num)
-               {
-                 format_tree = TREE_VALUE (inner_args);
-
-                 while (TREE_CODE (format_tree) == NOP_EXPR)
-                   format_tree = TREE_OPERAND (format_tree, 0);
-               }
-         }
-    }
+ restart:
+  code = TREE_CODE (x);
+  class = TREE_CODE_CLASS (code);
 
-  if (integer_zerop (format_tree))
-    {
-      warning ("null format string");
-      return;
-    }
-  if (TREE_CODE (format_tree) != ADDR_EXPR)
+  if (warning_candidate_p (x))
     {
-      /* The user may get multiple warnings if the supplied argument
-        isn't even a string pointer.  */
-      /* 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 (info->first_arg_num != 0 && warn_format > 1)
-       warning ("format not a string literal, argument types not checked");
+      *pno_sp = new_tlist (*pno_sp, x, writer);
       return;
     }
-  format_tree = TREE_OPERAND (format_tree, 0);
-  if (TREE_CODE (format_tree) != STRING_CST)
-    {
-      /* The user may get multiple warnings if the supplied argument
-        isn't even a string pointer.  */
-      /* 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 (info->first_arg_num != 0 && warn_format > 1)
-       warning ("format not a string literal, argument types not checked");
-      return;
-    }
-  format_chars = TREE_STRING_POINTER (format_tree);
-  format_length = TREE_STRING_LENGTH (format_tree);
-  if (format_length <= 1)
-    warning ("zero-length format string");
-  if (format_chars[--format_length] != 0)
-    {
-      warning ("unterminated format string");
-      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;
-    }
 
-  first_fillin_param = params;
-  init_dollar_format_checking (info->first_arg_num, first_fillin_param);
-  fki = &format_types[info->format_type];
-  while (1)
+  switch (code)
     {
-      int aflag;
-      first_wanted_type = NULL;
-      last_wanted_type = NULL;
-      if (*format_chars == 0)
-       {
-         if (format_chars - TREE_STRING_POINTER (format_tree) != format_length)
-           warning ("embedded `\\0' in format");
-         if (info->first_arg_num != 0 && params != 0
-             && has_operand_number <= 0)
-           warning ("too many arguments for format");
-         if (has_operand_number > 0)
-           finish_dollar_format_checking ();
-         return;
-       }
-      if (*format_chars++ != '%')
-       continue;
-      if (*format_chars == 0)
-       {
-         warning ("spurious trailing `%%' in format");
-         continue;
-       }
-      if (*format_chars == '%')
-       {
-         ++format_chars;
-         continue;
-       }
-      flag_chars[0] = 0;
-      suppressed = wide = precise = FALSE;
-      if (info->format_type == scanf_format_type)
-       {
-         int non_zero_width_char = FALSE;
-         suppressed = *format_chars == '*';
-         if (suppressed)
-           ++format_chars;
-         else if (has_operand_number != 0)
-           {
-             int opnum;
-             opnum = maybe_read_dollar_number (&format_chars,
-                                               has_operand_number == 1,
-                                               first_fillin_param, &params);
-             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;
-           }
-         while (ISDIGIT (*format_chars))
-           {
-             wide = TRUE;
-             if (*format_chars != '0')
-               non_zero_width_char = TRUE;
-             ++format_chars;
-           }
-         if (wide && !non_zero_width_char)
-           warning ("zero width in scanf format");
-       }
-      else if (info->format_type == strftime_format_type)
-        {
-         while (*format_chars != 0 && index ("_-0^#", *format_chars) != 0)
-           {
-             if (pedantic)
-               warning ("ISO C does not support the strftime `%c' flag",
-                        *format_chars);
-             if (index (flag_chars, *format_chars) != 0)
-               {
-                 warning ("repeated `%c' flag in format",
-                          *format_chars);
-                 ++format_chars;
-               }
-             else
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = *format_chars++;
-                 flag_chars[i] = 0;
-               }
-           }
-         while (ISDIGIT ((unsigned char) *format_chars))
-           {
-             wide = TRUE;
-              ++format_chars;
-           }
-         if (wide && pedantic)
-           warning ("ISO C does not support strftime format width");
-         if (*format_chars == 'E' || *format_chars == 'O')
-           {
-             i = strlen (flag_chars);
-             flag_chars[i++] = *format_chars++;
-             flag_chars[i] = 0;
-             if (*format_chars == 'E' || *format_chars == 'O')
-               {
-                 warning ("multiple E/O modifiers in format");
-                 while (*format_chars == 'E' || *format_chars == 'O')
-                   ++format_chars;
-               }
-           }
-       }
-      else if (info->format_type == printf_format_type)
-       {
-         if (has_operand_number != 0)
-           {
-             int opnum;
-             opnum = maybe_read_dollar_number (&format_chars,
-                                               has_operand_number == 1,
-                                               first_fillin_param, &params);
-             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;
-           }
-
-         while (*format_chars != 0 && index (" +#0-'I", *format_chars) != 0)
-           {
-             if (index (flag_chars, *format_chars) != 0)
-               warning ("repeated `%c' flag in format", *format_chars++);
-             else
-               {
-                 i = strlen (flag_chars);
-                 flag_chars[i++] = *format_chars++;
-                 flag_chars[i] = 0;
-               }
-           }
-         /* "If the space and + flags both appear,
-            the space flag will be ignored."  */
-         if (index (flag_chars, ' ') != 0
-             && index (flag_chars, '+') != 0)
-           warning ("use of both ` ' and `+' flags in format");
-         /* "If the 0 and - flags both appear,
-            the 0 flag will be ignored."  */
-         if (index (flag_chars, '0') != 0
-             && index (flag_chars, '-') != 0)
-           warning ("use of both `0' and `-' flags in format");
-         if (index (flag_chars, '\'') && pedantic)
-           warning ("ISO C does not support the `'' format flag");
-         if (index (flag_chars, 'I') && pedantic)
-           warning ("ISO C does not support the `I' format flag");
-         if (*format_chars == '*')
-           {
-             wide = TRUE;
-             /* "...a field width...may be indicated by an asterisk.
-                In this case, an int argument supplies the field width..."  */
-             ++format_chars;
-             if (params == 0)
-               {
-                 tfaff ();
-                 return;
-               }
-             if (has_operand_number > 0)
-               {
-                 int opnum;
-                 opnum = maybe_read_dollar_number (&format_chars, 1,
-                                                   first_fillin_param,
-                                                   &params);
-                 if (opnum <= 0)
-                   return;
-                 else
-                   arg_num = opnum + info->first_arg_num - 1;
-               }
-             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 = integer_type_node;
-                 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.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
-           {
-             while (ISDIGIT (*format_chars))
-               {
-                 wide = TRUE;
-                 ++format_chars;
-               }
-           }
-         if (*format_chars == '.')
-           {
-             precise = TRUE;
-             ++format_chars;
-             /* "...a...precision...may be indicated by an asterisk.
-                In this case, an int argument supplies the...precision."  */
-             if (*format_chars == '*')
-               {
-                 ++format_chars;
-                 if (has_operand_number > 0)
-                   {
-                     int opnum;
-                     opnum = maybe_read_dollar_number (&format_chars, 1,
-                                                       first_fillin_param,
-                                                       &params);
-                     if (opnum <= 0)
-                       return;
-                     else
-                       arg_num = opnum + info->first_arg_num - 1;
-                   }
-                 if (info->first_arg_num != 0)
-                   {
-                     if (params == 0)
-                       {
-                         tfaff ();
-                         return;
-                       }
-                     cur_param = TREE_VALUE (params);
-                     if (has_operand_number <= 0)
-                       {
-                         params = TREE_CHAIN (params);
-                         ++arg_num;
-                       }
-                     precision_wanted_type.wanted_type = integer_type_node;
-                     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.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;
-               }
-           }
-       }
-
-      aflag = 0;
+    case CONSTRUCTOR:
+      return;
 
-      fli = fki->length_char_specs;
-      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;
-               }
-           }
-         else
-           {
-             length_chars = NULL;
-             length_chars_val = FMT_LEN_none;
-             length_chars_std = STD_C89;
-           }
-         if (pedantic)
-           {
-             /* Warn if the length modifier is non-standard.  */
-             if (length_chars_std == STD_EXT)
-               warning ("ISO C does not support the `%s' %s length modifier",
-                        length_chars, fki->name);
-             else if ((length_chars_std == STD_C99 && !flag_isoc99)
-                      || (length_chars_std == STD_C94 && !flag_isoc94))
-               warning ("ISO C89 does not support the `%s' %s length modifier",
-                        length_chars, fki->name);
-           }
-         if (*format_chars == 'a' && info->format_type == scanf_format_type
-             && !flag_isoc99)
-           {
-             if (format_chars[1] == 's' || format_chars[1] == 'S'
-                 || format_chars[1] == '[')
-               {
-                 /* `a' is used as a flag.  */
-                 aflag = 1;
-                 format_chars++;
-               }
-           }
-         if (suppressed && length_chars_val != FMT_LEN_none)
-           warning ("use of `*' and `%s' together in format", length_chars);
-       }
-      format_char = *format_chars;
-      if (format_char == 0
-         || (info->format_type != strftime_format_type && format_char == '%'))
-       {
-         warning ("conversion lacks type at end of format");
-         continue;
-       }
-      format_chars++;
-      fci = fki->conversion_specs;
-      while (fci->format_chars != 0
-            && index (fci->format_chars, format_char) == 0)
-         ++fci;
-      if (fci->format_chars == 0)
-       {
-          if (ISGRAPH(format_char))
-           warning ("unknown conversion type character `%c' in format",
-                    format_char);
-         else
-           warning ("unknown conversion type character 0x%x in format",
-                    format_char);
-         continue;
-       }
-      if (pedantic)
-       {
-         if (fci->std == STD_EXT)
-           warning ("ISO C does not support the `%%%c' %s format",
-                    format_char, fki->name);
-         else if ((fci->std == STD_C99 && !flag_isoc99)
-                  || (fci->std == STD_C94 && !flag_isoc94))
-           warning ("ISO C89 does not support the `%%%c' %s format",
-                    format_char, fki->name);
-         if (index (flag_chars, 'O') != 0)
-           {
-             if (index (fci->flag_chars, 'o') != 0)
-               warning ("ISO C does not support `%%O%c'", format_char);
-             else if (!flag_isoc99 && index (fci->flag_chars, 'O') != 0)
-               warning ("ISO C89 does not support `%%O%c'", format_char);
-           }
-         if (!flag_isoc99 && index (flag_chars, 'E'))
-           warning ("ISO C89 does not support `%%E%c'", format_char);
-       }
-      if (wide && index (fci->flag_chars, 'w') == 0)
-       warning ("width used with `%c' format", format_char);
-      if (index (fci->flag_chars, '3') != 0
-         || (format_char == 'y' && index (flag_chars, 'E')))
-       warning ("`%%%c' yields only last 2 digits of year in some locales",
-                format_char);
-      else if (index (fci->flag_chars, '2') != 0)
-       warning ("`%%%c' yields only last 2 digits of year", format_char);
-      if (precise && index (fci->flag_chars, 'p') == 0)
-       warning ("precision used with `%c' format", format_char);
-      if (aflag && index (fci->flag_chars, 'a') == 0)
-       {
-         warning ("`a' flag used with `%c' format", format_char);
-         /* To simplify the following code.  */
-         aflag = 0;
-       }
-      /* The a flag is a GNU extension.  */
-      else if (pedantic && aflag)
-       warning ("ISO C does not support the `a' flag");
-      if (info->format_type == scanf_format_type && format_char == '[')
-       {
-         /* 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.  */
-           warning ("no closing `]' for `%%[' format");
-       }
-      if (suppressed)
-       {
-         if (index (fci->flag_chars, '*') == 0)
-           warning ("suppression of `%c' conversion in format", format_char);
-         continue;
-       }
-      for (i = 0; flag_chars[i] != 0; ++i)
-       {
-         if (index (fci->flag_chars, flag_chars[i]) == 0)
-           warning ("flag `%c' used with type `%c'",
-                    flag_chars[i], format_char);
-       }
-      if (info->format_type == strftime_format_type)
-       continue;
-      if (precise && index (flag_chars, '0') != 0
-         && (format_char == 'd' || format_char == 'i'
-             || format_char == 'o' || format_char == 'u'
-             || format_char == 'x' || format_char == 'X'))
-       warning ("`0' flag ignored with precision specifier and `%c' format",
-                format_char);
-      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)
-       {
-         warning ("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)
-           {
-             tfaff ();
-             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.  */
-              && wanted_type_std > length_chars_std
-              && wanted_type_std > fci->std)
-       {
-         if (wanted_type_std == STD_EXT)
-           warning ("ISO C does not support the `%%%s%c' %s format",
-                    length_chars, format_char, fki->name);
-         else if ((wanted_type_std == STD_C99 && !flag_isoc99)
-                  || (wanted_type_std == STD_C94 && !flag_isoc94))
-           warning ("ISO C89 does not support the `%%%s%c' %s format",
-                    length_chars, format_char, fki->name);
-       }
+    case COMPOUND_EXPR:
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+      tmp_before = tmp_nosp = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_nosp, 0);
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, pno_sp, NULL_TREE);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      return;
 
-      /* 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))
-       {
-         if (params == 0)
-           {
-             tfaff ();
-             return;
-           }
-         cur_param = TREE_VALUE (params);
-         params = TREE_CHAIN (params);
-         ++arg_num;
-         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 (index (fci->flag_chars, 'c') != 0)
-           main_wanted_type.char_lenient_flag = 1;
-         main_wanted_type.writing_in_flag = 0;
-         if (info->format_type == scanf_format_type
-              || (info->format_type == printf_format_type
-                  && format_char == 'n'))
-           main_wanted_type.writing_in_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;
-       }
+    case COND_EXPR:
+      tmp_before = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      merge_tlist (pbefore_sp, tmp_list2, 1);
+
+      tmp_list3 = tmp_nosp = 0;
+      verify_tree (TREE_OPERAND (x, 1), &tmp_list3, &tmp_nosp, NULL_TREE);
+      warn_for_collisions (tmp_nosp);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+
+      tmp_list3 = tmp_list2 = 0;
+      verify_tree (TREE_OPERAND (x, 2), &tmp_list3, &tmp_list2, NULL_TREE);
+      warn_for_collisions (tmp_list2);
+      merge_tlist (pbefore_sp, tmp_list3, 0);
+      /* Rather than add both tmp_nosp and tmp_list2, we have to merge the
+        two first, to avoid warning for (a ? b++ : b++).  */
+      merge_tlist (&tmp_nosp, tmp_list2, 0);
+      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+      return;
 
-      if (first_wanted_type != 0)
-       check_format_types (first_wanted_type);
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      verify_tree (TREE_OPERAND (x, 0), pno_sp, pno_sp, x);
+      return;
 
-    }
-}
+    case MODIFY_EXPR:
+      tmp_before = tmp_nosp = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 1), &tmp_before, &tmp_nosp, NULL_TREE);
+      verify_tree (TREE_OPERAND (x, 0), &tmp_list3, &tmp_list3, x);
+      /* Expressions inside the LHS are not ordered wrt. the sequence points
+        in the RHS.  Example:
+          *a = (a++, 2)
+        Despite the fact that the modification of "a" is in the before_sp
+        list (tmp_before), it conflicts with the use of "a" in the LHS.
+        We can handle this by adding the contents of tmp_list3
+        to those of tmp_before, and redoing the collision warnings for that
+        list.  */
+      add_tlist (&tmp_before, tmp_list3, x, 1);
+      warn_for_collisions (tmp_before);
+      /* Exclude the LHS itself here; we first have to merge it into the
+        tmp_nosp list.  This is done to avoid warning for "a = a"; if we
+        didn't exclude the LHS, we'd get it twice, once as a read and once
+        as a write.  */
+      add_tlist (pno_sp, tmp_list3, x, 0);
+      warn_for_collisions_1 (TREE_OPERAND (x, 0), x, tmp_nosp, 1);
+
+      merge_tlist (pbefore_sp, tmp_before, 0);
+      if (warning_candidate_p (TREE_OPERAND (x, 0)))
+       merge_tlist (&tmp_nosp, new_tlist (NULL, TREE_OPERAND (x, 0), x), 0);
+      add_tlist (pno_sp, tmp_nosp, NULL_TREE, 1);
+      return;
 
+    case CALL_EXPR:
+      /* We need to warn about conflicts among arguments and conflicts between
+        args and the function address.  Side effects of the function address,
+        however, are not ordered by the sequence point of the call.  */
+      tmp_before = tmp_nosp = tmp_list2 = tmp_list3 = 0;
+      verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+      if (TREE_OPERAND (x, 1))
+       verify_tree (TREE_OPERAND (x, 1), &tmp_list2, &tmp_list3, NULL_TREE);
+      merge_tlist (&tmp_list3, tmp_list2, 0);
+      add_tlist (&tmp_before, tmp_list3, NULL_TREE, 0);
+      add_tlist (&tmp_before, tmp_nosp, NULL_TREE, 0);
+      warn_for_collisions (tmp_before);
+      add_tlist (pbefore_sp, tmp_before, NULL_TREE, 0);
+      return;
 
-/* Check the argument types from a single format conversion (possibly
-   including width and precision arguments).  */
-static void
-check_format_types (types)
-     format_wanted_type *types;
-{
-  for (; types != 0; types = types->next)
-    {
-      tree cur_param;
-      tree cur_type;
-      tree orig_cur_type;
-      tree wanted_type;
-      int arg_num;
-      int i;
-      int char_type_flag;
-      cur_param = types->param;
-      cur_type = TREE_TYPE (cur_param);
-      if (TREE_CODE (cur_type) == ERROR_MARK)
-       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 ();
-
-      STRIP_NOPS (cur_param);
-
-      /* Check the types of any additional pointer arguments
-        that precede the "real" argument.  */
-      for (i = 0; i < types->pointer_count; ++i)
+    case TREE_LIST:
+      /* Scan all the list, e.g. indices of multi dimensional array.  */
+      while (x)
        {
-         if (TREE_CODE (cur_type) == POINTER_TYPE)
-           {
-             cur_type = TREE_TYPE (cur_type);
-             if (TREE_CODE (cur_type) == ERROR_MARK)
-               break;
-
-             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))))))
-               warning ("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)))
-               warning ("extra type qualifiers in format argument (arg %d)",
-                        arg_num);
-
-           }
-         else
-           {
-             if (types->pointer_count == 1)
-               warning ("format argument is not a pointer (arg %d)", arg_num);
-             else
-               warning ("format argument is not a pointer to a pointer (arg %d)", arg_num);
-             break;
-           }
+         tmp_before = tmp_nosp = 0;
+         verify_tree (TREE_VALUE (x), &tmp_before, &tmp_nosp, NULL_TREE);
+         merge_tlist (&tmp_nosp, tmp_before, 0);
+         add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+         x = TREE_CHAIN (x);
        }
+      return;
 
-      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.  */
+    case SAVE_EXPR:
       {
-       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)));
+       struct tlist_cache *t;
+       for (t = save_expr_cache; t; t = t->next)
+         if (t->expr == x)
+           break;
 
-       if (strcmp (this, that) != 0)
+       if (! t)
          {
-           /* 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)
-             warning ("%s is not type %s (arg %d)", types->name, this,
-                      arg_num);
-           else
-             warning ("%s format, %s arg (arg %d)", this, that, arg_num);
+           t = (struct tlist_cache *) obstack_alloc (&tlist_obstack,
+                                                     sizeof *t);
+           t->next = save_expr_cache;
+           t->expr = x;
+           save_expr_cache = t;
+
+           tmp_before = tmp_nosp = 0;
+           verify_tree (TREE_OPERAND (x, 0), &tmp_before, &tmp_nosp, NULL_TREE);
+           warn_for_collisions (tmp_nosp);
+
+           tmp_list3 = 0;
+           while (tmp_nosp)
+             {
+               struct tlist *t = tmp_nosp;
+               tmp_nosp = t->next;
+               merge_tlist (&tmp_list3, t, 0);
+             }
+           t->cache_before_sp = tmp_before;
+           t->cache_after_sp = tmp_list3;
          }
+       merge_tlist (pbefore_sp, t->cache_before_sp, 1);
+       add_tlist (pno_sp, t->cache_after_sp, NULL_TREE, 1);
+       return;
       }
+    default:
+      break;
     }
-}
-\f
-/* Print a warning if a constant expression had overflow in folding.
-   Invoke this function on every expression that the language
-   requires to be a constant expression.
-   Note the ANSI C standard says it is erroneous for a
-   constant expression to overflow.  */
-
-void
-constant_expression_warning (value)
-     tree value;
-{
-  if ((TREE_CODE (value) == INTEGER_CST || TREE_CODE (value) == REAL_CST
-       || TREE_CODE (value) == COMPLEX_CST)
-      && TREE_CONSTANT_OVERFLOW (value) && pedantic)
-    pedwarn ("overflow in constant expression");
-}
-
-/* Print a warning if an expression had overflow in folding.
-   Invoke this function on every expression that
-   (1) appears in the source code, and
-   (2) might be a constant expression that overflowed, and
-   (3) is not already checked by convert_and_check;
-   however, do not invoke this function on operands of explicit casts.  */
 
-void
-overflow_warning (value)
-     tree value;
-{
-  if ((TREE_CODE (value) == INTEGER_CST
-       || (TREE_CODE (value) == COMPLEX_CST
-          && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
-      && TREE_OVERFLOW (value))
+  if (class == '1')
     {
-      TREE_OVERFLOW (value) = 0;
-      if (skip_evaluation == 0)
-       warning ("integer overflow in expression");
+      if (first_rtl_op (code) == 0)
+       return;
+      x = TREE_OPERAND (x, 0);
+      writer = 0;
+      goto restart;
     }
-  else if ((TREE_CODE (value) == REAL_CST
-           || (TREE_CODE (value) == COMPLEX_CST
-               && TREE_CODE (TREE_REALPART (value)) == REAL_CST))
-          && TREE_OVERFLOW (value))
+
+  switch (class)
     {
-      TREE_OVERFLOW (value) = 0;
-      if (skip_evaluation == 0)
-       warning ("floating point overflow in expression");
+    case 'r':
+    case '<':
+    case '2':
+    case 'b':
+    case 'e':
+    case 's':
+    case 'x':
+      {
+       int lp;
+       int max = first_rtl_op (TREE_CODE (x));
+       for (lp = 0; lp < max; lp++)
+         {
+           tmp_before = tmp_nosp = 0;
+           verify_tree (TREE_OPERAND (x, lp), &tmp_before, &tmp_nosp, NULL_TREE);
+           merge_tlist (&tmp_nosp, tmp_before, 0);
+           add_tlist (pno_sp, tmp_nosp, NULL_TREE, 0);
+         }
+       break;
+      }
     }
 }
 
-/* Print a warning if a large constant is truncated to unsigned,
-   or if -Wconversion is used and a constant < 0 is converted to unsigned.
-   Invoke this function on every expression that might be implicitly
-   converted to an unsigned type.  */
+/* Try to warn for undefined behaviour in EXPR due to missing sequence
+   points.  */
 
-void
-unsigned_conversion_warning (result, operand)
-     tree result, operand;
+static void
+verify_sequence_points (expr)
+     tree expr;
 {
-  if (TREE_CODE (operand) == INTEGER_CST
-      && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
-      && TREE_UNSIGNED (TREE_TYPE (result))
-      && skip_evaluation == 0
-      && !int_fits_type_p (operand, TREE_TYPE (result)))
+  struct tlist *before_sp = 0, *after_sp = 0;
+
+  warned_ids = 0;
+  save_expr_cache = 0;
+  if (tlist_firstobj == 0)
     {
-      if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
-       /* This detects cases like converting -129 or 256 to unsigned char.  */
-       warning ("large integer implicitly truncated to unsigned type");
-      else if (warn_conversion)
-       warning ("negative integer implicitly converted to unsigned type");
+      gcc_obstack_init (&tlist_obstack);
+      tlist_firstobj = obstack_alloc (&tlist_obstack, 0);
     }
-}
 
-/* 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.  */
+  verify_tree (expr, &before_sp, &after_sp, 0);
+  warn_for_collisions (after_sp);
+  obstack_free (&tlist_obstack, tlist_firstobj);
+}
 
 tree
-convert_and_check (type, expr)
-     tree type, expr;
-{
-  tree t = convert (type, expr);
-  if (TREE_CODE (t) == INTEGER_CST)
-    {
-      if (TREE_OVERFLOW (t))
-       {
-         TREE_OVERFLOW (t) = 0;
-
-         /* Do not diagnose overflow in a constant expression merely
-            because a conversion overflowed.  */
-         TREE_CONSTANT_OVERFLOW (t) = TREE_CONSTANT_OVERFLOW (expr);
-
-         /* No warning for converting 0x80000000 to int.  */
-         if (!(TREE_UNSIGNED (type) < TREE_UNSIGNED (TREE_TYPE (expr))
-               && TREE_CODE (TREE_TYPE (expr)) == INTEGER_TYPE
-               && TYPE_PRECISION (type) == TYPE_PRECISION (TREE_TYPE (expr))))
-           /* If EXPR fits in the unsigned version of TYPE,
-              don't warn unless pedantic.  */
-           if ((pedantic
-                || TREE_UNSIGNED (type)
-                || ! int_fits_type_p (expr, unsigned_type (type)))
-               && skip_evaluation == 0)
-             warning ("overflow in implicit constant conversion");
-       }
-      else
-       unsigned_conversion_warning (t, expr);
-    }
-  return t;
-}
-\f
-void
 c_expand_expr_stmt (expr)
      tree expr;
 {
@@ -2801,13 +1806,16 @@ c_expand_expr_stmt (expr)
       || TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
     expr = default_conversion (expr);
 
+  if (warn_sequence_point)
+    verify_sequence_points (expr);
+
   if (TREE_TYPE (expr) != error_mark_node
       && !COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (expr))
       && TREE_CODE (TREE_TYPE (expr)) != ARRAY_TYPE)
     error ("expression statement has incomplete type");
 
   last_expr_type = TREE_TYPE (expr); 
-  add_stmt (build_stmt (EXPR_STMT, expr));
+  return add_stmt (build_stmt (EXPR_STMT, expr));
 }
 \f
 /* Validate the expression after `case' and apply default promotions.  */
@@ -2968,7 +1976,7 @@ type_for_mode (mode, unsignedp)
   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)
      tree type;
@@ -3674,91 +2682,10 @@ truthvalue_conversion (expr)
   return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
 }
 \f
-#if !USE_CPPLIB
-/* Read the rest of a #-directive from input stream FINPUT.
-   In normal use, the directive name and the white space after it
-   have already been read, so they won't be included in the result.
-   We allow for the fact that the directive line may contain
-   a newline embedded within a character or string literal which forms
-   a part of the directive.
-
-   The value is a string in a reusable buffer.  It remains valid
-   only until the next time this function is called.
-
-   The terminating character ('\n' or EOF) is left in FINPUT for the
-   caller to re-read.  */
-
-char *
-get_directive_line (finput)
-     register FILE *finput;
-{
-  static char *directive_buffer = NULL;
-  static unsigned buffer_length = 0;
-  register char *p;
-  register char *buffer_limit;
-  register int looking_for = 0;
-  register int char_escaped = 0;
-
-  if (buffer_length == 0)
-    {
-      directive_buffer = (char *)xmalloc (128);
-      buffer_length = 128;
-    }
+static tree builtin_function_2 PARAMS ((const char *, const char *, tree, tree,
+                                       int, enum built_in_class, int, int,
+                                       int));
 
-  buffer_limit = &directive_buffer[buffer_length];
-
-  for (p = directive_buffer; ; )
-    {
-      int c;
-
-      /* Make buffer bigger if it is full.  */
-      if (p >= buffer_limit)
-        {
-         register unsigned bytes_used = (p - directive_buffer);
-
-         buffer_length *= 2;
-         directive_buffer
-           = (char *)xrealloc (directive_buffer, buffer_length);
-         p = &directive_buffer[bytes_used];
-         buffer_limit = &directive_buffer[buffer_length];
-        }
-
-      c = getc (finput);
-
-      /* Discard initial whitespace.  */
-      if ((c == ' ' || c == '\t') && p == directive_buffer)
-       continue;
-
-      /* Detect the end of the directive.  */
-      if (looking_for == 0
-         && (c == '\n' || c == EOF))
-       {
-          ungetc (c, finput);
-         c = '\0';
-       }
-
-      *p++ = c;
-
-      if (c == 0)
-       return directive_buffer;
-
-      /* Handle string and character constant syntax.  */
-      if (looking_for)
-       {
-         if (looking_for == c && !char_escaped)
-           looking_for = 0;    /* Found terminator... stop looking.  */
-       }
-      else
-        if (c == '\'' || c == '"')
-         looking_for = c;      /* Don't stop buffering until we see another
-                                  one of these (or an EOF).  */
-
-      /* Handle backslash.  */
-      char_escaped = (c == '\\' && ! char_escaped);
-    }
-}
-#endif /* USE_CPPLIB */
-\f
 /* Make a variant type in the proper way for C/C++, propagating qualifiers
    down to the element type of an array.  */
 
@@ -3846,7 +2773,11 @@ lang_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
@@ -3898,64 +2829,314 @@ lang_get_alias_set (t)
         technically, an `int **' and `const int **' cannot point at
         the same thing.
 
-         But, the standard is wrong.  In particular, this code is
-        legal C++:
+         But, the standard is wrong.  In particular, this code is
+        legal C++:
+
+            int *ip;
+            int **ipp = &ip;
+            const int* const* cipp = &ipp;
+
+         And, it doesn't make sense for that to be legal unless you
+        can dereference IPP and CIPP.  So, we ignore cv-qualifiers on
+        the pointed-to types.  This issue has been reported to the
+        C++ committee.  */
+      t1 = build_type_no_quals (t);
+      if (t1 != t)
+       return get_alias_set (t1);
+    }
+  /* 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).  */
 
-            int *ip;
-            int **ipp = &ip;
-            const int* const* cipp = &ip;
+tree
+c_alignof_expr (expr)
+     tree expr;
+{
+  tree t;
 
-         And, it doesn't make sense for that to be legal unless you
-        can dereference IPP and CIPP.  So, we ignore cv-qualifiers on
-        the pointed-to types.  This issue has been reported to the
-        C++ committee.  */
-      t1 = TYPE_MAIN_VARIANT (TREE_TYPE (t));
-      t1 = ((TREE_CODE (t) == POINTER_TYPE)
-          ? build_pointer_type (t1) : build_reference_type (t1));
-      if (t1 != t)
-       return get_alias_set (t1);
+  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;
     }
-  /* 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;
+  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;
 
-  return -1;
-}
+         t = TREE_OPERAND (t, 0);
+         thisalign = TYPE_ALIGN (TREE_TYPE (TREE_TYPE (t)));
+         if (thisalign > bestalign)
+           best = t, bestalign = thisalign;
+       }
+      return c_alignof (TREE_TYPE (TREE_TYPE (best)));
+    }
+  else
+    return c_alignof (TREE_TYPE (expr));
 
+  return fold (build1 (NOP_EXPR, c_size_type_node, t));
+}
+\f
 /* Build tree nodes and builtin functions common to both C and C++ language
-   frontends.
-   CPLUS_MODE is nonzero if we are called from the C++ frontend, we generate
-   some stricter prototypes in that case.
-   NO_BUILTINS and NO_NONANSI_BUILTINS contain the respective values of
-   the language frontend flags flag_no_builtin and
-   flag_no_nonansi_builtin.  */
+   frontends.  */
 
 void
-c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_builtins)
-    int cplus_mode, no_builtins, no_nonansi_builtins;
+c_common_nodes_and_builtins ()
 {
-  tree temp;
-  tree memcpy_ftype, memset_ftype, strlen_ftype;
-  tree bzero_ftype, bcmp_ftype;
-  tree endlink, int_endlink, double_endlink, unsigned_endlink;
-  tree sizetype_endlink;
-  tree ptr_ftype, ptr_ftype_unsigned;
-  tree void_ftype_any, void_ftype_int, int_ftype_any;
-  tree double_ftype_double, double_ftype_double_double;
-  tree float_ftype_float, ldouble_ftype_ldouble;
-  tree int_ftype_cptr_cptr_sizet;
-  tree int_ftype_string_string, string_ftype_ptr_ptr;
-  tree long_ftype_long;
+  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;
   /* Either char* or void*.  */
   tree traditional_ptr_type_node;
   /* Either const char* or const void*.  */
   tree traditional_cptr_type_node;
   tree traditional_len_type_node;
-  tree traditional_len_endlink;
   tree va_list_ref_type_node;
   tree va_list_arg_type_node;
 
+  /* Define `int' and `char' first so that dbx will output them first.  */
+  record_builtin_type (RID_INT, NULL, 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 type_for_size and type_for_mode use.  */
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intQI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intHI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intSI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("__int128_t"), intTI_type_node));
+#endif
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intHI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intSI_type_node));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
+#if HOST_BITS_PER_WIDE_INT >= 64
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("__uint128_t"), unsigned_intTI_type_node));
+#endif
+
+  /* Create the widest literal types.  */
+  widest_integer_literal_type_node
+    = make_signed_type (HOST_BITS_PER_WIDE_INT * 2);
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+                       widest_integer_literal_type_node));
+
+  widest_unsigned_literal_type_node
+    = make_unsigned_type (HOST_BITS_PER_WIDE_INT * 2);
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE,
+                       widest_unsigned_literal_type_node));
+
+  /* `unsigned long' is the standard type for sizeof.
+     Note that stddef.h uses `unsigned long',
+     and this must agree, even if long and int are the same size.  */
+  c_size_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
+  signed_size_type_node = signed_type (c_size_type_node);
+  if (flag_traditional)
+    c_size_type_node = signed_size_type_node;
+  set_sizetype (c_size_type_node);
+
+  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);
+
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex int"),
+                       complex_integer_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex float"),
+                       complex_float_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex double"),
+                       complex_double_type_node));
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("complex long double"),
+                       complex_long_double_type_node));
+
+  record_builtin_type (RID_VOID, NULL, void_type_node);
+
+  void_zero_node = build_int_2 (0, 0);
+  TREE_TYPE (void_zero_node) = void_type_node;
+
+  void_list_node = build_void_list_node ();
+
+  /* Make a type to be the domain of a few array types
+     whose domains don't really matter.
+     200 is small enough that it always fits in size_t
+     and large enough that it can hold most function names for the
+     initializations of __FUNCTION__ and __PRETTY_FUNCTION__.  */
+  array_domain_type = build_index_type (size_int (200));
+
+  /* Make a type for arrays of characters.
+     With luck nothing will ever really depend on the length of this
+     array type.  */
+  char_array_type_node
+    = build_array_type (char_type_node, array_domain_type);
+
+  /* Likewise for arrays of ints.  */
+  int_array_type_node
+    = build_array_type (integer_type_node, array_domain_type);
+
+  string_type_node = build_pointer_type (char_type_node);
+  const_string_type_node
+    = build_pointer_type (build_qualified_type
+                         (char_type_node, TYPE_QUAL_CONST));
+
+  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);
+
+  (*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 = signed_type (wchar_type_node);
+      unsigned_wchar_type_node = unsigned_type (wchar_type_node);
+    }
+
+  /* This is for wide string constants.  */
+  wchar_array_type_node
+    = build_array_type (wchar_type_node, array_domain_type);
+
+  wint_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (WINT_TYPE)));
+
+  intmax_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (INTMAX_TYPE)));
+  uintmax_type_node =
+    TREE_TYPE (identifier_global_value (get_identifier (UINTMAX_TYPE)));
+
+  default_function_type = build_function_type (integer_type_node, NULL_TREE);
+  ptrdiff_type_node
+    = TREE_TYPE (identifier_global_value (get_identifier (PTRDIFF_TYPE)));
+  unsigned_ptrdiff_type_node = unsigned_type (ptrdiff_type_node);
+
   pushdecl (build_decl (TYPE_DECL, get_identifier ("__builtin_va_list"),
                        va_list_type_node));
 
@@ -3976,418 +3157,140 @@ c_common_nodes_and_builtins (cplus_mode, no_builtins, no_nonansi_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);
-
-  ptr_ftype = build_function_type (ptr_type_node, NULL_TREE);
-  ptr_ftype_unsigned = build_function_type (ptr_type_node, unsigned_endlink);
-  sizetype_endlink = tree_cons (NULL_TREE, TYPE_DOMAIN (sizetype), endlink);
-  /* We realloc here because sizetype could be int or unsigned.  S'ok.  */
-  ptr_ftype_sizetype = build_function_type (ptr_type_node, sizetype_endlink);
-
-  int_ftype_any = build_function_type (integer_type_node, NULL_TREE);
-  void_ftype_any = build_function_type (void_type_node, NULL_TREE);
-  void_ftype = build_function_type (void_type_node, endlink);
-  void_ftype_int = build_function_type (void_type_node, int_endlink);
-  void_ftype_ptr
-    = build_function_type (void_type_node,
-                          tree_cons (NULL_TREE, ptr_type_node, endlink));
-
-  float_ftype_float
-    = build_function_type (float_type_node,
-                          tree_cons (NULL_TREE, float_type_node, endlink));
-
-  double_ftype_double
-    = build_function_type (double_type_node, double_endlink);
-
-  ldouble_ftype_ldouble
-    = build_function_type (long_double_type_node,
-                          tree_cons (NULL_TREE, long_double_type_node,
-                                     endlink));
-
-  double_ftype_double_double
-    = build_function_type (double_type_node,
-                          tree_cons (NULL_TREE, double_type_node,
-                                     double_endlink));
-
-  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));
-
-  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,
-                                                tree_cons (NULL_TREE,
-                                                           sizetype,
-                                                           endlink))));
-
-  void_zero_node = build_int_2 (0, 0);
-  TREE_TYPE (void_zero_node) = void_type_node;
-
-  /* Prototype for strcpy.  */
-  string_ftype_ptr_ptr
-    = build_function_type (string_type_node,
-                          tree_cons (NULL_TREE, string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  traditional_len_type_node = (flag_traditional && ! cplus_mode
+  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_string_string
-    = build_function_type (integer_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     tree_cons (NULL_TREE,
-                                                const_string_type_node,
-                                                endlink)));
-
-  /* Prototype for strlen.  */
-  strlen_ftype
-    = build_function_type (traditional_len_type_node,
-                          tree_cons (NULL_TREE, const_string_type_node,
-                                     endlink));
-
-  traditional_ptr_type_node = (flag_traditional && ! cplus_mode
-                              ? string_type_node : ptr_type_node);
-  traditional_cptr_type_node = (flag_traditional && ! cplus_mode
-                              ? 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,
-                                                tree_cons (NULL_TREE,
-                                                           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)));
-
-  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 ("__builtin_ffs", int_ftype_int, BUILT_IN_FFS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  /* Define alloca, ffs as builtins.
-     Declare _exit just to mark it as volatile.  */
-  if (! no_builtins && ! no_nonansi_builtins)
-    {
-#ifndef SMALL_STACK
-      temp = builtin_function ("alloca", ptr_ftype_sizetype,
-                              BUILT_IN_ALLOCA, BUILT_IN_NORMAL, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-#endif
-      temp = builtin_function ("ffs", int_ftype_int, BUILT_IN_FFS,
-                              BUILT_IN_NORMAL, NULL_PTR);
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("_exit", void_ftype_int,
-                              0, NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-      /* Suppress error if redefined as a non-function.  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-
-      /* 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.  */
-      temp = builtin_function ("bzero", void_ftype_any,
-                              BUILT_IN_BZERO, BUILT_IN_NORMAL, NULL_PTR);
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-      temp = builtin_function ("bcmp", int_ftype_any,
-                              BUILT_IN_BCMP, BUILT_IN_NORMAL, NULL_PTR);
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-    }
-
-  builtin_function ("__builtin_abs", int_ftype_int, BUILT_IN_ABS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_fabsf", float_ftype_float, BUILT_IN_FABS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_fabs", double_ftype_double, BUILT_IN_FABS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  builtin_function ("__builtin_labs", long_ftype_long, BUILT_IN_LABS,
-                   BUILT_IN_NORMAL, NULL_PTR);
-  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,
-                                                   tree_cons (NULL_TREE,
-                                                              integer_type_node,
-                                                              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,
-                              tree_cons (NULL_TREE,
-                                         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 ("__builtin_memcpy", memcpy_ftype, BUILT_IN_MEMCPY,
-                   BUILT_IN_NORMAL, "memcpy");
-  builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
-                   BUILT_IN_MEMCMP, BUILT_IN_NORMAL, "memcmp");
-  builtin_function ("__builtin_memset", memset_ftype,
-                   BUILT_IN_MEMSET, BUILT_IN_NORMAL, "memset");
-  builtin_function ("__builtin_bzero", bzero_ftype,
-                   BUILT_IN_BZERO, BUILT_IN_NORMAL, "bzero");
-  builtin_function ("__builtin_bcmp", bcmp_ftype,
-                   BUILT_IN_BCMP, BUILT_IN_NORMAL, "bcmp");
-  builtin_function ("__builtin_strcmp", int_ftype_string_string,
-                   BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
-  builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
-                   BUILT_IN_STRCPY, BUILT_IN_NORMAL, "strcpy");
-  builtin_function ("__builtin_strlen", strlen_ftype,
-                   BUILT_IN_STRLEN, BUILT_IN_NORMAL, "strlen");
-  builtin_function ("__builtin_sqrtf", float_ftype_float,
-                   BUILT_IN_FSQRT, BUILT_IN_NORMAL, "sqrtf");
-  builtin_function ("__builtin_fsqrt", double_ftype_double,
-                   BUILT_IN_FSQRT, BUILT_IN_NORMAL, "sqrt");
-  builtin_function ("__builtin_sqrtl", ldouble_ftype_ldouble,
-                   BUILT_IN_FSQRT, BUILT_IN_NORMAL, "sqrtl");
-  builtin_function ("__builtin_sinf", float_ftype_float,
-                   BUILT_IN_SIN, BUILT_IN_NORMAL, "sinf");
-  builtin_function ("__builtin_sin", double_ftype_double,
-                   BUILT_IN_SIN, BUILT_IN_NORMAL, "sin");
-  builtin_function ("__builtin_sinl", ldouble_ftype_ldouble,
-                   BUILT_IN_SIN, BUILT_IN_NORMAL, "sinl");
-  builtin_function ("__builtin_cosf", float_ftype_float,
-                   BUILT_IN_COS, BUILT_IN_NORMAL, "cosf");
-  builtin_function ("__builtin_cos", double_ftype_double,
-                   BUILT_IN_COS, BUILT_IN_NORMAL, "cos");
-  builtin_function ("__builtin_cosl", ldouble_ftype_ldouble,
-                   BUILT_IN_COS, BUILT_IN_NORMAL, "cosl");
-  /* 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_FPUTC] =
-    builtin_function ("__builtin_fputc", int_ftype_any,
-                     BUILT_IN_FPUTC, BUILT_IN_NORMAL, "fputc");
-  built_in_decls[BUILT_IN_FPUTS] =
-    builtin_function ("__builtin_fputs", int_ftype_any,
-                     BUILT_IN_FPUTS, BUILT_IN_NORMAL, "fputs");
-
-  if (! no_builtins)
-    {
-      builtin_function ("abs", int_ftype_int, BUILT_IN_ABS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("fabsf", float_ftype_float, BUILT_IN_FABS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("fabs", double_ftype_double, BUILT_IN_FABS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("fabsl", ldouble_ftype_ldouble, BUILT_IN_FABS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("labs", long_ftype_long, BUILT_IN_LABS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sqrt", double_ftype_double, BUILT_IN_FSQRT,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sqrtl", ldouble_ftype_ldouble, BUILT_IN_FSQRT,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sinf", float_ftype_float, BUILT_IN_SIN,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sin", double_ftype_double, BUILT_IN_SIN,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("sinl", ldouble_ftype_ldouble, BUILT_IN_SIN,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("cosf", float_ftype_float, BUILT_IN_COS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("cos", double_ftype_double, BUILT_IN_COS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("cosl", ldouble_ftype_ldouble, BUILT_IN_COS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      /* 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.  */
-      builtin_function ("fputc", int_ftype_any, BUILT_IN_FPUTC,
-                       BUILT_IN_NORMAL, NULL_PTR);
-      builtin_function ("fputs", int_ftype_any, BUILT_IN_FPUTS,
-                       BUILT_IN_NORMAL, NULL_PTR);
-
-      /* Declare these functions volatile
-        to avoid spurious "control drops through" warnings.  */
-      temp = builtin_function ("abort", cplus_mode ? void_ftype : void_ftype_any,
-                              0, NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-
-#if 0 /* ??? The C++ frontend used to do this.  */
-      /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
-        them...  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-#endif
-      temp = builtin_function ("exit",
-                              cplus_mode ? void_ftype_int : void_ftype_any,
-                              0, NOT_BUILT_IN, NULL_PTR);
-      TREE_THIS_VOLATILE (temp) = 1;
-      TREE_SIDE_EFFECTS (temp) = 1;
-
-#if 0 /* ??? The C++ frontend used to do this.  */
-      /* Well, these are actually ANSI, but we can't set DECL_BUILT_IN on
-        them...  */
-      DECL_BUILT_IN_NONANSI (temp) = 1;
-#endif
-    }
 
-#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
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+  builtin_types[(int) ENUM] = VALUE;
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN)              \
+  builtin_types[(int) ENUM]                            \
+    = build_function_type (builtin_types[(int) RETURN],        \
+                          void_list_node);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1)                                \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN],                        \
+                          tree_cons (NULL_TREE,                        \
+                                     builtin_types[(int) ARG1],        \
+                                     void_list_node));
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2)  \
+  builtin_types[(int) ENUM]                            \
+    = build_function_type                              \
+      (builtin_types[(int) RETURN],                    \
+       tree_cons (NULL_TREE,                           \
+                 builtin_types[(int) ARG1],            \
+                 tree_cons (NULL_TREE,                 \
+                            builtin_types[(int) ARG2], \
+                            void_list_node)));
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3)             \
+  builtin_types[(int) ENUM]                                             \
+    = build_function_type                                               \
+      (builtin_types[(int) RETURN],                                     \
+       tree_cons (NULL_TREE,                                            \
+                 builtin_types[(int) ARG1],                             \
+                 tree_cons (NULL_TREE,                                  \
+                            builtin_types[(int) ARG2],                  \
+                            tree_cons (NULL_TREE,                       \
+                                       builtin_types[(int) ARG3],       \
+                                       void_list_node))));
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4)      \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type                                              \
+      (builtin_types[(int) RETURN],                                    \
+       tree_cons (NULL_TREE,                                           \
+                 builtin_types[(int) ARG1],                            \
+                 tree_cons (NULL_TREE,                                 \
+                            builtin_types[(int) ARG2],                 \
+                            tree_cons                                  \
+                            (NULL_TREE,                                \
+                             builtin_types[(int) ARG3],                \
+                             tree_cons (NULL_TREE,                     \
+                                        builtin_types[(int) ARG4],     \
+                                        void_list_node)))));
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN)                          \
+  builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN], NULL_TREE);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1)                     \
+   builtin_types[(int) ENUM]                                            \
+    = build_function_type (builtin_types[(int) RETURN],                 \
+                          tree_cons (NULL_TREE,                         \
+                                     builtin_types[(int) ARG1],         \
+                                     NULL_TREE));
+
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2)      \
+   builtin_types[(int) ENUM]                                   \
+    = build_function_type                                      \
+      (builtin_types[(int) RETURN],                            \
+       tree_cons (NULL_TREE,                                   \
+                 builtin_types[(int) ARG1],                    \
+                 tree_cons (NULL_TREE,                         \
+                            builtin_types[(int) ARG2],         \
+                            NULL_TREE)));
+#define DEF_POINTER_TYPE(ENUM, TYPE)                   \
+  builtin_types[(int) ENUM]                            \
+    = build_pointer_type (builtin_types[(int) TYPE]);
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_POINTER_TYPE
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS,                                 \
+                    TYPE, LIBTYPE, BOTH_P, FALLBACK_P, NONANSI_P)      \
+  if (NAME)                                                            \
+    {                                                                  \
+      tree decl;                                                       \
+                                                                       \
+      if (strncmp (NAME, "__builtin_", strlen ("__builtin_")) != 0)    \
+       abort ();                                                       \
+                                                                       \
+      if (!BOTH_P)                                                     \
+       decl = builtin_function (NAME, builtin_types[TYPE], ENUM,       \
+                                CLASS,                                 \
+                                (FALLBACK_P                            \
+                                 ? (NAME + strlen ("__builtin_"))      \
+                                 : NULL));                             \
+      else                                                             \
+       decl = builtin_function_2 (NAME,                                \
+                                  NAME + strlen ("__builtin_"),        \
+                                  builtin_types[TYPE],                 \
+                                  builtin_types[LIBTYPE],              \
+                                  ENUM,                                \
+                                  CLASS,                               \
+                                  FALLBACK_P,                          \
+                                  NONANSI_P,                           \
+                                  /*noreturn_p=*/0);                   \
+                                                                       \
+      built_in_decls[(int) ENUM] = decl;                               \
+    }                                                                  
+#include "builtins.def"
+#undef DEF_BUILTIN
+
+  /* Declare _exit and _Exit just to mark them as non-returning.  */
+  builtin_function_2 (NULL, "_exit", NULL_TREE, 
+                     builtin_types[BT_FN_VOID_INT],
+                     0, NOT_BUILT_IN, 0, 1, 1);
+  builtin_function_2 (NULL, "_Exit", NULL_TREE, 
+                     builtin_types[BT_FN_VOID_INT],
+                     0, NOT_BUILT_IN, 0, !flag_isoc99, 1);
+
+  /* Declare these functions non-returning
+     to avoid spurious "control drops through" warnings.  */
+  builtin_function_2 (NULL, "abort",
+                     NULL_TREE, ((c_language == clk_cplusplus)
+                                 ? builtin_types[BT_FN_VOID]
+                                 : builtin_types[BT_FN_VOID_VAR]),
+                     0, NOT_BUILT_IN, 0, 0, 1);
+
+  builtin_function_2 (NULL, "exit",
+                     NULL_TREE, ((c_language == clk_cplusplus)
+                                 ? builtin_types[BT_FN_VOID_INT]
+                                 : builtin_types[BT_FN_VOID_VAR]),
+                     0, NOT_BUILT_IN, 0, 0, 1);
 
   main_identifier_node = get_identifier ("main");
 
@@ -4402,7 +3305,92 @@ build_va_arg (expr, type)
 {
   return build1 (VA_ARG_EXPR, type, expr);
 }
+
+
+/* Possibly define a builtin function with one or two names.  BUILTIN_NAME
+   is an __builtin_-prefixed name; NAME is the ordinary name; one or both
+   of these may be NULL (though both being NULL is useless).
+   BUILTIN_TYPE is the type of the __builtin_-prefixed function;
+   TYPE is the type of the function with the ordinary name.  These
+   may differ if the ordinary name is declared with a looser type to avoid
+   conflicts with headers.  FUNCTION_CODE and CLASS are as for
+   builtin_function.  If LIBRARY_NAME_P is nonzero, NAME is passed as
+   the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME.
+   If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name; if
+   NORETURN_P is nonzero, the function is marked as non-returning.
+   Returns the declaration of BUILTIN_NAME, if any, otherwise
+   the declaration of NAME.  Does not declare NAME if flag_no_builtin,
+   or if NONANSI_P and flag_no_nonansi_builtin.  */
+
+static tree
+builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
+                   class, library_name_p, nonansi_p, noreturn_p)
+     const char *builtin_name;
+     const char *name;
+     tree builtin_type;
+     tree type;
+     int function_code;
+     enum built_in_class class;
+     int library_name_p;
+     int nonansi_p;
+     int noreturn_p;
+{
+  tree bdecl = NULL_TREE;
+  tree decl = NULL_TREE;
+  if (builtin_name != 0)
+    {
+      bdecl = builtin_function (builtin_name, builtin_type, function_code,
+                               class, library_name_p ? name : NULL);
+      if (noreturn_p)
+       {
+         TREE_THIS_VOLATILE (bdecl) = 1;
+         TREE_SIDE_EFFECTS (bdecl) = 1;
+       }
+    }
+  if (name != 0 && !flag_no_builtin && !(nonansi_p && flag_no_nonansi_builtin))
+    {
+      decl = builtin_function (name, type, function_code, class, NULL);
+      if (nonansi_p)
+       DECL_BUILT_IN_NONANSI (decl) = 1;
+      if (noreturn_p)
+       {
+         TREE_THIS_VOLATILE (decl) = 1;
+         TREE_SIDE_EFFECTS (decl) = 1;
+       }
+    }
+  return (bdecl != 0 ? bdecl : decl);
+}
 \f
+/* Nonzero if the type T promotes to int.  This is (nearly) the
+   integral promotions defined in ISO C99 6.3.1.1/2.  */
+
+bool
+c_promoting_integer_type_p (t)
+     tree t;
+{
+  switch (TREE_CODE (t))
+    {
+    case INTEGER_TYPE:
+      return (TYPE_MAIN_VARIANT (t) == char_type_node
+             || TYPE_MAIN_VARIANT (t) == signed_char_type_node
+             || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node
+             || TYPE_MAIN_VARIANT (t) == short_integer_type_node
+             || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node);
+
+    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
@@ -4417,7 +3405,7 @@ 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.  */
@@ -4452,12 +3440,25 @@ 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;
 }
 
+/* Recursively examines the array elements of TYPE, until a non-array
+   element type is found.  */
+
+tree
+strip_array_types (type)
+     tree type;
+{
+  while (TREE_CODE (type) == ARRAY_TYPE)
+    type = TREE_TYPE (type);
+
+  return type;
+}
+
 /* 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.  */
@@ -4479,11 +3480,36 @@ expand_tree_builtin (function, params, coerced_params)
     {
     case BUILT_IN_ABS:
     case BUILT_IN_LABS:
+    case BUILT_IN_LLABS:
+    case BUILT_IN_IMAXABS:
     case BUILT_IN_FABS:
+    case BUILT_IN_FABSL:
+    case BUILT_IN_FABSF:
       if (coerced_params == 0)
        return integer_zero_node;
       return build_unary_op (ABS_EXPR, TREE_VALUE (coerced_params), 0);
 
+    case BUILT_IN_CONJ:
+    case BUILT_IN_CONJF:
+    case BUILT_IN_CONJL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (CONJ_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_CREAL:
+    case BUILT_IN_CREALF:
+    case BUILT_IN_CREALL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (REALPART_EXPR, TREE_VALUE (coerced_params), 0);
+
+    case BUILT_IN_CIMAG:
+    case BUILT_IN_CIMAGF:
+    case BUILT_IN_CIMAGL:
+      if (coerced_params == 0)
+       return integer_zero_node;
+      return build_unary_op (IMAGPART_EXPR, TREE_VALUE (coerced_params), 0);
+
     case BUILT_IN_ISGREATER:
       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT)
        code = UNLE_EXPR;
@@ -4592,7 +3618,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
@@ -4638,25 +3664,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.  */
@@ -4842,6 +3868,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.  */
@@ -4909,6 +3968,20 @@ c_expand_expr (exp, target, tmode, modifier)
       }
       break;
       
+    case CALL_EXPR:
+      {
+       if (TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
+           && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == FUNCTION_DECL)
+           && DECL_BUILT_IN (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+           && (DECL_BUILT_IN_CLASS (TREE_OPERAND (TREE_OPERAND (exp, 0), 0))
+               == BUILT_IN_FRONTEND))
+         return c_expand_builtin (exp, target, tmode, modifier);
+       else
+         abort();
+      }
+      break;
+
     default:
       abort ();
     }
@@ -4945,7 +4018,21 @@ c_safe_from_p (target, exp)
   return 1;
 }
 
-/* Tree code classes. */
+/* Hook used by unsafe_for_reeval to handle language-specific tree codes.  */
+
+int
+c_unsafe_for_reeval (exp)
+     tree exp;
+{
+  /* Statement expressions may not be reevaluated.  */
+  if (TREE_CODE (exp) == STMT_EXPR)
+    return 2;
+
+  /* Walk all other expressions.  */
+  return -1;
+}
+
+/* Tree code classes.  */
 
 #define DEFTREECODE(SYM, NAME, TYPE, LENGTH) TYPE,
 
@@ -4978,7 +4065,7 @@ static const char *c_tree_code_name[] = {
 #undef DEFTREECODE
 
 /* Adds the tree codes specific to the C front end to the list of all
-   tree codes. */
+   tree codes.  */
 
 void
 add_c_tree_codes ()
@@ -4992,4 +4079,327 @@ add_c_tree_codes ()
   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;
+}
+
+#define CALLED_AS_BUILT_IN(NODE) \
+   (!strncmp (IDENTIFIER_POINTER (DECL_NAME (NODE)), "__builtin_", 10))
+
+static rtx
+c_expand_builtin (exp, target, tmode, modifier)
+     tree exp;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+{
+  tree type = TREE_TYPE (exp);
+  tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
+  tree arglist = TREE_OPERAND (exp, 1);
+  enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+  enum tree_code code = TREE_CODE (exp);
+  const int ignore = (target == const0_rtx
+                     || ((code == NON_LVALUE_EXPR || code == NOP_EXPR
+                          || code == CONVERT_EXPR || code == REFERENCE_EXPR
+                          || code == COND_EXPR)
+                         && TREE_CODE (type) == VOID_TYPE));
+
+  if (! optimize && ! CALLED_AS_BUILT_IN (fndecl))
+    return expand_call (exp, target, ignore);
+
+  switch (fcode)
+    {
+    case BUILT_IN_PRINTF:
+      target = c_expand_builtin_printf (arglist, target, tmode,
+                                       modifier, ignore);
+      if (target)
+       return target;
+      break;
+
+    case BUILT_IN_FPRINTF:
+      target = c_expand_builtin_fprintf (arglist, target, tmode,
+                                        modifier, ignore);
+      if (target)
+       return target;
+      break;
+
+    default:                   /* just do library call, if unknown builtin */
+      error ("built-in function `%s' not currently supported",
+            IDENTIFIER_POINTER (DECL_NAME (fndecl)));
+    }
+
+  /* The switch statement above can drop through to cause the function
+     to be called normally.  */
+  return expand_call (exp, target, ignore);
+}
+
+/* Check an arglist to *printf for problems.  The arglist should start
+   at the format specifier, with the remaining arguments immediately
+   following it.  */
+static int
+is_valid_printf_arglist (arglist)
+  tree arglist;
+{
+  /* Save this value so we can restore it later.  */
+  const int SAVE_pedantic = pedantic;
+  int diagnostic_occurred = 0;
+
+  /* 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'.  */
+  pedantic = SAVE_pedantic;
+
+  /* If calling `check_function_format_ptr' produces a warning, we
+     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.  */
+static rtx
+c_expand_builtin_printf (arglist, target, tmode, modifier, ignore)
+     tree arglist;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+     int ignore;
+{
+  tree fn_putchar = built_in_decls[BUILT_IN_PUTCHAR],
+    fn_puts = built_in_decls[BUILT_IN_PUTS];
+  tree fn, format_arg, stripped_string;
+
+  /* If the return value is used, or the replacement _DECL isn't
+     initialized, don't do the transformation.  */
+  if (!ignore || !fn_putchar || !fn_puts)
+    return 0;
+
+  /* Verify the required arguments in the original call.  */
+  if (arglist == 0
+      || (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE))
+    return 0;
+  
+  /* Check the specifier vs. the parameters.  */
+  if (!is_valid_printf_arglist (arglist))
+    return 0;
+  
+  format_arg = TREE_VALUE (arglist);
+  stripped_string = format_arg;
+  STRIP_NOPS (stripped_string);
+  if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
+    stripped_string = TREE_OPERAND (stripped_string, 0);
+
+  /* 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\n", call __builtin_puts(arg2).  */
+  if (strcmp (TREE_STRING_POINTER (stripped_string), "%s\n") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_puts;
+    }
+  /* If the format specifier was "%c", call __builtin_putchar (arg2).  */
+  else if (strcmp (TREE_STRING_POINTER (stripped_string), "%c") == 0)
+    {
+      arglist = TREE_CHAIN (arglist);
+      fn = fn_putchar;
+    }
+  else
+    {
+     /* We can't handle anything else with % args or %% ... yet.  */
+      if (strchr (TREE_STRING_POINTER (stripped_string), '%'))
+       return 0;
+      
+      /* If the resulting constant string has a length of 1, call
+         putchar.  Note, TREE_STRING_LENGTH includes the terminating
+         NULL in its count.  */
+      if (TREE_STRING_LENGTH (stripped_string) == 2)
+        {
+         /* Given printf("c"), (where c is any one character,)
+             convert "c"[0] to an int and pass that to the replacement
+             function.  */
+         arglist = build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0);
+         arglist = build_tree_list (NULL_TREE, arglist);
+         
+         fn = fn_putchar;
+        }
+      /* If the resulting constant was "string\n", call
+         __builtin_puts("string").  Ensure "string" has at least one
+         character besides the trailing \n.  Note, TREE_STRING_LENGTH
+         includes the terminating NULL in its count.  */
+      else if (TREE_STRING_LENGTH (stripped_string) > 2
+              && TREE_STRING_POINTER (stripped_string)
+              [TREE_STRING_LENGTH (stripped_string) - 2] == '\n')
+        {
+         /* Create a NULL-terminated string that's one char shorter
+            than the original, stripping off the trailing '\n'.  */
+         const int newlen = TREE_STRING_LENGTH (stripped_string) - 1;
+         char *newstr = (char *) alloca (newlen);
+         memcpy (newstr, TREE_STRING_POINTER (stripped_string), newlen - 1);
+         newstr[newlen - 1] = 0;
+         
+         arglist = combine_strings (build_string (newlen, newstr));
+         arglist = build_tree_list (NULL_TREE, arglist);
+         fn = fn_puts;
+       }
+      else
+       /* We'd like to arrange to call fputs(string) here, but we
+           need stdout and don't have a way to get it ... yet.  */
+       return 0;
+    }
+  
+  return expand_expr (build_function_call (fn, arglist),
+                     (ignore ? const0_rtx : target),
+                     tmode, modifier);
+}
+
+/* If the arguments passed to fprintf are suitable for optimizations,
+   we attempt to transform the call.  */
+static rtx
+c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore)
+     tree arglist;
+     rtx target;
+     enum machine_mode tmode;
+     enum expand_modifier modifier;
+     int ignore;
+{
+  tree fn_fputc = built_in_decls[BUILT_IN_FPUTC],
+    fn_fputs = 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
+   or decrement (as indicated by CODE) of ARG.  The front end must check for
+   invalid cases (e.g., decrement in C++).  */
+tree
+boolean_increment (code, arg)
+     enum tree_code code;
+     tree arg;
+{
+  tree val;
+  tree true_res = (c_language == clk_cplusplus
+                  ? boolean_true_node
+                  : c_bool_true_node);
+  arg = stabilize_reference (arg);
+  switch (code)
+    {
+    case PREINCREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+      break;
+    case POSTINCREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, true_res);
+      arg = save_expr (arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+      break;
+    case PREDECREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+      break;
+    case POSTDECREMENT_EXPR:
+      val = build (MODIFY_EXPR, TREE_TYPE (arg), arg, invert_truthvalue (arg));
+      arg = save_expr (arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), val, arg);
+      val = build (COMPOUND_EXPR, TREE_TYPE (arg), arg, val);
+      break;
+    default:
+      abort ();
+    }
+  TREE_SIDE_EFFECTS (val) = 1;
+  return val;
+}
+\f
+
+/* Do the parts of lang_init common to C and C++.  */
+void
+c_common_lang_init ()
+{
+  /* If still "unspecified", make it match -fbounded-pointers.  */
+  if (flag_bounds_check < 0)
+    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");
 }