Title
Implicitly moving the operand of a throw-expression in unevaluated contexts
Status
review
Section
7.5.5.3 [expr.prim.id.qual]
Submitter
Richard Smith

Created on 2022-03-11.00:00:00 last changed 4 days ago

Messages

Date: 2024-12-17.10:29:09

Proposed resolution:

Change in 7.5.5.2 [expr.prim.id.unqual] paragraph 4:

An implicitly movable entity is a variable of with automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following contexts, an An id-expression is move-eligible: if
  • it names an implicitly movable entity,
  • Ifit is the id-expression (possibly parenthesized) is the operand of a return or co_return statement, and names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression or if the id-expression (possibly parenthesized) is the operand of a throw-expression, and names an implicitly movable entity that belongs to a scope that does not contain the compound-statement of the innermost lambda-expression, try-block, or function-try-block (if any) whose compound-statement or ctor-initializer encloses the throw-expression
  • each intervening scope between the declaration of the entity and the innermost enclosing scope of the id-expression is a block scope and, for a throw-expression, is not the block scope of a try-block or function-try-block.
Date: 2024-12-15.00:00:00

Additional notes (December, 2024)

Treating potentially-evaluated expressions differently (as opposed to unevaluated ones) is surprising.

Date: 2024-12-17.10:29:09

Proposed resolution [SUPERSEDED]:

Change in 7.5.5.2 [expr.prim.id.unqual] paragraph 4:

An implicitly movable entity is a variable of with automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following contexts, an An id-expression is move-eligible: if
  • it names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression and
  • If the id-expression (possibly parenthesized) id-expression is the operand of
    • a return or co_return statement, and names an implicitly movable entity declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression or
    • if the id-expression (possibly parenthesized) is the operand of a potentially-evaluated throw-expression, and names an implicitly movable entity that belongs to a scope that does not contain the compound-statement of the innermost lambda-expression, try-block, or function-try-block (if any) whose compound-statement or ctor-initializer encloses the throw-expression where no try-block or function-try-block intervenes between the declaration of the entity and the innermost enclosing scope of the throw-expression.
Date: 2024-02-17.11:33:06

Consider:

  void f() {
    X x;
    // Is x an lvalue or an xvalue here?
    void g(int n = (decltype((throw x, 0))()));  // status quo: x is move-eligible here
  }

  void f() {
    X x;
    struct A {
      void g() {
        try {
          struct Y {
            // Is x an lvalue or an xvalue here?
            void h(int n = (decltype((throw x, 0))()));
          };
        } catch (...) { }
      }
    };
  }

11.9.6 [class.copy.elision] paragraph 3 specifies:

An implicitly movable entity is a variable of automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. In the following copy-initialization contexts, a move operation is first considered before attempting a copy operation:
  • ...
  • if the operand of a throw-expression (7.6.18 [expr.throw]) is a (possibly parenthesized) id-expression that names an implicitly movable entity that belongs to a scope that does not contain the compound-statement of the innermost try-block or function-try-block (if any) whose compound-statement or ctor-initializer contains the throw-expression,

Thus, in the first example above, x is treated as an xvalue, but it is treated as an lvalue in the second example. This outcome is surprising.

(P2266R2 (Simpler implicit move) moved this wording, introduced by P1825R0 (Merged wording for P0527R1 and P1155R3), from 11.9.6 [class.copy.elision] to 7.5.5.2 [expr.prim.id.unqual].)

History
Date User Action Args
2024-12-17 10:29:09adminsetmessages: + msg7923
2024-12-17 10:29:09adminsetmessages: + msg7922
2023-06-15 08:19:29adminsetstatus: open -> review
2022-03-11 00:00:00admincreate
2022-02-18 07:47:23adminsetmessages: + msg6762