// { dg-options "-std=gnu++20" }
// { dg-do compile { target c++20 } }
#include <type_traits>

#ifndef __cpp_lib_is_layout_compatible
# error "Feature test macro for is_layout_compatible is missing in <type_traits>"
#elif __cpp_lib_is_layout_compatible < 201907L
# error "Feature test macro for is_layout_compatible has wrong value in <type_traits>"
#endif

template<typename T, typename U>
concept variable_template_is_correct
  = std::is_layout_compatible_v<T, U> == std::is_layout_compatible<T, U>::value;

template<typename T, typename U>
requires variable_template_is_correct<T, U>
constexpr bool is_layout_compatible = std::is_layout_compatible_v<T, U>;

static_assert( is_layout_compatible<void, void> );
static_assert( is_layout_compatible<int, int> );
static_assert( ! is_layout_compatible<int, int[]> );
static_assert( ! is_layout_compatible<int, int[1]> );
static_assert( is_layout_compatible<int[], int[]> );
static_assert( is_layout_compatible<int[1], int[1]> );
static_assert( ! is_layout_compatible<int[1], int[]> );
static_assert( ! is_layout_compatible<int[1], int[2]> );

struct Incomplete;
// The standard says these are undefined, but they should work really:
// static_assert( is_layout_compatible<Incomplete, Incomplete> );
// static_assert( ! is_layout_compatible<Incomplete[], Incomplete> );
static_assert( is_layout_compatible<Incomplete[], Incomplete[]> );

enum E1 : int { };
enum E2 : int;
static_assert( is_layout_compatible<E1, E2> );
enum E3 : unsigned int;
static_assert( ! is_layout_compatible<E1, E3> );
enum E4 : char { };
enum E5 : signed char { };
enum E6 : unsigned char { };
static_assert( ! is_layout_compatible<E4, E5> );
static_assert( ! is_layout_compatible<E4, E6> );
static_assert( ! is_layout_compatible<E5, E6> );

struct A { int a; };
struct B { const int b; };
static_assert( is_layout_compatible<A, B> );
static_assert( is_layout_compatible<B, A> );

struct C : A { };
struct D : B { };
static_assert( is_layout_compatible<C, D> );

struct E : A { int i; }; // not standard-layout
static_assert( ! is_layout_compatible<E, A> );
