// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11

#ifndef __GXX_EXPERIMENTAL_CXX0X__
#define __CONCAT(__X, __Y) __CONCAT1(__X, __Y)
#define __CONCAT1(__X, __Y) __X ## __Y

#define static_assert(__b, __m) \
  typedef int __CONCAT(__sa, __LINE__)[__b ? 1 : -1]
#endif

class C {
  virtual void f() = 0; // expected-note {{unimplemented pure virtual method 'f'}}
};

static_assert(__is_abstract(C), "C has a pure virtual function");

class D : C {
};

static_assert(__is_abstract(D), "D inherits from an abstract class");

class E : D {
  virtual void f();
};

static_assert(!__is_abstract(E), "E inherits from an abstract class but implements f");

C *d = new C; // expected-error {{allocating an object of abstract class type 'C'}}

C c; // expected-error {{variable type 'C' is an abstract class}}
void t1(C c); // expected-error {{parameter type 'C' is an abstract class}}
void t2(C); // expected-error {{parameter type 'C' is an abstract class}}

struct S {
  C c; // expected-error {{field type 'C' is an abstract class}}
};

void t3(const C&);

void f() {
  C(); // expected-error {{allocating an object of abstract class type 'C'}}
  t3(C()); // expected-error {{allocating an object of abstract class type 'C'}}
}

C e1[2]; // expected-error {{array of abstract class type 'C'}}
C (*e2)[2]; // expected-error {{array of abstract class type 'C'}}
C (**e3)[2]; // expected-error {{array of abstract class type 'C'}}

void t4(C c[2]); // expected-error {{array of abstract class type 'C'}}

void t5(void (*)(C)); // expected-error {{parameter type 'C' is an abstract class}}

typedef void (*Func)(C); // expected-error {{parameter type 'C' is an abstract class}}
void t6(Func);

class F {
  F a() { while (1) {} } // expected-error {{return type 'F' is an abstract class}}
    
  class D {
    void f(F c); // expected-error {{parameter type 'F' is an abstract class}}
  };

  union U {
    void u(F c); // expected-error {{parameter type 'F' is an abstract class}}
  };
    
  virtual void f() = 0; // expected-note {{unimplemented pure virtual method 'f'}}
};

// Diagnosing in these cases is prohibitively expensive.  We still
// diagnose at the function definition, of course.

class Abstract;

void t7(Abstract a);

void t8() {
  void h(Abstract a);
}

namespace N {
void h(Abstract a);
}

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

// <rdar://problem/6854087>
class foo {
public:
  virtual foo *getFoo() = 0;
};

class bar : public foo {
public:
  virtual bar *getFoo();
};

bar x;

// <rdar://problem/6902298>
class A {
public:
  virtual void release() = 0;
  virtual void release(int count) = 0;
  virtual void retain() = 0;
};

class B : public A {
public:
  virtual void release();
  virtual void release(int count);
  virtual void retain();
};

void foo(void) {
  B b;
}

struct K {
 int f;
 virtual ~K();
};

struct L : public K {
 void f();
};

// PR5222
namespace PR5222 {
  struct A {
    virtual A *clone() = 0;
  };
  struct B : public A {
    virtual B *clone() = 0;
  };
  struct C : public B {
    virtual C *clone();
  };

  C c;  
}

// PR5550 - instantiating template didn't track overridden methods
namespace PR5550 {
  struct A {
    virtual void a() = 0;
    virtual void b() = 0;
  };
  template<typename T> struct B : public A {
    virtual void b();
    virtual void c() = 0;
  };
  struct C : public B<int> {
    virtual void a();
    virtual void c();
  }; 
  C x;
}

namespace PureImplicit {
  // A pure virtual destructor should be implicitly overridden.
  struct A { virtual ~A() = 0; };
  struct B : A {};
  B x;

  // A pure virtual assignment operator should be implicitly overridden.
  struct D;
  struct C { virtual D& operator=(const D&) = 0; };
  struct D : C {};
  D y;
}

namespace test1 {
  struct A {
    virtual void foo() = 0;
  };

  struct B : A {
    using A::foo;
  };

  struct C : B {
    void foo();
  };

  void test() {
    C c;
  }
}

// rdar://problem/8302168
namespace test2 {
  struct X1 {
    virtual void xfunc(void) = 0;  // expected-note {{unimplemented pure virtual method}}
    void g(X1 parm7);        // expected-error {{parameter type 'test2::X1' is an abstract class}}
    void g(X1 parm8[2]);     // expected-error {{array of abstract class type 'test2::X1'}}
  };

  template <int N>
  struct X2 {
    virtual void xfunc(void) = 0;  // expected-note {{unimplemented pure virtual method}}
    void g(X2 parm10);        // expected-error {{parameter type 'X2<N>' is an abstract class}}
    void g(X2 parm11[2]);     // expected-error {{array of abstract class type 'X2<N>'}}
  };
}

namespace test3 {
  struct A { // expected-note {{not complete until}}
    A x; // expected-error {{field has incomplete type}}
    virtual void abstract() = 0;
  };

  struct B { // expected-note {{not complete until}}
    virtual void abstract() = 0;
    B x; // expected-error {{field has incomplete type}}
  };

  struct C {
    static C x; // expected-error {{abstract class}}
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
  };

  struct D {
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
    static D x; // expected-error {{abstract class}}
  };
}

namespace test4 {
  template <class T> struct A {
    A x; // expected-error {{abstract class}}
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
  };

  template <class T> struct B {
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
    B x; // expected-error {{abstract class}}
  };

  template <class T> struct C {
    static C x; // expected-error {{abstract class}}
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
  };

  template <class T> struct D {
    virtual void abstract() = 0; // expected-note {{unimplemented pure virtual method}}
    static D x; // expected-error {{abstract class}}
  };
}

// PR9247: Crash on invalid in clang::Sema::ActOnFinishCXXMemberSpecification
namespace pr9247 {
  struct A {
    virtual void g(const A& input) = 0;
    struct B {
      C* f(int foo);
    };
  };
}
