C++ Logo

std-discussion

Advanced search

Re: Wording change about "base class type" in aliasing rules

From: language.lawyer_at <language.lawyer_at_[hidden]>
Date: Mon, 8 Nov 2021 12:39:42 +0300
On 28/10/2021 03:22, Yongwei Wu wrote:
> On Wed, 27 Oct 2021 at 21:41, <language.lawyer_at_[hidden]> wrote:
>
>> On 27/10/2021 16:24, Yongwei Wu wrote:
>>> On Wed, 27 Oct 2021 at 20:36, <language.lawyer_at_[hidden]> wrote:
>>>
>>>> On 27/10/2021 15:22, Yongwei Wu via Std-Discussion wrote:
>>>>> On Wed, 27 Oct 2021 at 19:57, <language.lawyer_at_[hidden]> 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]/
> 7.6.1.5 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, after this topic has been raised again in CWG list for something like fifths time (if not more), a more explicit rule will be added.

> 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.

[basic.lval] is not related to the incoherent object expression issue.
And there is nothing special in base vs. non-base class from [expr.ref] POV.

struct B1 { int i1; };
struct B2 { int i2; };

struct D : B1, B2 {};

D d;
B2* b2 = reinterpret_cast<B2*>(&d);

After all, you don't read C++17 [basic.lval] as meaning that doing b2->i2 is OK and (should) have defined behavior because it is «base-class access»?

>> 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...
>

Received on 2021-11-08 03:39:47