Louis Dionne 6929bd6d00 [libc++] Add UNSUPPORTED for clang-14 since the underlying bug hasn't been fixed yet
This started breaking in the CI because we bumped the Clang version to 14,
which requires adjusting the markup in the test suite. I think it's actually
nice the we need to do that and that it doesn't happen automatically, since
it serves as a reminder that this is broken in Clang.
2021-07-28 16:41:22 -04:00

134 lines
3.6 KiB
C++

//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// Triggers a Clang assertion: https://bugs.llvm.org/show_bug.cgi?id=45879
// UNSUPPORTED: clang-13, clang-14
// <tuple>
// template <class... Types> class tuple;
// template <class... UTypes>
// tuple& operator=(const tuple<UTypes...>& u);
// UNSUPPORTED: c++03
#include <tuple>
#include <string>
#include <cassert>
#include "test_macros.h"
struct B {
int id_;
constexpr explicit B(int i = 0) : id_(i) {}
};
struct D : B {
constexpr explicit D(int i = 0) : B(i) {}
};
struct NonAssignable {
NonAssignable& operator=(NonAssignable const&) = delete;
NonAssignable& operator=(NonAssignable&&) = delete;
};
struct NothrowCopyAssignable {
NothrowCopyAssignable& operator=(NothrowCopyAssignable const&) noexcept { return *this; }
};
struct PotentiallyThrowingCopyAssignable {
PotentiallyThrowingCopyAssignable& operator=(PotentiallyThrowingCopyAssignable const&) { return *this; }
};
TEST_CONSTEXPR_CXX20
bool test()
{
{
typedef std::tuple<long> T0;
typedef std::tuple<long long> T1;
T0 t0(2);
T1 t1;
t1 = t0;
assert(std::get<0>(t1) == 2);
}
{
typedef std::tuple<long, char> T0;
typedef std::tuple<long long, int> T1;
T0 t0(2, 'a');
T1 t1;
t1 = t0;
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == int('a'));
}
{
typedef std::tuple<long, char, D> T0;
typedef std::tuple<long long, int, B> T1;
T0 t0(2, 'a', D(3));
T1 t1;
t1 = t0;
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1).id_ == 3);
}
{
D d(3);
D d2(2);
typedef std::tuple<long, char, D&> T0;
typedef std::tuple<long long, int, B&> T1;
T0 t0(2, 'a', d2);
T1 t1(1, 'b', d);
t1 = t0;
assert(std::get<0>(t1) == 2);
assert(std::get<1>(t1) == int('a'));
assert(std::get<2>(t1).id_ == 2);
}
{
// Test that tuple evaluates correctly applies an lvalue reference
// before evaluating is_assignable (i.e. 'is_assignable<int&, int&>')
// instead of evaluating 'is_assignable<int&&, int&>' which is false.
int x = 42;
int y = 43;
std::tuple<int&&> t(std::move(x));
std::tuple<int&> t2(y);
t = t2;
assert(std::get<0>(t) == 43);
assert(&std::get<0>(t) == &x);
}
return true;
}
int main(int, char**)
{
test();
#if TEST_STD_VER >= 20
static_assert(test());
#endif
{
using T = std::tuple<int, NonAssignable>;
using U = std::tuple<NonAssignable, int>;
static_assert(!std::is_assignable<T&, U const&>::value, "");
static_assert(!std::is_assignable<U&, T const&>::value, "");
}
{
typedef std::tuple<NothrowCopyAssignable, long> T0;
typedef std::tuple<NothrowCopyAssignable, int> T1;
static_assert(std::is_nothrow_assignable<T0&, T1 const&>::value, "");
}
{
typedef std::tuple<PotentiallyThrowingCopyAssignable, long> T0;
typedef std::tuple<PotentiallyThrowingCopyAssignable, int> T1;
static_assert(std::is_assignable<T0&, T1 const&>::value, "");
static_assert(!std::is_nothrow_assignable<T0&, T1 const&>::value, "");
}
return 0;
}