Implement the notions of the "current instantiation" and "unknown
specialization" within a C++ template, and permit name lookup into the
current instantiation. For example, given:

  template<typename T, typename U>
  struct X {
    typedef T type;

    X* x1;  // current instantiation
    X<T, U> *x2; // current instantiation
    X<U, T> *x3; // not current instantiation
    ::X<type, U> *x4; // current instantiation
    X<typename X<type, U>::type, U>: *x5; // current instantiation
  };



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71471 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/test/SemaTemplate/current-instantiation.cpp b/test/SemaTemplate/current-instantiation.cpp
new file mode 100644
index 0000000..603c140
--- /dev/null
+++ b/test/SemaTemplate/current-instantiation.cpp
@@ -0,0 +1,71 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+// This test concerns the identity of dependent types within the
+// canonical type system, specifically focusing on the difference
+// between members of the current instantiation and membmers of an
+// unknown specialization. This considers C++ [temp.type], which
+// specifies type equivalence within a template, and C++0x
+// [temp.dep.type], which defines what it means to be a member of the
+// current instantiation.
+
+template<typename T, typename U>
+struct X0 {
+  typedef T T_type;
+  typedef U U_type;
+
+  void f0(T&); // expected-note{{previous}}
+  void f0(typename X0::U_type&);
+  void f0(typename X0::T_type&); // expected-error{{redecl}}
+
+  void f1(T&); // expected-note{{previous}}
+  void f1(typename X0::U_type&);
+  void f1(typename X0<T, U>::T_type&); // expected-error{{redecl}}
+
+  void f2(T&); // expected-note{{previous}}
+  void f2(typename X0::U_type&);
+  void f2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+  void f3(T&); // expected-note{{previous}}
+  void f3(typename X0::U_type&);
+  void f3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+  struct X1 {
+    typedef T my_T_type;
+
+    void g0(T&); // expected-note{{previous}}
+    void g0(typename X0::U_type&);
+    void g0(typename X0::T_type&); // expected-error{{redecl}}
+
+    void g1(T&); // expected-note{{previous}}
+    void g1(typename X0::U_type&);
+    void g1(typename X0<T, U>::T_type&); // expected-error{{redecl}}
+    
+    void g2(T&); // expected-note{{previous}}
+    void g2(typename X0::U_type&);
+    void g2(typename X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+    
+    void g3(T&); // expected-note{{previous}}
+    void g3(typename X0::U_type&);
+    void g3(typename ::X0<T_type, U_type>::T_type&); // expected-error{{redecl}}
+
+    void g4(T&); // expected-note{{previous}}
+    void g4(typename X0::U_type&);
+    void g4(typename X1::my_T_type&); // expected-error{{redecl}}
+
+    void g5(T&); // expected-note{{previous}}
+    void g5(typename X0::U_type&);
+    void g5(typename X0::X1::my_T_type&); // expected-error{{redecl}}
+
+    void g6(T&); // expected-note{{previous}}
+    void g6(typename X0::U_type&);
+    void g6(typename X0<T, U>::X1::my_T_type&); // expected-error{{redecl}}
+
+    void g7(T&); // expected-note{{previous}}
+    void g7(typename X0::U_type&);
+    void g7(typename ::X0<typename X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}}
+
+    void g8(T&); // expected-note{{previous}}
+    void g8(typename X0<U, T_type>::T_type&);
+    void g8(typename ::X0<typename X0<T_type, U>::X1::my_T_type, U_type>::X1::my_T_type&); // expected-error{{redecl}}
+  };
+};