From 7a7960ff7f88e70e97cf8469d82286aec7eec5fe Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Thu, 21 Jan 2016 18:22:43 +0000 Subject: [PATCH] Implement LWG#2101 'Some transformation types can produce impossible types' Introduced a new (internal) type trait '__is_referenceable' with tests. Use that trait in add_lvalue_reference, add_rvalue_reference and add_pointer. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@258418 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/type_traits | 63 ++++++-- .../utilities/meta/is_referenceable.pass.cpp | 153 ++++++++++++++++++ .../meta.trans.ptr/add_pointer.pass.cpp | 48 +++++- .../meta.trans.ptr/remove_pointer.pass.cpp | 3 +- .../meta.trans.ref/add_lvalue_ref.pass.cpp | 25 ++- .../meta.trans.ref/add_rvalue_ref.pass.cpp | 48 +++++- .../meta.trans.ref/remove_ref.pass.cpp | 3 +- www/cxx1z_status.html | 4 +- 8 files changed, 320 insertions(+), 27 deletions(-) create mode 100644 test/libcxx/utilities/meta/is_referenceable.pass.cpp diff --git a/include/type_traits b/include/type_traits index b7adfebce..3b80a9efa 100644 --- a/include/type_traits +++ b/include/type_traits @@ -957,6 +957,38 @@ template _LIBCPP_CONSTEXPR bool is_compound_v = is_compound<_Tp>::value; #endif + +// __is_referenceable [defns.referenceable] +template struct __is_referenceable + : public std::integral_constant::value || is_reference<_Tp>::value> {}; + +#ifndef _LIBCPP_HAS_NO_VARIADICS +template +struct __is_referenceable<_Ret(_Args...)> : public std::true_type {}; + +template +struct __is_referenceable<_Ret(_Args..., ...)> : public std::true_type {}; +#else +template +struct __is_referenceable<_Ret()> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0)> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0, _A1)> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0, _A1, _A2)> : public std::true_type {}; + +template +struct __is_referenceable<_Ret(...)> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0, ...)> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0, _A1, ...)> : public std::true_type {}; +template +struct __is_referenceable<_Ret(_A0, _A1, _A2, ...)> : public std::true_type {}; +#endif + + // add_const template ::value || @@ -1014,12 +1046,11 @@ template using remove_reference_t = typename remove_reference<_Tp>:: // add_lvalue_reference -template struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference {typedef _Tp& type;}; -template struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference<_Tp&> {typedef _Tp& type;}; // for older compiler -template <> struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference {typedef void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference {typedef const void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference {typedef volatile void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference {typedef const volatile void type;}; +template ::value> struct __add_lvalue_reference_impl { typedef _Tp type; }; +template struct __add_lvalue_reference_impl<_Tp, true> { typedef _Tp& type; }; + +template struct _LIBCPP_TYPE_VIS_ONLY add_lvalue_reference +{typedef typename __add_lvalue_reference_impl<_Tp>::type type;}; #if _LIBCPP_STD_VER > 11 template using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; @@ -1027,11 +1058,11 @@ template using add_lvalue_reference_t = typename add_lvalue_referenc #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES -template struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference {typedef _Tp&& type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference {typedef void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference {typedef const void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference {typedef volatile void type;}; -template <> struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference {typedef const volatile void type;}; +template ::value> struct __add_rvalue_reference_impl { typedef _Tp type; }; +template struct __add_rvalue_reference_impl<_Tp, true> { typedef _Tp&& type; }; + +template struct _LIBCPP_TYPE_VIS_ONLY add_rvalue_reference +{typedef typename __add_rvalue_reference_impl<_Tp>::type type;}; #if _LIBCPP_STD_VER > 11 template using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; @@ -1072,8 +1103,16 @@ template using remove_pointer_t = typename remove_pointer<_Tp>::type // add_pointer -template struct _LIBCPP_TYPE_VIS_ONLY add_pointer +template ::value || + is_same::type, void>::value> +struct __add_pointer_impl {typedef typename remove_reference<_Tp>::type* type;}; +template struct __add_pointer_impl<_Tp, false> + {typedef _Tp type;}; + +template struct _LIBCPP_TYPE_VIS_ONLY add_pointer + {typedef typename __add_pointer_impl<_Tp>::type type;}; #if _LIBCPP_STD_VER > 11 template using add_pointer_t = typename add_pointer<_Tp>::type; diff --git a/test/libcxx/utilities/meta/is_referenceable.pass.cpp b/test/libcxx/utilities/meta/is_referenceable.pass.cpp new file mode 100644 index 000000000..d292c6257 --- /dev/null +++ b/test/libcxx/utilities/meta/is_referenceable.pass.cpp @@ -0,0 +1,153 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// + +// __is_referenceable +// +// [defns.referenceable] defines "a referenceable type" as: +// An object type, a function type that does not have cv-qualifiers +// or a ref-qualifier, or a reference type. +// + +#include +#include + +#include "test_macros.h" + +struct Foo {}; + +static_assert((!std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +// Functions without cv-qualifiers are referenceable +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); +static_assert((!std::__is_referenceable::value), ""); + +// member functions with or without cv-qualifiers are referenceable +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); +static_assert(( std::__is_referenceable::value), ""); + +int main () {} diff --git a/test/std/utilities/meta/meta.trans/meta.trans.ptr/add_pointer.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.ptr/add_pointer.pass.cpp index 76d0f12d0..56acfc496 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.ptr/add_pointer.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.ptr/add_pointer.pass.cpp @@ -10,18 +10,42 @@ // type_traits // add_pointer +// If T names a referenceable type or a (possibly cv-qualified) void type then +// the member typedef type shall name the same type as remove_reference_t*; +// otherwise, type shall name T. #include +#include "test_macros.h" template void test_add_pointer() { static_assert((std::is_same::type, U>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, U>::value), ""); #endif } +template +void test_function0() +{ + static_assert((std::is_same::type, F*>::value), ""); +#if TEST_STD_VER > 11 + static_assert((std::is_same, F*>::value), ""); +#endif +} + +template +void test_function1() +{ + static_assert((std::is_same::type, F>::value), ""); +#if TEST_STD_VER > 11 + static_assert((std::is_same, F>::value), ""); +#endif +} + +struct Foo {}; + int main() { test_add_pointer(); @@ -31,4 +55,26 @@ int main() test_add_pointer(); test_add_pointer(); test_add_pointer(); + test_add_pointer(); + +// LWG 2101 specifically talks about add_pointer and functions. +// The term of art is "a referenceable type", which a cv- or ref-qualified function is not. + test_function0(); +#if TEST_STD_VER >= 11 + test_function1(); + test_function1(); + test_function1(); + test_function1(); + test_function1(); +#endif + +// But a cv- or ref-qualified member function *is* "a referenceable type" + test_function0(); +#if TEST_STD_VER >= 11 + test_function0(); + test_function0(); + test_function0(); + test_function0(); + test_function0(); +#endif } diff --git a/test/std/utilities/meta/meta.trans/meta.trans.ptr/remove_pointer.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.ptr/remove_pointer.pass.cpp index 9cecd3904..cccbb6011 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.ptr/remove_pointer.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.ptr/remove_pointer.pass.cpp @@ -12,12 +12,13 @@ // remove_pointer #include +#include "test_macros.h" template void test_remove_pointer() { static_assert((std::is_same::type, U>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, U>::value), ""); #endif } diff --git a/test/std/utilities/meta/meta.trans/meta.trans.ref/add_lvalue_ref.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.ref/add_lvalue_ref.pass.cpp index fb53312cb..c82c28299 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.ref/add_lvalue_ref.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.ref/add_lvalue_ref.pass.cpp @@ -10,14 +10,17 @@ // type_traits // add_lvalue_reference +// If T names a referenceable type then the member typedef type +// shall name T&; otherwise, type shall name T. #include +#include "test_macros.h" template void test_add_lvalue_reference() { static_assert((std::is_same::type, U>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, U>::value), ""); #endif } @@ -26,7 +29,7 @@ template void test_function0() { static_assert((std::is_same::type, F&>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, F&>::value), ""); #endif } @@ -35,7 +38,7 @@ template void test_function1() { static_assert((std::is_same::type, F>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, F>::value), ""); #endif } @@ -51,20 +54,26 @@ int main() test_add_lvalue_reference(); test_add_lvalue_reference(); test_add_lvalue_reference(); + test_add_lvalue_reference(); // LWG 2101 specifically talks about add_lvalue_reference and functions. // The term of art is "a referenceable type", which a cv- or ref-qualified function is not. test_function0(); -// test_function1(); -// test_function1(); -// test_function1(); -// test_function1(); -// test_function1(); +#if TEST_STD_VER >= 11 + test_function1(); + test_function1(); + test_function1(); + test_function1(); + test_function1(); +#endif +// But a cv- or ref-qualified member function *is* "a referenceable type" test_function0(); +#if TEST_STD_VER >= 11 test_function0(); test_function0(); test_function0(); test_function0(); test_function0(); +#endif } diff --git a/test/std/utilities/meta/meta.trans/meta.trans.ref/add_rvalue_ref.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.ref/add_rvalue_ref.pass.cpp index e8f08fdc3..fc147c37b 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.ref/add_rvalue_ref.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.ref/add_rvalue_ref.pass.cpp @@ -10,8 +10,11 @@ // type_traits // add_rvalue_reference +// If T names a referenceable type then the member typedef type +// shall name T&&; otherwise, type shall name T. #include +#include "test_macros.h" #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -19,13 +22,32 @@ template void test_add_rvalue_reference() { static_assert((std::is_same::type, U>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, U>::value), ""); #endif } +template +void test_function0() +{ + static_assert((std::is_same::type, F&&>::value), ""); +#if TEST_STD_VER > 11 + static_assert((std::is_same, F&&>::value), ""); +#endif +} + +template +void test_function1() +{ + static_assert((std::is_same::type, F>::value), ""); +#if TEST_STD_VER > 11 + static_assert((std::is_same, F>::value), ""); +#endif +} #endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES +struct Foo {}; + int main() { #ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES @@ -36,5 +58,27 @@ int main() test_add_rvalue_reference(); test_add_rvalue_reference(); test_add_rvalue_reference(); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + test_add_rvalue_reference(); + +// LWG 2101 specifically talks about add_rvalue_reference and functions. +// The term of art is "a referenceable type", which a cv- or ref-qualified function is not. + test_function0(); +#if TEST_STD_VER >= 11 + test_function1(); + test_function1(); + test_function1(); + test_function1(); + test_function1(); +#endif + +// But a cv- or ref-qualified member function *is* "a referenceable type" + test_function0(); +#if TEST_STD_VER >= 11 + test_function0(); + test_function0(); + test_function0(); + test_function0(); + test_function0(); +#endif +#endif } diff --git a/test/std/utilities/meta/meta.trans/meta.trans.ref/remove_ref.pass.cpp b/test/std/utilities/meta/meta.trans/meta.trans.ref/remove_ref.pass.cpp index f9ebc37a5..e335bd19e 100644 --- a/test/std/utilities/meta/meta.trans/meta.trans.ref/remove_ref.pass.cpp +++ b/test/std/utilities/meta/meta.trans/meta.trans.ref/remove_ref.pass.cpp @@ -12,12 +12,13 @@ // remove_reference #include +#include "test_macros.h" template void test_remove_reference() { static_assert((std::is_same::type, U>::value), ""); -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER > 11 static_assert((std::is_same, U>::value), ""); #endif } diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html index 42bc3d760..818c87327 100644 --- a/www/cxx1z_status.html +++ b/www/cxx1z_status.html @@ -149,7 +149,7 @@ 1169num_get not fully compatible with strto*Kona 2072Unclear wording about capacity of temporary buffersKonaComplete - 2101Some transformation types can produce impossible typesKona + 2101Some transformation types can produce impossible typesKonaComplete 2111Which unexpected/terminate handler is called from the exception handling runtime?KonaComplete 2119Missing hash specializations for extended integer typesKona 2127Move-construction with raw_storage_iteratorKonaComplete @@ -192,7 +192,7 @@ -

Last Updated: 5-Oct-2015

+

Last Updated: 21-Jan-2016