]> granicus.if.org Git - clang/commitdiff
Start canonicalizing template names. This is not yet complete, but it
authorDouglas Gregor <dgregor@apple.com>
Thu, 7 May 2009 06:41:52 +0000 (06:41 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 7 May 2009 06:41:52 +0000 (06:41 +0000)
improves type identity with dependent types.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@71152 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
lib/AST/ASTContext.cpp
lib/Sema/SemaTemplate.cpp
test/SemaTemplate/dependent-type-identity.cpp [new file with mode: 0644]

index 800fb5b0d0989ec247dd9fe49220712289d0a16b..8199affc83ba2eb55f6db31d0a04eaf7cb0e4064 100644 (file)
@@ -604,6 +604,26 @@ public:
   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
index c1a232c88e95f6f38b96e28f8242bf106d6d6ca2..3b1a11cb79547f519e0b46d88586d0aa620fd6ee 100644 (file)
@@ -1700,6 +1700,17 @@ QualType ASTContext::getCanonicalType(QualType T) {
                               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) 
index 3649abd9a741d583300187801677c278a276622e..6c4adbd0ae26739570d345cae2e1cba95faaff99 100644 (file)
@@ -818,8 +818,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
     // 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 (file)
index 0000000..0cb5534
--- /dev/null
@@ -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*);
+};