Start canonicalizing template names. This is not yet complete, but it
improves type identity with dependent types.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71152 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 800fb5b..8199aff 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -604,6 +604,26 @@
   NestedNameSpecifier *
   getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS);
 
+  /// \brief Retrieves the "canonical" template name that refers to a
+  /// given template.
+  ///
+  /// The canonical template name is the simplest expression that can
+  /// be used to refer to a given template. For most templates, this
+  /// expression is just the template declaration itself. For example,
+  /// the template std::vector can be referred to via a variety of
+  /// names---std::vector, ::std::vector, vector (if vector is in
+  /// scope), etc.---but all of these names map down to the same
+  /// TemplateDecl, which is used to form the canonical template name.
+  ///
+  /// Dependent template names are more interesting. Here, the
+  /// template name could be something like T::template apply or
+  /// std::allocator<T>::template rebind, where the nested name
+  /// specifier itself is dependent. In this case, the canonical
+  /// template name uses the shortest form of the dependent
+  /// nested-name-specifier, which itself contains all canonical
+  /// types, values, and templates.
+  TemplateName getCanonicalTemplateName(TemplateName Name);
+
   /// Type Query functions.  If the type is an instance of the specified class,
   /// return the Type pointer for the underlying maximally pretty type.  This
   /// is a member of ASTContext because this may need to do some amount of
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index c1a232c..3b1a11c 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1700,6 +1700,17 @@
                               VAT->getIndexTypeQualifier());
 }
 
+TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) {
+  // If this template name refers to a template, the canonical
+  // template name merely stores the template itself.
+  if (TemplateDecl *Template = Name.getAsTemplateDecl())
+    return TemplateName(Template);
+
+  DependentTemplateName *DTN = Name.getAsDependentTemplateName();
+  assert(DTN && "Non-dependent template names must refer to template decls.");
+  return DTN->CanonicalTemplateName;
+}
+
 NestedNameSpecifier *
 ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
   if (!NNS) 
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 3649abd..6c4adbd 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -818,8 +818,8 @@
     // A<T, T> have identical types when A is declared as:
     //
     //   template<typename T, typename U = T> struct A;
-
-    CanonType = Context.getTemplateSpecializationType(Name, 
+    TemplateName CanonName = Context.getCanonicalTemplateName(Name);
+    CanonType = Context.getTemplateSpecializationType(CanonName, 
                                                     &ConvertedTemplateArgs[0],
                                                 ConvertedTemplateArgs.size());
   } else if (ClassTemplateDecl *ClassTemplate 
diff --git a/test/SemaTemplate/dependent-type-identity.cpp b/test/SemaTemplate/dependent-type-identity.cpp
new file mode 100644
index 0000000..0cb5534
--- /dev/null
+++ b/test/SemaTemplate/dependent-type-identity.cpp
@@ -0,0 +1,40 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+struct X0 { };
+
+template<typename T, typename U>
+struct X1 {
+  typedef T type;
+
+  void f0(T); // expected-note{{previous}}
+  void f0(U);
+  void f0(type); // expected-error{{redeclar}}
+
+  void f1(T*); // expected-note{{previous}}
+  void f1(U*);
+  void f1(type*); // expected-error{{redeclar}}
+
+  void f2(X0<T>*); // expected-note{{previous}}
+  void f2(X0<U>*);
+  void f2(X0<type>*); // expected-error{{redeclar}}
+
+  void f3(X0<T>*); // expected-note{{previous}}
+  void f3(X0<U>*);
+  void f3(::X0<type>*); // expected-error{{redeclar}}  
+
+  void f4(typename T::template apply<U>*);
+  void f4(typename U::template apply<U>*);
+  void f4(typename type::template apply<T>*);
+  // FIXME: this is a duplicate of the first f4, but we are not fully
+  // canonicalizing nested-name-specifiers yet.
+  void f4(typename type::template apply<U>*);
+
+  void f5(typename T::template apply<U>::type*);
+  void f5(typename U::template apply<U>::type*);
+  void f5(typename U::template apply<T>::type*);
+  void f5(typename type::template apply<T>::type*);
+  // FIXME: this is a duplicate of the first f5, but we are not fully
+  // canonicalizing nested-name-specifiers yet.
+  void f5(typename type::template apply<U>::type*);
+};