From b99268b3083c882103bd1bd08bdcc9a76a2b4795 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 21 Dec 2010 00:52:54 +0000 Subject: [PATCH] Implement instantiation of pack expansions whose pattern is a type-id in an exception specification. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122297 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 46 ++++++++++- lib/Sema/SemaTemplateInstantiate.cpp | 82 ++----------------- lib/Sema/SemaTemplateInstantiateDecl.cpp | 55 +++++++++++++ lib/Sema/SemaTemplateVariadic.cpp | 80 ++++++++++++++++++ lib/Sema/TreeTransform.h | 5 +- test/CXX/temp/temp.decls/temp.variadic/p4.cpp | 12 +-- 6 files changed, 196 insertions(+), 84 deletions(-) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 24f1b217e0..ad96c675e2 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -3249,7 +3249,15 @@ public: /// unexpanded parameter packs. void collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, llvm::SmallVectorImpl &Unexpanded); - + + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param Arg The template argument that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(QualType T, + llvm::SmallVectorImpl &Unexpanded); + /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// @@ -3274,6 +3282,42 @@ public: TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern, SourceLocation EllipsisLoc); + /// \brief Determine whether we could expand a pack expansion with the + /// given set of parameter packs into separate arguments by repeatedly + /// transforming the pattern. + /// + /// \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 CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + unsigned &NumExpansions); + /// \brief Describes the result of template argument deduction. /// /// The TemplateDeductionResult enumeration describes the result of diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 95ccae28f5..37d8d8cb53 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -595,7 +595,14 @@ namespace { const UnexpandedParameterPack *Unexpanded, unsigned NumUnexpanded, bool &ShouldExpand, - unsigned &NumExpansions); + unsigned &NumExpansions) { + return getSema().CheckParameterPacksForExpansion(EllipsisLoc, + PatternRange, Unexpanded, + NumUnexpanded, + TemplateArgs, + ShouldExpand, + NumExpansions); + } /// \brief Transform the given declaration by instantiating a reference to /// this declaration. @@ -663,79 +670,6 @@ 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 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()) { - Depth = TTP->getDepth(); - Index = TTP->getIndex(); - Name = TTP->getName(); - } else { - NamedDecl *ND = Unexpanded[I].first.get(); - if (TemplateTypeParmDecl *TTP = dyn_cast(ND)) { - Depth = TTP->getDepth(); - Index = TTP->getIndex(); - } else if (NonTypeTemplateParmDecl *NTTP - = dyn_cast(ND)) { - Depth = NTTP->getDepth(); - Index = NTTP->getIndex(); - } else { - TemplateTemplateParmDecl *TTP = cast(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; diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index b6ef498874..115cdc4545 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -1983,6 +1983,61 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, llvm::SmallVector Exceptions; for (unsigned I = 0, N = Proto->getNumExceptions(); I != N; ++I) { // FIXME: Poor location information! + if (const PackExpansionType *PackExpansion + = Proto->getExceptionType(I)->getAs()) { + // We have a pack expansion. Instantiate it. + llvm::SmallVector Unexpanded; + SemaRef.collectUnexpandedParameterPacks(PackExpansion->getPattern(), + Unexpanded); + assert(!Unexpanded.empty() && + "Pack expansion without parameter packs?"); + + bool Expand = false; + unsigned NumExpansions = 0; + if (SemaRef.CheckParameterPacksForExpansion(New->getLocation(), + SourceRange(), + Unexpanded.data(), + Unexpanded.size(), + TemplateArgs, + Expand, NumExpansions)) + break; + + if (!Expand) { + // We can't expand this pack expansion into separate arguments yet; + // just substitute into the argument pack. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) + break; + + Exceptions.push_back(T); + continue; + } + + // Substitute into the pack expansion pattern for each template + bool Invalid = false; + for (unsigned ArgIdx = 0; ArgIdx != NumExpansions; ++ArgIdx) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, ArgIdx); + + QualType T = SemaRef.SubstType(PackExpansion->getPattern(), + TemplateArgs, + New->getLocation(), New->getDeclName()); + if (T.isNull()) { + Invalid = true; + break; + } + + Exceptions.push_back(T); + } + + if (Invalid) + break; + + continue; + } + QualType T = SemaRef.SubstType(Proto->getExceptionType(I), TemplateArgs, New->getLocation(), New->getDeclName()); diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 681bc8d072..f2651ef65c 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -259,6 +259,11 @@ void Sema::collectUnexpandedParameterPacks(TemplateArgumentLoc Arg, .TraverseTemplateArgumentLoc(Arg); } +void Sema::collectUnexpandedParameterPacks(QualType T, + llvm::SmallVectorImpl &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); +} + ParsedTemplateArgument Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc) { @@ -327,3 +332,78 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern, Pattern->getTypeLoc().getFullDataSize()); return TSResult; } + + +bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc, + SourceRange PatternRange, + const UnexpandedParameterPack *Unexpanded, + unsigned NumUnexpanded, + const MultiLevelTemplateArgumentList &TemplateArgs, + bool &ShouldExpand, + unsigned &NumExpansions) { + ShouldExpand = true; + std::pair 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()) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + Name = TTP->getName(); + } else { + NamedDecl *ND = Unexpanded[I].first.get(); + if (TemplateTypeParmDecl *TTP = dyn_cast(ND)) { + Depth = TTP->getDepth(); + Index = TTP->getIndex(); + } else if (NonTypeTemplateParmDecl *NTTP + = dyn_cast(ND)) { + Depth = NTTP->getDepth(); + Index = NTTP->getIndex(); + } else { + TemplateTemplateParmDecl *TTP = cast(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. + Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict) + << FirstPack.first << Name << NumExpansions << NewPackSize + << SourceRange(FirstPack.second) << SourceRange(Unexpanded[I].second); + return true; + } + } + + return false; +} diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index ae55d32fb4..728ece3601 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -91,11 +91,10 @@ template class TreeTransform { protected: Sema &SemaRef; - Sema::ArgumentPackSubstitutionIndexRAII SubstIndex; public: /// \brief Initializes a new tree transformer. - TreeTransform(Sema &SemaRef) : SemaRef(SemaRef), SubstIndex(SemaRef, -1) { } + TreeTransform(Sema &SemaRef) : SemaRef(SemaRef) { } /// \brief Retrieves a reference to the derived class. Derived &getDerived() { return static_cast(*this); } @@ -186,7 +185,7 @@ public: /// given set of parameter packs into separate arguments by repeatedly /// transforming the pattern. /// - /// By default, the transformed never tries to expand pack expansions. + /// By default, the transformer 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 diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp index 7d2fe85036..7f40e9c438 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -fexceptions -verify %s template struct tuple; @@ -30,12 +30,9 @@ extract_nested_types, identity >::types *t_int_float_2 // In a dynamic-exception-specification (15.4); the pattern is a type-id. template struct f_with_except { - virtual void f() throw(Types...); + virtual void f() throw(Types...); // expected-note{{overridden virtual function is here}} }; -// FIXME: the code below requires the ability to instantiate pack -// expansions whose pattern is a type-id. -#if 0 struct check_f_with_except_1 : f_with_except { virtual void f() throw(int, float); }; @@ -43,4 +40,7 @@ struct check_f_with_except_1 : f_with_except { struct check_f_with_except_2 : f_with_except { virtual void f() throw(int); }; -#endif + +struct check_f_with_except_3 : f_with_except { + virtual void f() throw(int, float, double); // expected-error{{exception specification of overriding function is more lax than base version}} +}; -- 2.50.1