1
+ // ===----------------------------------------------------------------------===//
2
+ //
3
+ // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
+ // See https://llvm.org/LICENSE.txt for license information.
5
+ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
+ //
7
+ // ===----------------------------------------------------------------------===//
8
+
9
+ // <vector>
10
+ // vector<bool>
11
+
12
+ // This test examines ambiguous calls to std::max in vector<bool>
13
+ // Fix https://github.com/llvm/llvm-project/issues/121713
14
+
15
+ #include < cassert>
16
+ #include < cstddef>
17
+ #include < cstdint>
18
+ #include < limits>
19
+ #include < memory>
20
+ #include < new>
21
+ #include < vector>
22
+
23
+ #include " test_macros.h"
24
+
25
+ template <typename T, typename SIZE_TYPE = std::size_t , typename DIFF_TYPE = std::ptrdiff_t >
26
+ class sized_allocator {
27
+ template <typename U, typename Sz, typename Diff>
28
+ friend class sized_allocator ;
29
+
30
+ public:
31
+ using value_type = T;
32
+ using size_type = SIZE_TYPE;
33
+ using difference_type = DIFF_TYPE;
34
+ using propagate_on_container_swap = std::true_type;
35
+
36
+ TEST_CONSTEXPR_CXX20 explicit sized_allocator (int d = 0 ) : data_(d) {}
37
+
38
+ template <typename U, typename Sz, typename Diff>
39
+ TEST_CONSTEXPR_CXX20 sized_allocator (const sized_allocator<U, Sz, Diff>& a) TEST_NOEXCEPT : data_(a.data_) {}
40
+
41
+ TEST_CONSTEXPR_CXX20 T* allocate (size_type n) {
42
+ if (n > max_size ())
43
+ TEST_THROW (std::bad_array_new_length ());
44
+ return std::allocator<T>().allocate (n);
45
+ }
46
+
47
+ TEST_CONSTEXPR_CXX20 void deallocate (T* p, size_type n) TEST_NOEXCEPT { std::allocator<T>().deallocate (p, n); }
48
+
49
+ TEST_CONSTEXPR size_type max_size () const TEST_NOEXCEPT {
50
+ return std::numeric_limits<size_type>::max () / sizeof (value_type);
51
+ }
52
+
53
+ private:
54
+ int data_;
55
+
56
+ TEST_CONSTEXPR friend bool operator ==(const sized_allocator& a, const sized_allocator& b) {
57
+ return a.data_ == b.data_ ;
58
+ }
59
+ TEST_CONSTEXPR friend bool operator !=(const sized_allocator& a, const sized_allocator& b) {
60
+ return a.data_ != b.data_ ;
61
+ }
62
+ };
63
+
64
+ TEST_CONSTEXPR_CXX20 bool tests () {
65
+ // The following tests are typical ways to trigger reallocations where `std::max` is used to calculate the capacity.
66
+ {
67
+ using Alloc = sized_allocator<bool , std::uint8_t , std::int8_t >;
68
+ std::vector<bool , Alloc> c{Alloc{1 }};
69
+ c.resize (10 );
70
+ }
71
+ {
72
+ using Alloc = sized_allocator<bool , std::uint8_t , std::int8_t >;
73
+ std::vector<bool , Alloc> c{Alloc{1 }};
74
+ c.assign (10 , true );
75
+ }
76
+ {
77
+ using Alloc = sized_allocator<bool , std::uint8_t , std::int8_t >;
78
+ std::vector<bool , Alloc> c{Alloc{1 }};
79
+ c.insert (c.end (), true );
80
+ }
81
+ {
82
+ using Alloc = sized_allocator<bool , std::uint16_t , std::int16_t >;
83
+ std::vector<bool , Alloc> c{Alloc{1 }};
84
+ c.insert (c.end (), 10 , true );
85
+ }
86
+ {
87
+ using Alloc = sized_allocator<bool , std::uint16_t , std::int16_t >;
88
+ std::vector<bool , Alloc> c{Alloc{1 }};
89
+ c.push_back (true );
90
+ }
91
+ {
92
+ using Alloc = sized_allocator<bool , std::uint16_t , std::int16_t >;
93
+ std::vector<bool , Alloc> c{Alloc{1 }};
94
+ c.resize (10 , true );
95
+ }
96
+ {
97
+ using Alloc = sized_allocator<bool , std::uint32_t , std::int32_t >;
98
+ std::vector<bool , Alloc> c{Alloc{1 }};
99
+ c.resize (10 );
100
+ }
101
+ {
102
+ using Alloc = sized_allocator<bool , std::uint64_t , std::int64_t >;
103
+ std::vector<bool , Alloc> c{Alloc{1 }};
104
+ c.resize (10 );
105
+ }
106
+ {
107
+ using Alloc = sized_allocator<bool , std::size_t , std::ptrdiff_t >;
108
+ std::vector<bool , Alloc> c{Alloc{1 }};
109
+ c.resize (10 );
110
+ }
111
+
112
+ return true ;
113
+ }
114
+
115
+ int main (int , char **) {
116
+ tests ();
117
+ #if TEST_STD_VER >= 20
118
+ static_assert (tests ());
119
+ #endif
120
+ return 0 ;
121
+ }
0 commit comments