]> granicus.if.org Git - clang/commitdiff
Instantiation for member classes of class templates. Note that only
authorDouglas Gregor <dgregor@apple.com>
Wed, 25 Mar 2009 21:17:03 +0000 (21:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 25 Mar 2009 21:17:03 +0000 (21:17 +0000)
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

include/clang/AST/DeclCXX.h
include/clang/Basic/DiagnosticSemaKinds.td
lib/AST/DeclCXX.cpp
lib/Sema/Sema.h
lib/Sema/SemaDecl.cpp
lib/Sema/SemaTemplateInstantiate.cpp
lib/Sema/SemaTemplateInstantiateDecl.cpp
lib/Sema/SemaType.cpp
test/SemaTemplate/instantiate-member-class.cpp [new file with mode: 0644]

index c689b77632b9bf490392cc79da5257f1a360d501..e1f1095d3d9a95cd428eaec41dd75d8928e8119c 100644 (file)
@@ -18,6 +18,8 @@
 #include "llvm/ADT/SmallVector.h"
 
 namespace clang {
+
+class ClassTemplateDecl;
 class CXXRecordDecl;
 class CXXConstructorDecl;
 class CXXDestructorDecl;
@@ -236,6 +238,17 @@ class CXXRecordDecl : public RecordDecl {
   /// 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 @@ public:
 
   /// 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 @@ public:
   /// 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.
index bdfbffa9b30cf3b7f7879ce3fc298e84d9af20f2..fb194fe4c3ed3a4e44a31e59cda6a97bf19d4ab0 100644 (file)
@@ -573,6 +573,7 @@ def err_template_arg_list_different_arity : Error<
 
 
 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 note_template_recursion_depth : Note<
 
 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<
index 33e870bc0d65d4ff07d554de8ae2b7cac50a84d5..98d7d8f48731e5eb5148615fc48b77558d35e8d7 100644 (file)
@@ -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 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
     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 @@ void CXXRecordDecl::addConversionFunction(ASTContext &Context,
   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,
index 42b0205bacbe47aef92f0b86b9835887f3526e0c..ad7aa3bee9a6d11d8611ae298cb1635eebae4606 100644 (file)
@@ -1784,8 +1784,7 @@ public:
     /// \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 @@ public:
   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 @@ public:
                         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,
index fd89507645ae6f3fcd98ae65edfcfcddff5b914e..cc1a5b32a77dcaefe80d495860e7ad533bce9381 100644 (file)
@@ -3392,11 +3392,12 @@ void Sema::ActOnTagStartDefinition(Scope *S, DeclTy *TagD) {
       //   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");
index 4d271a383099c06d7d1df619cfcb66813c02f2eb..60423f9f472ac94ada67c8b13742b83e5b5479b4 100644 (file)
@@ -26,7 +26,7 @@ using namespace clang;
 
 Sema::InstantiatingTemplate::
 InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
-                      ClassTemplateSpecializationDecl *Entity,
+                      CXXRecordDecl *Entity,
                       SourceRange InstantiationRange)
   :  SemaRef(SemaRef) {
 
@@ -100,11 +100,13 @@ void Sema::PrintInstantiationStack() {
        ++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 @@ QualType Sema::InstantiateType(QualType T,
 /// 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 @@ Sema::InstantiateBaseSpecifiers(
     }
 
     QualType BaseType = InstantiateType(Base->getType(), 
-                                        ClassTemplateSpec->getTemplateArgs(),
-                                        ClassTemplateSpec->getNumTemplateArgs(),
+                                        TemplateArgs, NumTemplateArgs,
                                         Base->getSourceRange().getBegin(),
                                         DeclarationName());
     if (BaseType.isNull()) {
@@ -617,7 +618,7 @@ Sema::InstantiateBaseSpecifiers(
     }
 
     if (CXXBaseSpecifier *InstantiatedBase
-          = CheckBaseSpecifier(ClassTemplateSpec,
+          = CheckBaseSpecifier(Instantiation,
                                Base->getSourceRange(),
                                Base->isVirtual(),
                                Base->getAccessSpecifierAsWritten(),
@@ -630,81 +631,82 @@ Sema::InstantiateBaseSpecifiers(
   }
 
   if (!Invalid &&
-      AttachBaseSpecifiers(ClassTemplateSpec, &InstantiatedBases[0],
+      AttachBaseSpecifiers(Instantiation, &InstantiatedBases[0],
                            InstantiatedBases.size()))
     Invalid = true;
 
   return Invalid;
 }
 
-bool 
-Sema::InstantiateClassTemplateSpecialization(
-                           ClassTemplateSpecializationDecl *ClassTemplateSpec,
-                           bool ExplicitInstantiation) {
-  // Perform the actual instantiation on the canonical declaration.
-  ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
-                               Context.getCanonicalDecl(ClassTemplateSpec));
-
-  // We can only instantiate something that hasn't already been
-  // instantiated or specialized. Fail without any diagnostics: our
-  // caller will provide an error message.
-  if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
-    return true;
-
-  // FIXME: Push this class template instantiation onto the
-  // instantiation stack, checking for recursion that exceeds a
-  // certain depth.
-
-  // FIXME: Perform class template partial specialization to select
-  // 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);
+/// \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;
 
-  // Note that this is an instantiation.  
-  ClassTemplateSpec->setSpecializationKind(
-                        ExplicitInstantiation? TSK_ExplicitInstantiation 
-                                             : TSK_ImplicitInstantiation);
-
-
-  bool Invalid = false;
-  
-  InstantiatingTemplate Inst(*this, ClassTemplateSpec->getLocation(),
-                             ClassTemplateSpec);
+  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 = ClassTemplateSpec;
+  CurContext = Instantiation;
 
   // Start the definition of this instantiation.
-  ClassTemplateSpec->startDefinition();
+  Instantiation->startDefinition();
 
   // Instantiate the base class specifiers.
-  if (InstantiateBaseSpecifiers(ClassTemplateSpec, Template))
+  if (InstantiateBaseSpecifiers(Instantiation, Pattern, TemplateArgs,
+                                NumTemplateArgs))
     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());
+    Decl *NewMember = InstantiateDecl(*Member, Instantiation,
+                                      TemplateArgs, NumTemplateArgs);
     if (NewMember) {
       if (NewMember->isInvalidDecl())
         Invalid = true;
@@ -719,12 +721,12 @@ Sema::InstantiateClassTemplateSpecialization(
   }
 
   // Finish checking fields.
-  ActOnFields(0, ClassTemplateSpec->getLocation(), ClassTemplateSpec,
+  ActOnFields(0, Instantiation->getLocation(), Instantiation,
               &Fields[0], Fields.size(), SourceLocation(), SourceLocation(),
               0);
 
   // Add any implicitly-declared members that we might need.
-  AddImplicitlyDeclaredMembersToClass(ClassTemplateSpec);
+  AddImplicitlyDeclaredMembersToClass(Instantiation);
 
   // Exit the scope of this instantiation.
   CurContext = PreviousContext;
@@ -732,6 +734,41 @@ Sema::InstantiateClassTemplateSpecialization(
   return Invalid;
 }
 
+bool 
+Sema::InstantiateClassTemplateSpecialization(
+                           ClassTemplateSpecializationDecl *ClassTemplateSpec,
+                           bool ExplicitInstantiation) {
+  // Perform the actual instantiation on the canonical declaration.
+  ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>(
+                               Context.getCanonicalDecl(ClassTemplateSpec));
+
+  // We can only instantiate something that hasn't already been
+  // instantiated or specialized. Fail without any diagnostics: our
+  // caller will provide an error message.
+  if (ClassTemplateSpec->getSpecializationKind() != TSK_Undeclared)
+    return true;
+
+  // FIXME: Push this class template instantiation onto the
+  // instantiation stack, checking for recursion that exceeds a
+  // certain depth.
+
+  // FIXME: Perform class template partial specialization to select
+  // the best template.
+  ClassTemplateDecl *Template = ClassTemplateSpec->getSpecializedTemplate();
+
+  CXXRecordDecl *Pattern = Template->getTemplatedDecl();
+
+  // Note that this is an instantiation.  
+  ClassTemplateSpec->setSpecializationKind(
+                        ExplicitInstantiation? TSK_ExplicitInstantiation 
+                                             : TSK_ImplicitInstantiation);
+
+  return InstantiateClass(ClassTemplateSpec->getLocation(),
+                          ClassTemplateSpec, Pattern,
+                          ClassTemplateSpec->getTemplateArgs(),
+                          ClassTemplateSpec->getNumTemplateArgs());
+}
+
 /// \brief Instantiate a sequence of nested-name-specifiers into a
 /// scope specifier.
 CXXScopeSpec 
index 7995def332248b414a7ef1ac48ec53effd9d2840..d9f6902b54e98ef52a0a14fc25b6e5bbdcffc0d2 100644 (file)
@@ -46,6 +46,7 @@ namespace {
     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 @@ Decl *TemplateDeclInstantiator::VisitEnumConstantDecl(EnumConstantDecl *D) {
   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.
index 196a30642b50e45cddf0d0833c2bed1c1398ed55..4b2565795a97c52abe7ea84f7ae830a2857ed80e 100644 (file)
@@ -1042,11 +1042,11 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
   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 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag,
         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 (file)
index 0000000..26fddcf
--- /dev/null
@@ -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'}}
+  
+}