diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | include/clang/AST/RecursiveASTVisitor.h | 2 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 53 | ||||
-rw-r--r-- | include/clang/AST/TypeLoc.h | 7 | ||||
-rw-r--r-- | include/clang/AST/TypeNodes.def | 1 | ||||
-rw-r--r-- | include/clang/Serialization/ASTBitCodes.h | 4 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 36 | ||||
-rw-r--r-- | lib/AST/ItaniumMangle.cpp | 5 | ||||
-rw-r--r-- | lib/AST/MicrosoftMangle.cpp | 6 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 28 | ||||
-rw-r--r-- | lib/AST/TypePrinter.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 5 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 45 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateVariadic.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/TreeTransform.h | 7 | ||||
-rw-r--r-- | lib/Serialization/ASTReader.cpp | 13 | ||||
-rw-r--r-- | lib/Serialization/ASTWriter.cpp | 12 | ||||
-rw-r--r-- | test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp | 20 |
18 files changed, 254 insertions, 5 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index a0544ef8bd..15bc301bd9 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -102,6 +102,8 @@ class ASTContext { mutable llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes; mutable llvm::FoldingSet<SubstTemplateTypeParmType> SubstTemplateTypeParmTypes; + mutable llvm::FoldingSet<SubstTemplateTypeParmPackType> + SubstTemplateTypeParmPackTypes; mutable llvm::ContextualFoldingSet<TemplateSpecializationType, ASTContext&> TemplateSpecializationTypes; mutable llvm::FoldingSet<ParenType> ParenTypes; @@ -664,6 +666,9 @@ public: QualType getSubstTemplateTypeParmType(const TemplateTypeParmType *Replaced, QualType Replacement) const; + QualType getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); QualType getTemplateTypeParmType(unsigned Depth, unsigned Index, bool ParameterPack, diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 31bb50dd9a..3d1279b252 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -718,6 +718,7 @@ DEF_TRAVERSE_TYPE(RecordType, { }) DEF_TRAVERSE_TYPE(EnumType, { }) DEF_TRAVERSE_TYPE(TemplateTypeParmType, { }) DEF_TRAVERSE_TYPE(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPE(SubstTemplateTypeParmPackType, { }) DEF_TRAVERSE_TYPE(TemplateSpecializationType, { TRY_TO(TraverseTemplateName(T->getTemplateName())); @@ -925,6 +926,7 @@ DEF_TRAVERSE_TYPELOC(RecordType, { }) DEF_TRAVERSE_TYPELOC(EnumType, { }) DEF_TRAVERSE_TYPELOC(TemplateTypeParmType, { }) DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmType, { }) +DEF_TRAVERSE_TYPELOC(SubstTemplateTypeParmPackType, { }) // FIXME: use the loc for the template name? DEF_TRAVERSE_TYPELOC(TemplateSpecializationType, { diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 19a16a3437..c081a161de 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2860,6 +2860,59 @@ public: static bool classof(const SubstTemplateTypeParmType *T) { return true; } }; +/// \brief Represents the result of substituting a set of types for a template +/// type parameter pack. +/// +/// When a pack expansion in the source code contains multiple parameter packs +/// and those parameter packs correspond to different levels of template +/// parameter lists, this type node is used to represent a template type +/// parameter pack from an outer level, which has already had its argument pack +/// substituted but that still lives within a pack expansion that itself +/// could not be instantiated. When actually performing a substitution into +/// that pack expansion (e.g., when all template parameters have corresponding +/// arguments), this type will be replaced with the \c SubstTemplateTypeParmType +/// at the current pack substitution index. +class SubstTemplateTypeParmPackType : public Type, public llvm::FoldingSetNode { + /// \brief The original type parameter. + const TemplateTypeParmType *Replaced; + + /// \brief A pointer to the set of template arguments that this + /// parameter pack is instantiated with. + const TemplateArgument *Arguments; + + /// \brief The number of template arguments in \c Arguments. + unsigned NumArguments; + + SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack); + + friend class ASTContext; + +public: + IdentifierInfo *getName() const { return Replaced->getName(); } + + /// Gets the template parameter that was substituted for. + const TemplateTypeParmType *getReplacedParameter() const { + return Replaced; + } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + TemplateArgument getArgumentPack() const; + + void Profile(llvm::FoldingSetNodeID &ID); + static void Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack); + + static bool classof(const Type *T) { + return T->getTypeClass() == SubstTemplateTypeParmPack; + } + static bool classof(const SubstTemplateTypeParmPackType *T) { return true; } +}; + /// \brief Represents the type of a template specialization as written /// in the source code. /// diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 16a8cb40c8..0b8ec0412a 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -592,6 +592,13 @@ class SubstTemplateTypeParmTypeLoc : SubstTemplateTypeParmType> { }; + /// \brief Wrapper for substituted template type parameters. +class SubstTemplateTypeParmPackTypeLoc : + public InheritingConcreteTypeLoc<TypeSpecTypeLoc, + SubstTemplateTypeParmPackTypeLoc, + SubstTemplateTypeParmPackType> { +}; + struct AttributedLocInfo { union { Expr *ExprOperand; diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 52b8f831ac..3587767f8f 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -91,6 +91,7 @@ NON_CANONICAL_TYPE(Elaborated, Type) NON_CANONICAL_TYPE(Attributed, Type) DEPENDENT_TYPE(TemplateTypeParm, Type) NON_CANONICAL_TYPE(SubstTemplateTypeParm, Type) +DEPENDENT_TYPE(SubstTemplateTypeParmPack, Type) NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index ea93d2e1d6..0ea9132915 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -555,7 +555,9 @@ namespace clang { /// \brief A PackExpansionType record. TYPE_PACK_EXPANSION = 35, /// \brief An AttributedType record. - TYPE_ATTRIBUTED = 36 + TYPE_ATTRIBUTED = 36, + /// \brief A SubstTemplateTypeParmPackType record. + TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK = 37 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 3abfe22caa..35d4b7a097 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1932,6 +1932,42 @@ ASTContext::getSubstTemplateTypeParmType(const TemplateTypeParmType *Parm, return QualType(SubstParm, 0); } +/// \brief Retrieve a +QualType ASTContext::getSubstTemplateTypeParmPackType( + const TemplateTypeParmType *Parm, + const TemplateArgument &ArgPack) { +#ifndef NDEBUG + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) { + assert(P->getKind() == TemplateArgument::Type &&"Pack contains a non-type"); + assert(P->getAsType().isCanonical() && "Pack contains non-canonical type"); + } +#endif + + llvm::FoldingSetNodeID ID; + SubstTemplateTypeParmPackType::Profile(ID, Parm, ArgPack); + void *InsertPos = 0; + if (SubstTemplateTypeParmPackType *SubstParm + = SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos)) + return QualType(SubstParm, 0); + + QualType Canon; + if (!Parm->isCanonicalUnqualified()) { + Canon = getCanonicalType(QualType(Parm, 0)); + Canon = getSubstTemplateTypeParmPackType(cast<TemplateTypeParmType>(Canon), + ArgPack); + SubstTemplateTypeParmPackTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + SubstTemplateTypeParmPackType *SubstParm + = new (*this, TypeAlignment) SubstTemplateTypeParmPackType(Parm, Canon, + ArgPack); + Types.push_back(SubstParm); + SubstTemplateTypeParmTypes.InsertNode(SubstParm, InsertPos); + return QualType(SubstParm, 0); +} + /// \brief Retrieve the template type parameter type for a template /// parameter or parameter pack with the given depth, index, and (optionally) /// name. diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index 8daba88ea8..0ebd7da679 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -1383,6 +1383,11 @@ void CXXNameMangler::mangleType(const TemplateTypeParmType *T) { mangleTemplateParameter(T->getIndex()); } +// <type> ::= <template-param> +void CXXNameMangler::mangleType(const SubstTemplateTypeParmPackType *T) { + mangleTemplateParameter(T->getReplacedParameter()->getIndex()); +} + // <type> ::= P <type> # pointer-to void CXXNameMangler::mangleType(const PointerType *T) { Out << 'P'; diff --git a/lib/AST/MicrosoftMangle.cpp b/lib/AST/MicrosoftMangle.cpp index ef50899e43..ce53fc2174 100644 --- a/lib/AST/MicrosoftMangle.cpp +++ b/lib/AST/MicrosoftMangle.cpp @@ -1011,6 +1011,12 @@ void MicrosoftCXXNameMangler::mangleType(const TemplateTypeParmType *T) { assert(false && "Don't know how to mangle TemplateTypeParmTypes yet!"); } +void MicrosoftCXXNameMangler::mangleType( + const SubstTemplateTypeParmPackType *T) { + assert(false && + "Don't know how to mangle SubstTemplateTypeParmPackTypes yet!"); +} + // <type> ::= <pointer-type> // <pointer-type> ::= <pointer-cvr-qualifiers> <cvr-qualifiers> <type> void MicrosoftCXXNameMangler::mangleType(const PointerType *T) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index d96993e7bd..3882f4960a 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1244,6 +1244,34 @@ bool EnumType::classof(const TagType *TT) { return isa<EnumDecl>(TT->getDecl()); } +SubstTemplateTypeParmPackType:: +SubstTemplateTypeParmPackType(const TemplateTypeParmType *Param, + QualType Canon, + const TemplateArgument &ArgPack) + : Type(SubstTemplateTypeParmPack, Canon, true, false, true), Replaced(Param), + Arguments(ArgPack.pack_begin()), NumArguments(ArgPack.pack_size()) +{ +} + +TemplateArgument SubstTemplateTypeParmPackType::getArgumentPack() const { + return TemplateArgument(Arguments, NumArguments); +} + +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getReplacedParameter(), getArgumentPack()); +} + +void SubstTemplateTypeParmPackType::Profile(llvm::FoldingSetNodeID &ID, + const TemplateTypeParmType *Replaced, + const TemplateArgument &ArgPack) { + ID.AddPointer(Replaced); + ID.AddInteger(ArgPack.pack_size()); + for (TemplateArgument::pack_iterator P = ArgPack.pack_begin(), + PEnd = ArgPack.pack_end(); + P != PEnd; ++P) + ID.AddPointer(P->getAsType().getAsOpaquePtr()); +} + bool TemplateSpecializationType:: anyDependentTemplateArguments(const TemplateArgumentListInfo &Args) { return anyDependentTemplateArguments(Args.getArgumentArray(), Args.size()); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index ef9704ec85..8a740d4ad8 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -568,6 +568,12 @@ void TypePrinter::printSubstTemplateTypeParm(const SubstTemplateTypeParmType *T, print(T->getReplacementType(), S); } +void TypePrinter::printSubstTemplateTypeParmPack( + const SubstTemplateTypeParmPackType *T, + std::string &S) { + printTemplateTypeParm(T->getReplacedParameter(), S); +} + void TypePrinter::printTemplateSpecialization( const TemplateSpecializationType *T, std::string &S) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 868458c2a9..6a37482d66 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2713,6 +2713,11 @@ bool UnnamedLocalNoLinkageFinder::VisitTemplateTypeParmType( return false; } +bool UnnamedLocalNoLinkageFinder::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitTemplateSpecializationType( const TemplateSpecializationType*) { return false; diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 5f181fb5e1..629dc58958 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -712,6 +712,12 @@ namespace { QualType TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateTypeParmTypeLoc TL); + /// \brief Transforms an already-substituted template type parameter pack + /// into either itself (if we aren't substituting into its pack expansion) + /// or the appropriate substituted argument. + QualType TransformSubstTemplateTypeParmPackType(TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL); + ExprResult TransformCallExpr(CallExpr *CE) { getSema().CallsUndergoingInstantiation.push_back(CE); ExprResult Result = @@ -1024,10 +1030,15 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, "Missing argument pack"); if (getSema().ArgumentPackSubstitutionIndex == -1) { - // FIXME: Variadic templates fun case. - getSema().Diag(TL.getSourceRange().getBegin(), - diag::err_pack_expansion_mismatch_unsupported); - return QualType(); + // We have the template argument pack, but we're not expanding the + // enclosing pack expansion yet. Just save the template argument + // pack for later substitution. + QualType Result + = getSema().Context.getSubstTemplateTypeParmPackType(T, Arg); + SubstTemplateTypeParmPackTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; } assert(getSema().ArgumentPackSubstitutionIndex < (int)Arg.pack_size()); @@ -1063,6 +1074,32 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return Result; } +QualType +TemplateInstantiator::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL) { + if (getSema().ArgumentPackSubstitutionIndex == -1) { + // We aren't expanding the parameter pack, so just return ourselves. + SubstTemplateTypeParmPackTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmPackTypeLoc>(TL.getType()); + NewTL.setNameLoc(TL.getNameLoc()); + return TL.getType(); + } + + const TemplateArgument &ArgPack = TL.getTypePtr()->getArgumentPack(); + unsigned Index = (unsigned)getSema().ArgumentPackSubstitutionIndex; + assert(Index < ArgPack.pack_size() && "Substitution index out-of-range"); + + QualType Result = ArgPack.pack_begin()[Index].getAsType(); + Result = getSema().Context.getSubstTemplateTypeParmType( + TL.getTypePtr()->getReplacedParameter(), + Result); + SubstTemplateTypeParmTypeLoc NewTL + = TLB.push<SubstTemplateTypeParmTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; +} + /// \brief Perform substitution on the type T with a given set of template /// arguments. /// diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 473dcb7d1f..dc5013c25d 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -456,6 +456,10 @@ bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, std::pair<IdentifierInfo *, SourceLocation> FirstPack; bool HaveFirstPack = false; + // FIXME: Variadic templates. Even if we don't expand, we'd still like to + // return the number of expansions back to the caller, perhaps as an + // llvm::Optional, so that it can be embedded in the pack expansion. This + // is important for the multi-level substitution case. for (unsigned I = 0; I != NumUnexpanded; ++I) { // Compute the depth and index for this parameter pack. unsigned Depth; diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 43d89e2875..4127d5045a 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3927,6 +3927,13 @@ QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmType( } template<typename Derived> +QualType TreeTransform<Derived>::TransformSubstTemplateTypeParmPackType( + TypeLocBuilder &TLB, + SubstTemplateTypeParmPackTypeLoc TL) { + return TransformTypeSpecType(TLB, TL); +} + +template<typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( TypeLocBuilder &TLB, TemplateSpecializationTypeLoc TL) { diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 487e23f19c..edb79ee808 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2997,6 +2997,15 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { Replacement); } + case TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK: { + unsigned Idx = 0; + QualType Parm = GetType(Record[Idx++]); + TemplateArgument ArgPack = ReadTemplateArgument(*Loc.F, Record, Idx); + return Context->getSubstTemplateTypeParmPackType( + cast<TemplateTypeParmType>(Parm), + ArgPack); + } + case TYPE_INJECTED_CLASS_NAME: { CXXRecordDecl *D = cast<CXXRecordDecl>(GetDecl(Record[0])); QualType TST = GetType(Record[1]); // probably derivable @@ -3233,6 +3242,10 @@ void TypeLocReader::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } +void TypeLocReader::VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) { + TL.setNameLoc(ReadSourceLocation(Record, Idx)); +} void TypeLocReader::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { TL.setTemplateNameLoc(ReadSourceLocation(Record, Idx)); diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index d3b103f56c..52cf3829dc 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -244,6 +244,14 @@ ASTTypeWriter::VisitSubstTemplateTypeParmType( } void +ASTTypeWriter::VisitSubstTemplateTypeParmPackType( + const SubstTemplateTypeParmPackType *T) { + Writer.AddTypeRef(QualType(T->getReplacedParameter(), 0), Record); + Writer.AddTemplateArgument(T->getArgumentPack(), Record); + Code = TYPE_SUBST_TEMPLATE_TYPE_PARM_PACK; +} + +void ASTTypeWriter::VisitTemplateSpecializationType( const TemplateSpecializationType *T) { Record.push_back(T->isDependentType()); @@ -491,6 +499,10 @@ void TypeLocWriter::VisitSubstTemplateTypeParmTypeLoc( SubstTemplateTypeParmTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } +void TypeLocWriter::VisitSubstTemplateTypeParmPackTypeLoc( + SubstTemplateTypeParmPackTypeLoc TL) { + Writer.AddSourceLocation(TL.getNameLoc(), Record); +} void TypeLocWriter::VisitTemplateSpecializationTypeLoc( TemplateSpecializationTypeLoc TL) { Writer.AddSourceLocation(TL.getTemplateNameLoc(), Record); diff --git a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp index 649c9b8ef2..ff2134dc33 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/multi-level-substitution.cpp @@ -11,3 +11,23 @@ struct X0 { void test_X0() { X0<int>().f<1, 2, 3, 4, 5>(); } + +namespace PacksAtDifferentLevels { + template<typename...> struct tuple { }; + template<typename T, typename U> struct pair { }; + + template<typename ...Types> + struct X { + template<typename> struct Inner; + + template<typename ...YTypes> + struct Inner<tuple<pair<Types, YTypes>...> > { + static const unsigned zero = sizeof...(Types) - sizeof...(YTypes); + }; + }; + + int check0[X<short, int, long>::Inner<tuple<pair<short, unsigned short>, + pair<int, unsigned int>, + pair<long, unsigned long>> + >::zero == 0? 1 : -1]; +} |