]> gcc.gnu.org Git - gcc.git/commitdiff
c-common.c (warn_nonnull): Declare.
authorJason Thorpe <thorpej@wasabisystems.com>
Thu, 23 May 2002 15:48:05 +0000 (15:48 +0000)
committerJason Thorpe <thorpej@gcc.gnu.org>
Thu, 23 May 2002 15:48:05 +0000 (15:48 +0000)
* c-common.c (warn_nonnull): Declare.
(c_common_attribute_table): Add "nonnull" attribute.
(handle_nonnull_attribute, check_function_nonnull, nonnull_check_p,
check_nonnull_arg, get_nonnull_operand, check_function_arguments,
check_function_arguments_recurse): New functions.
* c-common.h (warn_nonnull): Declare extern.
(check_function_arguments, check_function_arguments_recurse): New
prototypes.
* c-decl.c (c_decode_option): Add -Wnonnull option.
* c-format.c (set_Wformat): Set warn_nonnull if enabling
format checking.
(format_check_context): New structure.
(check_format_info_recurse): Remove recursion and rename to...
(check_format_arg): ...this.  Update comment.
(check_format_info): Use check_function_arguments_recurse.
* c-typeck.c (build_function_call): Call check_function_arguments
instead of check_function_format.
* doc/extend.texi: Document "nonnull" attribute.
* doc/invoke.texi: Docuemnt -Wnonnull option.
* testsuite/gcc.dg/nonnull-1.c: New test.
* testsuite/gcc.dg/nonnull-2.c: New test.

From-SVN: r53790

gcc/ChangeLog
gcc/c-common.c
gcc/c-common.h
gcc/c-decl.c
gcc/c-format.c
gcc/c-typeck.c
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/testsuite/gcc.dg/nonnull-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/nonnull-2.c [new file with mode: 0644]

index d7334a9cb7ae8e18225fea6816e1e9b182c6768d..be5370c4eae899d56f4761453d38cd8dd11e0691 100644 (file)
@@ -1,3 +1,27 @@
+2002-05-23  Jason Thorpe  <thorpej@wasabisystems.com>
+
+       * c-common.c (warn_nonnull): Declare.
+       (c_common_attribute_table): Add "nonnull" attribute.
+       (handle_nonnull_attribute, check_function_nonnull, nonnull_check_p,
+       check_nonnull_arg, get_nonnull_operand, check_function_arguments,
+       check_function_arguments_recurse): New functions.
+       * c-common.h (warn_nonnull): Declare extern.
+       (check_function_arguments, check_function_arguments_recurse): New
+       prototypes.
+       * c-decl.c (c_decode_option): Add -Wnonnull option.
+       * c-format.c (set_Wformat): Set warn_nonnull if enabling
+       format checking.
+       (format_check_context): New structure.
+       (check_format_info_recurse): Remove recursion and rename to...
+       (check_format_arg): ...this.  Update comment.
+       (check_format_info): Use check_function_arguments_recurse.
+       * c-typeck.c (build_function_call): Call check_function_arguments
+       instead of check_function_format.
+       * doc/extend.texi: Document "nonnull" attribute.
+       * doc/invoke.texi: Docuemnt -Wnonnull option.
+       * testsuite/gcc.dg/nonnull-1.c: New test.
+       * testsuite/gcc.dg/nonnull-2.c: New test.
+
 2002-05-23  David S. Miller  <davem@redhat.com>
 
        * basic-block.h (CLEANUP_NO_INSN_DEL): Define it.
index 900b5e9bb542c759c019d52c08f2be89698397c0..006a831cf3c2fb23276d47a58a0b3cbae7573d8e 100644 (file)
@@ -230,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;
@@ -344,8 +349,17 @@ 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 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[] =
 {
@@ -406,6 +420,8 @@ 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 },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -5599,3 +5615,280 @@ 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;
+}
+\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);
+}
index 320d03d8253dc70886ed68cd886e4d78d12a1234..834d78520dc0a5f3bed6a1dc050e3160eb4a57a6 100644 (file)
@@ -426,6 +426,11 @@ extern int warn_format_nonliteral;
 
 extern int warn_format_security;
 
+/* Warn about NULL being passed to argument slots marked as requiring
+   non-NULL.  */
+
+extern int warn_nonnull;
+
 /* Warn about possible violations of sequence point rules.  */
 
 extern int warn_sequence_point;
@@ -522,6 +527,12 @@ extern const char *fname_as_string         PARAMS ((int));
 extern tree fname_decl                         PARAMS ((unsigned, tree));
 extern const char *fname_string                        PARAMS ((unsigned));
 
+extern void check_function_arguments           PARAMS ((tree, tree));
+extern void check_function_arguments_recurse   PARAMS ((void (*) (void *,
+                                                                  tree,
+                                                                  unsigned HOST_WIDE_INT),
+                                                        void *, tree,
+                                                        unsigned HOST_WIDE_INT));
 extern void check_function_format              PARAMS ((int *, tree, tree));
 extern void set_Wformat                                PARAMS ((int));
 extern tree handle_format_attribute            PARAMS ((tree *, tree, tree,
index 0890a2a58c42a8e6d8612e2d48a200f08355a144..3dcb05540ec7c712ee28c372dca21c46defc8425 100644 (file)
@@ -489,6 +489,7 @@ c_decode_option (argc, argv)
     { "missing-prototypes", &warn_missing_prototypes },
     { "multichar", &warn_multichar },
     { "nested-externs", &warn_nested_externs },
+    { "nonnull", &warn_nonnull },
     { "parentheses", &warn_parentheses },
     { "pointer-arith", &warn_pointer_arith },
     { "redundant-decls", &warn_redundant_decls },
index dc73f4d69f1671e34e3be465d6a0a5c929364c1f..b3640c50190e502100152be7d1b331346a4c9d84 100644 (file)
@@ -71,6 +71,9 @@ set_Wformat (setting)
       warn_format_nonliteral = setting;
       warn_format_security = setting;
     }
+  /* Make sure not to disable -Wnonnull if -Wformat=0 is specified.  */
+  if (setting)
+    warn_nonnull = setting;
 }
 
 \f
@@ -900,10 +903,16 @@ typedef struct
   int number_other;
 } format_check_results;
 
+typedef struct
+{
+  format_check_results *res;
+  function_format_info *info;
+  tree params;
+  int *status;
+} format_check_context;
+
 static void check_format_info  PARAMS ((int *, function_format_info *, tree));
-static void check_format_info_recurse PARAMS ((int *, format_check_results *,
-                                              function_format_info *, tree,
-                                              tree, unsigned HOST_WIDE_INT));
+static void check_format_arg   PARAMS ((void *, tree, unsigned HOST_WIDE_INT));
 static void check_format_info_main PARAMS ((int *, format_check_results *,
                                            function_format_info *,
                                            const char *, int, tree,
@@ -1294,6 +1303,7 @@ check_format_info (status, info, params)
      function_format_info *info;
      tree params;
 {
+  format_check_context format_ctx;
   unsigned HOST_WIDE_INT arg_num;
   tree format_tree;
   format_check_results res;
@@ -1320,7 +1330,13 @@ check_format_info (status, info, params)
   res.number_unterminated = 0;
   res.number_other = 0;
 
-  check_format_info_recurse (status, &res, info, format_tree, params, arg_num);
+  format_ctx.res = &res;
+  format_ctx.info = info;
+  format_ctx.params = params;
+  format_ctx.status = status;
+
+  check_function_arguments_recurse (check_format_arg, &format_ctx,
+                                   format_tree, arg_num);
 
   if (res.number_non_literal > 0)
     {
@@ -1377,110 +1393,34 @@ check_format_info (status, info, params)
     status_warning (status, "unterminated format string");
 }
 
-
-/* Recursively check a call to a format function.  FORMAT_TREE is the
-   format parameter, which may be a conditional expression in which
-   both halves should be checked.  ARG_NUM is the number of the
-   format argument; PARAMS points just after it in the argument list.  */
+/* Callback from check_function_arguments_recurse to check a
+   format string.  FORMAT_TREE is the format parameter.  ARG_NUM
+   is the number of the format argument.  CTX points to a
+   format_check_context.  */
 
 static void
-check_format_info_recurse (status, res, info, format_tree, params, arg_num)
-     int *status;
-     format_check_results *res;
-     function_format_info *info;
+check_format_arg (ctx, format_tree, arg_num)
+     void *ctx;
      tree format_tree;
-     tree params;
      unsigned HOST_WIDE_INT arg_num;
 {
+  format_check_context *format_ctx = ctx;
+  format_check_results *res = format_ctx->res;
+  function_format_info *info = format_ctx->info;
+  tree params = format_ctx->params;
+  int *status = format_ctx->status;
+
   int format_length;
   HOST_WIDE_INT offset;
   const char *format_chars;
   tree array_size = 0;
   tree array_init;
 
-  if (TREE_CODE (format_tree) == NOP_EXPR)
-    {
-      /* Strip coercion.  */
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 0), params,
-                                arg_num);
-      return;
-    }
-
-  if (TREE_CODE (format_tree) == CALL_EXPR)
-    {
-      tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (format_tree, 0)));
-      tree attrs;
-      bool found_format_arg = false;
-
-      /* See if this is a call to a known internationalization function
-        that modifies the 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 (format_tree, 1), i = 1;
-                inner_args != 0;
-                inner_args = TREE_CHAIN (inner_args), i++)
-             if (i == format_num)
-               {
-                 check_format_info_recurse (status, res, info,
-                                            TREE_VALUE (inner_args), params,
-                                            arg_num);
-                 found_format_arg = true;
-                 break;
-               }
-         }
-
-      /* If we found a format_arg attribute and did a recursive check,
-        we are done with checking this format string.  Otherwise, we
-        continue and this will count as a non-literal format string.  */
-      if (found_format_arg)
-       return;
-    }
-
-  if (TREE_CODE (format_tree) == COND_EXPR)
-    {
-      /* Check both halves of the conditional expression.  */
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 1), params,
-                                arg_num);
-      check_format_info_recurse (status, res, info,
-                                TREE_OPERAND (format_tree, 2), params,
-                                arg_num);
-      return;
-    }
-
   if (integer_zerop (format_tree))
     {
-      /* FIXME: this warning should go away once Marc Espie's
-        __attribute__((nonnull)) patch is in.  Instead, checking for
-        nonnull attributes should probably change this function to act
-        specially if info == NULL and add a res->number_null entry for
-        that case, or maybe add a function pointer to be called at
-        the end instead of hardcoding check_format_info_main.  */
+      /* FIXME: instead of warning about a null format string here,
+        functions for which we want to perform this check should be
+        marked with the "nonnull" attribute on the appropriate arguments.  */
       status_warning (status, "null format string");
 
       /* Skip to first argument to check, so we can see if this format
index 7e91d4fc69217d604f346c8ca8b680c952676b2d..76ebc3416d940accb317ad75a72a0c3f1607fbb1 100644 (file)
@@ -1576,10 +1576,9 @@ build_function_call (function, params)
   coerced_params
     = convert_arguments (TYPE_ARG_TYPES (fntype), params, name, fundecl);
 
-  /* Check for errors in format strings.  */
+  /* Check that the arguments to the function are valid.  */
 
-  if (warn_format)
-    check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
+  check_function_arguments (TYPE_ATTRIBUTES (fntype), coerced_params);
 
   /* Recognize certain built-in functions so we can make tree-codes
      other than CALL_EXPR.  We do this when it enables fold-const.c
index 4209f2a5dbc9a9fbc40e9852929ea62bbb248578..301db237124e0e96168a860082720944f35e126e 100644 (file)
@@ -1869,6 +1869,7 @@ the enclosing block.
 @cindex @code{volatile} applied to function
 @cindex @code{const} applied to function
 @cindex functions with @code{printf}, @code{scanf}, @code{strftime} or @code{strfmon} style arguments
+@cindex functions with non-null pointer arguments
 @cindex functions that are passed arguments in registers on the 386
 @cindex functions that pop the argument stack on the 386
 @cindex functions that do not pop the argument stack on the 386
@@ -1885,11 +1886,11 @@ attributes are currently defined for functions on all targets:
 @code{pure}, @code{const},
 @code{format}, @code{format_arg}, @code{no_instrument_function},
 @code{section}, @code{constructor}, @code{destructor}, @code{used},
-@code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, and
-@code{alias}.  Several other attributes are defined for functions on
-particular target systems.  Other attributes, including @code{section}
-are supported for variables declarations (@pxref{Variable Attributes})
-and for types (@pxref{Type Attributes}).
+@code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
+@code{alias}, and @code{nonnull}.  Several other attributes are defined
+for functions on particular target systems.  Other attributes, including
+@code{section} are supported for variables declarations
+(@pxref{Variable Attributes}) and for types (@pxref{Type Attributes}).
 
 You may also specify attributes with @samp{__} preceding and following
 each keyword.  This allows you to use them in header files without
@@ -2101,6 +2102,35 @@ requested by @option{-ansi} or an appropriate @option{-std} option, or
 @option{-ffreestanding} is used.  @xref{C Dialect Options,,Options
 Controlling C Dialect}.
 
+@item nonnull (@var{arg-index,...})
+@cindex @code{nonnull} function attribute
+The @code{nonnull} attribute specifies that some function parameters should
+be non-null pointers.  For instance, the declaration:
+
+@smallexample
+extern void *
+my_memcpy (void *dest, const void *src, size_t len)
+       __attribute__((nonnull (1, 2)));
+@end smallexample
+
+@noindent
+causes the compiler to check that, in calls to @code{my_memcpy},
+arguments @var{dest} and @var{src} are non-null.  If the compiler
+determines that a null pointer is passed in an argument slot marked
+as non-null, and the @option{-Wnonnull} option is enabled, a warning
+is issued.  The compiler may also choose to make optimizations based
+on the knowledge that certain function arguments will not be null.
+
+If no argument index list is given to the @code{nonnull} attribute,
+all pointer arguments are marked as non-null.  To illustrate, the
+following declaration is equivalent to the previous example:
+
+@smallexample
+extern void *
+my_memcpy (void *dest, const void *src, size_t len)
+       __attribute__((nonnull));
+@end smallexample
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
index cedabdf5500e71995dc1579b59f5a8da779b58bd..1ab9cb39f9850f41858222bc38a22deca9ef0095 100644 (file)
@@ -225,7 +225,7 @@ in the following sections.
 -Wmain  -Wmissing-braces  -Wmissing-declarations @gol
 -Wmissing-format-attribute  -Wmissing-noreturn @gol
 -Wno-multichar  -Wno-format-extra-args  -Wno-format-y2k @gol
--Wno-import  -Wpacked  -Wpadded @gol
+-Wno-import  -Wnonnull  -Wpacked  -Wpadded @gol
 -Wparentheses  -Wpointer-arith  -Wredundant-decls @gol
 -Wreturn-type  -Wsequence-point  -Wshadow @gol
 -Wsign-compare  -Wswitch  -Wswitch-default -Wswitch-enum @gol
@@ -1842,6 +1842,9 @@ in the selected standard version (but not for @code{strfmon} formats,
 since those are not in any version of the C standard).  @xref{C Dialect
 Options,,Options Controlling C Dialect}.
 
+Since @option{-Wformat} also checks for null format arguments for
+several functions, @option{-Wformat} also implies @option{-Wnonnull}.
+
 @option{-Wformat} is included in @option{-Wall}.  For more control over some
 aspects of format checking, the options @option{-Wno-format-y2k},
 @option{-Wno-format-extra-args}, @option{-Wno-format-zero-length},
@@ -1896,6 +1899,14 @@ Enable @option{-Wformat} plus format checks not included in
 @option{-Wformat}.  Currently equivalent to @samp{-Wformat
 -Wformat-nonliteral -Wformat-security}.
 
+@item -Wnonnull
+@opindex Wnonnull
+Enable warning about passing a null pointer for arguments marked as
+requiring a non-null value by the @code{nonnull} function attribute.
+
+@option{-Wnonnull} is included in @option{-Wall} and @option{-Wformat}.  It
+can be disabled with the @option{-Wno-nonnull} option.
+
 @item -Wimplicit-int
 @opindex Wimplicit-int
 Warn when a declaration does not specify a type.
diff --git a/gcc/testsuite/gcc.dg/nonnull-1.c b/gcc/testsuite/gcc.dg/nonnull-1.c
new file mode 100644 (file)
index 0000000..51a8a33
--- /dev/null
@@ -0,0 +1,39 @@
+/* Test for the "nonnull" function attribute.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile } */
+/* { dg-options "-Wnonnull" } */
+
+#include <stddef.h>
+
+extern void func1 (char *, char *, int) __attribute__((nonnull));
+
+extern void func2 (char *, char *) __attribute__((nonnull(1)));
+
+extern void func3 (char *, int, char *, int)
+  __attribute__((nonnull(1,3)));
+
+extern void func4 (char *, char *) __attribute__((nonnull(1)))
+  __attribute__((nonnull(2)));
+
+void
+foo (int i1, int i2, int i3, char *cp1, char *cp2, char *cp3)
+{
+  func1(cp1, cp2, i1);
+
+  func1(NULL, cp2, i1); /* { dg-warning "null" "null with argless nonnull 1" } */
+  func1(cp1, NULL, i1); /* { dg-warning "null" "null with argless nonnull 2" } */
+  func1(cp1, cp2, 0);
+
+  func2(cp1, NULL);
+  func2(NULL, cp1); /* { dg-warning "null" "null with single explicit nonnull" } */
+
+  func3(NULL, i2, cp3, i3); /* { dg-warning "null" "null with explicit nonnull 1" } */
+  func3(cp3, i2, NULL, i3); /* { dg-warning "null" "null with explicit nonnull 3" } */
+
+  func1(i1 ? cp1 : NULL, cp2, i3); /* { dg-warning "null" "null with cond expr rhs" } */
+  func1(i1 ? NULL : cp1, cp2, i3); /* { dg-warning "null" "null with cond expr lhs" } */
+  func1(i1 ? (i2 ? cp1 : NULL) : cp2, cp3, i3); /* { dg-warning "null" "null with nested cond expr" } */
+
+  func4(NULL, cp1); /* { dg-warning "null" "null with multiple attributes 1" } */
+  func4(cp1, NULL); /* { dg-warning "null" "null with multiple attributes 2" } */
+}
diff --git a/gcc/testsuite/gcc.dg/nonnull-2.c b/gcc/testsuite/gcc.dg/nonnull-2.c
new file mode 100644 (file)
index 0000000..bd36d23
--- /dev/null
@@ -0,0 +1,16 @@
+/* Test for the invalid use of the "nonnull" function attribute.  */
+/* Origin: Jason Thorpe <thorpej@wasabisystems.com> */
+/* { dg-do compile } */
+
+extern void func1 () __attribute__((nonnull)); /* { dg-error "without arguments" } */
+
+extern void func2 (char *) __attribute__((nonnull(2))); /* { dg-error "out-of-range operand" } */
+
+extern void func3 (char *) __attribute__((nonnull(foo))); /* { dg-error "invalid operand number" } */
+
+extern void func4 (int) __attribute__((nonnull(1))); /* { dg-error "references non-pointer" } */
+
+void
+foo (void)
+{
+}
This page took 0.165579 seconds and 5 git commands to generate.