forked from OSchip/llvm-project
Implement template instantiation for ClassTemplateSpecializationTypes,
such as replacing 'T' in vector<T>. There are a few aspects to this: - Extend TemplateArgument to allow arbitrary expressions (an Expr*), and switch ClassTemplateSpecializationType to store TemplateArguments rather than it's own type-or-expression representation. - ClassTemplateSpecializationType can now store dependent types. In that case, the canonical type is another ClassTemplateSpecializationType (with default template arguments expanded) rather than a declaration (we don't build Decls for dependent types). - Split ActOnClassTemplateId into ActOnClassTemplateId (called from the parser) and CheckClassTemplateId (called from ActOnClassTemplateId and InstantiateType). They're smart enough to handle dependent types, now. llvm-svn: 66509
This commit is contained in:
parent
d5b35ee215
commit
c40290e452
|
@ -275,9 +275,9 @@ public:
|
||||||
IdentifierInfo *Name = 0);
|
IdentifierInfo *Name = 0);
|
||||||
|
|
||||||
QualType getClassTemplateSpecializationType(TemplateDecl *Template,
|
QualType getClassTemplateSpecializationType(TemplateDecl *Template,
|
||||||
|
const TemplateArgument *Args,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
uintptr_t *Args, bool *ArgIsType,
|
QualType Canon = QualType());
|
||||||
QualType Canon);
|
|
||||||
|
|
||||||
/// getObjCQualifiedInterfaceType - Return a
|
/// getObjCQualifiedInterfaceType - Return a
|
||||||
/// ObjCQualifiedInterfaceType type for the given interface decl and
|
/// ObjCQualifiedInterfaceType type for the given interface decl and
|
||||||
|
|
|
@ -68,6 +68,11 @@ public:
|
||||||
|
|
||||||
unsigned size() const { return NumParams; }
|
unsigned size() const { return NumParams; }
|
||||||
|
|
||||||
|
const Decl* getParam(unsigned Idx) const {
|
||||||
|
assert(Idx < size() && "Template parameter index out-of-range");
|
||||||
|
return begin()[Idx];
|
||||||
|
}
|
||||||
|
|
||||||
/// \btief Returns the minimum number of arguments needed to form a
|
/// \btief Returns the minimum number of arguments needed to form a
|
||||||
/// template specialization. This may be fewer than the number of
|
/// template specialization. This may be fewer than the number of
|
||||||
/// template parameters, if some of the parameters have default
|
/// template parameters, if some of the parameters have default
|
||||||
|
@ -400,51 +405,72 @@ protected:
|
||||||
/// specialization.
|
/// specialization.
|
||||||
class TemplateArgument {
|
class TemplateArgument {
|
||||||
union {
|
union {
|
||||||
uintptr_t TypeOrDeclaration;
|
uintptr_t TypeOrValue;
|
||||||
char IntegralValue[sizeof(llvm::APInt)];
|
char IntegralValue[sizeof(llvm::APInt)];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief Location of the beginning of this template argument.
|
||||||
|
SourceLocation StartLoc;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// \brief The type of template argument we're storing.
|
/// \brief The type of template argument we're storing.
|
||||||
enum ArgKind {
|
enum ArgKind {
|
||||||
/// The template argument is a type. It's value is stored in the
|
/// The template argument is a type. It's value is stored in the
|
||||||
/// TypeOrDeclaration field.
|
/// TypeOrValue field.
|
||||||
Type = 0,
|
Type = 0,
|
||||||
/// The template argument is a declaration
|
/// The template argument is a declaration
|
||||||
Declaration = 1,
|
Declaration = 1,
|
||||||
/// The template argument is an integral value stored in an llvm::APInt.
|
/// The template argument is an integral value stored in an llvm::APInt.
|
||||||
Integral = 2
|
Integral = 2,
|
||||||
|
/// The template argument is a value- or type-dependent expression
|
||||||
|
/// stored in an Expr*.
|
||||||
|
Expression = 3
|
||||||
} Kind;
|
} Kind;
|
||||||
|
|
||||||
|
/// \brief Construct an empty, invalid template argument.
|
||||||
|
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
|
||||||
|
|
||||||
/// \brief Construct a template type argument.
|
/// \brief Construct a template type argument.
|
||||||
TemplateArgument(QualType T) : Kind(Type) {
|
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
|
||||||
assert(T->isCanonical() &&
|
TypeOrValue = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
||||||
"Template arguments always use the canonical type");
|
StartLoc = Loc;
|
||||||
TypeOrDeclaration = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Construct a template argument that refers to a
|
/// \brief Construct a template argument that refers to a
|
||||||
/// declaration, which is either an external declaration or a
|
/// declaration, which is either an external declaration or a
|
||||||
/// template declaration.
|
/// template declaration.
|
||||||
TemplateArgument(Decl *D) : Kind(Declaration) {
|
TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) {
|
||||||
// FIXME: Need to be sure we have the "canonical" declaration!
|
// FIXME: Need to be sure we have the "canonical" declaration!
|
||||||
TypeOrDeclaration = reinterpret_cast<uintptr_t>(D);
|
TypeOrValue = reinterpret_cast<uintptr_t>(D);
|
||||||
|
StartLoc = Loc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Construct an integral constant template argument.
|
/// \brief Construct an integral constant template argument.
|
||||||
TemplateArgument(const llvm::APInt &Value) : Kind(Integral) {
|
TemplateArgument(SourceLocation Loc, const llvm::APInt &Value)
|
||||||
|
: Kind(Integral) {
|
||||||
new (IntegralValue) llvm::APInt(Value);
|
new (IntegralValue) llvm::APInt(Value);
|
||||||
|
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.
|
/// \brief Copy constructor for a template argument.
|
||||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||||
if (Kind == Integral)
|
if (Kind == Integral)
|
||||||
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
||||||
else
|
else
|
||||||
TypeOrDeclaration = Other.TypeOrDeclaration;
|
TypeOrValue = Other.TypeOrValue;
|
||||||
|
StartLoc = Other.StartLoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||||
|
// FIXME: Does not provide the strong guarantee for exception
|
||||||
|
// safety.
|
||||||
using llvm::APInt;
|
using llvm::APInt;
|
||||||
|
|
||||||
if (Kind == Other.Kind && Kind == Integral) {
|
if (Kind == Other.Kind && Kind == Integral) {
|
||||||
|
@ -460,8 +486,10 @@ public:
|
||||||
if (Other.Kind == Integral)
|
if (Other.Kind == Integral)
|
||||||
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
||||||
else
|
else
|
||||||
TypeOrDeclaration = Other.TypeOrDeclaration;
|
TypeOrValue = Other.TypeOrValue;
|
||||||
}
|
}
|
||||||
|
StartLoc = Other.StartLoc;
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,14 +509,14 @@ public:
|
||||||
return QualType();
|
return QualType();
|
||||||
|
|
||||||
return QualType::getFromOpaquePtr(
|
return QualType::getFromOpaquePtr(
|
||||||
reinterpret_cast<void*>(TypeOrDeclaration));
|
reinterpret_cast<void*>(TypeOrValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the template argument as a declaration.
|
/// \brief Retrieve the template argument as a declaration.
|
||||||
Decl *getAsDecl() const {
|
Decl *getAsDecl() const {
|
||||||
if (Kind != Declaration)
|
if (Kind != Declaration)
|
||||||
return 0;
|
return 0;
|
||||||
return reinterpret_cast<Decl *>(TypeOrDeclaration);
|
return reinterpret_cast<Decl *>(TypeOrValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Retrieve the template argument as an integral value.
|
/// \brief Retrieve the template argument as an integral value.
|
||||||
|
@ -502,6 +530,17 @@ public:
|
||||||
return const_cast<TemplateArgument*>(this)->getAsIntegral();
|
return const_cast<TemplateArgument*>(this)->getAsIntegral();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the template argument as an expression.
|
||||||
|
Expr *getAsExpr() const {
|
||||||
|
if (Kind != Expression)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return reinterpret_cast<Expr *>(TypeOrValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the location where the template argument starts.
|
||||||
|
SourceLocation getLocation() const { return StartLoc; }
|
||||||
|
|
||||||
/// \brief Used to insert TemplateArguments into FoldingSets.
|
/// \brief Used to insert TemplateArguments into FoldingSets.
|
||||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||||
ID.AddInteger(Kind);
|
ID.AddInteger(Kind);
|
||||||
|
@ -517,6 +556,11 @@ public:
|
||||||
case Integral:
|
case Integral:
|
||||||
getAsIntegral()->Profile(ID);
|
getAsIntegral()->Profile(ID);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Expression:
|
||||||
|
// FIXME: We need a canonical representation of expressions.
|
||||||
|
ID.AddPointer(getAsExpr());
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -46,6 +46,7 @@ namespace clang {
|
||||||
class Stmt;
|
class Stmt;
|
||||||
class SourceLocation;
|
class SourceLocation;
|
||||||
class StmtIteratorBase;
|
class StmtIteratorBase;
|
||||||
|
class TemplateArgument;
|
||||||
|
|
||||||
// Provide forward declarations for all of the *Type classes
|
// Provide forward declarations for all of the *Type classes
|
||||||
#define TYPE(Class, Base) class Class##Type;
|
#define TYPE(Class, Base) class Class##Type;
|
||||||
|
@ -1430,100 +1431,52 @@ class ClassTemplateSpecializationType
|
||||||
// possibly with template-names preceded by a nested-name-specifier.
|
// possibly with template-names preceded by a nested-name-specifier.
|
||||||
TemplateDecl *Template;
|
TemplateDecl *Template;
|
||||||
|
|
||||||
|
/// \brief - The number of template arguments named in this class
|
||||||
|
/// template specialization.
|
||||||
unsigned NumArgs;
|
unsigned NumArgs;
|
||||||
|
|
||||||
ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
|
ClassTemplateSpecializationType(TemplateDecl *T,
|
||||||
uintptr_t *Args, bool *ArgIsType,
|
const TemplateArgument *Args,
|
||||||
QualType Canon);
|
unsigned NumArgs, QualType Canon);
|
||||||
|
|
||||||
/// \brief Retrieve the number of packed words that precede the
|
|
||||||
/// actual arguments.
|
|
||||||
///
|
|
||||||
/// The flags that specify whether each argument is a type or an
|
|
||||||
/// expression are packed into the
|
|
||||||
/// ClassTemplateSpecializationType. This routine computes the
|
|
||||||
/// number of pointer-sized words we need to store this information,
|
|
||||||
/// based on the number of template arguments
|
|
||||||
static unsigned getNumPackedWords(unsigned NumArgs) {
|
|
||||||
const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
|
|
||||||
return NumArgs / BitsPerWord + (NumArgs % BitsPerWord > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Pack the given boolean values into words.
|
|
||||||
static void
|
|
||||||
packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words);
|
|
||||||
|
|
||||||
virtual void Destroy(ASTContext& C);
|
virtual void Destroy(ASTContext& C);
|
||||||
|
|
||||||
friend class ASTContext; // ASTContext creates these
|
friend class ASTContext; // ASTContext creates these
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/// \brief Determine whether any of the given template arguments are
|
||||||
|
/// dependent.
|
||||||
|
static bool anyDependentTemplateArguments(const TemplateArgument *Args,
|
||||||
|
unsigned NumArgs);
|
||||||
|
|
||||||
|
typedef const TemplateArgument * iterator;
|
||||||
|
|
||||||
|
iterator begin() const { return getArgs(); }
|
||||||
|
iterator end() const;
|
||||||
|
|
||||||
/// \brief Retrieve the template that we are specializing.
|
/// \brief Retrieve the template that we are specializing.
|
||||||
TemplateDecl *getTemplate() const { return Template; }
|
TemplateDecl *getTemplate() const { return Template; }
|
||||||
|
|
||||||
/// \briefe Retrieve the number of template arguments.
|
/// \brief Retrieve the template arguments.
|
||||||
|
const TemplateArgument *getArgs() const {
|
||||||
|
return reinterpret_cast<const TemplateArgument *>(this + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Retrieve the number of template arguments.
|
||||||
unsigned getNumArgs() const { return NumArgs; }
|
unsigned getNumArgs() const { return NumArgs; }
|
||||||
|
|
||||||
/// \brief Retrieve a specific template argument as a type.
|
/// \brief Retrieve a specific template argument as a type.
|
||||||
/// \precondition @c isArgType(Arg)
|
/// \precondition @c isArgType(Arg)
|
||||||
QualType getArgAsType(unsigned Arg) const {
|
const TemplateArgument &getArg(unsigned Idx) const;
|
||||||
assert(isArgType(Arg) && "Argument is not a type");
|
|
||||||
return QualType::getFromOpaquePtr(
|
|
||||||
reinterpret_cast<void *>(getArgAsOpaqueValue(Arg)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Retrieve a specific template argument as an expression.
|
|
||||||
/// \precondition @c !isArgType(Arg)
|
|
||||||
Expr *getArgAsExpr(unsigned Arg) const {
|
|
||||||
assert(!isArgType(Arg) && "Argument is not an expression");
|
|
||||||
return reinterpret_cast<Expr *>(getArgAsOpaqueValue(Arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \brief Retrieve the specified template argument as an opaque value.
|
|
||||||
uintptr_t getArgAsOpaqueValue(unsigned Arg) const;
|
|
||||||
|
|
||||||
/// \brief Determine whether the given template argument is a type.
|
|
||||||
bool isArgType(unsigned Arg) const;
|
|
||||||
|
|
||||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||||
|
|
||||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||||
// Add the template
|
Profile(ID, Template, getArgs(), NumArgs);
|
||||||
ID.AddPointer(Template);
|
|
||||||
|
|
||||||
// Add the packed words describing what kind of template arguments
|
|
||||||
// we have.
|
|
||||||
// FIXME: Would like to be smarter about the profile of expressions,
|
|
||||||
// so that we can combine expression nodes more effectively.
|
|
||||||
uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
|
|
||||||
for (unsigned Packed = 0, NumPacked = getNumPackedWords(NumArgs);
|
|
||||||
Packed != NumPacked; ++Packed)
|
|
||||||
ID.AddInteger(Data[Packed]);
|
|
||||||
|
|
||||||
// Add the template arguments themselves.
|
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
|
||||||
ID.AddInteger(getArgAsOpaqueValue(Arg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T,
|
static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T,
|
||||||
unsigned NumArgs, uintptr_t *Args, bool *ArgIsType) {
|
const TemplateArgument *Args, unsigned NumArgs);
|
||||||
// Add the template
|
|
||||||
ID.AddPointer(T);
|
|
||||||
|
|
||||||
// Add the packed words describing what kind of template arguments
|
|
||||||
// we have.
|
|
||||||
unsigned NumPackedWords = getNumPackedWords(NumArgs);
|
|
||||||
unsigned NumPackedBytes = NumPackedWords * sizeof(uintptr_t);
|
|
||||||
uintptr_t *PackedWords
|
|
||||||
= reinterpret_cast<uintptr_t *>(alloca(NumPackedBytes));
|
|
||||||
packBooleanValues(NumArgs, ArgIsType, PackedWords);
|
|
||||||
for (unsigned Packed = 0; Packed != NumPackedWords; ++Packed)
|
|
||||||
ID.AddInteger(PackedWords[Packed]);
|
|
||||||
|
|
||||||
// Add the template arguments themselves.
|
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
|
||||||
ID.AddInteger(Args[Arg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool classof(const Type *T) {
|
static bool classof(const Type *T) {
|
||||||
return T->getTypeClass() == ClassTemplateSpecialization;
|
return T->getTypeClass() == ClassTemplateSpecialization;
|
||||||
|
|
|
@ -1309,14 +1309,15 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
||||||
|
|
||||||
QualType
|
QualType
|
||||||
ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
|
ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
|
||||||
|
const TemplateArgument *Args,
|
||||||
unsigned NumArgs,
|
unsigned NumArgs,
|
||||||
uintptr_t *Args, bool *ArgIsType,
|
|
||||||
QualType Canon) {
|
QualType Canon) {
|
||||||
Canon = getCanonicalType(Canon);
|
if (!Canon.isNull())
|
||||||
|
Canon = getCanonicalType(Canon);
|
||||||
|
|
||||||
llvm::FoldingSetNodeID ID;
|
llvm::FoldingSetNodeID ID;
|
||||||
ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args,
|
ClassTemplateSpecializationType::Profile(ID, Template, Args, NumArgs);
|
||||||
ArgIsType);
|
|
||||||
void *InsertPos = 0;
|
void *InsertPos = 0;
|
||||||
ClassTemplateSpecializationType *Spec
|
ClassTemplateSpecializationType *Spec
|
||||||
= ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
|
= ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||||
|
@ -1324,13 +1325,11 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
|
||||||
if (Spec)
|
if (Spec)
|
||||||
return QualType(Spec, 0);
|
return QualType(Spec, 0);
|
||||||
|
|
||||||
void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) +
|
void *Mem = Allocate((sizeof(ClassTemplateSpecializationType) +
|
||||||
(sizeof(uintptr_t) *
|
sizeof(TemplateArgument) * NumArgs),
|
||||||
(ClassTemplateSpecializationType::
|
8);
|
||||||
getNumPackedWords(NumArgs) +
|
Spec = new (Mem) ClassTemplateSpecializationType(Template, Args, NumArgs,
|
||||||
NumArgs)), 8);
|
Canon);
|
||||||
Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args,
|
|
||||||
ArgIsType, Canon);
|
|
||||||
Types.push_back(Spec);
|
Types.push_back(Spec);
|
||||||
ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,15 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
|
||||||
: SourceLocation();
|
: SourceLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// TemplateArgument Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
|
||||||
|
TypeOrValue = reinterpret_cast<uintptr_t>(E);
|
||||||
|
StartLoc = E->getSourceRange().getBegin();
|
||||||
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
// ClassTemplateSpecializationDecl Implementation
|
// ClassTemplateSpecializationDecl Implementation
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -921,59 +921,77 @@ bool EnumType::classof(const TagType *TT) {
|
||||||
return isa<EnumDecl>(TT->getDecl());
|
return isa<EnumDecl>(TT->getDecl());
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
ClassTemplateSpecializationType::
|
ClassTemplateSpecializationType::
|
||||||
packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
|
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
|
||||||
const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
|
for (unsigned Idx = 0; Idx < NumArgs; ++Idx) {
|
||||||
|
switch (Args[Idx].getKind()) {
|
||||||
|
case TemplateArgument::Type:
|
||||||
|
if (Args[Idx].getAsType()->isDependentType())
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Declaration:
|
||||||
|
case TemplateArgument::Integral:
|
||||||
|
// Never dependent
|
||||||
|
break;
|
||||||
|
|
||||||
for (unsigned PW = 0, NumPackedWords = getNumPackedWords(NumArgs), Arg = 0;
|
case TemplateArgument::Expression:
|
||||||
PW != NumPackedWords; ++PW) {
|
if (Args[Idx].getAsExpr()->isTypeDependent() ||
|
||||||
uintptr_t Word = 0;
|
Args[Idx].getAsExpr()->isValueDependent())
|
||||||
for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) {
|
return true;
|
||||||
Word <<= 1;
|
break;
|
||||||
Word |= Values[Arg];
|
|
||||||
}
|
}
|
||||||
Words[PW] = Word;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassTemplateSpecializationType::
|
ClassTemplateSpecializationType::
|
||||||
ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
|
ClassTemplateSpecializationType(TemplateDecl *T, const TemplateArgument *Args,
|
||||||
uintptr_t *Args, bool *ArgIsType,
|
unsigned NumArgs, QualType Canon)
|
||||||
QualType Canon)
|
: Type(ClassTemplateSpecialization,
|
||||||
: Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false),
|
Canon.isNull()? QualType(this, 0) : Canon,
|
||||||
Template(T), NumArgs(NumArgs)
|
/*FIXME: Check for dependent template */
|
||||||
|
anyDependentTemplateArguments(Args, NumArgs)),
|
||||||
|
Template(T), NumArgs(NumArgs)
|
||||||
{
|
{
|
||||||
uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
|
assert((!Canon.isNull() ||
|
||||||
|
anyDependentTemplateArguments(Args, NumArgs)) &&
|
||||||
|
"No canonical type for non-dependent class template specialization");
|
||||||
|
|
||||||
// Pack the argument-is-type values into the words just after the
|
TemplateArgument *TemplateArgs
|
||||||
// class template specialization type.
|
= reinterpret_cast<TemplateArgument *>(this + 1);
|
||||||
packBooleanValues(NumArgs, ArgIsType, Data);
|
|
||||||
|
|
||||||
// Copy the template arguments after the packed words.
|
|
||||||
Data += getNumPackedWords(NumArgs);
|
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
||||||
Data[Arg] = Args[Arg];
|
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClassTemplateSpecializationType::Destroy(ASTContext& C) {
|
void ClassTemplateSpecializationType::Destroy(ASTContext& C) {
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
||||||
if (!isArgType(Arg))
|
if (Expr *E = getArg(Arg).getAsExpr())
|
||||||
getArgAsExpr(Arg)->Destroy(C);
|
E->Destroy(C);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintptr_t
|
ClassTemplateSpecializationType::iterator
|
||||||
ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
|
ClassTemplateSpecializationType::end() const {
|
||||||
const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
|
return begin() + getNumArgs();
|
||||||
Data += getNumPackedWords(NumArgs);
|
|
||||||
return Data[Arg];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
|
const TemplateArgument &
|
||||||
const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
|
ClassTemplateSpecializationType::getArg(unsigned Idx) const {
|
||||||
const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
|
assert(Idx < getNumArgs() && "Template argument out of range");
|
||||||
Data += Arg / BitsPerWord;
|
return getArgs()[Idx];
|
||||||
return (*Data >> ((NumArgs - Arg) % BitsPerWord - 1)) & 0x01;
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ClassTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID,
|
||||||
|
TemplateDecl *T,
|
||||||
|
const TemplateArgument *Args,
|
||||||
|
unsigned NumArgs) {
|
||||||
|
ID.AddPointer(T);
|
||||||
|
|
||||||
|
for (unsigned Idx = 0; Idx < NumArgs; ++Idx)
|
||||||
|
Args[Idx].Profile(ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
@ -1280,11 +1298,24 @@ getAsStringInternal(std::string &InnerString) const {
|
||||||
|
|
||||||
// Print the argument into a string.
|
// Print the argument into a string.
|
||||||
std::string ArgString;
|
std::string ArgString;
|
||||||
if (isArgType(Arg))
|
switch (getArg(Arg).getKind()) {
|
||||||
getArgAsType(Arg).getAsStringInternal(ArgString);
|
case TemplateArgument::Type:
|
||||||
else {
|
getArg(Arg).getAsType().getAsStringInternal(ArgString);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Declaration:
|
||||||
|
ArgString = cast<NamedDecl>(getArg(Arg).getAsDecl())->getNameAsString();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Integral:
|
||||||
|
ArgString = getArg(Arg).getAsIntegral()->toString(10, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Expression: {
|
||||||
llvm::raw_string_ostream s(ArgString);
|
llvm::raw_string_ostream s(ArgString);
|
||||||
getArgAsExpr(Arg)->printPretty(s);
|
getArg(Arg).getAsExpr()->printPretty(s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is the first argument and its string representation
|
// If this is the first argument and its string representation
|
||||||
|
|
|
@ -390,13 +390,7 @@ void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const {
|
||||||
S.Emit(getCanonicalTypeInternal());
|
S.Emit(getCanonicalTypeInternal());
|
||||||
S.EmitPtr(Template);
|
S.EmitPtr(Template);
|
||||||
S.EmitInt(NumArgs);
|
S.EmitInt(NumArgs);
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
|
// FIXME: Serialize class template specialization types
|
||||||
S.EmitBool(isArgType(Arg));
|
|
||||||
if (isArgType(Arg))
|
|
||||||
S.Emit(getArgAsType(Arg));
|
|
||||||
else
|
|
||||||
S.EmitOwnedPtr(getArgAsExpr(Arg));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
|
@ -409,19 +403,10 @@ CreateImpl(ASTContext& Context, Deserializer& D) {
|
||||||
TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
|
TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
|
||||||
unsigned NumArgs = D.ReadInt();
|
unsigned NumArgs = D.ReadInt();
|
||||||
|
|
||||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
|
// FIXME: De-serialize class template specialization types
|
||||||
bool IsType = D.ReadBool();
|
(void)Template;
|
||||||
ArgIsType.push_back(IsType);
|
(void)NumArgs;
|
||||||
if (IsType)
|
return 0;
|
||||||
Args.push_back(
|
|
||||||
reinterpret_cast<uintptr_t>(QualType::ReadVal(D).getAsOpaquePtr()));
|
|
||||||
else
|
|
||||||
Args.push_back(reinterpret_cast<uintptr_t>(D.ReadOwnedPtr<Expr>(Context)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Context.getClassTemplateSpecializationType(Template, NumArgs,
|
|
||||||
&Args[0], &ArgIsType[0],
|
|
||||||
Canon).getTypePtr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -1601,6 +1601,13 @@ public:
|
||||||
AttributeList *Attr,
|
AttributeList *Attr,
|
||||||
MultiTemplateParamsArg TemplateParameterLists);
|
MultiTemplateParamsArg TemplateParameterLists);
|
||||||
|
|
||||||
|
QualType CheckClassTemplateId(ClassTemplateDecl *ClassTemplate,
|
||||||
|
SourceLocation TemplateLoc,
|
||||||
|
SourceLocation LAngleLoc,
|
||||||
|
const TemplateArgument *TemplateArgs,
|
||||||
|
unsigned NumTemplateArgs,
|
||||||
|
SourceLocation RAngleLoc);
|
||||||
|
|
||||||
virtual TypeResult
|
virtual TypeResult
|
||||||
ActOnClassTemplateId(DeclTy *Template, SourceLocation TemplateLoc,
|
ActOnClassTemplateId(DeclTy *Template, SourceLocation TemplateLoc,
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
|
@ -1630,8 +1637,8 @@ public:
|
||||||
bool CheckTemplateArgumentList(TemplateDecl *Template,
|
bool CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
SourceLocation TemplateLoc,
|
SourceLocation TemplateLoc,
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
ASTTemplateArgsPtr& TemplateArgs,
|
const TemplateArgument *TemplateArgs,
|
||||||
SourceLocation *TemplateArgLocs,
|
unsigned NumTemplateArgs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
llvm::SmallVectorImpl<TemplateArgument> &Converted);
|
llvm::SmallVectorImpl<TemplateArgument> &Converted);
|
||||||
|
|
||||||
|
|
|
@ -383,7 +383,8 @@ Sema::BaseResult
|
||||||
Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
|
Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
|
||||||
bool Virtual, AccessSpecifier Access,
|
bool Virtual, AccessSpecifier Access,
|
||||||
TypeTy *basetype, SourceLocation BaseLoc) {
|
TypeTy *basetype, SourceLocation BaseLoc) {
|
||||||
CXXRecordDecl *Class = (CXXRecordDecl*)classdecl;
|
AdjustDeclIfTemplate(classdecl);
|
||||||
|
CXXRecordDecl *Class = cast<CXXRecordDecl>((Decl*)classdecl);
|
||||||
QualType BaseType = QualType::getFromOpaquePtr(basetype);
|
QualType BaseType = QualType::getFromOpaquePtr(basetype);
|
||||||
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
|
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
|
||||||
Virtual, Access,
|
Virtual, Access,
|
||||||
|
|
|
@ -658,61 +658,115 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
||||||
return Invalid;
|
return Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Translates template arguments as provided by the parser
|
||||||
|
/// into template arguments used by semantic analysis.
|
||||||
|
static void
|
||||||
|
translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
|
||||||
|
SourceLocation *TemplateArgLocs,
|
||||||
|
llvm::SmallVector<TemplateArgument, 16> &TemplateArgs) {
|
||||||
|
TemplateArgs.reserve(TemplateArgsIn.size());
|
||||||
|
|
||||||
|
void **Args = TemplateArgsIn.getArgs();
|
||||||
|
bool *ArgIsType = TemplateArgsIn.getArgIsType();
|
||||||
|
for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) {
|
||||||
|
TemplateArgs.push_back(
|
||||||
|
ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg],
|
||||||
|
QualType::getFromOpaquePtr(Args[Arg]))
|
||||||
|
: TemplateArgument(reinterpret_cast<Expr *>(Args[Arg])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QualType Sema::CheckClassTemplateId(ClassTemplateDecl *ClassTemplate,
|
||||||
|
SourceLocation TemplateLoc,
|
||||||
|
SourceLocation LAngleLoc,
|
||||||
|
const TemplateArgument *TemplateArgs,
|
||||||
|
unsigned NumTemplateArgs,
|
||||||
|
SourceLocation RAngleLoc) {
|
||||||
|
// Check that the template argument list is well-formed for this
|
||||||
|
// template.
|
||||||
|
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
||||||
|
if (CheckTemplateArgumentList(ClassTemplate, TemplateLoc, LAngleLoc,
|
||||||
|
TemplateArgs, NumTemplateArgs, RAngleLoc,
|
||||||
|
ConvertedTemplateArgs))
|
||||||
|
return QualType();
|
||||||
|
|
||||||
|
assert((ConvertedTemplateArgs.size() ==
|
||||||
|
ClassTemplate->getTemplateParameters()->size()) &&
|
||||||
|
"Converted template argument list is too short!");
|
||||||
|
|
||||||
|
QualType CanonType;
|
||||||
|
|
||||||
|
if (ClassTemplateSpecializationType::anyDependentTemplateArguments(
|
||||||
|
TemplateArgs,
|
||||||
|
NumTemplateArgs)) {
|
||||||
|
// This class template specialization is a dependent
|
||||||
|
// type. Therefore, its canonical type is another class template
|
||||||
|
// specialization type that contains all of the converted
|
||||||
|
// arguments in canonical form. This ensures that, e.g., A<T> and
|
||||||
|
// A<T, T> have identical types when A is declared as:
|
||||||
|
//
|
||||||
|
// template<typename T, typename U = T> struct A;
|
||||||
|
|
||||||
|
CanonType = Context.getClassTemplateSpecializationType(ClassTemplate,
|
||||||
|
&ConvertedTemplateArgs[0],
|
||||||
|
ConvertedTemplateArgs.size());
|
||||||
|
} else {
|
||||||
|
// Find the class template specialization declaration that
|
||||||
|
// corresponds to these arguments.
|
||||||
|
llvm::FoldingSetNodeID ID;
|
||||||
|
ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
|
||||||
|
ConvertedTemplateArgs.size());
|
||||||
|
void *InsertPos = 0;
|
||||||
|
ClassTemplateSpecializationDecl *Decl
|
||||||
|
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
|
||||||
|
if (!Decl) {
|
||||||
|
// This is the first time we have referenced this class template
|
||||||
|
// specialization. Create the canonical declaration and add it to
|
||||||
|
// the set of specializations.
|
||||||
|
Decl = ClassTemplateSpecializationDecl::Create(Context,
|
||||||
|
ClassTemplate->getDeclContext(),
|
||||||
|
TemplateLoc,
|
||||||
|
ClassTemplate,
|
||||||
|
&ConvertedTemplateArgs[0],
|
||||||
|
ConvertedTemplateArgs.size(),
|
||||||
|
0);
|
||||||
|
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
|
||||||
|
Decl->setLexicalDeclContext(CurContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
CanonType = Context.getTypeDeclType(Decl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the fully-sugared type for this class template
|
||||||
|
// specialization, which refers back to the class template
|
||||||
|
// specialization we created or found.
|
||||||
|
return Context.getClassTemplateSpecializationType(ClassTemplate,
|
||||||
|
TemplateArgs,
|
||||||
|
NumTemplateArgs,
|
||||||
|
CanonType);
|
||||||
|
}
|
||||||
|
|
||||||
Action::TypeResult
|
Action::TypeResult
|
||||||
Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
|
Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
ASTTemplateArgsPtr TemplateArgs,
|
ASTTemplateArgsPtr TemplateArgsIn,
|
||||||
SourceLocation *TemplateArgLocs,
|
SourceLocation *TemplateArgLocs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
const CXXScopeSpec *SS) {
|
const CXXScopeSpec *SS) {
|
||||||
TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
|
TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
|
||||||
ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
|
ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
|
||||||
|
|
||||||
// Check that the template argument list is well-formed for this
|
// Translate the parser's template argument list in our AST format.
|
||||||
// template.
|
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||||
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
||||||
if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
|
|
||||||
TemplateArgs, TemplateArgLocs, RAngleLoc,
|
|
||||||
ConvertedTemplateArgs))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
assert((ConvertedTemplateArgs.size() ==
|
QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc,
|
||||||
Template->getTemplateParameters()->size()) &&
|
LAngleLoc,
|
||||||
"Converted template argument list is too short!");
|
&TemplateArgs[0],
|
||||||
|
TemplateArgs.size(),
|
||||||
|
RAngleLoc);
|
||||||
|
|
||||||
// Find the class template specialization declaration that
|
TemplateArgsIn.release();
|
||||||
// corresponds to these arguments.
|
|
||||||
llvm::FoldingSetNodeID ID;
|
|
||||||
ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0],
|
|
||||||
ConvertedTemplateArgs.size());
|
|
||||||
void *InsertPos = 0;
|
|
||||||
ClassTemplateSpecializationDecl *Decl
|
|
||||||
= ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos);
|
|
||||||
if (!Decl) {
|
|
||||||
// This is the first time we have referenced this class template
|
|
||||||
// specialization. Create the canonical declaration and add it to
|
|
||||||
// the set of specializations.
|
|
||||||
Decl = ClassTemplateSpecializationDecl::Create(Context,
|
|
||||||
ClassTemplate->getDeclContext(),
|
|
||||||
TemplateLoc,
|
|
||||||
ClassTemplate,
|
|
||||||
&ConvertedTemplateArgs[0],
|
|
||||||
ConvertedTemplateArgs.size(),
|
|
||||||
0);
|
|
||||||
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
|
|
||||||
Decl->setLexicalDeclContext(CurContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build the fully-sugared type for this class template
|
|
||||||
// specialization, which refers back to the class template
|
|
||||||
// specialization we created or found.
|
|
||||||
QualType Result
|
|
||||||
= Context.getClassTemplateSpecializationType(Template,
|
|
||||||
TemplateArgs.size(),
|
|
||||||
reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
|
|
||||||
TemplateArgs.getArgIsType(),
|
|
||||||
Context.getTypeDeclType(Decl));
|
|
||||||
TemplateArgs.release();
|
|
||||||
return Result.getAsOpaquePtr();
|
return Result.getAsOpaquePtr();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,13 +775,13 @@ Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
|
||||||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
SourceLocation TemplateLoc,
|
SourceLocation TemplateLoc,
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
ASTTemplateArgsPtr& Args,
|
const TemplateArgument *TemplateArgs,
|
||||||
SourceLocation *TemplateArgLocs,
|
unsigned NumTemplateArgs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
|
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
|
||||||
TemplateParameterList *Params = Template->getTemplateParameters();
|
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||||
unsigned NumParams = Params->size();
|
unsigned NumParams = Params->size();
|
||||||
unsigned NumArgs = Args.size();
|
unsigned NumArgs = NumTemplateArgs;
|
||||||
bool Invalid = false;
|
bool Invalid = false;
|
||||||
|
|
||||||
if (NumArgs > NumParams ||
|
if (NumArgs > NumParams ||
|
||||||
|
@ -737,7 +791,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
// arguments.
|
// arguments.
|
||||||
SourceRange Range;
|
SourceRange Range;
|
||||||
if (NumArgs > NumParams)
|
if (NumArgs > NumParams)
|
||||||
Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc);
|
Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
|
||||||
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
|
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
|
||||||
<< (NumArgs > NumParams)
|
<< (NumArgs > NumParams)
|
||||||
<< (isa<ClassTemplateDecl>(Template)? 0 :
|
<< (isa<ClassTemplateDecl>(Template)? 0 :
|
||||||
|
@ -759,9 +813,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
ParamEnd = Params->end();
|
ParamEnd = Params->end();
|
||||||
Param != ParamEnd; ++Param, ++ArgIdx) {
|
Param != ParamEnd; ++Param, ++ArgIdx) {
|
||||||
// Decode the template argument
|
// Decode the template argument
|
||||||
QualType ArgType;
|
TemplateArgument Arg;
|
||||||
Expr *ArgExpr = 0;
|
|
||||||
SourceLocation ArgLoc;
|
|
||||||
if (ArgIdx >= NumArgs) {
|
if (ArgIdx >= NumArgs) {
|
||||||
// Retrieve the default template argument from the template
|
// Retrieve the default template argument from the template
|
||||||
// parameter.
|
// parameter.
|
||||||
|
@ -769,7 +821,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
if (!TTP->hasDefaultArgument())
|
if (!TTP->hasDefaultArgument())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ArgType = TTP->getDefaultArgument();
|
QualType ArgType = TTP->getDefaultArgument();
|
||||||
|
|
||||||
// If the argument type is dependent, instantiate it now based
|
// If the argument type is dependent, instantiate it now based
|
||||||
// on the previously-computed template arguments.
|
// on the previously-computed template arguments.
|
||||||
|
@ -781,15 +833,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
if (ArgType.isNull())
|
if (ArgType.isNull())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
ArgLoc = TTP->getDefaultArgumentLoc();
|
Arg = TemplateArgument(TTP->getLocation(), ArgType);
|
||||||
} else if (NonTypeTemplateParmDecl *NTTP
|
} else if (NonTypeTemplateParmDecl *NTTP
|
||||||
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
||||||
if (!NTTP->hasDefaultArgument())
|
if (!NTTP->hasDefaultArgument())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// FIXME: Instantiate default argument
|
// FIXME: Instantiate default argument
|
||||||
ArgExpr = NTTP->getDefaultArgument();
|
Arg = TemplateArgument(NTTP->getDefaultArgument());
|
||||||
ArgLoc = NTTP->getDefaultArgumentLoc();
|
|
||||||
} else {
|
} else {
|
||||||
TemplateTemplateParmDecl *TempParm
|
TemplateTemplateParmDecl *TempParm
|
||||||
= cast<TemplateTemplateParmDecl>(*Param);
|
= cast<TemplateTemplateParmDecl>(*Param);
|
||||||
|
@ -798,29 +849,24 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// FIXME: Instantiate default argument
|
// FIXME: Instantiate default argument
|
||||||
ArgExpr = TempParm->getDefaultArgument();
|
Arg = TemplateArgument(TempParm->getDefaultArgument());
|
||||||
ArgLoc = TempParm->getDefaultArgumentLoc();
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Retrieve the template argument produced by the user.
|
// Retrieve the template argument produced by the user.
|
||||||
ArgLoc = TemplateArgLocs[ArgIdx];
|
Arg = TemplateArgs[ArgIdx];
|
||||||
|
|
||||||
if (Args.getArgIsType()[ArgIdx])
|
|
||||||
ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
|
|
||||||
else
|
|
||||||
ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||||
// Check template type parameters.
|
// Check template type parameters.
|
||||||
if (!ArgType.isNull()) {
|
if (Arg.getKind() == TemplateArgument::Type) {
|
||||||
if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
|
if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation()))
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
|
|
||||||
// Add the converted template type argument.
|
// Add the converted template type argument.
|
||||||
Converted.push_back(
|
Converted.push_back(
|
||||||
TemplateArgument(Context.getCanonicalType(ArgType)));
|
TemplateArgument(Arg.getLocation(),
|
||||||
|
Context.getCanonicalType(Arg.getAsType())));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -829,9 +875,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
// type shall be a type-id.
|
// type shall be a type-id.
|
||||||
|
|
||||||
// We have a template type parameter but the template argument
|
// We have a template type parameter but the template argument
|
||||||
// is an expression.
|
// is not a type.
|
||||||
Diag(ArgExpr->getSourceRange().getBegin(),
|
Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
|
||||||
diag::err_template_arg_must_be_type);
|
|
||||||
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
} else if (NonTypeTemplateParmDecl *NTTP
|
} else if (NonTypeTemplateParmDecl *NTTP
|
||||||
|
@ -859,50 +904,81 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ArgExpr) {
|
switch (Arg.getKind()) {
|
||||||
if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted))
|
case TemplateArgument::Expression: {
|
||||||
|
Expr *E = Arg.getAsExpr();
|
||||||
|
if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
|
||||||
Invalid = true;
|
Invalid = true;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a non-type template parameter but the template
|
case TemplateArgument::Declaration:
|
||||||
// argument is a type.
|
case TemplateArgument::Integral:
|
||||||
|
// We've already checked this template argument, so just copy
|
||||||
|
// it to the list of converted arguments.
|
||||||
|
Converted.push_back(Arg);
|
||||||
|
break;
|
||||||
|
|
||||||
// C++ [temp.arg]p2:
|
case TemplateArgument::Type:
|
||||||
// In a template-argument, an ambiguity between a type-id and
|
// We have a non-type template parameter but the template
|
||||||
// an expression is resolved to a type-id, regardless of the
|
// argument is a type.
|
||||||
// form of the corresponding template-parameter.
|
|
||||||
//
|
// C++ [temp.arg]p2:
|
||||||
// We warn specifically about this case, since it can be rather
|
// In a template-argument, an ambiguity between a type-id and
|
||||||
// confusing for users.
|
// an expression is resolved to a type-id, regardless of the
|
||||||
if (ArgType->isFunctionType())
|
// form of the corresponding template-parameter.
|
||||||
Diag(ArgLoc, diag::err_template_arg_nontype_ambig)
|
//
|
||||||
<< ArgType;
|
// We warn specifically about this case, since it can be rather
|
||||||
else
|
// confusing for users.
|
||||||
Diag(ArgLoc, diag::err_template_arg_must_be_expr);
|
if (Arg.getAsType()->isFunctionType())
|
||||||
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig)
|
||||||
Invalid = true;
|
<< Arg.getAsType();
|
||||||
|
else
|
||||||
|
Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr);
|
||||||
|
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
||||||
|
Invalid = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check template template parameters.
|
// Check template template parameters.
|
||||||
TemplateTemplateParmDecl *TempParm
|
TemplateTemplateParmDecl *TempParm
|
||||||
= cast<TemplateTemplateParmDecl>(*Param);
|
= cast<TemplateTemplateParmDecl>(*Param);
|
||||||
|
|
||||||
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
|
switch (Arg.getKind()) {
|
||||||
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
|
case TemplateArgument::Expression: {
|
||||||
if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
|
Expr *ArgExpr = Arg.getAsExpr();
|
||||||
Invalid = true;
|
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
|
||||||
|
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
|
||||||
// Add the converted template argument.
|
if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
|
||||||
// FIXME: Need the "canonical" template declaration!
|
Invalid = true;
|
||||||
Converted.push_back(
|
|
||||||
TemplateArgument(cast<DeclRefExpr>(ArgExpr)->getDecl()));
|
// Add the converted template argument.
|
||||||
continue;
|
// FIXME: Need the "canonical" template declaration!
|
||||||
|
Converted.push_back(
|
||||||
|
TemplateArgument(Arg.getLocation(),
|
||||||
|
cast<DeclRefExpr>(ArgExpr)->getDecl()));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fall through
|
||||||
|
|
||||||
|
case TemplateArgument::Type: {
|
||||||
|
// We have a template template parameter but the template
|
||||||
|
// argument does not refer to a template.
|
||||||
|
Diag(Arg.getLocation(), diag::err_template_arg_must_be_template);
|
||||||
|
Invalid = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have a template template parameter but the template
|
case TemplateArgument::Declaration:
|
||||||
// argument does not refer to a template.
|
// We've already checked this template argument, so just copy
|
||||||
Diag(ArgLoc, diag::err_template_arg_must_be_template);
|
// it to the list of converted arguments.
|
||||||
Invalid = true;
|
Converted.push_back(Arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Integral:
|
||||||
|
assert(false && "Integral argument with template template parameter");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1109,11 +1185,16 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
|
||||||
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
QualType InstantiatedParamType, Expr *&Arg,
|
QualType InstantiatedParamType, Expr *&Arg,
|
||||||
llvm::SmallVectorImpl<TemplateArgument> *Converted) {
|
llvm::SmallVectorImpl<TemplateArgument> *Converted) {
|
||||||
|
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
|
||||||
|
|
||||||
// If either the parameter has a dependent type or the argument is
|
// If either the parameter has a dependent type or the argument is
|
||||||
// type-dependent, there's nothing we can check now.
|
// type-dependent, there's nothing we can check now.
|
||||||
// FIXME: Add template argument to Converted!
|
// FIXME: Add template argument to Converted!
|
||||||
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent())
|
if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) {
|
||||||
|
// FIXME: Produce a cloned, canonical expression?
|
||||||
|
Converted->push_back(TemplateArgument(Arg));
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// C++ [temp.arg.nontype]p5:
|
// C++ [temp.arg.nontype]p5:
|
||||||
// The following conversions are performed on each expression used
|
// The following conversions are performed on each expression used
|
||||||
|
@ -1188,7 +1269,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
IntegerType->isSignedIntegerType());
|
IntegerType->isSignedIntegerType());
|
||||||
CanonicalArg = Value;
|
CanonicalArg = Value;
|
||||||
|
|
||||||
Converted->push_back(TemplateArgument(CanonicalArg));
|
Converted->push_back(TemplateArgument(StartLoc, CanonicalArg));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1252,7 +1333,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Converted)
|
if (Converted)
|
||||||
Converted->push_back(TemplateArgument(Member));
|
Converted->push_back(TemplateArgument(StartLoc, Member));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1262,7 +1343,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Converted)
|
if (Converted)
|
||||||
Converted->push_back(TemplateArgument(Entity));
|
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,7 +1378,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Converted)
|
if (Converted)
|
||||||
Converted->push_back(TemplateArgument(Entity));
|
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1339,7 +1420,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Converted)
|
if (Converted)
|
||||||
Converted->push_back(TemplateArgument(Entity));
|
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1366,7 +1447,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
if (Converted)
|
if (Converted)
|
||||||
Converted->push_back(TemplateArgument(Member));
|
Converted->push_back(TemplateArgument(StartLoc, Member));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1649,7 +1730,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
DeclTy *TemplateD,
|
DeclTy *TemplateD,
|
||||||
SourceLocation TemplateNameLoc,
|
SourceLocation TemplateNameLoc,
|
||||||
SourceLocation LAngleLoc,
|
SourceLocation LAngleLoc,
|
||||||
ASTTemplateArgsPtr TemplateArgs,
|
ASTTemplateArgsPtr TemplateArgsIn,
|
||||||
SourceLocation *TemplateArgLocs,
|
SourceLocation *TemplateArgLocs,
|
||||||
SourceLocation RAngleLoc,
|
SourceLocation RAngleLoc,
|
||||||
AttributeList *Attr,
|
AttributeList *Attr,
|
||||||
|
@ -1701,12 +1782,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
|
Kind = ClassTemplate->getTemplatedDecl()->getTagKind();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Translate the parser's template argument list in our AST format.
|
||||||
|
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||||
|
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
||||||
|
|
||||||
// Check that the template argument list is well-formed for this
|
// Check that the template argument list is well-formed for this
|
||||||
// template.
|
// template.
|
||||||
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
||||||
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
|
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
|
||||||
TemplateArgs, TemplateArgLocs, RAngleLoc,
|
&TemplateArgs[0], TemplateArgs.size(),
|
||||||
ConvertedTemplateArgs))
|
RAngleLoc, ConvertedTemplateArgs))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
assert((ConvertedTemplateArgs.size() ==
|
assert((ConvertedTemplateArgs.size() ==
|
||||||
|
@ -1786,11 +1871,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
||||||
// template arguments in the specialization.
|
// template arguments in the specialization.
|
||||||
Specialization->setTypeAsWritten(
|
Specialization->setTypeAsWritten(
|
||||||
Context.getClassTemplateSpecializationType(ClassTemplate,
|
Context.getClassTemplateSpecializationType(ClassTemplate,
|
||||||
|
&TemplateArgs[0],
|
||||||
TemplateArgs.size(),
|
TemplateArgs.size(),
|
||||||
reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
|
|
||||||
TemplateArgs.getArgIsType(),
|
|
||||||
Context.getTypeDeclType(Specialization)));
|
Context.getTypeDeclType(Specialization)));
|
||||||
TemplateArgs.release();
|
TemplateArgsIn.release();
|
||||||
|
|
||||||
// C++ [temp.expl.spec]p9:
|
// C++ [temp.expl.spec]p9:
|
||||||
// A template explicit specialization is in the scope of the
|
// A template explicit specialization is in the scope of the
|
||||||
|
|
|
@ -302,9 +302,44 @@ TemplateTypeInstantiator::
|
||||||
InstantiateClassTemplateSpecializationType(
|
InstantiateClassTemplateSpecializationType(
|
||||||
const ClassTemplateSpecializationType *T,
|
const ClassTemplateSpecializationType *T,
|
||||||
unsigned Quals) const {
|
unsigned Quals) const {
|
||||||
// FIXME: Implement this
|
llvm::SmallVector<TemplateArgument, 16> InstantiatedTemplateArgs;
|
||||||
assert(false && "Cannot instantiate ClassTemplateSpecializationType yet");
|
InstantiatedTemplateArgs.reserve(T->getNumArgs());
|
||||||
return QualType();
|
for (ClassTemplateSpecializationType::iterator Arg = T->begin(),
|
||||||
|
ArgEnd = T->end();
|
||||||
|
Arg != ArgEnd; ++Arg) {
|
||||||
|
switch (Arg->getKind()) {
|
||||||
|
case TemplateArgument::Type: {
|
||||||
|
QualType T = SemaRef.InstantiateType(Arg->getAsType(),
|
||||||
|
TemplateArgs, NumTemplateArgs,
|
||||||
|
Arg->getLocation(),
|
||||||
|
DeclarationName());
|
||||||
|
if (T.isNull())
|
||||||
|
return QualType();
|
||||||
|
|
||||||
|
InstantiatedTemplateArgs.push_back(
|
||||||
|
TemplateArgument(Arg->getLocation(), T));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case TemplateArgument::Declaration:
|
||||||
|
case TemplateArgument::Integral:
|
||||||
|
InstantiatedTemplateArgs.push_back(*Arg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TemplateArgument::Expression:
|
||||||
|
assert(false && "Cannot instantiate expressions yet");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: We're missing the locations of the template name, '<', and
|
||||||
|
// '>'.
|
||||||
|
return SemaRef.CheckClassTemplateId(cast<ClassTemplateDecl>(T->getTemplate()),
|
||||||
|
Loc,
|
||||||
|
SourceLocation(),
|
||||||
|
&InstantiatedTemplateArgs[0],
|
||||||
|
InstantiatedTemplateArgs.size(),
|
||||||
|
SourceLocation());
|
||||||
}
|
}
|
||||||
|
|
||||||
QualType
|
QualType
|
||||||
|
|
|
@ -14,8 +14,7 @@ A<A<int> > *a6;
|
||||||
// [temp.arg.type]p2
|
// [temp.arg.type]p2
|
||||||
void f() {
|
void f() {
|
||||||
class X { };
|
class X { };
|
||||||
A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}} \
|
A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}
|
||||||
// FIXME: expected-error{{use of undeclared identifier 'a'}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
|
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
|
||||||
|
|
Loading…
Reference in New Issue