https://github.com/mattst88 created
https://github.com/llvm/llvm-project/pull/217815
GCC accepts the `wb`/`uwb` `_BitInt` suffixes before C23 without a warning, and
pedwarns about them under `-Wpedantic` ("ISO C does not support literal 'wb'
suffixes before C23") — in both `-std=c11` and `-std=gnu11`. Clang instead emits
`ext_c23_bitint_suffix`, an `ExtWarn` in the default-on `-Wc23-extensions`
group, so a literal such as `0uwb` is an error under `-Werror`.
That breaks code built in a GNU C mode with `-Werror`. glibc is one: it builds
with `-std=gnu11` (`Makeconfig`), and `stdlib/tst-stdbit-builtins.c` writes
`0uwb` directly.
In a GNU C mode before C23 the suffix is available as an extension, the same way
it is in C++, so this diagnoses it with a new `ext_bitint_suffix_in_gnu_mode`
rather than as a use of a C23 feature. This follows the existing
`ext_vla_cxx_in_gnu_mode`, which downgrades the C++ VLA `ExtWarn` to a silent
`Extension` in GNU mode and reuses the non-GNU variant's summary and diagnostic
group. Both the preprocessor expression evaluator and the Sema literal handler
need the same arm.
Resulting behaviour, which matches the shape GCC has:
| | before | after |
|---|---|---|
| `-std=gnu11` | warns (`-Wc23-extensions`) | silent |
| `-std=gnu11 -pedantic` | warns | warns (`-Wbit-int-extension`) |
| `-std=c11` | warns | warns (unchanged) |
**Tradeoff worth calling out for review:** a GNU C mode now reports the suffix
under `-Wbit-int-extension` instead of `-Wc23-extensions`, so `-std=gnu11
-Wc23-extensions` no longer flags it. Strict ISO modes are untouched. I think
that's the right split — it's what the VLA precedent does — but it is a
deliberate behaviour change and I'd rather it be discussed than discovered.
`clang/test/Lexer/bitint-constants-compat.c` gains two RUN lines covering a GNU
mode with and without `-Wbit-int-extension`. `clang/test/AST/ByteCode/complex.c`
has no `-std`, so it is gnu17 and its two expected warnings go away.
Full `check-clang` passes.
>From 7d86d1a67bfdfbb46775d201bf94be39f25e0cab Mon Sep 17 00:00:00 2001
From: Matt Turner <[email protected]>
Date: Fri, 10 Jul 2026 03:14:47 -0400
Subject: [PATCH] [clang] Diagnose the _BitInt suffix as an extension in GNU C
modes
GCC accepts the wb/uwb _BitInt suffixes before C23 without a warning and
pedwarns about them under -Wpedantic ("ISO C does not support literal 'wb'
suffixes before C23"), in both -std=c11 and -std=gnu11. Clang instead emitted
ext_c23_bitint_suffix, which is an ExtWarn in the default-on -Wc23-extensions
group, so a literal such as 0uwb was an error under -Werror. That breaks code
built in a GNU C mode with -Werror, glibc's stdlib/tst-stdbit-builtins.c for
one: glibc builds with -std=gnu11 and the test writes 0uwb directly.
In a GNU C mode before C23 the suffix is available as an extension, the same
way it is in C++, so diagnose it with a new ext_bitint_suffix_in_gnu_mode
rather than as a use of a C23 feature. This follows ext_vla_cxx_in_gnu_mode,
which downgrades the C++ VLA ExtWarn to a silent Extension the same way and
shares the non-GNU variant's summary and diagnostic group. Both the
preprocessor expression evaluator and the Sema literal handler need the same
arm.
The tradeoff is deliberate: a GNU C mode now reports the suffix under
-Wbit-int-extension instead of -Wc23-extensions, so -std=gnu11
-Wc23-extensions no longer flags it. Strict ISO modes such as -std=c11 are
untouched and still warn by default, and -std=gnu11 -pedantic still warns,
which is the shape GCC has.
Assisted-by: Claude Code
---
clang/docs/ReleaseNotes.md | 7 +++++++
clang/include/clang/Basic/DiagnosticCommonKinds.td | 2 ++
clang/lib/Lex/PPExpressions.cpp | 12 +++++++-----
clang/lib/Sema/SemaExpr.cpp | 1 +
clang/test/AST/ByteCode/complex.c | 4 +++-
clang/test/Lexer/bitint-constants-compat.c | 11 +++++++++++
6 files changed, 31 insertions(+), 6 deletions(-)
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 8c9467ca7b742..28caa1937acff 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -238,6 +238,13 @@ features cannot lower the translation-unit ABI level;
- More consistent rendering of Unicode characters in diagnostic messages.
+- The `wb` and `uwb` `_BitInt` literal suffixes are now diagnosed in GNU C
modes
+ before C23 as a Clang extension, under `-Wbit-int-extension` (so silent
unless
+ `-pedantic` or that flag is given), rather than under the default-on
+ `-Wc23-extensions`. This matches GCC, which accepts the suffixes in
`-std=gnu11`
+ and only pedwarns about them. Strict ISO modes such as `-std=c11` still warn
by
+ default.
+
- Fixed bug in `-Wdocumentation` so that it correctly handles explicit
function template instantiations (#64087).
diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td
b/clang/include/clang/Basic/DiagnosticCommonKinds.td
index 192fdf9299eb4..10343e2c340a0 100644
--- a/clang/include/clang/Basic/DiagnosticCommonKinds.td
+++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td
@@ -240,6 +240,8 @@ def ext_cxx_bitint_suffix : Extension<
def ext_c23_bitint_suffix : ExtWarn<
"'_BitInt' suffix for literals is a C23 extension">,
InGroup<C23>;
+def ext_bitint_suffix_in_gnu_mode : Extension<ext_cxx_bitint_suffix.Summary>,
+ InGroup<BitIntExtension>;
def warn_c23_compat_bitint_suffix : Warning<
"'_BitInt' suffix for literals is incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
diff --git a/clang/lib/Lex/PPExpressions.cpp b/clang/lib/Lex/PPExpressions.cpp
index 1040b83e8745d..4d47c1b6e9707 100644
--- a/clang/lib/Lex/PPExpressions.cpp
+++ b/clang/lib/Lex/PPExpressions.cpp
@@ -335,13 +335,15 @@ static bool EvaluateValue(PPValue &Result, Token
&PeekTok, DefinedTracker &DT,
: diag::ext_cxx23_size_t_suffix
: diag::err_cxx23_size_t_suffix);
- // 'wb/uwb' literals are a C23 feature.
+ // 'wb/uwb' literals are a C23 feature, and an extension before C23 in a
+ // GNU C mode, the way they are in C++.
// '__wb/__uwb' are a C++ extension.
if (Literal.isBitInt)
- PP.Diag(PeekTok, PP.getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
- : PP.getLangOpts().C23
- ? diag::warn_c23_compat_bitint_suffix
- : diag::ext_c23_bitint_suffix);
+ PP.Diag(PeekTok,
+ PP.getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
+ : PP.getLangOpts().C23 ? diag::warn_c23_compat_bitint_suffix
+ : PP.getLangOpts().GNUMode ? diag::ext_bitint_suffix_in_gnu_mode
+ : diag::ext_c23_bitint_suffix);
// Parse the integer literal into Result.
if (Literal.GetIntegerValue(Result.Val)) {
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index da76bbf3c35f0..a7fa009fd744c 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -4073,6 +4073,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok,
Scope *UDLScope) {
PP.Diag(Tok.getLocation(),
getLangOpts().CPlusPlus ? diag::ext_cxx_bitint_suffix
: getLangOpts().C23 ? diag::warn_c23_compat_bitint_suffix
+ : getLangOpts().GNUMode ? diag::ext_bitint_suffix_in_gnu_mode
: diag::ext_c23_bitint_suffix);
// Get the value in the widest-possible width. What is "widest" depends on
diff --git a/clang/test/AST/ByteCode/complex.c
b/clang/test/AST/ByteCode/complex.c
index 12c51f95ff7c6..c30d1d3f1f93f 100644
--- a/clang/test/AST/ByteCode/complex.c
+++ b/clang/test/AST/ByteCode/complex.c
@@ -29,4 +29,6 @@ void testComplexFloat(_Atomic(_Complex float) *fp) {
*fp = f;
}
-void ZeroNeedsAlloc() { 9999999999999999999wb / 1wbi; } // both-warning
2{{'_BitInt' suffix for literals is a C23 extension}}
+// The RUN lines above have no -std, so this is gnu17, where the suffix is an
+// extension Clang accepts silently.
+void ZeroNeedsAlloc() { 9999999999999999999wb / 1wbi; }
diff --git a/clang/test/Lexer/bitint-constants-compat.c
b/clang/test/Lexer/bitint-constants-compat.c
index d8bff94ef88ca..ef7d1e22a1d0c 100644
--- a/clang/test/Lexer/bitint-constants-compat.c
+++ b/clang/test/Lexer/bitint-constants-compat.c
@@ -1,23 +1,34 @@
// RUN: %clang_cc1 -std=c17 -fsyntax-only -verify=ext -Wno-unused %s
// RUN: %clang_cc1 -std=c2x -fsyntax-only -verify=compat -Wpre-c2x-compat
-Wno-unused %s
// RUN: %clang_cc1 -fsyntax-only -verify=cpp -Wbit-int-extension -Wno-unused
-x c++ %s
+//
+// gnu proves the extension warning fires in a GNU C mode, gnuquiet that it is
+// silent without -Wbit-int-extension.
+// RUN: %clang_cc1 -std=gnu17 -fsyntax-only -verify=gnu -Wbit-int-extension
-Wno-unused %s
+// RUN: %clang_cc1 -std=gnu17 -fsyntax-only -verify=gnuquiet -Wno-unused %s
#if 18446744073709551615uwb // ext-warning {{'_BitInt' suffix for literals is
a C23 extension}} \
compat-warning {{'_BitInt' suffix for literals
is incompatible with C standards before C23}} \
+ gnu-warning {{'_BitInt' suffix for literals is
a Clang extension}} \
cpp-error {{invalid suffix 'uwb' on integer
constant}}
#endif
#if 18446744073709551615__uwb // ext-error {{invalid suffix '__uwb' on integer
constant}} \
compat-error {{invalid suffix '__uwb' on
integer constant}} \
+ gnu-error {{invalid suffix '__uwb' on integer
constant}} \
+ gnuquiet-error {{invalid suffix '__uwb' on
integer constant}} \
cpp-warning {{'_BitInt' suffix for literals is
a Clang extension}}
#endif
void func(void) {
18446744073709551615wb; // ext-warning {{'_BitInt' suffix for literals is a
C23 extension}} \
compat-warning {{'_BitInt' suffix for literals is
incompatible with C standards before C23}} \
+ gnu-warning {{'_BitInt' suffix for literals is a
Clang extension}} \
cpp-error {{invalid suffix 'wb' on integer
constant}}
18446744073709551615__wb; // ext-error {{invalid suffix '__wb' on integer
constant}} \
compat-error {{invalid suffix '__wb' on integer
constant}} \
+ gnu-error {{invalid suffix '__wb' on integer
constant}} \
+ gnuquiet-error {{invalid suffix '__wb' on integer
constant}} \
cpp-warning {{'_BitInt' suffix for literals is a
Clang extension}}
}
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits