builtin-attrs.def (ATTR_SENTINEL, [...]): New.
authorKaveh Ghazi <ghazi@gcc.gnu.org>
Sun, 5 Sep 2004 02:50:09 +0000 (02:50 +0000)
committerKaveh Ghazi <ghazi@gcc.gnu.org>
Sun, 5 Sep 2004 02:50:09 +0000 (02:50 +0000)
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

gcc/ChangeLog
gcc/builtin-attrs.def
gcc/builtins.def
gcc/c-common.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/format/sentinel-1.c [new file with mode: 0644]
include/ChangeLog
include/ansidecl.h
include/libiberty.h

index be21a7f7e66156e57de34e9978a93780b4d6470d..95f0e026050dc0fab8d990b9666ab39c55e6ce02 100644 (file)
@@ -1,8 +1,19 @@
+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.
index 10d58649a82fc806cb9ef4f891edc783dda9b512..67cf193e4fd1c1c4a214ca3d40f550c07a1b5498 100644 (file)
@@ -84,6 +84,7 @@ DEF_ATTR_IDENT (ATTR_GCC_CDIAG, "gcc_cdiag")
 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")
 
@@ -97,6 +98,8 @@ DEF_ATTR_TREE_LIST (ATTR_NORETURN_NOTHROW_LIST, ATTR_NORETURN,        \
                        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)
index 1cfbf7129994efc06cf6252207a1def53db2c3ea..e89509fcebfa3a4cf5715095c9472b162b95dd8c 100644 (file)
@@ -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_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)
index 499829bd0e38c46670a4f1cae0dcd891601a16bc..3af1e6408ed0391406cf10b30488018397aa535d 100644 (file)
@@ -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;
+}
 \f
 /* 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
index fe25cd1b0662b7b58bd8bc7724263ba6c2310db6..4c27320f2b95195b0bfa112d133b8bc328a04033 100644 (file)
@@ -1496,7 +1496,7 @@ attributes when making a declaration.  This keyword is followed by an
 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},
@@ -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
 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.
 
index e0f86f13f7e9d3053d9b8d48eb4fa5dff9b0399f..4fb58cb251b55463f57303930ada633cb3d8a5f8 100644 (file)
@@ -1,3 +1,7 @@
+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.
diff --git a/gcc/testsuite/gcc.dg/format/sentinel-1.c b/gcc/testsuite/gcc.dg/format/sentinel-1.c
new file mode 100644 (file)
index 0000000..e1e127d
--- /dev/null
@@ -0,0 +1,37 @@
+/* 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);
+}
index 1e180da613c4ce0f8b642b4c0e5fe5125987cf5d..19d2f5099e43d986e9962e357ea1c64c2136bb93 100644 (file)
@@ -1,3 +1,9 @@
+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
index ccf0b2757ae30a5859fdf578ec1e01b08d8e03fb..04c3a30bb53bfa3204d61983d16b23067aea5f14 100644 (file)
@@ -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)
 #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.  */
index a90b4ddcbe857084e05c15823c4b3cc998a34d76..4aab80b215073badfdca76677700afe737d229a6 100644 (file)
@@ -93,7 +93,7 @@ extern char *lrealpath PARAMS ((const char *));
    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
@@ -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
    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.  */