From 3ade5704fe9ba52a5345e423a31d0f04f7919608 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 4 Nov 2010 00:09:33 +0000 Subject: [PATCH] When canonicalizing nested-name-specifiers involving dependent names or dependent specializations, rip apart the dependent name/dependent specialization to recanonicalize its pieces, because nested-name-specifiers store "dependent-type::identifier" differently than types do. Fixes PR7419. llvm-svn: 118211 --- clang/lib/AST/ASTContext.cpp | 30 +++++++++++++++++-- .../SemaTemplate/typename-specifier-4.cpp | 17 +++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 366fe7d28f17..7ed1035c0f1b 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -2723,9 +2723,33 @@ ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) { case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { QualType T = getCanonicalType(QualType(NNS->getAsType(), 0)); - return NestedNameSpecifier::Create(*this, 0, - NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, - T.getTypePtr()); + + // If we have some kind of dependent-named type (e.g., "typename T::type"), + // break it apart into its prefix and identifier, then reconsititute those + // as the canonical nested-name-specifier. This is required to canonicalize + // a dependent nested-name-specifier involving typedefs of dependent-name + // types, e.g., + // typedef typename T::type T1; + // typedef typename T1::type T2; + if (const DependentNameType *DNT = T->getAs()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DNT->getQualifier()); + return NestedNameSpecifier::Create(*this, Prefix, + const_cast(DNT->getIdentifier())); + } + + if (const DependentTemplateSpecializationType *DTST + = T->getAs()) { + NestedNameSpecifier *Prefix + = getCanonicalNestedNameSpecifier(DTST->getQualifier()); + TemplateName Name + = getDependentTemplateName(Prefix, DTST->getIdentifier()); + T = getTemplateSpecializationType(Name, + DTST->getArgs(), DTST->getNumArgs()); + T = getCanonicalType(T); + } + + return NestedNameSpecifier::Create(*this, 0, false, T.getTypePtr()); } case NestedNameSpecifier::Global: diff --git a/clang/test/SemaTemplate/typename-specifier-4.cpp b/clang/test/SemaTemplate/typename-specifier-4.cpp index 5a313bf2256a..f5bc7477dd4e 100644 --- a/clang/test/SemaTemplate/typename-specifier-4.cpp +++ b/clang/test/SemaTemplate/typename-specifier-4.cpp @@ -117,3 +117,20 @@ namespace PR6463 { return x; } } + +namespace PR7419 { + template struct S { + typedef typename T::Y T2; + typedef typename T2::Z T3; + typedef typename T3::W T4; + T4 *f(); + + typedef typename T::template Y TT2; + typedef typename TT2::template Z TT3; + typedef typename TT3::template W TT4; + TT4 g(); + }; + + template typename T::Y::Z::W *S::f() { } + template typename T::template Y::template Z::template W S::g() { } +}