diff options
author | Douglas Gregor <dgregor@apple.com> | 2011-01-03 22:36:02 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2011-01-03 22:36:02 +0000 |
commit | 752a595655d3dfcdbffb44b4d6a94275c550e7fe (patch) | |
tree | 8e1d4f1312ffa2fa438266a66a7b747cc6631ac8 | |
parent | d5756a609dbb14dff99cd83a0a50042da5275233 (diff) | |
download | bcm5719-llvm-752a595655d3dfcdbffb44b4d6a94275c550e7fe.tar.gz bcm5719-llvm-752a595655d3dfcdbffb44b4d6a94275c550e7fe.zip |
Implement pack expansions whose pattern is a base-specifier.
llvm-svn: 122782
-rw-r--r-- | clang/include/clang/AST/DeclCXX.h | 17 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 19 | ||||
-rw-r--r-- | clang/lib/AST/ASTImporter.cpp | 7 | ||||
-rw-r--r-- | clang/lib/AST/DeclCXX.cpp | 3 | ||||
-rw-r--r-- | clang/lib/CodeGen/Mangle.cpp | 15 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 9 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclCXX.cpp | 25 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiate.cpp | 55 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateVariadic.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriter.cpp | 3 | ||||
-rw-r--r-- | clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp | 18 |
12 files changed, 160 insertions, 20 deletions
diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 79832a41181..0c3d27b86a6 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -168,6 +168,10 @@ class CXXBaseSpecifier { /// specifier (if present). SourceRange Range; + /// \brief The source location of the ellipsis, if this is a pack + /// expansion. + SourceLocation EllipsisLoc; + /// Virtual - Whether this is a virtual base class or not. bool Virtual : 1; @@ -192,8 +196,9 @@ public: CXXBaseSpecifier() { } CXXBaseSpecifier(SourceRange R, bool V, bool BC, AccessSpecifier A, - TypeSourceInfo *TInfo) - : Range(R), Virtual(V), BaseOfClass(BC), Access(A), BaseTypeInfo(TInfo) { } + TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) + : Range(R), EllipsisLoc(EllipsisLoc), Virtual(V), BaseOfClass(BC), + Access(A), BaseTypeInfo(TInfo) { } /// getSourceRange - Retrieves the source range that contains the /// entire base specifier. @@ -207,6 +212,14 @@ public: /// with the 'class' keyword (vs. one declared with the 'struct' keyword). bool isBaseOfClass() const { return BaseOfClass; } + /// \brief Determine whether this base specifier is a pack expansion. + bool isPackExpansion() const { return EllipsisLoc.isValid(); } + + /// \brief For a pack expansion, determine the location of the ellipsis. + SourceLocation getEllipsisLoc() const { + return EllipsisLoc; + } + /// getAccessSpecifier - Returns the access specifier for this base /// specifier. This is the actual base specifier as used for /// semantic analysis, so the result can never be AS_none. To diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index b5dfe0a480c..fda0cf2c312 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -127,6 +127,7 @@ namespace clang { class TemplateTemplateParmDecl; class Token; class TypedefDecl; + class TypeLoc; class UnqualifiedId; class UnresolvedLookupExpr; class UnresolvedMemberExpr; @@ -2653,13 +2654,15 @@ public: CXXBaseSpecifier *CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeSourceInfo *TInfo); + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc); BaseResult ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - ParsedType basetype, SourceLocation - BaseLoc); + ParsedType basetype, + SourceLocation BaseLoc, + SourceLocation EllipsisLoc); bool AttachBaseSpecifiers(CXXRecordDecl *Class, CXXBaseSpecifier **Bases, unsigned NumBases); @@ -3273,11 +3276,19 @@ public: /// \brief Collect the set of unexpanded parameter packs within the given /// type. /// - /// \param Arg The template argument that will be traversed to find + /// \param T The type that will be traversed to find /// unexpanded parameter packs. void collectUnexpandedParameterPacks(QualType T, llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// \brief Collect the set of unexpanded parameter packs within the given + /// type. + /// + /// \param TL The type that will be traversed to find + /// unexpanded parameter packs. + void collectUnexpandedParameterPacks(TypeLoc TL, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded); + /// \brief Invoked when parsing a template argument followed by an /// ellipsis, which creates a pack expansion. /// diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp index 08c1ea45f74..c62225ef407 100644 --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -1709,6 +1709,10 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { QualType T = Importer.Import(Base1->getType()); if (T.isNull()) return true; + + SourceLocation EllipsisLoc; + if (Base1->isPackExpansion()) + EllipsisLoc = Importer.Import(Base1->getEllipsisLoc()); Bases.push_back( new (Importer.getToContext()) @@ -1716,7 +1720,8 @@ bool ASTNodeImporter::ImportDefinition(RecordDecl *From, RecordDecl *To) { Base1->isVirtual(), Base1->isBaseOfClass(), Base1->getAccessSpecifierAsWritten(), - Importer.Import(Base1->getTypeSourceInfo()))); + Importer.Import(Base1->getTypeSourceInfo()), + EllipsisLoc)); } if (!Bases.empty()) ToCXX->setBases(Bases.data(), Bases.size()); diff --git a/clang/lib/AST/DeclCXX.cpp b/clang/lib/AST/DeclCXX.cpp index 35c89971eae..3304ad9a293 100644 --- a/clang/lib/AST/DeclCXX.cpp +++ b/clang/lib/AST/DeclCXX.cpp @@ -196,7 +196,8 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases, data().getVBases()[I] = CXXBaseSpecifier(VBaseClassDecl->getSourceRange(), true, VBaseClassDecl->getTagKind() == TTK_Class, - VBases[I]->getAccessSpecifier(), VBaseTypeInfo); + VBases[I]->getAccessSpecifier(), VBaseTypeInfo, + SourceLocation()); } } diff --git a/clang/lib/CodeGen/Mangle.cpp b/clang/lib/CodeGen/Mangle.cpp index 0aa9f402f96..834ef4e5693 100644 --- a/clang/lib/CodeGen/Mangle.cpp +++ b/clang/lib/CodeGen/Mangle.cpp @@ -2137,8 +2137,9 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, // ::= I <template-arg>* E # argument pack // ::= sp <expression> # pack expansion of (C++0x) switch (A.getKind()) { - default: - assert(0 && "Unknown template argument kind!"); + case TemplateArgument::Null: + llvm_unreachable("Cannot mangle NULL template argument"); + case TemplateArgument::Type: mangleType(A.getAsType()); break; @@ -2187,6 +2188,16 @@ void CXXNameMangler::mangleTemplateArg(const NamedDecl *P, break; } + + case TemplateArgument::Pack: { + // Note: proposal by Mike Herrick on 12/20/10 + Out << 'J'; + for (TemplateArgument::pack_iterator PA = A.pack_begin(), + PAEnd = A.pack_end(); + PA != PAEnd; ++PA) + mangleTemplateArg(P, *PA); + Out << 'E'; + } } } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index fe2390f1aa0..adbecdc4a94 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1196,13 +1196,20 @@ Parser::BaseResult Parser::ParseBaseSpecifier(Decl *ClassDecl) { if (BaseType.isInvalid()) return true; + // Parse the optional ellipsis (for a pack expansion). The ellipsis is + // actually part of the base-specifier-list grammar productions, but we + // parse it here for convenience. + SourceLocation EllipsisLoc; + if (Tok.is(tok::ellipsis)) + EllipsisLoc = ConsumeToken(); + // Find the complete source range for the base-specifier. SourceRange Range(StartLoc, EndLocation); // Notify semantic analysis that we have parsed a complete // base-specifier. return Actions.ActOnBaseSpecifier(ClassDecl, Range, IsVirtual, Access, - BaseType.get(), BaseLoc); + BaseType.get(), BaseLoc, EllipsisLoc); } /// getAccessSpecifierIfPresent - Determine whether the next token is diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 0021c798235..10d04fa9a31 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -464,7 +464,8 @@ CXXBaseSpecifier * Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - TypeSourceInfo *TInfo) { + TypeSourceInfo *TInfo, + SourceLocation EllipsisLoc) { QualType BaseType = TInfo->getType(); // C++ [class.union]p1: @@ -475,10 +476,17 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, return 0; } + if (EllipsisLoc.isValid() && + !TInfo->getType()->containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << TInfo->getTypeLoc().getSourceRange(); + EllipsisLoc = SourceLocation(); + } + if (BaseType->isDependentType()) return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, - Access, TInfo); + Access, TInfo, EllipsisLoc); SourceLocation BaseLoc = TInfo->getTypeLoc().getBeginLoc(); @@ -527,7 +535,7 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // Create the base specifier. return new (Context) CXXBaseSpecifier(SpecifierRange, Virtual, Class->getTagKind() == TTK_Class, - Access, TInfo); + Access, TInfo, EllipsisLoc); } /// ActOnBaseSpecifier - Parsed a base specifier. A base specifier is @@ -538,7 +546,8 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, bool Virtual, AccessSpecifier Access, - ParsedType basetype, SourceLocation BaseLoc) { + ParsedType basetype, SourceLocation BaseLoc, + SourceLocation EllipsisLoc) { if (!classdecl) return true; @@ -550,12 +559,14 @@ Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, TypeSourceInfo *TInfo = 0; GetTypeFromParser(basetype, &TInfo); - if (DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, + if (EllipsisLoc.isInvalid() && + DiagnoseUnexpandedParameterPack(SpecifierRange.getBegin(), TInfo, UPPC_BaseType)) return true; - + if (CXXBaseSpecifier *BaseSpec = CheckBaseSpecifier(Class, SpecifierRange, - Virtual, Access, TInfo)) + Virtual, Access, TInfo, + EllipsisLoc)) return BaseSpec; return true; diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 8c9681ffd5a..77d3e64a157 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1155,6 +1155,58 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, continue; } + SourceLocation EllipsisLoc; + if (Base->isPackExpansion()) { + // This is a pack expansion. See whether we should expand it now, or + // wait until later. + llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded; + collectUnexpandedParameterPacks(Base->getTypeSourceInfo()->getTypeLoc(), + Unexpanded); + bool ShouldExpand = false; + unsigned NumExpansions = 0; + if (CheckParameterPacksForExpansion(Base->getEllipsisLoc(), + Base->getSourceRange(), + Unexpanded.data(), Unexpanded.size(), + TemplateArgs, ShouldExpand, + NumExpansions)) { + continue; + Invalid = true; + } + + // If we should expand this pack expansion now, do so. + if (ShouldExpand) { + for (unsigned I = 0; I != NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I); + + TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), + TemplateArgs, + Base->getSourceRange().getBegin(), + DeclarationName()); + if (!BaseTypeLoc) { + Invalid = true; + continue; + } + + if (CXXBaseSpecifier *InstantiatedBase + = CheckBaseSpecifier(Instantiation, + Base->getSourceRange(), + Base->isVirtual(), + Base->getAccessSpecifierAsWritten(), + BaseTypeLoc, + SourceLocation())) + InstantiatedBases.push_back(InstantiatedBase); + else + Invalid = true; + } + + continue; + } + + // The resulting base specifier will (still) be a pack expansion. + EllipsisLoc = Base->getEllipsisLoc(); + } + + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, -1); TypeSourceInfo *BaseTypeLoc = SubstType(Base->getTypeSourceInfo(), TemplateArgs, Base->getSourceRange().getBegin(), @@ -1169,7 +1221,8 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation, Base->getSourceRange(), Base->isVirtual(), Base->getAccessSpecifierAsWritten(), - BaseTypeLoc)) + BaseTypeLoc, + EllipsisLoc)) InstantiatedBases.push_back(InstantiatedBase); else Invalid = true; diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index a3e308fe11f..92df1fd8636 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -294,6 +294,11 @@ void Sema::collectUnexpandedParameterPacks(QualType T, CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseType(T); } +void Sema::collectUnexpandedParameterPacks(TypeLoc TL, + llvm::SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { + CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); +} + ParsedTemplateArgument Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg, SourceLocation EllipsisLoc) { diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 084778d856c..dd8807fb004 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -4292,7 +4292,9 @@ ASTReader::ReadCXXBaseSpecifier(PerFileData &F, AccessSpecifier AS = static_cast<AccessSpecifier>(Record[Idx++]); TypeSourceInfo *TInfo = GetTypeSourceInfo(F, Record, Idx); SourceRange Range = ReadSourceRange(F, Record, Idx); - return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, TInfo); + SourceLocation EllipsisLoc = ReadSourceLocation(F, Record, Idx); + return CXXBaseSpecifier(Range, isVirtual, isBaseOfClass, AS, TInfo, + EllipsisLoc); } std::pair<CXXBaseOrMemberInitializer **, unsigned> diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 8c0fb42f5f8..cbf5ac79192 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3231,6 +3231,9 @@ void ASTWriter::AddCXXBaseSpecifier(const CXXBaseSpecifier &Base, Record.push_back(Base.getAccessSpecifierAsWritten()); AddTypeSourceInfo(Base.getTypeSourceInfo(), Record); AddSourceRange(Base.getSourceRange(), Record); + AddSourceLocation(Base.isPackExpansion()? Base.getEllipsisLoc() + : SourceLocation(), + Record); } void ASTWriter::FlushCXXBaseSpecifiers() { diff --git a/clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp index 440bd4b5dbf..49f6993b399 100644 --- a/clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp +++ b/clang/test/CXX/temp/temp.decls/temp.variadic/p4.cpp @@ -34,6 +34,24 @@ void initializer_list_expansion() { template void initializer_list_expansion<1, 2, 3, 4, 5>(); template void initializer_list_expansion<1, 2, 3, 4, 5, 6>(); // expected-note{{in instantiation of function template specialization 'initializer_list_expansion<1, 2, 3, 4, 5, 6>' requested here}} +// In a base-specifier-list (Clause 10); the pattern is a base-specifier. +template<typename ...Mixins> +struct HasMixins : public Mixins... { }; + +struct A { }; +struct B { }; +struct C { }; +struct D { }; + +A *checkA = new HasMixins<A, B, C, D>; +B *checkB = new HasMixins<A, B, C, D>; +D *checkD = new HasMixins<A, B, C, D>; +C *checkC = new HasMixins<A, B, D>; // expected-error{{cannot initialize a variable of type 'C *' with an rvalue of type 'HasMixins<A, B, D> *'}} +HasMixins<> *checkNone = new HasMixins<>; + +template<typename Mixins> +struct BrokenMixins : public Mixins... { }; // expected-error{{pack expansion does not contain any unexpanded parameter packs}} + // In a template-argument-list (14.3); the pattern is a template-argument. template<typename ...Types> struct tuple_of_refs { |