mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 23:36:06 +00:00

Found while running libc++'s tests with MSVC's STL. * `libcxx/test/std/algorithms/alg.modifying.operations/alg.unique/ranges_unique_copy.pass.cpp` + Fix MSVC "warning C4389: '`==`': signed/unsigned mismatch". + This was x86-specific for me. The LHS is `int` and the RHS is `size_t`. We know the `array`'s size, so `static_cast<int>` is certainly safe, and this matches the following `numberOfProj` comparisons. * `libcxx/test/std/containers/sequences/insert_range_sequence_containers.h` + Fix MSVC "warning C4267: 'argument': conversion from '`size_t`' to '`const int`', possible loss of data". + `test_case.index` is `size_t`:b85f1f9b18/libcxx/test/std/containers/insert_range_helpers.h (L65-L68)
+ But the container's `difference_type` is `int`:b85f1f9b18/libcxx/test/support/test_allocator.h (L65-L76)
+ I introduced an alias `D` to make the long line more readable. * `libcxx/test/std/containers/unord/unord.map/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.multimap/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.multiset/eq.different_hash.pass.cpp` * `libcxx/test/std/containers/unord/unord.set/eq.different_hash.pass.cpp` + Fix MSVC "warning C6297: Arithmetic overflow. Results might not be an expected value." + This warning is almost annoying enough to outright disable, but we use similar `static_cast`s to deal with sign/truncation warnings elsewhere, because there's some value in ensuring that product code is clean with respect to these warnings. If there were many more occurrences, then disabling the warning would be appropriate. + Cleanup: Change 2 inconsistently unqualified occurrences of `size_t` to `std::size_t`. * `libcxx/test/std/containers/views/mdspan/layout_stride/index_operator.pass.cpp` + Fix MSVC "warning C4244: 'initializing': conversion from '`__int64`' to '`size_t`', possible loss of data". + This was x86-specific for me. The `args` are indeed `int64_t`, and we're storing the result in `size_t`, so we should cast. * `libcxx/test/std/ranges/range.utility/range.utility.conv/container.h` + Fix MSVC "warning C4244: 'initializing': conversion from '`ptrdiff_t`' to '`int`', possible loss of data". + Fix MSVC "warning C4267: 'initializing': conversion from '`size_t`' to '`int`', possible loss of data". + We're initializing `int size_`, so we should explicitly cast from pointer subtraction and `std::ranges::size`. * `libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp` * `libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/make_shared_for_overwrite.pass.cpp` * `libcxx/test/std/utilities/smartptr/unique.ptr/unique.ptr.create/make_unique_for_overwrite.default_init.pass.cpp` + Fix MSVC "warning C4309: 'initializing': truncation of constant value". + MSVC emits this warning because `0xDE` is outside the range of `char` (signed by default in our implementation). * `libcxx/test/support/concat_macros.h` + Fix MSVC "warning C4244: 'argument': conversion from '`char16_t`' to '`const char`', possible loss of data". + Fix MSVC "warning C4244: 'argument': conversion from '`unsigned int`' to '`const char`', possible loss of data". + This code was very recently introduced by @mordante in #73395.
199 lines
6.7 KiB
C++
199 lines
6.7 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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 TEST_SUPPORT_CONCAT_MACROS_H
|
|
#define TEST_SUPPORT_CONCAT_MACROS_H
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
#include "assert_macros.h"
|
|
#include "test_macros.h"
|
|
|
|
#ifndef TEST_HAS_NO_LOCALIZATION
|
|
# include <concepts>
|
|
# include <iterator>
|
|
# include <sstream>
|
|
#endif
|
|
|
|
#if TEST_STD_VER > 17
|
|
|
|
# ifndef TEST_HAS_NO_LOCALIZATION
|
|
|
|
[[nodiscard]] constexpr bool test_is_high_surrogate(char32_t value) { return value >= 0xd800 && value <= 0xdbff; }
|
|
|
|
[[nodiscard]] constexpr bool test_is_low_surrogate(char32_t value) { return value >= 0xdc00 && value <= 0xdfff; }
|
|
|
|
[[nodiscard]] constexpr bool test_is_surrogate(char32_t value) { return value >= 0xd800 && value <= 0xdfff; }
|
|
|
|
[[nodiscard]] constexpr bool test_is_code_point(char32_t value) { return value <= 0x10ffff; }
|
|
|
|
[[nodiscard]] constexpr bool test_is_scalar_value(char32_t value) {
|
|
return test_is_code_point(value) && !test_is_surrogate(value);
|
|
}
|
|
|
|
inline constexpr char32_t test_replacement_character = U'\ufffd';
|
|
|
|
template <class InIt, class OutIt>
|
|
OutIt test_transcode() = delete;
|
|
|
|
template <class InIt, class OutIt>
|
|
requires(std::output_iterator<OutIt, const char&> && std::same_as<std::iter_value_t<InIt>, char8_t>)
|
|
OutIt test_transcode(InIt first, InIt last, OutIt out_it) {
|
|
return std::copy(first, last, out_it);
|
|
}
|
|
|
|
template <class OutIt>
|
|
requires std::output_iterator<OutIt, const char&>
|
|
void test_encode(OutIt& out_it, char16_t value) {
|
|
if (value < 0x80)
|
|
*out_it++ = static_cast<char>(value);
|
|
else if (value < 0x800) {
|
|
*out_it++ = static_cast<char>(0b11000000 | (value >> 6));
|
|
*out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));
|
|
} else {
|
|
*out_it++ = static_cast<char>(0b11100000 | (value >> 12));
|
|
*out_it++ = static_cast<char>(0b10000000 | ((value) >> 6 & 0b00111111));
|
|
*out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));
|
|
}
|
|
}
|
|
|
|
template <class OutIt>
|
|
requires std::output_iterator<OutIt, const char&>
|
|
void test_encode(OutIt& out_it, char32_t value) {
|
|
if ((value & 0xffff0000) == 0)
|
|
test_encode(out_it, static_cast<char16_t>(value));
|
|
else {
|
|
*out_it++ = static_cast<char>(0b11100000 | (value >> 18));
|
|
*out_it++ = static_cast<char>(0b10000000 | ((value) >> 12 & 0b00111111));
|
|
*out_it++ = static_cast<char>(0b10000000 | ((value) >> 6 & 0b00111111));
|
|
*out_it++ = static_cast<char>(0b10000000 | (value & 0b00111111));
|
|
}
|
|
}
|
|
|
|
template <class InIt, class OutIt>
|
|
requires(std::output_iterator<OutIt, const char&> &&
|
|
(std::same_as<std::iter_value_t<InIt>, char16_t>
|
|
# ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
|
|| (std::same_as<std::iter_value_t<InIt>, wchar_t> && sizeof(wchar_t) == 2)
|
|
# endif
|
|
))
|
|
OutIt test_transcode(InIt first, InIt last, OutIt out_it) {
|
|
while (first != last) {
|
|
char32_t value = *first++;
|
|
|
|
if (test_is_low_surrogate(value)) [[unlikely]] {
|
|
test_encode(out_it, static_cast<char16_t>(test_replacement_character));
|
|
continue;
|
|
}
|
|
|
|
if (!test_is_high_surrogate(value)) {
|
|
test_encode(out_it, static_cast<char16_t>(value));
|
|
continue;
|
|
}
|
|
|
|
if (first == last || !test_is_low_surrogate(static_cast<char32_t>(*first))) [[unlikely]] {
|
|
test_encode(out_it, static_cast<char16_t>(test_replacement_character));
|
|
continue;
|
|
}
|
|
|
|
value -= 0xd800;
|
|
value <<= 10;
|
|
value += static_cast<char32_t>(*first++) - 0xdc00;
|
|
value += 0x10000;
|
|
|
|
if (test_is_code_point(value)) [[likely]]
|
|
test_encode(out_it, value);
|
|
else
|
|
test_encode(out_it, static_cast<char16_t>(test_replacement_character));
|
|
}
|
|
|
|
return out_it;
|
|
}
|
|
|
|
template <class InIt, class OutIt>
|
|
requires(std::output_iterator<OutIt, const char&> &&
|
|
(std::same_as<std::iter_value_t<InIt>, char32_t>
|
|
# ifndef TEST_HAS_NO_WIDE_CHARACTERS
|
|
|| (std::same_as<std::iter_value_t<InIt>, wchar_t> && sizeof(wchar_t) == 4)
|
|
# endif
|
|
))
|
|
OutIt test_transcode(InIt first, InIt last, OutIt out_it) {
|
|
while (first != last) {
|
|
char32_t value = *first++;
|
|
if (test_is_code_point(value)) [[likely]]
|
|
test_encode(out_it, value);
|
|
else
|
|
test_encode(out_it, static_cast<char16_t>(test_replacement_character));
|
|
}
|
|
return out_it;
|
|
}
|
|
|
|
template <class T>
|
|
concept test_streamable = requires(std::stringstream& stream, T&& value) { stream << value; };
|
|
|
|
template <class R>
|
|
concept test_convertable_range = (!test_streamable<R> && requires(R&& value) {
|
|
std::basic_string_view{std::begin(value), std::end(value)};
|
|
});
|
|
|
|
template <class T>
|
|
concept test_can_concat = test_streamable<T> || test_convertable_range<T>;
|
|
|
|
template <test_streamable T>
|
|
std::ostream& test_concat(std::ostream& stream, T&& value) {
|
|
return stream << value;
|
|
}
|
|
|
|
template <test_convertable_range T>
|
|
std::ostream& test_concat(std::ostream& stream, T&& value) {
|
|
auto b = std::begin(value);
|
|
auto e = std::end(value);
|
|
if (b != e) {
|
|
// When T is an array it's string-literal, remove the NUL terminator.
|
|
if constexpr (std::is_array_v<std::remove_cvref_t<T>>) {
|
|
--e;
|
|
}
|
|
test_transcode(b, e, std::ostream_iterator<char>{stream});
|
|
}
|
|
return stream;
|
|
}
|
|
# endif // TEST_HAS_NO_LOCALIZATION
|
|
|
|
// If possible concatenates message for the assertion function, else returns a
|
|
// default message. Not being able to stream is not considered an error. For
|
|
// example, streaming to std::wcerr doesn't work properly in the CI. Therefore
|
|
// the formatting tests should only stream to std::string.
|
|
//
|
|
// The macro TEST_WRITE_CONCATENATED can be used to evaluate the arguments
|
|
// lazily. This useful when using this function in combination with
|
|
// assert_macros.h.
|
|
template <class... Args>
|
|
std::string test_concat_message([[maybe_unused]] Args&&... args) {
|
|
# ifndef TEST_HAS_NO_LOCALIZATION
|
|
if constexpr ((test_can_concat<Args> && ...)) {
|
|
std::stringstream sstr;
|
|
((test_concat(sstr, std::forward<Args>(args))), ...);
|
|
return sstr.str();
|
|
} else
|
|
# endif // TEST_HAS_NO_LOCALIZATION
|
|
return "Message discarded since it can't be streamed to std::cerr.\n";
|
|
}
|
|
|
|
// Writes its arguments to stderr, using the test_concat_message helper.
|
|
# define TEST_WRITE_CONCATENATED(...) [&] { ::test_eprintf("%s", ::test_concat_message(__VA_ARGS__).c_str()); }
|
|
|
|
#else
|
|
|
|
// Fallback definition before C++20 that allows using the macro but doesn't provide a very good message.
|
|
# define TEST_WRITE_CONCATENATED(...) [&] { ::test_eprintf("%s", TEST_STRINGIZE(__VA_ARGS__)); }
|
|
|
|
#endif // TEST_STD_VER > 17
|
|
|
|
#endif // TEST_SUPPORT_CONCAT_MACROS_H
|