<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Mar 18, 2015 at 2:22 AM, Jeroen Dobbelaere <span dir="ltr"><<a href="mailto:jeroen.dobbelaere@gmail.com" target="_blank">jeroen.dobbelaere@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote"><span>On Tue, Mar 17, 2015 at 11:55 PM, Daniel Berlin <span dir="ltr"><<a href="mailto:dberlin@dberlin.org" target="_blank">dberlin@dberlin.org</a>></span> wrote:<br></span><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr">[..]<div class="gmail_extra"><div class="gmail_quote"><span><div><br></div></span><span><div>In theory, the last time i remember, you weren't allow to set one member of a union and read another.</div><div>But uh, that's not real user code :)</div><div><br></div><div>(and IIRC, it does not say anything real)</div><span><div> <br></div></span></span></div></div></div></blockquote><div>This is indeed correct. The main issue is that llvm thinks it is allowed to reorder 'stores' (as it thinks they are not aliasing),<br>so that a legal read afterwards will result in a wrong answer (if an optimization or the backend reorders the stores based on the wrong aliasing information).<br><br></div><span><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span><div></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>If you access a member (or nested member) of a union, starting from the union itself, then it depends if the other type is also accessible through the union.<br><br><br></div><div>So:<br><br></div><div>int foo(union foo* a, float* b, int* c) {<br></div><div> a->a=1;<br></div><div> *b=2;<br></div><div> // compiler must assume a->a and *b can alias<br></div><div> // compiler must not assume *b and *c alias (access not through union)<br></div><div>}<br><br></div><div>(Also see section 3.10 of the c++03 standard;</div></div></div></div></blockquote><div><br></div><div><br></div></span><div>This, IMHO, does not say what you seem to think it does :)</div><div><br></div><div>For C++03, 3.10 only includes the word "union" here: "If a program attempts to access the stored value of an object through an lvalue of other than one of the following
types the behavior is undefined: </div><div><br></div><div>— the dynamic type of the object, </div><div>— a cv-qualified version of the dynamic type of the object, </div><div>— a type that is the signed or unsigned type corresponding to the dynamic type of the object,</div><div> — a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of
the object, </div><div>— an aggregate or union type that includes one of the aforementioned types among its members (including,
recursively, a member of a subaggregate or contained union),</div><div> — a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,</div><div> — a char or unsigned char type."<br><div><br><br></div><div>C++ standard experts, at least on the GCC side, did not view this as saying "all accesses must have an explicit union access", but that "It must be part of a union type", but about whether you try to access it through a union that doesn't have the right actual types in it.</div></div><div><br></div><div>The type of those objects is right the type of the object. There is, IMHO, nothing illegal about those accesses.</div><div><br></div><div><br></div></div></div></div></blockquote></span><div><br>So, with that interpretation, the mere presence of a 'union { short s; int i; }' (in the same or a different compilation unit) should influence the (type based) aliasing of all short and int pointers ?<br></div></div></div></div></blockquote><div><br></div><div>That's not what this wording literally says (nor, I think, what it intends). The quoted text is specifically talking about the type of the lvalue used to perform the access. In C++, this is almost never a struct or union type; the only case where that can happen is when copying the object representation of a union in a case like this:</div><div><br></div><div> union A { int i; short s; };</div><div> A a;</div><div> A f() { return a; } // here, we copy the representation of 'a' through an lvalue of type 'A'.</div><div><br></div><div>(In C, where largely the same wording appears, this bullet is relevant in more cases, since copies of structs in C are performed directly by copying the object and not via a copy constructor.)</div><div><br></div><div>In a case like 'ihateunions', the expression '*a = 0;' would use an lvalue of type 'int' and the expression 'x = *b;' would use an lvalue of type 'float', so those two accesses are known to not access the same object by 3.10, irrespective of what aggregate or union types exist elsewhere in the program. Also note that C++ does not specify any way to change the active member of a union other than via a placement new-expression (and even that mechanism is only implied to work, never normatively stated) so these assignments presumably do not change the active member, and thus at least one of them must have undefined behavior (unlike C, C++ does not imbue storage with an effective type that can change through such an assignment; instead, it has objects whose lifetimes are started through declarations, when temporaries are created, and through new-expressions). As a sane implementation, we absolutely should guarantee that accessing a union member of primitive type and then immediately assigning to the result of that member access expression does change the active member, but we are not required to guarantee the same happens when the access is laundered through a function, according to the current C++ standard's wording, and attempting to provide such a guarantee seems largely pointless.</div></div></div></div>