Version 1.3 of ai12s/ai12-0367-1.txt

Unformatted version of ai12s/ai12-0367-1.txt version 1.3
Other versions for file ai12s/ai12-0367-1.txt

!standard 3.5.9(8/2)          20-03-12 AI12-0367-1/02
!standard 3.5.10(2/1)
!standard 13.1(9.1/5)
!standard 13.14(10)
!class binding interpretation 20-03-04
!status Amendment 1-2012 20-03-11
!status ARG Approved 14-0-0 20-03-11
!status work item 20-03-04
!status received 20-02-24
!priority Low
!difficulty Easy
!qualifier Omission
!subject Glitches in aspect specifications
!summary
A Small has to be specified to be a positive value.
An enumeration literal can appear in the specification of a Default_Value aspect.
!question
(1) The rules for specifying Small of a fixed point type require that the expression be static (3.5.10(2/1)) and less than the delta (3.5.9(8/2)). However, 0.0, -0.25, and -4596.0 are all less than any delta (since deltas are required to be positive by 3.5.9(7)), and are allowed by these rules. But these smalls are clearly nonsense. Should they be made illegal? (Yes.)
(2) 13.1(9.1/5) (added by AI12-0181-1) says that a representation aspect specification cannot contain something that freezes the type itself. However, in
type Kind is (Unknown, Raw, Bound, Solved) with Default_Value => Unknown;
the use of the enumeration literal Unknown freezes Kind, so this specification is illegal. This means that any specification of Default_Value for an enumeration type is illegal (an attribute reference to 'Val would also be illegal for the same reason). That cannot be intended; is specifying Default_Value for an enumeration type legal? (Yes.)
!recommendation
(See Summary.)
!wording
(1) Modify 3.5.10(2/1):
S'Small denotes the small of the type of S. The value of this attribute is of the type universal_real. Small may be specified for nonderived ordinary fixed point types via an attribute_definition_clause (see 13.3); the expression of such a clause shall be static {and positive}.
(2) Modify 13.14(10):
* At the place where an expression causes freezing, the type of the expression is frozen, unless the expression is an enumeration literal used {either} as a discrete_choice of the array_aggregate of an eumeration_representation_clause{ or as the aspect_definition of a specification for aspect Default_Value}.
!discussion
(1) Most of the rules for specifiable attributes require that the value is non-negative. It's inconsistent that this is missing here (we say "positive" here since a Small that equals 0.0 would give the same representation to all values).
Note that compilers could (and presumably do) use the Implementation Permission of 3.5.9(10) to reject nonsense smalls as "not supported", but it's silly to have to use an Implementation Permission to reject nonsense.
(2) We already had a special case to allow enumeration literals in enumeration representation clauses (the normal rules would have made any such clause illegal, which of course would have been silly). So we extend that special case to this case as well, these cases are essentially the same.
There are other similar cases that we don't chose to fix:
(1) Attributes of the type:
type Kind is (Unknown, Raw, Bound, Solved) with Default_Value => Kind'Val(0); -- Illegal.
and
type Small is range 1 .. 5 with Default_Value => Small'Last; -- Illegal.
(2) Typed constants of the type:
type Small is range 1 .. 5 with Default_Value => Max; -- Illegal. Max : constant Small := 5;
and
type Kind is (Unknown, Raw, Bound, Solved) with Default_Value => Not_Set; -- Illegal. Not_Set : constant Kind := Unknown;
Named numbers can be used in the numeric cases.
Note that Default_Component_Value does not suffer from any of the versions of this problem, since the value is of a different type than the type being declared.
!corrigendum 3.5.10(2/1)
Replace the paragraph:
S'Small denotes the small of the type of S. The value of this attribute is of the type universal_real. Small may be specified for nonderived ordinary fixed point types via an attribute_definition_clause (see 13.3); the expression of such a clause shall be static.
by:
S'Small denotes the small of the type of S. The value of this attribute is of the type universal_real. Small may be specified for nonderived ordinary fixed point types via an attribute_definition_clause (see 13.3); the expression of such a clause shall be static and positive.
!corrigendum 13.14(10)
Replace the paragraph:
by:
!ASIS
No ASIS effect.
!ACATS test
For (1), an ACATS B-Test could be constructed, but it seems to be of rather low value compared to other rules. Perhaps such a test case should be added to existing tests (both for attribute definition clauses and for aspect specifications).
For (2), an ACATS B-Test should be constructed to check that the use of typed constants is not allowed in Default_Value expressions. An ACATS C-Test should check that enumeration literals are allowed (this is a very standard use, so it should occur as the part of some other test).
!appendix

From: Randy Brukardt
Sent: Monday, February 24, 2020  9:10 PM

I've been working on redoing the freezing code in Janus/Ada to support
aspects. One of the aspect ACATS tests crashed the compiler by giving a
negative value, so I've been adding some checks for the "nonnegative" part
of the various specifiable attribute rules. (It was supposed to fall through
to the "unsupported size" part of the code, but got an overflow before
getting there. Not the best message anyway, so a redo.)

Anyway, this led to the question of what rule (other than common sense) has
this effect for ordinary fixed point types and specifying the Small
attribute (or equivalent aspect).

3.5.10(2/1) requires the expression to be static and be of some real type.
The typical wording about it needing to be nonnegative is missing here
(really would want it positive anyway, but that's not said either).

3.5.9(8/2) requires that the small be no greater than the delta of the type.

Nothing, however, seems to prevent Small from being specified as 0.0, -0.25,
or -4596.0, all of which are less than any delta. (Note that 3.5.9(7)
requires that delta expressions are positive.)

3.5.9(10) and 3.5.9(21) give implementation permissions to reject smalls
that are "not supported" and not "powers of two". It seems uncomfortable to
be required to use the "not supported" permission to reject clear nonsense,
and inconsistent with the rules for other representation aspects as well as
the rules for deltas.

Thus, I suggest that we require specified Smalls to be positive (like
deltas), probably by adding that to 3.5.10(2/1):

S'Small denotes the small of the type of S. The value of this attribute is
of the type universal_real. Small may be specified for nonderived ordinary
fixed point types via an attribute_definition_clause (see 13.3); the
expression of such a clause shall be static {and positive}.

Since this is Ada 95 wording, we'll have to put it in an AI somewhere,
probably the "presentation" AIs (since the impl perms don't allow these
portably anyway). 

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

From: Tucker Taft
Sent: Monday, February 24, 2020  9:58 PM

> ...
> 
> Thus, I suggest that we require specified Smalls to be positive (like 
> deltas), probably by adding that to 3.5.10(2/1):
> 
> S'Small denotes the small of the type of S. The value of this 
> attribute is of the type universal_real. Small may be specified for 
> nonderived ordinary fixed point types via an 
> attribute_definition_clause (see 13.3); the expression of such a clause 
> shall be static {and positive}.

Looks good to me!

> Since this is Ada 95 wording, we'll have to put it in an AI somewhere, 
> probably the "presentation" AIs (since the impl perms don't allow 
> these portably anyway).

Makes sense.

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

From: Steve Baird
Sent: Tuesday, February 25, 2020  2:23 PM

>> S'Small denotes the small of the type of S. The value of this 
>> attribute is of the type universal_real. Small may be specified for 
>> nonderived ordinary fixed point types via an 
>> attribute_definition_clause (see 13.3); the expression of such a clause 
>> shall be static {and positive}.

> Looks good to me!

And to me.

>> Since this is Ada 95 wording, we'll have to put it in an AI 
>> somewhere, probably the "presentation" AIs (since the impl perms 
>> don't allow these portably anyway).
>
> Makes sense.

Agreed.

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

From: Randy Brukardt
Sent: Wednesday, February 26, 2020  6:52 PM

I was implementing 13.1(9.1/5) yesterday, and thinking about the
(nonexistent) ACATS B-Test for Default_Value, and I think there is a problem 
with the existing set of rules with this aspect (and only this aspect, so far
as I can tell). This explanation is long, but given we're talking about 
freezing there's not much choice.

13.1(9.1/5) says:
   An expression or name that freezes an entity shall not occur within an 
   aspect_specification that specifies a representation or operational aspect 
   of that entity.

This was adopted to prevent nonsense like:

    type My_Int is range 1 .. 100 with Size => My_Int'Size;

or similar versions involving subtypes of My_Int.

Default_Value is a representation aspect by 3.5(56.2/3) (AARM 3.5(56.d/3) 
explains why. It makes sense in any case, since we need to know the default 
before generating any default-initialized objects). That means this rule 
applies to it. The expression is static by 3.5(56.3/3).

We could have something like:
    type My_Int is range 1 .. 100 with Default_Value => 100; 
and that is obviously not a problem.

But Ada is about naming things, so perhaps we wanted to say instead:

    type My_Int is range 1 .. 100 with 
        Default_Value => Unknown;

    Unknown : constant My_Int := 100;

This appears illegal to me. The type My_Int is frozen by the occurrence of the 
object declaration (13.14(6)), which causes the aspect(s) to be resolved, 
evaluated, and frozen (13.14(7.2/3)). The occurrence of "Unknown" is the name 
of an object, which causes freezing (13.14(8/4)), and specifically freezing of
the subtype My_Int (13.14(11)), which triggers our friend 13.1(9.1/5).

Note that the similar:

    type My_Int is range 1 .. 100 with 
        Default_Value => End_Val;

    Start_Val : constant My_Int := 1; -- Freezes My_Int.
    End_Val   : constant My_Int := 100; -- Too late.

is illegal regardless, since Start_Val freezes the type, resolving the aspect 
- before End_Val is even declared, so the resolution must fail. So the case 
we're talking about is rather narrow in any case.

We could have tried instead:

    type My_Int is range 1 .. 100 with 
        Default_Value => My_Int'Last;

This is exactly like the case that we were trying to prevent (reading 
attributes of the type we're freezing), so it's obviously illegal. That's 
annoying.

However, there is a work-around for these examples (which happens to match the 
way I tend to write these declarations anyway):

    Max_Int : constant := 100; -- Named number

    type My_Int is range 1 .. Max_Int with 
        Default_Value => Max_Int;

So none of this is earth-shaking. But now for the coupe-de-grace:

    type Kind is (Unknown, Raw, Bound, Solved)
        with Default_Value => Unknown;

The default value of Unknown is an implicit call to the function Unknown 
(various rules in 3.5.1), which freezes the profile of that function
(13.14(8.1/3 & 10.1/4)), which freezes Kind (13.14(14/3)), which triggers 
13.1(9.1/5). So this is illegal -- but that clearly triggers the Dewar rule 
(this is after all, one of the motivating cases for the feature).

I don't have a good idea for reconciling this. The easiest fix would be to 
have a Notwithstanding rule that allowed enumeration literals (and presumably 
static constants) in Default_Value expressions, even though they are 
technically freezing. I don't see any implementation issue so long as the 
items are static (the representation details aren't used to determine the 
static value). I wouldn't want to allow attributes of the type (surely don't 
want to allow My_Int'Size here), although I suppose we could explicitly allow 
'First and 'Last (which are necessarily static for an elementary *type*).

Note that this problem seems to occur only with Default_Value, which is pretty 
much the only aspect that is attempting to use a value of the same type on 
which it is applied. (Even Default_Component_Size, which is otherwise similar, 
doesn't run into this problem.) Thus it is probably best to make whatever fix 
is decided only on Default_Value rather than generally.

I'm thinking a Binding Interpretation will be needed for whatever we decide, 
since we clearly can't have the enumeration case illegal.

Thoughts??

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

From: Richard Wai
Sent: Wednesday, February 26, 2020  7:16 PM

Seems to me that just allowing that to be illegal (as per the existing
rules) is the more consistent choice.

In situations like this, I'd tend to think that being restricted to a named
number is a fair restriction, I.e:

type My_Int is range 1 .. 100 with 
        Default_Value => Unknown;

    Unknown : constant := 100;

I don't see how allowing an exception for this rule just so that you can set 
Default_Value to be a named object of that same type is something useful 
enough to justify that.. I think consistency is far more valuable.

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

From: Tucker Taft
Sent: Wednesday, February 26, 2020  8:40 PM

I would say we should not try to solve the problem with numeric types, since 
the named number solutions seems fine, but the enumeration literal issue seems
to be more of a problem. We already have a special case for enumeration 
literals, so you can use them in an enumeration rep clause:

13.14(10):

* At the place where an expression causes freezing, the type of the expression 
is frozen, unless the expression is an enumeration literal used as a 
discrete_choice of the array_aggregate of an 
enumeration_representation_clause.

Seems like we could include the Default_Value usage as another special case 
here for enumeration literals.

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

From: Randy Brukardt
Sent: Wednesday, February 26, 2020  9:35 PM

> Seems to me that just allowing that to be illegal (as per the existing
> rules) is the more consistent choice.

That means that Default_Value can't be used for an enumeration type. *That* 
doesn't make sense.

I don't care about the object case that much (even though it was the first 
thing I thought of), but not allowing this on enumerations at all is nonsense.

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

From: Randy Brukardt
Sent: Wednesday, February 26, 2020  9:46 PM

> Seems like we could include the Default_Value usage as another special 
> case here for enumeration literals.

Yes, that would work. Didn't remember this exception to the usual rules!

So we should just say:

* At the place where an expression causes freezing, the type of the expression 
is frozen, unless the expression is an enumeration literal used as a 
discrete_choice of the array_aggregate of an eumeration_representation_clause{ 
or the aspect_definition of a specification for aspect Default_Value}.

This is a very narrow exclusion to the usual rules, just enough to avoid 
nonsense. Guess I get to write this up. (This also lets me write ACATS tests 
for Default_Value, because we're not changing the rules.)

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

From: Richard Wai
Sent: Wednesday, February 26, 2020  10:25 PM

> > Seems to me that just allowing that to be illegal (as per the existing
> > rules) is the more consistent choice.
> 
> That means that Default_Value can't be used for an enumeration type.
> *That* doesn't make sense.

You got me there!

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

From: Tucker Taft
Sent: Thursday, February 27, 2020  9:20 AM

I presume it will be clear that "is an enumeration used as ..." applies to 
both phrases.  This could be even clearer by saying:

* At the place where an expression causes freezing, the type of the
expression is frozen, unless the expression is an enumeration literal 
used {either} as a discrete_choice of the array_aggregate of an
eumeration_representation_clause{ or as the  <-- added "as" here
aspect_definition of a 
specification for aspect Default_Value}.

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

From: Steve Baird
Sent: Thursday, February 27, 2020  12:23 PM

> * At the place where an expression causes freezing, the type of the 
> expression is frozen, unless the expression is an enumeration literal 
> used {either} as a discrete_choice of the array_aggregate of an 
> eumeration_representation_clause{ or as the aspect_definition of a  
> <-- added "as" here specification for aspect Default_Value}.

I like the extra clarity and agree that this is a good solution.

This will allow something like

     type Enum is (Aaa, Bbb, Ccc) with Default_Value => Aaa;
     ... <unrelated intervening stuff>...;
     for Enum use (Aaa => 123, Bbb => 456, Ccc => 789);

but I don't see any problem with that.

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

From: Randy Brukardt
Sent: Thursday, February 27, 2020  3:00 PM

Fine by me. I originally had the "as" and took it out as redundant. Maybe I 
was right in the first place. :-) - Randy.

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

From: Tucker Taft
Sent: Thursday, February 27, 2020  3:05 PM

It all depends on where you insert the "either".  I chose to insert it before 
the first "as" so you need another "as" after the "or".

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

Questions? Ask the ACAA Technical Agent