summaryrefslogtreecommitdiff
path: root/gcc/c-common.c
diff options
context:
space:
mode:
authorghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-05 02:50:09 +0000
committerghazi <ghazi@138bc75d-0d04-0410-961f-82ee72b054a4>2004-09-05 02:50:09 +0000
commitbf6c8de0ca844fe49b07d807047b6e648772c04b (patch)
tree616590e443b211fdf7309d929fce3872a4ff3f15 /gcc/c-common.c
parentb1d422af2ac49ae61000c4377ba4a8ae8f7ca3e2 (diff)
downloadgcc-bf6c8de0ca844fe49b07d807047b6e648772c04b.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@87096 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r--gcc/c-common.c61
1 files changed, 60 insertions, 1 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 499829bd0e3..3af1e6408ed 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -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