This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 117a. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2025-04-13
[Accepted as a DR at the March, 2024 meeting.]
Subclause 7.6.1.5 [expr.ref] paragraph 2 specifies:
For the first option (dot) the first expression shall be a glvalue. ...
This provision forces a temporary materialization conversion (i.e. a copy) per 7.2.1 [basic.lval] paragraph 7:
Whenever a prvalue appears as an operand of an operator that expects a glvalue for that operand, the temporary materialization conversion (7.3.5 [conv.rval]) is applied to convert the expression to an xvalue.
However, this is limiting in the case that an explicit object member function with a by-value object parameter is invoked for a non-copyable class object, for example:
struct X { X() = default; X(const X&) = delete; X& operator=(const X&) = delete; void f(this X self) { } }; void f() { X{}.f(); // OK? }
The example ought to be well-formed.
Proposed resolution (reviewed by CWG 2024-02-16) [SUPERSEDED]:
Change in 6.7.7 [class.temporary] paragraph 2 as follows:
... [Note 3: Temporary objects are materialized:—end note]
- when binding a reference to a prvalue (9.5.4 [dcl.init.ref], 7.6.1.4 [expr.type.conv], 7.6.1.7 [expr.dynamic.cast], 7.6.1.9 [expr.static.cast], 7.6.1.11 [expr.const.cast], 7.6.3 [expr.cast]),
- when performing member
accesson a class prvalue (7.6.1.5 [expr.ref], 7.6.4 [expr.mptr.oper]),- when invoking an implicit object member function on a class prvalue (7.6.1.3 [expr.call]),
- ...
Change in 7.6.1.3 [expr.call] paragraph 6 as follows:
When a function is called, each parameter (9.3.4.6 [dcl.fct]) is initialized (9.5 [dcl.init], 11.4.5.3 [class.copy.ctor]) with its corresponding argument. If the function is an explicit object member function and there is an implied object argument (12.2.2.2.2 [over.call.func]), the list of provided arguments is preceded by the implied object argument for the purposes of this correspondence. If there is no corresponding argument, the default argument for the parameter is used. [Example 1:template<typename ...T> int f(int n = 0, T ...t); int x = f<int>(); // error: no argument for second function parameter—end example] If the function is an implicit object member function, and the this parameter of the function (7.5.3 [expr.prim.this]) is initialized with a pointer to the object of the call, converted as if by an explicit type conversion (7.6.3 [expr.cast]). [Note 5: There is no access or ambiguity checking on this conversion; the access checking and disambiguation are done as part of the (possibly implicit) class member access operator. See 6.5.2 [class.member.lookup], 11.8.3 [class.access.base], and 7.6.1.5 [expr.ref]. —end note] When a function is called, the type of any parameter shall not be a class type that is either incomplete or abstract. [Note 6: This still allows a parameter to be a pointer or reference to such a type. However, it prevents a passed-by-value parameter to have an incomplete or abstract class type. —end note] It is implementation-defined whether ...
Change in 7.6.1.5 [expr.ref] paragraph 2 as follows:
For the first option (dot) the first expression shall be a glvalue. For the second option (arrow) the first expression shall be a prvalue having pointer type. ...
CWG 2024-02-16
When a class member access refers to a static data member or a member enumerator, the object expression should also be treated as a discarded-value expression.
Proposed resolution (approved by CWG 2024-03-01):
Change in 6.7.7 [class.temporary] paragraph 2 as follows:
... [Note 3: Temporary objects are materialized:—end note]
- when binding a reference to a prvalue (9.5.4 [dcl.init.ref], 7.6.1.4 [expr.type.conv], 7.6.1.7 [expr.dynamic.cast], 7.6.1.9 [expr.static.cast], 7.6.1.11 [expr.const.cast], 7.6.3 [expr.cast]),
- when performing member
accesson a class prvalue (7.6.1.5 [expr.ref], 7.6.4 [expr.mptr.oper]),- when invoking an implicit object member function on a class prvalue (7.6.1.3 [expr.call]),
- ...
Change in 7.6.1.3 [expr.call] paragraph 6 as follows:
When a function is called, each parameter (9.3.4.6 [dcl.fct]) is initialized (9.5 [dcl.init], 11.4.5.3 [class.copy.ctor]) with its corresponding argument. If the function is an explicit object member function and there is an implied object argument (12.2.2.2.2 [over.call.func]), the list of provided arguments is preceded by the implied object argument for the purposes of this correspondence. If there is no corresponding argument, the default argument for the parameter is used. [Example 1:template<typename ...T> int f(int n = 0, T ...t); int x = f<int>(); // error: no argument for second function parameter—end example] If the function is an implicit object member function, and the this parameter of the function (7.5.3 [expr.prim.this]) is initialized with a pointer to the object of the call, converted as if by an explicit type conversion (7.6.3 [expr.cast]). [Note 5: There is no access or ambiguity checking on this conversion; the access checking and disambiguation are done as part of the (possibly implicit) class member access operator. See 6.5.2 [class.member.lookup], 11.8.3 [class.access.base], and 7.6.1.5 [expr.ref]. —end note] When a function is called, the type of any parameter shall not be a class type that is either incomplete or abstract. [Note 6: This still allows a parameter to be a pointer or reference to such a type. However, it prevents a passed-by-value parameter to have an incomplete or abstract class type. —end note] It is implementation-defined whether ...
Change in 7.6.1.5 [expr.ref] paragraph 2 as follows:
For the first option (dot) the first expression shall be a glvalue. For the second option (arrow) the first expression shall be a prvalue having pointer type. ...