Skip to content

Commit ca1f1c9

Browse files
authored
[BitInt] Expose a _BitInt literal suffix in C++ (llvm#86586)
This exposes _BitInt literal suffixes __wb and u__wb as an extension in C++. There is a new Extension warning, and the tests are essentially the same as the existing _BitInt literal tests for C but with a few additional cases. Fixes llvm#85223
1 parent 9a35951 commit ca1f1c9

File tree

11 files changed

+273
-16
lines changed

11 files changed

+273
-16
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ sections with improvements to Clang's support for those languages.
8888

8989
C++ Language Changes
9090
--------------------
91+
- Implemented ``_BitInt`` literal suffixes ``__wb`` or ``__WB`` as a Clang extension with ``unsigned`` modifiers also allowed. (#GH85223).
9192

9293
C++20 Feature Support
9394
^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticCommonKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ def err_cxx23_size_t_suffix: Error<
234234
def err_size_t_literal_too_large: Error<
235235
"%select{signed |}0'size_t' literal is out of range of possible "
236236
"%select{signed |}0'size_t' values">;
237+
def ext_cxx_bitint_suffix : Extension<
238+
"'_BitInt' suffix for literals is a Clang extension">,
239+
InGroup<BitIntExtension>;
237240
def ext_c23_bitint_suffix : ExtWarn<
238241
"'_BitInt' suffix for literals is a C23 extension">,
239242
InGroup<C23>;

clang/include/clang/Basic/DiagnosticGroups.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,5 +1520,8 @@ def UnsafeBufferUsage : DiagGroup<"unsafe-buffer-usage", [UnsafeBufferUsageInCon
15201520
// Warnings and notes InstallAPI verification.
15211521
def InstallAPIViolation : DiagGroup<"installapi-violation">;
15221522

1523+
// Warnings related to _BitInt extension
1524+
def BitIntExtension : DiagGroup<"bit-int-extension">;
1525+
15231526
// Warnings about misuse of ExtractAPI options.
15241527
def ExtractAPIMisuse : DiagGroup<"extractapi-misuse">;

clang/include/clang/Basic/DiagnosticParseKinds.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1654,7 +1654,7 @@ def warn_ext_int_deprecated : Warning<
16541654
"'_ExtInt' is deprecated; use '_BitInt' instead">, InGroup<DeprecatedType>;
16551655
def ext_bit_int : Extension<
16561656
"'_BitInt' in %select{C17 and earlier|C++}0 is a Clang extension">,
1657-
InGroup<DiagGroup<"bit-int-extension">>;
1657+
InGroup<BitIntExtension>;
16581658
} // end of Parse Issue category.
16591659

16601660
let CategoryName = "Modules Issue" in {

clang/include/clang/Lex/LiteralSupport.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class NumericLiteralParser {
8080
bool isFloat128 : 1; // 1.0q
8181
bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr
8282
bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk
83-
bool isBitInt : 1; // 1wb, 1uwb (C23)
83+
bool isBitInt : 1; // 1wb, 1uwb (C23) or 1__wb, 1__uwb (Clang extension in C++
84+
// mode)
8485
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.
8586

8687

clang/lib/Lex/LiteralSupport.cpp

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -974,6 +974,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
974974
bool isFixedPointConstant = isFixedPointLiteral();
975975
bool isFPConstant = isFloatingLiteral();
976976
bool HasSize = false;
977+
bool DoubleUnderscore = false;
977978

978979
// Loop over all of the characters of the suffix. If we see something bad,
979980
// we break out of the loop.
@@ -1117,6 +1118,31 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
11171118
if (isImaginary) break; // Cannot be repeated.
11181119
isImaginary = true;
11191120
continue; // Success.
1121+
case '_':
1122+
if (isFPConstant)
1123+
break; // Invalid for floats
1124+
if (HasSize)
1125+
break;
1126+
if (DoubleUnderscore)
1127+
break; // Cannot be repeated.
1128+
if (LangOpts.CPlusPlus && s + 2 < ThisTokEnd &&
1129+
s[1] == '_') { // s + 2 < ThisTokEnd to ensure some character exists
1130+
// after __
1131+
DoubleUnderscore = true;
1132+
s += 2; // Skip both '_'
1133+
if (s + 1 < ThisTokEnd &&
1134+
(*s == 'u' || *s == 'U')) { // Ensure some character after 'u'/'U'
1135+
isUnsigned = true;
1136+
++s;
1137+
}
1138+
if (s + 1 < ThisTokEnd &&
1139+
((*s == 'w' && *(++s) == 'b') || (*s == 'W' && *(++s) == 'B'))) {
1140+
isBitInt = true;
1141+
HasSize = true;
1142+
continue;
1143+
}
1144+
}
1145+
break;
11201146
case 'w':
11211147
case 'W':
11221148
if (isFPConstant)
@@ -1127,9 +1153,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling,
11271153
// wb and WB are allowed, but a mixture of cases like Wb or wB is not. We
11281154
// explicitly do not support the suffix in C++ as an extension because a
11291155
// library-based UDL that resolves to a library type may be more
1130-
// appropriate there.
1131-
if (!LangOpts.CPlusPlus && ((s[0] == 'w' && s[1] == 'b') ||
1132-
(s[0] == 'W' && s[1] == 'B'))) {
1156+
// appropriate there. The same rules apply for __wb/__WB.
1157+
if ((!LangOpts.CPlusPlus || DoubleUnderscore) && s + 1 < ThisTokEnd &&
1158+
((s[0] == 'w' && s[1] == 'b') || (s[0] == 'W' && s[1] == 'B'))) {
11331159
isBitInt = true;
11341160
HasSize = true;
11351161
++s; // Skip both characters (2nd char skipped on continue).
@@ -1241,7 +1267,9 @@ bool NumericLiteralParser::isValidUDSuffix(const LangOptions &LangOpts,
12411267
return false;
12421268

12431269
// By C++11 [lex.ext]p10, ud-suffixes starting with an '_' are always valid.
1244-
if (Suffix[0] == '_')
1270+
// Suffixes starting with '__' (double underscore) are for use by
1271+
// the implementation.
1272+
if (Suffix.starts_with("_") && !Suffix.starts_with("__"))
12451273
return true;
12461274

12471275
// In C++11, there are no library suffixes.

clang/lib/Lex/PPExpressions.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -333,11 +333,11 @@ static bool EvaluateValue(PPValue &Result, Token &PeekTok, DefinedTracker &DT,
333333
: diag::ext_cxx23_size_t_suffix
334334
: diag::err_cxx23_size_t_suffix);
335335

336-
// 'wb/uwb' literals are a C23 feature. We explicitly do not support the
337-
// suffix in C++ as an extension because a library-based UDL that resolves
338-
// to a library type may be more appropriate there.
336+
// 'wb/uwb' literals are a C23 feature.
337+
// '__wb/__uwb' are a C++ extension.
339338
if (Literal.isBitInt)
340-
PP.Diag(PeekTok, PP.getLangOpts().C23
339+
PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
340+
: PP.getLangOpts().C23
341341
? diag::warn_c23_compat_bitint_suffix
342342
: diag::ext_c23_bitint_suffix);
343343

clang/lib/Sema/SemaExpr.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4137,11 +4137,13 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
41374137
// 'wb/uwb' literals are a C23 feature. We support _BitInt as a type in C++,
41384138
// but we do not currently support the suffix in C++ mode because it's not
41394139
// entirely clear whether WG21 will prefer this suffix to return a library
4140-
// type such as std::bit_int instead of returning a _BitInt.
4141-
if (Literal.isBitInt && !getLangOpts().CPlusPlus)
4142-
PP.Diag(Tok.getLocation(), getLangOpts().C23
4143-
? diag::warn_c23_compat_bitint_suffix
4144-
: diag::ext_c23_bitint_suffix);
4140+
// type such as std::bit_int instead of returning a _BitInt. '__wb/__uwb'
4141+
// literals are a C++ extension.
4142+
if (Literal.isBitInt)
4143+
PP.Diag(Tok.getLocation(),
4144+
getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
4145+
: getLangOpts().C23 ? diag::warn_c23_compat_bitint_suffix
4146+
: diag::ext_c23_bitint_suffix);
41454147

41464148
// Get the value in the widest-possible width. What is "widest" depends on
41474149
// whether the literal is a bit-precise integer or not. For a bit-precise

clang/test/AST/bitint-suffix.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -ast-dump -Wno-unused %s | FileCheck --strict-whitespace %s
2+
3+
// CHECK: FunctionDecl 0x{{[^ ]*}} <{{.*}}:[[@LINE+1]]:1, line:{{[0-9]*}}:1> line:[[@LINE+1]]:6 func 'void ()'
4+
void func() {
5+
// Ensure that we calculate the correct type from the literal suffix.
6+
7+
// Note: 0__wb should create an _BitInt(2) because a signed bit-precise
8+
// integer requires one bit for the sign and one bit for the value,
9+
// at a minimum.
10+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:29> col:29 zero_wb 'typeof (0wb)':'_BitInt(2)'
11+
typedef __typeof__(0__wb) zero_wb;
12+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:30> col:30 neg_zero_wb 'typeof (-0wb)':'_BitInt(2)'
13+
typedef __typeof__(-0__wb) neg_zero_wb;
14+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:29> col:29 one_wb 'typeof (1wb)':'_BitInt(2)'
15+
typedef __typeof__(1__wb) one_wb;
16+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:30> col:30 neg_one_wb 'typeof (-1wb)':'_BitInt(2)'
17+
typedef __typeof__(-1__wb) neg_one_wb;
18+
19+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:30> col:30 zero_uwb 'typeof (0uwb)':'unsigned _BitInt(1)'
20+
typedef __typeof__(0__uwb) zero_uwb;
21+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:31> col:31 neg_zero_uwb 'typeof (-0uwb)':'unsigned _BitInt(1)'
22+
typedef __typeof__(-0__uwb) neg_zero_uwb;
23+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:30> col:30 one_uwb 'typeof (1uwb)':'unsigned _BitInt(1)'
24+
typedef __typeof__(1__uwb) one_uwb;
25+
26+
// Try a value that is too large to fit in [u]intmax_t.
27+
28+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:49> col:49 huge_uwb 'typeof (18446744073709551616uwb)':'unsigned _BitInt(65)'
29+
typedef __typeof__(18446744073709551616__uwb) huge_uwb;
30+
// CHECK: TypedefDecl 0x{{[^ ]*}} <col:3, col:48> col:48 huge_wb 'typeof (18446744073709551616wb)':'_BitInt(66)'
31+
typedef __typeof__(18446744073709551616__wb) huge_wb;
32+
}
Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,23 @@
11
// RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=ext -Wno-unused %s
22
// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=compat -Wpre-c2x-compat -Wno-unused %s
3-
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -Wno-unused -x c++ %s
3+
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -Wbit-int-extension -Wno-unused -x c++ %s
44

55
#if 18446744073709551615uwb // ext-warning {{'_BitInt' suffix for literals is a C23 extension}} \
66
compat-warning {{'_BitInt' suffix for literals is incompatible with C standards before C23}} \
77
cpp-error {{invalid suffix 'uwb' on integer constant}}
88
#endif
99

10+
#if 18446744073709551615__uwb // ext-error {{invalid suffix '__uwb' on integer constant}} \
11+
compat-error {{invalid suffix '__uwb' on integer constant}} \
12+
cpp-warning {{'_BitInt' suffix for literals is a Clang extension}}
13+
#endif
14+
1015
void func(void) {
1116
18446744073709551615wb; // ext-warning {{'_BitInt' suffix for literals is a C23 extension}} \
1217
compat-warning {{'_BitInt' suffix for literals is incompatible with C standards before C23}} \
1318
cpp-error {{invalid suffix 'wb' on integer constant}}
19+
20+
18446744073709551615__wb; // ext-error {{invalid suffix '__wb' on integer constant}} \
21+
compat-error {{invalid suffix '__wb' on integer constant}} \
22+
cpp-warning {{'_BitInt' suffix for literals is a Clang extension}}
1423
}

0 commit comments

Comments
 (0)