// RUN: clang-cc -fsyntax-only -std=c++0x -verify %s
template< typename T, typename U >
struct SameType { static const bool result = false; };

template< typename T >
struct SameType<T,T> { static const bool result = true; };

namespace X {
typedef int t_int;                           t_int     tx_int;
using u_int = int;                           u_int     ux_int;
using u_fn = u_int(u_int);                   u_fn *    ux_fn;
using u_fn_not_ctor = u_int();               u_fn_not_ctor * ux_fn_not_ctor;
using u_fn_ptr = u_int(*)(u_int, u_int);     u_fn_ptr  ux_fn_ptr;
using u_fn_ref = u_int(&)(u_int, u_int);     u_fn_ref  ux_fn_ref = *ux_fn_ptr;
using u_fnx = u_int(*)(u_int) throw(u_int);  u_fnx     ux_fnx;
using u_array = int[13];                     u_array   ux_array;
using u_struct = struct{};                   u_struct  ux_struct;
using u_decl = decltype(1+2.0);              u_decl    ux_decl = 1+2.0;

using u_declfn = decltype(ux_fn_ref(ux_int, tx_int));  u_declfn ux_declfn = 0;

// duplicate definitions are allowed, so long as they are identical.
typedef double t_int;  // expected-error{{typedef redefinition with different types ('double' vs 'int')}}
using u_int = double;  // expected-error{{typedef redefinition with different types ('double' vs 'int')}}
typedef int t_int;
using u_int = int;
}

static_assert(SameType<X::t_int, int>::result, "X::t_int should be typdef int");
static_assert(SameType<X::u_int, int>::result, "X::u_int should be typdef int");
static_assert(SameType<X::u_fn, int(int)>::result, "X::::u_fn should be typdef int(int)");
static_assert(SameType<X::u_decl, double>::result, "X::u_decl should be typdef double");
static_assert(SameType<X::u_declfn, int>::result, "X::u_declfn should be typdef int");

// Test inside class scope too
struct wrapper {
   using u_int = int;
   using u_fn = u_int(u_int);
   using u_not_ctor = u_int();
   using u_fn_ptr = u_int(*)(u_int, u_int);
   using u_fn_ref = u_int(&)(u_int, u_int);
   using u_array = int[13];
};

using error = 42; // expected-error{{42 is not a type-id}}

struct fwd : wrapper {
   using u_int2 = wrapper::u_int;
   using u_int3 = X::u_int;
};

struct access_check : private wrapper {
   using u_int2 = wrapper::u_int; // expected-error{{cannot access private name}}
   using u_int3 = X::u_int;
};

template< typename T >
struct Tfwd {
   using u_int = typename T::u_int;
   using u_fn = typename T::u_int(typename T::u_int);
   using u_fn_ex = typename T::u_int(*)(typename T::u_int) throw(typename T::u_int);
};

Tfwd<wrapper>::u_int test;

template< typename T >
struct Tdep : T {
   typedef u_int u_int_err; // expected-error{{unknown type name 'u_int'}}
   using u_int2 = u_int;    // expected-error{{unknown type name 'u_int'}}
   using u_int_bad = T::u_int; // expected-error{{require the typename keyword}}
   using u_int3 = typename T::u_int;
   using u_fn = typename T::u_int(typename T::u_int);
   using u_fn_ex = typename T::u_int(*)(typename T::u_int) throw(typename T::u_int);
};

Tdep<wrapper>::u_int test_dep;

#if 0
// variadic support not quite ready yet
template< typename ... Types >
struct Variadic {
   typedef void fn_type(Types...);
   typedef void fn_dep_type(typename Types::type...);
   typedef void (*fn_ex_spec)() throw(Types...);
   typedef void (*fn_dep_ex_spec)() throw(typename Types::type...);
};
#endif

#if 0
// This does not look to be implemented in function type parser yet
typedef X::u_int u_fn(X::u_int) throw();  // expected-error{{function typedefs are not allowed exception specifications}}
using u_fn = X::u_int(X::u_int) throw();  // expected-error{{function typedefs are not allowed exception specifications}}
#endif
