diff options
Diffstat (limited to 'clang/lib')
-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 |
6 files changed, 178 insertions, 78 deletions
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; |