On Thu, 28 Oct 2021 at 08:22, Yongwei Wu <wuyongwei@gmail.com> wrote:
On Wed, 27 Oct 2021 at 21:41, <language.lawyer@gmail.com> wrote:
On 27/10/2021 16:24, Yongwei Wu wrote:
> On Wed, 27 Oct 2021 at 20:36, <language.lawyer@gmail.com> wrote:
>> On 27/10/2021 15:22, Yongwei Wu via Std-Discussion wrote:
>>> On Wed, 27 Oct 2021 at 19:57, <language.lawyer@gmail.com> wrote:
>>>> On 27/10/2021 14:44, Yongwei Wu via Std-Discussion wrote:
>>>>> When looking up the exact wording of aliasing rules in C++, I am
>>>> surprised
>>>>> to find that much content seems to be gone in the C++20 (draft, N4860)
>>>>> under 7.2.1 p11. Specifically, there is no mention of the validity of
>>>>> aliasing with "a type that is a (possibly cv-qualified) base class type
>>>> of
>>>>> the dynamic type of the object", which existed in earlier C++
>> standards.
>>>>> Also the online link: https://eel.is/c++draft/basic.lval#11
>>>>> I do not think the standard has changed the rule, so I must have missed
>>>>> something. Can anyone point to me how to read the rules, maybe pointing
>>>> me
>>>>> to a discussion of the wording change?
>>>> https://wg21.cmeerw.net/cwg/issue2051
>> https://stackoverflow.com/questions/56878519/what-happened-to-the-aggregate-or-union-type-that-includes-one-of-the-aforement
>>>> TL;DR the removed rules have never been applicable.
>>> Thanks for the info. But the issue is not completely resolved for me.
>>> Say:
>>> struct A { … };
>>> struct B : A { … };
>>> A* pA = new B{…};
>>> Is using pA->… to access the base-class fields undefined behaviour?
>>> Interpreting the rules literally, it seems to be the case … but that
>> seems
>>> very surprising to me.
>> According to the current C++ model, access only happens to the object
>> denoted by a glvalue. Access to a subobject doesn't count as access to the
>> containing object.
>> And the evaluation of the object expression of a class member access
>> expression *itself* (i.e. ignoring what happens in its subexpressions) is
>> not considered access to the class object it denotes.
> Let me understand it better by an example:
> struct A { uint32_t v1; uint32_t v2; };
> struct B { uint32_t v1; uint16_t v2; };
> A a;
> B* pB = reinterpret_cast<B*>(&a);
> Question: Is reading pB->v1 undefined behaviour?

It is, but not because of strict aliasing rules violation.
There is no explicit wording saying that this has undefined behavior. [expr.ref]/(6.1) could be read as that an object of type A doesn't have a member subobject corresponding to B::v1 and thus this bullet doesn't apply and the behavior is undefined by omission. Yes, this sounds weak. [expr.ref] should explicitly say something like that the type of the object expression, ignoring qualifiers, shall be the same as its dynamic type, otherwise the behavior is undefined.

I agree it is rather weak. I am still not able to determine from [expr.rf]/ that pB->v1 is undefined behaviour from the text. I do not think it applies, and it does not mention undefined behaviour at all.

Maybe the intention is the same, but it is simply not clear from the text that base-class access is defined and unrelated-class access is undefined. It is clearer in C++17 [basic.lval]/6.10.

Even more confusingly, currently on CppReference.com "AliasedType is a (possibly cv-qualified) base class of DynamicType" is listed under "two additional bullets partially inherited from C", which "describe situations that cannot arise in C++". Utterly confused (does C even have base classes?).

Of course, this is not the standard text, but it seems to indicate that the confusion is not just mine. Maybe this is something worth clarifying in the standard?