diff options
| author | Douglas Gregor <dgregor@apple.com> | 2009-05-13 00:25:59 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2009-05-13 00:25:59 +0000 |
| commit | a1f499736818abb14e03e244707df216bf6fbe91 (patch) | |
| tree | 078f430b7f060ec2bd3426a3e49aa27d9d583452 /clang/lib | |
| parent | 536de01bcfa09dd175fa5f965af3e0d8a19ab7d9 (diff) | |
| download | bcm5719-llvm-a1f499736818abb14e03e244707df216bf6fbe91.tar.gz bcm5719-llvm-a1f499736818abb14e03e244707df216bf6fbe91.zip | |
Semantic analysis for explicit instantiation of class templates. We
still aren't instantiating the definitions of class template members,
and core issues 275 and 259 will both affect the checking that we do
for explicit instantiations (but are not yet implemented).
llvm-svn: 71613
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Sema/Sema.h | 16 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 135 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 3 |
4 files changed, 158 insertions, 6 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 83565095509..2e617f573be 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1895,6 +1895,19 @@ public: AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); + virtual DeclResult + ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy Template, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgs, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr); + bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -2092,7 +2105,8 @@ public: bool InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs); + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation); bool InstantiateClassTemplateSpecialization( diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index fc44217252a..c80bb882f6a 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2141,6 +2141,141 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, return DeclPtrTy::make(Specialization); } +Sema::DeclResult +Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation TemplateLoc, + unsigned TagSpec, + SourceLocation KWLoc, + const CXXScopeSpec &SS, + TemplateTy TemplateD, + SourceLocation TemplateNameLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + AttributeList *Attr) { + // Find the class template we're specializing + TemplateName Name = TemplateD.getAsVal<TemplateName>(); + ClassTemplateDecl *ClassTemplate + = cast<ClassTemplateDecl>(Name.getAsTemplateDecl()); + + // Check that the specialization uses the same tag kind as the + // original template. + TagDecl::TagKind Kind; + switch (TagSpec) { + default: assert(0 && "Unknown tag type!"); + case DeclSpec::TST_struct: Kind = TagDecl::TK_struct; break; + case DeclSpec::TST_union: Kind = TagDecl::TK_union; break; + case DeclSpec::TST_class: Kind = TagDecl::TK_class; break; + } + if (!isAcceptableTagRedeclaration( + ClassTemplate->getTemplatedDecl()->getTagKind(), + Kind)) { + Diag(KWLoc, diag::err_use_with_wrong_tag) + << ClassTemplate + << CodeModificationHint::CreateReplacement(KWLoc, + ClassTemplate->getTemplatedDecl()->getKindName()); + Diag(ClassTemplate->getTemplatedDecl()->getLocation(), + diag::note_previous_use); + Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); + } + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + // Check that the template argument list is well-formed for this + // template. + llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs; + if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) + return true; + + assert((ConvertedTemplateArgs.size() == + ClassTemplate->getTemplateParameters()->size()) && + "Converted template argument list is too short!"); + + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *PrevDecl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + + ClassTemplateSpecializationDecl *Specialization = 0; + + if (PrevDecl) { + if (PrevDecl->getSpecializationKind() != TSK_Undeclared) { + // This particular specialization has already been declared or + // instantiated. We cannot explicitly instantiate it. + Diag(TemplateNameLoc, diag::err_explicit_instantiation_redef) + << Context.getTypeDeclType(PrevDecl) + << (int)PrevDecl->getSpecializationKind(); + Diag(PrevDecl->getLocation(), diag::note_previous_instantiation) + << (int)PrevDecl->getSpecializationKind(); + return DeclPtrTy::make(PrevDecl); + } + + // Since the only prior class template specialization with these + // arguments was referenced but not declared, reuse that + // declaration node as our own, updating its source location to + // reflect our new declaration. + Specialization = PrevDecl; + Specialization->setLocation(TemplateNameLoc); + PrevDecl = 0; + } else { + // Create a new class template specialization declaration node for + // this explicit specialization. + Specialization + = ClassTemplateSpecializationDecl::Create(Context, + ClassTemplate->getDeclContext(), + TemplateNameLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + + ClassTemplate->getSpecializations().InsertNode(Specialization, + InsertPos); + } + + // Build the fully-sugared type for this explicit instantiation as + // the user wrote in the explicit instantiation itself. This means + // that we'll pretty-print the type retrieved from the + // specialization's declaration the way that the user actually wrote + // the explicit instantiation, rather than formatting the name based + // on the "canonical" representation used to store the template + // arguments in the specialization. + QualType WrittenTy + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + Context.getTypeDeclType(Specialization)); + Specialization->setTypeAsWritten(WrittenTy); + TemplateArgsIn.release(); + + // Add the explicit instantiation into its lexical context. However, + // since explicit instantiations are never found by name lookup, we + // just put it into the declaration context directly. + Specialization->setLexicalDeclContext(CurContext); + CurContext->addDecl(Context, Specialization); + + // C++ [temp.explicit]p3: + // + // A definition of a class template or class member template + // shall be in scope at the point of the explicit instantiation of + // the class template or class member template. + // + // This check comes when we actually try to perform the + // instantiation. + if (InstantiateClassTemplateSpecialization(Specialization, true)) + return true; + + return DeclPtrTy::make(Specialization); +} + Sema::TypeResult Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS, const IdentifierInfo &II, SourceLocation IdLoc) { diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 0fe6cee882c..ce8cbe0f434 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -666,7 +666,8 @@ Sema::InstantiateBaseSpecifiers(CXXRecordDecl *Instantiation, bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, - const TemplateArgumentList &TemplateArgs) { + const TemplateArgumentList &TemplateArgs, + bool ExplicitInstantiation) { bool Invalid = false; CXXRecordDecl *PatternDef @@ -678,8 +679,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_member_of_template_here); } else { - Diag(PointOfInstantiation, - diag::err_template_implicit_instantiate_undefined) + Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) + << ExplicitInstantiation << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_template_decl_here); } @@ -766,7 +767,8 @@ Sema::InstantiateClassTemplateSpecialization( return InstantiateClass(ClassTemplateSpec->getLocation(), ClassTemplateSpec, Pattern, - ClassTemplateSpec->getTemplateArgs()); + ClassTemplateSpec->getTemplateArgs(), + ExplicitInstantiation); } /// \brief Instantiate a nested-name-specifier. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f3a31ea0deb..d04a5ad6c59 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1115,7 +1115,8 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, unsigned diag, 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()); + return InstantiateClass(Loc, Rec, Pattern, Spec->getTemplateArgs(), + /*ExplicitInstantiation=*/false); } } } |

