Skip to content

Commit 947cd67

Browse files
authored
[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
1 parent dc20a0e commit 947cd67

File tree

4 files changed

+69
-1
lines changed

4 files changed

+69
-1
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ C23 Feature Support
179179
- Clang now supports `N3018 The constexpr specifier for object definitions`
180180
<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3018.htm>`_.
181181

182+
- Properly promote bit-fields of bit-precise integer types to the field's type
183+
rather than to ``int``. #GH87641
184+
182185
Non-comprehensive list of changes in this release
183186
-------------------------------------------------
184187

clang/lib/AST/ASTContext.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7241,6 +7241,14 @@ QualType ASTContext::isPromotableBitField(Expr *E) const {
72417241
// We perform that promotion here to match GCC and C++.
72427242
// FIXME: C does not permit promotion of an enum bit-field whose rank is
72437243
// greater than that of 'int'. We perform that promotion to match GCC.
7244+
//
7245+
// C23 6.3.1.1p2:
7246+
// The value from a bit-field of a bit-precise integer type is converted to
7247+
// the corresponding bit-precise integer type. (The rest is the same as in
7248+
// C11.)
7249+
if (QualType QT = Field->getType(); QT->isBitIntType())
7250+
return QT;
7251+
72447252
if (BitWidth < IntSize)
72457253
return IntTy;
72467254

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ template <bool Signed> class IntegralAP final {
154154
}
155155

156156
IntegralAP truncate(unsigned BitWidth) const {
157-
return IntegralAP(V.trunc(BitWidth));
157+
if constexpr (Signed)
158+
return IntegralAP(V.trunc(BitWidth).sextOrTrunc(this->bitWidth()));
159+
else
160+
return IntegralAP(V.trunc(BitWidth).zextOrTrunc(this->bitWidth()));
158161
}
159162

160163
IntegralAP<false> toUnsigned() const {
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s
2+
3+
// GH87641 noticed that integer promotion of a bit-field of bit-precise integer
4+
// type was promoting to int rather than the type of the bit-field.
5+
struct S {
6+
unsigned _BitInt(7) x : 2;
7+
unsigned _BitInt(2) y : 2;
8+
unsigned _BitInt(72) z : 28;
9+
_BitInt(31) a : 12;
10+
_BitInt(33) b : 33;
11+
};
12+
13+
// We don't have to worry about promotion cases where the bit-precise type is
14+
// smaller than the width of the bit-field; that can't happen.
15+
struct T {
16+
unsigned _BitInt(28) oh_no : 72; // expected-error {{width of bit-field 'oh_no' (72 bits) exceeds the width of its type (28 bits)}}
17+
};
18+
19+
static_assert(
20+
_Generic(+(struct S){}.x,
21+
int : 0,
22+
unsigned _BitInt(7) : 1,
23+
unsigned _BitInt(2) : 2
24+
) == 1);
25+
26+
static_assert(
27+
_Generic(+(struct S){}.y,
28+
int : 0,
29+
unsigned _BitInt(7) : 1,
30+
unsigned _BitInt(2) : 2
31+
) == 2);
32+
33+
static_assert(
34+
_Generic(+(struct S){}.z,
35+
int : 0,
36+
unsigned _BitInt(72) : 1,
37+
unsigned _BitInt(28) : 2
38+
) == 1);
39+
40+
static_assert(
41+
_Generic(+(struct S){}.a,
42+
int : 0,
43+
_BitInt(31) : 1,
44+
_BitInt(12) : 2,
45+
unsigned _BitInt(31) : 3
46+
) == 1);
47+
48+
static_assert(
49+
_Generic(+(struct S){}.b,
50+
int : 0,
51+
long long : 1,
52+
_BitInt(33) : 2,
53+
unsigned _BitInt(33) : 3
54+
) == 2);

0 commit comments

Comments
 (0)