[libcxx-commits] [libcxx] [libc++] Flat containers should reject `vector<bool, Alloc>` (PR #224886)

Hristo Hristov via libcxx-commits libcxx-commits at lists.llvm.org
Sun Sep 20 00:19:43 PDT 2026


https://github.com/H-G-Hristov updated https://github.com/llvm/llvm-project/pull/224886

>From b41370f22bc42abaea5b1185100a141796984239 Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sat, 19 Sep 2026 15:51:54 +0300
Subject: [PATCH 1/2] [libc++] `flat_meow` also reject `vector<bool, Alloc>`

---
 libcxx/include/CMakeLists.txt                 |  1 +
 libcxx/include/__flat_map/flat_map.h          |  7 +++-
 libcxx/include/__flat_map/flat_multimap.h     |  7 +++-
 libcxx/include/__flat_set/flat_multiset.h     |  4 +-
 libcxx/include/__flat_set/flat_set.h          |  3 +-
 libcxx/include/__vector/is_vector.h           | 37 +++++++++++++++++++
 .../flat.map/types.verify.cpp                 | 14 +++++--
 .../flat.multimap/types.verify.cpp            | 14 +++++--
 .../flat.multiset/types.verify.cpp            |  7 +++-
 .../flat.set/types.verify.cpp                 |  7 +++-
 10 files changed, 87 insertions(+), 14 deletions(-)
 create mode 100644 libcxx/include/__vector/is_vector.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index caf90b0cbbafa..cc0ffecbada17 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -1001,6 +1001,7 @@ set(files
   __vector/layout.h
   __vector/pmr.h
   __vector/swap.h
+  __vector/is_vector.h
   __vector/vector.h
   __vector/vector_bool.h
   __vector/vector_bool_formatter.h
diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 27964aa421d21..233496dbfbd1f 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -61,6 +61,7 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
+#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 #include <stdexcept>
@@ -89,8 +90,10 @@ class flat_map {
                 "The stored elements' key type must match the underlying key container's value_type.");
   static_assert(is_same_v<_Tp, typename _MappedContainer::value_type>,
                 "The stored elements' mapped type must match the underlying mapped container's value_type.");
-  static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
-  static_assert(!is_same_v<_MappedContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
+  static_assert(!__is_vectorbool_v<_KeyContainer>,
+                "The underlying key container must not be std::vector<bool>, which is not a sequence container.");
+  static_assert(!__is_vectorbool_v<_MappedContainer>,
+                "The underlying mapped container must not be std::vector<bool>, which is not a sequence container.");
 
   template <bool _Const>
   using __iterator _LIBCPP_NODEBUG = __key_value_iterator<flat_map, _KeyContainer, _MappedContainer, _Const>;
diff --git a/libcxx/include/__flat_map/flat_multimap.h b/libcxx/include/__flat_map/flat_multimap.h
index 9acaedf0772a0..87fcb5f20305e 100644
--- a/libcxx/include/__flat_map/flat_multimap.h
+++ b/libcxx/include/__flat_map/flat_multimap.h
@@ -59,6 +59,7 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
+#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 
@@ -86,8 +87,10 @@ class flat_multimap {
                 "The stored elements' key type must match the underlying key container's value_type.");
   static_assert(is_same_v<_Tp, typename _MappedContainer::value_type>,
                 "The stored elements' mapped type must match the underlying mapped container's value_type.");
-  static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
-  static_assert(!is_same_v<_MappedContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
+  static_assert(!__is_vectorbool_v<_KeyContainer>,
+                "The underlying key container must not be std::vector<bool>, which is not a sequence container.");
+  static_assert(!__is_vectorbool_v<_MappedContainer>,
+                "The underlying mapped container must not be std::vector<bool>, which is not a sequence container.");
 
   template <bool _Const>
   using __iterator _LIBCPP_NODEBUG = __key_value_iterator<flat_multimap, _KeyContainer, _MappedContainer, _Const>;
diff --git a/libcxx/include/__flat_set/flat_multiset.h b/libcxx/include/__flat_set/flat_multiset.h
index 74c0427eae928..1bb1cdd7e5888 100644
--- a/libcxx/include/__flat_set/flat_multiset.h
+++ b/libcxx/include/__flat_set/flat_multiset.h
@@ -53,6 +53,7 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
+#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 
@@ -76,7 +77,8 @@ class flat_multiset {
 
   static_assert(is_same_v<_Key, typename _KeyContainer::value_type>,
                 "The stored elements' key type must match the underlying key container's value_type.");
-  static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
+  static_assert(!__is_vectorbool_v<_KeyContainer>,
+                "The underlying key container must not be std::vector<bool>, which is not a sequence container.");
 
 public:
   // types
diff --git a/libcxx/include/__flat_set/flat_set.h b/libcxx/include/__flat_set/flat_set.h
index 988ffbe1b4a70..430a4dbd2f953 100644
--- a/libcxx/include/__flat_set/flat_set.h
+++ b/libcxx/include/__flat_set/flat_set.h
@@ -78,7 +78,8 @@ class flat_set {
 
   static_assert(is_same_v<_Key, typename _KeyContainer::value_type>,
                 "The stored elements' key type must match the underlying key container's value_type.");
-  static_assert(!is_same_v<_KeyContainer, std::vector<bool>>, "vector<bool> is not a sequence container");
+  static_assert(!__is_vectorbool_v<_KeyContainer>,
+                "The underlying key container must not be std::vector<bool>, which is not a sequence container.");
 
   using __key_iterator _LIBCPP_NODEBUG = typename _KeyContainer::const_iterator;
 
diff --git a/libcxx/include/__vector/is_vector.h b/libcxx/include/__vector/is_vector.h
new file mode 100644
index 0000000000000..96dbb7347fc78
--- /dev/null
+++ b/libcxx/include/__vector/is_vector.h
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___VECTOR_IS_VECTOR_H
+#define _LIBCPP___VECTOR_IS_VECTOR_H
+
+#include <__config>
+#include <__fwd/vector.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+struct __is_vectorbool : false_type {};
+
+template <class _Allocator>
+struct __is_vectorbool<vector<bool, _Allocator>> : true_type {};
+
+template <class _Allocator>
+inline constexpr bool __is_vectorbool_v = __is_vectorbool<_Allocator>::value;
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___VECTOR_VECTOR_H
diff --git a/libcxx/test/std/containers/container.adaptors/flat.map/types.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.map/types.verify.cpp
index 3e02678f09623..51db2a8f9c7c1 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.map/types.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.map/types.verify.cpp
@@ -18,6 +18,8 @@
 #include <functional>
 #include <vector>
 
+#include "min_allocator.h"
+
 void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' key type must match the underlying key container's value_type.}}
   std::flat_map<double, int, std::less<double>, std::vector<char>> fm1;
@@ -25,9 +27,15 @@ void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' mapped type must match the underlying mapped container's value_type.}}
   std::flat_map<int, double, std::less<int>, std::vector<int>, std::vector<char>> fm2;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
   std::flat_map<bool, int, std::less<bool>, std::vector<bool>> fm3;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
-  std::flat_map<int, bool, std::less<int>, std::vector<int>, std::vector<bool>> fm4;
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_map<bool, int, std::less<bool>, std::vector<bool, min_allocator<bool>>> fm4;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying mapped container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_map<int, bool, std::less<int>, std::vector<int>, std::vector<bool>> fm5;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying mapped container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_map<int, bool, std::less<int>, std::vector<int>, std::vector<bool, min_allocator<bool>>> fm6;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multimap/types.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.multimap/types.verify.cpp
index ad6f701f9034c..147cbdea3e210 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multimap/types.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multimap/types.verify.cpp
@@ -18,6 +18,8 @@
 #include <functional>
 #include <vector>
 
+#include "min_allocator.h"
+
 void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' key type must match the underlying key container's value_type.}}
   std::flat_multimap<double, int, std::less<double>, std::vector<char>> fmm1;
@@ -25,9 +27,15 @@ void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' mapped type must match the underlying mapped container's value_type.}}
   std::flat_multimap<int, double, std::less<int>, std::vector<int>, std::vector<char>> fmm2;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
   std::flat_multimap<bool, int, std::less<bool>, std::vector<bool>> fmm3;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
-  std::flat_multimap<int, bool, std::less<int>, std::vector<int>, std::vector<bool>> fmm4;
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_multimap<bool, int, std::less<bool>, std::vector<bool, min_allocator<bool>>> fmm4;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying mapped container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_multimap<int, bool, std::less<int>, std::vector<int>, std::vector<bool>> fmm5;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying mapped container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_multimap<int, bool, std::less<int>, std::vector<int>, std::vector<bool, min_allocator<bool>>> fmm6;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.multiset/types.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.multiset/types.verify.cpp
index b70d193841e06..ffe9dc3284f8e 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.multiset/types.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.multiset/types.verify.cpp
@@ -17,10 +17,15 @@
 #include <functional>
 #include <vector>
 
+#include "min_allocator.h"
+
 void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' key type must match the underlying key container's value_type.}}
   std::flat_multiset<double, std::less<double>, std::vector<int>> fms1;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
   std::flat_multiset<bool, std::less<bool>, std::vector<bool>> fms2;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_multiset<bool, std::less<bool>, std::vector<bool, min_allocator<bool>>> fms3;
 }
diff --git a/libcxx/test/std/containers/container.adaptors/flat.set/types.verify.cpp b/libcxx/test/std/containers/container.adaptors/flat.set/types.verify.cpp
index 78621182a45f3..76755b19fe8ea 100644
--- a/libcxx/test/std/containers/container.adaptors/flat.set/types.verify.cpp
+++ b/libcxx/test/std/containers/container.adaptors/flat.set/types.verify.cpp
@@ -17,10 +17,15 @@
 #include <functional>
 #include <vector>
 
+#include "min_allocator.h"
+
 void test() {
   // expected-error-re@*:* {{static assertion failed{{.*}}The stored elements' key type must match the underlying key container's value_type.}}
   std::flat_set<double, std::less<double>, std::vector<int>> fs1;
 
-  // expected-error-re@*:* {{static assertion failed{{.*}}vector<bool> is not a sequence container}}
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
   std::flat_set<bool, std::less<bool>, std::vector<bool>> fs2;
+
+  // expected-error-re@*:* {{static assertion failed{{.*}}The underlying key container must not be std::vector<bool>, which is not a sequence container.}}
+  std::flat_set<bool, std::less<bool>, std::vector<bool, min_allocator<bool>>> fs3;
 }

>From c4eda979b825b16cb80dc2ccff06523f3cd78e5a Mon Sep 17 00:00:00 2001
From: Hristo Hristov <hghristov.rmm at gmail.com>
Date: Sun, 20 Sep 2026 10:16:11 +0300
Subject: [PATCH 2/2] Review comments

---
 libcxx/include/CMakeLists.txt             |  1 -
 libcxx/include/__flat_map/flat_map.h      |  1 -
 libcxx/include/__flat_map/flat_multimap.h |  1 -
 libcxx/include/__flat_set/flat_multiset.h |  1 -
 libcxx/include/__fwd/vector.h             |  6 ++++
 libcxx/include/__vector/is_vector.h       | 37 -----------------------
 6 files changed, 6 insertions(+), 41 deletions(-)
 delete mode 100644 libcxx/include/__vector/is_vector.h

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index cc0ffecbada17..caf90b0cbbafa 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -1001,7 +1001,6 @@ set(files
   __vector/layout.h
   __vector/pmr.h
   __vector/swap.h
-  __vector/is_vector.h
   __vector/vector.h
   __vector/vector_bool.h
   __vector/vector_bool_formatter.h
diff --git a/libcxx/include/__flat_map/flat_map.h b/libcxx/include/__flat_map/flat_map.h
index 233496dbfbd1f..63ed01bdd0f44 100644
--- a/libcxx/include/__flat_map/flat_map.h
+++ b/libcxx/include/__flat_map/flat_map.h
@@ -61,7 +61,6 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
-#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 #include <stdexcept>
diff --git a/libcxx/include/__flat_map/flat_multimap.h b/libcxx/include/__flat_map/flat_multimap.h
index 87fcb5f20305e..8d8d76f6f6bc4 100644
--- a/libcxx/include/__flat_map/flat_multimap.h
+++ b/libcxx/include/__flat_map/flat_multimap.h
@@ -59,7 +59,6 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
-#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 
diff --git a/libcxx/include/__flat_set/flat_multiset.h b/libcxx/include/__flat_set/flat_multiset.h
index 1bb1cdd7e5888..ec6c59d41a631 100644
--- a/libcxx/include/__flat_set/flat_multiset.h
+++ b/libcxx/include/__flat_set/flat_multiset.h
@@ -53,7 +53,6 @@
 #include <__utility/move.h>
 #include <__utility/pair.h>
 #include <__utility/scope_guard.h>
-#include <__vector/is_vector.h>
 #include <__vector/vector.h>
 #include <initializer_list>
 
diff --git a/libcxx/include/__fwd/vector.h b/libcxx/include/__fwd/vector.h
index 31084ec995b69..4662b20a4ae9f 100644
--- a/libcxx/include/__fwd/vector.h
+++ b/libcxx/include/__fwd/vector.h
@@ -24,6 +24,12 @@ class vector;
 template <class _Allocator>
 class vector<bool, _Allocator>;
 
+template <class _Tp>
+inline constexpr bool __is_vector_bool_v  = false;
+
+template <class _Allocator>
+inline constexpr bool __is_vector_bool_v<vector<bool, _Allocator>> = true;
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___FWD_VECTOR_H
diff --git a/libcxx/include/__vector/is_vector.h b/libcxx/include/__vector/is_vector.h
deleted file mode 100644
index 96dbb7347fc78..0000000000000
--- a/libcxx/include/__vector/is_vector.h
+++ /dev/null
@@ -1,37 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef _LIBCPP___VECTOR_IS_VECTOR_H
-#define _LIBCPP___VECTOR_IS_VECTOR_H
-
-#include <__config>
-#include <__fwd/vector.h>
-
-#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
-#  pragma GCC system_header
-#endif
-
-_LIBCPP_PUSH_MACROS
-#include <__undef_macros>
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-template <class _Tp>
-struct __is_vectorbool : false_type {};
-
-template <class _Allocator>
-struct __is_vectorbool<vector<bool, _Allocator>> : true_type {};
-
-template <class _Allocator>
-inline constexpr bool __is_vectorbool_v = __is_vectorbool<_Allocator>::value;
-
-_LIBCPP_END_NAMESPACE_STD
-
-_LIBCPP_POP_MACROS
-
-#endif // _LIBCPP___VECTOR_VECTOR_H



More information about the libcxx-commits mailing list