diff options
-rw-r--r-- | include/clang/AST/Decl.h | 37 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 47 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 35 | ||||
-rw-r--r-- | lib/CodeGen/CodeGenModule.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 11 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 20 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 38 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 17 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 4 | ||||
-rw-r--r-- | test/CodeGenCXX/explicit-instantiation.cpp | 12 |
10 files changed, 139 insertions, 87 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 1d6c9c1872..28456fff9f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -715,6 +715,29 @@ public: static bool classof(const OriginalParmVarDecl *D) { return true; } }; +// \brief Describes the kind of template specialization that a +// particular template specialization declaration represents. +enum TemplateSpecializationKind { + /// This template specialization was formed from a template-id but + /// has not yet been declared, defined, or instantiated. + TSK_Undeclared = 0, + /// This template specialization was implicitly instantiated from a + /// template. (C++ [temp.inst]). + TSK_ImplicitInstantiation, + /// This template specialization was declared or defined by an + /// explicit specialization (C++ [temp.expl.spec]) or partial + /// specialization (C++ [temp.class.spec]). + TSK_ExplicitSpecialization, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation declaration request + /// (C++0x [temp.explicit]). + TSK_ExplicitInstantiationDeclaration, + /// This template specialization was instantiated from a template + /// due to an explicit instantiation definition request + /// (C++ [temp.explicit]). + TSK_ExplicitInstantiationDefinition +}; + /// FunctionDecl - An instance of this class is created to represent a /// function declaration or definition. /// @@ -1077,14 +1100,14 @@ public: const TemplateArgumentList *TemplateArgs, void *InsertPos); - /// \brief Determine whether this is an explicit specialization of a - /// function template or a member function of a class template. - bool isExplicitSpecialization() const; + /// \brief Determine what kind of template instantiation this function + /// represents. + TemplateSpecializationKind getTemplateSpecializationKind() const; - /// \brief Note that this is an explicit specialization of a function template - /// or a member function of a class template. - void setExplicitSpecialization(bool ES); - + /// \brief Determine what kind of template instantiation this function + /// represents. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK); + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast; diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 971d6ea07b..24524dff38 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -510,9 +510,8 @@ public: /// \brief The function template from which this function template /// specialization was generated. /// - /// The bit will be 0 for an implicit instantiation, 1 for an explicit - /// specialization. - llvm::PointerIntPair<FunctionTemplateDecl *, 1> Template; + /// The two bits are contain the top 4 values of TemplateSpecializationKind. + llvm::PointerIntPair<FunctionTemplateDecl *, 2> Template; /// \brief The template arguments used to produce the function template /// specialization from the function template. @@ -520,14 +519,17 @@ public: /// \brief Retrieve the template from which this function was specialized. FunctionTemplateDecl *getTemplate() const { return Template.getPointer(); } - - /// \brief Determine whether this is an explicit specialization. - bool isExplicitSpecialization() const { return Template.getInt(); } - - /// \brief Set whether this is an explicit specialization or an implicit - /// instantiation. - void setExplicitSpecialization(bool ES) { - Template.setInt(ES); + + /// \brief Determine what kind of template specialization this is. + TemplateSpecializationKind getTemplateSpecializationKind() const { + return (TemplateSpecializationKind)(Template.getInt() + 1); + } + + /// \brief Set the template specialization kind. + void setTemplateSpecializationKind(TemplateSpecializationKind TSK) { + assert(TSK != TSK_Undeclared && + "Cannot encode TSK_Undeclared for a function template specialization"); + Template.setInt(TSK - 1); } void Profile(llvm::FoldingSetNodeID &ID) { @@ -871,24 +873,6 @@ public: static bool classof(const TemplateTemplateParmDecl *D) { return true; } }; -// \brief Describes the kind of template specialization that a -// particular template specialization declaration represents. -enum TemplateSpecializationKind { - /// This template specialization was formed from a template-id but - /// has not yet been declared, defined, or instantiated. - TSK_Undeclared = 0, - /// This template specialization was declared or defined by an - /// explicit specialization (C++ [temp.expl.spec]) or partial - /// specialization (C++ [temp.class.spec]). - TSK_ExplicitSpecialization, - /// This template specialization was implicitly instantiated from a - /// template. (C++ [temp.inst]). - TSK_ImplicitInstantiation, - /// This template specialization was instantiated from a template - /// due to an explicit instantiation request (C++ [temp.explicit]). - TSK_ExplicitInstantiation -}; - /// \brief Represents a class template specialization, which refers to /// a class template with a given set of template arguments. /// @@ -927,7 +911,7 @@ class ClassTemplateSpecializationDecl /// \brief The kind of specialization this declaration refers to. /// Really a value of type TemplateSpecializationKind. - unsigned SpecializationKind : 2; + unsigned SpecializationKind : 3; protected: ClassTemplateSpecializationDecl(ASTContext &Context, Kind DK, @@ -972,7 +956,8 @@ public: ClassTemplatePartialSpecializationDecl *> getInstantiatedFrom() const { if (getSpecializationKind() != TSK_ImplicitInstantiation && - getSpecializationKind() != TSK_ExplicitInstantiation) + getSpecializationKind() != TSK_ExplicitInstantiationDefinition && + getSpecializationKind() != TSK_ExplicitInstantiationDeclaration) return (ClassTemplateDecl*)0; if (SpecializedPartialSpecialization *PartialSpec diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 41ba1f1df9..ca1ae63ff8 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -640,7 +640,7 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, Info->Function = this; Info->Template.setPointer(Template); - Info->Template.setInt(0); // Implicit instantiation, unless told otherwise + Info->Template.setInt(TSK_ImplicitInstantiation - 1); Info->TemplateArguments = TemplateArgs; TemplateOrSpecialization = Info; @@ -649,24 +649,35 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, Template->getSpecializations().InsertNode(Info, InsertPos); } -bool FunctionDecl::isExplicitSpecialization() const { - // FIXME: check this property for explicit specializations of member - // functions of class templates. +TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const { + // For a function template specialization, query the specialization + // information object. FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (!Info) - return false; + if (Info) + return Info->getTemplateSpecializationKind(); + + if (!getInstantiatedFromMemberFunction()) + return TSK_Undeclared; - return Info->isExplicitSpecialization(); + // Find the class template specialization corresponding to this instantiation + // of a member function. + const DeclContext *Parent = getDeclContext(); + while (Parent && !isa<ClassTemplateSpecializationDecl>(Parent)) + Parent = Parent->getParent(); + + if (!Parent) + return TSK_Undeclared; + + return cast<ClassTemplateSpecializationDecl>(Parent)->getSpecializationKind(); } -void FunctionDecl::setExplicitSpecialization(bool ES) { - // FIXME: set this property for explicit specializations of member functions - // of class templates. +void +FunctionDecl::setTemplateSpecializationKind(TemplateSpecializationKind TSK) { FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); - if (Info) - Info->setExplicitSpecialization(ES); + assert(Info && "Not a function template specialization"); + Info->setTemplateSpecializationKind(TSK); } //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index cde6e89d66..180a68659d 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -250,9 +250,8 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, // The kind of external linkage this function will have, if it is not // inline or static. CodeGenModule::GVALinkage External = CodeGenModule::GVA_StrongExternal; - if (Context.getLangOptions().CPlusPlus && - (FD->getPrimaryTemplate() || FD->getInstantiatedFromMemberFunction()) && - !FD->isExplicitSpecialization()) + if (Context.getLangOptions().CPlusPlus && + FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) External = CodeGenModule::GVA_TemplateInstantiation; if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index d088387b05..1c118ab64e 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3011,21 +3011,24 @@ public: InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation, + TemplateSpecializationKind TSK, bool Complain = true); bool InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation, bool Complain = true); + TemplateSpecializationKind TSK, + bool Complain = true); void InstantiateClassMembers(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, - const MultiLevelTemplateArgumentList &TemplateArgs); + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK); void InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec); + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK); NestedNameSpecifier * SubstNestedNameSpecifier(NestedNameSpecifier *NNS, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 76b6d7ecaa..c243765bec 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2934,7 +2934,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, bool SpecializationRequiresInstantiation = true; if (PrevDecl) { - if (PrevDecl->getSpecializationKind() == TSK_ExplicitInstantiation) { + if (PrevDecl->getSpecializationKind() + == TSK_ExplicitInstantiationDefinition) { // This particular specialization has already been declared or // instantiated. We cannot explicitly instantiate it. Diag(TemplateNameLoc, diag::err_explicit_instantiation_duplicate) @@ -3028,16 +3029,19 @@ Sema::ActOnExplicitInstantiation(Scope *S, // // This check comes when we actually try to perform the // instantiation. + TemplateSpecializationKind TSK + = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition + : TSK_ExplicitInstantiationDeclaration; if (SpecializationRequiresInstantiation) - InstantiateClassTemplateSpecialization(Specialization, true); + InstantiateClassTemplateSpecialization(Specialization, TSK); else // Instantiate the members of this class template specialization. - InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization); + InstantiateClassTemplateSpecializationMembers(TemplateLoc, Specialization, + TSK); return DeclPtrTy::make(Specialization); } // Explicit instantiation of a member class of a class template. -// FIXME: Implement extern template semantics. Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, SourceLocation ExternLoc, @@ -3092,17 +3096,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, } } + TemplateSpecializationKind TSK + = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition + : TSK_ExplicitInstantiationDeclaration; + if (!Record->getDefinition(Context)) { // If the class has a definition, instantiate it (and all of its // members, recursively). Pattern = cast_or_null<CXXRecordDecl>(Pattern->getDefinition(Context)); if (Pattern && InstantiateClass(TemplateLoc, Record, Pattern, getTemplateInstantiationArgs(Record), - /*ExplicitInstantiation=*/true)) + TSK)) return true; } else // Instantiate all of the members of the class. InstantiateClassMembers(TemplateLoc, Record, - getTemplateInstantiationArgs(Record)); + getTemplateInstantiationArgs(Record), TSK); // FIXME: We don't have any representation for explicit instantiations of // member classes. Such a representation is not needed for compilation, but it diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 0c47e996c8..55e81aecbc 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -623,8 +623,7 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, /// \param TemplateArgs The template arguments to be substituted into /// the pattern. /// -/// \param ExplicitInstantiation whether this is an explicit instantiation -/// (otherwise, it is an implicit instantiation). +/// \param TSK the kind of implicit or explicit instantiation to perform. /// /// \param Complain whether to complain if the class cannot be instantiated due /// to the lack of a definition. @@ -634,7 +633,7 @@ bool Sema::InstantiateClass(SourceLocation PointOfInstantiation, CXXRecordDecl *Instantiation, CXXRecordDecl *Pattern, const MultiLevelTemplateArgumentList &TemplateArgs, - bool ExplicitInstantiation, + TemplateSpecializationKind TSK, bool Complain) { bool Invalid = false; @@ -650,7 +649,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Diag(Pattern->getLocation(), diag::note_member_of_template_here); } else { Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) - << ExplicitInstantiation + << (TSK != TSK_ImplicitInstantiation) << Context.getTypeDeclType(Instantiation); Diag(Pattern->getLocation(), diag::note_template_decl_here); } @@ -708,9 +707,10 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, Consumer.HandleTagDeclDefinition(Instantiation); // If this is an explicit instantiation, instantiate our members, too. - if (!Invalid && ExplicitInstantiation) { + if (!Invalid && TSK != TSK_ImplicitInstantiation) { Inst.Clear(); - InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs); + InstantiateClassMembers(PointOfInstantiation, Instantiation, TemplateArgs, + TSK); } return Invalid; @@ -719,7 +719,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool Sema::InstantiateClassTemplateSpecialization( ClassTemplateSpecializationDecl *ClassTemplateSpec, - bool ExplicitInstantiation, + TemplateSpecializationKind TSK, bool Complain) { // Perform the actual instantiation on the canonical declaration. ClassTemplateSpec = cast<ClassTemplateSpecializationDecl>( @@ -798,14 +798,12 @@ Sema::InstantiateClassTemplateSpecialization( } // Note that this is an instantiation. - ClassTemplateSpec->setSpecializationKind( - ExplicitInstantiation? TSK_ExplicitInstantiation - : TSK_ImplicitInstantiation); + ClassTemplateSpec->setSpecializationKind(TSK); bool Result = InstantiateClass(ClassTemplateSpec->getLocation(), ClassTemplateSpec, Pattern, getTemplateInstantiationArgs(ClassTemplateSpec), - ExplicitInstantiation, + TSK, Complain); for (unsigned I = 0, N = Matched.size(); I != N; ++I) { @@ -822,8 +820,10 @@ Sema::InstantiateClassTemplateSpecialization( /// or a member class of a template. void Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, - CXXRecordDecl *Instantiation, - const MultiLevelTemplateArgumentList &TemplateArgs) { + CXXRecordDecl *Instantiation, + const MultiLevelTemplateArgumentList &TemplateArgs, + TemplateSpecializationKind TSK) { + // FIXME: extern templates for (DeclContext::decl_iterator D = Instantiation->decls_begin(), DEnd = Instantiation->decls_end(); D != DEnd; ++D) { @@ -839,7 +839,8 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, "Missing instantiated-from-template information"); InstantiateClass(PointOfInstantiation, Record, Record->getInstantiatedFromMemberClass(), - TemplateArgs, true); + TemplateArgs, + TSK); } } } @@ -848,9 +849,11 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, /// \brief Instantiate the definitions of all of the members of the /// given class template specialization, which was named as part of an /// explicit instantiation. -void Sema::InstantiateClassTemplateSpecializationMembers( +void +Sema::InstantiateClassTemplateSpecializationMembers( SourceLocation PointOfInstantiation, - ClassTemplateSpecializationDecl *ClassTemplateSpec) { + ClassTemplateSpecializationDecl *ClassTemplateSpec, + TemplateSpecializationKind TSK) { // C++0x [temp.explicit]p7: // An explicit instantiation that names a class template // specialization is an explicit instantion of the same kind @@ -860,7 +863,8 @@ void Sema::InstantiateClassTemplateSpecializationMembers( // containing the explicit instantiation, except as described // below. InstantiateClassMembers(PointOfInstantiation, ClassTemplateSpec, - getTemplateInstantiationArgs(ClassTemplateSpec)); + getTemplateInstantiationArgs(ClassTemplateSpec), + TSK); } Sema::OwningStmtResult diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 807115eb67..b63fc400a5 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -402,6 +402,8 @@ Decl *TemplateDeclInstantiator::VisitClassTemplateDecl(ClassTemplateDecl *D) { Decl * TemplateDeclInstantiator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Dig out the out-of-line definition of this function template? + TemplateParameterList *TempParams = D->getTemplateParameters(); TemplateParameterList *InstParams = SubstTemplateParams(TempParams); if (!InstParams) @@ -496,7 +498,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { D->getStorageClass(), D->isInline(), D->hasWrittenPrototype()); Function->setLexicalDeclContext(Owner); - + // Attach the parameters for (unsigned P = 0; P < Params.size(); ++P) Params[P]->setOwningFunction(Function); @@ -622,7 +624,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Method->getDeclName(), TemplateParams, Method); if (D->isOutOfLine()) - FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); + FunctionTemplate->setLexicalDeclContext(D->getLexicalDeclContext()); Method->setDescribedFunctionTemplate(FunctionTemplate); } else if (!FunctionTemplate) Method->setInstantiationOfMemberFunction(D); @@ -979,6 +981,15 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (!Pattern) return; + // C++0x [temp.explicit]p9: + // Except for inline functions, other explicit instantiation declarations + // have the effect of suppressing the implicit instantiation of the entity + // to which they refer. + if (Function->getTemplateSpecializationKind() + == TSK_ExplicitInstantiationDeclaration && + PatternDecl->isOutOfLine() && !PatternDecl->isInline()) + return; + InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst) return; @@ -1080,6 +1091,8 @@ void Sema::InstantiateStaticDataMemberDefinition( return; } + // FIXME: extern templates + InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst) return; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index 11bbe4e2de..80cdcd5464 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1781,7 +1781,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, if (Loc.isValid()) ClassTemplateSpec->setLocation(Loc); return InstantiateClassTemplateSpecialization(ClassTemplateSpec, - /*ExplicitInstantiation=*/false, + TSK_ImplicitInstantiation, /*Complain=*/diag != 0); } } else if (CXXRecordDecl *Rec @@ -1790,7 +1790,7 @@ bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, // This record was instantiated from a class within a template. return InstantiateClass(Loc, Rec, Pattern, getTemplateInstantiationArgs(Rec), - /*ExplicitInstantiation=*/false, + TSK_ImplicitInstantiation, /*Complain=*/diag != 0); } } diff --git a/test/CodeGenCXX/explicit-instantiation.cpp b/test/CodeGenCXX/explicit-instantiation.cpp index 38966aad2d..33cbf7f872 100644 --- a/test/CodeGenCXX/explicit-instantiation.cpp +++ b/test/CodeGenCXX/explicit-instantiation.cpp @@ -1,11 +1,17 @@ // RUN: clang-cc -emit-llvm -femit-all-decls -o %t %s && // RUN: grep "_ZNK4plusIillEclERKiRKl" %t | count 1 +// FIXME: We should not need the -femit-all-decls, because operator() should +// be emitted as an external symbol rather than with linkonce_odr linkage. +// This is a Sema problem. template<typename T, typename U, typename Result> struct plus { - Result operator()(const T& t, const U& u) const { - return t + u; - } + Result operator()(const T& t, const U& u) const; }; +template<typename T, typename U, typename Result> +Result plus<T, U, Result>::operator()(const T& t, const U& u) const { + return t + u; +} + template struct plus<int, long, long>; |