OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 8233187..d194012 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines shared by all languages that are variants of C.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002 Free Software Foundation, Inc.
+   2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -21,6 +21,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "intl.h"
 #include "tree.h"
 #include "flags.h"
 #include "toplev.h"
@@ -28,21 +31,19 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "c-pragma.h"
 #include "rtl.h"
 #include "ggc.h"
+#include "varray.h"
 #include "expr.h"
 #include "c-common.h"
-#include "tree-inline.h"
 #include "diagnostic.h"
 #include "tm_p.h"
 #include "obstack.h"
-#include "c-lex.h"
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
-#include "except.h"            /* For USING_SJLJ_EXCEPTIONS.  */
-cpp_reader *parse_in;          /* Declared in c-lex.h.  */
+#include "tree-inline.h"
+#include "c-tree.h"
 
-#undef WCHAR_TYPE_SIZE
-#define WCHAR_TYPE_SIZE TYPE_PRECISION (wchar_type_node)
+cpp_reader *parse_in;          /* Declared in c-pragma.h.  */
 
 /* We let tm.h override the types used here, to handle trivial differences
    such as the choice of unsigned int or long unsigned int for size_t.
@@ -58,6 +59,10 @@ cpp_reader *parse_in;                /* Declared in c-lex.h.  */
 #define WCHAR_TYPE "int"
 #endif
 
+/* WCHAR_TYPE gets overridden by -fshort-wchar.  */
+#define MODIFIED_WCHAR_TYPE \
+       (flag_short_wchar ? "short unsigned int" : WCHAR_TYPE)
+
 #ifndef PTRDIFF_TYPE
 #define PTRDIFF_TYPE "long int"
 #endif
@@ -182,13 +187,50 @@ enum c_language_kind c_language;
 
 tree c_global_trees[CTI_MAX];
 
+/* TRUE if a code represents a statement.  The front end init
+   langhook should take care of initialization of this array.  */
+
+bool statement_code_p[MAX_TREE_CODES];
+
+/* Nonzero if we can read a PCH file now.  */
+
+int allow_pch = 1;
+\f
+/* Switches common to the C front ends.  */
+
 /* Nonzero if prepreprocessing only.  */
+
 int flag_preprocess_only;
 
+/* Nonzero means don't output line number information.  */
+
+char flag_no_line_commands;
+
+/* Nonzero causes -E output not to be done, but directives such as
+   #define that have side effects are still obeyed.  */
+
+char flag_no_output;
+
+/* Nonzero means dump macros in some fashion.  */
+
+char flag_dump_macros;
+
+/* Nonzero means pass #include lines through to the output.  */
+
+char flag_dump_includes;
+
+/* The file name to which we should write a precompiled header, or
+   NULL if no header will be written in this compile.  */
+
+const char *pch_file;
+
 /* Nonzero if an ISO standard was selected.  It rejects macros in the
    user's namespace.  */
 int flag_iso;
 
+/* Nonzero whenever Objective-C functionality is being used.  */
+int flag_objc;
+
 /* Nonzero if -undef was given.  It suppresses target built-in macros
    and assertions.  */
 int flag_undef;
@@ -210,9 +252,173 @@ int flag_short_double;
 
 int flag_short_wchar;
 
-/* Nonzero means warn about use of multicharacter literals.  */
+/* Nonzero means allow Microsoft extensions without warnings or errors.  */
+int flag_ms_extensions;
+
+/* Nonzero means don't recognize the keyword `asm'.  */
+
+int flag_no_asm;
+
+/* Nonzero means give string constants the type `const char *', as mandated
+   by the standard.  */
+
+int flag_const_strings;
+
+/* Nonzero means to treat bitfields as signed unless they say `unsigned'.  */
+
+int flag_signed_bitfields = 1;
+int explicit_flag_signed_bitfields;
+
+/* Nonzero means warn about pointer casts that can drop a type qualifier
+   from the pointer target type.  */
+
+int warn_cast_qual;
+
+/* Warn about functions which might be candidates for format attributes.  */
+
+int warn_missing_format_attribute;
+
+/* Nonzero means warn about sizeof(function) or addition/subtraction
+   of function pointers.  */
+
+int warn_pointer_arith;
+
+/* Nonzero means warn for any global function def
+   without separate previous prototype decl.  */
+
+int warn_missing_prototypes;
+
+/* Warn if adding () is suggested.  */
+
+int warn_parentheses;
+
+/* Warn if initializer is not completely bracketed.  */
+
+int warn_missing_braces;
+
+/* Warn about comparison of signed and unsigned values.
+   If -1, neither -Wsign-compare nor -Wno-sign-compare has been specified
+   (in which case -Wextra gets to decide).  */
+
+int warn_sign_compare = -1;
+
+/* Nonzero means warn about usage of long long when `-pedantic'.  */
+
+int warn_long_long = 1;
+
+/* Nonzero means warn about deprecated conversion from string constant to
+   `char *'.  */
+
+int warn_write_strings;
+
+/* Nonzero means warn about multiple (redundant) decls for the same single
+   variable or function.  */
+
+int warn_redundant_decls;
+
+/* Warn about testing equality of floating point numbers.  */
+
+int warn_float_equal;
+
+/* Warn about a subscript that has type char.  */
+
+int warn_char_subscripts;
+
+/* Warn if a type conversion is done that might have confusing results.  */
+
+int warn_conversion;
+
+/* Warn about #pragma directives that are not recognized.  */      
+
+int warn_unknown_pragmas; /* Tri state variable.  */  
+
+/* Warn about format/argument anomalies in calls to formatted I/O functions
+   (*printf, *scanf, strftime, strfmon, etc.).  */
+
+int warn_format;
+
+/* Warn about Y2K problems with strftime formats.  */
+
+int warn_format_y2k;
+
+/* Warn about excess arguments to formats.  */
+
+int warn_format_extra_args;
+
+/* Warn about zero-length formats.  */
+
+int warn_format_zero_length;
+
+/* Warn about non-literal format arguments.  */
+
+int warn_format_nonliteral;
 
-int warn_multichar = 1;
+/* Warn about possible security problems with calls to format functions.  */
+
+int warn_format_security;
+
+
+/* C/ObjC language option variables.  */
+
+
+/* Nonzero means message about use of implicit function declarations;
+ 1 means warning; 2 means error.  */
+
+int mesg_implicit_function_declaration = -1;
+
+/* Nonzero means allow type mismatches in conditional expressions;
+   just make their values `void'.  */
+
+int flag_cond_mismatch;
+
+/* Nonzero means enable C89 Amendment 1 features.  */
+
+int flag_isoc94;
+
+/* Nonzero means use the ISO C99 dialect of C.  */
+
+int flag_isoc99;
+
+/* Nonzero means that we have builtin functions, and main is an int */
+
+int flag_hosted = 1;
+
+/* Nonzero means add default format_arg attributes for functions not
+   in ISO C.  */
+
+int flag_noniso_default_format_attributes = 1;
+
+/* Nonzero means warn when casting a function call to a type that does
+   not match the return type (e.g. (float)sqrt() or (anything*)malloc()
+   when there is no previous declaration of sqrt or malloc.  */
+
+int warn_bad_function_cast;
+
+/* Warn about traditional constructs whose meanings changed in ANSI C.  */
+
+int warn_traditional;
+
+/* Nonzero means warn for non-prototype function decls
+   or non-prototyped defs without previous prototype.  */
+
+int warn_strict_prototypes;
+
+/* Nonzero means warn for any global function def
+   without separate previous decl.  */
+
+int warn_missing_declarations;
+
+/* Nonzero means warn about declarations of objects not at
+   file-scope level and about *all* declarations of functions (whether
+   or static) not at file-scope level.  Note that we exclude
+   implicit function declarations.  To get warnings about those, use
+   -Wimplicit.  */
+
+int warn_nested_externs;
+
+/* Warn if main is suspicious.  */
+
+int warn_main;
 
 /* Nonzero means warn about possible violations of sequence point rules.  */
 
@@ -221,16 +427,264 @@ int warn_sequence_point;
 /* Nonzero means to warn about compile-time division by zero.  */
 int warn_div_by_zero = 1;
 
+/* Nonzero means warn about use of implicit int.  */
+
+int warn_implicit_int;
+
+/* Warn about NULL being passed to argument slots marked as requiring
+   non-NULL.  */ 
+      
+int warn_nonnull;
+
+
+/* ObjC language option variables.  */
+
+
+/* Open and close the file for outputting class declarations, if
+   requested (ObjC).  */
+
+int flag_gen_declaration;
+
+/* Generate code for GNU or NeXT runtime environment.  */
+
+#ifdef NEXT_OBJC_RUNTIME
+int flag_next_runtime = 1;
+#else
+int flag_next_runtime = 0;
+#endif
+
+/* Tells the compiler that this is a special run.  Do not perform any
+   compiling, instead we are to test some platform dependent features
+   and output a C header file with appropriate definitions.  */
+
+int print_struct_values;
+
+/* ???.  Undocumented.  */
+
+const char *constant_string_class_name;
+
+/* Warn if multiple methods are seen for the same selector, but with
+   different argument types.  Performs the check on the whole selector
+   table at the end of compilation.  */
+
+int warn_selector;
+
+/* Warn if a @selector() is found, and no method with that selector
+   has been previously declared.  The check is done on each
+   @selector() as soon as it is found - so it warns about forward
+   declarations.  */
+
+int warn_undeclared_selector;
+
+/* Warn if methods required by a protocol are not implemented in the 
+   class adopting it.  When turned off, methods inherited to that
+   class are also considered implemented.  */
+
+int warn_protocol = 1;
+
+
+/* C++ language option variables.  */
+
+
+/* Nonzero means don't recognize any extension keywords.  */
+
+int flag_no_gnu_keywords;
+
+/* Nonzero means do emit exported implementations of functions even if
+   they can be inlined.  */
+
+int flag_implement_inlines = 1;
+
+/* Nonzero means do emit exported implementations of templates, instead of
+   multiple static copies in each file that needs a definition.  */
+
+int flag_external_templates;
+
+/* Nonzero means that the decision to emit or not emit the implementation of a
+   template depends on where the template is instantiated, rather than where
+   it is defined.  */
+
+int flag_alt_external_templates;
+
+/* Nonzero means that implicit instantiations will be emitted if needed.  */
+
+int flag_implicit_templates = 1;
+
+/* Nonzero means that implicit instantiations of inline templates will be
+   emitted if needed, even if instantiations of non-inline templates
+   aren't.  */
+
+int flag_implicit_inline_templates = 1;
+
+/* Nonzero means generate separate instantiation control files and
+   juggle them at link time.  */
+
+int flag_use_repository;
+
+/* Nonzero if we want to issue diagnostics that the standard says are not
+   required.  */
+
+int flag_optional_diags = 1;
+
+/* Nonzero means we should attempt to elide constructors when possible.  */
+
+int flag_elide_constructors = 1;
+
+/* Nonzero means that member functions defined in class scope are
+   inline by default.  */
+
+int flag_default_inline = 1;
+
+/* Controls whether compiler generates 'type descriptor' that give
+   run-time type information.  */
+
+int flag_rtti = 1;
+
+/* Nonzero if we want to conserve space in the .o files.  We do this
+   by putting uninitialized data and runtime initialized data into
+   .common instead of .data at the expense of not flagging multiple
+   definitions.  */
+
+int flag_conserve_space;
+
+/* Nonzero if we want to obey access control semantics.  */
+
+int flag_access_control = 1;
+
+/* Nonzero if we want to check the return value of new and avoid calling
+   constructors if it is a null pointer.  */
+
+int flag_check_new;
+
+/* Nonzero if we want the new ISO rules for pushing a new scope for `for'
+   initialization variables.
+   0: Old rules, set by -fno-for-scope.
+   2: New ISO rules, set by -ffor-scope.
+   1: Try to implement new ISO rules, but with backup compatibility
+   (and warnings).  This is the default, for now.  */
+
+int flag_new_for_scope = 1;
+
+/* Nonzero if we want to emit defined symbols with common-like linkage as
+   weak symbols where possible, in order to conform to C++ semantics.
+   Otherwise, emit them as local symbols.  */
+
+int flag_weak = 1;
+
+/* Nonzero to use __cxa_atexit, rather than atexit, to register
+   destructors for local statics and global objects.  */
+
+int flag_use_cxa_atexit = DEFAULT_USE_CXA_ATEXIT;
+
+/* Nonzero means output .vtable_{entry,inherit} for use in doing vtable gc.  */
+
+int flag_vtable_gc;
+
+/* Nonzero means make the default pedwarns warnings instead of errors.
+   The value of this flag is ignored if -pedantic is specified.  */
+
+int flag_permissive;
+
+/* Nonzero means to implement standard semantics for exception
+   specifications, calling unexpected if an exception is thrown that
+   doesn't match the specification.  Zero means to treat them as
+   assertions and optimize accordingly, but not check them.  */
+
+int flag_enforce_eh_specs = 1;
+
+/*  The version of the C++ ABI in use.  The following values are
+    allowed:
+
+    0: The version of the ABI believed most conformant with the 
+       C++ ABI specification.  This ABI may change as bugs are
+       discovered and fixed.  Therefore, 0 will not necessarily
+       indicate the same ABI in different versions of G++.
+
+    1: The version of the ABI first used in G++ 3.2.
+
+    Additional positive integers will be assigned as new versions of
+    the ABI become the default version of the ABI.  */
+
+int flag_abi_version = 1;
+
+/* Nonzero means warn about things that will change when compiling
+   with an ABI-compliant compiler.  */
+
+int warn_abi = 0;
+
+/* Nonzero means warn about invalid uses of offsetof. */
+int warn_invalid_offsetof = 1;
+
+/* Nonzero means warn about implicit declarations.  */
+
+int warn_implicit = 1;
+
+/* Nonzero means warn when all ctors or dtors are private, and the class
+   has no friends.  */
+
+int warn_ctor_dtor_privacy = 0;
+
+/* Nonzero means warn in function declared in derived class has the
+   same name as a virtual in the base class, but fails to match the
+   type signature of any virtual function in the base class.  */
+
+int warn_overloaded_virtual;
+
+/* Nonzero means warn when declaring a class that has a non virtual
+   destructor, when it really ought to have a virtual one.  */
+
+int warn_nonvdtor;
+
+/* Nonzero means warn when the compiler will reorder code.  */
+
+int warn_reorder;
+
+/* Nonzero means warn when synthesis behavior differs from Cfront's.  */
+
+int warn_synth;
+
+/* Nonzero means warn when we convert a pointer to member function
+   into a pointer to (void or function).  */
+
+int warn_pmf2ptr = 1;
+
+/* Nonzero means warn about violation of some Effective C++ style rules.  */
+
+int warn_ecpp;
+
+/* Nonzero means warn where overload resolution chooses a promotion from
+   unsigned to signed over a conversion to an unsigned of the same size.  */
+
+int warn_sign_promo;
+
+/* Nonzero means warn when an old-style cast is used.  */
+
+int warn_old_style_cast;
+
+/* Nonzero means warn when non-templatized friend functions are
+   declared within a template */
+
+int warn_nontemplate_friend = 1;
+
+/* Nonzero means complain about deprecated features.  */
+
+int warn_deprecated = 1;
+
+/* Maximum template instantiation depth.  This limit is rather
+   arbitrary, but it exists to limit the time it takes to notice
+   infinite template instantiations.  */
+
+int max_tinst_depth = 500;
+
+
+
 /* The elements of `ridpointers' are identifier nodes for the reserved
    type names and storage classes.  It is indexed by a RID_... value.  */
 tree *ridpointers;
 
 tree (*make_fname_decl)                PARAMS ((tree, int));
 
-/* If non-NULL, the address of a language-specific function that
-   returns 1 for language-specific statement codes.  */
-int (*lang_statement_code_p)           PARAMS ((enum tree_code));
-
 /* If non-NULL, the address of a language-specific function that takes
    any action required right before expand_function_end is called.  */
 void (*lang_expand_function_end)       PARAMS ((void));
@@ -270,8 +724,7 @@ static int constant_fits_type_p             PARAMS ((tree, tree));
 typedef struct
 {
   int compstmt_count;
-  int line;
-  const char *file;
+  location_t locus;
   int needs_warning;
   tree if_stmt;
 } if_elt;
@@ -284,8 +737,6 @@ static int if_stack_space = 0;
 /* Stack pointer.  */
 static int if_stack_pointer = 0;
 
-static void cb_register_builtins PARAMS ((cpp_reader *));
-
 static tree handle_packed_attribute    PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_nocommon_attribute  PARAMS ((tree *, tree, tree, int,
@@ -322,6 +773,8 @@ static tree handle_alias_attribute  PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_visibility_attribute        PARAMS ((tree *, tree, tree, int,
                                                 bool *));
+static tree handle_tls_model_attribute PARAMS ((tree *, tree, tree, int,
+                                                bool *));
 static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
                                                             tree, int,
                                                             bool *));
@@ -335,8 +788,21 @@ static tree handle_deprecated_attribute    PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
                                                  bool *));
+static tree handle_nonnull_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_nothrow_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
+static tree handle_cleanup_attribute   PARAMS ((tree *, tree, tree, int,
+                                                bool *));
 static tree vector_size_helper PARAMS ((tree, tree));
 
+static void check_function_nonnull     PARAMS ((tree, tree));
+static void check_nonnull_arg          PARAMS ((void *, tree,
+                                                unsigned HOST_WIDE_INT));
+static bool nonnull_check_p            PARAMS ((tree, unsigned HOST_WIDE_INT));
+static bool get_nonnull_operand                PARAMS ((tree,
+                                                unsigned HOST_WIDE_INT *));
+
 /* Table of machine-independent attributes common to all C-like languages.  */
 const struct attribute_spec c_common_attribute_table[] =
 {
@@ -397,11 +863,20 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_vector_size_attribute },
   { "visibility",            1, 1, true,  false, false,
                              handle_visibility_attribute },
+  { "tls_model",             1, 1, true,  false, false,
+                             handle_tls_model_attribute },
+  { "nonnull",                0, -1, false, true, true,
+                             handle_nonnull_attribute },
+  { "nothrow",                0, 0, true,  false, false,
+                             handle_nothrow_attribute },
+  { "may_alias",             0, 0, false, true, false, NULL },
+  { "cleanup",               1, 1, true, false, false,
+                             handle_cleanup_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
 /* Give the specifications for the format attributes, used by C and all
-   descendents.  */
+   descendants.  */
 
 const struct attribute_spec c_common_format_attribute_table[] =
 {
@@ -445,8 +920,7 @@ c_expand_start_cond (cond, compstmt_count, if_stmt)
 
   /* Record this if statement.  */
   if_stack[if_stack_pointer].compstmt_count = compstmt_count;
-  if_stack[if_stack_pointer].file = input_filename;
-  if_stack[if_stack_pointer].line = lineno;
+  if_stack[if_stack_pointer].locus = input_location;
   if_stack[if_stack_pointer].needs_warning = 0;
   if_stack[if_stack_pointer].if_stmt = if_stmt;
   if_stack_pointer++;
@@ -469,9 +943,8 @@ c_expand_end_cond ()
 {
   if_stack_pointer--;
   if (if_stack[if_stack_pointer].needs_warning)
-    warning_with_file_and_line (if_stack[if_stack_pointer].file,
-                               if_stack[if_stack_pointer].line,
-                               "suggest explicit braces to avoid ambiguous `else'");
+    warning ("%Hsuggest explicit braces to avoid ambiguous `else'",
+             &if_stack[if_stack_pointer].locus);
   last_expr_type = NULL_TREE;
 }
 
@@ -589,13 +1062,18 @@ finish_fname_decls ()
   
   if (body)
     {
-      /* They were called into existence, so add to statement tree.  */
-      body = chainon (body,
-                     TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)));
-      body = build_stmt (COMPOUND_STMT, body);
-      
-      COMPOUND_STMT_NO_SCOPE (body) = 1;
-      TREE_CHAIN (DECL_SAVED_TREE (current_function_decl)) = body;
+      /* They were called into existence, so add to statement tree.  Add
+        the DECL_STMTs inside the outermost scope.  */
+      tree *p = &DECL_SAVED_TREE (current_function_decl);
+      /* Skip the dummy EXPR_STMT and any EH_SPEC_BLOCK.  */
+      while (TREE_CODE (*p) != COMPOUND_STMT)
+       p = &TREE_CHAIN (*p);
+      p = &COMPOUND_BODY (*p);
+      if (TREE_CODE (*p) == SCOPE_STMT)
+       p = &TREE_CHAIN (*p);
+
+      body = chainon (body, *p);
+      *p = body;
     }
   
   for (ix = 0; fname_vars[ix].decl; ix++)
@@ -618,7 +1096,7 @@ finish_fname_decls ()
   saved_function_name_decls = stack;
 }
 
-/* Return the text name of the current function, suitable prettified
+/* Return the text name of the current function, suitably prettified
    by PRETTY_P.  */
 
 const char *
@@ -676,6 +1154,13 @@ fname_decl (rid, id)
   if (!decl)
     {
       tree saved_last_tree = last_tree;
+      /* If a tree is built here, it would normally have the lineno of
+        the current statement.  Later this tree will be moved to the
+        beginning of the function and this line number will be wrong.
+        To avoid this problem set the lineno to 0 here; that prevents
+        it from appearing in the RTL.  */
+      int saved_lineno = input_line;
+      input_line = 0;
       
       decl = (*make_fname_decl) (id, fname_vars[ix].pretty);
       if (last_tree != saved_last_tree)
@@ -691,10 +1176,11 @@ fname_decl (rid, id)
                                                 saved_function_name_decls);
        }
       *fname_vars[ix].decl = decl;
+      input_line = saved_lineno;
     }
   if (!ix && !current_function_decl)
     pedwarn_with_decl (decl, "`%s' is not defined outside of function scope");
-  
+
   return decl;
 }
 
@@ -802,7 +1288,8 @@ combine_strings (strings)
        }
       else
        {
-         const int nzeros = (WCHAR_TYPE_SIZE / BITS_PER_UNIT) - 1;
+         const int nzeros = (TYPE_PRECISION (wchar_type_node)
+                             / BITS_PER_UNIT) - 1;
          int j, k;
 
          if (BYTES_BIG_ENDIAN)
@@ -1376,7 +1863,7 @@ verify_tree (x, pbefore_sp, pno_sp, writer)
     }
 }
 
-/* Try to warn for undefined behaviour in EXPR due to missing sequence
+/* Try to warn for undefined behavior in EXPR due to missing sequence
    points.  */
 
 static void
@@ -1563,38 +2050,37 @@ c_common_type_for_mode (mode, unsignedp)
   if (mode == TYPE_MODE (build_pointer_type (integer_type_node)))
     return build_pointer_type (integer_type_node);
 
-#ifdef VECTOR_MODE_SUPPORTED_P
-  if (VECTOR_MODE_SUPPORTED_P (mode))
-    {
-      switch (mode)
-       {
-       case V16QImode:
-         return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node;
-       case V8HImode:
-         return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node;
-       case V4SImode:
-         return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node;
-       case V2DImode:
-         return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node;
-       case V2SImode:
-         return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node;
-       case V4HImode:
-         return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node;
-       case V8QImode:
-         return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node;
-       case V16SFmode:
-         return V16SF_type_node;
-       case V4SFmode:
-         return V4SF_type_node;
-       case V2SFmode:
-         return V2SF_type_node;
-       case V2DFmode:
-         return V2DF_type_node;
-       default:
-         break;
-       }
+  switch (mode)
+    {
+    case V16QImode:
+      return unsignedp ? unsigned_V16QI_type_node : V16QI_type_node;
+    case V8HImode:
+      return unsignedp ? unsigned_V8HI_type_node : V8HI_type_node;
+    case V4SImode:
+      return unsignedp ? unsigned_V4SI_type_node : V4SI_type_node;
+    case V2DImode:
+      return unsignedp ? unsigned_V2DI_type_node : V2DI_type_node;
+    case V2SImode:
+      return unsignedp ? unsigned_V2SI_type_node : V2SI_type_node;
+    case V2HImode:
+      return unsignedp ? unsigned_V2HI_type_node : V2HI_type_node;
+    case V4HImode:
+      return unsignedp ? unsigned_V4HI_type_node : V4HI_type_node;
+    case V8QImode:
+      return unsignedp ? unsigned_V8QI_type_node : V8QI_type_node;
+    case V1DImode:
+      return unsignedp ? unsigned_V1DI_type_node : V1DI_type_node;
+    case V16SFmode:
+      return V16SF_type_node;
+    case V4SFmode:
+      return V4SF_type_node;
+    case V2SFmode:
+      return V2SF_type_node;
+    case V2DFmode:
+      return V2DF_type_node;
+    default:
+      break;
     }
-#endif
 
   return 0;
 }
@@ -2333,12 +2819,13 @@ c_common_truthvalue_conversion (expr)
     case ABS_EXPR:
     case FLOAT_EXPR:
     case FFS_EXPR:
-      /* These don't change whether an object is non-zero or zero.  */
+    case POPCOUNT_EXPR:
+      /* These don't change whether an object is nonzero or zero.  */
       return c_common_truthvalue_conversion (TREE_OPERAND (expr, 0));
 
     case LROTATE_EXPR:
     case RROTATE_EXPR:
-      /* These don't change whether an object is zero or non-zero, but
+      /* These don't change whether an object is zero or nonzero, but
         we can't ignore them if their second arg has side-effects.  */
       if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
        return build (COMPOUND_EXPR, boolean_type_node, TREE_OPERAND (expr, 1),
@@ -2422,7 +2909,7 @@ c_common_truthvalue_conversion (expr)
 \f
 static tree builtin_function_2 PARAMS ((const char *, const char *, tree, tree,
                                        int, enum built_in_class, int, int,
-                                       int));
+                                       tree));
 
 /* Make a variant type in the proper way for C/C++, propagating qualifiers
    down to the element type of an array.  */
@@ -2493,10 +2980,6 @@ c_common_get_alias_set (t)
 {
   tree u;
   
-  /* We know nothing about vector types */
-  if (TREE_CODE (t) == VECTOR_TYPE)
-    return 0;          
-  
   /* Permit type-punning when accessing a union, provided the access
      is directly through the union.  For example, this code does not
      permit taking the address of a union member and then storing
@@ -2510,17 +2993,21 @@ c_common_get_alias_set (t)
        && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
       return 0;
 
-  /* If this is a char *, the ANSI C standard says it can alias
-     anything.  Note that all references need do this.  */
-  if (TREE_CODE_CLASS (TREE_CODE (t)) == 'r'
-      && TREE_CODE (TREE_TYPE (t)) == INTEGER_TYPE
-      && TYPE_PRECISION (TREE_TYPE (t)) == TYPE_PRECISION (char_type_node))
-    return 0;
-
   /* That's all the expressions we handle specially.  */
   if (! TYPE_P (t))
     return -1;
 
+  /* The C standard guarantees that any object may be accessed via an
+     lvalue that has character type.  */
+  if (t == char_type_node
+      || t == signed_char_type_node
+      || t == unsigned_char_type_node)
+    return 0;
+
+  /* If it has the may_alias attribute, it can alias anything.  */
+  if (lookup_attribute ("may_alias", TYPE_ATTRIBUTES (t)))
+    return 0;
+
   /* The C standard specifically allows aliasing between signed and
      unsigned variants of the same type.  We treat the signed
      variant as canonical.  */
@@ -2567,36 +3054,66 @@ c_common_get_alias_set (t)
   return -1;
 }
 \f
-/* Implement the __alignof keyword: Return the minimum required
-   alignment of TYPE, measured in bytes.  */
-
+/* Compute the value of 'sizeof (TYPE)' or '__alignof__ (TYPE)', where the
+   second parameter indicates which OPERATOR is being applied.  The COMPLAIN
+   flag controls whether we should diagnose possibly ill-formed
+   constructs or not.  */
 tree
-c_alignof (type)
+c_sizeof_or_alignof_type (type, op, complain)
      tree type;
+     enum tree_code op;
+     int complain;
 {
-  enum tree_code code = TREE_CODE (type);
-  tree t;
-
-  /* In C++, sizeof applies to the referent.  Handle alignof the same way.  */
-  if (code == REFERENCE_TYPE)
+  const char *op_name;
+  tree value = NULL;
+  enum tree_code type_code = TREE_CODE (type);
+  
+  my_friendly_assert (op == SIZEOF_EXPR || op == ALIGNOF_EXPR, 20020720);
+  op_name = op == SIZEOF_EXPR ? "sizeof" : "__alignof__";
+  
+  if (type_code == FUNCTION_TYPE)
+    {
+      if (op == SIZEOF_EXPR)
+       {
+         if (complain && (pedantic || warn_pointer_arith))
+           pedwarn ("invalid application of `sizeof' to a function type");
+         value = size_one_node;
+       }
+      else
+       value = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
+    }
+  else if (type_code == VOID_TYPE || type_code == ERROR_MARK)
     {
-      type = TREE_TYPE (type);
-      code = TREE_CODE (type);
+      if (type_code == VOID_TYPE 
+         && complain && (pedantic || warn_pointer_arith))
+       pedwarn ("invalid application of `%s' to a void type", op_name);
+      value = size_one_node;
     }
-
-  if (code == FUNCTION_TYPE)
-    t = size_int (FUNCTION_BOUNDARY / BITS_PER_UNIT);
-  else if (code == VOID_TYPE || code == ERROR_MARK)
-    t = size_one_node;
   else if (!COMPLETE_TYPE_P (type))
     {
-      error ("__alignof__ applied to an incomplete type");
-      t = size_zero_node;
+      if (complain)
+       error ("invalid application of `%s' to an incomplete type", op_name);
+      value = size_zero_node;
     }
   else
-    t = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+    {
+      if (op == SIZEOF_EXPR)
+       /* Convert in case a char is more than one unit.  */
+       value = size_binop (CEIL_DIV_EXPR, TYPE_SIZE_UNIT (type),
+                           size_int (TYPE_PRECISION (char_type_node)
+                                     / BITS_PER_UNIT));
+      else
+       value = size_int (TYPE_ALIGN (type) / BITS_PER_UNIT);
+    }
 
-  return fold (build1 (NOP_EXPR, c_size_type_node, t));
+  /* VALUE will have an integer type with TYPE_IS_SIZETYPE set.
+     TYPE_IS_SIZETYPE means that certain things (like overflow) will
+     never happen.  However, this node should really have type
+     `size_t', which is just a typedef for an ordinary integer type.  */
+  value = fold (build1 (NOP_EXPR, size_type_node, value));
+  my_friendly_assert (!TYPE_IS_SIZETYPE (TREE_TYPE (value)), 20001021);
+  
+  return value;
 }
 
 /* Implement the __alignof keyword: Return the minimum required
@@ -2644,28 +3161,53 @@ c_alignof_expr (expr)
   else
     return c_alignof (TREE_TYPE (expr));
 
-  return fold (build1 (NOP_EXPR, c_size_type_node, t));
+  return fold (build1 (NOP_EXPR, size_type_node, t));
 }
 \f
-/* Build tree nodes and builtin functions common to both C and C++ language
-   frontends.  */
+/* Handle C and C++ default attributes.  */
 
-void
-c_common_nodes_and_builtins ()
+enum built_in_attribute
 {
-  enum builtin_type 
-  {
-#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
-#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
-#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
-#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
-#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
-#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
-#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
-#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
-#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
-#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
-#include "builtin-types.def"
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum.  */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+  ATTR_LAST
+};
+
+static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
+
+/* Build tree nodes and builtin functions common to both C and C++ language
+   frontends.  */
+
+void
+c_common_nodes_and_builtins ()
+{
+  enum builtin_type 
+  {
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
 #undef DEF_PRIMITIVE_TYPE
 #undef DEF_FUNCTION_TYPE_0
 #undef DEF_FUNCTION_TYPE_1
@@ -2675,6 +3217,7 @@ c_common_nodes_and_builtins ()
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
 #undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_POINTER_TYPE
     BT_LAST
   };
@@ -2763,10 +3306,10 @@ c_common_nodes_and_builtins ()
   /* `unsigned long' is the standard type for sizeof.
      Note that stddef.h uses `unsigned long',
      and this must agree, even if long and int are the same size.  */
-  c_size_type_node =
+  size_type_node =
     TREE_TYPE (identifier_global_value (get_identifier (SIZE_TYPE)));
-  signed_size_type_node = c_common_signed_type (c_size_type_node);
-  set_sizetype (c_size_type_node);
+  signed_size_type_node = c_common_signed_type (size_type_node);
+  set_sizetype (size_type_node);
 
   build_common_tree_nodes_2 (flag_short_double);
 
@@ -2869,12 +3412,8 @@ c_common_nodes_and_builtins ()
     = build_pointer_type (build_qualified_type
                          (char_type_node, TYPE_QUAL_CONST));
 
-  (*targetm.init_builtins) ();
-
   /* This is special for C++ so functions can be overloaded.  */
-  wchar_type_node = get_identifier (flag_short_wchar
-                                   ? "short unsigned int"
-                                   : WCHAR_TYPE);
+  wchar_type_node = get_identifier (MODIFIED_WCHAR_TYPE);
   wchar_type_node = TREE_TYPE (identifier_global_value (wchar_type_node));
   wchar_type_size = TYPE_PRECISION (wchar_type_node);
   if (c_language == clk_cplusplus)
@@ -2996,6 +3535,19 @@ c_common_nodes_and_builtins ()
                  tree_cons (NULL_TREE,                         \
                             builtin_types[(int) ARG2],         \
                             NULL_TREE)));
+
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3)                \
+   builtin_types[(int) ENUM]                                           \
+    = build_function_type                                              \
+      (builtin_types[(int) RETURN],                                    \
+       tree_cons (NULL_TREE,                                           \
+                 builtin_types[(int) ARG1],                            \
+                 tree_cons (NULL_TREE,                                 \
+                            builtin_types[(int) ARG2],                 \
+                            tree_cons (NULL_TREE,                      \
+                                       builtin_types[(int) ARG3],      \
+                                       NULL_TREE))));
+
 #define DEF_POINTER_TYPE(ENUM, TYPE)                   \
   builtin_types[(int) ENUM]                            \
     = build_pointer_type (builtin_types[(int) TYPE]);
@@ -3007,10 +3559,15 @@ c_common_nodes_and_builtins ()
 #undef DEF_FUNCTION_TYPE_4
 #undef DEF_FUNCTION_TYPE_VAR_0
 #undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
 #undef DEF_POINTER_TYPE
 
-#define DEF_BUILTIN(ENUM, NAME, CLASS,                                 \
-                    TYPE, LIBTYPE, BOTH_P, FALLBACK_P, NONANSI_P)      \
+  if (!c_attrs_initialized)
+    c_init_attributes ();
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE,                  \
+                   BOTH_P, FALLBACK_P, NONANSI_P, ATTRS, IMPLICIT)     \
   if (NAME)                                                            \
     {                                                                  \
       tree decl;                                                       \
@@ -3023,7 +3580,8 @@ c_common_nodes_and_builtins ()
                                 CLASS,                                 \
                                 (FALLBACK_P                            \
                                  ? (NAME + strlen ("__builtin_"))      \
-                                 : NULL));                             \
+                                 : NULL),                              \
+                                built_in_attributes[(int) ATTRS]);     \
       else                                                             \
        decl = builtin_function_2 (NAME,                                \
                                   NAME + strlen ("__builtin_"),        \
@@ -3033,34 +3591,16 @@ c_common_nodes_and_builtins ()
                                   CLASS,                               \
                                   FALLBACK_P,                          \
                                   NONANSI_P,                           \
-                                  /*noreturn_p=*/0);                   \
+                                  built_in_attributes[(int) ATTRS]);   \
                                                                        \
       built_in_decls[(int) ENUM] = decl;                               \
+      if (IMPLICIT)                                                    \
+        implicit_built_in_decls[(int) ENUM] = decl;                    \
     }                                                                  
 #include "builtins.def"
 #undef DEF_BUILTIN
 
-  /* Declare _exit and _Exit just to mark them as non-returning.  */
-  builtin_function_2 (NULL, "_exit", NULL_TREE, 
-                     builtin_types[BT_FN_VOID_INT],
-                     0, NOT_BUILT_IN, 0, 1, 1);
-  builtin_function_2 (NULL, "_Exit", NULL_TREE, 
-                     builtin_types[BT_FN_VOID_INT],
-                     0, NOT_BUILT_IN, 0, !flag_isoc99, 1);
-
-  /* Declare these functions non-returning
-     to avoid spurious "control drops through" warnings.  */
-  builtin_function_2 (NULL, "abort",
-                     NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? builtin_types[BT_FN_VOID]
-                                 : builtin_types[BT_FN_VOID_VAR]),
-                     0, NOT_BUILT_IN, 0, 0, 1);
-
-  builtin_function_2 (NULL, "exit",
-                     NULL_TREE, ((c_language == clk_cplusplus)
-                                 ? builtin_types[BT_FN_VOID_INT]
-                                 : builtin_types[BT_FN_VOID_VAR]),
-                     0, NOT_BUILT_IN, 0, 0, 1);
+  (*targetm.init_builtins) ();
 
   main_identifier_node = get_identifier ("main");
 }
@@ -3129,15 +3669,15 @@ builtin_function_disabled_p (name)
    conflicts with headers.  FUNCTION_CODE and CLASS are as for
    builtin_function.  If LIBRARY_NAME_P is nonzero, NAME is passed as
    the LIBRARY_NAME parameter to builtin_function when declaring BUILTIN_NAME.
-   If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name; if
-   NORETURN_P is nonzero, the function is marked as non-returning.
+   If NONANSI_P is nonzero, the name NAME is treated as a non-ANSI name;
+   ATTRS is the tree list representing the builtin's function attributes.
    Returns the declaration of BUILTIN_NAME, if any, otherwise
    the declaration of NAME.  Does not declare NAME if flag_no_builtin,
    or if NONANSI_P and flag_no_nonansi_builtin.  */
 
 static tree
 builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
-                   class, library_name_p, nonansi_p, noreturn_p)
+                   class, library_name_p, nonansi_p, attrs)
      const char *builtin_name;
      const char *name;
      tree builtin_type;
@@ -3146,32 +3686,19 @@ builtin_function_2 (builtin_name, name, builtin_type, type, function_code,
      enum built_in_class class;
      int library_name_p;
      int nonansi_p;
-     int noreturn_p;
+     tree attrs;
 {
   tree bdecl = NULL_TREE;
   tree decl = NULL_TREE;
+
   if (builtin_name != 0)
-    {
-      bdecl = builtin_function (builtin_name, builtin_type, function_code,
-                               class, library_name_p ? name : NULL);
-      if (noreturn_p)
-       {
-         TREE_THIS_VOLATILE (bdecl) = 1;
-         TREE_SIDE_EFFECTS (bdecl) = 1;
-       }
-    }
+    bdecl = builtin_function (builtin_name, builtin_type, function_code,
+                             class, library_name_p ? name : NULL, attrs);
+
   if (name != 0 && !flag_no_builtin && !builtin_function_disabled_p (name)
       && !(nonansi_p && flag_no_nonansi_builtin))
-    {
-      decl = builtin_function (name, type, function_code, class, NULL);
-      if (nonansi_p)
-       DECL_BUILT_IN_NONANSI (decl) = 1;
-      if (noreturn_p)
-       {
-         TREE_THIS_VOLATILE (decl) = 1;
-         TREE_SIDE_EFFECTS (decl) = 1;
-       }
-    }
+    decl = builtin_function (name, type, function_code, class, NULL, attrs);
+
   return (bdecl != 0 ? bdecl : decl);
 }
 \f
@@ -3395,41 +3922,6 @@ expand_tree_builtin (function, params, coerced_params)
   return NULL_TREE;
 }
 
-/* Returns non-zero if CODE is the code for a statement.  */
-
-int
-statement_code_p (code)
-     enum tree_code code;
-{
-  switch (code)
-    {
-    case CLEANUP_STMT:
-    case EXPR_STMT:
-    case COMPOUND_STMT:
-    case DECL_STMT:
-    case IF_STMT:
-    case FOR_STMT:
-    case WHILE_STMT:
-    case DO_STMT:
-    case RETURN_STMT:
-    case BREAK_STMT:
-    case CONTINUE_STMT:
-    case SCOPE_STMT:
-    case SWITCH_STMT:
-    case GOTO_STMT:
-    case LABEL_STMT:
-    case ASM_STMT:
-    case FILE_STMT:
-    case CASE_LABEL:
-      return 1;
-
-    default:
-      if (lang_statement_code_p)
-       return (*lang_statement_code_p) (code);
-      return 0;
-    }
-}
-
 /* Walk the statement tree, rooted at *tp.  Apply FUNC to all the
    sub-trees of *TP in a pre-order traversal.  FUNC is called with the
    DATA and the address of each sub-tree.  If FUNC returns a non-NULL
@@ -3465,7 +3957,7 @@ walk_stmt_tree (tp, func, data)
     return NULL_TREE;
 
   /* Skip subtrees below non-statement nodes.  */
-  if (!statement_code_p (TREE_CODE (*tp)))
+  if (!STATEMENT_CODE_P (TREE_CODE (*tp)))
     return NULL_TREE;
 
   /* Call the function.  */
@@ -3479,7 +3971,7 @@ walk_stmt_tree (tp, func, data)
   /* FUNC may have modified the tree, recheck that we're looking at a
      statement node.  */
   code = TREE_CODE (*tp);
-  if (!statement_code_p (code))
+  if (!STATEMENT_CODE_P (code))
     return NULL_TREE;
 
   /* Visit the subtrees unless FUNC decided that there was nothing
@@ -3680,8 +4172,8 @@ c_add_case_label (cases, cond, low_value, high_value)
   return case_label;
 }
 
-/* Finish an expression taking the address of LABEL.  Returns an
-   expression for the address.  */
+/* Finish an expression taking the address of LABEL (an
+   IDENTIFIER_NODE).  Returns an expression for the address.  */
 
 tree 
 finish_label_address_expr (label)
@@ -3697,6 +4189,9 @@ finish_label_address_expr (label)
        pedwarn ("ISO C forbids taking the address of a label");
     }
 
+  if (label == error_mark_node)
+    return error_mark_node;
+
   label = lookup_label (label);
   if (label == NULL_TREE)
     result = null_pointer_node;
@@ -3713,41 +4208,6 @@ finish_label_address_expr (label)
   return result;
 }
 
-/* Mark P (a stmt_tree) for GC.  The use of a `void *' for the
-   parameter allows this function to be used as a GC-marking
-   function.  */
-
-void
-mark_stmt_tree (p)
-     void *p;
-{
-  stmt_tree st = (stmt_tree) p;
-
-  ggc_mark_tree (st->x_last_stmt);
-  ggc_mark_tree (st->x_last_expr_type);
-}
-
-/* Mark LD for GC.  */
-
-void
-c_mark_lang_decl (c)
-     struct c_lang_decl *c ATTRIBUTE_UNUSED;
-{
-}
-
-/* Mark F for GC.  */
-
-void
-mark_c_language_function (f)
-     struct language_function *f;
-{
-  if (!f)
-    return;
-
-  mark_stmt_tree (&f->x_stmt_tree);
-  ggc_mark_tree (f->x_scope_stmt_stack);
-}
-
 /* Hook used by expand_expr to expand language-specific tree codes.  */
 
 rtx
@@ -3764,6 +4224,7 @@ c_expand_expr (exp, target, tmode, modifier)
        tree rtl_expr;
        rtx result;
        bool preserve_result = false;
+       bool return_target = false;
 
        /* Since expand_expr_stmt calls free_temp_slots after every
           expression statement, we must call push_temp_slots here.
@@ -3791,8 +4252,20 @@ c_expand_expr (exp, target, tmode, modifier)
            if (TREE_CODE (last) == SCOPE_STMT
                && TREE_CODE (expr) == EXPR_STMT)
              {
-               TREE_ADDRESSABLE (expr) = 1;
-               preserve_result = true;
+               if (target && TREE_CODE (EXPR_STMT_EXPR (expr)) == VAR_DECL
+                   && DECL_RTL_IF_SET (EXPR_STMT_EXPR (expr)) == target)
+                 /* If the last expression is a variable whose RTL is the
+                    same as our target, just return the target; if it
+                    isn't valid expanding the decl would produce different
+                    RTL, and store_expr would try to do a copy.  */
+                 return_target = true;
+               else
+                 {
+                   /* Otherwise, note that we want the value from the last
+                      expression.  */
+                   TREE_ADDRESSABLE (expr) = 1;
+                   preserve_result = true;
+                 }
              }
          }
 
@@ -3800,7 +4273,9 @@ c_expand_expr (exp, target, tmode, modifier)
        expand_end_stmt_expr (rtl_expr);
 
        result = expand_expr (rtl_expr, target, tmode, modifier);
-       if (preserve_result && GET_CODE (result) == MEM)
+       if (return_target)
+         result = target;
+       else if (preserve_result && GET_CODE (result) == MEM)
          {
            if (GET_MODE (result) != BLKmode)
              result = copy_to_reg (result);
@@ -3871,7 +4346,7 @@ c_safe_from_p (target, exp)
     }
 
   /* For any statement, we must follow the statement-chain.  */
-  if (statement_code_p (TREE_CODE (exp)) && TREE_CHAIN (exp))
+  if (STATEMENT_CODE_P (TREE_CODE (exp)) && TREE_CHAIN (exp))
     return safe_from_p (target, TREE_CHAIN (exp), /*top_p=*/0);
 
   /* Assume everything else is safe.  */
@@ -4017,9 +4492,9 @@ c_expand_builtin_printf (arglist, target, tmode, modifier, ignore, unlocked)
      int unlocked;
 {
   tree fn_putchar = unlocked ?
-    built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : built_in_decls[BUILT_IN_PUTCHAR];
+    implicit_built_in_decls[BUILT_IN_PUTCHAR_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTCHAR];
   tree fn_puts = unlocked ?
-    built_in_decls[BUILT_IN_PUTS_UNLOCKED] : built_in_decls[BUILT_IN_PUTS];
+    implicit_built_in_decls[BUILT_IN_PUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_PUTS];
   tree fn, format_arg, stripped_string;
 
   /* If the return value is used, or the replacement _DECL isn't
@@ -4121,9 +4596,9 @@ c_expand_builtin_fprintf (arglist, target, tmode, modifier, ignore, unlocked)
      int unlocked;
 {
   tree fn_fputc = unlocked ?
-    built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : built_in_decls[BUILT_IN_FPUTC];
+    implicit_built_in_decls[BUILT_IN_FPUTC_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTC];
   tree fn_fputs = unlocked ?
-    built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : built_in_decls[BUILT_IN_FPUTS];
+    implicit_built_in_decls[BUILT_IN_FPUTS_UNLOCKED] : implicit_built_in_decls[BUILT_IN_FPUTS];
   tree fn, format_arg, stripped_string;
 
   /* If the return value is used, or the replacement _DECL isn't
@@ -4233,208 +4708,15 @@ boolean_increment (code, arg)
   return val;
 }
 \f
-/* Handle C and C++ default attributes.  */
-
-enum built_in_attribute
-{
-#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
-#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
-#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
-#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
-#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum.  */
-#include "builtin-attrs.def"
-#undef DEF_ATTR_NULL_TREE
-#undef DEF_ATTR_INT
-#undef DEF_ATTR_IDENT
-#undef DEF_ATTR_TREE_LIST
-#undef DEF_FN_ATTR
-  ATTR_LAST
-};
-
-static tree built_in_attributes[(int) ATTR_LAST];
-
-static bool c_attrs_initialized = false;
-
-static void c_init_attributes PARAMS ((void));
-
-/* Common initialization before parsing options.  */
-void
-c_common_init_options (lang)
-     enum c_language_kind lang;
-{
-  c_language = lang;
-  parse_in = cpp_create_reader (lang == clk_c ? CLK_GNUC89:
-                               lang == clk_cplusplus ? CLK_GNUCXX: CLK_OBJC);
-
-  /* Mark as "unspecified" (see c_common_post_options).  */
-  flag_bounds_check = -1;
-}
-
-/* Post-switch processing.  */
+/* Built-in macros for stddef.h, that require macros defined in this
+   file.  */
 void
-c_common_post_options ()
+c_stddef_cpp_builtins()
 {
-  cpp_post_options (parse_in);
-
-  flag_inline_trees = 1;
-
-  /* Use tree inlining if possible.  Function instrumentation is only
-     done in the RTL level, so we disable tree inlining.  */
-  if (! flag_instrument_function_entry_exit)
-    {
-      if (!flag_no_inline)
-       flag_no_inline = 1;
-      if (flag_inline_functions)
-       {
-         flag_inline_trees = 2;
-         flag_inline_functions = 0;
-       }
-    }
-
-  /* If still "unspecified", make it match -fbounded-pointers.  */
-  if (flag_bounds_check == -1)
-    flag_bounds_check = flag_bounded_pointers;
-
-  /* Special format checking options don't work without -Wformat; warn if
-     they are used.  */
-  if (warn_format_y2k && !warn_format)
-    warning ("-Wformat-y2k ignored without -Wformat");
-  if (warn_format_extra_args && !warn_format)
-    warning ("-Wformat-extra-args ignored without -Wformat");
-  if (warn_format_nonliteral && !warn_format)
-    warning ("-Wformat-nonliteral ignored without -Wformat");
-  if (warn_format_security && !warn_format)
-    warning ("-Wformat-security ignored without -Wformat");
-  if (warn_missing_format_attribute && !warn_format)
-    warning ("-Wmissing-format-attribute ignored without -Wformat");
-}
-
-/* Hook that registers front end and target-specific built-ins.  */
-static void
-cb_register_builtins (pfile)
-     cpp_reader *pfile;
-{
-  /* -undef turns off target-specific built-ins.  */
-  if (flag_undef)
-    return;
-
-  if (c_language == clk_cplusplus)
-    {
-      if (SUPPORTS_ONE_ONLY)
-       cpp_define (pfile, "__GXX_WEAK__");
-      else
-       cpp_define (pfile, "__GXX_WEAK__=0");
-    }
-
-  /* libgcc needs to know this.  */
-  if (USING_SJLJ_EXCEPTIONS)
-    cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");
-
-  /* A straightforward target hook doesn't work, because of problems
-     linking that hook's body when part of non-C front ends.  */
-  TARGET_CPU_CPP_BUILTINS ();
-  TARGET_OS_CPP_BUILTINS ();
-}
-
-/* Pass an object-like macro.  If it doesn't lie in the user's
-   namespace, defines it unconditionally.  Otherwise define a version
-   with two leading underscores, and another version with two leading
-   and trailing underscores, and define the original only if an ISO
-   standard was not nominated.
-
-   e.g. passing "unix" defines "__unix", "__unix__" and possibly
-   "unix".  Passing "_mips" defines "__mips", "__mips__" and possibly
-   "_mips".  */
-void
-builtin_define_std (macro)
-     const char *macro;
-{
-  size_t len = strlen (macro);
-  char *buff = alloca (len + 5);
-  char *p = buff + 2;
-  char *q = p + len;
-
-  /* prepend __ (or maybe just _) if in user's namespace.  */
-  memcpy (p, macro, len + 1);
-  if (*p != '_')
-    *--p = '_';
-  if (p[1] != '_' && !ISUPPER (p[1]))
-    *--p = '_';
-  cpp_define (parse_in, p);
-
-  /* If it was in user's namespace...  */
-  if (p != buff + 2)
-    {
-      /* Define the original macro if permitted.  */
-      if (!flag_iso)
-       cpp_define (parse_in, macro);
-
-      /* Define the macro with leading and following __.  */
-      if (q[-1] != '_')
-       *q++ = '_';
-      if (q[-2] != '_')
-       *q++ = '_';
-      *q = '\0';
-      cpp_define (parse_in, p);
-    }
-}
-
-/* Front end initialization common to C, ObjC and C++.  */
-const char *
-c_common_init (filename)
-     const char *filename;
-{
-  cpp_options *options = cpp_get_options (parse_in);
-
-  /* Set up preprocessor arithmetic.  Must be done after call to
-     c_common_nodes_and_builtins for wchar_type_node to be good.  */
-  options->char_precision = TYPE_PRECISION (char_type_node);
-  options->int_precision = TYPE_PRECISION (integer_type_node);
-  options->wchar_precision = TYPE_PRECISION (wchar_type_node);
-  options->unsigned_wchar = TREE_UNSIGNED (wchar_type_node);
-  /* This can be uncommented when 1) This all happens before
-     cpp_post_options() (needed for __CHAR_UNSIGNED__ builtin), which
-     in turn requires wchat_type_node to be set up properly by then,
-     and 2) tradcpp is integrated, so that the preprocessors don't
-     need to handle the command-line options and the specs in gcc.c
-     can be updated.
-
-     options->unsigned_char = !flag_signed_char; */
-
-  options->warn_multichar = warn_multichar;
-
-  /* Register preprocessor built-ins before calls to
-     cpp_main_file.  */
-  cpp_get_callbacks (parse_in)->register_builtins = cb_register_builtins;
-
-  /* NULL is passed up to toplev.c and we exit quickly.  */
-  if (flag_preprocess_only)
-    {
-      cpp_preprocess_file (parse_in);
-      return NULL;
-    }
-
-  /* Do this before initializing pragmas, as then cpplib's hash table
-     has been set up.  */
-  filename = init_c_lex (filename);
-
-  init_pragma ();
-
-  if (!c_attrs_initialized)
-    c_init_attributes ();
-
-  return filename;
-}
-
-/* Common finish hook for the C, ObjC and C++ front ends.  */
-void
-c_common_finish ()
-{
-  cpp_finish (parse_in);
-
-  /* For performance, avoid tearing down cpplib's internal structures.
-     Call cpp_errors () instead of cpp_destroy ().  */
-  errorcount += cpp_errors (parse_in);
+  builtin_define_with_value ("__SIZE_TYPE__", SIZE_TYPE, 0);
+  builtin_define_with_value ("__PTRDIFF_TYPE__", PTRDIFF_TYPE, 0);
+  builtin_define_with_value ("__WCHAR_TYPE__", MODIFIED_WCHAR_TYPE, 0);
+  builtin_define_with_value ("__WINT_TYPE__", WINT_TYPE, 0);
 }
 
 static void
@@ -4459,7 +4741,6 @@ c_init_attributes ()
 #undef DEF_ATTR_IDENT
 #undef DEF_ATTR_TREE_LIST
 #undef DEF_FN_ATTR
-  ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST);
   c_attrs_initialized = true;
 }
 
@@ -4490,17 +4771,22 @@ c_common_insert_default_attributes (decl)
 #undef DEF_FN_ATTR
 }
 
-/* Output a -Wshadow warning MSGID about NAME, an IDENTIFIER_NODE, and
-   additionally give the location of the previous declaration DECL.  */
+/* Output a -Wshadow warning MSGCODE about NAME, and give the location
+   of the previous declaration DECL.  */
 void
-shadow_warning (msgid, name, decl)
-     const char *msgid;
-     tree name, decl;
+shadow_warning (msgcode, name, decl)
+     enum sw_kind msgcode;
+     const char *name;
+     tree decl;
 {
-  warning ("declaration of `%s' shadows %s", IDENTIFIER_POINTER (name), msgid);
-  warning_with_file_and_line (DECL_SOURCE_FILE (decl),
-                             DECL_SOURCE_LINE (decl),
-                             "shadowed declaration is here");
+  static const char *const msgs[] = {
+    /* SW_PARAM  */ N_("declaration of \"%s\" shadows a parameter"),
+    /* SW_LOCAL  */ N_("declaration of \"%s\" shadows a previous local"),
+    /* SW_GLOBAL */ N_("declaration of \"%s\" shadows a global declaration")
+  };
+
+  warning (msgs[msgcode], name);
+  warning ("%Hshadowed declaration is here", &DECL_SOURCE_LOCATION (decl));
 }
 
 /* Attribute handlers common to C front ends.  */
@@ -4670,16 +4956,19 @@ handle_always_inline_attribute (node, name, args, flags, no_add_attrs)
    struct attribute_spec.handler.  */
 
 static tree
-handle_used_attribute (node, name, args, flags, no_add_attrs)
-     tree *node;
+handle_used_attribute (pnode, name, args, flags, no_add_attrs)
+     tree *pnode;
      tree name;
      tree args ATTRIBUTE_UNUSED;
      int flags ATTRIBUTE_UNUSED;
      bool *no_add_attrs;
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL)
-    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (*node))
-      = TREE_USED (*node) = 1;
+  tree node = *pnode;
+
+  if (TREE_CODE (node) == FUNCTION_DECL
+      || (TREE_CODE (node) == VAR_DECL && TREE_STATIC (node)))
+    TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (node))
+      = TREE_USED (node) = 1;
   else
     {
       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
@@ -4888,6 +5177,7 @@ handle_mode_attribute (node, name, args, flags, no_add_attrs)
       int len = strlen (p);
       enum machine_mode mode = VOIDmode;
       tree typefm;
+      tree ptr_type;
 
       if (len > 4 && p[0] == '_' && p[1] == '_'
          && p[len - 1] == '_' && p[len - 2] == '_')
@@ -4917,9 +5207,38 @@ handle_mode_attribute (node, name, args, flags, no_add_attrs)
       else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
                     (mode, TREE_UNSIGNED (type))))
        error ("no data type for mode `%s'", p);
+      else if ((TREE_CODE (type) == POINTER_TYPE
+               || TREE_CODE (type) == REFERENCE_TYPE)
+              && !(*targetm.valid_pointer_mode) (mode))
+       error ("invalid pointer mode `%s'", p);
       else
-       *node = typefm;
-        /* No need to layout the type here.  The caller should do this.  */
+       {
+         /* If this is a vector, make sure we either have hardware
+            support, or we can emulate it.  */
+         if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+              || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+             && !vector_mode_valid_p (mode))
+           {
+             error ("unable to emulate '%s'", GET_MODE_NAME (mode));
+             return NULL_TREE;
+           }
+
+         if (TREE_CODE (type) == POINTER_TYPE)
+           {
+             ptr_type = build_pointer_type_for_mode (TREE_TYPE (type),
+                                                     mode);
+             *node = ptr_type;
+           }
+         else if (TREE_CODE (type) == REFERENCE_TYPE)
+           {
+             ptr_type = build_reference_type_for_mode (TREE_TYPE (type),
+                                                       mode);
+             *node = ptr_type;
+           }
+         else
+         *node = typefm;
+         /* No need to layout the type here.  The caller should do this.  */
+       }
     }
 
   return NULL_TREE;
@@ -5163,9 +5482,53 @@ handle_visibility_attribute (node, name, args, flags, no_add_attrs)
        }
       if (strcmp (TREE_STRING_POINTER (id), "hidden")
          && strcmp (TREE_STRING_POINTER (id), "protected")
-         && strcmp (TREE_STRING_POINTER (id), "internal"))
+         && strcmp (TREE_STRING_POINTER (id), "internal")
+         && strcmp (TREE_STRING_POINTER (id), "default"))
        {
-         error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\"");
+         error ("visibility arg must be one of \"default\", \"hidden\", \"protected\" or \"internal\"");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle an "tls_model" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_tls_model_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (! DECL_THREAD_LOCAL (decl))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+       {
+         error ("tls_model arg not a string");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      if (strcmp (TREE_STRING_POINTER (id), "local-exec")
+         && strcmp (TREE_STRING_POINTER (id), "initial-exec")
+         && strcmp (TREE_STRING_POINTER (id), "local-dynamic")
+         && strcmp (TREE_STRING_POINTER (id), "global-dynamic"))
+       {
+         error ("tls_model arg must be one of \"local-exec\", \"initial-exec\", \"local-dynamic\" or \"global-dynamic\"");
          *no_add_attrs = true;
          return NULL_TREE;
        }
@@ -5352,7 +5715,7 @@ handle_deprecated_attribute (node, name, args, flags, no_add_attrs)
    The normal mechanism to prevent duplicates is to use type_hash_canon, but
    since we want to distinguish types that are essentially identical (except
    for their debug representation), we use a local list here.  */
-static tree vector_type_node_list = 0;
+static GTY(()) tree vector_type_node_list = 0;
 
 /* Handle a "vector_size" attribute; arguments as in
    struct attribute_spec.handler.  */
@@ -5464,6 +5827,16 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
 
       new_type = build_type_copy (new_type);
 
+      /* If this is a vector, make sure we either have hardware
+         support, or we can emulate it.  */
+      if ((GET_MODE_CLASS (mode) == MODE_VECTOR_INT
+          || GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
+         && !vector_mode_valid_p (mode))
+       {
+         error ("unable to emulate '%s'", GET_MODE_NAME (mode));
+         return NULL_TREE;
+       }
+
       /* Set the debug information here, because this is the only
         place where we know the underlying type for a vector made
         with vector_size.  For debugging purposes we pretend a vector
@@ -5527,3 +5900,354 @@ vector_size_helper (type, bottom)
 
   return outer;
 }
+
+/* Handle the "nonnull" attribute.  */
+static tree
+handle_nonnull_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name ATTRIBUTE_UNUSED;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree type = *node;
+  unsigned HOST_WIDE_INT attr_arg_num;
+
+  /* If no arguments are specified, all pointer arguments should be
+     non-null.  Verify a full prototype is given so that the arguments
+     will have the correct types when we actually check them later.  */
+  if (! args)
+    {
+      if (! TYPE_ARG_TYPES (type))
+       {
+         error ("nonnull attribute without arguments on a non-prototype");
+          *no_add_attrs = true;
+       }
+      return NULL_TREE;
+    }
+
+  /* Argument list specified.  Verify that each argument number references
+     a pointer argument.  */
+  for (attr_arg_num = 1; args; args = TREE_CHAIN (args))
+    {
+      tree argument;
+      unsigned HOST_WIDE_INT arg_num, ck_num;
+
+      if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+       {
+         error ("nonnull argument has invalid operand number (arg %lu)",
+                (unsigned long) attr_arg_num);
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+
+      argument = TYPE_ARG_TYPES (type);
+      if (argument)
+       {
+         for (ck_num = 1; ; ck_num++)
+           {
+             if (! argument || ck_num == arg_num)
+               break;
+             argument = TREE_CHAIN (argument);
+           }
+
+          if (! argument
+             || TREE_CODE (TREE_VALUE (argument)) == VOID_TYPE)
+           {
+             error ("nonnull argument with out-of-range operand number (arg %lu, operand %lu)",
+                    (unsigned long) attr_arg_num, (unsigned long) arg_num);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+
+          if (TREE_CODE (TREE_VALUE (argument)) != POINTER_TYPE)
+           {
+             error ("nonnull argument references non-pointer operand (arg %lu, operand %lu)",
+                  (unsigned long) attr_arg_num, (unsigned long) arg_num);
+             *no_add_attrs = true;
+             return NULL_TREE;
+           }
+       }
+    }
+
+  return NULL_TREE;
+}
+
+/* Check the argument list of a function call for null in argument slots
+   that are marked as requiring a non-null pointer argument.  */
+
+static void
+check_function_nonnull (attrs, params)
+     tree attrs;
+     tree params;
+{
+  tree a, args, param;
+  int param_num;
+
+  for (a = attrs; a; a = TREE_CHAIN (a))
+    {
+      if (is_attribute_p ("nonnull", TREE_PURPOSE (a)))
+       {
+          args = TREE_VALUE (a);
+
+          /* Walk the argument list.  If we encounter an argument number we
+             should check for non-null, do it.  If the attribute has no args,
+             then every pointer argument is checked (in which case the check
+            for pointer type is done in check_nonnull_arg).  */
+          for (param = params, param_num = 1; ;
+               param_num++, param = TREE_CHAIN (param))
+            {
+              if (! param)
+               break;
+              if (! args || nonnull_check_p (args, param_num))
+               check_function_arguments_recurse (check_nonnull_arg, NULL,
+                                                 TREE_VALUE (param),
+                                                 param_num);
+            }
+       }
+    }
+}
+
+/* Helper for check_function_nonnull; given a list of operands which
+   must be non-null in ARGS, determine if operand PARAM_NUM should be
+   checked.  */
+
+static bool
+nonnull_check_p (args, param_num)
+     tree args;
+     unsigned HOST_WIDE_INT param_num;
+{
+  unsigned HOST_WIDE_INT arg_num;
+
+  for (; args; args = TREE_CHAIN (args))
+    {
+      if (! get_nonnull_operand (TREE_VALUE (args), &arg_num))
+        abort ();
+
+      if (arg_num == param_num)
+       return true;
+    }
+  return false;
+}
+
+/* Check that the function argument PARAM (which is operand number
+   PARAM_NUM) is non-null.  This is called by check_function_nonnull
+   via check_function_arguments_recurse.  */
+
+static void
+check_nonnull_arg (ctx, param, param_num)
+     void *ctx ATTRIBUTE_UNUSED;
+     tree param;
+     unsigned HOST_WIDE_INT param_num;
+{
+  /* Just skip checking the argument if it's not a pointer.  This can
+     happen if the "nonnull" attribute was given without an operand
+     list (which means to check every pointer argument).  */
+
+  if (TREE_CODE (TREE_TYPE (param)) != POINTER_TYPE)
+    return;
+
+  if (integer_zerop (param))
+    warning ("null argument where non-null required (arg %lu)",
+             (unsigned long) param_num);
+}
+
+/* Helper for nonnull attribute handling; fetch the operand number
+   from the attribute argument list.  */
+
+static bool
+get_nonnull_operand (arg_num_expr, valp)
+     tree arg_num_expr;
+     unsigned HOST_WIDE_INT *valp;
+{
+  /* Strip any conversions from the arg number and verify they
+     are constants.  */
+  while (TREE_CODE (arg_num_expr) == NOP_EXPR
+        || TREE_CODE (arg_num_expr) == CONVERT_EXPR
+        || TREE_CODE (arg_num_expr) == NON_LVALUE_EXPR)
+    arg_num_expr = TREE_OPERAND (arg_num_expr, 0);
+
+  if (TREE_CODE (arg_num_expr) != INTEGER_CST
+      || TREE_INT_CST_HIGH (arg_num_expr) != 0)
+    return false;
+
+  *valp = TREE_INT_CST_LOW (arg_num_expr);
+  return true;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_nothrow_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_NOTHROW (*node) = 1;
+  /* ??? TODO: Support types.  */
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "cleanup" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_cleanup_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+  tree cleanup_id, cleanup_decl;
+
+  /* ??? Could perhaps support cleanups on TREE_STATIC, much like we do
+     for global destructors in C++.  This requires infrastructure that
+     we don't have generically at the moment.  It's also not a feature
+     we'd be missing too much, since we do have attribute constructor.  */
+  if (TREE_CODE (decl) != VAR_DECL || TREE_STATIC (decl))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* Verify that the argument is a function in scope.  */
+  /* ??? We could support pointers to functions here as well, if
+     that was considered desirable.  */
+  cleanup_id = TREE_VALUE (args);
+  if (TREE_CODE (cleanup_id) != IDENTIFIER_NODE)
+    {
+      error ("cleanup arg not an identifier");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  cleanup_decl = lookup_name (cleanup_id);
+  if (!cleanup_decl || TREE_CODE (cleanup_decl) != FUNCTION_DECL)
+    {
+      error ("cleanup arg not a function");
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+
+  /* That the function has proper type is checked with the 
+     eventual call to build_function_call.  */
+
+  return NULL_TREE;
+}
+\f
+/* Check for valid arguments being passed to a function.  */
+void
+check_function_arguments (attrs, params)
+     tree attrs;
+     tree params;
+{
+  /* Check for null being passed in a pointer argument that must be
+     non-null.  We also need to do this if format checking is enabled.  */
+
+  if (warn_nonnull)
+    check_function_nonnull (attrs, params);
+
+  /* Check for errors in format strings.  */
+
+  if (warn_format)
+    check_function_format (NULL, attrs, params);
+}
+
+/* Generic argument checking recursion routine.  PARAM is the argument to
+   be checked.  PARAM_NUM is the number of the argument.  CALLBACK is invoked
+   once the argument is resolved.  CTX is context for the callback.  */
+void
+check_function_arguments_recurse (callback, ctx, param, param_num)
+     void (*callback) PARAMS ((void *, tree, unsigned HOST_WIDE_INT));
+     void *ctx;
+     tree param;
+     unsigned HOST_WIDE_INT param_num;
+{
+  if (TREE_CODE (param) == NOP_EXPR)
+    {
+      /* Strip coercion.  */
+      check_function_arguments_recurse (callback, ctx,
+                                       TREE_OPERAND (param, 0), param_num);
+      return;
+    }
+
+  if (TREE_CODE (param) == CALL_EXPR)
+    {
+      tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (param, 0)));
+      tree attrs;
+      bool found_format_arg = false;
+
+      /* See if this is a call to a known internationalization function
+        that modifies a format arg.  Such a function may have multiple
+        format_arg attributes (for example, ngettext).  */
+
+      for (attrs = TYPE_ATTRIBUTES (type);
+          attrs;
+          attrs = TREE_CHAIN (attrs))
+       if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs)))
+         {
+           tree inner_args;
+           tree format_num_expr;
+           int format_num;
+           int i;
+
+           /* Extract the argument number, which was previously checked
+              to be valid.  */
+           format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
+           while (TREE_CODE (format_num_expr) == NOP_EXPR
+                  || TREE_CODE (format_num_expr) == CONVERT_EXPR
+                  || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
+             format_num_expr = TREE_OPERAND (format_num_expr, 0);
+
+           if (TREE_CODE (format_num_expr) != INTEGER_CST
+               || TREE_INT_CST_HIGH (format_num_expr) != 0)
+             abort ();
+
+           format_num = TREE_INT_CST_LOW (format_num_expr);
+
+           for (inner_args = TREE_OPERAND (param, 1), i = 1;
+                inner_args != 0;
+                inner_args = TREE_CHAIN (inner_args), i++)
+             if (i == format_num)
+               {
+                 check_function_arguments_recurse (callback, ctx,
+                                                   TREE_VALUE (inner_args),
+                                                   param_num);
+                 found_format_arg = true;
+                 break;
+               }
+         }
+
+      /* If we found a format_arg attribute and did a recursive check,
+        we are done with checking this argument.  Otherwise, we continue
+        and this will be considered a non-literal.  */
+      if (found_format_arg)
+       return;
+    }
+
+  if (TREE_CODE (param) == COND_EXPR)
+    {
+      /* Check both halves of the conditional expression.  */
+      check_function_arguments_recurse (callback, ctx,
+                                       TREE_OPERAND (param, 1), param_num);
+      check_function_arguments_recurse (callback, ctx,
+                                       TREE_OPERAND (param, 2), param_num);
+      return;
+    }
+
+  (*callback) (ctx, param, param_num);
+}
+
+#include "gt-c-common.h"