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: Tue, 9 Nov 2021 18:04:31 +0300
On 09/11/2021 17:15, Yongwei Wu wrote:
> On Tue, 9 Nov 2021 at 00:11, <language.lawyer_at_[hidden]> wrote:
>
>> On 08/11/2021 15:32, Yongwei Wu wrote:
>>> On Mon, 8 Nov 2021 at 17:39, <language.lawyer_at_[hidden]> wrote:
>>>
>>>>> 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»?
>>>>
>>>
>>> You do have a point, but this is not how I interpret the C++17 rule.
>>>
>>> According to the C++17 rule, if we have:
>>>
>>> struct B1 { int i1; };
>>> struct B2 { int i2; };
>>> struct B3 { int i3; };
>>>
>>> struct D : B1, B2 {};
>>>
>>> D* pD = …;
>>> B2* pB2 = …;
>>> B3* pB3 = …;
>>>
>>> Assuming the compiler cannot determine whether pD and pB2 are related
>> (say,
>>> they are passed in to a function), then changes to *pB2 should cause the
>>> compiler to consider *pD is possibly changed. But whatever change made to
>>> *pB3 will not cause the compiler to consider *pD might be tampered with.
>>>
>>> Does it still hold for C++20? If so, through which rules?
>>
>> I don't understand what is your concern here.
>> Is it again a question about why, if pB3 is used with the -> operator,
>> then it can be assumed to point to an object of type «cv B3»?
>>
>
> My understanding of the C++17 rule:
>
> Writing to *pB2 may change *pD, and the compiler will always assume *pD
> might have changed after I write to *pB2.
>
> Whereas:
>
> Writing to *pB3 must not change *pD (which would be undefined behaviour),
> and the compiler will always assume *pD does not change after I write to
> *pB3.
>
> My question has two parts:
>
> 1) Does it still hold for C++20? (I would guess yes.)
> 2) If so, through which rules? (I cannot deduce the result from the C++20
> standard text.)

In a well-behaving program, there is no such thing as access (read/modification) of an object of class type.
What can happen — is access to an object of a scalar type through different "paths", like pD->i1 and pB2->i1, if pB2 points to a base class subobject of *pD.

Knowing that pB2 may point to a base class subobject of *pD is enough for a compiler to invalidate its knowledge about pD->i1 when pB2->i1 is modified, since these expressions can denote the same (scalar) object.
I don't understand what kind of rule you are looking for. You have doubts that it is allowed to have a pointer to an object and a pointer to its base class subobject at the same time? If pD and pB2 are function parameters, you may look to the section about function call expression and everything which is related to it, like the section about initialization. They define behavior without such precondition.

For the pB3 case, I think I've already wrote that there is not very clearly specified rule about object of which type E1 expression in E1.E2 can denote.

Received on 2021-11-09 09:04:38