Improve parsing and instantiation of destructor names, so that we can
now cope with the destruction of types named as dependent templates,
e.g.,

  y->template Y<T>::~Y()

Nominally, we implement C++0x [basic.lookup.qual]p6. However, we don't
follow the letter of the standard here because that would fail to
parse

  template<typename T, typename U>
  X0<T, U>::~X0() { }

properly. The problem is captured in core issue 339, which gives some
(but not enough!) guidance. I expect to revisit this code when the
resolution of 339 is clear, and/or we start capturing better source
information for DeclarationNames.

Fixes PR6152.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@96367 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3c0adbe..25ca3d1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2056,6 +2056,12 @@
                                SourceLocation Loc,                                    
                       ASTOwningVector<&ActionBase::DeleteExpr> &ConvertedArgs);
     
+  virtual TypeTy *getDestructorName(SourceLocation TildeLoc,
+                                    IdentifierInfo &II, SourceLocation NameLoc,
+                                    Scope *S, const CXXScopeSpec &SS,
+                                    TypeTy *ObjectType,
+                                    bool EnteringContext);
+
   /// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's.
   virtual OwningExprResult ActOnCXXNamedCast(SourceLocation OpLoc,
                                              tok::TokenKind Kind,
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 9eeda54..4098d0f 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -24,6 +24,232 @@
 #include "llvm/ADT/STLExtras.h"
 using namespace clang;
 
+Action::TypeTy *Sema::getDestructorName(SourceLocation TildeLoc,
+                                        IdentifierInfo &II, 
+                                        SourceLocation NameLoc,
+                                        Scope *S, const CXXScopeSpec &SS,
+                                        TypeTy *ObjectTypePtr,
+                                        bool EnteringContext) {
+  // Determine where to perform name lookup.
+
+  // FIXME: This area of the standard is very messy, and the current
+  // wording is rather unclear about which scopes we search for the
+  // destructor name; see core issues 399 and 555. Issue 399 in
+  // particular shows where the current description of destructor name
+  // lookup is completely out of line with existing practice, e.g.,
+  // this appears to be ill-formed:
+  //
+  //   namespace N {
+  //     template <typename T> struct S {
+  //       ~S();
+  //     };
+  //   }
+  //
+  //   void f(N::S<int>* s) {
+  //     s->N::S<int>::~S();
+  //   }
+  //
+  // 
+  QualType SearchType;
+  DeclContext *LookupCtx = 0;
+  bool isDependent = false;
+  bool LookInScope = false;
+
+  // If we have an object type, it's because we are in a
+  // pseudo-destructor-expression or a member access expression, and
+  // we know what type we're looking for.
+  if (ObjectTypePtr)
+    SearchType = GetTypeFromParser(ObjectTypePtr);
+
+  if (SS.isSet()) {
+    // C++ [basic.lookup.qual]p6:
+    //   If a pseudo-destructor-name (5.2.4) contains a
+    //   nested-name-specifier, the type-names are looked up as types
+    //   in the scope designated by the nested-name-specifier. Similarly, in 
+    //   a qualified-id of theform:
+    //
+    //     :: [opt] nested-name-specifier[opt] class-name :: ~class-name 
+    //
+    //   the second class-name is looked up in the same scope as the first.
+    //
+    // To implement this, we look at the prefix of the
+    // nested-name-specifier we were given, and determine the lookup
+    // context from that.
+    NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep();
+    if (NestedNameSpecifier *Prefix = NNS->getPrefix()) {
+      CXXScopeSpec PrefixSS;
+      PrefixSS.setScopeRep(Prefix);
+      LookupCtx = computeDeclContext(PrefixSS, EnteringContext);
+      isDependent = isDependentScopeSpecifier(PrefixSS);
+    } else if (ObjectTypePtr) {
+      LookupCtx = computeDeclContext(SearchType);
+      isDependent = SearchType->isDependentType();
+    } else {
+      LookupCtx = computeDeclContext(SS, EnteringContext);
+      if (LookupCtx && !LookupCtx->isTranslationUnit()) {
+        LookupCtx = LookupCtx->getParent();
+        isDependent = LookupCtx->isDependentContext();
+      } else {
+        isDependent = false;
+      }
+    }
+
+    LookInScope = false;
+  } else if (ObjectTypePtr) {
+    // C++ [basic.lookup.classref]p3:
+    //   If the unqualified-id is ~type-name, the type-name is looked up
+    //   in the context of the entire postfix-expression. If the type T
+    //   of the object expression is of a class type C, the type-name is
+    //   also looked up in the scope of class C. At least one of the
+    //   lookups shall find a name that refers to (possibly
+    //   cv-qualified) T.
+    LookupCtx = computeDeclContext(SearchType);
+    isDependent = SearchType->isDependentType();
+    assert((isDependent || !SearchType->isIncompleteType()) && 
+           "Caller should have completed object type");
+
+    LookInScope = true;
+  } else {
+    // Perform lookup into the current scope (only).
+    LookInScope = true;
+  }
+
+  LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName);
+  for (unsigned Step = 0; Step != 2; ++Step) {
+    // Look for the name first in the computed lookup context (if we
+    // have one) and, if that fails to find a match, in the sope (if
+    // we're allowed to look there).
+    Found.clear();
+    if (Step == 0 && LookupCtx)
+      LookupQualifiedName(Found, LookupCtx);
+    else if (Step == 1 && LookInScope)
+      LookupName(Found, S);
+    else
+      continue;
+
+    // FIXME: Should we be suppressing ambiguities here?
+    if (Found.isAmbiguous())
+      return 0;
+
+    if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
+      QualType T = Context.getTypeDeclType(Type);
+      // If we found the injected-class-name of a class template, retrieve the
+      // type of that template.
+      // FIXME: We really shouldn't need to do this.
+      if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Type))
+        if (Record->isInjectedClassName())
+          if (Record->getDescribedClassTemplate())
+            T = Record->getDescribedClassTemplate()
+                                           ->getInjectedClassNameType(Context);
+
+      if (SearchType.isNull() || SearchType->isDependentType() ||
+          Context.hasSameUnqualifiedType(T, SearchType)) {
+        // We found our type!
+
+        return T.getAsOpaquePtr();
+      }
+    }
+
+    // If the name that we found is a class template name, and it is
+    // the same name as the template name in the last part of the
+    // nested-name-specifier (if present) or the object type, then
+    // this is the destructor for that class.
+    // FIXME: This is a workaround until we get real drafting for core
+    // issue 399, for which there isn't even an obvious direction. 
+    if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) {
+      QualType MemberOfType;
+      if (SS.isSet()) {
+        if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) {
+          // Figure out the type of the context, if it has one.
+          if (ClassTemplateSpecializationDecl *Spec
+                          = dyn_cast<ClassTemplateSpecializationDecl>(Ctx))
+            MemberOfType = Context.getTypeDeclType(Spec);
+          else if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) {
+            if (Record->getDescribedClassTemplate())
+              MemberOfType = Record->getDescribedClassTemplate()
+                                          ->getInjectedClassNameType(Context);
+            else
+              MemberOfType = Context.getTypeDeclType(Record);
+          }
+        }
+      }
+      if (MemberOfType.isNull())
+        MemberOfType = SearchType;
+      
+      if (MemberOfType.isNull())
+        continue;
+
+      // We're referring into a class template specialization. If the
+      // class template we found is the same as the template being
+      // specialized, we found what we are looking for.
+      if (const RecordType *Record = MemberOfType->getAs<RecordType>()) {
+        if (ClassTemplateSpecializationDecl *Spec
+              = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
+          if (Spec->getSpecializedTemplate()->getCanonicalDecl() ==
+                Template->getCanonicalDecl())
+            return MemberOfType.getAsOpaquePtr();
+        }
+
+        continue;
+      }
+      
+      // We're referring to an unresolved class template
+      // specialization. Determine whether we class template we found
+      // is the same as the template being specialized or, if we don't
+      // know which template is being specialized, that it at least
+      // has the same name.
+      if (const TemplateSpecializationType *SpecType
+            = MemberOfType->getAs<TemplateSpecializationType>()) {
+        TemplateName SpecName = SpecType->getTemplateName();
+
+        // The class template we found is the same template being
+        // specialized.
+        if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) {
+          if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl())
+            return MemberOfType.getAsOpaquePtr();
+
+          continue;
+        }
+
+        // The class template we found has the same name as the
+        // (dependent) template name being specialized.
+        if (DependentTemplateName *DepTemplate 
+                                    = SpecName.getAsDependentTemplateName()) {
+          if (DepTemplate->isIdentifier() &&
+              DepTemplate->getIdentifier() == Template->getIdentifier())
+            return MemberOfType.getAsOpaquePtr();
+
+          continue;
+        }
+      }
+    }
+  }
+
+  if (isDependent) {
+    // We didn't find our type, but that's okay: it's dependent
+    // anyway.
+    NestedNameSpecifier *NNS = 0;
+    SourceRange Range;
+    if (SS.isSet()) {
+      NNS = (NestedNameSpecifier *)SS.getScopeRep();
+      Range = SourceRange(SS.getRange().getBegin(), NameLoc);
+    } else {
+      NNS = NestedNameSpecifier::Create(Context, &II);
+      Range = SourceRange(NameLoc);
+    }
+
+    return CheckTypenameType(NNS, II, Range).getAsOpaquePtr();
+  }
+
+  if (ObjectTypePtr)
+    Diag(NameLoc, diag::err_ident_in_pseudo_dtor_not_a_type)
+      << &II;        
+  else
+    Diag(NameLoc, diag::err_destructor_class_name);
+
+  return 0;
+}
+
 /// ActOnCXXTypeidOfType - Parse typeid( type-id ).
 Action::OwningExprResult
 Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 10e411f..c98f88f 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -4911,18 +4911,21 @@
     /// \brief Transforms a typename type by determining whether the type now
     /// refers to a member of the current instantiation, and then
     /// type-checking and building a QualifiedNameType (when possible).
-    QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL);
+    QualType TransformTypenameType(TypeLocBuilder &TLB, TypenameTypeLoc TL, 
+                                   QualType ObjectType);
   };
 }
 
 QualType
 CurrentInstantiationRebuilder::TransformTypenameType(TypeLocBuilder &TLB,
-                                                     TypenameTypeLoc TL) {
+                                                     TypenameTypeLoc TL, 
+                                                     QualType ObjectType) {
   TypenameType *T = TL.getTypePtr();
 
   NestedNameSpecifier *NNS
     = TransformNestedNameSpecifier(T->getQualifier(),
-                              /*FIXME:*/SourceRange(getBaseLocation()));
+                                   /*FIXME:*/SourceRange(getBaseLocation()),
+                                   ObjectType);
   if (!NNS)
     return QualType();
 
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 51e17fe..f12c559 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -570,7 +570,8 @@
     /// \brief Transforms a template type parameter type by performing
     /// substitution of the corresponding template type argument.
     QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB,
-                                           TemplateTypeParmTypeLoc TL);
+                                           TemplateTypeParmTypeLoc TL,
+                                           QualType ObjectType);
   };
 }
 
@@ -859,7 +860,8 @@
 
 QualType
 TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB,
-                                                TemplateTypeParmTypeLoc TL) {
+                                                TemplateTypeParmTypeLoc TL, 
+                                                    QualType ObjectType) {
   TemplateTypeParmType *T = TL.getTypePtr();
   if (T->getDepth() < TemplateArgs.getNumLevels()) {
     // Replace the template type parameter with its corresponding
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index fc069f7..a596086 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -191,7 +191,7 @@
   /// switched to storing TypeSourceInfos.
   ///
   /// \returns the transformed type.
-  QualType TransformType(QualType T);
+  QualType TransformType(QualType T, QualType ObjectType = QualType());
 
   /// \brief Transforms the given type-with-location into a new
   /// type-with-location.
@@ -201,13 +201,15 @@
   /// may override this function (to take over all type
   /// transformations) or some set of the TransformXXXType functions
   /// to alter the transformation.
-  TypeSourceInfo *TransformType(TypeSourceInfo *DI);
+  TypeSourceInfo *TransformType(TypeSourceInfo *DI, 
+                                QualType ObjectType = QualType());
 
   /// \brief Transform the given type-with-location into a new
   /// type, collecting location information in the given builder
   /// as necessary.
   ///
-  QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL);
+  QualType TransformType(TypeLocBuilder &TLB, TypeLoc TL, 
+                         QualType ObjectType = QualType());
 
   /// \brief Transform the given statement.
   ///
@@ -307,20 +309,17 @@
 
 #define ABSTRACT_TYPELOC(CLASS, PARENT)
 #define TYPELOC(CLASS, PARENT)                                   \
-  QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T);
+  QualType Transform##CLASS##Type(TypeLocBuilder &TLB, CLASS##TypeLoc T, \
+                                  QualType ObjectType = QualType());
 #include "clang/AST/TypeLocNodes.def"
 
-  QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL);
+  QualType TransformReferenceType(TypeLocBuilder &TLB, ReferenceTypeLoc TL, 
+                                  QualType ObjectType);
 
   QualType 
   TransformTemplateSpecializationType(const TemplateSpecializationType *T,
                                       QualType ObjectType);
 
-  QualType
-  TransformTemplateSpecializationType(TypeLocBuilder &TLB,
-                                      TemplateSpecializationTypeLoc TL,
-                                      QualType ObjectType);
-  
   OwningStmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
 
 #define STMT(Node, Parent)                        \
@@ -1779,7 +1778,8 @@
   case NestedNameSpecifier::TypeSpecWithTemplate:
   case NestedNameSpecifier::TypeSpec: {
     TemporaryBase Rebase(*this, Range.getBegin(), DeclarationName());
-    QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0));
+    QualType T = getDerived().TransformType(QualType(NNS->getAsType(), 0),
+                                            ObjectType);
     if (T.isNull())
       return 0;
 
@@ -1820,14 +1820,8 @@
   case DeclarationName::CXXDestructorName:
   case DeclarationName::CXXConversionFunctionName: {
     TemporaryBase Rebase(*this, Loc, Name);
-    QualType T;
-    if (!ObjectType.isNull() && 
-        isa<TemplateSpecializationType>(Name.getCXXNameType())) {
-      TemplateSpecializationType *SpecType
-        = cast<TemplateSpecializationType>(Name.getCXXNameType());
-      T = TransformTemplateSpecializationType(SpecType, ObjectType);
-    } else
-      T = getDerived().TransformType(Name.getCXXNameType());
+    QualType T = getDerived().TransformType(Name.getCXXNameType(), 
+                                            ObjectType);
     if (T.isNull())
       return DeclarationName();
 
@@ -1847,7 +1841,8 @@
   if (QualifiedTemplateName *QTN = Name.getAsQualifiedTemplateName()) {
     NestedNameSpecifier *NNS
       = getDerived().TransformNestedNameSpecifier(QTN->getQualifier(),
-                      /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+                        /*FIXME:*/SourceRange(getDerived().getBaseLocation()),
+                                                  ObjectType);
     if (!NNS)
       return TemplateName();
 
@@ -1873,7 +1868,8 @@
   if (DependentTemplateName *DTN = Name.getAsDependentTemplateName()) {
     NestedNameSpecifier *NNS
       = getDerived().TransformNestedNameSpecifier(DTN->getQualifier(),
-                        /*FIXME:*/SourceRange(getDerived().getBaseLocation()));
+                        /*FIXME:*/SourceRange(getDerived().getBaseLocation()),
+                                                  ObjectType);
     if (!NNS && DTN->getQualifier())
       return TemplateName();
 
@@ -2055,7 +2051,8 @@
 //===----------------------------------------------------------------------===//
 
 template<typename Derived>
-QualType TreeTransform<Derived>::TransformType(QualType T) {
+QualType TreeTransform<Derived>::TransformType(QualType T, 
+                                               QualType ObjectType) {
   if (getDerived().AlreadyTransformed(T))
     return T;
 
@@ -2064,7 +2061,7 @@
   TypeSourceInfo *DI = getSema().Context.CreateTypeSourceInfo(T);
   DI->getTypeLoc().initialize(getDerived().getBaseLocation());
   
-  TypeSourceInfo *NewDI = getDerived().TransformType(DI);
+  TypeSourceInfo *NewDI = getDerived().TransformType(DI, ObjectType);
 
   if (!NewDI)
     return QualType();
@@ -2073,7 +2070,8 @@
 }
 
 template<typename Derived>
-TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI) {
+TypeSourceInfo *TreeTransform<Derived>::TransformType(TypeSourceInfo *DI,
+                                                      QualType ObjectType) {
   if (getDerived().AlreadyTransformed(DI->getType()))
     return DI;
 
@@ -2082,7 +2080,7 @@
   TypeLoc TL = DI->getTypeLoc();
   TLB.reserve(TL.getFullDataSize());
 
-  QualType Result = getDerived().TransformType(TLB, TL);
+  QualType Result = getDerived().TransformType(TLB, TL, ObjectType);
   if (Result.isNull())
     return 0;
 
@@ -2091,12 +2089,14 @@
 
 template<typename Derived>
 QualType
-TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T) {
+TreeTransform<Derived>::TransformType(TypeLocBuilder &TLB, TypeLoc T,
+                                      QualType ObjectType) {
   switch (T.getTypeLocClass()) {
 #define ABSTRACT_TYPELOC(CLASS, PARENT)
 #define TYPELOC(CLASS, PARENT) \
   case TypeLoc::CLASS: \
-    return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T));
+    return getDerived().Transform##CLASS##Type(TLB, cast<CLASS##TypeLoc>(T), \
+                                               ObjectType);
 #include "clang/AST/TypeLocNodes.def"
   }
 
@@ -2112,10 +2112,12 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformQualifiedType(TypeLocBuilder &TLB,
-                                               QualifiedTypeLoc T) {
+                                               QualifiedTypeLoc T,
+                                               QualType ObjectType) {
   Qualifiers Quals = T.getType().getLocalQualifiers();
 
-  QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc());
+  QualType Result = getDerived().TransformType(TLB, T.getUnqualifiedLoc(),
+                                               ObjectType);
   if (Result.isNull())
     return QualType();
 
@@ -2166,7 +2168,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformBuiltinType(TypeLocBuilder &TLB,
-                                                      BuiltinTypeLoc T) {
+                                                      BuiltinTypeLoc T,
+                                                      QualType ObjectType) {
   BuiltinTypeLoc NewT = TLB.push<BuiltinTypeLoc>(T.getType());
   NewT.setBuiltinLoc(T.getBuiltinLoc());
   if (T.needsExtraLocalData())
@@ -2176,21 +2179,24 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformComplexType(TypeLocBuilder &TLB,
-                                                      ComplexTypeLoc T) {
+                                                      ComplexTypeLoc T,
+                                                      QualType ObjectType) {
   // FIXME: recurse?
   return TransformTypeSpecType(TLB, T);
 }
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformPointerType(TypeLocBuilder &TLB,
-                                                      PointerTypeLoc TL) {
+                                                      PointerTypeLoc TL, 
+                                                      QualType ObjectType) {
   TransformPointerLikeType(PointerType);
 }
 
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformBlockPointerType(TypeLocBuilder &TLB,
-                                                  BlockPointerTypeLoc TL) {
+                                                  BlockPointerTypeLoc TL,
+                                                  QualType ObjectType) {
   TransformPointerLikeType(BlockPointerType);
 }
 
@@ -2201,7 +2207,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformReferenceType(TypeLocBuilder &TLB,
-                                               ReferenceTypeLoc TL) {
+                                               ReferenceTypeLoc TL,
+                                               QualType ObjectType) {
   const ReferenceType *T = TL.getTypePtr();
 
   // Note that this works with the pointee-as-written.
@@ -2233,21 +2240,24 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformLValueReferenceType(TypeLocBuilder &TLB,
-                                                 LValueReferenceTypeLoc TL) {
-  return TransformReferenceType(TLB, TL);
+                                                 LValueReferenceTypeLoc TL,
+                                                     QualType ObjectType) {
+  return TransformReferenceType(TLB, TL, ObjectType);
 }
 
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformRValueReferenceType(TypeLocBuilder &TLB,
-                                                 RValueReferenceTypeLoc TL) {
-  return TransformReferenceType(TLB, TL);
+                                                 RValueReferenceTypeLoc TL,
+                                                     QualType ObjectType) {
+  return TransformReferenceType(TLB, TL, ObjectType);
 }
 
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformMemberPointerType(TypeLocBuilder &TLB,
-                                                   MemberPointerTypeLoc TL) {
+                                                   MemberPointerTypeLoc TL,
+                                                   QualType ObjectType) {
   MemberPointerType *T = TL.getTypePtr();
 
   QualType PointeeType = getDerived().TransformType(TLB, TL.getPointeeLoc());
@@ -2279,7 +2289,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformConstantArrayType(TypeLocBuilder &TLB,
-                                                   ConstantArrayTypeLoc TL) {
+                                                   ConstantArrayTypeLoc TL,
+                                                   QualType ObjectType) {
   ConstantArrayType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
   if (ElementType.isNull())
@@ -2314,7 +2325,8 @@
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformIncompleteArrayType(
                                               TypeLocBuilder &TLB,
-                                              IncompleteArrayTypeLoc TL) {
+                                              IncompleteArrayTypeLoc TL,
+                                              QualType ObjectType) {
   IncompleteArrayType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
   if (ElementType.isNull())
@@ -2342,7 +2354,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformVariableArrayType(TypeLocBuilder &TLB,
-                                                   VariableArrayTypeLoc TL) {
+                                                   VariableArrayTypeLoc TL,
+                                                   QualType ObjectType) {
   VariableArrayType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
   if (ElementType.isNull())
@@ -2383,7 +2396,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformDependentSizedArrayType(TypeLocBuilder &TLB,
-                                             DependentSizedArrayTypeLoc TL) {
+                                             DependentSizedArrayTypeLoc TL,
+                                                        QualType ObjectType) {
   DependentSizedArrayType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(TLB, TL.getElementLoc());
   if (ElementType.isNull())
@@ -2426,7 +2440,8 @@
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType(
                                       TypeLocBuilder &TLB,
-                                      DependentSizedExtVectorTypeLoc TL) {
+                                      DependentSizedExtVectorTypeLoc TL,
+                                      QualType ObjectType) {
   DependentSizedExtVectorType *T = TL.getTypePtr();
 
   // FIXME: ext vector locs should be nested
@@ -2468,7 +2483,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformVectorType(TypeLocBuilder &TLB,
-                                                     VectorTypeLoc TL) {
+                                                     VectorTypeLoc TL,
+                                                     QualType ObjectType) {
   VectorType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(T->getElementType());
   if (ElementType.isNull())
@@ -2491,7 +2507,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformExtVectorType(TypeLocBuilder &TLB,
-                                                        ExtVectorTypeLoc TL) {
+                                                        ExtVectorTypeLoc TL,
+                                                        QualType ObjectType) {
   VectorType *T = TL.getTypePtr();
   QualType ElementType = getDerived().TransformType(T->getElementType());
   if (ElementType.isNull())
@@ -2516,7 +2533,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformFunctionProtoType(TypeLocBuilder &TLB,
-                                                   FunctionProtoTypeLoc TL) {
+                                                   FunctionProtoTypeLoc TL,
+                                                   QualType ObjectType) {
   FunctionProtoType *T = TL.getTypePtr();
   QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
   if (ResultType.isNull())
@@ -2592,7 +2610,8 @@
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformFunctionNoProtoType(
                                                  TypeLocBuilder &TLB,
-                                                 FunctionNoProtoTypeLoc TL) {
+                                                 FunctionNoProtoTypeLoc TL,
+                                                 QualType ObjectType) {
   FunctionNoProtoType *T = TL.getTypePtr();
   QualType ResultType = getDerived().TransformType(TLB, TL.getResultLoc());
   if (ResultType.isNull())
@@ -2612,7 +2631,8 @@
 
 template<typename Derived> QualType
 TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB,
-                                                 UnresolvedUsingTypeLoc TL) {
+                                                 UnresolvedUsingTypeLoc TL,
+                                                     QualType ObjectType) {
   UnresolvedUsingType *T = TL.getTypePtr();
   Decl *D = getDerived().TransformDecl(T->getDecl());
   if (!D)
@@ -2635,7 +2655,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTypedefType(TypeLocBuilder &TLB,
-                                                      TypedefTypeLoc TL) {
+                                                      TypedefTypeLoc TL,
+                                                      QualType ObjectType) {
   TypedefType *T = TL.getTypePtr();
   TypedefDecl *Typedef
     = cast_or_null<TypedefDecl>(getDerived().TransformDecl(T->getDecl()));
@@ -2658,7 +2679,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTypeOfExprType(TypeLocBuilder &TLB,
-                                                      TypeOfExprTypeLoc TL) {
+                                                      TypeOfExprTypeLoc TL,
+                                                       QualType ObjectType) {
   // typeof expressions are not potentially evaluated contexts
   EnterExpressionEvaluationContext Unevaluated(SemaRef, Action::Unevaluated);
 
@@ -2685,7 +2707,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTypeOfType(TypeLocBuilder &TLB,
-                                                     TypeOfTypeLoc TL) {
+                                                     TypeOfTypeLoc TL,
+                                                     QualType ObjectType) {
   TypeSourceInfo* Old_Under_TI = TL.getUnderlyingTInfo();
   TypeSourceInfo* New_Under_TI = getDerived().TransformType(Old_Under_TI);
   if (!New_Under_TI)
@@ -2709,7 +2732,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformDecltypeType(TypeLocBuilder &TLB,
-                                                       DecltypeTypeLoc TL) {
+                                                       DecltypeTypeLoc TL,
+                                                       QualType ObjectType) {
   DecltypeType *T = TL.getTypePtr();
 
   // decltype expressions are not potentially evaluated contexts
@@ -2736,7 +2760,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformRecordType(TypeLocBuilder &TLB,
-                                                     RecordTypeLoc TL) {
+                                                     RecordTypeLoc TL,
+                                                     QualType ObjectType) {
   RecordType *T = TL.getTypePtr();
   RecordDecl *Record
     = cast_or_null<RecordDecl>(getDerived().TransformDecl(T->getDecl()));
@@ -2759,7 +2784,8 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformEnumType(TypeLocBuilder &TLB,
-                                                   EnumTypeLoc TL) {
+                                                   EnumTypeLoc TL,
+                                                   QualType ObjectType) {
   EnumType *T = TL.getTypePtr();
   EnumDecl *Enum
     = cast_or_null<EnumDecl>(getDerived().TransformDecl(T->getDecl()));
@@ -2782,7 +2808,8 @@
 
 template <typename Derived>
 QualType TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB,
-                                                      ElaboratedTypeLoc TL) {
+                                                         ElaboratedTypeLoc TL,
+                                                       QualType ObjectType) {
   ElaboratedType *T = TL.getTypePtr();
 
   // FIXME: this should be a nested type.
@@ -2808,26 +2835,20 @@
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTemplateTypeParmType(
                                                 TypeLocBuilder &TLB,
-                                                TemplateTypeParmTypeLoc TL) {
+                                                TemplateTypeParmTypeLoc TL,
+                                                QualType ObjectType) {
   return TransformTypeSpecType(TLB, TL);
 }
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType(
                                          TypeLocBuilder &TLB,
-                                         SubstTemplateTypeParmTypeLoc TL) {
+                                         SubstTemplateTypeParmTypeLoc TL,
+                                         QualType ObjectType) {
   return TransformTypeSpecType(TLB, TL);
 }
 
 template<typename Derived>
-inline QualType 
-TreeTransform<Derived>::TransformTemplateSpecializationType(
-                                          TypeLocBuilder &TLB,
-                                          TemplateSpecializationTypeLoc TL) {
-  return TransformTemplateSpecializationType(TLB, TL, QualType());
-}
-
-template<typename Derived>
 QualType TreeTransform<Derived>::TransformTemplateSpecializationType(
                                       const TemplateSpecializationType *TST,
                                                         QualType ObjectType) {
@@ -2901,11 +2922,13 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformQualifiedNameType(TypeLocBuilder &TLB,
-                                                   QualifiedNameTypeLoc TL) {
+                                                   QualifiedNameTypeLoc TL,
+                                                   QualType ObjectType) {
   QualifiedNameType *T = TL.getTypePtr();
   NestedNameSpecifier *NNS
     = getDerived().TransformNestedNameSpecifier(T->getQualifier(),
-                                                SourceRange());
+                                                SourceRange(),
+                                                ObjectType);
   if (!NNS)
     return QualType();
 
@@ -2930,14 +2953,16 @@
 
 template<typename Derived>
 QualType TreeTransform<Derived>::TransformTypenameType(TypeLocBuilder &TLB,
-                                                       TypenameTypeLoc TL) {
+                                                       TypenameTypeLoc TL,
+                                                       QualType ObjectType) {
   TypenameType *T = TL.getTypePtr();
 
   /* FIXME: preserve source information better than this */
   SourceRange SR(TL.getNameLoc());
 
   NestedNameSpecifier *NNS
-    = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR);
+    = getDerived().TransformNestedNameSpecifier(T->getQualifier(), SR,
+                                                ObjectType);
   if (!NNS)
     return QualType();
 
@@ -2970,7 +2995,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB,
-                                                   ObjCInterfaceTypeLoc TL) {
+                                                   ObjCInterfaceTypeLoc TL,
+                                                   QualType ObjectType) {
   assert(false && "TransformObjCInterfaceType unimplemented");
   return QualType();
 }
@@ -2978,7 +3004,8 @@
 template<typename Derived>
 QualType
 TreeTransform<Derived>::TransformObjCObjectPointerType(TypeLocBuilder &TLB,
-                                               ObjCObjectPointerTypeLoc TL) {
+                                               ObjCObjectPointerTypeLoc TL,
+                                                       QualType ObjectType) {
   assert(false && "TransformObjCObjectPointerType unimplemented");
   return QualType();
 }