Daniel Berlin <[EMAIL PROTECTED]> writes:

| On Sat, 2005-07-16 at 12:50 -0400, D. Hugh Redelmeier wrote:
| > Sorry for the very late response.  It is actually triggered by the
| > bugzilla entry
| >     http://gcc.gnu.org/bugzilla/show_bug.cgi?id=22278
| > 
| > The motivating example, abstracted from a misbehaving part of X, is:
| >     void test (char *addr) {
| >             *((volatile char *) addr);
| >     }
| > In this case, the fetch ("access") is required for the hardware to
| > behave.
| > 
| ...
| 
| > 6.5.3.2:  applying `*' to a pointer of type `T *' which points to an
| > object yields an lvalue of type `T' designating that object.  So the
| > lvalue in the assignment has a volatile-qualified type. 
| > 
| > 6.3.2.1:  when an object is said to have a particular type, the type is
| > specified by the lvalue used to designate the object.  So the lvalue
| > having a volatile-qualified type *means* that the object it designates has
| > a volatile-qualified type; "has type X" and "is designated by an lvalue of
| 
| How does this reasoning not apply to *((char *)a) = 5 where a was
| originally of a const qualified type?
| Or do you think you can only *add* qualifiers, and not remove them?
If by analysis, you can determine that the argument bound to "a"
actually is the address of a const object (not just a plain pointer
that happens to accidently acquire a const), then it effectively is
invoking an undefined behaviour.  Otherwise, GCC has to accept the
cast-away and store 5.  In general, we just store "5", and let user has
its machine blow if the location is actually read only.



Interestingly, C++ uses a slightly different language and formulation
of its object model and type system.  I'm under the impression that in
previous discussions, there were a mixture of both both (C and C++)
models. 


   The constructs in a C++ program create, destroy, refer to,
   access, and manipulate objects. An object is a region of
   storage. [Note: A function is not an object, regardless of whether
   or not it occupies storage in the way that objects do. ] An object
   is created by a definition (3.1), by a new-expression (5.3.4) or by
   the implementation (12.2) when needed. The properties of an object are
   determined when the object is created.  An object can have a name
   (clause 3). An object has a storage duration (3.7) which influences
   its lifetime (3.8). An object has a type (3.9). The term object
   type refers to the type with which the object is created.  Some
   objects are polymorphic (10.3); the implementation generates
   information associated with each such object that makes it possible
   to determine that objects type during program execution. For other
   objects, the interpretation of the values found therein is
   determined by the type of the expressions (clause 5) used to access them.


Here, C++ says that the type of an object is acquired when the object
is created, NOT the type of the lvalue expression used to access it.

Someone allued to the type-based alias analysis, again C++ uses a
slightly different formulation talking about the "dynamic type", which
is well-defined, i.e. the type with which the object was created.
Thus GCC is well-founded there.

| Because if you allow casting away, then you can't ever trust const to be
| true either, just like we apparently can't trust the user saying "this
| is not volatile" (which they are doing by not declaring the original
| object volatile).

Indeed.  We must however make sure we distinguish between the meaning
of  const as in "const T* p" and that of const in "const T".

| There is no point in type qualifiers if they can be simply changed at
| will.  Do not lie about your objects, and you will not be screwed over.

only if the language you're implementing the compiler for says so, no
matter what nifty transformation you could have done.

-- Gaby

Reply via email to