If Rust doesn't allow spurious reads of volatile memory, then it must not link executables that use a malloc implementation that works like this.
Anyway, I did some research and I learned more about how LLVM works. Basically, AFAICT, LLVM doesn't keep track of which objects are volatile and which ones aren't. Instead, it just doesn't touch anything unless it is touched by a non-volatile load or non-volatile store. But, once a non-volatile load or non-volatile store is seen, it feels free to start optimizing those loads/stores which might result in a load/store getting moved to a different point in the program than it appears in the program's source.
Now, the question is whether this is guaranteed by the Rust language, or whether it is an implementation-specific behavior of rustc. In the case of Clang, we can see that the above behavior is not guaranteed by the C11 language spec; that is, Clang's behavior is much more conservative than what the C language spec requires.
Now, here's the thing I find strange: A huge part of the value proposition of Rust is that it uses its type system to prevent common types of bugs in error-prone aspects of programming. It seems to me that a useful constraint is "this memory must only be accessed via volatile loads and stores, not normal loads and stores"; that is, there should be some way to use types to force the exclusive use of volatile reads and writes and/or to disable the *
dereferencing operator for volatile objects in favor of explicit volatile_load
, volatile_store
, nonvolatile_load
, and nonvolatile_store
methods. Yet, the current volatile load/store proposal does not take advantage of Rust's type system to help programmers avoid mistakes at all. This doesn't seem “rustic“ to me.
Interestingly, I think one could easily use the volatile_load
and volatile_store
intrinsics and the rest of the features of Rust's type system to create such a safe interface to volatile memory in libstd similar to UnsafeCell
. In fact, I have to say I'm not even sure if that is what UnsafeCell
is supposed to be; it seems like UnsafeCell
is something similar but different, as it doesn't use volatile_load
and volatile_store
internally.
I'll try to put together such a thing and see if it makes sense. If somebody has already done so, or knows why it's a bad idea, I'd love to hear about it.