microsoft / STL

MSVC's implementation of the C++ Standard Library.
Other
10.15k stars 1.5k forks source link

<iterator>: checked_array_iterator/unchecked_array_iterator should have conversions #943

Closed AlexGuteniev closed 1 year ago

AlexGuteniev commented 4 years ago

Describe the bug The non-Standard extensions stdext::checked_array_iterator and stdext::unchecked_array_iterator don't participate in constness conversions like modern iterators do:

https://github.com/microsoft/STL/blob/5ef22f2a884706442257cea3dd9d5a6186f15c07/stl/inc/iterator#L521-L523 https://github.com/microsoft/STL/blob/5ef22f2a884706442257cea3dd9d5a6186f15c07/stl/inc/iterator#L718-L720

Command-line test case

C:\Temp>type meow.cpp
#include <array>
#include <iostream>
#include <iterator>
#include <type_traits>
using namespace std;
using stdext::checked_array_iterator;
using stdext::unchecked_array_iterator;

#define STATIC_ASSERT(...) static_assert(__VA_ARGS__, #__VA_ARGS__)

template <typename From, typename To>
void verify_convertible() {
    STATIC_ASSERT(is_convertible_v<From, To>);
    STATIC_ASSERT(is_constructible_v<To, From>);
    STATIC_ASSERT(is_assignable_v<To&, From>);
}

template <typename From, typename To>
void verify_NOT_convertible() {
    STATIC_ASSERT(!is_convertible_v<From, To>);
    STATIC_ASSERT(!is_constructible_v<To, From>);
    STATIC_ASSERT(!is_assignable_v<To&, From>);
}

struct Base {};
struct Derived : Base {};

int main() {
    array<int, 5> arr{{10, 20, 30, 40, 50}};

    {
        array<int, 5>::iterator standard_iter = arr.begin();
        standard_iter += 1;
        cout << *standard_iter << "\n";

        array<int, 5>::const_iterator standard_const_iter = arr.cbegin();
        standard_const_iter += 2;
        cout << *standard_const_iter << "\n";

        standard_const_iter = standard_iter;
        cout << *standard_const_iter << "\n";

        verify_convertible<array<int, 5>::iterator, array<int, 5>::const_iterator>();
        verify_NOT_convertible<array<Derived, 5>::iterator, array<Base, 5>::iterator>();
    }

    {
        checked_array_iterator<int*> checked_iter{arr.data(), arr.size()};
        checked_iter += 1;
        cout << *checked_iter << "\n";

        checked_array_iterator<const int*> checked_const_iter{arr.data(), arr.size()};
        checked_const_iter += 2;
        cout << *checked_const_iter << "\n";

#ifndef AVOID_ERRORS
        checked_const_iter = checked_iter;
        cout << *checked_const_iter << "\n";

        verify_convertible<checked_array_iterator<int*>, checked_array_iterator<const int*>>();
        verify_NOT_convertible<checked_array_iterator<Derived*>, checked_array_iterator<Base*>>();
#endif // AVOID_ERRORS
    }

    {
        unchecked_array_iterator<int*> unchecked_iter{arr.data()};
        unchecked_iter += 3;
        cout << *unchecked_iter << "\n";

        unchecked_array_iterator<const int*> unchecked_const_iter{arr.data()};
        unchecked_const_iter += 4;
        cout << *unchecked_const_iter << "\n";

#ifndef AVOID_ERRORS
        unchecked_const_iter = unchecked_iter;
        cout << *unchecked_const_iter << "\n";

        verify_convertible<unchecked_array_iterator<int*>, unchecked_array_iterator<const int*>>();
        verify_NOT_convertible<unchecked_array_iterator<Derived*>, unchecked_array_iterator<Base*>>();
#endif // AVOID_ERRORS
    }
}

C:\Temp>cl /EHsc /nologo /W4 /DAVOID_ERRORS meow.cpp && meow
meow.cpp
20
30
20
20
30
40
50

C:\Temp>cl /EHsc /nologo /W4 meow.cpp && meow
meow.cpp
meow.cpp(57): error C2679: binary '=': no operator found which takes a right-hand operand of type 'stdext::checked_array_iterator<int *>' (or there is no acceptable conversion)
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.27.29009\include\iterator(710): note: could be 'stdext::checked_array_iterator<const int *> &stdext::checked_array_iterator<const int *>::operator =(stdext::checked_array_iterator<const int *> &&)'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.27.29009\include\iterator(710): note: or       'stdext::checked_array_iterator<const int *> &stdext::checked_array_iterator<const int *>::operator =(const stdext::checked_array_iterator<const int *> &)'
meow.cpp(57): note: while trying to match the argument list '(stdext::checked_array_iterator<const int *>, stdext::checked_array_iterator<int *>)'
meow.cpp(75): error C2679: binary '=': no operator found which takes a right-hand operand of type 'stdext::unchecked_array_iterator<int *>' (or there is no acceptable conversion)
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.27.29009\include\iterator(850): note: could be 'stdext::unchecked_array_iterator<const int *> &stdext::unchecked_array_iterator<const int *>::operator =(stdext::unchecked_array_iterator<const int *> &&)'
C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\VC\Tools\MSVC\14.27.29009\include\iterator(850): note: or       'stdext::unchecked_array_iterator<const int *> &stdext::unchecked_array_iterator<const int *>::operator =(const stdext::unchecked_array_iterator<const int *> &)'
meow.cpp(75): note: while trying to match the argument list '(stdext::unchecked_array_iterator<const int *>, stdext::unchecked_array_iterator<int *>)'

Expected behavior Code should compile.

STL version Visual Studio Community 2019 Preview 16.7.0 Preview 3.1

Additional context This item is also tracked on Developer Community as DevCom-241515 and by Microsoft-internal VSO-146139 / AB#146139.

cpplearner commented 4 years ago

It seems to me that DevCom-241515 is talking about stdext::checked_array_iterator defined here. IIUC it wants to make stdext::checked_array_iterator<T> convertible to stdext::checked_array_iterator<const T>.

StephanTLavavej commented 4 years ago

@cpplearner, that's correct (except that they're templated on pointers). @AlexGuteniev, std::span::const_iterator was removed by LWG-3320 for C++20, see GH-542 and GH-548. Thanks for looking into this issue.

I've updated the issue with a comprehensive repro written from scratch, and linked the Microsoft-internal bug to this issue.