Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix compilation with avr-gcc 7x #33

Merged
merged 3 commits into from
Aug 27, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 300 additions & 1 deletion include/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -896,19 +896,265 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
"template argument must be a complete class or an unbounded array");
};

#if __GNUC__ >= 8
template<typename _Tp, typename... _Args>
struct __is_constructible_impl
: public __bool_constant<__is_constructible(_Tp, _Args...)>
{ };
#else
// Implementation of __is_constructible_impl.

struct __do_is_default_constructible_impl
{
template<typename _Tp, typename = decltype(_Tp())>
static true_type __test(int);

template<typename>
static false_type __test(...);
};

template<typename _Tp>
struct __is_default_constructible_impl
: public __do_is_default_constructible_impl
{
typedef decltype(__test<_Tp>(0)) type;
};

template<typename _Tp>
struct __is_default_constructible_atom
: public __and_<__not_<is_void<_Tp>>,
__is_default_constructible_impl<_Tp>>::type
{ };

template<typename _Tp, bool = is_array<_Tp>::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<typename _Tp>
struct __is_default_constructible_safe<_Tp, true>
: public __and_<__is_array_known_bounds<_Tp>,
__is_default_constructible_atom<typename
remove_all_extents<_Tp>::type>>::type
{ };

template<typename _Tp>
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<typename _From, typename _To, typename
= decltype(static_cast<_To>(declval<_From>()))>
static true_type __test(int);

template<typename, typename>
static false_type __test(...);
};

template<typename _From, typename _To>
struct __is_static_castable_impl
: public __do_is_static_castable_impl
{
typedef decltype(__test<_From, _To>(0)) type;
};

template<typename _From, typename _To>
struct __is_static_castable_safe
: public __is_static_castable_impl<_From, _To>::type
{ };

// __is_static_castable
template<typename _From, typename _To>
struct __is_static_castable
: public integral_constant<bool, (__is_static_castable_safe<
_From, _To>::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<typename _Tp, typename _Arg, typename
= decltype(::new _Tp(declval<_Arg>()))>
static true_type __test(int);

template<typename, typename>
static false_type __test(...);
};

template<typename _Tp, typename _Arg>
struct __is_direct_constructible_impl
: public __do_is_direct_constructible_impl
{
typedef decltype(__test<_Tp, _Arg>(0)) type;
};

template<typename _Tp, typename _Arg>
struct __is_direct_constructible_new_safe
: public __and_<is_destructible<_Tp>,
__is_direct_constructible_impl<_Tp, _Arg>>
{ };

template<typename, typename>
struct is_same;

template<typename, typename>
struct is_base_of;

template<typename>
struct remove_reference;

template<typename _From, typename _To, bool
= __not_<__or_<is_void<_From>,
is_function<_From>>>::value>
struct __is_base_to_derived_ref;

template<typename _Tp, typename... _Args>
struct is_constructible;

// Detect whether we have a downcast situation during
// reference binding.
template<typename _From, typename _To>
struct __is_base_to_derived_ref<_From, _To, true>
{
typedef typename remove_cv<typename remove_reference<_From
>::type>::type __src_t;
typedef typename remove_cv<typename remove_reference<_To
>::type>::type __dst_t;
typedef __and_<__not_<is_same<__src_t, __dst_t>>,
is_base_of<__src_t, __dst_t>,
__not_<is_constructible<__dst_t, _From>>> type;
static constexpr bool value = type::value;
};

template<typename _From, typename _To>
struct __is_base_to_derived_ref<_From, _To, false>
: public false_type
{ };

template<typename _From, typename _To, bool
= __and_<is_lvalue_reference<_From>,
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<typename _From, typename _To>
struct __is_lvalue_to_rvalue_ref<_From, _To, true>
{
typedef typename remove_cv<typename remove_reference<
_From>::type>::type __src_t;
typedef typename remove_cv<typename remove_reference<
_To>::type>::type __dst_t;
typedef __and_<__not_<is_function<__src_t>>,
__or_<is_same<__src_t, __dst_t>,
is_base_of<__dst_t, __src_t>>> type;
static constexpr bool value = type::value;
};

template<typename _From, typename _To>
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<typename _Tp, typename _Arg>
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<typename _Tp, typename _Arg>
struct __is_direct_constructible_new
: public conditional<is_reference<_Tp>::value,
__is_direct_constructible_ref_cast<_Tp, _Arg>,
__is_direct_constructible_new_safe<_Tp, _Arg>
>::type
{ };

template<typename _Tp, typename _Arg>
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<typename _Tp, typename... _Args, typename
= decltype(_Tp(declval<_Args>()...))>
static true_type __test(int);

template<typename, typename...>
static false_type __test(...);
};

template<typename _Tp, typename... _Args>
struct __is_nary_constructible_impl
: public __do_is_nary_constructible_impl
{
typedef decltype(__test<_Tp, _Args...>(0)) type;
};

template<typename _Tp, typename... _Args>
struct __is_nary_constructible
: public __is_nary_constructible_impl<_Tp, _Args...>::type
{
static_assert(sizeof...(_Args) > 1,
"Only useful for > 1 arguments");
};

template<typename _Tp, typename... _Args>
struct __is_constructible_impl
: public __is_nary_constructible<_Tp, _Args...>
{ };

template<typename _Tp, typename _Arg>
struct __is_constructible_impl<_Tp, _Arg>
: public __is_direct_constructible<_Tp, _Arg>
{ };

template<typename _Tp>
struct __is_constructible_impl<_Tp>
: public __is_default_constructible_safe<_Tp>::type
{ };
#endif

/// is_constructible
template<typename _Tp, typename... _Args>
struct is_constructible
: public __is_constructible_impl<_Tp, _Args...>
{
static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{}),
"template argument must be a complete class or an unbounded array");
};
};
adbancroft marked this conversation as resolved.
Show resolved Hide resolved

/// is_default_constructible
template<typename _Tp>
Expand Down Expand Up @@ -998,10 +1244,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ };
#endif

#if __GNUC__ >= 8
template<typename _Tp, typename... _Args>
using __is_nothrow_constructible_impl
= __is_nt_constructible_impl<__is_constructible(_Tp, _Args...),
_Tp, _Args...>;
#else
template<typename _Tp, typename... _Args>
using __is_nothrow_constructible_impl
= __is_nt_constructible_impl<__is_constructible_impl<_Tp, _Args...>::value,
_Tp, _Args...>;
#endif

/// is_nothrow_constructible
template<typename _Tp, typename... _Args>
Expand Down Expand Up @@ -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<typename _Tp, typename _Up>
struct is_assignable
Expand All @@ -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<typename _Tp, typename _Up>
class __is_assignable_helper
{
template<typename _Tp1, typename _Up1,
typename = decltype(declval<_Tp1>() = declval<_Up1>())>
static true_type
__test(int);

template<typename, typename>
static false_type
__test(...);

public:
typedef decltype(__test<_Tp, _Up>(0)) type;
};

/// is_assignable
template<typename _Tp, typename _Up>
struct is_assignable
: public __is_assignable_helper<_Tp, _Up>::type
{ };
#endif

template<typename _Tp, bool = __is_referenceable<_Tp>::value>
struct __is_copy_assignable_impl;
Expand All @@ -1080,10 +1357,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __is_copy_assignable_impl<_Tp, false>
: public false_type { };

#if __GNUC__ >= 8
template<typename _Tp>
struct __is_copy_assignable_impl<_Tp, true>
: public __bool_constant<__is_assignable(_Tp&, const _Tp&)>
{ };
#else
template<typename _Tp>
struct __is_copy_assignable_impl<_Tp, true>
: public is_assignable<_Tp&, const _Tp&>
{ };
#endif

/// is_copy_assignable
template<typename _Tp>
Expand All @@ -1101,10 +1385,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __is_move_assignable_impl<_Tp, false>
: public false_type { };

#if __GNUC__ >= 8
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, true>
: public __bool_constant<__is_assignable(_Tp&, _Tp&&)>
{ };
#else
template<typename _Tp>
struct __is_move_assignable_impl<_Tp, true>
: public is_assignable<_Tp&, _Tp&&>
{ };
#endif

/// is_move_assignable
template<typename _Tp>
Expand All @@ -1120,11 +1411,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: public integral_constant<bool, noexcept(declval<_Tp>() = declval<_Up>())>
{ };

#if __GNUC__ >= 8
template<typename _Tp, typename _Up>
struct __is_nothrow_assignable_impl
: public __and_<__bool_constant<__is_assignable(_Tp, _Up)>,
__is_nt_assignable_impl<_Tp, _Up>>
{ };
#else
template<typename _Tp, typename _Up>
struct __is_nothrow_assignable_impl
: public __and_<is_assignable<_Tp&, _Tp&&>,
__is_nt_assignable_impl<_Tp, _Up>>
{ };
#endif

/// is_nothrow_assignable
template<typename _Tp, typename _Up>
Expand Down
Loading
Loading