Instantiation for member classes of class templates. Note that only
the declarations of member classes are instantiated when the owning
class template is instantiated. The definitions of such member classes
are instantiated when a complete type is required.

This change also introduces the injected-class-name into a class
template specialization.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67707 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index c689b77..e1f1095 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -18,6 +18,8 @@
 #include "llvm/ADT/SmallVector.h"
 
 namespace clang {
+
+class ClassTemplateDecl;
 class CXXRecordDecl;
 class CXXConstructorDecl;
 class CXXDestructorDecl;
@@ -236,6 +238,17 @@
   /// CXXConversionDecl.
   OverloadedFunctionDecl Conversions;
 
+  /// \brief The template or declaration that is declaration is
+  /// instantiated from.
+  /// 
+  /// For non-templates, this value will be NULL. For record
+  /// declarations that describe a class template, this will be a
+  /// pointer to a ClassTemplateDecl (the bit is 0). For member
+  /// classes of class template specializations, this will be the
+  /// RecordDecl from which the member class was instantiated (the bit
+  /// is 1).
+  llvm::PointerIntPair<Decl*, 1> TemplateOrInstantiation;
+
 protected:
   CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
                 SourceLocation L, IdentifierInfo *Id);
@@ -294,7 +307,7 @@
 
   /// addedAssignmentOperator - Notify the class that another assignment
   /// operator has been added. This routine helps maintain information about the
-  /// class based on which operators have been added.
+   /// class based on which operators have been added.
   void addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl);
 
   /// hasUserDeclaredCopyAssignment - Whether this class has a
@@ -363,6 +376,49 @@
   /// setAbstract - Set whether this class is abstract (C++ [class.abstract])
   void setAbstract(bool Abs) { Abstract = Abs; }
   
+  /// \brief If this record is an instantiation of a member class,
+  /// retrieves the member class from which it was instantiated.
+  ///
+  /// This routine will return non-NULL for (non-templated) member
+  /// classes of class templates. For example, given:
+  ///
+  /// \code
+  /// template<typename T>
+  /// struct X {
+  ///   struct A { };
+  /// };
+  /// \endcode
+  ///
+  /// The declaration for X<int>::A is a (non-templated) CXXRecordDecl
+  /// whose parent is the class template specialization X<int>. For
+  /// this declaration, getInstantiatedFromMemberClass() will return
+  /// the CXXRecordDecl X<T>::A. When a complete definition of
+  /// X<int>::A is required, it will be instantiated from the
+  /// declaration returned by getInstantiatedFromMemberClass().
+  CXXRecordDecl *getInstantiatedFromMemberClass();
+
+  /// \brief Specify that this record is an instantiation of the
+  /// member class RD.
+  void setInstantiationOfMemberClass(CXXRecordDecl *RD) { 
+    TemplateOrInstantiation.setInt(1);
+    TemplateOrInstantiation.setPointer(RD);
+  }
+
+  /// \brief Retrieves the class template that is described by this
+  /// class declaration.
+  ///
+  /// Every class template is represented as a ClassTemplateDecl and a
+  /// CXXRecordDecl. The former contains template properties (such as
+  /// the template parameter lists) while the latter contains the
+  /// actual description of the template's
+  /// contents. ClassTemplateDecl::getTemplatedDecl() retrieves the
+  /// CXXRecordDecl that from a ClassTemplateDecl, while
+  /// getDescribedClassTemplate() retrieves the ClassTemplateDecl from
+  /// a CXXRecordDecl.
+  ClassTemplateDecl *getDescribedClassTemplate();
+
+  void setDescribedClassTemplate(ClassTemplateDecl *Template);
+
   /// viewInheritance - Renders and displays an inheritance diagram
   /// for this C++ class and all of its base classes (transitively) using
   /// GraphViz.
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index bdfbffa..fb194fe 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -573,6 +573,7 @@
 
 
 def note_template_decl_here : Note<"template is declared here">;
+def note_member_of_template_here : Note<"member is declared here">;
 def err_template_arg_must_be_type : Error<
   "template argument for template type parameter must be a type">;
 def err_template_arg_must_be_expr : Error<
@@ -666,8 +667,12 @@
 
 def err_template_implicit_instantiate_undefined : Error<
   "implicit instantiation of undefined template %0">;
+def err_implicit_instantiate_member_undefined : Error<
+  "implicit instantiation of undefined member %0">;
 def note_template_class_instantiation_here : Note<
   "in instantiation of template class %0 requested here">;
+def note_template_member_class_here : Note<
+  "in instantiation of member class %0 requested here">;
 def note_default_arg_instantiation_here : Note<
   "in instantiation of default argument for '%0' required here">;
 def err_field_instantiates_to_function : Error<
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index 33e870b..98d7d8f 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -12,6 +12,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Expr.h"
 #include "clang/Basic/IdentifierTable.h"
@@ -28,7 +29,8 @@
     UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
     UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
     Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false),
-    Bases(0), NumBases(0), Conversions(DC, DeclarationName()) { }
+    Bases(0), NumBases(0), Conversions(DC, DeclarationName()),
+    TemplateOrInstantiation() { }
 
 CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
                                      SourceLocation L, IdentifierInfo *Id,
@@ -177,6 +179,24 @@
   Conversions.addOverload(ConvDecl);
 }
 
+CXXRecordDecl *CXXRecordDecl::getInstantiatedFromMemberClass() {
+  if (TemplateOrInstantiation.getInt() == 1)
+    return cast_or_null<CXXRecordDecl>(TemplateOrInstantiation.getPointer());
+  return 0;
+}
+
+void CXXRecordDecl::setDescribedClassTemplate(ClassTemplateDecl *Template) {
+  TemplateOrInstantiation.setInt(0);
+  TemplateOrInstantiation.setPointer(Template);
+}
+
+ClassTemplateDecl *CXXRecordDecl::getDescribedClassTemplate() {
+  if (TemplateOrInstantiation.getInt() == 0)
+    return cast_or_null<ClassTemplateDecl>(
+                                     TemplateOrInstantiation.getPointer());
+  return 0;
+}
+
 CXXMethodDecl *
 CXXMethodDecl::Create(ASTContext &C, CXXRecordDecl *RD,
                       SourceLocation L, DeclarationName N,
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 42b0205..ad7aa3b 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1784,8 +1784,7 @@
     /// \brief The kind of template instantiation we are performing
     enum {
       /// We are instantiating a template declaration. The entity is
-      /// the declaration we're instantiation (e.g., a
-      /// ClassTemplateSpecializationDecl).
+      /// the declaration we're instantiation (e.g., a CXXRecordDecl).
       TemplateInstantiation,
 
       /// We are instantiating a default argument for a template
@@ -1870,7 +1869,7 @@
   struct InstantiatingTemplate {
     /// \brief Note that we are instantiating a class template.
     InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
-                          ClassTemplateSpecializationDecl *Entity,
+                          CXXRecordDecl *Entity,
                           SourceRange InstantiationRange = SourceRange());
 
     /// \brief Note that we are instantiating a default argument in a
@@ -1915,8 +1914,17 @@
                         unsigned NumTemplateArgs);
 
   bool 
-  InstantiateBaseSpecifiers(ClassTemplateSpecializationDecl *ClassTemplateSpec,
-                            ClassTemplateDecl *ClassTemplate);
+  InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+                            CXXRecordDecl *Pattern,
+                            const TemplateArgument *TemplateArgs,
+                            unsigned NumTemplateArgs);
+
+  bool
+  InstantiateClass(SourceLocation PointOfInstantiation,
+                   CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+                   const TemplateArgument *TemplateArgs,
+                   unsigned NumTemplateArgs);
+
   bool 
   InstantiateClassTemplateSpecialization(
                            ClassTemplateSpecializationDecl *ClassTemplateSpec,
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index fd89507..cc1a5b3 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3392,11 +3392,12 @@
       //   class itself; this is known as the injected-class-name. For
       //   purposes of access checking, the injected-class-name is treated
       //   as if it were a public member name.
-      RecordDecl *InjectedClassName
+      CXXRecordDecl *InjectedClassName
         = CXXRecordDecl::Create(Context, Record->getTagKind(),
                                 CurContext, Record->getLocation(),
                                 Record->getIdentifier(), Record);
       InjectedClassName->setImplicit();
+      InjectedClassName->setAccess(AS_public);
       PushOnScopeChains(InjectedClassName, S);
       assert(InjectedClassName->isInjectedClassName() && 
              "Broken injected-class-name");
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 4d271a3..60423f9 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -26,7 +26,7 @@
 
 Sema::InstantiatingTemplate::
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
-                      ClassTemplateSpecializationDecl *Entity,
+                      CXXRecordDecl *Entity,
                       SourceRange InstantiationRange)
   :  SemaRef(SemaRef) {
 
@@ -100,11 +100,13 @@
        ++Active) {
     switch (Active->Kind) {
     case ActiveTemplateInstantiation::TemplateInstantiation: {
-      ClassTemplateSpecializationDecl *Spec
-        = cast<ClassTemplateSpecializationDecl>((Decl*)Active->Entity);
+      unsigned DiagID = diag::note_template_member_class_here;
+      CXXRecordDecl *Record = (CXXRecordDecl *)Active->Entity;
+      if (isa<ClassTemplateSpecializationDecl>(Record))
+        DiagID = diag::note_template_class_instantiation_here;
       Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr), 
-                   diag::note_template_class_instantiation_here)
-        << Context.getTypeDeclType(Spec)
+                   DiagID)
+        << Context.getTypeDeclType(Record)
         << Active->InstantiationRange;
       break;
     }
@@ -591,14 +593,14 @@
 /// attaches the instantiated base classes to the class template
 /// specialization if successful.
 bool 
-Sema::InstantiateBaseSpecifiers(
-                           ClassTemplateSpecializationDecl *ClassTemplateSpec,
-                           ClassTemplateDecl *ClassTemplate) {
+Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation,
+                                CXXRecordDecl *Pattern,
+                                const TemplateArgument *TemplateArgs,
+                                unsigned NumTemplateArgs) {
   bool Invalid = false;
   llvm::SmallVector<CXXBaseSpecifier*, 8> InstantiatedBases;
-  for (ClassTemplateSpecializationDecl::base_class_iterator
-         Base = ClassTemplate->getTemplatedDecl()->bases_begin(),
-         BaseEnd = ClassTemplate->getTemplatedDecl()->bases_end();
+  for (ClassTemplateSpecializationDecl::base_class_iterator 
+         Base = Pattern->bases_begin(), BaseEnd = Pattern->bases_end();
        Base != BaseEnd; ++Base) {
     if (!Base->getType()->isDependentType()) {
       // FIXME: Allocate via ASTContext
@@ -607,8 +609,7 @@
     }
 
     QualType BaseType = InstantiateType(Base->getType(), 
-                                        ClassTemplateSpec->getTemplateArgs(),
-                                        ClassTemplateSpec->getNumTemplateArgs(),
+                                        TemplateArgs, NumTemplateArgs,
                                         Base->getSourceRange().getBegin(),
                                         DeclarationName());
     if (BaseType.isNull()) {
@@ -617,7 +618,7 @@
     }
 
     if (CXXBaseSpecifier *InstantiatedBase
-          = CheckBaseSpecifier(ClassTemplateSpec,
+          = CheckBaseSpecifier(Instantiation,
                                Base->getSourceRange(),
                                Base->isVirtual(),
                                Base->getAccessSpecifierAsWritten(),
@@ -630,13 +631,109 @@
   }
 
   if (!Invalid &&
-      AttachBaseSpecifiers(ClassTemplateSpec, &InstantiatedBases[0],
+      AttachBaseSpecifiers(Instantiation, &InstantiatedBases[0],
                            InstantiatedBases.size()))
     Invalid = true;
 
   return Invalid;
 }
 
+/// \brief Instantiate the definition of a class from a given pattern.
+///
+/// \param PointOfInstantiation The point of instantiation within the
+/// source code.
+///
+/// \param Instantiation is the declaration whose definition is being
+/// instantiated. This will be either a class template specialization
+/// or a member class of a class template specialization.
+///
+/// \param Pattern is the pattern from which the instantiation
+/// occurs. This will be either the declaration of a class template or
+/// the declaration of a member class of a class template.
+///
+/// \param TemplateArgs The template arguments to be substituted into
+/// the pattern.
+///
+/// \param NumTemplateArgs The number of templates arguments in
+/// TemplateArgs.
+///
+/// \returns true if an error occurred, false otherwise.
+bool
+Sema::InstantiateClass(SourceLocation PointOfInstantiation,
+                       CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern,
+                       const TemplateArgument *TemplateArgs,
+                       unsigned NumTemplateArgs) {
+  bool Invalid = false;
+  
+  CXXRecordDecl *PatternDef 
+    = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context));
+  if (!PatternDef) {
+    if (Pattern == Instantiation->getInstantiatedFromMemberClass()) {
+      Diag(PointOfInstantiation,
+           diag::err_implicit_instantiate_member_undefined)
+        << Context.getTypeDeclType(Instantiation);
+      Diag(Pattern->getLocation(), diag::note_member_of_template_here);
+    } else {
+      Diag(PointOfInstantiation, 
+           diag::err_template_implicit_instantiate_undefined)
+        << Context.getTypeDeclType(Instantiation);
+      Diag(Pattern->getLocation(), diag::note_template_decl_here);
+    }
+    return true;
+  }
+  Pattern = PatternDef;
+
+  InstantiatingTemplate Inst(*this, Instantiation->getLocation(),
+                             Instantiation);
+  if (Inst)
+    return true;
+
+  // Enter the scope of this instantiation. We don't use
+  // PushDeclContext because we don't have a scope.
+  DeclContext *PreviousContext = CurContext;
+  CurContext = Instantiation;
+
+  // Start the definition of this instantiation.
+  Instantiation->startDefinition();
+
+  // Instantiate the base class specifiers.
+  if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs,
+                                NumTemplateArgs))
+    Invalid = true;
+
+  llvm::SmallVector<DeclTy *, 32> Fields;
+  for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
+                              MemberEnd = Pattern->decls_end();
+       Member != MemberEnd; ++Member) {
+    Decl *NewMember = InstantiateDecl(*Member, Instantiation,
+                                      TemplateArgs, NumTemplateArgs);
+    if (NewMember) {
+      if (NewMember->isInvalidDecl())
+        Invalid = true;
+      else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
+        Fields.push_back(Field);
+    } else {
+      // FIXME: Eventually, a NULL return will mean that one of the
+      // instantiations was a semantic disaster, and we'll want to set
+      // Invalid = true. For now, we expect to skip some members that
+      // we can't yet handle.
+    }
+  }
+
+  // Finish checking fields.
+  ActOnFields(0, Instantiation->getLocation(), Instantiation,
+              &Fields[0], Fields.size(), SourceLocation(), SourceLocation(),
+              0);
+
+  // Add any implicitly-declared members that we might need.
+  AddImplicitlyDeclaredMembersToClass(Instantiation);
+
+  // Exit the scope of this instantiation.
+  CurContext = PreviousContext;
+
+  return Invalid;
+}
+
 bool 
 Sema::InstantiateClassTemplateSpecialization(
                            ClassTemplateSpecializationDecl *ClassTemplateSpec,
@@ -659,77 +756,17 @@
   // the best template.
   ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
 
-  RecordDecl *Pattern = cast_or_null<RecordDecl>(
-                          Template->getTemplatedDecl()->getDefinition(Context));
-  if (!Pattern) {
-    Diag(ClassTemplateSpec->getLocation(), 
-         diag::err_template_implicit_instantiate_undefined)
-      << Context.getTypeDeclType(ClassTemplateSpec);
-    Diag(Template->getTemplatedDecl()->getLocation(), 
-         diag::note_template_decl_here);
-    return true;
-  }
+  CXXRecordDecl *Pattern = Template->getTemplatedDecl();
 
   // Note that this is an instantiation.  
   ClassTemplateSpec->setSpecializationKind(
                         ExplicitInstantiation? TSK_ExplicitInstantiation 
                                              : TSK_ImplicitInstantiation);
 
-
-  bool Invalid = false;
-  
-  InstantiatingTemplate Inst(*this, ClassTemplateSpec->getLocation(),
-                             ClassTemplateSpec);
-  if (Inst)
-    return true;
-
-  // Enter the scope of this instantiation. We don't use
-  // PushDeclContext because we don't have a scope.
-  DeclContext *PreviousContext = CurContext;
-  CurContext = ClassTemplateSpec;
-
-  // Start the definition of this instantiation.
-  ClassTemplateSpec->startDefinition();
-
-  // Instantiate the base class specifiers.
-  if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
-    Invalid = true;
-
-  // FIXME: Create the injected-class-name for the
-  // instantiation. Should this be a typedef or something like it?
-
-  llvm::SmallVector<DeclTy *, 32> Fields;
-  for (RecordDecl::decl_iterator Member = Pattern->decls_begin(),
-                              MemberEnd = Pattern->decls_end();
-       Member != MemberEnd; ++Member) {
-    Decl *NewMember = InstantiateDecl(*Member, ClassTemplateSpec,
-                                      ClassTemplateSpec->getTemplateArgs(),
-                                      ClassTemplateSpec->getNumTemplateArgs());
-    if (NewMember) {
-      if (NewMember->isInvalidDecl())
-        Invalid = true;
-      else if (FieldDecl *Field = dyn_cast<FieldDecl>(NewMember))
-        Fields.push_back(Field);
-    } else {
-      // FIXME: Eventually, a NULL return will mean that one of the
-      // instantiations was a semantic disaster, and we'll want to set
-      // Invalid = true. For now, we expect to skip some members that
-      // we can't yet handle.
-    }
-  }
-
-  // Finish checking fields.
-  ActOnFields(0, ClassTemplateSpec->getLocation(), ClassTemplateSpec,
-              &Fields[0], Fields.size(), SourceLocation(), SourceLocation(),
-              0);
-
-  // Add any implicitly-declared members that we might need.
-  AddImplicitlyDeclaredMembersToClass(ClassTemplateSpec);
-
-  // Exit the scope of this instantiation.
-  CurContext = PreviousContext;
-
-  return Invalid;
+  return InstantiateClass(ClassTemplateSpec->getLocation(),
+                          ClassTemplateSpec, Pattern,
+                          ClassTemplateSpec->getTemplateArgs(),
+                          ClassTemplateSpec->getNumTemplateArgs());
 }
 
 /// \brief Instantiate a sequence of nested-name-specifiers into a
diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7995def..d9f6902 100644
--- a/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -46,6 +46,7 @@
     Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
     Decl *VisitEnumDecl(EnumDecl *D);
     Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+    Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
     Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
     Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
     Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
@@ -223,6 +224,24 @@
   return 0;
 }
 
+Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
+  CXXRecordDecl *PrevDecl = 0;
+  if (D->isInjectedClassName())
+    PrevDecl = cast<CXXRecordDecl>(Owner);
+
+  CXXRecordDecl *Record
+    = CXXRecordDecl::Create(SemaRef.Context, D->getTagKind(), Owner, 
+                            D->getLocation(), D->getIdentifier(), PrevDecl);
+  Record->setImplicit(D->isImplicit());
+  Record->setAccess(D->getAccess());
+
+  if (!D->isInjectedClassName())
+    Record->setInstantiationOfMemberClass(D);
+
+  Owner->addDecl(Record);
+  return Record;
+}
+
 Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
   // Only handle actual methods; we'll deal with constructors,
   // destructors, etc. separately.
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 196a306..4b25657 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1042,11 +1042,11 @@
   if (!T->isIncompleteType())
     return false;
 
-  // If we have a class template specialization, try to instantiate
-  // it.
-  if (const RecordType *Record = T->getAsRecordType())
+  // If we have a class template specialization or a class member of a
+  // class template specialization, try to instantiate it.
+  if (const RecordType *Record = T->getAsRecordType()) {
     if (ClassTemplateSpecializationDecl *ClassTemplateSpec
-          = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) 
+          = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) {
       if (ClassTemplateSpec->getSpecializationKind() == TSK_Undeclared) {
         // Update the class template specialization's location to
         // refer to the point of instantiation.
@@ -1055,7 +1055,22 @@
         return InstantiateClassTemplateSpecialization(ClassTemplateSpec,
                                              /*ExplicitInstantiation=*/false);
       }
-        
+    } else if (CXXRecordDecl *Rec 
+                 = dyn_cast<CXXRecordDecl>(Record->getDecl())) {
+      if (CXXRecordDecl *Pattern = Rec->getInstantiatedFromMemberClass()) {
+        // Find the class template specialization that surrounds this
+        // member class.
+        ClassTemplateSpecializationDecl *Spec = 0;
+        for (DeclContext *Parent = Rec->getDeclContext(); 
+             Parent && !Spec; Parent = Parent->getParent())
+          Spec = dyn_cast<ClassTemplateSpecializationDecl>(Parent);
+        assert(Spec && "Not a member of a class template specialization?");
+        return InstantiateClass(Loc, Rec, Pattern,
+                                Spec->getTemplateArgs(), 
+                                Spec->getNumTemplateArgs());
+      }
+    }
+  }
 
   if (PrintType.isNull())
     PrintType = T;
diff --git a/test/SemaTemplate/instantiate-member-class.cpp b/test/SemaTemplate/instantiate-member-class.cpp
new file mode 100644
index 0000000..26fddcf
--- /dev/null
+++ b/test/SemaTemplate/instantiate-member-class.cpp
@@ -0,0 +1,33 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+class X {
+public:
+  struct C { T &foo(); };
+
+  struct D {
+    struct E { T &bar(); };
+    struct F; // expected-note{{member is declared here}}
+  };
+};
+
+X<int>::C *c1;
+X<float>::C *c2;
+
+X<int>::X *xi;
+X<float>::X *xf;
+
+void test_naming() {
+  c1 = c2; // expected-error{{incompatible type assigning 'X<float>::C *', expected 'X<int>::C *'}}
+  xi = xf;  // expected-error{{incompatible type assigning}}
+    // FIXME: error above doesn't print the type X<int>::X cleanly!
+}
+
+void test_instantiation(X<double>::C *x,
+                        X<float>::D::E *e,
+                        X<float>::D::F *f) {
+  double &dr = x->foo();
+  float &fr = e->bar();
+  f->foo(); // expected-error{{implicit instantiation of undefined member 'struct X<float>::D::F'}}
+  
+}