builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New.
* builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New. * builtins.def (BUILT_IN_EXECLE): Set ATTR_NOTHROW_SENTINEL_1. * c-common.c (c_common_attribute_table): Accept parameters to sentinel attribute. (check_function_sentinel, handle_sentinel_attribute): Likewise. * doc/extend.texi: Update accordingly. testsuite: * gcc.dg/format/sentinel-1.c: Update for parameter option. From-SVN: r87098
This commit is contained in:
parent
44269c4093
commit
254986c7ff
7 changed files with 137 additions and 28 deletions
|
@ -1,3 +1,12 @@
|
|||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* builtin-attrs.def (ATTR_NOTHROW_SENTINEL_1): New.
|
||||
* builtins.def (BUILT_IN_EXECLE): Set ATTR_NOTHROW_SENTINEL_1.
|
||||
* c-common.c (c_common_attribute_table): Accept parameters to
|
||||
sentinel attribute.
|
||||
(check_function_sentinel, handle_sentinel_attribute): Likewise.
|
||||
* doc/extend.texi: Update accordingly.
|
||||
|
||||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* builtin-attrs.def (ATTR_SENTINEL, ATTR_SENTINEL_NOTHROW_LIST):
|
||||
|
|
|
@ -101,6 +101,8 @@ DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_LIST, ATTR_MALLOC, \
|
|||
DEF_ATTR_TREE_LIST (ATTR_SENTINEL_NOTHROW_LIST, ATTR_SENTINEL, \
|
||||
ATTR_NULL, ATTR_NOTHROW_LIST)
|
||||
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_SENTINEL_1, ATTR_SENTINEL, ATTR_LIST_1, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_1, ATTR_NONNULL, ATTR_LIST_1, \
|
||||
ATTR_NOTHROW_LIST)
|
||||
DEF_ATTR_TREE_LIST (ATTR_NOTHROW_NONNULL_2, ATTR_NONNULL, ATTR_LIST_2, \
|
||||
|
|
|
@ -556,7 +556,7 @@ DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN, "eh_return", BT_FN_VOID_PTRMODE_PTR,
|
|||
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_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_EXECLE, "execle", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_SENTINEL_1)
|
||||
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_EXECVE, "execve", BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
|
||||
|
|
|
@ -636,7 +636,7 @@ 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,
|
||||
{ "sentinel", 0, 1, false, true, true,
|
||||
handle_sentinel_attribute },
|
||||
{ NULL, 0, 0, false, false, false, NULL }
|
||||
};
|
||||
|
@ -5047,7 +5047,8 @@ check_function_nonnull (tree attrs, tree params)
|
|||
}
|
||||
}
|
||||
|
||||
/* Check the last argument of a function call is (pointer)0. */
|
||||
/* Check that the Nth argument of a function call (counting backwards
|
||||
from the end) is a (pointer)0. */
|
||||
|
||||
static void
|
||||
check_function_sentinel (tree attrs, tree params)
|
||||
|
@ -5060,11 +5061,40 @@ check_function_sentinel (tree attrs, tree 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)))
|
||||
tree sentinel, end;
|
||||
unsigned pos = 0;
|
||||
|
||||
if (TREE_VALUE (attr))
|
||||
{
|
||||
tree p = TREE_VALUE (TREE_VALUE (attr));
|
||||
STRIP_NOPS (p);
|
||||
pos = TREE_INT_CST_LOW (p);
|
||||
}
|
||||
|
||||
sentinel = end = params;
|
||||
|
||||
/* Advance `end' ahead of `sentinel' by `pos' positions. */
|
||||
while (pos > 0 && TREE_CHAIN (end))
|
||||
{
|
||||
pos--;
|
||||
end = TREE_CHAIN (end);
|
||||
}
|
||||
if (pos > 0)
|
||||
{
|
||||
warning ("not enough arguments to fit a sentinel");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Now advance both until we find the last parameter. */
|
||||
while (TREE_CHAIN (end))
|
||||
{
|
||||
end = TREE_CHAIN (end);
|
||||
sentinel = TREE_CHAIN (sentinel);
|
||||
}
|
||||
|
||||
/* Validate the sentinel. */
|
||||
if (!POINTER_TYPE_P (TREE_TYPE (TREE_VALUE (sentinel)))
|
||||
|| !integer_zerop (TREE_VALUE (sentinel)))
|
||||
warning ("missing sentinel in function call");
|
||||
}
|
||||
}
|
||||
|
@ -5215,8 +5245,7 @@ handle_warn_unused_result_attribute (tree *node, tree name,
|
|||
/* Handle a "sentinel" attribute. */
|
||||
|
||||
static tree
|
||||
handle_sentinel_attribute (tree *node, tree name,
|
||||
tree ARG_UNUSED (args),
|
||||
handle_sentinel_attribute (tree *node, tree name, tree args,
|
||||
int ARG_UNUSED (flags), bool *no_add_attrs)
|
||||
{
|
||||
tree params = TYPE_ARG_TYPES (*node);
|
||||
|
@ -5226,17 +5255,38 @@ handle_sentinel_attribute (tree *node, tree name,
|
|||
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)))
|
||||
else
|
||||
{
|
||||
warning ("`%s' attribute only applies to variadic functions",
|
||||
IDENTIFIER_POINTER (name));
|
||||
*no_add_attrs = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (args)
|
||||
{
|
||||
tree position = TREE_VALUE (args);
|
||||
|
||||
STRIP_NOPS (position);
|
||||
if (TREE_CODE (position) != INTEGER_CST)
|
||||
{
|
||||
warning ("requested position is not an integer constant");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tree_int_cst_lt (position, integer_zero_node))
|
||||
{
|
||||
warning ("requested position is less than zero");
|
||||
*no_add_attrs = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
|
|
|
@ -2113,15 +2113,30 @@ 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}.
|
||||
This function attribute ensures that a parameter in a function call is
|
||||
an explicit @code{NULL}. The attribute is only valid on variadic
|
||||
functions. By default, the sentinel is located at position zero, the
|
||||
last parameter of the function call. If an optional integer position
|
||||
argument P is supplied to the attribute, the sentinel must be located at
|
||||
position P counting backwards from the end of the argument list.
|
||||
|
||||
@smallexample
|
||||
__attribute__ ((sentinel))
|
||||
is equivalent to
|
||||
__attribute__ ((sentinel(0)))
|
||||
@end smallexample
|
||||
|
||||
The attribute is automatically set with a position of 0 for the built-in
|
||||
functions @code{execl} and @code{execlp}. The built-in function
|
||||
@code{execle} has the attribute set set with a position of 1.
|
||||
|
||||
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. GCC replaces @code{stddef.h}
|
||||
with a copy that redefines NULL appropriately.
|
||||
|
||||
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: Update for parameter option.
|
||||
|
||||
2004-09-04 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
|
||||
|
||||
* gcc.dg/format/sentinel-1.c: New test.
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
extern int execl (const char *, const char *, ...);
|
||||
extern int execlp (const char *, const char *, ...);
|
||||
extern int execle (const char *, const char *, ...);
|
||||
extern char *envp[];
|
||||
|
||||
#define ATTR __attribute__ ((__sentinel__))
|
||||
|
||||
|
@ -16,6 +18,12 @@ 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 foo5 (const char *, ...) __attribute__ ((__sentinel__(1)));
|
||||
extern void foo6 (const char *, ...) __attribute__ ((__sentinel__(5)));
|
||||
extern void foo7 (const char *, ...) __attribute__ ((__sentinel__(0)));
|
||||
extern void foo8 (const char *, ...) __attribute__ ((__sentinel__("a"))); /* { dg-warning "not an integer constant" "sentinel" } */
|
||||
extern void foo9 (const char *, ...) __attribute__ ((__sentinel__(-1))); /* { dg-warning "less than zero" "sentinel" } */
|
||||
extern void foo10 (const char *, ...) __attribute__ ((__sentinel__(1,3))); /* { dg-error "wrong number of arguments" "sentinel" } */
|
||||
|
||||
extern void bar(void)
|
||||
{
|
||||
|
@ -27,6 +35,23 @@ extern void bar(void)
|
|||
foo1 ("a", NULL, 1); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo1 ("a", NULL);
|
||||
|
||||
foo5 ("a", 1, 2, 3, NULL); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo5 ("a", 1, 2, NULL, 3);
|
||||
foo5 ("a", 1, NULL, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo5 ("a", NULL, 1, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo5 ("a", 0, 1, 2, 3); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
|
||||
foo6 ("a", 1, NULL); /* { dg-warning "not enough arguments" "sentinel" } */
|
||||
foo6 ("a", 1, NULL, 2); /* { dg-warning "not enough arguments" "sentinel" } */
|
||||
foo6 ("a", 1, NULL, 2, 3); /* { dg-warning "not enough arguments" "sentinel" } */
|
||||
foo6 ("a", NULL, 1, 2, 3); /* { dg-warning "not enough arguments" "sentinel" } */
|
||||
foo6 ("a", NULL, 1, 2, 3, 4); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo6 ("a", NULL, 1, 2, 3, 4, 5);
|
||||
foo6 ("a", 0, 1, 2, 3, 4, 5); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
foo6 ("a", NULL, 1, 2, 3, 4, 5, 6); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
|
||||
foo7 ("a", 1, 2, 3, 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);
|
||||
|
@ -34,4 +59,8 @@ extern void bar(void)
|
|||
execlp ("ls", "-aFC"); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execlp ("ls", "-aFC", 0); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execlp ("ls", "-aFC", NULL);
|
||||
|
||||
execle ("ls", "-aFC", ".", envp); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execle ("ls", "-aFC", ".", 0, envp); /* { dg-warning "missing sentinel" "sentinel" } */
|
||||
execle ("ls", "-aFC", ".", NULL, envp);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue