C++PATCH: va_arg & aggr type

Nathan Sidwell nathan@acm.org
Mon Oct 11 01:38:00 GMT 1999


Jason Merrill wrote:
> If the standard doesn't say it's an lvalue, I think we should assume it's
> not.
Okey dokey

> >         const int *i = &va_arg (args, int)
> > needs to be constructable at least internally -- otherwise we force an
> > unnecessary copy.

> That doesn't follow.  That's like saying that
>          const int *i = &(j+2);
> needs to be constructable.
Ok, I was vague in what I meant, and used a scalar example, when I
should've used an aggr. What I meant to convey was that a tree
representing
        const struct X *xp = &va_arg (args, struct X);
would be better than one representing
        struct X _tmp = va_arg (args, struct X);
        const struct X *xp = &_tmp;
which has the copy -- and at the moment doesn't work 'cos of the
problem I'm trying to fix in lvalue_p_1. (An optimization, not a legality
argument.)

> > It occurs to me that we should also be decaying array and function types
> > here, (to match the default conversion in `...'), but I'm not sure.

> I would agree.
C9X says the type given to va_arg should be such
that a pointer to that type can be formed by suffixing a `*' (so the
_form_ of the type arg is important, if we want to do a thorough job of
diagnosing undefined behaviour). And that
the type needs to be compatible with the default promotions which
happen in passing through `...'. We do error about 'char' etc, but
not about funcs and arrays. It all falls into undefined behaviour
otherwise. It seems to be that simple_type_promotes_to (c-common.c)
doesn't do a full job. Its comment
/* ??? 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.  */
mentions something similar in c++, but I can't find it, and we certainly
don't set lang_type_promotes_to to point to anything, to DTRT. Hence the
updated attached patch which does this. (Though it does lead to rather
icky error messages, due to the common part of the compiler not having
the capabilities of cp_error et al.)

> > *************** lvalue_p_1 (ref, treat_class_rvalues_as_
> > *** 142,147 ****
> > --- 142,148 ----
> >                      treat_class_rvalues_as_lvalues);
  
> >       case TARGET_EXPR:
> > +     case VA_ARG_EXPR:
> >         return treat_class_rvalues_as_lvalues ? clk_class : clk_none;

> We can get VA_ARG_EXPRs for non-class types, can't we?
Yes, but we only need to treat aggr things as lvalues so that we can
copy them. We don't want va_arg to give an lvalue do we? But, in that
case we need to check that TREE_TYPE (ref) is an aggr type, so I attach
the an updated patch. (This does mean that I don't understand why
TARGET_EXPR doesn't do such a check.)

This one ok?

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
        I have seen the death of PhotoShop -- it is called GIMP
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
1999-10-11  Nathan Sidwell  <nathan@acm.org>

	* cp-tree.h (build_x_va_arg): Prototype new function.
	(convert_type_from_ellipsis): Prototype new function.
	* call.c (build_x_va_arg): Define it.
	(convert_type_from_ellipsis): Define it.
	* parse.y (unary_expr): Call it.
	* decl.c (init_decl_processing): Set lang_type_promotes_to.
	
	* tree.c (lvalue_p_1): Accept VA_ARG_EXPR.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/call.c,v
retrieving revision 1.176
diff -c -3 -p -r1.176 call.c
*** call.c	1999/10/06 19:01:42	1.176
--- call.c	1999/10/11 08:23:40
*************** convert_arg_to_ellipsis (arg)
*** 3813,3818 ****
--- 3813,3860 ----
    return arg;
  }
  
+ /* va_arg (EXPR, TYPE) is a builtin. Make sure it is not abused.  */
+ 
+ tree
+ build_x_va_arg (expr, type)
+      tree expr;
+      tree type;
+ {
+   type = complete_type_or_else (type, NULL_TREE);
+ 
+   if (expr == error_mark_node || !type)
+     return error_mark_node;
+   
+   if (! pod_type_p (type))
+     {
+       /* Undefined behaviour [expr.call] 5.2.2/7.  */
+       cp_warning ("cannot receive objects of non-POD type `%#T' through `...'",
+ 		  type);
+     }
+   
+   return build_va_arg (expr, type);
+ }
+ 
+ /* TYPE has been given to va_arg. Apply the default conversions which would
+    have happened when passed via ellipsis. Return the promoted type, or
+    NULL_TREE, if there is no change.  */
+ 
+ tree
+ convert_type_from_ellipsis (type)
+      tree type;
+ {
+   tree promote;
+   
+   if (TREE_CODE (type) == ARRAY_TYPE)
+     promote = build_pointer_type (TREE_TYPE (type));
+   else if (TREE_CODE (type) == FUNCTION_TYPE)
+     promote = build_pointer_type (type);
+   else
+     promote = type_promotes_to (type);
+   
+   return same_type_p (type, promote) ? NULL_TREE : promote;
+ }
+ 
  /* ARG is a default argument expression being passed to a parameter of
     the indicated TYPE, which is a parameter to FN.  Do any required
     conversions.  Return the converted value.  */
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.330
diff -c -3 -p -r1.330 cp-tree.h
*** cp-tree.h	1999/10/08 05:50:43	1.330
--- cp-tree.h	1999/10/11 08:23:44
*************** extern int can_convert_arg			PROTO((tree
*** 3270,3275 ****
--- 3270,3277 ----
  extern int enforce_access                       PROTO((tree, tree));
  extern tree convert_default_arg                 PROTO((tree, tree, tree));
  extern tree convert_arg_to_ellipsis             PROTO((tree));
+ extern tree build_x_va_arg                      PROTO((tree, tree));
+ extern tree convert_type_from_ellipsis          PROTO((tree));
  extern int is_properly_derived_from             PROTO((tree, tree));
  extern tree initialize_reference                PROTO((tree, tree));
  extern tree strip_top_quals                     PROTO((tree));
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.480
diff -c -3 -p -r1.480 decl.c
*** decl.c	1999/10/06 17:48:17	1.480
--- decl.c	1999/10/11 08:23:54
*************** init_decl_processing ()
*** 6221,6226 ****
--- 6221,6227 ----
      = build_pointer_type (build_qualified_type (void_type_node,
  						TYPE_QUAL_CONST));
    c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
+   lang_type_promotes_to = convert_type_from_ellipsis;
  
    void_ftype_ptr
      = build_exception_variant (void_ftype_ptr, empty_except_spec);
Index: cp/parse.y
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/parse.y,v
retrieving revision 1.150
diff -c -3 -p -r1.150 parse.y
*** parse.y	1999/10/03 18:57:12	1.150
--- parse.y	1999/10/11 08:24:06
*************** unary_expr:
*** 1173,1179 ****
  	| IMAGPART cast_expr %prec UNARY
  		{ $$ = build_x_unary_op (IMAGPART_EXPR, $2); }
  	| VA_ARG '(' expr_no_commas ',' type_id ')'
! 		{ $$ = build_va_arg ($3, groktypename ($5.t));
  		  check_for_new_type ("__builtin_va_arg", $5); }
  	;
  
--- 1173,1179 ----
  	| IMAGPART cast_expr %prec UNARY
  		{ $$ = build_x_unary_op (IMAGPART_EXPR, $2); }
  	| VA_ARG '(' expr_no_commas ',' type_id ')'
! 		{ $$ = build_x_va_arg ($3, groktypename ($5.t));
  		  check_for_new_type ("__builtin_va_arg", $5); }
  	;
  
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/tree.c,v
retrieving revision 1.156
diff -c -3 -p -r1.156 tree.c
*** tree.c	1999/10/08 05:50:44	1.156
--- tree.c	1999/10/11 08:24:09
*************** lvalue_p_1 (ref, treat_class_rvalues_as_
*** 145,150 ****
--- 145,151 ----
        return treat_class_rvalues_as_lvalues ? clk_class : clk_none;
  
      case CALL_EXPR:
+     case VA_ARG_EXPR:
        return ((treat_class_rvalues_as_lvalues
  	       && IS_AGGR_TYPE (TREE_TYPE (ref)))
  	      ? clk_class : clk_none);


More information about the Gcc-patches mailing list