OSDN Git Service

* config/linux.h (ASM_COMMENT_START): Remove from here,
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index db99035..ba67ec5 100644 (file)
@@ -1,5 +1,5 @@
 /* Process declarations and variables for C compiler.
-   Copyright (C) 1988, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92-97, 1998 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.  */
 
 
 /* Process declarations and symbol lookup for C front end.
@@ -26,12 +27,13 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    line numbers.  For example, the CONST_DECLs for enum values.  */
 
 #include "config.h"
+#include "system.h"
 #include "tree.h"
 #include "flags.h"
 #include "output.h"
 #include "c-tree.h"
 #include "c-lex.h"
-#include <stdio.h>
+#include "toplev.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -142,11 +144,13 @@ tree intQI_type_node;
 tree intHI_type_node;
 tree intSI_type_node;
 tree intDI_type_node;
+tree intTI_type_node;
 
 tree unsigned_intQI_type_node;
 tree unsigned_intHI_type_node;
 tree unsigned_intSI_type_node;
 tree unsigned_intDI_type_node;
+tree unsigned_intTI_type_node;
 
 /* a VOID_TYPE node.  */
 
@@ -410,16 +414,20 @@ tree static_ctors, static_dtors;
 
 /* Forward declarations.  */
 
-static tree grokparms (), grokdeclarator ();
-tree pushdecl ();
-tree builtin_function ();
-void shadow_tag_warned ();
-
-static tree lookup_tag ();
-static tree lookup_tag_reverse ();
-tree lookup_name_current_level ();
-static char *redeclaration_error_message ();
-static void layout_array_type ();
+static struct binding_level * make_binding_level       PROTO((void));
+static void clear_limbo_values         PROTO((tree));
+static int duplicate_decls             PROTO((tree, tree, int));
+static char *redeclaration_error_message PROTO((tree, tree));
+static void storedecls                 PROTO((tree));
+static void storetags                  PROTO((tree));
+static tree lookup_tag                 PROTO((enum tree_code, tree,
+                                              struct binding_level *, int));
+static tree lookup_tag_reverse         PROTO((tree));
+static tree grokdeclarator             PROTO((tree, tree, enum decl_context,
+                                              int));
+static tree grokparms                  PROTO((tree, int));
+static int field_decl_cmp              PROTO((const GENERIC_PTR, const GENERIC_PTR));
+static void layout_array_type          PROTO((tree));
 \f
 /* C-specific option variables.  */
 
@@ -449,8 +457,12 @@ int flag_no_nonansi_builtin;
 
 int flag_traditional;
 
+/* Nonzero means that we have builtin functions, and main is an int */
+
+int flag_hosted = 1;
+
 /* Nonzero means to allow single precision math even if we're generally
-   being traditional. */
+   being traditional.  */
 int flag_allow_single_precision = 0;
 
 /* Nonzero means to treat bitfields as signed unless they say `unsigned'.  */
@@ -462,9 +474,14 @@ int explicit_flag_signed_bitfields = 0;
 
 int flag_no_ident = 0;
 
-/* Nonzero means warn about implicit declarations.  */
+/* Nonzero means warn about use of implicit int. */
+
+int warn_implicit_int;
 
-int warn_implicit;
+/* Nonzero means message about use of implicit function declarations;
+ 1 means warning; 2 means error. */
+
+int mesg_implicit_function_declaration;
 
 /* Nonzero means give string constants the type `const char *'
    to get extra warnings from them.  These warnings will be too numerous
@@ -520,7 +537,7 @@ int warn_redundant_decls = 0;
 
 int warn_nested_externs = 0;
 
-/* Warn about *printf or *scanf format/argument anomalies. */
+/* Warn about *printf or *scanf format/argument anomalies.  */
 
 int warn_format;
 
@@ -540,13 +557,25 @@ int warn_parentheses;
 
 int warn_missing_braces;
 
-/* Nonzero means `$' can be in an identifier.
-   See cccp.c for reasons why this breaks some obscure ANSI C programs.  */
+/* Warn if main is suspicious.  */
+
+int warn_main;
+
+/* Warn about #pragma directives that are not recognised.  */
+
+int warn_unknown_pragmas = 0; /* Tri state variable.  */  
+
+/* Warn about comparison of signed and unsigned values.
+   If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified.  */
+
+int warn_sign_compare = -1;
+
+/* Nonzero means `$' can be in an identifier.  */
 
 #ifndef DOLLARS_IN_IDENTIFIERS
 #define DOLLARS_IN_IDENTIFIERS 1
 #endif
-int dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
+int dollars_in_ident = DOLLARS_IN_IDENTIFIERS;
 
 /* Decode the string P as a language-specific option for C.
    Return 1 if it is recognized (and handle it);
@@ -560,24 +589,29 @@ c_decode_option (p)
     {
       flag_traditional = 1;
       flag_writable_strings = 1;
-#if DOLLARS_IN_IDENTIFIERS > 0
-      dollars_in_ident = 1;
-#endif
     }
   else if (!strcmp (p, "-fallow-single-precision"))
     flag_allow_single_precision = 1;
+  else if (!strcmp (p, "-fhosted") || !strcmp (p, "-fno-freestanding"))
+    {
+      flag_hosted = 1;
+      flag_no_builtin = 0;
+    }
+  else if (!strcmp (p, "-ffreestanding") || !strcmp (p, "-fno-hosted"))
+    {
+      flag_hosted = 0;
+      flag_no_builtin = 1;
+      /* warn_main will be 2 if set by -Wall, 1 if set by -Wmain */
+      if (warn_main == 2)
+       warn_main = 0;
+    }
   else if (!strcmp (p, "-fnotraditional") || !strcmp (p, "-fno-traditional"))
     {
       flag_traditional = 0;
       flag_writable_strings = 0;
-      dollars_in_ident = DOLLARS_IN_IDENTIFIERS > 1;
     }
   else if (!strcmp (p, "-fdollars-in-identifiers"))
-    {
-#if DOLLARS_IN_IDENTIFIERS > 0
-      dollars_in_ident = 1;
-#endif
-    }
+    dollars_in_ident = 1;
   else if (!strcmp (p, "-fno-dollars-in-identifiers"))
     dollars_in_ident = 0;
   else if (!strcmp (p, "-fsigned-char"))
@@ -625,11 +659,25 @@ c_decode_option (p)
   else if (!strcmp (p, "-fident"))
     flag_no_ident = 0;
   else if (!strcmp (p, "-ansi"))
-    flag_no_asm = 1, flag_no_nonansi_builtin = 1, dollars_in_ident = 0;
+    flag_no_asm = 1, flag_no_nonansi_builtin = 1;
+  else if (!strcmp (p, "-Werror-implicit-function-declaration"))
+    mesg_implicit_function_declaration = 2;
+  else if (!strcmp (p, "-Wimplicit-function-declaration"))
+    mesg_implicit_function_declaration = 1;
+  else if (!strcmp (p, "-Wno-implicit-function-declaration"))
+    mesg_implicit_function_declaration = 0;
+  else if (!strcmp (p, "-Wimplicit-int"))
+    warn_implicit_int = 1;
+  else if (!strcmp (p, "-Wno-implicit-int"))
+    warn_implicit_int = 0;
   else if (!strcmp (p, "-Wimplicit"))
-    warn_implicit = 1;
+    {
+      warn_implicit_int = 1;
+      if (mesg_implicit_function_declaration != 2)
+        mesg_implicit_function_declaration = 1;
+    }
   else if (!strcmp (p, "-Wno-implicit"))
-    warn_implicit = 0;
+    warn_implicit_int = 0, mesg_implicit_function_declaration = 0;
   else if (!strcmp (p, "-Wwrite-strings"))
     warn_write_strings = 1;
   else if (!strcmp (p, "-Wno-write-strings"))
@@ -702,6 +750,10 @@ c_decode_option (p)
     ; /* cpp handles this one.  */
   else if (!strcmp (p, "-Wno-trigraphs"))
     ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wundef"))
+    ; /* cpp handles this one.  */
+  else if (!strcmp (p, "-Wno-undef"))
+    ; /* cpp handles this one.  */
   else if (!strcmp (p, "-Wimport"))
     ; /* cpp handles this one.  */
   else if (!strcmp (p, "-Wno-import"))
@@ -710,15 +762,29 @@ c_decode_option (p)
     warn_missing_braces = 1;
   else if (!strcmp (p, "-Wno-missing-braces"))
     warn_missing_braces = 0;
+  else if (!strcmp (p, "-Wmain"))
+    warn_main = 1;
+  else if (!strcmp (p, "-Wno-main"))
+    warn_main = 0;
+  else if (!strcmp (p, "-Wsign-compare"))
+    warn_sign_compare = 1;
+  else if (!strcmp (p, "-Wno-sign-compare"))
+    warn_sign_compare = 0;
+  else if (!strcmp (p, "-Wunknown-pragmas"))
+    /* Set to greater than 1, so that even unknown pragmas in system
+       headers will be warned about.  */
+    warn_unknown_pragmas = 2;
+  else if (!strcmp (p, "-Wno-unknown-pragmas"))
+    warn_unknown_pragmas = 0;
   else if (!strcmp (p, "-Wall"))
     {
-      extra_warnings = 1;
       /* We save the value of warn_uninitialized, since if they put
         -Wuninitialized on the command line, we need to generate a
         warning about not using it without also specifying -O.  */
       if (warn_uninitialized != 1)
        warn_uninitialized = 2;
-      warn_implicit = 1;
+      warn_implicit_int = 1;
+      mesg_implicit_function_declaration = 1;
       warn_return_type = 1;
       warn_unused = 1;
       warn_switch = 1;
@@ -726,6 +792,11 @@ c_decode_option (p)
       warn_char_subscripts = 1;
       warn_parentheses = 1;
       warn_missing_braces = 1;
+      /* We set this to 2 here, but 1 in -Wmain, so -ffreestanding can turn
+        it off only if it's not explicit.  */
+      warn_main = 2;
+      /* Only warn about unknown pragmas that are not in system headers.  */
+      warn_unknown_pragmas = 1;
     }
   else
     return 0;
@@ -772,13 +843,16 @@ void
 finish_incomplete_decl (decl)
      tree decl;
 {
-  if (TREE_CODE (decl) == VAR_DECL && TREE_TYPE (decl) != error_mark_node)
+  if (TREE_CODE (decl) == VAR_DECL)
     {
       tree type = TREE_TYPE (decl);
-      if (TREE_CODE (type) == ARRAY_TYPE
-         && TYPE_DOMAIN (type) == 0
-         && TREE_CODE (decl) != TYPE_DECL)
+      if (type != error_mark_node
+         && TREE_CODE (type) == ARRAY_TYPE
+         && TYPE_DOMAIN (type) == 0)
        {
+         if (! DECL_EXTERNAL (decl))
+           warning_with_decl (decl, "array `%s' assumed to have one element");
+
          complete_array_type (type, NULL_TREE, 1);
 
          layout_decl (decl, 0);
@@ -890,6 +964,22 @@ pushlevel (tag_transparent)
   keep_next_if_subblocks = 0;
 }
 
+/* Clear the limbo values of all identifiers defined in BLOCK or a subblock. */
+
+static void
+clear_limbo_values (block)
+     tree block;
+{
+  tree tem;
+
+  for (tem = BLOCK_VARS (block); tem; tem = TREE_CHAIN (tem))
+    if (DECL_NAME (tem) != 0)
+      IDENTIFIER_LIMBO_VALUE (DECL_NAME (tem)) = 0;
+
+  for (tem = BLOCK_SUBBLOCKS (block); tem; tem = TREE_CHAIN (tem))
+    clear_limbo_values (tem);
+}
+    
 /* Exit a binding level.
    Pop the level off, and restore the state of the identifier-decl mappings
    that were in effect when this level was entered.
@@ -980,7 +1070,7 @@ poplevel (keep, reverse, functionbody)
        if (DECL_ABSTRACT_ORIGIN (decl) != 0
            && DECL_ABSTRACT_ORIGIN (decl) != decl)
          TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1;
-       else
+       else if (DECL_SAVED_INSNS (decl) != 0)
          {
            push_function_context ();
            output_inline_function (decl);
@@ -1043,6 +1133,8 @@ poplevel (keep, reverse, functionbody)
 
   if (functionbody)
     {
+      clear_limbo_values (block);
+
       /* If this is the top level block of a function,
         the vars are the function's parameters.
         Don't leave them in the BLOCK because they are
@@ -1299,6 +1391,10 @@ pushtag (name, type)
      tagged type.  */
 
   TYPE_STUB_DECL (type) = pushdecl (build_decl (TYPE_DECL, NULL_TREE, type));
+
+  /* An approximation for now, so we can tell this is a function-scope tag.
+     This will be updated in poplevel.  */
+  TYPE_CONTEXT (type) = DECL_CONTEXT (TYPE_STUB_DECL (type));
 }
 \f
 /* Handle when a new declaration NEWDECL
@@ -1307,11 +1403,15 @@ pushtag (name, type)
    Prints an error message if appropriate.
 
    If safely possible, alter OLDDECL to look like NEWDECL, and return 1.
-   Otherwise, return 0.  */
+   Otherwise, return 0.
+
+   When DIFFERENT_BINDING_LEVEL is true, NEWDECL is an external declaration,
+   and OLDDECL is in an outer binding level and should thus not be changed.  */
 
 static int
-duplicate_decls (newdecl, olddecl)
+duplicate_decls (newdecl, olddecl, different_binding_level)
      register tree newdecl, olddecl;
+     int different_binding_level;
 {
   int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
   int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
@@ -1321,7 +1421,8 @@ duplicate_decls (newdecl, olddecl)
   char *errmsg = 0;
 
   if (TREE_CODE_CLASS (TREE_CODE (olddecl)) == 'd')
-    DECL_MACHINE_ATTRIBUTES (newdecl) = DECL_MACHINE_ATTRIBUTES (olddecl);
+    DECL_MACHINE_ATTRIBUTES (newdecl)
+      =  merge_machine_decl_attributes (olddecl, newdecl);
 
   if (TREE_CODE (newtype) == ERROR_MARK
       || TREE_CODE (oldtype) == ERROR_MARK)
@@ -1404,8 +1505,8 @@ duplicate_decls (newdecl, olddecl)
       else if (!types_match)
        {
           /* Accept the return type of the new declaration if same modes.  */
-         tree oldreturntype = TREE_TYPE (TREE_TYPE (olddecl));
-         tree newreturntype = TREE_TYPE (TREE_TYPE (newdecl));
+         tree oldreturntype = TREE_TYPE (oldtype);
+         tree newreturntype = TREE_TYPE (newtype);
 
          /* Make sure we put the new type in the same obstack as the old ones.
             If the old types are not both in the same obstack, use the
@@ -1422,36 +1523,37 @@ duplicate_decls (newdecl, olddecl)
             {
              /* Function types may be shared, so we can't just modify
                 the return type of olddecl's function type.  */
-             tree newtype
+             tree trytype
                = build_function_type (newreturntype,
-                                      TYPE_ARG_TYPES (TREE_TYPE (olddecl)));
+                                      TYPE_ARG_TYPES (oldtype));
              
-              types_match = comptypes (TREE_TYPE (newdecl), newtype);
+              types_match = comptypes (newtype, trytype);
              if (types_match)
-               TREE_TYPE (olddecl) = newtype;
+               oldtype = trytype;
            }
          /* Accept harmless mismatch in first argument type also.
             This is for ffs.  */
          if (TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0
-             && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0
-             && TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))) != 0
-             && TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (olddecl))) != 0
-             && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))))
-                 ==
-                 TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (olddecl))))))
+             && TYPE_ARG_TYPES (oldtype) != 0
+             && TREE_VALUE (TYPE_ARG_TYPES (newtype)) != 0
+             && TREE_VALUE (TYPE_ARG_TYPES (oldtype)) != 0
+             && (TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (newtype)))
+                 == TYPE_MODE (TREE_VALUE (TYPE_ARG_TYPES (oldtype)))))
            {
              /* Function types may be shared, so we can't just modify
                 the return type of olddecl's function type.  */
-             tree newtype
-               = build_function_type (TREE_TYPE (TREE_TYPE (olddecl)),
+             tree trytype
+               = build_function_type (TREE_TYPE (oldtype),
                                       tree_cons (NULL_TREE, 
-                                                 TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (newdecl))),
-                                                 TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (olddecl)))));
+                                                 TREE_VALUE (TYPE_ARG_TYPES (newtype)),
+                                                 TREE_CHAIN (TYPE_ARG_TYPES (oldtype))));
              
-              types_match = comptypes (TREE_TYPE (newdecl), newtype);
+              types_match = comptypes (newtype, trytype);
              if (types_match)
-               TREE_TYPE (olddecl) = newtype;
+               oldtype = trytype;
            }
+         if (! different_binding_level)
+           TREE_TYPE (olddecl) = oldtype;
 
          pop_obstacks ();
        }
@@ -1672,7 +1774,7 @@ duplicate_decls (newdecl, olddecl)
 
   /* Optionally warn about more than one declaration for the same name.  */
   if (errmsg == 0 && warn_redundant_decls && DECL_SOURCE_LINE (olddecl) != 0
-      /* Dont warn about a function declaration
+      /* Don't warn about a function declaration
         followed by a definition.  */
       && !(TREE_CODE (newdecl) == FUNCTION_DECL && DECL_INITIAL (newdecl) != 0
           && DECL_INITIAL (olddecl) == 0)
@@ -1691,6 +1793,11 @@ duplicate_decls (newdecl, olddecl)
 
   if (types_match)
     {
+      /* When copying info to olddecl, we store into write_olddecl
+        instead.  This allows us to avoid modifying olddecl when
+        different_binding_level is true.  */
+      tree write_olddecl = different_binding_level ? newdecl : olddecl;
+
       /* Make sure we put the new type in the same obstack as the old ones.
         If the old types are not both in the same obstack, use the permanent
         one.  */
@@ -1704,9 +1811,18 @@ duplicate_decls (newdecl, olddecl)
                       
       /* Merge the data types specified in the two decls.  */
       if (TREE_CODE (newdecl) != FUNCTION_DECL || !DECL_BUILT_IN (olddecl))
-       TREE_TYPE (newdecl)
-         = TREE_TYPE (olddecl)
-           = common_type (newtype, oldtype);
+       {
+         if (different_binding_level)
+           TREE_TYPE (newdecl)
+             = build_type_attribute_variant
+               (newtype,
+                merge_attributes (TYPE_ATTRIBUTES (newtype),
+                                  TYPE_ATTRIBUTES (oldtype)));
+         else
+           TREE_TYPE (newdecl)
+             = TREE_TYPE (olddecl)
+               = common_type (newtype, oldtype);
+       }
 
       /* Lay the type out, unless already done.  */
       if (oldtype != TREE_TYPE (newdecl))
@@ -1733,36 +1849,37 @@ duplicate_decls (newdecl, olddecl)
       /* Merge the type qualifiers.  */
       if (DECL_BUILT_IN_NONANSI (olddecl) && TREE_THIS_VOLATILE (olddecl)
          && !TREE_THIS_VOLATILE (newdecl))
-       TREE_THIS_VOLATILE (olddecl) = 0;
+       TREE_THIS_VOLATILE (write_olddecl) = 0;
       if (TREE_READONLY (newdecl))
-       TREE_READONLY (olddecl) = 1;
+       TREE_READONLY (write_olddecl) = 1;
       if (TREE_THIS_VOLATILE (newdecl))
        {
-         TREE_THIS_VOLATILE (olddecl) = 1;
+         TREE_THIS_VOLATILE (write_olddecl) = 1;
          if (TREE_CODE (newdecl) == VAR_DECL)
            make_var_volatile (newdecl);
        }
 
-      /* Keep source location of definition rather than declaration.
-        Likewise, keep decl at outer scope.  */
-      if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
-         || (DECL_CONTEXT (newdecl) != 0 && DECL_CONTEXT (olddecl) == 0))
+      /* Keep source location of definition rather than declaration.  */
+      /* When called with different_binding_level set, keep the old
+        information so that meaningful diagnostics can be given.  */
+      if (DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0
+         && ! different_binding_level)
        {
          DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl);
          DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl);
-
-         if (DECL_CONTEXT (olddecl) == 0)
-           DECL_CONTEXT (newdecl) = 0;
        }
 
       /* Merge the unused-warning information.  */
       if (DECL_IN_SYSTEM_HEADER (olddecl))
        DECL_IN_SYSTEM_HEADER (newdecl) = 1;
       else if (DECL_IN_SYSTEM_HEADER (newdecl))
-       DECL_IN_SYSTEM_HEADER (olddecl) = 1;
+       DECL_IN_SYSTEM_HEADER (write_olddecl) = 1;
 
       /* Merge the initialization information.  */
-      if (DECL_INITIAL (newdecl) == 0)
+      /* When called with different_binding_level set, don't copy over
+        DECL_INITIAL, so that we don't accidentally change function
+        declarations into function definitions.  */
+      if (DECL_INITIAL (newdecl) == 0 && ! different_binding_level)
        DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
 
       /* Merge the section attribute.
@@ -1782,7 +1899,7 @@ duplicate_decls (newdecl, olddecl)
     }
   /* If cannot merge, then use the new type and qualifiers,
      and don't preserve the old rtl.  */
-  else
+  else if (! different_binding_level)
     {
       TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
       TREE_READONLY (olddecl) = TREE_READONLY (newdecl);
@@ -1791,12 +1908,15 @@ duplicate_decls (newdecl, olddecl)
     }
 
   /* Merge the storage class information.  */
+  DECL_WEAK (newdecl) |= DECL_WEAK (olddecl);    
   /* For functions, static overrides non-static.  */
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
       TREE_PUBLIC (newdecl) &= TREE_PUBLIC (olddecl);
       /* This is since we don't automatically
         copy the attributes of NEWDECL into OLDDECL.  */
+      /* No need to worry about different_binding_level here because
+        then TREE_PUBLIC (newdecl) was true.  */
       TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
       /* If this clears `static', clear it in the identifier too.  */
       if (! TREE_PUBLIC (olddecl))
@@ -1808,6 +1928,8 @@ duplicate_decls (newdecl, olddecl)
       DECL_EXTERNAL (newdecl) = DECL_EXTERNAL (olddecl);
       /* An extern decl does not override previous storage class.  */
       TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
+      if (! DECL_EXTERNAL (newdecl))
+       DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
     }
   else
     {
@@ -1821,37 +1943,55 @@ duplicate_decls (newdecl, olddecl)
     DECL_INLINE (olddecl) = 1;
   DECL_INLINE (newdecl) = DECL_INLINE (olddecl);
 
-  /* Get rid of any built-in function if new arg types don't match it
-     or if we have a function definition.  */
-  if (TREE_CODE (newdecl) == FUNCTION_DECL
-      && DECL_BUILT_IN (olddecl)
-      && (!types_match || new_is_definition))
-    {
-      TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
-      DECL_BUILT_IN (olddecl) = 0;
-    }
-
-  /* If redeclaring a builtin function, and not a definition,
-     it stays built in.
-     Also preserve various other info from the definition.  */
-  if (TREE_CODE (newdecl) == FUNCTION_DECL && !new_is_definition)
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
       if (DECL_BUILT_IN (olddecl))
        {
-         DECL_BUILT_IN (newdecl) = 1;
-         DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+         /* Get rid of any built-in function if new arg types don't match it
+            or if we have a function definition.  */
+         if (! types_match || new_is_definition)
+           {
+             if (! different_binding_level)
+               {
+                 TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+                 DECL_BUILT_IN (olddecl) = 0;
+               }
+           }
+         else
+           {
+             /* If redeclaring a builtin function, and not a definition,
+                it stays built in.  */
+             DECL_BUILT_IN (newdecl) = 1;
+             DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+           }
        }
-      else
+      /* Also preserve various other info from the definition.  */
+      else if (! new_is_definition)
        DECL_FRAME_SIZE (newdecl) = DECL_FRAME_SIZE (olddecl);
-
-      DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
-      DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
-      DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
-      DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+      if (! new_is_definition)
+       {
+         DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+         /* When called with different_binding_level set, don't copy over
+            DECL_INITIAL, so that we don't accidentally change function
+            declarations into function definitions.  */
+         if (! different_binding_level)
+           DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+         DECL_SAVED_INSNS (newdecl) = DECL_SAVED_INSNS (olddecl);
+         DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
+         if (DECL_INLINE (newdecl))
+           DECL_ABSTRACT_ORIGIN (newdecl) = olddecl;
+       }
+    }
+  if (different_binding_level)
+    {
+      /* Don't output a duplicate symbol or debugging information for this
+        declaration.  */
+      TREE_ASM_WRITTEN (newdecl) = DECL_IGNORED_P (newdecl) = 1;
+      return 0;
     }
 
   /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
-     But preserve OLDdECL's DECL_UID.  */
+     But preserve OLDDECL's DECL_UID.  */
   {
     register unsigned olddecl_uid = DECL_UID (olddecl);
 
@@ -1861,6 +2001,10 @@ duplicate_decls (newdecl, olddecl)
     DECL_UID (olddecl) = olddecl_uid;
   }
 
+  /* NEWDECL contains the merged attribute lists.
+     Update OLDDECL to be the same.  */
+  DECL_MACHINE_ATTRIBUTES (olddecl) = DECL_MACHINE_ATTRIBUTES (newdecl);
+
   return 1;
 }
 
@@ -1898,14 +2042,21 @@ pushdecl (x)
     {
       char *file;
       int line;
+      int different_binding_level = 0;
 
+      t = lookup_name_current_level (name);
       /* Don't type check externs here when -traditional.  This is so that
         code with conflicting declarations inside blocks will get warnings
         not errors.  X11 for instance depends on this.  */
-      if (DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional)
-       t = lookup_name_current_level_global (name);
-      else
-       t = lookup_name_current_level (name);
+      if (! t && DECL_EXTERNAL (x) && TREE_PUBLIC (x) && ! flag_traditional)
+       {
+         t = IDENTIFIER_GLOBAL_VALUE (name);
+         /* Type decls at global scope don't conflict with externs declared
+            inside lexical blocks.  */
+         if (t && TREE_CODE (t) == TYPE_DECL)
+           t = 0;
+         different_binding_level = 1;
+       }
       if (t != 0 && t == error_mark_node)
        /* error_mark_node is 0 for a while during initialization!  */
        {
@@ -1919,7 +2070,29 @@ pushdecl (x)
          line = DECL_SOURCE_LINE (t);
        }
 
-      if (t != 0 && duplicate_decls (x, t))
+      /* If this decl is `static' and an implicit decl was seen previously,
+        warn.  But don't complain if -traditional,
+        since traditional compilers don't complain.  */
+      if (! flag_traditional && TREE_PUBLIC (name)
+         /* Don't test for DECL_EXTERNAL, because grokdeclarator
+            sets this for all functions.  */
+         && ! TREE_PUBLIC (x)
+         && (TREE_CODE (x) == FUNCTION_DECL || b == global_binding_level)
+         /* We used to warn also for explicit extern followed by static,
+            but sometimes you need to do it that way.  */
+         && IDENTIFIER_IMPLICIT_DECL (name) != 0)
+       {
+         pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+                  IDENTIFIER_POINTER (name));
+         pedwarn_with_file_and_line
+           (DECL_SOURCE_FILE (IDENTIFIER_IMPLICIT_DECL (name)),
+            DECL_SOURCE_LINE (IDENTIFIER_IMPLICIT_DECL (name)),
+            "previous declaration of `%s'",
+            IDENTIFIER_POINTER (name));
+         TREE_THIS_VOLATILE (name) = 1;
+       }
+
+      if (t != 0 && duplicate_decls (x, t, different_binding_level))
        {
          if (TREE_CODE (t) == PARM_DECL)
            {
@@ -1928,27 +2101,7 @@ pushdecl (x)
              TREE_ASM_WRITTEN (t) = TREE_ASM_WRITTEN (x);
              return t;
            }
-         /* If this decl is `static' and an implicit decl was seen previously,
-            warn.  But don't complain if -traditional,
-            since traditional compilers don't complain.  */
-         if (!flag_traditional && TREE_PUBLIC (name)
-             && ! TREE_PUBLIC (x) && ! DECL_EXTERNAL (x)
-             /* We used to warn also for explicit extern followed by static,
-                but sometimes you need to do it that way.  */
-             && IDENTIFIER_IMPLICIT_DECL (name) != 0)
-           {
-             pedwarn ("`%s' was declared implicitly `extern' and later `static'",
-                      IDENTIFIER_POINTER (name));
-             pedwarn_with_file_and_line (file, line,
-                                         "previous declaration of `%s'",
-                                         IDENTIFIER_POINTER (name));
-           }
-
-         /* If this is a global decl, and there exists a conflicting local
-            decl in a parent block, then we can't return as yet, because we
-            need to register this decl in the current binding block.  */
-         if (! TREE_PUBLIC (x) || lookup_name (name) == t)
-           return t;
+         return t;
        }
 
       /* If we are processing a typedef statement, generate a whole new
@@ -1970,7 +2123,7 @@ pushdecl (x)
                MY_TYPE object;
 
         Later parts of the compiler might only know that `object' was of
-        type `struct S' if if were not for code just below.  With this
+        type `struct S' if it were not for code just below.  With this
         code however, later parts of the compiler see something like:
 
                struct S' == struct S
@@ -2001,10 +2154,11 @@ pushdecl (x)
              if (TYPE_NAME (TREE_TYPE (x)) == 0)
                TYPE_NAME (TREE_TYPE (x)) = x;
             }
-          else if (TREE_TYPE (x) != error_mark_node)
+          else if (TREE_TYPE (x) != error_mark_node
+                  && DECL_ORIGINAL_TYPE (x) == NULL_TREE)
             {
               tree tt = TREE_TYPE (x);
-
+             DECL_ORIGINAL_TYPE (x) = tt;
               tt = build_type_copy (tt);
               TYPE_NAME (tt) = x;
               TREE_TYPE (x) = tt;
@@ -2134,9 +2288,16 @@ pushdecl (x)
              /* Okay to declare a non-ANSI built-in as anything.  */
              else if (t != 0 && DECL_BUILT_IN_NONANSI (t))
                ;
+             /* Okay to have global type decl after an earlier extern
+                declaration inside a lexical block.  */
+             else if (TREE_CODE (x) == TYPE_DECL)
+               ;
              else if (IDENTIFIER_IMPLICIT_DECL (name))
-               pedwarn ("`%s' was declared implicitly `extern' and later `static'",
-                        IDENTIFIER_POINTER (name));
+               {
+                 if (! TREE_THIS_VOLATILE (name))
+                   pedwarn ("`%s' was declared implicitly `extern' and later `static'",
+                            IDENTIFIER_POINTER (name));
+               }
              else
                pedwarn ("`%s' was declared `extern' and later `static'",
                         IDENTIFIER_POINTER (name));
@@ -2206,11 +2367,11 @@ pushdecl (x)
             and no file-scope declaration has yet been seen,
             then if we later have a file-scope decl it must not be static.  */
          if (oldlocal == 0
-             && oldglobal == 0
              && DECL_EXTERNAL (x)
              && TREE_PUBLIC (x))
            {
-             TREE_PUBLIC (name) = 1;
+             if (oldglobal == 0)
+               TREE_PUBLIC (name) = 1;
 
              /* Save this decl, so that we can do type checking against
                 other decls after it falls out of scope.
@@ -2303,20 +2464,6 @@ pushdecl_top_level (x)
   current_binding_level = b;
   return t;
 }
-
-
-/* Invoke finish_decl at the global binding level.  */
-
-void
-finish_decl_top_level (d, i, a)
-     tree d, i, a;
-{
-  register struct binding_level *b = current_binding_level;
-
-  current_binding_level = global_binding_level;
-  finish_decl (d, i, a);
-  current_binding_level = b;
-}
 \f
 /* Generate an implicit declaration for identifier FUNCTIONID
    as a function of type int ().  Print a warning if appropriate.  */
@@ -2366,9 +2513,15 @@ implicitly_declare (functionid)
 
   rest_of_decl_compilation (decl, NULL_PTR, 0, 0);
 
-  if (warn_implicit && implicit_warning)
-    warning ("implicit declaration of function `%s'",
-            IDENTIFIER_POINTER (functionid));
+  if (mesg_implicit_function_declaration && implicit_warning)
+    {
+      if (mesg_implicit_function_declaration == 2)
+        error ("implicit declaration of function `%s'",
+                 IDENTIFIER_POINTER (functionid));
+      else
+        warning ("implicit declaration of function `%s'",
+                 IDENTIFIER_POINTER (functionid));
+    }
   else if (warn_traditional && traditional_warning)
     warning ("function `%s' was previously declared within a block",
             IDENTIFIER_POINTER (functionid));
@@ -2397,6 +2550,15 @@ redeclaration_error_message (newdecl, olddecl)
     {
       if (flag_traditional && TREE_TYPE (newdecl) == TREE_TYPE (olddecl))
        return 0;
+      /* pushdecl creates distinct types for TYPE_DECLs by calling
+        build_type_copy, so the above comparison generally fails.  We do
+        another test against the TYPE_MAIN_VARIANT of the olddecl, which
+        is equivalent to what this code used to do before the build_type_copy
+        call.  The variant type distinction should not matter for traditional
+        code, because it doesn't have type qualifiers.  */
+      if (flag_traditional 
+         && TYPE_MAIN_VARIANT (TREE_TYPE (olddecl)) == TREE_TYPE (newdecl))
+       return 0;
       if (DECL_IN_SYSTEM_HEADER (olddecl) || DECL_IN_SYSTEM_HEADER (newdecl))
        return 0;
       return "redefinition of `%s'";
@@ -2725,32 +2887,9 @@ lookup_name_current_level (name)
 
   return t;
 }
-
-/* Similar to `lookup_name_current_level' but also look at the global binding
-   level.  */
-
-tree
-lookup_name_current_level_global (name)
-     tree name;
-{
-  register tree t = 0;
-
-  if (current_binding_level == global_binding_level)
-    return IDENTIFIER_GLOBAL_VALUE (name);
-
-  if (IDENTIFIER_LOCAL_VALUE (name) != 0)
-    for (t = current_binding_level->names; t; t = TREE_CHAIN (t))
-      if (DECL_NAME (t) == name)
-       break;
-
-  if (t == 0)
-    t = IDENTIFIER_GLOBAL_VALUE (name);
-
-  return t;
-}
 \f
 /* Create the predefined scalar types of C,
-   and some nodes representing standard constants (0, 1, (void *)0).
+   and some nodes representing standard constants (0, 1, (void *) 0).
    Initialize the global binding level.
    Make definitions for built-in primitive functions.  */
 
@@ -2761,8 +2900,8 @@ init_decl_processing ()
   /* Either char* or void*.  */
   tree traditional_ptr_type_node;
   /* Data types of memcpy and strlen.  */
-  tree memcpy_ftype, strlen_ftype;
-  tree void_ftype_any;
+  tree memcpy_ftype, memset_ftype, strlen_ftype;
+  tree void_ftype_any, ptr_ftype_void, ptr_ftype_ptr;
   int wchar_type_size;
   tree temp;
   tree array_domain_type;
@@ -2810,37 +2949,29 @@ init_decl_processing ()
   pushdecl (build_decl (TYPE_DECL, get_identifier ("long long unsigned int"),
                        long_long_unsigned_type_node));
 
+  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
+                       short_integer_type_node));
+
+  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+  pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
+                       short_unsigned_type_node));
+
   /* `unsigned long' is the standard type for sizeof.
      Traditionally, use a signed type.
      Note that stddef.h uses `unsigned long',
-     and this must agree, even of long and int are the same size.  */
-  sizetype
-    = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE)));
+     and this must agree, even if long and int are the same size.  */
+  set_sizetype
+    (TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (SIZE_TYPE))));
   if (flag_traditional && TREE_UNSIGNED (sizetype))
-    sizetype = signed_type (sizetype);
+    set_sizetype (signed_type (sizetype));
 
   ptrdiff_type_node
     = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (get_identifier (PTRDIFF_TYPE)));
 
-  TREE_TYPE (TYPE_SIZE (integer_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (char_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (unsigned_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (long_unsigned_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (long_integer_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (long_long_integer_type_node)) = sizetype;
-  TREE_TYPE (TYPE_SIZE (long_long_unsigned_type_node)) = sizetype;
-
   error_mark_node = make_node (ERROR_MARK);
   TREE_TYPE (error_mark_node) = error_mark_node;
 
-  short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("short int"),
-                       short_integer_type_node));
-
-  short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
-  pushdecl (build_decl (TYPE_DECL, get_identifier ("short unsigned int"),
-                       short_unsigned_type_node));
-
   /* Define both `signed char' and `unsigned char'.  */
   signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
   pushdecl (build_decl (TYPE_DECL, get_identifier ("signed char"),
@@ -2862,6 +2993,9 @@ init_decl_processing ()
   intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
 
+  intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, intDI_type_node));
+
   unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intQI_type_node));
 
@@ -2874,6 +3008,9 @@ init_decl_processing ()
   unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
   pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intDI_type_node));
 
+  unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+  pushdecl (build_decl (TYPE_DECL, NULL_TREE, unsigned_intTI_type_node));
+
   float_type_node = make_node (REAL_TYPE);
   TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
   pushdecl (build_decl (TYPE_DECL, ridpointers[(int) RID_FLOAT],
@@ -3068,6 +3205,19 @@ init_decl_processing ()
                                                            sizetype,
                                                            endlink))));
 
+  memset_ftype /* memset prototype */
+    = 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))));
+
+  ptr_ftype_void = build_function_type (ptr_type_node, endlink);
+  ptr_ftype_ptr
+    = build_function_type (ptr_type_node,
+                          tree_cons (NULL_TREE, ptr_type_node, endlink));
+
   builtin_function ("__builtin_constant_p", default_function_type,
                    BUILT_IN_CONSTANT_P, NULL_PTR);
 
@@ -3085,6 +3235,42 @@ init_decl_processing ()
                                                    endlink)),
                    BUILT_IN_FRAME_ADDRESS, NULL_PTR);
 
+  builtin_function ("__builtin_aggregate_incoming_address",
+                   build_function_type (ptr_type_node, NULL_TREE),
+                   BUILT_IN_AGGREGATE_INCOMING_ADDRESS, NULL_PTR);
+
+  /* Hooks for the DWARF 2 __throw routine.  */
+  builtin_function ("__builtin_unwind_init",
+                   build_function_type (void_type_node, endlink),
+                   BUILT_IN_UNWIND_INIT, NULL_PTR);
+  builtin_function ("__builtin_fp", ptr_ftype_void, BUILT_IN_FP, NULL_PTR);
+  builtin_function ("__builtin_sp", ptr_ftype_void, BUILT_IN_SP, NULL_PTR);
+  builtin_function ("__builtin_dwarf_fp_regnum",
+                   build_function_type (unsigned_type_node, endlink),
+                   BUILT_IN_DWARF_FP_REGNUM, NULL_PTR);
+  builtin_function ("__builtin_dwarf_reg_size", int_ftype_int,
+                   BUILT_IN_DWARF_REG_SIZE, NULL_PTR);             
+  builtin_function ("__builtin_frob_return_addr", ptr_ftype_ptr,
+                   BUILT_IN_FROB_RETURN_ADDR, NULL_PTR);
+  builtin_function ("__builtin_extract_return_addr", ptr_ftype_ptr,
+                   BUILT_IN_EXTRACT_RETURN_ADDR, NULL_PTR);
+  builtin_function ("__builtin_set_return_addr_reg",
+                   build_function_type (void_type_node, 
+                                        tree_cons (NULL_TREE,
+                                                   ptr_type_node,
+                                                   endlink)),
+                   BUILT_IN_SET_RETURN_ADDR_REG, NULL_PTR);
+  builtin_function ("__builtin_eh_stub", ptr_ftype_void,
+                   BUILT_IN_EH_STUB, NULL_PTR);
+  builtin_function
+    ("__builtin_set_eh_regs",
+     build_function_type (void_type_node,
+                         tree_cons (NULL_TREE, ptr_type_node,
+                                    tree_cons (NULL_TREE,
+                                               type_for_mode (ptr_mode, 0),
+                                               endlink))),
+     BUILT_IN_SET_EH_REGS, NULL_PTR);
+
   builtin_function ("__builtin_alloca",
                    build_function_type (ptr_type_node,
                                         tree_cons (NULL_TREE,
@@ -3176,6 +3362,8 @@ init_decl_processing ()
                    BUILT_IN_MEMCPY, "memcpy");
   builtin_function ("__builtin_memcmp", int_ftype_cptr_cptr_sizet,
                    BUILT_IN_MEMCMP, "memcmp");
+  builtin_function ("__builtin_memset", memset_ftype,
+                   BUILT_IN_MEMSET, "memset");
   builtin_function ("__builtin_strcmp", int_ftype_string_string,
                    BUILT_IN_STRCMP, "strcmp");
   builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
@@ -3200,6 +3388,19 @@ init_decl_processing ()
                    BUILT_IN_COS, "cos");
   builtin_function ("__builtin_cosl", ldouble_ftype_ldouble, 
                    BUILT_IN_COS, "cosl");
+  builtin_function ("__builtin_setjmp",
+                   build_function_type (integer_type_node,
+                                        tree_cons (NULL_TREE,
+                                                   ptr_type_node, endlink)),
+                   BUILT_IN_SETJMP, NULL_PTR);
+  builtin_function ("__builtin_longjmp",
+                   build_function_type
+                   (void_type_node,
+                    tree_cons (NULL, ptr_type_node,
+                               tree_cons (NULL_TREE,
+                                          integer_type_node,
+                                          endlink))),
+                   BUILT_IN_LONGJMP, NULL_PTR);
 
   /* In an ANSI C program, it is okay to supply built-in meanings
      for these functions, since applications cannot validly use them
@@ -3216,6 +3417,7 @@ init_decl_processing ()
       builtin_function ("memcpy", memcpy_ftype, BUILT_IN_MEMCPY, NULL_PTR);
       builtin_function ("memcmp", int_ftype_cptr_cptr_sizet, BUILT_IN_MEMCMP,
                        NULL_PTR);
+      builtin_function ("memset", memset_ftype, BUILT_IN_MEMSET, NULL_PTR);
       builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
                        NULL_PTR);
       builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
@@ -3258,8 +3460,6 @@ init_decl_processing ()
                    BUILT_IN_FMOD, NULL_PTR);
   builtin_function ("__builtin_frem", double_ftype_double_double,
                    BUILT_IN_FREM, NULL_PTR);
-  builtin_function ("__builtin_memset", ptr_ftype_ptr_int_int,
-                   BUILT_IN_MEMSET, NULL_PTR);
   builtin_function ("__builtin_getexp", double_ftype_double, BUILT_IN_GETEXP,
                    NULL_PTR);
   builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
@@ -3345,9 +3545,14 @@ shadow_tag_warned (declspecs, warned)
 {
   int found_tag = 0;
   register tree link;
+  tree specs, attrs;
 
   pending_invalid_xref = 0;
 
+  /* Remove the attributes from declspecs, since they will confuse the
+     following code.  */
+  split_specs_attrs (declspecs, &specs, &attrs);
+
   for (link = declspecs; link; link = TREE_CHAIN (link))
     {
       register tree value = TREE_VALUE (link);
@@ -3384,7 +3589,7 @@ shadow_tag_warned (declspecs, warned)
        }
       else
        {
-         if (!warned)
+         if (!warned && ! in_system_header)
            {
              warning ("useless keyword or type name in empty declaration");
              warned = 2;
@@ -3461,6 +3666,9 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   /* The corresponding pop_obstacks is in finish_decl.  */
   push_obstacks_nochange ();
 
+  if (warn_main && !strcmp (IDENTIFIER_POINTER (declarator), "main"))
+    warning_with_decl (decl, "`%s' is usually a function");
+
   if (initialized)
     /* Is it valid for this decl to have an initializer at all?
        If not, set INITIALIZED to zero, which will indirectly
@@ -3545,6 +3753,14 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
   if (TREE_CODE (decl) == FUNCTION_DECL)
     gen_aux_info_record (decl, 0, 0, TYPE_ARG_TYPES (TREE_TYPE (decl)) != 0);
 
+  /* ANSI specifies that a tentative definition which is not merged with
+     a non-tentative definition behaves exactly like a definition with an
+     initializer equal to zero.  (Section 3.7.2)
+     -fno-common gives strict ANSI behavior.  Usually you don't want it.
+     This matters only for variables with external linkage.  */
+  if (! flag_no_common || ! TREE_PUBLIC (decl))
+    DECL_COMMON (decl) = 1;
+
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (decl, attributes, prefix_attributes);
 
@@ -3552,10 +3768,6 @@ start_decl (declarator, declspecs, initialized, attributes, prefix_attributes)
      TEM may equal DECL or it may be a previous decl of the same name.  */
   tem = pushdecl (decl);
 
-  /* For C and Obective-C, we by default put things in .common when
-     possible.  */
-  DECL_COMMON (tem) = 1;
-
   /* For a local variable, define the RTL now.  */
   if (current_binding_level != global_binding_level
       /* But not if this is a duplicate decl
@@ -3697,10 +3909,11 @@ finish_decl (decl, init, asmspec_tree)
                   Also if it is not file scope.
                   Otherwise, let it through, but if it is not `extern'
                   then it may cause an error message later.  */
-             /* We must use DECL_CONTEXT instead of current_binding_level,
-                because a duplicate_decls call could have changed the binding
-                level of this decl.  */
-               (DECL_INITIAL (decl) != 0 || DECL_CONTEXT (decl) != 0)
+             /* A duplicate_decls call could have changed an extern
+                declaration into a file scope one.  This can be detected
+                by TREE_ASM_WRITTEN being set.  */
+               (DECL_INITIAL (decl) != 0
+                || (DECL_CONTEXT (decl) != 0 && ! TREE_ASM_WRITTEN (decl)))
              :
                /* An automatic variable with an incomplete type
                   is an error.  */
@@ -3718,6 +3931,9 @@ finish_decl (decl, init, asmspec_tree)
          else
            error_with_decl (decl, "storage size of `%s' isn't constant");
        }
+
+      if (TREE_USED  (type))
+       TREE_USED (decl) = 1;
     }
 
   /* If this is a function and an assembler name is specified, it isn't
@@ -3742,7 +3958,9 @@ finish_decl (decl, init, asmspec_tree)
          end_temporary_allocation ();
          /* This is a no-op in c-lang.c or something real in objc-actions.c.  */
          maybe_objc_check_decl (decl);
-         rest_of_decl_compilation (decl, asmspec, DECL_CONTEXT (decl) == 0,
+         rest_of_decl_compilation (decl, asmspec,
+                                   (DECL_CONTEXT (decl) == 0
+                                    || TREE_ASM_WRITTEN (decl)),
                                    0);
          pop_obstacks ();
        }
@@ -3808,7 +4026,7 @@ finish_decl (decl, init, asmspec_tree)
            {
              preserve_initializer ();
              /* Hack?  Set the permanent bit for something that is permanent,
-                but not on the permenent obstack, so as to convince
+                but not on the permanent obstack, so as to convince
                 output_constant_def to make its rtl on the permanent
                 obstack.  */
              TREE_PERMANENT (DECL_INITIAL (decl)) = 1;
@@ -3984,12 +4202,6 @@ complete_array_type (type, initial_value, do_default)
       TYPE_DOMAIN (type) = build_index_type (maxindex);
       if (!TREE_TYPE (maxindex))
        TREE_TYPE (maxindex) = TYPE_DOMAIN (type);
-#if 0 /* I took out this change
-        together with the change in build_array_type. --rms  */
-      change_main_variant (type,
-                          build_array_type (TREE_TYPE (type),
-                                            TYPE_DOMAIN (type)));
-#endif
     }
 
   /* Lay out the type now that we can get the real answer.  */
@@ -4195,10 +4407,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
 
   if (type == 0)
     {
-      if (funcdef_flag && warn_return_type
-         && ! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
-                           | (1 << (int) RID_SIGNED) | (1 << (int) RID_UNSIGNED))))
-       warn_about_return_type = 1;
+      if ((! (specbits & ((1 << (int) RID_LONG) | (1 << (int) RID_SHORT)
+                         | (1 << (int) RID_SIGNED)
+                         | (1 << (int) RID_UNSIGNED))))
+         && ! (in_system_header && ! allocation_temporary_p ()))
+       {
+         /* C9x will probably require a diagnostic here.
+            For now, issue a warning if -Wreturn-type and this is a function,
+            or if -Wimplicit; prefer the former warning since it is more
+            explicit.  */
+         if ((warn_implicit_int || warn_return_type) && funcdef_flag)
+           warn_about_return_type = 1;
+         else if (warn_implicit_int)
+           warning ("type defaults to `int' in declaration of `%s'", name);
+       }
+
       defaulted_int = 1;
       type = integer_type_node;
     }
@@ -4208,7 +4431,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
 
   /* Long double is a special combination.  */
 
-  if ((specbits & 1 << (int) RID_LONG)
+  if ((specbits & 1 << (int) RID_LONG) && ! longlong
       && TYPE_MAIN_VARIANT (type) == double_type_node)
     {
       specbits &= ~ (1 << (int) RID_LONG);
@@ -4222,11 +4445,9 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
     {
       int ok = 0;
 
-      if (TREE_CODE (type) != INTEGER_TYPE)
-       error ("long, short, signed or unsigned invalid for `%s'", name);
-      else if ((specbits & 1 << (int) RID_LONG)
-              && (specbits & 1 << (int) RID_SHORT))
-       error ("long and short specified together for `%s'", name);
+      if ((specbits & 1 << (int) RID_LONG)
+         && (specbits & 1 << (int) RID_SHORT))
+       error ("both long and short specified for `%s'", name);
       else if (((specbits & 1 << (int) RID_LONG)
                || (specbits & 1 << (int) RID_SHORT))
               && explicit_char)
@@ -4234,10 +4455,21 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
       else if (((specbits & 1 << (int) RID_LONG)
                || (specbits & 1 << (int) RID_SHORT))
               && TREE_CODE (type) == REAL_TYPE)
-       error ("long or short specified with floating type for `%s'", name);
+       {
+         static int already = 0;
+
+         error ("long or short specified with floating type for `%s'", name);
+         if (! already && ! pedantic)
+           {
+             error ("the only valid combination is `long double'");
+             already = 1;
+           }
+       }
       else if ((specbits & 1 << (int) RID_SIGNED)
               && (specbits & 1 << (int) RID_UNSIGNED))
-       error ("signed and unsigned given together for `%s'", name);
+       error ("both signed and unsigned specified for `%s'", name);
+      else if (TREE_CODE (type) != INTEGER_TYPE)
+       error ("long, short, signed or unsigned invalid for `%s'", name);
       else
        {
          ok = 1;
@@ -4532,6 +4764,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
                                   convert (index_type, size),
                                   convert (index_type, size_one_node)));
 
+             /* If that overflowed, the array is too big.
+                ??? While a size of INT_MAX+1 technically shouldn't cause
+                an overflow (because we subtract 1), the overflow is recorded
+                during the conversion to index_type, before the subtraction.
+                Handling this case seems like an unnecessary complication.  */
+             if (TREE_OVERFLOW (itype))
+               {
+                 error ("size of array `%s' is too large", name);
+                 type = error_mark_node;
+                 continue;
+               }
+
              if (size_varies)
                itype = variable_size (itype);
              itype = build_index_type (itype);
@@ -4650,7 +4894,7 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
          {
            register tree link;
 
-           for (link = current_function_parm_tags;
+           for (link = last_function_parm_tags;
                 link;
                 link = TREE_CHAIN (link))
              TYPE_CONTEXT (TREE_VALUE (link)) = type;
@@ -4707,6 +4951,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
 
   /* Now TYPE has the actual type.  */
 
+  /* Did array size calculations overflow?  */
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type)
+      && TREE_OVERFLOW (TYPE_SIZE (type)))
+    error ("size of array `%s' is too large", name);
+
   /* If this is declaring a typedef name, return a TYPE_DECL.  */
 
   if (specbits & (1 << (int) RID_TYPEDEF))
@@ -4719,11 +4970,11 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
        pedwarn ("ANSI C forbids const or volatile function types");
       if (constp || volatilep)
        type = c_build_type_variant (type, constp, volatilep);
-      pop_obstacks ();
       decl = build_decl (TYPE_DECL, declarator, type);
       if ((specbits & (1 << (int) RID_SIGNED))
          || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
+      pop_obstacks ();
       return decl;
     }
 
@@ -4903,6 +5154,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
            && ! DECL_IN_SYSTEM_HEADER (decl))
          pedwarn ("ANSI C forbids const or volatile functions");
 
+       if (pedantic
+           && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl))) == void_type_node
+           && (TYPE_READONLY (TREE_TYPE (TREE_TYPE (decl)))
+               || TYPE_VOLATILE (TREE_TYPE (TREE_TYPE (decl))))
+           && ! DECL_IN_SYSTEM_HEADER (decl))
+         pedwarn ("ANSI C forbids const or volatile void function return type");
+
        if (volatilep
            && TREE_TYPE (TREE_TYPE (decl)) != void_type_node)
          warning ("`noreturn' function returns non-void value");
@@ -4920,9 +5178,6 @@ grokdeclarator (declarator, declspecs, decl_context, initialized)
 
            if (! strcmp (IDENTIFIER_POINTER (declarator), "main"))
              warning ("cannot inline function `main'");
-           else if (last && (TYPE_MAIN_VARIANT (TREE_VALUE (last))
-                             != void_type_node))
-             warning ("inline declaration ignored for function with `...'");
            else
              /* Assume that otherwise the function can be inlined.  */
              DECL_INLINE (decl) = 1;
@@ -5242,7 +5497,7 @@ parmlist_tags_warning ()
       enum tree_code code = TREE_CODE (TREE_VALUE (elt));
       /* An anonymous union parm type is meaningful as a GNU extension.
         So don't warn for that.  */
-      if (code == UNION_TYPE && !pedantic)
+      if (code == UNION_TYPE && TREE_PURPOSE (elt) == 0 && !pedantic)
        continue;
       if (TREE_PURPOSE (elt) != 0)
        warning ("`%s %s' declared inside parameter list",
@@ -5345,6 +5600,7 @@ start_struct (code, name)
   if (ref && TREE_CODE (ref) == code)
     {
       C_TYPE_BEING_DEFINED (ref) = 1;
+      TYPE_PACKED (ref) = flag_pack_struct;
       if (TYPE_FIELDS (ref))
        error ((code == UNION_TYPE ? "redefinition of `union %s'"
                : "redefinition of `struct %s'"),
@@ -5358,6 +5614,7 @@ start_struct (code, name)
   ref = make_node (code);
   pushtag (name, ref);
   C_TYPE_BEING_DEFINED (ref) = 1;
+  TYPE_PACKED (ref) = flag_pack_struct;
   return ref;
 }
 
@@ -5392,10 +5649,21 @@ grokfield (filename, line, declarator, declspecs, width)
 /* Function to help qsort sort FIELD_DECLs by name order.  */
 
 static int
-field_decl_cmp (x, y)
-     tree *x, *y;
+field_decl_cmp (xp, yp)
+     const GENERIC_PTR xp;
+     const GENERIC_PTR yp;
 {
-  return (long)DECL_NAME (*x) - (long)DECL_NAME (*y);
+  tree *x = (tree *)xp, *y = (tree *)yp;
+
+  if (DECL_NAME (*x) == DECL_NAME (*y))
+    return 0;
+  if (DECL_NAME (*x) == NULL)
+    return -1;
+  if (DECL_NAME (*y) == NULL)
+    return 1;
+  if (DECL_NAME (*x) < DECL_NAME (*y))
+    return -1;
+  return 1;
 }
 
 /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
@@ -5436,9 +5704,17 @@ finish_struct (t, fieldlist, attributes)
 
   old_momentary = suspend_momentary ();
 
-  if (fieldlist == 0 && pedantic)
-    pedwarn ((TREE_CODE (t) == UNION_TYPE ? "union has no members"
-             : "structure has no members"));
+  if (pedantic)
+    {
+      for (x = fieldlist; x; x = TREE_CHAIN (x))
+       if (DECL_NAME (x) != 0)
+         break;
+
+      if (x == 0)
+       pedwarn ("%s has no %smembers",
+                (TREE_CODE (t) == UNION_TYPE ? "union" : "structure"),
+                (fieldlist ? "named " : ""));
+    }
 
   /* Install struct as DECL_CONTEXT of each field decl.
      Also process specified field sizes.
@@ -5540,8 +5816,15 @@ finish_struct (t, fieldlist, attributes)
        {
          register int width = TREE_INT_CST_LOW (DECL_INITIAL (x));
 
+         if (TREE_CODE (TREE_TYPE (x)) == ENUMERAL_TYPE
+             && (width < min_precision (TYPE_MIN_VALUE (TREE_TYPE (x)),
+                                        TREE_UNSIGNED (TREE_TYPE (x)))
+                 || width < min_precision (TYPE_MAX_VALUE (TREE_TYPE (x)),
+                                           TREE_UNSIGNED (TREE_TYPE (x)))))
+           warning_with_decl (x, "`%s' is narrower than values of its type");
+
          DECL_FIELD_SIZE (x) = width;
-         DECL_BIT_FIELD (x) = 1;
+         DECL_BIT_FIELD (x) = DECL_C_BIT_FIELD (x) = 1;
          DECL_INITIAL (x) = NULL;
 
          if (width == 0)
@@ -5551,14 +5834,15 @@ finish_struct (t, fieldlist, attributes)
              DECL_ALIGN (x) = MAX (DECL_ALIGN (x), EMPTY_FIELD_BOUNDARY);
 #endif
 #ifdef PCC_BITFIELD_TYPE_MATTERS
-             DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
-                                   TYPE_ALIGN (TREE_TYPE (x)));
+             if (PCC_BITFIELD_TYPE_MATTERS)
+               DECL_ALIGN (x) = MAX (DECL_ALIGN (x),
+                                     TYPE_ALIGN (TREE_TYPE (x)));
 #endif
            }
        }
       else if (TREE_TYPE (x) != error_mark_node)
        {
-         int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
+         unsigned int min_align = (DECL_PACKED (x) ? BITS_PER_UNIT
                           : TYPE_ALIGN (TREE_TYPE (x)));
          /* Non-bit-fields are aligned for their type, except packed
             fields which require only BITS_PER_UNIT alignment.  */
@@ -5661,26 +5945,15 @@ finish_struct (t, fieldlist, attributes)
       TYPE_ALIGN (x) = TYPE_ALIGN (t);
     }
 
-  /* Promote each bit-field's type to int if it is narrower than that.  */
-  for (x = fieldlist; x; x = TREE_CHAIN (x))
-    if (DECL_BIT_FIELD (x)
-       && (C_PROMOTING_INTEGER_TYPE_P (TREE_TYPE (x))
-           || DECL_FIELD_SIZE (x) < TYPE_PRECISION (integer_type_node)))
-      {
-       tree type = TREE_TYPE (x);
-
-       /* Preserve unsignedness if traditional
-          or if not really getting any wider.  */
-       if (TREE_UNSIGNED (type)
-           && (flag_traditional
-               ||
-               (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
-                &&
-                DECL_FIELD_SIZE (x) == TYPE_PRECISION (integer_type_node))))
-         TREE_TYPE (x) = unsigned_type_node;
-       else
-         TREE_TYPE (x) = integer_type_node;
-      }
+  /* If this was supposed to be a transparent union, but we can't
+     make it one, warn and turn off the flag.  */
+  if (TREE_CODE (t) == UNION_TYPE
+      && TYPE_TRANSPARENT_UNION (t)
+      && TYPE_MODE (t) != DECL_MODE (TYPE_FIELDS (t)))
+    {
+      TYPE_TRANSPARENT_UNION (t) = 0;
+      warning ("union cannot be made transparent");
+    }
 
   /* If this structure or union completes the type of any previous
      variable declaration, lay it out and output its rtl.  */
@@ -5781,6 +6054,9 @@ start_enum (name)
   enum_next_value = integer_zero_node;
   enum_overflow = 0;
 
+  if (flag_short_enums)
+    TYPE_PACKED (enumtype) = 1;
+
   return enumtype;
 }
 
@@ -5837,10 +6113,17 @@ finish_enum (enumtype, values, attributes)
   highprec = min_precision (maxnode, TREE_UNSIGNED (enumtype));
   precision = MAX (lowprec, highprec);
 
-  if (flag_short_enums || TYPE_PACKED (enumtype)
-      || precision > TYPE_PRECISION (integer_type_node))
-    /* Use the width of the narrowest normal C type which is wide enough.  */
-    TYPE_PRECISION (enumtype) = TYPE_PRECISION (type_for_size (precision, 1));
+  if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
+    {
+      tree narrowest = type_for_size (precision, 1);
+      if (narrowest == 0)
+       {
+         warning ("enumeration values exceed range of largest integer");
+         narrowest = long_long_integer_type_node;
+       }
+
+      TYPE_PRECISION (enumtype) = TYPE_PRECISION (narrowest);
+    }
   else
     TYPE_PRECISION (enumtype) = TYPE_PRECISION (integer_type_node);
 
@@ -5961,8 +6244,8 @@ build_enumerator (name, value)
 }
 \f
 /* Create the FUNCTION_DECL for a function definition.
-   DECLSPECS, DECLARATOR, and ATTRIBUTES are the parts of the declaration;
-   they describe the function's name and the type it returns,
+   DECLSPECS, DECLARATOR, PREFIX_ATTRIBUTES and ATTRIBUTES are the parts of
+   the declaration; they describe the function's name and the type it returns,
    but twisted together in a fashion that parallels the syntax of C.
 
    This function creates a binding context for the function body
@@ -5975,15 +6258,15 @@ build_enumerator (name, value)
    NESTED is nonzero for a function nested within another function.  */
 
 int
-start_function (declspecs, declarator, attributes, nested)
-     tree declarator, declspecs, attributes;
+start_function (declspecs, declarator, prefix_attributes, attributes, nested)
+     tree declarator, declspecs, prefix_attributes, attributes;
      int nested;
 {
   tree decl1, old_decl;
   tree restype;
   int old_immediate_size_expand = immediate_size_expand;
 
-  current_function_returns_value = 0;  /* Assume, until we see it does. */
+  current_function_returns_value = 0;  /* Assume, until we see it does.  */
   current_function_returns_null = 0;
   warn_about_return_type = 0;
   current_extern_inline = 0;
@@ -5999,10 +6282,12 @@ start_function (declspecs, declarator, attributes, nested)
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
   if (decl1 == 0)
-    return 0;
+    {
+      immediate_size_expand = old_immediate_size_expand;
+      return 0;
+    }
 
-  if (attributes)
-    decl_attributes (decl1, NULL_TREE, attributes);
+  decl_attributes (decl1, prefix_attributes, attributes);
 
   announce_function (decl1);
 
@@ -6093,6 +6378,67 @@ start_function (declspecs, declarator, attributes, nested)
   if (current_function_decl != 0)
     TREE_PUBLIC (decl1) = 0;
 
+  /* Warn for unlikely, improbable, or stupid declarations of `main'. */
+  if (warn_main
+      && strcmp ("main", IDENTIFIER_POINTER (DECL_NAME (decl1))) == 0)
+    {
+      tree args;
+      int argct = 0;
+
+      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
+          != integer_type_node)
+       pedwarn_with_decl (decl1, "return type of `%s' is not `int'");
+
+      for (args = TYPE_ARG_TYPES (TREE_TYPE (decl1)); args;
+          args = TREE_CHAIN (args))
+       {
+         tree type = args ? TREE_VALUE (args) : 0;
+
+         if (type == void_type_node)
+           break;
+
+         ++argct;
+         switch (argct)
+           {
+           case 1:
+             if (TYPE_MAIN_VARIANT (type) != integer_type_node)
+               pedwarn_with_decl (decl1,
+                                  "first argument of `%s' should be `int'");
+             break;
+
+           case 2:
+             if (TREE_CODE (type) != POINTER_TYPE
+                 || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+                 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+                     != char_type_node))
+               pedwarn_with_decl (decl1,
+                              "second argument of `%s' should be `char **'");
+             break;
+
+           case 3:
+             if (TREE_CODE (type) != POINTER_TYPE
+                 || TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+                 || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
+                     != char_type_node))
+               pedwarn_with_decl (decl1,
+                  "third argument of `%s' should probably be `char **'");
+             break;
+           }
+       }
+
+      /* It is intentional that this message does not mention the third
+        argument, which is warned for only pedantically, because it's
+        blessed by mention in an appendix of the standard. */
+      if (argct > 0 && (argct < 2 || argct > 3))
+       pedwarn_with_decl (decl1, "`%s' takes only zero or two arguments");
+
+      if (argct == 3 && pedantic)
+       pedwarn_with_decl (decl1, "third argument of `%s' is deprecated");
+
+      if (! TREE_PUBLIC (decl1))
+       pedwarn_with_decl (decl1, "`%s' is normally a non-static function");
+    }
+
   /* Record the decl so that the function name is defined.
      If we already have a decl for this name, and it is a FUNCTION_DECL,
      use the old decl.  */
@@ -6706,7 +7052,9 @@ combine_parm_decls (specparms, parmlist, void_at_end)
   
   if (void_at_end)
     return saveable_tree_cons (parmdecls, nonparms,
-                              nreverse (saveable_tree_cons (NULL_TREE, void_type_node, types)));
+                              nreverse (saveable_tree_cons (NULL_TREE,
+                                                            void_type_node,
+                                                            types)));
 
   return saveable_tree_cons (parmdecls, nonparms, nreverse (types));
 }
@@ -6743,19 +7091,28 @@ finish_function (nested)
       setjmp_protect_args ();
     }
 
-#ifdef DEFAULT_MAIN_RETURN
   if (! strcmp (IDENTIFIER_POINTER (DECL_NAME (fndecl)), "main"))
     {
       if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
          != integer_type_node)
-       warning_with_decl (fndecl, "return type of `%s' is not `int'");
+       {
+         /* You would expect the sense of this test to be the other way
+            around, but if warn_main is set, we will already have warned,
+            so this would be a duplicate.  This is the warning you get
+            in some environments even if you *don't* ask for it, because
+            these are environments where it may be more of a problem than
+            usual.  */
+         if (! warn_main)
+           pedwarn_with_decl (fndecl, "return type of `%s' is not `int'");
+       }
       else
        {
+#ifdef DEFAULT_MAIN_RETURN
          /* Make it so that `main' always returns success by default.  */
          DEFAULT_MAIN_RETURN;
+#endif
        }
     }
-#endif
 
   /* Generate rtl for function exit.  */
   expand_function_end (input_filename, lineno, 0);