Index: include/__tuple =================================================================== --- include/__tuple +++ include/__tuple @@ -24,30 +24,26 @@ template class _LIBCPP_TYPE_VIS_ONLY tuple_size; -struct __empty_tuple_size_base {}; - -template -struct __tuple_size_base_type { - typedef __empty_tuple_size_base type; -}; - -template -struct __tuple_size_base_type<_Tp, typename __void_t::value)>::type> -{ - typedef integral_constant::value> type; -}; +#ifndef _LIBCPP_CXX03_LANG +template +using __enable_if_tuple_size_imp = _Tp; template -class _LIBCPP_TYPE_VIS_ONLY tuple_size - : public __tuple_size_base_type<_Tp>::type {}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp::type>::value)>> + : public integral_constant::value> {}; template -class _LIBCPP_TYPE_VIS_ONLY tuple_size - : public __tuple_size_base_type<_Tp>::type {}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp::type>::value)>> + : public integral_constant::value> {}; template -class _LIBCPP_TYPE_VIS_ONLY tuple_size - : public __tuple_size_base_type<_Tp>::type {}; +class _LIBCPP_TYPE_VIS_ONLY tuple_size<__enable_if_tuple_size_imp::type>::value)>> + : public integral_constant::value> {}; +#else +template class _LIBCPP_TYPE_VIS_ONLY tuple_size : tuple_size<_Tp> {}; +template class _LIBCPP_TYPE_VIS_ONLY tuple_size : tuple_size<_Tp> {}; +template class _LIBCPP_TYPE_VIS_ONLY tuple_size : tuple_size<_Tp> {}; +#endif template class _LIBCPP_TYPE_VIS_ONLY tuple_element; 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: 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,86 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// class tuple_size> +// : public integral_constant { }; + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include + +template )> +constexpr bool is_complete(int) { static_assert(Size > 0, ""); return true; } +template constexpr bool is_complete(long) { return false; } +template constexpr bool is_complete() { return is_complete(0); } + +struct Dummy1 {}; +struct Dummy2 {}; +struct Dummy3 {}; + +template <> +class std::tuple_size { +public: + static size_t value; +}; + +template <> +class std::tuple_size { +public: + static void value() {} +}; + +template <> +class std::tuple_size {}; + +template +void test_complete() { + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); +} + +template +void test_incomplete() { + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); +} + +int main() +{ + // Test that tuple_size is not incomplete when tuple_size::value + // is well-formed but not a constant expression. + { + // expected-error@__tuple:* 1 {{is not a constant expression}} + (void)std::tuple_size::value; // expected-note {{here}} + } + // Test that tuple_size is not incomplete when tuple_size::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::value; // expected-note {{here}} + } + // Test that tuple_size is incomplete when tuple_size::value is + // ill-formed. + // FIXME: it would be better if tuple_size were a complete type + // which generated diagnostics when used. + { + (void)std::tuple_size::value; + // expected-error@-1 {{implicit instantiation of undefined template}} + } +} 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,65 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// class tuple_size> +// : public integral_constant { }; + +// UNSUPPORTED: c++98, c++03 + +#include +#include +#include + +template )> +constexpr bool is_complete(int) { static_assert(Size > 0, ""); return true; } +template constexpr bool is_complete(long) { return false; } +template constexpr bool is_complete() { return is_complete(0); } + +struct Dummy1 {}; +struct Dummy2 {}; + +template <> +class std::tuple_size : public std::integral_constant {}; + +template +void test_complete() { + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); + static_assert(is_complete(), ""); +} + +template +void test_incomplete() { + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); + static_assert(!is_complete(), ""); +} + + +int main() +{ + test_complete >(); + test_complete >(); + test_complete>(); + test_complete >(); + test_complete >(); + test_complete(); + + test_incomplete(); + test_incomplete(); + test_incomplete&>(); + test_incomplete(); +} 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,105 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// + +// template class tuple; + +// template +// class tuple_size> +// : public integral_constant { }; + +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// XFAIL: libcpp-no-structured-bindings + +#include +#include +#include +#include + +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 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 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 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)); + } +} + +int main() { + test_decomp_user_type(); + test_decomp_tuple(); + test_decomp_pair(); + test_decomp_array(); +}