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

2024-11-11


2548. Array prvalues and additive operators

Section: 7.6.6  [expr.add]     Status: NAD     Submitter: Andrey Erokhin     Date: 2022-03-08     Liaison: EWG

Consider

  int main()
  {
    using IA = int[];
    IA{ 1, 2, 3 } + 0;
  }

This appears to be ill-formed given the current wording, because the operand is already a prvalue, thus 7.2.1 [basic.lval] paragraph 6 does not apply and the array-to-pointer conversion is not applied:

Whenever a glvalue appears as an operand of an operator that expects a prvalue for that operand, the lvalue-to-rvalue (7.3.2 [conv.lval]), array-to-pointer (7.3.3 [conv.array]), or function-to-pointer (7.3.4 [conv.func]) standard conversions are applied to convert the expression to a prvalue.

This outcome might be an oversight in the resolution for issue 1232.

See also clang issue 54016.

Proposed resolution [SUPERSEDED]:

Change in 7.6.6 [expr.add] paragraph 1 as follows:

The additive operators + and - group left-to-right. The usual arithmetic conversions (7.4 [expr.arith.conv]) are performed for operands of arithmetic or enumeration type. The array-to-pointer conversion (7.3.3 [conv.array]) is applied to an operand of array type.

CWG 2023-07-14

CWG is generally in favor of the proposed resolution, but the interaction with the surrounding text needs to be checked in more detail after a Working Draft reflecting the Varna straw polls has become available.

Additional notes (September, 2023)

It is questionable which use-cases are being addressed by this change. On the other hand, IA{1,2,3}[1] already works today (7.2.1 [basic.lval] paragraph 6 and 7.6.1.2 [expr.sub] paragraph 2). However, the latter does cause temporary lifetime extension (6.7.7 [class.temporary] paragraph 6), whereas the near-equivalent *(IA{1,2,3} + 1) does not.

Similar to the addition case, indirection through an array prvalue is also not valid today. Consistency seems desirable.

Related vendor tickets: clang, gcc.

Possible resolution (amended 2023-10-09):

  1. Change in 7.6.2.2 [expr.unary.op] paragraph 1 as follows:

    The unary * operator performs indirection. The array-to-pointer conversion (7.3.3 [conv.array]) is applied to an operand of array type; the possibly converted Its operand shall be a prvalue of type “pointer to T”, where T is an object or function type. The operator yields an lvalue of type T denoting the object or function to which the operand points.
  2. Change in 7.6.2.2 [expr.unary.op] paragraph 7 as follows:

    The unary + operator performs promotion. The array-to-pointer conversion (7.3.3 [conv.array]) is applied to an operand of array type; the possibly converted operand of the unary + operator shall be a prvalue of arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument. Integral promotion (7.3.7 [conv.prom]) is performed on integral or enumeration operands. The type of the result is the type of the promoted operand. The operator yields a prvalue of the type of the converted operand; the result is the value of the converted operand.
  3. Change in 7.6.6 [expr.add] paragraph 1 as follows:

    The additive operators + and - group left-to-right. Each operand shall be a prvalue. If both operands have arithmetic or unscoped enumeration type, the usual arithmetic conversions (7.4 [expr.arith.conv]) are performed. Otherwise, if one operand has arithmetic or unscoped enumeration type, integral promotion is applied (7.3.7 [conv.prom]) to that operand. The array-to-pointer conversion (7.3.3 [conv.array]) is applied to an operand of array type. A converted or promoted operand is used in place of the corresponding original operand for the remainder of this section.
  4. Change in 7.6.1.2 [expr.sub] paragraph 2 as follows:

    ... The result of the expression E1[E2] is identical (by definition) to that of *((E1)+(E2)), except that in the case of an array operand, the result is an lvalue if that operand is an lvalue and an xvalue otherwise.
    [ Note: The semantics of E1[E2] differ from those of *((E1)+(E2)) also for -- end note ]

CWG 2023-09-15 (amended 2023-10-09)

CWG seeks advice from EWG whether support for array prvalue operands should be added for the indirection operator, the unary + operator, and the additive operators, along the lines of the wording above. Similar to the [] operator, the specification of the indirection operation could be amended to yield an xvalue if the argument is a prvalue. The unary + operator is occasionally used to force an array-to-pointer decay.

Forwarded to EWG via paper issue 1633.

Paper P2865R2 seeks to remove the array-to-pointer conversion for the operands of relational operators, wheras this issue suggests adding more applications for the array-to-pointer conversion. These two directions appear not to be in harmony.

EWG 2023-11-07

The lack of support for the corner-case in this issue is not a defect given the direction in P2865 (Remove Deprecated Array Comparisons from C++26).