зеркало из 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
|
@ -962,6 +962,14 @@ public:
|
||||||
const TemplateArgumentList *TemplateArgs,
|
const TemplateArgumentList *TemplateArgs,
|
||||||
void *InsertPos);
|
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.
|
// Implement isa/cast/dyncast/etc.
|
||||||
static bool classof(const Decl *D) {
|
static bool classof(const Decl *D) {
|
||||||
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
|
return D->getKind() >= FunctionFirst && D->getKind() <= FunctionLast;
|
||||||
|
|
|
@ -511,12 +511,27 @@ public:
|
||||||
|
|
||||||
/// \brief The function template from which this function template
|
/// \brief The function template from which this function template
|
||||||
/// specialization was generated.
|
/// 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
|
/// \brief The template arguments used to produce the function template
|
||||||
/// specialization from the function template.
|
/// specialization from the function template.
|
||||||
const TemplateArgumentList *TemplateArguments;
|
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) {
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
Profile(ID, TemplateArguments->getFlatArgumentList(),
|
Profile(ID, TemplateArguments->getFlatArgumentList(),
|
||||||
TemplateArguments->flat_size());
|
TemplateArguments->flat_size());
|
||||||
|
|
|
@ -584,7 +584,7 @@ FunctionTemplateDecl *FunctionDecl::getPrimaryTemplate() const {
|
||||||
if (FunctionTemplateSpecializationInfo *Info
|
if (FunctionTemplateSpecializationInfo *Info
|
||||||
= TemplateOrSpecialization
|
= TemplateOrSpecialization
|
||||||
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
.dyn_cast<FunctionTemplateSpecializationInfo*>()) {
|
||||||
return Info->Template;
|
return Info->Template.getPointer();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -610,7 +610,8 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
||||||
Info = new (Context) FunctionTemplateSpecializationInfo;
|
Info = new (Context) FunctionTemplateSpecializationInfo;
|
||||||
|
|
||||||
Info->Function = this;
|
Info->Function = this;
|
||||||
Info->Template = Template;
|
Info->Template.setPointer(Template);
|
||||||
|
Info->Template.setInt(0); // Implicit instantiation, unless told otherwise
|
||||||
Info->TemplateArguments = TemplateArgs;
|
Info->TemplateArguments = TemplateArgs;
|
||||||
TemplateOrSpecialization = Info;
|
TemplateOrSpecialization = Info;
|
||||||
|
|
||||||
|
@ -619,6 +620,26 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
||||||
Template->getSpecializations().InsertNode(Info, InsertPos);
|
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
|
// TagDecl Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -243,12 +243,20 @@ void CodeGenModule::EmitAnnotations() {
|
||||||
static CodeGenModule::GVALinkage
|
static CodeGenModule::GVALinkage
|
||||||
GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
|
GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
|
||||||
const LangOptions &Features) {
|
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)) {
|
if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(FD)) {
|
||||||
// C++ member functions defined inside the class are always inline.
|
// C++ member functions defined inside the class are always inline.
|
||||||
if (MD->isInline() || !MD->isOutOfLine())
|
if (MD->isInline() || !MD->isOutOfLine())
|
||||||
return CodeGenModule::GVA_CXXInline;
|
return CodeGenModule::GVA_CXXInline;
|
||||||
|
|
||||||
return CodeGenModule::GVA_StrongExternal;
|
return External;
|
||||||
}
|
}
|
||||||
|
|
||||||
// "static" functions get internal linkage.
|
// "static" functions get internal linkage.
|
||||||
|
@ -256,7 +264,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
|
||||||
return CodeGenModule::GVA_Internal;
|
return CodeGenModule::GVA_Internal;
|
||||||
|
|
||||||
if (!FD->isInline())
|
if (!FD->isInline())
|
||||||
return CodeGenModule::GVA_StrongExternal;
|
return External;
|
||||||
|
|
||||||
// If the inline function explicitly has the GNU inline attribute on it, or if
|
// If the inline function explicitly has the GNU inline attribute on it, or if
|
||||||
// this is C89 mode, we use to GNU semantics.
|
// this is C89 mode, we use to GNU semantics.
|
||||||
|
@ -273,7 +281,7 @@ GetLinkageForFunction(ASTContext &Context, const FunctionDecl *FD,
|
||||||
if (FD->isExternGNUInline(Context))
|
if (FD->isExternGNUInline(Context))
|
||||||
return CodeGenModule::GVA_C99Inline;
|
return CodeGenModule::GVA_C99Inline;
|
||||||
// Normal inline is a strong symbol.
|
// Normal inline is a strong symbol.
|
||||||
return CodeGenModule::GVA_StrongExternal;
|
return External;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The definition of inline changes based on the language. Note that we
|
// 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
|
// In C99 mode, 'inline' functions are guaranteed to have a strong
|
||||||
// definition somewhere else, so we can use available_externally linkage.
|
// definition somewhere else, so we can use available_externally linkage.
|
||||||
GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
|
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
|
// In C++, the compiler has to emit a definition in every translation unit
|
||||||
// that references the function. We should use linkonce_odr because
|
// that references the function. We should use linkonce_odr because
|
||||||
// a) if all references in this translation unit are optimized away, we
|
// a) if all references in this translation unit are optimized away, we
|
||||||
|
|
|
@ -373,7 +373,8 @@ public:
|
||||||
GVA_Internal,
|
GVA_Internal,
|
||||||
GVA_C99Inline,
|
GVA_C99Inline,
|
||||||
GVA_CXXInline,
|
GVA_CXXInline,
|
||||||
GVA_StrongExternal
|
GVA_StrongExternal,
|
||||||
|
GVA_TemplateInstantiation
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -170,7 +170,29 @@ void CXXNameMangler::mangleGuardVariable(const VarDecl *D)
|
||||||
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
|
void CXXNameMangler::mangleFunctionEncoding(const FunctionDecl *FD) {
|
||||||
// <encoding> ::= <function name> <bare-function-type>
|
// <encoding> ::= <function name> <bare-function-type>
|
||||||
mangleName(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<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD) ||
|
||||||
|
isa<CXXConversionDecl>(FD)))
|
||||||
|
MangleReturnType = true;
|
||||||
|
mangleBareFunctionType(FD->getType()->getAsFunctionType(), MangleReturnType);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isStdNamespace(const DeclContext *DC) {
|
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!");
|
assert(false && "Can't mangle a using directive name!");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(ND)) {
|
||||||
|
if (const TemplateArgumentList *TemplateArgs
|
||||||
|
= Function->getTemplateSpecializationArgs())
|
||||||
|
mangleTemplateArgumentList(*TemplateArgs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CXXNameMangler::mangleSourceName(const IdentifierInfo *II) {
|
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>
|
template<typename T, typename U>
|
||||||
T* next(T* ptr, const U& diff);
|
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) {
|
void test(int *iptr, float *fptr, int diff) {
|
||||||
|
// FIXME: should be "_Z4nextIiiEPT_S1_RKT0_"
|
||||||
|
// RUN: grep "_Z4nextIiiEPiPiRKi" %t &&
|
||||||
iptr = next(iptr, diff);
|
iptr = next(iptr, diff);
|
||||||
|
// FIXME: should be "_Z4nextIfiEPT_S1_RKT0_"
|
||||||
|
// RUN: grep "_Z4nextIfiEPfPfRKi" %t &&
|
||||||
fptr = next(fptr, diff);
|
fptr = next(fptr, diff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,5 +21,7 @@ T* next(T* ptr, const U& diff);
|
||||||
|
|
||||||
void test2(int *iptr, double *dptr, int diff) {
|
void test2(int *iptr, double *dptr, int diff) {
|
||||||
iptr = next(iptr, diff);
|
iptr = next(iptr, diff);
|
||||||
|
// FIXME: should be "_Z4nextIdiEPT_S1_RKT0_"
|
||||||
|
// RUN: grep "_Z4nextIdiEPdPdRKi" %t
|
||||||
dptr = next(dptr, diff);
|
dptr = next(dptr, diff);
|
||||||
}
|
}
|
Загрузка…
Ссылка в новой задаче