Subject: Re: glibc-19980524: invalid use of GCC's `transparent union'

From: Gordon Matzigkeit <[email-masked]>
Date: 25 May 1998 15:32:45 -0600

Hi!

>>>>> Roland McGrath writes:

 RM> That is not correct.  The entire purpose of `transparent_union'
 RM> is for this hack, and the purpose of the hack is exactly that
 RM> such redeclarations will work without an error.

I disagree, and believe that it is a good idea to give an error for
such redeclarations.

 RM> If the boneheads broke this in GCC again, either it has to get
 RM> fixed or we have to just punt this feature entirely and break all
 RM> programs that use `union wait'.

It may very well be that `transparent_union' does not have the same
semantics as when it was originally implemented, but I believe it is
both simpler than the original semantics, and just as functional.

As far as I can tell, you are complaining because it is not possible
to do:

typedef union
  {
    union wait *__uptr;
    int *__iptr;
  } __WAIT_STATUS __attribute__ ((__transparent_union__));

/* Declaration */
extern __pid_t __wait __P ((__WAIT_STATUS __stat_loc));

/* Definition */
__pid_t
__wait (int *__stat_loc)
/* GCC complains about differing types in __wait's signature */
{
  /* some expression involving an int *. */
  return *__stat_loc = 0;
}

Now, I suggest that the above sequence of code is in bad style.  The
definition of __wait should use __WAIT_STATUS as its argument type.
The GCC implementors seem to agree with me.

So, my patch changes libc to do something like the following, in line
with the example in the GCC manual (*Note (gcc)Type Attributes::):

[omitting some hairy #if blocks...]
#  define __WAIT_PTR(stat_loc)	((stat_loc).__iptr)
[...]
/* Definition */
__pid_t
__wait (__WAIT_STATUS __stat_loc)
{
  return *__WAIT_PTR (stat_loc) = 0;
}

How many packages both #include libc's <sys/wait.h> *and* define their
own __wait function.  I would assert that there are no such packages,
except libc itself.  Even if there *are* packages who do this, then it
is certainly no inconvenience for them to use the macros I have
supplied.

But, that's only half the story (otherwise, there would be no reason
to use a transparent union at all).  The macros I define are fine for
smart implementors of wait, but what about naive users of wait?

The transparent_union allows them to do:

{
  union wait wu;
  int wi;
  float wf;
  wait (&wu);
  wait (&wi);
  wait (&wf);
}

causing GCC to warn about typecasts only on the last `wait' call, even
though to the naked eye it appears as if at least one of the other two
`wait' calls needs a typecast.

I believe that this behaviour is exactly the intention of the original
`transparent_union' flag, and that allowing different function
prototypes is both confusing and unnecessary, and therefore
undesirable.

So, please have another look at my patch.  It implements the above
semantics, and makes them obvious to a reader of the libc code.

Thanks,

-- 
Gordon Matzigkeit   \ Proudly running pieces of the GNU operating system.
[email-masked] \ Jacques Cousteau loved programming in assembler.

---

From: Roland McGrath <[email-masked]>
Date: Mon, 25 May 1998 17:50:01 -0400

> I disagree, and believe that it is a good idea to give an error for

That defeats the explicit purpose of the feature.

>   /* some expression involving an int *. */

I don't care about that per se.  But it *must* be possible to do:

	#include <sys/wait.h>
	pid_t wait(int *);

and it is highly desireable that it work for a prototype using `union wait *'
too.

> Now, I suggest that the above sequence of code is in bad style.

There is no question about that.  It really doesn't matter to me what
machinations are required in the wait.h decls or in the definitions of the
wait functions.  

But redeclarations with prototypes must be allowed; that is the whole point
of this ridiculous kludge.

> prototypes is both confusing and unnecessary, and therefore

I happen to know, being the original instigator of the functionality that
became transparent_union.  That is only half of the job originally intended.
The other half is that naive wait users can do:

	#include <sys/wait.h>
	...
	{
	  extern pid_t wait(int *);
	  int wi;
	  float wf;
	  wait(&wi);
	  wait(&wf);
	}

and the only type error should be the last wait call, just as if the
original decl were `pid_t wait(int *);'.