Version 1.3 of ai22s/ai22-0009-1.txt
!standard 4.6(58.4/5) 21-11-11 AI22-0009-1/01
!standard C.6(12/5)
!class binding interpretation 21-11-11
!status work item 21-11-11
!status received 21-08-26
!priority Low
!difficulty Easy
!qualifier Omission
!subject Nonvolatile views of volatile objects
!summary
Nonvolatile views of volatile objects are disallowed.
!issue
Two issues pertaining to avoiding non-volatile views of volatile objects.
1)
There are rules [starting at 4.6(58.1/5)] for type conversions that specify
whether a new object is created (as opposed to a new view of an existing
object).
In cases where the
"Otherwise, it is unspecified whether a new object is created."
clause currently applies, should a volatile-to-nonvolatile
conversion be required to generate a copy? (Yes.)
2)
Should a volatile extension of nonvolatile tagged type be illegal? (Yes.)
!recommendation
(See Summary.)
!wording
Add a new bullet after 4.6(58.4/5): [This is the penultimate item in this
list, just in front of "otherwise".]
* If the operand type is volatile (respectively, atomic) and
the target type is not, then a new object is created;
[Editor's comment: I turned around the wording that was provided by Steve,
as it did not match the question. He's on vacation until after the AI
deadline, so I can't check now whether he botched the wording.]
Modify C.6(12/5):
If an atomic object is passed as a parameter, then the formal parameter
shall either have an atomic type or allow pass by copy. If an atomic object
is used as an actual for a generic formal object of mode in out, then the
type of the generic formal object shall be atomic. If the prefix of an
attribute_reference for an Access attribute denotes an atomic object
[(including a component)], then the designated type of the resulting
access type shall be atomic. {An extension of a nonatomic tagged type
shall not be atomic.} Corresponding rules apply to volatile objects and
to full access objects types.
!discussion
We cannot have volatile (and atomic) objects that are operated on in a
nonvolatile (or atomic) manner. A type conversion to a nonvolatile
type that does not copy the object could easily pass the object to code
that would violate the volatile access rules. Thus we insist that
volatile objects are copied when converted to a nonvolatile type.
Similarly, tagged types are always by-reference types. Moreover, an
object of a descendant type can always be passed to a routine that was
written to accept objects of the parent type. A non-atomic parent type
will not have atomic behavior, and if an atomic extension was passed to
a routine of the parent type (explicitly or via inheritance), the atomic
behavior of the extension could be lost.
Note that this rule doesn't prevent having atomic extension components
in an extension of a non-atomic type; it's the type as a whole that is
an issue.
---
Note that a nonvolatile-to-volatile conversion (and especially a
nonatomic-to-atomic conversion) may also require a copy. A volatile or
atomic object may have representation requirements beyond
those of a normal object (for instance, for alignment). An implementation
can use the "unspecified" case to make a copy if this is a problem,
but it is not required if in fact the nonatomic object happens to be
aligned correctly.
!ACATS test
An ACATS B-Tests are needed for the second rules. The first rule is probably
not testable, as whether a copy was made would be difficult to tell solely
by behavior. One usually would use a controlled object for such a purpose,
but a volatile controlled object would not likely meet the usage-oriented
requirement for ACATS C-Tests.
!appendix
From: Steve Baird
Sent: Thursday, August 26, 2021 7:30 PM [Privately]
There are rules [starting at 4.6(58.1/5)] for type conversions that specify
whether a new object is created (as opposed to a new view of an existing
object).
In cases where the
Otherwise, it is unspecified whether a new object is created.
clause currently applies, should volatile-to-nonvolatile conversion
be required to generate a copy?
And should volatile-to-nonvolatile be illegal for unrelated-by-derivation
by-reference array types?
Should volatile extensions of nonvolatile tagged types be illegal?
Your opinion is solicited.
****************************************************************
From: Randy Brukardt
Sent: Thursday, August 26, 2021 10:06 PM [Privately]
I would agree that a volatile to nonvolatile conversion would need a copy.
What about the reverse? (A nonvolatile object might not be stored in a way
that independence can be guaranteed.)
Isn't the case of unrelated-by-derivation by-reference array types already
illegal (regardless of volatility?). It can only work if every property is
exactly the same, which is unlikely at best. In any case, 4.6(24.9/2) says
that the target type component of an (unrelated) array conversion cannot be
volatile.
Is there really such a thing as a non-volatile tagged type (it necessarily has
to be independent as you have to pass it by reference).
****************************************************************
From: Steve Baird
Sent: Friday, August 27, 2021 7:46 PM [Privately]
Tuck says that a volatile view of a nonvolatile object is ok.
That's probably true in practice, but maybe you are right that specifying Volatile for
a derived type could, at least in theory, result in a change of representation.
In which case I agree that a nonvolatile to volatile would also require a copy.
===
> Isn't the case of unrelated-by-derivation by-reference array types already
> illegal (regardless of volatility?).
You're right. I was thinking it was only prohibited if limited types were involved.
===
> Is there really such a thing as a non-volatile tagged type (it necessarily
> has to be independent as you have to pass it by reference).
I'm not sure what you mean. Volatile means, among other things, that you can't
make local copies because the underlying object might be modified by somebody
else, at least in some cases. Right? Surely you don't mean to suggest that a
compiler has to make conservative assumptions about every tagged formal
parameter.
I think that a volatile extension of a nonvolatile tagged type needs to be
illegal. Otherwise a call to an inherited-and-not-overridden primitive op
results in a non-volatile view of a volatile object inside the callee.
You could imagine some rule that the specified volatility somehow only
affects the "new" part for an extension, but even that could cause problems
with things like class-wide equality (and besides, that's not the present
rule).
****************************************************************
From: Randy Brukardt
Sent: Saturday, August 28, 2021 1:31 AM [Privately]
> Tuck says that a volatile view of a nonvolatile object is ok.
> That's probably true in practice, but maybe you are right that specifying
> Volatile for a derived type could, at least in theory, result in a change of
> representation. In which case I agree that a nonvolatile to volatile would
> also require a copy.
Right - a volatile object has to be Independent, while that is not required
of a nonvolatile object. I don't see how one can just expect volatility to
work as expected on an arbitrary set of bits. I suppose one could appeal to
the new last sentence of C.6(20/5) in such a case, but about all you could do
is handwave that if you have a volatile view of a nonvolatile object, pretty
much anything could happen.
And I've been presuming that you are also talking about atomic objects (since
atomic is also volatile). But I don't see how an atomic view of a non-volatile
object is supposed to work -- the last sentence of C.6(20/5) does not apply in
such cases.
>> Is there really such a thing as a non-volatile tagged type (it necessarily
>> has to be independent as you have to pass it by reference).
> I'm not sure what you mean. Volatile means, among other things, that you can't
> make local copies because the underlying object
> might be modified by somebody else, at least in some cases. Right? Surely you
> don't mean to suggest that a compiler has to make
> conservative assumptions about every tagged formal parameter.
What "conservative assumptions"? A tagged type is a by-reference type, so no one
should be making a copy of it in any situation. So I don't think that there is
much practical effect of "volatile" on tagged types. Maybe in an optimizer (since
volatile prevents common-subexpression optimizations)? But is anyone other than me
writing an Ada optimizer anyway (I certainly get the impression that AdaCore
isn't).
[Adding a thought on November 11th: any object passed by reference can be
aliased, in most circumstances a compiler cannot assume that the object isn't
changed. The difference with volatile is that one doesn't need to execute any
code for such a change to occur -- typically one assumes an object doesn't
change so long as there are no calls to unknown code. That's what I meant
above by common-subexpression optimizations. But calls are so common in Ada
code that such optimizations don't happen much, especially not on anything
indirectly accessed (like a reference parameter), since they are killed so
easily.]
> I think that a volatile extension of a nonvolatile tagged type needs to be
> illegal. Otherwise a call to an inherited-and-not-overridden primitive op
> results in a non-volatile view of a volatile object inside the callee.
> You could imagine some rule that the specified volatility somehow only
> affects the "new" part for an extension, but even that could cause problems
> with things like class-wide equality (and besides, that's not the present
> rule).
As I said, I don't see that there is much if any implementation change. But
you are probably right semantically, the model of volatility doesn't make a
ton of sense in such a case.
****************************************************************
Questions? Ask the ACAA Technical Agent