This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Patch: add position argument to attribute sentinel, plus regtest request


This patch is "step 2" in the attribute sentinel proposal I made here:
http://gcc.gnu.org/ml/gcc/2004-08/msg01068.html 
namely adding an optional `position' argument to the attribute for the
sentinel parameter location.  (I probably won't work on "step 3"
myself, which is allowing changing the value and/or type of the
sentinel.  But someone else can certainly carry the ball further if
they wish.)

The patch relies on the baseline sentinel patch previously submitted
here:
http://gcc.gnu.org/ml/gcc-patches/2004-09/msg00014.html

I need help doing the bootstrap + regtest for both patches because I
cannot run a full bootstrap on the systems I have access to at the
moment.  I've tested everything to the best of my ability.  If someone
could help me out by doing the bootstrap/regtest for both patches I
would appreciate it.  I'd like to get these reviewed and installed
before the sept 5 stage3 deadline.

		Thanks,
		--Kaveh


2004-09-01  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.

testsuite:
	* gcc.dg/format/sentinel-1.c: Update for parameter option.
	
diff -rup orig/egcc-CVS20040901/gcc/builtin-attrs.def egcc-CVS20040901/gcc/builtin-attrs.def
--- orig/egcc-CVS20040901/gcc/builtin-attrs.def	2004-09-01 09:22:56.387386000 -0400
+++ egcc-CVS20040901/gcc/builtin-attrs.def	2004-09-01 11:31:19.000000000 -0400
@@ -101,6 +101,8 @@ DEF_ATTR_TREE_LIST (ATTR_MALLOC_NOTHROW_
 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 -rup orig/egcc-CVS20040901/gcc/builtins.def egcc-CVS20040901/gcc/builtins.def
--- orig/egcc-CVS20040901/gcc/builtins.def	2004-09-01 09:22:56.497404000 -0400
+++ egcc-CVS20040901/gcc/builtins.def	2004-09-01 11:31:19.000000000 -0400
@@ -556,7 +556,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_EH_RETU
 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 -rup orig/egcc-CVS20040901/gcc/c-common.c egcc-CVS20040901/gcc/c-common.c
--- orig/egcc-CVS20040901/gcc/c-common.c	2004-09-01 09:22:56.637386000 -0400
+++ egcc-CVS20040901/gcc/c-common.c	2004-09-01 11:28:47.785892000 -0400
@@ -636,7 +636,7 @@ const struct attribute_spec c_common_att
 			      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 }
 };
@@ -5029,7 +5029,8 @@ check_function_nonnull (tree attrs, tree
     }
 }
 
-/* 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)
@@ -5042,11 +5043,40 @@ check_function_sentinel (tree attrs, tre
 	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");
 	}
     }
@@ -5197,8 +5227,7 @@ handle_warn_unused_result_attribute (tre
 /* 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);
@@ -5208,17 +5237,38 @@ handle_sentinel_attribute (tree *node, t
       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 -rup orig/egcc-CVS20040901/gcc/doc/extend.texi egcc-CVS20040901/gcc/doc/extend.texi
--- orig/egcc-CVS20040901/gcc/doc/extend.texi	2004-09-01 09:22:56.677426000 -0400
+++ egcc-CVS20040901/gcc/doc/extend.texi	2004-09-01 11:22:13.523632000 -0400
@@ -2113,15 +2113,30 @@ section, consider using the facilities o
 
 @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 -rup orig/egcc-CVS20040901/gcc/testsuite/gcc.dg/format/sentinel-1.c egcc-CVS20040901/gcc/testsuite/gcc.dg/format/sentinel-1.c
--- orig/egcc-CVS20040901/gcc/testsuite/gcc.dg/format/sentinel-1.c	2004-09-01 09:22:56.717405000 -0400
+++ egcc-CVS20040901/gcc/testsuite/gcc.dg/format/sentinel-1.c	2004-09-01 12:25:14.725026000 -0400
@@ -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 *, ...) ATT
 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);
 }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]