diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-07-21 23:53:31 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-07-21 23:53:31 +0000 |
commit | f59a56e180bf54528d7d1d5afa68fcc13300965a (patch) | |
tree | df0ccbf20fb79ddbd0b8939afcf838bfb16be0a2 /lib/Sema/SemaTemplate.cpp | |
parent | 3502deee1a93e86a97fb22df1cdb512c5a643dd6 (diff) |
Basic parsing and semantic analysis for out-of-line definitions of the
member functions of class templates, e.g.,
template<typename T>
struct X {
void f(T);
};
template<typename T> X<T>::f(T) { /* ... */ }
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76692 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 125 |
1 files changed, 121 insertions, 4 deletions
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c3acc24161..a55c956a2a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -739,6 +739,123 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, return Invalid; } +/// \brief Match the given template parameter lists to the given scope +/// specifier, returning the template parameter list that applies to the +/// name. +/// +/// \param DeclStartLoc the start of the declaration that has a scope +/// specifier or a template parameter list. +/// +/// \param SS the scope specifier that will be matched to the given template +/// parameter lists. This scope specifier precedes a qualified name that is +/// being declared. +/// +/// \param ParamLists the template parameter lists, from the outermost to the +/// innermost template parameter lists. +/// +/// \param NumParamLists the number of template parameter lists in ParamLists. +/// +/// \returns the template parameter list, if any, that corresponds to the +/// name that is preceded by the scope specifier @p SS. This template +/// parameter list may be have template parameters (if we're declaring a +/// template) or may have no template parameters (if we're declaring a +/// template specialization), or may be NULL (if we were's declaring isn't +/// itself a template). +TemplateParameterList * +Sema::MatchTemplateParametersToScopeSpecifier(SourceLocation DeclStartLoc, + const CXXScopeSpec &SS, + TemplateParameterList **ParamLists, + unsigned NumParamLists) { + // FIXME: This routine will need a lot more testing once we have support for + // member templates. + + // Find the template-ids that occur within the nested-name-specifier. These + // template-ids will match up with the template parameter lists. + llvm::SmallVector<const TemplateSpecializationType *, 4> + TemplateIdsInSpecifier; + for (NestedNameSpecifier *NNS = (NestedNameSpecifier *)SS.getScopeRep(); + NNS; NNS = NNS->getPrefix()) { + if (const TemplateSpecializationType *SpecType + = dyn_cast_or_null<TemplateSpecializationType>(NNS->getAsType())) { + TemplateDecl *Template = SpecType->getTemplateName().getAsTemplateDecl(); + if (!Template) + continue; // FIXME: should this be an error? probably... + + if (const RecordType *Record = SpecType->getAsRecordType()) { + ClassTemplateSpecializationDecl *SpecDecl + = cast<ClassTemplateSpecializationDecl>(Record->getDecl()); + // If the nested name specifier refers to an explicit specialization, + // we don't need a template<> header. + if (SpecDecl->getSpecializationKind() == TSK_ExplicitSpecialization) + continue; + } + + TemplateIdsInSpecifier.push_back(SpecType); + } + } + + // Reverse the list of template-ids in the scope specifier, so that we can + // more easily match up the template-ids and the template parameter lists. + std::reverse(TemplateIdsInSpecifier.begin(), TemplateIdsInSpecifier.end()); + + SourceLocation FirstTemplateLoc = DeclStartLoc; + if (NumParamLists) + FirstTemplateLoc = ParamLists[0]->getTemplateLoc(); + + // Match the template-ids found in the specifier to the template parameter + // lists. + unsigned Idx = 0; + for (unsigned NumTemplateIds = TemplateIdsInSpecifier.size(); + Idx != NumTemplateIds; ++Idx) { + bool DependentTemplateId = TemplateIdsInSpecifier[Idx]->isDependentType(); + if (Idx >= NumParamLists) { + // We have a template-id without a corresponding template parameter + // list. + if (DependentTemplateId) { + // FIXME: the location information here isn't great. + Diag(SS.getRange().getBegin(), + diag::err_template_spec_needs_template_parameters) + << QualType(TemplateIdsInSpecifier[Idx], 0) + << SS.getRange(); + } else { + Diag(SS.getRange().getBegin(), diag::err_template_spec_needs_header) + << SS.getRange() + << CodeModificationHint::CreateInsertion(FirstTemplateLoc, + "template<> "); + } + return 0; + } + + // Check the template parameter list against its corresponding template-id. + TemplateDecl *Template + = TemplateIdsInSpecifier[Idx]->getTemplateName().getAsTemplateDecl(); + TemplateParameterListsAreEqual(ParamLists[Idx], + Template->getTemplateParameters(), + true); + } + + // If there were at least as many template-ids as there were template + // parameter lists, then there are no template parameter lists remaining for + // the declaration itself. + if (Idx >= NumParamLists) + return 0; + + // If there were too many template parameter lists, complain about that now. + if (Idx != NumParamLists - 1) { + while (Idx < NumParamLists - 1) { + Diag(ParamLists[Idx]->getTemplateLoc(), + diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[Idx]->getTemplateLoc(), + ParamLists[Idx]->getRAngleLoc()); + ++Idx; + } + } + + // Return the last template parameter list, which corresponds to the + // entity being declared. + return ParamLists[NumParamLists - 1]; +} + /// \brief Translates template arguments as provided by the parser /// into template arguments used by semantic analysis. static void @@ -2572,12 +2689,12 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope, DeclPtrTy DP = HandleDeclarator(ParentScope, D, move(TemplateParameterLists), /*IsFunctionDefinition=*/true); - FunctionTemplateDecl *FunctionTemplate - = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>()); - if (FunctionTemplate) + if (FunctionTemplateDecl *FunctionTemplate + = dyn_cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>())) return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(FunctionTemplate->getTemplatedDecl())); - + if (FunctionDecl *Function = dyn_cast_or_null<FunctionDecl>(DP.getAs<Decl>())) + return ActOnStartOfFunctionDef(FnBodyScope, DeclPtrTy::make(Function)); return DeclPtrTy(); } |