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.

> I believe it was the case in C++17. Does the new definition of "access" (in
> 3.1) imply that pB->v1 is no longer undefined?

I think the definition of "access" was the same in C++17.

In C++17 "access" was defined as "to read or modify the value of an object". In C++20 "access" is explicitly limited to "only objects of scalar type". Yes, maybe the intentions are the same...

Yongwei Wu
URL: http://wyw.dcweb.cn/