<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">