From: Douglas Gregor Date: Mon, 20 Dec 2010 02:24:11 +0000 (+0000) Subject: Introduce a new type, PackExpansionType, to capture types that are X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7536dd5e6c99584481b7dab68b7e7d8df9c54054;p=clang Introduce a new type, PackExpansionType, to capture types that are pack expansions, e.g. given template struct tuple; template struct tuple_of_refs { typedef tuple types; }; the type of the "types" typedef is a PackExpansionType whose pattern is Types&. This commit introduces support for creating pack expansions for template type arguments, as above, but not for any other kind of pack expansion, nor for any form of instantiation. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122223 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 5d2bfb29c5..aee1612948 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -106,6 +106,7 @@ class ASTContext { llvm::FoldingSet DependentNameTypes; llvm::ContextualFoldingSet DependentTemplateSpecializationTypes; + llvm::FoldingSet PackExpansionTypes; llvm::FoldingSet ObjCObjectTypes; llvm::FoldingSet ObjCObjectPointerTypes; @@ -697,6 +698,8 @@ public: unsigned NumArgs, const TemplateArgument *Args); + QualType getPackExpansionType(QualType Pattern); + QualType getObjCInterfaceType(const ObjCInterfaceDecl *Decl); QualType getObjCObjectType(QualType Base, diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 2fd540a0be..263b006581 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -738,6 +738,10 @@ DEF_TRAVERSE_TYPE(DependentTemplateSpecializationType, { TRY_TO(TraverseTemplateArguments(T->getArgs(), T->getNumArgs())); }) +DEF_TRAVERSE_TYPE(PackExpansionType, { + TRY_TO(TraverseType(T->getPattern())); + }) + DEF_TRAVERSE_TYPE(ObjCInterfaceType, { }) DEF_TRAVERSE_TYPE(ObjCObjectType, { @@ -943,6 +947,10 @@ DEF_TRAVERSE_TYPELOC(DependentTemplateSpecializationType, { } }) +DEF_TRAVERSE_TYPELOC(PackExpansionType, { + TRY_TO(TraverseTypeLoc(TL.getPatternLoc())); + }) + DEF_TRAVERSE_TYPELOC(ObjCInterfaceType, { }) DEF_TRAVERSE_TYPELOC(ObjCObjectType, { diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 4c3a295ccb..f4898486e7 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -92,7 +92,6 @@ namespace clang { class TemplateArgument; class TemplateArgumentLoc; class TemplateArgumentListInfo; - class Type; class ElaboratedType; struct PrintingPolicy; @@ -3191,6 +3190,65 @@ public: } }; +/// \brief Represents a pack expansion of types. +/// +/// Pack expansions are part of C++0x variadic templates. A pack +/// expansion contains a pattern, which itself contains one or more +/// "unexpanded" parameter packs. When instantiated, a pack expansion +/// produces a series of types, each instantiated from the pattern of +/// the expansion, where the Ith instantiation of the pattern uses the +/// Ith arguments bound to each of the unexpanded parameter packs. The +/// pack expansion is considered to "expand" these unexpanded +/// parameter packs. +/// +/// \code +/// template struct tuple; +/// +/// template +/// struct tuple_of_references { +/// typedef tuple type; +/// }; +/// \endcode +/// +/// Here, the pack expansion \c Types&... is represented via a +/// PackExpansionType whose pattern is Types&. +class PackExpansionType : public Type, public llvm::FoldingSetNode { + /// \brief The pattern of the pack expansion. + QualType Pattern; + + PackExpansionType(QualType Pattern, QualType Canon) + : Type(PackExpansion, Canon, /*Dependent=*/true, + /*VariableModified=*/Pattern->isVariablyModifiedType(), + /*ContainsUnexpandedParameterPack=*/false), + Pattern(Pattern) { } + + friend class ASTContext; // ASTContext creates these + +public: + /// \brief Retrieve the pattern of this pack expansion, which is the + /// type that will be repeatedly instantiated when instantiating the + /// pack expansion itself. + QualType getPattern() const { return Pattern; } + + bool isSugared() const { return false; } + QualType desugar() const { return QualType(this, 0); } + + void Profile(llvm::FoldingSetNodeID &ID) { + Profile(ID, getPattern()); + } + + static void Profile(llvm::FoldingSetNodeID &ID, QualType Pattern) { + ID.AddPointer(Pattern.getAsOpaquePtr()); + } + + static bool classof(const Type *T) { + return T->getTypeClass() == PackExpansion; + } + static bool classof(const PackExpansionType *T) { + return true; + } +}; + /// ObjCObjectType - Represents a class type in Objective C. /// Every Objective C type is a combination of a base type and a /// list of protocols. diff --git a/include/clang/AST/TypeLoc.h b/include/clang/AST/TypeLoc.h index 5b695d0891..aecc0c4e71 100644 --- a/include/clang/AST/TypeLoc.h +++ b/include/clang/AST/TypeLoc.h @@ -1446,6 +1446,40 @@ private: } }; + +struct PackExpansionTypeLocInfo { + SourceLocation EllipsisLoc; +}; + +class PackExpansionTypeLoc + : public ConcreteTypeLoc { +public: + SourceLocation getEllipsisLoc() const { + return this->getLocalData()->EllipsisLoc; + } + + void setEllipsisLoc(SourceLocation Loc) { + this->getLocalData()->EllipsisLoc = Loc; + } + + SourceRange getLocalSourceRange() const { + return SourceRange(getEllipsisLoc(), getEllipsisLoc()); + } + + void initializeLocal(SourceLocation Loc) { + setEllipsisLoc(Loc); + } + + TypeLoc getPatternLoc() const { + return getInnerTypeLoc(); + } + + QualType getInnerType() const { + return this->getTypePtr()->getPattern(); + } +}; + } #endif diff --git a/include/clang/AST/TypeNodes.def b/include/clang/AST/TypeNodes.def index 5355af1c08..4e25b94c52 100644 --- a/include/clang/AST/TypeNodes.def +++ b/include/clang/AST/TypeNodes.def @@ -94,6 +94,7 @@ NON_CANONICAL_UNLESS_DEPENDENT_TYPE(TemplateSpecialization, Type) DEPENDENT_TYPE(InjectedClassName, Type) DEPENDENT_TYPE(DependentName, Type) DEPENDENT_TYPE(DependentTemplateSpecialization, Type) +DEPENDENT_TYPE(PackExpansion, Type) TYPE(ObjCObject, Type) TYPE(ObjCInterface, ObjCObjectType) TYPE(ObjCObjectPointer, Type) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b616cd9a3c..8dfc391ee3 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1853,6 +1853,13 @@ def err_unexpanded_parameter_pack_3_or_more : Error< "non-type template parameter type|exception type}0 " "contains unexpanded parameter packs %1, %2, ...">; +def err_pack_expansion_without_parameter_packs : Error< + "pack expansion does not contain any unexpanded parameter packs">; +def err_pack_expansion_unsupported : Error< + "clang does not yet support %select{non-type|template}0 pack expansions">; +def err_pack_expansion_instantiation_unsupported : Error< + "clang cannot yet instantiate pack expansions">; + def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; def err_unexpected_namespace : Error< diff --git a/include/clang/Sema/ParsedTemplate.h b/include/clang/Sema/ParsedTemplate.h index 9d814c712d..6a60ab1294 100644 --- a/include/clang/Sema/ParsedTemplate.h +++ b/include/clang/Sema/ParsedTemplate.h @@ -32,7 +32,9 @@ namespace clang { Template }; - /// \brief Build an empty template argument. This template argument + /// \brief Build an empty template argument. + /// + /// This template argument is invalid. ParsedTemplateArgument() : Kind(Type), Arg(0) { } /// \brief Create a template type argument or non-type template argument. diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index ed0d747d2f..d47cf9862a 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3236,6 +3236,25 @@ public: TemplateName Template, UnexpandedParameterPackContext UPPC); + /// \brief Invoked when parsing a template argument followed by an + /// ellipsis, which creates a pack expansion. + /// + /// \param Arg The template argument preceding the ellipsis, which + /// may already be invalid. + /// + /// \param EllipsisLoc The location of the ellipsis. + ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc); + + /// \brief Invoked when parsing a type follows by an ellipsis, which + /// creates a pack expansion. + /// + /// \param Type The type preceding the ellipsis, which will become + /// the pattern of the pack expansion. + /// + /// \param EllipsisLoc The location of the ellipsis. + TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index d32cc2717b..8665fb6465 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -551,7 +551,9 @@ namespace clang { /// \brief A DependentSizedArrayType record. TYPE_DEPENDENT_SIZED_ARRAY = 33, /// \brief A ParenType record. - TYPE_PAREN = 34 + TYPE_PAREN = 34, + /// \brief A PackExpansionType record. + TYPE_PACK_EXPANSION = 35 }; /// \brief The type IDs for special types constructed by semantic diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index e9d8c0f304..94038418df 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2216,6 +2216,32 @@ ASTContext::getDependentTemplateSpecializationType( return QualType(T, 0); } +QualType ASTContext::getPackExpansionType(QualType Pattern) { + llvm::FoldingSetNodeID ID; + PackExpansionType::Profile(ID, Pattern); + + assert(Pattern->containsUnexpandedParameterPack() && + "Pack expansions must expand one or more parameter packs"); + void *InsertPos = 0; + PackExpansionType *T + = PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + if (T) + return QualType(T, 0); + + QualType Canon; + if (!Pattern.isCanonical()) { + Canon = getPackExpansionType(getCanonicalType(Pattern)); + + // Find the insert position again. + PackExpansionTypes.FindNodeOrInsertPos(ID, InsertPos); + } + + T = new (*this) PackExpansionType(Pattern, Canon); + Types.push_back(T); + PackExpansionTypes.InsertNode(T, InsertPos); + return QualType(T, 0); +} + /// CmpProtocolNames - Comparison predicate for sorting protocols /// alphabetically. static bool CmpProtocolNames(const ObjCProtocolDecl *LHS, diff --git a/lib/AST/ASTImporter.cpp b/lib/AST/ASTImporter.cpp index cc485c47d9..7ff217e334 100644 --- a/lib/AST/ASTImporter.cpp +++ b/lib/AST/ASTImporter.cpp @@ -707,7 +707,14 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, } break; } - + + case Type::PackExpansion: + if (!IsStructurallyEquivalent(Context, + cast(T1)->getPattern(), + cast(T2)->getPattern())) + return false; + break; + case Type::ObjCInterface: { const ObjCInterfaceType *Iface1 = cast(T1); const ObjCInterfaceType *Iface2 = cast(T2); diff --git a/lib/AST/TypePrinter.cpp b/lib/AST/TypePrinter.cpp index 15c3fb2fbf..e12d7e0185 100644 --- a/lib/AST/TypePrinter.cpp +++ b/lib/AST/TypePrinter.cpp @@ -36,7 +36,7 @@ namespace { void printTag(TagDecl *T, std::string &S); #define ABSTRACT_TYPE(CLASS, PARENT) #define TYPE(CLASS, PARENT) \ - void print##CLASS(const CLASS##Type *T, std::string &S); + void print##CLASS(const CLASS##Type *T, std::string &S); #include "clang/AST/TypeNodes.def" }; } @@ -668,6 +668,12 @@ void TypePrinter::printDependentTemplateSpecialization( S = MyString + ' ' + S; } +void TypePrinter::printPackExpansion(const PackExpansionType *T, + std::string &S) { + print(T->getPattern(), S); + S += "..."; +} + void TypePrinter::printObjCInterface(const ObjCInterfaceType *T, std::string &S) { if (!S.empty()) // Prefix the basic type, e.g. 'typedefname X'. diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index 026f6ba3ff..4659831a66 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -1474,6 +1474,12 @@ void CXXNameMangler::mangleType(const DependentSizedExtVectorType *T) { mangleType(T->getElementType()); } +void CXXNameMangler::mangleType(const PackExpansionType *T) { + // FIXME: We may need to push this mangling into the callers + Out << "sp"; + mangleType(T->getPattern()); +} + void CXXNameMangler::mangleType(const ObjCInterfaceType *T) { mangleSourceName(T->getDecl()->getIdentifier()); } diff --git a/lib/CodeGen/MicrosoftCXXABI.cpp b/lib/CodeGen/MicrosoftCXXABI.cpp index dd2f1cb134..aa9046f981 100644 --- a/lib/CodeGen/MicrosoftCXXABI.cpp +++ b/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1140,6 +1140,10 @@ void MicrosoftCXXNameMangler::mangleType( "Don't know how to mangle DependentTemplateSpecializationTypes yet!"); } +void MicrosoftCXXNameMangler::mangleType(const PackExpansionType *T) { + assert(false && "Don't know how to mangle PackExpansionTypes yet!"); +} + void MicrosoftCXXNameMangler::mangleType(const TypeOfType *T) { assert(false && "Don't know how to mangle TypeOfTypes yet!"); } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 333d72a754..d38d0599ac 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -1045,6 +1045,11 @@ bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { while (true) { ParsedTemplateArgument Arg = ParseTemplateArgument(); + if (Tok.is(tok::ellipsis)) { + SourceLocation EllipsisLoc = ConsumeToken(); + Arg = Actions.ActOnPackExpansion(Arg, EllipsisLoc); + } + if (Arg.isInvalid()) { SkipUntil(tok::comma, tok::greater, true, true); return true; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 5819362e76..36bb76fdb3 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2386,6 +2386,7 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, // If we have a template parameter pack, check every remaining template // argument against that template parameter pack. + // FIXME: Variadic templates are unimplemented if ((*Param)->isTemplateParameterPack()) { Diag(TemplateLoc, diag::err_variadic_templates_unsupported); return true; @@ -2640,6 +2641,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType( return VisitNestedNameSpecifier(T->getQualifier()); } +bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType( + const PackExpansionType* T) { + return Visit(T->getPattern()); +} + bool UnnamedLocalNoLinkageFinder::VisitObjCObjectType(const ObjCObjectType *) { return false; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index da04b62198..d4e99e8ad9 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2815,6 +2815,12 @@ MarkUsedTemplateParameters(Sema &SemaRef, QualType T, OnlyDeduced, Depth, Used); break; + case Type::PackExpansion: + MarkUsedTemplateParameters(SemaRef, + cast(T)->getPattern(), + OnlyDeduced, Depth, Used); + break; + // None of these types have any template parameters in them. case Type::Builtin: case Type::VariableArray: diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index f190b3c774..321f38397d 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -10,6 +10,7 @@ //===----------------------------------------------------------------------===/ #include "clang/Sema/Sema.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" @@ -254,3 +255,62 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, return true; } +ParsedTemplateArgument +Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, + SourceLocation EllipsisLoc) { + if (Arg.isInvalid()) + return Arg; + + switch (Arg.getKind()) { + case ParsedTemplateArgument::Type: { + TypeResult Result = ActOnPackExpansion(Arg.getAsType(), EllipsisLoc); + if (Result.isInvalid()) + return ParsedTemplateArgument(); + + return ParsedTemplateArgument(Arg.getKind(), Result.get().getAsOpaquePtr(), + Arg.getLocation()); + } + + case ParsedTemplateArgument::NonType: + Diag(EllipsisLoc, diag::err_pack_expansion_unsupported) + << 0; + return ParsedTemplateArgument(); + + case ParsedTemplateArgument::Template: + Diag(EllipsisLoc, diag::err_pack_expansion_unsupported) + << 1; + return ParsedTemplateArgument(); + } + llvm_unreachable("Unhandled template argument kind?"); + return ParsedTemplateArgument(); +} + +TypeResult Sema::ActOnPackExpansion(ParsedType Type, + SourceLocation EllipsisLoc) { + TypeSourceInfo *TSInfo; + GetTypeFromParser(Type, &TSInfo); + if (!TSInfo) + return true; + + // C++0x [temp.variadic]p5: + // The pattern of a pack expansion shall name one or more + // parameter packs that are not expanded by a nested pack + // expansion. + if (!TSInfo->getType()->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << TSInfo->getTypeLoc().getSourceRange(); + return true; + } + + // Create the pack expansion type and source-location information. + QualType Result = Context.getPackExpansionType(TSInfo->getType()); + TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result); + PackExpansionTypeLoc TL = cast(TSResult->getTypeLoc()); + TL.setEllipsisLoc(EllipsisLoc); + + // Copy over the source-location information from the type. + memcpy(TL.getNextTypeLoc().getOpaqueData(), + TSInfo->getTypeLoc().getOpaqueData(), + TSInfo->getTypeLoc().getFullDataSize()); + return CreateParsedType(Result, TSResult); +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index f4a4ae28cf..a90ea39325 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -3505,6 +3505,15 @@ QualType TreeTransform:: return Result; } +template +QualType TreeTransform::TransformPackExpansionType(TypeLocBuilder &TLB, + PackExpansionTypeLoc TL) { + // FIXME: Implement! + getSema().Diag(TL.getEllipsisLoc(), + diag::err_pack_expansion_instantiation_unsupported); + return QualType(); +} + template QualType TreeTransform::TransformObjCInterfaceType(TypeLocBuilder &TLB, diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index 724ebdf96c..72360e7416 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -2930,6 +2930,18 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { return Context->getParenType(InnerType); } + case TYPE_PACK_EXPANSION: { + if (Record.size() != 1) { + Error("incorrect encoding of pack expansion type"); + return QualType(); + } + QualType Pattern = GetType(Record[0]); + if (Pattern.isNull()) + return QualType(); + + return Context->getPackExpansionType(Pattern); + } + case TYPE_ELABORATED: { unsigned Idx = 0; ElaboratedTypeKeyword Keyword = (ElaboratedTypeKeyword)Record[Idx++]; @@ -3229,6 +3241,9 @@ void TypeLocReader::VisitDependentTemplateSpecializationTypeLoc( TL.getTypePtr()->getArg(I).getKind(), Record, Idx)); } +void TypeLocReader::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + TL.setEllipsisLoc(ReadSourceLocation(Record, Idx)); +} void TypeLocReader::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { TL.setNameLoc(ReadSourceLocation(Record, Idx)); } diff --git a/lib/Serialization/ASTWriter.cpp b/lib/Serialization/ASTWriter.cpp index 26a54b1d55..345cc8e74c 100644 --- a/lib/Serialization/ASTWriter.cpp +++ b/lib/Serialization/ASTWriter.cpp @@ -298,6 +298,11 @@ ASTTypeWriter::VisitDependentTemplateSpecializationType( Code = TYPE_DEPENDENT_TEMPLATE_SPECIALIZATION; } +void ASTTypeWriter::VisitPackExpansionType(const PackExpansionType *T) { + Writer.AddTypeRef(T->getPattern(), Record); + Code = TYPE_PACK_EXPANSION; +} + void ASTTypeWriter::VisitParenType(const ParenType *T) { Writer.AddTypeRef(T->getInnerType(), Record); Code = TYPE_PAREN; @@ -499,6 +504,9 @@ void TypeLocWriter::VisitDependentTemplateSpecializationTypeLoc( Writer.AddTemplateArgumentLocInfo(TL.getArgLoc(I).getArgument().getKind(), TL.getArgLoc(I).getLocInfo(), Record); } +void TypeLocWriter::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + Writer.AddSourceLocation(TL.getEllipsisLoc(), Record); +} void TypeLocWriter::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { Writer.AddSourceLocation(TL.getNameLoc(), Record); } diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 259a862cf8..8fef90fbc2 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -1,11 +1,23 @@ // RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s +template struct pair; + +// A parameter pack whose name appears within the pattern of a pack +// expansion is expanded by that pack expansion. An appearance of the +// name of a parameter pack is only expanded by the innermost +// enclosing pack expansion. The pattern of a pack expansion shall +// name one or more parameter packs that are not expanded by a nested +// pack expansion. +template +struct Expansion { + typedef pair expand_with_pacs; // okay + typedef pair expand_no_packs; // expected-error{{pack expansion does not contain any unexpanded parameter packs}} + typedef pair..., int> expand_with_expanded_nested; // expected-error{{pack expansion does not contain any unexpanded parameter packs}} +}; // An appearance of a name of a parameter pack that is not expanded is // ill-formed. -template struct pair; - // Test for unexpanded parameter packs in each of the type nodes. template struct TestPPName diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index c8dbf3b588..ca6efe8d88 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -338,6 +338,7 @@ public: // FIXME: Implement visitors here when the unimplemented TypeLocs get // implemented bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); + bool VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL); bool VisitTypeOfTypeLoc(TypeOfTypeLoc TL); // Data-recursive visitor functions. @@ -1435,6 +1436,10 @@ bool CursorVisitor::VisitTypeOfTypeLoc(TypeOfTypeLoc TL) { return false; } +bool CursorVisitor::VisitPackExpansionTypeLoc(PackExpansionTypeLoc TL) { + return Visit(TL.getPatternLoc()); +} + bool CursorVisitor::VisitCXXRecordDecl(CXXRecordDecl *D) { if (D->isDefinition()) { for (CXXRecordDecl::base_class_iterator I = D->bases_begin(),