forked from OSchip/llvm-project
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:
parent
3c50922ea0
commit
264ec4f237
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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> *'}}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue