cplusplus / CWG

Core Working Group
23 stars 7 forks source link

[conv.integral] Conversion of bool to width-1 signed integer type #365

Open randomnetcat opened 1 year ago

randomnetcat commented 1 year ago

Full name of submitter: Janet Cobb

Reference (section label): [conv.integral]

Issue description:

A signed integer type of width 1 has possible values -1 to 0 per [basic.fundamental].

[conv.integral] states that:

A prvalue of an integer type can be converted to a prvalue of another integer type. A prvalue of an unscoped enumeration type can be converted to a prvalue of an integer type.

If the destination type is bool, see [conv.bool]. If the source type is bool, the value false is converted to zero and the value true is converted to one.

Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2^N, where N is the width of the destination type.

Converting true to a width-1 signed integer type therefore should result in the value 1, which is not representable in the target type. This likely results in undefined behavior per [expr.pre]/4.

Suggested resolution (explicitly define the behavior):

If the destination type is bool, see [conv.bool]. If the source type is bool, the value false is converted to considered to be zero and the value true is converted to considered to be one.

Otherwise, the The result is the unique value of the destination type that is congruent to the source integer modulo 2^N, where N is the width of the destination type.

This would result in false being converted to 0 and true being converted to -1.

Alternative resolution (explicitly note the behavior is undefined):

If the destination type is bool, see [conv.bool]. If the source type is bool, the value false is converted to zero and the value true is converted to one. If that value cannot be represented in the target type, the behavior is undefined. [Note: this occurs if the destination type is a signed integer type of width 1.]

Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2^N, where N is the width of the destination type.

jensmaurer commented 1 year ago

I don't think there are any integer types with width 1; [implimits] doesn't allow that.

randomnetcat commented 1 year ago

Sorry, which part of [implimits] prohibits such a type? It isn't immediately obvious to me.

JohelEGP commented 1 year ago

https://eel.is/c++draft/basic.fundamental#4.sentence-1 specifies the minimum width to be 8.

randomnetcat commented 1 year ago

I don't see a way to read that as applying to extended integer types.

JohelEGP commented 1 year ago

An extended integer type is an integer type. So it applies. Unless you can point to where that restriction is lifted.

jensmaurer commented 1 year ago

Sorry, which part of [implimits] prohibits such a type? It isn't immediately obvious to me.

Sorry, it's in [basic.fundamental], as @JohelEGP has pointed out.

JohelEGP commented 1 year ago

I don't see a way to read that as applying to extended integer types.

https://eel.is/c++draft/basic.fundamental#4.sentence-1 applies to "signed integer type", which is defined at https://eel.is/c++draft/basic.fundamental#def:type,signed_integer and includes extended signed integer types.

jensmaurer commented 1 year ago

I think that sentence should read "standard signed integer type". Otherwise, we couldn't have extended integer types at all (because the referenced table is exhaustive).

jensmaurer commented 1 year ago

[conv.rank] doesn't help either. Looks like we don't exclude "small" extended integer types. I wonder if we should.

frederick-vs-ja commented 1 year ago

FYI, the minimum width of C23's signed _BitInt types is 2 (1 for unsigned _BitInt) (see N2709, N3096).

But C doesn't seem to forbid "small" extended integer types either.

jensmaurer commented 10 months ago

A related question is whether an "int" bit-field of width 1 can faithfully store a "bool" value. [class.bit] p4 doesn't read to me like it could.

JohelEGP commented 10 months ago

Isn't that because it falls out from other rules? Initializing a non-bool bit-field from a value of bool stores 0 or 1.

jensmaurer commented 10 months ago

But a signed bit-field with width 1 can store the values 0 and -1 only. So, what do we do with the bool 1?

JohelEGP commented 10 months ago

Ah, I see. So if it doesn't fall out from other rules, it would be UB by omission. Maybe you can tag someone who's trying to document or get rid of UB in the standard.