Commit 3d091dac by Kaveh Ghazi

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
parent ecd46645
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> 2004-09-04 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* configure: Regenerated.
* gimplify.c (internal_get_tmp_var): Remove unused var CLASS. * gimplify.c (internal_get_tmp_var): Remove unused var CLASS.
* tree.c (save_expr): No longer TREE_READONLY. * tree.c (save_expr): No longer TREE_READONLY.
......
...@@ -84,6 +84,7 @@ DEF_ATTR_IDENT (ATTR_GCC_CDIAG, "gcc_cdiag") ...@@ -84,6 +84,7 @@ DEF_ATTR_IDENT (ATTR_GCC_CDIAG, "gcc_cdiag")
DEF_ATTR_IDENT (ATTR_GCC_CXXDIAG, "gcc_cxxdiag") DEF_ATTR_IDENT (ATTR_GCC_CXXDIAG, "gcc_cxxdiag")
DEF_ATTR_IDENT (ATTR_PURE, "pure") DEF_ATTR_IDENT (ATTR_PURE, "pure")
DEF_ATTR_IDENT (ATTR_SCANF, "scanf") DEF_ATTR_IDENT (ATTR_SCANF, "scanf")
DEF_ATTR_IDENT (ATTR_SENTINEL, "sentinel")
DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon") DEF_ATTR_IDENT (ATTR_STRFMON, "strfmon")
DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime") DEF_ATTR_IDENT (ATTR_STRFTIME, "strftime")
...@@ -97,6 +98,8 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN, \ ...@@ -97,6 +98,8 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN, \
ATTR_NULL, ATTR_NOTHROW_LIST) ATTR_NULL, ATTR_NOTHROW_LIST)
DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \ DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \
ATTR_NULL, ATTR_NOTHROW_LIST) 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, \ DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \
ATTR_NOTHROW_LIST) ATTR_NOTHROW_LIST)
......
...@@ -554,8 +554,8 @@ DEF_GCC_BUILTIN (BUILT_IN_DWARF_CFA, "dwarf_cfa", BT_FN_PTR, ATTR_NULL) ...@@ -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_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, "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_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_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_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_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_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) 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 *); ...@@ -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_cleanup_attribute (tree *, tree, tree, int, bool *);
static tree handle_warn_unused_result_attribute (tree *, tree, tree, int, static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
bool *); bool *);
static tree handle_sentinel_attribute (tree *, tree, tree, int, bool *);
static void check_function_nonnull (tree, tree); static void check_function_nonnull (tree, tree);
static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
...@@ -635,6 +636,8 @@ const struct attribute_spec c_common_attribute_table[] = ...@@ -635,6 +636,8 @@ const struct attribute_spec c_common_attribute_table[] =
handle_cleanup_attribute }, handle_cleanup_attribute },
{ "warn_unused_result", 0, 0, false, true, true, { "warn_unused_result", 0, 0, false, true, true,
handle_warn_unused_result_attribute }, handle_warn_unused_result_attribute },
{ "sentinel", 0, 0, false, true, true,
handle_sentinel_attribute },
{ NULL, 0, 0, false, false, false, NULL } { NULL, 0, 0, false, false, false, NULL }
}; };
...@@ -5044,6 +5047,29 @@ check_function_nonnull (tree attrs, tree params) ...@@ -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 /* Helper for check_function_nonnull; given a list of operands which
must be non-null in ARGS, determine if operand PARAM_NUM should be must be non-null in ARGS, determine if operand PARAM_NUM should be
checked. */ checked. */
...@@ -5185,6 +5211,36 @@ handle_warn_unused_result_attribute (tree *node, tree name, ...@@ -5185,6 +5211,36 @@ handle_warn_unused_result_attribute (tree *node, tree name,
return NULL_TREE; 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. */ /* Check for valid arguments being passed to a function. */
void void
...@@ -5199,7 +5255,10 @@ check_function_arguments (tree attrs, tree params) ...@@ -5199,7 +5255,10 @@ check_function_arguments (tree attrs, tree params)
/* Check for errors in format strings. */ /* Check for errors in format strings. */
if (warn_format) 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 /* 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 ...@@ -1496,7 +1496,7 @@ attributes when making a declaration. This keyword is followed by an
attribute specification inside double parentheses. The following attribute specification inside double parentheses. The following
attributes are currently defined for functions on all targets: attributes are currently defined for functions on all targets:
@code{noreturn}, @code{noinline}, @code{always_inline}, @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{format}, @code{format_arg}, @code{no_instrument_function},
@code{section}, @code{constructor}, @code{destructor}, @code{used}, @code{section}, @code{constructor}, @code{destructor}, @code{used},
@code{unused}, @code{deprecated}, @code{weak}, @code{malloc}, @code{unused}, @code{deprecated}, @code{weak}, @code{malloc},
...@@ -2111,6 +2111,18 @@ attribute is not available on all platforms. ...@@ -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 If you need to map the entire contents of a module to a particular
section, consider using the facilities of the linker instead. 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 @item short_call
See long_call/short_call. See long_call/short_call.
......
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> 2004-09-04 Uros Bizjak <uros@kss-loka.si>
* testsuite/gcc.dg/builtins-46.c: New. * testsuite/gcc.dg/builtins-46.c: New.
......
/* 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);
}
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> 2004-08-02 Gabriel Dos Reis <gdr@integrable-solutions.net>
* libiberty.h (XDELETE, XDELETEVEC, XRESIZEVEC): Remove any * libiberty.h (XDELETE, XDELETEVEC, XRESIZEVEC): Remove any
......
...@@ -322,6 +322,15 @@ So instead we use the macro below and test it against specific values. */ ...@@ -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) # define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
#endif /* ATTRIBUTE_NULL_PRINTF */ #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 /* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before about GCC extensions. This feature didn't work properly before
gcc 2.8. */ gcc 2.8. */
......
...@@ -93,7 +93,7 @@ extern char *lrealpath PARAMS ((const char *)); ...@@ -93,7 +93,7 @@ extern char *lrealpath PARAMS ((const char *));
the last argument of this function, to terminate the list of the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. */ 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 /* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of the last argument of this function, to terminate the list of
...@@ -102,27 +102,27 @@ extern char *concat PARAMS ((const char *, ...)) ATTRIBUTE_MALLOC; ...@@ -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 pointer to be freed after the new string is created, similar to the
way xrealloc works. */ 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 /* Determine the length of concatenating an arbitrary number of
strings. You must pass NULL as the last argument of this function, strings. You must pass NULL as the last argument of this function,
to terminate the list of strings. */ 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 /* Concatenate an arbitrary number of strings into a SUPPLIED area of
memory. You must pass NULL as the last argument of this function, memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed to terminate the list of strings. The supplied memory is assumed
to be large enough. */ 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 /* Concatenate an arbitrary number of strings into a GLOBAL area of
memory. You must pass NULL as the last argument of this function, memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed to terminate the list of strings. The supplied memory is assumed
to be large enough. */ 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. */ /* This is the global area used by concat_copy2. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment