builtin-attrs.def (ATTR_SENTINEL, [...]): New.
gcc: * builtin-attrs.def (ATTR_SENTINEL, ATTR_SENTINEL_NOTHROW_LIST): New. * builtins.def (BUILT_IN_EXECL, BUILT_IN_EXECLP): Add `sentinel' attribute. * c-common.c (handle_sentinel_attribute, check_function_sentinel): New functions. (c_common_attribute_table): Add `sentinel' attribute. (check_function_arguments): Handle `sentinel' attribute. * doc/extend.texi: Document `sentinel' attribute. gcc/testsuite: * gcc.dg/format/sentinel-1.c: New test. include: * ansidecl.h (ATTRIBUTE_SENTINEL): Define. * libiberty.h (concat, reconcat, concat_length, concat_copy, concat_copy2): Use ATTRIBUTE_SENTINEL. From-SVN: r87096
This commit is contained in:
parent
ecd466457c
commit
3d091dac56
@ -1,8 +1,19 @@
|
||||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* configure: Regenerated.
|
||||
* builtin-attrs.def (ATTR_SENTINEL, ATTR_SENTINEL_NOTHROW_LIST):
|
||||
New.
|
||||
* builtins.def (BUILT_IN_EXECL, BUILT_IN_EXECLP): Add `sentinel'
|
||||
attribute.
|
||||
* c-common.c (handle_sentinel_attribute, check_function_sentinel):
|
||||
New functions.
|
||||
(c_common_attribute_table): Add `sentinel' attribute.
|
||||
(check_function_arguments): Handle `sentinel' attribute.
|
||||
* doc/extend.texi: Document `sentinel' attribute.
|
||||
|
||||
2004-09-04 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
|
||||
|
||||
* configure: Regenerated.
|
||||
|
||||
* gimplify.c (internal_get_tmp_var): Remove unused var CLASS.
|
||||
|
||||
* tree.c (save_expr): No longer TREE_READONLY.
|
||||
|
@ -84,6 +84,7 @@ DEF_ATTR_IDENT (ATTR_GCC_CDIAG, "gcc_cdiag")
|
||||
DEF_ATTR_IDENT (ATTR_GCC_CXXDIAG, "gcc_cxxdiag")
|
||||
DEF_ATTR_IDENT (ATTR_PURE, "pure")
|
||||
DEF_ATTR_IDENT (ATTR_SCANF, "scanf")
|
||||
DEF_ATTR_IDENT (ATTR_SENTINEL, "sentinel")
|
||||
DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
|
||||
DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
|
||||
|
||||
@ -97,6 +98,8 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN, \
|
||||
ATTR_NULL, ATTR_NOTHROW_LIST)
|
||||
DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \
|
||||
ATTR_NULL, ATTR_NOTHROW_LIST)
|
||||
DEF_ATTR_TREE_LIST (ATTR_SENTINEL_NOTHROW_LIST, ATTR_SENTINEL, \
|
||||
ATTR_NULL, ATTR_NOTHROW_LIST)
|
||||
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
|
@ -554,8 +554,8 @@ DEF_GCC_BUILTIN (BUILT_IN_DWARF_CFA, "dwarf_cfa", BT_FN_PTR, ATTR_NULL)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_DWARF_SP_COLUMN, "dwarf_sp_column", BT_FN_UINT, ATTR_NULL)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN, "eh_return", BT_FN_VOID_PTRMODE_PTR, ATTR_NORETURN_NOTHROW_LIST)
|
||||
DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN_DATA_REGNO, "eh_return_data_regno", BT_FN_INT_INT, ATTR_NULL)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLP, "execlp", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLP, "execlp", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_SENTINEL_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECLE, "execle", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECV, "execv", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
|
||||
DEF_EXT_LIB_BUILTIN (BUILT_IN_EXECVP, "execvp", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
|
||||
|
@ -557,6 +557,7 @@ static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
|
||||
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
|
||||
bool *);
|
||||
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
|
||||
|
||||
static void check_function_nonnull (tree, tree);
|
||||
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
|
||||
@ -635,6 +636,8 @@ const struct attribute_spec c_common_attribute_table[] =
|
||||
handle_cleanup_attribute },
|
||||
{ "warn_unused_result", 0, 0, false, true, true,
|
||||
handle_warn_unused_result_attribute },
|
||||
{ "sentinel", 0, 0, false, true, true,
|
||||
handle_sentinel_attribute },
|
||||
{ NULL, 0, 0, false, false, false, NULL }
|
||||
};
|
||||
|
||||
@ -5044,6 +5047,29 @@ check_function_nonnull (tree attrs, tree params)
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the last argument of a function call is (pointer)0. */
|
||||
|
||||
static void
|
||||
check_function_sentinel (tree attrs, tree params)
|
||||
{
|
||||
tree attr = lookup_attribute ("sentinel", attrs);
|
||||
|
||||
if (attr)
|
||||
{
|
||||
if (!params)
|
||||
warning ("missing sentinel in function call");
|
||||
else
|
||||
{
|
||||
/* Find the last parameter. */
|
||||
while (TREE_CHAIN (params))
|
||||
params = TREE_CHAIN (params);
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (params)))
|
||||
|| !integer_zerop (TREE_VALUE (params)))
|
||||
warning ("missing sentinel in function call");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
@ -5185,6 +5211,36 @@ handle_warn_unused_result_attribute (tree *node, tree name,
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Handle a "sentinel" attribute. */
|
||||
|
||||
static tree
|
||||
handle_sentinel_attribute (tree *node, tree name,
|
||||
tree ARG_UNUSED (args),
|
||||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
tree params = TYPE_ARG_TYPES (*node);
|
||||
|
||||
if (!params)
|
||||
{
|
||||
warning ("`%s' attribute requires prototypes with named arguments",
|
||||
IDENTIFIER_POINTER (name));
|
||||
*no_add_attrs = true;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
while (TREE_CHAIN (params))
|
||||
params = TREE_CHAIN (params);
|
||||
|
||||
if (VOID_TYPE_P (TREE_VALUE (params)))
|
||||
{
|
||||
warning ("`%s' attribute only applies to variadic functions",
|
||||
IDENTIFIER_POINTER (name));
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Check for valid arguments being passed to a function. */
|
||||
void
|
||||
@ -5199,7 +5255,10 @@ check_function_arguments (tree attrs, tree params)
|
||||
/* Check for errors in format strings. */
|
||||
|
||||
if (warn_format)
|
||||
check_function_format (attrs, params);
|
||||
{
|
||||
check_function_format (attrs, params);
|
||||
check_function_sentinel (attrs, params);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generic argument checking recursion routine. PARAM is the argument to
|
||||
|
@ -1496,7 +1496,7 @@ attributes when making a declaration. This keyword is followed by an
|
||||
attribute specification inside double parentheses. The following
|
||||
attributes are currently defined for functions on all targets:
|
||||
@code{noreturn}, @code{noinline}, @code{always_inline},
|
||||
@code{pure}, @code{const}, @code{nothrow},
|
||||
@code{pure}, @code{const}, @code{nothrow}, @code{sentinel},
|
||||
@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},
|
||||
@ -2111,6 +2111,18 @@ attribute is not available on all platforms.
|
||||
If you need to map the entire contents of a module to a particular
|
||||
section, consider using the facilities of the linker instead.
|
||||
|
||||
@item sentinel
|
||||
@cindex @code{sentinel} function attribute
|
||||
This function attribute ensures that the last parameter in a function
|
||||
call is an explicit @code{NULL}. The attribute is only valid on
|
||||
variadic functions. For example the attribute is automatically set for
|
||||
the built-in functions @code{execl} and @code{execlp} where @code{NULL}
|
||||
is the marker for argument list termination. A valid @code{NULL} in
|
||||
this context is defined as zero with any pointer type. If your system
|
||||
defines the @code{NULL} macro with an integer type then you need to add
|
||||
an explicit cast. The warnings for missing or incorrect sentinels are
|
||||
enabled with @option{-Wformat}.
|
||||
|
||||
@item short_call
|
||||
See long_call/short_call.
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* gcc.dg/format/sentinel-1.c: New test.
|
||||
|
||||
2004-09-04 Uros Bizjak <uros@kss-loka.si>
|
||||
|
||||
* testsuite/gcc.dg/builtins-46.c: New.
|
||||
|
37
gcc/testsuite/gcc.dg/format/sentinel-1.c
Normal file
37
gcc/testsuite/gcc.dg/format/sentinel-1.c
Normal file
@ -0,0 +1,37 @@
|
||||
/* Test for attribute sentinel. */
|
||||
/* Origin: Kaveh Ghazi <ghazi@caip.rutgers.edu> */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-Wformat" } */
|
||||
|
||||
#include <stddef.h> /* For NULL, which must be (ptr)0. */
|
||||
|
||||
extern int execl (const char *, const char *, ...);
|
||||
extern int execlp (const char *, const char *, ...);
|
||||
|
||||
#define ATTR __attribute__ ((__sentinel__))
|
||||
|
||||
extern int a ATTR; /* { dg-warning "applies to function types" "sentinel" } */
|
||||
|
||||
extern void foo1 (const char *, ...) ATTR;
|
||||
extern void foo2 (...) ATTR; /* { dg-error "ISO C requires|named arguments" "sentinel" } */
|
||||
extern void foo3 () ATTR; /* { dg-warning "named arguments" "sentinel" } */
|
||||
extern void foo4 (const char *, int) ATTR; /* { dg-warning "variadic functions" "sentinel" } */
|
||||
|
||||
extern void bar(void)
|
||||
{
|
||||
foo1 (); /* { dg-error "missing sentinel|too few arguments" "sentinel" } */
|
||||
foo1 ("a"); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", 1); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", 0); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", (void*)1); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", NULL, 1); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", NULL);
|
||||
|
||||
execl ("/bin/ls", "-aFC"); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execl ("/bin/ls", "-aFC", 0); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execl ("/bin/ls", "-aFC", NULL);
|
||||
|
||||
execlp ("ls", "-aFC"); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execlp ("ls", "-aFC", 0); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execlp ("ls", "-aFC", NULL);
|
||||
}
|
@ -1,3 +1,9 @@
|
||||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* ansidecl.h (ATTRIBUTE_SENTINEL): Define.
|
||||
* libiberty.h (concat, reconcat, concat_length, concat_copy,
|
||||
concat_copy2): Use ATTRIBUTE_SENTINEL.
|
||||
|
||||
2004-08-02 Gabriel Dos Reis <gdr@integrable-solutions.net>
|
||||
|
||||
* libiberty.h (XDELETE, XDELETEVEC, XRESIZEVEC): Remove any
|
||||
|
@ -322,6 +322,15 @@ So instead we use the macro below and test it against specific values. */
|
||||
# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
|
||||
#endif /* ATTRIBUTE_NULL_PRINTF */
|
||||
|
||||
/* Attribute `sentinel' was valid as of gcc 3.5. */
|
||||
#ifndef ATTRIBUTE_SENTINEL
|
||||
# if (GCC_VERSION >= 3005)
|
||||
# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
|
||||
# else
|
||||
# define ATTRIBUTE_SENTINEL
|
||||
# endif /* GNUC >= 3.5 */
|
||||
#endif /* ATTRIBUTE_SENTINEL */
|
||||
|
||||
/* We use __extension__ in some places to suppress -pedantic warnings
|
||||
about GCC extensions. This feature didn't work properly before
|
||||
gcc 2.8. */
|
||||
|
@ -93,7 +93,7 @@ extern char *lrealpath PARAMS ((const char *));
|
||||
the last argument of this function, to terminate the list of
|
||||
strings. Allocates memory using xmalloc. */
|
||||
|
||||
extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC;
|
||||
extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* Concatenate an arbitrary number of strings. You must pass NULL as
|
||||
the last argument of this function, to terminate the list of
|
||||
@ -102,27 +102,27 @@ extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC;
|
||||
pointer to be freed after the new string is created, similar to the
|
||||
way xrealloc works. */
|
||||
|
||||
extern char *reconcat PARAMS ((char *, const char *, ...)) ATTRIBUTE_MALLOC;
|
||||
extern char *reconcat PARAMS ((char *, const char *, ...)) ATTRIBUTE_MALLOC ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* Determine the length of concatenating an arbitrary number of
|
||||
strings. You must pass NULL as the last argument of this function,
|
||||
to terminate the list of strings. */
|
||||
|
||||
extern unsigned long concat_length PARAMS ((const char *, ...));
|
||||
extern unsigned long concat_length PARAMS ((const char *, ...)) ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* Concatenate an arbitrary number of strings into a SUPPLIED area of
|
||||
memory. You must pass NULL as the last argument of this function,
|
||||
to terminate the list of strings. The supplied memory is assumed
|
||||
to be large enough. */
|
||||
|
||||
extern char *concat_copy PARAMS ((char *, const char *, ...));
|
||||
extern char *concat_copy PARAMS ((char *, const char *, ...)) ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* Concatenate an arbitrary number of strings into a GLOBAL area of
|
||||
memory. You must pass NULL as the last argument of this function,
|
||||
to terminate the list of strings. The supplied memory is assumed
|
||||
to be large enough. */
|
||||
|
||||
extern char *concat_copy2 PARAMS ((const char *, ...));
|
||||
extern char *concat_copy2 PARAMS ((const char *, ...)) ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* This is the global area used by concat_copy2. */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user