Skip to content

[libc++][C++03] Remove tests from libcxx-03 which aren't run in C++03 mode #144094

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: users/philnik777/cxx03_split_libcxx_tests
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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;
}
61 changes: 61 additions & 0 deletions libcxx/test/libcxx-03/algorithms/bad_iterator_traits.verify.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// std::sort

#include <algorithm>
#include <iterator>
#include <type_traits>
#include <utility>

struct BadIter {
struct Value {
friend bool operator==(const Value& x, const Value& y);
friend bool operator!=(const Value& x, const Value& y);
friend bool operator< (const Value& x, const Value& y);
friend bool operator<=(const Value& x, const Value& y);
friend bool operator> (const Value& x, const Value& y);
friend bool operator>=(const Value& x, const Value& y);
friend void swap(Value, Value);
};

using iterator_category = std::random_access_iterator_tag;
using value_type = Value;
using reference = Value&;
using difference_type = long;
using pointer = Value*;

Value operator*() const; // Not `Value&`.
reference operator[](difference_type n) const;

BadIter& operator++();
BadIter& operator--();
BadIter operator++(int);
BadIter operator--(int);

BadIter& operator+=(difference_type n);
BadIter& operator-=(difference_type n);
friend BadIter operator+(BadIter x, difference_type n);
friend BadIter operator+(difference_type n, BadIter x);
friend BadIter operator-(BadIter x, difference_type n);
friend difference_type operator-(BadIter x, BadIter y);

friend bool operator==(const BadIter& x, const BadIter& y);
friend bool operator!=(const BadIter& x, const BadIter& y);
friend bool operator< (const BadIter& x, const BadIter& y);
friend bool operator<=(const BadIter& x, const BadIter& y);
friend bool operator> (const BadIter& x, const BadIter& y);
friend bool operator>=(const BadIter& x, const BadIter& y);
};

// Verify that iterators with incorrect `iterator_traits` are rejected. This protects against potential undefined
// behavior when these iterators are passed to standard algorithms.
void test() {
std::sort(BadIter(), BadIter());
//expected-error-re@*:* {{static assertion failed {{.*}}It looks like your iterator's `iterator_traits<It>::reference` does not match the return type of dereferencing the iterator}}
}
59 changes: 59 additions & 0 deletions libcxx/test/libcxx-03/algorithms/half_positive.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//===----------------------------------------------------------------------===//
//
// 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>

// __half_positive divides an integer number by 2 as unsigned number for known types.
// It can be an important optimization for lower bound, for example.

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__algorithm/half_positive.h>
#include <cassert>
#include <cstddef>
#include <limits>

#include "test_macros.h"
#include "user_defined_integral.h"

namespace {

template <class IntType, class UnderlyingType = IntType>
TEST_CONSTEXPR bool test(IntType max_v = IntType(std::numeric_limits<UnderlyingType>::max())) {
return std::__half_positive(max_v) == max_v / 2;
}

} // namespace

int main(int, char**)
{
{
assert(test<char>());
assert(test<int>());
assert(test<long>());
assert((test<UserDefinedIntegral<int>, int>()));
assert(test<std::size_t>());
#if !defined(TEST_HAS_NO_INT128)
assert(test<__int128_t>());
#endif // !defined(TEST_HAS_NO_INT128)
}

#if TEST_STD_VER >= 11
{
static_assert(test<char>(), "");
static_assert(test<int>(), "");
static_assert(test<long>(), "");
static_assert(test<std::size_t>(), "");
#if !defined(TEST_HAS_NO_INT128)
static_assert(test<__int128_t>(), "");
#endif // !defined(TEST_HAS_NO_INT128)
}
#endif // TEST_STD_VER >= 11

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// 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>

// REQUIRES: libcpp-pstl-backend-libdispatch

// __chunk_partitions __partition_chunks(ptrdiff_t);

#include <__pstl/backends/libdispatch.h>
#include <cassert>
#include <cstddef>

int main(int, char**) {
{
auto chunks = std::__pstl::__libdispatch::__partition_chunks(0);
assert(chunks.__chunk_count_ == 1);
assert(chunks.__first_chunk_size_ == 0);
assert(chunks.__chunk_size_ == 0);
}

{
auto chunks = std::__pstl::__libdispatch::__partition_chunks(1);
assert(chunks.__chunk_count_ == 1);
assert(chunks.__first_chunk_size_ == 1);
assert(chunks.__chunk_size_ == 1);
}

for (std::ptrdiff_t i = 2; i != 2ll << 20; ++i) {
auto chunks = std::__pstl::__libdispatch::__partition_chunks(i);
assert(chunks.__chunk_count_ >= 1);
assert(chunks.__chunk_count_ <= i);
assert((chunks.__chunk_count_ - 1) * chunks.__chunk_size_ + chunks.__first_chunk_size_ == i);
}
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,323 @@
//===----------------------------------------------------------------------===//
//
// 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>

#include <algorithm>
#include <cassert>
#include <compare>
#include <cstddef>
#include <deque>
#include <ranges>
#include <type_traits>
#include <vector>

#include "test_macros.h"

template <class T>
struct Less {
int* copies_;
TEST_CONSTEXPR explicit Less(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 Less(const Less& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 Less& operator=(const Less&) = default;
TEST_CONSTEXPR bool operator()(T, T) const { return false; }
};

template <class T>
struct Equal {
int* copies_;
TEST_CONSTEXPR explicit Equal(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 Equal(const Equal& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 Equal& operator=(const Equal&) = default;
TEST_CONSTEXPR bool operator()(T, T) const { return true; }
};

template <class T>
struct UnaryVoid {
int* copies_;
TEST_CONSTEXPR explicit UnaryVoid(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 UnaryVoid(const UnaryVoid& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 UnaryVoid& operator=(const UnaryVoid&) = default;
TEST_CONSTEXPR_CXX14 void operator()(T) const {}
};

template <class T>
struct UnaryTrue {
int* copies_;
TEST_CONSTEXPR explicit UnaryTrue(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 UnaryTrue(const UnaryTrue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 UnaryTrue& operator=(const UnaryTrue&) = default;
TEST_CONSTEXPR bool operator()(T) const { return true; }
};

template <class T>
struct NullaryValue {
int* copies_;
TEST_CONSTEXPR explicit NullaryValue(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 NullaryValue(const NullaryValue& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 NullaryValue& operator=(const NullaryValue&) = default;
TEST_CONSTEXPR T operator()() const { return 0; }
};

template <class T>
struct UnaryTransform {
int* copies_;
TEST_CONSTEXPR explicit UnaryTransform(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 UnaryTransform(const UnaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 UnaryTransform& operator=(const UnaryTransform&) = default;
TEST_CONSTEXPR T operator()(T) const { return 0; }
};

template <class T>
struct BinaryTransform {
int* copies_;
TEST_CONSTEXPR explicit BinaryTransform(int* copies) : copies_(copies) {}
TEST_CONSTEXPR_CXX14 BinaryTransform(const BinaryTransform& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
TEST_CONSTEXPR_CXX14 BinaryTransform& operator=(const BinaryTransform&) = default;
TEST_CONSTEXPR T operator()(T, T) const { return 0; }
};

#if TEST_STD_VER > 17
template <class T>
struct ThreeWay {
int* copies_;
constexpr explicit ThreeWay(int* copies) : copies_(copies) {}
constexpr ThreeWay(const ThreeWay& rhs) : copies_(rhs.copies_) { *copies_ += 1; }
constexpr ThreeWay& operator=(const ThreeWay&) = default;
constexpr std::strong_ordering operator()(T, T) const { return std::strong_ordering::equal; }
};
#endif

template <class T>
TEST_CONSTEXPR_CXX20 bool all_the_algorithms() {
T a[10] = {};
T b[10] = {};
T* first = a;
T* mid = a + 5;
T* last = a + 10;
T* first2 = b;
T* mid2 = b + 5;
T* last2 = b + 10;
T value = 0;
int count = 1;

int copies = 0;
(void)std::adjacent_find(first, last, Equal<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER >= 11
(void)std::all_of(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::any_of(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
#endif
(void)std::binary_search(first, last, value, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER > 17
(void)std::clamp(value, value, value, Less<T>(&copies));
assert(copies == 0);
#endif
(void)std::count_if(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::copy_if(first, last, first2, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::equal(first, last, first2, Equal<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER > 11
(void)std::equal(first, last, first2, last2, Equal<T>(&copies));
assert(copies == 0);
#endif
(void)std::equal_range(first, last, value, Less<T>(&copies));
assert(copies == 0);
(void)std::find_end(first, last, first2, mid2, Equal<T>(&copies));
assert(copies == 0);
(void)std::find_first_of(first, last, first2, last2, Equal<T>(&copies));
assert(copies == 0);
(void)std::find_if(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::find_if_not(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::for_each(first, last, UnaryVoid<T>(&copies));
assert(copies == 1);
copies = 0;
#if TEST_STD_VER > 14
(void)std::for_each_n(first, count, UnaryVoid<T>(&copies));
assert(copies == 0);
#endif
(void)std::generate(first, last, NullaryValue<T>(&copies));
assert(copies == 0);
(void)std::generate_n(first, count, NullaryValue<T>(&copies));
assert(copies == 0);
(void)std::includes(first, last, first2, last2, Less<T>(&copies));
assert(copies == 0);
(void)std::is_heap(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::is_heap_until(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::is_partitioned(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::is_permutation(first, last, first2, Equal<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER > 11
(void)std::is_permutation(first, last, first2, last2, Equal<T>(&copies));
assert(copies == 0);
#endif
(void)std::is_sorted(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::is_sorted_until(first, last, Less<T>(&copies));
assert(copies == 0);
if (!TEST_IS_CONSTANT_EVALUATED) {
(void)std::inplace_merge(first, mid, last, Less<T>(&copies));
assert(copies == 0);
}
(void)std::lexicographical_compare(first, last, first2, last2, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER > 17
(void)std::lexicographical_compare_three_way(first, last, first2, last2, ThreeWay<T>(&copies));
assert(copies == 0);
#endif
(void)std::lower_bound(first, last, value, Less<T>(&copies));
assert(copies == 0);
(void)std::make_heap(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::max(value, value, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER >= 11
(void)std::max({value, value}, Less<T>(&copies));
assert(copies == 0);
#endif
(void)std::max_element(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::merge(first, mid, mid, last, first2, Less<T>(&copies));
assert(copies == 0);
(void)std::min(value, value, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER >= 11
(void)std::min({value, value}, Less<T>(&copies));
assert(copies == 0);
#endif
(void)std::min_element(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::minmax(value, value, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER >= 11
(void)std::minmax({value, value}, Less<T>(&copies));
assert(copies == 0);
#endif
(void)std::minmax_element(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::mismatch(first, last, first2, Equal<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER > 11
(void)std::mismatch(first, last, first2, last2, Equal<T>(&copies));
assert(copies == 0);
#endif
(void)std::next_permutation(first, last, Less<T>(&copies));
assert(copies == 0);
#if TEST_STD_VER >= 11
(void)std::none_of(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
#endif
(void)std::nth_element(first, mid, last, Less<T>(&copies));
assert(copies == 0);
(void)std::partial_sort(first, mid, last, Less<T>(&copies));
assert(copies == 0);
(void)std::partial_sort_copy(first, last, first2, mid2, Less<T>(&copies));
assert(copies == 0);
(void)std::partition(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::partition_copy(first, last, first2, last2, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::partition_point(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::pop_heap(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::prev_permutation(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::push_heap(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::remove_copy_if(first, last, first2, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::remove_if(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
(void)std::replace_copy_if(first, last, first2, UnaryTrue<T>(&copies), value);
assert(copies == 0);
(void)std::replace_if(first, last, UnaryTrue<T>(&copies), value);
assert(copies == 0);
(void)std::search(first, last, first2, mid2, Equal<T>(&copies));
assert(copies == 0);
(void)std::search_n(first, last, count, value, Equal<T>(&copies));
assert(copies == 0);
(void)std::set_difference(first, mid, mid, last, first2, Less<T>(&copies));
assert(copies == 0);
(void)std::set_intersection(first, mid, mid, last, first2, Less<T>(&copies));
assert(copies == 0);
(void)std::set_symmetric_difference(first, mid, mid, last, first2, Less<T>(&copies));
assert(copies == 0);
(void)std::set_union(first, mid, mid, last, first2, Less<T>(&copies));
assert(copies == 0);
(void)std::sort(first, first + 3, Less<T>(&copies));
assert(copies == 0);
(void)std::sort(first, first + 4, Less<T>(&copies));
assert(copies == 0);
(void)std::sort(first, first + 5, Less<T>(&copies));
assert(copies == 0);
(void)std::sort(first, last, Less<T>(&copies));
assert(copies == 0);
(void)std::sort_heap(first, last, Less<T>(&copies));
assert(copies == 0);
if (!TEST_IS_CONSTANT_EVALUATED) {
(void)std::stable_partition(first, last, UnaryTrue<T>(&copies));
assert(copies == 0);
}
if (!TEST_IS_CONSTANT_EVALUATED) {
(void)std::stable_sort(first, last, Less<T>(&copies));
assert(copies == 0);
}
(void)std::transform(first, last, first2, UnaryTransform<T>(&copies));
assert(copies == 0);
(void)std::transform(first, mid, mid, first2, BinaryTransform<T>(&copies));
assert(copies == 0);
(void)std::unique(first, last, Equal<T>(&copies));
assert(copies == 0);
(void)std::unique_copy(first, last, first2, Equal<T>(&copies));
assert(copies == 0);
(void)std::upper_bound(first, last, value, Less<T>(&copies));
assert(copies == 0);

return true;
}

bool test_segmented_iterator() {
int copies = 0;
std::deque<int> dq(10);
(void)std::for_each(dq.begin(), dq.end(), UnaryVoid<int>(&copies));
assert(copies == 1);
copies = 0;

#if TEST_STD_VER >= 20
std::vector<std::vector<int>> vecs(3, std::vector<int>(10));
auto v = std::views::join(vecs);
(void)std::for_each(v.begin(), v.end(), UnaryVoid<int>(&copies));
assert(copies == 1);
copies = 0;
#endif

return true;
}

int main(int, char**) {
all_the_algorithms<void*>();
all_the_algorithms<int>();
assert(test_segmented_iterator());
#if TEST_STD_VER > 17
static_assert(all_the_algorithms<void*>());
static_assert(all_the_algorithms<int>());
#endif

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Check that all STL classic algorithms can be instantiated with a C++20-hostile iterator

// ADDITIONAL_COMPILE_FLAGS: -Wno-ambiguous-reversed-operator

#include <algorithm>
#include <functional>
#include <iterator>
#include <random>

#include "test_macros.h"

template <class Sub, class Iterator>
struct IteratorAdaptorBase {
using OutTraits = std::iterator_traits<Iterator>;
using iterator_category = typename OutTraits::iterator_category;
using value_type = typename OutTraits::value_type;
using pointer = typename OutTraits::pointer;
using reference = typename OutTraits::reference;
using difference_type = typename OutTraits::difference_type;

IteratorAdaptorBase() {}
IteratorAdaptorBase(Iterator) {}

Sub& sub() { return static_cast<Sub&>(*this); }
const Sub& sub() const { return static_cast<Sub&>(*this); }

const Iterator& base() const { return it_; }

reference get() const { return *it_; }
reference operator*() const { return *it_; }
pointer operator->() const { return it_; }
reference operator[](difference_type) const { return *it_; }

Sub& operator++() { return static_cast<Sub&>(*this); }
Sub& operator--() { return static_cast<Sub&>(*this); }
Sub operator++(int) { return static_cast<Sub&>(*this); }
Sub operator--(int) { return static_cast<Sub&>(*this); }

Sub& operator+=(difference_type) { return static_cast<Sub&>(*this); }
Sub& operator-=(difference_type) { return static_cast<Sub&>(*this); }
bool operator==(Sub) const { return false; }
bool operator!=(Sub) const { return false; }
bool operator==(Iterator b) const { return *this == Sub(b); }
bool operator!=(Iterator b) const { return *this != Sub(b); }

friend Sub operator+(Sub, difference_type) { return Sub(); }
friend Sub operator+(difference_type, Sub) { return Sub(); }
friend Sub operator-(Sub, difference_type) { return Sub(); }
friend difference_type operator-(Sub, Sub) { return 0; }

friend bool operator<(Sub, Sub) { return false; }
friend bool operator>(Sub, Sub) { return false; }
friend bool operator<=(Sub, Sub) { return false; }
friend bool operator>=(Sub, Sub) { return false; }

private:
Iterator it_;
};

template <typename It>
struct Cpp20HostileIterator
: IteratorAdaptorBase<Cpp20HostileIterator<It>, It> {
Cpp20HostileIterator() {}
Cpp20HostileIterator(It) {}
};

struct Pred {
bool operator()(int, int) const { return false; }
bool operator()(int) const { return false; }
int operator()() const { return 0; }
};

void test() {
Cpp20HostileIterator<int*> it;
Pred pred;
std::mt19937_64 rng;

(void) std::adjacent_find(it, it);
(void) std::adjacent_find(it, it, pred);
(void) std::all_of(it, it, pred);
(void) std::any_of(it, it, pred);
(void) std::binary_search(it, it, 0);
(void) std::binary_search(it, it, 0, pred);
(void) std::copy_backward(it, it, it);
(void) std::copy_if(it, it, it, pred);
(void) std::copy_n(it, 0, it);
(void) std::copy(it, it, it);
(void) std::count_if(it, it, pred);
(void) std::count(it, it, 0);
(void) std::equal_range(it, it, 0);
(void) std::equal_range(it, it, 0, pred);
(void) std::equal(it, it, it);
(void) std::equal(it, it, it, pred);
#if TEST_STD_VER > 11
(void) std::equal(it, it, it, it);
(void) std::equal(it, it, it, it, pred);
#endif
(void) std::fill_n(it, 0, 0);
(void) std::fill(it, it, 0);
(void) std::find_end(it, it, it, it);
(void) std::find_end(it, it, it, it, pred);
(void) std::find_first_of(it, it, it, it);
(void) std::find_first_of(it, it, it, it, pred);
(void) std::find_if_not(it, it, pred);
(void) std::find_if(it, it, pred);
(void) std::find(it, it, 0);
#if TEST_STD_VER > 14
(void) std::for_each_n(it, 0, pred);
#endif
(void) std::for_each(it, it, pred);
(void) std::generate_n(it, 0, pred);
(void) std::generate(it, it, pred);
(void) std::includes(it, it, it, it);
(void) std::includes(it, it, it, it, pred);
(void) std::inplace_merge(it, it, it);
(void) std::inplace_merge(it, it, it, pred);
(void) std::is_heap_until(it, it);
(void) std::is_heap_until(it, it, pred);
(void) std::is_heap(it, it);
(void) std::is_heap(it, it, pred);
(void) std::is_partitioned(it, it, pred);
(void) std::is_permutation(it, it, it);
(void) std::is_permutation(it, it, it, pred);
#if TEST_STD_VER > 11
(void) std::is_permutation(it, it, it, it);
(void) std::is_permutation(it, it, it, it, pred);
#endif
(void) std::is_sorted_until(it, it);
(void) std::is_sorted_until(it, it, pred);
(void) std::is_sorted(it, it);
(void) std::is_sorted(it, it, pred);
(void) std::lexicographical_compare(it, it, it, it);
(void) std::lexicographical_compare(it, it, it, it, pred);
#if TEST_STD_VER > 17
(void)std::lexicographical_compare_three_way(it, it, it, it);
(void)std::lexicographical_compare_three_way(it, it, it, it, std::compare_three_way());
#endif
(void) std::lower_bound(it, it, 0);
(void) std::lower_bound(it, it, 0, pred);
(void) std::make_heap(it, it);
(void) std::make_heap(it, it, pred);
(void) std::max_element(it, it);
(void) std::max_element(it, it, pred);
(void) std::merge(it, it, it, it, it);
(void) std::merge(it, it, it, it, it, pred);
(void) std::min_element(it, it);
(void) std::min_element(it, it, pred);
(void) std::minmax_element(it, it);
(void) std::minmax_element(it, it, pred);
(void) std::mismatch(it, it, it);
(void) std::mismatch(it, it, it, pred);
(void) std::move_backward(it, it, it);
(void) std::move(it, it, it);
(void) std::next_permutation(it, it);
(void) std::next_permutation(it, it, pred);
(void) std::none_of(it, it, pred);
(void) std::nth_element(it, it, it);
(void) std::nth_element(it, it, it, pred);
(void) std::partial_sort_copy(it, it, it, it);
(void) std::partial_sort_copy(it, it, it, it, pred);
(void) std::partial_sort(it, it, it);
(void) std::partial_sort(it, it, it, pred);
(void) std::partition_copy(it, it, it, it, pred);
(void) std::partition_point(it, it, pred);
(void) std::partition(it, it, pred);
(void) std::pop_heap(it, it);
(void) std::pop_heap(it, it, pred);
(void) std::prev_permutation(it, it);
(void) std::prev_permutation(it, it, pred);
(void) std::push_heap(it, it);
(void) std::push_heap(it, it, pred);
(void) std::remove_copy_if(it, it, it, pred);
(void) std::remove_copy(it, it, it, 0);
(void) std::remove_if(it, it, pred);
(void) std::remove(it, it, 0);
(void) std::replace_copy_if(it, it, it, pred, 0);
(void) std::replace_copy(it, it, it, 0, 0);
(void) std::replace_if(it, it, pred, 0);
(void) std::replace(it, it, 0, 0);
(void) std::reverse_copy(it, it, it);
(void) std::reverse(it, it);
(void) std::rotate_copy(it, it, it, it);
(void) std::rotate(it, it, it);
#if TEST_STD_VER > 14
(void) std::sample(it, it, it, 0, rng);
#endif
(void) std::search(it, it, it, it);
(void) std::search(it, it, it, it, pred);
#if TEST_STD_VER > 14
(void) std::search(it, it, std::default_searcher<Cpp20HostileIterator<int*>>(it, it));
#endif
(void) std::set_difference(it, it, it, it, it);
(void) std::set_difference(it, it, it, it, it, pred);
(void) std::set_intersection(it, it, it, it, it);
(void) std::set_intersection(it, it, it, it, it, pred);
(void) std::set_symmetric_difference(it, it, it, it, it);
(void) std::set_symmetric_difference(it, it, it, it, it, pred);
(void) std::set_union(it, it, it, it, it);
(void) std::set_union(it, it, it, it, it, pred);
#if TEST_STD_VER > 17
(void) std::shift_left(it, it, 0);
(void) std::shift_right(it, it, 0);
#endif
(void) std::shuffle(it, it, rng);
(void) std::sort_heap(it, it);
(void) std::sort_heap(it, it, pred);
(void) std::sort(it, it);
(void) std::sort(it, it, pred);
(void) std::stable_partition(it, it, pred);
(void) std::stable_sort(it, it);
(void) std::swap_ranges(it, it, it);
(void) std::transform(it, it, it, pred);
(void) std::transform(it, it, it, it, pred);
(void) std::unique_copy(it, it, it);
(void) std::unique(it, it);
(void) std::upper_bound(it, it, 0);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <iterator>

#include "test_macros.h"

template <class T>
struct Iterator {
using value_type = T;
using pointer = value_type*;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
struct reference {
T* ptr_;

reference(T* ptr) : ptr_(ptr) {}

friend bool operator<(reference a, reference b) { return *a.ptr_ < *b.ptr_; }
friend bool operator<(reference a, value_type const& b) { return *a.ptr_ < b; }
friend bool operator<(value_type const& a, reference b) { return a < *b.ptr_; }

operator T&() const;
};

Iterator& operator++() {
ptr_++;
return *this;
}

Iterator operator++(int) {
Iterator tmp = *this;
ptr_++;
return tmp;
}

friend bool operator==(Iterator const& a, Iterator const& b) { return a.ptr_ == b.ptr_; }
friend bool operator!=(Iterator const& a, Iterator const& b) { return !(a == b); }

reference operator*() const { return reference(ptr_); }

explicit Iterator(T* ptr) : ptr_(ptr) {}
Iterator() = default;
Iterator(Iterator const&) = default;
Iterator(Iterator&&) = default;

Iterator& operator=(Iterator const&) = default;
Iterator& operator=(Iterator&&) = default;

private:
T* ptr_;
};

int main(int, char**) {
int array[5] = {1, 2, 3, 4, 5};
Iterator<int> first(array);
Iterator<int> middle(array + 3);
Iterator<int> last(array + 5);
(void)std::binary_search(first, last, 3);
(void)std::equal_range(first, last, 3);
(void)std::includes(first, last, first, last);
(void)std::is_sorted_until(first, last);
(void)std::is_sorted(first, last);
(void)std::lexicographical_compare(first, last, first, last);
(void)std::lower_bound(first, last, 3);
(void)std::max_element(first, last);
(void)std::min_element(first, last);
(void)std::minmax_element(first, last);
(void)std::upper_bound(first, last, 3);

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// This compile-time customization requires cross-file macros, which doesn't work with modules.
// UNSUPPORTED: clang-modules-build

// Make sure that we can customize the verbose termination function at compile-time by
// defining _LIBCPP_VERBOSE_ABORT ourselves. Note that this does not have any
// deployment target requirements.

// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_VERBOSE_ABORT(...)=my_abort(__VA_ARGS__)

#include <cstdlib>

void my_abort(char const*, ...) {
std::exit(EXIT_SUCCESS);
}

int main(int, char**) {
_LIBCPP_VERBOSE_ABORT("%s", "message");
return EXIT_FAILURE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Test that we can set a custom verbose termination function at link-time.

// We flag uses of the verbose termination function in older dylibs at compile-time to avoid runtime
// failures when back-deploying.
// XFAIL: availability-verbose_abort-missing

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__verbose_abort>
#include <cstdlib>

void std::__libcpp_verbose_abort(char const*, ...) _NOEXCEPT { std::exit(EXIT_SUCCESS); }

int main(int, char**) {
std::__libcpp_verbose_abort("%s", "message");
return EXIT_FAILURE;
}
28 changes: 28 additions & 0 deletions libcxx/test/libcxx-03/assertions/default_verbose_abort.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Test that the default verbose termination function aborts the program.
// XFAIL: availability-verbose_abort-missing

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__verbose_abort>
#include <csignal>
#include <cstdlib>

void signal_handler(int signal) {
if (signal == SIGABRT)
std::_Exit(EXIT_SUCCESS);
std::_Exit(EXIT_FAILURE);
}

int main(int, char**) {
if (std::signal(SIGABRT, signal_handler) != SIG_ERR)
std::__libcpp_verbose_abort("%s", "foo");
return EXIT_FAILURE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// This test verifies that setting the hardening mode to a value that's not part of the predefined constants triggers
// a compile-time error.

// Modules build produces a different error ("Could not build module 'std'").
// UNSUPPORTED: clang-modules-build
// REQUIRES: verify-support

// Note that GCC doesn't support `-Wno-macro-redefined`.
// RUN: %{verify} -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=42
// Make sure that common cases of misuse produce readable errors. We deliberately disallow setting the hardening mode as
// if it were a boolean flag.
// RUN: %{verify} -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=0
// RUN: %{verify} -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE=1
// RUN: %{verify} -U_LIBCPP_HARDENING_MODE -D_LIBCPP_HARDENING_MODE

#include <cassert>

// expected-error@*:* {{_LIBCPP_HARDENING_MODE must be set to one of the following values: _LIBCPP_HARDENING_MODE_NONE, _LIBCPP_HARDENING_MODE_FAST, _LIBCPP_HARDENING_MODE_EXTENSIVE, _LIBCPP_HARDENING_MODE_DEBUG}}
32 changes: 32 additions & 0 deletions libcxx/test/libcxx-03/assertions/modes/none.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// This test checks that if no hardening mode is defined (i.e., in the unchecked mode), by default assertions aren't
// triggered.

// REQUIRES: libcpp-hardening-mode=none

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__assert>
#include <cassert>

bool executed_condition = false;
bool f() {
executed_condition = true;
return false;
}

int main(int, char**) {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(true, "Should not fire");
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(false, "Also should not fire");
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(f(), "Should not execute anything");
assert(!executed_condition); // Really make sure we did not execute anything.

return 0;
}
34 changes: 34 additions & 0 deletions libcxx/test/libcxx-03/assertions/single_expression.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Make sure that `_LIBCPP_ASSERT` and `_LIBCPP_ASSUME` are each a single expression.
// This is useful so we can use them in places that require an expression, such as
// in a constructor initializer list.

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__assert>
#include <cassert>

void f() {
int i = (_LIBCPP_ASSERT(true, "message"), 3);
assert(i == 3);
return _LIBCPP_ASSERT(true, "message");
}

void g() {
int i = (_LIBCPP_ASSUME(true), 3);
assert(i == 3);
return _LIBCPP_ASSUME(true);
}

int main(int, char**) {
f();
g();
return 0;
}
43 changes: 43 additions & 0 deletions libcxx/test/libcxx-03/atomics/atomics.flag/init_bool.pass.cpp
Original file line number Diff line number Diff line change
@@ -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
//
//===----------------------------------------------------------------------===//

// <atomic>

// struct atomic_flag

// TESTING EXTENSION atomic_flag(bool)

#include <atomic>
#include <cassert>

#include "test_macros.h"

#if TEST_STD_VER >= 11
// Ensure that static initialization happens; this is PR#37226
extern std::atomic_flag global;
struct X { X() { global.test_and_set(); }};
X x;
std::atomic_flag global{false};
#endif

int main(int, char**)
{
#if TEST_STD_VER >= 11
assert(global.test_and_set() == 1);
#endif
{
std::atomic_flag f(false);
assert(f.test_and_set() == 0);
}
{
std::atomic_flag f(true);
assert(f.test_and_set() == 1);
}

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// This test ensures that std::memory_order has the same size under all
// standard versions to make sure we're not breaking the ABI. This is
// relevant because std::memory_order is a scoped enumeration in C++20,
// but an unscoped enumeration pre-C++20.
//
// See PR40977 for details.

#include <atomic>
#include <type_traits>

#include "test_macros.h"


enum cpp17_memory_order {
cpp17_memory_order_relaxed, cpp17_memory_order_consume, cpp17_memory_order_acquire,
cpp17_memory_order_release, cpp17_memory_order_acq_rel, cpp17_memory_order_seq_cst
};

static_assert((std::is_same<std::underlying_type<cpp17_memory_order>::type,
std::underlying_type<std::memory_order>::type>::value),
"std::memory_order should have the same underlying type as a corresponding "
"unscoped enumeration would. Otherwise, our ABI changes from C++17 to C++20.");

int main(int, char**) {
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// 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: no-threads
// REQUIRES: c++03 || c++11 || c++14 || c++17 || c++20

// No diagnostic gets emitted when we build with modules.
// XFAIL: clang-modules-build

// This test ensures that we issue a reasonable diagnostic when including <atomic> after
// <stdatomic.h> has been included. Before C++23, this otherwise leads to obscure errors
// because <atomic> may try to redefine things defined by <stdatomic.h>.

// Ignore additional weird errors that happen when the two headers are mixed.
// ADDITIONAL_COMPILE_FLAGS: -Xclang -verify-ignore-unexpected=error -Xclang -verify-ignore-unexpected=warning

#include <stdatomic.h>
#include <atomic>

// expected-error@*:* {{<atomic> is incompatible with <stdatomic.h> before C++23.}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

// <atomic>

// template <class T>
// T* atomic_fetch_add(volatile atomic<T*>* obj, ptrdiff_t op)
// template <class T>
// T* atomic_fetch_add(atomic<T*>* obj, ptrdiff_t op);

#include <atomic>

void void_pointer() {
{
volatile std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_add(&obj, 0);
}
{
std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_add(&obj, 0);
}
}

struct Incomplete;

void pointer_to_incomplete_type() {
{
volatile std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_add(&obj, 0);
}
{
std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_add(&obj, 0);
}
}

void function_pointer() {
{
volatile std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_add(&fun, 0);
}
{
std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_add(&fun, 0);
}
}

struct S {
void fun(int);
};

void member_function_pointer() {
{
volatile std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_add'}}
std::atomic_fetch_add(&fun, 0);
}
{
std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_add'}}
std::atomic_fetch_add(&fun, 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

// <atomic>

// template <class T>
// T*
// atomic_fetch_add_explicit(volatile atomic<T*>* obj, ptrdiff_t op,
// memory_order m);
// template <class T>
// T*
// atomic_fetch_add_explicit(atomic<T*>* obj, ptrdiff_t op, memory_order m);

#include <atomic>

void void_pointer() {
{
volatile std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed);
}
{
std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed);
}
}

struct Incomplete;

void pointer_to_incomplete_type() {
{
volatile std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed);
}
{
std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_add_explicit(&obj, 0, std::memory_order_relaxed);
}
}

void function_pointer() {
{
volatile std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed);
}
{
std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed);
}
}

struct S {
void fun(int);
};

void member_function_pointer() {
{
volatile std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_add_explicit'}}
std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed);
}
{
std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_add_explicit'}}
std::atomic_fetch_add_explicit(&fun, 0, std::memory_order_relaxed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

// <atomic>

// template <class T>
// T* atomic_fetch_sub(volatile atomic<T*>* obj, ptrdiff_t op)
// template <class T>
// T* atomic_fetch_sub(atomic<T*>* obj, ptrdiff_t op);

#include <atomic>

void void_pointer() {
{
volatile std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_sub(&obj, 0);
}
{
std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_sub(&obj, 0);
}
}

struct Incomplete;

void pointer_to_incomplete_type() {
{
volatile std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_sub(&obj, 0);
}
{
std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_sub(&obj, 0);
}
}

void function_pointer() {
{
volatile std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_sub(&fun, 0);
}
{
std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_sub(&fun, 0);
}
}

struct S {
void fun(int);
};

void member_function_pointer() {
{
volatile std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_sub'}}
std::atomic_fetch_sub(&fun, 0);
}
{
std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_sub'}}
std::atomic_fetch_sub(&fun, 0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

// <atomic>

// template <class T>
// T*
// atomic_fetch_sub_explicit(volatile atomic<T*>* obj, ptrdiff_t op,
// memory_order m);
// template <class T>
// T*
// atomic_fetch_sub_explicit(atomic<T*>* obj, ptrdiff_t op, memory_order m);

#include <atomic>

void void_pointer() {
{
volatile std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed);
}
{
std::atomic<void*> obj;
// expected-error@*:* {{incomplete type 'void' where a complete type is required}}
std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed);
}
}

struct Incomplete;

void pointer_to_incomplete_type() {
{
volatile std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed);
}
{
std::atomic<Incomplete*> obj;
// expected-error@*:* {{incomplete type 'Incomplete' where a complete type is required}}
std::atomic_fetch_sub_explicit(&obj, 0, std::memory_order_relaxed);
}
}

void function_pointer() {
{
volatile std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed);
}
{
std::atomic<void (*)(int)> fun;
// expected-error-re@*:* {{static assertion failed due to requirement '!is_function<void (int)>::value'{{.*}}Pointer to function isn't allowed}}
std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed);
}
}

struct S {
void fun(int);
};

void member_function_pointer() {
{
volatile std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_sub_explicit'}}
std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed);
}
{
std::atomic<void (S::*)(int)> fun;
// expected-error@*:* {{no matching function for call to 'atomic_fetch_sub_explicit'}}
std::atomic_fetch_sub_explicit(&fun, 0, std::memory_order_relaxed);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//===----------------------------------------------------------------------===//
//
// 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: diagnose-if-support

// <atomic>

// Test that invalid memory order arguments are diagnosed where possible.

#include <atomic>

void f() {
std::atomic<int> x(42);
volatile std::atomic<int>& vx = x;
int val1 = 1; ((void)val1);
int val2 = 2; ((void)val2);
// load operations
{
x.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
x.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.load(std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.load(std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
x.load(std::memory_order_relaxed);
x.load(std::memory_order_consume);
x.load(std::memory_order_acquire);
x.load(std::memory_order_seq_cst);
}
{
std::atomic_load_explicit(&x, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_load_explicit(&x, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_load_explicit(&vx, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_load_explicit(&vx, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
std::atomic_load_explicit(&x, std::memory_order_relaxed);
std::atomic_load_explicit(&x, std::memory_order_consume);
std::atomic_load_explicit(&x, std::memory_order_acquire);
std::atomic_load_explicit(&x, std::memory_order_seq_cst);
}
// store operations
{
x.store(42, std::memory_order_consume); // expected-warning {{memory order argument to atomic operation is invalid}}
x.store(42, std::memory_order_acquire); // expected-warning {{memory order argument to atomic operation is invalid}}
x.store(42, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.store(42, std::memory_order_consume); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.store(42, std::memory_order_acquire); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.store(42, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
x.store(42, std::memory_order_relaxed);
x.store(42, std::memory_order_release);
x.store(42, std::memory_order_seq_cst);
}
{
std::atomic_store_explicit(&x, 42, std::memory_order_consume); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_store_explicit(&x, 42, std::memory_order_acquire); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_store_explicit(&x, 42, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_store_explicit(&vx, 42, std::memory_order_consume); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_store_explicit(&vx, 42, std::memory_order_acquire); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_store_explicit(&vx, 42, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
std::atomic_store_explicit(&x, 42, std::memory_order_relaxed);
std::atomic_store_explicit(&x, 42, std::memory_order_release);
std::atomic_store_explicit(&x, 42, std::memory_order_seq_cst);
}
// compare exchange weak
{
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_relaxed);
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_consume);
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_acquire);
x.compare_exchange_weak(val1, val2, std::memory_order_seq_cst, std::memory_order_seq_cst);
// Test that the cmpxchg overload with only one memory order argument
// does not generate any diagnostics.
x.compare_exchange_weak(val1, val2, std::memory_order_release);
}
{
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_weak_explicit(&vx, &val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_weak_explicit(&vx, &val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_relaxed);
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_consume);
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_acquire);
std::atomic_compare_exchange_weak_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_seq_cst);
}
// compare exchange strong
{
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
vx.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_relaxed);
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_consume);
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_acquire);
x.compare_exchange_strong(val1, val2, std::memory_order_seq_cst, std::memory_order_seq_cst);
// Test that the cmpxchg overload with only one memory order argument
// does not generate any diagnostics.
x.compare_exchange_strong(val1, val2, std::memory_order_release);
}
{
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_strong_explicit(&vx, &val1, val2, std::memory_order_seq_cst, std::memory_order_release); // expected-warning {{memory order argument to atomic operation is invalid}}
std::atomic_compare_exchange_strong_explicit(&vx, &val1, val2, std::memory_order_seq_cst, std::memory_order_acq_rel); // expected-warning {{memory order argument to atomic operation is invalid}}
// valid memory orders
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_relaxed);
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_consume);
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_acquire);
std::atomic_compare_exchange_strong_explicit(&x, &val1, val2, std::memory_order_seq_cst, std::memory_order_seq_cst);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===----------------------------------------------------------------------===//
//
// 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: no-threads

// This test ensures that we don't hijack the <stdatomic.h> header (e.g. by providing
// an empty header) even when compiling before C++23, since some users were using the
// Clang or platform provided header before libc++ added its own.

// On GCC, the compiler-provided <stdatomic.h> is not C++ friendly, so including <stdatomic.h>
// doesn't work at all if we don't use the <stdatomic.h> provided by libc++ in C++23 and above.
// XFAIL: (c++11 || c++14 || c++17 || c++20) && gcc

#include <stdatomic.h>

void f() {
atomic_int i; // just make sure the header isn't empty
(void)i;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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: no-threads

// This test verifies that <stdatomic.h> DOES NOT redirect to <atomic> before C++23,
// since doing so is a breaking change. Several things can break when that happens,
// because the type of _Atomic(T) changes from _Atomic(T) to std::atomic<T>.
//
// For example, redeclarations can become invalid depending on whether they
// have been declared with <stdatomic.h> in scope or not.

// REQUIRES: c++03 || c++11 || c++14 || c++17 || c++20

// On GCC, the compiler-provided <stdatomic.h> is not C++ friendly, so including <stdatomic.h>
// doesn't work at all if we don't use the <stdatomic.h> provided by libc++ in C++23 and above.
// XFAIL: (c++11 || c++14 || c++17 || c++20) && gcc

#include <atomic>
#include <stdatomic.h>
#include <type_traits>

static_assert(!std::is_same<_Atomic(int), std::atomic<int> >::value, "");
97 changes: 97 additions & 0 deletions libcxx/test/libcxx-03/clang_modules_include.gen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# ===----------------------------------------------------------------------===##
#
# 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
#
# ===----------------------------------------------------------------------===##

# Test that we can include each header in a TU while using modules.
# This is important notably because the LLDB data formatters use
# libc++ headers with modules enabled.

# RUN: %{python} %s %{libcxx-dir}/utils

# 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,
)

for header in public_headers:
print(
f"""\
//--- {header}.compile.pass.cpp
// RUN: %{{cxx}} %s %{{flags}} %{{compile_flags}} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only
// Older macOS SDKs were not properly modularized, which causes issues with localization.
// This feature should instead be based on the SDK version.
// UNSUPPORTED: stdlib=system && target={{{{.+}}}}-apple-macosx13{{{{.*}}}}
// GCC doesn't support -fcxx-modules
// UNSUPPORTED: gcc
// The Windows headers don't appear to be compatible with modules
// UNSUPPORTED: windows
// UNSUPPORTED: buildhost=windows
// The Android headers don't appear to be compatible with modules yet
// UNSUPPORTED: LIBCXX-ANDROID-FIXME
// TODO: Investigate this failure
// UNSUPPORTED: LIBCXX-FREEBSD-FIXME
// TODO: Investigate why this doesn't work on Picolibc once the locale base API is refactored
// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
// TODO: Fix seemingly circular inclusion or <wchar.h> on AIX
// UNSUPPORTED: LIBCXX-AIX-FIXME
// UNSUPPORTED: FROZEN-CXX03-HEADERS-FIXME
{lit_header_restrictions.get(header, '')}
{lit_header_undeprecations.get(header, '')}
#include <{header}>
"""
)

print(
f"""\
//--- import_std.compile.pass.mm
// RUN: %{{cxx}} %s %{{flags}} %{{compile_flags}} -fmodules -fcxx-modules -fmodules-cache-path=%t -fsyntax-only
// REQUIRES: clang-modules-build
// Older macOS SDKs were not properly modularized, which causes issues with localization.
// This feature should instead be based on the SDK version.
// UNSUPPORTED: stdlib=system && target={{{{.+}}}}-apple-macosx13{{{{.*}}}}
// GCC doesn't support -fcxx-modules
// UNSUPPORTED: gcc
// The Windows headers don't appear to be compatible with modules
// UNSUPPORTED: windows
// UNSUPPORTED: buildhost=windows
// The Android headers don't appear to be compatible with modules yet
// UNSUPPORTED: LIBCXX-ANDROID-FIXME
// TODO: Investigate this failure
// UNSUPPORTED: LIBCXX-FREEBSD-FIXME
// TODO: Investigate why this doesn't work on Picolibc once the locale base API is refactored
// UNSUPPORTED: LIBCXX-PICOLIBC-FIXME
// TODO: Fix seemingly circular inclusion or <wchar.h> on AIX
// UNSUPPORTED: LIBCXX-AIX-FIXME
@import std;
"""
)
40 changes: 40 additions & 0 deletions libcxx/test/libcxx-03/clang_tidy.gen.py
Original file line number Diff line number Diff line change
@@ -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
#
# ===----------------------------------------------------------------------===##


# Run our custom libc++ clang-tidy checks on all public headers.

# RUN: %{python} %s %{libcxx-dir}/utils

# 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

for header in public_headers:
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.
// UNSUPPORTED: FROZEN-CXX03-HEADERS-FIXME
// The GCC compiler flags are not always compatible with clang-tidy.
// UNSUPPORTED: gcc
{lit_header_restrictions.get(header, '')}
{lit_header_undeprecations.get(header, '')}
// 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}>
""")
11 changes: 11 additions & 0 deletions libcxx/test/libcxx-03/clang_tidy.sh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# ===----------------------------------------------------------------------===##
#
# 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: has-clang-tidy

# RUN: %{python} %{libcxx-dir}/../clang-tools-extra/clang-tidy/tool/run-clang-tidy.py -clang-tidy-binary %{clang-tidy} -warnings-as-errors "*" -source-filter=".*libcxx/src.*" -quiet -p %{bin-dir}/..
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <map>

// class map

// mapped_type& at(const key_type& k);

// Make sure we abort() when exceptions are disabled and we fetch a key that
// is not in the map.

// REQUIRES: no-exceptions

#include <csignal>
#include <cstdlib>
#include <map>

#include "test_macros.h"

void exit_success(int) { std::_Exit(EXIT_SUCCESS); }

int main(int, char**) {
std::signal(SIGABRT, exit_success);
std::map<int, int> map;
map.at(1);
return EXIT_FAILURE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <map>

// class map

// const mapped_type& at(const key_type& k) const;

// Make sure we abort() when exceptions are disabled and we fetch a key that
// is not in the map.

// REQUIRES: no-exceptions

#include <csignal>
#include <cstdlib>
#include <map>

#include "test_macros.h"

void exit_success(int) { std::_Exit(EXIT_SUCCESS); }

int main(int, char**) {
std::signal(SIGABRT, exit_success);
std::map<int, int> const map;
map.at(1);
return EXIT_FAILURE;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Make sure that we don't get a compiler error when trying to use std::map::find
// from Objective-C++. This happened in Objective-C++ mode with modules enabled (rdar://106813461).

// REQUIRES: objective-c++

#include <map>

void f(std::map<int, int> const& map, int key) { (void)map.find(key); }
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <map>

// class map
// class multimap

// Extension: SCARY/N2913 iterator compatibility between map and multimap

#include <map>

#include "test_macros.h"

void test() {
typedef std::map<int, int> M1;
typedef std::multimap<int, int> M2;

ASSERT_SAME_TYPE(M1::iterator, M2::iterator);
ASSERT_SAME_TYPE(M1::const_iterator, M2::const_iterator);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Pin down the ABI of associative containers with respect to their size and alignment
// when passed a comparator that is a reference.
//
// While it's not even clear that reference comparators are legal in containers, an
// unintended ABI break was discovered after implementing the new compressed pair
// mechanism based on [[no_unique_address]], and this is a regression test for that.
// If we decide to make reference comparators ill-formed, this test would become
// unnecessary.
//
// See https://github.com/llvm/llvm-project/issues/118559 for more details.

#include <set>
#include <map>

#include "test_macros.h"

struct TEST_ALIGNAS(16) Cmp {
bool operator()(int, int) const;
};

template <class Compare>
struct Set {
char b;
std::set<int, Compare> s;
};

template <class Compare>
struct Multiset {
char b;
std::multiset<int, Compare> s;
};

template <class Compare>
struct Map {
char b;
std::map<int, char, Compare> s;
};

template <class Compare>
struct Multimap {
char b;
std::multimap<int, char, Compare> s;
};

static_assert(sizeof(Set<Cmp&>) == sizeof(Set<bool (*)(int, int)>), "");
static_assert(sizeof(Multiset<Cmp&>) == sizeof(Multiset<bool (*)(int, int)>), "");

static_assert(sizeof(Map<Cmp&>) == sizeof(Map<bool (*)(int, int)>), "");
static_assert(sizeof(Multimap<Cmp&>) == sizeof(Multimap<bool (*)(int, int)>), "");
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <set>

// class set
// class multiset

// Extension: SCARY/N2913 iterator compatibility between set and multiset

#include <set>

#include "test_macros.h"

void test() {
typedef std::set<int> M1;
typedef std::multiset<int> M2;

ASSERT_SAME_TYPE(M1::iterator, M2::iterator);
ASSERT_SAME_TYPE(M1::const_iterator, M2::const_iterator);
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__tree>
#include <map>
#include <set>
#include <type_traits>

#include "test_macros.h"
#include "min_allocator.h"

void testKeyValueTrait() {
{
typedef int Tp;
typedef std::__tree_key_value_types<Tp> Traits;
static_assert((std::is_same<Traits::key_type, int>::value), "");
static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
static_assert(Traits::__is_map == false, "");
}
{
typedef std::pair<int, int> Tp;
typedef std::__tree_key_value_types<Tp> Traits;
static_assert((std::is_same<Traits::key_type, Tp>::value), "");
static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
static_assert(Traits::__is_map == false, "");
}
{
typedef std::pair<const int, int> Tp;
typedef std::__tree_key_value_types<Tp> Traits;
static_assert((std::is_same<Traits::key_type, Tp>::value), "");
static_assert((std::is_same<Traits::__container_value_type, Tp>::value), "");
static_assert(Traits::__is_map == false, "");
}
{
typedef std::__value_type<int, int> Tp;
typedef std::__tree_key_value_types<Tp> Traits;
static_assert((std::is_same<Traits::key_type, int>::value), "");
static_assert((std::is_same<Traits::mapped_type, int>::value), "");
static_assert((std::is_same<Traits::__container_value_type, std::pair<const int, int> >::value), "");
static_assert((std::is_same<Traits::__map_value_type, std::pair<const int, int> >::value), "");
static_assert(Traits::__is_map == true, "");
}
}

int main(int, char**) {
testKeyValueTrait();

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Not a portable test

// Precondition: __x->__right_ != nullptr
// template <class _NodePtr>
// void
// __tree_left_rotate(_NodePtr __x);

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__tree>
#include <cassert>

#include "test_macros.h"

struct Node {
Node* __left_;
Node* __right_;
Node* __parent_;

Node* __parent_unsafe() const { return __parent_; }
void __set_parent(Node* x) { __parent_ = x; }

Node() : __left_(), __right_(), __parent_() {}
};

void test1() {
Node root;
Node x;
Node y;
root.__left_ = &x;
x.__left_ = 0;
x.__right_ = &y;
x.__parent_ = &root;
y.__left_ = 0;
y.__right_ = 0;
y.__parent_ = &x;
std::__tree_left_rotate(&x);
assert(root.__parent_ == 0);
assert(root.__left_ == &y);
assert(root.__right_ == 0);
assert(y.__parent_ == &root);
assert(y.__left_ == &x);
assert(y.__right_ == 0);
assert(x.__parent_ == &y);
assert(x.__left_ == 0);
assert(x.__right_ == 0);
}

void test2() {
Node root;
Node x;
Node y;
Node a;
Node b;
Node c;
root.__left_ = &x;
x.__left_ = &a;
x.__right_ = &y;
x.__parent_ = &root;
y.__left_ = &b;
y.__right_ = &c;
y.__parent_ = &x;
a.__parent_ = &x;
b.__parent_ = &y;
c.__parent_ = &y;
std::__tree_left_rotate(&x);
assert(root.__parent_ == 0);
assert(root.__left_ == &y);
assert(root.__right_ == 0);
assert(y.__parent_ == &root);
assert(y.__left_ == &x);
assert(y.__right_ == &c);
assert(x.__parent_ == &y);
assert(x.__left_ == &a);
assert(x.__right_ == &b);
assert(a.__parent_ == &x);
assert(a.__left_ == 0);
assert(a.__right_ == 0);
assert(b.__parent_ == &x);
assert(b.__left_ == 0);
assert(b.__right_ == 0);
assert(c.__parent_ == &y);
assert(c.__left_ == 0);
assert(c.__right_ == 0);
}

int main(int, char**) {
test1();
test2();

return 0;
}
1,646 changes: 1,646 additions & 0 deletions libcxx/test/libcxx-03/containers/associative/tree_remove.pass.cpp

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// Not a portable test

// Precondition: __x->__left_ != nullptr
// template <class _NodePtr>
// void
// __tree_right_rotate(_NodePtr __x);

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__tree>
#include <cassert>

#include "test_macros.h"

struct Node {
Node* __left_;
Node* __right_;
Node* __parent_;

Node* __parent_unsafe() const { return __parent_; }
void __set_parent(Node* x) { __parent_ = x; }

Node() : __left_(), __right_(), __parent_() {}
};

void test1() {
Node root;
Node x;
Node y;
root.__left_ = &x;
x.__left_ = &y;
x.__right_ = 0;
x.__parent_ = &root;
y.__left_ = 0;
y.__right_ = 0;
y.__parent_ = &x;
std::__tree_right_rotate(&x);
assert(root.__parent_ == 0);
assert(root.__left_ == &y);
assert(root.__right_ == 0);
assert(y.__parent_ == &root);
assert(y.__left_ == 0);
assert(y.__right_ == &x);
assert(x.__parent_ == &y);
assert(x.__left_ == 0);
assert(x.__right_ == 0);
}

void test2() {
Node root;
Node x;
Node y;
Node a;
Node b;
Node c;
root.__left_ = &x;
x.__left_ = &y;
x.__right_ = &c;
x.__parent_ = &root;
y.__left_ = &a;
y.__right_ = &b;
y.__parent_ = &x;
a.__parent_ = &y;
b.__parent_ = &y;
c.__parent_ = &x;
std::__tree_right_rotate(&x);
assert(root.__parent_ == 0);
assert(root.__left_ == &y);
assert(root.__right_ == 0);
assert(y.__parent_ == &root);
assert(y.__left_ == &a);
assert(y.__right_ == &x);
assert(x.__parent_ == &y);
assert(x.__left_ == &b);
assert(x.__right_ == &c);
assert(a.__parent_ == &y);
assert(a.__left_ == 0);
assert(a.__right_ == 0);
assert(b.__parent_ == &x);
assert(b.__left_ == 0);
assert(b.__right_ == 0);
assert(c.__parent_ == &x);
assert(c.__left_ == 0);
assert(c.__right_ == 0);
}

int main(int, char**) {
test1();
test2();

return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//===----------------------------------------------------------------------===//
//
// 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: libcpp-has-abi-fix-unordered-container-size-type, libcpp-abi-no-compressed-pair-padding

// std::unique_ptr is used as an implementation detail of the unordered containers, so the layout of
// unordered containers changes when bounded unique_ptr is enabled.
// UNSUPPORTED: libcpp-has-abi-bounded-unique_ptr

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <cstdint>
#include <unordered_map>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

template <class T>
class small_pointer {
std::uint16_t offset;
};

template <class T>
class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

template <class T>
class final_small_iter_allocator final {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

final_small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
final_small_iter_allocator(final_small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(final_small_iter_allocator, final_small_iter_allocator) { return true; }
friend bool operator!=(final_small_iter_allocator, final_small_iter_allocator) { return false; }
};

template <class T, class Alloc>
using unordered_map_alloc = std::unordered_map<T, T, std::hash<T>, std::equal_to<T>, Alloc>;

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(unordered_map_alloc<int, std::allocator<std::pair<const int, int> > >) == 40, "");
static_assert(sizeof(unordered_map_alloc<int, min_allocator<std::pair<const int, int> > >) == 40, "");
static_assert(sizeof(unordered_map_alloc<int, test_allocator<std::pair<const int, int> > >) == 64, "");
static_assert(sizeof(unordered_map_alloc<int, small_iter_allocator<std::pair<const int, int> > >) == 12, "");
static_assert(sizeof(unordered_map_alloc<int, final_small_iter_allocator<std::pair<const int, int> > >) == 16, "");

static_assert(sizeof(unordered_map_alloc<char, std::allocator<std::pair<const char, char> > >) == 40, "");
static_assert(sizeof(unordered_map_alloc<char, min_allocator<std::pair<const char, char> > >) == 40, "");
static_assert(sizeof(unordered_map_alloc<char, test_allocator<std::pair<const char, char> > >) == 64, "");
static_assert(sizeof(unordered_map_alloc<char, small_iter_allocator<std::pair<const char, char> > >) == 12, "");
static_assert(sizeof(unordered_map_alloc<char, final_small_iter_allocator<std::pair<const char, char> > >) == 16, "");

static_assert(TEST_ALIGNOF(unordered_map_alloc<int, std::allocator<std::pair<const int, int> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, min_allocator<std::pair<const int, int> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, test_allocator<std::pair<const int, int> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, small_iter_allocator<std::pair<const int, int> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, final_small_iter_allocator<std::pair<const int, int> > >) == 4, "");

static_assert(TEST_ALIGNOF(unordered_map_alloc<char, std::allocator<std::pair<const char, char> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, min_allocator<std::pair<const char, char> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, test_allocator<std::pair<const char, char> > >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, small_iter_allocator<std::pair<const char, char> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, final_small_iter_allocator<std::pair<const char, char> > >) == 4,
"");

struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};

// This part of the ABI has been broken between LLVM 19 and LLVM 20.
static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 64, "");
static_assert(TEST_ALIGNOF(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 32, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(unordered_map_alloc<int, std::allocator<std::pair<const int, int> > >) == 20, "");
static_assert(sizeof(unordered_map_alloc<int, min_allocator<std::pair<const int, int> > >) == 20, "");
static_assert(sizeof(unordered_map_alloc<int, test_allocator<std::pair<const int, int> > >) == 44, "");
static_assert(sizeof(unordered_map_alloc<int, small_iter_allocator<std::pair<const int, int> > >) == 12, "");
static_assert(sizeof(unordered_map_alloc<int, final_small_iter_allocator<std::pair<const int, int> > >) == 16, "");

static_assert(sizeof(unordered_map_alloc<char, std::allocator<std::pair<const char, char> > >) == 20, "");
static_assert(sizeof(unordered_map_alloc<char, min_allocator<std::pair<const char, char> > >) == 20, "");
static_assert(sizeof(unordered_map_alloc<char, test_allocator<std::pair<const char, char> > >) == 44, "");
static_assert(sizeof(unordered_map_alloc<char, small_iter_allocator<std::pair<const char, char> > >) == 12, "");
static_assert(sizeof(unordered_map_alloc<char, final_small_iter_allocator<std::pair<const char, char> > >) == 16, "");

static_assert(TEST_ALIGNOF(unordered_map_alloc<int, std::allocator<std::pair<const int, int> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, min_allocator<std::pair<const int, int> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, test_allocator<std::pair<const int, int> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, small_iter_allocator<std::pair<const int, int> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<int, final_small_iter_allocator<std::pair<const int, int> > >) == 4, "");

static_assert(TEST_ALIGNOF(unordered_map_alloc<char, std::allocator<std::pair<const char, char> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, min_allocator<std::pair<const char, char> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, test_allocator<std::pair<const char, char> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, small_iter_allocator<std::pair<const char, char> > >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_map_alloc<char, final_small_iter_allocator<std::pair<const char, char> > >) == 4,
"");

struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};

static_assert(sizeof(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 64);
static_assert(TEST_ALIGNOF(std::unordered_map<int, int, AlignedHash, UnalignedEqualTo>) == 32);

#else
# error std::size_t has an unexpected size
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <unordered_map>

// class unordered_map
// class unordered_multimap

// Extension: SCARY/N2913 iterator compatibility between unordered_map and unordered_multimap

#include <unordered_map>

#include "test_macros.h"

void test() {
typedef std::unordered_map<int, int> M1;
typedef std::unordered_multimap<int, int> M2;

ASSERT_SAME_TYPE(M1::iterator, M2::iterator);
ASSERT_SAME_TYPE(M1::const_iterator, M2::const_iterator);
ASSERT_SAME_TYPE(M1::local_iterator, M2::local_iterator);
ASSERT_SAME_TYPE(M1::const_local_iterator, M2::const_local_iterator);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
//===----------------------------------------------------------------------===//
//
// 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: libcpp-has-abi-fix-unordered-container-size-type, libcpp-abi-no-compressed-pair-padding

// std::unique_ptr is used as an implementation detail of the unordered containers, so the layout of
// unordered containers changes when bounded unique_ptr is enabled.
// UNSUPPORTED: libcpp-has-abi-bounded-unique_ptr

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <cstdint>
#include <unordered_set>

#include "min_allocator.h"
#include "test_allocator.h"
#include "test_macros.h"

template <class T>
class small_pointer {
std::uint16_t offset;
};

template <class T>
class small_iter_allocator {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
small_iter_allocator(small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(small_iter_allocator, small_iter_allocator) { return true; }
friend bool operator!=(small_iter_allocator, small_iter_allocator) { return false; }
};

template <class T>
class final_small_iter_allocator final {
public:
using value_type = T;
using pointer = small_pointer<T>;
using size_type = std::uint16_t;
using difference_type = std::int16_t;

final_small_iter_allocator() TEST_NOEXCEPT {}

template <class U>
final_small_iter_allocator(final_small_iter_allocator<U>) TEST_NOEXCEPT {}

T* allocate(std::size_t n);
void deallocate(T* p, std::size_t);

friend bool operator==(final_small_iter_allocator, final_small_iter_allocator) { return true; }
friend bool operator!=(final_small_iter_allocator, final_small_iter_allocator) { return false; }
};

template <class T, class Alloc>
using unordered_set_alloc = std::unordered_set<T, std::hash<T>, std::equal_to<T>, Alloc>;

#if __SIZE_WIDTH__ == 64

static_assert(sizeof(unordered_set_alloc<int, std::allocator<int> >) == 40, "");
static_assert(sizeof(unordered_set_alloc<int, min_allocator<int> >) == 40, "");
static_assert(sizeof(unordered_set_alloc<int, test_allocator<int> >) == 64, "");
static_assert(sizeof(unordered_set_alloc<int, small_iter_allocator<int> >) == 12, "");
static_assert(sizeof(unordered_set_alloc<int, final_small_iter_allocator<int> >) == 16, "");

static_assert(sizeof(unordered_set_alloc<char, std::allocator<char> >) == 40, "");
static_assert(sizeof(unordered_set_alloc<char, min_allocator<char> >) == 40, "");
static_assert(sizeof(unordered_set_alloc<char, test_allocator<char> >) == 64, "");
static_assert(sizeof(unordered_set_alloc<char, small_iter_allocator<char> >) == 12, "");
static_assert(sizeof(unordered_set_alloc<char, final_small_iter_allocator<char> >) == 16, "");

static_assert(TEST_ALIGNOF(unordered_set_alloc<int, std::allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, min_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, test_allocator<int> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, small_iter_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, final_small_iter_allocator<int> >) == 4, "");

static_assert(TEST_ALIGNOF(unordered_set_alloc<char, std::allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, min_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, test_allocator<char> >) == 8, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, small_iter_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, final_small_iter_allocator<char> >) == 4, "");

struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};

// This part of the ABI has been broken between LLVM 19 and LLVM 20.
static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 64, "");
static_assert(TEST_ALIGNOF(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 32, "");

#elif __SIZE_WIDTH__ == 32

static_assert(sizeof(unordered_set_alloc<int, std::allocator<int> >) == 20, "");
static_assert(sizeof(unordered_set_alloc<int, min_allocator<int> >) == 20, "");
static_assert(sizeof(unordered_set_alloc<int, test_allocator<int> >) == 44, "");
static_assert(sizeof(unordered_set_alloc<int, small_iter_allocator<int> >) == 12, "");
static_assert(sizeof(unordered_set_alloc<int, final_small_iter_allocator<int> >) == 16, "");

static_assert(sizeof(unordered_set_alloc<char, std::allocator<char> >) == 20, "");
static_assert(sizeof(unordered_set_alloc<char, min_allocator<char> >) == 20, "");
static_assert(sizeof(unordered_set_alloc<char, test_allocator<char> >) == 44, "");
static_assert(sizeof(unordered_set_alloc<char, small_iter_allocator<char> >) == 12, "");
static_assert(sizeof(unordered_set_alloc<char, final_small_iter_allocator<char> >) == 16, "");

static_assert(TEST_ALIGNOF(unordered_set_alloc<int, std::allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, min_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, test_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, small_iter_allocator<int> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<int, final_small_iter_allocator<int> >) == 4, "");

static_assert(TEST_ALIGNOF(unordered_set_alloc<char, std::allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, min_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, test_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, small_iter_allocator<char> >) == 4, "");
static_assert(TEST_ALIGNOF(unordered_set_alloc<char, final_small_iter_allocator<char> >) == 4, "");

struct TEST_ALIGNAS(32) AlignedHash {};
struct UnalignedEqualTo {};

static_assert(sizeof(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 64);
static_assert(TEST_ALIGNOF(std::unordered_set<int, AlignedHash, UnalignedEqualTo>) == 32);

#else
# error std::size_t has an unexpected size
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//

// <unordered_set>

// class unordered_set
// class unordered_multiset

// Extension: SCARY/N2913 iterator compatibility between unordered_set and unordered_multiset

#include <unordered_set>

#include "test_macros.h"

void test() {
typedef std::unordered_set<int> M1;
typedef std::unordered_multiset<int> M2;

ASSERT_SAME_TYPE(M1::iterator, M2::iterator);
ASSERT_SAME_TYPE(M1::const_iterator, M2::const_iterator);
ASSERT_SAME_TYPE(M1::local_iterator, M2::local_iterator);
ASSERT_SAME_TYPE(M1::const_local_iterator, M2::const_local_iterator);
}
165 changes: 165 additions & 0 deletions libcxx/test/libcxx-03/containers/container_traits.compile.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// <__type_traits/container_traits.h>
//

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <__type_traits/container_traits.h>

#include <deque>
#include <forward_list>
#include <list>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

#include "test_allocator.h"
#include "test_macros.h"
#include "MoveOnly.h"

struct ThrowOnMove {
ThrowOnMove();
ThrowOnMove(const ThrowOnMove&) TEST_NOEXCEPT_COND(false);
ThrowOnMove(ThrowOnMove&&) TEST_NOEXCEPT_COND(false);
ThrowOnMove& operator=(ThrowOnMove&&) TEST_NOEXCEPT_COND(false);
ThrowOnMove& operator=(const ThrowOnMove&) TEST_NOEXCEPT_COND(false);

bool operator<(ThrowOnMove const&) const;
bool operator==(ThrowOnMove const&) const;
};

struct NonCopyThrowOnMove {
NonCopyThrowOnMove();
NonCopyThrowOnMove(NonCopyThrowOnMove&&) TEST_NOEXCEPT_COND(false);
NonCopyThrowOnMove(const NonCopyThrowOnMove&) = delete;
NonCopyThrowOnMove& operator=(NonCopyThrowOnMove&&) TEST_NOEXCEPT_COND(false);
NonCopyThrowOnMove& operator=(const NonCopyThrowOnMove&) = delete;

bool operator<(NonCopyThrowOnMove const&) const;
bool operator==(NonCopyThrowOnMove const&) const;
};

struct ThrowingHash {
template <class T>
std::size_t operator()(const T&) const TEST_NOEXCEPT_COND(false);
};

struct NoThrowHash {
template <class T>
std::size_t operator()(const T&) const TEST_NOEXCEPT;
};

template <bool Expected, class Container>
void check() {
static_assert(
std::__container_traits<Container>::__emplacement_has_strong_exception_safety_guarantee == Expected, "");
}

void test() {
check<true, std::list<int> >();
check<true, std::list<int, test_allocator<int> > >();
check<true, std::list<MoveOnly> >();
check<true, std::list<ThrowOnMove> >();
check<true, std::list<NonCopyThrowOnMove> >();

check<true, std::forward_list<int> >();
check<true, std::forward_list<int, test_allocator<int> > >();
check<true, std::forward_list<MoveOnly> >();
check<true, std::forward_list<ThrowOnMove> >();
check<true, std::forward_list<NonCopyThrowOnMove> >();

check<true, std::deque<int> >();
check<true, std::deque<int, test_allocator<int> > >();
check<true, std::deque<MoveOnly> >();
check<true, std::deque<ThrowOnMove> >();
check<false, std::deque<NonCopyThrowOnMove> >();

check<true, std::vector<int> >();
check<true, std::vector<int, test_allocator<int> > >();
check<true, std::vector<MoveOnly> >();
check<true, std::vector<ThrowOnMove> >();
check<false, std::vector<NonCopyThrowOnMove> >();

check<true, std::set<int> >();
check<true, std::set<int, std::less<int>, test_allocator<int> > >();
check<true, std::set<MoveOnly> >();
check<true, std::set<ThrowOnMove> >();
check<true, std::set<NonCopyThrowOnMove> >();

check<true, std::multiset<int> >();
check<true, std::multiset<int, std::less<int>, test_allocator<int> > >();
check<true, std::multiset<MoveOnly> >();
check<true, std::multiset<ThrowOnMove> >();
check<true, std::multiset<NonCopyThrowOnMove> >();

check<true, std::map<int, int> >();
check<true, std::map<int, int, std::less<int>, test_allocator<int> > >();
check<true, std::map<MoveOnly, MoveOnly> >();
check<true, std::map<ThrowOnMove, ThrowOnMove> >();
check<true, std::map<NonCopyThrowOnMove, NonCopyThrowOnMove> >();

check<true, std::multimap<int, int> >();
check<true, std::multimap<int, int, std::less<int>, test_allocator<int> > >();
check<true, std::multimap<MoveOnly, MoveOnly> >();
check<true, std::multimap<ThrowOnMove, ThrowOnMove> >();
check<true, std::multimap<NonCopyThrowOnMove, NonCopyThrowOnMove> >();

#if TEST_STD_VER < 11
check<false, std::unordered_set<int> >();
check<false, std::unordered_set<int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_set<MoveOnly> >();
check<false, std::unordered_set<MoveOnly, NoThrowHash> >();
check<false, std::unordered_set<MoveOnly, ThrowingHash> >();

check<false, std::unordered_multiset<int> >();
check<false, std::unordered_multiset<int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_multiset<MoveOnly> >();
check<false, std::unordered_multiset<MoveOnly, NoThrowHash> >();
check<false, std::unordered_multiset<MoveOnly, ThrowingHash> >();

check<false, std::unordered_map<int, int> >();
check<false, std::unordered_map<int, int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_map<MoveOnly, MoveOnly> >();
check<false, std::unordered_map<MoveOnly, MoveOnly, NoThrowHash> >();
check<false, std::unordered_map<MoveOnly, MoveOnly, ThrowingHash> >();

check<false, std::unordered_multimap<int, int> >();
check<false, std::unordered_multimap<int, int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_multimap<MoveOnly, MoveOnly> >();
check<false, std::unordered_multimap<MoveOnly, MoveOnly, NoThrowHash> >();
check<false, std::unordered_multimap<MoveOnly, MoveOnly, ThrowingHash> >();
#else
check<true, std::unordered_set<int> >();
check<true, std::unordered_set<int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_set<MoveOnly> >();
check<true, std::unordered_set<MoveOnly, NoThrowHash> >();
check<false, std::unordered_set<MoveOnly, ThrowingHash> >();

check<true, std::unordered_multiset<int> >();
check<true, std::unordered_multiset<int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_multiset<MoveOnly> >();
check<true, std::unordered_multiset<MoveOnly, NoThrowHash> >();
check<false, std::unordered_multiset<MoveOnly, ThrowingHash> >();

check<true, std::unordered_map<int, int> >();
check<true, std::unordered_map<int, int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_map<MoveOnly, MoveOnly> >();
check<true, std::unordered_map<MoveOnly, MoveOnly, NoThrowHash> >();
check<false, std::unordered_map<MoveOnly, MoveOnly, ThrowingHash> >();

check<true, std::unordered_multimap<int, int> >();
check<true, std::unordered_multimap<int, int, std::hash<int>, std::less<int>, test_allocator<int> > >();
check<false, std::unordered_multimap<MoveOnly, MoveOnly> >();
check<true, std::unordered_multimap<MoveOnly, MoveOnly, NoThrowHash> >();
check<false, std::unordered_multimap<MoveOnly, MoveOnly, ThrowingHash> >();
#endif
}
36 changes: 36 additions & 0 deletions libcxx/test/libcxx-03/containers/gnu_cxx/hash_map.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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: clang-modules-build

// Prevent <ext/hash_map> from generating deprecated warnings for this test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated

#include <ext/hash_map>
#include <cassert>

#include "test_macros.h"
#include "count_new.h"

void test_default_does_not_allocate() {
DisableAllocationGuard g;
((void)g);
{
__gnu_cxx::hash_map<int, int> h;
assert(h.bucket_count() == 0);
}
{
__gnu_cxx::hash_multimap<int, int> h;
assert(h.bucket_count() == 0);
}
}

int main(int, char**) {
test_default_does_not_allocate();
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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: clang-modules-build

// Poison the std:: names we might use inside __gnu_cxx to ensure they're
// properly qualified.
struct allocator;
struct pair;
struct equal_to;
struct unique_ptr;

// Prevent <ext/hash_map> from generating deprecated warnings for this test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated

#include <ext/hash_map>

#include "test_macros.h"

namespace __gnu_cxx {
template class hash_map<int, int>;
}

int main(int, char**) {
typedef __gnu_cxx::hash_map<int, int> Map;
Map m;
Map m2(m);
((void)m2);

return 0;
}
36 changes: 36 additions & 0 deletions libcxx/test/libcxx-03/containers/gnu_cxx/hash_set.pass.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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: clang-modules-build

// Prevent <ext/hash_set> from generating deprecated warnings for this test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated

#include <ext/hash_set>
#include <cassert>

#include "test_macros.h"
#include "count_new.h"

void test_default_does_not_allocate() {
DisableAllocationGuard g;
((void)g);
{
__gnu_cxx::hash_set<int> h;
assert(h.bucket_count() == 0);
}
{
__gnu_cxx::hash_multiset<int> h;
assert(h.bucket_count() == 0);
}
}

int main(int, char**) {
test_default_does_not_allocate();
return 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//===----------------------------------------------------------------------===//
//
// 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: clang-modules-build

// Poison the std:: names we might use inside __gnu_cxx to ensure they're
// properly qualified.
struct allocator;
struct pair;
struct equal_to;
struct unique_ptr;

// Prevent <ext/hash_set> from generating deprecated warnings for this test.
// ADDITIONAL_COMPILE_FLAGS: -Wno-deprecated

#include <ext/hash_set>

#include "test_macros.h"

namespace __gnu_cxx {
template class hash_set<int>;
}

int main(int, char**) {
typedef __gnu_cxx::hash_set<int> Set;
Set s;
Set s2(s);
((void)s2);

return 0;
}
Original file line number Diff line number Diff line change
@@ -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
//
//===----------------------------------------------------------------------===//

// Make sure std::array<T, N> is trivially copyable whenever T is trivially copyable.
// This is not technically mandated by the Standard, but libc++ has been providing
// this property.

#include <array>
#include <type_traits>

struct Empty {};

struct TrivialCopy {
int i;
double j;
};

struct NonTrivialCopy {
NonTrivialCopy(NonTrivialCopy const&) {}
NonTrivialCopy& operator=(NonTrivialCopy const&) { return *this; }
};

template <typename T>
void check_trivially_copyable() {
static_assert(std::is_trivially_copyable<std::array<T, 0> >::value, "");
static_assert(std::is_trivially_copyable<std::array<T, 1> >::value, "");
static_assert(std::is_trivially_copyable<std::array<T, 2> >::value, "");
static_assert(std::is_trivially_copyable<std::array<T, 3> >::value, "");
}

int main(int, char**) {
check_trivially_copyable<int>();
check_trivially_copyable<long>();
check_trivially_copyable<double>();
check_trivially_copyable<long double>();
check_trivially_copyable<Empty>();
check_trivially_copyable<TrivialCopy>();

// Check that std::array<T, 0> is still trivially copyable when T is not
static_assert(std::is_trivially_copyable<std::array<NonTrivialCopy, 0> >::value, "");
static_assert(!std::is_trivially_copyable<std::array<NonTrivialCopy, 1> >::value, "");
static_assert(!std::is_trivially_copyable<std::array<NonTrivialCopy, 2> >::value, "");
static_assert(!std::is_trivially_copyable<std::array<NonTrivialCopy, 3> >::value, "");

return 0;
}
Loading