<table border="1" cellspacing="0" cellpadding="8">
<tr>
<th>Issue</th>
<td>
<a href=https://github.com/llvm/llvm-project/issues/121713>121713</a>
</td>
</tr>
<tr>
<th>Summary</th>
<td>
[libc++] Ambiguous call to `std::max` leads to complication failure
</td>
</tr>
<tr>
<th>Labels</th>
<td>
libc++
</td>
</tr>
<tr>
<th>Assignees</th>
<td>
</td>
</tr>
<tr>
<th>Reporter</th>
<td>
winner245
</td>
</tr>
</table>
<pre>
The following code snippet, which utilizes `vector<bool>` with a custom-sized allocator with `size_type = std::uint16_t` and `difference_type = std::int16_t`, fails to compile due to an ambiguous call to `std::max` within `vector<bool>`:
[Godbolt link](https://godbolt.org/z/3qGvoxsE1)
```cpp
#include <exception>
#include <iostream>
#include <limits>
#include <memory>
#include <vector>
template <typename T, typename SIZE_TYPE = std::size_t, typename DIFF_TYPE = std::ptrdiff_t>
class CustomSizedAllocator {
template <typename U, typename Sz, typename Diff>
friend class CustomSizedAllocator;
public:
using value_type = T;
using size_type = SIZE_TYPE;
using difference_type = DIFF_TYPE;
using propagate_on_container_swap = std::true_type;
explicit CustomSizedAllocator(int i = 0) : data_(i) {}
template <typename U, typename Sz, typename Diff>
constexpr CustomSizedAllocator(const CustomSizedAllocator<U, Sz, Diff>& a) noexcept : data_(a.data_) {}
constexpr T* allocate(size_type n) {
if (n > max_size())
throw std::bad_array_new_length();
return std::allocator<T>().allocate(n);
}
constexpr void deallocate(T* p, size_type n) noexcept { std::allocator<T>().deallocate(p, n); }
constexpr size_type max_size() const noexcept { return std::numeric_limits<size_type>::max() / sizeof(value_type); }
int get() { return data_; }
private:
int data_;
constexpr friend bool operator==(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
return a.data_ == b.data_;
}
constexpr friend bool operator!=(const CustomSizedAllocator& a, const CustomSizedAllocator& b) {
return a.data_ != b.data_;
}
};
int main() {
using Alloc = CustomSizedAllocator<bool, std::uint16_t, std::int16_t>;
std::vector<bool, Alloc> c{Alloc{1}};
c.resize(10);
return 0;
}
```
This code produces the following compilation error in libc++:
```
error: no matching function for call to 'max'
2331 | return std::max(2 * __cap, __align_it(__new_size));
| ^~~~~~~~
```
#### Root cause analysis
The root cause to the complication error is due to the following ambiguous `std::max` call within `vector<bool>`:
https://github.com/llvm/llvm-project/blob/f4230b4332262dffb0bd3b7a2f8d6deb2e96488e/libcxx/include/__vector/vector_bool.h#L529
In this context with the custom-sized allocator, the first operand's result type is `int` due to integral promotion in the arithmetic involving `int` and `std::uint16_t`. Meanwhile, the second operand retains the `size_type` type (i.e., `std::uint16_t`). This type mismatch leads to a failure in template type argument deduction for `std::max<T>`, resulting in the compilation error.
#### Proposed solution:
I've already submitted a PR #119801 to fix this issue. The solution is straightforward: explicitly specify the template type argument for `std::max` to ensure consistent types for both operands.
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJy0V09v67gR_zTMZbCGRNmWffAhduLFA1rgYTc9tBeBoiiLLUWqJGU779DPXgwpWXai7G5RbCC8Z4kzw9_85g-HzDl50kLsyGpPVi9PrPeNsbuL1FpYulw9laZ63701AmqjlLlIfQJuKgFOy64TntADXBrJG-i9VPKHcEDWyVlwbyzJDqUximSvZJ3ARfoGGPDeedP-5OQPUQFTynDmjY2rZJ3g98K_dwJI9gLOVyR7JtlzL7VP14VHQ0xXKFnJuhZWaD4nP4kjwJpJ5cAb4KbtpBJQ9QJfmQbWlvLUm94BZ0rhRwQxmmnZdYQu9ReOoWQSntX-Z1OVRnlQUv-LrF4I3TTedw5F6JHQ4ymuL4w9EXr8Qegx-_fPZ3N1rymh28HMOokP7zp8pZnUXPUVengQVy46L43GvT8uSuO8FaydW1Oyld7NrbSiNfZ9bmV09jUC86LtFPNhCRnXrBXwhvze3n799o_X4u3v318foxGD-iD58u14nJHsvMW4Fj7uyhVzDg4hZX7FjHm-JQzJ9yR5BphF9bdHVD8et5Z1Hc0D1FYKXcHX-5BsH73v-lJJHoMN0DsshDNT_ZB9n_7QrbeoPUhPqT0vfSNv0BrU5vL8xt6jaGdNx07Mi8LoghvtmdTCFu7CukeavR1w39wDce2U5NLPs0A3UnuQwUpC6BZI9gwV86zApfAh35P8ZTD2f0aFG-28uHb2KzBB4It4HcI20fpolK6BIUhtYgE9wGeL4ddHJyYYb4Q-j81KELqZQqlHNVQAkDUQutFAsldo2bVAQUI3WNyhvmO0fWPNZYpGyaqCWcveCy0uhRL65JtBKRsNW-F7qycddufwW3AR5Rd3GPWd_qxTZyMrqMSdSnCzQ-I-ODjxlu9_F8ODyWBtgHIHY0Ix7fTIVxR53PkjCbpvhZW8GJvb4WYM0dw6eLRH6DFsZmpCN1PlfoIGmOknPNk2Q2zHfWOa3At3Vp7Rz2zSHIU-8z30Gjw5wHTCRuZe8PnNjI7Je4DfFinvEnHAOyQ2xE2gXNxhG3PidwHS9E8AOCX0DWPYZx4j_jsSShI826FlUk8BumuBYcvQpr7oDuHgxgz_NFrcfxy_ZbcOe1t6HAHoIW6JBc9Jvo8v-T5F0CNuAL6wYsjtNLkVZlgaiEiGT9HjcQaIQm-NdHHq6qypei4c-A8TGc41DAcDENYaC1KDkiUndI_PbUS5sxvksA9qAy3zvEFDda95sFIbO01ENA9llCNemmUpkPww05NirVHALlIUnIXaLwqm5EkXEguqCB0uErF96G8w2BzPw9Xrf-LfZzYIzW4P_GKMB856J4Bppt6ddCNnAuy06E2gDIlSkj8w5cZx8JHTaTKcmQgDNX9sLPwwAUrf9OWCm5bQo1Ln8b-fOmv-Kbgn9FgqUxJ6rJc0S8plllG6plVdl0lZZWXOaL2p1pUoqdiul5uNQAOy5NcrocdheCP0WBQDJnqMPwqEtmgIzf6yGkfNbxp8TC3txdXHITzQNDukh_MaOZLW-dghdEVo7sAK1ysfDnPkk6wTqcOsPjArtRcnyxTmb2sC-VIHW8xK37TCSw5Sn406I_WT_jDrz90DFvBXwfSlkUqMwJzgRlcjMsxPJnWslfurBRqOoxTdyIVYoPoXm-B5BqH84hElXSgVUIJV4UbBwuWityI4NE49QZjZU98KPBJE1U9V9TGbhrMz3lQikcjBwM-nyl5gwcwUwndrOuNEBc6oPt4QQogJzc8CmLKCVe_g-rKV3mNU4fsvQGiWpttNkqIrtbzGdJDO9QLdFjdjGFXnLZOnxtfGXphFD25Do3oH1wku6_cA-gse5rzHUBgQ2iGFeIBI51EWNV3QKI1vxpA69P6p2mXVNtuyJ7FL82yd0iTP06dmt66Sim3XZbkuyzTP66SqVllZLul2uUlrnj7JHU3oKkmTFc2W6zRdUMGXybYqszJNeZomZJmIlkm1wJLEW9pT4GKX0jRPsyfFSqFcuCpTetdeKcWrs92FQi77kyPLREnn3WTHS6_CJftObfUCz3_k-nlLtofuNeTdU2_V7n_uMcEtR-hx8Oy8o_8NAAD__-r1Dns">