diff options
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 58 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 22 | ||||
-rw-r--r-- | clang/lib/Sema/Sema.h | 18 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 3 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 169 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaType.cpp | 25 | ||||
-rw-r--r-- | clang/test/SemaTemplate/instantiate-member-class.cpp | 33 |
9 files changed, 273 insertions, 79 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index c689b77632b..e1f1095d3d9 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/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 @@ 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. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index bdfbffa9b30..fb194fe4c3e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 33e870bc0d6..98d7d8f4873 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/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 @@ 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, diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 42b0205bacb..ad7aa3bee9a 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -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, diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index fd89507645a..cc1a5b32a77 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -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"); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 4d271a38309..60423f9f472 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -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 diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7995def3322..d9f6902b54e 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -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. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 196a30642b5..4b2565795a9 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -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/clang/test/SemaTemplate/instantiate-member-class.cpp b/clang/test/SemaTemplate/instantiate-member-class.cpp new file mode 100644 index 00000000000..26fddcfb344 --- /dev/null +++ b/clang/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'}} + +} |