Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
Eisenwave opened this issue Jan 2, 2025 · 8 comments
Open

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

Eisenwave opened this issue Jan 2, 2025 · 8 comments

Comments

@Eisenwave
Copy link

Eisenwave commented Jan 2, 2025

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:
@Eisenwave
Copy link
Author

Eisenwave commented Jan 2, 2025

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.

@jensmaurer
Copy link
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.

@Eisenwave
Copy link
Author

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

@jensmaurer
Copy link
Member

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

@Eisenwave
Copy link
Author

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.

@jensmaurer
Copy link
Member

9 places (max) need updates.

@Eisenwave
Copy link
Author

Eisenwave commented Jan 2, 2025

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. [...]

@jensmaurer
Copy link
Member

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

@jensmaurer jensmaurer changed the title [expr.arith.conv] 0 < 0 is an int CWG2981 [expr.arith.conv] 0 < 0 is an int Jan 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants