OSDN Git Service

2009-05-12 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / c-decl.c
index ff35e08..a9929c1 100644 (file)
@@ -1,12 +1,13 @@
 /* Process declarations and variables for C compiler.
    Copyright (C) 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 /* Process declarations and symbol lookup for C front end.
    Also constructs types; the standard scalar types at initialization,
@@ -52,7 +52,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "c-pragma.h"
 #include "langhooks.h"
 #include "tree-mudflap.h"
-#include "tree-gimple.h"
+#include "gimple.h"
+#include "tree-iterator.h"
 #include "diagnostic.h"
 #include "tree-dump.h"
 #include "cgraph.h"
@@ -61,6 +62,8 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "except.h"
 #include "langhooks-def.h"
 #include "pointer-set.h"
+#include "gimple.h"
+#include "plugin.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -70,6 +73,16 @@ enum decl_context
   FIELD,                       /* Declaration inside struct or union */
   TYPENAME};                   /* Typename (inside cast or sizeof)  */
 
+/* States indicating how grokdeclarator() should handle declspecs marked
+   with __attribute__((deprecated)).  An object declared as
+   __attribute__((deprecated)) suppresses warnings of uses of other
+   deprecated items.  */
+
+enum deprecated_states {
+  DEPRECATED_NORMAL,
+  DEPRECATED_SUPPRESS
+};
+
 \f
 /* Nonzero if we have seen an invalid cross reference
    to a struct, union, or enum, but not yet printed the message.  */
@@ -81,18 +94,6 @@ location_t pending_invalid_xref_location;
 /* True means we've initialized exception handling.  */
 bool c_eh_initialized_p;
 
-/* While defining an enum type, this is 1 plus the last enumerator
-   constant value.  Note that will do not have to save this or `enum_overflow'
-   around nested function definition since such a definition could only
-   occur in an enum value expression and we don't use these variables in
-   that case.  */
-
-static tree enum_next_value;
-
-/* Nonzero means that there was overflow computing enum_next_value.  */
-
-static int enum_overflow;
-
 /* The file and line that the prototype came from if this is an
    old-style definition; used for diagnostics in
    store_parm_decls_oldstyle.  */
@@ -125,6 +126,15 @@ static GTY(()) struct stmt_tree_s c_stmt_tree;
 tree c_break_label;
 tree c_cont_label;
 
+/* True if we are currently parsing the fields of a struct or
+   union.  */
+
+static bool in_struct;
+
+/* A list of types defined in the current struct or union.  */
+
+static VEC(tree,heap) *struct_types;
+
 /* Linked list of TRANSLATION_UNIT_DECLS for the translation units
    included in this invocation.  Note that the current translation
    unit is not included in this list.  */
@@ -154,10 +164,6 @@ int current_function_returns_abnormally;
 
 static int warn_about_return_type;
 
-/* Nonzero when starting a function declared `extern inline'.  */
-
-static int current_extern_inline;
-
 /* Nonzero when the current toplevel function contains a declaration
    of a nested function which is never defined.  */
 
@@ -201,8 +207,7 @@ bool c_override_global_bindings_to_false;
    in all such cases, the binding in the outer scope will have its
    invisible bit true.  */
 
-struct c_binding GTY((chain_next ("%h.prev")))
-{
+struct GTY((chain_next ("%h.prev"))) c_binding {
   tree decl;                   /* the decl bound */
   tree type;                   /* the type in this scope */
   tree id;                     /* the identifier it's bound to */
@@ -213,6 +218,7 @@ struct c_binding GTY((chain_next ("%h.prev")))
   BOOL_BITFIELD nested : 1;     /* do not set DECL_CONTEXT when popping */
   BOOL_BITFIELD inner_comp : 1; /* incomplete array completed in inner scope */
   /* one free bit */
+  location_t locus;            /* location for nested bindings */
 };
 #define B_IN_SCOPE(b1, b2) ((b1)->depth == (b2)->depth)
 #define B_IN_CURRENT_SCOPE(b) ((b)->depth == current_scope->depth)
@@ -238,8 +244,7 @@ struct c_binding GTY((chain_next ("%h.prev")))
    These describe the values of the identifier in the three different
    namespaces defined by the language.  */
 
-struct lang_identifier GTY(())
-{
+struct GTY(()) lang_identifier {
   struct c_common_identifier common_id;
   struct c_binding *symbol_binding; /* vars, funcs, constants, typedefs */
   struct c_binding *tag_binding;    /* struct/union/enum tags */
@@ -252,10 +257,9 @@ extern char C_SIZEOF_STRUCT_LANG_IDENTIFIER_isnt_accurate
 
 /* The resulting tree type.  */
 
-union lang_tree_node
-  GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
-       chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *) TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *) TREE_CHAIN (&%h.generic)")))
-{
+union GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
+       chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *) TYPE_NEXT_VARIANT (&%h.generic) : ((union lang_tree_node *) TREE_CHAIN (&%h.generic))")))  lang_tree_node
+ {
   union tree_node GTY ((tag ("0"),
                        desc ("tree_node_structure (&%h)")))
     generic;
@@ -307,8 +311,7 @@ union lang_tree_node
    pop_scope relies on this.  */
 
 
-struct c_scope GTY((chain_next ("%h.outer")))
-{
+struct GTY((chain_next ("%h.outer"))) c_scope {
   /* The scope containing this one.  */
   struct c_scope *outer;
 
@@ -331,6 +334,10 @@ struct c_scope GTY((chain_next ("%h.outer")))
      declarations.  */
   BOOL_BITFIELD parm_flag : 1;
 
+  /* True if we saw [*] in this scope.  Used to give an error messages
+     if these appears in a function definition.  */
+  BOOL_BITFIELD had_vla_unspec : 1;
+
   /* True if we already complained about forward parameter decls
      in this scope.  This prevents double warnings on
      foo (int a; int b; ...)  */
@@ -344,6 +351,9 @@ struct c_scope GTY((chain_next ("%h.outer")))
 
   /* True means make a BLOCK for this scope no matter what.  */
   BOOL_BITFIELD keep : 1;
+
+  /* True means that an unsuffixed float constant is _Decimal64.  */
+  BOOL_BITFIELD float_const_decimal64 : 1;
 };
 
 /* The scope currently in effect.  */
@@ -378,7 +388,7 @@ static GTY((deletable)) struct c_binding *binding_freelist;
   struct c_scope *s_ = (scope);                                \
   tree d_ = (decl);                                    \
   if (s_->list##_last)                                 \
-    TREE_CHAIN (s_->list##_last) = d_;                 \
+    BLOCK_CHAIN (s_->list##_last) = d_;                        \
   else                                                 \
     s_->list = d_;                                     \
   s_->list##_last = d_;                                        \
@@ -389,12 +399,38 @@ static GTY((deletable)) struct c_binding *binding_freelist;
   struct c_scope *t_ = (tscope);                               \
   struct c_scope *f_ = (fscope);                               \
   if (t_->to##_last)                                           \
-    TREE_CHAIN (t_->to##_last) = f_->from;                     \
+    BLOCK_CHAIN (t_->to##_last) = f_->from;                    \
   else                                                         \
     t_->to = f_->from;                                         \
   t_->to##_last = f_->from##_last;                             \
 } while (0)
 
+/* A c_inline_static structure stores details of a static identifier
+   referenced in a definition of a function that may be an inline
+   definition if no subsequent declaration of that function uses
+   "extern" or does not use "inline".  */
+
+struct GTY((chain_next ("%h.next"))) c_inline_static {
+  /* The location for a diagnostic.  */
+  location_t location;
+
+  /* The function that may be an inline definition.  */
+  tree function;
+
+  /* The object or function referenced.  */
+  tree static_decl;
+
+  /* What sort of reference this is.  */
+  enum c_inline_static_type type;
+
+  /* The next such structure or NULL.  */
+  struct c_inline_static *next;
+};
+
+/* List of static identifiers used or referenced in functions that may
+   be inline definitions.  */
+static GTY(()) struct c_inline_static *c_inline_statics;
+
 /* True means unconditionally make a BLOCK for the next scope pushed.  */
 
 static bool keep_next_level_flag;
@@ -405,17 +441,13 @@ static bool keep_next_level_flag;
 
 static bool next_is_function_body;
 
-/* Functions called automatically at the beginning and end of execution.  */
-
-static GTY(()) tree static_ctors;
-static GTY(()) tree static_dtors;
-
 /* Forward declarations.  */
 static tree lookup_name_in_scope (tree, struct c_scope *);
 static tree c_make_fname_decl (tree, int);
 static tree grokdeclarator (const struct c_declarator *,
                            struct c_declspecs *,
-                           enum decl_context, bool, tree *);
+                           enum decl_context, bool, tree *, tree *, tree *,
+                           bool *, enum deprecated_states);
 static tree grokparms (struct c_arg_info *, bool);
 static void layout_array_type (tree);
 \f
@@ -428,7 +460,7 @@ add_stmt (tree t)
 {
   enum tree_code code = TREE_CODE (t);
 
-  if (EXPR_P (t) && code != LABEL_EXPR)
+  if (CAN_HAVE_LOCATION_P (t) && code != LABEL_EXPR)
     {
       if (!EXPR_HAS_LOCATION (t))
        SET_EXPR_LOCATION (t, input_location);
@@ -444,17 +476,6 @@ add_stmt (tree t)
   return t;
 }
 \f
-/* States indicating how grokdeclarator() should handle declspecs marked
-   with __attribute__((deprecated)).  An object declared as
-   __attribute__((deprecated)) suppresses warnings of uses of other
-   deprecated items.  */
-
-enum deprecated_states {
-  DEPRECATED_NORMAL,
-  DEPRECATED_SUPPRESS
-};
-
-static enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
 
 void
 c_print_identifier (FILE *file, tree node, int indent)
@@ -462,7 +483,7 @@ c_print_identifier (FILE *file, tree node, int indent)
   print_node (file, "symbol", I_SYMBOL_DECL (node), indent + 4);
   print_node (file, "tag", I_TAG_DECL (node), indent + 4);
   print_node (file, "label", I_LABEL_DECL (node), indent + 4);
-  if (C_IS_RESERVED_WORD (node))
+  if (C_IS_RESERVED_WORD (node) && C_RID_CODE (node) != RID_CXX_COMPAT_WARN)
     {
       tree rid = ridpointers[C_RID_CODE (node)];
       indent_to (file, indent + 4);
@@ -475,7 +496,8 @@ c_print_identifier (FILE *file, tree node, int indent)
    which may be any of several kinds of DECL or TYPE or error_mark_node,
    in the scope SCOPE.  */
 static void
-bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
+bind (tree name, tree decl, struct c_scope *scope, bool invisible,
+      bool nested, location_t locus)
 {
   struct c_binding *b, **here;
 
@@ -494,6 +516,7 @@ bind (tree name, tree decl, struct c_scope *scope, bool invisible, bool nested)
   b->invisible = invisible;
   b->nested = nested;
   b->inner_comp = 0;
+  b->locus = locus;
 
   b->type = 0;
 
@@ -570,6 +593,53 @@ c_finish_incomplete_decl (tree decl)
     }
 }
 \f
+/* Record that inline function FUNC contains a reference (location
+   LOC) to static DECL (file-scope or function-local according to
+   TYPE).  */
+
+void
+record_inline_static (location_t loc, tree func, tree decl,
+                     enum c_inline_static_type type)
+{
+  struct c_inline_static *csi = GGC_NEW (struct c_inline_static);
+  csi->location = loc;
+  csi->function = func;
+  csi->static_decl = decl;
+  csi->type = type;
+  csi->next = c_inline_statics;
+  c_inline_statics = csi;
+}
+
+/* Check for references to static declarations in inline functions at
+   the end of the translation unit and diagnose them if the functions
+   are still inline definitions.  */
+
+static void
+check_inline_statics (void)
+{
+  struct c_inline_static *csi;
+  for (csi = c_inline_statics; csi; csi = csi->next)
+    {
+      if (DECL_EXTERNAL (csi->function))
+       switch (csi->type)
+         {
+         case csi_internal:
+           pedwarn (csi->location, 0,
+                    "%qD is static but used in inline function %qD "
+                    "which is not static", csi->static_decl, csi->function);
+           break;
+         case csi_modifiable:
+           pedwarn (csi->location, 0,
+                    "%q+D is static but declared in inline function %qD "
+                    "which is not static", csi->static_decl, csi->function);
+           break;
+         default:
+           gcc_unreachable ();
+         }
+    }
+  c_inline_statics = NULL;
+}
+\f
 /* The Objective-C front-end often needs to determine the current scope.  */
 
 void *
@@ -605,7 +675,9 @@ objc_mark_locals_volatile (void *enclosing_blk)
 int
 global_bindings_p (void)
 {
-  return current_scope == file_scope && !c_override_global_bindings_to_false;
+  return (current_scope == file_scope && !c_override_global_bindings_to_false
+         ? -1
+         : 0);
 }
 
 void
@@ -614,6 +686,30 @@ keep_next_level (void)
   keep_next_level_flag = true;
 }
 
+/* Set the flag for the FLOAT_CONST_DECIMAL64 pragma being ON.  */
+
+void
+set_float_const_decimal64 (void)
+{
+  current_scope->float_const_decimal64 = true;
+}
+
+/* Clear the flag for the FLOAT_CONST_DECIMAL64 pragma.  */
+
+void
+clear_float_const_decimal64 (void)
+{
+  current_scope->float_const_decimal64 = false;
+}
+
+/* Return nonzero if an unsuffixed float constant is _Decimal64.  */
+
+bool
+float_const_decimal64_p (void)
+{
+  return current_scope->float_const_decimal64;
+}
+
 /* Identify this scope as currently being filled with parameters.  */
 
 void
@@ -645,6 +741,13 @@ push_scope (void)
 
       keep_next_level_flag = false;
       next_is_function_body = false;
+
+      /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes.  */
+      if (current_scope->outer)
+       current_scope->float_const_decimal64
+         = current_scope->outer->float_const_decimal64;
+      else
+       current_scope->float_const_decimal64 = false;
     }
   else
     {
@@ -657,6 +760,12 @@ push_scope (void)
       else
        scope = GGC_CNEW (struct c_scope);
 
+      /* The FLOAT_CONST_DECIMAL64 pragma applies to nested scopes.  */
+      if (current_scope)
+       scope->float_const_decimal64 = current_scope->float_const_decimal64;
+      else
+       scope->float_const_decimal64 = false;
+
       scope->keep          = keep_next_level_flag;
       scope->outer         = current_scope;
       scope->depth        = current_scope ? (current_scope->depth + 1) : 0;
@@ -711,7 +820,7 @@ pop_scope (void)
       TREE_USED (block) = 1;
 
       /* In each subblock, record that this is its superior.  */
-      for (p = scope->blocks; p; p = TREE_CHAIN (p))
+      for (p = scope->blocks; p; p = BLOCK_CHAIN (p))
        BLOCK_SUPERCONTEXT (p) = block;
 
       BLOCK_VARS (block) = 0;
@@ -755,19 +864,15 @@ pop_scope (void)
              error ("label %q+D used but not defined", p);
              DECL_INITIAL (p) = error_mark_node;
            }
-         else if (!TREE_USED (p) && warn_unused_label)
-           {
-             if (DECL_INITIAL (p))
-               warning (0, "label %q+D defined but not used", p);
-             else
-               warning (0, "label %q+D declared but not defined", p);
-           }
+         else 
+           warn_for_unused_label (p);
+
          /* Labels go in BLOCK_VARS.  */
          TREE_CHAIN (p) = BLOCK_VARS (block);
          BLOCK_VARS (block) = p;
          gcc_assert (I_LABEL_BINDING (b->id) == b);
-         I_LABEL_BINDING (b->id) = b->shadowed;
-         break;
+         I_LABEL_BINDING (b->id) = b->shadowed;
+         break;
 
        case ENUMERAL_TYPE:
        case UNION_TYPE:
@@ -781,7 +886,7 @@ pop_scope (void)
              gcc_assert (I_TAG_BINDING (b->id) == b);
              I_TAG_BINDING (b->id) = b->shadowed;
            }
-         break;
+         break;
 
        case FUNCTION_DECL:
          /* Propagate TREE_ADDRESSABLE from nested functions to their
@@ -793,21 +898,37 @@ pop_scope (void)
              && DECL_ABSTRACT_ORIGIN (p) != p)
            TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (p)) = 1;
          if (!DECL_EXTERNAL (p)
-             && DECL_INITIAL (p) == 0)
+             && !DECL_INITIAL (p)
+             && scope != file_scope
+             && scope != external_scope)
            {
              error ("nested function %q+D declared but never defined", p);
              undef_nested_function = true;
            }
+         else if (DECL_DECLARED_INLINE_P (p)
+                  && TREE_PUBLIC (p)
+                  && !DECL_INITIAL (p))
+           {
+             /* C99 6.7.4p6: "a function with external linkage... declared
+                with an inline function specifier ... shall also be defined
+                in the same translation unit."  */
+             if (!flag_gnu89_inline)
+               pedwarn (input_location, 0,
+                        "inline function %q+D declared but never defined", p);
+             DECL_EXTERNAL (p) = 1;
+           }
+
          goto common_symbol;
 
        case VAR_DECL:
          /* Warnings for unused variables.  */
          if (!TREE_USED (p)
+             && !TREE_NO_WARNING (p)
              && !DECL_IN_SYSTEM_HEADER (p)
              && DECL_NAME (p)
              && !DECL_ARTIFICIAL (p)
              && scope != file_scope
-             && scope != external_scope) 
+             && scope != external_scope)
            warning (OPT_Wunused_variable, "unused variable %q+D", p);
 
          if (b->inner_comp)
@@ -827,6 +948,29 @@ pop_scope (void)
              TREE_CHAIN (p) = BLOCK_VARS (block);
              BLOCK_VARS (block) = p;
            }
+         else if (VAR_OR_FUNCTION_DECL_P (p))
+           {
+             /* For block local externs add a special
+                DECL_EXTERNAL decl for debug info generation.  */
+             tree extp = copy_node (p);
+
+             DECL_EXTERNAL (extp) = 1;
+             TREE_STATIC (extp) = 0;
+             TREE_PUBLIC (extp) = 1;
+             DECL_INITIAL (extp) = NULL_TREE;
+             DECL_LANG_SPECIFIC (extp) = NULL;
+             DECL_CONTEXT (extp) = current_function_decl;
+             if (TREE_CODE (p) == FUNCTION_DECL)
+               {
+                 DECL_RESULT (extp) = NULL_TREE;
+                 DECL_SAVED_TREE (extp) = NULL_TREE;
+                 DECL_STRUCT_FUNCTION (extp) = NULL;
+               }
+             if (b->locus != UNKNOWN_LOCATION)
+               DECL_SOURCE_LOCATION (extp) = b->locus;
+             TREE_CHAIN (extp) = BLOCK_VARS (block);
+             BLOCK_VARS (block) = extp;
+           }
          /* If this is the file scope, and we are processing more
             than one translation unit in this compilation, set
             DECL_CONTEXT of each decl to the TRANSLATION_UNIT_DECL.
@@ -908,7 +1052,7 @@ push_file_scope (void)
 
   for (decl = visible_builtins; decl; decl = TREE_CHAIN (decl))
     bind (DECL_NAME (decl), decl, file_scope,
-         /*invisible=*/false, /*nested=*/true);
+         /*invisible=*/false, /*nested=*/true, DECL_SOURCE_LOCATION (decl));
 }
 
 void
@@ -924,6 +1068,8 @@ pop_file_scope (void)
      still works without it.  */
   finish_fname_decls ();
 
+  check_inline_statics ();
+
   /* This is the point to write out a PCH if we're doing that.
      In that case we do not want to do anything else.  */
   if (pch_file)
@@ -940,16 +1086,6 @@ pop_file_scope (void)
   cgraph_finalize_compilation_unit ();
 }
 
-/* Insert BLOCK at the end of the list of subblocks of the current
-   scope.  This is used when a BIND_EXPR is expanded, to handle the
-   BLOCK node inside the BIND_EXPR.  */
-
-void
-insert_block (tree block)
-{
-  TREE_USED (block) = 1;
-  SCOPE_LIST_APPEND (current_scope, blocks, block);
-}
 \f
 /* Push a definition or a declaration of struct, union or enum tag "name".
    "type" should be the type node.
@@ -959,12 +1095,12 @@ insert_block (tree block)
    In that case, the TYPE_SIZE will be zero.  */
 
 static void
-pushtag (tree name, tree type)
+pushtag (tree name, tree type, location_t loc)
 {
   /* Record the identifier as the type's name if it has none.  */
   if (name && !TYPE_NAME (type))
     TYPE_NAME (type) = name;
-  bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false);
+  bind (name, type, current_scope, /*invisible=*/false, /*nested=*/false, loc);
 
   /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE will be the
      tagged type we just added to the current scope.  This fake
@@ -1046,14 +1182,14 @@ diagnose_arglist_conflict (tree newdecl, tree olddecl,
       if (TREE_CHAIN (t) == 0
          && TYPE_MAIN_VARIANT (type) != void_type_node)
        {
-         inform ("a parameter list with an ellipsis can%'t match "
+         inform (input_location, "a parameter list with an ellipsis can%'t match "
                  "an empty parameter name list declaration");
          break;
        }
 
       if (c_type_promotes_to (type) != type)
        {
-         inform ("an argument type that has a default promotion can%'t match "
+         inform (input_location, "an argument type that has a default promotion can%'t match "
                  "an empty parameter name list declaration");
          break;
        }
@@ -1078,8 +1214,14 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
 
   for (;;)
     {
-      tree oldargtype = TYPE_MAIN_VARIANT (TREE_VALUE (oldargs));
-      tree newargtype = TYPE_MAIN_VARIANT (TREE_VALUE (newargs));
+      tree oldargtype = TREE_VALUE (oldargs);
+      tree newargtype = TREE_VALUE (newargs);
+
+      if (oldargtype == error_mark_node || newargtype == error_mark_node)
+       return false;
+
+      oldargtype = TYPE_MAIN_VARIANT (oldargtype);
+      newargtype = TYPE_MAIN_VARIANT (newargtype);
 
       if (END_OF_ARGLIST (oldargtype) && END_OF_ARGLIST (newargtype))
        break;
@@ -1126,16 +1268,16 @@ validate_proto_after_old_defn (tree newdecl, tree newtype, tree oldtype)
    first in a pair of mismatched declarations, using the diagnostic
    function DIAG.  */
 static void
-locate_old_decl (tree decl, void (*diag)(const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2))
+locate_old_decl (tree decl)
 {
   if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
     ;
   else if (DECL_INITIAL (decl))
-    diag (G_("previous definition of %q+D was here"), decl);
+    inform (input_location, "previous definition of %q+D was here", decl);
   else if (C_DECL_IMPLICIT (decl))
-    diag (G_("previous implicit declaration of %q+D was here"), decl);
+    inform (input_location, "previous implicit declaration of %q+D was here", decl);
   else
-    diag (G_("previous declaration of %q+D was here"), decl);
+    inform (input_location, "previous declaration of %q+D was here", decl);
 }
 
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
@@ -1176,7 +1318,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            && !C_DECL_DECLARED_BUILTIN (olddecl)))
        {
          error ("%q+D redeclared as different kind of symbol", newdecl);
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
        }
       else if (TREE_PUBLIC (newdecl))
        warning (0, "built-in function %q+D declared as non-function",
@@ -1192,7 +1334,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
   if (TREE_CODE (olddecl) == CONST_DECL)
     {
       error ("redeclaration of enumerator %q+D", newdecl);
-      locate_old_decl (olddecl, error);
+      locate_old_decl (olddecl);
       return false;
     }
 
@@ -1236,11 +1378,11 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
               && TYPE_MAIN_VARIANT (TREE_TYPE (newtype)) == integer_type_node
               && C_FUNCTION_IMPLICIT_INT (newdecl) && !DECL_INITIAL (olddecl))
        {
-         pedwarn ("conflicting types for %q+D", newdecl);
+         pedwarned = pedwarn (input_location, 0,
+                              "conflicting types for %q+D", newdecl);
          /* Make sure we keep void as the return type.  */
          TREE_TYPE (newdecl) = *newtypep = newtype = oldtype;
          C_FUNCTION_IMPLICIT_INT (newdecl) = 0;
-         pedwarned = true;
        }
       /* Permit void foo (...) to match an earlier call to foo (...) with
         no declared type (thus, implicitly int).  */
@@ -1249,10 +1391,10 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
               && TYPE_MAIN_VARIANT (TREE_TYPE (oldtype)) == integer_type_node
               && C_DECL_IMPLICIT (olddecl) && !DECL_INITIAL (olddecl))
        {
-         pedwarn ("conflicting types for %q+D", newdecl);
+         pedwarned = pedwarn (input_location, 0,
+                              "conflicting types for %q+D", newdecl);
          /* Make sure we keep void as the return type.  */
          TREE_TYPE (olddecl) = *oldtypep = oldtype = newtype;
-         pedwarned = true;
        }
       else
        {
@@ -1261,7 +1403,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
          else
            error ("conflicting types for %q+D", newdecl);
          diagnose_arglist_conflict (newdecl, olddecl, newtype, oldtype);
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
          return false;
        }
     }
@@ -1271,20 +1413,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
      header.  (Conflicting redeclarations were handled above.)  */
   if (TREE_CODE (newdecl) == TYPE_DECL)
     {
-      if (DECL_IN_SYSTEM_HEADER (newdecl) || DECL_IN_SYSTEM_HEADER (olddecl))
+      if (DECL_IN_SYSTEM_HEADER (newdecl)
+         || DECL_IN_SYSTEM_HEADER (olddecl)
+         || TREE_NO_WARNING (newdecl)
+         || TREE_NO_WARNING (olddecl))
        return true;  /* Allow OLDDECL to continue in use.  */
 
       error ("redefinition of typedef %q+D", newdecl);
-      locate_old_decl (olddecl, error);
+      locate_old_decl (olddecl);
       return false;
     }
 
   /* Function declarations can either be 'static' or 'extern' (no
      qualifier is equivalent to 'extern' - C99 6.2.2p5) and therefore
-     can never conflict with each other on account of linkage (6.2.2p4).
-     Multiple definitions are not allowed (6.9p3,5) but GCC permits
-     two definitions if one is 'extern inline' and one is not.  The non-
-     extern-inline definition supersedes the extern-inline definition.  */
+     can never conflict with each other on account of linkage
+     (6.2.2p4).  Multiple definitions are not allowed (6.9p3,5) but
+     gnu89 mode permits two definitions if one is 'extern inline' and
+     one is not.  The non- extern-inline definition supersedes the
+     extern-inline definition.  */
 
   else if (TREE_CODE (newdecl) == FUNCTION_DECL)
     {
@@ -1310,20 +1456,22 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            {
              /* If both decls are in the same TU and the new declaration
                 isn't overriding an extern inline reject the new decl.
-                When we handle c99 style inline rules we'll want to reject
-                the following:
-
-                DECL_EXTERN_INLINE (olddecl)
-                && !DECL_EXTERN_INLINE (newdecl)
-
-                if they're in the same translation unit. Until we implement
-                the full semantics we accept the construct.  */
-             if (!(DECL_EXTERN_INLINE (olddecl)
-                   && !DECL_EXTERN_INLINE (newdecl))
+                In c99, no overriding is allowed in the same translation
+                unit.  */
+             if ((!DECL_EXTERN_INLINE (olddecl)
+                  || DECL_EXTERN_INLINE (newdecl)
+                  || (!flag_gnu89_inline
+                      && (!DECL_DECLARED_INLINE_P (olddecl)
+                          || !lookup_attribute ("gnu_inline",
+                                                DECL_ATTRIBUTES (olddecl)))
+                      && (!DECL_DECLARED_INLINE_P (newdecl)
+                          || !lookup_attribute ("gnu_inline",
+                                                DECL_ATTRIBUTES (newdecl))))
+                 )
                  && same_translation_unit_p (newdecl, olddecl))
                {
                  error ("redefinition of %q+D", newdecl);
-                 locate_old_decl (olddecl, error);
+                 locate_old_decl (olddecl);
                  return false;
                }
            }
@@ -1335,7 +1483,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
               && TYPE_ACTUAL_ARG_TYPES (oldtype)
               && !validate_proto_after_old_defn (newdecl, newtype, oldtype))
        {
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
          return false;
        }
       /* A non-static declaration (even an "extern") followed by a
@@ -1359,7 +1507,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            {
              error ("static declaration of %q+D follows "
                     "non-static declaration", newdecl);
-             locate_old_decl (olddecl, error);
+             locate_old_decl (olddecl);
            }
          return false;
        }
@@ -1369,14 +1517,31 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            {
              error ("non-static declaration of %q+D follows "
                     "static declaration", newdecl);
-             locate_old_decl (olddecl, error);
+             locate_old_decl (olddecl);
              return false;
            }
          else if (warn_traditional)
            {
-             warning (OPT_Wtraditional, "non-static declaration of %q+D "
-                      "follows static declaration", newdecl);
-             warned = true;
+             warned |= warning (OPT_Wtraditional, 
+                                "non-static declaration of %q+D "
+                                "follows static declaration", newdecl);
+           }
+       }
+
+      /* Make sure gnu_inline attribute is either not present, or
+        present on all inline decls.  */
+      if (DECL_DECLARED_INLINE_P (olddecl)
+         && DECL_DECLARED_INLINE_P (newdecl))
+       {
+         bool newa = lookup_attribute ("gnu_inline",
+                                       DECL_ATTRIBUTES (newdecl)) != NULL;
+         bool olda = lookup_attribute ("gnu_inline",
+                                       DECL_ATTRIBUTES (olddecl)) != NULL;
+         if (newa != olda)
+           {
+             error ("%<gnu_inline%> attribute present on %q+D",
+                    newa ? newdecl : olddecl);
+             error ("%Jbut not here", newa ? olddecl : newdecl);
            }
        }
     }
@@ -1384,7 +1549,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
     {
       /* Only variables can be thread-local, and all declarations must
         agree on this property.  */
-      if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl))
+      if (C_DECL_THREADPRIVATE_P (olddecl) && !DECL_THREAD_LOCAL_P (newdecl))
+       {
+         /* Nothing to check.  Since OLDDECL is marked threadprivate
+            and NEWDECL does not have a thread-local attribute, we
+            will merge the threadprivate attribute into NEWDECL.  */
+         ;
+       }
+      else if (DECL_THREAD_LOCAL_P (newdecl) != DECL_THREAD_LOCAL_P (olddecl))
        {
          if (DECL_THREAD_LOCAL_P (newdecl))
            error ("thread-local declaration of %q+D follows "
@@ -1393,7 +1565,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            error ("non-thread-local declaration of %q+D follows "
                   "thread-local declaration", newdecl);
 
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
          return false;
        }
 
@@ -1401,7 +1573,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       if (DECL_INITIAL (newdecl) && DECL_INITIAL (olddecl))
        {
          error ("redefinition of %q+D", newdecl);
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
          return false;
        }
 
@@ -1422,14 +1594,14 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                {
                  error ("extern declaration of %q+D follows "
                         "declaration with no linkage", newdecl);
-                 locate_old_decl (olddecl, error);
+                 locate_old_decl (olddecl);
                  return false;
                }
              else if (warn_traditional)
                {
-                 warning (OPT_Wtraditional, "non-static declaration of %q+D "
-                          "follows static declaration", newdecl);
-                 warned = true;
+                 warned |= warning (OPT_Wtraditional, 
+                                    "non-static declaration of %q+D "
+                                    "follows static declaration", newdecl);
                }
            }
          else
@@ -1441,7 +1613,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
                error ("static declaration of %q+D follows "
                       "non-static declaration", newdecl);
 
-             locate_old_decl (olddecl, error);
+             locate_old_decl (olddecl);
              return false;
            }
        }
@@ -1458,12 +1630,12 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
            {
              error ("declaration of %q+D with no linkage follows "
                     "extern declaration", newdecl);
-             locate_old_decl (olddecl, error);
+             locate_old_decl (olddecl);
            }
          else
            {
              error ("redeclaration of %q+D with no linkage", newdecl);
-             locate_old_decl (olddecl, error);
+             locate_old_decl (olddecl);
            }
 
          return false;
@@ -1472,13 +1644,12 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 
   /* warnings */
   /* All decls must agree on a visibility.  */
-  if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS) 
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (newdecl), TS_DECL_WITH_VIS)
       && DECL_VISIBILITY_SPECIFIED (newdecl) && DECL_VISIBILITY_SPECIFIED (olddecl)
       && DECL_VISIBILITY (newdecl) != DECL_VISIBILITY (olddecl))
     {
-      warning (0, "redeclaration of %q+D with different visibility "
-              "(old visibility preserved)", newdecl);
-      warned = true;
+      warned |= warning (0, "redeclaration of %q+D with different visibility "
+                        "(old visibility preserved)", newdecl);
     }
 
   if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -1487,36 +1658,16 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       if (DECL_DECLARED_INLINE_P (newdecl)
          && lookup_attribute ("noinline", DECL_ATTRIBUTES (olddecl)))
        {
-         warning (OPT_Wattributes, "inline declaration of %qD follows "
-                  "declaration with attribute noinline", newdecl);
-         warned = true;
+         warned |= warning (OPT_Wattributes, 
+                            "inline declaration of %qD follows "
+                            "declaration with attribute noinline", newdecl);
        }
       else if (DECL_DECLARED_INLINE_P (olddecl)
               && lookup_attribute ("noinline", DECL_ATTRIBUTES (newdecl)))
        {
-         warning (OPT_Wattributes, "declaration of %q+D with attribute "
-                  "noinline follows inline declaration ", newdecl);
-         warned = true;
-       }
-
-      /* Inline declaration after use or definition.
-        ??? Should we still warn about this now we have unit-at-a-time
-        mode and can get it right?
-        Definitely don't complain if the decls are in different translation
-        units.  */
-      if (DECL_DECLARED_INLINE_P (newdecl) && !DECL_DECLARED_INLINE_P (olddecl)
-         && same_translation_unit_p (olddecl, newdecl))
-       {
-         if (TREE_USED (olddecl))
-           {
-             warning (0, "%q+D declared inline after being called", olddecl);
-             warned = true;
-           }
-         else if (DECL_INITIAL (olddecl))
-           {
-             warning (0, "%q+D declared inline after its definition", olddecl);
-             warned = true;
-           }
+         warned |= warning (OPT_Wattributes, 
+                            "declaration of %q+D with attribute "
+                            "noinline follows inline declaration ", newdecl);
        }
     }
   else /* PARM_DECL, VAR_DECL */
@@ -1534,7 +1685,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
          && (!TREE_ASM_WRITTEN (olddecl) || TREE_ASM_WRITTEN (newdecl)))
        {
          error ("redefinition of parameter %q+D", newdecl);
-         locate_old_decl (olddecl, error);
+         locate_old_decl (olddecl);
          return false;
        }
     }
@@ -1555,16 +1706,18 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
       && !(DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl))
       /* Don't warn about forward parameter decls.  */
       && !(TREE_CODE (newdecl) == PARM_DECL
-          && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl)))
+          && TREE_ASM_WRITTEN (olddecl) && !TREE_ASM_WRITTEN (newdecl))
+      /* Don't warn about a variable definition following a declaration.  */
+      && !(TREE_CODE (newdecl) == VAR_DECL
+          && DECL_INITIAL (newdecl) && !DECL_INITIAL (olddecl)))
     {
-      warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D",
-              newdecl);
-      warned = true;
+      warned = warning (OPT_Wredundant_decls, "redundant redeclaration of %q+D",
+                       newdecl);
     }
 
-  /* Report location of previous decl/defn in a consistent manner.  */
+  /* Report location of previous decl/defn.  */
   if (warned || pedwarned)
-    locate_old_decl (olddecl, pedwarned ? pedwarn : warning0);
+    locate_old_decl (olddecl);
 
 #undef DECL_EXTERN_INLINE
 
@@ -1579,12 +1732,13 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
 static void
 merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
 {
-  int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
-                          && DECL_INITIAL (newdecl) != 0);
-  int new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
-                         && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
-  int old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
-                         && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
+  bool new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
+                           && DECL_INITIAL (newdecl) != 0);
+  bool new_is_prototype = (TREE_CODE (newdecl) == FUNCTION_DECL
+                          && TYPE_ARG_TYPES (TREE_TYPE (newdecl)) != 0);
+  bool old_is_prototype = (TREE_CODE (olddecl) == FUNCTION_DECL
+                          && TYPE_ARG_TYPES (TREE_TYPE (olddecl)) != 0);
+  bool extern_changed = false;
 
   /* For real parm decl following a forward decl, rechain the old decl
      in its new location and clear TREE_ASM_WRITTEN (it's not a
@@ -1632,201 +1786,238 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
       DECL_SIZE (newdecl) = DECL_SIZE (olddecl);
       DECL_SIZE_UNIT (newdecl) = DECL_SIZE_UNIT (olddecl);
       DECL_MODE (newdecl) = DECL_MODE (olddecl);
-      if (TREE_CODE (olddecl) != FUNCTION_DECL)
-       if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
-         {
-           DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
-           DECL_USER_ALIGN (newdecl) |= DECL_ALIGN (olddecl);
-         }
+      if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl))
+       {
+         DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl);
+         DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl);
+       }
     }
 
+  /* Keep the old rtl since we can safely use it.  */
+  if (HAS_RTL_P (olddecl))
+    COPY_DECL_RTL (olddecl, newdecl);
 
   /* Merge the type qualifiers.  */
   if (TREE_READONLY (newdecl))
     TREE_READONLY (olddecl) = 1;
 
   if (TREE_THIS_VOLATILE (newdecl))
-    {
-      TREE_THIS_VOLATILE (olddecl) = 1;
-      if (TREE_CODE (newdecl) == VAR_DECL)
-       make_var_volatile (newdecl);
-    }
+    TREE_THIS_VOLATILE (olddecl) = 1;
 
   /* Merge deprecatedness.  */
   if (TREE_DEPRECATED (newdecl))
     TREE_DEPRECATED (olddecl) = 1;
 
-  /* Keep source location of definition rather than declaration and of
-     prototype rather than non-prototype unless that prototype is
-     built-in.  */
-  if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
-      || (old_is_prototype && !new_is_prototype
-         && !C_DECL_BUILTIN_PROTOTYPE (olddecl)))
+  /* If a decl is in a system header and the other isn't, keep the one on the
+     system header. Otherwise, keep source location of definition rather than
+     declaration and of prototype rather than non-prototype unless that
+     prototype is built-in.  */
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)
+      && DECL_IN_SYSTEM_HEADER (olddecl)
+      && !DECL_IN_SYSTEM_HEADER (newdecl) )
+    DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
+  else if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS)
+          && DECL_IN_SYSTEM_HEADER (newdecl)
+          && !DECL_IN_SYSTEM_HEADER (olddecl))
+    DECL_SOURCE_LOCATION (olddecl) = DECL_SOURCE_LOCATION (newdecl);
+  else if ((DECL_INITIAL (newdecl) == 0 && DECL_INITIAL (olddecl) != 0)
+          || (old_is_prototype && !new_is_prototype
+              && !C_DECL_BUILTIN_PROTOTYPE (olddecl)))
     DECL_SOURCE_LOCATION (newdecl) = DECL_SOURCE_LOCATION (olddecl);
 
   /* Merge the initialization information.  */
    if (DECL_INITIAL (newdecl) == 0)
     DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
 
-   if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
-     {
-       /* 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;
-
-       /* Merge the section attribute.
-         We want to issue an error if the sections conflict but that must be
-         done later in decl_attributes since we are called before attributes
-         are assigned.  */
-       if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
-        DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
-       
-       /* Copy the assembler name.
-         Currently, it can only be defined in the prototype.  */
-       COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
-
-       /* Use visibility of whichever declaration had it specified */
-       if (DECL_VISIBILITY_SPECIFIED (olddecl))
-        {
-          DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
-          DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
-        }
-       
-       if (TREE_CODE (newdecl) == FUNCTION_DECL)
-        {
-          DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
-          DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
-          DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
-          DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
-            |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
-          TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
-          TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
-          DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
-          DECL_IS_PURE (newdecl) |= DECL_IS_PURE (olddecl);
-          DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
-        }
-       
-       /* Merge the storage class information.  */
-       merge_weak (newdecl, olddecl);
+  /* Merge the threadprivate attribute.  */
+  if (TREE_CODE (olddecl) == VAR_DECL && C_DECL_THREADPRIVATE_P (olddecl))
+    {
+      DECL_TLS_MODEL (newdecl) = DECL_TLS_MODEL (olddecl);
+      C_DECL_THREADPRIVATE_P (newdecl) = 1;
+    }
 
-       /* 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.  */
-          TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
-          /* If this clears `static', clear it in the identifier too.  */
-          if (!TREE_PUBLIC (olddecl))
-            TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
-        }
-     }
-   
-   if (DECL_EXTERNAL (newdecl))
-     {
-       TREE_STATIC (newdecl) = TREE_STATIC (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);
-          DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
-        }
-     }
-   else
-     {
-       TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
-       TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
-     }
-   
-   if (TREE_CODE (newdecl) == FUNCTION_DECL) 
-     {
-       /* If we're redefining a function previously defined as extern
-         inline, make sure we emit debug info for the inline before we
-         throw it away, in case it was inlined into a function that hasn't
-         been written out yet.  */
-       if (new_is_definition && DECL_INITIAL (olddecl))
-        {
-          if (TREE_USED (olddecl)
-              /* In unit-at-a-time mode we never inline re-defined extern
-                 inline functions.  */
-              && !flag_unit_at_a_time
-              && cgraph_function_possibly_inlined_p (olddecl))
-            (*debug_hooks->outlining_inline_function) (olddecl);
-
-          /* The new defn must not be inline.  */
-          DECL_INLINE (newdecl) = 0;
-          DECL_UNINLINABLE (newdecl) = 1;
-        }
-       else
-        {
-          /* If either decl says `inline', this fn is inline,
-             unless its definition was passed already.  */
-          if (DECL_DECLARED_INLINE_P (newdecl)
-              || DECL_DECLARED_INLINE_P (olddecl))
-            DECL_DECLARED_INLINE_P (newdecl) = 1;
-
-          DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
-            = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
-        }
+  if (CODE_CONTAINS_STRUCT (TREE_CODE (olddecl), TS_DECL_WITH_VIS))
+    {
+      /* Merge the section attribute.
+        We want to issue an error if the sections conflict but that
+        must be done later in decl_attributes since we are called
+        before attributes are assigned.  */
+      if (DECL_SECTION_NAME (newdecl) == NULL_TREE)
+       DECL_SECTION_NAME (newdecl) = DECL_SECTION_NAME (olddecl);
 
-       if (DECL_BUILT_IN (olddecl))
-        {
-          /* If redeclaring a builtin function, it stays built in.
-             But it gets tagged as having been declared.  */
-          DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
-          DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
-          C_DECL_DECLARED_BUILTIN (newdecl) = 1;
-          if (new_is_prototype)
-            C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
-          else
-            C_DECL_BUILTIN_PROTOTYPE (newdecl)
-              = C_DECL_BUILTIN_PROTOTYPE (olddecl);
-        }
+      /* Copy the assembler name.
+        Currently, it can only be defined in the prototype.  */
+      COPY_DECL_ASSEMBLER_NAME (olddecl, newdecl);
 
-       /* Also preserve various other info from the definition.  */
-       if (!new_is_definition)
-        {
-          DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
-          DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
-          DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
-          DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
-          DECL_ARGUMENTS (newdecl) = DECL_ARGUMENTS (olddecl);
-
-          /* Set DECL_INLINE on the declaration if we've got a body
-             from which to instantiate.  */
-          if (DECL_INLINE (olddecl) && !DECL_UNINLINABLE (newdecl))
-            {
-              DECL_INLINE (newdecl) = 1;
-              DECL_ABSTRACT_ORIGIN (newdecl)
-                = DECL_ABSTRACT_ORIGIN (olddecl);
-            }
-        }
-       else
-        {
-          /* If a previous declaration said inline, mark the
-             definition as inlinable.  */
-          if (DECL_DECLARED_INLINE_P (newdecl)
-              && !DECL_UNINLINABLE (newdecl))
-            DECL_INLINE (newdecl) = 1;
-        }
-     }
-   
-   /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
+      /* Use visibility of whichever declaration had it specified */
+      if (DECL_VISIBILITY_SPECIFIED (olddecl))
+       {
+         DECL_VISIBILITY (newdecl) = DECL_VISIBILITY (olddecl);
+         DECL_VISIBILITY_SPECIFIED (newdecl) = 1;
+       }
+
+      if (TREE_CODE (newdecl) == FUNCTION_DECL)
+       {
+         DECL_STATIC_CONSTRUCTOR(newdecl) |= DECL_STATIC_CONSTRUCTOR(olddecl);
+         DECL_STATIC_DESTRUCTOR (newdecl) |= DECL_STATIC_DESTRUCTOR (olddecl);
+         DECL_NO_LIMIT_STACK (newdecl) |= DECL_NO_LIMIT_STACK (olddecl);
+         DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (newdecl)
+           |= DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (olddecl);
+         TREE_THIS_VOLATILE (newdecl) |= TREE_THIS_VOLATILE (olddecl);
+         DECL_IS_MALLOC (newdecl) |= DECL_IS_MALLOC (olddecl);
+         DECL_IS_OPERATOR_NEW (newdecl) |= DECL_IS_OPERATOR_NEW (olddecl);
+         TREE_READONLY (newdecl) |= TREE_READONLY (olddecl);
+         DECL_PURE_P (newdecl) |= DECL_PURE_P (olddecl);
+         DECL_IS_NOVOPS (newdecl) |= DECL_IS_NOVOPS (olddecl);
+       }
+
+      /* Merge the storage class information.  */
+      merge_weak (newdecl, 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.  */
+         TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+         /* If this clears `static', clear it in the identifier too.  */
+         if (!TREE_PUBLIC (olddecl))
+           TREE_PUBLIC (DECL_NAME (olddecl)) = 0;
+       }
+    }
+
+  /* In c99, 'extern' declaration before (or after) 'inline' means this
+     function is not DECL_EXTERNAL, unless 'gnu_inline' attribute
+     is present.  */
+  if (TREE_CODE (newdecl) == FUNCTION_DECL
+      && !flag_gnu89_inline
+      && (DECL_DECLARED_INLINE_P (newdecl)
+         || DECL_DECLARED_INLINE_P (olddecl))
+      && (!DECL_DECLARED_INLINE_P (newdecl)
+         || !DECL_DECLARED_INLINE_P (olddecl)
+         || !DECL_EXTERNAL (olddecl))
+      && DECL_EXTERNAL (newdecl)
+      && !lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (newdecl))
+      && !current_function_decl)
+    DECL_EXTERNAL (newdecl) = 0;
+
+  if (DECL_EXTERNAL (newdecl))
+    {
+      TREE_STATIC (newdecl) = TREE_STATIC (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);
+         DECL_COMMON (newdecl) = DECL_COMMON (olddecl);
+       }
+    }
+  else
+    {
+      TREE_STATIC (olddecl) = TREE_STATIC (newdecl);
+      TREE_PUBLIC (olddecl) = TREE_PUBLIC (newdecl);
+    }
+
+  if (TREE_CODE (newdecl) == FUNCTION_DECL)
+    {
+      /* If we're redefining a function previously defined as extern
+        inline, make sure we emit debug info for the inline before we
+        throw it away, in case it was inlined into a function that
+        hasn't been written out yet.  */
+      if (new_is_definition && DECL_INITIAL (olddecl))
+       /* The new defn must not be inline.  */
+       DECL_UNINLINABLE (newdecl) = 1;
+      else
+       {
+         /* If either decl says `inline', this fn is inline, unless
+            its definition was passed already.  */
+         if (DECL_DECLARED_INLINE_P (newdecl)
+             || DECL_DECLARED_INLINE_P (olddecl))
+           DECL_DECLARED_INLINE_P (newdecl) = 1;
+
+         DECL_UNINLINABLE (newdecl) = DECL_UNINLINABLE (olddecl)
+           = (DECL_UNINLINABLE (newdecl) || DECL_UNINLINABLE (olddecl));
+
+         DECL_DISREGARD_INLINE_LIMITS (newdecl)
+           = DECL_DISREGARD_INLINE_LIMITS (olddecl)
+           = (DECL_DISREGARD_INLINE_LIMITS (newdecl)
+              || DECL_DISREGARD_INLINE_LIMITS (olddecl));
+       }
+
+      if (DECL_BUILT_IN (olddecl))
+       {
+         /* If redeclaring a builtin function, it stays built in.
+            But it gets tagged as having been declared.  */
+         DECL_BUILT_IN_CLASS (newdecl) = DECL_BUILT_IN_CLASS (olddecl);
+         DECL_FUNCTION_CODE (newdecl) = DECL_FUNCTION_CODE (olddecl);
+         C_DECL_DECLARED_BUILTIN (newdecl) = 1;
+         if (new_is_prototype)
+           C_DECL_BUILTIN_PROTOTYPE (newdecl) = 0;
+         else
+           C_DECL_BUILTIN_PROTOTYPE (newdecl)
+             = C_DECL_BUILTIN_PROTOTYPE (olddecl);
+       }
+
+      /* Preserve function specific target and optimization options */
+      if (DECL_FUNCTION_SPECIFIC_TARGET (olddecl)
+         && !DECL_FUNCTION_SPECIFIC_TARGET (newdecl))
+       DECL_FUNCTION_SPECIFIC_TARGET (newdecl)
+         = DECL_FUNCTION_SPECIFIC_TARGET (olddecl);
+
+      if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl)
+         && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl))
+       DECL_FUNCTION_SPECIFIC_OPTIMIZATION (newdecl)
+         = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (olddecl);
+
+      /* Also preserve various other info from the definition.  */
+      if (!new_is_definition)
+       {
+         tree t;
+         DECL_RESULT (newdecl) = DECL_RESULT (olddecl);
+         DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl);
+         DECL_STRUCT_FUNCTION (newdecl) = DECL_STRUCT_FUNCTION (olddecl);
+         DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl);
+         gimple_set_body (newdecl, gimple_body (olddecl));
+         DECL_ARGUMENTS (newdecl) = copy_list (DECL_ARGUMENTS (olddecl));
+         for (t = DECL_ARGUMENTS (newdecl); t ; t = TREE_CHAIN (t))
+           DECL_CONTEXT (t) = newdecl;
+
+         /* See if we've got a function to instantiate from.  */
+         if (DECL_SAVED_TREE (olddecl))
+           DECL_ABSTRACT_ORIGIN (newdecl)
+             = DECL_ABSTRACT_ORIGIN (olddecl);
+       }
+    }
+
+   extern_changed = DECL_EXTERNAL (olddecl) && !DECL_EXTERNAL (newdecl);
+
+   /* Merge the USED information.  */
+   if (TREE_USED (olddecl))
+     TREE_USED (newdecl) = 1;
+   else if (TREE_USED (newdecl))
+     TREE_USED (olddecl) = 1;
+
+  /* Copy most of the decl-specific fields of NEWDECL into OLDDECL.
      But preserve OLDDECL's DECL_UID and DECL_CONTEXT.  */
   {
     unsigned olddecl_uid = DECL_UID (olddecl);
     tree olddecl_context = DECL_CONTEXT (olddecl);
-    
+    tree olddecl_arguments = NULL;
+    if (TREE_CODE (olddecl) == FUNCTION_DECL)
+      olddecl_arguments = DECL_ARGUMENTS (olddecl);
+
     memcpy ((char *) olddecl + sizeof (struct tree_common),
            (char *) newdecl + sizeof (struct tree_common),
            sizeof (struct tree_decl_common) - sizeof (struct tree_common));
     switch (TREE_CODE (olddecl))
       {
+      case FUNCTION_DECL:
+       gimple_set_body (olddecl, gimple_body (newdecl));
+       /* fall through */
+
       case FIELD_DECL:
       case VAR_DECL:
       case PARM_DECL:
@@ -1834,20 +2025,21 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
       case RESULT_DECL:
       case CONST_DECL:
       case TYPE_DECL:
-      case FUNCTION_DECL:
        memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
                (char *) newdecl + sizeof (struct tree_decl_common),
                tree_code_size (TREE_CODE (olddecl)) - sizeof (struct tree_decl_common));
        break;
 
       default:
-       
+
        memcpy ((char *) olddecl + sizeof (struct tree_decl_common),
                (char *) newdecl + sizeof (struct tree_decl_common),
                sizeof (struct tree_decl_non_common) - sizeof (struct tree_decl_common));
       }
     DECL_UID (olddecl) = olddecl_uid;
     DECL_CONTEXT (olddecl) = olddecl_context;
+    if (TREE_CODE (olddecl) == FUNCTION_DECL)
+      DECL_ARGUMENTS (olddecl) = olddecl_arguments;
   }
 
   /* If OLDDECL had its DECL_RTL instantiated, re-invoke make_decl_rtl
@@ -1858,6 +2050,13 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)
          || (TREE_CODE (olddecl) == VAR_DECL
              && TREE_STATIC (olddecl))))
     make_decl_rtl (olddecl);
+
+  /* If we changed a function from DECL_EXTERNAL to !DECL_EXTERNAL,
+     and the definition is coming from the old version, cgraph needs
+     to be called again.  */
+  if (extern_changed && !new_is_definition
+      && TREE_CODE (olddecl) == FUNCTION_DECL && DECL_INITIAL (olddecl))
+    cgraph_mark_if_needed (olddecl);
 }
 
 /* Handle when a new declaration NEWDECL has the same name as an old
@@ -1873,7 +2072,11 @@ duplicate_decls (tree newdecl, tree olddecl)
   tree newtype = NULL, oldtype = NULL;
 
   if (!diagnose_mismatched_decls (newdecl, olddecl, &newtype, &oldtype))
-    return false;
+    {
+      /* Avoid `unused variable' and other warnings for OLDDECL.  */
+      TREE_NO_WARNING (olddecl) = 1;
+      return false;
+    }
 
   merge_decls (newdecl, olddecl, newtype, oldtype);
   return true;
@@ -1929,71 +2132,6 @@ warn_if_shadowing (tree new_decl)
       }
 }
 
-
-/* Subroutine of pushdecl.
-
-   X is a TYPE_DECL for a typedef statement.  Create a brand new
-   ..._TYPE node (which will be just a variant of the existing
-   ..._TYPE node with identical properties) and then install X
-   as the TYPE_NAME of this brand new (duplicate) ..._TYPE node.
-
-   The whole point here is to end up with a situation where each
-   and every ..._TYPE node the compiler creates will be uniquely
-   associated with AT MOST one node representing a typedef name.
-   This way, even though the compiler substitutes corresponding
-   ..._TYPE nodes for TYPE_DECL (i.e. "typedef name") nodes very
-   early on, later parts of the compiler can always do the reverse
-   translation and get back the corresponding typedef name.  For
-   example, given:
-
-        typedef struct S MY_TYPE;
-       MY_TYPE object;
-
-   Later parts of the compiler might only know that `object' was of
-   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
-       typedef struct S' MY_TYPE;
-       struct S' object;
-
-    And they can then deduce (from the node for type struct S') that
-    the original object declaration was:
-
-               MY_TYPE object;
-
-    Being able to do this is important for proper support of protoize,
-    and also for generating precise symbolic debugging information
-    which takes full account of the programmer's (typedef) vocabulary.
-
-    Obviously, we don't want to generate a duplicate ..._TYPE node if
-    the TYPE_DECL node that we are now processing really represents a
-    standard built-in type.
-
-    Since all standard types are effectively declared at line zero
-    in the source file, we can easily check to see if we are working
-    on a standard type by checking the current value of lineno.  */
-
-static void
-clone_underlying_type (tree x)
-{
-  if (DECL_IS_BUILTIN (x))
-    {
-      if (TYPE_NAME (TREE_TYPE (x)) == 0)
-       TYPE_NAME (TREE_TYPE (x)) = x;
-    }
-  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_variant_type_copy (tt);
-      TYPE_NAME (tt) = x;
-      TREE_USED (tt) = TREE_USED (x);
-      TREE_TYPE (x) = tt;
-    }
-}
-
 /* Record a decl-node X as belonging to the current lexical scope.
    Check for errors (such as an incompatible declaration for the same
    name already seen in the same scope).
@@ -2009,10 +2147,7 @@ pushdecl (tree x)
   struct c_scope *scope = current_scope;
   struct c_binding *b;
   bool nested = false;
-
-  /* Functions need the lang_decl data.  */
-  if (TREE_CODE (x) == FUNCTION_DECL && !DECL_LANG_SPECIFIC (x))
-    DECL_LANG_SPECIFIC (x) = GGC_CNEW (struct lang_decl);
+  location_t locus = DECL_SOURCE_LOCATION (x);
 
   /* Must set DECL_CONTEXT for everything not at file scope or
      DECL_FILE_SCOPE_P won't work.  Local externs don't count
@@ -2031,7 +2166,8 @@ pushdecl (tree x)
   /* Anonymous decls are just inserted in the scope.  */
   if (!name)
     {
-      bind (name, x, scope, /*invisible=*/false, /*nested=*/false);
+      bind (name, x, scope, /*invisible=*/false, /*nested=*/false,
+           locus);
       return x;
     }
 
@@ -2191,7 +2327,8 @@ pushdecl (tree x)
              = build_type_attribute_variant (thistype,
                                              TYPE_ATTRIBUTES (b->type));
          TREE_TYPE (b->decl) = thistype;
-         bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true);
+         bind (name, b->decl, scope, /*invisible=*/false, /*nested=*/true,
+               locus);
          return b->decl;
        }
       else if (TREE_PUBLIC (x))
@@ -2209,7 +2346,7 @@ pushdecl (tree x)
          else
            {
              bind (name, x, external_scope, /*invisible=*/true,
-                   /*nested=*/false);
+                   /*nested=*/false, locus);
              nested = true;
            }
        }
@@ -2220,9 +2357,9 @@ pushdecl (tree x)
 
  skip_external_and_shadow_checks:
   if (TREE_CODE (x) == TYPE_DECL)
-    clone_underlying_type (x);
+    set_underlying_type (x);
 
-  bind (name, x, scope, /*invisible=*/false, nested);
+  bind (name, x, scope, /*invisible=*/false, nested, locus);
 
   /* If x's type is incomplete because it's based on a
      structure or union which has not yet been fully declared,
@@ -2271,11 +2408,12 @@ pushdecl_top_level (tree x)
 
   if (TREE_PUBLIC (x))
     {
-      bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false);
+      bind (name, x, external_scope, /*invisible=*/true, /*nested=*/false,
+           UNKNOWN_LOCATION);
       nested = true;
     }
   if (file_scope)
-    bind (name, x, file_scope, /*invisible=*/false, nested);
+    bind (name, x, file_scope, /*invisible=*/false, nested, UNKNOWN_LOCATION);
 
   return x;
 }
@@ -2283,18 +2421,19 @@ pushdecl_top_level (tree x)
 static void
 implicit_decl_warning (tree id, tree olddecl)
 {
-  void (*diag) (const char *, ...) ATTRIBUTE_GCC_CDIAG(1,2);
-  switch (mesg_implicit_function_declaration)
+  if (warn_implicit_function_declaration)
     {
-    case 0: return;
-    case 1: diag = warning0; break;
-    case 2: diag = error;   break;
-    default: gcc_unreachable ();
-    }
+      bool warned;
 
-  diag (G_("implicit declaration of function %qE"), id);
-  if (olddecl)
-    locate_old_decl (olddecl, diag);
+      if (flag_isoc99)
+       warned = pedwarn (input_location, OPT_Wimplicit_function_declaration,
+                         "implicit declaration of function %qE", id);
+      else 
+       warned = warning (OPT_Wimplicit_function_declaration, 
+                         G_("implicit declaration of function %qE"), id);
+      if (olddecl && warned)
+       locate_old_decl (olddecl);
+    }
 }
 
 /* Generate an implicit declaration for identifier FUNCTIONID as a
@@ -2329,7 +2468,8 @@ implicitly_declare (tree functionid)
       if (!DECL_BUILT_IN (decl) && DECL_IS_BUILTIN (decl))
        {
          bind (functionid, decl, file_scope,
-               /*invisible=*/false, /*nested=*/true);
+               /*invisible=*/false, /*nested=*/true,
+               DECL_SOURCE_LOCATION (decl));
          return decl;
        }
       else
@@ -2364,13 +2504,14 @@ implicitly_declare (tree functionid)
                {
                  error ("incompatible implicit declaration of function %qD",
                         decl);
-                 locate_old_decl (decl, error);
+                 locate_old_decl (decl);
                }
            }
          b->type = TREE_TYPE (decl);
          TREE_TYPE (decl) = newtype;
          bind (functionid, decl, current_scope,
-               /*invisible=*/false, /*nested=*/true);
+               /*invisible=*/false, /*nested=*/true,
+               DECL_SOURCE_LOCATION (decl));
          return decl;
        }
     }
@@ -2430,10 +2571,11 @@ undeclared_variable (tree id, location_t loc)
        }
 
       /* If we are parsing old-style parameter decls, current_function_decl
-         will be nonnull but current_function_scope will be null.  */
+        will be nonnull but current_function_scope will be null.  */
       scope = current_function_scope ? current_function_scope : current_scope;
     }
-  bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false);
+  bind (id, error_mark_node, scope, /*invisible=*/false, /*nested=*/false,
+       UNKNOWN_LOCATION);
 }
 \f
 /* Subroutine of lookup_label, declare_label, define_label: construct a
@@ -2487,7 +2629,7 @@ lookup_label (tree name)
 
   /* Ordinary labels go in the current function scope.  */
   bind (name, label, current_function_scope,
-       /*invisible=*/false, /*nested=*/false);
+       /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
   return label;
 }
 
@@ -2506,7 +2648,7 @@ declare_label (tree name)
   if (b && B_IN_CURRENT_SCOPE (b))
     {
       error ("duplicate label declaration %qE", name);
-      locate_old_decl (b->decl, error);
+      locate_old_decl (b->decl);
 
       /* Just use the previous declaration.  */
       return b->decl;
@@ -2517,7 +2659,7 @@ declare_label (tree name)
 
   /* Declared labels go in the current scope.  */
   bind (name, label, current_scope,
-       /*invisible=*/false, /*nested=*/false);
+       /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
   return label;
 }
 
@@ -2542,7 +2684,7 @@ define_label (location_t location, tree name)
              && C_DECLARED_LABEL_FLAG (label))))
     {
       error ("%Hduplicate label %qD", &location, label);
-      locate_old_decl (label, error);
+      locate_old_decl (label);
       return 0;
     }
   else if (label && DECL_CONTEXT (label) == current_function_decl)
@@ -2564,12 +2706,12 @@ define_label (location_t location, tree name)
 
       /* Ordinary labels go in the current function scope.  */
       bind (name, label, current_function_scope,
-           /*invisible=*/false, /*nested=*/false);
+           /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
     }
 
   if (!in_system_header && lookup_name (name))
     warning (OPT_Wtraditional, "%Htraditional C lacks a separate namespace "
-             "for labels, identifier %qE conflicts", &location, name);
+            "for labels, identifier %qE conflicts", &location, name);
 
   nlist_se = XOBNEW (&parser_obstack, struct c_label_list);
   nlist_se->next = label_context_stack_se->labels_def;
@@ -2591,10 +2733,13 @@ define_label (location_t location, tree name)
    If THISLEVEL_ONLY is nonzero, searches only the current_scope.
    CODE says which kind of type the caller wants;
    it is RECORD_TYPE or UNION_TYPE or ENUMERAL_TYPE.
+   If PLOC is not NULL and this returns non-null, it sets *PLOC to the
+   location where the tag was defined.
    If the wrong kind of type is found, an error is reported.  */
 
 static tree
-lookup_tag (enum tree_code code, tree name, int thislevel_only)
+lookup_tag (enum tree_code code, tree name, int thislevel_only,
+           location_t *ploc)
 {
   struct c_binding *b = I_TAG_BINDING (name);
   int thislevel = 0;
@@ -2631,6 +2776,10 @@ lookup_tag (enum tree_code code, tree name, int thislevel_only)
       if (thislevel)
        pending_xref_error ();
     }
+
+  if (ploc != NULL)
+    *ploc = b->locus;
+
   return b->decl;
 }
 
@@ -2644,7 +2793,7 @@ pending_xref_error (void)
 {
   if (pending_invalid_xref != 0)
     error ("%H%qE defined as wrong kind of tag",
-           &pending_invalid_xref_location, pending_invalid_xref);
+          &pending_invalid_xref_location, pending_invalid_xref);
   pending_invalid_xref = 0;
 }
 
@@ -2700,12 +2849,7 @@ c_init_decl_processing (void)
   /* Declarations from c_common_nodes_and_builtins must not be associated
      with this input file, lest we get differences between using and not
      using preprocessed headers.  */
-#ifdef USE_MAPPED_LOCATION
   input_location = BUILTINS_LOCATION;
-#else
-  input_location.file = "<built-in>";
-  input_location.line = 0;
-#endif
 
   build_common_tree_nodes (flag_signed_char, false);
 
@@ -2753,53 +2897,73 @@ c_make_fname_decl (tree id, int type_dep)
   DECL_ARTIFICIAL (decl) = 1;
 
   init = build_string (length + 1, name);
-  free ((char *) name);
+  free (CONST_CAST (char *, name));
   TREE_TYPE (init) = type;
   DECL_INITIAL (decl) = init;
 
   TREE_USED (decl) = 1;
 
-  if (current_function_decl)
+  if (current_function_decl
+      /* For invalid programs like this:
+        
+         void foo()
+         const char* p = __FUNCTION__;
+        
+        the __FUNCTION__ is believed to appear in K&R style function
+        parameter declarator.  In that case we still don't have
+        function_scope.  */
+      && (!errorcount || current_function_scope))
     {
       DECL_CONTEXT (decl) = current_function_decl;
       bind (id, decl, current_function_scope,
-           /*invisible=*/false, /*nested=*/false);
+           /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
     }
 
-  finish_decl (decl, init, NULL_TREE);
+  finish_decl (decl, init, NULL_TREE, NULL_TREE);
 
   return decl;
 }
 
-/* Return a definition for a builtin function named NAME and whose data type
-   is TYPE.  TYPE should be a function type with argument types.
-   FUNCTION_CODE tells later passes how to compile calls to this function.
-   See tree.h for its possible values.
+tree
+c_builtin_function (tree decl)
+{
+  tree type = TREE_TYPE (decl);
+  tree   id = DECL_NAME (decl);
+
+  const char *name = IDENTIFIER_POINTER (id);
+  C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
+
+  /* Should never be called on a symbol with a preexisting meaning.  */
+  gcc_assert (!I_SYMBOL_BINDING (id));
+
+  bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false,
+       UNKNOWN_LOCATION);
+
+  /* Builtins in the implementation namespace are made visible without
+     needing to be explicitly declared.  See push_file_scope.  */
+  if (name[0] == '_' && (name[1] == '_' || ISUPPER (name[1])))
+    {
+      TREE_CHAIN (decl) = visible_builtins;
+      visible_builtins = decl;
+    }
 
-   If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME,
-   the name to be called if we can't opencode the function.  If
-   ATTRS is nonzero, use that for the function's attribute list.  */
+  return decl;
+}
 
 tree
-builtin_function (const char *name, tree type, int function_code,
-                 enum built_in_class cl, const char *library_name,
-                 tree attrs)
+c_builtin_function_ext_scope (tree decl)
 {
-  tree id = get_identifier (name);
-  tree decl = build_decl (FUNCTION_DECL, id, type);
-  TREE_PUBLIC (decl) = 1;
-  DECL_EXTERNAL (decl) = 1;
-  DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
-  DECL_BUILT_IN_CLASS (decl) = cl;
-  DECL_FUNCTION_CODE (decl) = function_code;
+  tree type = TREE_TYPE (decl);
+  tree   id = DECL_NAME (decl);
+
+  const char *name = IDENTIFIER_POINTER (id);
   C_DECL_BUILTIN_PROTOTYPE (decl) = (TYPE_ARG_TYPES (type) != 0);
-  if (library_name)
-    SET_DECL_ASSEMBLER_NAME (decl, get_identifier (library_name));
 
   /* Should never be called on a symbol with a preexisting meaning.  */
   gcc_assert (!I_SYMBOL_BINDING (id));
 
-  bind (id, decl, external_scope, /*invisible=*/true, /*nested=*/false);
+  bind (id, decl, external_scope, /*invisible=*/false, /*nested=*/false,
+       UNKNOWN_LOCATION);
 
   /* Builtins in the implementation namespace are made visible without
      needing to be explicitly declared.  See push_file_scope.  */
@@ -2809,12 +2973,6 @@ builtin_function (const char *name, tree type, int function_code,
       visible_builtins = decl;
     }
 
-  /* Possibly apply some default attributes to this built-in function.  */
-  if (attrs)
-    decl_attributes (&decl, attrs, ATTR_FLAG_BUILT_IN);
-  else
-    decl_attributes (&decl, NULL_TREE, 0);
-
   return decl;
 }
 \f
@@ -2853,12 +3011,19 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
 
          found_tag = true;
 
+         if (declspecs->restrict_p)
+           {
+             error ("invalid use of %<restrict%>");
+             warned = 1;
+           }
+
          if (name == 0)
            {
              if (warned != 1 && code != ENUMERAL_TYPE)
                /* Empty unnamed enum OK */
                {
-                 pedwarn ("unnamed struct/union that defines no instances");
+                 pedwarn (input_location, 0,
+                          "unnamed struct/union that defines no instances");
                  warned = 1;
                }
            }
@@ -2866,7 +3031,8 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
                   && declspecs->storage_class != csc_none)
            {
              if (warned != 1)
-               pedwarn ("empty declaration with storage class specifier "
+               pedwarn (input_location, 0,
+                        "empty declaration with storage class specifier "
                         "does not redeclare tag");
              warned = 1;
              pending_xref_error ();
@@ -2877,20 +3043,21 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
                       || declspecs->restrict_p))
            {
              if (warned != 1)
-               pedwarn ("empty declaration with type qualifier "
-                        "does not redeclare tag");
+               pedwarn (input_location, 0,
+                        "empty declaration with type qualifier "
+                         "does not redeclare tag");
              warned = 1;
              pending_xref_error ();
            }
          else
            {
              pending_invalid_xref = 0;
-             t = lookup_tag (code, name, 1);
+             t = lookup_tag (code, name, 1, NULL);
 
              if (t == 0)
                {
                  t = make_node (code);
-                 pushtag (name, t);
+                 pushtag (name, t, input_location);
                }
            }
        }
@@ -2898,14 +3065,15 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
        {
          if (warned != 1 && !in_system_header)
            {
-             pedwarn ("useless type name in empty declaration");
+             pedwarn (input_location, 0,
+                      "useless type name in empty declaration");
              warned = 1;
            }
        }
     }
   else if (warned != 1 && !in_system_header && declspecs->typedef_p)
     {
-      pedwarn ("useless type name in empty declaration");
+      pedwarn (input_location, 0, "useless type name in empty declaration");
       warned = 1;
     }
 
@@ -2952,7 +3120,7 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
   if (warned != 1)
     {
       if (!found_tag)
-       pedwarn ("empty declaration");
+       pedwarn (input_location, 0, "empty declaration");
     }
 }
 \f
@@ -2985,14 +3153,14 @@ quals_from_declspecs (const struct c_declspecs *specs)
   return quals;
 }
 
-/* Construct an array declarator.  EXPR is the expression inside [], or
-   NULL_TREE.  QUALS are the type qualifiers inside the [] (to be applied
-   to the pointer to which a parameter array is converted).  STATIC_P is
-   true if "static" is inside the [], false otherwise.  VLA_UNSPEC_P
-   is true if the array is [*], a VLA of unspecified length which is
-   nevertheless a complete type (not currently implemented by GCC),
-   false otherwise.  The field for the contained declarator is left to be
-   filled in by set_array_declarator_inner.  */
+/* Construct an array declarator.  EXPR is the expression inside [],
+   or NULL_TREE.  QUALS are the type qualifiers inside the [] (to be
+   applied to the pointer to which a parameter array is converted).
+   STATIC_P is true if "static" is inside the [], false otherwise.
+   VLA_UNSPEC_P is true if the array is [*], a VLA of unspecified
+   length which is nevertheless a complete type, false otherwise.  The
+   field for the contained declarator is left to be filled in by
+   set_array_declarator_inner.  */
 
 struct c_declarator *
 build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p,
@@ -3015,42 +3183,78 @@ build_array_declarator (tree expr, struct c_declspecs *quals, bool static_p,
     }
   declarator->u.array.static_p = static_p;
   declarator->u.array.vla_unspec_p = vla_unspec_p;
-  if (pedantic && !flag_isoc99)
+  if (!flag_isoc99)
     {
       if (static_p || quals != NULL)
-       pedwarn ("ISO C90 does not support %<static%> or type "
+       pedwarn (input_location, OPT_pedantic,
+                "ISO C90 does not support %<static%> or type "
                 "qualifiers in parameter array declarators");
       if (vla_unspec_p)
-       pedwarn ("ISO C90 does not support %<[*]%> array declarators");
+       pedwarn (input_location, OPT_pedantic,
+                "ISO C90 does not support %<[*]%> array declarators");
     }
   if (vla_unspec_p)
-    warning (0, "GCC does not yet properly implement %<[*]%> array declarators");
+    {
+      if (!current_scope->parm_flag)
+       {
+         /* C99 6.7.5.2p4 */
+         error ("%<[*]%> not allowed in other than function prototype scope");
+         declarator->u.array.vla_unspec_p = false;
+         return NULL;
+       }
+      current_scope->had_vla_unspec = true;
+    }
   return declarator;
 }
 
 /* Set the contained declarator of an array declarator.  DECL is the
    declarator, as constructed by build_array_declarator; INNER is what
-   appears on the left of the [].  ABSTRACT_P is true if it is an
-   abstract declarator, false otherwise; this is used to reject static
-   and type qualifiers in abstract declarators, where they are not in
-   the C99 grammar (subject to possible change in DR#289).  */
+   appears on the left of the [].  */
 
 struct c_declarator *
 set_array_declarator_inner (struct c_declarator *decl,
-                           struct c_declarator *inner, bool abstract_p)
+                           struct c_declarator *inner)
 {
   decl->declarator = inner;
-  if (abstract_p && (decl->u.array.quals != TYPE_UNQUALIFIED
-                    || decl->u.array.attrs != NULL_TREE
-                    || decl->u.array.static_p))
-    error ("static or type qualifiers in abstract declarator");
   return decl;
 }
+
+/* INIT is a constructor that forms DECL's initializer.  If the final
+   element initializes a flexible array field, add the size of that
+   initializer to DECL's size.  */
+
+static void
+add_flexible_array_elts_to_size (tree decl, tree init)
+{
+  tree elt, type;
+
+  if (VEC_empty (constructor_elt, CONSTRUCTOR_ELTS (init)))
+    return;
+
+  elt = VEC_last (constructor_elt, CONSTRUCTOR_ELTS (init))->value;
+  type = TREE_TYPE (elt);
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TYPE_SIZE (type) == NULL_TREE
+      && TYPE_DOMAIN (type) != NULL_TREE
+      && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) == NULL_TREE)
+    {
+      complete_array_type (&type, elt, false);
+      DECL_SIZE (decl)
+       = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (type));
+      DECL_SIZE_UNIT (decl)
+       = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl), TYPE_SIZE_UNIT (type));
+    }
+}
 \f
-/* Decode a "typename", such as "int **", returning a ..._TYPE node.  */
+/* Decode a "typename", such as "int **", returning a ..._TYPE node.
+   Set *EXPR, if EXPR not NULL, to any expression to be evaluated
+   before the type name, and set *EXPR_CONST_OPERANDS, if
+   EXPR_CONST_OPERANDS not NULL, to indicate whether the type name may
+   appear in a constant expression.  */
 
 tree
-groktypename (struct c_type_name *type_name)
+groktypename (struct c_type_name *type_name, tree *expr,
+             bool *expr_const_operands)
 {
   tree type;
   tree attrs = type_name->specs->attrs;
@@ -3058,7 +3262,8 @@ groktypename (struct c_type_name *type_name)
   type_name->specs->attrs = NULL_TREE;
 
   type = grokdeclarator (type_name->declarator, type_name->specs, TYPENAME,
-                        false, NULL);
+                        false, NULL, &attrs, expr, expr_const_operands,
+                        DEPRECATED_NORMAL);
 
   /* Apply attributes.  */
   decl_attributes (&type, attrs, 0);
@@ -3087,6 +3292,8 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
 {
   tree decl;
   tree tem;
+  tree expr = NULL_TREE;
+  enum deprecated_states deprecated_state = DEPRECATED_NORMAL;
 
   /* An object declared as __attribute__((deprecated)) suppresses
      warnings of uses of other deprecated items.  */
@@ -3094,14 +3301,15 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
     deprecated_state = DEPRECATED_SUPPRESS;
 
   decl = grokdeclarator (declarator, declspecs,
-                        NORMAL, initialized, NULL);
+                        NORMAL, initialized, NULL, &attributes, &expr, NULL,
+                        deprecated_state);
   if (!decl)
     return 0;
 
-  deprecated_state = DEPRECATED_NORMAL;
+  if (expr)
+    add_stmt (expr);
 
-  if (warn_main > 0 && TREE_CODE (decl) != FUNCTION_DECL
-      && MAIN_NAME_P (DECL_NAME (decl)))
+  if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl)))
     warning (OPT_Wmain, "%q+D is usually a function", decl);
 
   if (initialized)
@@ -3199,6 +3407,19 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
   /* Set attributes here so if duplicate decl, will have proper attributes.  */
   decl_attributes (&decl, attributes, 0);
 
+  /* Handle gnu_inline attribute.  */
+  if (declspecs->inline_p
+      && !flag_gnu89_inline
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl))
+         || current_function_decl))
+    {
+      if (declspecs->storage_class == csc_auto && current_scope != file_scope)
+       ;
+      else if (declspecs->storage_class != csc_static)
+       DECL_EXTERNAL (decl) = !DECL_EXTERNAL (decl);
+    }
+
   if (TREE_CODE (decl) == FUNCTION_DECL
       && targetm.calls.promote_prototypes (TREE_TYPE (decl)))
     {
@@ -3226,6 +3447,18 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
     warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
             decl);
 
+  /* C99 6.7.4p3: An inline definition of a function with external
+     linkage shall not contain a definition of a modifiable object
+     with static storage duration...  */
+  if (TREE_CODE (decl) == VAR_DECL
+      && current_scope != file_scope
+      && TREE_STATIC (decl)
+      && !TREE_READONLY (decl)
+      && DECL_DECLARED_INLINE_P (current_function_decl)
+      && DECL_EXTERNAL (current_function_decl))
+    record_inline_static (input_location, current_function_decl,
+                         decl, csi_modifiable);
+
   /* Add this decl to the current scope.
      TEM may equal DECL or it may be a previous decl of the same name.  */
   tem = pushdecl (decl);
@@ -3239,15 +3472,33 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,
   return tem;
 }
 
+/* Initialize EH if not initialized yet and exceptions are enabled.  */
+
+void
+c_maybe_initialize_eh (void)
+{
+  if (!flag_exceptions || c_eh_initialized_p)
+    return;
+
+  c_eh_initialized_p = true;
+  eh_personality_libfunc
+    = init_one_libfunc (USING_SJLJ_EXCEPTIONS
+                       ? "__gcc_personality_sj0"
+                       : "__gcc_personality_v0");
+  default_init_unwind_resume_libfunc ();
+  using_eh_for_cleanups ();
+}
+
 /* Finish processing of a declaration;
    install its initial value.
+   If ORIGTYPE is not NULL_TREE, it is the original type of INIT.
    If the length of an array type is not known before,
    it must be determined now, from the initial value, or it is an error.  */
 
 void
-finish_decl (tree decl, tree init, tree asmspec_tree)
+finish_decl (tree decl, tree init, tree origtype, tree asmspec_tree)
 {
-  tree type = TREE_TYPE (decl);
+  tree type;
   int was_incomplete = (DECL_SIZE (decl) == 0);
   const char *asmspec = 0;
 
@@ -3267,13 +3518,15 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
     init = 0;
 
   if (init)
-    store_init_value (decl, init);
+    store_init_value (decl, init, origtype);
 
   if (c_dialect_objc () && (TREE_CODE (decl) == VAR_DECL
                            || TREE_CODE (decl) == FUNCTION_DECL
                            || TREE_CODE (decl) == FIELD_DECL))
     objc_check_decl (decl);
 
+  type = TREE_TYPE (decl);
+
   /* Deduce size of array from initialization, if not already known.  */
   if (TREE_CODE (type) == ARRAY_TYPE
       && TYPE_DOMAIN (type) == 0
@@ -3345,6 +3598,9 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
 
   if (TREE_CODE (decl) == VAR_DECL)
     {
+      if (init && TREE_CODE (init) == CONSTRUCTOR)
+       add_flexible_array_elts_to_size (decl, init);
+
       if (DECL_SIZE (decl) == 0 && TREE_TYPE (decl) != error_mark_node
          && COMPLETE_TYPE_P (TREE_TYPE (decl)))
        layout_decl (decl, 0);
@@ -3374,7 +3630,10 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
          if (TREE_CODE (DECL_SIZE (decl)) == INTEGER_CST)
            constant_expression_warning (DECL_SIZE (decl));
          else
-           error ("storage size of %q+D isn%'t constant", decl);
+           {
+             error ("storage size of %q+D isn%'t constant", decl);
+             TREE_TYPE (decl) = error_mark_node;
+           }
        }
 
       if (TREE_USED (type))
@@ -3394,23 +3653,21 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
   /* If #pragma weak was used, mark the decl weak now.  */
   maybe_apply_pragma_weak (decl);
 
-  /* If this is a variable definition, determine its ELF visibility.  */
-  if (TREE_CODE (decl) == VAR_DECL 
-      && TREE_STATIC (decl) 
-      && !DECL_EXTERNAL (decl))
-    c_determine_visibility (decl);
-
   /* Output the assembler code and/or RTL code for variables and functions,
      unless the type is an undefined structure or union.
      If not, it will get done when the type is completed.  */
 
   if (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL)
     {
+      /* Determine the ELF visibility.  */
+      if (TREE_PUBLIC (decl))
+       c_determine_visibility (decl);
+
       /* This is a no-op in c-lang.c or something real in objc-act.c.  */
       if (c_dialect_objc ())
        objc_check_decl (decl);
 
-      if (asmspec) 
+      if (asmspec)
        {
          /* If this is not a static variable, issue a warning.
             It doesn't make any sense to give an ASMSPEC for an
@@ -3423,12 +3680,10 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
              && !TREE_STATIC (decl))
            warning (0, "ignoring asm-specifier for non-static local "
                     "variable %q+D", decl);
-         else if (C_DECL_REGISTER (decl))
-           change_decl_assembler_name (decl, get_identifier (asmspec));
          else
            set_user_assembler_name (decl, asmspec);
        }
-      
+
       if (DECL_FILE_SCOPE_P (decl))
        {
          if (DECL_INITIAL (decl) == NULL_TREE
@@ -3474,7 +3729,7 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
              add_stmt (build_stmt (DECL_EXPR, decl));
            }
        }
-  
+
 
       if (!DECL_FILE_SCOPE_P (decl))
        {
@@ -3492,10 +3747,6 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
        }
     }
 
-  /* If this was marked 'used', be sure it will be output.  */
-  if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))
-    mark_decl_referenced (decl);
-
   if (TREE_CODE (decl) == TYPE_DECL)
     {
       if (!DECL_FILE_SCOPE_P (decl)
@@ -3520,27 +3771,21 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
          tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
          tree cleanup_decl = lookup_name (cleanup_id);
          tree cleanup;
+         VEC(tree,gc) *vec;
 
          /* Build "cleanup(&decl)" for the destructor.  */
-         cleanup = build_unary_op (ADDR_EXPR, decl, 0);
-         cleanup = build_tree_list (NULL_TREE, cleanup);
-         cleanup = build_function_call (cleanup_decl, cleanup);
+         cleanup = build_unary_op (input_location, ADDR_EXPR, decl, 0);
+         vec = VEC_alloc (tree, gc, 1);
+         VEC_quick_push (tree, vec, cleanup);
+         cleanup = build_function_call_vec (cleanup_decl, vec, NULL);
+         VEC_free (tree, gc, vec);
 
          /* Don't warn about decl unused; the cleanup uses it.  */
          TREE_USED (decl) = 1;
          TREE_USED (cleanup_decl) = 1;
 
          /* Initialize EH, if we've been told to do so.  */
-         if (flag_exceptions && !c_eh_initialized_p)
-           {
-             c_eh_initialized_p = true;
-             eh_personality_libfunc
-               = init_one_libfunc (USING_SJLJ_EXCEPTIONS
-                                   ? "__gcc_personality_sj0"
-                                   : "__gcc_personality_v0");
-             default_init_unwind_resume_libfunc ();
-             using_eh_for_cleanups ();
-           }
+         c_maybe_initialize_eh ();
 
          push_cleanup (decl, cleanup, false);
        }
@@ -3552,10 +3797,11 @@ finish_decl (tree decl, tree init, tree asmspec_tree)
 tree
 grokparm (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl = grokdeclarator (parm->declarator, parm->specs, PARM, false,
-                             NULL);
+                             NULL, &attrs, NULL, NULL, DEPRECATED_NORMAL);
 
-  decl_attributes (&decl, parm->attrs, 0);
+  decl_attributes (&decl, attrs, 0);
 
   return decl;
 }
@@ -3566,14 +3812,16 @@ grokparm (const struct c_parm *parm)
 void
 push_parm_decl (const struct c_parm *parm)
 {
+  tree attrs = parm->attrs;
   tree decl;
 
-  decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL);
-  decl_attributes (&decl, parm->attrs, 0);
+  decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
+                        &attrs, NULL, NULL, DEPRECATED_NORMAL);
+  decl_attributes (&decl, attrs, 0);
 
   decl = pushdecl (decl);
 
-  finish_decl (decl, NULL_TREE, NULL_TREE);
+  finish_decl (decl, NULL_TREE, NULL_TREE, NULL_TREE);
 }
 
 /* Mark all the parameter declarations to date as forward decls.
@@ -3586,7 +3834,8 @@ mark_forward_parm_decls (void)
 
   if (pedantic && !current_scope->warned_forward_parm_decls)
     {
-      pedwarn ("ISO C forbids forward parameter declarations");
+      pedwarn (input_location, OPT_pedantic,
+              "ISO C forbids forward parameter declarations");
       current_scope->warned_forward_parm_decls = true;
     }
 
@@ -3595,15 +3844,14 @@ mark_forward_parm_decls (void)
       TREE_ASM_WRITTEN (b->decl) = 1;
 }
 \f
-static GTY(()) int compound_literal_number;
-
 /* Build a COMPOUND_LITERAL_EXPR.  TYPE is the type given in the compound
    literal, which may be an incomplete array type completed by the
    initializer; INIT is a CONSTRUCTOR that initializes the compound
-   literal.  */
+   literal.  NON_CONST is true if the initializers contain something
+   that cannot occur in a constant expression.  */
 
 tree
-build_compound_literal (tree type, tree init)
+build_compound_literal (tree type, tree init, bool non_const)
 {
   /* We do not use start_decl here because we have a type, not a declarator;
      and do not use finish_decl because the decl should be stored inside
@@ -3623,7 +3871,7 @@ build_compound_literal (tree type, tree init)
   TREE_USED (decl) = 1;
   TREE_TYPE (decl) = type;
   TREE_READONLY (decl) = TYPE_READONLY (type);
-  store_init_value (decl, init);
+  store_init_value (decl, init, NULL_TREE);
 
   if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
     {
@@ -3646,14 +3894,8 @@ build_compound_literal (tree type, tree init)
 
   if (TREE_STATIC (decl))
     {
-      /* This decl needs a name for the assembler output.  We also need
-        a unique suffix to be added to the name.  */
-      char *name;
-
-      ASM_FORMAT_PRIVATE_NAME (name, "__compound_literal",
-                              compound_literal_number);
-      compound_literal_number++;
-      DECL_NAME (decl) = get_identifier (name);
+      /* This decl needs a name for the assembler output.  */
+      set_compound_literal_name (decl);
       DECL_DEFER_OUTPUT (decl) = 1;
       DECL_COMDAT (decl) = 1;
       DECL_ARTIFICIAL (decl) = 1;
@@ -3662,8 +3904,25 @@ build_compound_literal (tree type, tree init)
       rest_of_decl_compilation (decl, 1, 0);
     }
 
+  if (non_const)
+    {
+      complit = build2 (C_MAYBE_CONST_EXPR, type, NULL, complit);
+      C_MAYBE_CONST_EXPR_NON_CONST (complit) = 1;
+    }
+
   return complit;
 }
+
+/* Check the type of a compound literal.  Here we just check that it
+   is valid for C++.  */
+
+void
+check_compound_literal_type (struct c_type_name *type_name, location_t loc)
+{
+  if (warn_cxx_compat && type_name->specs->tag_defined_p)
+    warning_at (loc, OPT_Wc___compat,
+               "defining a type in a compound literal is invalid in C++");
+}
 \f
 /* Determine whether TYPE is a structure with a flexible array member,
    or a union containing such a structure (possibly recursively).  */
@@ -3701,12 +3960,14 @@ flexible_array_type_p (tree type)
 /* Performs sanity checks on the TYPE and WIDTH of the bit-field NAME,
    replacing with appropriate values if they are invalid.  */
 static void
-check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
+check_bitfield_type_and_width (tree *type, tree *width, tree orig_name)
 {
   tree type_mv;
   unsigned int max_width;
   unsigned HOST_WIDE_INT w;
-  const char *name = orig_name ? orig_name: _("<anonymous>");
+  const char *name = (orig_name
+                     ? identifier_to_locale (IDENTIFIER_POINTER (orig_name))
+                     : _("<anonymous>"));
 
   /* Detect and ignore out of range field width and process valid
      field widths.  */
@@ -3741,16 +4002,14 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
     }
 
   type_mv = TYPE_MAIN_VARIANT (*type);
-  if (pedantic
+  if (!in_system_header
       && type_mv != integer_type_node
       && type_mv != unsigned_type_node
       && type_mv != boolean_type_node)
-    pedwarn ("type of bit-field %qs is a GCC extension", name);
+    pedwarn (input_location, OPT_pedantic,
+            "type of bit-field %qs is a GCC extension", name);
 
-  if (type_mv == boolean_type_node)
-    max_width = CHAR_TYPE_SIZE;
-  else
-    max_width = TYPE_PRECISION (*type);
+  max_width = TYPE_PRECISION (*type);
 
   if (0 < compare_tree_int (*width, max_width))
     {
@@ -3765,36 +4024,97 @@ check_bitfield_type_and_width (tree *type, tree *width, const char *orig_name)
     {
       struct lang_type *lt = TYPE_LANG_SPECIFIC (*type);
       if (!lt
-          || w < min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
-         || w < min_precision (lt->enum_max, TYPE_UNSIGNED (*type)))
+         || w < tree_int_cst_min_precision (lt->enum_min, TYPE_UNSIGNED (*type))
+         || w < tree_int_cst_min_precision (lt->enum_max, TYPE_UNSIGNED (*type)))
        warning (0, "%qs is narrower than values of its type", name);
     }
 }
 
-/* Build a bit-field integer type for the given WIDTH and UNSIGNEDP.  */
+\f
+
+/* Print warning about variable length array if necessary.  */
+
+static void
+warn_variable_length_array (tree name, tree size)
+{
+  int const_size = TREE_CONSTANT (size);
+
+  if (!flag_isoc99 && pedantic && warn_vla != 0)
+    {
+      if (const_size)
+       {
+         if (name)
+           pedwarn (input_location, OPT_Wvla,
+                    "ISO C90 forbids array %qE whose size "
+                    "can%'t be evaluated",
+                    name);
+         else
+           pedwarn (input_location, OPT_Wvla, "ISO C90 forbids array whose size "
+                    "can%'t be evaluated");
+       }
+      else
+       {
+         if (name) 
+           pedwarn (input_location, OPT_Wvla,
+                    "ISO C90 forbids variable length array %qE",
+                    name);
+         else
+           pedwarn (input_location, OPT_Wvla, "ISO C90 forbids variable length array");
+       }
+    }
+  else if (warn_vla > 0)
+    {
+      if (const_size)
+        {
+         if (name)
+           warning (OPT_Wvla,
+                    "the size of array %qE can"
+                    "%'t be evaluated", name);
+         else
+           warning (OPT_Wvla,
+                    "the size of array can %'t be evaluated");
+       }
+      else
+       {
+         if (name)
+           warning (OPT_Wvla,
+                    "variable length array %qE is used",
+                    name);
+         else
+           warning (OPT_Wvla,
+                    "variable length array is used");
+       }
+    }
+}
+
+/* Given a size SIZE that may not be a constant, return a SAVE_EXPR to
+   serve as the actual size-expression for a type or decl.  This is
+   like variable_size in stor-layout.c, but we make global_bindings_p
+   return negative to avoid calls to that function from outside the
+   front end resulting in errors at file scope, then call this version
+   instead from front-end code.  */
+
 static tree
-c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
+c_variable_size (tree size)
 {
-  /* Extended integer types of the same width as a standard type have
-     lesser rank, so those of the same width as int promote to int or
-     unsigned int and are valid for printf formats expecting int or
-     unsigned int.  To avoid such special cases, avoid creating
-     extended integer types for bit-fields if a standard integer type
-     is available.  */
-  if (width == TYPE_PRECISION (integer_type_node))
-    return unsignedp ? unsigned_type_node : integer_type_node;
-  if (width == TYPE_PRECISION (signed_char_type_node))
-    return unsignedp ? unsigned_char_type_node : signed_char_type_node;
-  if (width == TYPE_PRECISION (short_integer_type_node))
-    return unsignedp ? short_unsigned_type_node : short_integer_type_node;
-  if (width == TYPE_PRECISION (long_integer_type_node))
-    return unsignedp ? long_unsigned_type_node : long_integer_type_node;
-  if (width == TYPE_PRECISION (long_long_integer_type_node))
-    return (unsignedp ? long_long_unsigned_type_node
-           : long_long_integer_type_node);
-  return build_nonstandard_integer_type (width, unsignedp);
+  tree save;
+
+  if (TREE_CONSTANT (size))
+    return size;
+
+  size = save_expr (size);
+
+  save = skip_simple_arithmetic (size);
+
+  if (cfun && cfun->dont_save_pending_sizes_p)
+    return size;
+
+  if (!global_bindings_p ())
+    put_pending_size (save);
+
+  return size;
 }
-\f
+
 /* Given declspecs and a declarator,
    determine the name and type of the object declared
    and construct a ..._DECL node for it.
@@ -3816,6 +4136,16 @@ c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
    INITIALIZED is true if the decl has an initializer.
    WIDTH is non-NULL for bit-fields, and is a pointer to an INTEGER_CST node
    representing the width of the bit-field.
+   DECL_ATTRS points to the list of attributes that should be added to this
+     decl.  Any nested attributes that belong on the decl itself will be
+     added to this list.
+   If EXPR is not NULL, any expressions that need to be evaluated as
+     part of evaluating variably modified types will be stored in *EXPR.
+   If EXPR_CONST_OPERANDS is not NULL, *EXPR_CONST_OPERANDS will be
+     set to indicate whether operands in *EXPR can be used in constant
+     expressions.
+   DEPRECATED_STATE is a deprecated_states value indicating whether
+   deprecation warnings should be suppressed.
 
    In the TYPENAME case, DECLARATOR is really an absolute declarator.
    It may also be so in the PARM case, for a prototype where the
@@ -3827,7 +4157,9 @@ c_build_bitfield_integer_type (unsigned HOST_WIDE_INT width, int unsignedp)
 static tree
 grokdeclarator (const struct c_declarator *declarator,
                struct c_declspecs *declspecs,
-               enum decl_context decl_context, bool initialized, tree *width)
+               enum decl_context decl_context, bool initialized, tree *width,
+               tree *decl_attrs, tree *expr, bool *expr_const_operands,
+               enum deprecated_states deprecated_state)
 {
   tree type = declspecs->type;
   bool threadp = declspecs->thread_p;
@@ -3836,28 +4168,37 @@ grokdeclarator (const struct c_declarator *declarator,
   int restrictp;
   int volatilep;
   int type_quals = TYPE_UNQUALIFIED;
-  const char *name, *orig_name;
-  tree typedef_type = 0;
-  int funcdef_flag = 0;
+  tree name = NULL_TREE;
+  bool funcdef_flag = false;
   bool funcdef_syntax = false;
   int size_varies = 0;
   tree decl_attr = declspecs->decl_attr;
   int array_ptr_quals = TYPE_UNQUALIFIED;
   tree array_ptr_attrs = NULL_TREE;
   int array_parm_static = 0;
+  bool array_parm_vla_unspec_p = false;
   tree returned_attrs = NULL_TREE;
   bool bitfield = width != NULL;
   tree element_type;
   struct c_arg_info *arg_info = 0;
+  tree expr_dummy;
+  bool expr_const_operands_dummy;
+
+  if (expr == NULL)
+    expr = &expr_dummy;
+  if (expr_const_operands == NULL)
+    expr_const_operands = &expr_const_operands_dummy;
+
+  *expr = declspecs->expr;
+  *expr_const_operands = declspecs->expr_const_operands;
 
   if (decl_context == FUNCDEF)
-    funcdef_flag = 1, decl_context = NORMAL;
+    funcdef_flag = true, decl_context = NORMAL;
 
   /* Look inside a declarator for the name being declared
-     and get it as a string, for an error message.  */
+     and get it as an IDENTIFIER_NODE, for an error message.  */
   {
     const struct c_declarator *decl = declarator;
-    name = 0;
 
     while (decl)
       switch (decl->kind)
@@ -3875,16 +4216,21 @@ grokdeclarator (const struct c_declarator *declarator,
 
        case cdk_id:
          if (decl->u.id)
-           name = IDENTIFIER_POINTER (decl->u.id);
+           name = decl->u.id;
          decl = 0;
          break;
 
        default:
          gcc_unreachable ();
        }
-    orig_name = name;
     if (name == 0)
-      name = "type name";
+      {
+       gcc_assert (decl_context == PARM
+                   || decl_context == TYPENAME
+                   || (decl_context == FIELD
+                       && declarator->kind == cdk_id));
+       gcc_assert (!initialized);
+      }
   }
 
   /* A function definition's declarator must have the form of
@@ -3900,9 +4246,19 @@ grokdeclarator (const struct c_declarator *declarator,
     decl_context = PARM;
 
   if (declspecs->deprecated_p && deprecated_state != DEPRECATED_SUPPRESS)
-    warn_deprecated_use (declspecs->type);
+    warn_deprecated_use (declspecs->type, declspecs->decl_attr);
+
+  if ((decl_context == NORMAL || decl_context == FIELD)
+      && current_scope == file_scope
+      && variably_modified_type_p (type, NULL_TREE))
+    {
+      if (name)
+       error ("variably modified %qE at file scope", name);
+      else
+       error ("variably modified field at file scope");
+      type = integer_type_node;
+    }
 
-  typedef_type = type;
   size_varies = C_TYPE_VARIABLE_SIZE (type);
 
   /* Diagnose defaulting to "int".  */
@@ -3915,8 +4271,16 @@ grokdeclarator (const struct c_declarator *declarator,
       if ((warn_implicit_int || warn_return_type || flag_isoc99)
          && funcdef_flag)
        warn_about_return_type = 1;
-      else if (warn_implicit_int || flag_isoc99)
-       pedwarn_c99 ("type defaults to %<int%> in declaration of %qs", name);
+      else
+       {
+         if (name)
+           pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int, 
+                        "type defaults to %<int%> in declaration of %qE",
+                        name);
+         else
+           pedwarn_c99 (input_location, flag_isoc99 ? 0 : OPT_Wimplicit_int, 
+                        "type defaults to %<int%> in type name");
+       }
     }
 
   /* Adjust the type if a bit-field is being declared,
@@ -3924,7 +4288,7 @@ grokdeclarator (const struct c_declarator *declarator,
      "signed".  */
   if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p
       && TREE_CODE (type) == INTEGER_TYPE)
-    type = c_common_unsigned_type (type);
+    type = unsigned_type_for (type);
 
   /* Figure out the type qualifiers for the declaration.  There are
      two ways a declaration can become qualified.  One is something
@@ -3933,7 +4297,7 @@ grokdeclarator (const struct c_declarator *declarator,
      declaration contains the `const'.  A third possibility is that
      there is a type qualifier on the element type of a typedefed
      array type, in which case we should extract that qualifier so
-     that c_apply_type_quals_to_decls receives the full list of
+     that c_apply_type_quals_to_decl receives the full list of
      qualifiers to work with (C90 is not entirely clear about whether
      duplicate qualifiers should be diagnosed in this case, but it
      seems most appropriate to do so).  */
@@ -3944,11 +4308,11 @@ grokdeclarator (const struct c_declarator *declarator,
   if (pedantic && !flag_isoc99)
     {
       if (constp > 1)
-       pedwarn ("duplicate %<const%>");
+       pedwarn (input_location, OPT_pedantic, "duplicate %<const%>");
       if (restrictp > 1)
-       pedwarn ("duplicate %<restrict%>");
+       pedwarn (input_location, OPT_pedantic, "duplicate %<restrict%>");
       if (volatilep > 1)
-       pedwarn ("duplicate %<volatile%>");
+       pedwarn (input_location, OPT_pedantic, "duplicate %<volatile%>");
     }
   if (!flag_gen_aux_info && (TYPE_QUALS (element_type)))
     type = TYPE_MAIN_VARIANT (type);
@@ -3965,9 +4329,10 @@ grokdeclarator (const struct c_declarator *declarator,
          || storage_class == csc_register
          || storage_class == csc_typedef))
     {
-      if (storage_class == csc_auto
-         && (pedantic || current_scope == file_scope))
-       pedwarn ("function definition declared %<auto%>");
+      if (storage_class == csc_auto)
+       pedwarn (input_location, 
+                (current_scope == file_scope) ? 0 : OPT_pedantic, 
+                "function definition declared %<auto%>");
       if (storage_class == csc_register)
        error ("function definition declared %<register%>");
       if (storage_class == csc_typedef)
@@ -3989,11 +4354,17 @@ grokdeclarator (const struct c_declarator *declarator,
          switch (decl_context)
            {
            case FIELD:
-             error ("storage class specified for structure field %qs",
-                    name);
+             if (name)
+               error ("storage class specified for structure field %qE",
+                      name);
+             else
+               error ("storage class specified for structure field");
              break;
            case PARM:
-             error ("storage class specified for parameter %qs", name);
+             if (name)
+               error ("storage class specified for parameter %qE", name);
+             else
+               error ("storage class specified for unnamed parameter");
              break;
            default:
              error ("storage class specified for typename");
@@ -4008,25 +4379,31 @@ grokdeclarator (const struct c_declarator *declarator,
           && !funcdef_flag)
     {
       /* 'extern' with initialization is invalid if not at file scope.  */
-      if (current_scope == file_scope)
-       warning (0, "%qs initialized and declared %<extern%>", name);
+       if (current_scope == file_scope)
+         {
+           /* It is fine to have 'extern const' when compiling at C
+              and C++ intersection.  */
+           if (!(warn_cxx_compat && constp))
+             warning (0, "%qE initialized and declared %<extern%>", name);
+         }
       else
-       error ("%qs has both %<extern%> and initializer", name);
+       error ("%qE has both %<extern%> and initializer", name);
     }
   else if (current_scope == file_scope)
     {
       if (storage_class == csc_auto)
-       error ("file-scope declaration of %qs specifies %<auto%>", name);
+       error ("file-scope declaration of %qE specifies %<auto%>", name);
       if (pedantic && storage_class == csc_register)
-       pedwarn ("file-scope declaration of %qs specifies %<register%>", name);
+       pedwarn (input_location, OPT_pedantic,
+                "file-scope declaration of %qE specifies %<register%>", name);
     }
   else
     {
       if (storage_class == csc_extern && funcdef_flag)
-       error ("nested function %qs declared %<extern%>", name);
+       error ("nested function %qE declared %<extern%>", name);
       else if (threadp && storage_class == csc_none)
        {
-         error ("function-scope %qs implicitly auto and declared "
+         error ("function-scope %qE implicitly auto and declared "
                 "%<__thread%>",
                 name);
          threadp = false;
@@ -4112,29 +4489,37 @@ grokdeclarator (const struct c_declarator *declarator,
            array_ptr_quals = declarator->u.array.quals;
            array_ptr_attrs = declarator->u.array.attrs;
            array_parm_static = declarator->u.array.static_p;
-           
+           array_parm_vla_unspec_p = declarator->u.array.vla_unspec_p;
+
            declarator = declarator->declarator;
 
            /* Check for some types that there cannot be arrays of.  */
-           
+
            if (VOID_TYPE_P (type))
              {
-               error ("declaration of %qs as array of voids", name);
+               if (name)
+                 error ("declaration of %qE as array of voids", name);
+               else
+                 error ("declaration of type name as array of voids");
                type = error_mark_node;
              }
-           
+
            if (TREE_CODE (type) == FUNCTION_TYPE)
              {
-               error ("declaration of %qs as array of functions", name);
+               if (name)
+                 error ("declaration of %qE as array of functions", name);
+               else
+                 error ("declaration of type name as array of functions");
                type = error_mark_node;
              }
-           
+
            if (pedantic && !in_system_header && flexible_array_type_p (type))
-             pedwarn ("invalid use of structure with flexible array member");
-           
+             pedwarn (input_location, OPT_pedantic,
+                      "invalid use of structure with flexible array member");
+
            if (size == error_mark_node)
              type = error_mark_node;
-           
+
            if (type == error_mark_node)
              continue;
 
@@ -4144,53 +4529,87 @@ grokdeclarator (const struct c_declarator *declarator,
 
            if (size)
              {
+               bool size_maybe_const = true;
+               bool size_int_const = (TREE_CODE (size) == INTEGER_CST
+                                      && !TREE_OVERFLOW (size));
+               bool this_size_varies = false;
+
                /* Strip NON_LVALUE_EXPRs since we aren't using as an
                   lvalue.  */
                STRIP_TYPE_NOPS (size);
-               
+
                if (!INTEGRAL_TYPE_P (TREE_TYPE (size)))
                  {
-                   error ("size of array %qs has non-integer type", name);
+                   if (name)
+                     error ("size of array %qE has non-integer type", name);
+                   else
+                     error ("size of unnamed array has non-integer type");
                    size = integer_one_node;
                  }
-               
-               if (pedantic && integer_zerop (size))
-                 pedwarn ("ISO C forbids zero-size array %qs", name);
-               
-               if (TREE_CODE (size) == INTEGER_CST)
+
+               size = c_fully_fold (size, false, &size_maybe_const);
+
+               if (pedantic && size_maybe_const && integer_zerop (size))
+                 {
+                   if (name)
+                     pedwarn (input_location, OPT_pedantic,
+                              "ISO C forbids zero-size array %qE", name);
+                   else
+                     pedwarn (input_location, OPT_pedantic,
+                              "ISO C forbids zero-size array");
+                 }
+
+               if (TREE_CODE (size) == INTEGER_CST && size_maybe_const)
                  {
                    constant_expression_warning (size);
                    if (tree_int_cst_sgn (size) < 0)
                      {
-                       error ("size of array %qs is negative", name);
+                       if (name)
+                         error ("size of array %qE is negative", name);
+                       else
+                         error ("size of unnamed array is negative");
                        size = integer_one_node;
                      }
+                   /* Handle a size folded to an integer constant but
+                      not an integer constant expression.  */
+                   if (!size_int_const)
+                     {
+                       /* If this is a file scope declaration of an
+                          ordinary identifier, this is invalid code;
+                          diagnosing it here and not subsequently
+                          treating the type as variable-length avoids
+                          more confusing diagnostics later.  */
+                       if ((decl_context == NORMAL || decl_context == FIELD)
+                           && current_scope == file_scope)
+                         pedwarn (input_location, 0,
+                                  "variably modified %qE at file scope",
+                                  name);
+                       else
+                         this_size_varies = size_varies = 1;
+                       warn_variable_length_array (name, size);
+                     }
+                 }
+               else if ((decl_context == NORMAL || decl_context == FIELD)
+                        && current_scope == file_scope)
+                 {
+                   error ("variably modified %qE at file scope", name);
+                   size = integer_one_node;
                  }
                else
                  {
                    /* Make sure the array size remains visibly
                       nonconstant even if it is (eg) a const variable
                       with known value.  */
-                   size_varies = 1;
-                   
-                   if (!flag_isoc99 && pedantic)
-                     {
-                       if (TREE_CONSTANT (size))
-                         pedwarn ("ISO C90 forbids array %qs whose size "
-                                  "can%'t be evaluated",
-                                  name);
-                       else
-                         pedwarn ("ISO C90 forbids variable-size array %qs",
-                                  name);
-                     }
+                   this_size_varies = size_varies = 1;
+                   warn_variable_length_array (name, size);
                  }
 
-               if (integer_zerop (size))
+               if (integer_zerop (size) && !this_size_varies)
                  {
-                   /*  A zero-length array cannot be represented with
-                       an unsigned index type, which is what we'll
-                       get with build_index_type.  Create an
-                       open-ended range instead.  */
+                   /* A zero-length array cannot be represented with
+                      an unsigned index type, which is what we'll
+                      get with build_index_type.  Create an
+                      open-ended range instead.  */
                    itype = build_range_type (sizetype, size, NULL_TREE);
                  }
                else
@@ -4199,7 +4618,10 @@ grokdeclarator (const struct c_declarator *declarator,
                       MINUS_EXPR, which allows the -1 to get folded
                       with the +1 that happens when building TYPE_SIZE.  */
                    if (size_varies)
-                     size = variable_size (size);
+                     size = c_variable_size (size);
+                   if (this_size_varies && TREE_CODE (size) == INTEGER_CST)
+                     size = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+                                    integer_zero_node, size);
 
                    /* Compute the maximum valid index, that is, size
                       - 1.  Do the calculation in index_type, so that
@@ -4210,7 +4632,7 @@ grokdeclarator (const struct c_declarator *declarator,
                                         convert (index_type,
                                                  size_one_node));
 
-                   /* If that overflowed, the array is too big.  ??? 
+                   /* 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
@@ -4220,43 +4642,123 @@ grokdeclarator (const struct c_declarator *declarator,
                    if (TREE_CODE (itype) == INTEGER_CST
                        && TREE_OVERFLOW (itype))
                      {
-                       error ("size of array %qs is too large", name);
+                       if (name)
+                         error ("size of array %qE is too large", name);
+                       else
+                         error ("size of unnamed array is too large");
                        type = error_mark_node;
                        continue;
                      }
-                   
+
                    itype = build_index_type (itype);
                  }
+               if (this_size_varies)
+                 {
+                   if (*expr)
+                     *expr = build2 (COMPOUND_EXPR, TREE_TYPE (size),
+                                     *expr, size);
+                   else
+                     *expr = size;
+                   *expr_const_operands &= size_maybe_const;
+                 }
              }
            else if (decl_context == FIELD)
              {
-               if (pedantic && !flag_isoc99 && !in_system_header)
-                 pedwarn ("ISO C90 does not support flexible array members");
+               bool flexible_array_member = false;
+               if (array_parm_vla_unspec_p)
+                 /* Field names can in fact have function prototype
+                    scope so [*] is disallowed here through making
+                    the field variably modified, not through being
+                    something other than a declaration with function
+                    prototype scope.  */
+                 size_varies = 1;
+               else
+                 {
+                   const struct c_declarator *t = declarator;
+                   while (t->kind == cdk_attrs)
+                     t = t->declarator;
+                   flexible_array_member = (t->kind == cdk_id);
+                 }
+               if (flexible_array_member
+                   && pedantic && !flag_isoc99 && !in_system_header)
+                 pedwarn (input_location, OPT_pedantic,
+                          "ISO C90 does not support flexible array members");
 
                /* ISO C99 Flexible array members are effectively
                   identical to GCC's zero-length array extension.  */
-               itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+               if (flexible_array_member || array_parm_vla_unspec_p)
+                 itype = build_range_type (sizetype, size_zero_node,
+                                           NULL_TREE);
+             }
+           else if (decl_context == PARM)
+             {
+               if (array_parm_vla_unspec_p)
+                 {
+                   itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
+                   size_varies = 1;
+                 }
+             }
+           else if (decl_context == TYPENAME)
+             {
+               if (array_parm_vla_unspec_p)
+                 {
+                   /* C99 6.7.5.2p4 */
+                   warning (0, "%<[*]%> not in a declaration");
+                   /* We use this to avoid messing up with incomplete
+                      array types of the same type, that would
+                      otherwise be modified below.  */
+                   itype = build_range_type (sizetype, size_zero_node,
+                                             NULL_TREE);
+                   size_varies = 1;
+                 }
              }
 
             /* Complain about arrays of incomplete types.  */
            if (!COMPLETE_TYPE_P (type))
              {
                error ("array type has incomplete element type");
-               type = error_mark_node;
+               type = error_mark_node;
              }
            else
+           /* When itype is NULL, a shared incomplete array type is
+              returned for all array of a given type.  Elsewhere we
+              make sure we don't complete that type before copying
+              it, but here we want to make sure we don't ever
+              modify the shared type, so we gcc_assert (itype)
+              below.  */
              type = build_array_type (type, itype);
 
-           if (size_varies)
-             C_TYPE_VARIABLE_SIZE (type) = 1;
-
-           /* The GCC extension for zero-length arrays differs from
-              ISO flexible array members in that sizeof yields
-              zero.  */
-           if (size && integer_zerop (size))
+           if (type != error_mark_node)
              {
-               TYPE_SIZE (type) = bitsize_zero_node;
-               TYPE_SIZE_UNIT (type) = size_zero_node;
+               if (size_varies)
+                 {
+                   /* It is ok to modify type here even if itype is
+                      NULL: if size_varies, we're in a
+                      multi-dimensional array and the inner type has
+                      variable size, so the enclosing shared array type
+                      must too.  */
+                   if (size && TREE_CODE (size) == INTEGER_CST)
+                     type
+                       = build_distinct_type_copy (TYPE_MAIN_VARIANT (type));
+                   C_TYPE_VARIABLE_SIZE (type) = 1;
+                 }
+
+               /* The GCC extension for zero-length arrays differs from
+                  ISO flexible array members in that sizeof yields
+                  zero.  */
+               if (size && integer_zerop (size))
+                 {
+                   gcc_assert (itype);
+                   TYPE_SIZE (type) = bitsize_zero_node;
+                   TYPE_SIZE_UNIT (type) = size_zero_node;
+                 }
+               if (array_parm_vla_unspec_p)
+                 {
+                   gcc_assert (itype);
+                   /* The type is complete.  C99 6.7.5.2p4  */
+                   TYPE_SIZE (type) = bitsize_zero_node;
+                   TYPE_SIZE_UNIT (type) = size_zero_node;
+                 }
              }
 
            if (decl_context != PARM
@@ -4290,18 +4792,26 @@ grokdeclarator (const struct c_declarator *declarator,
               type for the function to return.  */
            if (type == error_mark_node)
              continue;
-           
+
            size_varies = 0;
 
            /* Warn about some types functions can't return.  */
            if (TREE_CODE (type) == FUNCTION_TYPE)
              {
-               error ("%qs declared as function returning a function", name);
+               if (name)
+                 error ("%qE declared as function returning a function",
+                        name);
+               else
+                 error ("type name declared as function "
+                        "returning a function");
                type = integer_type_node;
              }
            if (TREE_CODE (type) == ARRAY_TYPE)
              {
-               error ("%qs declared as function returning an array", name);
+               if (name)
+                 error ("%qE declared as function returning an array", name);
+               else
+                 error ("type name declared as function returning an array");
                type = integer_type_node;
              }
 
@@ -4309,36 +4819,39 @@ grokdeclarator (const struct c_declarator *declarator,
               inner layer of declarator.  */
            arg_info = declarator->u.arg_info;
            arg_types = grokparms (arg_info, really_funcdef);
+           if (really_funcdef)
+             put_pending_sizes (arg_info->pending_sizes);
 
            /* Type qualifiers before the return type of the function
               qualify the return type, not the function type.  */
            if (type_quals)
              {
-               /* Type qualifiers on a function return type are
+               /* Type qualifiers on a function return type are
                   normally permitted by the standard but have no
                   effect, so give a warning at -Wreturn-type.
                   Qualifiers on a void return type are banned on
                   function definitions in ISO C; GCC used to used
                   them for noreturn functions.  */
                if (VOID_TYPE_P (type) && really_funcdef)
-                 pedwarn ("function definition has qualified void return type");
+                 pedwarn (input_location, 0,
+                          "function definition has qualified void return type");
                else
-                 warning (OPT_Wreturn_type,
+                 warning (OPT_Wignored_qualifiers,
                           "type qualifiers ignored on function return type");
-               
+
                type = c_build_qualified_type (type, type_quals);
              }
            type_quals = TYPE_UNQUALIFIED;
-           
+
            type = build_function_type (type, arg_types);
            declarator = declarator->declarator;
-           
+
            /* Set the TYPE_CONTEXTs for each tagged type which is local to
               the formal parameter list of this FUNCTION_TYPE to point to
               the FUNCTION_TYPE node itself.  */
            {
              tree link;
-             
+
              for (link = arg_info->tags;
                   link;
                   link = TREE_CHAIN (link))
@@ -4353,13 +4866,48 @@ grokdeclarator (const struct c_declarator *declarator,
 
            if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
                && type_quals)
-             pedwarn ("ISO C forbids qualified function types");
+             pedwarn (input_location, OPT_pedantic,
+                      "ISO C forbids qualified function types");
            if (type_quals)
              type = c_build_qualified_type (type, type_quals);
            size_varies = 0;
 
+           /* When the pointed-to type involves components of variable size,
+              care must be taken to ensure that the size evaluation code is
+              emitted early enough to dominate all the possible later uses
+              and late enough for the variables on which it depends to have
+              been assigned.
+
+              This is expected to happen automatically when the pointed-to
+              type has a name/declaration of it's own, but special attention
+              is required if the type is anonymous.
+
+              We handle the NORMAL and FIELD contexts here by attaching an
+              artificial TYPE_DECL to such pointed-to type.  This forces the
+              sizes evaluation at a safe point and ensures it is not deferred
+              until e.g. within a deeper conditional context.
+
+              We expect nothing to be needed here for PARM or TYPENAME.
+              Pushing a TYPE_DECL at this point for TYPENAME would actually
+              be incorrect, as we might be in the middle of an expression
+              with side effects on the pointed-to type size "arguments" prior
+              to the pointer declaration point and the fake TYPE_DECL in the
+              enclosing context would force the size evaluation prior to the
+              side effects.  */
+
+           if (!TYPE_NAME (type)
+               && (decl_context == NORMAL || decl_context == FIELD)
+               && variably_modified_type_p (type, NULL_TREE))
+             {
+               tree decl = build_decl (TYPE_DECL, NULL_TREE, type);
+               DECL_ARTIFICIAL (decl) = 1;
+               pushdecl (decl);
+               finish_decl (decl, NULL_TREE, NULL_TREE, NULL_TREE);
+               TYPE_NAME (type) = decl;
+             }
+
            type = build_pointer_type (type);
-           
+
            /* Process type qualifiers (such as const or volatile)
               that were given inside the `*'.  */
            type_quals = declarator->u.pointer_quals;
@@ -4371,22 +4919,26 @@ grokdeclarator (const struct c_declarator *declarator,
          gcc_unreachable ();
        }
     }
+  *decl_attrs = chainon (returned_attrs, *decl_attrs);
 
   /* Now TYPE has the actual type, apart from any qualifiers in
      TYPE_QUALS.  */
 
   /* Check the type and width of a bit-field.  */
   if (bitfield)
-    check_bitfield_type_and_width (&type, width, orig_name);
+    check_bitfield_type_and_width (&type, width, name);
 
   /* Did array size calculations overflow?  */
 
   if (TREE_CODE (type) == ARRAY_TYPE
       && COMPLETE_TYPE_P (type)
-      && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
-      && TREE_OVERFLOW (TYPE_SIZE (type)))
+      && TREE_CODE (TYPE_SIZE_UNIT (type)) == INTEGER_CST
+      && TREE_OVERFLOW (TYPE_SIZE_UNIT (type)))
     {
-      error ("size of array %qs is too large", name);
+      if (name)
+       error ("size of array %qE is too large", name);
+      else
+       error ("size of unnamed array is too large");
       /* If we proceed with the array type as it is, we'll eventually
         crash in tree_low_cst().  */
       type = error_mark_node;
@@ -4399,33 +4951,19 @@ grokdeclarator (const struct c_declarator *declarator,
       tree decl;
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
          && type_quals)
-       pedwarn ("ISO C forbids qualified function types");
+       pedwarn (input_location, OPT_pedantic,
+                "ISO C forbids qualified function types");
       if (type_quals)
        type = c_build_qualified_type (type, type_quals);
       decl = build_decl (TYPE_DECL, declarator->u.id, type);
+      DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
       if (declspecs->explicit_signed_p)
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
-      decl_attributes (&decl, returned_attrs, 0);
       if (declspecs->inline_p)
-       pedwarn ("typedef %q+D declared %<inline%>", decl);
+       pedwarn (input_location, 0,"typedef %q+D declared %<inline%>", decl);
       return decl;
     }
 
-  /* Detect the case of an array type of unspecified size
-     which came, as such, direct from a typedef name.
-     We must copy the type, so that each identifier gets
-     a distinct type, so that each identifier's size can be
-     controlled separately by its own initializer.  */
-
-  if (type != 0 && typedef_type != 0
-      && TREE_CODE (type) == ARRAY_TYPE && TYPE_DOMAIN (type) == 0
-      && TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (typedef_type))
-    {
-      type = build_array_type (TREE_TYPE (type), 0);
-      if (size_varies)
-       C_TYPE_VARIABLE_SIZE (type) = 1;
-    }
-
   /* If this is a type name (such as, in a cast or sizeof),
      compute the type and return it now.  */
 
@@ -4437,13 +4975,21 @@ grokdeclarator (const struct c_declarator *declarator,
                  && !declspecs->inline_p);
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
          && type_quals)
-       pedwarn ("ISO C forbids const or volatile function types");
+       pedwarn (input_location, OPT_pedantic,
+                "ISO C forbids const or volatile function types");
       if (type_quals)
        type = c_build_qualified_type (type, type_quals);
-      decl_attributes (&type, returned_attrs, 0);
       return type;
     }
 
+  if (pedantic && decl_context == FIELD
+      && variably_modified_type_p (type, NULL_TREE))
+    {
+      /* C99 6.7.2.1p8 */
+      pedwarn (input_location, OPT_pedantic, 
+              "a member of a structure or union cannot have a variably modified type");
+    }
+
   /* Aside from typedefs and type names (handle above),
      `void' at top level (not within pointer)
      is allowed only in public variables.
@@ -4457,7 +5003,7 @@ grokdeclarator (const struct c_declarator *declarator,
                    && !(storage_class == csc_static
                         || storage_class == csc_register)))))
     {
-      error ("variable or field %qs declared void", name);
+      error ("variable or field %qE declared void", name);
       type = integer_type_node;
     }
 
@@ -4469,7 +5015,6 @@ grokdeclarator (const struct c_declarator *declarator,
 
     if (decl_context == PARM)
       {
-       tree type_as_written;
        tree promoted_type;
 
        /* A parameter declared as an array of T is really a pointer to T.
@@ -4483,6 +5028,8 @@ grokdeclarator (const struct c_declarator *declarator,
              type = c_build_qualified_type (type, type_quals);
            type = build_pointer_type (type);
            type_quals = array_ptr_quals;
+           if (type_quals)
+             type = c_build_qualified_type (type, type_quals);
 
            /* We don't yet implement attributes in this context.  */
            if (array_ptr_attrs != NULL_TREE)
@@ -4493,8 +5040,9 @@ grokdeclarator (const struct c_declarator *declarator,
          }
        else if (TREE_CODE (type) == FUNCTION_TYPE)
          {
-           if (pedantic && type_quals)
-             pedwarn ("ISO C forbids qualified function types");
+           if (type_quals)
+             pedwarn (input_location, OPT_pedantic,
+                      "ISO C forbids qualified function types");
            if (type_quals)
              type = c_build_qualified_type (type, type_quals);
            type = build_pointer_type (type);
@@ -4503,9 +5051,8 @@ grokdeclarator (const struct c_declarator *declarator,
        else if (type_quals)
          type = c_build_qualified_type (type, type_quals);
 
-       type_as_written = type;
-
        decl = build_decl (PARM_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        if (size_varies)
          C_DECL_VARIABLE_SIZE (decl) = 1;
 
@@ -4521,7 +5068,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
        DECL_ARG_TYPE (decl) = promoted_type;
        if (declspecs->inline_p)
-         pedwarn ("parameter %q+D declared %<inline%>", decl);
+         pedwarn (input_location, 0, "parameter %q+D declared %<inline%>", decl);
       }
     else if (decl_context == FIELD)
       {
@@ -4534,18 +5081,24 @@ grokdeclarator (const struct c_declarator *declarator,
 
        if (TREE_CODE (type) == FUNCTION_TYPE)
          {
-           error ("field %qs declared as a function", name);
+           error ("field %qE declared as a function", name);
            type = build_pointer_type (type);
          }
        else if (TREE_CODE (type) != ERROR_MARK
-                && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
+                && !COMPLETE_OR_UNBOUND_ARRAY_TYPE_P (type))
          {
-           error ("field %qs has incomplete type", name);
+           if (name)
+             error ("field %qE has incomplete type", name);
+           else
+             error ("unnamed field has incomplete type");
            type = error_mark_node;
          }
        type = c_build_qualified_type (type, type_quals);
        decl = build_decl (FIELD_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        DECL_NONADDRESSABLE_P (decl) = bitfield;
+       if (bitfield && !declarator->u.id)
+         TREE_NO_WARNING (decl) = 1;
 
        if (size_varies)
          C_DECL_VARIABLE_SIZE (decl) = 1;
@@ -4554,7 +5107,7 @@ grokdeclarator (const struct c_declarator *declarator,
       {
        if (storage_class == csc_register || threadp)
          {
-           error ("invalid storage class for function %qs", name);
+           error ("invalid storage class for function %qE", name);
           }
        else if (current_scope != file_scope)
          {
@@ -4563,15 +5116,13 @@ grokdeclarator (const struct c_declarator *declarator,
               6.7.1p5, and `extern' makes no difference.  However,
               GCC allows 'auto', perhaps with 'inline', to support
               nested functions.  */
-           if (storage_class == csc_auto)
-             {
-               if (pedantic)
-                 pedwarn ("invalid storage class for function %qs", name);
-             }
+           if (storage_class == csc_auto)
+               pedwarn (input_location, OPT_pedantic,
+                        "invalid storage class for function %qE", name);
            else if (storage_class == csc_static)
              {
-               error ("invalid storage class for function %qs", name);
-               if (funcdef_flag)
+               error ("invalid storage class for function %qE", name);
+               if (funcdef_flag)
                  storage_class = declspecs->storage_class = csc_none;
                else
                  return 0;
@@ -4579,12 +5130,12 @@ grokdeclarator (const struct c_declarator *declarator,
          }
 
        decl = build_decl (FUNCTION_DECL, declarator->u.id, type);
+       DECL_SOURCE_LOCATION (decl) = declarator->id_loc;
        decl = build_decl_attribute_variant (decl, decl_attr);
 
-       DECL_LANG_SPECIFIC (decl) = GGC_CNEW (struct lang_decl);
-
        if (pedantic && type_quals && !DECL_IN_SYSTEM_HEADER (decl))
-         pedwarn ("ISO C forbids qualified function types");
+         pedwarn (input_location, OPT_pedantic,
+                  "ISO C forbids qualified function types");
 
        /* GNU C interprets a volatile-qualified function type to indicate
           that the function does not return.  */
@@ -4599,8 +5150,16 @@ grokdeclarator (const struct c_declarator *declarator,
           GCC to signify a forward declaration of a nested function.  */
        if (storage_class == csc_auto && current_scope != file_scope)
          DECL_EXTERNAL (decl) = 0;
+       /* In C99, a function which is declared 'inline' with 'extern'
+          is not an external reference (which is confusing).  It
+          means that the later definition of the function must be output
+          in this file, C99 6.7.4p6.  In GNU C89, a function declared
+          'extern inline' is an external reference.  */
+       else if (declspecs->inline_p && storage_class != csc_static)
+         DECL_EXTERNAL (decl) = ((storage_class == csc_extern)
+                                 == flag_gnu89_inline);
        else
-         DECL_EXTERNAL (decl) = 1;
+         DECL_EXTERNAL (decl) = !initialized;
 
        /* Record absence of global scope for `static' or `auto'.  */
        TREE_PUBLIC (decl)
@@ -4618,29 +5177,11 @@ grokdeclarator (const struct c_declarator *declarator,
        if (flag_hosted && MAIN_NAME_P (declarator->u.id))
          {
            if (declspecs->inline_p)
-             pedwarn ("cannot inline function %<main%>");
+             pedwarn (input_location, 0, "cannot inline function %<main%>");
          }
        else if (declspecs->inline_p)
-         {
-           /* Record that the function is declared `inline'.  */
-           DECL_DECLARED_INLINE_P (decl) = 1;
-
-           /* Do not mark bare declarations as DECL_INLINE.  Doing so
-              in the presence of multiple declarations can result in
-              the abstract origin pointing between the declarations,
-              which will confuse dwarf2out.  */
-           if (initialized)
-             {
-               DECL_INLINE (decl) = 1;
-               if (storage_class == csc_extern)
-                 current_extern_inline = 1;
-             }
-         }
-       /* If -finline-functions, assume it can be inlined.  This does
-          two things: let the function be deferred until it is actually
-          needed, and let dwarf2 know that the function is inlinable.  */
-       else if (flag_inline_trees == 2 && initialized)
-         DECL_INLINE (decl) = 1;
+         /* Record that the function is declared `inline'.  */
+         DECL_DECLARED_INLINE_P (decl) = 1;
       }
     else
       {
@@ -4675,7 +5216,7 @@ grokdeclarator (const struct c_declarator *declarator,
          C_DECL_VARIABLE_SIZE (decl) = 1;
 
        if (declspecs->inline_p)
-         pedwarn ("variable %q+D declared %<inline%>", decl);
+         pedwarn (input_location, 0, "variable %q+D declared %<inline%>", decl);
 
        /* At file scope, an initialized extern declaration may follow
           a static declaration.  In that case, DECL_EXTERNAL will be
@@ -4685,11 +5226,10 @@ grokdeclarator (const struct c_declarator *declarator,
        /* At file scope, the presence of a `static' or `register' storage
           class specifier, or the absence of all storage class specifiers
           makes this declaration a definition (perhaps tentative).  Also,
-          the absence of both `static' and `register' makes it public.  */
+          the absence of `static' makes it public.  */
        if (current_scope == file_scope)
          {
-           TREE_PUBLIC (decl) = !(storage_class == csc_static
-                                  || storage_class == csc_register);
+           TREE_PUBLIC (decl) = storage_class != csc_static;
            TREE_STATIC (decl) = !extern_ref;
          }
        /* Not at file scope, only `static' makes a static definition.  */
@@ -4700,14 +5240,20 @@ grokdeclarator (const struct c_declarator *declarator,
          }
 
        if (threadp)
-         {
-           if (targetm.have_tls)
-             DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
-           else
-             /* A mere warning is sure to result in improper semantics
-                at runtime.  Don't bother to allow this to compile.  */
-             error ("thread-local storage not supported for this target");
-         }
+         DECL_TLS_MODEL (decl) = decl_default_tls_model (decl);
+      }
+
+    if ((storage_class == csc_extern
+        || (storage_class == csc_none
+            && TREE_CODE (type) == FUNCTION_TYPE
+            && !funcdef_flag))
+       && variably_modified_type_p (type, NULL_TREE))
+      {
+       /* C99 6.7.5.2p2 */
+       if (TREE_CODE (type) == FUNCTION_TYPE)
+         error ("non-nested function with variably modified type");
+       else
+         error ("object with variably modified type must have no linkage");
       }
 
     /* Record `register' declaration for warnings on &
@@ -4744,14 +5290,12 @@ grokdeclarator (const struct c_declarator *declarator,
      name of a variable.  Thus, if it's known before this, die horribly.  */
     gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
 
-    decl_attributes (&decl, returned_attrs, 0);
-
     return decl;
   }
 }
 \f
 /* Decode the parameter-list info for a function type or function definition.
-   The argument is the value returned by `get_parm_info' (or made in parse.y
+   The argument is the value returned by `get_parm_info' (or made in c-parse.c
    if there is an identifier list instead of a parameter decl list).
    These two functions are separate because when a function returns
    or receives functions then each is called multiple times but the order
@@ -4769,6 +5313,13 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
 {
   tree arg_types = arg_info->types;
 
+  if (funcdef_flag && arg_info->had_vla_unspec)
+    {
+      /* A function definition isn't function prototype scope C99 6.2.1p4.  */
+      /* C99 6.7.5.2p4 */
+      error ("%<[*]%> not allowed in other than function prototype scope");
+    }
+
   if (arg_types == 0 && !funcdef_flag && !in_system_header)
     warning (OPT_Wstrict_prototypes,
             "function declaration isn%'t a prototype");
@@ -4779,7 +5330,7 @@ grokparms (struct c_arg_info *arg_info, bool funcdef_flag)
   else if (arg_types && TREE_CODE (TREE_VALUE (arg_types)) == IDENTIFIER_NODE)
     {
       if (!funcdef_flag)
-       pedwarn ("parameter names (without types) in function declaration");
+       pedwarn (input_location, 0, "parameter names (without types) in function declaration");
 
       arg_info->parms = arg_info->types;
       arg_info->types = 0;
@@ -4865,6 +5416,8 @@ get_parm_info (bool ellipsis)
   arg_info->tags = 0;
   arg_info->types = 0;
   arg_info->others = 0;
+  arg_info->pending_sizes = 0;
+  arg_info->had_vla_unspec = current_scope->had_vla_unspec;
 
   /* The bindings in this scope must not get put into a block.
      We will take care of deleting the binding nodes.  */
@@ -4879,7 +5432,7 @@ get_parm_info (bool ellipsis)
      (by 'const' or 'volatile'), or has a storage class specifier
      ('register'), then the behavior is undefined; issue an error.
      Typedefs for 'void' are OK (see DR#157).  */
-  if (b->prev == 0                         /* one binding */
+  if (b->prev == 0                         /* one binding */
       && TREE_CODE (b->decl) == PARM_DECL   /* which is a parameter */
       && !DECL_NAME (b->decl)               /* anonymous */
       && VOID_TYPE_P (TREE_TYPE (b->decl))) /* of void type */
@@ -5019,6 +5572,7 @@ get_parm_info (bool ellipsis)
   arg_info->tags = tags;
   arg_info->types = types;
   arg_info->others = others;
+  arg_info->pending_sizes = get_pending_sizes ();
   return arg_info;
 }
 \f
@@ -5027,13 +5581,19 @@ get_parm_info (bool ellipsis)
    Return a c_typespec structure for the type specifier.  */
 
 struct c_typespec
-parser_xref_tag (enum tree_code code, tree name)
+parser_xref_tag (enum tree_code code, tree name, location_t loc)
 {
   struct c_typespec ret;
+  tree ref;
+  location_t refloc;
+
+  ret.expr = NULL_TREE;
+  ret.expr_const_operands = true;
+
   /* If a cross reference is requested, look up the type
      already defined for this tag and return it.  */
 
-  tree ref = lookup_tag (code, name, 0);
+  ref = lookup_tag (code, name, 0, &refloc);
   /* If this is the right type of tag, return what we found.
      (This reference will be shadowed by shadow_tag later if appropriate.)
      If this is the wrong type of tag, do not return it.  If it was the
@@ -5048,6 +5608,35 @@ parser_xref_tag (enum tree_code code, tree name)
   ret.kind = (ref ? ctsk_tagref : ctsk_tagfirstref);
   if (ref && TREE_CODE (ref) == code)
     {
+      if (C_TYPE_DEFINED_IN_STRUCT (ref)
+         && loc != UNKNOWN_LOCATION
+         && warn_cxx_compat)
+       {
+         switch (code)
+           {
+           case ENUMERAL_TYPE:
+             warning_at (loc, OPT_Wc___compat,
+                         ("enum type defined in struct or union "
+                          "is not visible in C++"));
+             inform (refloc, "enum type defined here");
+             break;
+           case RECORD_TYPE:
+             warning_at (loc, OPT_Wc___compat,
+                         ("struct defined in struct or union "
+                          "is not visible in C++"));
+             inform (refloc, "struct defined here");
+             break;
+           case UNION_TYPE:
+             warning_at (loc, OPT_Wc___compat,
+                         ("union defined in struct or union "
+                          "is not visible in C++"));
+             inform (refloc, "union defined here");
+             break;
+           default:
+             gcc_unreachable();
+           }
+       }
+
       ret.spec = ref;
       return ret;
     }
@@ -5062,7 +5651,7 @@ parser_xref_tag (enum tree_code code, tree name)
     {
       /* Give the type a default layout like unsigned int
         to avoid crashing if it does not get defined.  */
-      TYPE_MODE (ref) = TYPE_MODE (unsigned_type_node);
+      SET_TYPE_MODE (ref, TYPE_MODE (unsigned_type_node));
       TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node);
       TYPE_USER_ALIGN (ref) = 0;
       TYPE_UNSIGNED (ref) = 1;
@@ -5071,7 +5660,7 @@ parser_xref_tag (enum tree_code code, tree name)
       TYPE_MAX_VALUE (ref) = TYPE_MAX_VALUE (unsigned_type_node);
     }
 
-  pushtag (name, ref);
+  pushtag (name, ref, loc);
 
   ret.spec = ref;
   return ret;
@@ -5084,64 +5673,103 @@ parser_xref_tag (enum tree_code code, tree name)
 tree
 xref_tag (enum tree_code code, tree name)
 {
-  return parser_xref_tag (code, name).spec;
+  return parser_xref_tag (code, name, UNKNOWN_LOCATION).spec;
 }
 \f
 /* Make sure that the tag NAME is defined *in the current scope*
    at least as a forward reference.
-   CODE says which kind of tag NAME ought to be.  */
+   CODE says which kind of tag NAME ought to be.
+
+   This stores the current value of the file static IN_STRUCT in
+   *ENCLOSING_IN_STRUCT, and sets IN_STRUCT to true.  Similarly, this
+   sets STRUCT_TYPES in *ENCLOSING_STRUCT_TYPES, and sets STRUCT_TYPES
+   to an empty vector.  The old values are restored in
+   finish_struct.  */
 
 tree
-start_struct (enum tree_code code, tree name)
+start_struct (enum tree_code code, tree name, bool *enclosing_in_struct,
+             VEC(tree,heap) **enclosing_struct_types, location_t loc)
 {
   /* If there is already a tag defined at this scope
      (as a forward reference), just return it.  */
 
-  tree ref = 0;
+  tree ref = NULL_TREE;
+  location_t refloc = UNKNOWN_LOCATION;
 
-  if (name != 0)
-    ref = lookup_tag (code, name, 1);
+  if (name != NULL_TREE)
+    ref = lookup_tag (code, name, 1, &refloc);
   if (ref && TREE_CODE (ref) == code)
     {
       if (TYPE_SIZE (ref))
-        {
+       {
          if (code == UNION_TYPE)
-           error ("redefinition of %<union %E%>", name);
-          else
-           error ("redefinition of %<struct %E%>", name);
+           error_at (loc, "redefinition of %<union %E%>", name);
+         else
+           error_at (loc, "redefinition of %<struct %E%>", name);
+         if (refloc != UNKNOWN_LOCATION)
+           inform (refloc, "originally defined here");
+         /* Don't create structures using a name already in use.  */
+         ref = NULL_TREE;
        }
       else if (C_TYPE_BEING_DEFINED (ref))
        {
          if (code == UNION_TYPE)
-           error ("nested redefinition of %<union %E%>", name);
-          else
-           error ("nested redefinition of %<struct %E%>", name);
+           error_at (loc, "nested redefinition of %<union %E%>", name);
+         else
+           error_at (loc, "nested redefinition of %<struct %E%>", name);
+         /* Don't bother to report "originally defined here" for a
+            nested redefinition; the original definition should be
+            obvious.  */
+         /* Don't create structures that contain themselves.  */
+         ref = NULL_TREE;
        }
     }
-  else
-    {
-      /* Otherwise create a forward-reference just so the tag is in scope.  */
 
+  /* Otherwise create a forward-reference just so the tag is in scope.  */
+
+  if (ref == NULL_TREE || TREE_CODE (ref) != code)
+    {
       ref = make_node (code);
-      pushtag (name, ref);
+      pushtag (name, ref, loc);
     }
 
   C_TYPE_BEING_DEFINED (ref) = 1;
   TYPE_PACKED (ref) = flag_pack_struct;
+
+  *enclosing_in_struct = in_struct;
+  *enclosing_struct_types = struct_types;
+  in_struct = true;
+  struct_types = VEC_alloc(tree, heap, 0);
+
+  /* FIXME: This will issue a warning for a use of a type defined
+     within a statement expr used within sizeof, et. al.  This is not
+     terribly serious as C++ doesn't permit statement exprs within
+     sizeof anyhow.  */
+  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+    warning_at (loc, OPT_Wc___compat,
+               "defining type in %qs expression is invalid in C++",
+               (in_sizeof
+                ? "sizeof"
+                : (in_typeof ? "typeof" : "alignof")));
+
   return ref;
 }
 
 /* Process the specs, declarator and width (NULL if omitted)
    of a structure component, returning a FIELD_DECL node.
    WIDTH is non-NULL for bit-fields only, and is an INTEGER_CST node.
+   DECL_ATTRS is as for grokdeclarator.
+
+   LOC is the location of the structure component.
 
    This is done during the parsing of the struct declaration.
    The FIELD_DECL nodes are chained together and the lot of them
    are ultimately passed to `build_struct' to make the RECORD_TYPE node.  */
 
 tree
-grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
-          tree width)
+grokfield (location_t loc,
+          struct c_declarator *declarator, struct c_declspecs *declspecs,
+          tree width, tree *decl_attrs)
 {
   tree value;
 
@@ -5186,17 +5814,17 @@ grokfield (struct c_declarator *declarator, struct c_declspecs *declspecs,
        }
       if (!ok)
        {
-         pedwarn ("declaration does not declare anything");
+         pedwarn (loc, 0, "declaration does not declare anything");
          return NULL_TREE;
        }
-      if (pedantic)
-       pedwarn ("ISO C doesn%'t support unnamed structs/unions");
+      pedwarn (loc, OPT_pedantic, "ISO C doesn%'t support unnamed structs/unions");
     }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
-                         width ? &width : NULL);
+                         width ? &width : NULL, decl_attrs, NULL, NULL,
+                         DEPRECATED_NORMAL);
 
-  finish_decl (value, NULL_TREE, NULL_TREE);
+  finish_decl (value, NULL_TREE, NULL_TREE, NULL_TREE);
   DECL_INITIAL (value) = width;
 
   return value;
@@ -5261,14 +5889,22 @@ detect_field_duplicates (tree fieldlist)
 
 /* Fill in the fields of a RECORD_TYPE or UNION_TYPE node, T.
    FIELDLIST is a chain of FIELD_DECL nodes for the fields.
-   ATTRIBUTES are attributes to be applied to the structure.  */
+   ATTRIBUTES are attributes to be applied to the structure.
+
+   ENCLOSING_IN_STRUCT is the value of IN_STRUCT, and
+   ENCLOSING_STRUCT_TYPES is the value of STRUCT_TYPES, when the
+   struct was started.  This sets the C_TYPE_DEFINED_IN_STRUCT flag
+   for any type defined in the current struct.  */
 
 tree
-finish_struct (tree t, tree fieldlist, tree attributes)
+finish_struct (tree t, tree fieldlist, tree attributes,
+              bool enclosing_in_struct,
+              VEC(tree,heap) *enclosing_struct_types)
 {
   tree x;
   bool toplevel = file_scope == current_scope;
   int saw_named_field;
+  unsigned int ix;
 
   /* If this type was previously laid out as a forward reference,
      make sure we lay it out again.  */
@@ -5288,16 +5924,16 @@ finish_struct (tree t, tree fieldlist, tree attributes)
          if (TREE_CODE (t) == UNION_TYPE)
            {
              if (fieldlist)
-               pedwarn ("union has no named members");
+               pedwarn (input_location, OPT_pedantic, "union has no named members");
              else
-               pedwarn ("union has no members");
+               pedwarn (input_location, OPT_pedantic, "union has no members");
            }
          else
            {
              if (fieldlist)
-               pedwarn ("struct has no named members");
+               pedwarn (input_location, OPT_pedantic, "struct has no named members");
              else
-               pedwarn ("struct has no members");
+               pedwarn (input_location, OPT_pedantic, "struct has no members");
            }
        }
     }
@@ -5312,8 +5948,10 @@ finish_struct (tree t, tree fieldlist, tree attributes)
   saw_named_field = 0;
   for (x = fieldlist; x; x = TREE_CHAIN (x))
     {
+      if (TREE_TYPE (x) == error_mark_node)
+       continue;
+
       DECL_CONTEXT (x) = t;
-      DECL_PACKED (x) |= TYPE_PACKED (t);
 
       /* If any field is const, the structure type is pseudo-const.  */
       if (TREE_READONLY (x))
@@ -5346,6 +5984,11 @@ finish_struct (tree t, tree fieldlist, tree attributes)
          SET_DECL_C_BIT_FIELD (x);
        }
 
+      if (TYPE_PACKED (t)
+         && (DECL_BIT_FIELD (x)
+             || TYPE_ALIGN (TREE_TYPE (x)) > BITS_PER_UNIT))
+       DECL_PACKED (x) = 1;
+
       /* Detect flexible array member in an invalid context.  */
       if (TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
          && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
@@ -5371,7 +6014,8 @@ finish_struct (tree t, tree fieldlist, tree attributes)
 
       if (pedantic && !in_system_header && TREE_CODE (t) == RECORD_TYPE
          && flexible_array_type_p (TREE_TYPE (x)))
-       pedwarn ("%Jinvalid use of structure with flexible array member", x);
+       pedwarn (input_location, OPT_pedantic, 
+                "%Jinvalid use of structure with flexible array member", x);
 
       if (DECL_NAME (x))
        saw_named_field = 1;
@@ -5421,46 +6065,46 @@ finish_struct (tree t, tree fieldlist, tree attributes)
 
     for (x = fieldlist; x; x = TREE_CHAIN (x))
       {
-        if (len > 15 || DECL_NAME (x) == NULL)
-          break;
-        len += 1;
+       if (len > 15 || DECL_NAME (x) == NULL)
+         break;
+       len += 1;
       }
 
     if (len > 15)
       {
-        tree *field_array;
-        struct lang_type *space;
-        struct sorted_fields_type *space2;
+       tree *field_array;
+       struct lang_type *space;
+       struct sorted_fields_type *space2;
 
-        len += list_length (x);
+       len += list_length (x);
 
-        /* Use the same allocation policy here that make_node uses, to
-          ensure that this lives as long as the rest of the struct decl.
-          All decls in an inline function need to be saved.  */
+       /* Use the same allocation policy here that make_node uses, to
+         ensure that this lives as long as the rest of the struct decl.
+         All decls in an inline function need to be saved.  */
 
-        space = GGC_CNEW (struct lang_type);
-        space2 = GGC_NEWVAR (struct sorted_fields_type,
+       space = GGC_CNEW (struct lang_type);
+       space2 = GGC_NEWVAR (struct sorted_fields_type,
                             sizeof (struct sorted_fields_type) + len * sizeof (tree));
 
-        len = 0;
+       len = 0;
        space->s = space2;
        field_array = &space2->elts[0];
-        for (x = fieldlist; x; x = TREE_CHAIN (x))
-          {
-            field_array[len++] = x;
-
-            /* If there is anonymous struct or union, break out of the loop.  */
-            if (DECL_NAME (x) == NULL)
-              break;
-          }
-        /* Found no anonymous struct/union.  Add the TYPE_LANG_SPECIFIC.  */
-        if (x == NULL)
-          {
-            TYPE_LANG_SPECIFIC (t) = space;
-            TYPE_LANG_SPECIFIC (t)->s->len = len;
-            field_array = TYPE_LANG_SPECIFIC (t)->s->elts;
-            qsort (field_array, len, sizeof (tree), field_decl_cmp);
-          }
+       for (x = fieldlist; x; x = TREE_CHAIN (x))
+         {
+           field_array[len++] = x;
+
+           /* If there is anonymous struct or union, break out of the loop.  */
+           if (DECL_NAME (x) == NULL)
+             break;
+         }
+       /* Found no anonymous struct/union.  Add the TYPE_LANG_SPECIFIC.  */
+       if (x == NULL)
+         {
+           TYPE_LANG_SPECIFIC (t) = space;
+           TYPE_LANG_SPECIFIC (t)->s->len = len;
+           field_array = TYPE_LANG_SPECIFIC (t)->s->elts;
+           qsort (field_array, len, sizeof (tree), field_decl_cmp);
+         }
       }
   }
 
@@ -5468,8 +6112,6 @@ finish_struct (tree t, tree fieldlist, tree attributes)
     {
       TYPE_FIELDS (x) = TYPE_FIELDS (t);
       TYPE_LANG_SPECIFIC (x) = TYPE_LANG_SPECIFIC (t);
-      TYPE_ALIGN (x) = TYPE_ALIGN (t);
-      TYPE_USER_ALIGN (x) = TYPE_USER_ALIGN (t);
       C_TYPE_FIELDS_READONLY (x) = C_TYPE_FIELDS_READONLY (t);
       C_TYPE_FIELDS_VOLATILE (x) = C_TYPE_FIELDS_VOLATILE (t);
       C_TYPE_VARIABLE_SIZE (x) = C_TYPE_VARIABLE_SIZE (t);
@@ -5512,9 +6154,27 @@ finish_struct (tree t, tree fieldlist, tree attributes)
   /* If we're inside a function proper, i.e. not file-scope and not still
      parsing parameters, then arrange for the size of a variable sized type
      to be bound now.  */
-  if (cur_stmt_list && variably_modified_type_p (t, NULL))
+  if (cur_stmt_list && variably_modified_type_p (t, NULL_TREE))
     add_stmt (build_stmt (DECL_EXPR, build_decl (TYPE_DECL, NULL, t)));
 
+  /* Set the C_TYPE_DEFINED_IN_STRUCT flag for each type defined in
+     the current struct.  We do this now at the end of the struct
+     because the flag is used to issue visibility warnings when using
+     -Wc++-compat, and we only want to issue those warnings if the
+     type is referenced outside of the struct declaration.  */
+  for (ix = 0; VEC_iterate (tree, struct_types, ix, x); ++ix)
+    C_TYPE_DEFINED_IN_STRUCT (x) = 1;
+
+  VEC_free (tree, heap, struct_types);
+
+  in_struct = enclosing_in_struct;
+  struct_types = enclosing_struct_types;
+
+  /* If this struct is defined inside a struct, add it to
+     STRUCT_TYPES.  */
+  if (in_struct && !in_sizeof && !in_typeof && !in_alignof)
+    VEC_safe_push (tree, heap, struct_types, t);
+
   return t;
 }
 
@@ -5535,44 +6195,57 @@ layout_array_type (tree t)
    may be used to declare the individual values as they are read.  */
 
 tree
-start_enum (tree name)
+start_enum (struct c_enum_contents *the_enum, tree name, location_t loc)
 {
-  tree enumtype = 0;
+  tree enumtype = NULL_TREE;
+  location_t enumloc = UNKNOWN_LOCATION;
 
   /* If this is the real definition for a previous forward reference,
      fill in the contents in the same object that used to be the
      forward reference.  */
 
-  if (name != 0)
-    enumtype = lookup_tag (ENUMERAL_TYPE, name, 1);
+  if (name != NULL_TREE)
+    enumtype = lookup_tag (ENUMERAL_TYPE, name, 1, &enumloc);
 
   if (enumtype == 0 || TREE_CODE (enumtype) != ENUMERAL_TYPE)
     {
       enumtype = make_node (ENUMERAL_TYPE);
-      pushtag (name, enumtype);
+      pushtag (name, enumtype, loc);
     }
 
   if (C_TYPE_BEING_DEFINED (enumtype))
-    error ("nested redefinition of %<enum %E%>", name);
+    error_at (loc, "nested redefinition of %<enum %E%>", name);
 
   C_TYPE_BEING_DEFINED (enumtype) = 1;
 
   if (TYPE_VALUES (enumtype) != 0)
     {
       /* This enum is a named one that has been declared already.  */
-      error ("redeclaration of %<enum %E%>", name);
+      error_at (loc, "redeclaration of %<enum %E%>", name);
+      if (enumloc != UNKNOWN_LOCATION)
+       inform (enumloc, "originally defined here");
 
       /* Completely replace its old definition.
         The old enumerators remain defined, however.  */
       TYPE_VALUES (enumtype) = 0;
     }
 
-  enum_next_value = integer_zero_node;
-  enum_overflow = 0;
+  the_enum->enum_next_value = integer_zero_node;
+  the_enum->enum_overflow = 0;
 
   if (flag_short_enums)
     TYPE_PACKED (enumtype) = 1;
 
+  /* FIXME: This will issue a warning for a use of a type defined
+     within sizeof in a statement expr.  This is not terribly serious
+     as C++ doesn't permit statement exprs within sizeof anyhow.  */
+  if (warn_cxx_compat && (in_sizeof || in_typeof || in_alignof))
+    warning_at (loc, OPT_Wc___compat,
+               "defining type in %qs expression is invalid in C++",
+               (in_sizeof
+                ? "sizeof"
+                : (in_typeof ? "typeof" : "alignof")));
+
   return enumtype;
 }
 
@@ -5615,8 +6288,8 @@ finish_enum (tree enumtype, tree values, tree attributes)
      that normally we only go as narrow as int - and signed iff any of
      the values are negative.  */
   unsign = (tree_int_cst_sgn (minnode) >= 0);
-  precision = MAX (min_precision (minnode, unsign),
-                  min_precision (maxnode, unsign));
+  precision = MAX (tree_int_cst_min_precision (minnode, unsign),
+                  tree_int_cst_min_precision (maxnode, unsign));
 
   if (TYPE_PACKED (enumtype) || precision > TYPE_PRECISION (integer_type_node))
     {
@@ -5665,16 +6338,16 @@ finish_enum (tree enumtype, tree values, tree attributes)
 
          /* The ISO C Standard mandates enumerators to have type int,
             even though the underlying type of an enum type is
-            unspecified.  Here we convert any enumerators that fit in
-            an int to type int, to avoid promotions to unsigned types
-            when comparing integers with enumerators that fit in the
-            int range.  When -pedantic is given, build_enumerator()
-            would have already taken care of those that don't fit.  */
-         if (int_fits_type_p (ini, integer_type_node))
-           tem = integer_type_node;
-         else
-           tem = enumtype;
-         ini = convert (tem, ini);
+            unspecified.  However, GCC allows enumerators of any
+            integer type as an extensions.  build_enumerator()
+            converts any enumerators that fit in an int to type int,
+            to avoid promotions to unsigned types when comparing
+            integers with enumerators that fit in the int range.
+            When -pedantic is given, build_enumerator() would have
+            already warned about those that don't fit. Here we
+            convert the rest to the enumerator type. */
+         if (TREE_TYPE (ini) != integer_type_node)
+           ini = convert (enumtype, ini);
 
          DECL_INITIAL (enu) = ini;
          TREE_PURPOSE (pair) = DECL_NAME (enu);
@@ -5701,7 +6374,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
       TYPE_MAX_VALUE (tem) = TYPE_MAX_VALUE (enumtype);
       TYPE_SIZE (tem) = TYPE_SIZE (enumtype);
       TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype);
-      TYPE_MODE (tem) = TYPE_MODE (enumtype);
+      SET_TYPE_MODE (tem, TYPE_MODE (enumtype));
       TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype);
       TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype);
       TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype);
@@ -5712,6 +6385,11 @@ finish_enum (tree enumtype, tree values, tree attributes)
   /* Finish debugging output for this type.  */
   rest_of_type_compilation (enumtype, toplevel);
 
+  /* If this enum is defined inside a struct, add it to
+     STRUCT_TYPES.  */
+  if (in_struct && !in_sizeof && !in_typeof && !in_alignof)
+    VEC_safe_push (tree, heap, struct_types, enumtype);
+
   return enumtype;
 }
 
@@ -5721,7 +6399,8 @@ finish_enum (tree enumtype, tree values, tree attributes)
    Assignment of sequential values by default is handled here.  */
 
 tree
-build_enumerator (tree name, tree value)
+build_enumerator (struct c_enum_contents *the_enum, tree name, tree value,
+                 location_t value_loc)
 {
   tree decl, type;
 
@@ -5733,16 +6412,32 @@ build_enumerator (tree name, tree value)
         undeclared identifier) - just ignore the value expression.  */
       if (value == error_mark_node)
        value = 0;
-      else if (!INTEGRAL_TYPE_P (TREE_TYPE (value))
-              || TREE_CODE (value) != INTEGER_CST)
+      else if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
        {
          error ("enumerator value for %qE is not an integer constant", name);
          value = 0;
        }
       else
        {
-         value = default_conversion (value);
-         constant_expression_warning (value);
+         if (TREE_CODE (value) != INTEGER_CST)
+           {
+             value = c_fully_fold (value, false, NULL);
+             if (TREE_CODE (value) == INTEGER_CST)
+               pedwarn (value_loc, OPT_pedantic,
+                        "enumerator value for %qE is not an integer "
+                        "constant expression", name);
+           }
+         if (TREE_CODE (value) != INTEGER_CST)
+           {
+             error ("enumerator value for %qE is not an integer constant",
+                    name);
+             value = 0;
+           }
+         else
+           {
+             value = default_conversion (value);
+             constant_expression_warning (value);
+           }
        }
     }
 
@@ -5751,22 +6446,36 @@ build_enumerator (tree name, tree value)
      in the default.  */
   if (value == 0)
     {
-      value = enum_next_value;
-      if (enum_overflow)
+      value = the_enum->enum_next_value;
+      if (the_enum->enum_overflow)
        error ("overflow in enumeration values");
     }
-
-  if (pedantic && !int_fits_type_p (value, integer_type_node))
-    {
-      pedwarn ("ISO C restricts enumerator values to range of %<int%>");
-      /* XXX This causes -pedantic to change the meaning of the program.
-        Remove?  -zw 2004-03-15  */
-      value = convert (integer_type_node, value);
-    }
+  /* Even though the underlying type of an enum is unspecified, the
+     type of enumeration constants is explicitly defined as int
+     (6.4.4.3/2 in the C99 Standard).  GCC allows any integer type as
+     an extension.  */
+  else if (!int_fits_type_p (value, integer_type_node))
+    pedwarn (value_loc, OPT_pedantic, 
+            "ISO C restricts enumerator values to range of %<int%>");
+
+  /* The ISO C Standard mandates enumerators to have type int, even
+     though the underlying type of an enum type is unspecified.
+     However, GCC allows enumerators of any integer type as an
+     extensions.  Here we convert any enumerators that fit in an int
+     to type int, to avoid promotions to unsigned types when comparing
+     integers with enumerators that fit in the int range.  When
+     -pedantic is given, we would have already warned about those that
+     don't fit. We have to do this here rather than in finish_enum
+     because this value may be used to define more enumerators.  */
+  if (int_fits_type_p (value, integer_type_node))
+    value = convert (integer_type_node, value);
 
   /* Set basis for default for next value.  */
-  enum_next_value = build_binary_op (PLUS_EXPR, value, integer_one_node, 0);
-  enum_overflow = tree_int_cst_lt (enum_next_value, value);
+  the_enum->enum_next_value
+    = build_binary_op
+         (EXPR_HAS_LOCATION (value) ? EXPR_LOCATION (value) : input_location,
+        PLUS_EXPR, value, integer_one_node, 0);
+  the_enum->enum_overflow = tree_int_cst_lt (the_enum->enum_next_value, value);
 
   /* Now create a declaration for the enum value name.  */
 
@@ -5810,7 +6519,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   current_function_returns_null = 0;
   current_function_returns_abnormally = 0;
   warn_about_return_type = 0;
-  current_extern_inline = 0;
   c_switch_stack = NULL;
 
   nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
@@ -5831,7 +6539,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
      error message in c_finish_bc_stmt.  */
   c_break_label = c_cont_label = size_zero_node;
 
-  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL);
+  decl1 = grokdeclarator (declarator, declspecs, FUNCDEF, true, NULL,
+                         &attributes, NULL, NULL, DEPRECATED_NORMAL);
 
   /* If the declarator is not suitable for a function definition,
      cause a syntax error.  */
@@ -5850,6 +6559,17 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
     warning (OPT_Wattributes, "inline function %q+D given attribute noinline",
             decl1);
 
+  /* Handle gnu_inline attribute.  */
+  if (declspecs->inline_p
+      && !flag_gnu89_inline
+      && TREE_CODE (decl1) == FUNCTION_DECL
+      && (lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (decl1))
+         || current_function_decl))
+    {
+      if (declspecs->storage_class != csc_static)
+       DECL_EXTERNAL (decl1) = !DECL_EXTERNAL (decl1);
+    }
+
   announce_function (decl1);
 
   if (!COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl1))))
@@ -5862,7 +6582,9 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
     }
 
   if (warn_about_return_type)
-    pedwarn_c99 ("return type defaults to %<int%>");
+    pedwarn_c99 (input_location, flag_isoc99 ? 0 
+                : (warn_return_type ? OPT_Wreturn_type : OPT_Wimplicit_int),
+                "return type defaults to %<int%>");
 
   /* Make the init_value nonzero so pushdecl knows this is not tentative.
      error_mark_node is replaced below (in pop_scope) with the BLOCK.  */
@@ -5871,6 +6593,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   /* If this definition isn't a prototype and we had a prototype declaration
      before, copy the arg type info from that prototype.  */
   old_decl = lookup_name_in_scope (DECL_NAME (decl1), current_scope);
+  if (old_decl && TREE_CODE (old_decl) != FUNCTION_DECL)
+    old_decl = 0;
   current_function_prototype_locus = UNKNOWN_LOCATION;
   current_function_prototype_built_in = false;
   current_function_prototype_arg_types = NULL_TREE;
@@ -5960,12 +6684,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
     warning (OPT_Wmissing_declarations,
             "%q+D was used with no declaration before its definition", decl1);
 
-  /* This is a definition, not a reference.
-     So normally clear DECL_EXTERNAL.
-     However, `extern inline' acts like a declaration
-     except for defining how to inline.  So set DECL_EXTERNAL in that case.  */
-  DECL_EXTERNAL (decl1) = current_extern_inline;
-
   /* This function exists in static storage.
      (This does not mean `static' in the C sense!)  */
   TREE_STATIC (decl1) = 1;
@@ -5983,59 +6701,16 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
     maybe_apply_pragma_weak (decl1);
 
   /* Warn for unlikely, improbable, or stupid declarations of `main'.  */
-  if (warn_main > 0 && MAIN_NAME_P (DECL_NAME (decl1)))
+  if (warn_main && MAIN_NAME_P (DECL_NAME (decl1)))
     {
-      tree args;
-      int argct = 0;
-
       if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (decl1)))
          != integer_type_node)
-       pedwarn ("return type of %q+D is not %<int%>", decl1);
-
-      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;
+       pedwarn (input_location, OPT_Wmain, "return type of %q+D is not %<int%>", decl1);
 
-         ++argct;
-         switch (argct)
-           {
-           case 1:
-             if (TYPE_MAIN_VARIANT (type) != integer_type_node)
-               pedwarn ("first argument of %q+D should be %<int%>", decl1);
-             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 ("second argument of %q+D should be %<char **%>",
-                         decl1);
-             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 ("third argument of %q+D should probably be "
-                         "%<char **%>", decl1);
-             break;
-           }
-       }
-
-      /* It is intentional that this message does not mention the third
-        argument because it's only mentioned in an appendix of the
-        standard.  */
-      if (argct > 0 && (argct < 2 || argct > 3))
-       pedwarn ("%q+D takes only zero or two arguments", decl1);
+      check_main_parameter_types (decl1);
 
       if (!TREE_PUBLIC (decl1))
-       pedwarn ("%q+D is normally a non-static function", decl1);
+       pedwarn (input_location, OPT_Wmain, "%q+D is normally a non-static function", decl1);
     }
 
   /* Record the decl so that the function name is defined.
@@ -6048,18 +6723,6 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
   declare_parm_level ();
 
   restype = TREE_TYPE (TREE_TYPE (current_function_decl));
-  /* Promote the value to int before returning it.  */
-  if (c_promoting_integer_type_p (restype))
-    {
-      /* It retains unsignedness if not really getting wider.  */
-      if (TYPE_UNSIGNED (restype)
-         && (TYPE_PRECISION (restype)
-                 == TYPE_PRECISION (integer_type_node)))
-       restype = unsigned_type_node;
-      else
-       restype = integer_type_node;
-    }
-
   resdecl = build_decl (RESULT_DECL, NULL_TREE, restype);
   DECL_ARTIFICIAL (resdecl) = 1;
   DECL_IGNORED_P (resdecl) = 1;
@@ -6106,7 +6769,8 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info)
       if (DECL_NAME (decl))
        {
          bind (DECL_NAME (decl), decl, current_scope,
-               /*invisible=*/false, /*nested=*/false);
+               /*invisible=*/false, /*nested=*/false,
+               UNKNOWN_LOCATION);
          if (!TREE_USED (decl))
            warn_if_shadowing (decl);
        }
@@ -6123,14 +6787,14 @@ store_parm_decls_newstyle (tree fndecl, const struct c_arg_info *arg_info)
       DECL_CONTEXT (decl) = current_function_decl;
       if (DECL_NAME (decl))
        bind (DECL_NAME (decl), decl, current_scope,
-             /*invisible=*/false, /*nested=*/false);
+             /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
     }
 
   /* And all the tag declarations.  */
   for (decl = arg_info->tags; decl; decl = TREE_CHAIN (decl))
     if (TREE_PURPOSE (decl))
       bind (TREE_PURPOSE (decl), TREE_VALUE (decl), current_scope,
-           /*invisible=*/false, /*nested=*/false);
+           /*invisible=*/false, /*nested=*/false, UNKNOWN_LOCATION);
 }
 
 /* Subroutine of store_parm_decls which handles old-style function
@@ -6195,9 +6859,9 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
          warn_if_shadowing (decl);
 
          if (flag_isoc99)
-           pedwarn ("type of %q+D defaults to %<int%>", decl);
-         else if (extra_warnings)
-           warning (OPT_Wextra, "type of %q+D defaults to %<int%>", decl);
+           pedwarn (input_location, 0, "type of %q+D defaults to %<int%>", decl);
+         else 
+           warning (OPT_Wmissing_parameter_type, "type of %q+D defaults to %<int%>", decl);
        }
 
       TREE_PURPOSE (parm) = decl;
@@ -6264,8 +6928,8 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
       tree type;
       for (parm = DECL_ARGUMENTS (fndecl),
             type = current_function_prototype_arg_types;
-          parm || (type && (TYPE_MAIN_VARIANT (TREE_VALUE (type))
-                            != void_type_node));
+          parm || (type && TREE_VALUE (type) != error_mark_node
+                   && (TYPE_MAIN_VARIANT (TREE_VALUE (type)) != void_type_node));
           parm = TREE_CHAIN (parm), type = TREE_CHAIN (type))
        {
          if (parm == 0 || type == 0
@@ -6285,8 +6949,10 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
          /* Type for passing arg must be consistent with that
             declared for the arg.  ISO C says we take the unqualified
             type for parameters declared with qualified type.  */
-         if (!comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
-                         TYPE_MAIN_VARIANT (TREE_VALUE (type))))
+         if (TREE_TYPE (parm) != error_mark_node
+             && TREE_TYPE (type) != error_mark_node
+             && !comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
+                            TYPE_MAIN_VARIANT (TREE_VALUE (type))))
            {
              if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
                  == TYPE_MAIN_VARIANT (TREE_VALUE (type)))
@@ -6304,22 +6970,19 @@ store_parm_decls_oldstyle (tree fndecl, const struct c_arg_info *arg_info)
                      < TYPE_PRECISION (integer_type_node))
                    DECL_ARG_TYPE (parm) = integer_type_node;
 
-                 if (pedantic)
+                 /* ??? Is it possible to get here with a
+                    built-in prototype or will it always have
+                    been diagnosed as conflicting with an
+                    old-style definition and discarded?  */
+                 if (current_function_prototype_built_in)
+                   warning (OPT_pedantic, "promoted argument %qD "
+                            "doesn%'t match built-in prototype", parm);
+                 else
                    {
-                     /* ??? Is it possible to get here with a
-                        built-in prototype or will it always have
-                        been diagnosed as conflicting with an
-                        old-style definition and discarded?  */
-                     if (current_function_prototype_built_in)
-                       warning (0, "promoted argument %qD "
-                                "doesn%'t match built-in prototype", parm);
-                     else
-                       {
-                         pedwarn ("promoted argument %qD "
-                                  "doesn%'t match prototype", parm);
-                         pedwarn ("%Hprototype declaration",
-                                  &current_function_prototype_locus);
-                       }
+                     pedwarn (input_location, OPT_pedantic, "promoted argument %qD "
+                              "doesn%'t match prototype", parm);
+                     pedwarn (current_function_prototype_locus, OPT_pedantic,
+                              "prototype declaration");
                    }
                }
              else
@@ -6423,7 +7086,7 @@ store_parm_decls (void)
   gen_aux_info_record (fndecl, 1, 0, proto);
 
   /* Initialize the RTL code for the function.  */
-  allocate_struct_function (fndecl);
+  allocate_struct_function (fndecl, false);
 
   /* Begin the statement tree for this function.  */
   DECL_SAVED_TREE (fndecl) = push_stmt_list ();
@@ -6444,24 +7107,29 @@ store_parm_decls (void)
      call expand_expr to calculate the size of a variable-sized array.
      We haven't necessarily assigned RTL to all variables yet, so it's
      not safe to try to expand expressions involving them.  */
-  cfun->x_dont_save_pending_sizes_p = 1;
+  cfun->dont_save_pending_sizes_p = 1;
 }
 \f
-/* Handle attribute((warn_unused_result)) on FNDECL and all its nested
-   functions.  */
+/* Emit diagnostics that require gimple input for detection.  Operate on
+   FNDECL and all its nested functions.  */
 
 static void
-c_warn_unused_result_recursively (tree fndecl)
+c_gimple_diagnostics_recursively (tree fndecl)
 {
   struct cgraph_node *cgn;
+  gimple_seq body = gimple_body (fndecl);
 
   /* Handle attribute((warn_unused_result)).  Relies on gimple input.  */
-  c_warn_unused_result (&DECL_SAVED_TREE (fndecl));
+  c_warn_unused_result (body);
+
+  /* Notice when OpenMP structured block constraints are violated.  */
+  if (flag_openmp)
+    diagnose_omp_structured_block_errors (fndecl);
 
   /* Finalize all nested functions now.  */
   cgn = cgraph_node (fndecl);
   for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested)
-    c_warn_unused_result_recursively (cgn->decl);
+    c_gimple_diagnostics_recursively (cgn->decl);
 }
 
 /* Finish up a function declaration and compile that function
@@ -6483,12 +7151,12 @@ finish_function (void)
     {
       tree args = DECL_ARGUMENTS (fndecl);
       for (; args; args = TREE_CHAIN (args))
-       {
-         tree type = TREE_TYPE (args);
-         if (INTEGRAL_TYPE_P (type)
-             && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
-           DECL_ARG_TYPE (args) = integer_type_node;
-       }
+       {
+         tree type = TREE_TYPE (args);
+         if (INTEGRAL_TYPE_P (type)
+             && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
+           DECL_ARG_TYPE (args) = integer_type_node;
+       }
     }
 
   if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
@@ -6499,37 +7167,18 @@ finish_function (void)
   if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node)
     DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
 
-  if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted)
+  if (MAIN_NAME_P (DECL_NAME (fndecl)) && flag_hosted
+      && TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
+      == integer_type_node && flag_isoc99)
     {
-      if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
-         != integer_type_node)
-       {
-         /* If warn_main is 1 (-Wmain) or 2 (-Wall), we have already warned.
-            If warn_main is -1 (-Wno-main) we don't want to be warned.  */
-         if (!warn_main)
-           pedwarn ("return type of %q+D is not %<int%>", fndecl);
-       }
-      else
-       {
-         if (flag_isoc99)
-           {
-             tree stmt = c_finish_return (integer_zero_node);
-#ifdef USE_MAPPED_LOCATION
-             /* Hack.  We don't want the middle-end to warn that this return
-                is unreachable, so we mark its location as special.  Using
-                UNKNOWN_LOCATION has the problem that it gets clobbered in
-                annotate_one_with_locus.  A cleaner solution might be to
-                ensure ! should_carry_locus_p (stmt), but that needs a flag.
-             */
-             SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION);
-#else
-             /* Hack.  We don't want the middle-end to warn that this
-                return is unreachable, so put the statement on the
-                special line 0.  */
-             annotate_with_file_line (stmt, input_filename, 0);
-#endif
-           }
-       }
+      tree stmt = c_finish_return (integer_zero_node, NULL_TREE);
+      /* Hack.  We don't want the middle-end to warn that this return
+        is unreachable, so we mark its location as special.  Using
+        UNKNOWN_LOCATION has the problem that it gets clobbered in
+        annotate_one_with_locus.  A cleaner solution might be to
+        ensure ! should_carry_locus_p (stmt), but that needs a flag.
+      */
+      SET_EXPR_LOCATION (stmt, BUILTINS_LOCATION);
     }
 
   /* Tie off the statement tree for this function.  */
@@ -6547,38 +7196,27 @@ finish_function (void)
       && !MAIN_NAME_P (DECL_NAME (fndecl))
       /* Or if they didn't actually specify a return type.  */
       && !C_FUNCTION_IMPLICIT_INT (fndecl)
-      /* Normally, with -Wreturn-type, flow will complain.  Unless we're an
-        inline function, as we might never be compiled separately.  */
-      && DECL_INLINE (fndecl))
+      /* Normally, with -Wreturn-type, flow will complain, but we might
+         optimize out static functions.  */
+      && !TREE_PUBLIC (fndecl))
     {
       warning (OPT_Wreturn_type,
               "no return statement in function returning non-void");
       TREE_NO_WARNING (fndecl) = 1;
     }
 
-  /* With just -Wextra, complain only if function returns both with
-     and without a value.  */
-  if (extra_warnings
-      && current_function_returns_value
-      && current_function_returns_null)
-    warning (OPT_Wextra, "this function may return with or without a value");
-
   /* Store the end of the function, so that we get good line number
      info for the epilogue.  */
   cfun->function_end_locus = input_location;
 
-  /* If we don't have ctors/dtors sections, and this is a static
-     constructor or destructor, it must be recorded now.  */
-  if (DECL_STATIC_CONSTRUCTOR (fndecl)
-      && !targetm.have_ctors_dtors)
-    static_ctors = tree_cons (NULL_TREE, fndecl, static_ctors);
-  if (DECL_STATIC_DESTRUCTOR (fndecl)
-      && !targetm.have_ctors_dtors)
-    static_dtors = tree_cons (NULL_TREE, fndecl, static_dtors);
-
   /* Finalize the ELF visibility for the function.  */
   c_determine_visibility (fndecl);
 
+  /* For GNU C extern inline functions disregard inline limits.  */
+  if (DECL_EXTERNAL (fndecl) 
+      && DECL_DECLARED_INLINE_P (fndecl))
+    DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
+
   /* Genericize before inlining.  Delay genericizing nested functions
      until their parent function is genericized.  Since finalizing
      requires GENERIC, delay that as well.  */
@@ -6587,27 +7225,27 @@ finish_function (void)
       && !undef_nested_function)
     {
       if (!decl_function_context (fndecl))
-        {
-          c_genericize (fndecl);
-          c_warn_unused_result_recursively (fndecl);
+       {
+         c_genericize (fndecl);
+         c_gimple_diagnostics_recursively (fndecl);
 
          /* ??? Objc emits functions after finalizing the compilation unit.
             This should be cleaned up later and this conditional removed.  */
          if (cgraph_global_info_ready)
            {
-             c_expand_body (fndecl);
+             cgraph_add_new_function (fndecl, false);
              return;
            }
 
          cgraph_finalize_function (fndecl, false);
-        }
+       }
       else
-        {
-          /* Register this function with cgraph just far enough to get it
-            added to our parent's nested function list.  Handy, since the
-            C front end doesn't have such a list.  */
-          (void) cgraph_node (fndecl);
-        }
+       {
+         /* Register this function with cgraph just far enough to get it
+           added to our parent's nested function list.  Handy, since the
+           C front end doesn't have such a list.  */
+         (void) cgraph_node (fndecl);
+       }
     }
 
   if (!decl_function_context (fndecl))
@@ -6616,46 +7254,34 @@ finish_function (void)
   /* We're leaving the context of this function, so zap cfun.
      It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
      tree_rest_of_compilation.  */
-  cfun = NULL;
+  set_cfun (NULL);
   current_function_decl = NULL;
 }
-
-/* Generate the RTL for the body of FNDECL.  */
-
-void
-c_expand_body (tree fndecl)
-{
-
-  if (!DECL_INITIAL (fndecl)
-      || DECL_INITIAL (fndecl) == error_mark_node)
-    return;
-
-  tree_rest_of_compilation (fndecl);
-
-  if (DECL_STATIC_CONSTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.constructor (XEXP (DECL_RTL (fndecl), 0),
-                                 DEFAULT_INIT_PRIORITY);
-  if (DECL_STATIC_DESTRUCTOR (fndecl)
-      && targetm.have_ctors_dtors)
-    targetm.asm_out.destructor (XEXP (DECL_RTL (fndecl), 0),
-                                DEFAULT_INIT_PRIORITY);
-}
 \f
 /* Check the declarations given in a for-loop for satisfying the C99
-   constraints.  */
-void
+   constraints.  If exactly one such decl is found, return it.  */
+
+tree
 check_for_loop_decls (void)
 {
   struct c_binding *b;
+  tree one_decl = NULL_TREE;
+  int n_decls = 0;
 
   if (!flag_isoc99)
     {
+      static bool hint = true;
       /* If we get here, declarations have been used in a for loop without
         the C99 for loop scope.  This doesn't make much sense, so don't
         allow it.  */
-      error ("%<for%> loop initial declaration used outside C99 mode");
-      return;
+      error ("%<for%> loop initial declarations are only allowed in C99 mode");
+      if (hint)
+       {
+         inform (input_location, 
+                 "use option -std=c99 or -std=gnu99 to compile your code");
+         hint = false;
+       }
+      return NULL_TREE;
     }
   /* C99 subclause 6.8.5 paragraph 3:
 
@@ -6706,18 +7332,23 @@ check_for_loop_decls (void)
          error ("declaration of non-variable %q+D in %<for%> loop "
                 "initial declaration", decl);
        }
+
+      n_decls++;
+      one_decl = decl;
     }
+
+  return n_decls == 1 ? one_decl : NULL_TREE;
 }
 \f
 /* Save and reinitialize the variables
    used during compilation of a C function.  */
 
 void
-c_push_function_context (struct function *f)
+c_push_function_context (void)
 {
   struct language_function *p;
   p = GGC_NEW (struct language_function);
-  f->language = p;
+  cfun->language = p;
 
   p->base.x_stmt_tree = c_stmt_tree;
   p->x_break_label = c_break_label;
@@ -6728,15 +7359,20 @@ c_push_function_context (struct function *f)
   p->returns_null = current_function_returns_null;
   p->returns_abnormally = current_function_returns_abnormally;
   p->warn_about_return_type = warn_about_return_type;
-  p->extern_inline = current_extern_inline;
+
+  push_function_context ();
 }
 
 /* Restore the variables used during compilation of a C function.  */
 
 void
-c_pop_function_context (struct function *f)
+c_pop_function_context (void)
 {
-  struct language_function *p = f->language;
+  struct language_function *p;
+
+  pop_function_context ();
+  p = cfun->language;
+  cfun->language = NULL;
 
   if (DECL_STRUCT_FUNCTION (current_function_decl) == 0
       && DECL_SAVED_TREE (current_function_decl) == NULL_TREE)
@@ -6757,9 +7393,6 @@ c_pop_function_context (struct function *f)
   current_function_returns_null = p->returns_null;
   current_function_returns_abnormally = p->returns_abnormally;
   warn_about_return_type = p->warn_about_return_type;
-  current_extern_inline = p->extern_inline;
-
-  f->language = NULL;
 }
 
 /* Copy the DECL_LANG_SPECIFIC data associated with DECL.  */
@@ -6792,15 +7425,6 @@ current_stmt_tree (void)
   return &c_stmt_tree;
 }
 
-/* Nonzero if TYPE is an anonymous union or struct type.  Always 0 in
-   C.  */
-
-int
-anon_aggr_type_p (tree ARG_UNUSED (node))
-{
-  return 0;
-}
-
 /* Return the global value of T as a symbol.  */
 
 tree
@@ -6930,10 +7554,12 @@ build_null_declspecs (void)
 {
   struct c_declspecs *ret = XOBNEW (&parser_obstack, struct c_declspecs);
   ret->type = 0;
+  ret->expr = 0;
   ret->decl_attr = 0;
   ret->attrs = 0;
   ret->typespec_word = cts_none;
   ret->storage_class = csc_none;
+  ret->expr_const_operands = true;
   ret->declspecs_seen_p = false;
   ret->type_seen_p = false;
   ret->non_sc_seen_p = false;
@@ -6953,6 +7579,7 @@ build_null_declspecs (void)
   ret->const_p = false;
   ret->volatile_p = false;
   ret->restrict_p = false;
+  ret->saturating_p = false;
   return ret;
 }
 
@@ -6986,8 +7613,8 @@ declspecs_add_qual (struct c_declspecs *specs, tree qual)
     default:
       gcc_unreachable ();
     }
-  if (dupe && pedantic && !flag_isoc99)
-    pedwarn ("duplicate %qE", qual);
+  if (dupe && !flag_isoc99)
+    pedwarn (input_location, OPT_pedantic, "duplicate %qE", qual);
   return specs;
 }
 
@@ -7005,7 +7632,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
     specs->deprecated_p = true;
 
   /* Handle type specifier keywords.  */
-  if (TREE_CODE (type) == IDENTIFIER_NODE && C_IS_RESERVED_WORD (type))
+  if (TREE_CODE (type) == IDENTIFIER_NODE
+      && C_IS_RESERVED_WORD (type)
+      && C_RID_CODE (type) != RID_CXX_COMPAT_WARN)
     {
       enum rid i = C_RID_CODE (type);
       if (specs->type)
@@ -7015,7 +7644,7 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
        }
       if ((int) i <= (int) RID_LAST_MODIFIER)
        {
-         /* "long", "short", "signed", "unsigned" or "_Complex".  */
+         /* "long", "short", "signed", "unsigned", "_Complex" or "_Sat".  */
          bool dupe = false;
          switch (i)
            {
@@ -7033,9 +7662,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
                             "declaration specifiers");
                      break;
                    }
-                 if (pedantic && !flag_isoc99 && !in_system_header
-                     && warn_long_long)
-                   pedwarn ("ISO C90 does not support %<long long%>");
+                 pedwarn_c90 (input_location, OPT_Wlong_long, 
+                              "ISO C90 does not support %<long long%>");
                  specs->long_long_p = 1;
                  break;
                }
@@ -7054,6 +7682,15 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->typespec_word == cts_float)
                error ("both %<long%> and %<float%> in "
                       "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<long%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<long%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<long%> and %<_Decimal128%> in "
+                      "declaration specifiers");
              else
                specs->long_p = true;
              break;
@@ -7077,6 +7714,15 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->typespec_word == cts_double)
                error ("both %<short%> and %<double%> in "
                       "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat32)
+                error ("both %<short%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<short%> and %<_Decimal64%> in "
+                                       "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<short%> and %<_Decimal128%> in "
+                      "declaration specifiers");
              else
                specs->short_p = true;
              break;
@@ -7097,6 +7743,15 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->typespec_word == cts_double)
                error ("both %<signed%> and %<double%> in "
                       "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<signed%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<signed%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<signed%> and %<_Decimal128%> in "
+                      "declaration specifiers");
              else
                specs->signed_p = true;
              break;
@@ -7117,22 +7772,85 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->typespec_word == cts_double)
                error ("both %<unsigned%> and %<double%> in "
                       "declaration specifiers");
+              else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<unsigned%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<unsigned%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<unsigned%> and %<_Decimal128%> in "
+                      "declaration specifiers");
              else
                specs->unsigned_p = true;
              break;
            case RID_COMPLEX:
              dupe = specs->complex_p;
-             if (pedantic && !flag_isoc99 && !in_system_header)
-               pedwarn ("ISO C90 does not support complex types");
+             if (!flag_isoc99 && !in_system_header)
+               pedwarn (input_location, OPT_pedantic, "ISO C90 does not support complex types");
              if (specs->typespec_word == cts_void)
                error ("both %<complex%> and %<void%> in "
                       "declaration specifiers");
              else if (specs->typespec_word == cts_bool)
                error ("both %<complex%> and %<_Bool%> in "
                       "declaration specifiers");
+              else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<complex%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<complex%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<complex%> and %<_Decimal128%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_fract)
+               error ("both %<complex%> and %<_Fract%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_accum)
+               error ("both %<complex%> and %<_Accum%> in "
+                      "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<complex%> and %<_Sat%> in "
+                      "declaration specifiers");
              else
                specs->complex_p = true;
              break;
+           case RID_SAT:
+             dupe = specs->saturating_p;
+             pedwarn (input_location, OPT_pedantic, "ISO C does not support saturating types");
+             if (specs->typespec_word == cts_void)
+               error ("both %<_Sat%> and %<void%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_bool)
+               error ("both %<_Sat%> and %<_Bool%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_char)
+               error ("both %<_Sat%> and %<char%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_int)
+               error ("both %<_Sat%> and %<int%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_float)
+               error ("both %<_Sat%> and %<float%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_double)
+               error ("both %<_Sat%> and %<double%> in "
+                      "declaration specifiers");
+              else if (specs->typespec_word == cts_dfloat32)
+               error ("both %<_Sat%> and %<_Decimal32%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat64)
+               error ("both %<_Sat%> and %<_Decimal64%> in "
+                      "declaration specifiers");
+             else if (specs->typespec_word == cts_dfloat128)
+               error ("both %<_Sat%> and %<_Decimal128%> in "
+                      "declaration specifiers");
+             else if (specs->complex_p)
+               error ("both %<_Sat%> and %<complex%> in "
+                      "declaration specifiers");
+             else
+               specs->saturating_p = true;
+             break;
            default:
              gcc_unreachable ();
            }
@@ -7144,7 +7862,8 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
        }
       else
        {
-         /* "void", "_Bool", "char", "int", "float" or "double".  */
+         /* "void", "_Bool", "char", "int", "float", "double", "_Decimal32",
+            "_Decimal64", "_Decimal128", "_Fract" or "_Accum".  */
          if (specs->typespec_word != cts_none)
            {
              error ("two or more data types in declaration specifiers");
@@ -7168,6 +7887,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->complex_p)
                error ("both %<complex%> and %<void%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<void%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_void;
              return specs;
@@ -7187,6 +7909,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->complex_p)
                error ("both %<complex%> and %<_Bool%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<_Bool%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_bool;
              return specs;
@@ -7197,11 +7922,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->short_p)
                error ("both %<short%> and %<char%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<char%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_char;
              return specs;
            case RID_INT:
-             specs->typespec_word = cts_int;
+             if (specs->saturating_p)
+               error ("both %<_Sat%> and %<int%> in "
+                      "declaration specifiers");
+             else
+               specs->typespec_word = cts_int;
              return specs;
            case RID_FLOAT:
              if (specs->long_p)
@@ -7216,6 +7948,9 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->unsigned_p)
                error ("both %<unsigned%> and %<float%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<float%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_float;
              return specs;
@@ -7232,9 +7967,77 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
              else if (specs->unsigned_p)
                error ("both %<unsigned%> and %<double%> in "
                       "declaration specifiers");
+             else if (specs->saturating_p)
+               error ("both %<_Sat%> and %<double%> in "
+                      "declaration specifiers");
              else
                specs->typespec_word = cts_double;
              return specs;
+           case RID_DFLOAT32:
+           case RID_DFLOAT64:
+           case RID_DFLOAT128:
+             { 
+               const char *str;
+               if (i == RID_DFLOAT32)
+                 str = "_Decimal32";
+               else if (i == RID_DFLOAT64)
+                 str = "_Decimal64";
+               else
+                 str = "_Decimal128";
+               if (specs->long_long_p)
+                 error ("both %<long long%> and %<%s%> in "
+                        "declaration specifiers", str);
+               if (specs->long_p)
+                 error ("both %<long%> and %<%s%> in "
+                        "declaration specifiers", str);
+               else if (specs->short_p)
+                 error ("both %<short%> and %<%s%> in "
+                        "declaration specifiers", str);
+               else if (specs->signed_p)
+                 error ("both %<signed%> and %<%s%> in "
+                        "declaration specifiers", str);
+               else if (specs->unsigned_p)
+                 error ("both %<unsigned%> and %<%s%> in "
+                        "declaration specifiers", str);
+                else if (specs->complex_p)
+                  error ("both %<complex%> and %<%s%> in "
+                         "declaration specifiers", str);
+                else if (specs->saturating_p)
+                  error ("both %<_Sat%> and %<%s%> in "
+                         "declaration specifiers", str);
+               else if (i == RID_DFLOAT32)
+                 specs->typespec_word = cts_dfloat32;
+               else if (i == RID_DFLOAT64)
+                 specs->typespec_word = cts_dfloat64;
+               else
+                 specs->typespec_word = cts_dfloat128;
+             }
+             if (!targetm.decimal_float_supported_p ())
+               error ("decimal floating point not supported for this target");
+             pedwarn (input_location, OPT_pedantic, 
+                      "ISO C does not support decimal floating point");
+             return specs;
+           case RID_FRACT:
+           case RID_ACCUM:
+             {
+               const char *str;
+               if (i == RID_FRACT)
+                 str = "_Fract";
+               else
+                 str = "_Accum";
+                if (specs->complex_p)
+                  error ("both %<complex%> and %<%s%> in "
+                         "declaration specifiers", str);
+               else if (i == RID_FRACT)
+                   specs->typespec_word = cts_fract;
+               else
+                   specs->typespec_word = cts_accum;
+             }
+             if (!targetm.fixed_point_supported_p ())
+               error ("fixed-point types not supported for this target");
+             pedwarn (input_location, OPT_pedantic, 
+                      "ISO C does not support fixed-point types");
+             return specs;
            default:
              /* ObjC reserved word "id", handled below.  */
              break;
@@ -7278,7 +8081,18 @@ declspecs_add_type (struct c_declspecs *specs, struct c_typespec spec)
       if (spec.kind == ctsk_tagdef || spec.kind == ctsk_tagfirstref)
        specs->tag_defined_p = true;
       if (spec.kind == ctsk_typeof)
-       specs->typedef_p = true;
+       {
+         specs->typedef_p = true;
+         if (spec.expr)
+           {
+             if (specs->expr)
+               specs->expr = build2 (COMPOUND_EXPR, TREE_TYPE (spec.expr),
+                                     specs->expr, spec.expr);
+             else
+               specs->expr = spec.expr;
+             specs->expr_const_operands &= spec.expr_const_operands;
+           }
+       }
       specs->type = type;
     }
 
@@ -7298,8 +8112,9 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
   gcc_assert (TREE_CODE (scspec) == IDENTIFIER_NODE
              && C_IS_RESERVED_WORD (scspec));
   i = C_RID_CODE (scspec);
-  if (extra_warnings && specs->non_sc_seen_p)
-    warning (OPT_Wextra, "%qE is not at beginning of declaration", scspec);
+  if (specs->non_sc_seen_p)
+    warning (OPT_Wold_style_declaration, 
+             "%qE is not at beginning of declaration", scspec);
   switch (i)
     {
     case RID_INLINE:
@@ -7405,17 +8220,24 @@ finish_declspecs (struct c_declspecs *specs)
      "_Complex short" is equivalent to "_Complex short int".  */
   if (specs->typespec_word == cts_none)
     {
-      if (specs->long_p || specs->short_p
-         || specs->signed_p || specs->unsigned_p)
+      if (specs->saturating_p)
+       {
+         error ("%<_Sat%> is used without %<_Fract%> or %<_Accum%>");
+         if (!targetm.fixed_point_supported_p ())
+           error ("fixed-point types not supported for this target");
+         specs->typespec_word = cts_fract;
+       }
+      else if (specs->long_p || specs->short_p
+              || specs->signed_p || specs->unsigned_p)
        {
          specs->typespec_word = cts_int;
        }
       else if (specs->complex_p)
        {
          specs->typespec_word = cts_double;
-         if (pedantic)
-           pedwarn ("ISO C does not support plain %<complex%> meaning "
-                    "%<double complex%>");
+         pedwarn (input_location, OPT_pedantic, 
+                  "ISO C does not support plain %<complex%> meaning "
+                  "%<double complex%>");
        }
       else
        {
@@ -7458,8 +8280,8 @@ finish_declspecs (struct c_declspecs *specs)
        specs->type = char_type_node;
       if (specs->complex_p)
        {
-         if (pedantic)
-           pedwarn ("ISO C does not support complex integer types");
+         pedwarn (input_location, OPT_pedantic, 
+                  "ISO C does not support complex integer types");
          specs->type = build_complex_type (specs->type);
        }
       break;
@@ -7484,8 +8306,8 @@ finish_declspecs (struct c_declspecs *specs)
                       : integer_type_node);
       if (specs->complex_p)
        {
-         if (pedantic)
-           pedwarn ("ISO C does not support complex integer types");
+         pedwarn (input_location, OPT_pedantic, 
+                  "ISO C does not support complex integer types");
          specs->type = build_complex_type (specs->type);
        }
       break;
@@ -7512,6 +8334,104 @@ finish_declspecs (struct c_declspecs *specs)
                         : double_type_node);
        }
       break;
+    case cts_dfloat32:
+    case cts_dfloat64:
+    case cts_dfloat128:
+      gcc_assert (!specs->long_p && !specs->long_long_p && !specs->short_p
+                 && !specs->signed_p && !specs->unsigned_p && !specs->complex_p);
+      if (specs->typespec_word == cts_dfloat32)
+       specs->type = dfloat32_type_node;
+      else if (specs->typespec_word == cts_dfloat64)
+       specs->type = dfloat64_type_node;
+      else
+       specs->type = dfloat128_type_node;
+      break;
+    case cts_fract:
+      gcc_assert (!specs->complex_p);
+      if (!targetm.fixed_point_supported_p ())
+       specs->type = integer_type_node;
+      else if (specs->saturating_p)
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_long_fract_type_node
+                         : sat_long_long_fract_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_fract_type_node
+                         : sat_long_fract_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_short_fract_type_node
+                         : sat_short_fract_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_fract_type_node
+                         : sat_fract_type_node;
+       }
+      else
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_long_fract_type_node
+                         : long_long_fract_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_fract_type_node
+                         : long_fract_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_short_fract_type_node
+                         : short_fract_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? unsigned_fract_type_node
+                         : fract_type_node;
+       }
+      break;
+    case cts_accum:
+      gcc_assert (!specs->complex_p);
+      if (!targetm.fixed_point_supported_p ())
+       specs->type = integer_type_node;
+      else if (specs->saturating_p)
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_long_accum_type_node
+                         : sat_long_long_accum_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_long_accum_type_node
+                         : sat_long_accum_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_short_accum_type_node
+                         : sat_short_accum_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? sat_unsigned_accum_type_node
+                         : sat_accum_type_node;
+       }
+      else
+       {
+         if (specs->long_long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_long_accum_type_node
+                         : long_long_accum_type_node;
+         else if (specs->long_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_long_accum_type_node
+                         : long_accum_type_node;
+         else if (specs->short_p)
+           specs->type = specs->unsigned_p
+                         ? unsigned_short_accum_type_node
+                         : short_accum_type_node;
+         else
+           specs->type = specs->unsigned_p
+                         ? unsigned_accum_type_node
+                         : accum_type_node;
+       }
+      break;
     default:
       gcc_unreachable ();
     }
@@ -7519,38 +8439,19 @@ finish_declspecs (struct c_declspecs *specs)
   return specs;
 }
 
-/* Synthesize a function which calls all the global ctors or global
-   dtors in this file.  This is only used for targets which do not
-   support .ctors/.dtors sections.  FIXME: Migrate into cgraph.  */
-static void
-build_cdtor (int method_type, tree cdtors)
-{
-  tree body = 0;
-
-  if (!cdtors)
-    return;
-
-  for (; cdtors; cdtors = TREE_CHAIN (cdtors))
-    append_to_statement_list (build_function_call (TREE_VALUE (cdtors), 0),
-                             &body);
-
-  cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY);
-}
+/* A subroutine of c_write_global_declarations.  Perform final processing
+   on one file scope's declarations (or the external scope's declarations),
+   GLOBALS.  */
 
-/* Perform final processing on one file scope's declarations (or the
-   external scope's declarations), GLOBALS.  */
 static void
 c_write_global_declarations_1 (tree globals)
 {
-  size_t len = list_length (globals);
-  tree *vec = XNEWVEC (tree, len);
-  size_t i;
   tree decl;
+  bool reconsider;
 
   /* Process the decls in the order they were written.  */
-  for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
+  for (decl = globals; decl; decl = TREE_CHAIN (decl))
     {
-      vec[i] = decl;
       /* Check for used but undefined static functions using the C
         standard's definition of "used", and set TREE_NO_WARNING so
         that check_global_declarations doesn't repeat the check.  */
@@ -7560,21 +8461,44 @@ c_write_global_declarations_1 (tree globals)
          && !TREE_PUBLIC (decl)
          && C_DECL_USED (decl))
        {
-         pedwarn ("%q+F used but never defined", decl);
+         pedwarn (input_location, 0, "%q+F used but never defined", decl);
          TREE_NO_WARNING (decl) = 1;
        }
+
+      wrapup_global_declaration_1 (decl);
     }
 
-  wrapup_global_declarations (vec, len);
-  check_global_declarations (vec, len);
+  do
+    {
+      reconsider = false;
+      for (decl = globals; decl; decl = TREE_CHAIN (decl))
+       reconsider |= wrapup_global_declaration_2 (decl);
+    }
+  while (reconsider);
+
+  for (decl = globals; decl; decl = TREE_CHAIN (decl))
+    check_global_declaration_1 (decl);
+}
+
+/* A subroutine of c_write_global_declarations Emit debug information for each
+   of the declarations in GLOBALS.  */
+
+static void
+c_write_global_declarations_2 (tree globals)
+{
+  tree decl;
 
-  free (vec);
+  for (decl = globals; decl ; decl = TREE_CHAIN (decl))
+    debug_hooks->global_decl (decl);
 }
 
+/* Preserve the external declarations scope across a garbage collect.  */
+static GTY(()) tree ext_block;
+
 void
 c_write_global_declarations (void)
 {
-  tree ext_block, t;
+  tree t;
 
   /* We don't want to do this if generating a PCH.  */
   if (pch_file)
@@ -7582,7 +8506,7 @@ c_write_global_declarations (void)
 
   /* Don't waste time on further processing if -fsyntax-only or we've
      encountered errors.  */
-  if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in))
+  if (flag_syntax_only || errorcount || sorrycount)
     return;
 
   /* Close the external scope.  */
@@ -7590,32 +8514,40 @@ c_write_global_declarations (void)
   external_scope = 0;
   gcc_assert (!current_scope);
 
-  /* Process all file scopes in this compilation, and the external_scope,
-     through wrapup_global_declarations and check_global_declarations.  */
-  for (t = all_translation_units; t; t = TREE_CHAIN (t))
-    c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
   if (ext_block)
     {
       tree tmp = BLOCK_VARS (ext_block);
       int flags;
       FILE * stream = dump_begin (TDI_tu, &flags);
       if (stream && tmp)
-        {
-          dump_node (tmp, flags & ~TDF_SLIM, stream);
-          dump_end (TDI_tu, stream);
-        }
+       {
+         dump_node (tmp, flags & ~TDF_SLIM, stream);
+         dump_end (TDI_tu, stream);
+       }
     }
-  c_write_global_declarations_1 (BLOCK_VARS (ext_block));
 
-  /* Generate functions to call static constructors and destructors
-     for targets that do not support .ctors/.dtors sections.  These
-     functions have magic names which are detected by collect2.  */
-  build_cdtor ('I', static_ctors); static_ctors = 0;
-  build_cdtor ('D', static_dtors); static_dtors = 0;
+  /* Process all file scopes in this compilation, and the external_scope,
+     through wrapup_global_declarations and check_global_declarations.  */
+  for (t = all_translation_units; t; t = TREE_CHAIN (t))
+    c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
+  c_write_global_declarations_1 (BLOCK_VARS (ext_block));
 
   /* We're done parsing; proceed to optimize and emit assembly.
      FIXME: shouldn't be the front end's responsibility to call this.  */
   cgraph_optimize ();
+
+  /* After cgraph has had a chance to emit everything that's going to
+     be emitted, output debug information for globals.  */
+  if (errorcount == 0 && sorrycount == 0)
+    {
+      timevar_push (TV_SYMOUT);
+      for (t = all_translation_units; t; t = TREE_CHAIN (t))
+       c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t)));
+      c_write_global_declarations_2 (BLOCK_VARS (ext_block));
+      timevar_pop (TV_SYMOUT);
+    }
+
+  ext_block = NULL;
 }
 
 #include "gt-c-decl.h"