blob: 28ab56fa32b9146aff18557572fef1b62023f5b0 [file] [log] [blame]
// { dg-do run { target c++26 } }
// { dg-require-atomic-cmpxchg-word "" }
// { dg-add-options libatomic }
#include <atomic>
#include <testsuite_hooks.h>
struct X
{
X() = default;
X(int i) : i(i) { }
int i;
friend bool
operator==(X, X) = default;
};
template<typename T>
void testTemporary()
{
static_assert( !std::is_constructible_v<std::atomic_ref<T>, T> );
static_assert( !std::is_constructible_v<std::atomic_ref<const T>, T> );
static_assert( !std::is_constructible_v<std::atomic_ref<T>, const T> );
static_assert( !std::is_constructible_v<std::atomic_ref<const T>, const T> );
if constexpr (std::atomic_ref<T>::is_always_lock_free)
{
static_assert( !std::is_constructible_v<std::atomic_ref<volatile T>, T> );
static_assert( !std::is_constructible_v<std::atomic_ref<volatile T>, volatile T> );
static_assert( !std::is_constructible_v<std::atomic_ref<const volatile T>, T> );
static_assert( !std::is_constructible_v<std::atomic_ref<const volatile T>, const volatile T> );
}
struct X { X(T) {} };
struct Overload
{
static int operator()(X) { return 1; }
static int operator()(std::atomic_ref<T>) { return 2; }
};
VERIFY( Overload{}(T()) == 1 );
static_assert( !requires { Overload{}({T()}); } );
}
template<typename T>
bool same_address(const std::atomic_ref<T>& t, const std::type_identity_t<T>& u)
{
#if (__cplusplus > 202302L)
return t.address() == &u;
#endif
return true;
}
template<typename From, typename To = From>
void
testConv()
{
alignas(std::atomic_ref<From>::required_alignment) From val{};
std::atomic_ref<From> src(val);
std::atomic_ref<const From> csrc(val);
std::atomic_ref<const To> d1(src);
VERIFY( same_address(d1, val) );
std::atomic_ref<const To> d2(csrc);
VERIFY( same_address(d2, val) );
static_assert( !std::is_convertible_v<std::atomic_ref<const From>,
std::atomic_ref<To>> );
if constexpr (std::atomic_ref<From>::is_always_lock_free)
{
std::atomic_ref<const volatile To> d4(src);
VERIFY( same_address(d4, val) );
std::atomic_ref<const volatile To> d5(csrc);
VERIFY( same_address(d5, val) );
if constexpr (std::is_same_v<From, To>)
{
std::atomic_ref<volatile To> d3(src);
VERIFY( same_address(d3, val) );
}
static_assert( !std::is_convertible_v<std::atomic_ref<volatile From>,
std::atomic_ref<To>> );
static_assert( !std::is_convertible_v<std::atomic_ref<volatile From>,
std::atomic_ref<const To>> );
static_assert( !std::is_convertible_v<std::atomic_ref<const volatile From>,
std::atomic_ref<To>> );
static_assert( !std::is_convertible_v<std::atomic_ref<const volatile From>,
std::atomic_ref<const To>> );
}
}
template<typename From, typename To>
void
testSimilarConv()
{
testConv<From, To>();
static_assert( !std::is_convertible_v< To, From> );
static_assert( !std::is_convertible_v< To, const From> );
static_assert( !std::is_convertible_v<const To, From> );
static_assert( !std::is_convertible_v<const To, const From> );
if constexpr (std::atomic_ref<From>::is_always_lock_free)
{
static_assert( !std::is_convertible_v<volatile To, From> );
static_assert( !std::is_convertible_v< To, volatile From> );
static_assert( !std::is_convertible_v<volatile To, volatile From> );
static_assert( !std::is_convertible_v<const volatile To, From> );
static_assert( !std::is_convertible_v< To, const volatile From> );
static_assert( !std::is_convertible_v<const volatile To, const volatile From> );
static_assert( !std::is_convertible_v< To, volatile From> );
static_assert( !std::is_convertible_v<const To, volatile From> );
static_assert( !std::is_convertible_v< To, const volatile From> );
static_assert( !std::is_convertible_v<const To, const volatile From> );
static_assert( !std::is_convertible_v<volatile To, From> );
static_assert( !std::is_convertible_v<volatile To, const From> );
static_assert( !std::is_convertible_v<const volatile To, From> );
static_assert( !std::is_convertible_v<const volatile To, const From> );
}
}
template<typename T, template<typename> typename MakePtr = std::add_pointer_t>
void
testPtrConv()
{
testConv<MakePtr<T>>();
testSimilarConv<MakePtr<T>, MakePtr<const T>>();
testSimilarConv<MakePtr<T*>, MakePtr<const T* const>>();
testSimilarConv<MakePtr<const T*>, MakePtr<const T* const>>();
testSimilarConv<MakePtr<T* const>, MakePtr<const T* const>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<const T[2]>>();
testSimilarConv<MakePtr<T[]>, MakePtr<const T[]>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<T[]>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<const T[]>>();
testSimilarConv<MakePtr<const T[2]>, MakePtr<const T[]>>();
if constexpr (std::atomic_ref<MakePtr<T>>::is_always_lock_free)
{
testSimilarConv<MakePtr<T>, MakePtr<volatile T>>();
testSimilarConv<MakePtr<T>, MakePtr<const volatile T>>();
testSimilarConv<MakePtr<volatile T>, MakePtr<const volatile T>>();
testSimilarConv<MakePtr<T*>, MakePtr<volatile T* const>>();
testSimilarConv<MakePtr<volatile T*>, MakePtr<volatile T* const>>();
testSimilarConv<MakePtr<T*>, MakePtr<const volatile T* const>>();
testSimilarConv<MakePtr<volatile T*>, MakePtr<const volatile T* const>>();
testSimilarConv<MakePtr<volatile T* const>, MakePtr<const volatile T* const>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<volatile T[2]>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<const volatile T[2]>>();
testSimilarConv<MakePtr<const T[2]>, MakePtr<const volatile T[2]>>();
testSimilarConv<MakePtr<volatile T[2]>, MakePtr<const volatile T[2]>>();
testSimilarConv<MakePtr<T[]>, MakePtr<volatile T[]>>();
testSimilarConv<MakePtr<T[]>, MakePtr<const volatile T[]>>();
testSimilarConv<MakePtr<const T[]>, MakePtr<const volatile T[]>>();
testSimilarConv<MakePtr<volatile T[]>, MakePtr<const volatile T[]>>();
testSimilarConv<MakePtr<T[2]>, MakePtr<volatile T[]>>();
testSimilarConv<MakePtr<volatile T[2]>, MakePtr<volatile T[]>>();
testSimilarConv<MakePtr<const T[2]>, MakePtr<const volatile T[]>>();
testSimilarConv<MakePtr<volatile T[2]>, MakePtr<const volatile T[]>>();
testSimilarConv<MakePtr<const volatile T[2]>, MakePtr<const volatile T[]>>();
}
}
struct D : X {};
static_assert( !std::is_convertible_v<std::atomic_ref<D>, std::atomic_ref<X>> );
static_assert( !std::is_convertible_v<std::atomic_ref<D>, std::atomic_ref<const X>> );
static_assert( !std::is_convertible_v<std::atomic_ref<D*>, std::atomic_ref<const X* const>> );
static_assert( !std::is_convertible_v<std::atomic_ref<const D*>, std::atomic_ref<const X* const>> );
template<typename T>
using member_pointer_t = T X::*;
int
main()
{
testTemporary<bool>();
testTemporary<int>();
testTemporary<float>();
testTemporary<int*>();
testTemporary<X>();
testConv<bool>();
testConv<int>();
testConv<float>();
testConv<X>();
testPtrConv<int>();
testPtrConv<int, member_pointer_t>();
}