Title
Type punning in class member access
Status
cd6
Section
7.6.1.5 [expr.ref]
Submitter
Andrey Erokhin

Created on 2022-02-17.00:00:00 last changed 27 months ago

Messages

Date: 2022-06-18.06:58:04

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.
Date: 2022-07-15.00:00:00

[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.
History
Date User Action Args
2022-08-19 07:54:33adminsetstatus: ready -> cd6
2022-06-18 06:58:04adminsetstatus: open -> ready
2022-02-18 07:47:23adminsetmessages: + msg6737
2022-02-17 00:00:00admincreate