[libc++] Take 2: Implement LWG 2510

Summary:
LWG2510 makes tag types like allocator_arg_t explicitly default
constructible instead of implicitly default constructible. It also
makes the constructors for std::pair and std::tuple conditionally
explicit based on the explicit-ness of the default constructibility
for the pair/tuple's elements.

This was previously committed as r372777 and reverted in r372832 due to
the commit breaking LLVM's build in C++14 mode. This issue has now been
addressed.

Reviewers: mclow.lists

Subscribers: christof, jkorous, dexonsmith, libcxx-commits

Tags: #libc

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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@372983 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/__functional_base b/include/__functional_base
index 9587d7a..ca761c4 100644
--- a/include/__functional_base
+++ b/include/__functional_base
@@ -558,7 +558,7 @@
 
 // allocator_arg_t
 
-struct _LIBCPP_TEMPLATE_VIS allocator_arg_t { };
+struct _LIBCPP_TEMPLATE_VIS allocator_arg_t { explicit allocator_arg_t() = default; };
 
 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
 extern _LIBCPP_EXPORTED_FROM_ABI const allocator_arg_t allocator_arg;
diff --git a/include/__mutex_base b/include/__mutex_base
index a4ac361..ed75c82 100644
--- a/include/__mutex_base
+++ b/include/__mutex_base
@@ -66,9 +66,9 @@
 static_assert(is_nothrow_default_constructible<mutex>::value,
               "the default constructor for std::mutex must be nothrow");
 
-struct _LIBCPP_TYPE_VIS defer_lock_t {};
-struct _LIBCPP_TYPE_VIS try_to_lock_t {};
-struct _LIBCPP_TYPE_VIS adopt_lock_t {};
+struct _LIBCPP_TYPE_VIS defer_lock_t { explicit defer_lock_t() = default; };
+struct _LIBCPP_TYPE_VIS try_to_lock_t { explicit try_to_lock_t() = default; };
+struct _LIBCPP_TYPE_VIS adopt_lock_t { explicit adopt_lock_t() = default; };
 
 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
 
diff --git a/include/mutex b/include/mutex
index dca6220..8fc3c61 100644
--- a/include/mutex
+++ b/include/mutex
@@ -86,9 +86,9 @@
     void unlock();
 };
 
-struct defer_lock_t {};
-struct try_to_lock_t {};
-struct adopt_lock_t {};
+struct defer_lock_t { explicit defer_lock_t() = default; };
+struct try_to_lock_t { explicit try_to_lock_t() = default; };
+struct adopt_lock_t { explicit adopt_lock_t() = default; };
 
 inline constexpr defer_lock_t  defer_lock{};
 inline constexpr try_to_lock_t try_to_lock{};
diff --git a/include/new b/include/new
index 85e4c4b..40d351e 100644
--- a/include/new
+++ b/include/new
@@ -39,7 +39,7 @@
 };
 inline constexpr destroying_delete_t destroying_delete{}; // C++20
 
-struct nothrow_t {};
+struct nothrow_t { explicit nothrow_t() = default; };
 extern const nothrow_t nothrow;
 typedef void (*new_handler)();
 new_handler set_new_handler(new_handler new_p) noexcept;
@@ -126,7 +126,7 @@
 {
 
 #if !defined(_LIBCPP_ABI_VCRUNTIME)
-struct _LIBCPP_TYPE_VIS nothrow_t {};
+struct _LIBCPP_TYPE_VIS nothrow_t { explicit nothrow_t() = default; };
 extern _LIBCPP_FUNC_VIS const nothrow_t nothrow;
 
 class _LIBCPP_EXCEPTION_ABI bad_alloc
diff --git a/include/tuple b/include/tuple
index 32bc869..c33b48a 100644
--- a/include/tuple
+++ b/include/tuple
@@ -19,7 +19,7 @@
 template <class... T>
 class tuple {
 public:
-    constexpr tuple();
+    explicit(see-below) constexpr tuple();
     explicit(see-below) tuple(const T&...);  // constexpr in C++14
     template <class... U>
         explicit(see-below) tuple(U&&...);  // constexpr in C++14
@@ -500,8 +500,19 @@
     struct _CheckArgsConstructor<true, _Dummy>
     {
         template <class ..._Args>
-        static constexpr bool __enable_default() {
-            return __all<is_default_constructible<_Args>::value...>::value;
+        static constexpr bool __enable_implicit_default() {
+            // In C++03, there's no way to implement the resolution of LWG2510.
+#ifdef _LIBCPP_CXX03_LANG
+            return true;
+#else
+            return __all<__is_implicitly_default_constructible<_Args>::value...>::value;
+#endif
+        }
+
+        template <class ..._Args>
+        static constexpr bool __enable_explicit_default() {
+            return __all<is_default_constructible<_Args>::value...>::value
+                && !__enable_implicit_default<_Args...>();
         }
 
         template <class ..._Args>
@@ -641,11 +652,18 @@
         const typename tuple_element<_Jp, tuple<_Up...> >::type&& get(const tuple<_Up...>&&) _NOEXCEPT;
 public:
 
-    template <bool _Dummy = true, class = typename enable_if<
-        _CheckArgsConstructor<_Dummy>::template __enable_default<_Tp...>()
-    >::type>
-    _LIBCPP_INLINE_VISIBILITY
-    _LIBCPP_CONSTEXPR tuple()
+    template <bool _Dummy = true, _EnableIf<
+        _CheckArgsConstructor<_Dummy>::template __enable_implicit_default<_Tp...>()
+    , void*> = nullptr>
+    _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    tuple()
+        _NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
+
+    template <bool _Dummy = true, _EnableIf<
+        _CheckArgsConstructor<_Dummy>::template __enable_explicit_default<_Tp...>()
+    , void*> = nullptr>
+    explicit _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    tuple()
         _NOEXCEPT_(__all<is_nothrow_default_constructible<_Tp>::value...>::value) {}
 
     tuple(tuple const&) = default;
diff --git a/include/type_traits b/include/type_traits
index ee17824..77dcc23 100644
--- a/include/type_traits
+++ b/include/type_traits
@@ -2807,6 +2807,30 @@
     = is_default_constructible<_Tp>::value;
 #endif
 
+#ifndef _LIBCPP_CXX03_LANG
+// First of all, we can't implement this check in C++03 mode because the {}
+// default initialization syntax isn't valid.
+// Second, we implement the trait in a funny manner with two defaulted template
+// arguments to workaround Clang's PR43454.
+template <class _Tp>
+void __test_implicit_default_constructible(_Tp);
+
+template <class _Tp, class = void, bool = is_default_constructible<_Tp>::value>
+struct __is_implicitly_default_constructible
+    : false_type
+{ };
+
+template <class _Tp>
+struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), true>
+    : true_type
+{ };
+
+template <class _Tp>
+struct __is_implicitly_default_constructible<_Tp, decltype(__test_implicit_default_constructible<_Tp const&>({})), false>
+    : false_type
+{ };
+#endif // !C++03
+
 // is_copy_constructible
 
 template <class _Tp>
diff --git a/include/utility b/include/utility
index 64599c8..c90d049 100644
--- a/include/utility
+++ b/include/utility
@@ -69,7 +69,7 @@
 
     pair(const pair&) = default;
     pair(pair&&) = default;
-    constexpr pair();
+    explicit(see-below) constexpr pair();
     explicit(see-below) pair(const T1& x, const T2& y);                          // constexpr in C++14
     template <class U, class V> explicit(see-below) pair(U&& x, V&& y);          // constexpr in C++14
     template <class U, class V> explicit(see-below) pair(const pair<U, V>& p);   // constexpr in C++14
@@ -99,7 +99,7 @@
 void
 swap(pair<T1, T2>& x, pair<T1, T2>& y) noexcept(noexcept(x.swap(y)));
 
-struct piecewise_construct_t { };
+struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
 inline constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();
 
 template <class T> struct tuple_size;
@@ -276,7 +276,7 @@
 template <class _Tp>                        void as_const(const _Tp&&) = delete;
 #endif
 
-struct _LIBCPP_TEMPLATE_VIS piecewise_construct_t { };
+struct _LIBCPP_TEMPLATE_VIS piecewise_construct_t { explicit piecewise_construct_t() = default; };
 #if defined(_LIBCPP_CXX03_LANG) || defined(_LIBCPP_BUILDING_LIBRARY)
 extern _LIBCPP_EXPORTED_FROM_ABI const piecewise_construct_t piecewise_construct;// = piecewise_construct_t();
 #else
@@ -335,9 +335,21 @@
 
     struct _CheckArgs {
       template <class _U1, class _U2>
-      static constexpr bool __enable_default() {
+      static constexpr bool __enable_explicit_default() {
           return is_default_constructible<_U1>::value
-              && is_default_constructible<_U2>::value;
+              && is_default_constructible<_U2>::value
+              && !__enable_implicit_default<_U1, _U2>();
+      }
+
+      template <class _U1, class _U2>
+      static constexpr bool __enable_implicit_default() {
+          // In C++03, there's no way to implement the resolution of LWG2510.
+#ifdef _LIBCPP_CXX03_LANG
+          return true;
+#else
+          return __is_implicitly_default_constructible<_U1>::value
+              && __is_implicitly_default_constructible<_U2>::value;
+#endif
       }
 
       template <class _U1, class _U2>
@@ -388,7 +400,15 @@
     >::type;
 
     template<bool _Dummy = true, _EnableB<
-            _CheckArgsDep<_Dummy>::template __enable_default<_T1, _T2>()
+            _CheckArgsDep<_Dummy>::template __enable_explicit_default<_T1, _T2>()
+    > = false>
+    explicit _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+    pair() _NOEXCEPT_(is_nothrow_default_constructible<first_type>::value &&
+                      is_nothrow_default_constructible<second_type>::value)
+        : first(), second() {}
+
+    template<bool _Dummy = true, _EnableB<
+            _CheckArgsDep<_Dummy>::template __enable_implicit_default<_T1, _T2>()
     > = false>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
     pair() _NOEXCEPT_(is_nothrow_default_constructible<first_type>::value &&
diff --git a/src/mutex.cpp b/src/mutex.cpp
index 1827857..7e979cd 100644
--- a/src/mutex.cpp
+++ b/src/mutex.cpp
@@ -21,9 +21,9 @@
 _LIBCPP_BEGIN_NAMESPACE_STD
 #ifndef _LIBCPP_HAS_NO_THREADS
 
-const defer_lock_t  defer_lock = {};
-const try_to_lock_t try_to_lock = {};
-const adopt_lock_t  adopt_lock = {};
+const defer_lock_t  defer_lock{};
+const try_to_lock_t try_to_lock{};
+const adopt_lock_t  adopt_lock{};
 
 // ~mutex is defined elsewhere
 
diff --git a/src/utility.cpp b/src/utility.cpp
index 016a5d9..6a690dc 100644
--- a/src/utility.cpp
+++ b/src/utility.cpp
@@ -10,6 +10,6 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-const piecewise_construct_t piecewise_construct = {};
+const piecewise_construct_t piecewise_construct{};
 
 _LIBCPP_END_NAMESPACE_STD
diff --git a/test/libcxx/type_traits/is_implicitly_default_constructible.pass.cpp b/test/libcxx/type_traits/is_implicitly_default_constructible.pass.cpp
new file mode 100644
index 0000000..eef2828
--- /dev/null
+++ b/test/libcxx/type_traits/is_implicitly_default_constructible.pass.cpp
@@ -0,0 +1,85 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// Before GCC 6, this trait fails. See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <type_traits>
+
+// __is_implicitly_default_constructible<Tp>
+
+#include <type_traits>
+
+
+struct ExplicitlyDefaultConstructible1 {
+    explicit ExplicitlyDefaultConstructible1() = default;
+};
+
+struct ExplicitlyDefaultConstructible2 {
+    explicit ExplicitlyDefaultConstructible2() { }
+};
+
+struct ImplicitlyDefaultConstructible1 {
+    ImplicitlyDefaultConstructible1() { }
+};
+
+struct ImplicitlyDefaultConstructible2 {
+    ImplicitlyDefaultConstructible2() = default;
+};
+
+struct NonDefaultConstructible1 {
+    NonDefaultConstructible1() = delete;
+};
+
+struct NonDefaultConstructible2 {
+    explicit NonDefaultConstructible2() = delete;
+};
+
+struct NonDefaultConstructible3 {
+    NonDefaultConstructible3(NonDefaultConstructible3&&) { }
+};
+
+struct ProtectedDefaultConstructible {
+protected:
+    ProtectedDefaultConstructible() = default;
+};
+
+struct PrivateDefaultConstructible {
+private:
+    PrivateDefaultConstructible() = default;
+};
+
+struct Base { };
+
+struct ProtectedDefaultConstructibleWithBase : Base {
+protected:
+    ProtectedDefaultConstructibleWithBase() = default;
+};
+
+struct PrivateDefaultConstructibleWithBase : Base {
+private:
+    PrivateDefaultConstructibleWithBase() = default;
+};
+
+static_assert(!std::__is_implicitly_default_constructible<ExplicitlyDefaultConstructible1>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<ExplicitlyDefaultConstructible2>::value, "");
+static_assert(std::__is_implicitly_default_constructible<ImplicitlyDefaultConstructible1>::value, "");
+static_assert(std::__is_implicitly_default_constructible<ImplicitlyDefaultConstructible2>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<NonDefaultConstructible1>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<NonDefaultConstructible2>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<NonDefaultConstructible3>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<ProtectedDefaultConstructible>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<PrivateDefaultConstructible>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<ProtectedDefaultConstructibleWithBase>::value, "");
+static_assert(!std::__is_implicitly_default_constructible<PrivateDefaultConstructibleWithBase>::value, "");
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/language.support/support.dynamic/nothrow_t.fail.cpp b/test/std/language.support/support.dynamic/nothrow_t.fail.cpp
new file mode 100644
index 0000000..78ab087
--- /dev/null
+++ b/test/std/language.support/support.dynamic/nothrow_t.fail.cpp
@@ -0,0 +1,30 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// struct nothrow_t {
+//   explicit nothrow_t() = default;
+// };
+// extern const nothrow_t nothrow;
+
+// This test checks for LWG 2510.
+
+#include <new>
+
+
+std::nothrow_t f() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/language.support/support.dynamic/nothrow_t.pass.cpp b/test/std/language.support/support.dynamic/nothrow_t.pass.cpp
new file mode 100644
index 0000000..3a62313
--- /dev/null
+++ b/test/std/language.support/support.dynamic/nothrow_t.pass.cpp
@@ -0,0 +1,23 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// struct nothrow_t {
+//   explicit nothrow_t() = default;
+// };
+// extern const nothrow_t nothrow;
+
+#include <new>
+
+
+int main(int, char**) {
+  std::nothrow_t x = std::nothrow;
+  (void)x;
+
+  return 0;
+}
diff --git a/test/std/thread/thread.mutex/thread.lock/types.fail.cpp b/test/std/thread/thread.mutex/thread.lock/types.fail.cpp
new file mode 100644
index 0000000..4542c04
--- /dev/null
+++ b/test/std/thread/thread.mutex/thread.lock/types.fail.cpp
@@ -0,0 +1,34 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+// UNSUPPORTED: libcpp-has-no-threads
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <mutex>
+
+// struct defer_lock_t { explicit defer_lock_t() = default; };
+// struct try_to_lock_t { explicit try_to_lock_t() = default; };
+// struct adopt_lock_t { explicit adopt_lock_t() = default; };
+
+// This test checks for LWG 2510.
+
+#include <mutex>
+
+
+std::defer_lock_t f1() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::try_to_lock_t f2() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::adopt_lock_t f3() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/thread/thread.mutex/thread.lock/types.pass.cpp b/test/std/thread/thread.mutex/thread.lock/types.pass.cpp
index 84c39ba..c03ca46 100644
--- a/test/std/thread/thread.mutex/thread.lock/types.pass.cpp
+++ b/test/std/thread/thread.mutex/thread.lock/types.pass.cpp
@@ -10,16 +10,15 @@
 
 // <mutex>
 
-// struct defer_lock_t {};
-// struct try_to_lock_t {};
-// struct adopt_lock_t {};
+// struct defer_lock_t { explicit defer_lock_t() = default; };
+// struct try_to_lock_t { explicit try_to_lock_t() = default; };
+// struct adopt_lock_t { explicit adopt_lock_t() = default; };
 //
 // constexpr defer_lock_t  defer_lock{};
 // constexpr try_to_lock_t try_to_lock{};
 // constexpr adopt_lock_t  adopt_lock{};
 
 #include <mutex>
-#include <type_traits>
 
 #include "test_macros.h"
 
@@ -33,5 +32,5 @@
     T2 t2 = std::try_to_lock; ((void)t2);
     T3 t3 = std::adopt_lock; ((void)t3);
 
-  return 0;
+    return 0;
 }
diff --git a/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp b/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp
new file mode 100644
index 0000000..fb991d4
--- /dev/null
+++ b/test/std/utilities/memory/allocator.tag/allocator_arg.fail.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <memory>
+
+// struct allocator_arg_t { explicit allocator_arg_t() = default; };
+// const allocator_arg_t allocator_arg = allocator_arg_t();
+
+// This test checks for LWG 2510.
+
+#include <memory>
+
+
+std::allocator_arg_t f() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/utilities/memory/allocator.tag/allocator_arg.pass.cpp b/test/std/utilities/memory/allocator.tag/allocator_arg.pass.cpp
index 0253243..e22bec1 100644
--- a/test/std/utilities/memory/allocator.tag/allocator_arg.pass.cpp
+++ b/test/std/utilities/memory/allocator.tag/allocator_arg.pass.cpp
@@ -8,7 +8,7 @@
 
 // <memory>
 
-// struct allocator_arg_t { };
+// struct allocator_arg_t { explicit allocator_arg_t() = default; };
 // const allocator_arg_t allocator_arg = allocator_arg_t();
 
 #include <memory>
@@ -21,5 +21,5 @@
 {
     test(std::allocator_arg);
 
-  return 0;
+    return 0;
 }
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp
new file mode 100644
index 0000000..616550f
--- /dev/null
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.fail.cpp
@@ -0,0 +1,53 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <tuple>
+
+// template <class... Types> class tuple;
+
+// explicit(see-below) constexpr tuple();
+
+#include <tuple>
+
+
+struct Implicit {
+    Implicit() = default;
+};
+
+struct Explicit {
+    explicit Explicit() = default;
+};
+
+std::tuple<> test1() { return {}; }
+
+std::tuple<Implicit> test2() { return {}; }
+std::tuple<Explicit> test3() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+std::tuple<Implicit, Implicit> test4() { return {}; }
+std::tuple<Explicit, Implicit> test5() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Implicit, Explicit> test6() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Explicit, Explicit> test7() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+std::tuple<Implicit, Implicit, Implicit> test8() { return {}; }
+std::tuple<Implicit, Implicit, Explicit> test9() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Implicit, Explicit, Implicit> test10() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Implicit, Explicit, Explicit> test11() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Explicit, Implicit, Implicit> test12() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Explicit, Implicit, Explicit> test13() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Explicit, Explicit, Implicit> test14() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::tuple<Explicit, Explicit, Explicit> test15() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp
index 46fd35a..c5b650d 100644
--- a/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp
+++ b/test/std/utilities/tuple/tuple.tuple/tuple.cnstr/default.pass.cpp
@@ -10,7 +10,7 @@
 
 // template <class... Types> class tuple;
 
-// constexpr tuple();
+// explicit(see-below) constexpr tuple();
 
 // UNSUPPORTED: c++98, c++03
 
@@ -107,6 +107,11 @@
         IllFormedDefault v(0);
         std::tuple<IllFormedDefault> t(v);
     }
+    {
+        struct Base { };
+        struct Derived : Base { protected: Derived() = default; };
+        static_assert(!std::is_default_constructible<std::tuple<Derived, int> >::value, "");
+    }
 
-  return 0;
+    return 0;
 }
diff --git a/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct.pass.cpp b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct.pass.cpp
index d70d060..903aa93 100644
--- a/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct.pass.cpp
+++ b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct.pass.cpp
@@ -12,7 +12,7 @@
 
 // template <class T1, class T2> struct pair
 
-// struct piecewise_construct_t { };
+// struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
 // constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();
 
 #include <utility>
diff --git a/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.fail.cpp b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.fail.cpp
new file mode 100644
index 0000000..b8dd28a
--- /dev/null
+++ b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.fail.cpp
@@ -0,0 +1,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <utility>
+
+// struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
+// constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();
+
+// This test checks for LWG 2510.
+
+#include <utility>
+
+
+std::piecewise_construct_t f() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.pass.cpp b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.pass.cpp
new file mode 100644
index 0000000..0fdba06
--- /dev/null
+++ b/test/std/utilities/utility/pairs/pair.piecewise/piecewise_construct_t.pass.cpp
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// <utility>
+
+// struct piecewise_construct_t { explicit piecewise_construct_t() = default; };
+// constexpr piecewise_construct_t piecewise_construct = piecewise_construct_t();
+
+#include <utility>
+
+
+int main(int, char**) {
+    std::piecewise_construct_t x = std::piecewise_construct;
+    (void)x;
+
+    return 0;
+}
diff --git a/test/std/utilities/utility/pairs/pairs.pair/default.explicit.fail.cpp b/test/std/utilities/utility/pairs/pairs.pair/default.explicit.fail.cpp
new file mode 100644
index 0000000..511f21e
--- /dev/null
+++ b/test/std/utilities/utility/pairs/pairs.pair/default.explicit.fail.cpp
@@ -0,0 +1,42 @@
+//===----------------------------------------------------------------------===//
+//
+// 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++98, c++03
+
+// Before GCC 6, aggregate initialization kicks in.
+// See https://stackoverflow.com/q/41799015/627587.
+// UNSUPPORTED: gcc-5
+
+// <utility>
+
+// template <class T1, class T2> struct pair
+
+// explicit(see-below) constexpr pair();
+
+// This test checks the conditional explicitness of std::pair's default
+// constructor as introduced by the resolution of LWG 2510.
+
+#include <utility>
+
+
+struct ImplicitlyDefaultConstructible {
+    ImplicitlyDefaultConstructible() = default;
+};
+
+struct ExplicitlyDefaultConstructible {
+    explicit ExplicitlyDefaultConstructible() = default;
+};
+
+std::pair<ImplicitlyDefaultConstructible, ExplicitlyDefaultConstructible> test1() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::pair<ExplicitlyDefaultConstructible, ImplicitlyDefaultConstructible> test2() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::pair<ExplicitlyDefaultConstructible, ExplicitlyDefaultConstructible> test3() { return {}; } // expected-error 1 {{chosen constructor is explicit in copy-initialization}}
+std::pair<ImplicitlyDefaultConstructible, ImplicitlyDefaultConstructible> test4() { return {}; }
+
+int main(int, char**) {
+    return 0;
+}
diff --git a/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp b/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp
index 049c220..dc05a2b 100644
--- a/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp
+++ b/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp
@@ -10,7 +10,7 @@
 
 // template <class T1, class T2> struct pair
 
-// constexpr pair();
+// explicit(see-below) constexpr pair();
 
 // NOTE: The SFINAE on the default constructor is tested in
 //       default-sfinae.pass.cpp
@@ -45,6 +45,11 @@
         using P2 = std::pair<NoDefault, int>;
         static_assert(!std::is_default_constructible<P2>::value, "");
     }
+    {
+        struct Base { };
+        struct Derived : Base { protected: Derived() = default; };
+        static_assert(!std::is_default_constructible<std::pair<Derived, int> >::value, "");
+    }
 #endif
 
   return 0;
diff --git a/www/cxx1z_status.html b/www/cxx1z_status.html
index 227c05f..627f9a0 100644
--- a/www/cxx1z_status.html
+++ b/www/cxx1z_status.html
@@ -372,7 +372,7 @@
 	<tr><td><a href="https://wg21.link/LWG2468">2468</a></td><td>Self-move-assignment of library types</td><td>Issaquah</td><td></td></tr>
 	<tr><td><a href="https://wg21.link/LWG2475">2475</a></td><td>Allow overwriting of std::basic_string terminator with charT() to allow cleaner interoperation with legacy APIs</td><td>Issaquah</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG2503">2503</a></td><td>multiline option should be added to syntax_option_type</td><td>Issaquah</td><td></td></tr>
-	<tr><td><a href="https://wg21.link/LWG2510">2510</a></td><td>Tag types should not be DefaultConstructible</td><td>Issaquah</td><td></td></tr>
+	<tr><td><a href="https://wg21.link/LWG2510">2510</a></td><td>Tag types should not be DefaultConstructible</td><td>Issaquah</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG2514">2514</a></td><td>Type traits must not be final</td><td>Issaquah</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG2518">2518</a></td><td>[fund.ts.v2] Non-member swap for propagate_const should call member swap</td><td>Issaquah</td><td>Complete</td></tr>
 	<tr><td><a href="https://wg21.link/LWG2519">2519</a></td><td>Iterator operator-= has gratuitous undefined behaviour</td><td>Issaquah</td><td>Complete</td></tr>