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

2024-04-18


2535. Type punning in class member access

Section: 7.6.1.5  [expr.ref]     Status: CD6     Submitter: Andrey Erokhin     Date: 2022-02-17

[Accepted at the July, 2022 meeting.]

The initialization of j ought to have undefined behavior, but the standard does not explicitly say so:

  struct C { int m; };

  int i = 0;
  int j = reinterpret_cast<C&>(i).m; // the same as int j = i ?

A related case for pointer-to-member expressions is covered by 7.6.4 [expr.mptr.oper] paragraph 4:

If the dynamic type of E1 does not contain the member to which E2 refers, the behavior is undefined.

The invocation of non-static member functions is covered by 11.4.3 [class.mfct.non.static] paragraph 2:

If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.

Proposed resolution (approved by CWG 2022-06-17):

(updated according to 2022-05-20 and 2022-06-03 CWG guidance)

  1. Add a new paragraph after 7.6.1.5 [expr.ref] paragraph 7:

    If E2 is a non-static data member or a non-static member function, the program is ill-formed if the class of which E2 is directly a member is an ambiguous base (6.5.2 [class.member.lookup]) of the naming class (11.8.3 [class.access.base]) of E2. [Note: The program is also ill-formed if the naming class is an ambiguous base of the class type of the object expression; see 11.8.3 [class.access.base]. —end note -- end note]

    If E2 is a non-static member and the result of E1 is an object whose type is not similar (7.3.6 [conv.qual]) to the type of E1, the behavior is undefined. [ Example:

      struct A { int i; };
      struct B { int j; };
      struct D : A, B {};
      void f() {
        D d;
        static_cast<B&>(d).j;       // OK, object expression designates the B subobject of d
        reinterpret_cast<B&>(d).j;  // undefined behavior
      }
    
    -- end example ]

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

    If the dynamic type of E1 If the result of E1 is an object whose type is not similar to the type of E1, or whose most derived object does not contain the member to which E2 refers, the behavior is undefined. Otherwise, t The expression E1 is sequenced before the expression E2.
  3. Remove 11.4.3 [class.mfct.non.static] paragraph 2:

    If a non-static member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.