diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -109,7 +109,7 @@ `3392 `__,"``ranges::distance()`` cannot be used on a move-only iterator with a sized sentinel","October 2021","","","|ranges|" `3407 `__,"Some problems with the wording changes of P1739R4","October 2021","","","|ranges|" `3422 `__,"Issues of ``seed_seq``'s constructors","October 2021","|Complete|","14.0" -`3470 `__,"``convertible-to-non-slicing`` seems to reject valid case","October 2021","","","|ranges|" +`3470 `__,"``convertible-to-non-slicing`` seems to reject valid case","October 2021","|Complete|","14.0","|ranges|" `3480 `__,"``directory_iterator`` and ``recursive_directory_iterator`` are not C++20 ranges","October 2021","|Complete|","14.0","|ranges|" `3498 `__,"Inconsistent ``noexcept``-specifiers for ``basic_syncbuf``","October 2021","","" `3535 `__,"``join_view::iterator::iterator_category`` and ``::iterator_concept`` lie","October 2021","","","|ranges|" diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -39,13 +39,15 @@ #if !defined(_LIBCPP_HAS_NO_RANGES) namespace ranges { + template + concept __uses_nonqualification_pointer_conversion = + is_pointer_v<_From> && is_pointer_v<_To> && + !convertible_to(*)[], remove_pointer_t<_To>(*)[]>; + template concept __convertible_to_non_slicing = convertible_to<_From, _To> && - // If they're both pointers, they must have the same element type. - !(is_pointer_v> && - is_pointer_v> && - __different_from>, remove_pointer_t>>); + !__uses_nonqualification_pointer_conversion, decay_t<_To>>; template concept __pair_like = diff --git a/libcxx/test/std/ranges/range.utility/range.subrange/lwg3470.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/lwg3470.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.subrange/lwg3470.pass.cpp @@ -0,0 +1,50 @@ +//===----------------------------------------------------------------------===// +// +// 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-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// class std::ranges::subrange; +// Test the example from LWG 3470, +// qualification conversions in __convertible_to_non_slicing + +#include + +#include + +#include "test_macros.h" + +constexpr bool test() +{ + // The example from LWG3470, using implicit conversion. + int a[3] = { 1, 2, 3 }; + int* b[3] = { &a[2], &a[0], &a[1] }; + std::ranges::subrange c = b; + assert(c.begin() == b + 0); + assert(c.end() == b + 3); + + // Also test CTAD and a subrange-to-subrange conversion. + std::same_as> auto d = std::ranges::subrange(b); + assert(d.begin() == b + 0); + assert(d.end() == b + 3); + + std::ranges::subrange e = d; + assert(e.begin() == b + 0); + assert(e.end() == b + 3); + + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +}