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
This commit is contained in:
Douglas Gregor 2010-11-04 00:09:33 +00:00
parent 2eed7a1310
commit 3ade5704fe
2 changed files with 44 additions and 3 deletions

View File

@ -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<DependentNameType>()) {
NestedNameSpecifier *Prefix
= getCanonicalNestedNameSpecifier(DNT->getQualifier());
return NestedNameSpecifier::Create(*this, Prefix,
const_cast<IdentifierInfo *>(DNT->getIdentifier()));
}
if (const DependentTemplateSpecializationType *DTST
= T->getAs<DependentTemplateSpecializationType>()) {
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:

View File

@ -117,3 +117,20 @@ namespace PR6463 {
return x;
}
}
namespace PR7419 {
template <typename T> struct S {
typedef typename T::Y T2;
typedef typename T2::Z T3;
typedef typename T3::W T4;
T4 *f();
typedef typename T::template Y<int> TT2;
typedef typename TT2::template Z<float> TT3;
typedef typename TT3::template W<double> TT4;
TT4 g();
};
template <typename T> typename T::Y::Z::W *S<T>::f() { }
template <typename T> typename T::template Y<int>::template Z<float>::template W<double> S<T>::g() { }
}