This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 116a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-12-19


2593. Insufficient base class restriction for pointer-to-member expression

Section: 7.6.4  [expr.mptr.oper]     Status: review     Submitter: Hubert Tong     Date: 2022-06-04

Consider:

  struct A {};
  struct AA : A { int y; };
  struct B : A { int x; };
  struct C : AA, B {};

  constexpr int f(const A &a) {
    int A::*mp = static_cast<int A::*>(&B::x);
    return a.*mp;
  }

  extern char x[f(static_cast<const AA &>(C{{{}, 13}, {{}, 42}}))];
  extern char x[13];

Subclause 7.6.4 [expr.mptr.oper] paragraph 4 specifies:

Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

In the example, the dynamic type of a is C, which does contain B::x, and the undefined behavior provision does not trigger. Thus the call to f is required to yield 42; however common implementations produce 13. The behavior for this case ought to be undefined.

Suggested resolution:

Change in 7.6.4 [expr.mptr.oper] paragraph 4 as follows:

Abbreviating pm-expression.*cast-expression as E1.*E2, E1 is called the object expression. If the dynamic type of E1 does not contain the member to which E2 refers, Where the type of E2 is "pointer to member of T", C is the (unique) class of which the member to which E2 refers is a direct member, and B is the object of type T that either is the result of E1 or is the uniquely so-typed base subobject thereof, if B is neither of type C nor a base class subobject of an object of type C, then the behavior is undefined.