diff --git a/include/clang/AST/TemplateBase.h b/include/clang/AST/TemplateBase.h index fc1d4232d6d78b07dc217bb287d08ffa07b87375..4096dc1731f480ff8e5520df0da58f137612aade 100644 --- a/include/clang/AST/TemplateBase.h +++ b/include/clang/AST/TemplateBase.h @@ -197,6 +197,9 @@ public: /// parameter pack. bool containsUnexpandedParameterPack() const; + /// \brief Determine whether this template argument is a pack expansion. + bool isPackExpansion() const; + /// \brief Retrieve the template argument as a type. QualType getAsType() const { if (Kind != Type) @@ -409,6 +412,13 @@ public: assert(Argument.getKind() == TemplateArgument::Template); return LocInfo.getTemplateNameLoc(); } + + /// \brief When the template argument is a pack expansion, returns + /// the pattern of the pack expansion. + /// + /// \param Ellipsis Will be set to the location of the ellipsis. + TemplateArgumentLoc getPackExpansionPattern(SourceLocation &Ellipsis, + ASTContext &Context) const; }; /// A convenient class for passing around template argument diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 32bf184f6edf269d9e1bc7bb170b83cfb6836898..a6f4cc81303d3605cb1f9eb0bdc0f55dd2d8a0c2 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1855,10 +1855,16 @@ def err_unexpanded_parameter_pack_3_or_more : Error< def err_pack_expansion_without_parameter_packs : Error< "pack expansion does not contain any unexpanded parameter packs">; +def err_pack_expansion_length_conflict : Error< + "pack expansion contains parameter packs %0 and %1 that have different " + "lengths (%2 vs. %3)">; + 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_pack_expansion_mismatch_unsupported : Error< + "clang cannot yet instantiate pack expansions with mismatched pack levels">; def err_unexpected_typedef : Error< "unexpected type name %0: expected expression">; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index d47cf9862ade489139d82f3a3014dc59db277004..77ecde89e117285ce8928b24a03642b909f42afb 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -185,6 +185,11 @@ public: static bool classof(const LocInfoType *) { return true; } }; +// FIXME: No way to easily map from TemplateTypeParmTypes to +// TemplateTypeParmDecls, so we have this horrible PointerUnion. +typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, + SourceLocation> UnexpandedParameterPack; + /// Sema - This implements semantic analysis and AST building for C. class Sema { Sema(const Sema&); // DO NOT IMPLEMENT @@ -3236,6 +3241,14 @@ public: TemplateName Template, UnexpandedParameterPackContext UPPC); + /// \brief Collect the set of unexpanded parameter packs within the given + /// template argument. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// @@ -3255,6 +3268,11 @@ public: /// \param EllipsisLoc The location of the ellipsis. TypeResult ActOnPackExpansion(ParsedType Type, SourceLocation EllipsisLoc); + /// \brief Construct a pack expansion type from the pattern of the pack + /// expansion. + TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of @@ -3517,6 +3535,35 @@ public: /// to implement it anywhere else. ActiveTemplateInstantiation LastTemplateInstantiationErrorContext; + /// \brief The current index into pack expansion arguments that will be + /// used for substitution of parameter packs. + /// + /// The pack expansion index will be -1 to indicate that parameter packs + /// should be instantiated as themselves. Otherwise, the index specifies + /// which argument within the parameter pack will be used for substitution. + int ArgumentPackSubstitutionIndex; + + /// \brief RAII object used to change the argument pack substitution index + /// within a \c Sema object. + /// + /// See \c ArgumentPackSubstitutionIndex for more information. + class ArgumentPackSubstitutionIndexRAII { + Sema &Self; + int OldSubstitutionIndex; + + public: + ArgumentPackSubstitutionIndexRAII(Sema &Self, int NewSubstitutionIndex) + : Self(Self), OldSubstitutionIndex(Self.ArgumentPackSubstitutionIndex) { + Self.ArgumentPackSubstitutionIndex = NewSubstitutionIndex; + } + + ~ArgumentPackSubstitutionIndexRAII() { + Self.ArgumentPackSubstitutionIndex = OldSubstitutionIndex; + } + }; + + friend class ArgumentPackSubstitutionRAII; + /// \brief The stack of calls expression undergoing template instantiation. /// /// The top of this stack is used by a fixit instantiating unresolved diff --git a/include/clang/Sema/Template.h b/include/clang/Sema/Template.h index 38d4b9fd254131411d7dc5897a7710c78d9632aa..484d58dd0b102de8c9f5f5a1792b2478d9331222 100644 --- a/include/clang/Sema/Template.h +++ b/include/clang/Sema/Template.h @@ -242,8 +242,10 @@ namespace clang { }; class TemplateDeclInstantiator - : public DeclVisitor<TemplateDeclInstantiator, Decl *> { + : public DeclVisitor<TemplateDeclInstantiator, Decl *> + { Sema &SemaRef; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; DeclContext *Owner; const MultiLevelTemplateArgumentList &TemplateArgs; @@ -257,7 +259,8 @@ namespace clang { public: TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner, const MultiLevelTemplateArgumentList &TemplateArgs) - : SemaRef(SemaRef), Owner(Owner), TemplateArgs(TemplateArgs) { } + : SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner), + TemplateArgs(TemplateArgs) { } // FIXME: Once we get closer to completion, replace these manually-written // declarations with automatically-generated ones from @@ -347,7 +350,7 @@ namespace clang { InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, ClassTemplatePartialSpecializationDecl *PartialSpec); - }; + }; } #endif // LLVM_CLANG_SEMA_TEMPLATE_H diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index ee404852262cbb71d610457519226740dd30431f..fd1146c084dda0e854d94d6462226a264624e7aa 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -63,6 +63,29 @@ bool TemplateArgument::isDependent() const { return false; } +bool TemplateArgument::isPackExpansion() const { + switch (getKind()) { + case Null: + case Declaration: + case Integral: + case Pack: + return false; + + case Type: + return llvm::isa<PackExpansionType>(getAsType()); + + case Template: + // FIXME: Template template pack expansions. + break; + + case Expression: + // FIXME: Expansion pack expansions. + break; + } + + return false; +} + bool TemplateArgument::containsUnexpandedParameterPack() const { switch (getKind()) { case Null: @@ -265,6 +288,47 @@ SourceRange TemplateArgumentLoc::getSourceRange() const { return SourceRange(); } +TemplateArgumentLoc +TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis, + ASTContext &Context) const { + assert(Argument.isPackExpansion()); + + switch (Argument.getKind()) { + case TemplateArgument::Type: { + PackExpansionTypeLoc Expansion + = cast<PackExpansionTypeLoc>(getTypeSourceInfo()->getTypeLoc()); + Ellipsis = Expansion.getEllipsisLoc(); + + TypeLoc Pattern = Expansion.getPatternLoc(); + + // FIXME: This is horrible. We know where the source location data is for + // the pattern, and we have the pattern's type, but we are forced to copy + // them into an ASTContext because TypeSourceInfo bundles them together + // and TemplateArgumentLoc traffics in TypeSourceInfo pointers. + TypeSourceInfo *PatternTSInfo + = Context.CreateTypeSourceInfo(Pattern.getType(), + Pattern.getFullDataSize()); + memcpy(PatternTSInfo->getTypeLoc().getOpaqueData(), + Pattern.getOpaqueData(), Pattern.getFullDataSize()); + return TemplateArgumentLoc(TemplateArgument(Pattern.getType()), + PatternTSInfo); + } + + case TemplateArgument::Expression: + case TemplateArgument::Template: + // FIXME: Variadic templates. + llvm_unreachable("Expression and template pack expansions unsupported"); + + case TemplateArgument::Declaration: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return TemplateArgumentLoc(); + } + + return TemplateArgumentLoc(); +} + const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, const TemplateArgument &Arg) { switch (Arg.getKind()) { diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index fcc5370ed9e500508b1ccef53df56bee087e8b39..ca69d69959cac791ffba0e2e81e43276ffe8f79a 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -140,7 +140,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, GlobalNewDeleteDeclared(false), CompleteTranslationUnit(CompleteTranslationUnit), NumSFINAEErrors(0), SuppressAccessChecking(false), - NonInstantiationEntries(0), CurrentInstantiationScope(0), TyposCorrected(0), + NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), + CurrentInstantiationScope(0), TyposCorrected(0), AnalysisWarnings(*this) { TUScope = 0; diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 4651759398303090b090c280963fbfe0077e1799..923e7cc30f3c9bd2b5cb9ae62e8ce28b3f3e0225 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -2295,8 +2295,6 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, MultiLevelTemplateArgumentList(TemplateArgs))); if (!TempParm) return true; - - // FIXME: TempParam is leaked. } switch (Arg.getArgument().getKind()) { diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index fe9750108bf3097addc15f2b22e2ec7375c4c914..4c1b3807f71831c95d0335ae732d2ed04f805af3 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -589,7 +589,14 @@ namespace { this->Loc = Loc; this->Entity = Entity; } - + + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + bool &ShouldExpand, + unsigned &NumExpansions); + /// \brief Transform the given declaration by instantiating a reference to /// this declaration. Decl *TransformDecl(SourceLocation Loc, Decl *D); @@ -656,6 +663,79 @@ bool TemplateInstantiator::AlreadyTransformed(QualType T) { return true; } +bool TemplateInstantiator::TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + bool &ShouldExpand, + unsigned &NumExpansions) { + ShouldExpand = true; + std::pair<IdentifierInfo *, SourceLocation> FirstPack; + bool HaveFirstPack = false; + + for (unsigned I = 0; I != NumUnexpanded; ++I) { + // Compute the depth and index for this parameter pack. + unsigned Depth; + unsigned Index; + IdentifierInfo *Name; + + if (const TemplateTypeParmType *TTP + = Unexpanded[I].first.dyn_cast<const TemplateTypeParmType *>()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + Name = TTP->getName(); + } else { + NamedDecl *ND = Unexpanded[I].first.get<NamedDecl *>(); + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND)) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(ND)) { + Depth = NTTP->getDepth(); + Index = NTTP->getIndex(); + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND); + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + } + // FIXME: Variadic templates function parameter packs? + Name = ND->getIdentifier(); + } + + // If we don't have a template argument at this depth/index, then we + // cannot expand the pack expansion. Make a note of this, but we still + // want to check that any parameter packs we *do* have arguments for. + if (!TemplateArgs.hasTemplateArgument(Depth, Index)) { + ShouldExpand = false; + continue; + } + + // Determine the size of the argument pack. + unsigned NewPackSize = TemplateArgs(Depth, Index).pack_size(); + if (!HaveFirstPack) { + // The is the first pack we've seen for which we have an argument. + // Record it. + NumExpansions = NewPackSize; + FirstPack.first = Name; + FirstPack.second = Unexpanded[I].second; + HaveFirstPack = true; + continue; + } + + if (NewPackSize != NumExpansions) { + // C++0x [temp.variadic]p5: + // All of the parameter packs expanded by a pack expansion shall have + // the same number of arguments specified. + getSema().Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << NumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second); + return true; + } + } + + return false; +} + Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { if (!D) return 0; @@ -670,6 +750,7 @@ Decl *TemplateInstantiator::TransformDecl(SourceLocation Loc, Decl *D) { TTP->getPosition())) return D; + // FIXME: Variadic templates index substitution. TemplateName Template = TemplateArgs(TTP->getDepth(), TTP->getPosition()).getAsTemplate(); assert(!Template.isNull() && Template.getAsTemplateDecl() && @@ -702,6 +783,7 @@ TemplateInstantiator::TransformFirstQualifierInScope(NamedDecl *D, const TemplateTypeParmType *TTP = cast<TemplateTypeParmType>(getSema().Context.getTypeDeclType(TTPD)); if (TTP->getDepth() < TemplateArgs.getNumLevels()) { + // FIXME: Variadic templates index substitution. QualType T = TemplateArgs(TTP->getDepth(), TTP->getIndex()).getAsType(); if (T.isNull()) return cast_or_null<NamedDecl>(TransformDecl(Loc, D)); @@ -844,6 +926,7 @@ ExprResult TemplateInstantiator::TransformDeclRefExpr(DeclRefExpr *E) { NamedDecl *D = E->getDecl(); if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) { + // FIXME: Variadic templates index substitution. if (NTTP->getDepth() < TemplateArgs.getNumLevels()) return TransformTemplateParmRefExpr(E, NTTP); @@ -895,12 +978,26 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, return TL.getType(); } - assert(TemplateArgs(T->getDepth(), T->getIndex()).getKind() - == TemplateArgument::Type && + TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); + + if (T->isParameterPack()) { + assert(Arg.getKind() == TemplateArgument::Pack && + "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(); + } + + Arg = Arg.pack_begin()[getSema().ArgumentPackSubstitutionIndex]; + } + + assert(Arg.getKind() == TemplateArgument::Type && "Template argument kind mismatch"); - QualType Replacement - = TemplateArgs(T->getDepth(), T->getIndex()).getAsType(); + QualType Replacement = Arg.getAsType(); // TODO: only do this uniquing once, at the start of instantiation. QualType Result diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 321f38397d5d5d55dd68cdec9246331f3cdf700c..e71c2334ca555f3827565bfbba699a37cc55369f 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -12,6 +12,7 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/SemaInternal.h" +#include "clang/Sema/Template.h" #include "clang/AST/Expr.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/TypeLoc.h" @@ -22,11 +23,6 @@ using namespace clang; // Visitor that collects unexpanded parameter packs //---------------------------------------------------------------------------- -// FIXME: No way to easily map from TemplateTypeParmTypes to -// TemplateTypeParmDecls, so we have this horrible PointerUnion. -typedef std::pair<llvm::PointerUnion<const TemplateTypeParmType*, NamedDecl*>, - SourceLocation> UnexpandedParameterPack; - namespace { /// \brief A class that collects unexpanded parameter packs. class CollectUnexpandedParameterPacksVisitor : @@ -255,6 +251,12 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc, return true; } +void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded) + .TraverseTemplateArgumentLoc(Arg); +} + ParsedTemplateArgument Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc) { @@ -292,25 +294,34 @@ TypeResult Sema::ActOnPackExpansion(ParsedType Type, if (!TSInfo) return true; + TypeSourceInfo *TSResult = CheckPackExpansion(TSInfo, EllipsisLoc); + if (!TSResult) + return true; + + return CreateParsedType(TSResult->getType(), TSResult); +} + +TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern, + SourceLocation EllipsisLoc) { // 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()) { + if (!Pattern->getType()->containsUnexpandedParameterPack()) { Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) - << TSInfo->getTypeLoc().getSourceRange(); - return true; + << Pattern->getTypeLoc().getSourceRange(); + return 0; } - + // Create the pack expansion type and source-location information. - QualType Result = Context.getPackExpansionType(TSInfo->getType()); + QualType Result = Context.getPackExpansionType(Pattern->getType()); TypeSourceInfo *TSResult = Context.CreateTypeSourceInfo(Result); PackExpansionTypeLoc TL = cast<PackExpansionTypeLoc>(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); + Pattern->getTypeLoc().getOpaqueData(), + Pattern->getTypeLoc().getFullDataSize()); + return TSResult; } diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 55388129f4ab0e245b2654773d98e75dc8b10f7d..fc0b749828f942ddbbde7b8bb221894b11d24682 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -15,6 +15,7 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" @@ -90,10 +91,11 @@ template<typename Derived> class TreeTransform { protected: Sema &SemaRef; - + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; + public: /// \brief Initializes a new tree transformer. - TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } + TreeTransform(Sema &SemaRef) : SemaRef(SemaRef), SubstIndex(SemaRef, -1) { } /// \brief Retrieves a reference to the derived class. Derived &getDerived() { return static_cast<Derived&>(*this); } @@ -180,6 +182,47 @@ public: return E->isDefaultArgument(); } + /// \brief Determine whether we should expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// By default, the transformed never tries to expand pack expansions. + /// Subclasses can override this routine to provide different behavior. + /// + /// \param EllipsisLoc The location of the ellipsis that identifies the + /// pack expansion. + /// + /// \param PatternRange The source range that covers the entire pattern of + /// the pack expansion. + /// + /// \param Unexpanded The set of unexpanded parameter packs within the + /// pattern. + /// + /// \param NumUnexpanded The number of unexpanded parameter packs in + /// \p Unexpanded. + /// + /// \param ShouldExpand Will be set to \c true if the transformer should + /// expand the corresponding pack expansions into separate arguments. When + /// set, \c NumExpansions must also be set. + /// + /// \param NumExpansions The number of separate arguments that will be in + /// the expanded form of the corresponding pack expansion. Must be set when + /// \c ShouldExpand is \c true. + /// + /// \returns true if an error occurred (e.g., because the parameter packs + /// are to be instantiated with arguments of different lengths), false + /// otherwise. If false, \c ShouldExpand (and possibly \c NumExpansions) + /// must be set. + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + bool &ShouldExpand, + unsigned &NumExpansions) { + ShouldExpand = false; + return false; + } + /// \brief Transforms the given type into another type. /// /// By default, this routine transforms a type by creating a @@ -2018,6 +2061,36 @@ public: return move(Result); } + /// \brief Build a new template argument pack expansion. + /// + /// By default, performs semantic analysis to build a new pack expansion + /// for a template argument. Subclasses may override this routine to provide + /// different behavior. + TemplateArgumentLoc RebuildPackExpansion(TemplateArgumentLoc Pattern, + SourceLocation EllipsisLoc) { + switch (Pattern.getArgument().getKind()) { + case TemplateArgument::Expression: + case TemplateArgument::Template: + llvm_unreachable("Unsupported pack expansion of expressions/templates"); + + case TemplateArgument::Null: + case TemplateArgument::Integral: + case TemplateArgument::Declaration: + case TemplateArgument::Pack: + llvm_unreachable("Pack expansion pattern has no parameter packs"); + + case TemplateArgument::Type: + if (TypeSourceInfo *Expansion + = getSema().CheckPackExpansion(Pattern.getTypeSourceInfo(), + EllipsisLoc)) + return TemplateArgumentLoc(TemplateArgument(Expansion->getType()), + Expansion); + break; + } + + return TemplateArgumentLoc(); + } + private: QualType TransformTypeInObjectScope(QualType T, QualType ObjectType, @@ -2457,7 +2530,86 @@ bool TreeTransform<Derived>::TransformTemplateArgumentsFromArgLoc( TemplateArgumentListInfo &Outputs) { for (unsigned I = 0, N = Inputs.getNumArgs(); I != N; ++I) { TemplateArgumentLoc Out; - if (getDerived().TransformTemplateArgument(Inputs.getArgLoc(I), Out)) + TemplateArgumentLoc In = Inputs.getArgLoc(I); + + if (In.getArgument().getKind() == TemplateArgument::Pack) { + // Unpack argument packs, which we translate them into separate + // arguments. + // FIXME: It would be far better to make this a recursive call using + // some kind of argument-pack adaptor. + for (TemplateArgument::pack_iterator P = In.getArgument().pack_begin(), + PEnd = In.getArgument().pack_end(); + P != PEnd; ++P) { + TemplateArgumentLoc PLoc; + + // FIXME: We could do much better if we could guarantee that the + // TemplateArgumentLocInfo for the pack expansion would be usable for + // all of the template arguments in the argument pack. + getDerived().InventTemplateArgumentLoc(*P, PLoc); + if (getDerived().TransformTemplateArgument(PLoc, Out)) + return true; + + Outputs.addArgument(Out); + } + + continue; + } + + if (In.getArgument().isPackExpansion()) { + // We have a pack expansion, for which we will be substituting into + // the pattern. + SourceLocation Ellipsis; + TemplateArgumentLoc Pattern + = In.getPackExpansionPattern(Ellipsis, getSema().Context); + + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + unsigned NumExpansions = 0; + if (getDerived().TryExpandParameterPacks(Ellipsis, + Pattern.getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + Expand, NumExpansions)) + return true; + + if (!Expand) { + // The transform has determined that we should perform a simple + // transformation on the pack expansion, producing another pack + // expansion. + TemplateArgumentLoc OutPattern; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + if (getDerived().TransformTemplateArgument(Pattern, OutPattern)) + return true; + + Out = getDerived().RebuildPackExpansion(OutPattern, Ellipsis); + if (Out.getArgument().isNull()) + return true; + + Outputs.addArgument(Out); + continue; + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + for (unsigned I = 0; I != NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + + if (getDerived().TransformTemplateArgument(Pattern, Out)) + return true; + + Outputs.addArgument(Out); + } + + continue; + } + + // The simple case: + if (getDerived().TransformTemplateArgument(In, Out)) return true; Outputs.addArgument(Out); @@ -3738,9 +3890,8 @@ TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { // Convert the condition to a boolean value. if (S->getCond()) { - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getIfLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getIfLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); @@ -3834,9 +3985,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { if (S->getCond()) { // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getWhileLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getWhileLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); Cond = CondE; @@ -3912,9 +4062,8 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (S->getCond()) { // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(0, - S->getForLoc(), - Cond.get()); + ExprResult CondE = getSema().ActOnBooleanCondition(0, S->getForLoc(), + Cond.get()); if (CondE.isInvalid()) return StmtError(); diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp new file mode 100644 index 0000000000000000000000000000000000000000..47883fe423c23ab2650d5af8046c8b1c433c87bf --- /dev/null +++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template<typename... Types> struct Tuple; + +// FIXME: Many more bullets to go + +// In a template-argument-list (14.3); the pattern is a template-argument. +template<typename ...Types> +struct tuple_of_refs { + typedef Tuple<Types& ...> types; +}; + +Tuple<int&, float&> *t_int_ref_float_ref; +tuple_of_refs<int&, float&>::types *t_int_ref_float_ref_2 = t_int_ref_float_ref; + diff --git a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp index 8fef90fbc2bf0b523d14f350043b91a28455a753..94d874fc8d77606a039cdac3e0f43c8a93f961ff 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p5.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p5.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -std=c++0x -fblocks -fsyntax-only -verify %s template<typename T, typename U> struct pair; +template<typename ...> struct tuple; // A parameter pack whose name appears within the pattern of a pack // expansion is expanded by that pack expansion. An appearance of the @@ -15,6 +16,24 @@ struct Expansion { typedef pair<pair<Types..., int>..., int> expand_with_expanded_nested; // expected-error{{pack expansion does not contain any unexpanded parameter packs}} }; +// All of the parameter packs expanded by a pack expansion shall have +// the same number of arguments specified. +template<typename ...Types> +struct ExpansionLengthMismatch { + template<typename ...OtherTypes> + struct Inner { + typedef tuple<pair<Types, OtherTypes>...> type; // expected-error{{pack expansion contains parameter packs 'Types' and 'OtherTypes' that have different lengths (3 vs. 2)}} + }; +}; + +ExpansionLengthMismatch<int, long>::Inner<unsigned int, unsigned long>::type + *il_pairs; +tuple<pair<int, unsigned int>, pair<long, unsigned long> >*il_pairs_2 = il_pairs; + +ExpansionLengthMismatch<short, int, long>::Inner<unsigned int, unsigned long>::type // expected-note{{in instantiation of}} + *il_pairs_bad; + + // An appearance of a name of a parameter pack that is not expanded is // ill-formed.