OSDN Git Service

* c-common.c: Add support for __attribute__((nothrow)) to specify
[pf3gnuchains/gcc-fork.git] / gcc / c-common.c
index 8233187..aeb6a2e 100644 (file)
@@ -34,15 +34,12 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #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.  */
 
-#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 +55,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
@@ -82,6 +83,14 @@ cpp_reader *parse_in;                /* Declared in c-lex.h.  */
                        : "long long unsigned int"))
 #endif
 
+#ifndef STDC_0_IN_SYSTEM_HEADERS
+#define STDC_0_IN_SYSTEM_HEADERS 0
+#endif
+
+#ifndef REGISTER_PREFIX
+#define REGISTER_PREFIX ""
+#endif
+
 /* The variant of the C language being processed.  */
 
 enum c_language_kind c_language;
@@ -221,6 +230,11 @@ int warn_sequence_point;
 /* Nonzero means to warn about compile-time division by zero.  */
 int warn_div_by_zero = 1;
 
+/* Warn about NULL being passed to argument slots marked as requiring
+   non-NULL.  */ 
+      
+int warn_nonnull;
+
 /* The elements of `ridpointers' are identifier nodes for the reserved
    type names and storage classes.  It is indexed by a RID_... value.  */
 tree *ridpointers;
@@ -335,8 +349,22 @@ 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 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 *));
+void builtin_define_std PARAMS ((const char *));
+static void builtin_define_with_value PARAMS ((const char *, const char *,
+                                              int));
+
 /* Table of machine-independent attributes common to all C-like languages.  */
 const struct attribute_spec c_common_attribute_table[] =
 {
@@ -397,6 +425,10 @@ const struct attribute_spec c_common_attribute_table[] =
                              handle_vector_size_attribute },
   { "visibility",            1, 1, true,  false, false,
                              handle_visibility_attribute },
+  { "nonnull",                0, -1, false, true, true,
+                             handle_nonnull_attribute },
+  { "nothrow",                0, 0, true,  false, false,
+                             handle_nothrow_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -802,7 +834,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)
@@ -2872,9 +2905,7 @@ c_common_nodes_and_builtins ()
   (*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)
@@ -4263,8 +4294,10 @@ 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);
+  parse_in = cpp_create_reader (lang == clk_c || lang == clk_objective_c
+                               ? CLK_GNUC89 : CLK_GNUCXX);
+  if (lang == clk_objective_c)
+    cpp_get_options (parse_in)->objc = 1;
 
   /* Mark as "unspecified" (see c_common_post_options).  */
   flag_bounds_check = -1;
@@ -4301,12 +4334,18 @@ c_common_post_options ()
     warning ("-Wformat-y2k ignored without -Wformat");
   if (warn_format_extra_args && !warn_format)
     warning ("-Wformat-extra-args ignored without -Wformat");
+  if (warn_format_zero_length && !warn_format)
+    warning ("-Wformat-zero-length 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");
+
+  /* If an error has occurred in cpplib, note it so we fail
+     immediately.  */
+  errorcount += cpp_errors (parse_in);
 }
 
 /* Hook that registers front end and target-specific built-ins.  */
@@ -4321,7 +4360,7 @@ cb_register_builtins (pfile)
   if (c_language == clk_cplusplus)
     {
       if (SUPPORTS_ONE_ONLY)
-       cpp_define (pfile, "__GXX_WEAK__");
+       cpp_define (pfile, "__GXX_WEAK__=1");
       else
        cpp_define (pfile, "__GXX_WEAK__=0");
     }
@@ -4330,8 +4369,47 @@ cb_register_builtins (pfile)
   if (USING_SJLJ_EXCEPTIONS)
     cpp_define (pfile, "__USING_SJLJ_EXCEPTIONS__");
 
+  /* stddef.h needs to know these.  */
+  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);
+
+  /* For use in assembly language.  */
+  builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0);
+  builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0);
+
+  /* Misc.  */
+  builtin_define_with_value ("__VERSION__", version_string, 1);
+
+  /* Other target-independent built-ins determined by command-line
+     options.  */
+  if (optimize_size)
+    cpp_define (pfile, "__OPTIMIZE_SIZE__");
+  if (optimize)
+    cpp_define (pfile, "__OPTIMIZE__");
+
+  if (flag_hosted)
+    cpp_define (pfile, "__STDC_HOSTED__=1");
+  else
+    cpp_define (pfile, "__STDC_HOSTED__=0");
+
+  if (fast_math_flags_set_p ())
+    cpp_define (pfile, "__FAST_MATH__");
+  if (flag_no_inline)
+    cpp_define (pfile, "__NO_INLINE__");
+
+  if (flag_iso)
+    cpp_define (pfile, "__STRICT_ANSI__");
+
+  if (!flag_signed_char)
+    cpp_define (pfile, "__CHAR_UNSIGNED__");
+
   /* A straightforward target hook doesn't work, because of problems
      linking that hook's body when part of non-C front ends.  */
+# define preprocessing_asm_p() (cpp_get_options (pfile)->lang == CLK_ASM)
+# define builtin_define(TXT) cpp_define (pfile, TXT)
+# define builtin_assert(TXT) cpp_assert (pfile, TXT)
   TARGET_CPU_CPP_BUILTINS ();
   TARGET_OS_CPP_BUILTINS ();
 }
@@ -4365,10 +4443,6 @@ builtin_define_std (macro)
   /* 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++ = '_';
@@ -4376,9 +4450,39 @@ builtin_define_std (macro)
        *q++ = '_';
       *q = '\0';
       cpp_define (parse_in, p);
+
+      /* Finally, define the original macro if permitted.  */
+      if (!flag_iso)
+       cpp_define (parse_in, macro);
     }
 }
 
+/* Pass an object-like macro and a value to define it to.  The third
+   parameter says whether or not to turn the value into a string
+   constant.  */
+static void
+builtin_define_with_value (macro, expansion, is_str)
+     const char *macro;
+     const char *expansion;
+     int is_str;
+{
+  char *buf;
+  size_t mlen = strlen (macro);
+  size_t elen = strlen (expansion);
+  size_t extra = 2;  /* space for an = and a NUL */
+
+  if (is_str)
+    extra += 2;  /* space for two quote marks */
+
+  buf = alloca (mlen + elen + extra);
+  if (is_str)
+    sprintf (buf, "%s=\"%s\"", macro, expansion);
+  else
+    sprintf (buf, "%s=%s", macro, expansion);
+
+  cpp_define (parse_in, buf);
+}
+
 /* Front end initialization common to C, ObjC and C++.  */
 const char *
 c_common_init (filename)
@@ -4388,20 +4492,14 @@ c_common_init (filename)
 
   /* Set up preprocessor arithmetic.  Must be done after call to
      c_common_nodes_and_builtins for wchar_type_node to be good.  */
+  options->precision = TYPE_PRECISION (intmax_type_node);
   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->unsigned_char = !flag_signed_char;
   options->warn_multichar = warn_multichar;
+  options->stdc_0_in_system_headers = STDC_0_IN_SYSTEM_HEADERS;
 
   /* Register preprocessor built-ins before calls to
      cpp_main_file.  */
@@ -5527,3 +5625,303 @@ 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.  Veryify 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;
+}
+\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);
+}