va_list: rfc: invalid types

Richard Henderson rth@cygnus.com
Thu Sep 30 23:58:00 GMT 1999


On Sun, Sep 05, 1999 at 06:52:56PM -0700, Mark Mitchell wrote:
> How about an error unless the sizes of the types are the same, and
> then a pedwarn?  There's little harm using `float' if `float' and
> `double' are the same, and we already allow lots of other mistakes
> like this.  But, an error doesn't really bother me either.

I went with the error.

> How about:
> 
>    `char' is promoted to `int' when passed through `...'
> 
> and, if it's the first time we issue the message,
> 
>    (and so you should pass `int', not `char' to `va_arg')

And I liked this suggestion best.  Appended is the patch I committed.



r~


        * c-typeck.c (type_lists_compatible_p): Use simple_type_promotes_to.
        (self_promoting_type_p): Delete.
        (self_promoting_args_p): Move ...
        * c-common.c: ... here.
        (c_common_nodes_and_builtins): Initialize lang_type_promotes_to.
        (simple_type_promotes_to): New.
        * builtins.c (lang_type_promotes_to): New.
        (expand_builtin_va_arg): Use it to give diagnostic for illegal types.
        * c-tree.h (C_PROMOTING_INTEGER_TYPE_P): Move ...
        * c-common.h: ... here.
        (self_promoting_args_p, simple_type_promotes_to): Declare.
        * c-decl.c (duplicate_decls): Use simple_type_promotes_to.
        (grokdeclarator): Likewise.
        * tree.h (lang_type_promotes_to): Declare.

        * cp-tree.h (C_PROMOTING_INTEGER_TYPE_P): Delete.
        * typeck.c (self_promoting_args_p): Delete.

        * gcc.dg/va-arg-1.c: New.

Index: builtins.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/builtins.c,v
retrieving revision 1.9
diff -c -p -d -r1.9 builtins.c
*** builtins.c	1999/08/26 05:18:40	1.9
--- builtins.c	1999/09/08 04:18:04
*************** Boston, MA 02111-1307, USA.  */
*** 52,57 ****
--- 52,59 ----
  #define OUTGOING_REGNO(IN) (IN)
  #endif
  
+ tree (*lang_type_promotes_to) PROTO((tree));
+ 
  static int get_pointer_alignment	PROTO((tree, unsigned));
  static tree c_strlen			PROTO((tree));
  static rtx get_memory_rtx		PROTO((tree));
*************** expand_builtin_va_arg (valist, type)
*** 1972,1982 ****
       tree valist, type;
  {
    rtx addr, result;
  
    if (TYPE_MAIN_VARIANT (TREE_TYPE (valist))
        != TYPE_MAIN_VARIANT (va_list_type_node))
      {
!       error ("first argument to `__builtin_va_arg' not of type `va_list'");
        addr = const0_rtx;
      }
    else
--- 1974,2016 ----
       tree valist, type;
  {
    rtx addr, result;
+   tree promoted_type;
  
    if (TYPE_MAIN_VARIANT (TREE_TYPE (valist))
        != TYPE_MAIN_VARIANT (va_list_type_node))
      {
!       error ("first argument to `va_arg' not of type `va_list'");
!       addr = const0_rtx;
!     }
!   else if ((promoted_type = (*lang_type_promotes_to) (type)) != NULL_TREE)
!     {
!       const char *name = "<anonymous type>", *pname;
!       static int gave_help;
! 
!       if (TYPE_NAME (type))
! 	{
! 	  if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
! 	    name = IDENTIFIER_POINTER (TYPE_NAME (type));
! 	  else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
! 		   && DECL_NAME (TYPE_NAME (type)))
! 	    name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
! 	}
!       if (TYPE_NAME (promoted_type))
! 	{
! 	  if (TREE_CODE (TYPE_NAME (promoted_type)) == IDENTIFIER_NODE)
! 	    pname = IDENTIFIER_POINTER (TYPE_NAME (promoted_type));
! 	  else if (TREE_CODE (TYPE_NAME (promoted_type)) == TYPE_DECL
! 		   && DECL_NAME (TYPE_NAME (promoted_type)))
! 	    pname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (promoted_type)));
! 	}
! 
!       error ("`%s' is promoted to `%s' when passed through `...'", name, pname);
!       if (! gave_help)
! 	{
! 	  gave_help = 1;
! 	  error ("(so you should pass `%s' not `%s' to `va_arg')", pname, name);
! 	}
! 
        addr = const0_rtx;
      }
    else
Index: c-common.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.c,v
retrieving revision 1.67
diff -c -p -d -r1.67 c-common.c
*** c-common.c	1999/09/06 21:28:19	1.67
--- c-common.c	1999/09/08 04:18:04
*************** c_common_nodes_and_builtins (cplus_mode,
*** 3804,3809 ****
--- 3804,3813 ----
    builtin_function ("__builtin_getman", double_ftype_double, BUILT_IN_GETMAN,
  		    NULL_PTR);
  #endif
+ 
+   /* ??? Perhaps there's a better place to do this.  But it is related
+      to __builtin_va_arg, so it isn't that off-the-wall.  */
+   lang_type_promotes_to = simple_type_promotes_to;
  }
  
  tree
*************** initializer_constant_valid_p (value, end
*** 3967,3970 ****
--- 3971,4028 ----
  
    return 0;
  }
+ 
+ /* Given a type, apply default promotions wrt unnamed function arguments
+    and return the new type.  Return NULL_TREE if no change.  */
+ /* ??? There is a function of the same name in the C++ front end that 
+    does something similar, but is more thorough and does not return NULL
+    if no change.  We could perhaps share code, but it would make the 
+    self_promoting_type property harder to identify.  */
+ 
+ tree
+ simple_type_promotes_to (type)
+      tree type;
+ {
+   if (TYPE_MAIN_VARIANT (type) == float_type_node)
+     return double_type_node;
+ 
+   if (C_PROMOTING_INTEGER_TYPE_P (type))
+     {
+       /* Traditionally, unsignedness is preserved in default promotions.
+          Also preserve unsignedness if not really getting any wider.  */
+       if (TREE_UNSIGNED (type)
+           && (flag_traditional
+               || TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)))
+         return unsigned_type_node;
+       return integer_type_node;
+     }
+ 
+   return NULL_TREE;
+ }
+ 
+ /* Return 1 if PARMS specifies a fixed number of parameters
+    and none of their types is affected by default promotions.  */
+ 
+ int
+ self_promoting_args_p (parms)
+      tree parms;
+ {
+   register tree t;
+   for (t = parms; t; t = TREE_CHAIN (t))
+     {
+       register tree type = TREE_VALUE (t);
  
+       if (TREE_CHAIN (t) == 0 && type != void_type_node)
+ 	return 0;
+ 
+       if (type == 0)
+ 	return 0;
+ 
+       if (TYPE_MAIN_VARIANT (type) == float_type_node)
+ 	return 0;
+ 
+       if (C_PROMOTING_INTEGER_TYPE_P (type))
+ 	return 0;
+     }
+   return 1;
+ }
Index: c-common.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-common.h,v
retrieving revision 1.4
diff -c -p -d -r1.4 c-common.h
*** c-common.h	1999/07/31 01:13:08	1.4
--- c-common.h	1999/09/08 04:18:04
*************** extern void c_common_nodes_and_builtins	
*** 192,194 ****
--- 192,208 ----
  extern tree build_va_arg			PROTO((tree, tree));
  
  extern tree initializer_constant_valid_p	PROTO((tree, tree));
+ 
+ /* Nonzero if the type T promotes to itself.
+    ANSI C states explicitly the list of types that promote;
+    in particular, short promotes to int even if they have the same width.  */
+ #define C_PROMOTING_INTEGER_TYPE_P(t)				\
+   (TREE_CODE ((t)) == INTEGER_TYPE				\
+    && (TYPE_MAIN_VARIANT (t) == char_type_node			\
+        || TYPE_MAIN_VARIANT (t) == signed_char_type_node	\
+        || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node	\
+        || TYPE_MAIN_VARIANT (t) == short_integer_type_node	\
+        || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node))
+ 
+ extern int self_promoting_args_p		PROTO((tree));
+ extern tree simple_type_promotes_to		PROTO((tree));
Index: c-decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-decl.c,v
retrieving revision 1.70
diff -c -p -d -r1.70 c-decl.c
*** c-decl.c	1999/09/07 05:47:26	1.70
--- c-decl.c	1999/09/08 04:18:04
*************** duplicate_decls (newdecl, olddecl, diffe
*** 1664,1671 ****
  		  break;
  		}
  
! 	      if (TYPE_MAIN_VARIANT (type) == float_type_node
! 		  || C_PROMOTING_INTEGER_TYPE_P (type))
  		{
  		  error ("An argument type that has a default promotion can't match an empty parameter name list declaration.");
  		  break;
--- 1664,1670 ----
  		  break;
  		}
  
! 	      if (simple_type_promotes_to (type) != NULL_TREE)
  		{
  		  error ("An argument type that has a default promotion can't match an empty parameter name list declaration.");
  		  break;
*************** grokdeclarator (declarator, declspecs, d
*** 4858,4864 ****
      if (decl_context == PARM)
        {
  	tree type_as_written = type;
! 	tree main_type;
  
  	/* A parameter declared as an array of T is really a pointer to T.
  	   One declared as a function is really a pointer to a function.  */
--- 4857,4863 ----
      if (decl_context == PARM)
        {
  	tree type_as_written = type;
! 	tree promoted_type;
  
  	/* A parameter declared as an array of T is really a pointer to T.
  	   One declared as a function is really a pointer to a function.  */
*************** grokdeclarator (declarator, declspecs, d
*** 4892,4916 ****
  	   (For example, shorts and chars are passed as ints.)
  	   When there is a prototype, this is overridden later.  */
  
! 	DECL_ARG_TYPE (decl) = type;
! 	main_type = (type == error_mark_node
! 		     ? error_mark_node
! 		     : TYPE_MAIN_VARIANT (type));
! 	if (main_type == float_type_node)
! 	  DECL_ARG_TYPE (decl) = double_type_node;
! 	/* Don't use TYPE_PRECISION to decide whether to promote,
! 	   because we should convert short if it's the same size as int,
! 	   but we should not convert long if it's the same size as int.  */
! 	else if (TREE_CODE (main_type) != ERROR_MARK
! 		 && C_PROMOTING_INTEGER_TYPE_P (main_type))
  	  {
! 	    if (TYPE_PRECISION (type) == TYPE_PRECISION (integer_type_node)
! 		&& TREE_UNSIGNED (type))
! 	      DECL_ARG_TYPE (decl) = unsigned_type_node;
! 	    else
! 	      DECL_ARG_TYPE (decl) = integer_type_node;
  	  }
  
  	DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written;
        }
      else if (decl_context == FIELD)
--- 4891,4906 ----
  	   (For example, shorts and chars are passed as ints.)
  	   When there is a prototype, this is overridden later.  */
  
! 	if (type == error_mark_node)
! 	  promoted_type = type;
! 	else
  	  {
! 	    promoted_type = simple_type_promotes_to (type);
! 	    if (! promoted_type)
! 	      promoted_type = type;
  	  }
  
+ 	DECL_ARG_TYPE (decl) = promoted_type;
  	DECL_ARG_TYPE_AS_WRITTEN (decl) = type_as_written;
        }
      else if (decl_context == FIELD)
Index: c-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-tree.h,v
retrieving revision 1.25
diff -c -p -d -r1.25 c-tree.h
*** c-tree.h	1999/09/06 21:28:21	1.25
--- c-tree.h	1999/09/08 04:18:05
*************** struct lang_type
*** 145,161 ****
  /* In a FIELD_DECL, nonzero if the decl was originally a bitfield.  */
  #define DECL_C_BIT_FIELD(NODE) DECL_LANG_FLAG_4 (NODE)
  
- /* Nonzero if the type T promotes to itself.
-    ANSI C states explicitly the list of types that promote;
-    in particular, short promotes to int even if they have the same width.  */
- #define C_PROMOTING_INTEGER_TYPE_P(t)				\
-   (TREE_CODE ((t)) == INTEGER_TYPE				\
-    && (TYPE_MAIN_VARIANT (t) == char_type_node			\
-        || TYPE_MAIN_VARIANT (t) == signed_char_type_node	\
-        || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node	\
-        || TYPE_MAIN_VARIANT (t) == short_integer_type_node	\
-        || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node))
- 
  /* In a VAR_DECL, means the variable is really an iterator.  */
  #define ITERATOR_P(D) (DECL_LANG_FLAG_4(D))
  
--- 145,150 ----
*************** extern void incomplete_type_error		PROTO
*** 260,266 ****
     Given two compatible ANSI C types, returns the merged type.  */
  extern tree common_type                         PROTO((tree, tree));
  extern int comptypes				PROTO((tree, tree));
- extern int self_promoting_args_p		PROTO((tree));
  extern tree c_sizeof                            PROTO((tree));
  extern tree c_sizeof_nowarn                     PROTO((tree));
  extern tree c_size_in_bytes                     PROTO((tree));
--- 249,254 ----
Index: c-typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-typeck.c,v
retrieving revision 1.35
diff -c -p -d -r1.35 c-typeck.c
*** c-typeck.c	1999/09/07 05:47:29	1.35
--- c-typeck.c	1999/09/08 04:18:05
*************** static tree qualify_type		PROTO((tree, t
*** 48,54 ****
  static int comp_target_types		PROTO((tree, tree));
  static int function_types_compatible_p	PROTO((tree, tree));
  static int type_lists_compatible_p	PROTO((tree, tree));
- static int self_promoting_type_p	PROTO((tree));
  static tree decl_constant_value		PROTO((tree));
  static tree lookup_field		PROTO((tree, tree, tree *));
  static tree convert_arguments		PROTO((tree, tree, tree, tree));
--- 48,53 ----
*************** type_lists_compatible_p (args1, args2)
*** 626,637 ****
  	 So match anything that self-promotes.  */
        if (TREE_VALUE (args1) == 0)
  	{
! 	  if (! self_promoting_type_p (TREE_VALUE (args2)))
  	    return 0;
  	}
        else if (TREE_VALUE (args2) == 0)
  	{
! 	  if (! self_promoting_type_p (TREE_VALUE (args1)))
  	    return 0;
  	}
        else if (! (newval = comptypes (TREE_VALUE (args1), TREE_VALUE (args2))))
--- 625,636 ----
  	 So match anything that self-promotes.  */
        if (TREE_VALUE (args1) == 0)
  	{
! 	  if (simple_type_promotes_to (TREE_VALUE (args2)) != NULL_TREE)
  	    return 0;
  	}
        else if (TREE_VALUE (args2) == 0)
  	{
! 	  if (simple_type_promotes_to (TREE_VALUE (args1)) != NULL_TREE)
  	    return 0;
  	}
        else if (! (newval = comptypes (TREE_VALUE (args1), TREE_VALUE (args2))))
*************** type_lists_compatible_p (args1, args2)
*** 679,726 ****
        args1 = TREE_CHAIN (args1);
        args2 = TREE_CHAIN (args2);
      }
- }
- 
- /* Return 1 if PARMS specifies a fixed number of parameters
-    and none of their types is affected by default promotions.  */
- 
- int
- self_promoting_args_p (parms)
-      tree parms;
- {
-   register tree t;
-   for (t = parms; t; t = TREE_CHAIN (t))
-     {
-       register tree type = TREE_VALUE (t);
- 
-       if (TREE_CHAIN (t) == 0 && type != void_type_node)
- 	return 0;
- 
-       if (type == 0)
- 	return 0;
- 
-       if (TYPE_MAIN_VARIANT (type) == float_type_node)
- 	return 0;
- 
-       if (C_PROMOTING_INTEGER_TYPE_P (type))
- 	return 0;
-     }
-   return 1;
- }
- 
- /* Return 1 if TYPE is not affected by default promotions.  */
- 
- static int
- self_promoting_type_p (type)
-      tree type;
- {
-   if (TYPE_MAIN_VARIANT (type) == float_type_node)
-     return 0;
- 
-   if (C_PROMOTING_INTEGER_TYPE_P (type))
-     return 0;
- 
-   return 1;
  }
  
  /* Compute the value of the `sizeof' operator.  */
--- 678,683 ----
Index: tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/tree.h,v
retrieving revision 1.86
diff -c -p -d -r1.86 tree.h
*** tree.h	1999/09/07 05:48:11	1.86
--- tree.h	1999/09/08 04:18:05
*************** extern void rrotate_double	PROTO((HOST_W
*** 2040,2045 ****
--- 2040,2051 ----
  				       HOST_WIDE_INT *));
  extern int operand_equal_p	PROTO((tree, tree, int));
  extern tree invert_truthvalue	PROTO((tree));
+ 
+ /* In builtins.c.  Given a type, apply default promotions wrt unnamed
+    function arguments and return the new type.  Return NULL_TREE if no
+    change.  Required by any language that supports variadic arguments.  */
+ 
+ extern tree (*lang_type_promotes_to)	PROTO((tree));
  
  /* Interface of the DWARF2 unwind info support.  */
  
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.287
diff -c -p -d -r1.287 cp-tree.h
*** cp-tree.h	1999/09/07 16:07:19	1.287
--- cp-tree.h	1999/09/08 04:18:07
*************** extern int flag_new_for_scope;
*** 1902,1918 ****
  #define SET_DECL_C_BIT_FIELD(NODE) \
    (DECL_LANG_SPECIFIC (NODE)->decl_flags.bitfield = 1)
  
- /* Nonzero if the type T promotes to itself.
-    ANSI C states explicitly the list of types that promote;
-    in particular, short promotes to int even if they have the same width.  */
- #define C_PROMOTING_INTEGER_TYPE_P(t)				\
-   (TREE_CODE ((t)) == INTEGER_TYPE				\
-    && (TYPE_MAIN_VARIANT (t) == char_type_node			\
-        || TYPE_MAIN_VARIANT (t) == signed_char_type_node	\
-        || TYPE_MAIN_VARIANT (t) == unsigned_char_type_node	\
-        || TYPE_MAIN_VARIANT (t) == short_integer_type_node	\
-        || TYPE_MAIN_VARIANT (t) == short_unsigned_type_node))
- 
  #define INTEGRAL_CODE_P(CODE) \
    (CODE == INTEGER_TYPE || CODE == ENUMERAL_TYPE || CODE == BOOLEAN_TYPE)
  
--- 1902,1907 ----
*************** extern int compparms				PROTO((tree, tre
*** 3751,3757 ****
  extern int comp_target_types			PROTO((tree, tree, int));
  extern int comp_cv_qualification                PROTO((tree, tree));
  extern int comp_cv_qual_signature               PROTO((tree, tree));
- extern int self_promoting_args_p		PROTO((tree));
  extern tree unsigned_type			PROTO((tree));
  extern tree signed_type				PROTO((tree));
  extern tree signed_or_unsigned_type		PROTO((int, tree));
--- 3740,3745 ----
Index: cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.202
diff -c -p -d -r1.202 typeck.c
*** typeck.c	1999/09/04 02:19:29	1.202
--- typeck.c	1999/09/08 04:18:07
*************** comp_target_parms (parms1, parms2, stric
*** 1623,1655 ****
      }
    return warn_contravariance ? -1 : 1;
  }
- 
- /* Return 1 if PARMS specifies a fixed number of parameters
-    and none of their types is affected by default promotions.  */
- 
- int
- self_promoting_args_p (parms)
-      tree parms;
- {
-   register tree t;
-   for (t = parms; t; t = TREE_CHAIN (t))
-     {
-       register tree type = TREE_VALUE (t);
- 
-       if (TREE_CHAIN (t) == 0 && type != void_type_node)
- 	return 0;
- 
-       if (type == 0)
- 	return 0;
- 
-       if (TYPE_MAIN_VARIANT (type) == float_type_node)
- 	return 0;
- 
-       if (C_PROMOTING_INTEGER_TYPE_P (type))
- 	return 0;
-     }
-   return 1;
- }
  
  /* Compute the value of the `sizeof' operator.  */
  
--- 1623,1628 ----
Index: testsuite/gcc.dg/va-arg-1.c
===================================================================
RCS file: va-arg-1.c
diff -N va-arg-1.c
*** /dev/null	Sat Dec  5 20:30:03 1998
--- va-arg-1.c	Tue Sep  7 21:18:08 1999
***************
*** 0 ****
--- 1,13 ----
+ /* { dg-do compile } */
+ 
+ #include <stdarg.h>
+ 
+ va_list v;
+ volatile int i;
+ 
+ void foo()
+ {
+   i = va_arg(v, char); /* { dg-error "is promoted to|so you should" "char" } */
+   i = va_arg(v, short); /* { dg-error "is promoted to" "short" } */
+   i = va_arg(v, float); /* { dg-error "is promoted to" "float" } */
+ }



More information about the Gcc-patches mailing list