Skip to content
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

Detect allocate_at_least with a concept #3891

Merged
merged 2 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions stl/inc/xmemory
Original file line number Diff line number Diff line change
Expand Up @@ -471,12 +471,17 @@ struct _Is_default_allocator<allocator<_Ty>, void_t<typename allocator<_Ty>::_Fr
: is_same<typename allocator<_Ty>::_From_primary, allocator<_Ty>>::type {};

#if _HAS_CXX23
#ifdef __cpp_lib_concepts // TRANSITION, GH-395
template <class _Alloc, class _SizeTy>
concept _Has_member_allocate_at_least = requires(_Alloc& _Al, const _SizeTy& _Count) { _Al.allocate_at_least(_Count); };
#else // ^^^ no workaround / workaround vvv
template <class _Alloc, class _SizeTy, class = void>
inline constexpr bool _Has_member_allocate_at_least = false;

template <class _Alloc, class _SizeTy>
inline constexpr bool _Has_member_allocate_at_least<_Alloc, _SizeTy,
void_t<decltype(_STD declval<_Alloc&>().allocate_at_least(_STD declval<const _SizeTy&>()))>> = true;
#endif // __cpp_lib_concepts
#endif // _HAS_CXX23

template <class _Void, class... _Types>
Expand Down
25 changes: 25 additions & 0 deletions tests/std/tests/GH_003570_allocate_at_least/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,31 @@ void test_inheriting_allocator() {
assert(accumulate(vec.begin(), vec.end(), 0, plus<>{}) == 36);
}

// Also test GH-3890, in which we incorrectly tried to use allocate_at_least from an inaccessible std::allocator
// base due to an MSVC bug.
template <class T>
struct less_icky_allocator : private allocator<T> {
using value_type = T;

less_icky_allocator() = default;
template <class U>
less_icky_allocator(const less_icky_allocator<U>&) {}

T* allocate(size_t n) {
return allocator<T>::allocate(n);
}

void deallocate(T* ptr, size_t n) {
return allocator<T>::deallocate(ptr, n);
}

template <class U>
bool operator==(const less_icky_allocator<U>&) const {
return true;
}
};
static_assert(!std::_Should_allocate_at_least<less_icky_allocator<int>>);

int main() {
test_deque();
test_container<basic_string<char, char_traits<char>, signalling_allocator<char>>>();
Expand Down