Skip to content

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

Description

@randomnetcat

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.

Activity

  1. jensmaurer commented on Jul 16, 2023

    @jensmaurer
    Member

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

  2. randomnetcat commented on Jul 16, 2023

    @randomnetcat
    Author

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

  3. JohelEGP commented on Jul 16, 2023

    @JohelEGP

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

  4. randomnetcat commented on Jul 16, 2023

    @randomnetcat
    Author

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

  5. JohelEGP commented on Jul 16, 2023

    @JohelEGP

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

  6. jensmaurer commented on Jul 16, 2023

    @jensmaurer
    Member

    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.

  7. JohelEGP commented on Jul 16, 2023

    @JohelEGP

    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.

  8. jensmaurer commented on Jul 16, 2023

    @jensmaurer
    Member

    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).

  9. jensmaurer commented on Jul 16, 2023

    @jensmaurer
    Member

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

  10. frederick-vs-ja commented on Jul 25, 2023

    @frederick-vs-ja

    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.

  11. jensmaurer commented on Oct 22, 2023

    @jensmaurer
    Member

    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.

  12. JohelEGP commented on Oct 22, 2023

    @JohelEGP

    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.

  13. jensmaurer commented on Oct 22, 2023

    @jensmaurer
    Member

    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?

  14. JohelEGP commented on Oct 22, 2023

    @JohelEGP

    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.

  15. Halalaluyafail3 commented on Jun 24, 2026

    @Halalaluyafail3

    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.

    C2Y supports _BitInt(1) now because N3747 was accepted.

  16. eisenwave commented on Jun 25, 2026

    @eisenwave
    Member

    I think this deserves a CWG issue now.

    We now say "The width of each standard signed integer type shall not be less than the values specified in Table 14." in [basic.fundamental], so this no longer applies to extended integer types.

    It would be possible for the implementation to provide an _ExtInt(1) extended signed integer type with a single bit, so it's unclear what static_cast<_ExtInt(1)>(true) does. P3666 would concretely introduce a _BitInt(1) type as well, and that's past EWG, but the defect is pre-existing.

    The C standard is also not super helpful here https://cstd.eisie.net/c2y.html#6.3.2.3p3

    Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

    true -> _BitInt(1) either gives an implementation-defined result or raises a signal, and C compilers don't support _BitInt(1) yet so we don't know yet how they'll deal with this case.

    In my opinion, this should be ill-formed in C++, which would keep the door open to future standardization that aligns with different behavior in C2y.

  17. Halalaluyafail3 commented on Jun 25, 2026

    @Halalaluyafail3

    The C standard is also not super helpful here https://cstd.eisie.net/c2y.html#6.3.2.3p3

    Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

    true -> _BitInt(1) either gives an implementation-defined result or raises a signal, and C compilers don't support _BitInt(1) yet so we don't know yet how they'll deal with this case.

    GCC documents what will happen here: https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html

    In my opinion, this should be ill-formed in C++, which would keep the door open to future standardization that aligns with different behavior in C2y.

    bool to _BitInt(1) conversions would be ill-formed? That seems very arbitrary when any other integer type can be converted to _BitInt(1). Also I have created C Issue 1063 which discusses this so perhaps the wording can be changed.

  18. changed the title [-][conv.integral] Conversion of bool to width-1 signed integer type[/-] [+]CWG3225 [conv.integral] Conversion of bool to width-1 signed integer type[/+] on Aug 30, 2026
  19. jensmaurer commented on Aug 30, 2026

    @jensmaurer
    Member
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