Am Montag, dem 18.03.2024 um 09:26 +0100 schrieb Richard Biener: > On Mon, Mar 18, 2024 at 8:03 AM Martin Uecker <uec...@tugraz.at> wrote: > > > > > > Hi, > > > > can you please take a quick look at this? This is intended to align > > the C standard with existing practice with respect to aliasing by > > removing the special rules for "objects with no declared type" and > > making it fully symmetric and only based on types with non-atomic > > character types being able to alias everything. > > > > > > Unrelated to this change, I have another question: I wonder if GCC > > (or any other compiler) actually exploits the " or is copied as an > > array of byte type, " rule to make assumptions about the effective > > types of the target array? > > We do not make assumptions about this anymore. We did in the > past (might be a distant past) transform say > > struct X { int i; float f; } a, b; > > void foo () > { > __builtin_memcpy (&a, &b, sizeof (struct X)); > } > > into > > a = b; > > which has an lvalue of type struct X. But this assumed b's effective > type was X. Nowadays we treat the copy as using alias set zero. > That effectively means the destination gets its effective type "cleared" > (all subsequent accesses are valid to access storage with the effective > type of a byte array).
Ok, thanks! I wonder whether we should remove this special rule from the standard. I mostly worried about the "copied as an array of byte type" wording which seems difficult to precisely define. > > > I know compilers do this work memcpy... > > Maybe also if a loop is transformed to memcpy? > > We currently do not preserve the original effective type of the destination > (or the effective type used to access the source) when doing this. With > some tricks we could (we also lose aligment guarantees of the original > accesses). > > > Martin > > > > > > Add the following definition after 3.5, paragraph 2: > > > > byte array > > object having either no declared type or an array of objects declared with > > a byte type > > > > byte type > > non-atomic character type This essentially becomes the "alias anything" type. > > > > Modify 6.5,paragraph 6: > > The effective type of an object that is not a byte array, for an access to > > its > > stored value, is the declared type of the object.97) If a value is > > stored into a byte array through an lvalue having a byte type, then > > the type of the lvalue becomes the effective type of the object for that > > access and for subsequent accesses that do not modify the stored value. > > If a value is copied into a byte array using memcpy or memmove, or is > > copied as an array of byte type, then the effective type of the > > modified object for that access and for subsequent accesses that do not > > modify the value is the effective type of the object from which the > > value is copied, if it has one. For all other accesses to a byte array, > > the effective type of the object is simply the type of the lvalue used > > for the access. > > What's the purpose of this change? To me this reads more confusing and > complicated than what I find in the c23 draft from April last year. Note that C23 has been finalized. This change is proposed for the revision after c23. > > I'll note that GCC does not take advantage of "The effective type of an > object for an access to its stored value is the declard type of the object", > instead it always relies on the type of the lvalue (treating non-atomic > character types specially, as well as treating all string ops like memcpy > or strcpy as using a character type for the access) and the effective type > of the object for that access and for subsequent accesses that do not > modify the stored value always becomes that of the lvalue type used for > the access. Understood. > > Let me give you an complication example made valid in C++: > > struct B { float x; float y; }; > struct X { int n; char buf[8]; } x, y; > > void foo(struct B *b) > { > memcpy (x.buf, b, sizeof (struct B)); // in C++: new (x.buf) B (*b); Let's make it an explicit store for the moment (should not make a difference though): *(struct B*)x.buf = *b; > y = x; // (*) > } > > What's the effective type of 'x' in the 'y = x' copy? Good point. The existing wording would take the declared type of x as the effective type, but this may not be what you are interested in. Let's assume that x has no declared type but that it had effective type struct X before the store to x.buf (because of an even earlier store to x with type struct X). There is a general question how stores to subobjects affect effective types and I do not think this is clear even before this proposed change. > With your new > wording, does 'B' transfer to x.buf with memcpy? Yes, it would. At least this is the intention. Note that this would currently be undefined behavior because x.buf has a declared type. So this is main thing we want to change, i.e. making this defined. > What's the > frankenstein effective type of 'x' then? What's the effective type > of 'y' after the copy? Can an lvalue of type 'B' access y.buf? All good questions, but unfortunately not clear even in the current wording I think. Martin > > Richard. > > > https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3230.pdf > > > >