builtins: choose_expr and types_compatible_p

Aldy Hernandez aldyh@redhat.com
Sat Dec 8 11:40:00 GMT 2001


On Sat, 2001-12-08 at 06:05, Joseph S. Myers wrote:

*sigh* and i tried so hard to get the docs and tests right :).  i
appreciate your input.

> On 7 Dec 2001, Aldy Hernandez wrote:
> 
> > + 		  $$ = e1 == e2 ? build_int_2 (1, 0) : build_int_2 (0, 0);
> 
> The test should be *compatibility* (comptypes), not comparing the tree
> nodes for equality.

ahh, i think all my doc errors stem from this mistake.

> * this is C-only (otherwise, the code would need to support it for C++ as
> well); and

fixed.

> * the unused part of __builtin_choose_expr may still generate errors
> (though this should be fixed when the necessary diagnostics support is on
> the mainline, and the docs should note that it may change).

fixed

> "builtin" is not a word; see codingconventions.html.  You should say
> "built-in function" as a noun; or phrases such as "this is built in".

hmm, fixed.

> @code{const}, @code{volatile}.  static isn't a qualifier, it's a storage
> class specifier.

fixed.

> > + The type @code{int[]} and @code{int[5]} are compatible.  On the other
> 
> All examples in the documentation should be covered in the testcases.  As
> is, some of them don't work.

fixed.  fixed.

> > + An @code{enum} type is not considered to be compatible with another
> > + @code{enum} type.  For example, @code{enum @{foo, bar@}} is not similar
> 
> This is wrong - they should be compatible (and this should be tested) when
> the implementation-defined types the enums are compatible with (6.7.2.2#4)  
> are the same.

fixed

> > + to @code{enum @{hot, dog@}}.  However, the type of an @code{enum}
> > + element is considered to be of the same type as the type of any another
> > + @code{enum} element.  In the above example, @code{hot} has the same type
> > + as @code{bar}.  Lastly, @code{enum} elements are considered to have the
> > + same type as an @code{int}.  In the above example, @code{foo} has the
> > + same type as @code{int}.
> 
> Enumeration constants *have* type int (6.4.4.3#2).  Can't we assume users
> are familiar with the basics of the language?

fixed

> > + @deftypefn {Built-in Function} int __builtin_choose_expr (@var{const_exp}, @var{exp1}, @var{exp2})
> 
> The return type isn't int - it should be written @var{type}.

fixed

> > + expression that must be able to be determined at runtime, is non zero.
> 
> "nonzero".

fixed

> Use @r{} around English text in comments in examples.

really?  like this:? 

	@{/* foobar more foobar }
	@{   more and more foo }

or like:

	@{/* foobar more foobar
	     more and more foo}

anyways, fixed like the former.  lemee know.

> This isn't what you want here - since you're not checking conditional
> expressions, but __builtin_choose_expr - you want to adapt it to test that
> with 0 used __builtin_choose_expr has the type of one argument, and with 1
> used it has the type of the other argument.

feeeexhed.

weeee. how's this patch?

-- 
Aldy Hernandez			E-mail: aldyh@redhat.com
Professional Gypsy
Red Hat, Inc.

2001-10-07  Aldy Hernandez  <aldyh@redhat.com>

        * testsuite/gcc.c-torture/execute/builtin-types-compatible-p.c: New.

        * testsuite/gcc.c-torture/gcc.dg/builtin-choose-expr.c: New.

        * c-common.h (rid): Add RID_CHOOSE_EXPR and
        RID_TYPES_COMPATIBLE_P.

        * c-parse.in (reswords): Add __builtin_choose_expr.
        Add __builtin_types_compatible_p.
        Add CHOOSE_EXPR token.
        Add TYPES_COMPATIBLE_P token.
        Add production for CHOOSE_EXPR.
        Add production for TYPES_COMPATIBLE_P.

        * doc/extend.texi (__builtin_choose_expr): Add documentation.
        (__builtin_types_compatible_p): Likewise.


Index: c-common.h
===================================================================
RCS file: /cvs/uberbaum/gcc/c-common.h,v
retrieving revision 1.104
diff -c -p -r1.104 c-common.h
*** c-common.h	2001/12/05 23:19:55	1.104
--- c-common.h	2001/12/08 19:07:02
*************** enum rid
*** 74,80 ****
    /* C extensions */
    RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_PTRBASE,
!   RID_PTREXTENT, RID_PTRVALUE,
  
    /* Too many ways of getting the name of a function as a string */
    RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
--- 74,80 ----
    /* C extensions */
    RID_ASM,       RID_TYPEOF,   RID_ALIGNOF,  RID_ATTRIBUTE,  RID_VA_ARG,
    RID_EXTENSION, RID_IMAGPART, RID_REALPART, RID_LABEL,      RID_PTRBASE,
!   RID_PTREXTENT, RID_PTRVALUE, RID_CHOOSE_EXPR, RID_TYPES_COMPATIBLE_P,
  
    /* Too many ways of getting the name of a function as a string */
    RID_FUNCTION_NAME, RID_PRETTY_FUNCTION_NAME, RID_C99_FUNCTION_NAME,
Index: c-parse.in
===================================================================
RCS file: /cvs/uberbaum/gcc/c-parse.in,v
retrieving revision 1.118
diff -c -p -r1.118 c-parse.in
*** c-parse.in	2001/12/08 12:01:52	1.118
--- c-parse.in	2001/12/08 19:07:02
*************** end ifobjc
*** 110,116 ****
  %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
  %token ATTRIBUTE EXTENSION LABEL
! %token REALPART IMAGPART VA_ARG
  %token PTR_VALUE PTR_BASE PTR_EXTENT
  
  /* function name can be a string const or a var decl. */
--- 110,116 ----
  %token SIZEOF ENUM STRUCT UNION IF ELSE WHILE DO FOR SWITCH CASE DEFAULT
  %token BREAK CONTINUE RETURN GOTO ASM_KEYWORD TYPEOF ALIGNOF
  %token ATTRIBUTE EXTENSION LABEL
! %token REALPART IMAGPART VA_ARG CHOOSE_EXPR TYPES_COMPATIBLE_P
  %token PTR_VALUE PTR_BASE PTR_EXTENT
  
  /* function name can be a string const or a var decl. */
*************** primary:
*** 670,675 ****
--- 670,695 ----
  		{ $$ = build_function_call ($1, $3); }
  	| VA_ARG '(' expr_no_commas ',' typename ')'
  		{ $$ = build_va_arg ($3, groktypename ($5)); }
+       | CHOOSE_EXPR '(' expr_no_commas ',' expr_no_commas ',' expr_no_commas ')'
+ 		{
+                   tree c;
+ 
+                   c = fold ($3);
+                   STRIP_NOPS (c);
+                   if (TREE_CODE (c) != INTEGER_CST)
+                     error ("first argument to __builtin_choose_expr not a constant");
+                   $$ = integer_zerop (c) ? $7 : $5;
+ 		}
+       | TYPES_COMPATIBLE_P '(' typename ',' typename ')'
+ 		{
+ 		  tree e1, e2;
+ 
+ 		  e1 = TYPE_MAIN_VARIANT (groktypename ($3));
+ 		  e2 = TYPE_MAIN_VARIANT (groktypename ($5));
+ 
+ 		  $$ = comptypes (e1, e2)
+ 		    ? build_int_2 (1, 0) : build_int_2 (0, 0);
+ 		}
  	| primary '[' expr ']'   %prec '.'
  		{ $$ = build_array_ref ($1, $3); }
  	| primary '.' identifier
*************** static const struct resword reswords[] =
*** 3224,3229 ****
--- 3244,3251 ----
    { "__attribute__",	RID_ATTRIBUTE,	0 },
    { "__bounded",	RID_BOUNDED,	0 },
    { "__bounded__",	RID_BOUNDED,	0 },
+   { "__builtin_choose_expr", RID_CHOOSE_EXPR, 0 },
+   { "__builtin_types_compatible_p", RID_TYPES_COMPATIBLE_P, 0 },
    { "__builtin_va_arg",	RID_VA_ARG,	0 },
    { "__complex",	RID_COMPLEX,	0 },
    { "__complex__",	RID_COMPLEX,	0 },
*************** static const short rid_to_yy[RID_MAX] =
*** 3395,3400 ****
--- 3417,3425 ----
    /* RID_PTRBASE */	PTR_BASE,
    /* RID_PTREXTENT */	PTR_EXTENT,
    /* RID_PTRVALUE */	PTR_VALUE,
+ 
+   /* RID_CHOOSE_EXPR */			CHOOSE_EXPR,
+   /* RID_TYPES_COMPATIBLE_P */		TYPES_COMPATIBLE_P,
  
    /* RID_FUNCTION_NAME */		STRING_FUNC_NAME,
    /* RID_PRETTY_FUNCTION_NAME */	STRING_FUNC_NAME,
Index: doc/extend.texi
===================================================================
RCS file: /cvs/uberbaum/gcc/doc/extend.texi,v
retrieving revision 1.43
diff -c -p -r1.43 extend.texi
*** extend.texi	2001/12/07 23:00:16	1.43
--- extend.texi	2001/12/08 19:07:03
*************** the same names as the standard macros ( 
*** 4388,4393 ****
--- 4388,4480 ----
  prefixed.  We intend for a library implementor to be able to simply
  @code{#define} each standard macro to its built-in equivalent.
  
+ @deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
+ 
+ You can use the built-in function @code{__builtin_types_compatible_p} to
+ determine whether two types are the same.
+ 
+ This built-in returns 1 if the unqualified versions of the types
+ @var{type1} and @var{type2} (which are types, not expressions) are
+ compatible, 0 otherwise.  The result of this built-in can be used in
+ integer constant expressions.
+ 
+ This built-in ignores top level qualifiers (e.g., @code{const},
+ @code{volatile}).  For example, @code{int} is equivalent to @code{const
+ int}.
+ 
+ The type @code{int[]} and @code{int[5]} are compatible.  On the other
+ hand, @code{int} and @code{char *} are not compatible, even if the size
+ of their types, on the particular architecture are the same.  Also, the
+ amount of pointer indirection is taken into account when determining
+ similarity.  Consequently, @code{short *} is not similar to
+ @code{short **}.  Furthermore, two types that are typedefed are
+ considered compatible if their underlying types are compatible.
+ 
+ An @code{enum} type is considered to be compatible with another
+ @code{enum} type.  For example, @code{enum @{foo, bar@}} is similar to
+ @code{enum @{hot, dog@}}.
+ 
+ You would typically use this function in code whose execution varies
+ depending on the arguments' types.  For example:
+ 
+ @smallexample
+ #define foo(x)                                                        \
+   (@{                                                                 \
+     typeof (x) tmp;                                                   \
+     if (__builtin_types_compatible_p (typeof (x), long double))       \
+       tmp = foo_long_double (tmp);                                    \
+     else if (__builtin_types_compatible_p (typeof (x), double))       \
+       tmp = foo_double (tmp);                                         \
+     else if (__builtin_types_compatible_p (typeof (x), float))        \
+       tmp = foo_float (tmp);                                          \
+     else                                                              \
+       abort ();                                                       \
+     tmp;                                                              \
+   @})
+ @end smallexample
+ 
+ @emph{Note:} This construct is only available for C.
+ 
+ @end deftypefn
+ 
+ @deftypefn {Built-in Function} @var{type} __builtin_choose_expr (@var{const_exp}, @var{exp1}, @var{exp2})
+ 
+ You can use the built-in function @code{__builtin_choose_expr} to
+ evaluate code depending on the value of a constant expression.  This
+ built-in returns @var{exp1} if @var{const_exp}, which is a constant
+ expression that must be able to be determined at runtime, is nonzero.
+ Otherwise it returns 0.
+ 
+ This built-in is analogous to the @code{? :} operator in C, except that
+ the expression returned has its type unaltered by promotion rules.
+ Also, the built-in does not evaluate the expression that was not chosen.
+ For example, if @var{const_exp} evaluates to true, @var{exp2} is not
+ evaluated even if it has side-effects.
+ 
+ If @var{exp1} is returned, the return type is the same as @var{exp1}'s
+ type.  Similarly, if @var{exp2} is returned, its return type is the same
+ as @var{exp2}.
+ 
+ Example:
+ 
+ @smallexample
+ #define foo(x)                                                               \
+   __builtin_choose_expr (__builtin_types_compatible_p (typeof (x), double),  \
+     foo_double (x),                                                          \
+     __builtin_choose_expr (__builtin_types_compatible_p (typeof (x), float), \
+       foo_float (x),                                                         \
+       @r{/* The void expression results in a compile-time error}             \
+       @r{   when assigning the result to something.  */}                     \
+       (void)0))
+ @end smallexample
+ 
+ @emph{Note:} This construct is only available for C.  Furthermore, the
+ unused expression (@var{exp1} or @var{exp2}, depending on the value of
+ @var{const_exp}, may still generate syntax errors.  This may change in
+ future revisions.
+ 
+ @end deftypefn
+ 
  @deftypefn {Built-in Function} int __builtin_constant_p (@var{exp})
  You can use the built-in function @code{__builtin_constant_p} to
  determine if a value is known to be constant at compile-time and hence
Index: testsuite/gcc.dg/builtin-choose-expr.c
===================================================================
RCS file: builtin-choose-expr.c
diff -N builtin-choose-expr.c
*** /dev/null	Tue May  5 13:32:27 1998
--- builtin-choose-expr.c	Sat Dec  8 11:07:03 2001
***************
*** 0 ****
--- 1,70 ----
+ /* { dg-do run { target *-*-* } } */
+ /* { dg-options { "-O1" } } */
+ 
+ #define choose __builtin_choose_expr
+ 
+ /* Assertion that the type of a conditional expression between E1 and E2
+   is T.  Checks the expression both ways round.  */
+ #define ASSERT_COND_TYPE(E1, E2, T)                     	\
+         do {                                            	\
+           typedef T type;                               	\
+           typedef type **typepp;                        	\
+           typedef __typeof(choose (0, (E1), (E2))) ctype;	\
+           typedef __typeof(choose (0, (E2),  (E1))) ctype2;     \
+           typedef ctype **ctypepp;                      	\
+           typedef ctype2 **ctype2pp;                    	\
+           typepp x = 0;                                 	\
+           ctypepp y = 0;                                	\
+           ctype2pp z = 0;                               	\
+           x = y;                                        	\
+           x = z;                                        	\
+         } while (0)
+ 
+ double dd, d;
+ char c;
+ float f;
+ 
+ struct S { int x, y; } pour, some, sugar;
+ 
+ extern void abort ();
+ extern void exit ();
+ 
+ void bad ()
+ {
+   abort ();
+ }
+ 
+ void good ()
+ {
+   exit (0);
+ }
+ 
+ int main (void)
+ {
+   if (__builtin_choose_expr (0, 12, 0)
+       || !__builtin_choose_expr (45, 5, 0)
+       || !__builtin_choose_expr (45, 3, 0))
+     abort ();
+ 
+   ASSERT_COND_TYPE (dd, __builtin_choose_expr (0, 35, d), double);
+ 
+   ASSERT_COND_TYPE (f,
+ 		    __builtin_choose_expr
+ 		    (__builtin_types_compatible_p (char, typeof (c)),
+ 		     3.14F, 's'),
+ 		    float);
+ 
+   pour.y = 69;
+   __builtin_choose_expr (0, bad (), sugar) = pour;
+   if (sugar.y != 69)
+     abort ();
+ 
+   __builtin_choose_expr (sizeof (int), f, bad ()) = 3.5F;
+ 
+   if (f != 3.5F)
+     abort ();
+ 
+   __builtin_choose_expr (1, good, bad)();
+ 
+   exit (0);
+ }
Index: testsuite/gcc.c-torture/execute/builtin-types-compatible-p.c
===================================================================
RCS file: builtin-types-compatible-p.c
diff -N builtin-types-compatible-p.c
*** /dev/null	Tue May  5 13:32:27 1998
--- builtin-types-compatible-p.c	Sat Dec  8 11:07:04 2001
***************
*** 0 ****
--- 1,31 ----
+ int i;
+ double d;
+ 
+ typedef enum { hot, dog, poo, bear } dingos;
+ typedef enum { janette, laura, amanda } cranberry;
+ 
+ typedef float same1;
+ typedef float same2;
+ 
+ int main (void);
+ 
+ int main (void)
+ {
+   /* Compatible types.  */
+   if (!(__builtin_types_compatible_p (int, const int)
+ 	&& __builtin_types_compatible_p (typeof (hot), int)
+ 	&& __builtin_types_compatible_p (typeof (hot), typeof (laura))
+ 	&& __builtin_types_compatible_p (int[5], int[])
+ 	&& __builtin_types_compatible_p (typeof (dingos), typeof (cranberry))
+ 	&& __builtin_types_compatible_p (same1, same2)))
+     abort ();
+ 
+   /* Incompatible types.  */
+   if (__builtin_types_compatible_p (char *, int)
+       || __builtin_types_compatible_p (long double, double)
+       || __builtin_types_compatible_p (typeof (i), typeof (d))
+       || __builtin_types_compatible_p (char, int)
+       || __builtin_types_compatible_p (char *, char **))
+     abort ();
+   exit (0);
+ }



More information about the Gcc-patches mailing list