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:
Douglas Gregor 2009-03-09 23:48:35 +00:00
parent d5b35ee215
commit c40290e452
12 changed files with 428 additions and 281 deletions

View File

@ -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

View File

@ -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;
}
}
};

View File

@ -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;

View File

@ -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);

View File

@ -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
//===----------------------------------------------------------------------===//

View File

@ -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

View File

@ -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;
}
//===----------------------------------------------------------------------===//

View File

@ -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);

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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}}