AI22-0009-1

!standard C.6(12/5)                                        23-02-01  AI22-0009-1/07

!standard C.6(12.1/5)

!class binding interpretation 21-11-11

!status Corrigendum 1-2022 22-11-10

!status ARG Approved 14-0-0  22-11-10

!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 (and some related constructs) are illegal or are prevented by making a copy.

!issue

Two issues pertaining to avoiding non-volatile views of volatile objects (and vice versa):

Are the answers the same if we ask about atomicity instead of volatility? (Yes.)

!recommendation

(See Summary.)

!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 [Redundant: (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.

Add new paragraph after C.6(12.1/5):

In evaluating a type conversion, a new object is created [redundant: (as opposed to a new view of the operand object)] if one but not both of the target type and the operand object is atomic. A corresponding rule applies in the case of volatile. In the case of an array conversion, corresponding rules apply if the Atomic_Components or Volatile_Components aspects of the array types do not match.

   

!discussion

We cannot have volatile (and atomic) objects that are operated on in a nonvolatile (or nonatomic) 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 nonatomic 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 nonatomic 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) also requires a copy. A volatile or atomic object may have representation requirements beyond those of a normal object (for instance, for alignment), and the access code is likely to be different. It might be possible in some implementations to avoid this copy (if the representation is the same and the access code is similar enough), but we opt for simplicity in the rules and certainty for the programmer.

!corrigendum C.6(12/5)

@drepl

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 @b{in out}, then the type of the generic formal object shall be atomic. If the @fa{prefix} of an @fa{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. Corresponding rules apply to volatile objects and to full access objects.

@dby

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 @b{in out}, then the type of the generic formal object shall be atomic. If the @fa{prefix} of an @fa{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.

!corrigendum C.6(12.1/5)

@dinsa

If a nonatomic subcomponent of a full access object is passed as an actual parameter in a call then the formal parameter shall allow pass by copy (and, at run time, the parameter shall be passed by copy). A nonatomic subcomponent of a full access object shall not be used as an actual for a generic formal of mode @b{in out}. The @fa{prefix} of an @fa{attribute_reference} for an Access attribute shall not denote a nonatomic subcomponent of a full access object.

@dinst

In evaluating a type conversion, a new object is created (as opposed to a new view of the operand object) if one but not both of the target type and the operand object is atomic. A corresponding rule applies in the case of volatile. In the case of an array conversion, corresponding rules apply if the Atomic_Components or Volatile_Components aspects of the array types do not match.

!ACATS test

An ACATS B-Test is needed for the type extension rule. The type conversion rule would be difficult to test, given the usage-oriented requirement for ACATS C-Tests. In particular, the only way to reliably tell if an object is copied is to use a controlled type, but combining that with volatility would be unusual.

!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.

 

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

From: Steve Baird

Sent: Tuesday, June 21, 2022  4:21 PM [Privately]

In the new wording for C.6(12/5) we include what was supposed to be a copy

of some existing wording:

   Corresponding rules apply to volatile objects and to full access objects

   types.

If you look in the online RM, you'll see that final "types" but it is crossed

out with a change-bar. Presumably a cut-and-paste error by me.

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