+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.
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")
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)
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)
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);
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 }
};
}
}
+/* 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. */
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;
+}
\f
/* Check for valid arguments being passed to a function. */
void
/* 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
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},
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.
+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.
--- /dev/null
+/* 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>
* libiberty.h (XDELETE, XDELETEVEC, XRESIZEVEC): Remove any
# 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. */
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
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. */