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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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