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