// RUN: %clang_cc1 -std=c++1z -verify %s

struct Noncopyable {
  Noncopyable();
  Noncopyable(const Noncopyable &) = delete; // expected-note 1+{{deleted}} expected-note 1+ {{not viable}}
  virtual ~Noncopyable();
};
struct Derived : Noncopyable {};
struct NoncopyableAggr { // expected-note 3{{candidate}}
  Noncopyable nc;
};
struct Indestructible {
  Indestructible();
  ~Indestructible() = delete; // expected-note 1+{{deleted}}
};
struct Incomplete; // expected-note 1+{{declar}}

Noncopyable make(int kind = 0) {
  switch (kind) {
  case 0: return {};
  case 1: return Noncopyable();
  case 2: return Noncopyable{};
  case 3: return make();
  }
  __builtin_unreachable();
}

Indestructible make_indestructible();
Incomplete make_incomplete(); // expected-note 1+{{here}}

void take(Noncopyable nc) {}

Noncopyable nrvo() {
  Noncopyable nrvo;
  return nrvo; // expected-error {{deleted constructor}}
}

Noncopyable nc1 = make();
Noncopyable nc2 = Noncopyable();
Noncopyable nc3 = Derived(); // expected-error {{deleted constructor}}
Noncopyable nc4((Noncopyable()));
Noncopyable nc5 = {Noncopyable()};
Noncopyable nc6{Noncopyable()};

NoncopyableAggr nca1 = NoncopyableAggr{};
NoncopyableAggr nca2 = NoncopyableAggr{{}};
NoncopyableAggr nca3 = NoncopyableAggr{NoncopyableAggr{Noncopyable()}};

template<typename T> struct Convert { operator T(); }; // expected-note 1+{{candidate}}
Noncopyable conv1 = Convert<Noncopyable>();
Noncopyable conv2((Convert<Noncopyable>()));
Noncopyable conv3 = {Convert<Noncopyable>()};
Noncopyable conv4{Convert<Noncopyable>()};

Noncopyable ref_conv1 = Convert<Noncopyable&>(); // expected-error {{deleted constructor}}
Noncopyable ref_conv2((Convert<Noncopyable&>())); // expected-error {{deleted constructor}}
Noncopyable ref_conv3 = {Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}
Noncopyable ref_conv4{Convert<Noncopyable&>()}; // expected-error {{deleted constructor}}

Noncopyable derived_conv1 = Convert<Derived>(); // expected-error {{deleted constructor}}
Noncopyable derived_conv2((Convert<Derived>())); // expected-error {{deleted constructor}}
Noncopyable derived_conv3 = {Convert<Derived>()}; // expected-error {{deleted constructor}}
Noncopyable derived_conv4{Convert<Derived>()}; // expected-error {{deleted constructor}}

NoncopyableAggr nc_aggr1 = Convert<NoncopyableAggr>();
NoncopyableAggr nc_aggr2((Convert<NoncopyableAggr>()));
NoncopyableAggr nc_aggr3 = {Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
NoncopyableAggr nc_aggr4{Convert<NoncopyableAggr>()}; // expected-error {{no viable conversion}}
NoncopyableAggr nc_aggr5 = Convert<Noncopyable>(); // expected-error {{no viable}}
NoncopyableAggr nc_aggr6((Convert<Noncopyable>())); // expected-error {{no matching constructor}}
NoncopyableAggr nc_aggr7 = {Convert<Noncopyable>()};
NoncopyableAggr nc_aggr8{Convert<Noncopyable>()};

void test_expressions(bool b) {
  auto lambda = [a = make()] {};

  take({});
  take(Noncopyable());
  take(Noncopyable{});
  take(make());

  Noncopyable &&dc1 = dynamic_cast<Noncopyable&&>(Noncopyable());
  Noncopyable &&dc2 = dynamic_cast<Noncopyable&&>(nc1);
  Noncopyable &&dc3 = dynamic_cast<Noncopyable&&>(Derived());

  Noncopyable sc1 = static_cast<Noncopyable>(Noncopyable());
  Noncopyable sc2 = static_cast<Noncopyable>(nc1); // expected-error {{deleted}}
  Noncopyable sc3 = static_cast<Noncopyable&&>(Noncopyable()); // expected-error {{deleted}}
  Noncopyable sc4 = static_cast<Noncopyable>(static_cast<Noncopyable&&>(Noncopyable())); // expected-error {{deleted}}

  Noncopyable cc1 = (Noncopyable)Noncopyable();
  Noncopyable cc2 = (Noncopyable)Derived(); // expected-error {{deleted}}

  Noncopyable fc1 = Noncopyable(Noncopyable());
  Noncopyable fc2 = Noncopyable(Derived()); // expected-error {{deleted}}

  // We must check for a complete type for every materialized temporary. (Note
  // that in the special case of the top level of a decltype, no temporary is
  // materialized.)
  make_incomplete(); // expected-error {{incomplete}}
  make_incomplete().a; // expected-error {{incomplete}}
  make_incomplete().*(int Incomplete::*)nullptr; // expected-error {{incomplete}}
  dynamic_cast<Incomplete&&>(make_incomplete()); // expected-error {{incomplete}}
  const_cast<Incomplete&&>(make_incomplete()); // expected-error {{incomplete}}

  sizeof(Indestructible{}); // expected-error {{deleted}}
  sizeof(make_indestructible()); // expected-error {{deleted}}
  sizeof(make_incomplete()); // expected-error {{incomplete}}
  typeid(Indestructible{}); // expected-error {{deleted}}
  typeid(make_indestructible()); // expected-error {{deleted}}
  typeid(make_incomplete()); // expected-error {{incomplete}}

  // FIXME: The first two cases here are now also valid in C++17 onwards.
  using I = decltype(Indestructible()); // expected-error {{deleted}}
  using I = decltype(Indestructible{}); // expected-error {{deleted}}
  using I = decltype(make_indestructible());
  using J = decltype(make_incomplete());

  Noncopyable cond1 = b ? Noncopyable() : make();
  Noncopyable cond2 = b ? Noncopyable() : Derived(); // expected-error {{incompatible}}
  Noncopyable cond3 = b ? Derived() : Noncopyable(); // expected-error {{incompatible}}
  Noncopyable cond4 = b ? Noncopyable() : nc1; // expected-error {{deleted}}
  Noncopyable cond5 = b ? nc1 : Noncopyable(); // expected-error {{deleted}}
  // Could convert both to an xvalue of type Noncopyable here, but we're not
  // permitted to consider that.
  Noncopyable &&cond6 = b ? Noncopyable() : Derived(); // expected-error {{incompatible}}
  Noncopyable &&cond7 = b ? Derived() : Noncopyable(); // expected-error {{incompatible}}
  // Could convert both to a const lvalue of type Noncopyable here, but we're
  // not permitted to consider that, either.
  const Noncopyable cnc;
  const Noncopyable &cond8 = b ? cnc : Derived(); // expected-error {{incompatible}}
  const Noncopyable &cond9 = b ? Derived() : cnc; // expected-error {{incompatible}}

  extern const volatile Noncopyable make_cv();
  Noncopyable cv_difference1 = make_cv();
  const volatile Noncopyable cv_difference2 = make();
}

template<typename T> struct ConversionFunction { operator T(); };
Noncopyable cf1 = ConversionFunction<Noncopyable>();
Noncopyable cf2 = ConversionFunction<Noncopyable&&>(); // expected-error {{deleted}}
Noncopyable cf3 = ConversionFunction<const volatile Noncopyable>();
const volatile Noncopyable cf4 = ConversionFunction<Noncopyable>();
Noncopyable cf5 = ConversionFunction<Derived>(); // expected-error {{deleted}}

struct AsMember {
  Noncopyable member;
  AsMember() : member(make()) {}
};
// FIXME: DR (no number yet): we still get a copy for base or delegating construction.
struct AsBase : Noncopyable {
  AsBase() : Noncopyable(make()) {} // expected-error {{deleted}}
};
struct AsDelegating final {
  AsDelegating(const AsDelegating &) = delete; // expected-note {{deleted}}
  static AsDelegating make(int);

  // The base constructor version of this is problematic; the complete object
  // version would be OK. Perhaps we could allow copy omission here for final
  // classes?
  AsDelegating(int n) : AsDelegating(make(n)) {} // expected-error {{deleted}}
};

namespace CtorTemplateBeatsNonTemplateConversionFn {
  struct Foo { template <typename Derived> Foo(const Derived &); };
  template <typename Derived> struct Base { operator Foo() const = delete; }; // expected-note {{deleted}}
  struct Derived : Base<Derived> {};

  Foo f(Derived d) { return d; } // expected-error {{invokes a deleted function}}
  Foo g(Derived d) { return Foo(d); } // ok, calls constructor
}
