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);
|
||||
|
||||
QualType getClassTemplateSpecializationType(TemplateDecl *Template,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
uintptr_t *Args, bool *ArgIsType,
|
||||
QualType Canon);
|
||||
QualType Canon = QualType());
|
||||
|
||||
/// getObjCQualifiedInterfaceType - Return a
|
||||
/// ObjCQualifiedInterfaceType type for the given interface decl and
|
||||
|
|
|
@ -68,6 +68,11 @@ public:
|
|||
|
||||
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
|
||||
/// template specialization. This may be fewer than the number of
|
||||
/// template parameters, if some of the parameters have default
|
||||
|
@ -400,51 +405,72 @@ protected:
|
|||
/// specialization.
|
||||
class TemplateArgument {
|
||||
union {
|
||||
uintptr_t TypeOrDeclaration;
|
||||
uintptr_t TypeOrValue;
|
||||
char IntegralValue[sizeof(llvm::APInt)];
|
||||
};
|
||||
|
||||
/// \brief Location of the beginning of this template argument.
|
||||
SourceLocation StartLoc;
|
||||
|
||||
public:
|
||||
/// \brief The type of template argument we're storing.
|
||||
enum ArgKind {
|
||||
/// The template argument is a type. It's value is stored in the
|
||||
/// TypeOrDeclaration field.
|
||||
/// TypeOrValue field.
|
||||
Type = 0,
|
||||
/// The template argument is a declaration
|
||||
Declaration = 1,
|
||||
/// 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;
|
||||
|
||||
/// \brief Construct an empty, invalid template argument.
|
||||
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
|
||||
|
||||
/// \brief Construct a template type argument.
|
||||
TemplateArgument(QualType T) : Kind(Type) {
|
||||
assert(T->isCanonical() &&
|
||||
"Template arguments always use the canonical type");
|
||||
TypeOrDeclaration = reinterpret_cast<uintptr_t>(T.getAsOpaquePtr());
|
||||
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(Decl *D) : Kind(Declaration) {
|
||||
TemplateArgument(SourceLocation Loc, Decl *D) : Kind(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.
|
||||
TemplateArgument(const llvm::APInt &Value) : Kind(Integral) {
|
||||
TemplateArgument(SourceLocation Loc, const llvm::APInt &Value)
|
||||
: Kind(Integral) {
|
||||
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.
|
||||
TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) {
|
||||
if (Kind == Integral)
|
||||
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
||||
else
|
||||
TypeOrDeclaration = Other.TypeOrDeclaration;
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
StartLoc = Other.StartLoc;
|
||||
}
|
||||
|
||||
TemplateArgument& operator=(const TemplateArgument& Other) {
|
||||
// FIXME: Does not provide the strong guarantee for exception
|
||||
// safety.
|
||||
using llvm::APInt;
|
||||
|
||||
if (Kind == Other.Kind && Kind == Integral) {
|
||||
|
@ -460,8 +486,10 @@ public:
|
|||
if (Other.Kind == Integral)
|
||||
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
|
||||
else
|
||||
TypeOrDeclaration = Other.TypeOrDeclaration;
|
||||
TypeOrValue = Other.TypeOrValue;
|
||||
}
|
||||
StartLoc = Other.StartLoc;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -481,14 +509,14 @@ public:
|
|||
return QualType();
|
||||
|
||||
return QualType::getFromOpaquePtr(
|
||||
reinterpret_cast<void*>(TypeOrDeclaration));
|
||||
reinterpret_cast<void*>(TypeOrValue));
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as a declaration.
|
||||
Decl *getAsDecl() const {
|
||||
if (Kind != Declaration)
|
||||
return 0;
|
||||
return reinterpret_cast<Decl *>(TypeOrDeclaration);
|
||||
return reinterpret_cast<Decl *>(TypeOrValue);
|
||||
}
|
||||
|
||||
/// \brief Retrieve the template argument as an integral value.
|
||||
|
@ -502,6 +530,17 @@ public:
|
|||
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.
|
||||
void Profile(llvm::FoldingSetNodeID &ID) const {
|
||||
ID.AddInteger(Kind);
|
||||
|
@ -517,6 +556,11 @@ public:
|
|||
case Integral:
|
||||
getAsIntegral()->Profile(ID);
|
||||
break;
|
||||
|
||||
case Expression:
|
||||
// FIXME: We need a canonical representation of expressions.
|
||||
ID.AddPointer(getAsExpr());
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -46,6 +46,7 @@ namespace clang {
|
|||
class Stmt;
|
||||
class SourceLocation;
|
||||
class StmtIteratorBase;
|
||||
class TemplateArgument;
|
||||
|
||||
// Provide forward declarations for all of the *Type classes
|
||||
#define TYPE(Class, Base) class Class##Type;
|
||||
|
@ -1430,100 +1431,52 @@ class ClassTemplateSpecializationType
|
|||
// possibly with template-names preceded by a nested-name-specifier.
|
||||
TemplateDecl *Template;
|
||||
|
||||
/// \brief - The number of template arguments named in this class
|
||||
/// template specialization.
|
||||
unsigned NumArgs;
|
||||
|
||||
ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
|
||||
uintptr_t *Args, bool *ArgIsType,
|
||||
QualType Canon);
|
||||
ClassTemplateSpecializationType(TemplateDecl *T,
|
||||
const TemplateArgument *Args,
|
||||
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);
|
||||
|
||||
friend class ASTContext; // ASTContext creates these
|
||||
|
||||
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.
|
||||
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; }
|
||||
|
||||
/// \brief Retrieve a specific template argument as a type.
|
||||
/// \precondition @c isArgType(Arg)
|
||||
QualType getArgAsType(unsigned Arg) 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;
|
||||
const TemplateArgument &getArg(unsigned Idx) const;
|
||||
|
||||
virtual void getAsStringInternal(std::string &InnerString) const;
|
||||
|
||||
void Profile(llvm::FoldingSetNodeID &ID) {
|
||||
// Add the template
|
||||
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));
|
||||
Profile(ID, Template, getArgs(), NumArgs);
|
||||
}
|
||||
|
||||
static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T,
|
||||
unsigned NumArgs, uintptr_t *Args, bool *ArgIsType) {
|
||||
// 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]);
|
||||
}
|
||||
const TemplateArgument *Args, unsigned NumArgs);
|
||||
|
||||
static bool classof(const Type *T) {
|
||||
return T->getTypeClass() == ClassTemplateSpecialization;
|
||||
|
|
|
@ -1309,14 +1309,15 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index,
|
|||
|
||||
QualType
|
||||
ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
|
||||
const TemplateArgument *Args,
|
||||
unsigned NumArgs,
|
||||
uintptr_t *Args, bool *ArgIsType,
|
||||
QualType Canon) {
|
||||
Canon = getCanonicalType(Canon);
|
||||
if (!Canon.isNull())
|
||||
Canon = getCanonicalType(Canon);
|
||||
|
||||
llvm::FoldingSetNodeID ID;
|
||||
ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args,
|
||||
ArgIsType);
|
||||
ClassTemplateSpecializationType::Profile(ID, Template, Args, NumArgs);
|
||||
|
||||
void *InsertPos = 0;
|
||||
ClassTemplateSpecializationType *Spec
|
||||
= ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
|
||||
|
@ -1324,13 +1325,11 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
|
|||
if (Spec)
|
||||
return QualType(Spec, 0);
|
||||
|
||||
void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) +
|
||||
(sizeof(uintptr_t) *
|
||||
(ClassTemplateSpecializationType::
|
||||
getNumPackedWords(NumArgs) +
|
||||
NumArgs)), 8);
|
||||
Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args,
|
||||
ArgIsType, Canon);
|
||||
void *Mem = Allocate((sizeof(ClassTemplateSpecializationType) +
|
||||
sizeof(TemplateArgument) * NumArgs),
|
||||
8);
|
||||
Spec = new (Mem) ClassTemplateSpecializationType(Template, Args, NumArgs,
|
||||
Canon);
|
||||
Types.push_back(Spec);
|
||||
ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
|
||||
|
||||
|
|
|
@ -144,6 +144,15 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
|
|||
: SourceLocation();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TemplateArgument Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
|
||||
TypeOrValue = reinterpret_cast<uintptr_t>(E);
|
||||
StartLoc = E->getSourceRange().getBegin();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ClassTemplateSpecializationDecl Implementation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -921,59 +921,77 @@ bool EnumType::classof(const TagType *TT) {
|
|||
return isa<EnumDecl>(TT->getDecl());
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
ClassTemplateSpecializationType::
|
||||
packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
|
||||
const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
|
||||
anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) {
|
||||
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;
|
||||
PW != NumPackedWords; ++PW) {
|
||||
uintptr_t Word = 0;
|
||||
for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) {
|
||||
Word <<= 1;
|
||||
Word |= Values[Arg];
|
||||
case TemplateArgument::Expression:
|
||||
if (Args[Idx].getAsExpr()->isTypeDependent() ||
|
||||
Args[Idx].getAsExpr()->isValueDependent())
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
Words[PW] = Word;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
ClassTemplateSpecializationType::
|
||||
ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
|
||||
uintptr_t *Args, bool *ArgIsType,
|
||||
QualType Canon)
|
||||
: Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false),
|
||||
Template(T), NumArgs(NumArgs)
|
||||
ClassTemplateSpecializationType(TemplateDecl *T, const TemplateArgument *Args,
|
||||
unsigned NumArgs, QualType Canon)
|
||||
: Type(ClassTemplateSpecialization,
|
||||
Canon.isNull()? QualType(this, 0) : Canon,
|
||||
/*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
|
||||
// class template specialization type.
|
||||
packBooleanValues(NumArgs, ArgIsType, Data);
|
||||
|
||||
// Copy the template arguments after the packed words.
|
||||
Data += getNumPackedWords(NumArgs);
|
||||
TemplateArgument *TemplateArgs
|
||||
= reinterpret_cast<TemplateArgument *>(this + 1);
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
||||
Data[Arg] = Args[Arg];
|
||||
new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]);
|
||||
}
|
||||
|
||||
void ClassTemplateSpecializationType::Destroy(ASTContext& C) {
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
|
||||
if (!isArgType(Arg))
|
||||
getArgAsExpr(Arg)->Destroy(C);
|
||||
if (Expr *E = getArg(Arg).getAsExpr())
|
||||
E->Destroy(C);
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
|
||||
const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
|
||||
Data += getNumPackedWords(NumArgs);
|
||||
return Data[Arg];
|
||||
ClassTemplateSpecializationType::iterator
|
||||
ClassTemplateSpecializationType::end() const {
|
||||
return begin() + getNumArgs();
|
||||
}
|
||||
|
||||
bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
|
||||
const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
|
||||
const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
|
||||
Data += Arg / BitsPerWord;
|
||||
return (*Data >> ((NumArgs - Arg) % BitsPerWord - 1)) & 0x01;
|
||||
const TemplateArgument &
|
||||
ClassTemplateSpecializationType::getArg(unsigned Idx) const {
|
||||
assert(Idx < getNumArgs() && "Template argument out of range");
|
||||
return getArgs()[Idx];
|
||||
}
|
||||
|
||||
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.
|
||||
std::string ArgString;
|
||||
if (isArgType(Arg))
|
||||
getArgAsType(Arg).getAsStringInternal(ArgString);
|
||||
else {
|
||||
switch (getArg(Arg).getKind()) {
|
||||
case TemplateArgument::Type:
|
||||
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);
|
||||
getArgAsExpr(Arg)->printPretty(s);
|
||||
getArg(Arg).getAsExpr()->printPretty(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is the first argument and its string representation
|
||||
|
|
|
@ -390,13 +390,7 @@ void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const {
|
|||
S.Emit(getCanonicalTypeInternal());
|
||||
S.EmitPtr(Template);
|
||||
S.EmitInt(NumArgs);
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
|
||||
S.EmitBool(isArgType(Arg));
|
||||
if (isArgType(Arg))
|
||||
S.Emit(getArgAsType(Arg));
|
||||
else
|
||||
S.EmitOwnedPtr(getArgAsExpr(Arg));
|
||||
}
|
||||
// FIXME: Serialize class template specialization types
|
||||
}
|
||||
|
||||
Type*
|
||||
|
@ -409,19 +403,10 @@ CreateImpl(ASTContext& Context, Deserializer& D) {
|
|||
TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
|
||||
unsigned NumArgs = D.ReadInt();
|
||||
|
||||
for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
|
||||
bool IsType = D.ReadBool();
|
||||
ArgIsType.push_back(IsType);
|
||||
if (IsType)
|
||||
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();
|
||||
// FIXME: De-serialize class template specialization types
|
||||
(void)Template;
|
||||
(void)NumArgs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1601,6 +1601,13 @@ public:
|
|||
AttributeList *Attr,
|
||||
MultiTemplateParamsArg TemplateParameterLists);
|
||||
|
||||
QualType CheckClassTemplateId(ClassTemplateDecl *ClassTemplate,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc);
|
||||
|
||||
virtual TypeResult
|
||||
ActOnClassTemplateId(DeclTy *Template, SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
|
@ -1630,8 +1637,8 @@ public:
|
|||
bool CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr& TemplateArgs,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
llvm::SmallVectorImpl<TemplateArgument> &Converted);
|
||||
|
||||
|
|
|
@ -383,7 +383,8 @@ Sema::BaseResult
|
|||
Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange,
|
||||
bool Virtual, AccessSpecifier Access,
|
||||
TypeTy *basetype, SourceLocation BaseLoc) {
|
||||
CXXRecordDecl *Class = (CXXRecordDecl*)classdecl;
|
||||
AdjustDeclIfTemplate(classdecl);
|
||||
CXXRecordDecl *Class = cast<CXXRecordDecl>((Decl*)classdecl);
|
||||
QualType BaseType = QualType::getFromOpaquePtr(basetype);
|
||||
if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange,
|
||||
Virtual, Access,
|
||||
|
|
|
@ -658,61 +658,115 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams,
|
|||
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
|
||||
Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
ASTTemplateArgsPtr TemplateArgsIn,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc,
|
||||
const CXXScopeSpec *SS) {
|
||||
TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
|
||||
ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
|
||||
|
||||
// Check that the template argument list is well-formed for this
|
||||
// template.
|
||||
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
||||
if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc,
|
||||
TemplateArgs, TemplateArgLocs, RAngleLoc,
|
||||
ConvertedTemplateArgs))
|
||||
return true;
|
||||
// Translate the parser's template argument list in our AST format.
|
||||
llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
|
||||
translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
|
||||
|
||||
assert((ConvertedTemplateArgs.size() ==
|
||||
Template->getTemplateParameters()->size()) &&
|
||||
"Converted template argument list is too short!");
|
||||
QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc,
|
||||
LAngleLoc,
|
||||
&TemplateArgs[0],
|
||||
TemplateArgs.size(),
|
||||
RAngleLoc);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// 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();
|
||||
TemplateArgsIn.release();
|
||||
return Result.getAsOpaquePtr();
|
||||
}
|
||||
|
||||
|
@ -721,13 +775,13 @@ Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
|
|||
bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
||||
SourceLocation TemplateLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr& Args,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
const TemplateArgument *TemplateArgs,
|
||||
unsigned NumTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
|
||||
TemplateParameterList *Params = Template->getTemplateParameters();
|
||||
unsigned NumParams = Params->size();
|
||||
unsigned NumArgs = Args.size();
|
||||
unsigned NumArgs = NumTemplateArgs;
|
||||
bool Invalid = false;
|
||||
|
||||
if (NumArgs > NumParams ||
|
||||
|
@ -737,7 +791,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
// arguments.
|
||||
SourceRange Range;
|
||||
if (NumArgs > NumParams)
|
||||
Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc);
|
||||
Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc);
|
||||
Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
|
||||
<< (NumArgs > NumParams)
|
||||
<< (isa<ClassTemplateDecl>(Template)? 0 :
|
||||
|
@ -759,9 +813,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
ParamEnd = Params->end();
|
||||
Param != ParamEnd; ++Param, ++ArgIdx) {
|
||||
// Decode the template argument
|
||||
QualType ArgType;
|
||||
Expr *ArgExpr = 0;
|
||||
SourceLocation ArgLoc;
|
||||
TemplateArgument Arg;
|
||||
if (ArgIdx >= NumArgs) {
|
||||
// Retrieve the default template argument from the template
|
||||
// parameter.
|
||||
|
@ -769,7 +821,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
if (!TTP->hasDefaultArgument())
|
||||
break;
|
||||
|
||||
ArgType = TTP->getDefaultArgument();
|
||||
QualType ArgType = TTP->getDefaultArgument();
|
||||
|
||||
// If the argument type is dependent, instantiate it now based
|
||||
// on the previously-computed template arguments.
|
||||
|
@ -781,15 +833,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
if (ArgType.isNull())
|
||||
return true;
|
||||
|
||||
ArgLoc = TTP->getDefaultArgumentLoc();
|
||||
Arg = TemplateArgument(TTP->getLocation(), ArgType);
|
||||
} else if (NonTypeTemplateParmDecl *NTTP
|
||||
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
|
||||
if (!NTTP->hasDefaultArgument())
|
||||
break;
|
||||
|
||||
// FIXME: Instantiate default argument
|
||||
ArgExpr = NTTP->getDefaultArgument();
|
||||
ArgLoc = NTTP->getDefaultArgumentLoc();
|
||||
Arg = TemplateArgument(NTTP->getDefaultArgument());
|
||||
} else {
|
||||
TemplateTemplateParmDecl *TempParm
|
||||
= cast<TemplateTemplateParmDecl>(*Param);
|
||||
|
@ -798,29 +849,24 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
break;
|
||||
|
||||
// FIXME: Instantiate default argument
|
||||
ArgExpr = TempParm->getDefaultArgument();
|
||||
ArgLoc = TempParm->getDefaultArgumentLoc();
|
||||
Arg = TemplateArgument(TempParm->getDefaultArgument());
|
||||
}
|
||||
} else {
|
||||
// Retrieve the template argument produced by the user.
|
||||
ArgLoc = TemplateArgLocs[ArgIdx];
|
||||
|
||||
if (Args.getArgIsType()[ArgIdx])
|
||||
ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]);
|
||||
else
|
||||
ArgExpr = reinterpret_cast<Expr *>(Args.getArgs()[ArgIdx]);
|
||||
Arg = TemplateArgs[ArgIdx];
|
||||
}
|
||||
|
||||
|
||||
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
|
||||
// Check template type parameters.
|
||||
if (!ArgType.isNull()) {
|
||||
if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
|
||||
if (Arg.getKind() == TemplateArgument::Type) {
|
||||
if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation()))
|
||||
Invalid = true;
|
||||
|
||||
// Add the converted template type argument.
|
||||
Converted.push_back(
|
||||
TemplateArgument(Context.getCanonicalType(ArgType)));
|
||||
TemplateArgument(Arg.getLocation(),
|
||||
Context.getCanonicalType(Arg.getAsType())));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -829,9 +875,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
// type shall be a type-id.
|
||||
|
||||
// We have a template type parameter but the template argument
|
||||
// is an expression.
|
||||
Diag(ArgExpr->getSourceRange().getBegin(),
|
||||
diag::err_template_arg_must_be_type);
|
||||
// is not a type.
|
||||
Diag(Arg.getLocation(), diag::err_template_arg_must_be_type);
|
||||
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
||||
Invalid = true;
|
||||
} else if (NonTypeTemplateParmDecl *NTTP
|
||||
|
@ -859,50 +904,81 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
|
|||
}
|
||||
}
|
||||
|
||||
if (ArgExpr) {
|
||||
if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted))
|
||||
switch (Arg.getKind()) {
|
||||
case TemplateArgument::Expression: {
|
||||
Expr *E = Arg.getAsExpr();
|
||||
if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
|
||||
Invalid = true;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
// We have a non-type template parameter but the template
|
||||
// argument is a type.
|
||||
case TemplateArgument::Declaration:
|
||||
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:
|
||||
// In a template-argument, an ambiguity between a type-id and
|
||||
// an expression is resolved to a type-id, regardless of the
|
||||
// form of the corresponding template-parameter.
|
||||
//
|
||||
// We warn specifically about this case, since it can be rather
|
||||
// confusing for users.
|
||||
if (ArgType->isFunctionType())
|
||||
Diag(ArgLoc, diag::err_template_arg_nontype_ambig)
|
||||
<< ArgType;
|
||||
else
|
||||
Diag(ArgLoc, diag::err_template_arg_must_be_expr);
|
||||
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
||||
Invalid = true;
|
||||
case TemplateArgument::Type:
|
||||
// We have a non-type template parameter but the template
|
||||
// argument is a type.
|
||||
|
||||
// C++ [temp.arg]p2:
|
||||
// In a template-argument, an ambiguity between a type-id and
|
||||
// an expression is resolved to a type-id, regardless of the
|
||||
// form of the corresponding template-parameter.
|
||||
//
|
||||
// We warn specifically about this case, since it can be rather
|
||||
// confusing for users.
|
||||
if (Arg.getAsType()->isFunctionType())
|
||||
Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig)
|
||||
<< Arg.getAsType();
|
||||
else
|
||||
Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr);
|
||||
Diag((*Param)->getLocation(), diag::note_template_param_here);
|
||||
Invalid = true;
|
||||
}
|
||||
} else {
|
||||
// Check template template parameters.
|
||||
TemplateTemplateParmDecl *TempParm
|
||||
= cast<TemplateTemplateParmDecl>(*Param);
|
||||
|
||||
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
|
||||
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
|
||||
if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
|
||||
Invalid = true;
|
||||
|
||||
// Add the converted template argument.
|
||||
// FIXME: Need the "canonical" template declaration!
|
||||
Converted.push_back(
|
||||
TemplateArgument(cast<DeclRefExpr>(ArgExpr)->getDecl()));
|
||||
continue;
|
||||
switch (Arg.getKind()) {
|
||||
case TemplateArgument::Expression: {
|
||||
Expr *ArgExpr = Arg.getAsExpr();
|
||||
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
|
||||
isa<TemplateDecl>(cast<DeclRefExpr>(ArgExpr)->getDecl())) {
|
||||
if (CheckTemplateArgument(TempParm, cast<DeclRefExpr>(ArgExpr)))
|
||||
Invalid = true;
|
||||
|
||||
// Add the converted template argument.
|
||||
// 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
|
||||
// argument does not refer to a template.
|
||||
Diag(ArgLoc, diag::err_template_arg_must_be_template);
|
||||
Invalid = true;
|
||||
case TemplateArgument::Declaration:
|
||||
// We've already checked this template argument, so just copy
|
||||
// it to the list of converted arguments.
|
||||
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,
|
||||
QualType InstantiatedParamType, Expr *&Arg,
|
||||
llvm::SmallVectorImpl<TemplateArgument> *Converted) {
|
||||
SourceLocation StartLoc = Arg->getSourceRange().getBegin();
|
||||
|
||||
// If either the parameter has a dependent type or the argument is
|
||||
// type-dependent, there's nothing we can check now.
|
||||
// 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;
|
||||
}
|
||||
|
||||
// C++ [temp.arg.nontype]p5:
|
||||
// The following conversions are performed on each expression used
|
||||
|
@ -1188,7 +1269,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
IntegerType->isSignedIntegerType());
|
||||
CanonicalArg = Value;
|
||||
|
||||
Converted->push_back(TemplateArgument(CanonicalArg));
|
||||
Converted->push_back(TemplateArgument(StartLoc, CanonicalArg));
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -1252,7 +1333,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
|
||||
if (Converted)
|
||||
Converted->push_back(TemplateArgument(Member));
|
||||
Converted->push_back(TemplateArgument(StartLoc, Member));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1262,7 +1343,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
|
||||
if (Converted)
|
||||
Converted->push_back(TemplateArgument(Entity));
|
||||
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1297,7 +1378,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
|
||||
if (Converted)
|
||||
Converted->push_back(TemplateArgument(Entity));
|
||||
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1339,7 +1420,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
|
||||
if (Converted)
|
||||
Converted->push_back(TemplateArgument(Entity));
|
||||
Converted->push_back(TemplateArgument(StartLoc, Entity));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1366,7 +1447,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
|
|||
return true;
|
||||
|
||||
if (Converted)
|
||||
Converted->push_back(TemplateArgument(Member));
|
||||
Converted->push_back(TemplateArgument(StartLoc, Member));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -1649,7 +1730,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
|||
DeclTy *TemplateD,
|
||||
SourceLocation TemplateNameLoc,
|
||||
SourceLocation LAngleLoc,
|
||||
ASTTemplateArgsPtr TemplateArgs,
|
||||
ASTTemplateArgsPtr TemplateArgsIn,
|
||||
SourceLocation *TemplateArgLocs,
|
||||
SourceLocation RAngleLoc,
|
||||
AttributeList *Attr,
|
||||
|
@ -1701,12 +1782,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
|||
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
|
||||
// template.
|
||||
llvm::SmallVector<TemplateArgument, 16> ConvertedTemplateArgs;
|
||||
if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc,
|
||||
TemplateArgs, TemplateArgLocs, RAngleLoc,
|
||||
ConvertedTemplateArgs))
|
||||
&TemplateArgs[0], TemplateArgs.size(),
|
||||
RAngleLoc, ConvertedTemplateArgs))
|
||||
return 0;
|
||||
|
||||
assert((ConvertedTemplateArgs.size() ==
|
||||
|
@ -1786,11 +1871,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK,
|
|||
// template arguments in the specialization.
|
||||
Specialization->setTypeAsWritten(
|
||||
Context.getClassTemplateSpecializationType(ClassTemplate,
|
||||
&TemplateArgs[0],
|
||||
TemplateArgs.size(),
|
||||
reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
|
||||
TemplateArgs.getArgIsType(),
|
||||
Context.getTypeDeclType(Specialization)));
|
||||
TemplateArgs.release();
|
||||
TemplateArgsIn.release();
|
||||
|
||||
// C++ [temp.expl.spec]p9:
|
||||
// A template explicit specialization is in the scope of the
|
||||
|
|
|
@ -302,9 +302,44 @@ TemplateTypeInstantiator::
|
|||
InstantiateClassTemplateSpecializationType(
|
||||
const ClassTemplateSpecializationType *T,
|
||||
unsigned Quals) const {
|
||||
// FIXME: Implement this
|
||||
assert(false && "Cannot instantiate ClassTemplateSpecializationType yet");
|
||||
return QualType();
|
||||
llvm::SmallVector<TemplateArgument, 16> InstantiatedTemplateArgs;
|
||||
InstantiatedTemplateArgs.reserve(T->getNumArgs());
|
||||
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
|
||||
|
|
|
@ -14,8 +14,7 @@ A<A<int> > *a6;
|
|||
// [temp.arg.type]p2
|
||||
void f() {
|
||||
class X { };
|
||||
A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}} \
|
||||
// FIXME: expected-error{{use of undeclared identifier 'a'}}
|
||||
A<X> * a = 0; // expected-error{{template argument uses local type 'class X'}}
|
||||
}
|
||||
|
||||
struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}}
|
||||
|
|
Loading…
Reference in New Issue