<algorithm>: reverse_copy is mistakenly vectorized for pair<int&, int&> on 32-bit targets (original) (raw)

Describe the bug

From DevCom-10662768.

MSVC STL's pair<int&, int&> is trivially copyable but not trivially copy assignable. Currently, vectorization of reverse_copy incorrectly detects the element type with is_trivially_copyable, which is problematic with pair<int&, int&> and its friends.

#if _USE_STD_VECTOR_ALGORITHMS
using _Elem = remove_reference_t<_Iter_ref_t<remove_const_t<decltype(_UFirst)>>>;
using _DestElem = remove_reference_t<_Iter_ref_t<decltype(_UDest)>>;
constexpr bool _Allow_vectorization = conjunction_v<is_same<remove_const_t<_Elem>, _DestElem>,
bool_constant<_Iterators_are_contiguous<decltype(_ULast), decltype(_UDest)>>, is_trivially_copyable<_Elem>,
negation<is_volatile<_Elem>>>;
constexpr size_t _Nx = sizeof(_Elem);
if constexpr (_Allow_vectorization && _Nx <= 8 && (_Nx & (_Nx - 1)) == 0) {
#if _HAS_CXX20
if (!_STD is_constant_evaluated())
#endif // _HAS_CXX20
{
_STD _Reverse_copy_vectorized<_Nx>(
_STD _To_address(_UFirst), _STD _To_address(_ULast), _STD _To_address(_UDest));
_UDest += _ULast - _UFirst;
_STD _Seek_wrapped(_Dest, _UDest);
return _Dest;
}
}
#endif // _USE_STD_VECTOR_ALGORITHMS
#if _USE_STD_VECTOR_ALGORITHMS
if constexpr (contiguous_iterator<_It> && contiguous_iterator<_Out>) {
using _Elem = remove_reference_t<iter_reference_t<_It>>;
using _DestElem = remove_reference_t<iter_reference_t<_Out>>;
constexpr bool _Allow_vectorization = conjunction_v<is_same<remove_const_t<_Elem>, _DestElem>,
is_trivially_copyable<_Elem>, negation<is_volatile<_Elem>>>;
constexpr size_t _Nx = sizeof(_Elem);
if constexpr (_Allow_vectorization && _Nx <= 8 && (_Nx & (_Nx - 1)) == 0) {
if (!_STD is_constant_evaluated()) {
_STD _Reverse_copy_vectorized<_Nx>(
_STD to_address(_First), _STD to_address(_Last), _STD to_address(_Result));
_Result += _Last - _First;
return _Result;
}
}
}
#endif // _USE_STD_VECTOR_ALGORITHMS

Command-line test case

C:\repro>type repro.cpp
#include <algorithm>
#include <cstdio>
#include <utility>

using Pear = std::pair<int &, int &>;
#ifdef _MSC_VER
static_assert(__is_trivially_copyable(Pear));
static_assert(__is_assignable(Pear &, const Pear &));
static_assert(!__is_trivially_assignable(Pear &, const Pear &));
#endif

int main() {
  std::pair<int, int> src[] = {{1, 2}, {3, 4}, {5, 6}};
  std::pair<int, int> dst[] = {{3, 1}, {4, 1}, {5, 9}};
  std::pair<int &, int &> srcref[] = {src[0], src[1], src[2]};
  std::pair<int &, int &> dstref[] = {dst[0], dst[1], dst[2]};
  std::reverse_copy(srcref, srcref + 3, dstref);
  // Now dst should be {5,6}, {3,4}, {1,2}
  for (auto &p : dst) {
    printf("%d %d\n", p.first, p.second);
  }
}

C:\repro>cl /EHsc /W4 /WX /std:c++latest .\repro.cpp
用于 x86 的 Microsoft (R) C/C++ 优化编译器 19.41.33901 版
版权所有(C) Microsoft Corporation。保留所有权利。

/std:c++latest 作为最新的 C++
working 草稿中的语言功能预览提供。我们希望你提供有关 bug 和改进建议的反馈。
但是,请注意,这些功能按原样提供,没有支持,并且会随着工作草稿的变化
而更改或移除。有关详细信息,请参阅
https://go.microsoft.com/fwlink/?linkid=2045807。

repro.cpp
Microsoft (R) Incremental Linker Version 14.41.33901.0
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:repro.exe
repro.obj

C:\repro>.\repro.exe
3 1
4 1
5 9

Expected behavior

The output should be

A 64-bit target program outputs the correct results.

STL version

Microsoft Visual Studio Community 2022 Preview
Version 17.11.0 Preview 1.0

Additional context

See also WG21-P3279R0.