EricWF updated this revision to Diff 83145. EricWF added a comment. Updating with final changes.
https://reviews.llvm.org/D28222 Files: include/__tuple test/libcxx/test/config.py test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.pass.cpp test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_value_sfinae.pass.cpp
Index: test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_value_sfinae.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_value_sfinae.pass.cpp @@ -0,0 +1,39 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <tuple> + +// template <class... Types> class tuple; + +// template <class... Types> +// class tuple_size<tuple<Types...>> +// : public integral_constant<size_t, sizeof...(Types)> { }; + +// XFAIL: gcc-4.9 +// UNSUPPORTED: c++98, c++03 + +#include <tuple> +#include <type_traits> + +template <class T, class = decltype(std::tuple_size<T>::value)> +constexpr bool has_value(int) { return true; } +template <class> constexpr bool has_value(long) { return false; } +template <class T> constexpr bool has_value() { return has_value<T>(0); } + +struct Dummy {}; + +int main() { + // Test that the ::value member does not exist + static_assert(has_value<std::tuple<int> const>(), ""); + static_assert(has_value<std::pair<int, long> volatile>(), ""); + static_assert(!has_value<int>(), ""); + static_assert(!has_value<const int>(), ""); + static_assert(!has_value<volatile void>(), ""); + static_assert(!has_value<const volatile std::tuple<int>&>(), ""); +} Index: test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_structured_bindings.pass.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <tuple> + +// template <class... Types> class tuple; + +// template <class... Types> +// class tuple_size<tuple<Types...>> +// : public integral_constant<size_t, sizeof...(Types)> { }; + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// XFAIL: libcpp-no-structured-bindings + +#include <tuple> +#include <array> +#include <type_traits> +#include <cassert> + +struct S { int x; }; + +void test_decomp_user_type() { + { + S s{99}; + auto [m1] = s; + auto& [r1] = s; + assert(m1 == 99); + assert(&r1 == &s.x); + } + { + S const s{99}; + auto [m1] = s; + auto& [r1] = s; + assert(m1 == 99); + assert(&r1 == &s.x); + } +} + +void test_decomp_tuple() { + typedef std::tuple<int> T; + { + T s{99}; + auto [m1] = s; + auto& [r1] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } + { + T const s{99}; + auto [m1] = s; + auto& [r1] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } +} + + +void test_decomp_pair() { + typedef std::pair<int, double> T; + { + T s{99, 42.1}; + auto [m1, m2] = s; + auto& [r1, r2] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } + { + T const s{99, 42.1}; + auto [m1, m2] = s; + auto& [r1, r2] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } +} + +void test_decomp_array() { + typedef std::array<int, 3> T; + { + T s{{99, 42, -1}}; + auto [m1, m2, m3] = s; + auto& [r1, r2, r3] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } + { + T const s{{99, 42, -1}}; + auto [m1, m2, m3] = s; + auto& [r1, r2, r3] = s; + assert(m1 == 99); + assert(&r1 == &std::get<0>(s)); + } +} + +struct Test { + int x; +}; + +template <size_t N> +int get(Test const&) { static_assert(N == 0, ""); return -1; } + +template <> +class std::tuple_element<0, Test> { +public: + typedef int type; +}; + +void test_before_tuple_size_specialization() { + Test const t{99}; + auto& [p] = t; + assert(p == 99); +} + +template <> +class std::tuple_size<Test> { +public: + static const size_t value = 1; +}; + +void test_after_tuple_size_specialization() { + Test const t{99}; + auto& [p] = t; + assert(p == -1); +} + +int main() { + test_decomp_user_type(); + test_decomp_tuple(); + test_decomp_pair(); + test_decomp_array(); + test_before_tuple_size_specialization(); + test_after_tuple_size_specialization(); +} Index: test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <tuple> + +// template <class... Types> class tuple; + +// template <class... Types> +// class tuple_size<tuple<Types...>> +// : public integral_constant<size_t, sizeof...(Types)> { }; + +// XFAIL: gcc-4.9 +// UNSUPPORTED: c++98, c++03 + +#include <tuple> +#include <array> +#include <type_traits> + +template <class T, size_t Size = sizeof(std::tuple_size<T>)> +constexpr bool is_complete(int) { static_assert(Size > 0, ""); return true; } +template <class> constexpr bool is_complete(long) { return false; } +template <class T> constexpr bool is_complete() { return is_complete<T>(0); } + +struct Dummy1 {}; +struct Dummy2 {}; + +namespace std { +template <> class tuple_size<Dummy1> : public integral_constant<size_t, 0> {}; +} + +template <class T> +void test_complete() { + static_assert(is_complete<T>(), ""); + static_assert(is_complete<const T>(), ""); + static_assert(is_complete<volatile T>(), ""); + static_assert(is_complete<const volatile T>(), ""); +} + +template <class T> +void test_incomplete() { + static_assert(!is_complete<T>(), ""); + static_assert(!is_complete<const T>(), ""); + static_assert(!is_complete<volatile T>(), ""); + static_assert(!is_complete<const volatile T>(), ""); +} + + +int main() +{ + test_complete<std::tuple<> >(); + test_complete<std::tuple<int&> >(); + test_complete<std::tuple<int&&, int&, void*>>(); + test_complete<std::pair<int, long> >(); + test_complete<std::array<int, 5> >(); + test_complete<Dummy1>(); + + test_incomplete<void>(); + test_incomplete<int>(); + test_incomplete<std::tuple<int>&>(); + test_incomplete<Dummy2>(); +} Index: test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size_incomplete.fail.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// <tuple> + +// template <class... Types> class tuple; + +// template <class... Types> +// class tuple_size<tuple<Types...>> +// : public integral_constant<size_t, sizeof...(Types)> { }; + +// UNSUPPORTED: c++98, c++03 + +#include <tuple> +#include <array> +#include <type_traits> + +struct Dummy1 {}; +struct Dummy2 {}; +struct Dummy3 {}; + +template <> +class std::tuple_size<Dummy1> { +public: + static size_t value; +}; + +template <> +class std::tuple_size<Dummy2> { +public: + static void value() {} +}; + +template <> +class std::tuple_size<Dummy3> {}; + +int main() +{ + // Test that tuple_size<const T> is not incomplete when tuple_size<T>::value + // is well-formed but not a constant expression. + { + // expected-error@__tuple:* 1 {{is not a constant expression}} + (void)std::tuple_size<const Dummy1>::value; // expected-note {{here}} + } + // Test that tuple_size<const T> is not incomplete when tuple_size<T>::value + // is well-formed but not convertible to size_t. + { + // expected-error@__tuple:* 1 {{value of type 'void ()' is not implicitly convertible to 'unsigned long'}} + (void)std::tuple_size<const Dummy2>::value; // expected-note {{here}} + } + // Test that tuple_size<const T> generates an error when tuple_size<T> is + // complete but ::value isn't a constant expression convertible to size_t. + { + // expected-error@__tuple:* 1 {{no member named 'value'}} + (void)std::tuple_size<const Dummy3>::value; // expected-note {{here}} + } +} Index: test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.pass.cpp =================================================================== --- test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.pass.cpp +++ test/std/utilities/tuple/tuple.tuple/tuple.helper/tuple_size.pass.cpp @@ -20,13 +20,6 @@ #include <tuple> #include <type_traits> -template <class T, class = decltype(std::tuple_size<T>::value)> -constexpr bool has_value(int) { return true; } -template <class> constexpr bool has_value(long) { return false; } -template <class T> constexpr bool has_value() { return has_value<T>(0); } - -struct Dummy {}; - template <class T, std::size_t N> void test() { @@ -40,21 +33,10 @@ std::tuple_size<const volatile T> >::value), ""); } -void test_tuple_size_value_sfinae() { - // Test that the ::value member does not exist - static_assert(has_value<std::tuple<int> const>(), ""); - static_assert(has_value<std::pair<int, long> volatile>(), ""); - static_assert(!has_value<int>(), ""); - static_assert(!has_value<const int>(), ""); - static_assert(!has_value<volatile void>(), ""); - static_assert(!has_value<const volatile std::tuple<int>&>(), ""); -} - int main() { test<std::tuple<>, 0>(); test<std::tuple<int>, 1>(); test<std::tuple<char, int>, 2>(); test<std::tuple<char, char*, int>, 3>(); - test_tuple_size_value_sfinae(); } Index: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -335,9 +335,13 @@ if self.get_lit_bool('has_libatomic', False): self.config.available_features.add('libatomic') - if '__cpp_if_constexpr' not in self.cxx.dumpMacros(): + macros = self.cxx.dumpMacros() + if '__cpp_if_constexpr' not in macros: self.config.available_features.add('libcpp-no-if-constexpr') + if '__cpp_structured_bindings' not in macros: + self.config.available_features.add('libcpp-no-structured-bindings') + def configure_compile_flags(self): no_default_flags = self.get_lit_bool('no_default_flags', False) if not no_default_flags: Index: include/__tuple =================================================================== --- include/__tuple +++ include/__tuple @@ -24,30 +24,35 @@ template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size; -struct __empty_tuple_size_base {}; - -template <class _Tp, class = void> -struct __tuple_size_base_type { - typedef __empty_tuple_size_base type; -}; +#if !defined(_LIBCPP_CXX03_LANG) +template <class _Tp, class...> +using __enable_if_tuple_size_imp = _Tp; template <class _Tp> -struct __tuple_size_base_type<_Tp, typename __void_t<decltype(tuple_size<_Tp>::value)>::type> -{ - typedef integral_constant<size_t, tuple_size<_Tp>::value> type; -}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp< + const _Tp, + typename enable_if<!is_volatile<_Tp>::value>::type, + integral_constant<size_t, sizeof(tuple_size<_Tp>)>>> + : public integral_constant<size_t, tuple_size<_Tp>::value> {}; template <class _Tp> -class _LIBCPP_TYPE_VIS_ONLY tuple_size<const _Tp> - : public __tuple_size_base_type<_Tp>::type {}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp< + volatile _Tp, + typename enable_if<!is_const<_Tp>::value>::type, + integral_constant<size_t, sizeof(tuple_size<_Tp>)>>> + : public integral_constant<size_t, tuple_size<_Tp>::value> {}; template <class _Tp> -class _LIBCPP_TYPE_VIS_ONLY tuple_size<volatile _Tp> - : public __tuple_size_base_type<_Tp>::type {}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp< + const volatile _Tp, + integral_constant<size_t, sizeof(tuple_size<_Tp>)>>> + : public integral_constant<size_t, tuple_size<_Tp>::value> {}; -template <class _Tp> -class _LIBCPP_TYPE_VIS_ONLY tuple_size<const volatile _Tp> - : public __tuple_size_base_type<_Tp>::type {}; +#else +template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size<const _Tp> : tuple_size<_Tp> {}; +template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size<volatile _Tp> : tuple_size<_Tp> {}; +template <class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_size<const volatile _Tp> : tuple_size<_Tp> {}; +#endif template <size_t _Ip, class _Tp> class _LIBCPP_TYPE_VIS_ONLY tuple_element;
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits