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 @@ -105,6 +105,20 @@ second = __p.second; return *this; } + + // Extension: This is provided in C++03 because it allows properly handling the + // assignment to a pair containing references, which would be a hard + // error otherwise. + template ::value && + is_assignable::value + > > + _LIBCPP_HIDE_FROM_ABI + pair& operator=(pair<_U1, _U2> const& __p) { + first = __p.first; + second = __p.second; + return *this; + } #else struct _CheckArgs { template diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_pair_U_V.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_pair_U_V.pass.cpp --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_pair_U_V.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_const_pair_U_V.pass.cpp @@ -74,6 +74,16 @@ static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); } +#endif +#if TEST_STD_VER >= 11 || defined(_LIBCPP_VERSION) // valid in C++11, provided in C++03 with libc++ as an extension + { + int i = 0, j = 0; + std::pair p(i, j); + const std::pair from(11, 12); + p = from; + assert(i == 11); + assert(j == 12); + } #endif return true; } diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/assign_pair_cxx03.pass.cpp @@ -29,20 +29,37 @@ struct Incomplete; extern Incomplete inc_obj; +struct ConstructibleFromInt { + ConstructibleFromInt() : value(-1) { } + explicit ConstructibleFromInt(int v) : value(v) { } + int value; +}; + int main(int, char**) { { - // Test that we don't constrain the assignment operator in C++03 mode. - // Since we don't have access control SFINAE having pair evaluate SFINAE - // may cause a hard error. - typedef std::pair P; - static_assert(std::is_copy_assignable

::value, ""); + // Test that we don't constrain the assignment operator in C++03 mode. + // Since we don't have access control SFINAE having pair evaluate SFINAE + // may cause a hard error. + typedef std::pair P; + static_assert(std::is_copy_assignable

::value, ""); + } + { + typedef std::pair P; + static_assert(std::is_copy_assignable

::value, ""); + P p(42, inc_obj); + assert(&p.second == &inc_obj); } { - typedef std::pair P; - static_assert(std::is_copy_assignable

::value, ""); - P p(42, inc_obj); - assert(&p.second == &inc_obj); + // The type is constructible from int, but not assignable from int. + // This ensures that operator=(pair const&) can be used in conjunction with + // pair(pair const&) to mimic operator=(pair const&) in C++03. + // This is weird but valid in C++03. + std::pair p; + std::pair from(11, 'x'); + p = from; + assert(p.first.value == 11); + assert(p.second == 'x'); } return 0;