[libc++] Rewrite the tuple constructors to be strictly Standards conforming
authorLouis Dionne <ldionne.2@gmail.com>
Wed, 10 Feb 2021 21:19:50 +0000 (16:19 -0500)
committerLouis Dionne <ldionne.2@gmail.com>
Fri, 23 Apr 2021 16:46:37 +0000 (12:46 -0400)
This nasty patch rewrites the tuple constructors to match those defined
by the Standard. We were previously providing several extensions in those
constructors - those extensions are removed by this patch.

The issue with those extensions is that we've had numerous bugs filed
against us over the years for problems essentially caused by them. As a
result, people are unable to use tuple in ways that are blessed by the
Standard, all that for the perceived benefit of providing them extensions
that they never asked for.

Since this is an API break, I communicated it in the release notes.
I do not foresee major issues with this break because I don't think the
extensions are too widely relied upon, but we can ship it and see if we
get complaints before the next LLVM release - that will give us some
amount of information regarding how much use these extensions have.

Differential Revision: https://reviews.llvm.org/D96523

25 files changed:
libcxx/docs/ReleaseNotes.rst
libcxx/docs/UsingLibcxx.rst
libcxx/include/tuple
libcxx/include/type_traits
libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp [deleted file]
libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp [deleted file]
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_binding_diagnostics.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR22806_constrain_tuple_like_ctor.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR23256_constrain_UTypes_ctor.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR27684_contains_ref_to_incomplete_type.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/PR31384.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/UTypes.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_Types.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_const_pair.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_copy.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_convert_move.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_copy.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/alloc_move_pair.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/const_Types.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/deduct.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp [new file with mode: 0644]
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/test_lazy_sfinae.pass.cpp
libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp [deleted file]

index 00ada48..1bcb26d 100644 (file)
@@ -43,4 +43,15 @@ New Features
 API Changes
 -----------
 
-- ...
+- There has been several changes in the tuple constructors provided by libc++.
+  Those changes were made as part of an effort to regularize libc++'s tuple
+  implementation, which contained several subtle bugs due to these extensions.
+  If you notice a build breakage when initializing a tuple, make sure you
+  properly initialize all the tuple elements - this is probably the culprit.
+
+  In particular, the extension allowing tuples to be constructed from fewer
+  elements than the number of elements in the tuple (in which case the remaining
+  elements would be default-constructed) has been removed. See https://godbolt.org/z/sqozjd.
+
+  Also, the extension allowing a tuple to be constructed from an array has been
+  removed. See https://godbolt.org/z/5esqbW.
index f7de6f6..f146abd 100644 (file)
@@ -165,33 +165,6 @@ thread safety annotations.
   headers. The intended use case is for clients who wish to use the libc++
   headers without taking a dependency on the libc++ library itself.
 
-**_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION**:
-  This macro is used to re-enable an extension in `std::tuple` which allowed
-  it to be implicitly constructed from fewer initializers than contained
-  elements. Elements without an initializer are default constructed. For example:
-
-  .. code-block:: cpp
-
-    std::tuple<std::string, int, std::error_code> foo() {
-      return {"hello world", 42}; // default constructs error_code
-    }
-
-
-  Since libc++ 4.0 this extension has been disabled by default. This macro
-  may be defined to re-enable it in order to support existing code that depends
-  on the extension. New use of this extension should be discouraged.
-  See `PR 27374 <https://llvm.org/PR27374>`_ for more information.
-
-  Note: The "reduced-arity-initialization" extension is still offered but only
-  for explicit conversions. Example:
-
-  .. code-block:: cpp
-
-    auto foo() {
-      using Tup = std::tuple<std::string, int, std::error_code>;
-      return Tup{"hello world", 42}; // explicit constructor called. OK.
-    }
-
 **_LIBCPP_DISABLE_ADDITIONAL_DIAGNOSTICS**:
   This macro disables the additional diagnostics generated by libc++ using the
   `diagnose_if` attribute. These additional diagnostics include checks for:
index 2b11a3f..9a58d6a 100644 (file)
@@ -449,165 +449,6 @@ class _LIBCPP_TEMPLATE_VIS tuple
 
     _BaseT __base_;
 
-#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION)
-    static constexpr bool _EnableImplicitReducedArityExtension = true;
-#else
-    static constexpr bool _EnableImplicitReducedArityExtension = false;
-#endif
-
-    template <class ..._Args>
-    struct _PackExpandsToThisTuple : false_type {};
-
-    template <class _Arg>
-    struct _PackExpandsToThisTuple<_Arg>
-        : is_same<typename __uncvref<_Arg>::type, tuple> {};
-
-    template <bool _MaybeEnable, class _Dummy = void>
-    struct _CheckArgsConstructor : __check_tuple_constructor_fail {};
-
-    template <class _Dummy>
-    struct _CheckArgsConstructor<true, _Dummy>
-    {
-        template <int&...>
-        static constexpr bool __enable_implicit_default() {
-           return __all<__is_implicitly_default_constructible<_Tp>::value... >::value;
-        }
-
-        template <int&...>
-        static constexpr bool __enable_explicit_default() {
-            return
-                __all<is_default_constructible<_Tp>::value...>::value &&
-                !__enable_implicit_default< >();
-        }
-
-
-        template <class ..._Args>
-        static constexpr bool __enable_explicit() {
-            return
-                __tuple_constructible<
-                    tuple<_Args...>,
-                    typename __make_tuple_types<tuple,
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value &&
-                !__tuple_convertible<
-                    tuple<_Args...>,
-                    typename __make_tuple_types<tuple,
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value &&
-                __all_default_constructible<
-                    typename __make_tuple_types<tuple, sizeof...(_Tp),
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value;
-        }
-
-        template <class ..._Args>
-        static constexpr bool __enable_implicit() {
-            return
-               __tuple_constructible<
-                    tuple<_Args...>,
-                    typename __make_tuple_types<tuple,
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value &&
-                __tuple_convertible<
-                    tuple<_Args...>,
-                    typename __make_tuple_types<tuple,
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value &&
-                __all_default_constructible<
-                    typename __make_tuple_types<tuple, sizeof...(_Tp),
-                             sizeof...(_Args) < sizeof...(_Tp) ?
-                                 sizeof...(_Args) :
-                                 sizeof...(_Tp)>::type
-                >::value;
-        }
-    };
-
-    template <bool _MaybeEnable,
-              bool = sizeof...(_Tp) == 1,
-              class _Dummy = void>
-    struct _CheckTupleLikeConstructor : __check_tuple_constructor_fail {};
-
-    template <class _Dummy>
-    struct _CheckTupleLikeConstructor<true, false, _Dummy>
-    {
-        template <class _Tuple>
-        static constexpr bool __enable_implicit() {
-            return __tuple_constructible<_Tuple, tuple>::value
-                && __tuple_convertible<_Tuple, tuple>::value;
-        }
-
-        template <class _Tuple>
-        static constexpr bool __enable_explicit() {
-            return __tuple_constructible<_Tuple, tuple>::value
-               && !__tuple_convertible<_Tuple, tuple>::value;
-        }
-    };
-
-    template <class _Dummy>
-    struct _CheckTupleLikeConstructor<true, true, _Dummy>
-    {
-        // This trait is used to disable the tuple-like constructor when
-        // the UTypes... constructor should be selected instead.
-        // See LWG issue #2549.
-        template <class _Tuple>
-        using _PreferTupleLikeConstructor = _Or<
-            // Don't attempt the two checks below if the tuple we are given
-            // has the same type as this tuple.
-            _IsSame<__uncvref_t<_Tuple>, tuple>,
-            _Lazy<_And,
-                _Not<is_constructible<_Tp..., _Tuple>>,
-                _Not<is_convertible<_Tuple, _Tp...>>
-            >
-        >;
-
-        template <class _Tuple>
-        static constexpr bool __enable_implicit() {
-            return _And<
-                __tuple_constructible<_Tuple, tuple>,
-                __tuple_convertible<_Tuple, tuple>,
-                _PreferTupleLikeConstructor<_Tuple>
-            >::value;
-        }
-
-        template <class _Tuple>
-        static constexpr bool __enable_explicit() {
-            return _And<
-                __tuple_constructible<_Tuple, tuple>,
-                _PreferTupleLikeConstructor<_Tuple>,
-                _Not<__tuple_convertible<_Tuple, tuple>>
-            >::value;
-        }
-    };
-
-    template <class _Tuple, bool _DisableIfLValue>
-    using _EnableImplicitTupleLikeConstructor = _EnableIf<
-                         _CheckTupleLikeConstructor<
-                             __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
-                             && !_PackExpandsToThisTuple<_Tuple>::value
-                             && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue)
-                         >::template __enable_implicit<_Tuple>(),
-                         bool
-                      >;
-
-    template <class _Tuple, bool _DisableIfLValue>
-    using _EnableExplicitTupleLikeConstructor = _EnableIf<
-                         _CheckTupleLikeConstructor<
-                             __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
-                             && !_PackExpandsToThisTuple<_Tuple>::value
-                             && (!is_lvalue_reference<_Tuple>::value || !_DisableIfLValue)
-                         >::template __enable_explicit<_Tuple>(),
-                         bool
-                      >;
     template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
         typename tuple_element<_Jp, tuple<_Up...> >::type& get(tuple<_Up...>&) _NOEXCEPT;
     template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
@@ -617,57 +458,69 @@ class _LIBCPP_TEMPLATE_VIS tuple
     template <size_t _Jp, class ..._Up> friend _LIBCPP_CONSTEXPR_AFTER_CXX11
         const typename tuple_element<_Jp, tuple<_Up...> >::type&& get(const tuple<_Up...>&&) _NOEXCEPT;
 public:
+    // [tuple.cnstr]
 
-    template <bool _Dummy = true, _EnableIf<
-        _CheckArgsConstructor<_Dummy>::__enable_implicit_default()
-    , void*> = nullptr>
+    // tuple() constructors (including allocator_arg_t variants)
+    template <template<class...> class _IsImpDefault = __is_implicitly_default_constructible, _EnableIf<
+        _And<
+            _IsImpDefault<_Tp>... // explicit check
+        >::value
+    , int> = 0>
     _LIBCPP_INLINE_VISIBILITY constexpr
     tuple()
-        _NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
-
-    template <bool _Dummy = true, _EnableIf<
-        _CheckArgsConstructor<_Dummy>::__enable_explicit_default()
-    , void*> = nullptr>
-    explicit _LIBCPP_INLINE_VISIBILITY constexpr
-    tuple()
-        _NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
+        _NOEXCEPT_(_And<is_nothrow_default_constructible<_Tp>...>::value)
+    { }
 
-    tuple(tuple const&) = default;
-    tuple(tuple&&) = default;
+    template <template<class...> class _IsImpDefault = __is_implicitly_default_constructible,
+              template<class...> class _IsDefault = is_default_constructible, _EnableIf<
+        _And<
+            _IsDefault<_Tp>...,
+            _Not<_Lazy<_And, _IsImpDefault<_Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    explicit tuple()
+        _NOEXCEPT_(_And<is_nothrow_default_constructible<_Tp>...>::value)
+    { }
 
-    template <class _AllocArgT, class _Alloc, _EnableIf<
-             _CheckArgsConstructor<_IsSame<allocator_arg_t, _AllocArgT>::value >::__enable_implicit_default()
-      , void*> = nullptr
-    >
+    template <class _Alloc, template<class...> class _IsImpDefault = __is_implicitly_default_constructible, _EnableIf<
+        _And<
+            _IsImpDefault<_Tp>... // explicit check
+        >::value
+    , int> = 0>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-    tuple(_AllocArgT, _Alloc const& __a)
+    tuple(allocator_arg_t, _Alloc const& __a)
       : __base_(allocator_arg_t(), __a,
                     __tuple_indices<>(), __tuple_types<>(),
                     typename __make_tuple_indices<sizeof...(_Tp), 0>::type(),
                     __tuple_types<_Tp...>()) {}
 
-    template <class _AllocArgT, class _Alloc, _EnableIf<
-             _CheckArgsConstructor<_IsSame<allocator_arg_t, _AllocArgT>::value>::__enable_explicit_default()
-      , void*> = nullptr
-    >
-    explicit _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-    tuple(_AllocArgT, _Alloc const& __a)
+    template <class _Alloc,
+              template<class...> class _IsImpDefault = __is_implicitly_default_constructible,
+              template<class...> class _IsDefault = is_default_constructible, _EnableIf<
+        _And<
+            _IsDefault<_Tp>...,
+            _Not<_Lazy<_And, _IsImpDefault<_Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, _Alloc const& __a)
       : __base_(allocator_arg_t(), __a,
                     __tuple_indices<>(), __tuple_types<>(),
                     typename __make_tuple_indices<sizeof...(_Tp), 0>::type(),
                     __tuple_types<_Tp...>()) {}
 
-    template <bool _Dummy = true,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                            _Dummy
-                         >::template __enable_implicit<_Tp const&...>(),
-                         bool
-                      >::type = false
-        >
+    // tuple(const T&...) constructors (including allocator_arg_t variants)
+    template <template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) >= 1>,
+            is_copy_constructible<_Tp>...,
+            is_convertible<const _Tp&, _Tp>... // explicit check
+        >::value
+    , int> = 0>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-    tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
+    tuple(const _Tp& ... __t)
+        _NOEXCEPT_(_And<is_nothrow_copy_constructible<_Tp>...>::value)
         : __base_(typename __make_tuple_indices<sizeof...(_Tp)>::type(),
                 typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
                 typename __make_tuple_indices<0>::type(),
@@ -675,17 +528,16 @@ public:
                 __t...
                ) {}
 
-    template <bool _Dummy = true,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                            _Dummy
-                         >::template __enable_explicit<_Tp const&...>(),
-                         bool
-                      >::type = false
-        >
+    template <template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) >= 1>,
+            is_copy_constructible<_Tp>...,
+            _Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-    explicit tuple(const _Tp& ... __t) _NOEXCEPT_((__all<is_nothrow_copy_constructible<_Tp>::value...>::value))
+    explicit tuple(const _Tp& ... __t)
+        _NOEXCEPT_(_And<is_nothrow_copy_constructible<_Tp>...>::value)
         : __base_(typename __make_tuple_indices<sizeof...(_Tp)>::type(),
                 typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
                 typename __make_tuple_indices<0>::type(),
@@ -693,17 +545,15 @@ public:
                 __t...
                ) {}
 
-    template <class _Alloc, bool _Dummy = true,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                            _Dummy
-                         >::template __enable_implicit<_Tp const&...>(),
-                         bool
-                      >::type = false
-        >
-      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
+    template <class _Alloc, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) >= 1>,
+            is_copy_constructible<_Tp>...,
+            is_convertible<const _Tp&, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
         : __base_(allocator_arg_t(), __a,
                 typename __make_tuple_indices<sizeof...(_Tp)>::type(),
                 typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
@@ -712,18 +562,15 @@ public:
                 __t...
                ) {}
 
-    template <class _Alloc, bool _Dummy = true,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                            _Dummy
-                         >::template __enable_explicit<_Tp const&...>(),
-                         bool
-                      >::type = false
-        >
-      _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-      explicit
-      tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
+    template <class _Alloc, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) >= 1>,
+            is_copy_constructible<_Tp>...,
+            _Not<_Lazy<_And, is_convertible<const _Tp&, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, const _Tp& ... __t)
         : __base_(allocator_arg_t(), __a,
                 typename __make_tuple_indices<sizeof...(_Tp)>::type(),
                 typename __make_tuple_types<tuple, sizeof...(_Tp)>::type(),
@@ -732,158 +579,368 @@ public:
                 __t...
                ) {}
 
-    template <class ..._Up,
-              bool _PackIsTuple = _PackExpandsToThisTuple<_Up...>::value,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                             sizeof...(_Up) == sizeof...(_Tp)
-                             && !_PackIsTuple
-                         >::template __enable_implicit<_Up...>() ||
-                        _CheckArgsConstructor<
-                            _EnableImplicitReducedArityExtension
-                            && sizeof...(_Up) < sizeof...(_Tp)
-                            && !_PackIsTuple
-                         >::template __enable_implicit<_Up...>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        tuple(_Up&&... __u)
-            _NOEXCEPT_((
-                is_nothrow_constructible<_BaseT,
-                    typename __make_tuple_indices<sizeof...(_Up)>::type,
-                    typename __make_tuple_types<tuple, sizeof...(_Up)>::type,
-                    typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type,
-                    typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type,
-                    _Up...
-                >::value
-            ))
-            : __base_(typename __make_tuple_indices<sizeof...(_Up)>::type(),
+    // tuple(U&& ...) constructors (including allocator_arg_t variants)
+    template <class ..._Up> struct _IsThisTuple : false_type { };
+    template <class _Up> struct _IsThisTuple<_Up> : is_same<__uncvref_t<_Up>, tuple> { };
+
+    template <class ..._Up>
+    struct _EnableUTypesCtor : _And<
+        _BoolConstant<sizeof...(_Tp) >= 1>,
+        _Not<_IsThisTuple<_Up...> >, // extension to allow mis-behaved user constructors
+        is_constructible<_Tp, _Up>...
+    > { };
+
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableUTypesCtor<_Up...>,
+            is_convertible<_Up, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    tuple(_Up&&... __u)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, _Up>...>::value))
+        : __base_(typename __make_tuple_indices<sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
                     typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
                     _VSTD::forward<_Up>(__u)...) {}
 
-    template <class ..._Up,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                             sizeof...(_Up) <= sizeof...(_Tp)
-                             && !_PackExpandsToThisTuple<_Up...>::value
-                         >::template __enable_explicit<_Up...>() ||
-                         _CheckArgsConstructor<
-                            !_EnableImplicitReducedArityExtension
-                            && sizeof...(_Up) < sizeof...(_Tp)
-                            && !_PackExpandsToThisTuple<_Up...>::value
-                         >::template __enable_implicit<_Up...>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        explicit
-        tuple(_Up&&... __u)
-            _NOEXCEPT_((
-                is_nothrow_constructible<_BaseT,
-                    typename __make_tuple_indices<sizeof...(_Up)>::type,
-                    typename __make_tuple_types<tuple, sizeof...(_Up)>::type,
-                    typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type,
-                    typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type,
-                    _Up...
-                >::value
-            ))
-            : __base_(typename __make_tuple_indices<sizeof...(_Up)>::type(),
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableUTypesCtor<_Up...>,
+            _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    explicit tuple(_Up&&... __u)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, _Up>...>::value))
+        : __base_(typename __make_tuple_indices<sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
                     typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
                     _VSTD::forward<_Up>(__u)...) {}
 
-    template <class _Alloc, class ..._Up,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                             sizeof...(_Up) == sizeof...(_Tp) &&
-                             !_PackExpandsToThisTuple<_Up...>::value
-                         >::template __enable_implicit<_Up...>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
-            : __base_(allocator_arg_t(), __a,
+    template <class _Alloc, class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableUTypesCtor<_Up...>,
+            is_convertible<_Up, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
+        : __base_(allocator_arg_t(), __a,
                     typename __make_tuple_indices<sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
                     typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
                     _VSTD::forward<_Up>(__u)...) {}
 
-    template <class _Alloc, class ..._Up,
-              typename enable_if
-                      <
-                         _CheckArgsConstructor<
-                             sizeof...(_Up) == sizeof...(_Tp) &&
-                             !_PackExpandsToThisTuple<_Up...>::value
-                         >::template __enable_explicit<_Up...>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-        explicit
-        tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
-            : __base_(allocator_arg_t(), __a,
+    template <class _Alloc, class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableUTypesCtor<_Up...>,
+            _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, _Up&&... __u)
+        : __base_(allocator_arg_t(), __a,
                     typename __make_tuple_indices<sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Up)>::type(),
                     typename __make_tuple_indices<sizeof...(_Tp), sizeof...(_Up)>::type(),
                     typename __make_tuple_types<tuple, sizeof...(_Tp), sizeof...(_Up)>::type(),
                     _VSTD::forward<_Up>(__u)...) {}
 
-    template <class _Tuple, _EnableImplicitTupleLikeConstructor<_Tuple, true> = false>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
-            : __base_(_VSTD::forward<_Tuple>(__t)) {}
+    // Copy and move constructors (including the allocator_arg_t variants)
+    tuple(const tuple&) = default;
+    tuple(tuple&&) = default;
 
-    template <class _Tuple, _EnableImplicitTupleLikeConstructor<const _Tuple&, false> = false>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value))
-            : __base_(__t) {}
-    template <class _Tuple, _EnableExplicitTupleLikeConstructor<_Tuple, true> = false>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        explicit
-        tuple(_Tuple&& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, _Tuple>::value))
-            : __base_(_VSTD::forward<_Tuple>(__t)) {}
+    template <class _Alloc, template<class...> class _And = _And, _EnableIf<
+        _And<is_copy_constructible<_Tp>...>::value
+    , int> = 0>
+    tuple(allocator_arg_t, const _Alloc& __alloc, const tuple& __t)
+        : __base_(allocator_arg_t(), __alloc, __t)
+    { }
+
+    template <class _Alloc, template<class...> class _And = _And, _EnableIf<
+        _And<is_move_constructible<_Tp>...>::value
+    , int> = 0>
+    tuple(allocator_arg_t, const _Alloc& __alloc, tuple&& __t)
+        : __base_(allocator_arg_t(), __alloc, _VSTD::move(__t))
+    { }
+
+    // tuple(const tuple<U...>&) constructors (including allocator_arg_t variants)
+    template <class ..._Up>
+    struct _EnableCopyFromOtherTuple : _And<
+        _Or<
+            _BoolConstant<sizeof...(_Tp) != 1>,
+            // _Tp and _Up are 1-element packs - the pack expansions look
+            // weird to avoid tripping up the type traits in degenerate cases
+            _Lazy<_And,
+                _Not<is_same<_Tp, _Up> >...,
+                _Not<is_convertible<const tuple<_Up>&, _Tp> >...,
+                _Not<is_constructible<_Tp, const tuple<_Up>&> >...
+            >
+        >,
+        is_constructible<_Tp, const _Up&>...
+    > { };
 
-    template <class _Tuple, _EnableExplicitTupleLikeConstructor<const _Tuple&, false> = false>
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
-        explicit
-        tuple(const _Tuple& __t) _NOEXCEPT_((is_nothrow_constructible<_BaseT, const _Tuple&>::value))
-            : __base_(__t) {}
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableCopyFromOtherTuple<_Up...>,
+            is_convertible<const _Up&, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    tuple(const tuple<_Up...>& __t)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, const _Up&>...>::value))
+        : __base_(__t)
+    { }
 
-    template <class _Alloc, class _Tuple,
-              typename enable_if
-                      <
-                         _CheckTupleLikeConstructor<
-                             __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
-                         >::template __enable_implicit<_Tuple>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
-            : __base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {}
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableCopyFromOtherTuple<_Up...>,
+            _Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    explicit tuple(const tuple<_Up...>& __t)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, const _Up&>...>::value))
+        : __base_(__t)
+    }
 
-    template <class _Alloc, class _Tuple,
-              typename enable_if
-                      <
-                         _CheckTupleLikeConstructor<
-                             __tuple_like_with_size<_Tuple, sizeof...(_Tp)>::value
-                         >::template __enable_explicit<_Tuple>(),
-                         bool
-                      >::type = false
-             >
-        _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
-        explicit
-        tuple(allocator_arg_t, const _Alloc& __a, _Tuple&& __t)
-            : __base_(allocator_arg_t(), __a, _VSTD::forward<_Tuple>(__t)) {}
+    template <class ..._Up, class _Alloc, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableCopyFromOtherTuple<_Up...>,
+            is_convertible<const _Up&, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t)
+        : __base_(allocator_arg_t(), __a, __t)
+    { }
+
+    template <class ..._Up, class _Alloc, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableCopyFromOtherTuple<_Up...>,
+            _Not<_Lazy<_And, is_convertible<const _Up&, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, const tuple<_Up...>& __t)
+        : __base_(allocator_arg_t(), __a, __t)
+    { }
+
+    // tuple(tuple<U...>&&) constructors (including allocator_arg_t variants)
+    template <class ..._Up>
+    struct _EnableMoveFromOtherTuple : _And<
+        _Or<
+            _BoolConstant<sizeof...(_Tp) != 1>,
+            // _Tp and _Up are 1-element packs - the pack expansions look
+            // weird to avoid tripping up the type traits in degenerate cases
+            _Lazy<_And,
+                _Not<is_same<_Tp, _Up> >...,
+                _Not<is_convertible<tuple<_Up>, _Tp> >...,
+                _Not<is_constructible<_Tp, tuple<_Up> > >...
+            >
+        >,
+        is_constructible<_Tp, _Up>...
+    > { };
+
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableMoveFromOtherTuple<_Up...>,
+            is_convertible<_Up, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    tuple(tuple<_Up...>&& __t)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, _Up>...>::value))
+        : __base_(_VSTD::move(__t))
+    { }
+
+    template <class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableMoveFromOtherTuple<_Up...>,
+            _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    explicit tuple(tuple<_Up...>&& __t)
+        _NOEXCEPT_((_And<is_nothrow_constructible<_Tp, _Up>...>::value))
+        : __base_(_VSTD::move(__t))
+    { }
+
+    template <class _Alloc, class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableMoveFromOtherTuple<_Up...>,
+            is_convertible<_Up, _Tp>... // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t)
+        : __base_(allocator_arg_t(), __a, _VSTD::move(__t))
+    { }
+
+    template <class _Alloc, class ..._Up, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>,
+            _EnableMoveFromOtherTuple<_Up...>,
+            _Not<_Lazy<_And, is_convertible<_Up, _Tp>...> > // explicit check
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, tuple<_Up...>&& __t)
+        : __base_(allocator_arg_t(), __a, _VSTD::move(__t))
+    { }
+
+    // tuple(const pair<U1, U2>&) constructors (including allocator_arg_t variants)
+    template <class _Up1, class _Up2, class ..._DependentTp>
+    struct _EnableImplicitCopyFromPair : _And<
+        is_constructible<_FirstType<_DependentTp...>, const _Up1&>,
+        is_constructible<_SecondType<_DependentTp...>, const _Up2&>,
+        is_convertible<const _Up1&, _FirstType<_DependentTp...> >, // explicit check
+        is_convertible<const _Up2&, _SecondType<_DependentTp...> >
+    > { };
+
+    template <class _Up1, class _Up2, class ..._DependentTp>
+    struct _EnableExplicitCopyFromPair : _And<
+        is_constructible<_FirstType<_DependentTp...>, const _Up1&>,
+        is_constructible<_SecondType<_DependentTp...>, const _Up2&>,
+        _Not<is_convertible<const _Up1&, _FirstType<_DependentTp...> > >, // explicit check
+        _Not<is_convertible<const _Up2&, _SecondType<_DependentTp...> > >
+    > { };
+
+    template <class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    tuple(const pair<_Up1, _Up2>& __p)
+        _NOEXCEPT_((_And<
+            is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>,
+            is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&>
+        >::value))
+        : __base_(__p)
+    { }
+
+    template <class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
+    explicit tuple(const pair<_Up1, _Up2>& __p)
+        _NOEXCEPT_((_And<
+            is_nothrow_constructible<_FirstType<_Tp...>, const _Up1&>,
+            is_nothrow_constructible<_SecondType<_Tp...>, const _Up2&>
+        >::value))
+        : __base_(__p)
+    { }
+
+    template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableImplicitCopyFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p)
+        : __base_(allocator_arg_t(), __a, __p)
+    { }
+
+    template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableExplicitCopyFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, const pair<_Up1, _Up2>& __p)
+        : __base_(allocator_arg_t(), __a, __p)
+    { }
+
+    // tuple(pair<U1, U2>&&) constructors (including allocator_arg_t variants)
+    template <class _Up1, class _Up2, class ..._DependentTp>
+    struct _EnableImplicitMoveFromPair : _And<
+        is_constructible<_FirstType<_DependentTp...>, _Up1>,
+        is_constructible<_SecondType<_DependentTp...>, _Up2>,
+        is_convertible<_Up1, _FirstType<_DependentTp...> >, // explicit check
+        is_convertible<_Up2, _SecondType<_DependentTp...> >
+    > { };
+
+    template <class _Up1, class _Up2, class ..._DependentTp>
+    struct _EnableExplicitMoveFromPair : _And<
+        is_constructible<_FirstType<_DependentTp...>, _Up1>,
+        is_constructible<_SecondType<_DependentTp...>, _Up2>,
+        _Not<is_convertible<_Up1, _FirstType<_DependentTp...> > >, // explicit check
+        _Not<is_convertible<_Up2, _SecondType<_DependentTp...> > >
+    > { };
+
+    template <class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY
+    tuple(pair<_Up1, _Up2>&& __p)
+        _NOEXCEPT_((_And<
+            is_nothrow_constructible<_FirstType<_Tp...>, _Up1>,
+            is_nothrow_constructible<_SecondType<_Tp...>, _Up2>
+        >::value))
+        : __base_(_VSTD::move(__p))
+    { }
+
+    template <class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY
+    explicit tuple(pair<_Up1, _Up2>&& __p)
+        _NOEXCEPT_((_And<
+            is_nothrow_constructible<_FirstType<_Tp...>, _Up1>,
+            is_nothrow_constructible<_SecondType<_Tp...>, _Up2>
+        >::value))
+        : __base_(_VSTD::move(__p))
+    { }
+
+    template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableImplicitMoveFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p)
+        : __base_(allocator_arg_t(), __a, _VSTD::move(__p))
+    { }
+
+    template <class _Alloc, class _Up1, class _Up2, template<class...> class _And = _And, _EnableIf<
+        _And<
+            _BoolConstant<sizeof...(_Tp) == 2>,
+            _EnableExplicitMoveFromPair<_Up1, _Up2, _Tp...>
+        >::value
+    , int> = 0>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
+    explicit tuple(allocator_arg_t, const _Alloc& __a, pair<_Up1, _Up2>&& __p)
+        : __base_(allocator_arg_t(), __a, _VSTD::move(__p))
+    { }
 
     // [tuple.assign]
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17
index 9ba5d25..e68021e 100644 (file)
@@ -3206,18 +3206,18 @@ _LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool is_default_constructible_v
 template <class _Tp>
 void __test_implicit_default_constructible(_Tp);
 
-template <class _Tp, class = void, bool = is_default_constructible<_Tp>::value>
+template <class _Tp, class = void, class = typename is_default_constructible<_Tp>::type>
 struct __is_implicitly_default_constructible
     : false_type
 { };
 
 template <class _Tp>
-struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), true>
+struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), true_type>
     : true_type
 { };
 
 template <class _Tp>
-struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), false>
+struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), false_type>
     : false_type
 { };
 #endif // !C++03
diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/disable_reduced_arity_initialization_extension.pass.cpp
deleted file mode 100644 (file)
index 53e8f5f..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <tuple>
-
-// template <class... Types> class tuple;
-
-// template <class... UTypes>
-//   explicit tuple(UTypes&&... u);
-
-// UNSUPPORTED: c++03
-
-#include <tuple>
-#include <cassert>
-#include <type_traits>
-#include <string>
-#include <system_error>
-
-#include "test_macros.h"
-#include "test_convertible.h"
-#include "MoveOnly.h"
-
-#if defined(_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION)
-#error This macro should not be defined by default
-#endif
-
-struct NoDefault { NoDefault() = delete; };
-
-
-// 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.
-void test_default_constructible_extension_sfinae()
-{
-    typedef MoveOnly MO;
-    typedef NoDefault ND;
-    {
-        typedef std::tuple<MO, ND> Tuple;
-        static_assert(!std::is_constructible<Tuple, MO>::value, "");
-        static_assert(std::is_constructible<Tuple, MO, ND>::value, "");
-        static_assert(test_convertible<Tuple, MO, ND>(), "");
-    }
-    {
-        typedef std::tuple<MO, MO, ND> Tuple;
-        static_assert(!std::is_constructible<Tuple, MO, MO>::value, "");
-        static_assert(std::is_constructible<Tuple, MO, MO, ND>::value, "");
-        static_assert(test_convertible<Tuple, MO, MO, ND>(), "");
-    }
-    {
-        // Same idea as above but with a nested tuple type.
-        typedef std::tuple<MO, ND> Tuple;
-        typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
-
-        static_assert(!std::is_constructible<
-            NestedTuple, MO, MO, MO, MO>::value, "");
-        static_assert(std::is_constructible<
-            NestedTuple, MO, Tuple, MO, MO>::value, "");
-    }
-}
-
-using ExplicitTup = std::tuple<std::string, int, std::error_code>;
-ExplicitTup doc_example() {
-      return ExplicitTup{"hello world", 42}; // explicit constructor called. OK.
-}
-
-// Test that the example given in UsingLibcxx.rst actually works.
-void test_example_from_docs() {
-  auto tup = doc_example();
-  assert(std::get<0>(tup) == "hello world");
-  assert(std::get<1>(tup) == 42);
-  assert(std::get<2>(tup) == std::error_code{});
-}
-
-int main(int, char**)
-{
-    {
-        using E = MoveOnly;
-        using Tup = std::tuple<E, E, E>;
-        // Test that the reduced arity initialization extension is only
-        // allowed on the explicit constructor.
-        static_assert(test_convertible<Tup, E, E, E>(), "");
-
-        Tup t(E(0), E(1));
-        static_assert(std::is_constructible<Tup, E, E>::value, "");
-        static_assert(!test_convertible<Tup, E, E>(), "");
-        assert(std::get<0>(t) == E(0));
-        assert(std::get<1>(t) == E(1));
-        assert(std::get<2>(t) == E());
-
-        Tup t2(E(0));
-        static_assert(std::is_constructible<Tup, E>::value, "");
-        static_assert(!test_convertible<Tup, E>(), "");
-        assert(std::get<0>(t2) == E(0));
-        assert(std::get<1>(t2) == E());
-        assert(std::get<2>(t2) == E());
-    }
-    // Check that SFINAE is properly applied with the default reduced arity
-    // constructor extensions.
-    test_default_constructible_extension_sfinae();
-    test_example_from_docs();
-
-  return 0;
-}
diff --git a/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp b/libcxx/test/libcxx/utilities/tuple/tuple.tuple/tuple.cnstr/enable_reduced_arity_initialization_extension.pass.cpp
deleted file mode 100644 (file)
index 5f941ad..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// <tuple>
-
-// template <class... Types> class tuple;
-
-// template <class... UTypes>
-//   explicit tuple(UTypes&&... u);
-
-// UNSUPPORTED: c++03
-
-// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_TUPLE_IMPLICIT_REDUCED_ARITY_EXTENSION
-
-#include <tuple>
-#include <cassert>
-#include <type_traits>
-#include <string>
-#include <system_error>
-
-#include "test_macros.h"
-#include "test_convertible.h"
-#include "MoveOnly.h"
-
-
-struct NoDefault { NoDefault() = delete; };
-
-
-// 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.
-void test_default_constructible_extension_sfinae()
-{
-    typedef MoveOnly MO;
-    typedef NoDefault ND;
-    {
-        typedef std::tuple<MO, ND> Tuple;
-        static_assert(!std::is_constructible<Tuple, MO>::value, "");
-        static_assert(std::is_constructible<Tuple, MO, ND>::value, "");
-        static_assert(test_convertible<Tuple, MO, ND>(), "");
-    }
-    {
-        typedef std::tuple<MO, MO, ND> Tuple;
-        static_assert(!std::is_constructible<Tuple, MO, MO>::value, "");
-        static_assert(std::is_constructible<Tuple, MO, MO, ND>::value, "");
-        static_assert(test_convertible<Tuple, MO, MO, ND>(), "");
-    }
-    {
-        // Same idea as above but with a nested tuple type.
-        typedef std::tuple<MO, ND> Tuple;
-        typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
-
-        static_assert(!std::is_constructible<
-            NestedTuple, MO, MO, MO, MO>::value, "");
-        static_assert(std::is_constructible<
-            NestedTuple, MO, Tuple, MO, MO>::value, "");
-    }
-    {
-        typedef std::tuple<MO, int> Tuple;
-        typedef std::tuple<MO, Tuple, MO, MO> NestedTuple;
-
-        static_assert(std::is_constructible<
-            NestedTuple, MO, MO, MO, MO>::value, "");
-        static_assert(test_convertible<
-            NestedTuple, MO, MO, MO, MO>(), "");
-
-        static_assert(std::is_constructible<
-            NestedTuple, MO, Tuple, MO, MO>::value, "");
-        static_assert(test_convertible<
-            NestedTuple, MO, Tuple, MO, MO>(), "");
-    }
-}
-
-std::tuple<std::string, int, std::error_code> doc_example() {
-      return {"hello world", 42};
-}
-
-// Test that the example given in UsingLibcxx.rst actually works.
-void test_example_from_docs() {
-  auto tup = doc_example();
-  assert(std::get<0>(tup) == "hello world");
-  assert(std::get<1>(tup) == 42);
-  assert(std::get<2>(tup) == std::error_code{});
-}
-
-int main(int, char**)
-{
-
-    {
-        using E = MoveOnly;
-        using Tup = std::tuple<E, E, E>;
-        static_assert(test_convertible<Tup, E, E, E>(), "");
-
-        Tup t = {E(0), E(1)};
-        static_assert(test_convertible<Tup, E, E>(), "");
-        assert(std::get<0>(t) == E(0));
-        assert(std::get<1>(t) == E(1));
-        assert(std::get<2>(t) == E());
-
-        Tup t2 = {E(0)};
-        static_assert(test_convertible<Tup, E>(), "");
-        assert(std::get<0>(t2) == E(0));
-        assert(std::get<1>(t2) == E());
-        assert(std::get<2>(t2) == E());
-    }
-    // Check that SFINAE is properly applied with the default reduced arity
-    // constructor extensions.
-    test_default_constructible_extension_sfinae();
-    test_example_from_docs();
-
-  return 0;
-}
index 09a9bdf..648f8bf 100644 (file)
 
 // template <class... Types> class tuple;
 
-// template <class TupleLike>
-//   tuple(TupleLike&&);
-// template <class Alloc, class TupleLike>
-//   tuple(std::allocator_arg_t, Alloc const&, TupleLike&&);
-
 // Check that the tuple-like ctors are properly disabled when the UTypes...
-// constructor should be selected. See PR22806.
+// constructor should be selected.
+//
+// See https://llvm.org/PR22806.
 
 #include <tuple>
 #include <memory>
index f2c66f4..ebc31ce 100644 (file)
 //    EXPLICIT(...) tuple(UTypes&&...)
 
 // Check that the UTypes... ctor is properly disabled before evaluating any
-// SFINAE when the tuple-like copy/move ctor should *clearly* be selected
+// SFINAE when the copy/move ctor from another tuple should clearly be selected
 // instead. This happens 'sizeof...(UTypes) == 1' and the first element of
-// 'UTypes...' is an instance of the tuple itself. See PR23256.
+// 'UTypes...' is an instance of the tuple itself.
+//
+// See https://llvm.org/PR23256.
 
 #include <tuple>
 #include <memory>
index a3289eb..cdc0ec2 100644 (file)
 
 // template <class Alloc> tuple(allocator_arg_t, Alloc const&)
 
-// Libc++ has to deduce the 'allocator_arg_t' parameter for this constructor
-// as 'AllocArgT'. Previously libc++ has tried to support tags derived from
-// 'allocator_arg_t' by using 'is_base_of<AllocArgT, allocator_arg_t>'.
-// However this breaks whenever a 2-tuple contains a reference to an incomplete
-// type as its first parameter. See PR27684.
+// See https://llvm.org/PR27684.
 
 #include <tuple>
 #include <cassert>
index 055d9cb..20f64da 100644 (file)
@@ -9,11 +9,8 @@
 
 // UNSUPPORTED: c++03
 
-// <tuple>
+// See https://llvm.org/PR31384.
 
-// template <class TupleLike> tuple(TupleLike&&); // libc++ extension
-
-// See llvm.org/PR31384
 #include <tuple>
 #include <cassert>
 
@@ -50,42 +47,51 @@ int main(int, char**) {
   {
     std::tuple<Explicit> foo = Derived<int>{42}; ((void)foo);
     assert(count == 1);
-    std::tuple<Explicit> bar(Derived<int>{42}); ((void)bar);
+    Derived<int> d{42};
+    std::tuple<Explicit> bar(std::move(d)); ((void)bar);
+#if TEST_STD_VER < 17
+    assert(count == 1);
+#else
     assert(count == 2);
+#endif
   }
   count = 0;
   {
     std::tuple<Implicit> foo = Derived<int>{42}; ((void)foo);
     assert(count == 1);
-    std::tuple<Implicit> bar(Derived<int>{42}); ((void)bar);
+    Derived<int> d{42};
+    std::tuple<Implicit> bar(std::move(d)); ((void)bar);
+#if TEST_STD_VER < 17
+    assert(count == 1);
+#else
     assert(count == 2);
+#endif
   }
   count = 0;
   {
-    static_assert(!std::is_convertible<
-        ExplicitDerived<int>, std::tuple<Explicit>>::value, "");
-    std::tuple<Explicit> bar(ExplicitDerived<int>{42}); ((void)bar);
+    static_assert(!std::is_convertible<ExplicitDerived<int>, std::tuple<Explicit>>::value, "");
+    ExplicitDerived<int> d{42};
+    std::tuple<Explicit> bar(std::move(d)); ((void)bar);
+#if TEST_STD_VER < 17
+    assert(count == 0);
+#else
     assert(count == 1);
+#endif
   }
   count = 0;
   {
-    // FIXME: Libc++ incorrectly rejects this code.
-#ifndef _LIBCPP_VERSION
     std::tuple<Implicit> foo = ExplicitDerived<int>{42}; ((void)foo);
-    static_assert(std::is_convertible<
-        ExplicitDerived<int>, std::tuple<Implicit>>::value,
-        "correct STLs accept this");
-#else
-    static_assert(!std::is_convertible<
-        ExplicitDerived<int>, std::tuple<Implicit>>::value,
-        "libc++ incorrectly rejects this");
-#endif
+    static_assert(std::is_convertible<ExplicitDerived<int>, std::tuple<Implicit>>::value, "");
     assert(count == 0);
-    std::tuple<Implicit> bar(ExplicitDerived<int>{42}); ((void)bar);
+    ExplicitDerived<int> d{42};
+    std::tuple<Implicit> bar(std::move(d)); ((void)bar);
+#if TEST_STD_VER < 17
+    assert(count == 0);
+#else
     assert(count == 1);
+#endif
   }
   count = 0;
 
-
   return 0;
 }
index c28e49a..d6e41a4 100644 (file)
@@ -36,11 +36,9 @@ struct A
 
 struct NoDefault { NoDefault() = delete; };
 
-// 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.
-void test_default_constructible_extension_sfinae()
+// Make sure the _Up... constructor SFINAEs out when there are fewer
+// constructor arguments than tuple elements.
+void test_sfinae_missing_elements()
 {
     {
         typedef std::tuple<MoveOnly, NoDefault> Tuple;
@@ -83,23 +81,6 @@ void test_default_constructible_extension_sfinae()
             MoveOnly, Tuple, MoveOnly, MoveOnly
         >::value, "");
     }
-    // testing extensions
-#ifdef _LIBCPP_VERSION
-    {
-        typedef std::tuple<MoveOnly, int> Tuple;
-        typedef std::tuple<MoveOnly, Tuple, MoveOnly, MoveOnly> NestedTuple;
-
-        static_assert(std::is_constructible<
-            NestedTuple,
-            MoveOnly, MoveOnly, MoveOnly, MoveOnly
-        >::value, "");
-
-        static_assert(std::is_constructible<
-            NestedTuple,
-            MoveOnly, Tuple, MoveOnly, MoveOnly
-        >::value, "");
-    }
-#endif
 }
 
 int main(int, char**)
@@ -121,28 +102,6 @@ int main(int, char**)
         assert(std::get<1>(t) == 1);
         assert(std::get<2>(t) == 2);
     }
-    // extensions
-#ifdef _LIBCPP_VERSION
-    {
-        using E = MoveOnly;
-        using Tup = std::tuple<E, E, E>;
-        // Test that the reduced arity initialization extension is only
-        // allowed on the explicit constructor.
-        static_assert(test_convertible<Tup, E, E, E>(), "");
-
-        Tup t(E(0), E(1));
-        static_assert(!test_convertible<Tup, E, E>(), "");
-        assert(std::get<0>(t) == E(0));
-        assert(std::get<1>(t) == E(1));
-        assert(std::get<2>(t) == E());
-
-        Tup t2(E(0));
-        static_assert(!test_convertible<Tup, E>(), "");
-        assert(std::get<0>(t2) == E(0));
-        assert(std::get<1>(t2) == E());
-        assert(std::get<2>(t2) == E());
-    }
-#endif
 #if TEST_STD_VER > 11
     {
         constexpr std::tuple<Empty> t0{Empty()};
@@ -153,9 +112,8 @@ int main(int, char**)
         static_assert(std::get<0>(t).id_ == 3, "");
     }
 #endif
-    // Check that SFINAE is properly applied with the default reduced arity
-    // constructor extensions.
-    test_default_constructible_extension_sfinae();
+
+    test_sfinae_missing_elements();
 
   return 0;
 }
index 5267f69..f3ddc85 100644 (file)
 // template <class Alloc>
 //   explicit(see-below) tuple(allocator_arg_t, const Alloc& a);
 
-// NOTE: this constructor does not currently support tags derived from
-// allocator_arg_t because libc++ has to deduce the parameter as a template
-// argument. See PR27684 (https://llvm.org/PR27684)
-
 #include <tuple>
 #include <cassert>
 
@@ -95,6 +91,14 @@ int main(int, char**)
         assert(std::get<2>(t) == alloc_last());
     }
     {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<> t1(derived, A1<int>());
+        std::tuple<int> t2(derived, A1<int>());
+        std::tuple<int, int> t3(derived, A1<int>());
+    }
+    {
         // Test that the uses-allocator default constructor does not evaluate
         // its SFINAE when it otherwise shouldn't be selected. Do this by
         // using 'NonDefaultConstructible' which will cause a compile error
index f5055b3..2ded9d5 100644 (file)
@@ -95,6 +95,14 @@ int main(int, char**)
         assert(!alloc_last::allocator_constructed);
         assert(std::get<2>(t) == alloc_last(3));
     }
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<> t1(derived, A1<int>());
+        std::tuple<int> t2(derived, A1<int>(), 1);
+        std::tuple<int, int> t3(derived, A1<int>(), 1, 2);
+    }
 
-  return 0;
+    return 0;
 }
index 0772e21..6b81f71 100644 (file)
@@ -56,6 +56,13 @@ int main(int, char**)
         assert(std::get<0>(t1) == 2);
         assert(std::get<1>(t1) == 3);
     }
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::pair<int, int> p(1, 2);
+        std::tuple<int, int> t(derived, A1<int>(), p);
+    }
 
-  return 0;
+    return 0;
 }
index 1f784bf..681e2e7 100644 (file)
@@ -87,6 +87,13 @@ int main(int, char**)
         std::tuple<Implicit> t2 = {std::allocator_arg, std::allocator<int>{}, t1};
         assert(std::get<0>(t2).value == 42);
     }
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<long> from(3l);
+        std::tuple<long long> t0(derived, A1<int>(), from);
+    }
 
-  return 0;
+    return 0;
 }
index 7179bf9..b823e8f 100644 (file)
@@ -101,6 +101,13 @@ int main(int, char**)
         std::tuple<Implicit> t2 = {std::allocator_arg, std::allocator<int>{}, std::move(t1)};
         assert(std::get<0>(t2).value == 42);
     }
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<long> from(3l);
+        std::tuple<long long> t0(derived, A1<int>(), std::move(from));
+    }
 
-  return 0;
+    return 0;
 }
index e101808..72a8fbf 100644 (file)
@@ -52,8 +52,6 @@ int main(int, char**)
         assert(alloc_last::allocator_constructed);
         assert(std::get<0>(t) == 2);
     }
-// testing extensions
-#ifdef _LIBCPP_VERSION
     {
         typedef std::tuple<alloc_first, alloc_last> T;
         T t0(2, 3);
@@ -77,7 +75,13 @@ int main(int, char**)
         assert(std::get<1>(t) == 2);
         assert(std::get<2>(t) == 3);
     }
-#endif
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<int> from(3);
+        std::tuple<int> t0(derived, A1<int>(), from);
+    }
 
-  return 0;
+    return 0;
 }
index 58de67e..d13f76f 100644 (file)
@@ -53,8 +53,6 @@ int main(int, char**)
         assert(alloc_last::allocator_constructed);
         assert(std::get<0>(t) == 1);
     }
-// testing extensions
-#ifdef _LIBCPP_VERSION
     {
         typedef std::tuple<MoveOnly, alloc_first> T;
         T t0(0 ,1);
@@ -76,7 +74,13 @@ int main(int, char**)
         assert(std::get<1>(t) == 2);
         assert(std::get<2>(t) == 3);
     }
-#endif
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::tuple<int> from(3);
+        std::tuple<int> t0(derived, A1<int>(), std::move(from));
+    }
 
-  return 0;
+    return 0;
 }
index ee8e005..e7e438e 100644 (file)
@@ -52,6 +52,13 @@ int main(int, char**)
         assert(std::get<0>(t1) == 2);
         assert(std::get<1>(t1)->id_ == 3);
     }
+    {
+        // Test that we can use a tag derived from allocator_arg_t
+        struct DerivedFromAllocatorArgT : std::allocator_arg_t { };
+        DerivedFromAllocatorArgT derived;
+        std::pair<int, int> from(1, 2);
+        std::tuple<int, int> t0(derived, A1<int>(), std::move(from));
+    }
 
-  return 0;
+    return 0;
 }
index b78cc06..9609abb 100644 (file)
@@ -137,28 +137,6 @@ int main(int, char**)
         assert(std::get<2>(t) == 2);
         assert(std::get<3>(t) == 3);
     }
-// extensions
-#ifdef _LIBCPP_VERSION
-    {
-        std::tuple<int, char*, std::string> t(2);
-        assert(std::get<0>(t) == 2);
-        assert(std::get<1>(t) == nullptr);
-        assert(std::get<2>(t) == "");
-    }
-    {
-        std::tuple<int, char*, std::string> t(2, nullptr);
-        assert(std::get<0>(t) == 2);
-        assert(std::get<1>(t) == nullptr);
-        assert(std::get<2>(t) == "");
-    }
-    {
-        std::tuple<int, char*, std::string, double> t(2, nullptr, "text");
-        assert(std::get<0>(t) == 2);
-        assert(std::get<1>(t) == nullptr);
-        assert(std::get<2>(t) == "text");
-        assert(std::get<3>(t) == 0.0);
-    }
-#endif
 
   return 0;
 }
index db0958c..b882e66 100644 (file)
@@ -13,7 +13,7 @@
 // GCC's implementation of class template deduction is still immature and runs
 // into issues with libc++. However GCC accepts this code when compiling
 // against libstdc++.
-// XFAIL: gcc-5, gcc-6, gcc-7
+// XFAIL: gcc-5, gcc-6, gcc-7, gcc-8, gcc-9, gcc-10
 
 // <tuple>
 
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.lazy.verify.cpp
new file mode 100644 (file)
index 0000000..e3ad94d
--- /dev/null
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test makes sure that we don't evaluate `is_default_constructible<T>`
+// too early in std::tuple's default constructor.
+
+// UNSUPPORTED: c++03
+
+#include <tuple>
+
+#include "test_macros.h"
+
+struct Outer {
+    template <class T>
+    struct Inner {
+        bool foo = false;
+    };
+    std::tuple<Inner<int>> tup;
+};
+
+Outer x; // expected-no-diagnostics
index 7f7c76c..93f8fbc 100644 (file)
 
 // UNSUPPORTED: c++03
 
+// Test the following constructors:
+// (1) tuple(Types const&...)
+// (2) tuple(UTypes&&...)
+// Test that (1) short circuits before evaluating the copy constructor of the
+// second argument. Constructor (2) should be selected.
+
 #include <tuple>
 #include <utility>
 #include <cassert>
 
 #include "test_macros.h"
 
-template <class ConstructFrom>
-struct ConstructibleFromT {
-  ConstructibleFromT() = default;
-  ConstructibleFromT(ConstructFrom v) : value(v) {}
-  ConstructFrom value;
-};
-
-template <class AssertOn>
-struct CtorAssertsT {
-  bool defaulted;
-  CtorAssertsT() : defaulted(true) {}
-  template <class T>
-  constexpr CtorAssertsT(T) : defaulted(false) {
-      static_assert(!std::is_same<T, AssertOn>::value, "");
-  }
-};
-
-template <class AllowT, class AssertT>
-struct AllowAssertT {
-  AllowAssertT() = default;
-  AllowAssertT(AllowT) {}
-  template <class U>
-  constexpr AllowAssertT(U) {
-      static_assert(!std::is_same<U, AssertT>::value, "");
-  }
-};
-
-// Construct a tuple<T1, T2> from pair<int, int> where T1 and T2
-// are not constructible from ints but T1 is constructible from std::pair.
-// This considers the following constructors:
-// (1) tuple(TupleLike) -> checks is_constructible<Tn, int>
-// (2) tuple(UTypes...) -> checks is_constructible<T1, pair<int, int>>
-//                            and is_default_constructible<T2>
-// The point of this test is to ensure that the consideration of (1)
-// short circuits before evaluating is_constructible<T2, int>, which
-// will cause a static assertion.
-void test_tuple_like_lazy_sfinae() {
-#if defined(_LIBCPP_VERSION)
-    // This test requires libc++'s reduced arity initialization.
-    using T1 = ConstructibleFromT<std::pair<int, int>>;
-    using T2 = CtorAssertsT<int>;
-    std::pair<int, int> p(42, 100);
-    std::tuple<T1, T2> t(p);
-    assert(std::get<0>(t).value == p);
-    assert(std::get<1>(t).defaulted);
-#endif
-}
-
-
 struct NonConstCopyable {
   NonConstCopyable() = default;
   explicit NonConstCopyable(int v) : value(v) {}
@@ -84,22 +41,11 @@ struct BlowsUpOnConstCopy {
   BlowsUpOnConstCopy(BlowsUpOnConstCopy&) = default;
 };
 
-// Test the following constructors:
-// (1) tuple(Types const&...)
-// (2) tuple(UTypes&&...)
-// Test that (1) short circuits before evaluating the copy constructor of the
-// second argument. Constructor (2) should be selected.
-void test_const_Types_lazy_sfinae()
-{
-    NonConstCopyable v(42);
-    BlowsUpOnConstCopy<int> b;
-    std::tuple<NonConstCopyable, BlowsUpOnConstCopy<int>> t(v, b);
-    assert(std::get<0>(t).value == 42);
-}
-
 int main(int, char**) {
-    test_tuple_like_lazy_sfinae();
-    test_const_Types_lazy_sfinae();
+  NonConstCopyable v(42);
+  BlowsUpOnConstCopy<int> b;
+  std::tuple<NonConstCopyable, BlowsUpOnConstCopy<int>> t(v, b);
+  assert(std::get<0>(t).value == 42);
 
   return 0;
 }
diff --git a/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp b/libcxx/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/tuple_array_template_depth.pass.cpp
deleted file mode 100644 (file)
index 11ba79a..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-// UNSUPPORTED: c++03
-
-// <tuple>
-
-// template <class... Types> class tuple;
-
-// template <class Tuple, __tuple_convertible<Tuple, tuple> >
-//   tuple(Tuple &&);
-//
-// template <class Tuple, __tuple_constructible<Tuple, tuple> >
-//   tuple(Tuple &&);
-
-// This test checks that we do not evaluate __make_tuple_types
-// on the array.
-
-#include <array>
-#include <tuple>
-
-#include "test_macros.h"
-
-// Use 1256 to try and blow the template instantiation depth for all compilers.
-typedef std::array<char, 1256> array_t;
-typedef std::tuple<array_t> tuple_t;
-
-int main(int, char**)
-{
-    array_t arr;
-    tuple_t tup(arr);
-
-  return 0;
-}