From 13bda46cb6d546ae650d96d162fe1178453632c1 Mon Sep 17 00:00:00 2001 From: tx_haggis <13982343+adbancroft@users.noreply.github.com> Date: Mon, 6 May 2024 17:36:25 -0500 Subject: [PATCH 1/3] Type traits: fix compilation with avr-gcc 7x --- include/type_traits | 301 +++++++++++++++++++++++++++++++++++++++++++- include/utility | 60 +++++++++ 2 files changed, 360 insertions(+), 1 deletion(-) diff --git a/include/type_traits b/include/type_traits index d551a99..c31d679 100644 --- a/include/type_traits +++ b/include/type_traits @@ -896,11 +896,257 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if __GNUC__ >= 8 template struct __is_constructible_impl : public __bool_constant<__is_constructible(_Tp, _Args...)> + { }; +#else + // Implementation of __is_constructible_impl. + + struct __do_is_default_constructible_impl + { + template + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_default_constructible_impl + : public __do_is_default_constructible_impl + { + typedef decltype(__test<_Tp>(0)) type; + }; + + template + struct __is_default_constructible_atom + : public __and_<__not_>, + __is_default_constructible_impl<_Tp>>::type + { }; + + template::value> + struct __is_default_constructible_safe; + + // The following technique is a workaround for a current core language + // restriction, which does not allow for array types to occur in + // functional casts of the form T(). Complete arrays can be default- + // constructed, if the element type is default-constructible, but + // arrays with unknown bounds are not. + template + struct __is_default_constructible_safe<_Tp, true> + : public __and_<__is_array_known_bounds<_Tp>, + __is_default_constructible_atom::type>>::type + { }; + + template + struct __is_default_constructible_safe<_Tp, false> + : public __is_default_constructible_atom<_Tp>::type + { }; + + // The hardest part of this trait is the binary direct-initialization + // case, because we hit into a functional cast of the form T(arg). + // This implementation uses different strategies depending on the + // target type to reduce the test overhead as much as possible: + // + // a) For a reference target type, we use a static_cast expression + // modulo its extra cases. + // + // b) For a non-reference target type we use a ::new expression. + struct __do_is_static_castable_impl + { + template(declval<_From>()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_static_castable_impl + : public __do_is_static_castable_impl + { + typedef decltype(__test<_From, _To>(0)) type; + }; + + template + struct __is_static_castable_safe + : public __is_static_castable_impl<_From, _To>::type + { }; + + // __is_static_castable + template + struct __is_static_castable + : public integral_constant::value)> + { }; + + // Implementation for non-reference types. To meet the proper + // variable definition semantics, we also need to test for + // is_destructible in this case. + // This form should be simplified by a single expression: + // ::delete ::new _Tp(declval<_Arg>()), see c++/51222. + struct __do_is_direct_constructible_impl + { + template()))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_direct_constructible_impl + : public __do_is_direct_constructible_impl + { + typedef decltype(__test<_Tp, _Arg>(0)) type; + }; + + template + struct __is_direct_constructible_new_safe + : public __and_, + __is_direct_constructible_impl<_Tp, _Arg>> + { }; + + template + struct is_same; + + template + struct is_base_of; + + template + struct remove_reference; + + template, + is_function<_From>>>::value> + struct __is_base_to_derived_ref; + + template + struct is_constructible; + + // Detect whether we have a downcast situation during + // reference binding. + template + struct __is_base_to_derived_ref<_From, _To, true> + { + typedef typename remove_cv::type>::type __src_t; + typedef typename remove_cv::type>::type __dst_t; + typedef __and_<__not_>, + is_base_of<__src_t, __dst_t>, + __not_>> type; + static constexpr bool value = type::value; + }; + + template + struct __is_base_to_derived_ref<_From, _To, false> + : public false_type { }; + template, + is_rvalue_reference<_To>>::value> + struct __is_lvalue_to_rvalue_ref; + + // Detect whether we have an lvalue of non-function type + // bound to a reference-compatible rvalue-reference. + template + struct __is_lvalue_to_rvalue_ref<_From, _To, true> + { + typedef typename remove_cv::type>::type __src_t; + typedef typename remove_cv::type>::type __dst_t; + typedef __and_<__not_>, + __or_, + is_base_of<__dst_t, __src_t>>> type; + static constexpr bool value = type::value; + }; + + template + struct __is_lvalue_to_rvalue_ref<_From, _To, false> + : public false_type + { }; + + // Here we handle direct-initialization to a reference type as + // equivalent to a static_cast modulo overshooting conversions. + // These are restricted to the following conversions: + // a) A base class value to a derived class reference + // b) An lvalue to an rvalue-reference of reference-compatible + // types that are not functions + template + struct __is_direct_constructible_ref_cast + : public __and_<__is_static_castable<_Arg, _Tp>, + __not_<__or_<__is_base_to_derived_ref<_Arg, _Tp>, + __is_lvalue_to_rvalue_ref<_Arg, _Tp> + >>> + { }; + + template + struct __is_direct_constructible_new + : public conditional::value, + __is_direct_constructible_ref_cast<_Tp, _Arg>, + __is_direct_constructible_new_safe<_Tp, _Arg> + >::type + { }; + + template + struct __is_direct_constructible + : public __is_direct_constructible_new<_Tp, _Arg>::type + { }; + + // Since default-construction and binary direct-initialization have + // been handled separately, the implementation of the remaining + // n-ary construction cases is rather straightforward. We can use + // here a functional cast, because array types are excluded anyway + // and this form is never interpreted as a C cast. + struct __do_is_nary_constructible_impl + { + template()...))> + static true_type __test(int); + + template + static false_type __test(...); + }; + + template + struct __is_nary_constructible_impl + : public __do_is_nary_constructible_impl + { + typedef decltype(__test<_Tp, _Args...>(0)) type; + }; + + template + struct __is_nary_constructible + : public __is_nary_constructible_impl<_Tp, _Args...>::type + { + static_assert(sizeof...(_Args) > 1, + "Only useful for > 1 arguments"); + }; + + template + struct __is_constructible_impl + : public __is_nary_constructible<_Tp, _Args...> + { }; + + template + struct __is_constructible_impl<_Tp, _Arg> + : public __is_direct_constructible<_Tp, _Arg> + { }; + + template + struct __is_constructible_impl<_Tp> + : public __is_default_constructible_safe<_Tp>::type + { }; +#endif + /// is_constructible template struct is_constructible @@ -908,7 +1154,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); - }; + }; /// is_default_constructible template @@ -998,10 +1244,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { }; #endif +#if __GNUC__ >= 8 template using __is_nothrow_constructible_impl = __is_nt_constructible_impl<__is_constructible(_Tp, _Args...), _Tp, _Args...>; +#else + template + using __is_nothrow_constructible_impl + = __is_nt_constructible_impl<__is_constructible_impl<_Tp, _Args...>::value, + _Tp, _Args...>; +#endif /// is_nothrow_constructible template @@ -1064,6 +1317,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION "template argument must be a complete class or an unbounded array"); }; +#if __GNUC__ >= 8 /// is_assignable template struct is_assignable @@ -1072,6 +1326,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); }; +#else + template + class __is_assignable_helper + { + template() = declval<_Up1>())> + static true_type + __test(int); + + template + static false_type + __test(...); + + public: + typedef decltype(__test<_Tp, _Up>(0)) type; + }; + + /// is_assignable + template + struct is_assignable + : public __is_assignable_helper<_Tp, _Up>::type + { }; +#endif template::value> struct __is_copy_assignable_impl; @@ -1080,10 +1357,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_copy_assignable_impl<_Tp, false> : public false_type { }; +#if __GNUC__ >= 8 template struct __is_copy_assignable_impl<_Tp, true> : public __bool_constant<__is_assignable(_Tp&, const _Tp&)> { }; +#else + template + struct __is_copy_assignable_impl<_Tp, true> + : public is_assignable<_Tp&, const _Tp&> + { }; +#endif /// is_copy_assignable template @@ -1101,10 +1385,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __is_move_assignable_impl<_Tp, false> : public false_type { }; +#if __GNUC__ >= 8 template struct __is_move_assignable_impl<_Tp, true> : public __bool_constant<__is_assignable(_Tp&, _Tp&&)> { }; +#else + template + struct __is_move_assignable_impl<_Tp, true> + : public is_assignable<_Tp&, _Tp&&> + { }; +#endif /// is_move_assignable template @@ -1120,11 +1411,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : public integral_constant() = declval<_Up>())> { }; +#if __GNUC__ >= 8 template struct __is_nothrow_assignable_impl : public __and_<__bool_constant<__is_assignable(_Tp, _Up)>, __is_nt_assignable_impl<_Tp, _Up>> { }; +#else + template + struct __is_nothrow_assignable_impl + : public __and_, + __is_nt_assignable_impl<_Tp, _Up>> + { }; +#endif /// is_nothrow_assignable template diff --git a/include/utility b/include/utility index 32747f8..9c8309b 100644 --- a/include/utility +++ b/include/utility @@ -297,6 +297,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // extract the elements in a tuple. template struct _Index_tuple { }; +#if __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) + #ifdef __has_builtin # if __has_builtin(__make_integer_seq) # define _GLIBCXX_USE_MAKE_INTEGER_SEQ 1 @@ -316,11 +318,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __type = _Index_tuple<__integer_pack(_Num)...>; #endif }; +#else + // Concatenates two _Index_tuples. + template struct _Itup_cat; + + template + struct _Itup_cat<_Index_tuple<_Ind1...>, _Index_tuple<_Ind2...>> + { + using __type = _Index_tuple<_Ind1..., (_Ind2 + sizeof...(_Ind1))...>; + }; + + // Builds an _Index_tuple<0, 1, 2, ..., _Num-1>. + template + struct _Build_index_tuple + : _Itup_cat::__type, + typename _Build_index_tuple<_Num - _Num / 2>::__type> + { }; + + template<> + struct _Build_index_tuple<1> + { + typedef _Index_tuple<0> __type; + }; + + template<> + struct _Build_index_tuple<0> + { + typedef _Index_tuple<> __type; + }; +#endif // __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) #if __cplusplus > 201103L #define __cpp_lib_integer_sequence 201304 +#if __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) /// Class template integer_sequence template struct integer_sequence @@ -340,6 +372,34 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #undef _GLIBCXX_USE_MAKE_INTEGER_SEQ +#else + /// Class template integer_sequence + template + struct integer_sequence + { + typedef _Tp value_type; + static constexpr size_t size() { return sizeof...(_Idx); } + }; + + template::__type> + struct _Make_integer_sequence; + + template + struct _Make_integer_sequence<_Tp, _Num, _Index_tuple<_Idx...>> + { + static_assert( _Num >= 0, + "Cannot make integer sequence of negative length" ); + + typedef integer_sequence<_Tp, static_cast<_Tp>(_Idx)...> __type; + }; + + /// Alias template make_integer_sequence + template + using make_integer_sequence + = typename _Make_integer_sequence<_Tp, _Num>::__type; +#endif // __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) + /// Alias template index_sequence template using index_sequence = integer_sequence; From f49010afa86466e52798bdd8599e930b1d87add8 Mon Sep 17 00:00:00 2001 From: tx_haggis <13982343+adbancroft@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:37:53 -0500 Subject: [PATCH 2/3] Remove accidental whitespace change --- include/type_traits | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/type_traits b/include/type_traits index c31d679..37ef423 100644 --- a/include/type_traits +++ b/include/type_traits @@ -1154,7 +1154,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}), "template argument must be a complete class or an unbounded array"); - }; + }; /// is_default_constructible template From 6a11d0697dedef039219d4fb9e0bc4293601c25b Mon Sep 17 00:00:00 2001 From: tx_haggis <13982343+adbancroft@users.noreply.github.com> Date: Tue, 4 Jun 2024 13:02:22 -0500 Subject: [PATCH 3/3] Fix conditional compilation _GLIBCXX_USE_MAKE_INTEGER_SEQ was being tested before it was set. --- include/utility | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/utility b/include/utility index 9c8309b..f7533d5 100644 --- a/include/utility +++ b/include/utility @@ -297,7 +297,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // extract the elements in a tuple. template struct _Index_tuple { }; -#if __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) +#if __GNUC__ >= 8 #ifdef __has_builtin # if __has_builtin(__make_integer_seq) @@ -318,7 +318,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION using __type = _Index_tuple<__integer_pack(_Num)...>; #endif }; -#else +#else // __GNUC__ < 8 // Concatenates two _Index_tuples. template struct _Itup_cat; @@ -346,13 +346,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typedef _Index_tuple<> __type; }; -#endif // __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) +#endif // __GNUC__ < 8 #if __cplusplus > 201103L #define __cpp_lib_integer_sequence 201304 -#if __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) +#if __GNUC__ >= 8 /// Class template integer_sequence template struct integer_sequence @@ -372,7 +372,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #undef _GLIBCXX_USE_MAKE_INTEGER_SEQ -#else +#else // __GNUC__ < 8 /// Class template integer_sequence template struct integer_sequence @@ -398,7 +398,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template using make_integer_sequence = typename _Make_integer_sequence<_Tp, _Num>::__type; -#endif // __GNUC__ >= 8 || defined(_GLIBCXX_USE_MAKE_INTEGER_SEQ) +#endif // __GNUC__ < 8 /// Alias template index_sequence template