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