diff --git a/libcxx/include/__algorithm/in_fun_result.h b/libcxx/include/__algorithm/in_fun_result.h --- a/libcxx/include/__algorithm/in_fun_result.h +++ b/libcxx/include/__algorithm/in_fun_result.h @@ -20,7 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) namespace ranges { template @@ -42,7 +42,7 @@ }; } // namespace ranges -#endif // _LIBCPP_STD_VER > 17 +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/in_in_out_result.h b/libcxx/include/__algorithm/in_in_out_result.h --- a/libcxx/include/__algorithm/in_in_out_result.h +++ b/libcxx/include/__algorithm/in_in_out_result.h @@ -41,7 +41,7 @@ requires convertible_to<_I1, _II1> && convertible_to<_I2, _II2> && convertible_to<_O1, _OO1> _LIBCPP_HIDE_FROM_ABI constexpr operator in_in_out_result<_II1, _II2, _OO1>() && { - return {_VSTD::move(in1), _VSTD::move(in2), _VSTD::move(out)}; + return {std::move(in1), std::move(in2), std::move(out)}; } }; diff --git a/libcxx/include/__algorithm/in_in_result.h b/libcxx/include/__algorithm/in_in_result.h --- a/libcxx/include/__algorithm/in_in_result.h +++ b/libcxx/include/__algorithm/in_in_result.h @@ -20,7 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) namespace ranges { @@ -39,12 +39,14 @@ template requires convertible_to<_I1, _II1> && convertible_to<_I2, _II2> _LIBCPP_HIDE_FROM_ABI constexpr - operator in_in_result<_II1, _II2>() && { return {_VSTD::move(in1), _VSTD::move(in2)}; } + operator in_in_result<_II1, _II2>() && { + return {std::move(in1), std::move(in2)}; + } }; } // namespace ranges -#endif // _LIBCPP_STD_VER > 17 +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/in_out_out_result.h b/libcxx/include/__algorithm/in_out_out_result.h --- a/libcxx/include/__algorithm/in_out_out_result.h +++ b/libcxx/include/__algorithm/in_out_out_result.h @@ -20,7 +20,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) namespace ranges { template @@ -40,12 +40,12 @@ requires convertible_to<_I1, _II1> && convertible_to<_O1, _OO1> && convertible_to<_O2, _OO2> _LIBCPP_HIDE_FROM_ABI constexpr operator in_out_out_result<_II1, _OO1, _OO2>() && { - return {_VSTD::move(in), _VSTD::move(out1), _VSTD::move(out2)}; + return {std::move(in), std::move(out1), std::move(out2)}; } }; } // namespace ranges -#endif // _LIBCPP_STD_VER > 17 +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/in_out_result.h b/libcxx/include/__algorithm/in_out_result.h --- a/libcxx/include/__algorithm/in_out_result.h +++ b/libcxx/include/__algorithm/in_out_result.h @@ -24,24 +24,23 @@ namespace ranges { -template +template struct in_out_result { - _LIBCPP_NO_UNIQUE_ADDRESS _InputIterator in; - _LIBCPP_NO_UNIQUE_ADDRESS _OutputIterator out; + _LIBCPP_NO_UNIQUE_ADDRESS _I1 in; + _LIBCPP_NO_UNIQUE_ADDRESS _O1 out; - template - requires convertible_to && convertible_to + template + requires convertible_to && convertible_to _LIBCPP_HIDE_FROM_ABI - constexpr operator in_out_result<_InputIterator2, _OutputIterator2>() const & { + constexpr operator in_out_result<_I2, _O2>() const & { return {in, out}; } - template - requires convertible_to<_InputIterator, _InputIterator2> && convertible_to<_OutputIterator, _OutputIterator2> + template + requires convertible_to<_I1, _I2> && convertible_to<_O1, _O2> _LIBCPP_HIDE_FROM_ABI - constexpr operator in_out_result<_InputIterator2, _OutputIterator2>() && { - return {_VSTD::move(in), _VSTD::move(out)}; + constexpr operator in_out_result<_I2, _O2>() && { + return {std::move(in), std::move(out)}; } }; diff --git a/libcxx/include/__algorithm/min_max_result.h b/libcxx/include/__algorithm/min_max_result.h --- a/libcxx/include/__algorithm/min_max_result.h +++ b/libcxx/include/__algorithm/min_max_result.h @@ -53,4 +53,4 @@ _LIBCPP_POP_MACROS -#endif +#endif // _LIBCPP___ALGORITHM_MIN_MAX_RESULT_H diff --git a/libcxx/include/__algorithm/ranges_mismatch.h b/libcxx/include/__algorithm/ranges_mismatch.h --- a/libcxx/include/__algorithm/ranges_mismatch.h +++ b/libcxx/include/__algorithm/ranges_mismatch.h @@ -27,7 +27,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -#if _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) namespace ranges { @@ -78,7 +78,7 @@ } // namespace __cpo } // namespace ranges -#endif // _LIBCPP_STD_VER > 17 +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/ranges_swap_ranges.h b/libcxx/include/__algorithm/ranges_swap_ranges.h --- a/libcxx/include/__algorithm/ranges_swap_ranges.h +++ b/libcxx/include/__algorithm/ranges_swap_ranges.h @@ -22,7 +22,7 @@ # pragma GCC system_header #endif -#if _LIBCPP_STD_VER > 17 +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) _LIBCPP_BEGIN_NAMESPACE_STD @@ -64,6 +64,6 @@ _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP_STD_VER > 17 +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) #endif // _LIBCPP___ALGORITHM_RANGES_SWAP_RANGES_H diff --git a/libcxx/test/std/algorithms/algorithms.results/in_found_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_found_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_found_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_found_result.pass.cpp @@ -18,21 +18,17 @@ #include "MoveOnly.h" -template -struct ConvertibleFrom { - constexpr ConvertibleFrom(T c) : content{c} {} - T content; -}; - struct A { explicit A(int); }; +// no implicit conversion static_assert(!std::is_constructible_v, std::ranges::in_found_result>); struct B { B(const int&); B(int&&); }; +// implicit conversion static_assert(std::is_constructible_v, std::ranges::in_found_result>); static_assert(std::is_constructible_v, std::ranges::in_found_result&>); static_assert(std::is_constructible_v, const std::ranges::in_found_result>); @@ -43,17 +39,31 @@ }; static_assert(!std::is_constructible_v, std::ranges::in_found_result&>); +// has to be convertible via const& static_assert(std::is_convertible_v&, std::ranges::in_found_result>); static_assert(std::is_convertible_v&, std::ranges::in_found_result>); static_assert(std::is_convertible_v&&, std::ranges::in_found_result>); static_assert(std::is_convertible_v&&, std::ranges::in_found_result>); +// should be move constructible +static_assert(std::is_move_constructible_v>); + +// should not be copy constructible +static_assert(!std::is_copy_constructible_v>); + struct NotConvertible {}; +// conversions should not work if there is no conversion static_assert(!std::is_convertible_v, std::ranges::in_found_result>); static_assert(std::is_same_v::in), int>); static_assert(std::is_same_v::found), bool>); +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + constexpr bool test() { { std::ranges::in_found_result res{10, true}; @@ -61,7 +71,7 @@ assert(res.found == true); std::ranges::in_found_result> res2 = res; assert(res2.in.content == 10); - assert(res2.found); + assert(res2.found == true); } { std::ranges::in_found_result res{MoveOnly{}, false}; diff --git a/libcxx/test/std/algorithms/algorithms.results/in_fun_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_fun_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_fun_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_fun_result.pass.cpp @@ -37,9 +37,9 @@ struct C { C(int&); }; -// has to be convertible via const& static_assert(!std::is_constructible_v, std::ranges::in_fun_result&>); +// has to be convertible via const& static_assert(std::is_convertible_v&, std::ranges::in_fun_result>); static_assert(std::is_convertible_v&, std::ranges::in_fun_result>); static_assert(std::is_convertible_v&&, std::ranges::in_fun_result>); @@ -55,10 +55,8 @@ struct NotConvertible {}; // conversions should not work if there is no conversion -static_assert(!std::is_convertible_v, - std::ranges::in_fun_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_fun_result>); +static_assert(!std::is_convertible_v, std::ranges::in_fun_result>); +static_assert(!std::is_convertible_v, std::ranges::in_fun_result>); template struct ConvertibleFrom { diff --git a/libcxx/test/std/algorithms/algorithms.results/in_in_out_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_in_out_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_in_out_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_in_out_result.pass.cpp @@ -18,22 +18,17 @@ #include "MoveOnly.h" -template -struct ConvertibleFrom { - constexpr ConvertibleFrom(T c) : content{c} {} - T content; -}; - struct A { explicit A(int); }; -// conversion is not implicit +// no implicit conversion static_assert(!std::is_constructible_v, std::ranges::in_in_out_result>); struct B { B(int); }; +// implicit conversion static_assert(std::is_constructible_v, std::ranges::in_in_out_result>); static_assert(std::is_constructible_v, std::ranges::in_in_out_result&>); static_assert(std::is_constructible_v, const std::ranges::in_in_out_result>); @@ -44,34 +39,34 @@ }; static_assert(!std::is_constructible_v, std::ranges::in_in_out_result&>); -static_assert(std::is_convertible_v&, - std::ranges::in_in_out_result>); -static_assert(std::is_convertible_v&, - std::ranges::in_in_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_in_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_in_out_result>); - -struct NotConvertible {}; -static_assert(!std::is_convertible_v, - std::ranges::in_in_out_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_in_out_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_in_out_result>); - -static_assert(std::is_constructible_v, - std::ranges::in_in_out_result&>); +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_in_out_result>); +static_assert(std::is_convertible_v&, std::ranges::in_in_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_in_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_in_out_result>); +// should be move constructible static_assert(std::is_move_constructible_v>); static_assert(std::is_move_constructible_v>); static_assert(std::is_move_constructible_v>); +// should not be copy constructible static_assert(!std::is_copy_constructible_v>); static_assert(!std::is_copy_constructible_v>); static_assert(!std::is_copy_constructible_v>); +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert(!std::is_convertible_v, std::ranges::in_in_out_result>); +static_assert(!std::is_convertible_v, std::ranges::in_in_out_result>); +static_assert(!std::is_convertible_v, std::ranges::in_in_out_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + constexpr bool test() { { std::ranges::in_in_out_result res{10, 0., 1.f}; diff --git a/libcxx/test/std/algorithms/algorithms.results/in_in_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_in_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_in_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_in_result.pass.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// // UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges // template // struct in_in_result; @@ -17,22 +18,16 @@ #include "MoveOnly.h" -template -struct ConstructibleFrom { - constexpr ConstructibleFrom(T c) : content{c} {} - T content; -}; - struct A { explicit A(int); }; -static_assert(!std::is_constructible_v, - std::ranges::in_in_result>); +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_in_result>); struct B { - B(const int&); - B(int&&); + B(int); }; +// implicit conversion static_assert(std::is_constructible_v, std::ranges::in_in_result>); static_assert(std::is_constructible_v, std::ranges::in_in_result&>); static_assert(std::is_constructible_v, const std::ranges::in_in_result>); @@ -43,20 +38,26 @@ }; static_assert(!std::is_constructible_v, std::ranges::in_in_result&>); -static_assert(std::is_convertible_v< std::ranges::in_in_result&, std::ranges::in_in_result>); -static_assert(!std::is_nothrow_convertible_v&, std::ranges::in_in_result>); -static_assert(std::is_convertible_v< const std::ranges::in_in_result&, std::ranges::in_in_result>); -static_assert(!std::is_nothrow_convertible_v&, std::ranges::in_in_result>); -static_assert(std::is_convertible_v< std::ranges::in_in_result&&, std::ranges::in_in_result>); -static_assert(!std::is_nothrow_convertible_v&&, std::ranges::in_in_result>); -static_assert(std::is_convertible_v< const std::ranges::in_in_result&&, std::ranges::in_in_result>); -static_assert(!std::is_nothrow_convertible_v&&, std::ranges::in_in_result>); +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_in_result>); +static_assert(std::is_convertible_v&, std::ranges::in_in_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_in_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_in_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); struct NotConvertible {}; -static_assert(!std::is_convertible_v, - std::ranges::in_in_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_in_result>); +// conversions should not work if there is no conversion +static_assert(!std::is_convertible_v, std::ranges::in_in_result>); +static_assert(!std::is_convertible_v, std::ranges::in_in_result>); + +template +struct ConstructibleFrom { + constexpr ConstructibleFrom(T c) : content{c} {} + T content; +}; constexpr bool test() { { @@ -73,9 +74,11 @@ [[maybe_unused]] auto res2 = static_cast>(std::move(res)); assert(res.in1.get() == 0); } - auto [in1, in2] = std::ranges::in_in_result{1, 2}; - assert(in1 == 1); - assert(in2 == 2); + { + auto [in1, in2] = std::ranges::in_in_result{1, 2}; + assert(in1 == 1); + assert(in2 == 2); + } return true; } diff --git a/libcxx/test/std/algorithms/algorithms.results/in_out_out_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_out_out_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_out_out_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_out_out_result.pass.cpp @@ -18,22 +18,16 @@ #include "MoveOnly.h" -template -struct ConvertibleFrom { - constexpr ConvertibleFrom(T c) : content{c} {} - T content; -}; - struct A { explicit A(int); }; -// conversion is not implicit -static_assert(!std::is_constructible_v, - std::ranges::in_out_out_result>); +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_out_out_result>); struct B { B(int); }; +// implicit conversion static_assert(std::is_constructible_v, std::ranges::in_out_out_result>); static_assert(std::is_constructible_v, std::ranges::in_out_out_result&>); static_assert(std::is_constructible_v, const std::ranges::in_out_out_result>); @@ -44,26 +38,13 @@ }; static_assert(!std::is_constructible_v, std::ranges::in_out_out_result&>); -static_assert(std::is_convertible_v&, - std::ranges::in_out_out_result>); -static_assert(std::is_convertible_v&, - std::ranges::in_out_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_out_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_out_out_result>); - -struct NotConvertible {}; -static_assert(!std::is_convertible_v, - std::ranges::in_out_out_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_out_out_result>); -static_assert(!std::is_convertible_v, - std::ranges::in_out_out_result>); - -static_assert(std::is_constructible_v, - std::ranges::in_out_out_result&>); +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_out_out_result>); +static_assert(std::is_convertible_v&, std::ranges::in_out_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_out_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_out_out_result>); +// should be move constructible static_assert(std::is_move_constructible_v>); static_assert(std::is_move_constructible_v>); static_assert(std::is_move_constructible_v>); @@ -72,6 +53,18 @@ static_assert(!std::is_copy_constructible_v>); static_assert(!std::is_copy_constructible_v>); +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert(!std::is_convertible_v, std::ranges::in_out_out_result>); +static_assert(!std::is_convertible_v, std::ranges::in_out_out_result>); +static_assert(!std::is_convertible_v, std::ranges::in_out_out_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + constexpr bool test() { { std::ranges::in_out_out_result res{10, 0., 1.f}; diff --git a/libcxx/test/std/algorithms/algorithms.results/in_out_result.compile.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_out_result.compile.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/algorithms/algorithms.results/in_out_result.compile.pass.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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, c++11, c++14, c++17 -// UNSUPPORTED: libcpp-has-no-incomplete-ranges -// -// clang-cl and cl currently don't support [[no_unique_address]] -// XFAIL: msvc - -// namespace ranges { -// template -// struct in_out_result; -// } - -#include - -// Size optimization. -struct Empty {}; -struct Empty2 {}; - -static_assert(sizeof(std::ranges::in_out_result) == sizeof(int)); -static_assert(sizeof(std::ranges::in_out_result) == sizeof(int)); -static_assert(sizeof(std::ranges::in_out_result) == sizeof(char)); diff --git a/libcxx/test/std/algorithms/algorithms.results/in_out_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/in_out_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/in_out_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/in_out_result.pass.cpp @@ -9,125 +9,85 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-has-no-incomplete-ranges -// -// -// namespace ranges { -// template -// struct in_out_result; -// } +// template +// struct in_out_result; #include #include #include +#include "MoveOnly.h" + struct A { - A(int&); + explicit A(int); }; -static_assert(!std::is_constructible_v, std::ranges::in_out_result&>); +// no implicit conversion +static_assert(!std::is_constructible_v, std::ranges::in_out_result>); -static_assert(std::is_convertible_v&, - std::ranges::in_out_result>); -static_assert(!std::is_nothrow_convertible_v&, - std::ranges::in_out_result>); -static_assert(std::is_convertible_v&, - std::ranges::in_out_result>); -static_assert(!std::is_nothrow_convertible_v&, - std::ranges::in_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_out_result>); -static_assert(!std::is_nothrow_convertible_v&&, - std::ranges::in_out_result>); -static_assert(std::is_convertible_v&&, - std::ranges::in_out_result>); -static_assert(!std::is_nothrow_convertible_v&&, - std::ranges::in_out_result>); +struct B { + B(int); +}; +// implicit conversion +static_assert(std::is_constructible_v, std::ranges::in_out_result>); +static_assert(std::is_constructible_v, std::ranges::in_out_result&>); +static_assert(std::is_constructible_v, const std::ranges::in_out_result>); +static_assert(std::is_constructible_v, const std::ranges::in_out_result&>); + +struct C { + C(int&); +}; +static_assert(!std::is_constructible_v, std::ranges::in_out_result&>); + +// has to be convertible via const& +static_assert(std::is_convertible_v&, std::ranges::in_out_result>); +static_assert(std::is_convertible_v&, std::ranges::in_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_out_result>); +static_assert(std::is_convertible_v&&, std::ranges::in_out_result>); + +// should be move constructible +static_assert(std::is_move_constructible_v>); +static_assert(std::is_move_constructible_v>); + +struct NotConvertible {}; +// conversions should not work if there is no conversion +static_assert(!std::is_convertible_v, std::ranges::in_out_result>); +static_assert(!std::is_convertible_v, std::ranges::in_out_result>); + +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; -int main(int, char**) { - // Conversion, fundamental types. +constexpr bool test() { { - std::ranges::in_out_result x = {2, false}; - // FIXME(varconst): try a narrowing conversion. - std::ranges::in_out_result y = x; - assert(y.in == 2); - assert(y.out == '\0'); + std::ranges::in_out_result res{10, 1}; + assert(res.in == 10); + assert(res.out == 1); + std::ranges::in_out_result, ConvertibleFrom> res2 = res; + assert(res2.in.content == 10); + assert(res2.out.content == 1); } - - // Conversion, user-defined types. { - struct From1 { - int value = 0; - From1(int v) : value(v) {} - }; - - struct To1 { - int value = 0; - To1(int v) : value(v) {} - - To1(const From1& f) : value(f.value) {}; - }; - - struct To2 { - int value = 0; - To2(int v) : value(v) {} - }; - struct From2 { - int value = 0; - From2(int v) : value(v) {} - - operator To2() const { return To2(value); } - }; - - std::ranges::in_out_result x{42, 99}; - std::ranges::in_out_result y = x; - assert(y.in.value == 42); - assert(y.out.value == 99); + std::ranges::in_out_result res{MoveOnly{}, 10}; + assert(res.in.get() == 1); + assert(res.out == 10); + auto res2 = std::move(res); + assert(res.in.get() == 0); + assert(res.out == 10); + assert(res2.in.get() == 1); + assert(res2.out == 10); } - - // Copy-only type. { - struct CopyOnly { - int value = 0; - CopyOnly() = default; - CopyOnly(int v) : value(v) {} - - CopyOnly(const CopyOnly&) = default; - CopyOnly(CopyOnly&&) = delete; - }; - - std::ranges::in_out_result x; - x.in.value = 42; - x.out.value = 99; - - auto y = x; - assert(y.in.value == 42); - assert(y.out.value == 99); - } - - // Move-only type. - { - struct MoveOnly { - int value = 0; - MoveOnly(int v) : value(v) {} - - MoveOnly(MoveOnly&&) = default; - MoveOnly(const MoveOnly&) = delete; - }; - - std::ranges::in_out_result x{42, 99}; - auto y = std::move(x); - assert(y.in.value == 42); - assert(y.out.value == 99); + auto [min, max] = std::ranges::in_out_result{1, 2}; + assert(min == 1); + assert(max == 2); } - // Unsuccessful conversion. - { - struct Foo1 {}; - struct Foo2 {}; - struct Bar1 {}; - struct Bar2 {}; - static_assert( - !std::is_convertible_v, std::ranges::in_out_result>); - } + return true; +} - return 0; +int main(int, char**) { + test(); + static_assert(test()); } diff --git a/libcxx/test/std/algorithms/algorithms.results/min_max_result.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/min_max_result.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/min_max_result.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/min_max_result.pass.cpp @@ -18,21 +18,16 @@ #include "MoveOnly.h" -template -struct ConvertibleFrom { - constexpr ConvertibleFrom(T c) : content{c} {} - T content; -}; - struct A { explicit A(int); }; +// no implicit conversion static_assert(!std::is_constructible_v, std::ranges::min_max_result>); struct B { - B(const int&); - B(int&&); + B(int); }; +// implicit conversion static_assert(std::is_constructible_v, std::ranges::min_max_result>); static_assert(std::is_constructible_v, std::ranges::min_max_result&>); static_assert(std::is_constructible_v, const std::ranges::min_max_result>); @@ -43,14 +38,28 @@ }; static_assert(!std::is_constructible_v, std::ranges::min_max_result&>); +// has to be convertible via const& static_assert(std::is_convertible_v&, std::ranges::min_max_result>); static_assert(std::is_convertible_v&, std::ranges::min_max_result>); static_assert(std::is_convertible_v&&, std::ranges::min_max_result>); static_assert(std::is_convertible_v&&, std::ranges::min_max_result>); +// should be move constructible +static_assert(std::is_move_constructible_v>); + +// should not be copy constructible +static_assert(!std::is_copy_constructible_v>); + struct NotConvertible {}; +// conversions should not work if there is no conversion static_assert(!std::is_convertible_v, std::ranges::min_max_result>); +template +struct ConvertibleFrom { + constexpr ConvertibleFrom(T c) : content{c} {} + T content; +}; + constexpr bool test() { { std::ranges::min_max_result res{10, 1}; @@ -64,13 +73,17 @@ std::ranges::min_max_result res{MoveOnly{}, MoveOnly{}}; assert(res.min.get() == 1); assert(res.max.get() == 1); - [[maybe_unused]] auto res2 = static_cast>(std::move(res)); + auto res2 = std::move(res); assert(res.min.get() == 0); assert(res.max.get() == 0); + assert(res2.min.get() == 1); + assert(res2.max.get() == 1); + } + { + auto [min, max] = std::ranges::min_max_result{1, 2}; + assert(min == 1); + assert(max == 2); } - auto [min, max] = std::ranges::min_max_result{1, 2}; - assert(min == 1); - assert(max == 2); return true; } diff --git a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp --- a/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp +++ b/libcxx/test/std/algorithms/algorithms.results/no_unique_address.compile.pass.cpp @@ -19,13 +19,23 @@ #include +#include "test_macros.h" + struct Empty {}; struct Empty2 {}; +static_assert(sizeof(std::ranges::in_fun_result) == sizeof(int)); +static_assert(sizeof(std::ranges::in_fun_result) == sizeof(int)); +static_assert(sizeof(std::ranges::in_fun_result) == 2); + static_assert(sizeof(std::ranges::in_in_result) == sizeof(int)); static_assert(sizeof(std::ranges::in_in_result) == sizeof(int)); static_assert(sizeof(std::ranges::in_in_result) == 2); +static_assert(sizeof(std::ranges::in_out_result) == sizeof(int)); +static_assert(sizeof(std::ranges::in_out_result) == sizeof(int)); +static_assert(sizeof(std::ranges::in_out_result) == sizeof(char)); + static_assert(sizeof(std::ranges::in_in_out_result) == 2 * sizeof(int)); static_assert(sizeof(std::ranges::in_in_out_result) == 2 * sizeof(int)); static_assert(sizeof(std::ranges::in_in_out_result) == 2 * sizeof(int)); @@ -44,6 +54,15 @@ static_assert(sizeof(std::ranges::in_out_out_result) == sizeof(int)); static_assert(sizeof(std::ranges::in_out_out_result) == 3); -static_assert(sizeof(std::ranges::in_fun_result) == sizeof(int)); -static_assert(sizeof(std::ranges::in_fun_result) == sizeof(int)); -static_assert(sizeof(std::ranges::in_fun_result) == 2); +// In min_max_result both elements have the same type, so they can't have the same address. +// So the only way to test that [[no_unique_address]] is used is to have it in another struct +struct MinMaxNoUniqueAddress { + int a; + TEST_NO_UNIQUE_ADDRESS std::ranges::min_max_result b; + int c; +}; + +static_assert(sizeof(std::ranges::min_max_result) == 2); +static_assert(sizeof(MinMaxNoUniqueAddress) == 8); + +static_assert(sizeof(std::ranges::in_found_result) == sizeof(bool)); diff --git a/libcxx/test/support/test_macros.h b/libcxx/test/support/test_macros.h --- a/libcxx/test/support/test_macros.h +++ b/libcxx/test/support/test_macros.h @@ -415,4 +415,12 @@ # define TEST_MSVC_DIAGNOSTIC_IGNORED(num) #endif +#if __has_cpp_attribute(msvc::no_unique_address) +#define TEST_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] +#elif __has_cpp_attribute(no_unique_address) +#define TEST_NO_UNIQUE_ADDRESS [[no_unique_address]] +#else +#define TEST_NO_UNIQUE_ADDRESS +#endif + #endif // SUPPORT_TEST_MACROS_HPP