[clang] [C23] Select the correct promoted type for a bit-field (PR #89254)
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 19 06:26:42 PDT 2024
https://github.com/AaronBallman updated https://github.com/llvm/llvm-project/pull/89254
>From f0a1f1e48a1bb6e91b819a8ee1502773063ae8a2 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Thu, 18 Apr 2024 11:56:20 -0400
Subject: [PATCH 1/3] [C23] Select the correct promoted type for a bit-field
Bit-fields of bit-precise integer type do not promote to int, but
instead promote to the type of the field.
Fixes #87641
---
clang/docs/ReleaseNotes.rst | 3 ++
clang/lib/AST/ASTContext.cpp | 8 +++++
clang/test/Sema/bitint-bitfield-promote.c | 38 +++++++++++++++++++++++
3 files changed, 49 insertions(+)
create mode 100644 clang/test/Sema/bitint-bitfield-promote.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3fe15934323c53..1b5d69059230e6 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/test/Sema/bitint-bitfield-promote.c b/clang/test/Sema/bitint-bitfield-promote.c
new file mode 100644
index 00000000000000..df09c40efca390
--- /dev/null
+++ b/clang/test/Sema/bitint-bitfield-promote.c
@@ -0,0 +1,38 @@
+// 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;
+};
+
+// 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);
+
+
>From 41bad7b06e1442fc761176308b87ad27585a1433 Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 19 Apr 2024 08:36:40 -0400
Subject: [PATCH 2/3] Fix the experimental constexpr interpreter
---
clang/lib/AST/Interp/IntegralAP.h | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
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 {
>From b88c90e1560b26f1ef522d7c467ebf04d4dd0a5d Mon Sep 17 00:00:00 2001
From: Aaron Ballman <aaron at aaronballman.com>
Date: Fri, 19 Apr 2024 09:26:12 -0400
Subject: [PATCH 3/3] Add some additional test coverage for boundaries
---
clang/test/Sema/bitint-bitfield-promote.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/clang/test/Sema/bitint-bitfield-promote.c b/clang/test/Sema/bitint-bitfield-promote.c
index df09c40efca390..e82e94975cfd4a 100644
--- a/clang/test/Sema/bitint-bitfield-promote.c
+++ b/clang/test/Sema/bitint-bitfield-promote.c
@@ -6,6 +6,8 @@ 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
@@ -35,4 +37,18 @@ static_assert(
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