c-common.c (warn_nonnull): Declare.

* 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
This commit is contained in:
Jason Thorpe 2002-05-23 15:48:05 +00:00 committed by Jason Thorpe
parent 9547983155
commit b34c788149
10 changed files with 468 additions and 104 deletions

View 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.

View 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;
}
/* 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);
}

View 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,

View 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 },

View 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;
}
@ -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

View 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

View 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

View 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.

View File

@ -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" } */
}

View File

@ -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)
{
}