// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors
// RUN: %clang_cc1 -std=c++1y %s -verify -fexceptions -fcxx-exceptions -pedantic-errors

namespace dr500 { // dr500: dup 372
  class D;
  class A {
    class B;
    class C;
    friend class D;
  };
  class A::B {};
  class A::C : public A::B {};
  class D : public A::B {};
}

namespace dr501 { // dr501: yes
  struct A {
    friend void f() {}
    void g() {
      void (*p)() = &f; // expected-error {{undeclared identifier}}
    }
  };
}

namespace dr502 { // dr502: yes
  struct Q {};
  template<typename T> struct A {
    enum E { e = 1 };
    void q1() { f(e); }
    void q2() { Q arr[sizeof(E)]; f(arr); }
    void q3() { Q arr[e]; f(arr); }
    void sanity() { Q arr[1]; f(arr); } // expected-error {{undeclared identifier 'f'}}
  };
  int f(A<int>::E);
  template<int N> int f(Q (&)[N]);
  template struct A<int>;
}

namespace dr505 { // dr505: yes
  const char *exts = "\e\(\{\[\%"; // expected-error 5{{use of non-standard escape}}
  const char *unknown = "\Q"; // expected-error {{unknown escape sequence}}
}

namespace dr506 { // dr506: yes
  struct NonPod { ~NonPod(); };
  void f(...);
  void g(NonPod np) { f(np); } // expected-error {{cannot pass}}
}

// FIXME: Add tests here once DR260 is resolved.
// dr507: dup 260

// dr508: na
// dr509: na
// dr510: na

namespace dr512 { // dr512: yes
  struct A {
    A(int);
  };
  union U { A a; };
#if __cplusplus < 201103L
  // expected-error@-2 {{has a non-trivial constructor}}
  // expected-note@-6 {{no default constructor}}
  // expected-note@-6 {{suppressed by user-declared constructor}}
#endif
}

// dr513: na

namespace dr514 { // dr514: yes
  namespace A { extern int x, y; }
  int A::x = y;
}

namespace dr515 { // dr515: sup 1017
  // FIXME: dr1017 reverses the wording of dr515, but the current draft has
  // dr515's wording, with a different fix for dr1017.

  struct X { int n; };
  template<typename T> struct Y : T {
    int f() { return X::n; }
  };
  int k = Y<X>().f();

  struct A { int a; };
  struct B { void f() { int k = sizeof(A::a); } };
#if __cplusplus < 201103L
  // expected-error@-2 {{invalid use of non-static data member}}
#endif
}

// dr516: na

namespace dr517 { // dr517: no
  // This is NDR, but we should diagnose it anyway.
  template<typename T> struct S {};
  template<typename T> int v = 0; // expected-error 0-1{{extension}}

  template struct S<int*>;
  template int v<int*>;

  S<char&> s;
  int k = v<char&>;

  // FIXME: These are both ill-formed.
  template<typename T> struct S<T*> {};
  template<typename T> int v<T*> = 0; // expected-error 0-1{{extension}}

  // FIXME: These are both ill-formed.
  template<typename T> struct S<T&> {};
  template<typename T> int v<T&> = 0; // expected-error 0-1{{extension}}
}

namespace dr518 { // dr518: yes c++11
  enum E { e, };
#if __cplusplus < 201103L
  // expected-error@-2 {{C++11 extension}}
#endif
}

namespace dr519 { // dr519: yes
// FIXME: Add a codegen test.
#if __cplusplus >= 201103L
#define fold(x) (__builtin_constant_p(x) ? (x) : (x))
  int test[fold((int*)(void*)0) ? -1 : 1];
#undef fold
#endif
}

// dr520: na

// dr521: no
// FIXME: The wording here is broken. It's not reasonable to expect a
// diagnostic here. Once the relevant DR gets a number, mark this as a dup.

namespace dr522 { // dr522: yes
  struct S {};
  template<typename T> void b1(volatile T &);
  template<typename T> void b2(volatile T * const *);
  template<typename T> void b2(volatile T * const S::*);
  template<typename T> void b2(volatile T * const S::* const *);
  // FIXME: This diagnostic isn't very good. The problem is not substitution failure.
  template<typename T> void b2a(volatile T *S::* const *); // expected-note {{substitution failure}}

  template<typename T> struct Base {};
  struct Derived : Base<int> {};
  template<typename T> void b3(Base<T>);
  template<typename T> void b3(Base<T> *);

  void test(int n, const int cn, int **p, int *S::*pm) {
    int *a[3], *S::*am[3]; 
    const Derived cd = Derived();
    Derived d[3];

    b1(n);
    b1(cn);
    b2(p);
    b2(pm);
    b2(a);
    b2(am);
    b2a(am); // expected-error {{no matching function}}
    b3(d);
    b3(cd);
  }
}

namespace dr524 { // dr524: yes
  template<typename T> void f(T a, T b) { operator+(a, b); } // expected-error {{call}}

  struct S {};
  void operator+(S, S);
  template void f(S, S);

  namespace N { struct S {}; }
  void operator+(N::S, N::S); // expected-note {{should be declared}}
  template void f(N::S, N::S); // expected-note {{instantiation}}
}

namespace dr525 { // dr525: yes
  namespace before {
    // Note, the example was correct prior to the change; instantiation is
    // required for cases like this:
    template <class T> struct D { operator T*(); };
    void g(D<double> ppp) {
      delete ppp;
    }
  }
  namespace after {
    template <class T> struct D { typename T::error e; }; // expected-error {{prior to '::'}}
    void g(D<double> *ppp) {
      delete ppp; // expected-note {{instantiation of}}
    }
  }
}

// PR8130
namespace dr532 { // dr532: 3.5
  struct A { };

  template<class T> struct B {
    template<class R> int &operator*(R&);
  };

  template<class T, class R> float &operator*(T&, R&);
  void test() {
    A a;
    B<A> b;
    int &ir = b * a;
  }
}
