This is a question about ISO C, which contains this sentence:
If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.
In ISO9899:1999 (C99) this appears in 6.7.3 Type Qualifiers.
Firstly, if we entirely removed this sentence from the text, would the behavior still be undefined? That is to say, is this re-stating an existing lack of a requirement, or is it explicitly taking away a requirement that could otherwise be inferred from elsewhere in the text?  (Imagine that a sentence were added which says "whenever two values of type int are added together whose arithmetic sum is forty-two, the behavior is undefined". Without such a sentence, the requirement for such an addition to produce a value can (and is) inferred).
Secondly, what useful behaviors does this allow an implementation to provide? That is to say, can an implementation do something beneficial which breaks programs that access something volatile with a non-volatile lvalue, and which therefore depends on the above sentence?  Are there any implementations which do this, whatever it is?
For example, it is interesting and noteworthy that C programs can access const-qualified objects with non-const lvalues, just not store to them. Making the store behavior undefined is tangibly beneficial: implementations can place constants in read-only storage, and in some cases can propagate constants through a program image at translation time as if they were manifest constants.  Yet, mere non-const access is required to work. Not requiring non-const accesses to const objects to work would presumably be a permissiveness  which brings no benefits.  Yet, in the case of volatile, it is that strict: no non-volatile-qualified access is required to work. What is the benefit?
Can an object which is defined as volatile by the C program itself be endowed with useful properties which break if there take place any accesses whatsoever to that object through a non-volatile lvalue?
(Under "useful", I would specifically like to exclude diagnosis. Terminating the program upon detecting such an access, without a message, or with a message like "volatile accessed as non-volatile" doesn't count as useful; it serves only to enforce the lack of requirement.)
(Also, I'm not interested in memory mapped registers and such; strictly objects defined by the program in static, dynamic or automatic storage. Use of hardware registers is inherently nonportable.)
All I can think of is that a non-volatile access to a volatile object could retrieve a stale value, rather than value that was last stored 
(properly, through the volatile lvalue).  This is an economic benefit in the following way: if a write occurs through, say, a volatile int lvalue, the compiler does not have to suspect that this has any effect on any plain int lvalue. This leads to better code generation in functions which work with  mixtures volatile and non-volatile objects of the same type:
volatile int global;
void foo(int *p)
{
   int x = *p, y;
   global++; 
   y = *p;
}
Here, the compiler doesn't have to consider that *p might be an alias for global, because that usage is not required to work according to ISO C.  Hence it can freely assume that the value of *p does not change between the two references. Both x and y receive to the same value, derived from a single access to *p.
If the aliasing were permitted, then the compiler would have to generate code to re-load *p on the second access, in order that it pick up the most recent value stored in global.
(If we remove volatile from the above program fragment, then this is in fact the case; it has to be at least suspected, if not confirmed. that *p may be an alias for global and so *p has to be re-inspected. Or else code has to be generated which compares the run-time value of p to the address of global and takes two different paths.)
However, we don't introduce volatile into programs to obtain this kind of obscure optimization benefit; it is used to defeat optimization. The restrict keyword can be used instead to allow the implementation to reason about lvalues not being aliased. It seems that the above cannot be the rationale.