Commit 22f1f4c7 by Jonathan Wakely Committed by Jonathan Wakely

PR libstdc++/85951 for make_signed/make_unsigned for character types

Because the wide character types are neither signed integer types nor
unsigned integer types they need to be transformed to an integral type
of the correct size and the lowest rank (which is not necessarily the
underlying type). Reuse the helpers for enumeration types to select the
correct integer.

The refactoring of __make_unsigned_selector and __make_signed_selector
slightly reduces the number of template instantiations and so reduces
memory usage.

	PR libstdc++/85951
	* include/std/type_traits [_GLIBCXX_USE_C99_STDINT_TR1]: Do not define
	uint_least16_t and uint_least32_t.
	(__make_unsigned<wchar_t>): Define unconditionally.
	(__make_unsigned_selector<_Tp, true, false>): Remove intermediate
	typedefs.
	(__make_unsigned_selector_base): New type to provide helper templates.
	(__make_unsigned_selector<_Tp, false, true>): Reimplement using
	__make_unsigned_selector_base helpers.
	(__make_unsigned<char16_t>, __make_unsigned<char32_t>): Define.
	(__make_signed_selector<_Tp, true, false>): Remove intermediate
	typedefs.
	(__make_signed<wchar_t>, __make_signed<char16_t>)
	(__make_signed<char32_t>)): Define unconditionally.
	* testsuite/20_util/make_signed/requirements/typedefs-3.cc: Check
	wchar_t, char16_t and char32_t are transformed correctly.
	* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
	dg-error lineno.
	* testsuite/20_util/make_unsigned/requirements/typedefs-3.cc: Check
	wchar_t, char16_t and char32_t are transformed correctly.
	* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
	dg-error lineno.

From-SVN: r261023
parent 2ae39fb2
2018-05-31 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/85951
* include/std/type_traits [_GLIBCXX_USE_C99_STDINT_TR1]: Do not define
uint_least16_t and uint_least32_t.
(__make_unsigned<wchar_t>): Define unconditionally.
(__make_unsigned_selector<_Tp, true, false>): Remove intermediate
typedefs.
(__make_unsigned_selector_base): New type to provide helper templates.
(__make_unsigned_selector<_Tp, false, true>): Reimplement using
__make_unsigned_selector_base helpers.
(__make_unsigned<char16_t>, __make_unsigned<char32_t>): Define.
(__make_signed_selector<_Tp, true, false>): Remove intermediate
typedefs.
(__make_signed<wchar_t>, __make_signed<char16_t>)
(__make_signed<char32_t>)): Define unconditionally.
* testsuite/20_util/make_signed/requirements/typedefs-3.cc: Check
wchar_t, char16_t and char32_t are transformed correctly.
* testsuite/20_util/make_signed/requirements/typedefs_neg.cc: Adjust
dg-error lineno.
* testsuite/20_util/make_unsigned/requirements/typedefs-3.cc: Check
wchar_t, char16_t and char32_t are transformed correctly.
* testsuite/20_util/make_unsigned/requirements/typedefs_neg.cc: Adjust
dg-error lineno.
2018-05-29 Jonathan Wakely <jwakely@redhat.com> 2018-05-29 Jonathan Wakely <jwakely@redhat.com>
* include/std/variant (__erased_dtor): Qualify call to __get. * include/std/variant (__erased_dtor): Qualify call to __get.
......
...@@ -37,18 +37,6 @@ ...@@ -37,18 +37,6 @@
#include <bits/c++config.h> #include <bits/c++config.h>
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
# if defined (__UINT_LEAST16_TYPE__) && defined(__UINT_LEAST32_TYPE__)
namespace std
{
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
}
# else
# include <cstdint>
# endif
#endif
namespace std _GLIBCXX_VISIBILITY(default) namespace std _GLIBCXX_VISIBILITY(default)
{ {
_GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_VERSION
...@@ -1576,12 +1564,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1576,12 +1564,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __make_unsigned<long long> struct __make_unsigned<long long>
{ typedef unsigned long long __type; }; { typedef unsigned long long __type; };
#if defined(_GLIBCXX_USE_WCHAR_T) && !defined(__WCHAR_UNSIGNED__)
template<>
struct __make_unsigned<wchar_t> : __make_unsigned<__WCHAR_TYPE__>
{ };
#endif
#if defined(__GLIBCXX_TYPE_INT_N_0) #if defined(__GLIBCXX_TYPE_INT_N_0)
template<> template<>
struct __make_unsigned<__GLIBCXX_TYPE_INT_N_0> struct __make_unsigned<__GLIBCXX_TYPE_INT_N_0>
...@@ -1612,36 +1594,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1612,36 +1594,77 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp> template<typename _Tp>
class __make_unsigned_selector<_Tp, true, false> class __make_unsigned_selector<_Tp, true, false>
{ {
typedef __make_unsigned<typename remove_cv<_Tp>::type> __unsignedt; using __unsigned_type
typedef typename __unsignedt::__type __unsigned_type; = typename __make_unsigned<typename remove_cv<_Tp>::type>::__type;
typedef __match_cv_qualifiers<_Tp, __unsigned_type> __cv_unsigned;
public: public:
typedef typename __cv_unsigned::__type __type; using __type
= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
}; };
class __make_unsigned_selector_base
{
protected:
template<typename...> struct _List { };
template<typename _Tp, typename... _Up>
struct _List<_Tp, _Up...> : _List<_Up...>
{ static constexpr size_t __size = sizeof(_Tp); };
template<size_t _Sz, typename _Tp, bool = (_Sz <= _Tp::__size)>
struct __select;
template<size_t _Sz, typename _Uint, typename... _UInts>
struct __select<_Sz, _List<_Uint, _UInts...>, true>
{ using __type = _Uint; };
template<size_t _Sz, typename _Uint, typename... _UInts>
struct __select<_Sz, _List<_Uint, _UInts...>, false>
: __select<_Sz, _List<_UInts...>>
{ };
};
// Choose unsigned integer type with the smallest rank and same size as _Tp
template<typename _Tp> template<typename _Tp>
class __make_unsigned_selector<_Tp, false, true> class __make_unsigned_selector<_Tp, false, true>
: __make_unsigned_selector_base
{ {
// With -fshort-enums, an enum may be as small as a char. // With -fshort-enums, an enum may be as small as a char.
typedef unsigned char __smallest; using _UInts = _List<unsigned char, unsigned short, unsigned int,
static const bool __b0 = sizeof(_Tp) <= sizeof(__smallest); unsigned long, unsigned long long>;
static const bool __b1 = sizeof(_Tp) <= sizeof(unsigned short);
static const bool __b2 = sizeof(_Tp) <= sizeof(unsigned int); using __unsigned_type = typename __select<sizeof(_Tp), _UInts>::__type;
static const bool __b3 = sizeof(_Tp) <= sizeof(unsigned long);
typedef conditional<__b3, unsigned long, unsigned long long> __cond3;
typedef typename __cond3::type __cond3_type;
typedef conditional<__b2, unsigned int, __cond3_type> __cond2;
typedef typename __cond2::type __cond2_type;
typedef conditional<__b1, unsigned short, __cond2_type> __cond1;
typedef typename __cond1::type __cond1_type;
typedef typename conditional<__b0, __smallest, __cond1_type>::type
__unsigned_type;
typedef __match_cv_qualifiers<_Tp, __unsigned_type> __cv_unsigned;
public: public:
typedef typename __cv_unsigned::__type __type; using __type
= typename __match_cv_qualifiers<_Tp, __unsigned_type>::__type;
};
// wchar_t, char16_t and char32_t are integral types but are neither
// signed integer types not unsigned integer types, so must be
// transformed to the unsigned integer type with the smallest rank.
// Use the partial specialization for enumeration types to do that.
#if defined(_GLIBCXX_USE_WCHAR_T)
template<>
struct __make_unsigned<wchar_t>
{
using __type
= typename __make_unsigned_selector<wchar_t, false, true>::__type;
};
#endif
template<>
struct __make_unsigned<char16_t>
{
using __type
= typename __make_unsigned_selector<char16_t, false, true>::__type;
};
template<>
struct __make_unsigned<char32_t>
{
using __type
= typename __make_unsigned_selector<char32_t, false, true>::__type;
}; };
// Given an integral/enum type, return the corresponding unsigned // Given an integral/enum type, return the corresponding unsigned
...@@ -1686,21 +1709,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1686,21 +1709,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
struct __make_signed<unsigned long long> struct __make_signed<unsigned long long>
{ typedef signed long long __type; }; { typedef signed long long __type; };
#if defined(_GLIBCXX_USE_WCHAR_T) && defined(__WCHAR_UNSIGNED__)
template<>
struct __make_signed<wchar_t> : __make_signed<__WCHAR_TYPE__>
{ };
#endif
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
template<>
struct __make_signed<char16_t> : __make_signed<uint_least16_t>
{ };
template<>
struct __make_signed<char32_t> : __make_signed<uint_least32_t>
{ };
#endif
#if defined(__GLIBCXX_TYPE_INT_N_0) #if defined(__GLIBCXX_TYPE_INT_N_0)
template<> template<>
struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_0> struct __make_signed<unsigned __GLIBCXX_TYPE_INT_N_0>
...@@ -1731,14 +1739,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1731,14 +1739,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp> template<typename _Tp>
class __make_signed_selector<_Tp, true, false> class __make_signed_selector<_Tp, true, false>
{ {
typedef __make_signed<typename remove_cv<_Tp>::type> __signedt; using __signed_type
typedef typename __signedt::__type __signed_type; = typename __make_signed<typename remove_cv<_Tp>::type>::__type;
typedef __match_cv_qualifiers<_Tp, __signed_type> __cv_signed;
public: public:
typedef typename __cv_signed::__type __type; using __type
= typename __match_cv_qualifiers<_Tp, __signed_type>::__type;
}; };
// Choose signed integer type with the smallest rank and same size as _Tp
template<typename _Tp> template<typename _Tp>
class __make_signed_selector<_Tp, false, true> class __make_signed_selector<_Tp, false, true>
{ {
...@@ -1748,6 +1757,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION ...@@ -1748,6 +1757,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef typename __make_signed_selector<__unsigned_type>::__type __type; typedef typename __make_signed_selector<__unsigned_type>::__type __type;
}; };
// wchar_t, char16_t and char32_t are integral types but are neither
// signed integer types not unsigned integer types, so must be
// transformed to the signed integer type with the smallest rank.
// Use the partial specialization for enumeration types to do that.
#if defined(_GLIBCXX_USE_WCHAR_T)
template<>
struct __make_signed<wchar_t>
{
using __type
= typename __make_signed_selector<wchar_t, false, true>::__type;
};
#endif
template<>
struct __make_signed<char16_t>
{
using __type
= typename __make_signed_selector<char16_t, false, true>::__type;
};
template<>
struct __make_signed<char32_t>
{
using __type
= typename __make_signed_selector<char32_t, false, true>::__type;
};
// Given an integral/enum type, return the corresponding signed // Given an integral/enum type, return the corresponding signed
// integer type. // integer type.
// Primary template. // Primary template.
......
...@@ -59,8 +59,21 @@ using I4 = smallest_rank_t<E4>; ...@@ -59,8 +59,21 @@ using I4 = smallest_rank_t<E4>;
static_assert(is_same<make_signed<E4>::type, I4>::value, ""); static_assert(is_same<make_signed<E4>::type, I4>::value, "");
static_assert(is_same<make_signed<E4 const>::type, I4 const>::value, ""); static_assert(is_same<make_signed<E4 const>::type, I4 const>::value, "");
// PI libstdc++/60333 // PR libstdc++/60333
enum E5 : long long { }; enum E5 : long long { };
using I5 = smallest_rank_t<E5>; using I5 = smallest_rank_t<E5>;
static_assert(is_same<make_signed<E5>::type, I5>::value, ""); static_assert(is_same<make_signed<E5>::type, I5>::value, "");
static_assert(is_same<make_signed<E5 const>::type, I5 const>::value, ""); static_assert(is_same<make_signed<E5 const>::type, I5 const>::value, "");
// PR libstdc++/85951
using I6 = smallest_rank_t<char16_t>;
static_assert(is_same<make_signed<char16_t>::type, I6>::value, "");
static_assert(is_same<make_signed<char16_t const>::type, I6 const>::value, "");
using I7 = smallest_rank_t<char32_t>;
static_assert(is_same<make_signed<char32_t>::type, I7>::value, "");
static_assert(is_same<make_signed<char32_t const>::type, I7 const>::value, "");
#ifdef _GLIBCXX_USE_WCHAR_T
using I8 = smallest_rank_t<wchar_t>;
static_assert(is_same<make_signed<wchar_t>::type, I8>::value, "");
static_assert(is_same<make_signed<wchar_t const>::type, I8 const>::value, "");
#endif
...@@ -28,7 +28,7 @@ void test01() ...@@ -28,7 +28,7 @@ void test01()
{ {
using std::make_signed; using std::make_signed;
// Negative tests. // Negative tests.
typedef make_signed<bool>::type test1_type; typedef make_signed<bool>::type test1_type;
typedef make_signed<__gnu_test::pod_uint>::type test2_type; typedef make_signed<__gnu_test::pod_uint>::type test2_type;
...@@ -47,4 +47,4 @@ void test01() ...@@ -47,4 +47,4 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 } // { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 } // { dg-error "required from here" "" { target *-*-* } 41 }
// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1757 } // { dg-error "invalid use of incomplete type" "" { target *-*-* } 1793 }
...@@ -59,8 +59,21 @@ using I4 = smallest_rank_t<E4>; ...@@ -59,8 +59,21 @@ using I4 = smallest_rank_t<E4>;
static_assert(is_same<make_unsigned<E4>::type, I4>::value, ""); static_assert(is_same<make_unsigned<E4>::type, I4>::value, "");
static_assert(is_same<make_unsigned<E4 const>::type, I4 const>::value, ""); static_assert(is_same<make_unsigned<E4 const>::type, I4 const>::value, "");
// PI libstdc++/60333 // PR libstdc++/60333
enum E5 : long long { }; enum E5 : long long { };
using I5 = smallest_rank_t<E5>; using I5 = smallest_rank_t<E5>;
static_assert(is_same<make_unsigned<E5>::type, I5>::value, ""); static_assert(is_same<make_unsigned<E5>::type, I5>::value, "");
static_assert(is_same<make_unsigned<E5 const>::type, I5 const>::value, ""); static_assert(is_same<make_unsigned<E5 const>::type, I5 const>::value, "");
// PR libstdc++/85951
using I6 = smallest_rank_t<char16_t>;
static_assert(is_same<make_unsigned<char16_t>::type, I6>::value, "");
static_assert(is_same<make_unsigned<char16_t const>::type, I6 const>::value, "");
using I7 = smallest_rank_t<char32_t>;
static_assert(is_same<make_unsigned<char32_t>::type, I7>::value, "");
static_assert(is_same<make_unsigned<char32_t const>::type, I7 const>::value, "");
#ifdef _GLIBCXX_USE_WCHAR_T
using I8 = smallest_rank_t<wchar_t>;
static_assert(is_same<make_unsigned<wchar_t>::type, I8>::value, "");
static_assert(is_same<make_unsigned<wchar_t const>::type, I8 const>::value, "");
#endif
...@@ -28,7 +28,7 @@ void test01() ...@@ -28,7 +28,7 @@ void test01()
{ {
using std::make_unsigned; using std::make_unsigned;
// Negative tests. // Negative tests.
typedef make_unsigned<bool>::type test1_type; typedef make_unsigned<bool>::type test1_type;
typedef make_unsigned<__gnu_test::pod_uint>::type test2_type; typedef make_unsigned<__gnu_test::pod_uint>::type test2_type;
...@@ -47,5 +47,5 @@ void test01() ...@@ -47,5 +47,5 @@ void test01()
// { dg-error "required from here" "" { target *-*-* } 39 } // { dg-error "required from here" "" { target *-*-* } 39 }
// { dg-error "required from here" "" { target *-*-* } 41 } // { dg-error "required from here" "" { target *-*-* } 41 }
// { dg-error "invalid use of incomplete type" "" { target *-*-* } 1653 } // { dg-error "invalid use of incomplete type" "" { target *-*-* } 1676 }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment