diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -133,7 +133,7 @@ `[range.dangling] `_,"| ranges::dangling | ranges::borrowed_iterator_t | ranges::borrowed_subrange_t","| [range.range] -| [range.subrange]",Unassigned,Not started +| [range.subrange]",Christopher Di Bella,✅ `[range.all] `_,`view::all `_,"[range.subrange], [range.view.ref]",Zoe Carver,✅ `[range.view.ref] `_,`ref-view `_,[view.interface],Zoe Carver,✅ `[range.filter] `_,filter_view,[range.all],Louis Dionne,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -186,6 +186,7 @@ __ranges/all.h __ranges/concepts.h __ranges/copyable_box.h + __ranges/dangling.h __ranges/data.h __ranges/drop_view.h __ranges/empty_view.h diff --git a/libcxx/include/__ranges/dangling.h b/libcxx/include/__ranges/dangling.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/dangling.h @@ -0,0 +1,47 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___RANGES_DANGLING_H +#define _LIBCPP___RANGES_DANGLING_H + +#include <__config> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { +struct dangling { + dangling() = default; + _LIBCPP_HIDE_FROM_ABI constexpr dangling(auto&&...) noexcept {} +}; + +template +using borrowed_iterator_t = _If, iterator_t<_Rp>, dangling>; + +// borrowed_subrange_t defined in <__ranges/subrange.h> +} // namespace ranges + +#endif // !_LIBCPP_HAS_NO_RANGES + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_DANGLING_H 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 @@ -16,6 +16,7 @@ #include <__iterator/advance.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> @@ -248,6 +249,9 @@ template inline constexpr bool enable_borrowed_range> = true; + + template + using borrowed_subrange_t = _If, subrange >, dangling>; } // namespace ranges using ranges::get; diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -606,6 +606,7 @@ module all { private header "__ranges/all.h" } module concepts { private header "__ranges/concepts.h" } module copyable_box { private header "__ranges/copyable_box.h" } + module dangling { private header "__ranges/dangling.h" } module data { private header "__ranges/data.h" } module drop_view { private header "__ranges/drop_view.h" } module empty { private header "__ranges/empty.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -103,6 +103,15 @@ template inline constexpr bool enable_borrowed_range> = true; + // [range.dangling], dangling iterator handling + struct dangling; + + template + using borrowed_iterator_t = see below; + + template + using borrowed_subrange_t = see below; + // [range.empty], empty view template requires is_object_v @@ -145,6 +154,7 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__ranges/data.h> #include <__ranges/drop_view.h> #include <__ranges/empty.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/dangling.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/dangling.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/dangling.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__ranges/dangling.h'}} +#include <__ranges/dangling.h> diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// std::ranges::borrowed_iterator_t; + +#include + +#include +#include +#include +#include +#include + +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as >, std::ranges::dangling>); + +static_assert(std::same_as, std::string::iterator>); +static_assert(std::same_as, std::string_view::iterator>); +static_assert(std::same_as >, std::span::iterator>); + +template +constexpr bool has_borrowed_iterator = requires { + typename std::ranges::borrowed_iterator_t; +}; + +static_assert(!has_borrowed_iterator); diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// std::ranges::borrowed_subrange_t; + +#include + +#include +#include +#include +#include +#include + +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as >, std::ranges::dangling>); + +static_assert( + std::same_as, std::ranges::subrange >); + +static_assert( + std::same_as >, std::ranges::subrange::iterator> >); + +static_assert(std::same_as, + std::ranges::subrange >); + +template +constexpr bool has_type = requires { + typename std::ranges::borrowed_subrange_t; +}; + +static_assert(!has_type); + +struct S {}; +static_assert(!has_type); diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/dangling.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/dangling.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/dangling.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// std::ranges::dangling; + +#include + +#include +#include + +static_assert(std::is_empty_v); + +template struct S { }; +static_assert(std::is_nothrow_constructible_v); +static_assert(std::is_nothrow_constructible_v>); +static_assert(std::is_nothrow_constructible_v, S<1>>); +static_assert(std::is_nothrow_constructible_v, S<1>, S<2>>); + +constexpr bool test_dangling() { + [[maybe_unused]] auto a = std::ranges::dangling(); + [[maybe_unused]] auto b = std::ranges::dangling(S<0>()); + [[maybe_unused]] auto c = std::ranges::dangling(S<0>(), S<1>()); + [[maybe_unused]] auto d = std::ranges::dangling(S<0>(), S<1>(), S<2>()); + return true; +} + +int main(int, char**) { + static_assert(test_dangling()); + test_dangling(); + return 0; +}