// Test C++ chained PCH functionality

// Without PCH
// RUN: %clang_cc1 -fsyntax-only -verify -include %s -include %s %s

// With PCH
// RUN: %clang_cc1 -fsyntax-only -verify %s -chain-include %s -chain-include %s

// With modules
// RUN: %clang_cc1 -fsyntax-only -verify -fmodules %s -chain-include %s -chain-include %s

// expected-no-diagnostics

#ifndef HEADER1
#define HEADER1
//===----------------------------------------------------------------------===//
// Primary header for C++ chained PCH test

void f();

// Name not appearing in dependent
void pf();

namespace ns {
  void g();

  void pg();
}

template <typename T>
struct S { typedef int G; };

// Partially specialize
template <typename T>
struct S<T *> { typedef int H; };

template <typename T> struct TS2;
typedef TS2<int> TS2int;

template <typename T> struct TestBaseSpecifiers { };
template<typename T> struct TestBaseSpecifiers2 : TestBaseSpecifiers<T> { };

template <typename T>
struct TS3 {
  static const int value = 0;
  static const int value2;
};
template <typename T>
const int TS3<T>::value;
template <typename T>
const int TS3<T>::value2 = 1;
// Instantiate struct, but not value.
struct instantiate : TS3<int> {};

// Typedef
typedef int Integer;

//===----------------------------------------------------------------------===//
#elif not defined(HEADER2)
#define HEADER2
#if !defined(HEADER1)
#error Header inclusion order messed up
#endif

//===----------------------------------------------------------------------===//
// Dependent header for C++ chained PCH test

// Overload function from primary
void f(int);

// Add function with different name
void f2();

// Reopen namespace
namespace ns {
  // Overload function from primary
  void g(int);

  // Add different name
  void g2();
}

// Specialize template from primary
template <>
struct S<int> { typedef int I; };

// Partially specialize
template <typename T>
struct S<T &> { typedef int J; };

// Specialize previous partial specialization
template <>
struct S<int *> { typedef int K; };

// Specialize the partial specialization from this file
template <>
struct S<int &> { typedef int L; };

template <typename T> struct TS2 { };

struct TestBaseSpecifiers3 { };
struct TestBaseSpecifiers4 : TestBaseSpecifiers3 { };

struct A { };
struct B : A { };

// Instantiate TS3's members.
static const int ts3m1 = TS3<int>::value;
extern int arr[TS3<int>::value2];

// Redefinition of typedef
typedef int Integer;

//===----------------------------------------------------------------------===//
#else
//===----------------------------------------------------------------------===//

void test() {
  f();
  f(1);
  pf();
  f2();

  ns::g();
  ns::g(1);
  ns::pg();
  ns::g2();

  typedef S<double>::G T1;
  typedef S<double *>::H T2;
  typedef S<int>::I T3;
  typedef S<double &>::J T4;
  typedef S<int *>::K T5;
  typedef S<int &>::L T6;

  TS2int ts2;

  B b;
  Integer i = 17;
}

// Should have remembered that there is a definition.
static const int ts3m2 = TS3<int>::value;
int arr[TS3<int>::value2];

//===----------------------------------------------------------------------===//
#endif
