summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthorpej <thorpej@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-23 15:48:05 +0000
committerthorpej <thorpej@138bc75d-0d04-0410-961f-82ee72b054a4>2002-05-23 15:48:05 +0000
commitdbf6c367801e1bf1d0cec09a2fe8fef7f7957c3f (patch)
treeec1ff9d3e5c1ac88998d2453691cca3c42bc0416
parent43a852ea4edb3bace60c8f0880cdc1768ace6151 (diff)
downloadgcc-dbf6c367801e1bf1d0cec09a2fe8fef7f7957c3f.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@53790 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/c-common.c293
-rw-r--r--gcc/c-common.h11
-rw-r--r--gcc/c-decl.c1
-rw-r--r--gcc/c-format.c130
-rw-r--r--gcc/c-typeck.c5
-rw-r--r--gcc/doc/extend.texi40
-rw-r--r--gcc/doc/invoke.texi13
-rw-r--r--gcc/testsuite/gcc.dg/nonnull-1.c39
-rw-r--r--gcc/testsuite/gcc.dg/nonnull-2.c16
10 files changed, 468 insertions, 104 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d7334a9cb7a..be5370c4eae 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 900b5e9bb54..006a831cf3c 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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;
+}
+
+/* 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);
+}
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 320d03d8253..834d78520dc 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -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,
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 0890a2a58c4..3dcb05540ec 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -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 },
diff --git a/gcc/c-format.c b/gcc/c-format.c
index dc73f4d69f1..b3640c50190 100644
--- a/gcc/c-format.c
+++ b/gcc/c-format.c
@@ -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;
}
@@ -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
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 7e91d4fc692..76ebc3416d9 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -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
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4209f2a5dbc..301db237124 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index cedabdf5500..1ab9cb39f98 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -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
index 00000000000..51a8a3373ee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nonnull-1.c
@@ -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
index 00000000000..bd36d232d38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/nonnull-2.c
@@ -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)
+{
+}