зеркало из https://github.com/microsoft/clang-1.git
Improve code generation for function template specializations:
- Track implicit instantiations vs. the not-yet-supported explicit specializations - Give implicit instantiations of function templates (and member functions of class templates) linkonce_odr linkage. - Improve name mangling for function template specializations, including the template arguments of the instantiation and the return type of the function. Note that our name-mangling is improved, but not correct: we still don't mangle substitutions, although the manglings we produce can be demangled. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74466 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
7881a05658
Коммит
1fd2dd145d
|
@ -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;
|
||||
|
|
|
@ -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<FunctionTemplateDecl *, 1> 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());
|
||||
|
|
|
@ -584,7 +584,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
|||
if (FunctionTemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization
|
||||
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
||||
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<FunctionTemplateSpecializationInfo*>();
|
||||
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<FunctionTemplateSpecializationInfo*>();
|
||||
if (Info)
|
||||
Info->setExplicitSpecialization(ES);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TagDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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<CXXMethodDecl>(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
|
||||
|
|
|
@ -373,7 +373,8 @@ public:
|
|||
GVA_Internal,
|
||||
GVA_C99Inline,
|
||||
GVA_CXXInline,
|
||||
GVA_StrongExternal
|
||||
GVA_StrongExternal,
|
||||
GVA_TemplateInstantiation
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -170,7 +170,29 @@ void CXXNameMangler::mangleGuardVariable(const VarDecl *D)
|
|||
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
|
||||
// <encoding> ::= <function name> <bare-function-type>
|
||||
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<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
|
||||
isa<CXXConversionDecl>(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<FunctionDecl>(ND)) {
|
||||
if (const TemplateArgumentList *TemplateArgs
|
||||
= Function->getTemplateSpecializationArgs())
|
||||
mangleTemplateArgumentList(*TemplateArgs);
|
||||
}
|
||||
}
|
||||
|
||||
void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// RUN: clang-cc -emit-llvm %s -o -
|
||||
// RUN: clang-cc -emit-llvm %s -o %t &&
|
||||
template<typename T, typename U>
|
||||
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);
|
||||
}
|
Загрузка…
Ссылка в новой задаче