-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[libc++][C++03] Split libc++-specific tests for the frozen headers #144093
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
base: main
Are you sure you want to change the base?
Conversation
You can test this locally with the following command:darker --check --diff -r HEAD~1...HEAD libcxx/test/libcxx-03/clang_modules_include.gen.py libcxx/test/libcxx-03/clang_tidy.gen.py libcxx/test/libcxx-03/clang_tidy.sh.py libcxx/test/libcxx-03/double_include.gen.py libcxx/test/libcxx-03/feature_test_macro/ftm_metadata.sh.py libcxx/test/libcxx-03/feature_test_macro/generate_header_test.sh.py libcxx/test/libcxx-03/feature_test_macro/implemented_ftms.sh.py libcxx/test/libcxx-03/feature_test_macro/invalid.sh.py libcxx/test/libcxx-03/feature_test_macro/is_implemented.sh.py libcxx/test/libcxx-03/feature_test_macro/standard_ftms.sh.py libcxx/test/libcxx-03/feature_test_macro/standard_library_headers.sh.py libcxx/test/libcxx-03/feature_test_macro/std_dialects.sh.py libcxx/test/libcxx-03/feature_test_macro/version_header.sh.py libcxx/test/libcxx-03/feature_test_macro/version_header_implementation.sh.py libcxx/test/libcxx-03/gdb/gdb_pretty_printer_test.py libcxx/test/libcxx-03/header_inclusions.gen.py libcxx/test/libcxx-03/headers_in_modulemap.sh.py libcxx/test/libcxx-03/libcpp_version.gen.py libcxx/test/libcxx-03/lint/lint_cmakelists.sh.py libcxx/test/libcxx-03/lint/lint_headers.sh.py libcxx/test/libcxx-03/module_std.gen.py libcxx/test/libcxx-03/module_std_compat.gen.py libcxx/test/libcxx-03/no_assert_include.gen.py libcxx/test/libcxx-03/selftest/dsl/dsl.sh.py libcxx/test/libcxx-03/system_reserved_names.gen.py libcxx/test/libcxx-03/transitive_includes.gen.py libcxx/test/libcxx-03/transitive_includes/to_csv.py libcxx/test/libcxx-03/xopen_source.gen.py View the diff from darker here.--- clang_modules_include.gen.py 2025-06-18 17:34:03.000000 +0000
+++ clang_modules_include.gen.py 2025-06-18 17:36:00.359267 +0000
@@ -14,10 +14,11 @@
# block Lit from interpreting a RUN/XFAIL/etc inside the generation script
# END.
import sys
+
sys.path.append(sys.argv[1])
from libcxx.header_information import (
lit_header_restrictions,
lit_header_undeprecations,
public_headers,
--- clang_tidy.gen.py 2025-06-18 17:34:03.000000 +0000
+++ clang_tidy.gen.py 2025-06-18 17:36:00.367798 +0000
@@ -13,15 +13,21 @@
# block Lit from interpreting a RUN/XFAIL/etc inside the generation script
# END.
import sys
+
sys.path.append(sys.argv[1])
-from libcxx.header_information import lit_header_restrictions, lit_header_undeprecations, public_headers
+from libcxx.header_information import (
+ lit_header_restrictions,
+ lit_header_undeprecations,
+ public_headers,
+)
for header in public_headers:
- print(f"""\
+ print(
+ f"""\
//--- {header}.sh.cpp
// REQUIRES: has-clang-tidy
// The frozen headers should not be updated to the latest libc++ style, so don't test.
@@ -35,6 +41,7 @@
// TODO: run clang-tidy with modules enabled once they are supported
// RUN: %{{clang-tidy}} %s --warnings-as-errors=* -header-filter=.* --config-file=%{{libcxx-dir}}/.clang-tidy --load=%{{test-tools-dir}}/clang_tidy_checks/libcxx-tidy.plugin -- -Wweak-vtables %{{compile_flags}} -fno-modules
#include <{header}>
-""")
+"""
+ )
--- double_include.gen.py 2025-06-18 17:34:03.000000 +0000
+++ double_include.gen.py 2025-06-18 17:36:00.381337 +0000
@@ -12,10 +12,11 @@
# Block Lit from interpreting a RUN/XFAIL/etc inside the generation script.
# END.
import sys
+
sys.path.append(sys.argv[1])
from libcxx.header_information import (
lit_header_restrictions,
lit_header_undeprecations,
public_headers,
--- feature_test_macro/implemented_ftms.sh.py 2025-06-18 17:34:03.000000 +0000
+++ feature_test_macro/implemented_ftms.sh.py 2025-06-18 17:36:00.433084 +0000
@@ -23,11 +23,10 @@
def setUp(self):
self.ftm = FeatureTestMacros(TEST_DATA, ["charconv"])
self.maxDiff = None # This causes the diff to be printed when the test fails
def test_implementation(self):
-
expected = {
"__cpp_lib_any": {
"c++17": "201606L",
"c++20": "201606L",
"c++23": "201606L",
--- headers_in_modulemap.sh.py 2025-06-18 17:34:03.000000 +0000
+++ headers_in_modulemap.sh.py 2025-06-18 17:36:00.570755 +0000
@@ -1,8 +1,9 @@
# RUN: %{python} %s %{libcxx-dir}/utils
import sys
+
sys.path.append(sys.argv[1])
from libcxx.header_information import all_headers, libcxx_include
with open(libcxx_include / "module.modulemap.in") as f:
modulemap = f.read()
--- libcpp_version.gen.py 2025-06-18 17:34:03.000000 +0000
+++ libcpp_version.gen.py 2025-06-18 17:36:00.578918 +0000
@@ -9,10 +9,11 @@
# Test that all headers define the _LIBCPP_VERSION macro.
# RUN: %{python} %s %{libcxx-dir}/utils
import sys
+
sys.path.append(sys.argv[1])
from libcxx.header_information import (
lit_header_restrictions,
lit_header_undeprecations,
public_headers,
--- selftest/dsl/dsl.sh.py 2025-06-18 17:34:03.000000 +0000
+++ selftest/dsl/dsl.sh.py 2025-06-18 17:36:00.812257 +0000
@@ -308,11 +308,11 @@
def test_basic(self):
macros = dsl.compilerMacros(self.config)
self.assertIsInstance(macros, dict)
self.assertGreater(len(macros), 0)
- for (k, v) in macros.items():
+ for k, v in macros.items():
self.assertIsInstance(k, str)
self.assertIsInstance(v, str)
def test_no_flag(self):
macros = dsl.compilerMacros(self.config)
@@ -341,11 +341,11 @@
def test_basic(self):
macros = dsl.featureTestMacros(self.config)
self.assertIsInstance(macros, dict)
self.assertGreater(len(macros), 0)
- for (k, v) in macros.items():
+ for k, v in macros.items():
self.assertIsInstance(k, str)
self.assertIsInstance(v, int)
class TestFeature(SetupConfigs):
--- transitive_includes/to_csv.py 2025-06-18 17:34:03.000000 +0000
+++ transitive_includes/to_csv.py 2025-06-18 17:36:00.863352 +0000
@@ -14,13 +14,16 @@
import os
import pathlib
import re
import sys
-libcxx_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
+libcxx_root = os.path.dirname(
+ os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+)
sys.path.append(os.path.join(libcxx_root, "utils"))
from libcxx.header_information import Header
+
def parse_line(line: str) -> Tuple[int, str]:
"""
Parse a single line of --trace-includes output.
@@ -31,10 +34,11 @@
raise ArgumentError(f"Line {line} contains invalid data.")
# The number of periods in front of the header name is the nesting level of
# that header.
return (len(match.group(1)), match.group(2))
+
def make_cxx_v1_relative(header: str) -> Optional[str]:
"""
Returns the path of the header as relative to <whatever>/c++/v1, or None if the path
doesn't contain c++/v1.
@@ -51,10 +55,11 @@
match = re.match(CXX_V1_REGEX, header)
if not match:
return None
else:
return match.group(1)
+
def parse_file(file: io.TextIOBase) -> List[Tuple[Header, Header]]:
"""
Parse a file containing --trace-includes output to generate a list of the
transitive includes contained in it.
@@ -79,25 +84,27 @@
else:
assert includer is not None
result.append((includer, Header(relative)))
return result
+
def print_csv(includes: List[Tuple[Header, Header]]) -> None:
"""
Print the transitive includes as space-delimited CSV.
This function only prints public libc++ headers that are not C compatibility headers.
"""
# Sort and group by includer
by_includer = lambda t: t[0]
includes = itertools.groupby(sorted(includes, key=by_includer), key=by_includer)
- for (includer, includees) in includes:
+ for includer, includees in includes:
includees = map(lambda t: t[1], includees)
for h in sorted(set(includees)):
if h.is_public() and not h.is_C_compatibility():
print(f"{includer} {h}")
+
def main(argv):
parser = argparse.ArgumentParser(
description="""
Given a list of headers produced by --trace-includes, produce a list of libc++ headers in that output.
@@ -106,15 +113,22 @@
information for this script to run.
The output of this script is provided in space-delimited CSV format where each line contains:
<header performing inclusion> <header being included>
- """)
- parser.add_argument("inputs", type=argparse.FileType("r"), nargs='+', default=None,
- help="One or more files containing the result of --trace-includes")
+ """
+ )
+ parser.add_argument(
+ "inputs",
+ type=argparse.FileType("r"),
+ nargs="+",
+ default=None,
+ help="One or more files containing the result of --trace-includes",
+ )
args = parser.parse_args(argv)
includes = [line for file in args.inputs for line in parse_file(file)]
print_csv(includes)
+
if __name__ == "__main__":
main(sys.argv[1:])
--- transitive_includes.gen.py 2025-06-18 17:34:03.000000 +0000
+++ transitive_includes.gen.py 2025-06-18 17:36:00.880194 +0000
@@ -20,10 +20,11 @@
# block Lit from interpreting a RUN/XFAIL/etc inside the generation script
# END.
import sys
+
sys.path.append(sys.argv[1])
from libcxx.header_information import lit_header_restrictions, public_headers
import re
|
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesThe C++03 headers are essentially a separate implementation, so it doesn't make a ton of sense to try to test two implementations with a single set of implementation-specific tests. Most of the tests will be removed in a follow-up, since they don't run in C++03 mode. This patch adds them to make as few changes to the copy as possible. The most notable changes are that This also modifies This is part of https://discourse.llvm.org/t/rfc-freezing-c-03-headers-in-libc. Patch is 2.92 MiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/144093.diff 921 Files Affected:
diff --git a/libcxx/test/libcxx-03/Wnon_modular_include_in_module.compile.pass.cpp b/libcxx/test/libcxx-03/Wnon_modular_include_in_module.compile.pass.cpp
new file mode 100644
index 0000000000000..aa7a6d98d7d68
--- /dev/null
+++ b/libcxx/test/libcxx-03/Wnon_modular_include_in_module.compile.pass.cpp
@@ -0,0 +1,21 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: target={{.*}}-apple-{{.*}}
+// UNSUPPORTED: c++03
+
+// This test ensures that libc++ supports being compiled with modules enabled and with
+// -Wnon-modular-include-in-module. This effectively checks that we don't include any
+// non-modular header from the library.
+//
+// Since most underlying platforms are not modularized properly, this test currently only
+// works on Apple platforms.
+
+// ADDITIONAL_COMPILE_FLAGS: -Wnon-modular-include-in-module -Wsystem-headers-in-module=std -fmodules -fcxx-modules
+
+#include <vector>
diff --git a/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.cxx1z.pass.cpp b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.cxx1z.pass.cpp
new file mode 100644
index 0000000000000..4e51014f20b18
--- /dev/null
+++ b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.cxx1z.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// template <class RandomAccessIterator>
+// void
+// random_shuffle(RandomAccessIterator first, RandomAccessIterator last);
+//
+// template <class RandomAccessIterator, class RandomNumberGenerator>
+// void
+// random_shuffle(RandomAccessIterator first, RandomAccessIterator last,
+// RandomNumberGenerator& rand);
+
+//
+// In C++17, random_shuffle has been removed.
+// However, for backwards compatibility, if _LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE
+// is defined before including <algorithm>, then random_shuffle will be restored.
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DISABLE_DEPRECATION_WARNINGS
+
+#include <algorithm>
+#include <cstddef>
+#include <vector>
+
+#include "test_macros.h"
+
+struct gen
+{
+ std::ptrdiff_t operator()(std::ptrdiff_t n)
+ {
+ return n-1;
+ }
+};
+
+
+int main(int, char**)
+{
+ std::vector<int> v;
+ std::random_shuffle(v.begin(), v.end());
+ gen r;
+ std::random_shuffle(v.begin(), v.end(), r);
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.depr_in_cxx14.verify.cpp b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.depr_in_cxx14.verify.cpp
new file mode 100644
index 0000000000000..057f126a93cfe
--- /dev/null
+++ b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/alg.random.shuffle/random_shuffle.depr_in_cxx14.verify.cpp
@@ -0,0 +1,43 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// <algorithm>
+
+// template <class RandomAccessIterator>
+// void
+// random_shuffle(RandomAccessIterator first, RandomAccessIterator last);
+//
+// template <class RandomAccessIterator, class RandomNumberGenerator>
+// void
+// random_shuffle(RandomAccessIterator first, RandomAccessIterator last,
+// RandomNumberGenerator& rand);
+
+// UNSUPPORTED: c++03, c++11
+
+// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_CXX17_REMOVED_RANDOM_SHUFFLE
+
+#include <algorithm>
+#include <cstddef>
+
+#include "test_macros.h"
+
+struct gen
+{
+ std::ptrdiff_t operator()(std::ptrdiff_t n)
+ {
+ return n-1;
+ }
+};
+
+
+void f() {
+ int v[1] = {1};
+ std::random_shuffle(&v[0], &v[1]); // expected-warning {{'random_shuffle<int *>' is deprecated}}
+ gen r;
+ std::random_shuffle(&v[0], &v[1], r); // expected-warning {{'random_shuffle<int *, gen &>' is deprecated}}
+}
diff --git a/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp
new file mode 100644
index 0000000000000..0c5ae84d97700
--- /dev/null
+++ b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_nontrivial.pass.cpp
@@ -0,0 +1,331 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// In the modules build, adding another overload of `memmove` doesn't work.
+// UNSUPPORTED: clang-modules-build
+// GCC complains about "ambiguating" `__builtin_memmove`.
+// UNSUPPORTED: gcc
+
+// <algorithm>
+
+#include <cassert>
+#include <cstddef>
+
+// These tests check that `std::copy` and `std::move` (including their variations like `copy_n`) don't forward to
+// `std::memmove` when doing so would be observable.
+
+// This template is a better match than the actual `builtin_memmove` (it can match the pointer type exactly, without an
+// implicit conversion to `void*`), so it should hijack the call inside `std::copy` and similar algorithms if it's made.
+template <class Dst, class Src>
+constexpr void* __builtin_memmove(Dst*, Src*, std::size_t) {
+ assert(false);
+ return nullptr;
+}
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+#include "test_macros.h"
+
+// S1 and S2 are simple structs that are convertible to each other and have the same bit representation.
+struct S1 {
+ int x;
+
+ constexpr S1() = default;
+ constexpr S1(int set_x) : x(set_x) {}
+
+ friend constexpr bool operator==(const S1& lhs, const S1& rhs) { return lhs.x == rhs.x; }
+};
+
+struct S2 {
+ int x;
+
+ constexpr S2() = default;
+ constexpr S2(int set_x) : x(set_x) {}
+ constexpr S2(S1 from) : x(from.x) {}
+
+ friend constexpr bool operator==(const S1& lhs, const S2& rhs) { return lhs.x == rhs.x; }
+ friend constexpr bool operator==(const S2& lhs, const S2& rhs) { return lhs.x == rhs.x; }
+};
+
+// U1 and U2 are simple unions that are convertible to each other and have the same bit representation.
+union U1 {
+ int x;
+
+ constexpr U1() = default;
+ constexpr U1(int set_x) : x(set_x) {}
+
+ friend constexpr bool operator==(const U1& lhs, const U1& rhs) { return lhs.x == rhs.x; }
+};
+
+union U2 {
+ int x;
+
+ constexpr U2() = default;
+ constexpr U2(int set_x) : x(set_x) {}
+ constexpr U2(U1 from) : x(from.x) {}
+
+ friend constexpr bool operator==(const U1& lhs, const U2& rhs) { return lhs.x == rhs.x; }
+ friend constexpr bool operator==(const U2& lhs, const U2& rhs) { return lhs.x == rhs.x; }
+};
+
+struct NonTrivialMoveAssignment {
+ int i;
+
+ constexpr NonTrivialMoveAssignment() = default;
+ constexpr NonTrivialMoveAssignment(int set_i) : i(set_i) {}
+
+ constexpr NonTrivialMoveAssignment(NonTrivialMoveAssignment&& rhs) = default;
+ constexpr NonTrivialMoveAssignment& operator=(NonTrivialMoveAssignment&& rhs) noexcept {
+ i = rhs.i;
+ return *this;
+ }
+
+ constexpr friend bool operator==(const NonTrivialMoveAssignment&, const NonTrivialMoveAssignment&) = default;
+};
+
+static_assert(!std::is_trivially_move_assignable_v<NonTrivialMoveAssignment>);
+static_assert(!std::is_trivially_assignable<NonTrivialMoveAssignment&, NonTrivialMoveAssignment&>::value);
+
+struct NonTrivialMoveCtr {
+ int i;
+
+ constexpr NonTrivialMoveCtr() = default;
+ constexpr NonTrivialMoveCtr(int set_i) : i(set_i) {}
+
+ constexpr NonTrivialMoveCtr(NonTrivialMoveCtr&& rhs) noexcept : i(rhs.i) {}
+ constexpr NonTrivialMoveCtr& operator=(NonTrivialMoveCtr&& rhs) = default;
+
+ constexpr friend bool operator==(const NonTrivialMoveCtr&, const NonTrivialMoveCtr&) = default;
+};
+
+static_assert(std::is_trivially_move_assignable_v<NonTrivialMoveCtr>);
+static_assert(!std::is_trivially_copyable_v<NonTrivialMoveCtr>);
+
+struct NonTrivialCopyAssignment {
+ int i;
+
+ constexpr NonTrivialCopyAssignment() = default;
+ constexpr NonTrivialCopyAssignment(int set_i) : i(set_i) {}
+
+ constexpr NonTrivialCopyAssignment(const NonTrivialCopyAssignment& rhs) = default;
+ constexpr NonTrivialCopyAssignment& operator=(const NonTrivialCopyAssignment& rhs) {
+ i = rhs.i;
+ return *this;
+ }
+
+ constexpr friend bool operator==(const NonTrivialCopyAssignment&, const NonTrivialCopyAssignment&) = default;
+};
+
+static_assert(!std::is_trivially_copy_assignable_v<NonTrivialCopyAssignment>);
+
+struct NonTrivialCopyCtr {
+ int i;
+
+ constexpr NonTrivialCopyCtr() = default;
+ constexpr NonTrivialCopyCtr(int set_i) : i(set_i) {}
+
+ constexpr NonTrivialCopyCtr(const NonTrivialCopyCtr& rhs) : i(rhs.i) {}
+ constexpr NonTrivialCopyCtr& operator=(const NonTrivialCopyCtr& rhs) = default;
+
+ constexpr friend bool operator==(const NonTrivialCopyCtr&, const NonTrivialCopyCtr&) = default;
+};
+
+static_assert(std::is_trivially_copy_assignable_v<NonTrivialCopyCtr>);
+static_assert(!std::is_trivially_copyable_v<NonTrivialCopyCtr>);
+
+template <class T>
+constexpr T make(int from) {
+ return T(from);
+}
+
+template <typename PtrT, typename T = std::remove_pointer_t<PtrT>>
+static T make_internal_array[5] = {T(), T(), T(), T(), T()};
+
+template <class T>
+requires std::is_pointer_v<T>
+constexpr T make(int i) {
+ if constexpr (!std::same_as<std::remove_pointer_t<T>, void>) {
+ return make_internal_array<T> + i;
+ } else {
+ return make_internal_array<int> + i;
+ }
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter, class Func>
+constexpr void test_one(Func func) {
+ using From = typename std::iterator_traits<InIter>::value_type;
+ using To = typename std::iterator_traits<OutIter>::value_type;
+
+ {
+ const std::size_t N = 5;
+
+ From input[N] = {make<From>(0), make<From>(1), make<From>(2), make<From>(3), make<From>(4)};
+ To output[N];
+
+ auto in = InIter(input);
+ auto in_end = InIter(input + N);
+ auto sent = SentWrapper<decltype(in_end)>(in_end);
+ auto out = OutIter(output);
+
+ func(in, sent, out, N);
+ if constexpr (!std::same_as<To, bool>) {
+ assert(std::equal(input, input + N, output));
+ } else {
+ bool expected[N] = {false, true, true, true, true};
+ assert(std::equal(output, output + N, expected));
+ }
+ }
+
+ {
+ 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);
+
+ func(in, sent, out, N);
+ assert(output[0] == make<To>(2));
+ }
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter>
+constexpr void test_copy() {
+ // Classic.
+ if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
+ std::copy(first, last, out);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
+ std::copy_backward(first, last, out + n);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto, auto out, std::size_t n) {
+ std::copy_n(first, n, out);
+ });
+ }
+
+ // Ranges.
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
+ std::ranges::copy(first, last, out);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
+ std::ranges::copy_backward(first, last, out + n);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto, auto out, std::size_t n) {
+ std::ranges::copy_n(first, n, out);
+ });
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter>
+constexpr void test_move() {
+ if constexpr (std::same_as<InIter, SentWrapper<InIter>>) {
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
+ std::move(first, last, out);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
+ std::move_backward(first, last, out + n);
+ });
+ }
+
+ // Ranges.
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t) {
+ std::ranges::move(first, last, out);
+ });
+ test_one<InIter, SentWrapper, OutIter>([](auto first, auto last, auto out, std::size_t n) {
+ std::ranges::move_backward(first, last, out + n);
+ });
+}
+
+template <class From, class To = From>
+constexpr void test_copy_with_type() {
+ using FromIter = contiguous_iterator<From*>;
+ using ToIter = contiguous_iterator<To*>;
+
+ test_copy<FromIter, std::type_identity_t, ToIter>();
+ test_copy<FromIter, sized_sentinel, ToIter>();
+ test_copy<FromIter, std::type_identity_t, To*>();
+ test_copy<From*, std::type_identity_t, To*>();
+ test_copy<From*, std::type_identity_t, ToIter>();
+}
+
+template <class From, class To = From>
+constexpr void test_move_with_type() {
+ using FromIter = contiguous_iterator<From*>;
+ using ToIter = contiguous_iterator<To*>;
+
+ test_move<FromIter, std::type_identity_t, ToIter>();
+ test_move<FromIter, sized_sentinel, ToIter>();
+ test_move<FromIter, std::type_identity_t, To*>();
+ test_move<From*, std::type_identity_t, To*>();
+ test_move<From*, std::type_identity_t, ToIter>();
+}
+
+template <class From, class To>
+constexpr void test_copy_and_move() {
+ test_copy_with_type<From, To>();
+ test_move_with_type<From, To>();
+}
+
+template <class From, class To>
+constexpr void test_both_directions() {
+ test_copy_and_move<From, To>();
+ if (!std::same_as<From, To>) {
+ test_copy_and_move<To, From>();
+ }
+}
+
+constexpr bool test() {
+ test_copy_with_type<NonTrivialCopyAssignment>();
+ test_move_with_type<NonTrivialMoveAssignment>();
+
+ // Copying from a smaller type into a larger type and vice versa.
+ test_both_directions<char, int>();
+ test_both_directions<std::int32_t, std::int64_t>();
+
+ // Copying between types with different representations.
+ test_both_directions<int, float>();
+ // Copying from `bool` to `char` will invoke the optimization, so only check one direction.
+ test_copy_and_move<char, bool>();
+
+ // Copying between different structs with the same representation (there is no way to guarantee the representation is
+ // the same).
+ test_copy_and_move<S1, S2>();
+ // Copying between different unions with the same representation.
+ test_copy_and_move<U1, U2>();
+
+ // Copying from a regular pointer to a void pointer (these are not considered trivially copyable).
+ test_copy_and_move<int*, void*>();
+ // Copying from a non-const pointer to a const pointer (these are not considered trivially copyable).
+ test_copy_and_move<int*, const int*>();
+
+ // `memmove` does not support volatile pointers.
+ // (See also https://github.com/llvm/llvm-project/issues/28901).
+ if (!std::is_constant_evaluated()) {
+ test_both_directions<volatile int, int>();
+ test_both_directions<volatile int, volatile int>();
+ }
+
+ return true;
+}
+
+int main(int, char**) {
+ test();
+ static_assert(test());
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp
new file mode 100644
index 0000000000000..ff10c7919200d
--- /dev/null
+++ b/libcxx/test/libcxx-03/algorithms/alg.modifying.operations/copy_move_trivial.pass.cpp
@@ -0,0 +1,334 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// In the modules build, adding another overload of `memmove` doesn't work.
+// UNSUPPORTED: clang-modules-build
+// GCC complains about "ambiguating" `__builtin_memmove`.
+// UNSUPPORTED: gcc
+
+// <algorithm>
+
+// These tests check that `std::copy` and `std::move` (including their variations like `copy_n`) forward to
+// `memmove` when possible.
+
+#include <cstddef>
+
+struct Foo {
+ int i = 0;
+
+ Foo() = default;
+ Foo(int set_i) : i(set_i) {}
+
+ friend bool operator==(const Foo&, const Foo&) = default;
+};
+
+static bool memmove_called = false;
+
+// This template is a better match than the actual `builtin_memmove` (it can match the pointer type exactly, without an
+// implicit conversion to `void*`), so it should hijack the call inside `std::copy` and similar algorithms if it's made.
+template <class Dst, class Src>
+constexpr void* __builtin_memmove(Dst* dst, Src* src, std::size_t count) {
+ memmove_called = true;
+ return __builtin_memmove(static_cast<void*>(dst), static_cast<const void*>(src), count);
+}
+
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+#include <limits>
+#include <ranges>
+#include <type_traits>
+
+#include "test_iterators.h"
+
+static_assert(std::is_trivially_copyable_v<Foo>);
+
+// To test pointers to functions.
+void Func() {}
+using FuncPtr = decltype(&Func);
+
+// To test pointers to members.
+struct S {
+ int mem_obj = 0;
+ void MemFunc() {}
+};
+using MemObjPtr = decltype(&S::mem_obj);
+using MemFuncPtr = decltype(&S::MemFunc);
+
+// To test bitfields.
+struct BitfieldS {
+ unsigned char b1 : 3;
+ unsigned char : 2;
+ unsigned char b2 : 5;
+ friend bool operator==(const BitfieldS&, const BitfieldS&) = default;
+};
+
+// To test non-default alignment.
+struct AlignedS {
+ alignas(64) int x;
+ alignas(8) int y;
+ friend bool operator==(const AlignedS&, const AlignedS&) = default;
+};
+
+template <class T>
+T make(int from) {
+ return T(from);
+}
+
+template <class T>
+requires (std::is_pointer_v<T> && !std::is_function_v<std::remove_pointer_t<T>>)
+T make(int i) {
+ static std::remove_pointer_t<T> arr[8];
+ return arr + i;
+}
+
+template <class T>
+requires std::same_as<T, FuncPtr>
+FuncPtr make(int) {
+ return &Func;
+}
+
+template <class T>
+requires std::same_as<T, MemObjPtr>
+MemObjPtr make(int) {
+ return &S::mem_obj;
+}
+
+template <class T>
+requires std::same_as<T, MemFuncPtr>
+MemFuncPtr make(int) {
+ return &S::MemFunc;
+}
+
+template <class T>
+requires std::same_as<T, BitfieldS>
+BitfieldS make(int x) {
+ BitfieldS result = {};
+ result.b1 = x;
+ result.b2 = x;
+ return result;
+}
+
+template <class T>
+requires std::same_as<T, AlignedS>
+AlignedS make(int x) {
+ AlignedS result;
+ result.x = x;
+ result.y = x;
+ return result;
+}
+
+template <class InIter, template <class> class SentWrapper, class OutIter, class Func>
+void test_one(Func func) {
+ using From = std::iter_value_t<InIter>;
+ using To = std::iter_value_t<OutIter>;
+
+ // Normal case.
+ {
+ const std::size_t N = 4;
+
+ From input[N] = {make<From>(1), make<From>(2), make<From>(3), make<From>(4)...
[truncated]
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but please also make a pass to get all of the implementation-detail tests that were removed since the headers were frozen, and re-add those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After discussing this some more, we decided to reorganize a few parts of libcxx/test/libcxx before we actually make a copy. I have partially reviewed what needs to be split out and marked where I left it at.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's split this out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of these tests should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These tests too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one should definitely be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be split out.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be split out.
CONTINUE HERE
The C++03 headers are essentially a separate implementation, so it doesn't make a ton of sense to try to test two implementations with a single set of implementation-specific tests.
Most of the tests will be removed in a follow-up, since they don't run in C++03 mode. This patch adds them to make as few changes to the copy as possible. The most notable changes are that
lit.local.cfg
files are touched to change the path fromlibcxx/test/libcxx
tolibcxx/test/libcxx-03
in a few places.This also modifies
lit.local.cfg
files to runlibcxx/test/libcxx-03
only when using the frozen headers andlbcxx/test/libcxx
tests only when not using the frozen headers.This is part of https://discourse.llvm.org/t/rfc-freezing-c-03-headers-in-libc.