1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03 10 11 // <algorithm> 12 13 // We optimize std::copy(_backward) and std::move(_backward) into memmove 14 // when the iterator is trivial and contiguous and the type in question 15 // is also trivially (copyable, movable). This test verifies that the 16 // optimization never eliminates an actually non-trivial copy or move. 17 18 #include <algorithm> 19 #include <iterator> 20 #include <cassert> 21 22 #include "test_macros.h" 23 #include "test_iterators.h" 24 25 struct TMBNTC { 26 int *p; 27 constexpr TMBNTC(int& copies) : p(&copies) {} 28 constexpr TMBNTC(const TMBNTC&) = default; 29 TEST_CONSTEXPR_CXX14 TMBNTC& operator=(TMBNTC&&) = default; 30 TEST_CONSTEXPR_CXX14 TMBNTC& operator=(const TMBNTC&) { ++*p; return *this; } 31 }; 32 33 TEST_CONSTEXPR_CXX20 bool 34 test_trivial_moveassign_but_no_trivial_copyassign() 35 { 36 int copies = 0; 37 TMBNTC ia[] = { copies, copies, copies, copies }; 38 TMBNTC ib[] = { copies, copies, copies, copies }; 39 std::copy(ia, ia+4, ib); 40 assert(copies == 4); 41 copies = 0; 42 std::copy_backward(ia, ia+4, ib+4); 43 assert(copies == 4); 44 45 copies = 0; 46 std::copy(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib); 47 assert(copies == 0); 48 std::copy_backward(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib+4); 49 assert(copies == 0); 50 51 std::move(ia, ia+4, ib); 52 assert(copies == 0); 53 std::move_backward(ia, ia+4, ib+4); 54 assert(copies == 0); 55 56 return true; 57 } 58 59 struct TCBNTM { 60 int *p; 61 constexpr TCBNTM(int& moves) : p(&moves) {} 62 constexpr TCBNTM(const TCBNTM&) = default; 63 TEST_CONSTEXPR_CXX14 TCBNTM& operator=(TCBNTM&&) { ++*p; return *this; } 64 TEST_CONSTEXPR_CXX14 TCBNTM& operator=(const TCBNTM&) = default; 65 }; 66 67 TEST_CONSTEXPR_CXX20 bool 68 test_trivial_copyassign_but_no_trivial_moveassign() 69 { 70 int moves = 0; 71 TCBNTM ia[] = { moves, moves, moves, moves }; 72 TCBNTM ib[] = { moves, moves, moves, moves }; 73 std::move(ia, ia+4, ib); 74 assert(moves == 4); 75 moves = 0; 76 std::move_backward(ia, ia+4, ib+4); 77 assert(moves == 4); 78 79 moves = 0; 80 std::copy(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib); 81 assert(moves == 4); 82 moves = 0; 83 std::copy_backward(std::make_move_iterator(ia), std::make_move_iterator(ia+4), ib+4); 84 assert(moves == 4); 85 86 moves = 0; 87 std::copy(ia, ia+4, ib); 88 assert(moves == 0); 89 std::copy_backward(ia, ia+4, ib+4); 90 assert(moves == 0); 91 92 return true; 93 } 94 95 int main(int, char**) 96 { 97 test_trivial_moveassign_but_no_trivial_copyassign(); 98 test_trivial_copyassign_but_no_trivial_moveassign(); 99 100 #if TEST_STD_VER > 17 101 static_assert(test_trivial_moveassign_but_no_trivial_copyassign()); 102 static_assert(test_trivial_copyassign_but_no_trivial_moveassign()); 103 #endif 104 105 return 0; 106 } 107