[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