[cfe-commits] r67707 - in /cfe/trunk: 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

Douglas Gregor dgregor at apple.com
Wed Mar 25 14:17:03 PDT 2009


Author: dgregor
Date: Wed Mar 25 16:17:03 2009
New Revision: 67707

URL: http://llvm.org/viewvc/llvm-project?rev=67707&view=rev
Log:
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.


Added:
    cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp
Modified:
    cfe/trunk/include/clang/AST/DeclCXX.h
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/AST/DeclCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Wed Mar 25 16:17:03 2009
@@ -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.

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Mar 25 16:17:03 2009
@@ -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<

Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Wed Mar 25 16:17:03 2009
@@ -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,

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Mar 25 16:17:03 2009
@@ -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,

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Wed Mar 25 16:17:03 2009
@@ -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");

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Mar 25 16:17:03 2009
@@ -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,81 +631,82 @@
   }
 
   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 @@
   }
 
   // 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 @@
   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 

Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Wed Mar 25 16:17:03 2009
@@ -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.

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=67707&r1=67706&r2=67707&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Wed Mar 25 16:17:03 2009
@@ -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;

Added: cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp?rev=67707&view=auto

==============================================================================
--- cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp (added)
+++ cfe/trunk/test/SemaTemplate/instantiate-member-class.cpp Wed Mar 25 16:17:03 2009
@@ -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'}}
+  
+}





More information about the cfe-commits mailing list