Version 1.2 of ai05s/ai05-0089-1.txt

Unformatted version of ai05s/ai05-0089-1.txt version 1.2
Other versions for file ai05s/ai05-0089-1.txt

!standard 8.5.1(5/2)          08-02-21 AI05-0089-1/01
!class binding interpretation 08-01-31
!status No Action (7-0-2) 08-02-10
!status work item 08-01-31
!status received 08-01-28
!priority Low
!difficulty Medium
!qualifier Omission
!subject Renames of components of Unchecked_Union types
!summary
** TBD **
!question
Is the rule stated in 8.5.1(5/2), which forbids the renaming of components that depend on discriminants, intended to apply to components of an unchecked_union object? The current rules (taking approved AI05-0008-1 into account) imply that it depends on whether or not the subtype of the object is constrained or is indefinite. But given that all tests that require reading the discriminant are suppressed, maybe there are other intended permissions concerning the static semantics of such objects?
!recommendation
(See summary.)
!wording
** TBD **
!discussion
It is important to keep in mind that these rules apply to not only renames, but also to the prefix of 'Access and to actuals for generic formal in out parameters. So whatever is decided needs to make sense in all of these places.
On one hand, it is bizarre that the legality of renaming of unchecked union components depend on whether a discriminant default (which will never be stored or used) is given on the declaration of the type. Indeed, such a default simply adds confusion to the declaration; all such types should be treated as mutable.
Moreover, this is an interfacing construct, and interfacing constructs often have to do things that are not kosher (that is, erroneous) in Ada terms. An implementation which tries to prevent erroneousness in such constructs is likely to be harmful (by preventing the ugly stuff that needs to be done in foreign language bindings).
Plus, if the goal is to reduce erroneousness, then all renamings of components of unchecked union types should be banned. But that clearly is too draconian -- especially as these same rules apply to the prefix of 'Access.
On the other hand, having special rules (and capabilities) for unchecked union types could give an incentive to use them outside of their intended interfacing purpose. That would be bad, as it would spread additional erroneousness to an Ada program without a significant additional capability.
Moreover, such special rules would require additional implementation work (to implement the special cases). It's not clear that the benefit of such renaming is worth the additional language and implementation complexity.
So the correct answer is as clear as mud.
--!corrigendum 8.5.1(5/2)
!ACATS Test
!appendix

From: Edmund Schonberg
Sent: Monday, January 28, 2008  10:17 PM

Is the rule stated in 8.5.1 (5/2), which forbids the renaming of  
components that depend on discriminants, intended to apply to  
components of an unchecked_union object?  Maybe it follows from the  
fact that the first subtype of an unchecked_union type is  
unconstrained, but given that all tests that require reading the  
discriminant are suppressed, maybe there are other intended  
permissions concerning the static semantics of such objects?  This  
came up in connection with rather perverse user code that "used to  
work with another compiler", and that may be made to look legal with  
the use of unchecked unions.

****************************************************************

From: Randy Brukardt
Sent: Monday, January 28, 2008  10:37 PM

> Is the rule stated in 8.5.1 (5/2), which forbids the renaming of
> components that depend on discriminants, intended to apply to
> components of an unchecked_union object?

I would think it depends on whether or not the object is "known to be
constrained". (Careful: that rule was rewritten by AI05-0008-1, which
introduced "known to be constrained" and which is somewhat incompatible with
Ada 95 -- because Ada 95 allowed bad renames.)

> Maybe it follows from the
> fact that the first subtype of an unchecked_union type is
> unconstrained, but given that all tests that require reading the
> discriminant are suppressed, maybe there are other intended
> permissions concerning the static semantics of such objects?

I don't think so. With the AI05-0008 rules, what matters is whether the
first subtype is indefinite -- that is, whether it has defaults. It appears
that it would be legal to rename the components if the first subtype is
indefinite (because then all objects would have to have discriminants
specified).

OTOH, that seems weird. It would seem that such renaming should be illegal
since the discriminants can be changed without warning.

> This came up in connection with rather perverse user code that "used to
> work with another compiler", and that may be made to look legal with
> the use of unchecked unions.

Could you give us a better idea of what the perverse code does, so that we
can judge whether or not it should be legal? It's tough to guess what the
rules should be without an example.

****************************************************************

From: Tucker Taft
Sent: Monday, January 28, 2008  10:48 PM

I'm not sure we ever discussed this, and I don't see
any mention of it in the AI.  So lacking any reason
to the contrary, 8.5.1(5/2) should apply.  It is a
bit weird that 8.5.1(5/2) depends on whether the
discriminants have defaults (i.e. whether the type
is definite or indefinite).  This seems somewhat
irrelevant to an unchecked union.  But I suppose not
entirely, since the implicit discriminant of an
unchecked union would be constrained by its initial
value if the discriminants lack defaults, and it
would be erroneous to change it, even though the
associated constraint check is necessarily suppressed.

So bottom line seems to be that 8.5.1(5/2) should
apply to unchecked unions as written.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  5:19 AM

> Could you give us a better idea of what the perverse code does, so that we
> can judge whether or not it should be legal? It's tough to guess what the
> rules should be without an example.

Basically, this is C-style programming in which you have a variable
of the type, and willy nilly you assign and reference fields in it,
being careful to only reference a field if you previously assigned it,
and not expecting any compiler or run time help to enforce that
approach.

Sounds just like what unchecked unions are supposed to be about.

Here is an example showing what is going on:

>      1. package UU_Example is
>      2.    type R (X : Boolean := True) is record
>      3.       case X is
>      4.          when True =>
>      5.             Y : Integer;
>      6.          when False =>
>      7.             Z : Integer;
>      8.       end case;
>      9.    end record;
>     10.    pragma Unchecked_Union (R);
>     11.
>     12.    --  The following is what we would like to work, but the
>     13.    --  renamings are not permitted currently at least according
>     14.    --  to GNAT, but that perhaps should be allowed???
>     15.
>     16.    RV : R;
>     17.    Y : Integer renames RV.Y;    --  ERROR
>                                  |
>         >>> illegal renaming of discriminant-dependent component
> 
>     18.    Z : Integer renames RV.Z;    --  ERROR
>                                  |
>         >>> illegal renaming of discriminant-dependent component
> 
>     19.    ZZ : Integer := RV.Z;        --  OK
>     20.
>     21.    --  Here is what worked for user with old compiler
>     22.    --  with checks suppressed (UGH!). But even with
>     23.    --  checks suppressed, GNAT can tell this is no good
>     24.    --  and erroneous, and warns and raises CE, which seems
>     25.    --  fine since in the general case you don't know if
>     26.    --  RV1 is long enough to have a Z field.
>     27.
>     28.    RV1 : R (True);
>     29.    Y1 : Integer renames RV1.Y;
>     30.    ZZ1 : Integer := RV1.Z;
>                                |
>         >>> warning: component not present in subtype of "R" defined at line 28
>         >>> warning: "Constraint_Error" will be raised at run time
> 
>     31.
>     32.    --  Here is what user is currently using to work around
>     33.    --  this, really ugly, and still erroneous, but GNAT
>     34.    --  does not complain (it might in a future cleverer
>     35.    --  version of course), and happens to allocate the
>     36.    --  maximum space in this situation, so all is OK.
>     37.
>     38.    Var : Boolean := True;
>     39.    RV2 : R (Var);
>     40.    Y2 : Integer renames RV2.Y;
>     41.    ZZ2 : Integer := RV2.Z;
>     42.
>     43.    --  Note: in these examples, there are references to
>     44.    --  fields that are uninitialized, but that's irrelevant
>     45.    --  to the examples, in real life we would assign any
>     46.    --  field before using it.
>     47.
>     48. end;

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  5:30 AM

> So bottom line seems to be that 8.5.1(5/2) should
> apply to unchecked unions as written.

That's the behavior of GNAT, as per previous example,
but (especially since this was never discussed), the
question is whether it makes sense to relax the rule
for unchecked unions.

Of course you can only allow this where there is
a default, and it would not work for a compiler
that did not allocate the max size in this case,
but I can't imagine a compiler not allocating the
max size in the unchecked union case, after all
the whole point is to mimic C!

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 29, 2008  8:07 AM

The rules are quite clear that you are required
to allocate the same size for all instances of
an unchecked-union type.  Nevertheless, it is
erroneous to use unchecked union to accomplish
an unchecked conversion.  It is merely an optimization
that the discriminant is omitted.  Everything you
do must be consistent with actually having the
discriminant.  I encourage you to reread the
RM section on Unchecked_Union.  It spells a lot
of this out pretty clearly.

This makes Ada's unchecked unions
a way of mapping to a C union that is used as
a poor man's variant record, but not a way of
mapping to a C union used as a poor man's
bucket-of-bits.  Or at least on the "Ada"
side, you can't cheat willy nilly in the
same way you might cheat on the "C" side.

****************************************************************

From: Robert A. Duff
Sent: Tuesday, January 29, 2008  8:07 AM

The purpose of forbidding these renamings (and similar rules about 'Access)
is to prevent you from getting your hands on components that don't exist.
But with unchecked unions, you _can_ get your hands on such components
(by writing erroneous code).  Therefore, it would seem pointless
to forbid the renamings -- instead, they could be allowed, and any
misuse (referring to the renaming after changing the nonexistent
discriminant) could be erroneous.

This would allow the C style usage (assigning to components -- there's no rule
in C that you have to do a whole-record assignment in order to change which
branch of the union exists).

> Of course you can only allow this where there is
> a default, and it would not work for a compiler
> that did not allocate the max size in this case,
> but I can't imagine a compiler not allocating the
> max size in the unchecked union case, after all
> the whole point is to mimic C!

The RM appears to require the max-size implementation:

  14/2  All objects of an unchecked union type have the same size.

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 29, 2008  8:21 AM

I don't see the point of allowing the renamings,
as they would require special cases in places
in the compiler where there seems no need for one.
If you rename the "base" pointer to the unchecked
union, do you really get any significant speed
up to rename a particular component?  Even defining
the erroneousness rules in the presence of
the renamings will be more difficult I would guess.

And the general philosophy, I believe, of the unchecked
union pragma is to match the C representation, but not to
match the C way of manipulating the innards.  You still are
supposed to use the "Ada" way for that, so that if you
wanted to, you could remove the pragma to test that you
are doing things legitimately, and then add back the
pragma to get the representation you want.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  8:36 AM

> The rules are quite clear that you are required
> to allocate the same size for all instances of
> an unchecked-union type.  Nevertheless, it is
> erroneous to use unchecked union to accomplish
> an unchecked conversion.  It is merely an optimization
> that the discriminant is omitted.  Everything you
> do must be consistent with actually having the
> discriminant.  I encourage you to reread the
> RM section on Unchecked_Union.  It spells a lot
> of this out pretty clearly.

We are NOT talking about unchecked conversions
here, please reread the discussion. We are always
assuming that we assign a value to the field before
we read the field, so the talk of unchecked
conversion is an irrelevant red herring. No need
for me to reread the section, since the whole
business of worrying about unchecked conversions
is irrelevant.

> This makes Ada's unchecked unions
> a way of mapping to a C union that is used as
> a poor man's variant record, but not a way of
> mapping to a C union used as a poor man's
> bucket-of-bits.  Or at least on the "Ada"
> side, you can't cheat willy nilly in the
> same way you might cheat on the "C" side.

Right, and in C, without restriction you can
read a field if you have assigned to it, the
same as in Ada. Using unions for unchecked
conversions is undefined in C as well (GNU
C defines it in limited cases, but the C
standard does not!)

But what on earth is the point in forbidding
the renaming. Yes, it might be that accessing
via the renaming would be erroneous, but no
more or less erroneous than accessing directly

    X : Integer renames QV.X;

    --  access through X is no more or less
    --  erroneous than accessing QV.X. In
    --  other words, the renamed variable
    --  X is in all respects the same as
    --  referencing QV.X

Note that this is ONLY true in the UU case.
In the normal case, the renaming is a way
of bypassing the discriminant check (or
might be), so it must be forbidden, but
the basis if disallowing it focuses on
the discriminant check.

Tuck, you will have to come up with something
more convincing than this to make me think that
rejecting the renaming is sensible.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  8:43 AM

> I don't see the point of allowing the renamings,
> as they would require special cases in places
> in the compiler where there seems no need for one.

Well need is an odd word, obviously we have a user
who "needs" this capability, as shown by my example.
I really hate telling him to declare all his variables
using that bogus subtype with a variable discriminant.

> If you rename the "base" pointer to the unchecked
> union, do you really get any significant speed
> up to rename a particular component?  Even defining
> the erroneousness rules in the presence of
> the renamings will be more difficult I would guess.

Renaming is not for speeding things up most of the time,
since the compiler can usually do that by CE elimination,
it is to make access notationally more convenient.

> And the general philosophy, I believe, of the unchecked
> union pragma is to match the C representation, but not to
> match the C way of manipulating the innards.  You still are
> supposed to use the "Ada" way for that, so that if you
> wanted to, you could remove the pragma to test that you
> are doing things legitimately, and then add back the
> pragma to get the representation you want.

Once again, we have a situation where we want to
reference

Variable3.Field1

several times. Each such reference will be erroneous
if there is no previous assignment to Field1, and that
is understood.

So the user wants to do

   F1 : Integer renames Variable3.Field1;

to make the multiple references easier to read
and write (a standard use of renames!)

It is quite understood here that referencing F1
is ENTIRELY equivalent to referencing Variable3.Field1
and that in particular it is erroneous iff the
full reference is erroneous.

Now to Tuck's point about being able to remove the
pragma and check the program. I think that is bogus.
Why? Because I see only two cases in which UU would
be used in practice:

1. To match external C stuff, in this case removing
UU would not work anyway.

2. To play games on the Ada side, C-style. In this
case removing the UU wouldn't work either.

Tuck seems to have in mind (and perhaps I never
realized this, I always had trouble understanding
his view of this pragma) a third use

3. Removing the discriminant to save time and
or space.

I think this is quite bogus, I have never seen
it used that way, and never expect to! This
is the only case to which the point about
removing UU to do full checking makes sense.

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 29, 2008  9:20 AM

> 3. Removing the discriminant to save time and
> or space.

I didn't mean to imply that.  The point of UU is
to match the C *representation*, but use it like
a variant record on the Ada side.  In my view
UU was *not* intended to introduce a whole new way
of doing business on the Ada side.  Of course
it would be convenient at times to be able to rename
discriminant-dependent components of a variant
record, but to associate that convenience with the
use of a UU pragma creates all kinds of bizarre
incentives in my view.  I see no reason why it should
be more convenient to use variant records with a
UU pragma than it should be to use "normal ones.
UU is an interfacing pragma, not a cool new "stream-lined"
variant record.

It is also worth looking at cases where there are multiple
fields in each variant, and you rename them all.  Now
does a reference via a rename of one field in one of the
variants effectively deinitialize all of the fields of
other variants?  It is not just that you need to initialize
a field before you use it, but that you also mustn't read
or write a field from a different variant between the
initialization of the first field and its subsequent use.

Being able to rename fields of an unchecked union seems
like a marginal capability that we have lived without for
variant records, and will necessarily make defining "safe"
use of an unchecked union that much more complex.  In my view... ;-)

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  9:35 AM

...
> UU is an interfacing pragma, not a cool new "stream-lined"
> variant record.

Odd, that's what I thought but you were insistent
on adding non-C stuff to unchecked unions, in
particular multiple components in a union, which
does not match anything on the C side. So to me it
was you promoting it as a cool new Ada feature. :-)

Speaking of which .. side issue .. we were discussing
this the other day, and Bob said, well that was useful
for matching the use of an anonymous struct on the
C side. Do we even have IA that says that this is a
valid mapping that will give the same representation?

> It is also worth looking at cases where there are multiple
> fields in each variant, and you rename them all.  Now
> does a reference via a rename of one field in one of the
> variants effectively deinitialize all of the fields of
> other variants?  It is not just that you need to initialize
> a field before you use it, but that you also mustn't read
> or write a field from a different variant between the
> initialization of the first field and its subsequent use.

The rule is quite simple, the reference via a renames is
IDENTICAL to referencing it without the renames. That's
generally what renames does, but we have to worry about
checks in the normal case, and we understand why the
rename, which makes perfect sense in the normal case
as well, is just a bit tricky to deal with check-wise,
so annoyingly we prevent it.

Why annoying, well suppose I have

      X : Rectype;

Then I do

      A := X.Q * X.Q - (2.0 * X.Q);

It is reasonable to do

      declare
        XQ : Float renames X.Q;
      begin
        A := XQ * XQ - (2.0 * XQ);
      end;

but arbitrarily disallowed

Actually as I think of it, I think the weakness
in this argument I am making (that it is perfectly
reasonable to allow the renaming) is that it applies
equally well to the non-UU case (there is really no
very good reason to disallow the above example, it's
just implementation and formal description convenience
to do so).

So the best argument I would say against allowing the
renaming is to say:

"Well in the normal case, there are annoying rules
forbidding perfectly reasonable uses of renaming,
which you have to live with. So you have to live
with these same annoying rules in the UU case,
learn to live with it!"

****************************************************************

From: Randy Brukardt
Sent: Tuesday, January 29, 2008  1:30 PM

...
> But what on earth is the point in forbidding
> the renaming. Yes, it might be that accessing
> via the renaming would be erroneous, but no
> more or less erroneous than accessing directly
>
>     X : Integer renames QV.X;
>
>     --  access through X is no more or less
>     --  erroneous than accessing QV.X. In
>     --  other words, the renamed variable
>     --  X is in all respects the same as
>     --  referencing QV.X

Keep in mind that the renaming is legal if the type of QV does not have
defaults for its discriminants. It is only illegal if QV does have such
defaults.

It strikes me that either way this is silly: either you have to put
constraints on your objects which are pretty meaningless, or you have to put
defaults on your record type which also are pretty meaningless. It's
unfortunate that Ada chose to tie discriminant defaults with mutability, but
I suppose it isn't possible to fix that.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  1:37 PM

Indeed, of course you can (as an implementor and language designer) 
understand the discrepancy (in the mutable case, you would have to
check on reference, which doesn't fit the model of renaming), in
the non-mutable case you check at the point of renaming (which
does fit that model).

But the worry of when to do the discriminant check, and consequential
language rules seems a bit besides the point when you are in a
situation where no check can be done in any case.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, January 29, 2008  2:01 PM

You are right of course, but you missed my point, which doesn't have
anything to do with renaming per-se.

In Ada, in order to get a mutable object, you have to specify defaults for
the discriminants. It is often the case that those defaults are completely
arbitrary and have nothing whatsoever to do with the actual use of the type.

This seems especially bad for Unchecked_Union, because the "default" value
for the discriminant will not be used for any purpose in the actual code. It
simply is a very confusing way to specify mutability, while it looks like
something else altogether.

It probably is too late to do something about that.

> But the worry of when to do the discriminant check, and consequential
> language rules seems a bit besides the point when you are in a
> situation where no check can be done in any case.

Right. Part of my point is that all Unchecked_Union types are mutable,
whether they are declared that way or not. So it is odd to have different
rules depending on whether or not a default is given: especially a default
which probably has nothing whatsoever to do with the actual use of the type.

OTOH, I do agree that Unchecked_Union wasn't intended to be a new fancy
gizmo, and having special rules for it would probably encourage its use when
it isn't appropriate (just like it is better to declare all records tagged,
even if you don't need dispatching, in order to get proper composition on
equality, the elimination of reemergence in generic, and the ability to take
'Access of parameters).

So I don't know what the right answer is.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  2:16 PM

> Right. Part of my point is that all Unchecked_Union types are mutable,
> whether they are declared that way or not. So it is odd to have different
> rules depending on whether or not a default is given: especially a default
> which probably has nothing whatsoever to do with the actual use of the type.

Oh yes, indeed, I agree that this is a case of confusion in the language.

****************************************************************

From: Robert A. Duff
Sent: Tuesday, January 29, 2008  3:14 PM

> Right. Part of my point is that all Unchecked_Union types are mutable,
> whether they are declared that way or not.

If the discrims do not have defaults, then any attempt to mutate an unchecked
union is necessarily erroneous.  And if the compiler is able to track the
discriminant value at compile time, it might well raise an exception when
the program tries to do "naughty" things.  And it might well warn in such a
case.

So I guess it's not strictly true that "all Unchecked_Union types are mutable",
although you can mutate any such object, if you can outwit the compiler.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  3:30 PM

> If the discrims do not have defaults, then any attempt to mutate an unchecked
> union is necessarily erroneous.

But why? It is fine to say this is true by the rules, but why
are these kind of silly rules there for unchecked union, it
seems just daft to have to supply a default discriminant value.

> And if the compiler is able to track the
> discriminant value at compile time, it might well raise an exception when
> the program tries to do "naughty" things.  And it might well warn in such a
> case.
> 
> So I guess it's not strictly true that "all Unchecked_Union types are mutable",
> although you can mutate any such object, if you can outwit the compiler.

Well it is obvious to me that compilers should NOT intefere in this way 
in the case of unchecked unions. Just from a useability point of view.

****************************************************************

From: Randy Brukardt
Sent: Tuesday, January 29, 2008  3:32 PM

> If the discrims do not have defaults, then any attempt to mutate an unchecked
> union is necessarily erroneous.  And if the compiler is able to track the
> discriminant value at compile time, it might well raise an exception when
> the program tries to do "naughty" things.  And it might well warn
> in such a case.

True, but surely that also applies to renames (if you detect such misuses,
you'll also detect most renames that are problematic). And it seems odd to
me to be attempting to diagnose misuse in a type that is specifically
declared to say that you intend to misuse it. After all, the majority of
real programs are erroneous for some reason or other (especially interface
to other languages) - that doesn't mean that the compiler necessarily ought
to refuse to make them work.

****************************************************************

From: Robert A. Duff
Sent: Tuesday, January 29, 2008  4:40 PM

> >> Right. Part of my point is that all Unchecked_Union types are mutable,
> >> whether they are declared that way or not.
> > If the discrims do not have defaults, then any attempt to mutate an unchecked
> > union is necessarily erroneous.
> 
> But why?

I don't know.  I can see both sides of this argument.

>...It is fine to say this is true by the rules, 

Right, that's all I meant in my above comment -- the current rules say it's
erroneous.

****************************************************************

From: Robert A. Duff
Sent: Tuesday, January 29, 2008  4:52 PM

> > If the discrims do not have defaults, then any attempt to mutate an > unchecked
> > union is necessarily erroneous.  And if the compiler is able to track the
> > discriminant value at compile time, it might well raise an exception when
> > the program tries to do "naughty" things.  And it might well warn
> > in such a case.
> 
> True, but surely that also applies to renames (if you detect such misuses,
> you'll also detect most renames that are problematic).

Sure.

I think the customer's example that Robert mentioned tripped over a warning
given by GNAT, and a Constraint_Error at run time.  But I don't know the exact
details.

>...And it seems odd to
> me to be attempting to diagnose misuse in a type that is specifically
> declared to say that you intend to misuse it.

Unchecked_Union does not necessarily mean you intend to misuse it.
That's one possibility, but the other possibility is you want
to interface to C, and you intend to obey the Ada rules on the
Ada side, and the C rules on the C side.

>... After all, the majority of
> real programs are erroneous for some reason or other (especially interface
> to other languages) - that doesn't mean that the compiler necessarily ought
> to refuse to make them work.

Perhaps, but my comment was simply that the current rules say it's erroneous,
and compilers can therefore raise exceptions if they like.  Maybe
Unchecked_Union should be an exception, but normally, catching erroneousness is
helpful.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  5:33 PM

> Perhaps, but my comment was simply that the current rules say it's erroneous,
> and compilers can therefore raise exceptions if they like.  Maybe
> Unchecked_Union should be an exception, but normally, catching erroneousness is
> helpful.

Well as I just said to Bob when we talked on the phone, there are two 
kinds of erroneousness.

1. Things that will work fine in practice, but are still technically
erroneous and cause language lawyers to go tsk-tsk.

2. Things that are genuinely dangerous

So to me the warning that GNAT generates for the non-existent
component is in category 1 for unchecked union, but category
2 if the pragma is not there (because then the non-existent
field might be outside the allocated space for the variable).

I think probably what we should do in GNAT is to essentially
ignore the staticness of a static discriminant from most points
of view, and try to eliminate the warning in my second example.

That would certainly be the easiest for the user in this case.

It is interesting to me that the former compiler they were
using did NOT give a warning in this case (where there was
of course no UU because it did not exist). I guess they
were just lucky :-)

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 29, 2008  3:20 PM

> Speaking of which .. side issue .. we were discussing
> this the other day, and Bob said, well that was useful
> for matching the use of an anonymous struct on the
> C side. Do we even have IA that says that this is a
> valid mapping that will give the same representation?

There are examples in the AI, but the RM example
doesn't illustrate this.

For what it's worth, here is a struct/union/struct example
from a part of our Ada->Java-byte-code front end.
Structures like this appear in a lot of C code that
I have worked with.

-------------

typedef struct _ils_decl_struct {
     ils_decl_enum         kind;
     ilw_type_ptr          type;
     il_entity_name_ptr    entity;
     int                   number;
     int                   nesting_level;  /* 0 = lib-level subp/object */
                                           /* 1 = local var/nested subp */

     bool                  is_constant:8;
     bool                  is_volatile:8;
     bool                  is_indirect:16;

     su_count_t            known_su_size;

     union {
         struct {        /* FOR_BLOCK_ARG */
             ils_decl_ptr                addr_of_param_block;
             ilc_component_ptr           this_param;
             Field_Ref_ptr               java_field_ptr;
         } blk_arg;

         struct {        /* FOR_STATIC/IMPORTED_OBJ */
             Field_Ref_ptr               java_static_var_ptr;
         } lib_level;

         struct {        /* FOR_STR_LIT */
             Field_Ref_ptr               java_static_var_ptr;
             char                        *str;
             int                         length;
         } str_lit;

         struct {        /* FOR_SUBP */
             ils_dispatch_info_ptr       dispatch_info;
             Method_Ref_ptr              java_method_ptr;
             bool                        all_calls_virtual:16;
             bool                        explicitly_calls_constructor:16;
         } subp;

         struct {        /* FOR_LOCAL_OBJ/PARAMETER/UNDER_CONSTRUCTION */
             Local_Var_Ref_ptr           java_var_ptr;
             ils_state_ptr               last_use;
             Field_Ref_ptr               uplevel_field;
         } local;

         struct {        /* FOR_EXCEPTION */
             Class_Ref_ptr               java_class;
             bool                        is_constraint_error;
         } excep;
     } u;

} ils_decl_struct;

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  3:35 PM

> For what it's worth, here is a struct/union/struct example
> from a part of our Ada->Java-byte-code front end.
> Structures like this appear in a lot of C code that
> I have worked with.

Sure they do, but you can't map them into UU's on the
Ada side with multiple fields in a single branch of the
union, because there is no reason to think this will
result in the same layout as a record containing the
fields .. they may get layed out differently, or even
reordered differently.

So I repeat my question:

> Speaking of which .. side issue .. we were discussing
>> this the other day, and Bob said, well that was useful
>> for matching the use of an anonymous struct on the
>> C side. Do we even have IA that says that this is a
>> valid mapping that will give the same representation?

An example is not good enough, you need at LEAST IA and
preferably a requirement that the layout be the same as
if a named record type is used.

If that is the intention behind allowing multiple fields,
then the job did not get completed (and indeed the failure
to include this requirement made me completely miss the
intent!)

****************************************************************

From: Tucker Taft
Sent: Tuesday, January 29, 2008  3:53 PM

Not surprisingly, the intent for unchecked-union
was obvious to me, given the discussion in the AI.
But if you fear it will not be obvious to other
implementors, or simply to record the intent for
posterity, then I agree we should add implementation
requirements or advice to make sure such C
struct/union/struct examples map properly to an
unchecked-union variant record.

****************************************************************

From: Robert Dewar
Sent: Tuesday, January 29, 2008  4:01 PM

It certainly was not obvious to us, and I don't know
if we make such a guarantee, we certainly don't make
it explicitly, and I have no idea what the back end
does. Of course such a guarantee is only valid if
there are no rep clauses for the UU, I am not clear
what the situation is if there are partial records.

In particular, the alignment may often be modified
by wrapping things in a struct, and I am not sure
how that plays out for us.

****************************************************************

Questions? Ask the ACAA Technical Agent