summaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-05 02:55:28 +0000
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-05 02:55:28 +0000
commit50ca527f840b57f26fb9fd430a8c48eb88dab325 (patch)
tree35944d27904d831ba5d78370c59d633d19c4fe13 /gcc
parentb9135568e4678ac8bc90cf37db2ae5c750b08bdd (diff)
downloadgcc-50ca527f840b57f26fb9fd430a8c48eb88dab325.tar.gz
* 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@87098 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/builtin-attrs.def2
-rw-r--r--gcc/builtins.def2
-rw-r--r--gcc/c-common.c84
-rw-r--r--gcc/doc/extend.texi33
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/format/sentinel-1.c29
7 files changed, 136 insertions, 27 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 96da912b162..88486b14796 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
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):
New.
* builtins.def (BUILT_IN_EXECL, BUILT_IN_EXECLP): Add `sentinel'
diff --git a/gcc/builtin-attrs.def b/gcc/builtin-attrs.def
index 67cf193e4fd..f376f5571b5 100644
--- a/gcc/builtin-attrs.def
+++ b/gcc/builtin-attrs.def
@@ -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, \
diff --git a/gcc/builtins.def b/gcc/builtins.def
index e89509fcebf..1bdc8aa79ee 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -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)
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 3af1e6408ed..1a105701eb0 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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;
}
+ else
+ {
+ while (TREE_CHAIN (params))
+ params = TREE_CHAIN (params);
- while (TREE_CHAIN (params))
- params = TREE_CHAIN (params);
-
- if (VOID_TYPE_P (TREE_VALUE (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)
{
- warning ("`%s' attribute only applies to variadic functions",
- IDENTIFIER_POINTER (name));
- *no_add_attrs = true;
+ 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;
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 4c27320f2b9..bbde788ee5c 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4fb58cb251b..01e0815f462 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,9 @@
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.
2004-09-04 Uros Bizjak <uros@kss-loka.si>
diff --git a/gcc/testsuite/gcc.dg/format/sentinel-1.c b/gcc/testsuite/gcc.dg/format/sentinel-1.c
index e1e127dca38..12915b7dc5a 100644
--- a/gcc/testsuite/gcc.dg/format/sentinel-1.c
+++ b/gcc/testsuite/gcc.dg/format/sentinel-1.c
@@ -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);
}