Skip to content

[Clang][C] What is the type of a bit-field? (For generic selection / constexpr initialization) #101299

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

Open
MitalAshok opened this issue Jul 31, 2024 · 3 comments
Assignees
Labels
accepts-invalid c23 clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party

Comments

@MitalAshok
Copy link
Contributor

MitalAshok commented Jul 31, 2024

Seen at #78112 (review), this compiles surprisingly in C23:

struct C {
  signed long long i : 8;
};
constexpr struct C c = { 255 };

My reading of N3096:

§6.7.1p6:

If an object or subobject declared with storage-class specifier constexpr has [...] integer [..] type, any explicit initializer value for it shall be [.,.] an integer constant expression

§6.6p4:

Each constant expression shall evaluate to a constant that is in the range of representable values for its type.

§6.7.2.1p12:

A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits.

... So the member i has a signed type with 8 bits, which 255 is not representable in, and Clang should reject the initializer.

Two other places I can think of where the type of something is observed is typeof (which explicitly bans bit-fields), and _Generic. Clang currently allows:

struct C {
  signed long long i : 8;
} c;
static_assert(_Generic(c.i, long long: 1));

which according to §6.7.2.1p12, it shouldn't? The bit-field type with width 8 should not be compatible with a 64 bit wide type. Unless the lvalue conversion done converts the bit-field type to long long, but that doesn't seem to be allowed by §6.3.2.1

CC @AaronBallman @Fznamznon

See also:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88731
DR#315
DR#481

@github-actions github-actions bot added the clang Clang issues not falling into any other category label Jul 31, 2024
@AaronBallman
Copy link
Collaborator

AaronBallman commented Jul 31, 2024

... So the member i has a signed type with 8 bits, which 255 is not representable in, and Clang should reject the initializer.

Correct, this is a Clang bug IMO.

which according to §6.7.2.1p12, it shouldn't? The bit-field type with width 8 should not be compatible with a 64 bit wide type.

That's a bit less clear IMO. GCC took the stance that bit-fields form a unique, unutterable type, and Clang seems to take the stance that they're an implementation-defined type that matches that of the declared type (sans bit width). It might make sense for Clang to follow GCC's lead, but that also runs the risk of breaking people's code. This should probably be filed as a separate issue because constexpr initialization is more clearly a bug and there's far less existing code relying on the current behavior.

@AaronBallman AaronBallman added c23 clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party and removed clang Clang issues not falling into any other category labels Jul 31, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2024

@llvm/issue-subscribers-clang-frontend

Author: Mital Ashok (MitalAshok)

Seen at https://github.com//pull/78112#pullrequestreview-2205422888, this compiles surprisingly in C23:
struct C {
  signed long long i : 8;
};
constexpr struct C c = { 255 };

My reading of N3096:

§6.7.1p6:

> If an object or subobject declared with storage-class specifier constexpr has [...] integer [..] type, any explicit initializer value for it shall be [.,.] an integer constant expression

§6.6p4:

> Each constant expression shall evaluate to a constant that is in the range of representable values for its type.

§6.7.2.1p12:

> A bit-field is interpreted as having a signed or unsigned integer type consisting of the specified number of bits.

... So the member i has a signed type with 8 bits, which 255 is not representable in, and Clang should reject the initializer.

Two other places I can think of where the type of something is observed is typeof (which explicitly bans bit-fields), and _Generic. Clang currently allows:

struct C {
  signed long long i : 8;
} c;
static_assert(_Generic(c.i, long long: 1));

which according to §6.7.2.1p12, it shouldn't? The bit-field type with width 8 should not be compatible with a 64 bit wide type. Unless the lvalue conversion done converts the bit-field type to long long, but that doesn't seem to be allowed by §6.3.2.1

CC @AaronBallman @Fznamznon

See also:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=88731
DR#315
DR#481

@pinskia
Copy link

pinskia commented Jul 31, 2024

related to #42784

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
accepts-invalid c23 clang:frontend Language frontend issues, e.g. anything involving "Sema" confirmed Verified by a second party
Projects
None yet
Development

No branches or pull requests

5 participants