Index: libcxx/include/CMakeLists.txt =================================================================== --- libcxx/include/CMakeLists.txt +++ libcxx/include/CMakeLists.txt @@ -172,7 +172,6 @@ __format/formatter_integral.h __format/formatter_string.h __format/parser_std_format_spec.h - __function_like.h __functional_base __functional/binary_function.h __functional/binary_negate.h Index: libcxx/include/__function_like.h =================================================================== --- libcxx/include/__function_like.h +++ /dev/null @@ -1,51 +0,0 @@ -// -*- 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___ITERATOR_FUNCTION_LIKE_H -#define _LIBCPP___ITERATOR_FUNCTION_LIKE_H - -#include <__config> - -#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header -#endif - -_LIBCPP_BEGIN_NAMESPACE_STD - -#if !defined(_LIBCPP_HAS_NO_RANGES) - -namespace ranges { -// Per [range.iter.ops.general] and [algorithms.requirements], functions in namespace std::ranges -// can't be found by ADL and inhibit ADL when found by unqualified lookup. The easiest way to -// facilitate this is to use function objects. -// -// Since these are still standard library functions, we use `__function_like` to eliminate most of -// the properties that function objects get by default (e.g. semiregularity, addressability), to -// limit the surface area of the unintended public interface, so as to curb the effect of Hyrum's -// law. -struct __function_like { - __function_like() = delete; - __function_like(__function_like const&) = delete; - __function_like& operator=(__function_like const&) = delete; - - void operator&() const = delete; - - struct __tag { }; - -protected: - constexpr explicit __function_like(__tag) noexcept {} - ~__function_like() = default; -}; -} // namespace ranges - -#endif // !defined(_LIBCPP_HAS_NO_RANGES) - -_LIBCPP_END_NAMESPACE_STD - -#endif // _LIBCPP___ITERATOR_FUNCTION_LIKE_H Index: libcxx/include/__iterator/advance.h =================================================================== --- libcxx/include/__iterator/advance.h +++ libcxx/include/__iterator/advance.h @@ -12,7 +12,6 @@ #include <__config> #include <__debug> -#include <__function_like.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> @@ -70,7 +69,7 @@ namespace ranges { // [range.iter.op.advance] // TODO(varconst): rename `__advance_fn` to `__fn`. -struct __advance_fn final : private __function_like { +struct __advance_fn { private: template _LIBCPP_HIDE_FROM_ABI @@ -97,8 +96,6 @@ } public: - constexpr explicit __advance_fn(__tag __x) noexcept : __function_like(__x) {} - // Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative. template _LIBCPP_HIDE_FROM_ABI @@ -186,7 +183,7 @@ } }; -inline constexpr auto advance = __advance_fn(__function_like::__tag()); +inline constexpr auto advance = __advance_fn(); } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) Index: libcxx/include/__iterator/next.h =================================================================== --- libcxx/include/__iterator/next.h +++ libcxx/include/__iterator/next.h @@ -12,7 +12,6 @@ #include <__config> #include <__debug> -#include <__function_like.h> #include <__iterator/advance.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> @@ -40,10 +39,7 @@ namespace ranges { // TODO(varconst): rename `__next_fn` to `__fn`. -struct __next_fn final : private __function_like { - _LIBCPP_HIDE_FROM_ABI - constexpr explicit __next_fn(__tag __x) noexcept : __function_like(__x) {} - +struct __next_fn { template _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const { @@ -73,7 +69,7 @@ } }; -inline constexpr auto next = __next_fn(__function_like::__tag()); +inline constexpr auto next = __next_fn(); } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) Index: libcxx/include/__iterator/prev.h =================================================================== --- libcxx/include/__iterator/prev.h +++ libcxx/include/__iterator/prev.h @@ -12,7 +12,6 @@ #include <__config> #include <__debug> -#include <__function_like.h> #include <__iterator/advance.h> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> @@ -39,10 +38,7 @@ namespace ranges { // TODO(varconst): rename `__prev_fn` to `__fn`. -struct __prev_fn final : private __function_like { - _LIBCPP_HIDE_FROM_ABI - constexpr explicit __prev_fn(__tag __x) noexcept : __function_like(__x) {} - +struct __prev_fn { template _LIBCPP_HIDE_FROM_ABI constexpr _Ip operator()(_Ip __x) const { @@ -65,7 +61,7 @@ } }; -inline constexpr auto prev = __prev_fn(__function_like::__tag()); +inline constexpr auto prev = __prev_fn(); } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) Index: libcxx/include/__memory/ranges_uninitialized_algorithms.h =================================================================== --- libcxx/include/__memory/ranges_uninitialized_algorithms.h +++ libcxx/include/__memory/ranges_uninitialized_algorithms.h @@ -12,7 +12,6 @@ #include <__concepts/constructible.h> #include <__config> -#include <__function_like.h> #include <__iterator/incrementable_traits.h> #include <__iterator/iterator_traits.h> #include <__iterator/readable_traits.h> @@ -37,10 +36,7 @@ namespace __uninitialized_default_construct { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator, __nothrow_sentinel_for<_ForwardIterator> _Sentinel> requires default_initializable> @@ -55,25 +51,19 @@ borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const { return (*this)(ranges::begin(__range), ranges::end(__range)); } - }; } // namespace __uninitialized_default_construct inline namespace __cpo { -inline constexpr auto uninitialized_default_construct = - __uninitialized_default_construct::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_default_construct = __uninitialized_default_construct::__fn(); } // namespace __cpo // uninitialized_default_construct_n namespace __uninitialized_default_construct_n { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : - __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator> requires default_initializable> _ForwardIterator operator()(_ForwardIterator __first, @@ -81,24 +71,19 @@ using _ValueType = remove_reference_t>; return _VSTD::__uninitialized_default_construct_n<_ValueType>(_VSTD::move(__first), __n); } - }; } // namespace __uninitialized_default_construct_n inline namespace __cpo { -inline constexpr auto uninitialized_default_construct_n = - __uninitialized_default_construct_n::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_default_construct_n = __uninitialized_default_construct_n::__fn(); } // namespace __cpo // uninitialized_value_construct namespace __uninitialized_value_construct { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator, __nothrow_sentinel_for<_ForwardIterator> _Sentinel> requires default_initializable> @@ -113,24 +98,19 @@ borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const { return (*this)(ranges::begin(__range), ranges::end(__range)); } - }; } // namespace __uninitialized_value_construct inline namespace __cpo { -inline constexpr auto uninitialized_value_construct = - __uninitialized_value_construct::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_value_construct = __uninitialized_value_construct::__fn(); } // namespace __cpo // uninitialized_value_construct_n namespace __uninitialized_value_construct_n { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator> requires default_initializable> _ForwardIterator operator()(_ForwardIterator __first, @@ -138,24 +118,19 @@ using _ValueType = remove_reference_t>; return _VSTD::__uninitialized_value_construct_n<_ValueType>(_VSTD::move(__first), __n); } - }; } // namespace __uninitialized_value_construct_n inline namespace __cpo { -inline constexpr auto uninitialized_value_construct_n = - __uninitialized_value_construct_n::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_value_construct_n = __uninitialized_value_construct_n::__fn(); } // namespace __cpo // uninitialized_fill namespace __uninitialized_fill { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator, __nothrow_sentinel_for<_ForwardIterator> _Sentinel, class _Tp> @@ -170,23 +145,19 @@ borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range, const _Tp& __x) const { return (*this)(ranges::begin(__range), ranges::end(__range), __x); } - }; -} // namespace __uninitialized_fil +} // namespace __uninitialized_fill inline namespace __cpo { -inline constexpr auto uninitialized_fill = __uninitialized_fill::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_fill = __uninitialized_fill::__fn(); } // namespace __cpo // uninitialized_fill_n namespace __uninitialized_fill_n { -struct __fn final : private __function_like { - - constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {} - +struct __fn { template <__nothrow_forward_iterator _ForwardIterator, class _Tp> requires constructible_from, const _Tp&> _ForwardIterator operator()(_ForwardIterator __first, @@ -195,13 +166,12 @@ using _ValueType = remove_reference_t>; return _VSTD::__uninitialized_fill_n<_ValueType>(_VSTD::move(__first), __n, __x); } - }; } // namespace __uninitialized_fill_n inline namespace __cpo { -inline constexpr auto uninitialized_fill_n = __uninitialized_fill_n::__fn(__function_like::__tag()); + inline constexpr auto uninitialized_fill_n = __uninitialized_fill_n::__fn(); } // namespace __cpo } // namespace ranges Index: libcxx/include/module.modulemap =================================================================== --- libcxx/include/module.modulemap +++ libcxx/include/module.modulemap @@ -579,10 +579,7 @@ module __iterator { module access { private header "__iterator/access.h" } - module advance { - private header "__iterator/advance.h" - export __function_like - } + module advance { private header "__iterator/advance.h" } module back_insert_iterator { private header "__iterator/back_insert_iterator.h" } module common_iterator { private header "__iterator/common_iterator.h" } module concepts { private header "__iterator/concepts.h" } @@ -602,16 +599,10 @@ module iterator { private header "__iterator/iterator.h" } module iterator_traits { private header "__iterator/iterator_traits.h" } module move_iterator { private header "__iterator/move_iterator.h" } - module next { - private header "__iterator/next.h" - export __function_like - } + module next { private header "__iterator/next.h" } module ostream_iterator { private header "__iterator/ostream_iterator.h" } module ostreambuf_iterator { private header "__iterator/ostreambuf_iterator.h" } - module prev { - private header "__iterator/prev.h" - export __function_like - } + module prev { private header "__iterator/prev.h" } module projected { private header "__iterator/projected.h" } module readable_traits { private header "__iterator/readable_traits.h" } module reverse_access { private header "__iterator/reverse_access.h" } @@ -659,10 +650,7 @@ module concepts { private header "__memory/concepts.h" } module construct_at { private header "__memory/construct_at.h" } module pointer_traits { private header "__memory/pointer_traits.h" } - module ranges_uninitialized_algorithms { - private header "__memory/ranges_uninitialized_algorithms.h" - export __function_like - } + module ranges_uninitialized_algorithms { private header "__memory/ranges_uninitialized_algorithms.h" } module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" } module shared_ptr { private header "__memory/shared_ptr.h" } module temporary_buffer { private header "__memory/temporary_buffer.h" } @@ -968,7 +956,6 @@ module __bits { private header "__bits" export * } module __debug { header "__debug" export * } module __errc { private header "__errc" export * } - module __function_like { private header "__function_like.h" export * } module __hash_table { header "__hash_table" export * } module __locale { private header "__locale" export * } module __mbstate { private header "__mbstate_t.h" export * } Index: libcxx/test/libcxx/diagnostics/detail.headers/function_like.h.module.verify.cpp =================================================================== --- libcxx/test/libcxx/diagnostics/detail.headers/function_like.h.module.verify.cpp +++ /dev/null @@ -1,15 +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 -// -//===----------------------------------------------------------------------===// - -// 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: '__function_like.h'}} -#include <__function_like.h> Index: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/special_function.compile.pass.cpp =================================================================== --- libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/special_function.compile.pass.cpp +++ libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/special_function.compile.pass.cpp @@ -13,82 +13,9 @@ #include -#include "test_standard_function.h" +#include "test_macros.h" -static_assert(is_function_like()); - -// FIXME: We're bending the rules here by adding a new type to namespace std::ranges. Since this is -// the standard library's test suite, this should be fine (we *are* the implementation), but it's -// necessary at the time of writing since there aren't any iterators in std::ranges that we can -// borrow for this test. -namespace std::ranges { -class fake_forward_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - fake_forward_iterator() = default; - - value_type operator*() const; - fake_forward_iterator& operator++(); - fake_forward_iterator operator++(int); - - bool operator==(fake_forward_iterator const&) const = default; -}; -} // namespace std::ranges - -template -constexpr bool unqualified_lookup_works = requires(I i, Args... args) { - advance(i, args...); -}; - -static_assert(!unqualified_lookup_works); -static_assert(!unqualified_lookup_works); -static_assert( - !unqualified_lookup_works); - -namespace test { -template -class forward_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - forward_iterator() = default; - - value_type operator*() const; - forward_iterator& operator++(); - forward_iterator operator++(int); - - bool operator==(forward_iterator const&) const = default; -}; - -template -void advance(forward_iterator&, std::ptrdiff_t) { - static_assert(std::same_as); -} - -template -void advance(forward_iterator&, forward_iterator) { - static_assert(std::same_as); -} - -template -void advance(forward_iterator&, std::ptrdiff_t, forward_iterator) { - static_assert(std::same_as); -} -} // namespace test - -// TODO(varconst): simply check that `advance` is a variable and not a function. -// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a -// function call ([expr.call]), they inhibit argument-dependent name lookup. -void adl_inhibition() { - test::forward_iterator x; - - using std::ranges::advance; - advance(x, 0); - advance(x, x); - advance(x, 0, x); -} +// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, +// implementations are allowed to use a different mechanism to achieve this effect, so this check is +// libc++-specific. +LIBCPP_STATIC_ASSERT(std::is_class_v); Index: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/special_function.compile.pass.cpp =================================================================== --- libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/special_function.compile.pass.cpp +++ libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/special_function.compile.pass.cpp @@ -13,91 +13,9 @@ #include -#include "test_standard_function.h" +#include "test_macros.h" -static_assert(is_function_like()); - -// FIXME: We're bending the rules here by adding a new type to namespace std::ranges. Since this is -// the standard library's test suite, this should be fine (we *are* the implementation), but it's -// necessary at the time of writing since there aren't any iterators in std::ranges that we can -// borrow for this test. -namespace std::ranges { -class fake_forward_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - fake_forward_iterator() = default; - - value_type operator*() const; - fake_forward_iterator& operator++(); - fake_forward_iterator operator++(int); - - bool operator==(fake_forward_iterator const&) const = default; -}; -} // namespace std::ranges - -// The function templates defined in [range.iter.ops] are not found by argument-dependent name lookup ([basic.lookup.argdep]). -template -constexpr bool unqualified_lookup_works = requires(I i, Args... args) { - next(i, args...); -}; - -static_assert(!unqualified_lookup_works); -static_assert(!unqualified_lookup_works); -static_assert(!unqualified_lookup_works); -static_assert( - !unqualified_lookup_works); - -namespace test { -template -class forward_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::forward_iterator_tag; - - forward_iterator() = default; - - value_type operator*() const; - forward_iterator& operator++(); - forward_iterator operator++(int); - - bool operator==(forward_iterator const&) const = default; -}; - -template -void next(forward_iterator) { - static_assert(std::same_as); -} - -template -void next(forward_iterator, std::ptrdiff_t) { - static_assert(std::same_as); -} - -template -void next(forward_iterator, forward_iterator) { - static_assert(std::same_as); -} - -template -void next(forward_iterator, std::ptrdiff_t, forward_iterator) { - static_assert(std::same_as); -} -} // namespace test - -// TODO(varconst): simply check that `next` is a variable and not a function. -// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a -// function call ([expr.call]), they inhibit argument-dependent name lookup. -void adl_inhibition() { - test::forward_iterator x; - - using std::ranges::next; - - (void)next(x); - (void)next(x, 5); - (void)next(x, x); - (void)next(x, 6, x); -} +// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, +// implementations are allowed to use a different mechanism to achieve this effect, so this check is +// libc++-specific. +LIBCPP_STATIC_ASSERT(std::is_class_v); Index: libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp =================================================================== --- libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp +++ libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.prev/special_function.compile.pass.cpp @@ -13,85 +13,9 @@ #include -#include "test_iterators.h" -#include "test_standard_function.h" +#include "test_macros.h" -static_assert(is_function_like()); - -namespace std::ranges { -class fake_bidirectional_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::bidirectional_iterator_tag; - - fake_bidirectional_iterator() = default; - - value_type operator*() const; - fake_bidirectional_iterator& operator++(); - fake_bidirectional_iterator operator++(int); - fake_bidirectional_iterator& operator--(); - fake_bidirectional_iterator operator--(int); - - bool operator==(fake_bidirectional_iterator const&) const = default; -}; -} // namespace std::ranges - -// The function templates defined in [range.iter.ops] are not found by argument-dependent name lookup ([basic.lookup.argdep]). -template -constexpr bool unqualified_lookup_works = requires(I i, Args... args) { - prev(i, args...); -}; - -static_assert(!unqualified_lookup_works); -static_assert(!unqualified_lookup_works); -static_assert(!unqualified_lookup_works); - -namespace test { -template -class bidirectional_iterator { -public: - using value_type = int; - using difference_type = std::ptrdiff_t; - using iterator_category = std::bidirectional_iterator_tag; - - bidirectional_iterator() = default; - - value_type operator*() const; - bidirectional_iterator& operator++(); - bidirectional_iterator operator++(int); - bidirectional_iterator& operator--(); - bidirectional_iterator operator--(int); - - bool operator==(bidirectional_iterator const&) const = default; -}; - -template -void prev(bidirectional_iterator) { - static_assert(std::same_as); -} - -template -void prev(bidirectional_iterator, std::ptrdiff_t) { - static_assert(std::same_as); -} - -template -void prev(bidirectional_iterator, std::ptrdiff_t, bidirectional_iterator) { - static_assert(std::same_as); -} -} // namespace test - -// TODO(varconst): simply check that `prev` is a variable and not a function. -// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a -// function call ([expr.call]), they inhibit argument-dependent name lookup. -void adl_inhibition() { - test::bidirectional_iterator x; - - using std::ranges::prev; - - (void)prev(x); - (void)prev(x, 5); - (void)prev(x, 6, x); -} +// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, +// implementations are allowed to use a different mechanism to achieve this effect, so this check is +// libc++-specific. +LIBCPP_STATIC_ASSERT(std::is_class_v); Index: libcxx/test/support/test_standard_function.h =================================================================== --- libcxx/test/support/test_standard_function.h +++ /dev/null @@ -1,39 +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 -// -//===----------------------------------------------------------------------===// -#ifndef LIBCXX_TEST_SUPPORT_TEST_STANDARD_FUNCTION_H -#define LIBCXX_TEST_SUPPORT_TEST_STANDARD_FUNCTION_H - -#include "test_macros.h" - -#if TEST_STD_VER >= 20 -template -constexpr bool is_addressable = requires(T t) { - &t; -}; - -template -constexpr bool is_function_like() { - using X = std::remove_cvref_t; - static_assert(!is_addressable); - static_assert(!is_addressable); - - static_assert(std::destructible && !std::default_initializable); - - static_assert(!std::move_constructible); - static_assert(!std::assignable_from); - - static_assert(!std::copy_constructible); - static_assert(!std::assignable_from); - static_assert(!std::assignable_from); - static_assert(!std::assignable_from); - static_assert(std::is_final_v); - return true; -} -#endif - -#endif // LIBCXX_TEST_SUPPORT_TEST_STANDARD_FUNCTION_H