On Mon, 8 Nov 2021 at 17:39, <language.lawyer@gmail.com> 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?