// RUN: %clang_cc1 -verify -emit-llvm-only %s

namespace test0 {
template <typename T> struct Num {
  T value_;

public:
  Num(T value) : value_(value) {}
  T get() const { return value_; }

  template <typename U> struct Rep {
    U count_;
    Rep(U count) : count_(count) {}

    friend Num operator*(const Num &a, const Rep &n) {
      Num x = 0;
      for (U count = n.count_; count; --count)
        x += a;
      return x;
    } 
  };

  friend Num operator+(const Num &a, const Num &b) {
    return a.value_ + b.value_;
  }

  Num& operator+=(const Num& b) {
    value_ += b.value_;
    return *this;
  }

  class Representation {};
  friend class Representation;
};

class A {
  template <typename T> friend bool iszero(const A &a) throw();
};

template <class T> class B_iterator;
template <class T> class B {
  friend class B_iterator<T>;
};

int calc1() {
  Num<int> left = -1;
  Num<int> right = 1;
  Num<int> result = left + right;
  return result.get();
}

int calc2() {
  Num<int> x = 3;
  Num<int>::Rep<char> n = (char) 10;
  Num<int> result = x * n;
  return result.get();
}
}

// Reduced from GNU <locale>
namespace test1 {
  class A {
    bool b; // expected-note {{declared private here}}
    template <typename T> friend bool has(const A&);
  };
  template <typename T> bool has(const A &x) {
    return x.b;
  }
  template <typename T> bool hasnot(const A &x) {
    return x.b; // expected-error {{'b' is a private member of 'test1::A'}}
  }
}

namespace test2 {
  class A {
    bool b; // expected-note {{declared private here}}
    template <typename T> friend class HasChecker;
  };
  template <typename T> class HasChecker {
    bool check(A *a) {
      return a->b;
    }
  };
  template <typename T> class HasNotChecker {
    bool check(A *a) {
      return a->b; // expected-error {{'b' is a private member of 'test2::A'}}
    }
  };
}

namespace test3 {
  class Bool;
  template <class T> class User;
  template <class T> T transform(class Bool, T);

  class Bool {
    friend class User<bool>;
    friend bool transform<>(Bool, bool);

    bool value; // expected-note 2 {{declared private here}}
  };

  template <class T> class User {
    static T compute(Bool b) {
      return b.value; // expected-error {{'value' is a private member of 'test3::Bool'}}
    }
  };

  template <class T> T transform(Bool b, T value) {
    if (b.value) // expected-error {{'value' is a private member of 'test3::Bool'}}
      return value;
    return value + 1;
  }

  template bool transform(Bool, bool);
  template int transform(Bool, int); // expected-note {{requested here}}

  template class User<bool>;
  template class User<int>; // expected-note {{requested here}}
}

namespace test4 {
  template <class T> class A {
    template <class T0> friend class B;
    bool foo(const A<T> *) const;
  };

  template <class T> class B {
    bool bar(const A<T> *a, const A<T> *b) {
      return a->foo(b);
    }
  };

  template class B<int>;
}

namespace test5 {
  template <class T, class U=int> class A {};
  template <class T> class B {
    template <class X, class Y> friend class A;
  };
  template class B<int>;
  template class A<int>;
}

namespace Dependent {
  template<typename T, typename Traits> class X;
  template<typename T, typename Traits> 
  X<T, Traits> operator+(const X<T, Traits>&, const T*);

  template<typename T, typename Traits> class X {
    typedef typename Traits::value_type value_type;
    friend X operator+<>(const X&, const value_type*);
  };
}

namespace test7 {
  template <class T> class A { // expected-note {{declared here}}
    friend class B;
    int x; // expected-note {{declared private here}}
  };

  class B {
    int foo(A<int> &a) {
      return a.x;
    }
  };

  class C {
    int foo(A<int> &a) {
      return a.x; // expected-error {{'x' is a private member of 'test7::A<int>'}}
    }
  };

  // This shouldn't crash.
  template <class T> class D {
    friend class A; // expected-error {{elaborated type refers to a template}}
  };
  template class D<int>;
}

namespace test8 {
  template <class N> class A {
    static int x;
    template <class T> friend void foo();
  };
  template class A<int>;

  template <class T> void foo() {
    A<int>::x = 0;
  }
  template void foo<int>();
}

namespace test9 {
  template <class T> class A {
    class B; class C;

    int foo(B *b) {
      return b->x;
    }

    int foo(C *c) {
      return c->x; // expected-error {{'x' is a private member}}
    }

    class B {
      int x;
      friend int A::foo(B*);
    };

    class C {
      int x; // expected-note {{declared private here}}
    };
  };

  template class A<int>; // expected-note {{in instantiation}}
}

namespace test10 {
  template <class T> class A;
  template <class T> A<T> bar(const T*, const A<T>&);
  template <class T> class A {
  private:
    void foo(); // expected-note {{declared private here}}
    friend A bar<>(const T*, const A<T>&);
  };

  template <class T> A<T> bar(const T *l, const A<T> &r) {
    A<T> l1;
    l1.foo();

    A<char> l2;
    l2.foo(); // expected-error {{'foo' is a private member of 'test10::A<char>'}}

    return l1;
  }

  template A<int> bar<int>(const int *, const A<int> &); // expected-note {{in instantiation}}
}

// PR6752: this shouldn't crash.
namespace test11 {
  struct Foo {
    template<class A>
    struct IteratorImpl {
      template<class T> friend class IteratorImpl;
    };
  };

  template struct Foo::IteratorImpl<int>;
  template struct Foo::IteratorImpl<long>;  
}

// PR6827
namespace test12 {
  template <typename T> class Foo;
  template <typename T> Foo<T> foo(T* t){ return Foo<T>(t, true); }

  template <typename T> class Foo {
  public:
    Foo(T*);
    friend Foo<T> foo<T>(T*);
  private:
    Foo(T*, bool); // expected-note {{declared private here}}
  };

  // Should work.
  int globalInt;
  Foo<int> f = foo(&globalInt);

  // Shouldn't work.
  long globalLong;
  template <> Foo<long> foo(long *t) {
    Foo<int> s(&globalInt, false); // expected-error {{calling a private constructor}}
    return Foo<long>(t, true);
  }
}

// PR6514
namespace test13 {
  template <int N, template <int> class Temp>
  class Role : public Temp<N> {
    friend class Temp<N>;
    int x;
  };

  template <int N> class Foo {
    void foo(Role<N, test13::Foo> &role) {
      (void) role.x;
    }
  };

  template class Foo<0>;
}

namespace test14 {
  template <class T> class B;
  template <class T> class A {
    friend void B<T>::foo();
    static void foo(); // expected-note {{declared private here}}
  };

  template <class T> class B {
    void foo() { return A<long>::foo(); } // expected-error {{'foo' is a private member of 'test14::A<long>'}}
  };

  template class B<int>; // expected-note {{in instantiation}}
}

namespace test15 {
  template <class T> class B;
  template <class T> class A {
    friend void B<T>::foo();

    // This shouldn't be misrecognized as a templated-scoped reference.
    template <class U> friend void B<T>::bar(U);

    static void foo(); // expected-note {{declared private here}}
  };

  template <class T> class B {
    void foo() { return A<long>::foo(); } // expected-error {{'foo' is a private member of 'test15::A<long>'}}
  };

  template <> class B<float> {
    void foo() { return A<float>::foo(); }
    template <class U> void bar(U u) {
      (void) A<float>::foo();
    }
  };

  template class B<int>; // expected-note {{in instantiation}}
}
