// RUN: %clang_cc1 -g -triple %itanium_abi_triple -emit-llvm-only %s
// Check that we don't crash.
// PR12305, PR12315

# 1 "a.h"  3
template < typename T1 > struct Types1
{
  typedef T1 Head;
};
template < typename > struct Types;
template < template < typename > class Tmpl > struct TemplateSel
{
  template < typename T > struct Bind
  {
    typedef Tmpl < T > type;
  };
};
template < typename > struct NoneT;
template < template < typename > class T1, template < typename > class > struct Templates2
{
  typedef TemplateSel < T1 > Head;
};
template < template < typename > class, template < typename > class =
  NoneT, template < typename > class = NoneT, template < typename > class =
  NoneT > struct Templates;
template < template < typename > class T1,
  template < typename > class T2 > struct Templates <T1, T2 >
{
  typedef Templates2 < T1, T2 > type;
};
template < typename T > struct TypeList
{
  typedef Types1 < T > type;
};
template < template < typename > class, class TestSel,
  typename Types > class TypeParameterizedTest
{
public:static bool Register ()
  {
    typedef typename Types::Head Type;
    typename TestSel::template Bind < Type >::type TestClass;
}};

template < template < typename > class Fixture, typename Tests,
  typename Types > class TypeParameterizedTestCase
{
public:static bool Register (char *, char *, int *)
  {
    typedef typename Tests::Head Head;
    TypeParameterizedTest < Fixture, Head, Types >::Register;
}};

template < typename > class TypedTestP1
{
};

namespace gtest_case_TypedTestP1_
{
  template < typename gtest_TypeParam_ > class A:TypedTestP1 <
    gtest_TypeParam_ >
  {
  };
template < typename gtest_TypeParam_ > class B:TypedTestP1 <
    gtest_TypeParam_ >
  {
  };
  typedef Templates < A >::type gtest_AllTests_;
}

template < typename > class TypedTestP2
{
};

namespace gtest_case_TypedTestP2_
{
  template < typename gtest_TypeParam_ > class A:TypedTestP2 <
    gtest_TypeParam_ >
  {
  };
  typedef Templates < A >::type gtest_AllTests_;
}

bool gtest_Int_TypedTestP1 =
  TypeParameterizedTestCase < TypedTestP1,
  gtest_case_TypedTestP1_::gtest_AllTests_,
  TypeList < int >::type >::Register ("Int", "TypedTestP1", 0);
bool gtest_Int_TypedTestP2 =
  TypeParameterizedTestCase < TypedTestP2,
  gtest_case_TypedTestP2_::gtest_AllTests_,
  TypeList < Types < int > >::type >::Register ("Int", "TypedTestP2", 0);

template < typename _Tp > struct new_allocator
{
  typedef _Tp *pointer;
  template < typename > struct rebind {
    typedef new_allocator other;
  };
};
template < typename _Tp > struct allocator:new_allocator < _Tp > {
};
template < typename _Tp, typename _Alloc > struct _Vector_base {
  typedef typename _Alloc::template rebind < _Tp >::other _Tp_alloc_type;
  struct _Vector_impl {
    typename _Tp_alloc_type::pointer _M_end_of_storage;
  };
  _Vector_base () {
    foo((int *) this->_M_impl._M_end_of_storage);
  }
  void foo(int *);
  _Vector_impl _M_impl;
};
template < typename _Tp, typename _Alloc =
allocator < _Tp > >struct vector:_Vector_base < _Tp, _Alloc > { };


template < class T> struct HHH {};
struct DDD { int x_;};
struct Data;
struct X1;
struct CCC:DDD {   virtual void xxx (HHH < X1 >); };
template < class SSS > struct EEE:vector < HHH < SSS > > { };
template < class SSS, class = EEE < SSS > >class FFF { };
template < class SSS, class GGG = EEE < SSS > >class AAA:FFF <GGG> { };
class BBB:virtual CCC {
  void xxx (HHH < X1 >);
  vector < HHH < X1 > >aaa;
};
class ZZZ:AAA < Data >, BBB { virtual ZZZ *ppp () ; };
ZZZ * ZZZ::ppp () { return new ZZZ; }

namespace std
{
  template < class, class > struct pair;
}
namespace __gnu_cxx {
template < typename > class new_allocator;
}
namespace std {
template < typename _Tp > class allocator:__gnu_cxx::new_allocator < _Tp > {
};
template < typename, typename > struct _Vector_base {
};
template < typename _Tp, typename _Alloc = std::allocator < _Tp > >class vector:_Vector_base < _Tp,
  _Alloc
        > {
        };
}

namespace
std {
  template <
      typename,
      typename > struct unary_function;
  template <
      typename,
      typename,
      typename > struct binary_function;
  template <
      typename
      _Tp > struct equal_to:
        binary_function <
        _Tp,
        _Tp,
        bool > {
        };
  template <
      typename
      _Pair > struct _Select1st:
        unary_function <
        _Pair,
        typename
        _Pair::first_type > {
        };
}
# 1 "f.h"  3
using
std::pair;
namespace
__gnu_cxx {
  template <
      class > struct hash;
  template <
      class,
      class,
      class,
      class,
      class
          _EqualKey,
      class >
          class
          hashtable {
           public:
            typedef _EqualKey
                key_equal;
            typedef void key_type;
          };
  using
      std::equal_to;
  using
      std::allocator;
  using
      std::_Select1st;
  template < class _Key, class _Tp, class _HashFn =
      hash < _Key >, class _EqualKey = equal_to < _Key >, class _Alloc =
      allocator < _Tp > >class hash_map {
        typedef
            hashtable <
            pair <
            _Key,
        _Tp >,
        _Key,
        _HashFn,
        _Select1st <
            pair <
            _Key,
        _Tp > >,
        _EqualKey,
        _Alloc >
            _Ht;
       public:
        typedef typename _Ht::key_type key_type;
        typedef typename
            _Ht::key_equal
            key_equal;
      };
}
using
__gnu_cxx::hash_map;
class
C2;
template < class > class scoped_ptr {
};
namespace {
class
    AAA {
      virtual ~
          AAA () {
          }};
}
template < typename > class EEE;
template < typename CCC, typename =
typename CCC::key_equal, typename =
EEE < CCC > >class III {
};
namespace
util {
  class
      EEE {
      };
}
namespace {
class
    C1:
      util::EEE {
       public:
        class
            C3:
              AAA {
                struct FFF;
                typedef
                    III <
                    hash_map <
                    C2,
                    FFF > >
                        GGG;
                GGG
                    aaa;
                friend
                    C1;
              };
        void
            HHH (C3::GGG &);
      };
}
namespace
n1 {
  class
      Test {
      };
  template <
      typename >
      class
      C7 {
      };
  class
      C4:
        n1::Test {
          vector <
              C1::C3 * >
              a1;
        };
  enum C5 { };
  class
      C6:
        C4,
        n1::C7 <
        C5 > {
        };
  class
      C8:
        C6 {
        };
  class
      C9:
        C8 {
          void
              TestBody ();
        };
  void
      C9::TestBody () {
        scoped_ptr < C1::C3 > context;
      }
}
