From: Douglas Gregor Date: Thu, 15 Oct 2009 17:21:20 +0000 (+0000) Subject: Simplify checking of explicit template specialization/explicit X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0a897e32a09d290aa5b375444fe33928e47168bb;p=clang Simplify checking of explicit template specialization/explicit instantiation redeclaration semantics for function template specializations and member functions of class template specializations. Also, record the point of instantiation for explicit-instantiated functions and static data members. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84188 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index f21541c3e7..2a077fb223 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -604,7 +604,8 @@ public: /// \brief For a static data member that was instantiated from a static /// data member of a class template, set the template specialiation kind. - void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); /// isFileVarDecl - Returns true for file scoped variable declaration. bool isFileVarDecl() const { @@ -1170,7 +1171,16 @@ public: /// \brief Determine what kind of template instantiation this function /// represents. - void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + void setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation = SourceLocation()); + + /// \brief Retrieve the (first) point of instantiation of a function template + /// specialization or a member of a class template specialization. + /// + /// \returns the first point of instantiation, if this function was + /// instantiated from a template; otherwie, returns an invalid source + /// location. + SourceLocation getPointOfInstantiation() const; /// \brief Determine whether this is or was instantiated from an out-of-line /// definition of a member function. diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index da7959b16f..9d7d3d087c 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -408,10 +408,15 @@ MemberSpecializationInfo *VarDecl::getMemberSpecializationInfo() const { return getASTContext().getInstantiatedFromStaticDataMember(this); } -void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +void VarDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { MemberSpecializationInfo *MSI = getMemberSpecializationInfo(); assert(MSI && "Not an instantiated static data member?"); MSI->setTemplateSpecializationKind(TSK); + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSI->getPointOfInstantiation().isInvalid()) + MSI->setPointOfInstantiation(PointOfInstantiation); } bool VarDecl::isTentativeDefinition(ASTContext &Context) const { @@ -812,18 +817,39 @@ TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { } void -FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK, + SourceLocation PointOfInstantiation) { if (FunctionTemplateSpecializationInfo *FTSInfo = TemplateOrSpecialization.dyn_cast< - FunctionTemplateSpecializationInfo*>()) + FunctionTemplateSpecializationInfo*>()) { FTSInfo->setTemplateSpecializationKind(TSK); - else if (MemberSpecializationInfo *MSInfo - = TemplateOrSpecialization.dyn_cast()) + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + FTSInfo->getPointOfInstantiation().isInvalid()) + FTSInfo->setPointOfInstantiation(PointOfInstantiation); + } else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast()) { MSInfo->setTemplateSpecializationKind(TSK); - else + if (TSK != TSK_ExplicitSpecialization && + PointOfInstantiation.isValid() && + MSInfo->getPointOfInstantiation().isInvalid()) + MSInfo->setPointOfInstantiation(PointOfInstantiation); + } else assert(false && "Function cannot have a template specialization kind"); } +SourceLocation FunctionDecl::getPointOfInstantiation() const { + if (FunctionTemplateSpecializationInfo *FTSInfo + = TemplateOrSpecialization.dyn_cast< + FunctionTemplateSpecializationInfo*>()) + return FTSInfo->getPointOfInstantiation(); + else if (MemberSpecializationInfo *MSInfo + = TemplateOrSpecialization.dyn_cast()) + return MSInfo->getPointOfInstantiation(); + + return SourceLocation(); +} + bool FunctionDecl::isOutOfLine() const { if (Decl::isOutOfLine()) return true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b0d0a88259..8d7e199e7a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3980,7 +3980,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return DeclPtrTy(); // Instantiate static data member. - Prev->setTemplateSpecializationKind(TSK); + Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); if (TSK == TSK_ExplicitInstantiationDefinition) InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false, /*DefinitionRequired=*/true); @@ -4054,9 +4054,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, if (!Specialization) return true; - // FIXME: Use CheckSpecializationInstantiationRedecl - switch (Specialization->getTemplateSpecializationKind()) { - case TSK_Undeclared: + if (Specialization->getTemplateSpecializationKind() == TSK_Undeclared) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_member_function_not_instantiated) << Specialization @@ -4064,35 +4062,30 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TSK_ExplicitSpecialization); Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here); return true; - - case TSK_ExplicitSpecialization: - // C++ [temp.explicit]p4: - // For a given set of template parameters, if an explicit instantiation - // of a template appears after a declaration of an explicit - // specialization for that template, the explicit instantiation has no - // effect. - break; - - case TSK_ExplicitInstantiationDefinition: - // FIXME: Check that we aren't trying to perform an explicit instantiation - // declaration now. - // Fall through - - case TSK_ImplicitInstantiation: - case TSK_ExplicitInstantiationDeclaration: - // Instantiate the function, if this is an explicit instantiation - // definition. - if (TSK == TSK_ExplicitInstantiationDefinition) - InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, - false, /*DefinitionRequired=*/true); - - Specialization->setTemplateSpecializationKind(TSK); - break; + } + + FunctionDecl *PrevDecl = Specialization->getPreviousDeclaration(); + if (PrevDecl) { + bool SuppressNew = false; + if (CheckSpecializationInstantiationRedecl(*this, D.getIdentifierLoc(), TSK, + PrevDecl, + PrevDecl->getTemplateSpecializationKind(), + PrevDecl->getPointOfInstantiation(), + SuppressNew)) + return true; + + // FIXME: We may still want to build some representation of this + // explicit specialization. + if (SuppressNew) + return DeclPtrTy(); } - - // Check the scope of this explicit instantiation. - FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); + if (TSK == TSK_ExplicitInstantiationDefinition) + InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization, + false, /*DefinitionRequired=*/true); + + Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); + // C++0x [temp.explicit]p2: // If the explicit instantiation is for a member function, a member class // or a static data member of a class template specialization, the name of @@ -4100,6 +4093,7 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // name shall be a simple-template-id. // // C++98 has the same restriction, just worded differently. + FunctionTemplateDecl *FunTmpl = Specialization->getPrimaryTemplate(); if (D.getKind() != Declarator::DK_TemplateId && !FunTmpl && D.getCXXScopeSpec().isSet() && !ScopeSpecifierHasTemplateId(D.getCXXScopeSpec()))