[clang] 947cd67 - [C23] Select the correct promoted type for a bit-field (#89254)

via cfe-commits cfe-commits at lists.llvm.org
Mon Apr 22 08:59:57 PDT 2024


Author: Aaron Ballman
Date: 2024-04-22T11:59:54-04:00
New Revision: 947cd677083d69412b5a900d8fad59e3062c4875

URL: https://github.com/llvm/llvm-project/commit/947cd677083d69412b5a900d8fad59e3062c4875
DIFF: https://github.com/llvm/llvm-project/commit/947cd677083d69412b5a900d8fad59e3062c4875.diff

LOG: [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

Added: 
    clang/test/Sema/bitint-bitfield-promote.c

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/Interp/IntegralAP.h

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index db5830a6371583..009531bae8a9de 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 b974fc28283c77..b36fb5523af5a6 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 bab9774288bfa6..fb7ee14515715a 100644
--- a/clang/lib/AST/Interp/IntegralAP.h
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -154,7 +154,10 @@ template <bool Signed> class IntegralAP final {
   }
 
   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 00000000000000..e82e94975cfd4a
--- /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);


        


More information about the cfe-commits mailing list