OSDN Git Service

(handle_braces): Rework last change.
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index b71a425..1e2f6c5 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines shared by all languages that are variants of C.
-   Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
 
 #include "config.h"
 #include "tree.h"
@@ -26,9 +27,29 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include <stdio.h>
 #include <ctype.h>
 
+#ifndef WCHAR_TYPE_SIZE
+#ifdef INT_TYPE_SIZE
+#define WCHAR_TYPE_SIZE INT_TYPE_SIZE
+#else
+#define WCHAR_TYPE_SIZE        BITS_PER_WORD
+#endif
+#endif
+
 extern struct obstack permanent_obstack;
 
-static void declare_hidden_char_array PROTO((char *, char *));
+/* Nonzero means the expression being parsed will never be evaluated.
+   This is a count, since unevaluated expressions can nest.  */
+int skip_evaluation;
+
+enum attrs {A_PACKED, A_NOCOMMON, A_COMMON, A_NORETURN, A_CONST, A_T_UNION,
+           A_CONSTRUCTOR, A_DESTRUCTOR, A_MODE, A_SECTION, A_ALIGNED,
+           A_UNUSED, A_FORMAT, A_FORMAT_ARG, A_WEAK, A_ALIAS};
+
+static void declare_hidden_char_array  PROTO((char *, char *));
+static void add_attribute              PROTO((enum attrs, char *,
+                                              int, int, int));
+static void init_attributes            PROTO((void));
+static void record_international_format        PROTO((tree, tree, int));
 
 /* Make bindings for __FUNCTION__ and __PRETTY_FUNCTION__.  */
 
@@ -80,6 +101,7 @@ declare_hidden_char_array (name, value)
   TREE_READONLY (decl) = 1;
   TREE_ASM_WRITTEN (decl) = 1;
   DECL_SOURCE_LINE (decl) = 0;
+  DECL_ARTIFICIAL (decl) = 1;
   DECL_IN_SYSTEM_HEADER (decl) = 1;
   DECL_IGNORED_P (decl) = 1;
   init = build_string (vlen, value);
@@ -148,7 +170,12 @@ combine_strings (strings)
            {
              int i;
              for (i = 0; i < len; i++)
-               ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+               {
+                 if (WCHAR_TYPE_SIZE == HOST_BITS_PER_SHORT)
+                   ((short *) q)[i] = TREE_STRING_POINTER (t)[i];
+                 else
+                   ((int *) q)[i] = TREE_STRING_POINTER (t)[i];
+               }
              q += len * wchar_bytes;
            }
        }
@@ -199,242 +226,605 @@ combine_strings (strings)
   return value;
 }
 \f
-/* Process the attributes listed in ATTRIBUTES
-   and install them in DECL.  */
+/* To speed up processing of attributes, we maintain an array of
+   IDENTIFIER_NODES and the corresponding attribute types.  */
+
+/* Array to hold attribute information.  */
+
+static struct {enum attrs id; tree name; int min, max, decl_req;} attrtab[50];
+
+static int attrtab_idx = 0;
+
+/* Add an entry to the attribute table above.  */
+
+static void
+add_attribute (id, string, min_len, max_len, decl_req)
+     enum attrs id;
+     char *string;
+     int min_len, max_len;
+     int decl_req;
+{
+  char buf[100];
+
+  attrtab[attrtab_idx].id = id;
+  attrtab[attrtab_idx].name = get_identifier (string);
+  attrtab[attrtab_idx].min = min_len;
+  attrtab[attrtab_idx].max = max_len;
+  attrtab[attrtab_idx++].decl_req = decl_req;
+
+  sprintf (buf, "__%s__", string);
+
+  attrtab[attrtab_idx].id = id;
+  attrtab[attrtab_idx].name = get_identifier (buf);
+  attrtab[attrtab_idx].min = min_len;
+  attrtab[attrtab_idx].max = max_len;
+  attrtab[attrtab_idx++].decl_req = decl_req;
+}
+
+/* Initialize attribute table.  */
+
+static void
+init_attributes ()
+{
+  add_attribute (A_PACKED, "packed", 0, 0, 0);
+  add_attribute (A_NOCOMMON, "nocommon", 0, 0, 1);
+  add_attribute (A_COMMON, "common", 0, 0, 1);
+  add_attribute (A_NORETURN, "noreturn", 0, 0, 1);
+  add_attribute (A_NORETURN, "volatile", 0, 0, 1);
+  add_attribute (A_UNUSED, "unused", 0, 0, 1);
+  add_attribute (A_CONST, "const", 0, 0, 1);
+  add_attribute (A_T_UNION, "transparent_union", 0, 0, 0);
+  add_attribute (A_CONSTRUCTOR, "constructor", 0, 0, 1);
+  add_attribute (A_DESTRUCTOR, "destructor", 0, 0, 1);
+  add_attribute (A_MODE, "mode", 1, 1, 1);
+  add_attribute (A_SECTION, "section", 1, 1, 1);
+  add_attribute (A_ALIGNED, "aligned", 0, 1, 0);
+  add_attribute (A_FORMAT, "format", 3, 3, 1);
+  add_attribute (A_FORMAT_ARG, "format_arg", 1, 1, 1);
+  add_attribute (A_WEAK, "weak", 0, 0, 1);
+  add_attribute (A_ALIAS, "alias", 1, 1, 1);
+}
+\f
+/* Process the attributes listed in ATTRIBUTES and PREFIX_ATTRIBUTES
+   and install them in NODE, which is either a DECL (including a TYPE_DECL)
+   or a TYPE.  PREFIX_ATTRIBUTES can appear after the declaration specifiers
+   and declaration modifiers but before the declaration proper.  */
 
 void
-decl_attributes (decl, attributes)
-     tree decl, attributes;
+decl_attributes (node, attributes, prefix_attributes)
+     tree node, attributes, prefix_attributes;
 {
+  tree decl = 0, type;
+  int is_type;
   tree a;
 
+  if (attrtab_idx == 0)
+    init_attributes ();
+
+  if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd')
+    {
+      decl = node;
+      type = TREE_TYPE (decl);
+      is_type = TREE_CODE (node) == TYPE_DECL;
+    }
+  else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't')
+    type = node, is_type = 1;
+
+  attributes = chainon (prefix_attributes, attributes);
+
   for (a = attributes; a; a = TREE_CHAIN (a))
-    if (TREE_VALUE (a) == get_identifier ("packed"))
-      {
-       if (TREE_CODE (decl) == FIELD_DECL)
-         DECL_PACKED (decl) = 1;
-       /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
-          used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
-       else
-         warning_with_decl (decl, "`packed' attribute ignore");
-
-      }
-    else if (TREE_VALUE (a) == get_identifier ("noreturn")
-            || TREE_VALUE (a) == get_identifier ("volatile"))
-      {
-       tree type = TREE_TYPE (decl);
-
-       if (TREE_CODE (decl) == FUNCTION_DECL)
-         TREE_THIS_VOLATILE (decl) = 1;
-       else if (TREE_CODE (type) == POINTER_TYPE
-                && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-         TREE_TYPE (decl)
-           = build_pointer_type
-             (build_type_variant (TREE_TYPE (type),
-                                  TREE_READONLY (TREE_TYPE (type)), 1));
-       else
-         warning_with_decl (decl, "`%s' attribute ignored",
-                            IDENTIFIER_POINTER (TREE_VALUE (a)));
-      }
-    else if (TREE_VALUE (a) == get_identifier ("const"))
-      {
-       tree type = TREE_TYPE (decl);
-
-       if (TREE_CODE (decl) == FUNCTION_DECL)
-         TREE_READONLY (decl) = 1;
-       else if (TREE_CODE (type) == POINTER_TYPE
-                && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
-         TREE_TYPE (decl)
-           = build_pointer_type
-             (build_type_variant (TREE_TYPE (type), 1,
-                                  TREE_THIS_VOLATILE (TREE_TYPE (type))));
-       else
-         warning_with_decl (decl, "`const' attribute ignored");
-      }
-    else if (TREE_VALUE (a) != 0
-            && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
-            && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("mode"))
-      {
-       int i;
-       char *specified_name
-         = IDENTIFIER_POINTER (TREE_VALUE (TREE_VALUE (a)));
-
-       /* Give this decl a type with the specified mode.  */
-       for (i = 0; i < NUM_MACHINE_MODES; i++)
-         if (!strcmp (specified_name, GET_MODE_NAME (i)))
+    {
+      tree name = TREE_PURPOSE (a);
+      tree args = TREE_VALUE (a);
+      int i;
+      enum attrs id;
+      
+      for (i = 0; i < attrtab_idx; i++)
+       if (attrtab[i].name == name)
+         break;
+
+      if (i == attrtab_idx)
+       {
+         if (! valid_machine_attribute (name, args, decl, type))
+           warning ("`%s' attribute directive ignored",
+                    IDENTIFIER_POINTER (name));
+         else if (decl != 0)
+           type = TREE_TYPE (decl);
+         continue;
+       }
+      else if (attrtab[i].decl_req && decl == 0)
+       {
+         warning ("`%s' attribute does not apply to types",
+                  IDENTIFIER_POINTER (name));
+         continue;
+       }
+      else if (list_length (args) < attrtab[i].min
+              || list_length (args) > attrtab[i].max)
+       {
+         error ("wrong number of arguments specified for `%s' attribute",
+                IDENTIFIER_POINTER (name));
+         continue;
+       }
+
+      id = attrtab[i].id;
+      switch (id)
+       {
+       case A_PACKED:
+         if (is_type)
+           TYPE_PACKED (type) = 1;
+         else if (TREE_CODE (decl) == FIELD_DECL)
+           DECL_PACKED (decl) = 1;
+         /* We can't set DECL_PACKED for a VAR_DECL, because the bit is
+            used for DECL_REGISTER.  It wouldn't mean anything anyway.  */
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_NOCOMMON:
+         if (TREE_CODE (decl) == VAR_DECL)
+           DECL_COMMON (decl) = 0;
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_COMMON:
+         if (TREE_CODE (decl) == VAR_DECL)
+           DECL_COMMON (decl) = 1;
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_NORETURN:
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           TREE_THIS_VOLATILE (decl) = 1;
+         else if (TREE_CODE (type) == POINTER_TYPE
+                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+           TREE_TYPE (decl) = type 
+             = build_pointer_type
+               (build_type_variant (TREE_TYPE (type),
+                                    TREE_READONLY (TREE_TYPE (type)), 1));
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_UNUSED:
+         if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == VAR_DECL
+             || TREE_CODE (decl) == FUNCTION_DECL)
+           TREE_USED (decl) = 1;
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_CONST:
+         if (TREE_CODE (decl) == FUNCTION_DECL)
+           TREE_READONLY (decl) = 1;
+         else if (TREE_CODE (type) == POINTER_TYPE
+                  && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+           TREE_TYPE (decl) = type
+             = build_pointer_type
+               (build_type_variant (TREE_TYPE (type), 1,
+                                    TREE_THIS_VOLATILE (TREE_TYPE (type))));
+         else
+           warning ( "`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_T_UNION:
+         if (is_type
+             && TREE_CODE (type) == UNION_TYPE
+             && (decl == 0
+                 || (TYPE_FIELDS (type) != 0
+                     && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))))
+           TYPE_TRANSPARENT_UNION (type) = 1;
+         else if (decl != 0 && TREE_CODE (decl) == PARM_DECL
+                  && TREE_CODE (type) == UNION_TYPE
+                  && TYPE_MODE (type) == DECL_MODE (TYPE_FIELDS (type)))
+           DECL_TRANSPARENT_UNION (decl) = 1;
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_CONSTRUCTOR:
+         if (TREE_CODE (decl) == FUNCTION_DECL
+             && TREE_CODE (type) == FUNCTION_TYPE
+             && decl_function_context (decl) == 0)
+           {
+             DECL_STATIC_CONSTRUCTOR (decl) = 1;
+             TREE_USED (decl) = 1;
+           }
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_DESTRUCTOR:
+         if (TREE_CODE (decl) == FUNCTION_DECL
+             && TREE_CODE (type) == FUNCTION_TYPE
+             && decl_function_context (decl) == 0)
+           {
+             DECL_STATIC_DESTRUCTOR (decl) = 1;
+             TREE_USED (decl) = 1;
+           }
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+
+       case A_MODE:
+         if (TREE_CODE (TREE_VALUE (args)) != IDENTIFIER_NODE)
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         else
            {
-             tree type
-               = type_for_mode (i, TREE_UNSIGNED (TREE_TYPE (decl)));
-             if (type != 0)
+             int j;
+             char *p = IDENTIFIER_POINTER (TREE_VALUE (args));
+             int len = strlen (p);
+             enum machine_mode mode = VOIDmode;
+             tree typefm;
+
+             if (len > 4 && p[0] == '_' && p[1] == '_'
+                 && p[len - 1] == '_' && p[len - 2] == '_')
                {
-                 TREE_TYPE (decl) = type;
+                 char *newp = (char *) alloca (len - 1);
+
+                 strcpy (newp, &p[2]);
+                 newp[len - 4] = '\0';
+                 p = newp;
+               }
+
+             /* Give this decl a type with the specified mode.
+                First check for the special modes.  */
+             if (! strcmp (p, "byte"))
+               mode = byte_mode;
+             else if (!strcmp (p, "word"))
+               mode = word_mode;
+             else if (! strcmp (p, "pointer"))
+               mode = ptr_mode;
+             else
+               for (j = 0; j < NUM_MACHINE_MODES; j++)
+                 if (!strcmp (p, GET_MODE_NAME (j)))
+                   mode = (enum machine_mode) j;
+
+             if (mode == VOIDmode)
+               error ("unknown machine mode `%s'", p);
+             else if (0 == (typefm = type_for_mode (mode,
+                                                    TREE_UNSIGNED (type))))
+               error ("no data type for mode `%s'", p);
+             else
+               {
+                 TREE_TYPE (decl) = type = typefm;
                  DECL_SIZE (decl) = 0;
                  layout_decl (decl, 0);
                }
-             else
-               error ("no data type for mode `%s'", specified_name);
-             break;
            }
-       if (i == NUM_MACHINE_MODES)
-         error_with_decl (decl, "unknown machine mode `%s'", specified_name);
-      }
-    else if (TREE_VALUE (a) != 0
-            && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
-            && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("section"))
-      {
+         break;
+
+       case A_SECTION:
 #ifdef ASM_OUTPUT_SECTION_NAME
-       if (TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL)
-         {
-           if (TREE_CODE (decl) == VAR_DECL && current_function_decl != NULL_TREE)
-             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 (TREE_VALUE (a)))) != 0)
-             error_with_decl (decl,
-                              "section of `%s' conflicts with previous declaration");
-           else
-             DECL_SECTION_NAME (decl) = TREE_VALUE (TREE_VALUE (a));
-         }
-       else
-         error_with_decl (decl,
+         if ((TREE_CODE (decl) == FUNCTION_DECL
+              || TREE_CODE (decl) == VAR_DECL)
+             && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+           {
+             if (TREE_CODE (decl) == VAR_DECL 
+                 && current_function_decl != NULL_TREE
+                 && ! TREE_STATIC (decl))
+               error_with_decl (decl,
+                 "section attribute cannot be specified for local variables");
+             /* The decl may have already been given a section attribute from
+                a previous declaration.  Ensure they match.  */
+             else if (DECL_SECTION_NAME (decl) != NULL_TREE
+                      && strcmp (TREE_STRING_POINTER (DECL_SECTION_NAME (decl)),
+                                 TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+               error_with_decl (node,
+                                "section of `%s' conflicts with previous declaration");
+             else
+               DECL_SECTION_NAME (decl) = TREE_VALUE (args);
+           }
+         else
+           error_with_decl (node,
                           "section attribute not allowed for `%s'");
 #else
-       error_with_decl (decl, "section attributes are not supported for this target");
+         error_with_decl (node,
+                 "section attributes are not supported for this target");
 #endif
-      }
-    else if (TREE_VALUE (a) != 0
-            && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
-            && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("aligned"))
-      {
-       tree align_expr = TREE_VALUE (TREE_VALUE (a));
-       int align;
-
-       /* Strip any NOPs of any kind.  */
-       while (TREE_CODE (align_expr) == NOP_EXPR
-              || TREE_CODE (align_expr) == CONVERT_EXPR
-              || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
-         align_expr = TREE_OPERAND (align_expr, 0);
-
-       if (TREE_CODE (align_expr) != INTEGER_CST)
+         break;
+
+       case A_ALIGNED:
          {
-           error_with_decl (decl,
-                            "requested alignment of `%s' is not a constant");
-           continue;
+           tree align_expr
+             = (args ? TREE_VALUE (args)
+                : size_int (BIGGEST_ALIGNMENT / BITS_PER_UNIT));
+           int align;
+
+           /* Strip any NOPs of any kind.  */
+           while (TREE_CODE (align_expr) == NOP_EXPR
+                  || TREE_CODE (align_expr) == CONVERT_EXPR
+                  || TREE_CODE (align_expr) == NON_LVALUE_EXPR)
+             align_expr = TREE_OPERAND (align_expr, 0);
+         
+           if (TREE_CODE (align_expr) != INTEGER_CST)
+             {
+               error ("requested alignment is not a constant");
+               continue;
+             }
+
+           align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT;
+
+           if (exact_log2 (align) == -1)
+             error ("requested alignment is not a power of 2");
+           else if (is_type)
+             TYPE_ALIGN (type) = align;
+           else if (TREE_CODE (decl) != VAR_DECL
+                    && TREE_CODE (decl) != FIELD_DECL)
+             error_with_decl (decl,
+                              "alignment may not be specified for `%s'");
+           else
+             DECL_ALIGN (decl) = align;
          }
+         break;
 
-       align = TREE_INT_CST_LOW (align_expr) * BITS_PER_UNIT;
-       
-       if (exact_log2 (align) == -1)
-         error_with_decl (decl,
-                          "requested alignment of `%s' is not a power of 2");
-       else if (TREE_CODE (decl) != VAR_DECL
-                && TREE_CODE (decl) != FIELD_DECL)
-         error_with_decl (decl,
-                          "alignment specified for `%s'");
-       else
-         DECL_ALIGN (decl) = align;
-      }
-    else if (TREE_VALUE (a) != 0
-            && TREE_CODE (TREE_VALUE (a)) == TREE_LIST
-            && TREE_PURPOSE (TREE_VALUE (a)) == get_identifier ("format"))
-      {
-        tree list = TREE_VALUE (TREE_VALUE (a));
-        tree format_type = TREE_PURPOSE (list);
-       tree format_num_expr = TREE_PURPOSE (TREE_VALUE (list));
-       tree first_arg_num_expr = TREE_VALUE (TREE_VALUE (list));
-       int format_num;
-       int first_arg_num;
-       int is_scan;
-       tree argument;
-       int arg_num;
-       
-       if (TREE_CODE (decl) != FUNCTION_DECL)
+       case A_FORMAT:
          {
-           error_with_decl (decl,
-                            "argument format specified for non-function `%s'");
-           continue;
-         }
+           tree format_type = TREE_VALUE (args);
+           tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
+           tree first_arg_num_expr
+             = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
+           int format_num;
+           int first_arg_num;
+           int is_scan;
+           tree argument;
+           int arg_num;
        
-       if (format_type == get_identifier ("printf"))
-         is_scan = 0;
-       else if (format_type == get_identifier ("scanf"))
-         is_scan = 1;
-       else
-         {
-           error_with_decl (decl, "unrecognized format specifier for `%s'");
-           continue;
-         }
+           if (TREE_CODE (decl) != FUNCTION_DECL)
+             {
+               error_with_decl (decl,
+                        "argument format specified for non-function `%s'");
+               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_CODE (first_arg_num_expr) != INTEGER_CST)
-         {
-           error_with_decl (decl,
-                  "format string for `%s' has non-constant operand number");
-           continue;
-         }
+           if (TREE_CODE (format_type) == IDENTIFIER_NODE
+               && (!strcmp (IDENTIFIER_POINTER (format_type), "printf")
+                   || !strcmp (IDENTIFIER_POINTER (format_type),
+                               "__printf__")))
+             is_scan = 0;
+           else if (TREE_CODE (format_type) == IDENTIFIER_NODE
+                    && (!strcmp (IDENTIFIER_POINTER (format_type), "scanf")
+                        || !strcmp (IDENTIFIER_POINTER (format_type),
+                                    "__scanf__")))
+             is_scan = 1;
+           else if (TREE_CODE (format_type) == IDENTIFIER_NODE)
+             {
+               error ("`%s' is an unrecognized format function type",
+                      IDENTIFIER_POINTER (format_type));
+               continue;
+             }
+           else
+             {
+               error ("unrecognized format specifier");
+               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_with_decl (decl,
-             "format string arg follows the args to be formatted, for `%s'");
-           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_CODE (first_arg_num_expr) != INTEGER_CST)
+             {
+               error ("format string has non-constant 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; ; ++arg_num)
+                 {
+                   if (argument == 0 || arg_num == format_num)
+                     break;
+                   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 (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),
+                                   is_scan, format_num, first_arg_num);
+           break;
          }
 
-       /* 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 (TREE_TYPE (decl));
-       if (argument)
+       case A_FORMAT_ARG:
          {
-           for (arg_num = 1; ; ++arg_num)
+           tree format_num_expr = TREE_VALUE (args);
+           int format_num, arg_num;
+           tree argument;
+       
+           if (TREE_CODE (decl) != FUNCTION_DECL)
              {
-               if (argument == 0 || arg_num == format_num)
-                 break;
-               argument = TREE_CHAIN (argument);
+               error_with_decl (decl,
+                        "argument format specified for non-function `%s'");
+               continue;
              }
-           if (! argument
-               || TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE
-               || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
-                   != char_type_node))
+       
+           /* 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)
              {
-               error_with_decl (decl,
-                            "format string arg not a string type, for `%s'");
+               error ("format string has non-constant operand number");
                continue;
              }
-           if (first_arg_num != 0)
+
+           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)
              {
-               /* 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)
+               for (arg_num = 1; ; ++arg_num)
                  {
-                   error_with_decl (decl,
-                                "args to be formatted is not ..., for `%s'");
+                   if (argument == 0 || arg_num == format_num)
+                     break;
+                   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;
          }
 
-       record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
-                               is_scan, format_num, first_arg_num);
-      }
+       case A_WEAK:
+         declare_weak (decl);
+         break;
+
+       case A_ALIAS:
+         if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+             || (TREE_CODE (decl) != FUNCTION_DECL && ! DECL_EXTERNAL (decl)))
+           error_with_decl (decl,
+                            "`%s' defined both normally and as an alias");
+         else if (decl_function_context (decl) == 0)
+           {
+             tree id = get_identifier (TREE_STRING_POINTER
+                                       (TREE_VALUE (args)));
+             if (TREE_CODE (decl) == FUNCTION_DECL)
+               DECL_INITIAL (decl) = error_mark_node;
+             else
+               DECL_EXTERNAL (decl) = 0;
+             assemble_alias (decl, id);
+           }
+         else
+           warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+         break;
+       }
+    }
+}
+
+/* Split SPECS_ATTRS, a list of declspecs and prefix attributes, into two
+   lists.  SPECS_ATTRS may also be just a typespec (eg: RECORD_TYPE).
+
+   The head of the declspec list is stored in DECLSPECS.
+   The head of the attribute list is stored in PREFIX_ATTRIBUTES.
+
+   Note that attributes in SPECS_ATTRS are stored in the TREE_PURPOSE of
+   the list elements.  We drop the containing TREE_LIST nodes and link the
+   resulting attributes together the way decl_attributes expects them.  */
+
+void
+split_specs_attrs (specs_attrs, declspecs, prefix_attributes)
+     tree specs_attrs;
+     tree *declspecs, *prefix_attributes;
+{
+  tree t, s, a, next, specs, attrs;
+
+  /* This can happen in c++ (eg: decl: typespec initdecls ';').  */
+  if (specs_attrs != NULL_TREE
+      && TREE_CODE (specs_attrs) != TREE_LIST)
+    {
+      *declspecs = specs_attrs;
+      *prefix_attributes = NULL_TREE;
+      return;
+    }
+
+  /* Remember to keep the lists in the same order, element-wise.  */
+
+  specs = s = NULL_TREE;
+  attrs = a = NULL_TREE;
+  for (t = specs_attrs; t; t = next)
+    {
+      next = TREE_CHAIN (t);
+      /* Declspecs have a non-NULL TREE_VALUE.  */
+      if (TREE_VALUE (t) != NULL_TREE)
+       {
+         if (specs == NULL_TREE)
+           specs = s = t;
+         else
+           {
+             TREE_CHAIN (s) = t;
+             s = t;
+           }
+       }
+      else
+       {
+         if (attrs == NULL_TREE)
+           attrs = a = TREE_PURPOSE (t);
+         else
+           {
+             TREE_CHAIN (a) = TREE_PURPOSE (t);
+             a = TREE_PURPOSE (t);
+           }
+         /* More attrs can be linked here, move A to the end.  */
+         while (TREE_CHAIN (a) != NULL_TREE)
+           a = TREE_CHAIN (a);
+       }
+    }
+
+  /* Terminate the lists.  */
+  if (s != NULL_TREE)
+    TREE_CHAIN (s) = NULL_TREE;
+  if (a != NULL_TREE)
+    TREE_CHAIN (a) = NULL_TREE;
+
+  /* All done.  */
+  *declspecs = specs;
+  *prefix_attributes = attrs;
 }
 \f
 /* Check a printf/fprintf/sprintf/scanf/fscanf/sscanf format against
@@ -442,9 +832,11 @@ decl_attributes (decl, attributes)
 
 #define T_I    &integer_type_node
 #define T_L    &long_integer_type_node
+#define T_LL   &long_long_integer_type_node
 #define T_S    &short_integer_type_node
 #define T_UI   &unsigned_type_node
 #define T_UL   &long_unsigned_type_node
+#define T_ULL  &long_long_unsigned_type_node
 #define T_US   &short_unsigned_type_node
 #define T_F    &float_type_node
 #define T_D    &double_type_node
@@ -465,6 +857,9 @@ typedef struct {
   /* Type of argument if length modifier `l' is used.
      If NULL, then this modifier is not allowed.  */
   tree *llen;
+  /* Type of argument if length modifier `q' or `ll' is used.
+     If NULL, then this modifier is not allowed.  */
+  tree *qlen;
   /* Type of argument if length modifier `L' is used.
      If NULL, then this modifier is not allowed.  */
   tree *bigllen;
@@ -473,36 +868,37 @@ typedef struct {
 } format_char_info;
 
 static format_char_info print_char_table[] = {
-  { "di",      0,      T_I,    T_I,    T_L,    NULL,   "-wp0 +"        },
-  { "oxX",     0,      T_UI,   T_UI,   T_UL,   NULL,   "-wp0#"         },
-  { "u",       0,      T_UI,   T_UI,   T_UL,   NULL,   "-wp0"          },
+  { "di",      0,      T_I,    T_I,    T_L,    T_LL,   T_LL,   "-wp0 +"        },
+  { "oxX",     0,      T_UI,   T_UI,   T_UL,   T_ULL,  T_ULL,  "-wp0#"         },
+  { "u",       0,      T_UI,   T_UI,   T_UL,   T_ULL,  T_ULL,  "-wp0"          },
 /* Two GNU extensions.  */
-  { "Z",       0,      T_ST,   NULL,   NULL,   NULL,   "-wp0"          },
-  { "m",       0,      T_UI,   T_UI,   T_UL,   NULL,   "-wp"           },
-  { "feEgG",   0,      T_D,    NULL,   NULL,   T_LD,   "-wp0 +#"       },
-  { "c",       0,      T_I,    NULL,   T_W,    NULL,   "-w"            },
-  { "C",       0,      T_W,    NULL,   NULL,   NULL,   "-w"            },
-  { "s",       1,      T_C,    NULL,   T_W,    NULL,   "-wp"           },
-  { "S",       1,      T_W,    NULL,   NULL,   NULL,   "-wp"           },
-  { "p",       1,      T_V,    NULL,   NULL,   NULL,   "-w"            },
-  { "n",       1,      T_I,    T_S,    T_L,    NULL,   ""              },
+  { "Z",       0,      T_ST,   NULL,   NULL,   NULL,   NULL,   "-wp0"          },
+  { "m",       0,      T_V,    NULL,   NULL,   NULL,   NULL,   "-wp"           },
+  { "feEgG",   0,      T_D,    NULL,   NULL,   NULL,   T_LD,   "-wp0 +#"       },
+  { "c",       0,      T_I,    NULL,   T_W,    NULL,   NULL,   "-w"            },
+  { "C",       0,      T_W,    NULL,   NULL,   NULL,   NULL,   "-w"            },
+  { "s",       1,      T_C,    NULL,   T_W,    NULL,   NULL,   "-wp"           },
+  { "S",       1,      T_W,    NULL,   NULL,   NULL,   NULL,   "-wp"           },
+  { "p",       1,      T_V,    NULL,   NULL,   NULL,   NULL,   "-w"            },
+  { "n",       1,      T_I,    T_S,    T_L,    T_LL,   NULL,   ""              },
   { NULL }
 };
 
 static format_char_info scan_char_table[] = {
-  { "di",      1,      T_I,    T_S,    T_L,    NULL,   "*"     },
-  { "ouxX",    1,      T_UI,   T_US,   T_UL,   NULL,   "*"     },      
-  { "efgEG",   1,      T_F,    NULL,   T_D,    T_LD,   "*"     },
-  { "sc",      1,      T_C,    NULL,   T_W,    NULL,   "*a"    },
-  { "[",       1,      T_C,    NULL,   NULL,   NULL,   "*a"    },
-  { "C",       1,      T_W,    NULL,   NULL,   NULL,   "*"     },
-  { "S",       1,      T_W,    NULL,   NULL,   NULL,   "*"     },
-  { "p",       2,      T_V,    NULL,   NULL,   NULL,   "*"     },
-  { "n",       1,      T_I,    T_S,    T_L,    NULL,   ""      },
+  { "di",      1,      T_I,    T_S,    T_L,    T_LL,   T_LL,   "*"     },
+  { "ouxX",    1,      T_UI,   T_US,   T_UL,   T_ULL,  T_ULL,  "*"     },      
+  { "efgEG",   1,      T_F,    NULL,   T_D,    NULL,   T_LD,   "*"     },
+  { "sc",      1,      T_C,    NULL,   T_W,    NULL,   NULL,   "*a"    },
+  { "[",       1,      T_C,    NULL,   NULL,   NULL,   NULL,   "*a"    },
+  { "C",       1,      T_W,    NULL,   NULL,   NULL,   NULL,   "*"     },
+  { "S",       1,      T_W,    NULL,   NULL,   NULL,   NULL,   "*"     },
+  { "p",       2,      T_V,    NULL,   NULL,   NULL,   NULL,   "*"     },
+  { "n",       1,      T_I,    T_S,    T_L,    T_LL,   NULL,   ""      },
   { NULL }
 };
 
-typedef struct function_format_info {
+typedef struct function_format_info
+{
   struct function_format_info *next;  /* next structure on the list */
   tree name;                   /* identifier such as "printf" */
   tree assembler_name;         /* optional mangled identifier (for C++) */
@@ -513,14 +909,27 @@ typedef struct function_format_info {
 
 static function_format_info *function_format_list = NULL;
 
-static void check_format_info PROTO((function_format_info *, tree));
+typedef struct international_format_info
+{
+  struct international_format_info *next;  /* next structure on the list */
+  tree name;                   /* identifier such as "gettext" */
+  tree assembler_name;         /* optional mangled identifier (for C++) */
+  int format_num;              /* number of format argument */
+} international_format_info;
+
+static international_format_info *international_format_list = NULL;
+
+static void check_format_info          PROTO((function_format_info *, tree));
 
 /* Initialize the table of functions to perform format checking on.
    The ANSI 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 ANSI reserves these function names whether you include the
-   header file or not.  In any case, the checking is harmless.  */
+   header file or not.  In any case, the checking is harmless. 
+
+   Also initialize the name of function that modify the format string for
+   internationalization purposes.  */
 
 void
 init_function_format_info ()
@@ -534,6 +943,10 @@ init_function_format_info ()
   record_function_format (get_identifier ("vprintf"), NULL_TREE, 0, 1, 0);
   record_function_format (get_identifier ("vfprintf"), NULL_TREE, 0, 2, 0);
   record_function_format (get_identifier ("vsprintf"), NULL_TREE, 0, 2, 0);
+
+  record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
+  record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
+  record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
 }
 
 /* Record information for argument format checking.  FUNCTION_IDENT is
@@ -542,7 +955,7 @@ init_function_format_info ()
    false indicates printf-style 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 teh format string, or zero if no checking is not be done
+   against the format string, or zero if no checking is not be done
    (e.g. for varargs such as vfprintf).  */
 
 void
@@ -578,6 +991,43 @@ record_function_format (name, assembler_name, is_scan,
   info->first_arg_num = first_arg_num;
 }
 
+/* Record information for the names of function that modify the format
+   argument to format functions.  FUNCTION_IDENT is the identifier node for
+   the name of the function (its decl need not exist yet) and FORMAT_NUM is
+   the number of the argument which is the format control string (starting
+   from 1).  */
+
+static void
+record_international_format (name, assembler_name, format_num)
+      tree name;
+      tree assembler_name;
+      int format_num;
+{
+  international_format_info *info;
+
+  /* Re-use existing structure if it's there.  */
+
+  for (info = international_format_list; info; info = info->next)
+    {
+      if (info->name == name && info->assembler_name == assembler_name)
+       break;
+    }
+
+  if (! info)
+    {
+      info
+       = (international_format_info *)
+         xmalloc (sizeof (international_format_info));
+      info->next = international_format_list;
+      international_format_list = info;
+
+      info->name = name;
+      info->assembler_name = assembler_name;
+    }
+
+  info->format_num = format_num;
+}
+
 static char    tfaff[] = "too few arguments for format";
 \f
 /* Check the argument list of a call to printf, scanf, etc.
@@ -648,10 +1098,44 @@ check_format_info (info, params)
   params = TREE_CHAIN (params);
   if (format_tree == 0)
     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 (format_tree == null_pointer_node)
+
+  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);
+               }
+         }
+    }
+
+  if (integer_zerop (format_tree))
     {
       warning ("null format string");
       return;
@@ -844,10 +1328,23 @@ check_format_info (info, params)
                }
            }
        }
-      if (*format_chars == 'h' || *format_chars == 'l' || *format_chars == 'L')
+      if (*format_chars == 'h' || *format_chars == 'l')
        length_char = *format_chars++;
+      else if (*format_chars == 'q' || *format_chars == 'L')
+       {
+         length_char = *format_chars++;
+         if (pedantic)
+           pedwarn ("ANSI C does not support the `%c' length modifier",
+                    length_char);
+       }
       else
        length_char = 0;
+      if (length_char == 'l' && *format_chars == 'l')
+       {
+         length_char = 'q', format_chars++;
+         if (pedantic)
+           pedwarn ("ANSI C does not support the `ll' length modifier");
+       }
       aflag = 0;
       if (*format_chars == 'a')
        {
@@ -862,7 +1359,7 @@ check_format_info (info, params)
          warning (message);
        }
       format_char = *format_chars;
-      if (format_char == 0)
+      if (format_char == 0 || format_char == '%')
        {
          warning ("conversion lacks type at end of format");
          continue;
@@ -944,7 +1441,7 @@ check_format_info (info, params)
              || format_char == 'x' || format_char == 'x'))
        {
          sprintf (message,
-                  "precision and `0' flag not both allowed with `%c' format",
+                  "`0' flag ignored with precision specifier and `%c' format",
                   format_char);
          warning (message);
        }
@@ -953,6 +1450,7 @@ check_format_info (info, params)
        default: wanted_type = fci->nolen ? *(fci->nolen) : 0; break;
        case 'h': wanted_type = fci->hlen ? *(fci->hlen) : 0; break;
        case 'l': wanted_type = fci->llen ? *(fci->llen) : 0; break;
+       case 'q': wanted_type = fci->qlen ? *(fci->qlen) : 0; break;
        case 'L': wanted_type = fci->bigllen ? *(fci->bigllen) : 0; break;
        }
       if (wanted_type == 0)
@@ -975,6 +1473,9 @@ check_format_info (info, params)
       /* 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)
+       /* This specifier takes no argument.  */
+       continue;
       if (params == 0)
        {
          warning (tfaff);
@@ -994,16 +1495,20 @@ check_format_info (info, params)
              cur_type = TREE_TYPE (cur_type);
              continue;
            }
-         sprintf (message,
-                  "format argument is not a %s (arg %d)",
-                  ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
-                  arg_num);
-         warning (message);
+         if (TREE_CODE (cur_type) != ERROR_MARK)
+           {
+             sprintf (message,
+                      "format argument is not a %s (arg %d)",
+                      ((fci->pointer_count == 1) ? "pointer" : "pointer to a pointer"),
+                      arg_num);
+             warning (message);
+           }
          break;
        }
 
       /* Check the type of the "real" argument, if there's a type we want.  */
       if (i == fci->pointer_count && wanted_type != 0
+         && TREE_CODE (cur_type) != ERROR_MARK
          && wanted_type != TYPE_MAIN_VARIANT (cur_type)
          /* If we want `void *', allow any pointer type.
             (Anything else would already have got a warning.)  */
@@ -1078,9 +1583,10 @@ void
 constant_expression_warning (value)
      tree value;
 {
-  if (TREE_CODE (value) == INTEGER_CST && TREE_CONSTANT_OVERFLOW (value))
-    if (pedantic)
-      pedwarn ("overflow in constant expression");
+  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.
@@ -1094,10 +1600,23 @@ void
 overflow_warning (value)
      tree value;
 {
-  if (TREE_CODE (value) == INTEGER_CST && TREE_OVERFLOW (value))
+  if ((TREE_CODE (value) == INTEGER_CST
+       || (TREE_CODE (value) == COMPLEX_CST
+          && TREE_CODE (TREE_REALPART (value)) == INTEGER_CST))
+      && TREE_OVERFLOW (value))
     {
       TREE_OVERFLOW (value) = 0;
-      warning ("integer overflow in expression");
+      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");
     }
 }
 
@@ -1113,6 +1632,7 @@ unsigned_conversion_warning (result, operand)
   if (TREE_CODE (operand) == INTEGER_CST
       && TREE_CODE (TREE_TYPE (result)) == INTEGER_TYPE
       && TREE_UNSIGNED (TREE_TYPE (result))
+      && skip_evaluation == 0
       && !int_fits_type_p (operand, TREE_TYPE (result)))
     {
       if (!int_fits_type_p (operand, signed_type (TREE_TYPE (result))))
@@ -1138,16 +1658,21 @@ convert_and_check (type, expr)
        {
          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)))
-             warning ("overflow in implicit constant conversion");
+           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);
@@ -1208,15 +1733,15 @@ type_for_size (bits, unsignedp)
      unsigned bits;
      int unsignedp;
 {
+  if (bits == TYPE_PRECISION (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
   if (bits == TYPE_PRECISION (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
 
   if (bits == TYPE_PRECISION (short_integer_type_node))
     return unsignedp ? short_unsigned_type_node : short_integer_type_node;
 
-  if (bits == TYPE_PRECISION (integer_type_node))
-    return unsignedp ? unsigned_type_node : integer_type_node;
-
   if (bits == TYPE_PRECISION (long_integer_type_node))
     return unsignedp ? long_unsigned_type_node : long_integer_type_node;
 
@@ -1248,15 +1773,15 @@ type_for_mode (mode, unsignedp)
      enum machine_mode mode;
      int unsignedp;
 {
+  if (mode == TYPE_MODE (integer_type_node))
+    return unsignedp ? unsigned_type_node : integer_type_node;
+
   if (mode == TYPE_MODE (signed_char_type_node))
     return unsignedp ? unsigned_char_type_node : signed_char_type_node;
 
   if (mode == TYPE_MODE (short_integer_type_node))
     return unsignedp ? short_unsigned_type_node : short_integer_type_node;
 
-  if (mode == TYPE_MODE (integer_type_node))
-    return unsignedp ? unsigned_type_node : integer_type_node;
-
   if (mode == TYPE_MODE (long_integer_type_node))
     return unsignedp ? long_unsigned_type_node : long_integer_type_node;
 
@@ -1293,6 +1818,37 @@ type_for_mode (mode, unsignedp)
   return 0;
 }
 \f
+/* Return the minimum number of bits needed to represent VALUE in a
+   signed or unsigned type, UNSIGNEDP says which.  */
+
+int
+min_precision (value, unsignedp)
+     tree value;
+     int unsignedp;
+{
+  int log;
+
+  /* If the value is negative, compute its negative minus 1.  The latter
+     adjustment is because the absolute value of the largest negative value
+     is one larger than the largest positive value.  This is equivalent to
+     a bit-wise negation, so use that operation instead.  */
+
+  if (tree_int_cst_sgn (value) < 0)
+    value = fold (build1 (BIT_NOT_EXPR, TREE_TYPE (value), value));
+
+  /* Return the number of bits needed, taking into account the fact
+     that we need one more bit for a signed than unsigned type.  */
+
+  if (integer_zerop (value))
+    log = 0;
+  else if (TREE_INT_CST_HIGH (value) != 0)
+    log = HOST_BITS_PER_WIDE_INT + floor_log2 (TREE_INT_CST_HIGH (value));
+  else
+    log = floor_log2 (TREE_INT_CST_LOW (value));
+
+  return log + 1 + ! unsignedp;
+}
+\f
 /* Print an error message for invalid operands to arith operation CODE.
    NOP_EXPR is used as a special case (see truthvalue_conversion).  */
 
@@ -1404,9 +1960,11 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
   real2 = TREE_CODE (TREE_TYPE (primop1)) == REAL_TYPE;
 
   /* If first arg is constant, swap the args (changing operation
-     so value is preserved), for canonicalization.  */
+     so value is preserved), for canonicalization.  Don't do this if
+     the second arg is 0.  */
 
-  if (TREE_CONSTANT (primop0))
+  if (TREE_CONSTANT (primop0)
+      && ! integer_zerop (primop1) && ! real_zerop (primop1))
     {
       register tree tem = primop0;
       register int temi = unsignedp0;
@@ -1504,40 +2062,40 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
       if (code == NE_EXPR)
        {
          if (max_lt || min_gt)
-           val = integer_one_node;
+           val = boolean_true_node;
        }
       else if (code == EQ_EXPR)
        {
          if (max_lt || min_gt)
-           val = integer_zero_node;
+           val = boolean_false_node;
        }
       else if (code == LT_EXPR)
        {
          if (max_lt)
-           val = integer_one_node;
+           val = boolean_true_node;
          if (!min_lt)
-           val = integer_zero_node;
+           val = boolean_false_node;
        }
       else if (code == GT_EXPR)
        {
          if (min_gt)
-           val = integer_one_node;
+           val = boolean_true_node;
          if (!max_gt)
-           val = integer_zero_node;
+           val = boolean_false_node;
        }
       else if (code == LE_EXPR)
        {
          if (!max_gt)
-           val = integer_one_node;
+           val = boolean_true_node;
          if (min_gt)
-           val = integer_zero_node;
+           val = boolean_false_node;
        }
       else if (code == GE_EXPR)
        {
          if (!min_lt)
-           val = integer_one_node;
+           val = boolean_true_node;
          if (max_lt)
-           val = integer_zero_node;
+           val = boolean_false_node;
        }
 
       /* If primop0 was sign-extended and unsigned comparison specd,
@@ -1575,18 +2133,18 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
        {
          /* This is the case of (char)x >?< 0x80, which people used to use
             expecting old C compilers to change the 0x80 into -0x80.  */
-         if (val == integer_zero_node)
+         if (val == boolean_false_node)
            warning ("comparison is always 0 due to limited range of data type");
-         if (val == integer_one_node)
+         if (val == boolean_true_node)
            warning ("comparison is always 1 due to limited range of data type");
        }
 
       if (!min_lt && unsignedp0 && TREE_CODE (primop0) != INTEGER_CST)
        {
          /* This is the case of (unsigned char)x >?< -1 or < 0.  */
-         if (val == integer_zero_node)
+         if (val == boolean_false_node)
            warning ("comparison is always 0 due to limited range of data type");
-         if (val == integer_one_node)
+         if (val == boolean_true_node)
            warning ("comparison is always 1 due to limited range of data type");
        }
 
@@ -1639,21 +2197,31 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
       primop1 = op1;
 
       if (!real1 && !real2 && integer_zerop (primop1)
-         && TREE_UNSIGNED (TREE_TYPE (primop0)))
+         && TREE_UNSIGNED (*restype_ptr))
        {
          tree value = 0;
          switch (code)
            {
            case GE_EXPR:
-             if (extra_warnings)
+             /* All unsigned values are >= 0, so we warn if extra warnings
+                are requested.  However, if OP0 is a constant that is
+                >= 0, the signedness of the comparison isn't an issue,
+                so suppress the warning.  */
+             if (extra_warnings
+                 && ! (TREE_CODE (primop0) == INTEGER_CST
+                       && ! TREE_OVERFLOW (convert (signed_type (type),
+                                                    primop0))))
                warning ("unsigned value >= 0 is always 1");
-             value = integer_one_node;
+             value = boolean_true_node;
              break;
 
            case LT_EXPR:
-             if (extra_warnings)
+             if (extra_warnings
+                 && ! (TREE_CODE (primop0) == INTEGER_CST
+                       && ! TREE_OVERFLOW (convert (signed_type (type),
+                                                    primop0))))
                warning ("unsigned value < 0 is always 0");
-             value = integer_zero_node;
+             value = boolean_false_node;
            }
 
          if (value != 0)
@@ -1670,7 +2238,7 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
   *op0_ptr = convert (type, primop0);
   *op1_ptr = convert (type, primop1);
 
-  *restype_ptr = integer_type_node;
+  *restype_ptr = boolean_type_node;
 
   return 0;
 }
@@ -1681,17 +2249,15 @@ shorten_compare (op0_ptr, op1_ptr, restype_ptr, rescode_ptr)
    This preparation consists of taking the ordinary
    representation of an expression expr and producing a valid tree
    boolean expression describing whether expr is nonzero.  We could
-   simply always do build_binary_op (NE_EXPR, expr, integer_zero_node, 1),
+   simply always do build_binary_op (NE_EXPR, expr, boolean_false_node, 1),
    but we optimize comparisons, &&, ||, and !.
 
-   The resulting type should always be `integer_type_node'.  */
+   The resulting type should always be `boolean_type_node'.  */
 
 tree
 truthvalue_conversion (expr)
      tree expr;
 {
-  register enum tree_code code;
-
   if (TREE_CODE (expr) == ERROR_MARK)
     return expr;
 
@@ -1702,15 +2268,15 @@ truthvalue_conversion (expr)
     {
     case RECORD_TYPE:
       error ("struct type value used where scalar is required");
-      return integer_zero_node;
+      return boolean_false_node;
 
     case UNION_TYPE:
       error ("union type value used where scalar is required");
-      return integer_zero_node;
+      return boolean_false_node;
 
     case ARRAY_TYPE:
       error ("array type value used where scalar is required");
-      return integer_zero_node;
+      return boolean_false_node;
 
     default:
       break;
@@ -1743,21 +2309,31 @@ truthvalue_conversion (expr)
     case TRUTH_AND_EXPR:
     case TRUTH_OR_EXPR:
     case TRUTH_XOR_EXPR:
+    case TRUTH_NOT_EXPR:
+      TREE_TYPE (expr) = boolean_type_node;
+      return expr;
+
     case ERROR_MARK:
       return expr;
 
     case INTEGER_CST:
-      return integer_zerop (expr) ? integer_zero_node : integer_one_node;
+      return integer_zerop (expr) ? boolean_false_node : boolean_true_node;
 
     case REAL_CST:
-      return real_zerop (expr) ? integer_zero_node : integer_one_node;
+      return real_zerop (expr) ? boolean_false_node : boolean_true_node;
 
     case ADDR_EXPR:
+      /* If we are taking the address of a external decl, it might be zero
+        if it is weak, so we cannot optimize.  */
+      if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (expr, 0))) == 'd'
+         && DECL_EXTERNAL (TREE_OPERAND (expr, 0)))
+       break;
+
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 0)))
-       return build (COMPOUND_EXPR, integer_type_node,
-                     TREE_OPERAND (expr, 0), integer_one_node);
+       return build (COMPOUND_EXPR, boolean_type_node,
+                     TREE_OPERAND (expr, 0), boolean_true_node);
       else
-       return integer_one_node;
+       return boolean_true_node;
 
     case COMPLEX_EXPR:
       return build_binary_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
@@ -1778,14 +2354,14 @@ truthvalue_conversion (expr)
       /* These don't change whether an object is zero or non-zero, but
         we can't ignore them if their second arg has side-effects.  */
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
-       return build (COMPOUND_EXPR, integer_type_node, TREE_OPERAND (expr, 1),
+       return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1),
                      truthvalue_conversion (TREE_OPERAND (expr, 0)));
       else
        return truthvalue_conversion (TREE_OPERAND (expr, 0));
       
     case COND_EXPR:
       /* Distribute the conversion into the arms of a COND_EXPR.  */
-      return fold (build (COND_EXPR, integer_type_node, TREE_OPERAND (expr, 0),
+      return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0),
                          truthvalue_conversion (TREE_OPERAND (expr, 1)),
                          truthvalue_conversion (TREE_OPERAND (expr, 2))));
 
@@ -1795,7 +2371,7 @@ truthvalue_conversion (expr)
       if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
          || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
        break;
-      /* fall through... */
+      /* fall through...  */
     case NOP_EXPR:
       /* If this is widening the argument, we can ignore it.  */
       if (TYPE_PRECISION (TREE_TYPE (expr))
@@ -1809,7 +2385,7 @@ truthvalue_conversion (expr)
       if (TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT
          && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE)
        break;
-      /* fall through... */
+      /* fall through...  */
     case BIT_XOR_EXPR:
       /* This and MINUS_EXPR can be changed into a comparison of the
         two objects.  */
@@ -1822,6 +2398,13 @@ truthvalue_conversion (expr)
                                            TREE_TYPE (TREE_OPERAND (expr, 0)),
                                            TREE_OPERAND (expr, 1))), 1);
 
+    case BIT_AND_EXPR:
+      if (integer_onep (TREE_OPERAND (expr, 1))
+         && TREE_TYPE (expr) != boolean_type_node)
+       /* Using convert here would cause infinite recursion.  */
+       return build1 (NOP_EXPR, boolean_type_node, expr);
+      break;
+
     case MODIFY_EXPR:
       if (warn_parentheses && C_EXP_ORIGINAL_CODE (expr) == MODIFY_EXPR)
        warning ("suggest parentheses around assignment used as truth value");
@@ -1847,7 +2430,10 @@ truthvalue_conversion (expr)
    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.  */
+   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)
@@ -1891,7 +2477,8 @@ get_directive_line (finput)
        continue;
 
       /* Detect the end of the directive.  */
-      if (c == '\n' && looking_for == 0)
+      if (looking_for == 0
+         && (c == '\n' || c == EOF))
        {
           ungetc (c, finput);
          c = '\0';
@@ -1930,10 +2517,22 @@ c_build_type_variant (type, constp, volatilep)
     {
       tree real_main_variant = TYPE_MAIN_VARIANT (type);
 
-      push_obstacks (TYPE_OBSTACK (type), TYPE_OBSTACK (type));
+      push_obstacks (TYPE_OBSTACK (real_main_variant),
+                    TYPE_OBSTACK (real_main_variant));
       type = build_array_type (c_build_type_variant (TREE_TYPE (type),
                                                     constp, volatilep),
                               TYPE_DOMAIN (type));
+
+      /* TYPE must be on same obstack as REAL_MAIN_VARIANT.  If not,
+        make a copy.  (TYPE might have come from the hash table and
+        REAL_MAIN_VARIANT might be in some function's obstack.)  */
+
+      if (TYPE_OBSTACK (type) != TYPE_OBSTACK (real_main_variant))
+       {
+         type = copy_node (type);
+         TYPE_POINTER_TO (type) = TYPE_REFERENCE_TO (type) = 0;
+       }
+
       TYPE_MAIN_VARIANT (type) = real_main_variant;
       pop_obstacks ();
     }