diff --git a/libcxx/docs/Status/Cxx2bPapers.csv b/libcxx/docs/Status/Cxx2bPapers.csv --- a/libcxx/docs/Status/Cxx2bPapers.csv +++ b/libcxx/docs/Status/Cxx2bPapers.csv @@ -18,8 +18,8 @@ "`P1425R4 `__","LWG","Iterators pair constructors for stack and queue","June 2021","","" "`P1518R2 `__","LWG","Stop overconstraining allocators in container deduction guides","June 2021","|Complete|","13.0" "`P1659R3 `__","LWG","starts_with and ends_with","June 2021","","" -"`P1951R1 `__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","","" +"`P1951R1 `__","LWG","Default Arguments for pair Forwarding Constructor","June 2021","|Complete|","14.0" "`P1989R2 `__","LWG","Range constructor for std::string_view","June 2021","","" "`P2136R3 `__","LWG","invoke_r","June 2021","","" "`P2166R1 `__","LWG","A Proposal to Prohibit std::basic_string and std::basic_string_view construction from nullptr","June 2021","|Complete|","13.0" "","","","","","" \ No newline at end of file diff --git a/libcxx/include/__utility/pair.h b/libcxx/include/__utility/pair.h --- 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 struct __non_trivially_copyable_base { @@ -167,7 +166,7 @@ is_nothrow_copy_constructible::value) : first(__t1), second(__t2) {} - template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 @@ -176,7 +175,7 @@ is_nothrow_constructible::value)) : first(_VSTD::forward<_U1>(__u1)), second(_VSTD::forward<_U2>(__u2)) {} - template() >::type* = nullptr> _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 diff --git a/libcxx/include/utility b/libcxx/include/utility --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -79,7 +79,7 @@ pair(pair&&) = default; explicit(see-below) constexpr pair(); explicit(see-below) pair(const T1& x, const T2& y); // constexpr in C++14 - template explicit(see-below) pair(U&& x, V&& y); // constexpr in C++14 + template explicit(see-below) pair(U&&, V&&); // constexpr in C++14 template explicit(see-below) pair(const pair& p); // constexpr in C++14 template explicit(see-below) pair(pair&& p); // constexpr in C++14 template 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 --- 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 struct pair -// template pair(U&& x, V&& y); - +// template pair(U&&, V&&); #include -#include #include +#include #include "archetypes.h" #include "test_convertible.h" @@ -47,7 +46,6 @@ int value; }; - int main(int, char**) { { @@ -99,5 +97,48 @@ } #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 p({}, 3); + assert( p.first.wasMoveInit); + assert(!p.first.wasCopyInit); + } + { + std::pair p(3, {}); + assert( p.second.wasMoveInit); + assert(!p.second.wasCopyInit); + } + } + + // Implicit constructor + { + { + std::pair p = {{}, 3}; + assert( p.first.wasMoveInit); + assert(!p.first.wasCopyInit); + } + { + std::pair 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 --- /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 + +// + +// template struct pair +// +// pair(const T1&, const T2&); +// template pair(U&&, V&&); + +// This test checks support for brace-initialization of pairs. + +#include +#include + +#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 ({}, {}))> +constexpr bool can_construct_with_brace_init(int) { return true; } +template +constexpr bool can_construct_with_brace_init(...) { return false; } + +#if TEST_STD_VER >= 17 // CTAD isn't supported before C++17 +template +constexpr bool can_construct_with_ctad_brace_init(int) { return true; } +template +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) { return 1; } +constexpr int explicit_vs_implicit_brace_init(std::pair) { return 2; } + +TEST_CONSTEXPR_CXX14 bool test() { + // Explicit constructor + { + std::pair p1(ExplicitT{42}, {}); + assert(p1.first.value == 42); + + std::pair p2{ExplicitT{42}, {}}; + assert(p2.first.value == 42); + } + { + std::pair p1({}, ExplicitT{42}); + assert(p1.second.value == 42); + + std::pair p2{{}, ExplicitT{42}}; + assert(p2.second.value == 42); + } + { + std::pair p{{}, {}}; + (void)p; + } + + // Implicit constructor + { + std::pair p = {42, {}}; + assert(p.first.value == 42); + } + { + std::pair p = {{}, 42}; + assert(p.second.value == 42); + } + { + std::pair p = {{}, {}}; + (void)p; + } + + // SFINAE-friendliness of some invalid cases + { + static_assert( can_construct_with_brace_init(0), ""); + static_assert(!can_construct_with_brace_init(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(0), ""); + static_assert(!can_construct_with_ctad_brace_init(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; +}