Implement pack expansions whose pattern is a base-specifier.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122782 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2011-01-03 22:36:02 +00:00
Родитель 0fe5397b26
Коммит f90b27ad07
12 изменённых файлов: 160 добавлений и 20 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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.
///

Просмотреть файл

@ -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());

Просмотреть файл

@ -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());
}
}

Просмотреть файл

@ -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';
}
}
}

Просмотреть файл

@ -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

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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>

Просмотреть файл

@ -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() {

Просмотреть файл

@ -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 {