[libc++] Fix std::copy and std::move for ranges with potentially overlapping tail...
authorNikolas Klauser <n_klauser@apple.com>
Fri, 30 Jun 2023 20:47:39 +0000 (13:47 -0700)
committerNikolas Klauser <nikolasklauser@berlin.de>
Fri, 30 Jun 2023 20:48:16 +0000 (13:48 -0700)
This fixes thr bug reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108846.

Reviewed By: ldionne, #libc

Spies: mstorsjo, libcxx-commits

Differential Revision: https://reviews.llvm.org/D151953

22 files changed:
libcxx/include/CMakeLists.txt
libcxx/include/__algorithm/copy_move_common.h
libcxx/include/__string/char_traits.h
libcxx/include/__string/constexpr_c_functions.h
libcxx/include/__type_traits/datasizeof.h [new file with mode: 0644]
libcxx/include/__utility/is_pointer_in_range.h
libcxx/include/module.modulemap.in
libcxx/include/string
libcxx/test/libcxx/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp
libcxx/test/libcxx/transitive_includes/cxx03.csv
libcxx/test/libcxx/transitive_includes/cxx11.csv
libcxx/test/libcxx/transitive_includes/cxx14.csv
libcxx/test/libcxx/transitive_includes/cxx17.csv
libcxx/test/libcxx/transitive_includes/cxx20.csv
libcxx/test/libcxx/transitive_includes/cxx23.csv
libcxx/test/libcxx/transitive_includes/cxx26.csv
libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp [new file with mode: 0644]
libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_backward.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/copy_n.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move.pass.cpp
libcxx/test/std/algorithms/alg.modifying.operations/alg.move/move_backward.pass.cpp

index 9ab8fcf..0253691 100644 (file)
@@ -707,6 +707,7 @@ set(files
   __type_traits/conjunction.h
   __type_traits/copy_cv.h
   __type_traits/copy_cvref.h
+  __type_traits/datasizeof.h
   __type_traits/decay.h
   __type_traits/dependent_type.h
   __type_traits/disjunction.h
index b88c149..c06892e 100644 (file)
@@ -15,6 +15,7 @@
 #include <__config>
 #include <__iterator/iterator_traits.h>
 #include <__memory/pointer_traits.h>
+#include <__string/constexpr_c_functions.h>
 #include <__type_traits/enable_if.h>
 #include <__type_traits/is_always_bitcastable.h>
 #include <__type_traits/is_constant_evaluated.h>
@@ -61,7 +62,8 @@ template <class _In, class _Out>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
 __copy_trivial_impl(_In* __first, _In* __last, _Out* __result) {
   const size_t __n = static_cast<size_t>(__last - __first);
-  ::__builtin_memmove(__result, __first, __n * sizeof(_Out));
+
+  std::__constexpr_memmove(__result, __first, __element_count(__n));
 
   return std::make_pair(__last, __result + __n);
 }
@@ -72,7 +74,7 @@ __copy_backward_trivial_impl(_In* __first, _In* __last, _Out* __result) {
   const size_t __n = static_cast<size_t>(__last - __first);
   __result -= __n;
 
-  ::__builtin_memmove(__result, __first, __n * sizeof(_Out));
+  std::__constexpr_memmove(__result, __first, __element_count(__n));
 
   return std::make_pair(__last, __result);
 }
@@ -119,16 +121,6 @@ __unwrap_and_dispatch(_InIter __first, _Sent __last, _OutIter __out_first) {
   return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first));
 }
 
-template <class _IterOps, class _InValue, class _OutIter, class = void>
-struct __can_copy_without_conversion : false_type {};
-
-template <class _IterOps, class _InValue, class _OutIter>
-struct __can_copy_without_conversion<
-    _IterOps,
-    _InValue,
-    _OutIter,
-    __enable_if_t<is_same<_InValue, typename _IterOps::template __value_type<_OutIter> >::value> > : true_type {};
-
 template <class _AlgPolicy,
           class _NaiveAlgorithm,
           class _OptimizedAlgorithm,
@@ -137,23 +129,6 @@ template <class _AlgPolicy,
           class _OutIter>
 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
 __dispatch_copy_or_move(_InIter __first, _Sent __last, _OutIter __out_first) {
-#ifdef _LIBCPP_COMPILER_GCC
-  // GCC doesn't support `__builtin_memmove` during constant evaluation.
-  if (__libcpp_is_constant_evaluated()) {
-    return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
-  }
-#else
-  // In Clang, `__builtin_memmove` only supports fully trivially copyable types (just having trivial copy assignment is
-  // insufficient). Also, conversions are not supported.
-  if (__libcpp_is_constant_evaluated()) {
-    using _InValue = typename _IterOps<_AlgPolicy>::template __value_type<_InIter>;
-    if (!is_trivially_copyable<_InValue>::value ||
-        !__can_copy_without_conversion<_IterOps<_AlgPolicy>, _InValue, _OutIter>::value) {
-      return std::__unwrap_and_dispatch<_NaiveAlgorithm>(std::move(__first), std::move(__last), std::move(__out_first));
-    }
-  }
-#endif // _LIBCPP_COMPILER_GCC
-
   using _Algorithm = __overload<_NaiveAlgorithm, _OptimizedAlgorithm>;
   return std::__unwrap_and_dispatch<_Algorithm>(std::move(__first), std::move(__last), std::move(__out_first));
 }
index a61c70c..e423474 100644 (file)
@@ -170,25 +170,6 @@ struct _LIBCPP_DEPRECATED_("char_traits<T> for T not equal to char, wchar_t, cha
         {return int_type(EOF);}
 };
 
-template <class _CharT>
-_LIBCPP_HIDE_FROM_ABI static inline _LIBCPP_CONSTEXPR_SINCE_CXX20
-_CharT* __char_traits_move(_CharT* __dest, const _CharT* __source, size_t __n) _NOEXCEPT
-{
-#ifdef _LIBCPP_COMPILER_GCC
-  if (__libcpp_is_constant_evaluated()) {
-    if (__n == 0)
-      return __dest;
-    _CharT* __allocation = new _CharT[__n];
-    std::copy_n(__source, __n, __allocation);
-    std::copy_n(static_cast<const _CharT*>(__allocation), __n, __dest);
-    delete[] __allocation;
-    return __dest;
-  }
-#endif
-  ::__builtin_memmove(__dest, __source, __n * sizeof(_CharT));
-  return __dest;
-}
-
 // char_traits<char>
 
 template <>
@@ -249,7 +230,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char>
 
     static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-        return std::__char_traits_move(__s1, __s2, __n);
+        return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     }
 
     static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -320,7 +301,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<wchar_t>
 
     static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     char_type* move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-        return std::__char_traits_move(__s1, __s2, __n);
+        return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     }
 
     static inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -384,7 +365,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char8_t>
 
     static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
     char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-        return std::__char_traits_move(__s1, __s2, __n);
+        return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     }
 
     static _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -468,7 +449,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char16_t>
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
     static char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-        return std::__char_traits_move(__s1, __s2, __n);
+        return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
@@ -562,7 +543,7 @@ struct _LIBCPP_TEMPLATE_VIS char_traits<char32_t>
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
     static char_type*       move(char_type* __s1, const char_type* __s2, size_t __n) _NOEXCEPT {
-        return std::__char_traits_move(__s1, __s2, __n);
+        return std::__constexpr_memmove(__s1, __s2, __element_count(__n));
     }
 
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20
index 13084e6..86b3394 100644 (file)
 #define _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H
 
 #include <__config>
+#include <__type_traits/datasizeof.h>
+#include <__type_traits/is_always_bitcastable.h>
 #include <__type_traits/is_constant_evaluated.h>
 #include <__type_traits/is_equality_comparable.h>
 #include <__type_traits/is_same.h>
+#include <__type_traits/is_trivially_copyable.h>
 #include <__type_traits/is_trivially_lexicographically_comparable.h>
 #include <__type_traits/remove_cv.h>
+#include <__utility/is_pointer_in_range.h>
 #include <cstddef>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -129,6 +133,30 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp* __constexpr_memchr(_Tp*
   }
 }
 
+template <class _Tp, class _Up, __enable_if_t<__is_always_bitcastable<_Up, _Tp>::value, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Tp*
+__constexpr_memmove(_Tp* __dest, _Up* __src, __element_count __n) {
+  size_t __count = static_cast<size_t>(__n);
+  if (__libcpp_is_constant_evaluated()) {
+#ifdef _LIBCPP_COMPILER_CLANG_BASED
+    if (is_same<__remove_cv_t<_Tp>, __remove_cv_t<_Up> >::value) {
+      ::__builtin_memmove(__dest, __src, __count * sizeof(_Tp));
+      return __dest;
+    }
+#endif
+    if (std::__is_pointer_in_range(__src, __src + __count, __dest)) {
+      for (; __count > 0; --__count)
+        __dest[__count - 1] = __src[__count - 1];
+    } else {
+      for (size_t __i = 0; __i != __count; ++__i)
+        __dest[__i] = __src[__i];
+    }
+  } else if (__count > 0) {
+    ::__builtin_memmove(__dest, __src, (__count - 1) * sizeof(_Tp) + __libcpp_datasizeof<_Tp>::value);
+  }
+  return __dest;
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___STRING_CONSTEXPR_C_FUNCTIONS_H
diff --git a/libcxx/include/__type_traits/datasizeof.h b/libcxx/include/__type_traits/datasizeof.h
new file mode 100644 (file)
index 0000000..019099a
--- /dev/null
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_DATASIZEOF_H
+#define _LIBCPP___TYPE_TRAITS_DATASIZEOF_H
+
+#include <__config>
+#include <__type_traits/is_class.h>
+#include <__type_traits/is_final.h>
+#include <cstddef>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+// This trait provides the size of a type excluding any tail padding.
+//
+// It is useful in contexts where performing an operation using the full size of the class (including padding) may
+// have unintended side effects, such as overwriting a derived class' member when writing the tail padding of a class
+// through a pointer-to-base.
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <class _Tp>
+struct __libcpp_datasizeof {
+#if __has_cpp_attribute(__no_unique_address__)
+  template <class = char>
+  struct _FirstPaddingByte {
+    [[__no_unique_address__]] _Tp __v_;
+    char __first_padding_byte_;
+  };
+#else
+  template <bool = __libcpp_is_final<_Tp>::value || !is_class<_Tp>::value>
+  struct _FirstPaddingByte : _Tp {
+    char __first_padding_byte_;
+  };
+
+  template <>
+  struct _FirstPaddingByte<true> {
+    _Tp __v_;
+    char __first_padding_byte_;
+  };
+#endif
+
+  static const size_t value = offsetof(_FirstPaddingByte<>, __first_padding_byte_);
+};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_DATASIZEOF_H
index e8f07a0..e859562 100644 (file)
@@ -15,8 +15,6 @@
 #include <__type_traits/enable_if.h>
 #include <__type_traits/integral_constant.h>
 #include <__type_traits/is_constant_evaluated.h>
-#include <__type_traits/is_function.h>
-#include <__type_traits/is_member_pointer.h>
 #include <__type_traits/void_t.h>
 #include <__utility/declval.h>
 
 
 _LIBCPP_BEGIN_NAMESPACE_STD
 
+template <class _Tp, class _Up, class = void>
+struct __is_less_than_comparable : false_type {};
+
 template <class _Tp, class _Up>
+struct __is_less_than_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() < std::declval<_Up>())> > : true_type {
+};
+
+template <class _Tp, class _Up, __enable_if_t<__is_less_than_comparable<const _Tp*, const _Up*>::value, int> = 0>
 _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range(
     const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
-  static_assert(!is_function<_Tp>::value && !is_function<_Up>::value,
-                "__is_pointer_in_range should not be called with function pointers");
-  static_assert(!is_member_pointer<_Tp>::value && !is_member_pointer<_Up>::value,
-                "__is_pointer_in_range should not be called with member pointers");
-
   if (__libcpp_is_constant_evaluated()) {
     _LIBCPP_ASSERT_UNCATEGORIZED(__builtin_constant_p(__begin <= __end), "__begin and __end do not form a range");
 
@@ -47,6 +47,16 @@ _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address
   return !__less<>()(__ptr, __begin) && __less<>()(__ptr, __end);
 }
 
+template <class _Tp, class _Up, __enable_if_t<!__is_less_than_comparable<const _Tp*, const _Up*>::value, int> = 0>
+_LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI _LIBCPP_NO_SANITIZE("address") bool __is_pointer_in_range(
+    const _Tp* __begin, const _Tp* __end, const _Up* __ptr) {
+  if (__libcpp_is_constant_evaluated())
+    return false;
+
+  return reinterpret_cast<const char*>(__begin) <= reinterpret_cast<const char*>(__ptr) &&
+         reinterpret_cast<const char*>(__ptr) < reinterpret_cast<const char*>(__end);
+}
+
 _LIBCPP_END_NAMESPACE_STD
 
 #endif // _LIBCPP___UTILITY_IS_POINTER_IN_RANGE_H
index ced3a49..007b6b0 100644 (file)
@@ -1576,6 +1576,7 @@ module std [system] {
     module conjunction                               { private header "__type_traits/conjunction.h" }
     module copy_cv                                   { private header "__type_traits/copy_cv.h" }
     module copy_cvref                                { private header "__type_traits/copy_cvref.h" }
+    module datasizeof                                { private header "__type_traits/datasizeof.h" }
     module decay                                     { private header "__type_traits/decay.h" }
     module dependent_type                            { private header "__type_traits/dependent_type.h" }
     module disjunction                               { private header "__type_traits/disjunction.h" }
index 1a58cf0..e0cbea6 100644 (file)
@@ -663,13 +663,6 @@ struct __can_be_converted_to_string_view : public _BoolConstant<
 
 struct __uninitialized_size_tag {};
 
-template <class _Tp, class _Up, class = void>
-struct __is_less_than_comparable : false_type {};
-
-template <class _Tp, class _Up>
-struct __is_less_than_comparable<_Tp, _Up, __void_t<decltype(std::declval<_Tp>() < std::declval<_Up>())> > : true_type {
-};
-
 template<class _CharT, class _Traits, class _Allocator>
 class basic_string
 {
@@ -1910,25 +1903,11 @@ private:
       return *this;
     }
 
-    template <
-        class _Tp,
-        __enable_if_t<__is_less_than_comparable<const __remove_cvref_t<_Tp>*, const value_type*>::value, int> = 0>
+    template <class _Tp>
     _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const {
       return std::__is_pointer_in_range(data(), data() + size() + 1, std::addressof(__v));
     }
 
-    template <
-        class _Tp,
-        __enable_if_t<!__is_less_than_comparable<const __remove_cvref_t<_Tp>*, const value_type*>::value, int> = 0>
-    _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __addr_in_range(const _Tp& __v) const {
-      if (__libcpp_is_constant_evaluated())
-                return false;
-
-      auto __t_ptr = reinterpret_cast<const char*>(std::addressof(__v));
-      return reinterpret_cast<const char*>(data()) <= __t_ptr &&
-             __t_ptr < reinterpret_cast<const char*>(data() + size() + 1);
-    }
-
     _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI
     void __throw_length_error() const {
         std::__throw_length_error("basic_string");
index 5c3bd31..525f4a7 100644 (file)
@@ -156,26 +156,6 @@ void test_one(Func func) {
         }
     }));
   }
-
-  // Empty input sequence.
-  {
-    const std::size_t N = 0;
-
-    From input[1]  = {make<From>(1)};
-    To output[1] = {make<To>(2)};
-
-    auto in     = InIter(input);
-    auto in_end = InIter(input + N);
-    auto sent   = SentWrapper<decltype(in_end)>(in_end);
-    auto out    = OutIter(output);
-
-    assert(!memmove_called);
-    func(in, sent, out, N);
-
-    assert(memmove_called);
-    memmove_called = false;
-    assert(output[0] == make<To>(2));
-  }
 }
 
 template <class InIter, template <class> class SentWrapper, class OutIter>
index 9f555fb..4183dd9 100644 (file)
@@ -42,6 +42,7 @@ array algorithm
 array compare
 array concepts
 array cstddef
+array cstdint
 array cstdlib
 array initializer_list
 array iterator
@@ -506,6 +507,7 @@ locale version
 map compare
 map concepts
 map cstddef
+map cstdint
 map cstdlib
 map functional
 map initializer_list
@@ -731,6 +733,7 @@ semaphore version
 set compare
 set concepts
 set cstddef
+set cstdint
 set cstdlib
 set functional
 set initializer_list
index 0f00c22..ded6747 100644 (file)
@@ -42,6 +42,7 @@ array algorithm
 array compare
 array concepts
 array cstddef
+array cstdint
 array cstdlib
 array initializer_list
 array iterator
@@ -506,6 +507,7 @@ locale version
 map compare
 map concepts
 map cstddef
+map cstdint
 map cstdlib
 map functional
 map initializer_list
@@ -732,6 +734,7 @@ semaphore version
 set compare
 set concepts
 set cstddef
+set cstdint
 set cstdlib
 set functional
 set initializer_list
index 596ea36..4ef5973 100644 (file)
@@ -42,6 +42,7 @@ array algorithm
 array compare
 array concepts
 array cstddef
+array cstdint
 array cstdlib
 array initializer_list
 array iterator
@@ -508,6 +509,7 @@ locale version
 map compare
 map concepts
 map cstddef
+map cstdint
 map cstdlib
 map functional
 map initializer_list
@@ -734,6 +736,7 @@ semaphore version
 set compare
 set concepts
 set cstddef
+set cstdint
 set cstdlib
 set functional
 set initializer_list
index 596ea36..4ef5973 100644 (file)
@@ -42,6 +42,7 @@ array algorithm
 array compare
 array concepts
 array cstddef
+array cstdint
 array cstdlib
 array initializer_list
 array iterator
@@ -508,6 +509,7 @@ locale version
 map compare
 map concepts
 map cstddef
+map cstdint
 map cstdlib
 map functional
 map initializer_list
@@ -734,6 +736,7 @@ semaphore version
 set compare
 set concepts
 set cstddef
+set cstdint
 set cstdlib
 set functional
 set initializer_list
index e80b9a0..a081de7 100644 (file)
@@ -41,6 +41,7 @@ array algorithm
 array compare
 array concepts
 array cstddef
+array cstdint
 array cstdlib
 array initializer_list
 array iterator
@@ -514,6 +515,7 @@ locale version
 map compare
 map concepts
 map cstddef
+map cstdint
 map cstdlib
 map functional
 map initializer_list
@@ -740,6 +742,7 @@ semaphore version
 set compare
 set concepts
 set cstddef
+set cstdint
 set cstdlib
 set functional
 set initializer_list
index 27e9acf..c1c24a9 100644 (file)
@@ -21,6 +21,7 @@ any typeinfo
 any version
 array compare
 array cstddef
+array cstdint
 array initializer_list
 array limits
 array stdexcept
@@ -348,6 +349,7 @@ locale string
 locale version
 map compare
 map cstddef
+map cstdint
 map initializer_list
 map limits
 map new
@@ -501,6 +503,7 @@ semaphore ratio
 semaphore version
 set compare
 set cstddef
+set cstdint
 set initializer_list
 set limits
 set new
index 27e9acf..c1c24a9 100644 (file)
@@ -21,6 +21,7 @@ any typeinfo
 any version
 array compare
 array cstddef
+array cstdint
 array initializer_list
 array limits
 array stdexcept
@@ -348,6 +349,7 @@ locale string
 locale version
 map compare
 map cstddef
+map cstdint
 map initializer_list
 map limits
 map new
@@ -501,6 +503,7 @@ semaphore ratio
 semaphore version
 set compare
 set cstddef
+set cstdint
 set initializer_list
 set limits
 set new
diff --git a/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp b/libcxx/test/libcxx/type_traits/datasizeof.compile.pass.cpp
new file mode 100644 (file)
index 0000000..9a88b0d
--- /dev/null
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// ADDITIONAL_COMPILE_FLAGS: -Wno-private-header
+
+#include <__type_traits/datasizeof.h>
+#include <cstdint>
+
+static_assert(std::__libcpp_datasizeof<std::int8_t>::value == 1, "");
+static_assert(std::__libcpp_datasizeof<std::int16_t>::value == 2, "");
+static_assert(std::__libcpp_datasizeof<std::int32_t>::value == 4, "");
+static_assert(std::__libcpp_datasizeof<std::int64_t>::value == 8, "");
+
+struct OneBytePadding {
+  OneBytePadding() {}
+
+  std::int16_t a;
+  std::int8_t b;
+};
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+static_assert(std::__libcpp_datasizeof<OneBytePadding>::value == 4, "");
+#else
+static_assert(std::__libcpp_datasizeof<OneBytePadding>::value == 3, "");
+#endif
+
+struct InBetweenPadding {
+  InBetweenPadding() {}
+
+  std::int32_t a;
+  std::int8_t b;
+  std::int16_t c;
+};
+
+static_assert(std::__libcpp_datasizeof<InBetweenPadding>::value == 8, "");
index f3a7090..b5f0a32 100644 (file)
 #include "test_macros.h"
 #include "test_iterators.h"
 
-template <class InIter, class OutIter>
-TEST_CONSTEXPR_CXX20 void
-test_copy()
-{
+class PaddedBase {
+public:
+  TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
+
+  std::int16_t a_;
+  std::int8_t b_;
+};
+
+class Derived : public PaddedBase {
+public:
+  TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
+
+  std::int8_t c_;
+};
+
+template <class InIter>
+struct Test {
+  template <class OutIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
     const unsigned N = 1000;
-    int ia[N] = {};
+    int ia[N]        = {};
     for (unsigned i = 0; i < N; ++i)
-        ia[i] = i;
+      ia[i] = i;
     int ib[N] = {0};
 
-    OutIter r = std::copy(InIter(ia), InIter(ia+N), OutIter(ib));
-    assert(base(r) == ib+N);
+    OutIter r = std::copy(InIter(ia), InIter(ia + N), OutIter(ib));
+    assert(base(r) == ib + N);
     for (unsigned i = 0; i < N; ++i)
-        assert(ia[i] == ib[i]);
-}
-
-TEST_CONSTEXPR_CXX20 bool
-test()
-{
-    test_copy<cpp17_input_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test_copy<cpp17_input_iterator<const int*>, forward_iterator<int*> >();
-    test_copy<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >();
-    test_copy<cpp17_input_iterator<const int*>, random_access_iterator<int*> >();
-    test_copy<cpp17_input_iterator<const int*>, int*>();
-
-    test_copy<forward_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test_copy<forward_iterator<const int*>, forward_iterator<int*> >();
-    test_copy<forward_iterator<const int*>, bidirectional_iterator<int*> >();
-    test_copy<forward_iterator<const int*>, random_access_iterator<int*> >();
-    test_copy<forward_iterator<const int*>, int*>();
-
-    test_copy<bidirectional_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test_copy<bidirectional_iterator<const int*>, forward_iterator<int*> >();
-    test_copy<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
-    test_copy<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
-    test_copy<bidirectional_iterator<const int*>, int*>();
-
-    test_copy<random_access_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test_copy<random_access_iterator<const int*>, forward_iterator<int*> >();
-    test_copy<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
-    test_copy<random_access_iterator<const int*>, random_access_iterator<int*> >();
-    test_copy<random_access_iterator<const int*>, int*>();
-
-    test_copy<const int*, cpp17_output_iterator<int*> >();
-    test_copy<const int*, forward_iterator<int*> >();
-    test_copy<const int*, bidirectional_iterator<int*> >();
-    test_copy<const int*, random_access_iterator<int*> >();
-    test_copy<const int*, int*>();
-
-#if TEST_STD_VER > 17
-    test_copy<cpp17_input_iterator<const int*>, contiguous_iterator<int*>>();
-    test_copy<forward_iterator<const int*>, contiguous_iterator<int*>>();
-    test_copy<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
-    test_copy<random_access_iterator<const int*>, contiguous_iterator<int*>>();
-    test_copy<const int*, contiguous_iterator<int*>>();
-
-    test_copy<contiguous_iterator<const int*>, cpp17_output_iterator<int*>>();
-    test_copy<contiguous_iterator<const int*>, forward_iterator<int*>>();
-    test_copy<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
-    test_copy<contiguous_iterator<const int*>, random_access_iterator<int*>>();
-    test_copy<contiguous_iterator<const int*>, int*>();
-#endif
+      assert(ia[i] == ib[i]);
+  }
+};
+
+struct TestInIters {
+  template <class InIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    types::for_each(
+        types::concatenate_t<types::cpp17_input_iterator_list<int*>, types::type_list<cpp17_output_iterator<int*> > >(),
+        Test<InIter>());
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::cpp17_input_iterator_list<int*>(), TestInIters());
+
+  { // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::copy(static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst));
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
+  }
+
+  { // Make sure that overlapping ranges can be copied
+    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    std::copy(a + 3, a + 10, a);
+    int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
+    assert(std::equal(a, a + 10, expected));
+  }
 
   return true;
 }
 
-int main(int, char**)
-{
-    test();
+int main(int, char**) {
+  test();
 
 #if TEST_STD_VER > 17
-    static_assert(test());
+  static_assert(test());
 #endif
 
   return 0;
index 7b620db..928903d 100644 (file)
 #include "test_iterators.h"
 #include "user_defined_integral.h"
 
+class PaddedBase {
+public:
+  TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
+
+  std::int16_t a_;
+  std::int8_t b_;
+};
+
+class Derived : public PaddedBase {
+public:
+  TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
+
+  std::int8_t c_;
+};
+
 template <class InIter, class OutIter>
 TEST_CONSTEXPR_CXX20 void
 test_copy_backward()
 {
+  {
     const unsigned N = 1000;
     int ia[N] = {};
     for (unsigned i = 0; i < N; ++i)
@@ -34,6 +50,7 @@ test_copy_backward()
     assert(base(r) == ib);
     for (unsigned i = 0; i < N; ++i)
         assert(ia[i] == ib[i]);
+  }
 }
 
 TEST_CONSTEXPR_CXX20 bool
@@ -62,6 +79,23 @@ test()
     test_copy_backward<const int*, contiguous_iterator<int*>>();
 #endif
 
+  { // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::copy_backward(
+        static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst) + 1);
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
+  }
+
+  { // Make sure that overlapping ranges can be copied
+    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    std::copy_backward(a, a + 7, a + 10);
+    int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7};
+    assert(std::equal(a, a + 10, expected));
+  }
+
     return true;
 }
 
index fa425c7..b0acc10 100644 (file)
 
 typedef UserDefinedIntegral<unsigned> UDI;
 
+class PaddedBase {
+public:
+  TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
+
+  std::int16_t a_;
+  std::int8_t b_;
+};
+
+class Derived : public PaddedBase {
+public:
+  TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
+
+  std::int8_t c_;
+};
+
 template <class InIter, class OutIter>
 TEST_CONSTEXPR_CXX20 void
 test_copy_n()
 {
+  {
     const unsigned N = 1000;
     int ia[N] = {};
     for (unsigned i = 0; i < N; ++i)
@@ -35,6 +51,23 @@ test_copy_n()
     assert(base(r) == ib+N/2);
     for (unsigned i = 0; i < N/2; ++i)
         assert(ia[i] == ib[i]);
+  }
+
+  { // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::copy_n(static_cast<PaddedBase*>(&src), 1, static_cast<PaddedBase*>(&dst));
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
+  }
+
+  { // Make sure that overlapping ranges can be copied
+    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    std::copy_n(a + 3, 7, a);
+    int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
+    assert(std::equal(a, a + 10, expected));
+  }
 }
 
 TEST_CONSTEXPR_CXX20 bool
index 5e0837e..3795314 100644 (file)
@@ -6,6 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: c++03 && !stdlib=libc++
+// ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000
+
 // <algorithm>
 
 // template<InputIterator InIter, typename OutIter>
 #include "test_macros.h"
 #include "test_iterators.h"
 
-template <class InIter, class OutIter>
-TEST_CONSTEXPR_CXX17 bool
-test()
-{
+class PaddedBase {
+public:
+  TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
+
+  std::int16_t a_;
+  std::int8_t b_;
+};
+
+class Derived : public PaddedBase {
+public:
+  TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
+
+  std::int8_t c_;
+};
+
+template <class InIter>
+struct Test {
+  template <class OutIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
     const unsigned N = 1000;
     int ia[N] = {};
     for (unsigned i = 0; i < N; ++i)
@@ -34,15 +52,22 @@ test()
     assert(base(r) == ib+N);
     for (unsigned i = 0; i < N; ++i)
         assert(ia[i] == ib[i]);
-
-    return true;
-}
-
-#if TEST_STD_VER >= 11
-template <class InIter, class OutIter>
-void
-test1()
-{
+  }
+};
+
+struct TestOutIters {
+  template <class InIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    types::for_each(
+        types::concatenate_t<types::cpp17_input_iterator_list<int*>, types::type_list<cpp17_output_iterator<int*> > >(),
+        Test<InIter>());
+  }
+};
+
+template <class InIter>
+struct Test1 {
+  template <class OutIter>
+  TEST_CONSTEXPR_CXX23 void operator()() {
     const unsigned N = 100;
     std::unique_ptr<int> ia[N];
     for (unsigned i = 0; i < N; ++i)
@@ -53,140 +78,48 @@ test1()
     assert(base(r) == ib+N);
     for (unsigned i = 0; i < N; ++i)
         assert(*ib[i] == static_cast<int>(i));
+  }
+};
+
+struct Test1OutIters {
+  template <class InIter>
+  TEST_CONSTEXPR_CXX23 void operator()() {
+    types::for_each(types::concatenate_t<types::cpp17_input_iterator_list<std::unique_ptr<int>*>,
+                                         types::type_list<cpp17_output_iterator<std::unique_ptr<int>*> > >(),
+                    Test1<InIter>());
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::cpp17_input_iterator_list<int*>(), TestOutIters());
+  if (TEST_STD_VER >= 23 || !TEST_IS_CONSTANT_EVALUATED)
+    types::for_each(types::cpp17_input_iterator_list<std::unique_ptr<int>*>(), Test1OutIters());
+
+  { // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::move(static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst));
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
+  }
+
+  { // Make sure that overlapping ranges can be copied
+    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    std::move(a + 3, a + 10, a);
+    int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10};
+    assert(std::equal(a, a + 10, expected));
+  }
+
+  return true;
 }
-#endif
 
 int main(int, char**)
 {
-    test<cpp17_input_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test<cpp17_input_iterator<const int*>, forward_iterator<int*> >();
-    test<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<cpp17_input_iterator<const int*>, random_access_iterator<int*> >();
-    test<cpp17_input_iterator<const int*>, int*>();
-
-    test<forward_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test<forward_iterator<const int*>, forward_iterator<int*> >();
-    test<forward_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<forward_iterator<const int*>, random_access_iterator<int*> >();
-    test<forward_iterator<const int*>, int*>();
-
-    test<bidirectional_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, forward_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, int*>();
-
-    test<random_access_iterator<const int*>, cpp17_output_iterator<int*> >();
-    test<random_access_iterator<const int*>, forward_iterator<int*> >();
-    test<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<random_access_iterator<const int*>, random_access_iterator<int*> >();
-    test<random_access_iterator<const int*>, int*>();
-
-    test<const int*, cpp17_output_iterator<int*> >();
-    test<const int*, forward_iterator<int*> >();
-    test<const int*, bidirectional_iterator<int*> >();
-    test<const int*, random_access_iterator<int*> >();
-    test<const int*, int*>();
-
-#if TEST_STD_VER >= 11
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<forward_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
-    test1<forward_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
-    test1<forward_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<forward_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<forward_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<random_access_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<std::unique_ptr<int>*, cpp17_output_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, forward_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, std::unique_ptr<int>*>();
-#endif // TEST_STD_VER >= 11
-
-#if TEST_STD_VER > 17
-    test<cpp17_input_iterator<const int*>, contiguous_iterator<int*>>();
-    test<forward_iterator<const int*>, contiguous_iterator<int*>>();
-    test<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
-    test<random_access_iterator<const int*>, contiguous_iterator<int*>>();
-    test<const int*, contiguous_iterator<int*>>();
-    test<contiguous_iterator<const int*>, cpp17_output_iterator<int*>>();
-    test<contiguous_iterator<const int*>, forward_iterator<int*>>();
-    test<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
-    test<contiguous_iterator<const int*>, random_access_iterator<int*>>();
-    test<contiguous_iterator<const int*>, int*>();
-    test<contiguous_iterator<const int*>, contiguous_iterator<int*>>();
-
-    test1<cpp17_input_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<forward_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<random_access_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<std::unique_ptr<int>*, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, cpp17_output_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, forward_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-
-    static_assert(test<cpp17_input_iterator<const int*>, cpp17_input_iterator<int*> >());
-    static_assert(test<cpp17_input_iterator<const int*>, forward_iterator<int*> >());
-    static_assert(test<cpp17_input_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<cpp17_input_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<cpp17_input_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<cpp17_input_iterator<const int*>, int*>());
-
-    static_assert(test<forward_iterator<const int*>, cpp17_input_iterator<int*> >());
-    static_assert(test<forward_iterator<const int*>, forward_iterator<int*> >());
-    static_assert(test<forward_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<forward_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<forward_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<forward_iterator<const int*>, int*>());
-
-    static_assert(test<bidirectional_iterator<const int*>, cpp17_input_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, forward_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, int*>());
-
-    static_assert(test<random_access_iterator<const int*>, cpp17_input_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, forward_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, int*>());
-
-    static_assert(test<contiguous_iterator<const int*>, cpp17_input_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, forward_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, int*>());
-
-    static_assert(test<const int*, cpp17_input_iterator<int*> >());
-    static_assert(test<const int*, forward_iterator<int*> >());
-    static_assert(test<const int*, bidirectional_iterator<int*> >());
-    static_assert(test<const int*, random_access_iterator<int*> >());
-    static_assert(test<const int*, contiguous_iterator<int*> >());
-    static_assert(test<const int*, int*>());
-#endif // TEST_STD_VER > 17
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
+#endif
 
   return 0;
 }
index 4aafcd2..04ecd48 100644 (file)
@@ -6,6 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
+// UNSUPPORTED: c++03 && !stdlib=libc++
+
 // <algorithm>
 
 // template<BidirectionalIterator InIter, BidirectionalIterator OutIter>
 #include "test_macros.h"
 #include "test_iterators.h"
 
-template <class InIter, class OutIter>
-TEST_CONSTEXPR_CXX17 bool
-test()
-{
+class PaddedBase {
+public:
+  TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {}
+
+  std::int16_t a_;
+  std::int8_t b_;
+};
+
+class Derived : public PaddedBase {
+public:
+  TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {}
+
+  std::int8_t c_;
+};
+
+template <class InIter>
+struct Test {
+  template <class OutIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
     const unsigned N = 1000;
     int ia[N] = {};
     for (unsigned i = 0; i < N; ++i)
@@ -34,15 +51,22 @@ test()
     assert(base(r) == ib);
     for (unsigned i = 0; i < N; ++i)
         assert(ia[i] == ib[i]);
-
-    return true;
-}
-
-#if TEST_STD_VER >= 11
-template <class InIter, class OutIter>
-void
-test1()
-{
+  }
+};
+
+struct TestOutIters {
+  template <class InIter>
+  TEST_CONSTEXPR_CXX20 void operator()() {
+    types::for_each(
+        types::concatenate_t<types::bidirectional_iterator_list<int*> >(),
+        Test<InIter>());
+  }
+};
+
+template <class InIter>
+struct Test1 {
+  template <class OutIter>
+  TEST_CONSTEXPR_CXX23 void operator()() {
     const unsigned N = 100;
     std::unique_ptr<int> ia[N];
     for (unsigned i = 0; i < N; ++i)
@@ -53,74 +77,48 @@ test1()
     assert(base(r) == ib);
     for (unsigned i = 0; i < N; ++i)
         assert(*ib[i] == static_cast<int>(i));
+  }
+};
+
+struct Test1OutIters {
+  template <class InIter>
+  TEST_CONSTEXPR_CXX23 void operator()() {
+    types::for_each(types::concatenate_t<types::bidirectional_iterator_list<std::unique_ptr<int>*> >(),
+                    Test1<InIter>());
+  }
+};
+
+TEST_CONSTEXPR_CXX20 bool test() {
+  types::for_each(types::bidirectional_iterator_list<int*>(), TestOutIters());
+  if (TEST_STD_VER >= 23 || !TEST_IS_CONSTANT_EVALUATED)
+    types::for_each(types::bidirectional_iterator_list<std::unique_ptr<int>*>(), Test1OutIters());
+
+  { // Make sure that padding bits aren't copied
+    Derived src(1, 2, 3);
+    Derived dst(4, 5, 6);
+    std::move_backward(
+        static_cast<PaddedBase*>(&src), static_cast<PaddedBase*>(&src) + 1, static_cast<PaddedBase*>(&dst) + 1);
+    assert(dst.a_ == 1);
+    assert(dst.b_ == 2);
+    assert(dst.c_ == 6);
+  }
+
+  { // Make sure that overlapping ranges can be copied
+    int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    std::move_backward(a, a + 7, a + 10);
+    int expected[] = {1, 2, 3, 1, 2, 3, 4, 5, 6, 7};
+    assert(std::equal(a, a + 10, expected));
+  }
+
+  return true;
 }
-#endif
 
 int main(int, char**)
 {
-    test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, random_access_iterator<int*> >();
-    test<bidirectional_iterator<const int*>, int*>();
-
-    test<random_access_iterator<const int*>, bidirectional_iterator<int*> >();
-    test<random_access_iterator<const int*>, random_access_iterator<int*> >();
-    test<random_access_iterator<const int*>, int*>();
-
-    test<const int*, bidirectional_iterator<int*> >();
-    test<const int*, random_access_iterator<int*> >();
-    test<const int*, int*>();
-
-#if TEST_STD_VER >= 11
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<random_access_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<random_access_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-
-    test1<std::unique_ptr<int>*, bidirectional_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, random_access_iterator<std::unique_ptr<int>*> >();
-    test1<std::unique_ptr<int>*, std::unique_ptr<int>*>();
-#endif // TEST_STD_VER >= 11
-
-#if TEST_STD_VER > 17
-    test<bidirectional_iterator<const int*>, contiguous_iterator<int*>>();
-    test<random_access_iterator<const int*>, contiguous_iterator<int*>>();
-    test<const int*, contiguous_iterator<int*>>();
-    test<contiguous_iterator<const int*>, bidirectional_iterator<int*>>();
-    test<contiguous_iterator<const int*>, random_access_iterator<int*>>();
-    test<contiguous_iterator<const int*>, int*>();
-    test<contiguous_iterator<const int*>, contiguous_iterator<int*>>();
-
-    test1<bidirectional_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<random_access_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<std::unique_ptr<int>*, contiguous_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, bidirectional_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, random_access_iterator<std::unique_ptr<int>*>>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, std::unique_ptr<int>*>();
-    test1<contiguous_iterator<std::unique_ptr<int>*>, contiguous_iterator<std::unique_ptr<int>*>>();
-
-    static_assert(test<bidirectional_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<bidirectional_iterator<const int*>, int*>());
-
-    static_assert(test<random_access_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<random_access_iterator<const int*>, int*>());
-
-    static_assert(test<contiguous_iterator<const int*>, bidirectional_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, random_access_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, contiguous_iterator<int*> >());
-    static_assert(test<contiguous_iterator<const int*>, int*>());
-
-    static_assert(test<const int*, bidirectional_iterator<int*> >());
-    static_assert(test<const int*, random_access_iterator<int*> >());
-    static_assert(test<const int*, contiguous_iterator<int*> >());
-    static_assert(test<const int*, int*>());
-#endif // TEST_STD_VER > 17
+  test();
+#if TEST_STD_VER >= 20
+  static_assert(test());
+#endif
 
   return 0;
 }