-
Notifications
You must be signed in to change notification settings - Fork 12.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[libc++] Fix ambiguous call to std::max in vector<bool> #119801
base: main
Are you sure you want to change the base?
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
4657768
to
fe95a47
Compare
fe95a47
to
885d70b
Compare
@llvm/pr-subscribers-libcxx Author: Peng Liu (winner245) ChangesThis PR addresses a compilation error in The following code snippet reproduces the bug in #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 fails to compile in libc++, while it compiles successfully in other standard library implementations. The underlying issue is found in the following line of code within return std::max(2 * __cap, __align_it(__new_size)); where the first operand's result type is promoted to int, while the second operand retains the The solution is straightforward: explicitly specify the template type for Full diff: https://github.com/llvm/llvm-project/pull/119801.diff 4 Files Affected:
diff --git a/libcxx/include/__cxx03/string b/libcxx/include/__cxx03/string
index c4431dcb04d41e..c29f74290bd416 100644
--- a/libcxx/include/__cxx03/string
+++ b/libcxx/include/__cxx03/string
@@ -2483,7 +2483,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
__throw_length_error();
pointer __old_p = __get_pointer();
size_type __cap =
- __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
+ __old_cap < __ms / 2 - __alignment
+ ? __recommend(std::max<size_type>(__old_cap + __delta_cap, 2 * __old_cap))
+ : __ms - 1;
__annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
@@ -2526,7 +2528,9 @@ _LIBCPP_DEPRECATED_("use __grow_by_without_replace") basic_string<_CharT, _Trait
__throw_length_error();
pointer __old_p = __get_pointer();
size_type __cap =
- __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
+ __old_cap < __ms / 2 - __alignment
+ ? __recommend(std::max<size_type>(__old_cap + __delta_cap, 2 * __old_cap))
+ : __ms - 1;
__annotate_delete();
auto __allocation = std::__allocate_at_least(__alloc(), __cap + 1);
pointer __p = __allocation.ptr;
diff --git a/libcxx/include/__cxx03/vector b/libcxx/include/__cxx03/vector
index 6ee35b4e36258f..80da74ded67b7a 100644
--- a/libcxx/include/__cxx03/vector
+++ b/libcxx/include/__cxx03/vector
@@ -2328,7 +2328,7 @@ vector<bool, _Allocator>::__recommend(size_type __new_size) const {
const size_type __cap = capacity();
if (__cap >= __ms / 2)
return __ms;
- return std::max(2 * __cap, __align_it(__new_size));
+ return std::max<size_type>(2 * __cap, __align_it(__new_size));
}
// Default constructs __n objects starting at __end_
diff --git a/libcxx/include/__vector/vector_bool.h b/libcxx/include/__vector/vector_bool.h
index 36eb7f350ac406..26b172af9138db 100644
--- a/libcxx/include/__vector/vector_bool.h
+++ b/libcxx/include/__vector/vector_bool.h
@@ -527,7 +527,7 @@ vector<bool, _Allocator>::__recommend(size_type __new_size) const {
const size_type __cap = capacity();
if (__cap >= __ms / 2)
return __ms;
- return std::max(2 * __cap, __align_it(__new_size));
+ return std::max<size_type>(2 * __cap, __align_it(__new_size));
}
// Default constructs __n objects starting at __end_
diff --git a/libcxx/include/string b/libcxx/include/string
index 17bf4b3b98bf34..911b67cfcf26e8 100644
--- a/libcxx/include/string
+++ b/libcxx/include/string
@@ -2518,7 +2518,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::__
__throw_length_error();
pointer __old_p = __get_pointer();
size_type __cap =
- __old_cap < __ms / 2 - __alignment ? __recommend(std::max(__old_cap + __delta_cap, 2 * __old_cap)) : __ms - 1;
+ __old_cap < __ms / 2 - __alignment
+ ? __recommend(std::max<size_type>(__old_cap + __delta_cap, 2 * __old_cap))
+ : __ms - 1;
__annotate_delete();
auto __guard = std::__make_scope_guard(__annotate_new_size(*this));
auto __allocation = std::__allocate_at_least(__alloc_, __cap + 1);
|
This PR fixes an ambiguous call to
std::max
invector<bool>
and also improves similar usage ofstd::max
withinstd::basic_string
to prevent potential issues.Closes #121713.