[cfe-commits] r64716 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/AST/DeclNodes.def include/clang/AST/DeclTemplate.h include/clang/AST/Type.h lib/AST/DeclCXX.cpp lib/AST/DeclTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp test/SemaTemplate/class-template-id.cpp
Douglas Gregor
dgregor at apple.com
Mon Feb 16 17:05:44 PST 2009
Author: dgregor
Date: Mon Feb 16 19:05:43 2009
New Revision: 64716
URL: http://llvm.org/viewvc/llvm-project?rev=64716&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclNodes.def
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/AST/DeclTemplate.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/test/SemaTemplate/class-template-id.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Feb 16 19:05:43 2009
@@ -23,6 +23,7 @@
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 @@
/// 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 @@
/// 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.
Modified: cfe/trunk/include/clang/AST/DeclNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclNodes.def?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclNodes.def (original)
+++ cfe/trunk/include/clang/AST/DeclNodes.def Mon Feb 16 19:05:43 2009
@@ -84,6 +84,7 @@
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(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)
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Mon Feb 16 19:05:43 2009
@@ -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 @@
{ 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 @@
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
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Mon Feb 16 19:05:43 2009
@@ -1502,6 +1502,8 @@
// 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)
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Feb 16 19:05:43 2009
@@ -21,9 +21,9 @@
// 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::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;
}
Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Mon Feb 16 19:05:43 2009
@@ -143,3 +143,39 @@
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);
+}
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Feb 16 19:05:43 2009
@@ -61,6 +61,7 @@
class ExtVectorType;
class TypedefDecl;
class TemplateDecl;
+ class TemplateArgument;
class TemplateParameterList;
class TemplateTemplateParmDecl;
class ObjCInterfaceDecl;
@@ -1554,13 +1555,16 @@
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,
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Mon Feb 16 19:05:43 2009
@@ -654,21 +654,51 @@
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 @@
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 @@
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 @@
= 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 @@
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 @@
/// \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 @@
}
// Okay: we've named a function with external linkage.
+ Entity = Func;
return Invalid;
}
@@ -909,6 +976,7 @@
}
// Okay: we've named an object with external linkage
+ Entity = Var;
return Invalid;
}
@@ -923,7 +991,8 @@
/// \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 @@
// 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 @@
///
/// 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
Modified: cfe/trunk/test/SemaTemplate/class-template-id.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/class-template-id.cpp?rev=64716&r1=64715&r2=64716&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/class-template-id.cpp (original)
+++ cfe/trunk/test/SemaTemplate/class-template-id.cpp Mon Feb 16 19:05:43 2009
@@ -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> *'}}
+}
+
More information about the cfe-commits
mailing list