[libcxx-commits] [libcxx] 312ad74 - [libc++] Implement P1951, default arguments for pair's forwarding constructor

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Thu Sep 9 05:28:30 PDT 2021


Author: Louis Dionne
Date: 2021-09-09T08:28:22-04:00
New Revision: 312ad74aea4886159472597ed6b2c40dea9e5ca7

URL: https://github.com/llvm/llvm-project/commit/312ad74aea4886159472597ed6b2c40dea9e5ca7
DIFF: https://github.com/llvm/llvm-project/commit/312ad74aea4886159472597ed6b2c40dea9e5ca7.diff

LOG: [libc++] Implement P1951, default arguments for pair's forwarding constructor

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

Added: 
    libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.pass.cpp

Modified: 
    libcxx/docs/Status/Cxx2bPapers.csv
    libcxx/include/__utility/pair.h
    libcxx/include/utility
    libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv
index 4df0bfcddbf7a..d1b7314d48a71 100644
--- a/libcxx/docs/Status/Cxx2bPapers.csv
+++ b/libcxx/docs/Status/Cxx2bPapers.csv
@@ -18,7 +18,7 @@
 "`P1425R4 <https://wg21.link/P1425R4>`__","LWG","Iterators pair constructors for stack and queue","June 2021","",""
 "`P1518R2 <https://wg21.link/P1518R2>`__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0"
 "`P1659R3 <https://wg21.link/P1659R3>`__","LWG","starts_with and ends_with","June 2021","",""
-"`P1951R1 <https://wg21.link/P1951R1>`__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","",""
+"`P1951R1 <https://wg21.link/P1951R1>`__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","|Complete|","14.0"
 "`P1989R2 <https://wg21.link/P1989R2>`__","LWG","Range constructor for std::string_view","June 2021","",""
 "`P2136R3 <https://wg21.link/P2136R3>`__","LWG","invoke_r","June 2021","",""
 "`P2166R1 <https://wg21.link/P2166R1>`__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0"

diff  --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h
index 6acb26b5bc590..d2bc8db2550e4 100644
--- a/libcxx/include/__utility/pair.h
+++ b/libcxx/include/__utility/pair.h
@@ -24,7 +24,6 @@
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
-
 #if defined(_LIBCPP_DEPRECATED_ABI_DISABLE_PAIR_TRIVIAL_COPY_CTOR)
 template <class, class>
 struct __non_trivially_copyable_base {
@@ -167,7 +166,7 @@ struct _LIBCPP_TEMPLATE_VIS pair
                    is_nothrow_copy_constructible<second_type>::value)
         : first(__t1), second(__t2) {}
 
-    template<class _U1, class _U2, typename enable_if<
+    template<class _U1 = _T1, class _U2 = _T2, typename enable_if<
              _CheckArgs::template __enable_explicit<_U1, _U2>()
     >::type* = nullptr>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
@@ -176,7 +175,7 @@ struct _LIBCPP_TEMPLATE_VIS pair
                     is_nothrow_constructible<second_type, _U2>::value))
         : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {}
 
-    template<class _U1, class _U2, typename enable_if<
+    template<class _U1 = _T1, class _U2 = _T2, typename enable_if<
             _CheckArgs::template __enable_implicit<_U1, _U2>()
     >::type* = nullptr>
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11

diff  --git a/libcxx/include/utility b/libcxx/include/utility
index 83ad035c9f90a..6ec3e3faa72e8 100644
--- a/libcxx/include/utility
+++ b/libcxx/include/utility
@@ -79,7 +79,7 @@ struct pair
     pair(pair&&) = default;
     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 = T1, class V = T2> explicit(see-below) pair(U&&, V&&);    // constexpr in C++14
     template <class U, class V> explicit(see-below) pair(const pair<U, V>& p);   // constexpr in C++14
     template <class U, class V> explicit(see-below) pair(pair<U, V>&& p);        // constexpr in C++14
     template <class... Args1, class... Args2>

diff  --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp
index de32d5e6b1d9c..5086a298ac037 100644
--- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/U_V.pass.cpp
@@ -12,12 +12,11 @@
 
 // template <class T1, class T2> struct pair
 
-// template<class U, class V> pair(U&& x, V&& y);
-
+// template<class U = T1, class V = T2> pair(U&&, V&&);
 
 #include <utility>
-#include <memory>
 #include <cassert>
+#include <memory>
 
 #include "archetypes.h"
 #include "test_convertible.h"
@@ -47,7 +46,6 @@ struct ImplicitT {
   int value;
 };
 
-
 int main(int, char**)
 {
     {
@@ -99,5 +97,48 @@ int main(int, char**)
     }
 #endif
 
-  return 0;
+    // Test support for http://wg21.link/P1951, default arguments for pair's constructor.
+    // Basically, this turns copies for brace initialization into moves. Note that libc++
+    // applies this in all standard modes.
+#if TEST_STD_VER > 20 || defined(_LIBCPP_VERSION)
+    {
+        struct TrackInit {
+            TrackInit() = default;
+            constexpr TrackInit(TrackInit const&) : wasCopyInit(true) { }
+            constexpr TrackInit(TrackInit&&) : wasMoveInit(true) { }
+            bool wasMoveInit = false;
+            bool wasCopyInit = false;
+        };
+
+        // Explicit constructor
+        {
+            {
+                std::pair<TrackInit, int> p({}, 3);
+                assert( p.first.wasMoveInit);
+                assert(!p.first.wasCopyInit);
+            }
+            {
+                std::pair<int, TrackInit> p(3, {});
+                assert( p.second.wasMoveInit);
+                assert(!p.second.wasCopyInit);
+            }
+        }
+
+        // Implicit constructor
+        {
+            {
+                std::pair<TrackInit, int> p = {{}, 3};
+                assert( p.first.wasMoveInit);
+                assert(!p.first.wasCopyInit);
+            }
+            {
+                std::pair<int, TrackInit> p = {3, {}};
+                assert( p.second.wasMoveInit);
+                assert(!p.second.wasCopyInit);
+            }
+        }
+    }
+#endif
+
+    return 0;
 }

diff  --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.pass.cpp
new file mode 100644
index 0000000000000..f4f55b8edb91a
--- /dev/null
+++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/ctor.brace-init.pass.cpp
@@ -0,0 +1,122 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+
+// TODO: Revisit this test once we have more information
+//       with https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102247
+// XFAIL: gcc
+
+// <utility>
+
+// template <class T1, class T2> struct pair
+//
+// pair(const T1&, const T2&);
+// template<class U = T1, class V = T2> pair(U&&, V&&);
+
+// This test checks support for brace-initialization of pairs.
+
+#include <utility>
+#include <cassert>
+
+#include "test_macros.h"
+
+struct ExplicitT {
+  constexpr explicit ExplicitT(int x) : value(x) {}
+  constexpr explicit ExplicitT(ExplicitT const& o) : value(o.value) {}
+  int value;
+};
+
+struct ImplicitT {
+  constexpr ImplicitT(int x) : value(x) {}
+  constexpr ImplicitT(ImplicitT const& o) : value(o.value) {}
+  int value;
+};
+
+template <class T, class = decltype(std::pair<T, T>({}, {}))>
+constexpr bool can_construct_with_brace_init(int) { return true; }
+template <class T>
+constexpr bool can_construct_with_brace_init(...) { return false; }
+
+#if TEST_STD_VER >= 17 // CTAD isn't supported before C++17
+template <class T, class = decltype(std::pair(T{}, {}))>
+constexpr bool can_construct_with_ctad_brace_init(int) { return true; }
+template <class T>
+constexpr bool can_construct_with_ctad_brace_init(...) { return false; }
+#endif
+
+struct BraceInit { BraceInit() = default; };
+struct NoBraceInit { NoBraceInit(int); };
+struct ExplicitBraceInit { explicit ExplicitBraceInit() = default; };
+
+constexpr int explicit_vs_implicit_brace_init(std::pair<ExplicitBraceInit, ExplicitBraceInit>) { return 1; }
+constexpr int explicit_vs_implicit_brace_init(std::pair<BraceInit, BraceInit>) { return 2; }
+
+TEST_CONSTEXPR_CXX14 bool test() {
+    // Explicit constructor
+    {
+        std::pair<ExplicitT, BraceInit> p1(ExplicitT{42}, {});
+        assert(p1.first.value == 42);
+
+        std::pair<ExplicitT, BraceInit> p2{ExplicitT{42}, {}};
+        assert(p2.first.value == 42);
+    }
+    {
+        std::pair<BraceInit, ExplicitT> p1({}, ExplicitT{42});
+        assert(p1.second.value == 42);
+
+        std::pair<BraceInit, ExplicitT> p2{{}, ExplicitT{42}};
+        assert(p2.second.value == 42);
+    }
+    {
+        std::pair<BraceInit, BraceInit> p{{}, {}};
+        (void)p;
+    }
+
+    // Implicit constructor
+    {
+        std::pair<ImplicitT, BraceInit> p = {42, {}};
+        assert(p.first.value == 42);
+    }
+    {
+        std::pair<BraceInit, ImplicitT> p = {{}, 42};
+        assert(p.second.value == 42);
+    }
+    {
+        std::pair<BraceInit, BraceInit> p = {{}, {}};
+        (void)p;
+    }
+
+    // SFINAE-friendliness of some invalid cases
+    {
+        static_assert( can_construct_with_brace_init<BraceInit>(0), "");
+        static_assert(!can_construct_with_brace_init<NoBraceInit>(0), "");
+
+#if TEST_STD_VER >= 17
+        // CTAD with {} should never work, since we can't possibly deduce the types
+        static_assert(!can_construct_with_ctad_brace_init<BraceInit>(0), "");
+        static_assert(!can_construct_with_ctad_brace_init<int>(0), "");
+#endif
+    }
+
+    // Make sure there is no ambiguity between the explicit and the non-explicit constructors
+    {
+        assert(explicit_vs_implicit_brace_init({{}, {}}) == 2);
+    }
+
+    return true;
+}
+
+int main(int, char**) {
+    test();
+#if TEST_STD_VER > 11
+    static_assert(test(), "");
+#endif
+
+    return 0;
+}


        


More information about the libcxx-commits mailing list