Keep track of function template specializations, to eliminate

redundant, implicit instantiations of function templates and provide a
place where we can hang function template specializations.

llvm-svn: 74454
This commit is contained in:
Douglas Gregor 2009-06-29 20:59:39 +00:00
parent 10de9e6602
commit 8f5d4423ca
9 changed files with 530 additions and 382 deletions

View File

@ -809,9 +809,7 @@ public:
return PreviousDeclaration; return PreviousDeclaration;
} }
void setPreviousDeclaration(FunctionDecl * PrevDecl) { void setPreviousDeclaration(FunctionDecl * PrevDecl);
PreviousDeclaration = PrevDecl;
}
unsigned getBuiltinID(ASTContext &Context) const; unsigned getBuiltinID(ASTContext &Context) const;
@ -961,7 +959,8 @@ public:
/// function template specialization from the template. /// function template specialization from the template.
void setFunctionTemplateSpecialization(ASTContext &Context, void setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template, FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs); const TemplateArgumentList *TemplateArgs,
void *InsertPos);
// Implement isa/cast/dyncast/etc. // Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) { static bool classof(const Decl *D) {

View File

@ -100,6 +100,352 @@ public:
} }
}; };
/// \brief Represents a template argument within a class template
/// specialization.
class TemplateArgument {
union {
uintptr_t TypeOrValue;
struct {
char Value[sizeof(llvm::APSInt)];
void *Type;
} Integer;
struct {
TemplateArgument *Args;
unsigned NumArgs;
bool CopyArgs;
} Args;
};
/// \brief Location of the beginning of this template argument.
SourceLocation StartLoc;
public:
/// \brief The type of template argument we're storing.
enum ArgKind {
Null = 0,
/// The template argument is a type. Its value is stored in the
/// TypeOrValue field.
Type = 1,
/// The template argument is a declaration
Declaration = 2,
/// The template argument is an integral value stored in an llvm::APSInt.
Integral = 3,
/// The template argument is a value- or type-dependent expression
/// stored in an Expr*.
Expression = 4,
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
Pack = 5
} Kind;
/// \brief Construct an empty, invalid template argument.
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
/// \brief Construct a template type argument.
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
StartLoc = Loc;
}
/// \brief Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
// FIXME: Need to be sure we have the "canonical" declaration!
TypeOrValue = reinterpret_cast<uintptr_t>(D);
StartLoc = Loc;
}
/// \brief Construct an integral constant template argument.
TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
QualType Type)
: Kind(Integral) {
new (Integer.Value) llvm::APSInt(Value);
Integer.Type = Type.getAsOpaquePtr();
StartLoc = Loc;
}
/// \brief Construct a template argument that is an expression.
///
/// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list.
TemplateArgument(Expr *E);
/// \brief Copy constructor for a template argument.
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
if (Kind == Integral) {
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
Integer.Type = Other.Integer.Type;
} else if (Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = new TemplateArgument[Args.NumArgs];
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I] = Other.Args.Args[I];
}
else
TypeOrValue = Other.TypeOrValue;
StartLoc = Other.StartLoc;
}
TemplateArgument& operator=(const TemplateArgument& Other) {
// FIXME: Does not provide the strong guarantee for exception
// safety.
using llvm::APSInt;
// FIXME: Handle Packs
assert(Kind != Pack && "FIXME: Handle packs");
assert(Other.Kind != Pack && "FIXME: Handle packs");
if (Kind == Other.Kind && Kind == Integral) {
// Copy integral values.
*this->getAsIntegral() = *Other.getAsIntegral();
Integer.Type = Other.Integer.Type;
} else {
// Destroy the current integral value, if that's what we're holding.
if (Kind == Integral)
getAsIntegral()->~APSInt();
Kind = Other.Kind;
if (Other.Kind == Integral) {
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
Integer.Type = Other.Integer.Type;
} else
TypeOrValue = Other.TypeOrValue;
}
StartLoc = Other.StartLoc;
return *this;
}
~TemplateArgument() {
using llvm::APSInt;
if (Kind == Integral)
getAsIntegral()->~APSInt();
else if (Kind == Pack && Args.CopyArgs)
delete[] Args.Args;
}
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
/// \brief Determine whether this template argument has no value.
bool isNull() const { return Kind == Null; }
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
return QualType();
return QualType::getFromOpaquePtr(
reinterpret_cast<void*>(TypeOrValue));
}
/// \brief Retrieve the template argument as a declaration.
Decl *getAsDecl() const {
if (Kind != Declaration)
return 0;
return reinterpret_cast<Decl *>(TypeOrValue);
}
/// \brief Retrieve the template argument as an integral value.
llvm::APSInt *getAsIntegral() {
if (Kind != Integral)
return 0;
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
}
const llvm::APSInt *getAsIntegral() const {
return const_cast<TemplateArgument*>(this)->getAsIntegral();
}
/// \brief Retrieve the type of the integral value.
QualType getIntegralType() const {
if (Kind != Integral)
return QualType();
return QualType::getFromOpaquePtr(Integer.Type);
}
void setIntegralType(QualType T) {
assert(Kind == Integral &&
"Cannot set the integral type of a non-integral template argument");
Integer.Type = T.getAsOpaquePtr();
};
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
if (Kind != Expression)
return 0;
return reinterpret_cast<Expr *>(TypeOrValue);
}
/// \brief Iterator that traverses the elements of a template argument pack.
typedef const TemplateArgument * pack_iterator;
/// \brief Iterator referencing the first argument of a template argument
/// pack.
pack_iterator pack_begin() const {
assert(Kind == Pack);
return Args.Args;
}
/// \brief Iterator referencing one past the last argument of a template
/// argument pack.
pack_iterator pack_end() const {
assert(Kind == Pack);
return Args.Args + Args.NumArgs;
}
/// \brief The number of template arguments in the given template argument
/// pack.
unsigned pack_size() const {
assert(Kind == Pack);
return Args.NumArgs;
}
/// \brief Retrieve the location where the template argument starts.
SourceLocation getLocation() const { return StartLoc; }
/// \brief Construct a template argument pack.
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
/// \brief Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
break;
case Type:
getAsType().Profile(ID);
break;
case Declaration:
ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
break;
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
break;
case Expression:
// FIXME: We need a canonical representation of expressions.
ID.AddPointer(getAsExpr());
break;
case Pack:
ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I].Profile(ID);
}
}
};
/// \brief A helper class for making template argument lists.
class TemplateArgumentListBuilder {
TemplateArgument *StructuredArgs;
unsigned MaxStructuredArgs;
unsigned NumStructuredArgs;
TemplateArgument *FlatArgs;
unsigned MaxFlatArgs;
unsigned NumFlatArgs;
bool AddingToPack;
unsigned PackBeginIndex;
public:
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
unsigned NumTemplateArgs)
: StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
NumStructuredArgs(0), FlatArgs(0),
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
AddingToPack(false), PackBeginIndex(0) { }
void Append(const TemplateArgument& Arg);
void BeginPack();
void EndPack();
void ReleaseArgs();
unsigned flatSize() const {
return NumFlatArgs;
}
const TemplateArgument *getFlatArguments() const {
return FlatArgs;
}
unsigned structuredSize() const {
// If we don't have any structured args, just reuse the flat size.
if (!StructuredArgs)
return flatSize();
return NumStructuredArgs;
}
const TemplateArgument *getStructuredArguments() const {
// If we don't have any structured args, just reuse the flat args.
if (!StructuredArgs)
return getFlatArguments();
return StructuredArgs;
}
};
/// \brief A template argument list.
///
/// FIXME: In the future, this class will be extended to support
/// variadic templates and member templates, which will make some of
/// the function names below make more sense.
class TemplateArgumentList {
/// \brief The template argument list.
///
/// The integer value will be non-zero to indicate that this
/// template argument list does not own the pointer.
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
/// \brief The number of template arguments in this template
/// argument list.
unsigned NumFlatArguments;
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
unsigned NumStructuredArguments;
public:
TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs);
~TemplateArgumentList();
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumFlatArguments && "Invalid template argument index");
return getFlatArgumentList()[Idx];
}
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
/// \brief Retrieve the number of template arguments in this
/// template argument list.
unsigned size() const { return NumFlatArguments; }
/// \brief Retrieve the number of template arguments in the
/// flattened template argument list.
unsigned flat_size() const { return NumFlatArguments; }
/// \brief Retrieve the flattened template argument list.
const TemplateArgument *getFlatArgumentList() const {
return FlatArguments.getPointer();
}
};
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Kinds of Templates // Kinds of Templates
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -157,40 +503,92 @@ protected:
/// \brief Provides information about a function template specialization, /// \brief Provides information about a function template specialization,
/// which is a FunctionDecl that has been explicitly specialization or /// which is a FunctionDecl that has been explicitly specialization or
/// instantiated from a function template. /// instantiated from a function template.
class FunctionTemplateSpecializationInfo { class FunctionTemplateSpecializationInfo : public llvm::FoldingSetNode {
public: public:
/// \brief The function template specialization that this structure
/// describes.
FunctionDecl *Function;
/// \brief The function template from which this function template
/// specialization was generated.
FunctionTemplateDecl *Template; FunctionTemplateDecl *Template;
/// \brief The template arguments used to produce the function template
/// specialization from the function template.
const TemplateArgumentList *TemplateArguments; const TemplateArgumentList *TemplateArguments;
void Profile(llvm::FoldingSetNodeID &ID) {
Profile(ID, TemplateArguments->getFlatArgumentList(),
TemplateArguments->flat_size());
}
static void
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
ID.AddInteger(NumTemplateArgs);
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
TemplateArgs[Arg].Profile(ID);
}
}; };
/// Declaration of a template function. /// Declaration of a template function.
class FunctionTemplateDecl : public TemplateDecl { class FunctionTemplateDecl : public TemplateDecl {
protected: protected:
/// \brief Data that is common to all of the declarations of a given /// \brief Data that is common to all of the declarations of a given
/// class template. /// function template.
struct Common { struct Common {
/// \brief The class template specializations for this class /// \brief The function template specializations for this function
/// template, including explicit specializations and instantiations. /// template, including explicit specializations and instantiations.
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; llvm::FoldingSet<FunctionTemplateSpecializationInfo> Specializations;
/// \brief The class template partial specializations for this class
/// template.
llvm::FoldingSet<ClassTemplatePartialSpecializationDecl>
PartialSpecializations;
/// \brief The injected-class-name type for this class template.
QualType InjectedClassNameType;
}; };
/// \brief A pointer to the previous declaration (if this is a redeclaration)
/// or to the data that is common to all declarations of this function
/// template.
llvm::PointerUnion<Common*, FunctionTemplateDecl*> CommonOrPrev;
/// \brief Retrieves the "common" pointer shared by all
/// (re-)declarations of the same function template. Calling this routine
/// may implicitly allocate memory for the common pointer.
Common *getCommonPtr();
FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, FunctionTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl) TemplateParameterList *Params, NamedDecl *Decl)
: TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl) { } : TemplateDecl(FunctionTemplate, DC, L, Name, Params, Decl),
CommonOrPrev((Common*)0) { }
public: public:
/// Get the underling function declaration of the template. void Destroy(ASTContext &C);
/// Get the underlying function declaration of the template.
FunctionDecl *getTemplatedDecl() const { FunctionDecl *getTemplatedDecl() const {
return static_cast<FunctionDecl*>(TemplatedDecl); return static_cast<FunctionDecl*>(TemplatedDecl);
} }
/// \brief Retrieve the set of function template specializations of this
/// function template.
llvm::FoldingSet<FunctionTemplateSpecializationInfo> &getSpecializations() {
return getCommonPtr()->Specializations;
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
const FunctionTemplateDecl *getPreviousDeclaration() const {
return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>();
}
/// \brief Retrieve the previous declaration of this function template, or
/// NULL if no such declaration exists.
FunctionTemplateDecl *getPreviousDeclaration() {
return CommonOrPrev.dyn_cast<FunctionTemplateDecl*>();
}
/// \brief Set the previous declaration of this function template.
void setPreviousDeclaration(FunctionTemplateDecl *Prev) {
if (Prev)
CommonOrPrev = Prev;
}
/// Create a template function node. /// Create a template function node.
static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC, static FunctionTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L, SourceLocation L,
@ -421,352 +819,6 @@ public:
static bool classof(const TemplateTemplateParmDecl *D) { return true; } static bool classof(const TemplateTemplateParmDecl *D) { return true; }
}; };
/// \brief Represents a template argument within a class template
/// specialization.
class TemplateArgument {
union {
uintptr_t TypeOrValue;
struct {
char Value[sizeof(llvm::APSInt)];
void *Type;
} Integer;
struct {
TemplateArgument *Args;
unsigned NumArgs;
bool CopyArgs;
} Args;
};
/// \brief Location of the beginning of this template argument.
SourceLocation StartLoc;
public:
/// \brief The type of template argument we're storing.
enum ArgKind {
Null = 0,
/// The template argument is a type. Its value is stored in the
/// TypeOrValue field.
Type = 1,
/// The template argument is a declaration
Declaration = 2,
/// The template argument is an integral value stored in an llvm::APSInt.
Integral = 3,
/// The template argument is a value- or type-dependent expression
/// stored in an Expr*.
Expression = 4,
/// The template argument is actually a parameter pack. Arguments are stored
/// in the Args struct.
Pack = 5
} Kind;
/// \brief Construct an empty, invalid template argument.
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
/// \brief Construct a template type argument.
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
StartLoc = Loc;
}
/// \brief Construct a template argument that refers to a
/// declaration, which is either an external declaration or a
/// template declaration.
TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
// FIXME: Need to be sure we have the "canonical" declaration!
TypeOrValue = reinterpret_cast<uintptr_t>(D);
StartLoc = Loc;
}
/// \brief Construct an integral constant template argument.
TemplateArgument(SourceLocation Loc, const llvm::APSInt &Value,
QualType Type)
: Kind(Integral) {
new (Integer.Value) llvm::APSInt(Value);
Integer.Type = Type.getAsOpaquePtr();
StartLoc = Loc;
}
/// \brief Construct a template argument that is an expression.
///
/// This form of template argument only occurs in template argument
/// lists used for dependent types and for expression; it will not
/// occur in a non-dependent, canonical template argument list.
TemplateArgument(Expr *E);
/// \brief Copy constructor for a template argument.
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
if (Kind == Integral) {
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
Integer.Type = Other.Integer.Type;
} else if (Kind == Pack) {
Args.NumArgs = Other.Args.NumArgs;
Args.Args = new TemplateArgument[Args.NumArgs];
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I] = Other.Args.Args[I];
}
else
TypeOrValue = Other.TypeOrValue;
StartLoc = Other.StartLoc;
}
TemplateArgument& operator=(const TemplateArgument& Other) {
// FIXME: Does not provide the strong guarantee for exception
// safety.
using llvm::APSInt;
// FIXME: Handle Packs
assert(Kind != Pack && "FIXME: Handle packs");
assert(Other.Kind != Pack && "FIXME: Handle packs");
if (Kind == Other.Kind && Kind == Integral) {
// Copy integral values.
*this->getAsIntegral() = *Other.getAsIntegral();
Integer.Type = Other.Integer.Type;
} else {
// Destroy the current integral value, if that's what we're holding.
if (Kind == Integral)
getAsIntegral()->~APSInt();
Kind = Other.Kind;
if (Other.Kind == Integral) {
new (Integer.Value) llvm::APSInt(*Other.getAsIntegral());
Integer.Type = Other.Integer.Type;
} else
TypeOrValue = Other.TypeOrValue;
}
StartLoc = Other.StartLoc;
return *this;
}
~TemplateArgument() {
using llvm::APSInt;
if (Kind == Integral)
getAsIntegral()->~APSInt();
else if (Kind == Pack && Args.CopyArgs)
delete[] Args.Args;
}
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
/// \brief Determine whether this template argument has no value.
bool isNull() const { return Kind == Null; }
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
return QualType();
return QualType::getFromOpaquePtr(
reinterpret_cast<void*>(TypeOrValue));
}
/// \brief Retrieve the template argument as a declaration.
Decl *getAsDecl() const {
if (Kind != Declaration)
return 0;
return reinterpret_cast<Decl *>(TypeOrValue);
}
/// \brief Retrieve the template argument as an integral value.
llvm::APSInt *getAsIntegral() {
if (Kind != Integral)
return 0;
return reinterpret_cast<llvm::APSInt*>(&Integer.Value[0]);
}
const llvm::APSInt *getAsIntegral() const {
return const_cast<TemplateArgument*>(this)->getAsIntegral();
}
/// \brief Retrieve the type of the integral value.
QualType getIntegralType() const {
if (Kind != Integral)
return QualType();
return QualType::getFromOpaquePtr(Integer.Type);
}
void setIntegralType(QualType T) {
assert(Kind == Integral &&
"Cannot set the integral type of a non-integral template argument");
Integer.Type = T.getAsOpaquePtr();
};
/// \brief Retrieve the template argument as an expression.
Expr *getAsExpr() const {
if (Kind != Expression)
return 0;
return reinterpret_cast<Expr *>(TypeOrValue);
}
/// \brief Iterator that traverses the elements of a template argument pack.
typedef const TemplateArgument * pack_iterator;
/// \brief Iterator referencing the first argument of a template argument
/// pack.
pack_iterator pack_begin() const {
assert(Kind == Pack);
return Args.Args;
}
/// \brief Iterator referencing one past the last argument of a template
/// argument pack.
pack_iterator pack_end() const {
assert(Kind == Pack);
return Args.Args + Args.NumArgs;
}
/// \brief The number of template arguments in the given template argument
/// pack.
unsigned pack_size() const {
assert(Kind == Pack);
return Args.NumArgs;
}
/// \brief Retrieve the location where the template argument starts.
SourceLocation getLocation() const { return StartLoc; }
/// \brief Construct a template argument pack.
void setArgumentPack(TemplateArgument *Args, unsigned NumArgs, bool CopyArgs);
/// \brief Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
break;
case Type:
getAsType().Profile(ID);
break;
case Declaration:
ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
break;
case Integral:
getAsIntegral()->Profile(ID);
getIntegralType().Profile(ID);
break;
case Expression:
// FIXME: We need a canonical representation of expressions.
ID.AddPointer(getAsExpr());
break;
case Pack:
ID.AddInteger(Args.NumArgs);
for (unsigned I = 0; I != Args.NumArgs; ++I)
Args.Args[I].Profile(ID);
}
}
};
/// \brief A helper class for making template argument lists.
class TemplateArgumentListBuilder {
TemplateArgument *StructuredArgs;
unsigned MaxStructuredArgs;
unsigned NumStructuredArgs;
TemplateArgument *FlatArgs;
unsigned MaxFlatArgs;
unsigned NumFlatArgs;
bool AddingToPack;
unsigned PackBeginIndex;
public:
TemplateArgumentListBuilder(const TemplateParameterList *Parameters,
unsigned NumTemplateArgs)
: StructuredArgs(0), MaxStructuredArgs(Parameters->size()),
NumStructuredArgs(0), FlatArgs(0),
MaxFlatArgs(std::max(MaxStructuredArgs, NumTemplateArgs)), NumFlatArgs(0),
AddingToPack(false), PackBeginIndex(0) { }
void Append(const TemplateArgument& Arg);
void BeginPack();
void EndPack();
void ReleaseArgs();
unsigned flatSize() const {
return NumFlatArgs;
}
const TemplateArgument *getFlatArguments() const {
return FlatArgs;
}
unsigned structuredSize() const {
// If we don't have any structured args, just reuse the flat size.
if (!StructuredArgs)
return flatSize();
return NumStructuredArgs;
}
const TemplateArgument *getStructuredArguments() const {
// If we don't have any structured args, just reuse the flat args.
if (!StructuredArgs)
return getFlatArguments();
return StructuredArgs;
}
};
/// \brief A template argument list.
///
/// FIXME: In the future, this class will be extended to support
/// variadic templates and member templates, which will make some of
/// the function names below make more sense.
class TemplateArgumentList {
/// \brief The template argument list.
///
/// The integer value will be non-zero to indicate that this
/// template argument list does not own the pointer.
llvm::PointerIntPair<const TemplateArgument *, 1> FlatArguments;
/// \brief The number of template arguments in this template
/// argument list.
unsigned NumFlatArguments;
llvm::PointerIntPair<const TemplateArgument *, 1> StructuredArguments;
unsigned NumStructuredArguments;
public:
TemplateArgumentList(ASTContext &Context,
TemplateArgumentListBuilder &Builder,
bool TakeArgs);
~TemplateArgumentList();
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &get(unsigned Idx) const {
assert(Idx < NumFlatArguments && "Invalid template argument index");
return getFlatArgumentList()[Idx];
}
/// \brief Retrieve the template argument at a given index.
const TemplateArgument &operator[](unsigned Idx) const { return get(Idx); }
/// \brief Retrieve the number of template arguments in this
/// template argument list.
unsigned size() const { return NumFlatArguments; }
/// \brief Retrieve the number of template arguments in the
/// flattened template argument list.
unsigned flat_size() const { return NumFlatArguments; }
/// \brief Retrieve the flattened template argument list.
const TemplateArgument *getFlatArgumentList() const {
return FlatArguments.getPointer();
}
};
// \brief Describes the kind of template specialization that a // \brief Describes the kind of template specialization that a
// particular template specialization declaration represents. // particular template specialization declaration represents.
enum TemplateSpecializationKind { enum TemplateSpecializationKind {

View File

@ -1806,6 +1806,12 @@ Decl *ASTContext::getCanonicalDecl(Decl *D) {
return const_cast<FunctionDecl *>(Function); return const_cast<FunctionDecl *>(Function);
} }
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(D)) {
while (FunTmpl->getPreviousDeclaration())
FunTmpl = FunTmpl->getPreviousDeclaration();
return FunTmpl;
}
if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {
while (Var->getPreviousDeclaration()) while (Var->getPreviousDeclaration())
Var = Var->getPreviousDeclaration(); Var = Var->getPreviousDeclaration();

View File

@ -372,11 +372,6 @@ void FunctionDecl::Destroy(ASTContext& C) {
C.Deallocate(ParamInfo); C.Deallocate(ParamInfo);
if (FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization
.dyn_cast<FunctionTemplateSpecializationInfo*>())
C.Deallocate(Info);
Decl::Destroy(C); Decl::Destroy(C);
} }
@ -564,6 +559,18 @@ bool FunctionDecl::isExternGNUInline(ASTContext &Context) const {
return false; return false;
} }
void
FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
PreviousDeclaration = PrevDecl;
if (FunctionTemplateDecl *FunTmpl = getDescribedFunctionTemplate()) {
FunctionTemplateDecl *PrevFunTmpl
= PrevDecl? PrevDecl->getDescribedFunctionTemplate() : 0;
assert((!PrevDecl || PrevFunTmpl) && "Function/function template mismatch");
FunTmpl->setPreviousDeclaration(PrevFunTmpl);
}
}
/// getOverloadedOperator - Which C++ overloaded operator this /// getOverloadedOperator - Which C++ overloaded operator this
/// function represents, if any. /// function represents, if any.
OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const {
@ -595,15 +602,21 @@ FunctionDecl::getTemplateSpecializationArgs() const {
void void
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context, FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
FunctionTemplateDecl *Template, FunctionTemplateDecl *Template,
const TemplateArgumentList *TemplateArgs) { const TemplateArgumentList *TemplateArgs,
void *InsertPos) {
FunctionTemplateSpecializationInfo *Info FunctionTemplateSpecializationInfo *Info
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>(); = TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
if (!Info) if (!Info)
Info = new (Context) FunctionTemplateSpecializationInfo; Info = new (Context) FunctionTemplateSpecializationInfo;
Info->Function = this;
Info->Template = Template; Info->Template = Template;
Info->TemplateArguments = TemplateArgs; Info->TemplateArguments = TemplateArgs;
TemplateOrSpecialization = Info; TemplateOrSpecialization = Info;
// Insert this function template specialization into the set of known
// function template specialiations.
Template->getSpecializations().InsertNode(Info, InsertPos);
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -81,11 +81,36 @@ FunctionTemplateDecl *FunctionTemplateDecl::Create(ASTContext &C,
DeclContext *DC, DeclContext *DC,
SourceLocation L, SourceLocation L,
DeclarationName Name, DeclarationName Name,
TemplateParameterList *Params, TemplateParameterList *Params,
NamedDecl *Decl) { NamedDecl *Decl) {
return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl); return new (C) FunctionTemplateDecl(DC, L, Name, Params, Decl);
} }
void FunctionTemplateDecl::Destroy(ASTContext &C) {
if (Common *CommonPtr = CommonOrPrev.dyn_cast<Common*>()) {
for (llvm::FoldingSet<FunctionTemplateSpecializationInfo>::iterator
Spec = CommonPtr->Specializations.begin(),
SpecEnd = CommonPtr->Specializations.end();
Spec != SpecEnd; ++Spec)
C.Deallocate(&*Spec);
}
Decl::Destroy(C);
}
FunctionTemplateDecl::Common *FunctionTemplateDecl::getCommonPtr() {
// Find the first declaration of this function template.
FunctionTemplateDecl *First = this;
while (First->getPreviousDeclaration())
First = First->getPreviousDeclaration();
if (First->CommonOrPrev.isNull()) {
// FIXME: Allocate with the ASTContext
First->CommonOrPrev = new Common;
}
return First->CommonOrPrev.get<Common*>();
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// ClassTemplateDecl Implementation // ClassTemplateDecl Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -1500,6 +1500,8 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
break; break;
// No code generation needed. // No code generation needed.
case Decl::Using: case Decl::Using:
case Decl::ClassTemplate:
case Decl::FunctionTemplate:
break; break;
case Decl::CXXConstructor: case Decl::CXXConstructor:
EmitCXXConstructors(cast<CXXConstructorDecl>(D)); EmitCXXConstructors(cast<CXXConstructorDecl>(D));

View File

@ -1036,14 +1036,22 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
InstantiateDecl(FunctionTemplate->getTemplatedDecl(), InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
FunctionTemplate->getDeclContext(), FunctionTemplate->getDeclContext(),
*DeducedArgumentList)); *DeducedArgumentList));
if (!Specialization)
if (!Specialization || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure; return TDK_SubstitutionFailure;
// If the template argument list is owned by the function template
// specialization, release it.
if (Specialization->getTemplateSpecializationArgs() == DeducedArgumentList)
Info.take();
// Turn the specialization into an actual function template specialization. // There may have been an error that did not prevent us from constructing a
Specialization->setFunctionTemplateSpecialization(Context, // declaration. Mark the declaration invalid and return with a substitution
FunctionTemplate, // failure.
Info.take()); if (Trap.hasErrorOccurred()) {
Specialization->setInvalidDecl(true);
return TDK_SubstitutionFailure;
}
return TDK_Success; return TDK_Success;
} }

View File

@ -294,7 +294,24 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) {
} }
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
// FIXME: Look for existing specializations (explicit or otherwise). // Check whether there is already a function template specialization for
// this declaration.
FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
void *InsertPos = 0;
if (FunctionTemplate) {
llvm::FoldingSetNodeID ID;
FunctionTemplateSpecializationInfo::Profile(ID,
TemplateArgs.getFlatArgumentList(),
TemplateArgs.flat_size());
FunctionTemplateSpecializationInfo *Info
= FunctionTemplate->getSpecializations().FindNodeOrInsertPos(ID,
InsertPos);
// If we already have a function template specialization, return it.
if (Info)
return Info->Function;
}
Sema::LocalInstantiationScope Scope(SemaRef); Sema::LocalInstantiationScope Scope(SemaRef);
@ -325,10 +342,15 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
NamedDecl *PrevDecl = 0; NamedDecl *PrevDecl = 0;
SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration, SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
/*FIXME:*/OverloadableAttrRequired); /*FIXME:*/OverloadableAttrRequired);
// FIXME: link this to the function template from which it was instantiated. if (FunctionTemplate) {
// Record this function template specialization.
Function->setFunctionTemplateSpecialization(SemaRef.Context,
FunctionTemplate,
&TemplateArgs,
InsertPos);
}
return Function; return Function;
} }

View File

@ -0,0 +1,21 @@
// RUN: clang-cc -emit-llvm %s -o -
template<typename T, typename U>
T* next(T* ptr, const U& diff);
template<typename T, typename U>
T* next(T* ptr, const U& diff) {
return ptr + diff;
}
void test(int *iptr, float *fptr, int diff) {
iptr = next(iptr, diff);
fptr = next(fptr, diff);
}
template<typename T, typename U>
T* next(T* ptr, const U& diff);
void test2(int *iptr, double *dptr, int diff) {
iptr = next(iptr, diff);
dptr = next(dptr, diff);
}