diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-17 01:05:43 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-17 01:05:43 +0000 |
commit | 3e00bad490f1bae8a2c60f934e7eb5dbb9752c5d (patch) | |
tree | cd116f187b667c5f88dd380a317592ad5ccdb287 | |
parent | f50adff9997578a021c5fb1689852949e8e4d9b4 (diff) |
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.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64716 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 12 | ||||
-rw-r--r-- | include/clang/AST/DeclNodes.def | 3 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 259 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 2 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 6 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 12 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 176 | ||||
-rw-r--r-- | test/SemaTemplate/class-template-id.cpp | 28 |
9 files changed, 465 insertions, 69 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 9b25e29c69..a9d6a7dbd5 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -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. diff --git a/include/clang/AST/DeclNodes.def b/include/clang/AST/DeclNodes.def index a22fa70b8b..984b21e10b 100644 --- a/include/clang/AST/DeclNodes.def +++ b/include/clang/AST/DeclNodes.def @@ -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) diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 334a03a439..d9ce70ba49 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -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 diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index b93b06ba1e..478f459bf5 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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) diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 6de575411b..294e94f5f4 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -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; } diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index dccb8df075..81ef3ab70e 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -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); +} diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 3475b2dada..2e457156d1 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index b339a7ba38..8c2a8bcd4a 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -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 diff --git a/test/SemaTemplate/class-template-id.cpp b/test/SemaTemplate/class-template-id.cpp index 0bdc3e9875..39dc29796b 100644 --- a/test/SemaTemplate/class-template-id.cpp +++ b/test/SemaTemplate/class-template-id.cpp @@ -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> *'}} +} + |