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
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
/// 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) {
if (Other.Kind == Integral)
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
else
- TypeOrDeclaration = Other.TypeOrDeclaration;
+ TypeOrValue = Other.TypeOrValue;
}
+ StartLoc = Other.StartLoc;
+
return *this;
}
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.
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);
case Integral:
getAsIntegral()->Profile(ID);
break;
+
+ case Expression:
+ // FIXME: We need a canonical representation of expressions.
+ ID.AddPointer(getAsExpr());
+ break;
}
}
};
class Stmt;
class SourceLocation;
class StmtIteratorBase;
+ class TemplateArgument;
// Provide forward declarations for all of the *Type classes
#define TYPE(Class, Base) class Class##Type;
// 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;
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);
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);
: SourceLocation();
}
+//===----------------------------------------------------------------------===//
+// TemplateArgument Implementation
+//===----------------------------------------------------------------------===//
+
+TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) {
+ TypeOrValue = reinterpret_cast<uintptr_t>(E);
+ StartLoc = E->getSourceRange().getBegin();
+}
+
//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
return isa<EnumDecl>(TT->getDecl());
}
-void
+bool
ClassTemplateSpecializationType::
-packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
- const unsigned BitsPerWord = sizeof(uintptr_t) * 8;
-
- 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];
+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;
+
+ 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);
+}
+
+ClassTemplateSpecializationType::iterator
+ClassTemplateSpecializationType::end() const {
+ return begin() + getNumArgs();
}
-uintptr_t
-ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
- const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
- Data += getNumPackedWords(NumArgs);
- return Data[Arg];
+const TemplateArgument &
+ClassTemplateSpecializationType::getArg(unsigned Idx) const {
+ assert(Idx < getNumArgs() && "Template argument out of range");
+ return getArgs()[Idx];
}
-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;
+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);
}
//===----------------------------------------------------------------------===//
// 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
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*
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;
}
//===----------------------------------------------------------------------===//
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,
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr& TemplateArgs,
- SourceLocation *TemplateArgLocs,
+ const TemplateArgument *TemplateArgs,
+ unsigned NumTemplateArgs,
SourceLocation RAngleLoc,
llvm::SmallVectorImpl<TemplateArgument> &Converted);
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,
return Invalid;
}
-Action::TypeResult
-Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
+/// \brief Translates template arguments as provided by the parser
+/// into template arguments used by semantic analysis.
+static void
+translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn,
SourceLocation *TemplateArgLocs,
- SourceLocation RAngleLoc,
- const CXXScopeSpec *SS) {
- TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
- ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
+ 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(Template, TemplateLoc, LAngleLoc,
- TemplateArgs, TemplateArgLocs, RAngleLoc,
+ if (CheckTemplateArgumentList(ClassTemplate, TemplateLoc, LAngleLoc,
+ TemplateArgs, NumTemplateArgs, RAngleLoc,
ConvertedTemplateArgs))
- return true;
+ return QualType();
assert((ConvertedTemplateArgs.size() ==
- Template->getTemplateParameters()->size()) &&
+ ClassTemplate->getTemplateParameters()->size()) &&
"Converted template argument list is too short!");
- // 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,
+ 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);
+ 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.
- QualType Result
- = Context.getClassTemplateSpecializationType(Template,
- TemplateArgs.size(),
- reinterpret_cast<uintptr_t *>(TemplateArgs.getArgs()),
- TemplateArgs.getArgIsType(),
- Context.getTypeDeclType(Decl));
- TemplateArgs.release();
+ return Context.getClassTemplateSpecializationType(ClassTemplate,
+ TemplateArgs,
+ NumTemplateArgs,
+ CanonType);
+}
+
+Action::TypeResult
+Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc,
+ SourceLocation LAngleLoc,
+ ASTTemplateArgsPtr TemplateArgsIn,
+ SourceLocation *TemplateArgLocs,
+ SourceLocation RAngleLoc,
+ const CXXScopeSpec *SS) {
+ TemplateDecl *Template = cast<TemplateDecl>(static_cast<Decl *>(TemplateD));
+ ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(Template);
+
+ // Translate the parser's template argument list in our AST format.
+ llvm::SmallVector<TemplateArgument, 16> TemplateArgs;
+ translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs);
+
+ QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc,
+ LAngleLoc,
+ &TemplateArgs[0],
+ TemplateArgs.size(),
+ RAngleLoc);
+
+ TemplateArgsIn.release();
return Result.getAsOpaquePtr();
}
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 ||
// 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 :
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.
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.
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);
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;
}
// 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
}
}
- 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.
-
- // 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::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;
+
+ 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;
+ }
}
}
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
IntegerType->isSignedIntegerType());
CanonicalArg = Value;
- Converted->push_back(TemplateArgument(CanonicalArg));
+ Converted->push_back(TemplateArgument(StartLoc, CanonicalArg));
}
return false;
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
return false;
}
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Entity));
+ Converted->push_back(TemplateArgument(StartLoc, Entity));
return false;
}
return true;
if (Converted)
- Converted->push_back(TemplateArgument(Member));
+ Converted->push_back(TemplateArgument(StartLoc, Member));
return false;
}
DeclTy *TemplateD,
SourceLocation TemplateNameLoc,
SourceLocation LAngleLoc,
- ASTTemplateArgsPtr TemplateArgs,
+ ASTTemplateArgsPtr TemplateArgsIn,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc,
AttributeList *Attr,
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() ==
// 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
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
// [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}}