From: Douglas Gregor Date: Thu, 7 May 2009 06:41:52 +0000 (+0000) Subject: Start canonicalizing template names. This is not yet complete, but it X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=25a3ef7cc5fd55dc8cc67c6e6770c8595657e082;p=clang 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 800fb5b0d0..8199affc83 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -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::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 c1a232c88e..3b1a11cb79 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -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) diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3649abd9a7..6c4adbd0ae 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -818,8 +818,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // A have identical types when A is declared as: // // template 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 0000000000..0cb5534ca5 --- /dev/null +++ b/test/SemaTemplate/dependent-type-identity.cpp @@ -0,0 +1,40 @@ +// RUN: clang-cc -fsyntax-only -verify %s + +template +struct X0 { }; + +template +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*); // expected-note{{previous}} + void f2(X0*); + void f2(X0*); // expected-error{{redeclar}} + + void f3(X0*); // expected-note{{previous}} + void f3(X0*); + void f3(::X0*); // expected-error{{redeclar}} + + void f4(typename T::template apply*); + void f4(typename U::template apply*); + void f4(typename type::template apply*); + // 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*); + + void f5(typename T::template apply::type*); + void f5(typename U::template apply::type*); + void f5(typename U::template apply::type*); + void f5(typename type::template apply::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::type*); +};