From d7e1e79d303662cba25f45bbb9fb4af79d9a6139 Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Thu, 16 Feb 2023 18:02:25 -0800 Subject: [PATCH 1/2] Workaround some Clang-16-rc2 regressions * ``: wrap `zip_transform_view`'s constraints in a named concept so we can redeclare the class template, e.g., in a `friend` declaration. Repetitions of atomic constraints with equal expressions do not subsume, and Clang 16 is enforcing this rule more strictly. * ``: allow clang-format to format some more code, add some parens to keep it from going wild. Define a `_Store_size` helper concept for `subrange` instead of using a `static constexpr bool` class member as a perma-workaround for LLVM-60868. * `tests/std/tests/P0323R12_expected`: Don't reference a local variable in a local class definition. (Clang 16 refuses to compile this; I suspect current compilers should as well.) These changes don't make all tests pass with Clang 16, but should suffice to enable it to use the STL. --- stl/inc/ranges | 18 ++-- stl/inc/xutility | 117 +++++++++++---------- tests/std/tests/P0323R12_expected/test.cpp | 2 +- 3 files changed, 70 insertions(+), 67 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 78b1c04e432..4c07f0e138c 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -7570,6 +7570,12 @@ namespace ranges { && (convertible_to, sentinel_t> && ...); #endif // ^^^ workaround ^^^ + template + concept _Zip_transform_constraints = move_constructible<_Func> && is_object_v<_Func> && (sizeof...(_Views) > 0) + && (input_range<_Views> && ...) && (view<_Views> && ...) + && regular_invocable<_Func&, range_reference_t<_Views>...> + && _Can_reference...>>; + _EXPORT_STD template requires (view<_ViewTypes> && ...) && (sizeof...(_ViewTypes) > 0) class zip_view : public view_interface> { @@ -7590,10 +7596,8 @@ namespace ranges { private: friend zip_view; - template - requires ((view<_OtherViews> && ...) && (sizeof...(_OtherViews) > 0) - && is_object_v<_Func> && regular_invocable<_Func&, range_reference_t<_OtherViews>...> - && _Can_reference...>>) + template + requires _Zip_transform_constraints<_Func, _OtherViews...> friend class zip_transform_view; using _My_tuple = tuple>...>; @@ -7988,10 +7992,8 @@ namespace ranges { _EXPORT_STD inline constexpr _Zip_fn zip{}; } // namespace views - _EXPORT_STD template - requires ((view<_ViewTypes> && ...) && (sizeof...(_ViewTypes) > 0) - && is_object_v<_Func> && regular_invocable<_Func&, range_reference_t<_ViewTypes>...> - && _Can_reference...>>) + _EXPORT_STD template + requires _Zip_transform_constraints<_Func, _ViewTypes...> class zip_transform_view : public view_interface> { private: using _Inner_view = zip_view<_ViewTypes...>; diff --git a/stl/inc/xutility b/stl/inc/xutility index c53c060d248..11a731e43f6 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3599,99 +3599,100 @@ _EXPORT_STD template _NODISCARD constexpr const tuple_element_t<_Index, tuple<_Types...>>&& get(const tuple<_Types...>&& _Tuple) noexcept; namespace ranges { - // clang-format off template concept _Uses_nonqualification_pointer_conversion = is_pointer_v<_From> && is_pointer_v<_To> - && !convertible_to(*)[], remove_pointer_t<_To>(*)[]>; + && (!convertible_to (*)[], remove_pointer_t<_To> (*)[]>); template concept _Convertible_to_non_slicing = convertible_to<_From, _To> - && !_Uses_nonqualification_pointer_conversion, decay_t<_To>>; + && (!_Uses_nonqualification_pointer_conversion, decay_t<_To>>); template - concept _Pair_like = !is_reference_v<_Ty> && requires(_Ty __t) { - typename tuple_size<_Ty>::type; - requires derived_from, integral_constant>; - typename tuple_element_t<0, remove_const_t<_Ty>>; - typename tuple_element_t<1, remove_const_t<_Ty>>; - { _STD get<0>(__t) } -> convertible_to&>; - { _STD get<1>(__t) } -> convertible_to&>; - }; + concept _Pair_like = + (!is_reference_v<_Ty>) && requires(_Ty __t) { + typename tuple_size<_Ty>::type; + requires derived_from, integral_constant>; + typename tuple_element_t<0, remove_const_t<_Ty>>; + typename tuple_element_t<1, remove_const_t<_Ty>>; + { _STD get<0>(__t) } -> convertible_to&>; + { _STD get<1>(__t) } -> convertible_to&>; + }; template - concept _Pair_like_convertible_from = !range<_Ty> && _Pair_like<_Ty> - && constructible_from<_Ty, _First, _Second> - && _Convertible_to_non_slicing<_First, tuple_element_t<0, _Ty>> - && convertible_to<_Second, tuple_element_t<1, _Ty>>; - // clang-format on + concept _Pair_like_convertible_from = (!range<_Ty>) && _Pair_like<_Ty> && constructible_from<_Ty, _First, _Second> + && _Convertible_to_non_slicing<_First, tuple_element_t<0, _Ty>> + && convertible_to<_Second, tuple_element_t<1, _Ty>>; - template > - class _Subrange_base : public view_interface> { // TRANSITION, [[no_unique_address]] - protected: - using _Size_type = _Make_unsigned_like_t>; - static constexpr bool _Store_size = true; + template + concept _Store_size = (_Ki == subrange_kind::sized) + && /* sentinel_for<_Se, _It> && */ (!sized_sentinel_for<_Se, _It>); - _Size_type _Size = 0; + template + class _Subrange_base : public view_interface> { + protected: + using _Size_type = _Make_unsigned_like_t>; public: _Subrange_base() = default; - constexpr explicit _Subrange_base(const _Size_type& _Size_) noexcept : _Size(_Size_) {} + constexpr explicit _Subrange_base(const _Size_type&) noexcept {} }; template - class _Subrange_base<_It, _Se, _Ki, false> : public view_interface> { + requires _Store_size<_It, _Se, _Ki> + class _Subrange_base<_It, _Se, _Ki> : public view_interface> { protected: - using _Size_type = _Make_unsigned_like_t>; - static constexpr bool _Store_size = false; + using _Size_type = _Make_unsigned_like_t>; + + _Size_type _Size = 0; public: _Subrange_base() = default; - constexpr explicit _Subrange_base(const _Size_type&) noexcept {} + constexpr explicit _Subrange_base(const _Size_type& _Size_) noexcept : _Size(_Size_) {} }; #if 1 // TRANSITION, VSO-1695918 - Warning C4324 incorrectly firing in the presence of `pragma pack` #pragma warning(push) #pragma warning(disable : 4324) // structure was padded due to alignment specifier -#endif // TRANSITION, VSO-1695918 - Warning C4324 incorrectly firing in the presence of `pragma pack` +#endif // ^^^ workaround ^^^ _EXPORT_STD template _Se, subrange_kind _Ki> requires (_Ki == subrange_kind::sized || !sized_sentinel_for<_Se, _It>) class subrange : public _Subrange_base<_It, _Se, _Ki> { private: - using _Mybase = _Subrange_base<_It, _Se, _Ki>; - using _Mybase::_Store_size; - using typename _Mybase::_Size_type; + using _Size_type = _Make_unsigned_like_t>; // TRANSITION, [[no_unique_address]]: /* [[no_unique_address]] */ _It _First{}; /* [[no_unique_address]] */ _Se _Last{}; - // [[no_unique_address]] conditional_t<_Store_size, _Size_type, _Nil> _Size{}; + // [[no_unique_address]] conditional_t<_Store_size<_It, _Se, _Ki>, _Size_type, _Nil> _Size{}; template constexpr subrange(true_type, _Rng&& _Val) : subrange(_STD forward<_Rng>(_Val), static_cast<_Size_type>(_RANGES size(_Val))) { // delegation target for subrange(_Rng&&) when we must store the range size - _STL_INTERNAL_STATIC_ASSERT(_Store_size); + _STL_INTERNAL_STATIC_ASSERT(_Store_size<_It, _Se, _Ki>); } template constexpr subrange(false_type, _Rng&& _Val) : subrange(_RANGES begin(_Val), _RANGES end(_Val)) { // delegation target for subrange(_Rng&&) when we need not store the range size - _STL_INTERNAL_STATIC_ASSERT(!_Store_size); + _STL_INTERNAL_STATIC_ASSERT(!_Store_size<_It, _Se, _Ki>); } public: // clang-format off subrange() requires default_initializable<_It> = default; + // clang-format on template <_Convertible_to_non_slicing<_It> _It2> - constexpr subrange(_It2 _First_, _Se _Last_) requires (!_Store_size) + constexpr subrange(_It2 _First_, _Se _Last_) + requires (!_Store_size<_It, _Se, _Ki>) : _First(_STD move(_First_)), _Last(_STD move(_Last_)) {} template <_Convertible_to_non_slicing<_It> _It2> - constexpr subrange(_It2 _First_, _Se _Last_, const _Size_type _Size_) requires (_Ki == subrange_kind::sized) - : _Mybase(_Size_), _First(_STD move(_First_)), _Last(_STD move(_Last_)) { + constexpr subrange(_It2 _First_, _Se _Last_, const _Size_type _Size_) + requires (_Ki == subrange_kind::sized) + : _Subrange_base<_It, _Se, _Ki>(_Size_), _First(_STD move(_First_)), _Last(_STD move(_Last_)) { if constexpr (sized_sentinel_for<_Se, _It>) { _STL_ASSERT(_Size_ == static_cast<_Size_type>(_Last - _First), "This constructor's third argument should be equal to the distance " @@ -3700,17 +3701,17 @@ namespace ranges { } template <_Different_from _Rng> - requires borrowed_range<_Rng> - && _Convertible_to_non_slicing, _It> - && convertible_to, _Se> - constexpr subrange(_Rng&& _Val) requires (!_Store_size || sized_range<_Rng>) - : subrange{bool_constant<_Store_size>{}, _STD forward<_Rng>(_Val)} {} + requires (borrowed_range<_Rng> && _Convertible_to_non_slicing, _It> + && convertible_to, _Se>) + constexpr subrange(_Rng&& _Val) + requires (!_Store_size<_It, _Se, _Ki> || sized_range<_Rng>) + : subrange{bool_constant<_Store_size<_It, _Se, _Ki>>{}, _STD forward<_Rng>(_Val)} {} template - requires _Convertible_to_non_slicing, _It> && convertible_to, _Se> - constexpr subrange(_Rng&& _Val, const _Size_type _Count) requires (_Ki == subrange_kind::sized) + requires (_Convertible_to_non_slicing, _It> && convertible_to, _Se>) + constexpr subrange(_Rng&& _Val, const _Size_type _Count) + requires (_Ki == subrange_kind::sized) : subrange{_RANGES begin(_Val), _RANGES end(_Val), _Count} {} - // clang-format on template <_Different_from _Pair_like> requires _Pair_like_convertible_from<_Pair_like, const _It&, const _Se&> @@ -3723,9 +3724,9 @@ namespace ranges { { return _First; } - // clang-format off - _NODISCARD constexpr _It begin() requires (!copyable<_It>) { - // clang-format on + _NODISCARD constexpr _It begin() + requires (!copyable<_It>) + { return _STD move(_First); } @@ -3737,10 +3738,10 @@ namespace ranges { return _First == _Last; } - // clang-format off - _NODISCARD constexpr _Size_type size() const requires (_Ki == subrange_kind::sized) { - // clang-format on - if constexpr (_Store_size) { + _NODISCARD constexpr _Size_type size() const + requires (_Ki == subrange_kind::sized) + { + if constexpr (_Store_size<_It, _Se, _Ki>) { return this->_Size; } else { return static_cast<_Size_type>(_Last - _First); @@ -3753,7 +3754,7 @@ namespace ranges { auto _Tmp = *this; if (_Tmp._First != _Tmp._Last) { ++_Tmp._First; - if constexpr (_Store_size) { + if constexpr (_Store_size<_It, _Se, _Ki>) { --_Tmp._Size; } } @@ -3770,7 +3771,7 @@ namespace ranges { _NODISCARD constexpr subrange next() && { if (_First != _Last) { ++_First; - if constexpr (_Store_size) { + if constexpr (_Store_size<_It, _Se, _Ki>) { --this->_Size; } } @@ -3786,7 +3787,7 @@ namespace ranges { { auto _Tmp = *this; --_Tmp._First; - if constexpr (_Store_size) { + if constexpr (_Store_size<_It, _Se, _Ki>) { ++_Tmp._Size; } return _Tmp; @@ -3803,7 +3804,7 @@ namespace ranges { if constexpr (bidirectional_iterator<_It>) { if (_Count < 0) { _RANGES advance(_First, _Count); - if constexpr (_Store_size) { + if constexpr (_Store_size<_It, _Se, _Ki>) { this->_Size += static_cast<_Size_type>(-_Count); } return *this; @@ -3811,7 +3812,7 @@ namespace ranges { } const auto _Remainder = _RANGES advance(_First, _Count, _Last); - if constexpr (_Store_size) { + if constexpr (_Store_size<_It, _Se, _Ki>) { this->_Size -= static_cast<_Size_type>(_Count - _Remainder); } return *this; diff --git a/tests/std/tests/P0323R12_expected/test.cpp b/tests/std/tests/P0323R12_expected/test.cpp index 1f02f528726..14bfc85b158 100644 --- a/tests/std/tests/P0323R12_expected/test.cpp +++ b/tests/std/tests/P0323R12_expected/test.cpp @@ -202,7 +202,7 @@ namespace test_expected { struct payload_default_constructor { constexpr payload_default_constructor() - requires (should_be_defaultable) + requires (IsYes(defaultConstructible)) : _val(42) {} [[nodiscard]] constexpr bool operator==(const int val) const noexcept { From 93d85c462cf076f1f7e5de4e192cc3997f8af82a Mon Sep 17 00:00:00 2001 From: Casey Carter Date: Sun, 19 Feb 2023 22:28:05 -0800 Subject: [PATCH 2/2] Casey's review comments --- stl/inc/xutility | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/stl/inc/xutility b/stl/inc/xutility index 11a731e43f6..d3ddf7d260b 100644 --- a/stl/inc/xutility +++ b/stl/inc/xutility @@ -3625,8 +3625,7 @@ namespace ranges { && convertible_to<_Second, tuple_element_t<1, _Ty>>; template - concept _Store_size = (_Ki == subrange_kind::sized) - && /* sentinel_for<_Se, _It> && */ (!sized_sentinel_for<_Se, _It>); + concept _Store_size = (_Ki == subrange_kind::sized) && (!sized_sentinel_for<_Se, _It>); template class _Subrange_base : public view_interface> { @@ -3820,7 +3819,7 @@ namespace ranges { }; #if 1 // TRANSITION, VSO-1695918 - Warning C4324 incorrectly firing in the presence of `pragma pack` #pragma warning(pop) -#endif // TRANSITION, VSO-1695918 - Warning C4324 incorrectly firing in the presence of `pragma pack` +#endif // ^^^ workaround ^^^ template _Se> subrange(_It, _Se) -> subrange<_It, _Se>;