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/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;