diff --git a/include/etl/memory.h b/include/etl/memory.h index f923a6ce..742766c5 100644 --- a/include/etl/memory.h +++ b/include/etl/memory.h @@ -53,6 +53,44 @@ SOFTWARE. namespace etl { + namespace private_memory + { + //************************************************************************* + /// Checks whether a type can be copied to uninitialised storage by using + /// assignment instead of placement new. + //************************************************************************* + template + struct is_trivially_copy_assignable_to_uninitialised_storage + : etl::bool_constant::value && etl::is_trivially_copy_constructible::value + && etl::is_trivially_copy_assignable::value> + { + }; + +#if ETL_USING_CPP11 + //************************************************************************* + /// Checks whether a type can be moved to uninitialised storage by using + /// assignment instead of placement new. + //************************************************************************* + template + struct is_trivially_move_assignable_to_uninitialised_storage + : etl::bool_constant::value && etl::is_trivially_move_constructible::value + && etl::is_trivially_move_assignable::value> + { + }; +#endif + + //************************************************************************* + /// Checks whether a value-initialised type can be copied to uninitialised + /// storage by using assignment instead of placement new. + //************************************************************************* + template + struct is_trivially_value_assignable_to_uninitialised_storage + : etl::bool_constant::value && etl::is_trivially_copyable::value + && etl::is_trivially_copy_assignable::value> + { + }; + } // namespace private_memory + //***************************************************************************** /// Obtain the address represented by p without forming a reference to the /// object pointed to by p. Defined when not using the STL or C++20 @@ -428,7 +466,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value) { etl::fill(o_begin, o_end, value); @@ -442,8 +482,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value) { typedef typename etl::iterator_traits::value_type value_type; @@ -464,7 +505,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count) { count += static_cast(etl::distance(o_begin, o_end)); @@ -481,8 +524,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_fill(TOutputIterator o_begin, TOutputIterator o_end, const T& value, TCounter& count) { count += static_cast(etl::distance(o_begin, o_end)); @@ -577,7 +621,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { return etl::copy(i_begin, i_end, o_begin); @@ -589,8 +635,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { typedef typename etl::iterator_traits::value_type value_type; @@ -614,7 +661,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::copy(i_begin, i_end, o_begin); @@ -630,8 +679,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_copy_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_copy(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::uninitialized_copy(i_begin, i_end, o_begin); @@ -910,7 +960,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { return etl::move(i_begin, i_end, o_begin); @@ -922,8 +974,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin) { typedef typename etl::iterator_traits::value_type value_type; @@ -947,7 +1000,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::move(i_begin, i_end, o_begin); @@ -963,8 +1018,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move(TInputIterator i_begin, TInputIterator i_end, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::uninitialized_move(i_begin, i_end, o_begin); @@ -1037,7 +1093,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin) { return etl::move(i_begin, i_begin + n, o_begin); @@ -1049,8 +1107,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin) { typedef typename etl::iterator_traits::value_type value_type; @@ -1074,7 +1133,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, TOutputIterator>::type + typename etl::enable_if< + etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::move(i_begin, i_begin + n, o_begin); @@ -1090,8 +1151,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, - TOutputIterator>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_move_assignable_to_uninitialised_storage::value_type>::value, + TOutputIterator>::type uninitialized_move_n(TInputIterator i_begin, TSize n, TOutputIterator o_begin, TCounter& count) { TOutputIterator o_end = etl::uninitialized_move(i_begin, i_begin + n, o_begin); @@ -1527,7 +1589,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, void>::type + typename etl::enable_if< + etl::private_memory::is_trivially_value_assignable_to_uninitialised_storage::value_type>::value, + void>::type uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) { typedef typename etl::iterator_traits::value_type value_type; @@ -1541,7 +1605,9 @@ namespace etl ///\ingroup memory //***************************************************************************** template - typename etl::enable_if< !etl::is_trivially_constructible< typename etl::iterator_traits::value_type>::value, void>::type + typename etl::enable_if< + !etl::private_memory::is_trivially_value_assignable_to_uninitialised_storage::value_type>::value, + void>::type uninitialized_value_construct(TOutputIterator o_begin, TOutputIterator o_end) { typedef typename etl::iterator_traits::value_type value_type; diff --git a/include/etl/profiles/determine_builtin_support.h b/include/etl/profiles/determine_builtin_support.h index ad681fb5..994cbadf 100644 --- a/include/etl/profiles/determine_builtin_support.h +++ b/include/etl/profiles/determine_builtin_support.h @@ -53,6 +53,10 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE 1 #endif + #if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR) + #define ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR 1 + #endif + #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE) #define ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE 1 #endif @@ -61,6 +65,10 @@ SOFTWARE. #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE 1 #endif + #if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR 1 + #endif + #if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE) #define ETL_USING_BUILTIN_IS_DESTRUCTIBLE 1 #endif @@ -177,7 +185,14 @@ SOFTWARE. #endif #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE) - #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE (__has_builtin(__has_trivial_constructor) || __has_builtin(__is_trivially_constructible)) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE __has_builtin(__is_trivially_constructible) + #endif + + // The legacy __has_trivial_constructor builtin. Deprecated by GCC 12 and + // removed by GCC 15, so it must be detected separately from the standard + // __is_trivially_constructible builtin. + #if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR) + #define ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR __has_builtin(__has_trivial_constructor) #endif #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_ASSIGNABLE) @@ -185,7 +200,14 @@ SOFTWARE. #endif #if !defined(ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE) - #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE (__has_builtin(__has_trivial_destructor) || __has_builtin(__is_trivially_destructible)) + #define ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE __has_builtin(__is_trivially_destructible) + #endif + + // The legacy __has_trivial_destructor builtin. Deprecated by GCC 12 and + // removed by GCC 15, so it must be detected separately from the standard + // __is_trivially_destructible builtin. + #if !defined(ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR) + #define ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR __has_builtin(__has_trivial_destructor) #endif #if !defined(ETL_USING_BUILTIN_IS_DESTRUCTIBLE) diff --git a/include/etl/type_traits.h b/include/etl/type_traits.h index ea9823a7..b01b308f 100644 --- a/include/etl/type_traits.h +++ b/include/etl/type_traits.h @@ -4193,8 +4193,9 @@ namespace etl }; #if ETL_USING_CPP11 - //*************************************************************************** - /// is_constructible + //*************************************************************************** + /// is_constructible + #if !ETL_USING_BUILTIN_IS_CONSTRUCTIBLE namespace private_type_traits { template @@ -4207,11 +4208,19 @@ namespace etl { }; } // namespace private_type_traits + #endif - //********************************************* - // is_constructible + //********************************************* + // is_constructible + #if ETL_USING_BUILTIN_IS_CONSTRUCTIBLE + template + struct is_constructible : public etl::bool_constant<__is_constructible(T, TArgs...)> + { + }; + #else template using is_constructible = private_type_traits::is_constructible_, T, TArgs...>; + #endif //********************************************* // is_copy_constructible @@ -4304,49 +4313,79 @@ namespace etl //********************************************* // is_nothrow_constructible template + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + struct is_nothrow_constructible : public etl::bool_constant<__is_nothrow_constructible(T, TArgs...)> + #else struct is_nothrow_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_default_constructible template + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + struct is_nothrow_default_constructible : public etl::is_nothrow_constructible + #else struct is_nothrow_default_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_copy_constructible template + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + struct is_nothrow_copy_constructible : public etl::is_nothrow_constructible::type> + #else struct is_nothrow_copy_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_move_constructible template + #if ETL_USING_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE + struct is_nothrow_move_constructible : public etl::is_nothrow_constructible::type> + #else struct is_nothrow_move_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_assignable template + #if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE + struct is_nothrow_assignable : public etl::bool_constant<__is_nothrow_assignable(T, U)> + #else struct is_nothrow_assignable : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_copy_assignable template + #if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE + struct is_nothrow_copy_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_lvalue_reference::type> + #else struct is_nothrow_copy_assignable : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_nothrow_move_assignable template + #if ETL_USING_BUILTIN_IS_NOTHROW_ASSIGNABLE + struct is_nothrow_move_assignable + : public etl::is_nothrow_assignable::type, typename etl::add_rvalue_reference::type> + #else struct is_nothrow_move_assignable : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; #endif @@ -4354,35 +4393,68 @@ namespace etl //********************************************* // is_trivially_constructible template + #if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE + struct is_trivially_constructible : public etl::bool_constant<__is_trivially_constructible(T)> + #elif ETL_USING_CPP11 && ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR + struct is_trivially_constructible : public etl::bool_constant<__has_trivial_constructor(T) && etl::is_constructible::value> + #else struct is_trivially_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_trivially_copy_constructible template + #if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE + struct is_trivially_copy_constructible + : public etl::bool_constant<__is_trivially_constructible(T, typename etl::add_lvalue_reference::type)> + #elif ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE + // A trivially copyable type may still have a deleted copy constructor, so the + // copy constructor must be checked for as well. + struct is_trivially_copy_constructible : public etl::bool_constant<__is_trivially_copyable(T) && etl::is_copy_constructible::value> + #else struct is_trivially_copy_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_trivially_default_constructible template + #if ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE || ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR + struct is_trivially_default_constructible : public etl::is_trivially_constructible + #else struct is_trivially_default_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_trivially_move_constructible template + #if ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE + struct is_trivially_move_constructible : public etl::bool_constant<__is_trivially_constructible(T, typename etl::add_rvalue_reference::type)> + #elif ETL_USING_CPP11 && ETL_USING_BUILTIN_IS_TRIVIALLY_COPYABLE + // A trivially copyable type may still have a deleted move constructor, so the + // move constructor must be checked for as well. + struct is_trivially_move_constructible : public etl::bool_constant<__is_trivially_copyable(T) && etl::is_move_constructible::value> + #else struct is_trivially_move_constructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; //********************************************* // is_trivially_destructible template + #if ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE + struct is_trivially_destructible : public etl::bool_constant<__is_trivially_destructible(T)> + #elif ETL_USING_CPP11 && ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR + struct is_trivially_destructible : public etl::bool_constant<__has_trivial_destructor(T) && etl::is_destructible::value> + #else struct is_trivially_destructible : public etl::bool_constant::value || etl::is_pointer::value> + #endif { }; diff --git a/test/test_memory.cpp b/test/test_memory.cpp index 70f03493..a8fda0fa 100644 --- a/test/test_memory.cpp +++ b/test/test_memory.cpp @@ -138,6 +138,33 @@ namespace } }; +#if ETL_USING_CPP11 + // A trivially copyable type that can be copy constructed but not copy + // assigned. It must use the placement-new uninitialized algorithm path. + struct CopyConstructOnly + { + int value; + + CopyConstructOnly() = default; + + CopyConstructOnly(const CopyConstructOnly&) = default; + CopyConstructOnly& operator=(const CopyConstructOnly&) = delete; + }; + + // A trivially copyable type that can be move constructed but not move + // assigned. It must use the placement-new uninitialized algorithm path. + struct MoveConstructOnly + { + int value; + + MoveConstructOnly() = default; + + MoveConstructOnly(const MoveConstructOnly&) = delete; + MoveConstructOnly(MoveConstructOnly&&) = default; + MoveConstructOnly& operator=(MoveConstructOnly&&) = delete; + }; +#endif + //*********************************** template struct NoDelete @@ -546,6 +573,59 @@ namespace CHECK_EQUAL(0U, count); } +#if ETL_USING_CPP11 + //************************************************************************* + TEST(test_uninitialized_algorithms_use_construction_when_assignment_is_deleted) + { + CopyConstructOnly copy_source[2]; + copy_source[0].value = 1; + copy_source[1].value = 2; + + alignas(CopyConstructOnly) unsigned char copy_storage[sizeof(CopyConstructOnly) * 2U]; + CopyConstructOnly* copy_destination = reinterpret_cast(copy_storage); + + etl::uninitialized_copy(copy_source, copy_source + 2, copy_destination); + CHECK_EQUAL(1, copy_destination[0].value); + CHECK_EQUAL(2, copy_destination[1].value); + + alignas(CopyConstructOnly) unsigned char fill_storage[sizeof(CopyConstructOnly) * 2U]; + CopyConstructOnly* fill_destination = reinterpret_cast(fill_storage); + + etl::uninitialized_fill(fill_destination, fill_destination + 2, copy_source[0]); + CHECK_EQUAL(1, fill_destination[0].value); + CHECK_EQUAL(1, fill_destination[1].value); + + alignas(CopyConstructOnly) unsigned char value_storage[sizeof(CopyConstructOnly) * 2U]; + CopyConstructOnly* value_destination = reinterpret_cast(value_storage); + + etl::uninitialized_value_construct(value_destination, value_destination + 2); + CHECK_EQUAL(0, value_destination[0].value); + CHECK_EQUAL(0, value_destination[1].value); + + MoveConstructOnly move_source[2]; + move_source[0].value = 3; + move_source[1].value = 4; + + alignas(MoveConstructOnly) unsigned char move_storage[sizeof(MoveConstructOnly) * 2U]; + MoveConstructOnly* move_destination = reinterpret_cast(move_storage); + + etl::uninitialized_move(move_source, move_source + 2, move_destination); + CHECK_EQUAL(3, move_destination[0].value); + CHECK_EQUAL(4, move_destination[1].value); + + MoveConstructOnly move_n_source[2]; + move_n_source[0].value = 5; + move_n_source[1].value = 6; + + alignas(MoveConstructOnly) unsigned char move_n_storage[sizeof(MoveConstructOnly) * 2U]; + MoveConstructOnly* move_n_destination = reinterpret_cast(move_n_storage); + + etl::uninitialized_move_n(move_n_source, 2U, move_n_destination); + CHECK_EQUAL(5, move_n_destination[0].value); + CHECK_EQUAL(6, move_n_destination[1].value); + } +#endif + //************************************************************************* TEST(test_uninitialized_default_construct_n_trivial) { diff --git a/test/test_type_traits.cpp b/test/test_type_traits.cpp index 0c031435..844b3511 100644 --- a/test/test_type_traits.cpp +++ b/test/test_type_traits.cpp @@ -150,6 +150,29 @@ namespace NotDefaultConstructible& operator=(NotDefaultConstructible&&) = delete; }; + // The legacy compiler builtin for trivial construction does not test + // accessibility, unlike is_trivially_constructible. + struct PrivateTrivialDefaultConstructor + { + private: + + PrivateTrivialDefaultConstructor() = default; + }; + + // The legacy compiler builtin for trivial destruction does not test + // accessibility or deletion, unlike is_trivially_destructible. + struct PrivateTrivialDestructor + { + private: + + ~PrivateTrivialDestructor() = default; + }; + + struct DeletedTrivialDestructor + { + ~DeletedTrivialDestructor() = delete; + }; + // A function to test etl::type_identity. template T type_identity_test_add(T first, typename etl::type_identity::type second) @@ -2851,7 +2874,8 @@ namespace //************************************************************************* TEST(test_is_trivially_constructible) { -#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) +#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) || ETL_USING_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE \ + || ETL_USING_BUILTIN_HAS_TRIVIAL_CONSTRUCTOR #if ETL_USING_CPP17 CHECK((etl::is_trivially_constructible_v) == (std::is_trivially_constructible_v)); CHECK((etl::is_trivially_constructible_v) == (std::is_trivially_constructible_v)); @@ -2861,6 +2885,11 @@ namespace CHECK((etl::is_trivially_constructible::value) == (std::is_trivially_constructible::value)); CHECK((etl::is_trivially_constructible::value) == (std::is_trivially_constructible::value)); #endif + #if ETL_USING_CPP11 + CHECK(!etl::is_trivially_constructible::value); + CHECK((etl::is_trivially_constructible::value) + == (std::is_trivially_constructible::value)); + #endif #endif } @@ -2919,7 +2948,8 @@ namespace //************************************************************************* TEST(test_is_trivially_destructible) { -#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) +#if ETL_USING_STL || defined(ETL_USE_TYPE_TRAITS_BUILTINS) || defined(ETL_USER_DEFINED_TYPE_TRAITS) || ETL_USING_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE \ + || ETL_USING_BUILTIN_HAS_TRIVIAL_DESTRUCTOR #if ETL_USING_CPP17 CHECK((etl::is_trivially_destructible_v) == (std::is_trivially_destructible_v)); CHECK((etl::is_trivially_destructible_v) == (std::is_trivially_destructible_v)); @@ -2929,6 +2959,12 @@ namespace CHECK((etl::is_trivially_destructible::value) == (std::is_trivially_destructible::value)); CHECK((etl::is_trivially_destructible::value) == (std::is_trivially_destructible::value)); #endif + #if ETL_USING_CPP11 + CHECK(!etl::is_trivially_destructible::value); + CHECK(!etl::is_trivially_destructible::value); + CHECK((etl::is_trivially_destructible::value) == (std::is_trivially_destructible::value)); + CHECK((etl::is_trivially_destructible::value) == (std::is_trivially_destructible::value)); + #endif #endif }