(root)/
gcc-13.2.0/
gcc/
testsuite/
g++.dg/
ext/
is_convertible1.C
// PR c++/106784
// { dg-do compile { target c++11 } }

#define SA(X) static_assert((X),#X)

template<typename From, typename To>
struct is_convertible {
  static const bool value = __is_convertible(From, To);
};

struct from_int {
  from_int(int);
};

struct from_charp {
  from_charp(const char *);
};

struct to_int {
  operator int();
};

typedef int Fn(int);
typedef char Arr[10];
enum E { XYZZY };

SA(!__is_convertible(int, void));
SA(__is_convertible(int, int));
SA(__is_convertible(int, from_int));
SA(__is_convertible(long, from_int));
SA(__is_convertible(double, from_int));
SA(__is_convertible(const int, from_int));
SA(__is_convertible(const int&, from_int));
SA(__is_convertible(to_int, int));
SA(__is_convertible(to_int, const int&));
SA(__is_convertible(to_int, long));
SA(!__is_convertible(to_int, int&));
SA(!__is_convertible(to_int, from_int));
SA(!__is_convertible(int, Fn));
SA(!__is_convertible(int, Fn*));
SA(!__is_convertible(int, Fn&));
SA(!__is_convertible(int, Arr));
SA(!__is_convertible(int, Arr&));
SA(!__is_convertible(int, int&));
SA(__is_convertible(int, const int&));
SA(!__is_convertible(const int, int&));
SA(__is_convertible(const int, const int&));
SA(!__is_convertible(int, int*));

SA(!__is_convertible(int, E));
SA(__is_convertible(E, int));

SA(__is_convertible(int&, int));
SA(__is_convertible(int&, int&));
SA(__is_convertible(int&, const int&));
SA(!__is_convertible(const int&, int&));
SA(__is_convertible(const int&, const int&));
SA(!__is_convertible(int&, int*));
SA(!__is_convertible(int&, void));
SA(!__is_convertible(int&, Fn));
SA(!__is_convertible(int&, Fn*));
SA(!__is_convertible(int&, Fn&));
SA(!__is_convertible(int&, Arr));
SA(!__is_convertible(int&, Arr&));

SA(!__is_convertible(int*, int));
SA(!__is_convertible(int*, int&));
SA(!__is_convertible(int*, void));
SA(__is_convertible(int*, int*));
SA(__is_convertible(int*, const int*));
SA(!__is_convertible(const int*, int*));
SA(__is_convertible(const int*, const int*));
SA(!__is_convertible(int*, Fn));
SA(!__is_convertible(int*, Fn*));
SA(!__is_convertible(int*, Fn&));
SA(!__is_convertible(int*, Arr));
SA(!__is_convertible(int*, Arr&));
SA(!__is_convertible(int*, float*));

SA(__is_convertible(void, void));
SA(!__is_convertible(void, char));
SA(!__is_convertible(void, char&));
SA(!__is_convertible(void, char*));
SA(!__is_convertible(char, void));
SA(__is_convertible(const void, void));
SA(__is_convertible(void, const void));
SA(__is_convertible(const void, const void));
SA(!__is_convertible(void, Fn));
SA(!__is_convertible(void, Fn&));
SA(!__is_convertible(void, Fn*));
SA(!__is_convertible(void, Arr));
SA(!__is_convertible(void, Arr&));

SA(!__is_convertible(Fn, void));
SA(!__is_convertible(Fn, Fn));
SA(__is_convertible(Fn, Fn*));
SA(__is_convertible(Fn, Fn&));
SA(!__is_convertible(int(int), int(int)));
SA(__is_convertible(int(int), int(&)(int)));
SA(__is_convertible(int(int), int(&&)(int)));
SA(__is_convertible(int(int), int(*)(int)));
SA(__is_convertible(int(int), int(*const)(int)));
SA(!__is_convertible(int(int), char));
SA(!__is_convertible(int(int), char*));
SA(!__is_convertible(int(int), char&));

SA(!__is_convertible(Fn&, void));
SA(!__is_convertible(Fn&, Fn));
SA(__is_convertible(Fn&, Fn&));
SA(__is_convertible(Fn&, Fn*));
SA(!__is_convertible(Fn&, Arr));
SA(!__is_convertible(Fn&, Arr&));
SA(!__is_convertible(Fn&, char));
SA(!__is_convertible(Fn&, char&));
SA(!__is_convertible(Fn&, char*));

SA(!__is_convertible(Fn*, void));
SA(!__is_convertible(Fn*, Fn));
SA(!__is_convertible(Fn*, Fn&));
SA(__is_convertible(Fn*, Fn*));
SA(!__is_convertible(Fn*, Arr));
SA(!__is_convertible(Fn*, Arr&));
SA(!__is_convertible(Fn*, char));
SA(!__is_convertible(Fn*, char&));
SA(!__is_convertible(Fn*, char*));

SA(!__is_convertible(Arr, void));
SA(!__is_convertible(Arr, Fn));
SA(!__is_convertible(Arr, Fn*));
SA(!__is_convertible(Arr, Fn&));
SA(!__is_convertible(Arr, Arr));
SA(!__is_convertible(Arr, Arr&));
SA(__is_convertible(Arr, const Arr&));
SA(!__is_convertible(Arr, volatile Arr&));
SA(!__is_convertible(Arr, const volatile Arr&));
SA(!__is_convertible(const Arr, Arr&));
SA(__is_convertible(const Arr, const Arr&));
SA(__is_convertible(Arr, Arr&&));
SA(__is_convertible(Arr, const Arr&&));
SA(__is_convertible(Arr, volatile Arr&&));
SA(__is_convertible(Arr, const volatile Arr&&));
SA(__is_convertible(const Arr, const Arr&&));
SA(!__is_convertible(Arr&, Arr&&));
SA(!__is_convertible(Arr&&, Arr&));
SA(!__is_convertible(Arr, char));
SA(__is_convertible(Arr, char*));
SA(__is_convertible(Arr, const char*));
SA(!__is_convertible(Arr, char&));
SA(!__is_convertible(const Arr, char*));
SA(__is_convertible(const Arr, const char*));
SA(!__is_convertible(int, int[1]));
SA(!__is_convertible(int[1], int[1]));
SA(!__is_convertible(int[1], int(&)[1]));
SA(__is_convertible(int(&)[1], int(&)[1]));
SA(__is_convertible(int(&)[1], const int(&)[1]));
SA(!__is_convertible(const int(&)[1], int(&)[1]));
SA(!__is_convertible(int[1][1], int*));
SA(!__is_convertible(int[][1], int*));

SA(!__is_convertible(Arr&, void));
SA(!__is_convertible(Arr&, Fn));
SA(!__is_convertible(Arr&, Fn*));
SA(!__is_convertible(Arr&, Fn&));
SA(!__is_convertible(Arr&, Arr));
SA(__is_convertible(Arr&, Arr&));
SA(__is_convertible(Arr&, const Arr&));
SA(!__is_convertible(const Arr&, Arr&));
SA(__is_convertible(const Arr&, const Arr&));
SA(!__is_convertible(Arr&, char));
SA(__is_convertible(Arr&, char*));
SA(__is_convertible(Arr&, const char*));
SA(!__is_convertible(Arr&, char&));
SA(!__is_convertible(const Arr&, char*));
SA(__is_convertible(const Arr&, const char*));
SA(__is_convertible(Arr, from_charp));
SA(__is_convertible(Arr&, from_charp));

struct B { };
struct D : B { };

SA(__is_convertible(D, B));
SA(__is_convertible(D*, B*));
SA(__is_convertible(D&, B&));
SA(!__is_convertible(B, D));
SA(!__is_convertible(B*, D*));
SA(!__is_convertible(B&, D&));

/* These are taken from LLVM's test/SemaCXX/type-traits.cpp.  */

struct I {
  int i;
  I(int _i) : i(_i) { }
  operator int() const {
    return i;
  }
};

struct F
{
  float f;
  F(float _f) : f(_f) {}
  F(const I& obj)
    : f(static_cast<float>(obj.i)) {}
  operator float() const {
    return f;
  }
  operator I() const {
    return I(static_cast<int>(f));
  }
};

SA(__is_convertible(I, I));
SA(__is_convertible(I, const I));
SA(__is_convertible(I, int));
SA(__is_convertible(int, I));
SA(__is_convertible(I, F));
SA(__is_convertible(F, I));
SA(__is_convertible(F, float));
SA(__is_convertible(float, F));

template<typename>
struct X {
  template<typename U> X(const X<U>&);
};

SA(__is_convertible(X<int>, X<float>));
SA(__is_convertible(X<float>, X<int>));

struct Abstract {
  virtual void f() = 0;
};

SA(!__is_convertible(Abstract, Abstract));

class hidden {
  hidden(const hidden&);
  friend void test ();
};

SA(__is_convertible(hidden&, hidden&));
SA(__is_convertible(hidden&, const hidden&));
SA(__is_convertible(hidden&, volatile hidden&));
SA(__is_convertible(hidden&, const volatile hidden&));
SA(__is_convertible(const hidden&, const hidden&));
SA(__is_convertible(const hidden&, const volatile hidden&));
SA(__is_convertible(volatile hidden&, const volatile hidden&));
SA(__is_convertible(const volatile hidden&, const volatile hidden&));
SA(!__is_convertible(const hidden&, hidden&));

void
test ()
{
  /* __is_convertible(hidden, hidden) should be false despite the
     friend declaration above, because "Access checks are performed
     as if from a context unrelated to either type", but we don't
     implement that for the built-in (std::is_convertible works as
     expected).  This is the case for __is_assignable as well.  */
  //SA(!__is_convertible(hidden, hidden));
}

void
test2 ()
{
  struct X { };
  struct Y {
    explicit Y(X); // not viable for implicit conversions
  };
  SA(!__is_convertible(X, Y));
}