[clang] [clang] Deduce _BitInt(N) template parameter as size_t (PR #195534)
Jan Schultke via cfe-commits
cfe-commits at lists.llvm.org
Fri May 8 02:55:33 PDT 2026
https://github.com/eisenwave updated https://github.com/llvm/llvm-project/pull/195534
>From 9e700211401821a4238f6088729236aab2e52915 Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Sun, 3 May 2026 17:17:24 +0200
Subject: [PATCH 1/7] [clang] Deduce _BitInt(N) template parameter as size_t
Update template argument deduction to deduce the N in _BitInt(N) as size_t rather than int.
This increases consistency with deduction of array sizes, and matches the behavior proposed in P3666.
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 7 ++++--
clang/test/SemaTemplate/deduction.cpp | 27 ++++++++++++++++++++++++
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index a287319cc4f88..3528fa001c201 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2521,11 +2521,14 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (!NTTP)
return TemplateDeductionResult::Success;
- llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false);
+ // P3666 suggested wording for [temp.deduct.type]:
+ // The type of N in the type _BitInt(N) is std::size_t.
+ QualType T = S.Context.getSizeType();
+ llvm::APSInt ArgSize(S.Context.getTypeSize(T), false);
ArgSize = IA->getNumBits();
return DeduceNonTypeTemplateArgument(
- S, TemplateParams, NTTP, ArgSize, S.Context.IntTy, true, Info,
+ S, TemplateParams, NTTP, ArgSize, T, true, Info,
POK != PartialOrderingKind::None, Deduced, HasDeducedAnyParam);
}
diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp
index a209615c36479..e1ac6a9e5d267 100644
--- a/clang/test/SemaTemplate/deduction.cpp
+++ b/clang/test/SemaTemplate/deduction.cpp
@@ -633,6 +633,33 @@ namespace dependent_list_deduction {
}
}
+namespace bitint_deduction {
+#if __cplusplus >= 201703L
+ template<auto X> void f(unsigned _BitInt(X)) {
+ static_assert(is_same<decltype(X), decltype(sizeof(0))>::value, "");
+ static_assert(X == 31, "");
+ }
+ template<auto X> void g(_BitInt(X)) {
+ static_assert(is_same<decltype(X), decltype(sizeof(0))>::value, "");
+ static_assert(X == 32, "");
+ }
+ template<typename T, T V> void i(unsigned _BitInt(V)) {
+ static_assert(is_same<T, decltype(sizeof(0))>::value, "");
+ static_assert(V == 33, "");
+ }
+ template<typename T, T V> void j(_BitInt(V)) {
+ static_assert(is_same<T, decltype(sizeof(0))>::value, "");
+ static_assert(V == 34, "");
+ }
+ void h() {
+ f(static_cast<unsigned _BitInt(31)>(0));
+ g(static_cast<_BitInt(32)>(0));
+ i(static_cast<unsigned _BitInt(33)>(0));
+ j(static_cast<_BitInt(34)>(0));
+ }
+#endif
+}
+
namespace designators {
template<typename T, int N> constexpr int f(T (&&)[N]) { return N; } // expected-note 2{{couldn't infer template argument 'T'}}
static_assert(f({1, 2, [20] = 3}) == 3, ""); // expected-error {{no matching function}} expected-warning 2{{C99}} expected-note {{}}
>From 6519a0e71345d54bb4853d02cbad325c052613c2 Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Sun, 3 May 2026 18:27:47 +0200
Subject: [PATCH 2/7] Move test to ext-int.cpp, add size_t
---
clang/test/SemaCXX/ext-int.cpp | 50 ++++++++++++++++++++++-----
clang/test/SemaTemplate/deduction.cpp | 27 ---------------
2 files changed, 41 insertions(+), 36 deletions(-)
diff --git a/clang/test/SemaCXX/ext-int.cpp b/clang/test/SemaCXX/ext-int.cpp
index 5c566dafed931..cb43ada30d13b 100644
--- a/clang/test/SemaCXX/ext-int.cpp
+++ b/clang/test/SemaCXX/ext-int.cpp
@@ -61,6 +61,38 @@ template<typename T>
void deduced_whole_type(T){}
template<int I>
void deduced_bound(_BitInt(I)){}
+template<int I>
+void deduced_bound_unsigned(unsigned _BitInt(I)){}
+
+template <typename T, typename U>
+struct is_same {
+ static constexpr bool value = false;
+};
+template <typename T>
+struct is_same<T,T> {
+ static constexpr bool value = true;
+};
+
+using size_t = decltype(sizeof(0));
+
+#if __cplusplus >= 201703L
+template<auto X> void deduced_bound_auto(_BitInt(X)) {
+ static_assert(is_same<decltype(X), size_t>::value, "");
+ static_assert(X == 9, "");
+}
+template<auto X> void deduced_bound_auto_unsigned(unsigned _BitInt(X)) {
+ static_assert(is_same<decltype(X), size_t>::value, "");
+ static_assert(X == 11, "");
+}
+template<typename T, T V> void deduced_bound_dependent(_BitInt(V)) {
+ static_assert(is_same<T, size_t>::value, "");
+ static_assert(V == 9, "");
+}
+template<typename T, T V> void deduced_bound_dependent_unsigned(unsigned _BitInt(V)) {
+ static_assert(is_same<T, size_t>::value, "");
+ static_assert(V == 11, "");
+}
+#endif
// Ensure ext-int can be used in template places.
void Templates() {
@@ -69,20 +101,20 @@ void Templates() {
ExtIntTemplParam<b> c;
constexpr _BitInt(9) d = 1;
ExtIntTemplParam<b> e;
+ constexpr unsigned _BitInt(11) f = 1;
deduced_whole_type(b);
+ deduced_whole_type(f);
deduced_bound(b);
+ deduced_bound_unsigned(f);
+#if __cplusplus >= 201703L
+ deduced_bound_auto(d);
+ deduced_bound_auto_unsigned(f);
+ deduced_bound_dependent(d);
+ deduced_bound_dependent_unsigned(f);
+#endif
}
-template <typename T, typename U>
-struct is_same {
- static constexpr bool value = false;
-};
-template <typename T>
-struct is_same<T,T> {
- static constexpr bool value = true;
-};
-
// Reject vector types:
// expected-error at +1{{'_BitInt' vector element width must be a power of 2}}
typedef _BitInt(5) __attribute__((vector_size(16))) VecTy3;
diff --git a/clang/test/SemaTemplate/deduction.cpp b/clang/test/SemaTemplate/deduction.cpp
index e1ac6a9e5d267..a209615c36479 100644
--- a/clang/test/SemaTemplate/deduction.cpp
+++ b/clang/test/SemaTemplate/deduction.cpp
@@ -633,33 +633,6 @@ namespace dependent_list_deduction {
}
}
-namespace bitint_deduction {
-#if __cplusplus >= 201703L
- template<auto X> void f(unsigned _BitInt(X)) {
- static_assert(is_same<decltype(X), decltype(sizeof(0))>::value, "");
- static_assert(X == 31, "");
- }
- template<auto X> void g(_BitInt(X)) {
- static_assert(is_same<decltype(X), decltype(sizeof(0))>::value, "");
- static_assert(X == 32, "");
- }
- template<typename T, T V> void i(unsigned _BitInt(V)) {
- static_assert(is_same<T, decltype(sizeof(0))>::value, "");
- static_assert(V == 33, "");
- }
- template<typename T, T V> void j(_BitInt(V)) {
- static_assert(is_same<T, decltype(sizeof(0))>::value, "");
- static_assert(V == 34, "");
- }
- void h() {
- f(static_cast<unsigned _BitInt(31)>(0));
- g(static_cast<_BitInt(32)>(0));
- i(static_cast<unsigned _BitInt(33)>(0));
- j(static_cast<_BitInt(34)>(0));
- }
-#endif
-}
-
namespace designators {
template<typename T, int N> constexpr int f(T (&&)[N]) { return N; } // expected-note 2{{couldn't infer template argument 'T'}}
static_assert(f({1, 2, [20] = 3}) == 3, ""); // expected-error {{no matching function}} expected-warning 2{{C99}} expected-note {{}}
>From 084dc0cbb1326dde31c3f1c75ba25cdb117047c8 Mon Sep 17 00:00:00 2001
From: Jan Schultke <me at eisenwave.net>
Date: Sun, 3 May 2026 18:29:06 +0200
Subject: [PATCH 3/7] Update clang/lib/Sema/SemaTemplateDeduction.cpp
Co-authored-by: Corentin Jabot <corentinjabot at gmail.com>
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 3528fa001c201..947f742600a64 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2521,8 +2521,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
if (!NTTP)
return TemplateDeductionResult::Success;
- // P3666 suggested wording for [temp.deduct.type]:
- // The type of N in the type _BitInt(N) is std::size_t.
+ // Deduce the size parameter of _BitInt as std::size_t
QualType T = S.Context.getSizeType();
llvm::APSInt ArgSize(S.Context.getTypeSize(T), false);
ArgSize = IA->getNumBits();
>From d750161666fc0b3eeffec5e3bacae512ec352e08 Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Sun, 3 May 2026 20:28:03 +0200
Subject: [PATCH 4/7] Update release notes
---
clang/docs/ReleaseNotes.rst | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 2319ff13f7864..31e04fc169061 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -130,6 +130,11 @@ C++ Specific Potentially Breaking Changes
- ``VarTemplateSpecializationDecl::getTemplateArgsAsWritten()`` method now
returns ``nullptr`` for implicitly instantiated declarations.
+- Template argument deduction now treats the ``N`` in ``_BitInt(N)``
+ as being of type ``std::size_t`` instead of ``int``,
+ matching the deduction of array sizes from ``int(&)[N]``.
+ This is a breaking change for code that depended on the previously deduced type. (#GH195033)
+
ABI Changes in This Version
---------------------------
- Fix AArch64 argument passing for C++ empty classes with large explicitly specified alignment.
>From 9d60be5afcee23be08143ac964fc0630d667255c Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Wed, 6 May 2026 20:51:25 +0200
Subject: [PATCH 5/7] Make ArgSize unsigned
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 947f742600a64..452c0ff88ac27 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2523,7 +2523,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Deduce the size parameter of _BitInt as std::size_t
QualType T = S.Context.getSizeType();
- llvm::APSInt ArgSize(S.Context.getTypeSize(T), false);
+ llvm::APSInt ArgSize(S.Context.getTypeSize(T), true);
ArgSize = IA->getNumBits();
return DeduceNonTypeTemplateArgument(
>From 857c343dcf6455e9180b2f48fdb1b943d42239c2 Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Fri, 8 May 2026 11:54:48 +0200
Subject: [PATCH 6/7] add comment for magic constant
---
clang/lib/Sema/SemaTemplateDeduction.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index 41ef8335fd83d..defdd9ca6968a 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -2513,7 +2513,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
// Deduce the size parameter of _BitInt as std::size_t
QualType T = S.Context.getSizeType();
- llvm::APSInt ArgSize(S.Context.getTypeSize(T), true);
+ llvm::APSInt ArgSize(S.Context.getTypeSize(T), /*IsUnsigned=*/true);
ArgSize = IA->getNumBits();
return DeduceNonTypeTemplateArgument(
>From 5a10b8767d71a44c247aad609662482e644e80fd Mon Sep 17 00:00:00 2001
From: Eisenwave <me at eisenwave.net>
Date: Fri, 8 May 2026 11:55:14 +0200
Subject: [PATCH 7/7] replace is_same trait with __is_same
---
clang/test/SemaCXX/ext-int.cpp | 85 +++++++++++++++-------------------
1 file changed, 38 insertions(+), 47 deletions(-)
diff --git a/clang/test/SemaCXX/ext-int.cpp b/clang/test/SemaCXX/ext-int.cpp
index cb43ada30d13b..281ae3d3c1779 100644
--- a/clang/test/SemaCXX/ext-int.cpp
+++ b/clang/test/SemaCXX/ext-int.cpp
@@ -64,32 +64,23 @@ void deduced_bound(_BitInt(I)){}
template<int I>
void deduced_bound_unsigned(unsigned _BitInt(I)){}
-template <typename T, typename U>
-struct is_same {
- static constexpr bool value = false;
-};
-template <typename T>
-struct is_same<T,T> {
- static constexpr bool value = true;
-};
-
using size_t = decltype(sizeof(0));
#if __cplusplus >= 201703L
template<auto X> void deduced_bound_auto(_BitInt(X)) {
- static_assert(is_same<decltype(X), size_t>::value, "");
+ static_assert(__is_same(decltype(X), size_t), "");
static_assert(X == 9, "");
}
template<auto X> void deduced_bound_auto_unsigned(unsigned _BitInt(X)) {
- static_assert(is_same<decltype(X), size_t>::value, "");
+ static_assert(__is_same(decltype(X), size_t), "");
static_assert(X == 11, "");
}
template<typename T, T V> void deduced_bound_dependent(_BitInt(V)) {
- static_assert(is_same<T, size_t>::value, "");
+ static_assert(__is_same(T, size_t), "");
static_assert(V == 9, "");
}
template<typename T, T V> void deduced_bound_dependent_unsigned(unsigned _BitInt(V)) {
- static_assert(is_same<T, size_t>::value, "");
+ static_assert(__is_same(T, size_t), "");
static_assert(V == 11, "");
}
#endif
@@ -175,16 +166,16 @@ void Ops() {
x4_u - b;
x43_s + b;
x43_u - b;
- static_assert(is_same<decltype(x43_s + x_int), _BitInt(43)>::value, "");
- static_assert(is_same<decltype(x43_u + x_int), unsigned _BitInt(43)>::value, "");
- static_assert(is_same<decltype(x32_s + x_int), int>::value, "");
- static_assert(is_same<decltype(x32_u + x_int), unsigned int>::value, "");
- static_assert(is_same<decltype(x32_s + x_uint), unsigned int>::value, "");
- static_assert(is_same<decltype(x32_u + x_uint), unsigned int>::value, "");
- static_assert(is_same<decltype(x4_s + x_int), int>::value, "");
- static_assert(is_same<decltype(x4_u + x_int), int>::value, "");
- static_assert(is_same<decltype(x4_s + x_uint), unsigned int>::value, "");
- static_assert(is_same<decltype(x4_u + x_uint), unsigned int>::value, "");
+ static_assert(__is_same(decltype(x43_s + x_int), _BitInt(43)), "");
+ static_assert(__is_same(decltype(x43_u + x_int), unsigned _BitInt(43)), "");
+ static_assert(__is_same(decltype(x32_s + x_int), int), "");
+ static_assert(__is_same(decltype(x32_u + x_int), unsigned int), "");
+ static_assert(__is_same(decltype(x32_s + x_uint), unsigned int), "");
+ static_assert(__is_same(decltype(x32_u + x_uint), unsigned int), "");
+ static_assert(__is_same(decltype(x4_s + x_int), int), "");
+ static_assert(__is_same(decltype(x4_u + x_int), int), "");
+ static_assert(__is_same(decltype(x4_s + x_uint), unsigned int), "");
+ static_assert(__is_same(decltype(x4_u + x_uint), unsigned int), "");
// Bitwise checks.
x43_s % y4_u;
@@ -200,28 +191,28 @@ void Ops() {
x4_s > 33; // expected-warning {{result of comparison of constant 33 with expression of type '_BitInt(4)' is always false}}
// Same size/sign ops don't change type.
- static_assert(is_same<decltype(x43_s + y43_s), _BitInt(43)>::value,"");
- static_assert(is_same<decltype(x4_s - y4_s), _BitInt(4)>::value,"");
- static_assert(is_same<decltype(x43_u * y43_u), unsigned _BitInt(43)>::value,"");
- static_assert(is_same<decltype(x4_u / y4_u), unsigned _BitInt(4)>::value,"");
+ static_assert(__is_same(decltype(x43_s + y43_s), _BitInt(43)),"");
+ static_assert(__is_same(decltype(x4_s - y4_s), _BitInt(4)),"");
+ static_assert(__is_same(decltype(x43_u * y43_u), unsigned _BitInt(43)),"");
+ static_assert(__is_same(decltype(x4_u / y4_u), unsigned _BitInt(4)),"");
// Unary ops shouldn't go through integer promotions.
- static_assert(is_same<decltype(~x43_s), _BitInt(43)>::value,"");
- static_assert(is_same<decltype(~x4_s), _BitInt(4)>::value,"");
- static_assert(is_same<decltype(+x43_s), _BitInt(43)>::value,"");
- static_assert(is_same<decltype(+x4_s), _BitInt(4)>::value,"");
- static_assert(is_same<decltype(-x43_u), unsigned _BitInt(43)>::value,"");
- static_assert(is_same<decltype(-x4_u), unsigned _BitInt(4)>::value,"");
+ static_assert(__is_same(decltype(~x43_s), _BitInt(43)),"");
+ static_assert(__is_same(decltype(~x4_s), _BitInt(4)),"");
+ static_assert(__is_same(decltype(+x43_s), _BitInt(43)),"");
+ static_assert(__is_same(decltype(+x4_s), _BitInt(4)),"");
+ static_assert(__is_same(decltype(-x43_u), unsigned _BitInt(43)),"");
+ static_assert(__is_same(decltype(-x4_u), unsigned _BitInt(4)),"");
// expected-warning at +1{{expression with side effects has no effect in an unevaluated context}}
- static_assert(is_same<decltype(++x43_s), _BitInt(43)&>::value,"");
+ static_assert(__is_same(decltype(++x43_s), _BitInt(43)&),"");
// expected-warning at +1{{expression with side effects has no effect in an unevaluated context}}
- static_assert(is_same<decltype(--x4_s), _BitInt(4)&>::value,"");
+ static_assert(__is_same(decltype(--x4_s), _BitInt(4)&),"");
// expected-warning at +1{{expression with side effects has no effect in an unevaluated context}}
- static_assert(is_same<decltype(x43_s--), _BitInt(43)>::value,"");
+ static_assert(__is_same(decltype(x43_s--), _BitInt(43)),"");
// expected-warning at +1{{expression with side effects has no effect in an unevaluated context}}
- static_assert(is_same<decltype(x4_s++), _BitInt(4)>::value,"");
- static_assert(is_same<decltype(x4_s >> 1), _BitInt(4)>::value,"");
- static_assert(is_same<decltype(x4_u << 1), unsigned _BitInt(4)>::value,"");
+ static_assert(__is_same(decltype(x4_s++), _BitInt(4)),"");
+ static_assert(__is_same(decltype(x4_s >> 1), _BitInt(4)),"");
+ static_assert(__is_same(decltype(x4_u << 1), unsigned _BitInt(4)),"");
static_assert(sizeof(x43_s) == 8, "");
static_assert(sizeof(x4_s) == 1, "");
@@ -234,7 +225,7 @@ constexpr int func() { return 42;}
void ConstexprBitsize() {
_BitInt(func()) F;
- static_assert(is_same<decltype(F), _BitInt(42)>::value, "");
+ static_assert(__is_same(decltype(F), _BitInt(42)), "");
}
// Not useable as an underlying type.
@@ -305,9 +296,9 @@ void Ternary(_BitInt(30) s30, _BitInt(31) s31a, _BitInt(31) s31b,
(void)(b ? s31a : s31b);
(void)(s30 ? s31a : s31b);
- static_assert(is_same<decltype(b ? s30 : s31a), _BitInt(31)>::value, "");
- static_assert(is_same<decltype(b ? s32 : s30), _BitInt(32)>::value, "");
- static_assert(is_same<decltype(b ? s30 : 0), int>::value, "");
+ static_assert(__is_same(decltype(b ? s30 : s31a), _BitInt(31)), "");
+ static_assert(__is_same(decltype(b ? s32 : s30), _BitInt(32)), "");
+ static_assert(__is_same(decltype(b ? s30 : 0), int), "");
}
void FromPaper1() {
@@ -317,11 +308,11 @@ void FromPaper1() {
_BitInt(33) a33 = 1;
char c = 3;
- static_assert(is_same<decltype(a2 * a3), _BitInt(3)>::value, "");
- static_assert(is_same<decltype(a2 * c), int>::value, "");
- static_assert(is_same<decltype(a33 * c), _BitInt(33)>::value, "");
+ static_assert(__is_same(decltype(a2 * a3), _BitInt(3)), "");
+ static_assert(__is_same(decltype(a2 * c), int), "");
+ static_assert(__is_same(decltype(a33 * c), _BitInt(33)), "");
}
void FromPaper2(_BitInt(8) a1, _BitInt(24) a2) {
- static_assert(is_same<decltype(a1 * (_BitInt(32))a2), _BitInt(32)>::value, "");
+ static_assert(__is_same(decltype(a1 * (_BitInt(32))a2), _BitInt(32)), "");
}
More information about the cfe-commits
mailing list