After #3864, VSO-1852860 / AB#1852860 "[RWC][prod/fe][std:c++latest][Regression] Catch2 failed with error C2247 and error C2248" was reported, due to a custom allocator privately inheriting from std::allocator (see https://github.com/catchorg/Catch2/blob/4acc51828f7f93f3b2058a63f54d112af4034503/tests/SelfTest/UsageTests/Matchers.tests.cpp#L229-L254 ):
D:\GitHub\STL\out\x64>type meow.cpp
#include <cassert>
#include <memory>
#include <vector>
using namespace std;
template <typename T>
struct CustomAllocator : private allocator<T> {
using value_type = T;
CustomAllocator() = default;
template <typename U>
CustomAllocator(const CustomAllocator<U>&) {}
using allocator<T>::allocate;
using allocator<T>::deallocate;
template <typename U>
bool operator==(const CustomAllocator<U>&) const {
return true;
}
};
int main() {
vector<int, CustomAllocator<int>> v;
v.push_back(1729);
assert(v.back() == 1729);
}
D:\GitHub\STL\out\x64>cl /EHsc /nologo /W4 /std:c++20 /MTd /Od meow.cpp && meow
meow.cpp
D:\GitHub\STL\out\x64>cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp && meow
meow.cpp
D:\GitHub\STL\out\x64\out\inc\xmemory(2197): error C2247: 'std::allocator<int>::allocate_at_least' not accessible because 'CustomAllocator<int>' uses 'private' to inherit from 'std::allocator<int>'
D:\GitHub\STL\out\x64\out\inc\xmemory(978): note: see declaration of 'std::allocator<int>::allocate_at_least'
meow.cpp(25): note: see declaration of 'CustomAllocator<int>'
D:\GitHub\STL\out\x64\out\inc\xmemory(1049): note: see declaration of 'std::allocator<int>'
D:\GitHub\STL\out\x64\out\inc\vector(831): note: see reference to function template instantiation 'int *std::_Allocate_at_least_helper<CustomAllocator<int>>(_Alloc &,unsigned __int64 &)' being compiled
with
[
_Alloc=CustomAllocator<int>
]
D:\GitHub\STL\out\x64\out\inc\vector(785): note: see reference to function template instantiation 'int *std::vector<int,CustomAllocator<int>>::_Emplace_reallocate<_Ty>(int *const ,_Ty &&)' being compiled
with
[
_Ty=int
]
D:\GitHub\STL\out\x64\out\inc\vector(878): note: see reference to function template instantiation '_Ty &std::vector<_Ty,CustomAllocator<int>>::_Emplace_one_at_back<int>(int &&)' being compiled
with
[
_Ty=int
]
D:\GitHub\STL\out\x64\out\inc\vector(876): note: while compiling class template member function 'void std::vector<int,CustomAllocator<int>>::push_back(_Ty &&)'
with
[
_Ty=int
]
meow.cpp(26): note: see the first reference to 'std::vector<int,CustomAllocator<int>>::push_back' in 'main'
meow.cpp(25): note: see reference to class template instantiation 'std::vector<int,CustomAllocator<int>>' being compiled
D:\GitHub\STL\out\x64\out\inc\xmemory(2197): error C2248: 'std::allocator<int>::allocate_at_least': cannot access private member declared in class 'CustomAllocator<int>'
D:\GitHub\STL\out\x64\out\inc\xmemory(978): note: see declaration of 'std::allocator<int>::allocate_at_least'
meow.cpp(25): note: see declaration of 'CustomAllocator<int>'
D:\GitHub\STL\out\x64>clang-cl /EHsc /nologo /W4 /std:c++20 /MTd /Od meow.cpp && meow
D:\GitHub\STL\out\x64>clang-cl /EHsc /nologo /W4 /std:c++latest /MTd /Od meow.cpp && meow
D:\GitHub\STL\out\x64>
This appears to involve an MSVC compiler bug in SFINAE, because Clang accepts this code. For MSVC, it appears that classic SFINAE is properly detecting that typename _Ty::_From_primary is inaccessible, but then Expression SFINAE is incorrectly detecting that allocate_at_least is accessible:
|
#if _HAS_CXX23
|
|
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 // _HAS_CXX23
|
|
#if _HAS_CXX23
|
|
template <class _Ty, class = void>
|
|
inline constexpr bool _Has_member_from_primary = false;
|
|
template <class _Ty>
|
|
inline constexpr bool _Has_member_from_primary<_Ty, void_t<typename _Ty::_From_primary>> = true;
|
|
|
|
// Avoid using allocate_at_least when the allocator publicly derives from std::allocator:
|
|
// "old" allocators might hide allocate and deallocate but fail to hide allocate_at_least.
|
|
// Also avoid using allocate_at_least from std::allocator itself because it currently doesn't do anything useful.
|
|
template <class _Alloc>
|
|
inline constexpr bool _Should_allocate_at_least =
|
|
!_Has_member_from_primary<_Alloc>
|
|
&& _Has_member_allocate_at_least<_Alloc, typename allocator_traits<_Alloc>::size_type>;
|
|
#endif // _HAS_CXX23
|
We should report this compiler bug, and then we may need to work around it with is_base_of to bluntly forbid all std::allocator inheritance (is_base_of sees through private and ambiguous bases).
After #3864, VSO-1852860 / AB#1852860 "[RWC][prod/fe][std:c++latest][Regression] Catch2 failed with error C2247 and error C2248" was reported, due to a custom allocator privately inheriting from
std::allocator(see https://github.com/catchorg/Catch2/blob/4acc51828f7f93f3b2058a63f54d112af4034503/tests/SelfTest/UsageTests/Matchers.tests.cpp#L229-L254 ):This appears to involve an MSVC compiler bug in SFINAE, because Clang accepts this code. For MSVC, it appears that classic SFINAE is properly detecting that
typename _Ty::_From_primaryis inaccessible, but then Expression SFINAE is incorrectly detecting thatallocate_at_leastis accessible:STL/stl/inc/xmemory
Lines 473 to 480 in f51733c
STL/stl/inc/xmemory
Lines 2177 to 2190 in f51733c
We should report this compiler bug, and then we may need to work around it with
is_base_ofto bluntly forbid allstd::allocatorinheritance (is_base_ofsees through private and ambiguous bases).