forked from OSchip/llvm-project
[libcxx][NFC] Make sequence containers slightly more SFINAE-friendly during CTAD.
Disable the constructors taking `(size_type, const value_type&, allocator_type)` if `allocator_type` is not a valid allocator. Otherwise, these constructors are considered when resolving e.g. `(int*, int*, NotAnAllocator())`, leading to a hard error during instantiation. A hard error makes the Standard's requirement to not consider deduction guides of the form `(Iterator, Iterator, BadAllocator)` during overload resolution essentially non-functional. The previous approach was to SFINAE away `allocator_traits`. This patch SFINAEs away the specific constructors instead, for consistency with `basic_string` -- see [LWG3076](wg21.link/lwg3076) which describes a very similar problem for strings (note, however, that unlike LWG3076, no valid constructor call is affected by the bad instantiation). Differential Revision: https://reviews.llvm.org/D114311
This commit is contained in:
parent
9e647806f3
commit
7da4ee6f23
|
@ -349,14 +349,6 @@ struct _LIBCPP_TEMPLATE_VIS allocator_traits
|
|||
}
|
||||
};
|
||||
|
||||
// A version of `allocator_traits` for internal usage that SFINAEs away if the
|
||||
// given allocator doesn't have a nested `value_type`. This helps avoid hard
|
||||
// errors when forming implicit deduction guides for a container that has an
|
||||
// invalid Allocator type. See https://wg21.link/LWGXXXXX.
|
||||
// TODO(varconst): use the actual link once available.
|
||||
template <class _Alloc, class _ValueType = typename _Alloc::value_type>
|
||||
struct _LIBCPP_TEMPLATE_VIS __allocator_traits : allocator_traits<_Alloc> {};
|
||||
|
||||
template <class _Traits, class _Tp>
|
||||
struct __rebind_alloc_helper {
|
||||
#ifndef _LIBCPP_CXX03_LANG
|
||||
|
|
|
@ -1266,7 +1266,7 @@ public:
|
|||
typedef typename __base::const_reference const_reference;
|
||||
typedef typename __base::iterator iterator;
|
||||
typedef typename __base::const_iterator const_iterator;
|
||||
typedef typename __allocator_traits<allocator_type>::size_type size_type;
|
||||
typedef typename __base::size_type size_type;
|
||||
typedef typename __base::difference_type difference_type;
|
||||
|
||||
typedef typename __base::pointer pointer;
|
||||
|
@ -1289,7 +1289,14 @@ public:
|
|||
explicit deque(size_type __n, const _Allocator& __a);
|
||||
#endif
|
||||
deque(size_type __n, const value_type& __v);
|
||||
deque(size_type __n, const value_type& __v, const allocator_type& __a);
|
||||
|
||||
template <class = __enable_if_t<__is_allocator<_Allocator>::value> >
|
||||
deque(size_type __n, const value_type& __v, const allocator_type& __a) : __base(__a)
|
||||
{
|
||||
if (__n > 0)
|
||||
__append(__n, __v);
|
||||
}
|
||||
|
||||
template <class _InputIter>
|
||||
deque(_InputIter __f, _InputIter __l,
|
||||
typename enable_if<__is_cpp17_input_iterator<_InputIter>::value>::type* = 0);
|
||||
|
@ -1608,14 +1615,6 @@ deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v)
|
|||
__append(__n, __v);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Allocator>
|
||||
deque<_Tp, _Allocator>::deque(size_type __n, const value_type& __v, const allocator_type& __a)
|
||||
: __base(__a)
|
||||
{
|
||||
if (__n > 0)
|
||||
__append(__n, __v);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Allocator>
|
||||
template <class _InputIter>
|
||||
deque<_Tp, _Allocator>::deque(_InputIter __f, _InputIter __l,
|
||||
|
|
|
@ -186,6 +186,7 @@ template <class T, class Allocator, class Predicate>
|
|||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <version>
|
||||
|
||||
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
|
||||
|
@ -647,7 +648,7 @@ public:
|
|||
typedef const value_type& const_reference;
|
||||
typedef typename allocator_traits<allocator_type>::pointer pointer;
|
||||
typedef typename allocator_traits<allocator_type>::const_pointer const_pointer;
|
||||
typedef typename __allocator_traits<allocator_type>::size_type size_type;
|
||||
typedef typename allocator_traits<allocator_type>::size_type size_type;
|
||||
typedef typename allocator_traits<allocator_type>::difference_type difference_type;
|
||||
|
||||
typedef typename base::iterator iterator;
|
||||
|
@ -669,7 +670,13 @@ public:
|
|||
explicit forward_list(size_type __n, const allocator_type& __a);
|
||||
#endif
|
||||
forward_list(size_type __n, const value_type& __v);
|
||||
forward_list(size_type __n, const value_type& __v, const allocator_type& __a);
|
||||
|
||||
template <class = __enable_if_t<__is_allocator<_Alloc>::value> >
|
||||
forward_list(size_type __n, const value_type& __v, const allocator_type& __a) : base(__a)
|
||||
{
|
||||
insert_after(cbefore_begin(), __n, __v);
|
||||
}
|
||||
|
||||
template <class _InputIterator>
|
||||
forward_list(_InputIterator __f, _InputIterator __l,
|
||||
typename enable_if<
|
||||
|
@ -943,14 +950,6 @@ forward_list<_Tp, _Alloc>::forward_list(size_type __n, const value_type& __v)
|
|||
insert_after(cbefore_begin(), __n, __v);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
forward_list<_Tp, _Alloc>::forward_list(size_type __n, const value_type& __v,
|
||||
const allocator_type& __a)
|
||||
: base(__a)
|
||||
{
|
||||
insert_after(cbefore_begin(), __n, __v);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
template <class _InputIterator>
|
||||
forward_list<_Tp, _Alloc>::forward_list(_InputIterator __f, _InputIterator __l,
|
||||
|
|
|
@ -853,7 +853,7 @@ public:
|
|||
typedef const value_type& const_reference;
|
||||
typedef typename base::pointer pointer;
|
||||
typedef typename base::const_pointer const_pointer;
|
||||
typedef typename __allocator_traits<allocator_type>::size_type size_type;
|
||||
typedef typename base::size_type size_type;
|
||||
typedef typename base::difference_type difference_type;
|
||||
typedef typename base::iterator iterator;
|
||||
typedef typename base::const_iterator const_iterator;
|
||||
|
@ -885,7 +885,16 @@ public:
|
|||
explicit list(size_type __n, const allocator_type& __a);
|
||||
#endif
|
||||
list(size_type __n, const value_type& __x);
|
||||
list(size_type __n, const value_type& __x, const allocator_type& __a);
|
||||
template <class = __enable_if_t<__is_allocator<_Alloc>::value> >
|
||||
list(size_type __n, const value_type& __x, const allocator_type& __a) : base(__a)
|
||||
{
|
||||
#if _LIBCPP_DEBUG_LEVEL == 2
|
||||
__get_db()->__insert_c(this);
|
||||
#endif
|
||||
for (; __n > 0; --__n)
|
||||
push_back(__x);
|
||||
}
|
||||
|
||||
template <class _InpIter>
|
||||
list(_InpIter __f, _InpIter __l,
|
||||
typename enable_if<__is_cpp17_input_iterator<_InpIter>::value>::type* = 0);
|
||||
|
@ -1241,17 +1250,6 @@ list<_Tp, _Alloc>::list(size_type __n, const value_type& __x)
|
|||
push_back(__x);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
list<_Tp, _Alloc>::list(size_type __n, const value_type& __x, const allocator_type& __a)
|
||||
: base(__a)
|
||||
{
|
||||
#if _LIBCPP_DEBUG_LEVEL == 2
|
||||
__get_db()->__insert_c(this);
|
||||
#endif
|
||||
for (; __n > 0; --__n)
|
||||
push_back(__x);
|
||||
}
|
||||
|
||||
template <class _Tp, class _Alloc>
|
||||
template <class _InpIter>
|
||||
list<_Tp, _Alloc>::list(_InpIter __f, _InpIter __l,
|
||||
|
|
|
@ -359,7 +359,7 @@ public:
|
|||
typedef allocator_traits<allocator_type> __alloc_traits;
|
||||
typedef value_type& reference;
|
||||
typedef const value_type& const_reference;
|
||||
typedef typename __allocator_traits<allocator_type>::size_type size_type;
|
||||
typedef typename __alloc_traits::size_type size_type;
|
||||
typedef typename __alloc_traits::difference_type difference_type;
|
||||
typedef typename __alloc_traits::pointer pointer;
|
||||
typedef typename __alloc_traits::const_pointer const_pointer;
|
||||
|
@ -395,7 +395,21 @@ public:
|
|||
explicit vector(size_type __n, const allocator_type& __a);
|
||||
#endif
|
||||
vector(size_type __n, const value_type& __x);
|
||||
vector(size_type __n, const value_type& __x, const allocator_type& __a);
|
||||
|
||||
template <class = __enable_if_t<__is_allocator<_Allocator>::value> >
|
||||
vector(size_type __n, const value_type& __x, const allocator_type& __a)
|
||||
: __base(__a)
|
||||
{
|
||||
#if _LIBCPP_DEBUG_LEVEL == 2
|
||||
__get_db()->__insert_c(this);
|
||||
#endif
|
||||
if (__n > 0)
|
||||
{
|
||||
__vallocate(__n);
|
||||
__construct_at_end(__n, __x);
|
||||
}
|
||||
}
|
||||
|
||||
template <class _InputIterator>
|
||||
vector(_InputIterator __first,
|
||||
typename enable_if<__is_cpp17_input_iterator <_InputIterator>::value &&
|
||||
|
@ -1126,20 +1140,6 @@ vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x)
|
|||
}
|
||||
}
|
||||
|
||||
template <class _Tp, class _Allocator>
|
||||
vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x, const allocator_type& __a)
|
||||
: __base(__a)
|
||||
{
|
||||
#if _LIBCPP_DEBUG_LEVEL == 2
|
||||
__get_db()->__insert_c(this);
|
||||
#endif
|
||||
if (__n > 0)
|
||||
{
|
||||
__vallocate(__n);
|
||||
__construct_at_end(__n, __x);
|
||||
}
|
||||
}
|
||||
|
||||
template <class _Tp, class _Allocator>
|
||||
template <class _InputIterator>
|
||||
vector<_Tp, _Allocator>::vector(_InputIterator __first,
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -25,6 +25,7 @@ struct some_alloc
|
|||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
~some_alloc() noexcept(false);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -34,6 +34,7 @@ struct some_alloc
|
|||
|
||||
some_alloc() {}
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::true_type propagate_on_container_swap;
|
||||
|
@ -46,6 +47,7 @@ struct some_alloc2
|
|||
|
||||
some_alloc2() {}
|
||||
some_alloc2(const some_alloc2&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_swap;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -25,6 +25,7 @@ struct some_alloc
|
|||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
~some_alloc() noexcept(false);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -35,6 +35,7 @@ struct some_alloc
|
|||
|
||||
some_alloc() {}
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::true_type propagate_on_container_swap;
|
||||
|
@ -47,6 +48,7 @@ struct some_alloc2
|
|||
|
||||
some_alloc2() {}
|
||||
some_alloc2(const some_alloc2&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_swap;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -25,6 +25,7 @@ struct some_alloc
|
|||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
~some_alloc() noexcept(false);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -34,6 +34,7 @@ struct some_alloc
|
|||
|
||||
some_alloc() {}
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::true_type propagate_on_container_swap;
|
||||
|
@ -46,6 +47,7 @@ struct some_alloc2
|
|||
|
||||
some_alloc2() {}
|
||||
some_alloc2(const some_alloc2&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_swap;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -25,6 +25,7 @@ struct some_alloc
|
|||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
~some_alloc() noexcept(false);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -29,6 +29,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
@ -38,6 +39,7 @@ struct some_alloc2
|
|||
|
||||
some_alloc2() {}
|
||||
some_alloc2(const some_alloc2&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_move_assignment;
|
||||
|
@ -51,6 +53,7 @@ struct some_alloc3
|
|||
|
||||
some_alloc3() {}
|
||||
some_alloc3(const some_alloc3&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_move_assignment;
|
||||
|
|
|
@ -27,6 +27,7 @@ struct some_alloc
|
|||
{
|
||||
typedef T value_type;
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
};
|
||||
|
||||
int main(int, char**)
|
||||
|
|
|
@ -35,6 +35,7 @@ struct some_alloc
|
|||
|
||||
some_alloc() {}
|
||||
some_alloc(const some_alloc&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::true_type propagate_on_container_swap;
|
||||
|
@ -47,6 +48,7 @@ struct some_alloc2
|
|||
|
||||
some_alloc2() {}
|
||||
some_alloc2(const some_alloc2&);
|
||||
void allocate(size_t);
|
||||
void deallocate(void*, unsigned) {}
|
||||
|
||||
typedef std::false_type propagate_on_container_swap;
|
||||
|
|
Loading…
Reference in New Issue