From ed5219283b0ceafae9e3d3634ced915a4de50e3e Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Wed, 2 Sep 2026 09:58:40 +0200 Subject: [PATCH] Detect builtins (#1581) Even without ETL_USE_TYPE_TRAITS_BUILTINS in the profile, we get compiler builtins detected. Makes detection more consistent now. Previously, some type trait builtins were detected automatically, and some others needed to be activated via ETL_USE_TYPE_TRAITS_BUILTINS in the profile explicitly. Replaces: #1174 Co-authored-by: John Wellbelove --- include/etl/memory.h | 118 ++++++++++++++---- .../etl/profiles/determine_builtin_support.h | 26 +++- include/etl/type_traits.h | 80 +++++++++++- test/test_memory.cpp | 80 ++++++++++++ test/test_type_traits.cpp | 40 +++++- 5 files changed, 310 insertions(+), 34 deletions(-) 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 }