Skip to content

[libc++] Ambiguous call to std::max leads to compilation failure #121713

@winner245

Description

@winner245

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

#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'

Root cause analysis

The root cause to the complication error is due to the following ambiguous std::max call within vector<bool>:

return std::max(2 * __cap, __align_it(__new_size));

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.

Metadata

Metadata

Assignees

Labels

libc++libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions