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