Skip to content

Commit

Permalink
[libc++] Test suite portability improvements (llvm#98527)
Browse files Browse the repository at this point in the history
This patch contains a number of small portability improvements for the
test suite, making it easier to run the test suite with other standard
library implementations.

- Guard checks for _LIBCPP_HARDENING_MODE to avoid -Wundef
- Avoid defining _LIBCPP_HARDENING_MODE even when no hardening mode is
  specified -- we should use the default mode of the library in that case.
- Add missing includes and qualify a few function calls.
- Avoid opening namespace std to forward declare stdlib containers. The
  test suite should represent user code, and user code isn't allowed to do
  that.
  • Loading branch information
ldionne authored Jul 12, 2024
1 parent dd4658f commit 7918e62
Show file tree
Hide file tree
Showing 11 changed files with 47 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,9 @@ constexpr bool test() {
return value;
};
assert(std::ranges::clamp(3, 2, 4, std::ranges::less{}, projection_function) == 3);
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && \
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_EXTENSIVE && \
_LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
assert(counter <= 3);
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ int main(int, char**) {
std::sort_heap(first, last);
LIBCPP_ASSERT(stats.copied == 0);
LIBCPP_ASSERT(stats.moved <= 2 * n + n * logn);
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
LIBCPP_ASSERT(stats.compared <= n * logn);
#else
LIBCPP_ASSERT(stats.compared <= 2 * n * logn + debug_comparisons);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ void test_complexity() {
std::ranges::sort_heap(first, last, &MyInt::Comp);
LIBCPP_ASSERT(stats.copied == 0);
LIBCPP_ASSERT(stats.moved <= 2 * n + n * logn);
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
LIBCPP_ASSERT(stats.compared <= n * logn);
#else
LIBCPP_ASSERT(stats.compared <= 2 * n * logn + debug_comparisons);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ test_one(unsigned N, unsigned M)
assert(ia[0] == static_cast<int>(N)-1);
assert(ia[N-1] == 0);
assert(std::is_sorted(ia, ia+N, std::greater<value_type>()));
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
assert(pred.count() <= (N-1));
#endif
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ constexpr void test_comparator_invocation_count() {
// The comparator is invoked only `min(left.size(), right.size())` times
test_lexicographical_compare<const int*, const int*>(
std::array{0, 1, 2}, std::array{0, 1, 2, 3}, compare_last_digit_counting, std::strong_ordering::less);
#if _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE != _LIBCPP_HARDENING_MODE_DEBUG
assert(compare_invocation_count <= 3);
#else
assert(compare_invocation_count <= 6);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ void test_iterator_sentinel() {
assert(s.data() == std::data(arr));
}

#if _LIBCPP_STD_VER >= 26
#if TEST_STD_VER >= 26
// P3029R1: deduction from `integral_constant`
{
std::span s{std::begin(arr), std::integral_constant<size_t, 3>{}};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ int main(int, char**)
err = std::ios_base::goodbit;
t = std::tm();
I i = f.get_date(I(in), I(in+sizeof(in)/sizeof(in[0])-1), ios, err, &t);
#if _LIBCPP_VERSION
#if defined(_LIBCPP_VERSION)
// libc++ points to the '/' after the month.
assert(base(i) == in+2);
#else
Expand All @@ -129,7 +129,7 @@ int main(int, char**)
err = std::ios_base::goodbit;
t = std::tm();
I i = f.get_date(I(in), I(in+sizeof(in)/sizeof(in[0])-1), ios, err, &t);
#if _LIBCPP_VERSION
#if defined(_LIBCPP_VERSION)
// libc++ points to the '/' after the month.
assert(base(i) == in+2);
#else
Expand Down
2 changes: 1 addition & 1 deletion libcxx/test/support/check_assertion.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ bool ExpectDeath(DeathCause expected_cause, const char* stmt, Func&& func) {
#define EXPECT_STD_TERMINATE(...) \
assert( ExpectDeath(DeathCause::StdTerminate, #__VA_ARGS__, __VA_ARGS__) )

#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#if defined(_LIBCPP_HARDENING_MODE) && _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_DEBUG
#define TEST_LIBCPP_ASSERT_FAILURE(expr, message) \
assert(( ExpectDeath(DeathCause::VerboseAbort, #expr, [&]() { (void)(expr); }, MakeAssertionMessageMatcher(message)) ))
#else
Expand Down
41 changes: 8 additions & 33 deletions libcxx/test/support/container_test_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,16 @@

#include <cassert>
#include <cstddef>
#include <deque>
#include <functional>
#include <list>
#include <map>
#include <new>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "test_macros.h"

Expand Down Expand Up @@ -420,12 +427,7 @@ bool operator <(CopyInsertable<ID> const& L, CopyInsertable<ID> const& R) {
return L.data < R.data;
}


#ifdef _LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_BEGIN_NAMESPACE_STD
#else
namespace std {
#endif
template <int ID>
struct hash< ::CopyInsertable<ID> > {
typedef ::CopyInsertable<ID> argument_type;
Expand All @@ -435,34 +437,7 @@ namespace std {
return arg.data;
}
};
template <class T, class Alloc>
class vector;
template <class T, class Alloc>
class deque;
template <class T, class Alloc>
class list;
template <class _Key, class _Value, class _Less, class _Alloc>
class map;
template <class _Key, class _Value, class _Less, class _Alloc>
class multimap;
template <class _Value, class _Less, class _Alloc>
class set;
template <class _Value, class _Less, class _Alloc>
class multiset;
template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
class unordered_map;
template <class _Key, class _Value, class _Hash, class _Equals, class _Alloc>
class unordered_multimap;
template <class _Value, class _Hash, class _Equals, class _Alloc>
class unordered_set;
template <class _Value, class _Hash, class _Equals, class _Alloc>
class unordered_multiset;

#ifdef _LIBCPP_END_NAMESPACE_STD
_LIBCPP_END_NAMESPACE_STD
#else
} // end namespace std
#endif
}

// TCT - Test container type
namespace TCT {
Expand Down
46 changes: 23 additions & 23 deletions libcxx/test/support/filesystem_test_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <chrono>
#include <cstdint>
#include <cstdio> // for printf
#include <cstring>
#include <string>
#include <system_error>
#include <type_traits>
Expand Down Expand Up @@ -232,9 +233,9 @@ struct scoped_test_env
if (size >
static_cast<typename std::make_unsigned<utils::off64_t>::type>(
std::numeric_limits<utils::off64_t>::max())) {
fprintf(stderr, "create_file(%s, %ju) too large\n",
filename.c_str(), size);
abort();
std::fprintf(stderr, "create_file(%s, %ju) too large\n",
filename.c_str(), size);
std::abort();
}

#if defined(_WIN32) || defined(__MVS__)
Expand All @@ -244,20 +245,20 @@ struct scoped_test_env
#endif
FILE* file = utils::fopen64(filename.c_str(), "w" FOPEN_CLOEXEC_FLAG);
if (file == nullptr) {
fprintf(stderr, "fopen %s failed: %s\n", filename.c_str(),
strerror(errno));
abort();
std::fprintf(stderr, "fopen %s failed: %s\n", filename.c_str(),
std::strerror(errno));
std::abort();
}

if (utils::ftruncate64(
fileno(file), static_cast<utils::off64_t>(size)) == -1) {
fprintf(stderr, "ftruncate %s %ju failed: %s\n", filename.c_str(),
size, strerror(errno));
fclose(file);
abort();
std::fprintf(stderr, "ftruncate %s %ju failed: %s\n", filename.c_str(),
size, std::strerror(errno));
std::fclose(file);
std::abort();
}

fclose(file);
std::fclose(file);
return filename;
}

Expand Down Expand Up @@ -616,10 +617,9 @@ struct ExceptionChecker {
}();
assert(format == Err.what());
if (format != Err.what()) {
fprintf(stderr,
"filesystem_error::what() does not match expected output:\n");
fprintf(stderr, " expected: \"%s\"\n", format.c_str());
fprintf(stderr, " actual: \"%s\"\n\n", Err.what());
std::fprintf(stderr, "filesystem_error::what() does not match expected output:\n");
std::fprintf(stderr, " expected: \"%s\"\n", format.c_str());
std::fprintf(stderr, " actual: \"%s\"\n\n", Err.what());
}
}

Expand All @@ -639,23 +639,23 @@ inline fs::path GetWindowsInaccessibleDir() {
continue;
// Basic sanity checks on the directory_entry
if (!ent.exists() || !ent.is_directory()) {
fprintf(stderr, "The expected inaccessible directory \"%s\" was found "
"but doesn't behave as expected, skipping tests "
"regarding it\n", dir.string().c_str());
std::fprintf(stderr, "The expected inaccessible directory \"%s\" was found "
"but doesn't behave as expected, skipping tests "
"regarding it\n", dir.string().c_str());
return fs::path();
}
// Check that it indeed is inaccessible as expected
(void)fs::exists(ent, ec);
if (!ec) {
fprintf(stderr, "The expected inaccessible directory \"%s\" was found "
"but seems to be accessible, skipping tests "
"regarding it\n", dir.string().c_str());
std::fprintf(stderr, "The expected inaccessible directory \"%s\" was found "
"but seems to be accessible, skipping tests "
"regarding it\n", dir.string().c_str());
return fs::path();
}
return ent;
}
fprintf(stderr, "No inaccessible directory \"%s\" found, skipping tests "
"regarding it\n", dir.string().c_str());
std::fprintf(stderr, "No inaccessible directory \"%s\" found, skipping tests "
"regarding it\n", dir.string().c_str());
return fs::path();
}

Expand Down
9 changes: 5 additions & 4 deletions libcxx/utils/libcxx/test/params.py
Original file line number Diff line number Diff line change
Expand Up @@ -374,19 +374,20 @@ def getSuitableClangTidy(cfg):
),
Parameter(
name="hardening_mode",
choices=["none", "fast", "extensive", "debug"],
choices=["none", "fast", "extensive", "debug", "undefined"],
type=str,
default="none",
default="undefined",
help="Whether to enable one of the hardening modes when compiling the test suite. This is only "
"meaningful when running the tests against libc++.",
"meaningful when running the tests against libc++. By default, no hardening mode is specified "
"so the default hardening mode of the standard library will be used (if any).",
actions=lambda hardening_mode: filter(
None,
[
AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_NONE") if hardening_mode == "none" else None,
AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_FAST") if hardening_mode == "fast" else None,
AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE") if hardening_mode == "extensive" else None,
AddCompileFlag("-D_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG") if hardening_mode == "debug" else None,
AddFeature("libcpp-hardening-mode={}".format(hardening_mode)),
AddFeature("libcpp-hardening-mode={}".format(hardening_mode)) if hardening_mode != "undefined" else None,
],
),
),
Expand Down

0 comments on commit 7918e62

Please sign in to comment.