diff options
| author | Aaron Ballman <aaron@aaronballman.com> | 2024-04-22 11:59:54 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-22 11:59:54 -0400 |
| commit | 947cd677083d69412b5a900d8fad59e3062c4875 (patch) | |
| tree | 30dfe0b617772c3be03c08ae75069f21d5c5e1b6 | |
| parent | dc20a0ea1fd04a2ef95eb5c73e9f88357fc5f694 (diff) | |
| download | llvm-947cd677083d69412b5a900d8fad59e3062c4875.zip llvm-947cd677083d69412b5a900d8fad59e3062c4875.tar.gz llvm-947cd677083d69412b5a900d8fad59e3062c4875.tar.bz2 | |
[C23] Select the correct promoted type for a bit-field (#89254)
Bit-fields of bit-precise integer type do not promote to int, but
instead promote to the type of the field.
Fixes #87641
| -rw-r--r-- | clang/docs/ReleaseNotes.rst | 3 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/AST/Interp/IntegralAP.h | 5 | ||||
| -rw-r--r-- | clang/test/Sema/bitint-bitfield-promote.c | 54 |
4 files changed, 69 insertions, 1 deletions
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index db5830a..009531b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -179,6 +179,9 @@ C23 Feature Support - Clang now supports `N3018 The constexpr specifier for object definitions` <https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm>`_. +- Properly promote bit-fields of bit-precise integer types to the field's type + rather than to ``int``. #GH87641 + Non-comprehensive list of changes in this release ------------------------------------------------- diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index b974fc28..b36fb55 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -7241,6 +7241,14 @@ QualType ASTContext::isPromotableBitField(Expr *E) const { // We perform that promotion here to match GCC and C++. // FIXME: C does not permit promotion of an enum bit-field whose rank is // greater than that of 'int'. We perform that promotion to match GCC. + // + // C23 6.3.1.1p2: + // The value from a bit-field of a bit-precise integer type is converted to + // the corresponding bit-precise integer type. (The rest is the same as in + // C11.) + if (QualType QT = Field->getType(); QT->isBitIntType()) + return QT; + if (BitWidth < IntSize) return IntTy; diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h index bab9774..fb7ee14 100644 --- a/clang/lib/AST/Interp/IntegralAP.h +++ b/clang/lib/AST/Interp/IntegralAP.h @@ -154,7 +154,10 @@ public: } IntegralAP truncate(unsigned BitWidth) const { - return IntegralAP(V.trunc(BitWidth)); + if constexpr (Signed) + return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth())); + else + return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth())); } IntegralAP<false> toUnsigned() const { diff --git a/clang/test/Sema/bitint-bitfield-promote.c b/clang/test/Sema/bitint-bitfield-promote.c new file mode 100644 index 0000000..e82e949 --- /dev/null +++ b/clang/test/Sema/bitint-bitfield-promote.c @@ -0,0 +1,54 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s + +// GH87641 noticed that integer promotion of a bit-field of bit-precise integer +// type was promoting to int rather than the type of the bit-field. +struct S { + unsigned _BitInt(7) x : 2; + unsigned _BitInt(2) y : 2; + unsigned _BitInt(72) z : 28; + _BitInt(31) a : 12; + _BitInt(33) b : 33; +}; + +// We don't have to worry about promotion cases where the bit-precise type is +// smaller than the width of the bit-field; that can't happen. +struct T { + unsigned _BitInt(28) oh_no : 72; // expected-error {{width of bit-field 'oh_no' (72 bits) exceeds the width of its type (28 bits)}} +}; + +static_assert( + _Generic(+(struct S){}.x, + int : 0, + unsigned _BitInt(7) : 1, + unsigned _BitInt(2) : 2 + ) == 1); + +static_assert( + _Generic(+(struct S){}.y, + int : 0, + unsigned _BitInt(7) : 1, + unsigned _BitInt(2) : 2 + ) == 2); + +static_assert( + _Generic(+(struct S){}.z, + int : 0, + unsigned _BitInt(72) : 1, + unsigned _BitInt(28) : 2 + ) == 1); + +static_assert( + _Generic(+(struct S){}.a, + int : 0, + _BitInt(31) : 1, + _BitInt(12) : 2, + unsigned _BitInt(31) : 3 + ) == 1); + +static_assert( + _Generic(+(struct S){}.b, + int : 0, + long long : 1, + _BitInt(33) : 2, + unsigned _BitInt(33) : 3 + ) == 2); |
