diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 2b42239b01..1e82d6574f 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -961,7 +961,15 @@ public: FunctionTemplateDecl *Template, 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 Note that this is an explicit specialization of a function template + /// or a member function of a class template. + void setExplicitSpecialization(bool ES); + // 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 531525d5d4..5d0fe158e0 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -511,12 +511,27 @@ public: /// \brief The function template from which this function template /// specialization was generated. - FunctionTemplateDecl *Template; + /// + /// The bit will be 0 for an implicit instantiation, 1 for an explicit + /// specialization. + llvm::PointerIntPair Template; /// \brief The template arguments used to produce the function template /// specialization from the function template. const TemplateArgumentList *TemplateArguments; + /// \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); + } + void Profile(llvm::FoldingSetNodeID &ID) { Profile(ID, TemplateArguments->getFlatArgumentList(), TemplateArguments->flat_size()); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index e25fe90b4d..fa4d93c8de 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -584,7 +584,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const { if (FunctionTemplateSpecializationInfo *Info = TemplateOrSpecialization .dyn_cast()) { - return Info->Template; + return Info->Template.getPointer(); } return 0; } @@ -610,7 +610,8 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, Info = new (Context) FunctionTemplateSpecializationInfo; Info->Function = this; - Info->Template = Template; + Info->Template.setPointer(Template); + Info->Template.setInt(0); // Implicit instantiation, unless told otherwise Info->TemplateArguments = TemplateArgs; TemplateOrSpecialization = Info; @@ -619,6 +620,26 @@ 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. + FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast(); + if (!Info) + return false; + + return Info->isExplicitSpecialization(); +} + +void FunctionDecl::setExplicitSpecialization(bool ES) { + // FIXME: set this property for explicit specializations of member functions + // of class templates. + FunctionTemplateSpecializationInfo *Info + = TemplateOrSpecialization.dyn_cast(); + if (Info) + Info->setExplicitSpecialization(ES); +} + //===----------------------------------------------------------------------===// // TagDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index acd90e2646..7957a9fe88 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -243,12 +243,20 @@ void CodeGenModule::EmitAnnotations() { static CodeGenModule::GVALinkage GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, const LangOptions &Features) { + // 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()) + External = CodeGenModule::GVA_TemplateInstantiation; + if (const CXXMethodDecl *MD = dyn_cast(FD)) { // C++ member functions defined inside the class are always inline. if (MD->isInline() || !MD->isOutOfLine()) return CodeGenModule::GVA_CXXInline; - return CodeGenModule::GVA_StrongExternal; + return External; } // "static" functions get internal linkage. @@ -256,7 +264,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, return CodeGenModule::GVA_Internal; if (!FD->isInline()) - return CodeGenModule::GVA_StrongExternal; + return External; // If the inline function explicitly has the GNU inline attribute on it, or if // this is C89 mode, we use to GNU semantics. @@ -273,7 +281,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD, if (FD->isExternGNUInline(Context)) return CodeGenModule::GVA_C99Inline; // Normal inline is a strong symbol. - return CodeGenModule::GVA_StrongExternal; + return External; } // The definition of inline changes based on the language. Note that we @@ -306,7 +314,7 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, // In C99 mode, 'inline' functions are guaranteed to have a strong // definition somewhere else, so we can use available_externally linkage. GV->setLinkage(llvm::Function::AvailableExternallyLinkage); - } else if (Linkage == GVA_CXXInline) { + } else if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) { // In C++, the compiler has to emit a definition in every translation unit // that references the function. We should use linkonce_odr because // a) if all references in this translation unit are optimized away, we diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 4d50e8946b..ba9f1b28a0 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -373,7 +373,8 @@ public: GVA_Internal, GVA_C99Inline, GVA_CXXInline, - GVA_StrongExternal + GVA_StrongExternal, + GVA_TemplateInstantiation }; private: diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index b5ad5acc01..850183568a 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -170,7 +170,29 @@ void CXXNameMangler::mangleGuardVariable(const VarDecl *D) void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) { // ::= mangleName(FD); - mangleBareFunctionType(FD->getType()->getAsFunctionType(), false); + + // Whether the mangling of a function type includes the return type depends + // on the context and the nature of the function. The rules for deciding + // whether the return type is included are: + // + // 1. Template functions (names or types) have return types encoded, with + // the exceptions listed below. + // 2. Function types not appearing as part of a function name mangling, + // e.g. parameters, pointer types, etc., have return type encoded, with the + // exceptions listed below. + // 3. Non-template function names do not have return types encoded. + // + // The exceptions mentioned in (1) and (2) above, for which the return + // type is never included, are + // 1. Constructors. + // 2. Destructors. + // 3. Conversion operator functions, e.g. operator int. + bool MangleReturnType = false; + if (FD->getPrimaryTemplate() && + !(isa(FD) || isa(FD) || + isa(FD))) + MangleReturnType = true; + mangleBareFunctionType(FD->getType()->getAsFunctionType(), MangleReturnType); } static bool isStdNamespace(const DeclContext *DC) { @@ -253,6 +275,12 @@ void CXXNameMangler::mangleUnqualifiedName(const NamedDecl *ND) { assert(false && "Can't mangle a using directive name!"); break; } + + if (const FunctionDecl *Function = dyn_cast(ND)) { + if (const TemplateArgumentList *TemplateArgs + = Function->getTemplateSpecializationArgs()) + mangleTemplateArgumentList(*TemplateArgs); + } } void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) { diff --git a/test/CodeGenCXX/function-template-specialization.cpp b/test/CodeGenCXX/function-template-specialization.cpp index 685306f8be..bea3af2bb5 100644 --- a/test/CodeGenCXX/function-template-specialization.cpp +++ b/test/CodeGenCXX/function-template-specialization.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -emit-llvm %s -o - +// RUN: clang-cc -emit-llvm %s -o %t && template T* next(T* ptr, const U& diff); @@ -8,7 +8,11 @@ T* next(T* ptr, const U& diff) { } void test(int *iptr, float *fptr, int diff) { + // FIXME: should be "_Z4nextIiiEPT_S1_RKT0_" + // RUN: grep "_Z4nextIiiEPiPiRKi" %t && iptr = next(iptr, diff); + // FIXME: should be "_Z4nextIfiEPT_S1_RKT0_" + // RUN: grep "_Z4nextIfiEPfPfRKi" %t && fptr = next(fptr, diff); } @@ -17,5 +21,7 @@ T* next(T* ptr, const U& diff); void test2(int *iptr, double *dptr, int diff) { iptr = next(iptr, diff); + // FIXME: should be "_Z4nextIdiEPT_S1_RKT0_" + // RUN: grep "_Z4nextIdiEPdPdRKi" %t dptr = next(dptr, diff); } \ No newline at end of file