Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADL-proof implementation of range verifying and functor passing components that involve arbitrary types #4402

Merged
merged 8 commits into from
Feb 27, 2024
2 changes: 1 addition & 1 deletion stl/inc/mutex
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ public:
template <class _Rep, class _Period, class _Predicate>
bool wait_for(unique_lock<mutex>& _Lck, const chrono::duration<_Rep, _Period>& _Rel_time, _Predicate _Pred) {
// wait for signal with timeout and check predicate
return wait_until(_Lck, _To_absolute_time(_Rel_time), _Pass_fn(_Pred));
return wait_until(_Lck, _To_absolute_time(_Rel_time), _STD _Pass_fn(_Pred));
}

template <class _Clock, class _Duration>
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/span
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ public:

template <_Span_compatible_iterator<element_type> _It>
constexpr explicit(_Extent != dynamic_extent) span(_It _First, size_type _Count) noexcept // strengthened
: _Mybase(_STD to_address(_Get_unwrapped_n(_First, _Count)), _Count) {
: _Mybase(_STD to_address(_STD _Get_unwrapped_n(_First, _Count)), _Count) {
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Extent != dynamic_extent) {
_STL_VERIFY(_Count == _Extent,
Expand All @@ -301,7 +301,7 @@ public:
constexpr explicit(_Extent != dynamic_extent)
span(_It _First, _Sentinel _Last) noexcept(noexcept(_Last - _First)) // strengthened
: _Mybase(_STD to_address(_First), static_cast<size_type>(_Last - _First)) {
_Adl_verify_range(_First, _Last);
_STD _Adl_verify_range(_First, _Last);
#if _CONTAINER_DEBUG_LEVEL > 0
if constexpr (_Extent != dynamic_extent) {
_STL_VERIFY(_Last - _First == _Extent,
Expand Down
41 changes: 22 additions & 19 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -1546,8 +1546,8 @@ _CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { // increment iterator by
_STL_ASSERT(_Off >= 0, "negative advance of non-bidirectional iterator");
}

decltype(auto) _UWhere = _Get_unwrapped_n(_STD move(_Where), _Off);
constexpr bool _Need_rewrap = !is_reference_v<decltype(_Get_unwrapped_n(_STD move(_Where), _Off))>;
decltype(auto) _UWhere = _STD _Get_unwrapped_n(_STD move(_Where), _Off);
constexpr bool _Need_rewrap = !is_reference_v<decltype(_STD _Get_unwrapped_n(_STD move(_Where), _Off))>;

if constexpr (is_signed_v<_Diff> && _Is_ranges_bidi_iter_v<_InIt>) {
for (; _Off < 0; ++_Off) {
Expand All @@ -1560,7 +1560,7 @@ _CONSTEXPR17 void advance(_InIt& _Where, _Diff _Off) { // increment iterator by
}

if constexpr (_Need_rewrap) {
_Seek_wrapped(_Where, _STD move(_UWhere));
_STD _Seek_wrapped(_Where, _STD move(_UWhere));
}
}
}
Expand All @@ -1570,9 +1570,9 @@ _NODISCARD _CONSTEXPR17 _Iter_diff_t<_InIt> distance(_InIt _First, _InIt _Last)
if constexpr (_Is_ranges_random_iter_v<_InIt>) {
return _Last - _First; // assume the iterator will do debug checking
} else {
_Adl_verify_range(_First, _Last);
auto _UFirst = _Get_unwrapped(_First);
const auto _ULast = _Get_unwrapped(_Last);
_STD _Adl_verify_range(_First, _Last);
auto _UFirst = _STD _Get_unwrapped(_First);
const auto _ULast = _STD _Get_unwrapped(_Last);
_Iter_diff_t<_InIt> _Off = 0;
for (; _UFirst != _ULast; ++_UFirst) {
++_Off;
Expand Down Expand Up @@ -3363,8 +3363,8 @@ namespace ranges {
_STL_ASSERT(_Off >= 0, "negative advance of non-bidirectional iterator");
}

decltype(auto) _UWhere = _Get_unwrapped_n(_STD move(_Where), _Off);
constexpr bool _Need_rewrap = !is_reference_v<decltype(_Get_unwrapped_n(_STD move(_Where), _Off))>;
decltype(auto) _UWhere = _STD _Get_unwrapped_n(_STD move(_Where), _Off);
constexpr bool _Need_rewrap = !is_reference_v<decltype(_STD _Get_unwrapped_n(_STD move(_Where), _Off))>;

if constexpr (bidirectional_iterator<_It>) {
for (; _Off < 0; ++_Off) {
Expand All @@ -3377,7 +3377,7 @@ namespace ranges {
}

if constexpr (_Need_rewrap) {
_Seek_wrapped(_Where, _STD move(_UWhere));
_STD _Seek_wrapped(_Where, _STD move(_UWhere));
}
}
}
Expand All @@ -3389,18 +3389,19 @@ namespace ranges {
} else if constexpr (sized_sentinel_for<_Se, _It>) {
operator()(_Where, _Last - _Where);
} else {
_Adl_verify_range(_Where, _Last);
_STD _Adl_verify_range(_Where, _Last);

decltype(auto) _UWhere = _Unwrap_iter<_Se>(static_cast<_It&&>(_Where));
constexpr bool _Need_rewrap = !is_reference_v<decltype(_Unwrap_iter<_Se>(static_cast<_It&&>(_Where)))>;
decltype(auto) _ULast = _Unwrap_sent<_It>(static_cast<_Se&&>(_Last));
decltype(auto) _UWhere = _RANGES _Unwrap_iter<_Se>(static_cast<_It&&>(_Where));
constexpr bool _Need_rewrap =
!is_reference_v<decltype(_RANGES _Unwrap_iter<_Se>(static_cast<_It&&>(_Where)))>;
decltype(auto) _ULast = _RANGES _Unwrap_sent<_It>(static_cast<_Se&&>(_Last));

while (_UWhere != _ULast) {
++_UWhere;
}

if constexpr (_Need_rewrap) {
_Seek_wrapped(_Where, _STD move(_UWhere));
_STD _Seek_wrapped(_Where, _STD move(_UWhere));
}
}
}
Expand Down Expand Up @@ -3446,11 +3447,13 @@ namespace ranges {
public:
template <class _It, sentinel_for<_It> _Se>
requires (!sized_sentinel_for<_Se, _It>)
_NODISCARD _STATIC_CALL_OPERATOR constexpr iter_difference_t<_It> operator()(_It _First,
_Se _Last) _CONST_CALL_OPERATOR noexcept(noexcept(_Distance_unchecked(_Get_unwrapped(_STD move(_First)),
_Get_unwrapped(_STD move(_Last))))) /* strengthened */ {
_Adl_verify_range(_First, _Last);
return _Distance_unchecked(_Unwrap_iter<_Se>(_STD move(_First)), _Unwrap_sent<_It>(_STD move(_Last)));
_NODISCARD _STATIC_CALL_OPERATOR constexpr iter_difference_t<_It> operator()(
_It _First, _Se _Last) _CONST_CALL_OPERATOR
noexcept(noexcept(_Distance_unchecked(
_STD _Get_unwrapped(_STD move(_First)), _STD _Get_unwrapped(_STD move(_Last))))) /* strengthened */ {
_STD _Adl_verify_range(_First, _Last);
return _Distance_unchecked(
_RANGES _Unwrap_iter<_Se>(_STD move(_First)), _RANGES _Unwrap_sent<_It>(_STD move(_Last)));
}

template <class _It, sized_sentinel_for<decay_t<_It>> _Se>
Expand Down
44 changes: 44 additions & 0 deletions tests/std/tests/Dev11_1114006_condition_variable_pred/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,50 @@ void test(const int waiter, const int sleeper) {
t1.join();
}

#ifndef _M_CEE // TRANSITION, VSO-1659496
// GH-140: "STL: We should _STD qualify _Ugly function calls to avoid ADL"
template <class T>
struct tagged_pred {
bool operator()() const noexcept {
return true;
}
};

template <class T>
struct holder {
T t;
};

struct incomplete;

template <class CV>
void test_adl_proof_waiting() { // COMPILE-ONLY
using validating_pred = tagged_pred<holder<incomplete>>;

mutex mut;
{
CV cv;
unique_lock<mutex> guard(mut);
(void) cv.wait(guard, validating_pred{});
}
{
CV cv;
unique_lock<mutex> guard(mut);
(void) cv.wait_for(guard, 1ms, validating_pred{});
}
{
CV cv;
unique_lock<mutex> guard(mut);
(void) cv.wait_until(guard, steady_clock::now() + 1ms, validating_pred{});
}
}

void test_adl_proof_waiting_all() { // COMPILE-ONLY
test_adl_proof_waiting<condition_variable>();
test_adl_proof_waiting<condition_variable_any>();
}
#endif // ^^^ no workaround ^^^

int main() {
for (int waiter = 0; waiter < 3; ++waiter) {
for (int sleeper = 0; sleeper < 3; ++sleeper) { // Intentionally test a case without sleeping.
Expand Down
21 changes: 21 additions & 0 deletions tests/std/tests/P0122R7_span/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1050,6 +1050,27 @@ void test_non_constexpr() {
assert(sp_6.size() == SizeBytes);
}

#if !_HAS_CXX23 // TRANSITION, ABI, const_iterator<_Span_iterator<holder<incomplete>*>> is ill-formed due to ADL in
// constraints checking
#ifndef _M_CEE // TRANSITION, VSO-1659496
// GH-1596: "<algorithm>: unqualified calls to _Adl_verify_range incorrectly cause instantiation"
template <class T>
struct holder {
T t;
};

struct incomplete;

void test_adl_proof_span_constructors() { // COMPILE-ONLY
using validator = holder<incomplete>*;
validator varr[1]{};

[[maybe_unused]] span<validator> s1{varr, varr + 1};
[[maybe_unused]] span<validator> s2{varr, 1};
}
#endif // ^^^ no workaround ^^^
#endif // !_HAS_CXX23

int main() {
static_assert(test());
assert(test());
Expand Down
52 changes: 52 additions & 0 deletions tests/std/tests/P0896R4_ranges_iterator_machinery/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1725,6 +1725,58 @@ namespace incomplete_test {
using V = std::iter_value_t<E*>;
using D = std::iter_difference_t<E*>;
using R = std::iter_reference_t<E*>;

#ifndef _M_CEE // TRANSITION, VSO-1659496
// GH-1596: "<algorithm>: unqualified calls to _Adl_verify_range incorrectly cause instantiation"

template <class Tag>
struct tagged_base {};

template <class Tag>
struct tagged_derived : tagged_base<Tag> {};

template <class T>
struct holder {
T t;
};

struct incomplete;

void test_adl_proof_ranges_advance_distance() { // COMPILE-ONLY
using std::ranges::advance, std::ranges::distance;
using validating_base = tagged_base<holder<incomplete>>;
using validating_derived = tagged_derived<holder<incomplete>>;

struct validating_empty_range {
constexpr validating_derived* begin() const noexcept {
return ptr_;
}
constexpr validating_base* end() const noexcept {
return ptr_;
}

validating_derived* ptr_;
};

static_assert(std::sentinel_for<validating_base*, validating_derived*>);
#ifndef __EDG__ // TRANSITION, DevCom-10581519
static_assert(!std::sized_sentinel_for<validating_base*, validating_derived*>);
#endif // ^^^ no workaround ^^^

validating_derived darr[1]{};
validating_derived* const pd = +darr;
validating_base* const pb = +darr;
auto pd_mut = pd;
const validating_empty_range r{+darr};

(void) advance(pd_mut, 0);
(void) advance(pd_mut, pb);
(void) advance(pd_mut, 0, pb);

(void) distance(pd, pb);
(void) distance(r);
}
#endif // ^^^ no workaround ^^^
} // namespace incomplete_test

namespace default_sentinel_test {
Expand Down