Skip to content

CWG3209 [basic.compound] Pointer-interconvertibility with bit-fields #916

Description

@Halalaluyafail3

Full name of submitter (unless configured in github; will be published with the issue): Jay Ghiron

Reference (section label): [basic.compound]/6.3

Issue description:

struct{int x:2;}x;

According to this, x and x.x are pointer-interconvertible. That is surely not intended.

Activity

  1. jensmaurer commented on Jun 7, 2026

    @jensmaurer
    Member

    You can't even form a pointer to the bit-field, so why does this matter?

  2. Halalaluyafail3 commented on Jun 7, 2026

    @Halalaluyafail3
    Author

    You can't even form a pointer to the bit-field, so why does this matter?

    [expr.static.cast]/12 combined with this would mean that reinterpret_cast<int*>(&x) should be a pointer to the bit-field, it is pointer-interconvertible with the bit-field member and the type of the bit-field is similar to int.

  3. jensmaurer commented on Jun 7, 2026

    @jensmaurer
    Member

    Maybe the right fix is to amend [basic.compound] so that "pointer values" can't point to bit-field objects. This would moot the question, i think.

  4. safocl commented on Jun 7, 2026

    @safocl

    In my opinion, the rule from [class.bit#3] refutes the receipt of pointers or references to bit-fields already in the existing text of the C++ standard.

  5. safocl commented on Jun 7, 2026

    @safocl

    the type of the bit-field is similar to int.

    Doesn't [class.bit#1] refute this perception of the provisions of the standard?

    the bit-field semantic property is not part of the type of the class member.

  6. safocl commented on Jun 7, 2026

    @safocl

    I also believe that the standard's [class.mem#general-31] provision makes it impossible to treat a standard-layout class object and its first member (if it is a bit-field) as pointer-interconvertible
    (since the [basic.compound]/6.3 rule relies on the provisions of [class.mem])

  7. safocl commented on Jun 7, 2026

    @safocl

    I think we can add an additional note for [basic.compound]/6:

    [Note 7: A standard-layout class object and its first non-static data member, which is a bit field, are not pointer-interconvertible because they are not guaranteed to have the same address ([class.mem.general]). — end note]

  8. leni536 commented on Jun 7, 2026

    @leni536

    I also believe that the standard's [class.mem#general-31] provision makes it impossible to treat a standard-layout class object and its first member (if it is a bit-field) as pointer-interconvertible (since the [basic.compound]/6.3 rule relies on the provisions of [class.mem])

    I don't follow how you arrived at this conclusion. "pointer-interconvertible", as currently defined, doesn't depend on the address of the corresponding objects to be the same.

    As for reinterpret_cast<int*>(&x) the following applies:

    1. https://eel.is/c++draft/expr.reinterpret.cast#7
    2. https://eel.is/c++draft/expr.static.cast#12.sentence-3

    I don't where would https://eel.is/c++draft/class.mem#general-31.sentence-1 enter, as neither the reinterpret_cast nor pointer-interconvertible require the addresses to be the same, as currently defined.

    As for https://eel.is/c++draft/class.bit#3:

    The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields.

    This feels editorially weird, as ,so ... reads like a conclusion, not as normative wording. In my opinion that should be a note.

    I think the issue is valid and bit-fields should be explicitly excluded from pointer-interconvertible.

  9. safocl commented on Jun 7, 2026

    @safocl

    I don't follow how you arrived at this conclusion. "pointer-interconvertible", as currently defined, doesn't depend on the address of the corresponding objects to be the same.

    It's very simple – following the provisions of [basic.compound#6]:

    If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast ([expr.reinterpret.cast]).

    Perhaps you only paid attention to the situations in which objects are pointer-interconvertible, but did not pay attention to the definition of what effect this gives (as well as, in essence, the definition).

    I don't where would https://eel.is/c++draft/class.mem#general-31.sentence-1 enter, as neither the reinterpret_cast nor pointer-interconvertible require the addresses to be the same, as currently defined.

    As I stated above, I believe this clearly follows from the definition of "pointer-interconvertible" objects.

    I think the issue is valid and bit-fields should be explicitly excluded from pointer-interconvertible.

    I believe it is already explicitly excluded, since the [class.mem] clause explicitly states that in certain cases objects have the same address, which is accordingly required by the definition of pointer-interconvertible itself (which cannot be the case with bit-fields).

  10. safocl commented on Jun 7, 2026

    @safocl

    It seems to me that in this case, normative unity in the standard is ensured.

  11. languagelawyer commented on Jun 7, 2026

    @languagelawyer

    If two objects are pointer-interconvertible, then they have the same address, and it is possible to obtain a pointer to one from a pointer to the other via a reinterpret_cast ([expr.reinterpret.cast]).

    This sentence always felt like a Note which is not formatted as one by accident

  12. safocl commented on Jun 7, 2026

    @safocl

    This sentence always felt like a Note which is not formatted as one by accident

    But it's essentially a definition for "pointer-interconvertible-objects"

  13. languagelawyer commented on Jun 7, 2026

    @languagelawyer

    This sentence always felt like a Note which is not formatted as one by accident

    But it's essentially a definition for "pointer-interconvertible-objects"

    No, it is before this sentence.

  14. Halalaluyafail3 commented on Jun 7, 2026

    @Halalaluyafail3
    Author

    Another issue with this wording is unnamed bit-fields:

    struct{int:1,y;}y;

    y and y.y should be pointer-interconvertible currently. Since the unnamed bit-field is not a member, the non-bit-field is the first non-static data member. Perhaps unnamed bit-fields with widths of zero should be exempt from this, since implementations do not change the class layout for initial unnamed bit-fields with widths of zero.

  15. frederick-vs-ja commented on Jun 8, 2026

    @frederick-vs-ja

    Maybe the fix can be...

    1. Two non-bit-field objects a and b are pointer-interconvertible if
      [...]
      (6.3) - one is a standard-layout class object and the other is the first non-static data member of that object, where the member is not declared after any unnamed bit-field with positive width, or any base class subobject of that object ([class.mem]) or

    This approach will make a bit-field object not even pointer-interconvertible with itself. But as there's no pointer to bit-field, the side effect might also be desired.

  16. safocl commented on Jun 8, 2026

    @safocl

    but in this case the criterion for "same address" is again not satisfied, since unnamed bit-fields contribute padding-bits.

  17. jensmaurer commented on Jun 29, 2026

    @jensmaurer
    Member
  18. changed the title [-][basic.compound] Pointer-interconvertibility with bit-fields[/-] [+]CWG3209 [basic.compound] Pointer-interconvertibility with bit-fields[/+] on Jun 29, 2026
  19. Halalaluyafail3 commented on Jun 29, 2026

    @Halalaluyafail3
    Author

    CWG3209

    For the change in [expr.unary.op]/3, [expr.unary.op]/5 already says:

    The operand of & shall not be a bit-field.

    It seems redundant to mention this twice.

  20. jensmaurer commented on Jun 30, 2026

    @jensmaurer
    Member

    Agreed; updated CWG3209.

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