Moreover, I'm not sure 'volatile' memory access without some sort of external linkage is even meaningful. The idea of volatile is that access to a volatile variable could have observable side effects outside the program, but that discussion seems rather moot for a variable that doesn't have connections to the outside world to begin with. Heck, by the same reasoning, even for a variable with external linkage, the rules might still permit it to be optimized out under link-time optimization, unless it has been declared to be externally reachable somehow (e.g. at a fixed/exported/otherwise 'known' address)... otherwise it's by definition externally unreachable and thus again unobservable under the as-if rule.
At least, I could see the reasoning going that way, and that's how it makes sense to me as far as the abstract machine goes. I can also see people disputing it though, and claiming (say) a debugger inspecting a program is sufficient accessibility for considering side effects, or something like that. I'm not sure I agree with every objection, but I see room for debate. It's just not clear what the implications are under the as-if rule.
There is little value on explicitly optimizing volatiles but of course that can happen as a side effect (ah!) of unrelated optimizations.
I rarely use volatile at all, but when I do, I do make sure not to apply it to local objects.
edit: I think the most reliable and portable way to make sure that the address of a variable escapes is something like this:
volatile std::atomic<void*> sink; // global
void escape(void*x) {
std::atomic_signal_fence(std::memory_oreder_release);
sink.store(x, std::memory_order_relaxed);
}
any signal handler executed after escape(&val) is guaranteed to be able to see the last value stored into val.
In fact the fact that volatile atomic has additional guarantees is a strong reason for plain atomic not to have them, otherwise there wouldn't be a way to express the more relaxed requirement.
I think atomic not being volatile by default is a good default: the majority of code doesn't need to care about atomic in the first place, for the majority of the remaining code, these sort of optimizations are benign and desirable. For the remaining code that cares, volatile is the safety hatch.