diff --git a/libcxx/include/__memory/allocator_traits.h b/libcxx/include/__memory/allocator_traits.h --- a/libcxx/include/__memory/allocator_traits.h +++ b/libcxx/include/__memory/allocator_traits.h @@ -367,34 +367,34 @@ template struct __is_default_allocator > : true_type { }; -// __is_cpp17_move_insertable -template -struct __is_cpp17_move_insertable - : is_move_constructible -{ }; +template +decltype(allocator_traits<_Alloc>::construct(std::declval<_Alloc&>(), + std::declval::value_type*>(), + std::declval<_Args>()...), + true_type()) +__alloc_traits_has_construct_impl(int); + +template +false_type __alloc_traits_has_construct_impl(...); + +template +struct __alloc_traits_has_construct + : _If<__is_default_allocator<_Alloc>::value, + is_constructible::value_type, _Args...>, + decltype(__alloc_traits_has_construct_impl<_Alloc, _Args...>(0))> {}; template -struct __is_cpp17_move_insertable<_Alloc, __enable_if_t< - !__is_default_allocator<_Alloc>::value && - __has_construct<_Alloc, typename _Alloc::value_type*, typename _Alloc::value_type&&>::value -> > : true_type { }; +struct __is_cpp17_default_insertable : __alloc_traits_has_construct<_Alloc> {}; -// __is_cpp17_copy_insertable template -struct __is_cpp17_copy_insertable - : integral_constant::value && - __is_cpp17_move_insertable<_Alloc>::value - > -{ }; +struct __is_cpp17_move_insertable + : __alloc_traits_has_construct<_Alloc, typename allocator_traits<_Alloc>::value_type&&> {}; -template -struct __is_cpp17_copy_insertable<_Alloc, __enable_if_t< - !__is_default_allocator<_Alloc>::value && - __has_construct<_Alloc, typename _Alloc::value_type*, const typename _Alloc::value_type&>::value -> > - : __is_cpp17_move_insertable<_Alloc> -{ }; +template +struct __is_cpp17_copy_insertable + : _And<__is_cpp17_move_insertable<_Alloc>, + __alloc_traits_has_construct<_Alloc, typename allocator_traits<_Alloc>::value_type&>, + __alloc_traits_has_construct<_Alloc, const typename allocator_traits<_Alloc>::value_type&> > {}; #undef _LIBCPP_ALLOCATOR_TRAITS_HAS_XXX diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -386,6 +386,7 @@ vector(size_type __n, const value_type& __x, const allocator_type& __a) : __end_cap_(nullptr, __a) { + static_assert(__is_cpp17_copy_insertable<_Allocator>::value, "value_type has to be Cpp17CopyInserable"); std::__debug_db_insert_c(this); if (__n > 0) { @@ -1075,6 +1076,7 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17 vector<_Tp, _Allocator>::vector(size_type __n) { + static_assert(__is_cpp17_default_insertable<_Allocator>::value, "value_type has to be Cpp17DefaultInsertable"); std::__debug_db_insert_c(this); if (__n > 0) { @@ -1089,6 +1091,7 @@ vector<_Tp, _Allocator>::vector(size_type __n, const allocator_type& __a) : __end_cap_(nullptr, __a) { + static_assert(__is_cpp17_default_insertable<_Allocator>::value, "value_type has to be Cpp17DefaultInsertable"); std::__debug_db_insert_c(this); if (__n > 0) { @@ -1102,6 +1105,7 @@ _LIBCPP_CONSTEXPR_AFTER_CXX17 vector<_Tp, _Allocator>::vector(size_type __n, const value_type& __x) { + static_assert(__is_cpp17_copy_insertable<_Allocator>::value, "value_type has to be Cpp17CopyInserable"); std::__debug_db_insert_c(this); if (__n > 0) { @@ -1492,6 +1496,7 @@ void vector<_Tp, _Allocator>::reserve(size_type __n) { + static_assert(__is_cpp17_move_insertable<_Allocator>::value, "value_type has to be Cpp17MoveInserable"); if (__n > capacity()) { if (__n > max_size()) @@ -1507,6 +1512,7 @@ void vector<_Tp, _Allocator>::shrink_to_fit() _NOEXCEPT { + static_assert(__is_cpp17_move_insertable<_Allocator>::value, "value_type has to be Cpp17MoveInserable"); if (capacity() > size()) { #ifndef _LIBCPP_NO_EXCEPTIONS @@ -1913,6 +1919,8 @@ void vector<_Tp, _Allocator>::resize(size_type __sz) { + static_assert(__is_cpp17_move_insertable<_Allocator>::value, "value_type has to be Cpp17MoveInserable"); + static_assert(__is_cpp17_default_insertable<_Allocator>::value, "value_type has to be Cpp17DefaultInsertable"); size_type __cs = size(); if (__cs < __sz) this->__append(__sz - __cs); @@ -1925,6 +1933,7 @@ void vector<_Tp, _Allocator>::resize(size_type __sz, const_reference __x) { + static_assert(__is_cpp17_copy_insertable<_Allocator>::value, "value_type has to be Cpp17CopyInserable"); size_type __cs = size(); if (__cs < __sz) this->__append(__sz - __cs, __x); diff --git a/libcxx/test/libcxx/containers/sequences/vector/preconditions.verify.cpp b/libcxx/test/libcxx/containers/sequences/vector/preconditions.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/vector/preconditions.verify.cpp @@ -0,0 +1,59 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// ensure that preconditions are checked + +#include + +struct NotDefaultInsertable { + NotDefaultInsertable(int); +}; + +struct NotMoveInsertable { + NotMoveInsertable(NotMoveInsertable&&) = delete; +}; + +struct NotCopyInsertable { + NotCopyInsertable(int); + NotCopyInsertable(NotCopyInsertable&&); +}; + +int main() { + // expected-error@* {{failed due to requirement}} + // expected-error@* {{no matching function for call to}} + std::vector v1(10); + + // expected-error@* {{failed due to requirement}} + std::vector v2(10, std::allocator()); + + // expected-error@* {{failed due to requirement}} + // expected-error@* {{no matching function for call to}} + std::vector v3( + 10, NotCopyInsertable(1), std::allocator()); + + std::vector v4; + + // expected-error@* {{failed due to requirement}} + // expected-error@* {{failed due to requirement}} + // expected-error@* {{no matching function for call to}} + v4.reserve(1); + // expected-error@* {{failed due to requirement}} + v4.shrink_to_fit(); + // expected-error@* {{failed due to requirement}} + // expected-error@* {{failed due to requirement}} + // expected-error@* {{no matching function for call to}} + v4.resize(1); + + std::vector v5; + // expected-error@* {{failed due to requirement}} + v5.resize(1); + + std::vector v6; + // expected-error@* {{failed due to requirement}} + v6.resize(1, NotCopyInsertable(1)); +}