From 14c5ec51945be51c55c58cc4d2a1e4f1cfb56533 Mon Sep 17 00:00:00 2001 From: Marshall Clow Date: Wed, 15 Oct 2014 10:33:02 +0000 Subject: [PATCH] Fixes PR21157 'tuple: non-default constructible tuple hard failure' Thanks to Louis Dionne for the bug report and the patch. llvm-svn: 219785 --- libcxx/include/tuple | 42 ++++++++++++++++------ .../tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp | 11 ++++++ .../tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp | 17 +++++++++ .../tuple/tuple.tuple/tuple.cnstr/default.pass.cpp | 28 +++++++++++++++ 4 files changed, 87 insertions(+), 11 deletions(-) diff --git a/libcxx/include/tuple b/libcxx/include/tuple index 1463170..aa7185c 100644 --- a/libcxx/include/tuple +++ b/libcxx/include/tuple @@ -376,19 +376,18 @@ template _LIBCPP_INLINE_VISIBILITY void __swallow(_Tp&&...) _NOEXCEPT {} -template struct __all; +template +struct __all + : is_same<__all<_B...>, __all<(_B, true)...>> +{ }; -template <> -struct __all<> -{ - static const bool value = true; -}; +template +struct __all_default_constructible; -template -struct __all<_B0, _Bp...> -{ - static const bool value = _B0 && __all<_Bp...>::value; -}; +template +struct __all_default_constructible<__tuple_types<_Tp...>> + : __all::value...> +{ }; // __tuple_impl @@ -512,6 +511,9 @@ class _LIBCPP_TYPE_VIS_ONLY tuple typename tuple_element<_Jp, tuple<_Up...> >::type&& get(tuple<_Up...>&&) _NOEXCEPT; public: + template ::value)...>::value + >::type> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR tuple() _NOEXCEPT_(__all::value...>::value) {} @@ -547,6 +549,12 @@ public: sizeof...(_Up) < sizeof...(_Tp) ? sizeof...(_Up) : sizeof...(_Tp)>::type + >::value && + __all_default_constructible< + typename __make_tuple_types::type >::value, bool >::type = false @@ -587,6 +595,12 @@ public: sizeof...(_Up) < sizeof...(_Tp) ? sizeof...(_Up) : sizeof...(_Tp)>::type + >::value && + __all_default_constructible< + typename __make_tuple_types::type >::value, bool >::type =false @@ -620,6 +634,12 @@ public: sizeof...(_Up) < sizeof...(_Tp) ? sizeof...(_Up) : sizeof...(_Tp)>::type + >::value && + __all_default_constructible< + typename __make_tuple_types::type >::value >::type > diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp index d6fbdae..7359d77 100644 --- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp +++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp @@ -16,6 +16,7 @@ #include #include +#include #include "../MoveOnly.h" @@ -30,6 +31,8 @@ struct A #endif +struct NoDefault { NoDefault() = delete; }; + int main() { { @@ -63,6 +66,14 @@ int main() assert(std::get<1>(t) == MoveOnly()); assert(std::get<2>(t) == MoveOnly()); } + { + // Make sure the _Up... constructor SFINAEs out when the types that + // are not explicitly initialized are not all default constructible. + // Otherwise, std::is_constructible would return true but instantiating + // the constructor would fail. + static_assert(!std::is_constructible, MoveOnly>(), ""); + static_assert(!std::is_constructible, MoveOnly, MoveOnly>(), ""); + } #if _LIBCPP_STD_VER > 11 { constexpr std::tuple t0{Empty()}; diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp index 667c4dd..9746986 100644 --- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp +++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_UTypes.pass.cpp @@ -22,6 +22,8 @@ #include "../alloc_first.h" #include "../alloc_last.h" +struct NoDefault { NoDefault() = delete; }; + int main() { { @@ -68,4 +70,19 @@ int main() assert(std::get<1>(t) == MoveOnly()); assert(std::get<2>(t) == MoveOnly()); } + { + // Make sure the _Up... constructor SFINAEs out when the types that + // are not explicitly initialized are not all default constructible. + // Otherwise, std::is_constructible would return true but instantiating + // the constructor would fail. + static_assert(!std::is_constructible< + std::tuple, + std::allocator_arg_t, A1, MoveOnly + >::value, ""); + + static_assert(!std::is_constructible< + std::tuple, + std::allocator_arg_t, A1, MoveOnly, MoveOnly + >::value, ""); + } } diff --git a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp index b72b77e..9cde90d 100644 --- a/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp +++ b/libcxx/test/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp @@ -16,9 +16,23 @@ #include #include #include +#include #include "DefaultOnly.h" +struct NoDefault { + NoDefault() = delete; + explicit NoDefault(int) { } +}; + +struct NoExceptDefault { + NoExceptDefault() noexcept = default; +}; + +struct ThrowingDefault { + ThrowingDefault() { } +}; + int main() { { @@ -46,6 +60,20 @@ int main() assert(std::get<2>(t) == ""); assert(std::get<3>(t) == DefaultOnly()); } + { + // See bug #21157. + static_assert(!std::is_default_constructible>(), ""); + static_assert(!std::is_default_constructible>(), ""); + static_assert(!std::is_default_constructible>(), ""); + } + { + static_assert(noexcept(std::tuple()), ""); + static_assert(noexcept(std::tuple()), ""); + + static_assert(!noexcept(std::tuple()), ""); + static_assert(!noexcept(std::tuple()), ""); + static_assert(!noexcept(std::tuple()), ""); + } #ifndef _LIBCPP_HAS_NO_CONSTEXPR { constexpr std::tuple<> t; -- 2.7.4