Skip to content

Commit

Permalink
Detect allocate_at_least with a concept (#3891)
Browse files Browse the repository at this point in the history
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
CaseyCarter and StephanTLavavej authored Jul 20, 2023
1 parent 8a93121 commit b81f61c
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 0 deletions.
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

0 comments on commit b81f61c

Please sign in to comment.