Skip to content

CWG2981 [expr.arith.conv] 0 < 0 is an int #663

Description

@eisenwave

Reference (section label): [expr.arith.conv] pargraph 1

Issue description

[expr.rel] paragraph 2 states that the result of the relational operator for e.g. 0 < 0 is bool. This is subsequently contradicted by [expr.rel] paragraph 3, which states that the usual arithmetic conversions are applied, and [expr.arith.conv] paragraph 1 states:

The purpose [of the usual arithmetic conversions] is to yield a common type, which is also the type of the result.

If paragraph 3 supersedes paragraph 2, then 0 < 0 is of type int.

Suggested resolution

Update [expr.arith.conv] paragraph 1 as follows:

Many binary operators that expect operands of arithmetic or enumeration type
cause conversions and yield result types in a similar way.
The purpose is to yield a common type
-, which
+; unless otherwise stated, that common type
is also the type of the result.
This pattern is called the usual arithmetic conversions, which are defined as follows:

Activity

  1. eisenwave commented on Jan 2, 2025

    @eisenwave
    MemberAuthor

    I'm not really sure what the intended wording strategy here is. https://eel.is/c++draft/expr.mul chooses to say that:

    The usual arithmetic conversions are performed on the operands and determine the type of the result.

    But why wouldn't the usual arithmetic conversions determine the result by default? [expr.arith.conv] simply states what the result is, and that wording isn't conditional on "if stated to determine the type of the result". Also note that [expr.add] relies on the type of 0 + 0 being determined by the usual arithmetic conversions without this being stated explicitly; it is nowhere stated in [expr.add] what the type of 0 + 0 is.

    In short, we end up with three cases at least:

    • [expr.add] implicitly uses the result type of usual arithmetic conversions
    • [expr.mul] explicitly uses the result type of usual arithmetic conversions
    • [expr.rel] inadvertently (?) uses the result type and contradicts prior wording

    On another side note, I couldn't find any wording which states what the value category of 0 + 0 is.

    My preferred overarching fix would be to purge the practice of using [expr.arith.conv] to determine the result type completely (it's weird, done inconsistently, and doesn't save that much wording elsewhere anyway), and that could be done as an editorial fix once normative wording problems are fixed.

  2. jensmaurer commented on Jan 2, 2025

    @jensmaurer
    Member

    I think we should limit "usual arithmetic conversions" to exactly that: conversions on the operands. The result type (and value category) should be specified by each individual operator.

  3. eisenwave commented on Jan 2, 2025

    @eisenwave
    MemberAuthor

    You know what, I think I'll just make a paper for that.

  4. jensmaurer commented on Jan 2, 2025

    @jensmaurer
    Member

    Why a paper? I certainly want a bit of CWG review on the change, but this feels entirely like a core issue.

  5. eisenwave commented on Jan 2, 2025

    @eisenwave
    MemberAuthor

    Because the blast radius is pretty large here, and I think as a drive-by fix, we should also specify the value category where needed. I'll look into how big of a change that really is first. I guess I can post the diff here and see if that needs a paper.

    In the end, we should clearly state that e.g. x + y for integers is a prvalue of the common type after usual arithmetic conversions.

  6. jensmaurer commented on Jan 2, 2025

    @jensmaurer
    Member

    9 places (max) need updates.

  7. eisenwave commented on Jan 2, 2025

    @eisenwave
    MemberAuthor

    Suggested resolution v2

    Update [expr.arith.conv] paragraph 1 as follows:

    Many binary operators that expect operands of arithmetic or enumeration type cause conversions and yield result types in a similar way. The purpose is to yield a common type, which is also the type of the result. This pattern is called the usual arithmetic conversions, which are defined as follows: [...]

    Editor's note: While it's not incorrect that result types are also often yielded in a similar way, it's not always the case (e.g. [expr.rel], [expr.eq]), and we should purge any mention of result types if these conversions aren't stated to determine the result anyway.

    Update [expr.mul] paragraph 2 as follows:

    The usual arithmetic conversions are performed on the operands and determine the type of the result, and the result is a prvalue of the common type determined by the usual arithmetic conversions.

    Update [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 are performed on the operands, and the result is a prvalue of the common type determined by the usual arithmetic conversions.
    Otherwise, if one operand has arithmetic or unscoped enumeration type, integral promotion is applied to that operand.
    A converted or promoted operand is used in place of the corresponding original operand for the remainder of this section.

    Update [expr.rel] paragraph 2 as follows:

    [...] The type of the result is a prvalue of type bool.

    Editor's note: Since we state that false or true are always yielded, this is only an editorial fix. Nonetheless, we should do it for consistency here. This core issue introduces "prvalue of type" wording for every case that was previously covered by the usual arithmetic conversions, and so updating this part of [expr.rel] should be within its scope.

    Update [expr.eq] paragraph 7 as follows:

    If both operands are of arithmetic or enumeration type, the usual arithmetic conversions are performed on both operands; each of the operators shall yield true if the specified relationship is true and false if it is false.
    The result is a prvalue of type bool.

    Update [expr.bit.and] paragraph 1 as follows:

    The & operator groups left-to-right.
    The operands shall be of integral or unscoped enumeration type.
    The usual arithmetic conversions are performed on the operands, and the result is a prvalue of the common type determined by the usual arithmetic conversions. [...]

    Update [expr.xor] paragraph 1 as follows:

    The ^ operator groups left-to-right.
    The operands shall be of integral or unscoped enumeration type.
    The usual arithmetic conversions are performed on the operands, and the result is a prvalue of the common type determined by the usual arithmetic conversions. [...]

    Update [expr.bit.or] paragraph 1 as follows:

    The | operator groups left-to-right.
    The operands shall be of integral or unscoped enumeration type.
    The usual arithmetic conversions are performed on the operands, and the result is a prvalue of the common type determined by the usual arithmetic conversions. [...]

  8. jensmaurer commented on Jan 2, 2025

    @jensmaurer
    Member

    CWG2981 with suggested resolution adjusted to be consistent with [expr.cond] p7.2

  9. changed the title [-][expr.arith.conv] `0 < 0` is an `int`[/-] [+]CWG2981 [expr.arith.conv] `0 < 0` is an `int`[/+] on Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions