From 40808ce6ac04b102c3b56244a635d6b98eed6d97 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 9 Mar 2009 23:48:35 +0000 Subject: [PATCH] Implement template instantiation for ClassTemplateSpecializationTypes, such as replacing 'T' in vector. There are a few aspects to this: - Extend TemplateArgument to allow arbitrary expressions (an Expr*), and switch ClassTemplateSpecializationType to store TemplateArguments rather than it's own type-or-expression representation. - ClassTemplateSpecializationType can now store dependent types. In that case, the canonical type is another ClassTemplateSpecializationType (with default template arguments expanded) rather than a declaration (we don't build Decls for dependent types). - Split ActOnClassTemplateId into ActOnClassTemplateId (called from the parser) and CheckClassTemplateId (called from ActOnClassTemplateId and InstantiateType). They're smart enough to handle dependent types, now. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@66509 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 4 +- include/clang/AST/DeclTemplate.h | 72 +++++-- include/clang/AST/Type.h | 97 +++------ lib/AST/ASTContext.cpp | 21 +- lib/AST/DeclTemplate.cpp | 9 + lib/AST/Type.cpp | 111 ++++++---- lib/AST/TypeSerialization.cpp | 25 +-- lib/Sema/Sema.h | 11 +- lib/Sema/SemaDeclCXX.cpp | 3 +- lib/Sema/SemaTemplate.cpp | 306 +++++++++++++++++---------- lib/Sema/SemaTemplateInstantiate.cpp | 41 +++- test/SemaTemplate/temp_arg_type.cpp | 3 +- 12 files changed, 425 insertions(+), 278 deletions(-) diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index ca2b79579b..8a8be1e775 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -275,9 +275,9 @@ public: IdentifierInfo *Name = 0); QualType getClassTemplateSpecializationType(TemplateDecl *Template, + const TemplateArgument *Args, unsigned NumArgs, - uintptr_t *Args, bool *ArgIsType, - QualType Canon); + QualType Canon = QualType()); /// getObjCQualifiedInterfaceType - Return a /// ObjCQualifiedInterfaceType type for the given interface decl and diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index d93bbf5562..cc309b4ea5 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -68,6 +68,11 @@ public: unsigned size() const { return NumParams; } + const Decl* getParam(unsigned Idx) const { + assert(Idx < size() && "Template parameter index out-of-range"); + return begin()[Idx]; + } + /// \btief Returns the minimum number of arguments needed to form a /// template specialization. This may be fewer than the number of /// template parameters, if some of the parameters have default @@ -400,51 +405,72 @@ protected: /// specialization. class TemplateArgument { union { - uintptr_t TypeOrDeclaration; + uintptr_t TypeOrValue; char IntegralValue[sizeof(llvm::APInt)]; }; + /// \brief Location of the beginning of this template argument. + SourceLocation StartLoc; + public: /// \brief The type of template argument we're storing. enum ArgKind { /// The template argument is a type. It's value is stored in the - /// TypeOrDeclaration field. + /// TypeOrValue field. Type = 0, /// The template argument is a declaration Declaration = 1, /// The template argument is an integral value stored in an llvm::APInt. - Integral = 2 + Integral = 2, + /// The template argument is a value- or type-dependent expression + /// stored in an Expr*. + Expression = 3 } Kind; + /// \brief Construct an empty, invalid template argument. + TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { } + /// \brief Construct a template type argument. - TemplateArgument(QualType T) : Kind(Type) { - assert(T->isCanonical() && - "Template arguments always use the canonical type"); - TypeOrDeclaration = reinterpret_cast(T.getAsOpaquePtr()); + TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) { + TypeOrValue = reinterpret_cast(T.getAsOpaquePtr()); + StartLoc = Loc; } /// \brief Construct a template argument that refers to a /// declaration, which is either an external declaration or a /// template declaration. - TemplateArgument(Decl *D) : Kind(Declaration) { + TemplateArgument(SourceLocation Loc, Decl *D) : Kind(Declaration) { // FIXME: Need to be sure we have the "canonical" declaration! - TypeOrDeclaration = reinterpret_cast(D); + TypeOrValue = reinterpret_cast(D); + StartLoc = Loc; } /// \brief Construct an integral constant template argument. - TemplateArgument(const llvm::APInt &Value) : Kind(Integral) { + TemplateArgument(SourceLocation Loc, const llvm::APInt &Value) + : Kind(Integral) { new (IntegralValue) llvm::APInt(Value); + StartLoc = Loc; } + /// \brief Construct a template argument that is an expression. + /// + /// This form of template argument only occurs in template argument + /// lists used for dependent types and for expression; it will not + /// occur in a non-dependent, canonical template argument list. + TemplateArgument(Expr *E); + /// \brief Copy constructor for a template argument. TemplateArgument(const TemplateArgument &Other) : Kind(Other.Kind) { if (Kind == Integral) new (IntegralValue) llvm::APInt(*Other.getAsIntegral()); else - TypeOrDeclaration = Other.TypeOrDeclaration; + TypeOrValue = Other.TypeOrValue; + StartLoc = Other.StartLoc; } TemplateArgument& operator=(const TemplateArgument& Other) { + // FIXME: Does not provide the strong guarantee for exception + // safety. using llvm::APInt; if (Kind == Other.Kind && Kind == Integral) { @@ -460,8 +486,10 @@ public: if (Other.Kind == Integral) new (IntegralValue) llvm::APInt(*Other.getAsIntegral()); else - TypeOrDeclaration = Other.TypeOrDeclaration; + TypeOrValue = Other.TypeOrValue; } + StartLoc = Other.StartLoc; + return *this; } @@ -481,14 +509,14 @@ public: return QualType(); return QualType::getFromOpaquePtr( - reinterpret_cast(TypeOrDeclaration)); + reinterpret_cast(TypeOrValue)); } /// \brief Retrieve the template argument as a declaration. Decl *getAsDecl() const { if (Kind != Declaration) return 0; - return reinterpret_cast(TypeOrDeclaration); + return reinterpret_cast(TypeOrValue); } /// \brief Retrieve the template argument as an integral value. @@ -502,6 +530,17 @@ public: return const_cast(this)->getAsIntegral(); } + /// \brief Retrieve the template argument as an expression. + Expr *getAsExpr() const { + if (Kind != Expression) + return 0; + + return reinterpret_cast(TypeOrValue); + } + + /// \brief Retrieve the location where the template argument starts. + SourceLocation getLocation() const { return StartLoc; } + /// \brief Used to insert TemplateArguments into FoldingSets. void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(Kind); @@ -517,6 +556,11 @@ public: case Integral: getAsIntegral()->Profile(ID); break; + + case Expression: + // FIXME: We need a canonical representation of expressions. + ID.AddPointer(getAsExpr()); + break; } } }; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index b6a1ec17b9..1c0a081c45 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -46,6 +46,7 @@ namespace clang { class Stmt; class SourceLocation; class StmtIteratorBase; + class TemplateArgument; // Provide forward declarations for all of the *Type classes #define TYPE(Class, Base) class Class##Type; @@ -1430,100 +1431,52 @@ class ClassTemplateSpecializationType // possibly with template-names preceded by a nested-name-specifier. TemplateDecl *Template; + /// \brief - The number of template arguments named in this class + /// template specialization. unsigned NumArgs; - ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs, - uintptr_t *Args, bool *ArgIsType, - QualType Canon); + ClassTemplateSpecializationType(TemplateDecl *T, + const TemplateArgument *Args, + unsigned NumArgs, QualType Canon); - /// \brief Retrieve the number of packed words that precede the - /// actual arguments. - /// - /// The flags that specify whether each argument is a type or an - /// expression are packed into the - /// ClassTemplateSpecializationType. This routine computes the - /// number of pointer-sized words we need to store this information, - /// based on the number of template arguments - static unsigned getNumPackedWords(unsigned NumArgs) { - const unsigned BitsPerWord = sizeof(uintptr_t) * 8; - return NumArgs / BitsPerWord + (NumArgs % BitsPerWord > 0); - } - - /// \brief Pack the given boolean values into words. - static void - packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words); - virtual void Destroy(ASTContext& C); friend class ASTContext; // ASTContext creates these public: + /// \brief Determine whether any of the given template arguments are + /// dependent. + static bool anyDependentTemplateArguments(const TemplateArgument *Args, + unsigned NumArgs); + + typedef const TemplateArgument * iterator; + + iterator begin() const { return getArgs(); } + iterator end() const; + /// \brief Retrieve the template that we are specializing. TemplateDecl *getTemplate() const { return Template; } - /// \briefe Retrieve the number of template arguments. + /// \brief Retrieve the template arguments. + const TemplateArgument *getArgs() const { + return reinterpret_cast(this + 1); + } + + /// \brief Retrieve the number of template arguments. unsigned getNumArgs() const { return NumArgs; } /// \brief Retrieve a specific template argument as a type. /// \precondition @c isArgType(Arg) - QualType getArgAsType(unsigned Arg) const { - assert(isArgType(Arg) && "Argument is not a type"); - return QualType::getFromOpaquePtr( - reinterpret_cast(getArgAsOpaqueValue(Arg))); - } - - /// \brief Retrieve a specific template argument as an expression. - /// \precondition @c !isArgType(Arg) - Expr *getArgAsExpr(unsigned Arg) const { - assert(!isArgType(Arg) && "Argument is not an expression"); - return reinterpret_cast(getArgAsOpaqueValue(Arg)); - } - - /// \brief Retrieve the specified template argument as an opaque value. - uintptr_t getArgAsOpaqueValue(unsigned Arg) const; - - /// \brief Determine whether the given template argument is a type. - bool isArgType(unsigned Arg) const; + const TemplateArgument &getArg(unsigned Idx) const; virtual void getAsStringInternal(std::string &InnerString) const; void Profile(llvm::FoldingSetNodeID &ID) { - // Add the template - ID.AddPointer(Template); - - // Add the packed words describing what kind of template arguments - // we have. - // FIXME: Would like to be smarter about the profile of expressions, - // so that we can combine expression nodes more effectively. - uintptr_t *Data = reinterpret_cast(this + 1); - for (unsigned Packed = 0, NumPacked = getNumPackedWords(NumArgs); - Packed != NumPacked; ++Packed) - ID.AddInteger(Data[Packed]); - - // Add the template arguments themselves. - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - ID.AddInteger(getArgAsOpaqueValue(Arg)); + Profile(ID, Template, getArgs(), NumArgs); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateDecl *T, - unsigned NumArgs, uintptr_t *Args, bool *ArgIsType) { - // Add the template - ID.AddPointer(T); - - // Add the packed words describing what kind of template arguments - // we have. - unsigned NumPackedWords = getNumPackedWords(NumArgs); - unsigned NumPackedBytes = NumPackedWords * sizeof(uintptr_t); - uintptr_t *PackedWords - = reinterpret_cast(alloca(NumPackedBytes)); - packBooleanValues(NumArgs, ArgIsType, PackedWords); - for (unsigned Packed = 0; Packed != NumPackedWords; ++Packed) - ID.AddInteger(PackedWords[Packed]); - - // Add the template arguments themselves. - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - ID.AddInteger(Args[Arg]); - } + const TemplateArgument *Args, unsigned NumArgs); static bool classof(const Type *T) { return T->getTypeClass() == ClassTemplateSpecialization; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 4579fb5a60..a51f432880 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1309,14 +1309,15 @@ QualType ASTContext::getTemplateTypeParmType(unsigned Depth, unsigned Index, QualType ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, + const TemplateArgument *Args, unsigned NumArgs, - uintptr_t *Args, bool *ArgIsType, QualType Canon) { - Canon = getCanonicalType(Canon); + if (!Canon.isNull()) + Canon = getCanonicalType(Canon); llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args, - ArgIsType); + ClassTemplateSpecializationType::Profile(ID, Template, Args, NumArgs); + void *InsertPos = 0; ClassTemplateSpecializationType *Spec = ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos); @@ -1324,13 +1325,11 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, if (Spec) return QualType(Spec, 0); - void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) + - (sizeof(uintptr_t) * - (ClassTemplateSpecializationType:: - getNumPackedWords(NumArgs) + - NumArgs)), 8); - Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args, - ArgIsType, Canon); + void *Mem = Allocate((sizeof(ClassTemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs), + 8); + Spec = new (Mem) ClassTemplateSpecializationType(Template, Args, NumArgs, + Canon); Types.push_back(Spec); ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index ed4fd44e70..ac76c258a7 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -144,6 +144,15 @@ SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { : SourceLocation(); } +//===----------------------------------------------------------------------===// +// TemplateArgument Implementation +//===----------------------------------------------------------------------===// + +TemplateArgument::TemplateArgument(Expr *E) : Kind(Expression) { + TypeOrValue = reinterpret_cast(E); + StartLoc = E->getSourceRange().getBegin(); +} + //===----------------------------------------------------------------------===// // ClassTemplateSpecializationDecl Implementation //===----------------------------------------------------------------------===// diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 3b06b4ee28..412b0cf834 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -921,59 +921,77 @@ bool EnumType::classof(const TagType *TT) { return isa(TT->getDecl()); } -void +bool ClassTemplateSpecializationType:: -packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) { - const unsigned BitsPerWord = sizeof(uintptr_t) * 8; - - for (unsigned PW = 0, NumPackedWords = getNumPackedWords(NumArgs), Arg = 0; - PW != NumPackedWords; ++PW) { - uintptr_t Word = 0; - for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) { - Word <<= 1; - Word |= Values[Arg]; +anyDependentTemplateArguments(const TemplateArgument *Args, unsigned NumArgs) { + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) { + switch (Args[Idx].getKind()) { + case TemplateArgument::Type: + if (Args[Idx].getAsType()->isDependentType()) + return true; + break; + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // Never dependent + break; + + case TemplateArgument::Expression: + if (Args[Idx].getAsExpr()->isTypeDependent() || + Args[Idx].getAsExpr()->isValueDependent()) + return true; + break; } - Words[PW] = Word; } + + return false; } ClassTemplateSpecializationType:: -ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs, - uintptr_t *Args, bool *ArgIsType, - QualType Canon) - : Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false), - Template(T), NumArgs(NumArgs) +ClassTemplateSpecializationType(TemplateDecl *T, const TemplateArgument *Args, + unsigned NumArgs, QualType Canon) + : Type(ClassTemplateSpecialization, + Canon.isNull()? QualType(this, 0) : Canon, + /*FIXME: Check for dependent template */ + anyDependentTemplateArguments(Args, NumArgs)), + Template(T), NumArgs(NumArgs) { - uintptr_t *Data = reinterpret_cast(this + 1); + assert((!Canon.isNull() || + anyDependentTemplateArguments(Args, NumArgs)) && + "No canonical type for non-dependent class template specialization"); - // Pack the argument-is-type values into the words just after the - // class template specialization type. - packBooleanValues(NumArgs, ArgIsType, Data); - - // Copy the template arguments after the packed words. - Data += getNumPackedWords(NumArgs); + TemplateArgument *TemplateArgs + = reinterpret_cast(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - Data[Arg] = Args[Arg]; + new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); } void ClassTemplateSpecializationType::Destroy(ASTContext& C) { for (unsigned Arg = 0; Arg < NumArgs; ++Arg) - if (!isArgType(Arg)) - getArgAsExpr(Arg)->Destroy(C); + if (Expr *E = getArg(Arg).getAsExpr()) + E->Destroy(C); +} + +ClassTemplateSpecializationType::iterator +ClassTemplateSpecializationType::end() const { + return begin() + getNumArgs(); } -uintptr_t -ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const { - const uintptr_t *Data = reinterpret_cast(this + 1); - Data += getNumPackedWords(NumArgs); - return Data[Arg]; +const TemplateArgument & +ClassTemplateSpecializationType::getArg(unsigned Idx) const { + assert(Idx < getNumArgs() && "Template argument out of range"); + return getArgs()[Idx]; } -bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const { - const unsigned BitsPerWord = sizeof(uintptr_t) * 8; - const uintptr_t *Data = reinterpret_cast(this + 1); - Data += Arg / BitsPerWord; - return (*Data >> ((NumArgs - Arg) % BitsPerWord - 1)) & 0x01; +void +ClassTemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, + TemplateDecl *T, + const TemplateArgument *Args, + unsigned NumArgs) { + ID.AddPointer(T); + + for (unsigned Idx = 0; Idx < NumArgs; ++Idx) + Args[Idx].Profile(ID); } //===----------------------------------------------------------------------===// @@ -1280,11 +1298,24 @@ getAsStringInternal(std::string &InnerString) const { // Print the argument into a string. std::string ArgString; - if (isArgType(Arg)) - getArgAsType(Arg).getAsStringInternal(ArgString); - else { + switch (getArg(Arg).getKind()) { + case TemplateArgument::Type: + getArg(Arg).getAsType().getAsStringInternal(ArgString); + break; + + case TemplateArgument::Declaration: + ArgString = cast(getArg(Arg).getAsDecl())->getNameAsString(); + break; + + case TemplateArgument::Integral: + ArgString = getArg(Arg).getAsIntegral()->toString(10, true); + break; + + case TemplateArgument::Expression: { llvm::raw_string_ostream s(ArgString); - getArgAsExpr(Arg)->printPretty(s); + getArg(Arg).getAsExpr()->printPretty(s); + break; + } } // If this is the first argument and its string representation diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp index b7a8f1a366..1b9fed4866 100644 --- a/lib/AST/TypeSerialization.cpp +++ b/lib/AST/TypeSerialization.cpp @@ -390,13 +390,7 @@ void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const { S.Emit(getCanonicalTypeInternal()); S.EmitPtr(Template); S.EmitInt(NumArgs); - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - S.EmitBool(isArgType(Arg)); - if (isArgType(Arg)) - S.Emit(getArgAsType(Arg)); - else - S.EmitOwnedPtr(getArgAsExpr(Arg)); - } + // FIXME: Serialize class template specialization types } Type* @@ -409,19 +403,10 @@ CreateImpl(ASTContext& Context, Deserializer& D) { TemplateDecl *Template = cast(D.ReadPtr()); unsigned NumArgs = D.ReadInt(); - for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { - bool IsType = D.ReadBool(); - ArgIsType.push_back(IsType); - if (IsType) - Args.push_back( - reinterpret_cast(QualType::ReadVal(D).getAsOpaquePtr())); - else - Args.push_back(reinterpret_cast(D.ReadOwnedPtr(Context))); - } - - return Context.getClassTemplateSpecializationType(Template, NumArgs, - &Args[0], &ArgIsType[0], - Canon).getTypePtr(); + // FIXME: De-serialize class template specialization types + (void)Template; + (void)NumArgs; + return 0; } //===----------------------------------------------------------------------===// diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 4ac8ffc0fb..83be895909 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1601,6 +1601,13 @@ public: AttributeList *Attr, MultiTemplateParamsArg TemplateParameterLists); + QualType CheckClassTemplateId(ClassTemplateDecl *ClassTemplate, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc); + virtual TypeResult ActOnClassTemplateId(DeclTy *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, @@ -1630,8 +1637,8 @@ public: bool CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ASTTemplateArgsPtr& TemplateArgs, - SourceLocation *TemplateArgLocs, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, SourceLocation RAngleLoc, llvm::SmallVectorImpl &Converted); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 7773b9e615..e9e2e3c2ac 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -383,7 +383,8 @@ Sema::BaseResult Sema::ActOnBaseSpecifier(DeclTy *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, TypeTy *basetype, SourceLocation BaseLoc) { - CXXRecordDecl *Class = (CXXRecordDecl*)classdecl; + AdjustDeclIfTemplate(classdecl); + CXXRecordDecl *Class = cast((Decl*)classdecl); QualType BaseType = QualType::getFromOpaquePtr(basetype); if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, Virtual, Access, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index a55e3a5184..281984de2c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -658,61 +658,115 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, return Invalid; } -Action::TypeResult -Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, - SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, +/// \brief Translates template arguments as provided by the parser +/// into template arguments used by semantic analysis. +static void +translateTemplateArguments(ASTTemplateArgsPtr &TemplateArgsIn, SourceLocation *TemplateArgLocs, - SourceLocation RAngleLoc, - const CXXScopeSpec *SS) { - TemplateDecl *Template = cast(static_cast(TemplateD)); - ClassTemplateDecl *ClassTemplate = cast(Template); + llvm::SmallVector &TemplateArgs) { + TemplateArgs.reserve(TemplateArgsIn.size()); + + void **Args = TemplateArgsIn.getArgs(); + bool *ArgIsType = TemplateArgsIn.getArgIsType(); + for (unsigned Arg = 0, Last = TemplateArgsIn.size(); Arg != Last; ++Arg) { + TemplateArgs.push_back( + ArgIsType[Arg]? TemplateArgument(TemplateArgLocs[Arg], + QualType::getFromOpaquePtr(Args[Arg])) + : TemplateArgument(reinterpret_cast(Args[Arg]))); + } +} +QualType Sema::CheckClassTemplateId(ClassTemplateDecl *ClassTemplate, + SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, + SourceLocation RAngleLoc) { // Check that the template argument list is well-formed for this // template. llvm::SmallVector ConvertedTemplateArgs; - if (CheckTemplateArgumentList(Template, TemplateLoc, LAngleLoc, - TemplateArgs, TemplateArgLocs, RAngleLoc, + if (CheckTemplateArgumentList(ClassTemplate, TemplateLoc, LAngleLoc, + TemplateArgs, NumTemplateArgs, RAngleLoc, ConvertedTemplateArgs)) - return true; + return QualType(); assert((ConvertedTemplateArgs.size() == - Template->getTemplateParameters()->size()) && + ClassTemplate->getTemplateParameters()->size()) && "Converted template argument list is too short!"); - // Find the class template specialization declaration that - // corresponds to these arguments. - llvm::FoldingSetNodeID ID; - ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size()); - void *InsertPos = 0; - ClassTemplateSpecializationDecl *Decl - = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); - if (!Decl) { - // This is the first time we have referenced this class template - // specialization. Create the canonical declaration and add it to - // the set of specializations. - Decl = ClassTemplateSpecializationDecl::Create(Context, + QualType CanonType; + + if (ClassTemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs, + NumTemplateArgs)) { + // This class template specialization is a dependent + // type. Therefore, its canonical type is another class template + // specialization type that contains all of the converted + // arguments in canonical form. This ensures that, e.g., A and + // A have identical types when A is declared as: + // + // template struct A; + + CanonType = Context.getClassTemplateSpecializationType(ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + } else { + // Find the class template specialization declaration that + // corresponds to these arguments. + llvm::FoldingSetNodeID ID; + ClassTemplateSpecializationDecl::Profile(ID, &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size()); + void *InsertPos = 0; + ClassTemplateSpecializationDecl *Decl + = ClassTemplate->getSpecializations().FindNodeOrInsertPos(ID, InsertPos); + if (!Decl) { + // This is the first time we have referenced this class template + // specialization. Create the canonical declaration and add it to + // the set of specializations. + Decl = ClassTemplateSpecializationDecl::Create(Context, ClassTemplate->getDeclContext(), - TemplateLoc, - ClassTemplate, - &ConvertedTemplateArgs[0], - ConvertedTemplateArgs.size(), - 0); - ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); - Decl->setLexicalDeclContext(CurContext); + TemplateLoc, + ClassTemplate, + &ConvertedTemplateArgs[0], + ConvertedTemplateArgs.size(), + 0); + ClassTemplate->getSpecializations().InsertNode(Decl, InsertPos); + Decl->setLexicalDeclContext(CurContext); + } + + CanonType = Context.getTypeDeclType(Decl); } // Build the fully-sugared type for this class template // specialization, which refers back to the class template // specialization we created or found. - QualType Result - = Context.getClassTemplateSpecializationType(Template, - TemplateArgs.size(), - reinterpret_cast(TemplateArgs.getArgs()), - TemplateArgs.getArgIsType(), - Context.getTypeDeclType(Decl)); - TemplateArgs.release(); + return Context.getClassTemplateSpecializationType(ClassTemplate, + TemplateArgs, + NumTemplateArgs, + CanonType); +} + +Action::TypeResult +Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, + SourceLocation LAngleLoc, + ASTTemplateArgsPtr TemplateArgsIn, + SourceLocation *TemplateArgLocs, + SourceLocation RAngleLoc, + const CXXScopeSpec *SS) { + TemplateDecl *Template = cast(static_cast(TemplateD)); + ClassTemplateDecl *ClassTemplate = cast(Template); + + // Translate the parser's template argument list in our AST format. + llvm::SmallVector TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + + QualType Result = CheckClassTemplateId(ClassTemplate, TemplateLoc, + LAngleLoc, + &TemplateArgs[0], + TemplateArgs.size(), + RAngleLoc); + + TemplateArgsIn.release(); return Result.getAsOpaquePtr(); } @@ -721,13 +775,13 @@ Sema::ActOnClassTemplateId(DeclTy *TemplateD, SourceLocation TemplateLoc, bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, SourceLocation TemplateLoc, SourceLocation LAngleLoc, - ASTTemplateArgsPtr& Args, - SourceLocation *TemplateArgLocs, + const TemplateArgument *TemplateArgs, + unsigned NumTemplateArgs, SourceLocation RAngleLoc, llvm::SmallVectorImpl &Converted) { TemplateParameterList *Params = Template->getTemplateParameters(); unsigned NumParams = Params->size(); - unsigned NumArgs = Args.size(); + unsigned NumArgs = NumTemplateArgs; bool Invalid = false; if (NumArgs > NumParams || @@ -737,7 +791,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // arguments. SourceRange Range; if (NumArgs > NumParams) - Range = SourceRange(TemplateArgLocs[NumParams], RAngleLoc); + Range = SourceRange(TemplateArgs[NumParams].getLocation(), RAngleLoc); Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << (NumArgs > NumParams) << (isa(Template)? 0 : @@ -759,9 +813,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, ParamEnd = Params->end(); Param != ParamEnd; ++Param, ++ArgIdx) { // Decode the template argument - QualType ArgType; - Expr *ArgExpr = 0; - SourceLocation ArgLoc; + TemplateArgument Arg; if (ArgIdx >= NumArgs) { // Retrieve the default template argument from the template // parameter. @@ -769,7 +821,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (!TTP->hasDefaultArgument()) break; - ArgType = TTP->getDefaultArgument(); + QualType ArgType = TTP->getDefaultArgument(); // If the argument type is dependent, instantiate it now based // on the previously-computed template arguments. @@ -781,15 +833,14 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, if (ArgType.isNull()) return true; - ArgLoc = TTP->getDefaultArgumentLoc(); + Arg = TemplateArgument(TTP->getLocation(), ArgType); } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*Param)) { if (!NTTP->hasDefaultArgument()) break; // FIXME: Instantiate default argument - ArgExpr = NTTP->getDefaultArgument(); - ArgLoc = NTTP->getDefaultArgumentLoc(); + Arg = TemplateArgument(NTTP->getDefaultArgument()); } else { TemplateTemplateParmDecl *TempParm = cast(*Param); @@ -798,29 +849,24 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, break; // FIXME: Instantiate default argument - ArgExpr = TempParm->getDefaultArgument(); - ArgLoc = TempParm->getDefaultArgumentLoc(); + Arg = TemplateArgument(TempParm->getDefaultArgument()); } } else { // Retrieve the template argument produced by the user. - ArgLoc = TemplateArgLocs[ArgIdx]; - - if (Args.getArgIsType()[ArgIdx]) - ArgType = QualType::getFromOpaquePtr(Args.getArgs()[ArgIdx]); - else - ArgExpr = reinterpret_cast(Args.getArgs()[ArgIdx]); + Arg = TemplateArgs[ArgIdx]; } if (TemplateTypeParmDecl *TTP = dyn_cast(*Param)) { // Check template type parameters. - if (!ArgType.isNull()) { - if (CheckTemplateArgument(TTP, ArgType, ArgLoc)) + if (Arg.getKind() == TemplateArgument::Type) { + if (CheckTemplateArgument(TTP, Arg.getAsType(), Arg.getLocation())) Invalid = true; // Add the converted template type argument. Converted.push_back( - TemplateArgument(Context.getCanonicalType(ArgType))); + TemplateArgument(Arg.getLocation(), + Context.getCanonicalType(Arg.getAsType()))); continue; } @@ -829,9 +875,8 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // type shall be a type-id. // We have a template type parameter but the template argument - // is an expression. - Diag(ArgExpr->getSourceRange().getBegin(), - diag::err_template_arg_must_be_type); + // is not a type. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_type); Diag((*Param)->getLocation(), diag::note_template_param_here); Invalid = true; } else if (NonTypeTemplateParmDecl *NTTP @@ -859,50 +904,81 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } } - if (ArgExpr) { - if (CheckTemplateArgument(NTTP, NTTPType, ArgExpr, &Converted)) + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *E = Arg.getAsExpr(); + if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted)) Invalid = true; - continue; + break; } - // We have a non-type template parameter but the template - // argument is a type. - - // C++ [temp.arg]p2: - // In a template-argument, an ambiguity between a type-id and - // an expression is resolved to a type-id, regardless of the - // form of the corresponding template-parameter. - // - // We warn specifically about this case, since it can be rather - // confusing for users. - if (ArgType->isFunctionType()) - Diag(ArgLoc, diag::err_template_arg_nontype_ambig) - << ArgType; - else - Diag(ArgLoc, diag::err_template_arg_must_be_expr); - Diag((*Param)->getLocation(), diag::note_template_param_here); - Invalid = true; + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Type: + // We have a non-type template parameter but the template + // argument is a type. + + // C++ [temp.arg]p2: + // In a template-argument, an ambiguity between a type-id and + // an expression is resolved to a type-id, regardless of the + // form of the corresponding template-parameter. + // + // We warn specifically about this case, since it can be rather + // confusing for users. + if (Arg.getAsType()->isFunctionType()) + Diag(Arg.getLocation(), diag::err_template_arg_nontype_ambig) + << Arg.getAsType(); + else + Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr); + Diag((*Param)->getLocation(), diag::note_template_param_here); + Invalid = true; + } } else { // Check template template parameters. TemplateTemplateParmDecl *TempParm = cast(*Param); - if (ArgExpr && isa(ArgExpr) && - isa(cast(ArgExpr)->getDecl())) { - if (CheckTemplateArgument(TempParm, cast(ArgExpr))) - Invalid = true; - - // Add the converted template argument. - // FIXME: Need the "canonical" template declaration! - Converted.push_back( - TemplateArgument(cast(ArgExpr)->getDecl())); - continue; + switch (Arg.getKind()) { + case TemplateArgument::Expression: { + Expr *ArgExpr = Arg.getAsExpr(); + if (ArgExpr && isa(ArgExpr) && + isa(cast(ArgExpr)->getDecl())) { + if (CheckTemplateArgument(TempParm, cast(ArgExpr))) + Invalid = true; + + // Add the converted template argument. + // FIXME: Need the "canonical" template declaration! + Converted.push_back( + TemplateArgument(Arg.getLocation(), + cast(ArgExpr)->getDecl())); + continue; + } + } + // fall through + + case TemplateArgument::Type: { + // We have a template template parameter but the template + // argument does not refer to a template. + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Invalid = true; + break; } - // We have a template template parameter but the template - // argument does not refer to a template. - Diag(ArgLoc, diag::err_template_arg_must_be_template); - Invalid = true; + case TemplateArgument::Declaration: + // We've already checked this template argument, so just copy + // it to the list of converted arguments. + Converted.push_back(Arg); + break; + + case TemplateArgument::Integral: + assert(false && "Integral argument with template template parameter"); + break; + } } } @@ -1109,11 +1185,16 @@ Sema::CheckTemplateArgumentPointerToMember(Expr *Arg, NamedDecl *&Member) { bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType InstantiatedParamType, Expr *&Arg, llvm::SmallVectorImpl *Converted) { + SourceLocation StartLoc = Arg->getSourceRange().getBegin(); + // If either the parameter has a dependent type or the argument is // type-dependent, there's nothing we can check now. // FIXME: Add template argument to Converted! - if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) + if (InstantiatedParamType->isDependentType() || Arg->isTypeDependent()) { + // FIXME: Produce a cloned, canonical expression? + Converted->push_back(TemplateArgument(Arg)); return false; + } // C++ [temp.arg.nontype]p5: // The following conversions are performed on each expression used @@ -1188,7 +1269,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, IntegerType->isSignedIntegerType()); CanonicalArg = Value; - Converted->push_back(TemplateArgument(CanonicalArg)); + Converted->push_back(TemplateArgument(StartLoc, CanonicalArg)); } return false; @@ -1252,7 +1333,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); return false; } @@ -1262,7 +1343,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1297,7 +1378,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1339,7 +1420,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Entity)); + Converted->push_back(TemplateArgument(StartLoc, Entity)); return false; } @@ -1366,7 +1447,7 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return true; if (Converted) - Converted->push_back(TemplateArgument(Member)); + Converted->push_back(TemplateArgument(StartLoc, Member)); return false; } @@ -1649,7 +1730,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, DeclTy *TemplateD, SourceLocation TemplateNameLoc, SourceLocation LAngleLoc, - ASTTemplateArgsPtr TemplateArgs, + ASTTemplateArgsPtr TemplateArgsIn, SourceLocation *TemplateArgLocs, SourceLocation RAngleLoc, AttributeList *Attr, @@ -1701,12 +1782,16 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, Kind = ClassTemplate->getTemplatedDecl()->getTagKind(); } + // Translate the parser's template argument list in our AST format. + llvm::SmallVector TemplateArgs; + translateTemplateArguments(TemplateArgsIn, TemplateArgLocs, TemplateArgs); + // Check that the template argument list is well-formed for this // template. llvm::SmallVector ConvertedTemplateArgs; if (CheckTemplateArgumentList(ClassTemplate, TemplateNameLoc, LAngleLoc, - TemplateArgs, TemplateArgLocs, RAngleLoc, - ConvertedTemplateArgs)) + &TemplateArgs[0], TemplateArgs.size(), + RAngleLoc, ConvertedTemplateArgs)) return 0; assert((ConvertedTemplateArgs.size() == @@ -1786,11 +1871,10 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, // template arguments in the specialization. Specialization->setTypeAsWritten( Context.getClassTemplateSpecializationType(ClassTemplate, + &TemplateArgs[0], TemplateArgs.size(), - reinterpret_cast(TemplateArgs.getArgs()), - TemplateArgs.getArgIsType(), Context.getTypeDeclType(Specialization))); - TemplateArgs.release(); + TemplateArgsIn.release(); // C++ [temp.expl.spec]p9: // A template explicit specialization is in the scope of the diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index faeebc0680..71bba49af9 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -302,9 +302,44 @@ TemplateTypeInstantiator:: InstantiateClassTemplateSpecializationType( const ClassTemplateSpecializationType *T, unsigned Quals) const { - // FIXME: Implement this - assert(false && "Cannot instantiate ClassTemplateSpecializationType yet"); - return QualType(); + llvm::SmallVector InstantiatedTemplateArgs; + InstantiatedTemplateArgs.reserve(T->getNumArgs()); + for (ClassTemplateSpecializationType::iterator Arg = T->begin(), + ArgEnd = T->end(); + Arg != ArgEnd; ++Arg) { + switch (Arg->getKind()) { + case TemplateArgument::Type: { + QualType T = SemaRef.InstantiateType(Arg->getAsType(), + TemplateArgs, NumTemplateArgs, + Arg->getLocation(), + DeclarationName()); + if (T.isNull()) + return QualType(); + + InstantiatedTemplateArgs.push_back( + TemplateArgument(Arg->getLocation(), T)); + break; + } + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + InstantiatedTemplateArgs.push_back(*Arg); + break; + + case TemplateArgument::Expression: + assert(false && "Cannot instantiate expressions yet"); + break; + } + } + + // FIXME: We're missing the locations of the template name, '<', and + // '>'. + return SemaRef.CheckClassTemplateId(cast(T->getTemplate()), + Loc, + SourceLocation(), + &InstantiatedTemplateArgs[0], + InstantiatedTemplateArgs.size(), + SourceLocation()); } QualType diff --git a/test/SemaTemplate/temp_arg_type.cpp b/test/SemaTemplate/temp_arg_type.cpp index 216a283e2e..94e4505f40 100644 --- a/test/SemaTemplate/temp_arg_type.cpp +++ b/test/SemaTemplate/temp_arg_type.cpp @@ -14,8 +14,7 @@ A > *a6; // [temp.arg.type]p2 void f() { class X { }; - A * a = 0; // expected-error{{template argument uses local type 'class X'}} \ - // FIXME: expected-error{{use of undeclared identifier 'a'}} + A * a = 0; // expected-error{{template argument uses local type 'class X'}} } struct { int x; } Unnamed; // expected-note{{unnamed type used in template argument was declared here}} -- 2.40.0