Added ClassTemplateSpecializationDecl, which is a subclass of

CXXRecordDecl that is used to represent class template
specializations. These are canonical declarations that can refer to
either an actual class template specialization in the code, e.g.,

  template<> class vector<bool> { };

or to a template instantiation. However, neither of these features is
actually implemented yet, so really we're just using (and uniqing) the
declarations to make sure that, e.g., A<int> is a different type from
A<float>. Note that we carefully distinguish between what the user
wrote in the source code (e.g., "A<FLOAT>") and the semantic entity it
represents (e.g., "A<float, int>"); the former is in the sugared Type,
the latter is an actual Decl.

llvm-svn: 64716
This commit is contained in:
Douglas Gregor 2009-02-17 01:05:43 +00:00
parent 3c50922ea0
commit 264ec4f237
9 changed files with 465 additions and 69 deletions

View File

@ -23,6 +23,7 @@ class CXXConstructorDecl;
class CXXDestructorDecl;
class CXXConversionDecl;
class CXXMethodDecl;
class ClassTemplateSpecializationDecl;
/// OverloadedFunctionDecl - An instance of this class represents a
/// set of overloaded functions. All of the functions have the same
@ -231,7 +232,8 @@ class CXXRecordDecl : public RecordDecl {
/// CXXConversionDecl.
OverloadedFunctionDecl Conversions;
CXXRecordDecl(TagKind TK, DeclContext *DC,
protected:
CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id);
~CXXRecordDecl();
@ -355,8 +357,14 @@ public:
/// GraphViz.
void viewInheritance(ASTContext& Context) const;
static bool classof(const Decl *D) { return D->getKind() == CXXRecord; }
static bool classof(const Decl *D) {
return D->getKind() == CXXRecord ||
D->getKind() == ClassTemplateSpecialization;
}
static bool classof(const CXXRecordDecl *D) { return true; }
static bool classof(const ClassTemplateSpecializationDecl *D) {
return true;
}
protected:
/// EmitImpl - Serialize this CXXRecordDecl. Called by Decl::Emit.

View File

@ -84,6 +84,7 @@ ABSTRACT_DECL(Named, Decl)
DECL(Enum, TagDecl)
DECL(Record, TagDecl)
DECL(CXXRecord, RecordDecl)
DECL(ClassTemplateSpecialization, CXXRecordDecl)
DECL(TemplateTypeParm, TypeDecl)
ABSTRACT_DECL(Value, NamedDecl)
DECL(EnumConstant, ValueDecl)
@ -139,7 +140,7 @@ DECL_RANGE(ObjCContainer, ObjCContainer, ObjCInterface)
DECL_RANGE(Field, Field, ObjCAtDefsField)
DECL_RANGE(Type, Typedef, TemplateTypeParm)
DECL_RANGE(Tag, Enum, CXXRecord)
DECL_RANGE(Record, Record, CXXRecord)
DECL_RANGE(Record, Record, ClassTemplateSpecialization)
DECL_RANGE(Value, EnumConstant, NonTypeTemplateParm)
DECL_RANGE(Function, Function, CXXConversion)
DECL_RANGE(Template, Template, TemplateTemplateParm)

View File

@ -15,6 +15,8 @@
#define LLVM_CLANG_AST_DECLTEMPLATE_H
#include "clang/AST/DeclCXX.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/FoldingSet.h"
namespace clang {
@ -161,37 +163,10 @@ public:
{ return true; }
};
/// Declaration of a template class.
class ClassTemplateDecl : public TemplateDecl {
protected:
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
public:
/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
return static_cast<CXXRecordDecl *>(TemplatedDecl);
}
/// Create a class teplate node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl);
// Implement isa/cast/dyncast support
static bool classof(const Decl *D)
{ return D->getKind() == ClassTemplate; }
static bool classof(const ClassTemplateDecl *D)
{ return true; }
};
//===----------------------------------------------------------------------===//
// Kinds of Template Parameters
//===----------------------------------------------------------------------===//
/// The TemplateParmPosition class defines the position of a template parameter
/// within a template parameter list. Because template parameter can be listed
/// sequentially for out-of-line template members, each template parameter is
@ -421,6 +396,236 @@ protected:
friend Decl* Decl::Create(llvm::Deserializer& D, ASTContext& C);
};
/// \brief Represents a template argument within a class template
/// specialization.
class TemplateArgument {
union {
uintptr_t TypeOrDeclaration;
char IntegralValue[sizeof(llvm::APInt)];
};
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.
Type = 0,
/// The template argument is a declaration
Declaration = 1,
/// The template argument is an integral value stored in an llvm::APInt.
Integral = 2
} Kind;
/// \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());
}
/// \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) {
// FIXME: Need to be sure we have the "canonical" declaration!
TypeOrDeclaration = reinterpret_cast<uintptr_t>(D);
}
/// \brief Construct an integral constant template argument.
TemplateArgument(const llvm::APInt &Value) : Kind(Integral) {
new (IntegralValue) llvm::APInt(Value);
}
/// \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;
}
TemplateArgument& operator=(const TemplateArgument& Other) {
using llvm::APInt;
if (Kind == Other.Kind && Kind == Integral) {
// Copy integral values.
*this->getAsIntegral() = *Other.getAsIntegral();
} else {
// Destroy the current integral value, if that's what we're holding.
if (Kind == Integral)
getAsIntegral()->~APInt();
Kind = Other.Kind;
if (Other.Kind == Integral)
new (IntegralValue) llvm::APInt(*Other.getAsIntegral());
else
TypeOrDeclaration = Other.TypeOrDeclaration;
}
return *this;
}
~TemplateArgument() {
using llvm::APInt;
if (Kind == Integral)
getAsIntegral()->~APInt();
}
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
return QualType();
return QualType::getFromOpaquePtr(
reinterpret_cast<void*>(TypeOrDeclaration));
}
/// \brief Retrieve the template argument as a declaration.
Decl *getAsDecl() const {
if (Kind != Declaration)
return 0;
return reinterpret_cast<Decl *>(TypeOrDeclaration);
}
/// \brief Retrieve the template argument as an integral value.
llvm::APInt *getAsIntegral() {
if (Kind != Integral)
return 0;
return reinterpret_cast<llvm::APInt*>(&IntegralValue[0]);
}
const llvm::APInt *getAsIntegral() const {
return const_cast<TemplateArgument*>(this)->getAsIntegral();
}
/// \brief Used to insert TemplateArguments into FoldingSets.
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
case Type:
getAsType().Profile(ID);
break;
case Declaration:
ID.AddPointer(getAsDecl()); // FIXME: Must be canonical!
break;
case Integral:
getAsIntegral()->Profile(ID);
break;
}
}
};
/// \brief Represents a class template specialization, which refers to
/// a class template with a given set of template arguments.
///
/// Class template specializations represent both explicit
/// specialization of class templates, as in the example below, and
/// implicit instantiations of class templates.
///
/// \code
/// template<typename T> class array;
///
/// template<>
/// class array<bool> { }; // class template specialization array<bool>
/// \endcode
class ClassTemplateSpecializationDecl
: public CXXRecordDecl, public llvm::FoldingSetNode {
/// \brief The template that this specialization specializes
ClassTemplateDecl *SpecializedTemplate;
/// \brief The number of template arguments. The actual arguments
/// are allocated after the ClassTemplateSpecializationDecl object.
unsigned NumTemplateArgs;
ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs);
public:
static ClassTemplateSpecializationDecl *
Create(ASTContext &Context, DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs, unsigned NumTemplateArgs);
/// \brief Retrieve the template that this specialization specializes.
ClassTemplateDecl *getSpecializedTemplate() const {
return SpecializedTemplate;
}
typedef const TemplateArgument * template_arg_iterator;
template_arg_iterator template_arg_begin() const {
return reinterpret_cast<template_arg_iterator>(this + 1);
}
template_arg_iterator template_arg_end() const {
return template_arg_begin() + NumTemplateArgs;
}
unsigned getNumTemplateArgs() const { return NumTemplateArgs; }
void Profile(llvm::FoldingSetNodeID &ID) const {
Profile(ID, template_arg_begin(), getNumTemplateArgs());
}
static void
Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
for (unsigned Arg = 0; Arg != NumTemplateArgs; ++Arg)
TemplateArgs[Arg].Profile(ID);
}
static bool classof(const Decl *D) {
return D->getKind() == ClassTemplateSpecialization;
}
static bool classof(const ClassTemplateSpecializationDecl *) {
return true;
}
};
/// Declaration of a class template.
class ClassTemplateDecl : public TemplateDecl {
protected:
ClassTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name,
TemplateParameterList *Params, NamedDecl *Decl)
: TemplateDecl(ClassTemplate, DC, L, Name, Params, Decl) { }
/// \brief The class template specializations for this class
/// template, including explicit specializations and instantiations.
llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations;
public:
/// Get the underlying class declarations of the template.
CXXRecordDecl *getTemplatedDecl() const {
return static_cast<CXXRecordDecl *>(TemplatedDecl);
}
/// Create a class teplate node.
static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC,
SourceLocation L,
DeclarationName Name,
TemplateParameterList *Params,
NamedDecl *Decl);
/// \brief Retrieve the set of specializations of this class template.
llvm::FoldingSet<ClassTemplateSpecializationDecl> &getSpecializations() {
return Specializations;
}
// Implement isa/cast/dyncast support
static bool classof(const Decl *D)
{ return D->getKind() == ClassTemplate; }
static bool classof(const ClassTemplateDecl *D)
{ return true; }
};
} /* end of namespace clang */
#endif

View File

@ -1502,6 +1502,8 @@ public:
// 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)

View File

@ -21,9 +21,9 @@ using namespace clang;
// Decl Allocation/Deallocation Method Implementations
//===----------------------------------------------------------------------===//
CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC,
CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id)
: RecordDecl(CXXRecord, TK, DC, L, Id),
: RecordDecl(K, TK, DC, L, Id),
UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false),
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
Aggregate(true), PlainOldData(true), Polymorphic(false), Bases(0),
@ -32,7 +32,7 @@ CXXRecordDecl::CXXRecordDecl(TagKind TK, DeclContext *DC,
CXXRecordDecl *CXXRecordDecl::Create(ASTContext &C, TagKind TK, DeclContext *DC,
SourceLocation L, IdentifierInfo *Id,
CXXRecordDecl* PrevDecl) {
CXXRecordDecl* R = new (C) CXXRecordDecl(TK, DC, L, Id);
CXXRecordDecl* R = new (C) CXXRecordDecl(CXXRecord, TK, DC, L, Id);
C.getTypeDeclType(R, PrevDecl);
return R;
}

View File

@ -143,3 +143,39 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const {
return DefaultArgument? DefaultArgument->getSourceRange().getBegin()
: SourceLocation();
}
//===----------------------------------------------------------------------===//
// ClassTemplateSpecializationDecl Implementation
//===----------------------------------------------------------------------===//
ClassTemplateSpecializationDecl::
ClassTemplateSpecializationDecl(DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs)
: CXXRecordDecl(ClassTemplateSpecialization,
SpecializedTemplate->getTemplatedDecl()->getTagKind(),
DC, L,
// FIXME: Should we use DeclarationName for the name of
// class template specializations?
SpecializedTemplate->getIdentifier()),
SpecializedTemplate(SpecializedTemplate),
NumTemplateArgs(NumTemplateArgs) {
TemplateArgument *Arg = reinterpret_cast<TemplateArgument *>(this + 1);
for (unsigned ArgIdx = 0; ArgIdx < NumTemplateArgs; ++ArgIdx, ++Arg)
*Arg = TemplateArgs[ArgIdx];
}
ClassTemplateSpecializationDecl *
ClassTemplateSpecializationDecl::Create(ASTContext &Context,
DeclContext *DC, SourceLocation L,
ClassTemplateDecl *SpecializedTemplate,
TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs) {
unsigned Size = sizeof(ClassTemplateSpecializationDecl) +
sizeof(TemplateArgument) * NumTemplateArgs;
unsigned Align = llvm::AlignOf<ClassTemplateSpecializationDecl>::Alignment;
void *Mem = Context.Allocate(Size, Align);
return new (Mem) ClassTemplateSpecializationDecl(DC, L, SpecializedTemplate,
TemplateArgs,
NumTemplateArgs);
}

View File

@ -61,6 +61,7 @@ namespace clang {
class ExtVectorType;
class TypedefDecl;
class TemplateDecl;
class TemplateArgument;
class TemplateParameterList;
class TemplateTemplateParmDecl;
class ObjCInterfaceDecl;
@ -1554,13 +1555,16 @@ public:
SourceLocation LAngleLoc,
ASTTemplateArgsPtr& TemplateArgs,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc);
SourceLocation RAngleLoc,
llvm::SmallVectorImpl<TemplateArgument> &Converted);
bool CheckTemplateArgument(TemplateTypeParmDecl *Param, QualType Arg,
SourceLocation ArgLoc);
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg);
bool CheckTemplateArgumentPointerToMember(Expr *Arg);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg);
bool CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity);
bool CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member);
bool CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Expr *&Arg,
llvm::SmallVectorImpl<TemplateArgument> *Converted = 0);
bool CheckTemplateArgument(TemplateTemplateParmDecl *Param, DeclRefExpr *Arg);
bool TemplateParameterListsAreEqual(TemplateParameterList *New,
TemplateParameterList *Old,

View File

@ -654,21 +654,51 @@ Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD,
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))
TemplateArgs, TemplateArgLocs, RAngleLoc,
ConvertedTemplateArgs))
return 0;
// Yes, all class template specializations are just silly sugar for
// 'int'. Gotta problem wit dat?
assert((ConvertedTemplateArgs.size() ==
Template->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 an appropriate declaration node and add
// it to the list of specializations. This is the canonical
// declaration of the class template.
Decl = ClassTemplateSpecializationDecl::Create(Context,
ClassTemplate->getDeclContext(),
TemplateLoc,
ClassTemplate,
&ConvertedTemplateArgs[0],
ConvertedTemplateArgs.size());
ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos);
}
// 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.IntTy);
Context.getTypeDeclType(Decl));
TemplateArgs.release();
return Result.getAsOpaquePtr();
}
@ -680,7 +710,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation LAngleLoc,
ASTTemplateArgsPtr& Args,
SourceLocation *TemplateArgLocs,
SourceLocation RAngleLoc) {
SourceLocation RAngleLoc,
llvm::SmallVectorImpl<TemplateArgument> &Converted) {
TemplateParameterList *Params = Template->getTemplateParameters();
unsigned NumParams = Params->size();
unsigned NumArgs = Args.size();
@ -719,22 +750,51 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
Expr *ArgExpr = 0;
SourceLocation ArgLoc;
if (ArgIdx >= NumArgs) {
// FIXME: Get the default argument here, which might
// (eventually) require instantiation.
break;
} else
// Retrieve the default template argument from the template
// parameter.
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(*Param)) {
if (!TTP->hasDefaultArgument())
break;
ArgType = TTP->getDefaultArgument();
ArgLoc = TTP->getDefaultArgumentLoc();
} else if (NonTypeTemplateParmDecl *NTTP
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
if (!NTTP->hasDefaultArgument())
break;
ArgExpr = NTTP->getDefaultArgument();
ArgLoc = NTTP->getDefaultArgumentLoc();
} else {
TemplateTemplateParmDecl *TempParm
= cast<TemplateTemplateParmDecl>(*Param);
if (!TempParm->hasDefaultArgument())
break;
ArgExpr = TempParm->getDefaultArgument();
ArgLoc = TempParm->getDefaultArgumentLoc();
}
} 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]);
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)) {
// Check template type parameters.
if (!ArgType.isNull()) {
if (CheckTemplateArgument(TTP, ArgType, ArgLoc))
Invalid = true;
// Add the converted template type argument.
Converted.push_back(
TemplateArgument(Context.getCanonicalType(ArgType)));
continue;
}
@ -752,7 +812,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
= dyn_cast<NonTypeTemplateParmDecl>(*Param)) {
// Check non-type template parameters.
if (ArgExpr) {
if (CheckTemplateArgument(NTTP, ArgExpr))
if (CheckTemplateArgument(NTTP, ArgExpr, &Converted))
Invalid = true;
continue;
}
@ -783,6 +843,11 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
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;
}
@ -828,7 +893,8 @@ bool Sema::CheckTemplateArgument(TemplateTypeParmDecl *Param,
/// \brief Checks whether the given template argument is the address
/// of an object or function according to C++ [temp.arg.nontype]p1.
bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg,
NamedDecl *&Entity) {
bool Invalid = false;
// See through any implicit casts we added to fix the type.
@ -895,6 +961,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
}
// Okay: we've named a function with external linkage.
Entity = Func;
return Invalid;
}
@ -909,6 +976,7 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
}
// Okay: we've named an object with external linkage
Entity = Var;
return Invalid;
}
@ -923,7 +991,8 @@ bool Sema::CheckTemplateArgumentAddressOfObjectOrFunction(Expr *Arg) {
/// \brief Checks whether the given template argument is a pointer to
/// member constant according to C++ [temp.arg.nontype]p1.
bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
bool
Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) {
bool Invalid = false;
// See through any implicit casts we added to fix the type.
@ -966,6 +1035,7 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
// Okay: this is the address of a non-static member, and therefore
// a member pointer constant.
Member = DRE->getDecl();
return Invalid;
}
@ -983,10 +1053,15 @@ bool Sema::CheckTemplateArgumentPointerToMember(Expr *Arg) {
///
/// This routine implements the semantics of C++ [temp.arg.nontype].
/// It returns true if an error occurred, and false otherwise.
///
/// If Converted is non-NULL and no errors occur, the value
/// of this argument will be added to the end of the Converted vector.
bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Expr *&Arg) {
Expr *&Arg,
llvm::SmallVectorImpl<TemplateArgument> *Converted) {
// 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 (Param->getType()->isDependentType() || Arg->isTypeDependent())
return false;
@ -1011,6 +1086,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
// type; or
// -- the name of a non-type template-parameter; or
SourceLocation NonConstantLoc;
llvm::APSInt Value;
if (!ArgType->isIntegralType() && !ArgType->isEnumeralType()) {
Diag(Arg->getSourceRange().getBegin(),
diag::err_template_arg_not_integral_or_enumeral)
@ -1018,7 +1094,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
Diag(Param->getLocation(), diag::note_template_param_here);
return true;
} else if (!Arg->isValueDependent() &&
!Arg->isIntegerConstantExpr(Context, &NonConstantLoc)) {
!Arg->isIntegerConstantExpr(Value, Context, &NonConstantLoc)) {
Diag(NonConstantLoc, diag::err_template_arg_not_ice)
<< ArgType << Arg->getSourceRange();
return true;
@ -1048,6 +1124,23 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
// FIXME: Check overflow of template arguments?
if (Converted) {
// Add the value of this argument to the list of converted
// arguments. We use the bitwidth and signedness of the template
// parameter.
QualType IntegerType = Context.getCanonicalType(ParamType);
if (const EnumType *Enum = IntegerType->getAsEnumType())
IntegerType = Enum->getDecl()->getIntegerType();
llvm::APInt CanonicalArg(Context.getTypeSize(IntegerType), 0,
IntegerType->isSignedIntegerType());
CanonicalArg = Value;
Converted->push_back(TemplateArgument(CanonicalArg));
}
return false;
}
@ -1100,10 +1193,24 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
if (ParamType->isMemberPointerType())
return CheckTemplateArgumentPointerToMember(Arg);
if (ParamType->isMemberPointerType()) {
NamedDecl *Member = 0;
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
if (Converted)
Converted->push_back(TemplateArgument(Member));
return false;
}
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
if (Converted)
Converted->push_back(TemplateArgument(Entity));
return false;
}
if (const PointerType *ParamPtrType = ParamType->getAsPointerType()) {
@ -1132,7 +1239,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
if (Converted)
Converted->push_back(TemplateArgument(Entity));
return false;
}
if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
@ -1167,7 +1281,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
return CheckTemplateArgumentAddressOfObjectOrFunction(Arg);
NamedDecl *Entity = 0;
if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity))
return true;
if (Converted)
Converted->push_back(TemplateArgument(Entity));
return false;
}
// -- For a non-type template-parameter of type pointer to data
@ -1187,7 +1308,14 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param,
return true;
}
return CheckTemplateArgumentPointerToMember(Arg);
NamedDecl *Member = 0;
if (CheckTemplateArgumentPointerToMember(Arg, Member))
return true;
if (Converted)
Converted->push_back(TemplateArgument(Member));
return false;
}
/// \brief Check a template argument against its corresponding

View File

@ -1,17 +1,29 @@
// RUN: clang -fsyntax-only -verify %s
template<typename T> struct A { };
template<typename T, typename U = float> struct A { };
typedef A<int> A_int;
float *foo(A<int> *ptr, A<int> const *ptr2) {
typedef float FLOAT;
A<int, FLOAT> *foo(A<int> *ptr, A<int> const *ptr2, A<int, double> *ptr3) {
if (ptr)
return ptr; // expected-error{{incompatible type returning 'A<int> *', expected 'float *'}}
return ptr; // okay
else if (ptr2)
return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'float *'}}
return ptr2; // expected-error{{incompatible type returning 'A<int> const *', expected 'A<int, FLOAT> *'}}
else {
// FIXME: This is completely bogus, but we're using it temporarily
// to test the syntactic sugar for class template specializations.
int *ip = ptr;
return 0;
return ptr3; // expected-error{{incompatible type returning 'A<int, double> *', expected 'A<int, FLOAT> *'}}
}
}
template<int I> struct B;
const int value = 12;
B<17 + 2> *bar(B<(19)> *ptr1, B< (::value + 7) > *ptr2, B<19 - 3> *ptr3) {
if (ptr1)
return ptr1;
else if (ptr2)
return ptr2;
else
return ptr3; // expected-error{{incompatible type returning 'B<19 - 3> *', expected 'B<17 + 2> *'}}
}