C11 6.7.3 Type qualifiers, paragraph 7, reads:
An object that has volatile-qualified type may be modified in ways unknown to the implementation or hav
Update 18 February 2017
The answer below quotes & discusses the language in the Standard, some contradictory language in the Rationale and some comments from gnu.cc re the contradiction. There is a defect report which essentially has committee agreement (although still open) that the Standard should say, and that the intent has always been, and that implementations have always reflected, that it is not the volatility of an object that matters (per the Standard) but of the volatility of (the lvalue of) an access (per the Rationale). (Credit to Olaf for mentioning this DR.)
Defect Report Summary for C11 Version 1.10 Date: April 2016 DR 476 volatile semantics for lvalues 04/2016 Open
No. Because the object accessed is not volatile.
Object p is of type pointer to volatile int. But x is not an object of a volatile-qualified type. The qualifications on p affect what accesses can be made through it, but do not affect the type of the object that it points to. There is no restriction on accessing a non-qualified-type object via a volatile lvalue. So accessing x through p is not an access of a object of a volatile-qualified type.
(See 6.7.3 Type qualifiers for the restrictions on accessing objects of qualified types. It just says you can't access a volatile qualified object via an unqualified lvalue.)
On the other hand, this post quotes from the 6.7.3 of the Rationale for International Standard--Programming Languages--C:
A cast of a value to a qualified type has no effect; the qualification (volatile, say) can have no effect on the access since it has occurred prior to the case. If it is necessary to access a non-volatile object using volatile semantics, the technique is to cast the address of the object to the appropriate pointer-to-qualified type, then dereference that pointer.
However, I can't find language in the standard that says that the semantics is based on the lvalue type. From gnu.org:
One area of confusion is the distinction between objects defined with volatile types, and volatile lvalues. From the C standard's point of view, an object defined with a volatile type has externally visible behavior. You can think of such objects as having little oscilloscope probes attached to them, so that the user can observe some properties of accesses to them, just as the user can observe data written to output files. However, the standard does not make it clear whether users can observe accesses by volatile lvalues to ordinary objects.
[..] it is not clear from the standard whether volatile lvalues provide more guarantees in general than nonvolatile lvalues, if the underlying objects are ordinary.
No, because there are no side effects:
Even if the semantics of *p must be that of a volatile, the standard nevertheless says:
5.1.2.3 Program execution 4 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object).
Again, there is no volatile object in your code. Although a compilation unit that only sees p couldn't make that optimization.
Also keep in mind
6.7.3 Type qualifiers 7 [...] What constitutes an access to an object that has volatile-qualified type is implementation-defined.
5.1.2.3 Program execution 8 More stringent correspondences between abstract and actual semantics may be defined by each implementation.
So mere appearances of volatile lvalues does not tell you what "accesses" there are. You have no right to talk about "the single access to *p from tmp = *p" except per documented implementation behaviour.