forked from OSchip/llvm-project
Implement pack expansion of base initializers, so that we can
initialize those lovely mixins that come from pack expansions of base specifiers. llvm-svn: 122793
This commit is contained in:
parent
bd9dfb2e29
commit
44e7df67d9
|
@ -1122,11 +1122,14 @@ public:
|
|||
/// @endcode
|
||||
class CXXBaseOrMemberInitializer {
|
||||
/// \brief Either the base class name (stored as a TypeSourceInfo*), an normal
|
||||
/// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being initialized.
|
||||
llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *> BaseOrMember;
|
||||
/// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being
|
||||
/// initialized.
|
||||
llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
|
||||
BaseOrMember;
|
||||
|
||||
/// \brief The source location for the field name.
|
||||
SourceLocation MemberLocation;
|
||||
/// \brief The source location for the field name or, for a base initializer
|
||||
/// pack expansion, the location of the ellipsis.
|
||||
SourceLocation MemberOrEllipsisLocation;
|
||||
|
||||
/// \brief The argument used to initialize the base or member, which may
|
||||
/// end up constructing an object (when multiple arguments are involved).
|
||||
|
@ -1168,7 +1171,8 @@ public:
|
|||
TypeSourceInfo *TInfo, bool IsVirtual,
|
||||
SourceLocation L,
|
||||
Expr *Init,
|
||||
SourceLocation R);
|
||||
SourceLocation R,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
/// CXXBaseOrMemberInitializer - Creates a new member initializer.
|
||||
explicit
|
||||
|
@ -1213,6 +1217,17 @@ public:
|
|||
return BaseOrMember.is<IndirectFieldDecl*>();
|
||||
}
|
||||
|
||||
/// \brief Determine whether this initializer is a pack expansion.
|
||||
bool isPackExpansion() const {
|
||||
return isBaseInitializer() && MemberOrEllipsisLocation.isValid();
|
||||
}
|
||||
|
||||
// \brief For a pack expansion, returns the location of the ellipsis.
|
||||
SourceLocation getEllipsisLoc() const {
|
||||
assert(isPackExpansion() && "Initializer is not a pack expansion");
|
||||
return MemberOrEllipsisLocation;
|
||||
}
|
||||
|
||||
/// If this is a base class initializer, returns the type of the
|
||||
/// base class with location information. Otherwise, returns an NULL
|
||||
/// type location.
|
||||
|
@ -1261,7 +1276,7 @@ public:
|
|||
}
|
||||
|
||||
SourceLocation getMemberLocation() const {
|
||||
return MemberLocation;
|
||||
return MemberOrEllipsisLocation;
|
||||
}
|
||||
|
||||
/// \brief Determine the source location of the initializer.
|
||||
|
|
|
@ -1862,6 +1862,8 @@ def err_pack_expansion_without_parameter_packs : Error<
|
|||
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_member_init : Error<
|
||||
"pack expansion for initialization of member %0">;
|
||||
|
||||
def err_function_parameter_pack_without_parameter_packs : Error<
|
||||
"type %0 of function parameter pack does not contain any unexpanded "
|
||||
|
|
|
@ -2541,7 +2541,8 @@ public:
|
|||
SourceLocation IdLoc,
|
||||
SourceLocation LParenLoc,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation RParenLoc);
|
||||
SourceLocation RParenLoc,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
MemInitResult BuildMemberInitializer(ValueDecl *Member, Expr **Args,
|
||||
unsigned NumArgs, SourceLocation IdLoc,
|
||||
|
@ -2553,7 +2554,8 @@ public:
|
|||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation LParenLoc,
|
||||
SourceLocation RParenLoc,
|
||||
CXXRecordDecl *ClassDecl);
|
||||
CXXRecordDecl *ClassDecl,
|
||||
SourceLocation EllipsisLoc);
|
||||
|
||||
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
|
||||
CXXBaseOrMemberInitializer **Initializers,
|
||||
|
|
|
@ -1002,8 +1002,9 @@ bool CXXMethodDecl::hasInlineBody() const {
|
|||
CXXBaseOrMemberInitializer::
|
||||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
TypeSourceInfo *TInfo, bool IsVirtual,
|
||||
SourceLocation L, Expr *Init, SourceLocation R)
|
||||
: BaseOrMember(TInfo), Init(Init),
|
||||
SourceLocation L, Expr *Init, SourceLocation R,
|
||||
SourceLocation EllipsisLoc)
|
||||
: BaseOrMember(TInfo), MemberOrEllipsisLocation(EllipsisLoc), Init(Init),
|
||||
LParenLoc(L), RParenLoc(R), IsVirtual(IsVirtual), IsWritten(false),
|
||||
SourceOrderOrNumArrayIndices(0)
|
||||
{
|
||||
|
@ -1013,7 +1014,7 @@ CXXBaseOrMemberInitializer::
|
|||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
FieldDecl *Member, SourceLocation MemberLoc,
|
||||
SourceLocation L, Expr *Init, SourceLocation R)
|
||||
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
||||
: BaseOrMember(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
||||
LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
||||
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
||||
{
|
||||
|
@ -1023,7 +1024,7 @@ CXXBaseOrMemberInitializer::
|
|||
CXXBaseOrMemberInitializer(ASTContext &Context,
|
||||
IndirectFieldDecl *Member, SourceLocation MemberLoc,
|
||||
SourceLocation L, Expr *Init, SourceLocation R)
|
||||
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
||||
: BaseOrMember(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
||||
LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
||||
IsWritten(false), SourceOrderOrNumArrayIndices(0)
|
||||
{
|
||||
|
@ -1035,7 +1036,7 @@ CXXBaseOrMemberInitializer(ASTContext &Context,
|
|||
SourceLocation L, Expr *Init, SourceLocation R,
|
||||
VarDecl **Indices,
|
||||
unsigned NumIndices)
|
||||
: BaseOrMember(Member), MemberLocation(MemberLoc), Init(Init),
|
||||
: BaseOrMember(Member), MemberOrEllipsisLocation(MemberLoc), Init(Init),
|
||||
LParenLoc(L), RParenLoc(R), IsVirtual(false),
|
||||
IsWritten(false), SourceOrderOrNumArrayIndices(NumIndices)
|
||||
{
|
||||
|
|
|
@ -1739,8 +1739,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc,
|
|||
/// ':' mem-initializer-list
|
||||
///
|
||||
/// [C++] mem-initializer-list:
|
||||
/// mem-initializer
|
||||
/// mem-initializer , mem-initializer-list
|
||||
/// mem-initializer ...[opt]
|
||||
/// mem-initializer ...[opt] , mem-initializer-list
|
||||
void Parser::ParseConstructorInitializer(Decl *ConstructorDecl) {
|
||||
assert(Tok.is(tok::colon) && "Constructor initializer always starts with ':'");
|
||||
|
||||
|
@ -1839,10 +1839,15 @@ Parser::MemInitResult Parser::ParseMemInitializer(Decl *ConstructorDecl) {
|
|||
|
||||
SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
|
||||
|
||||
SourceLocation EllipsisLoc;
|
||||
if (Tok.is(tok::ellipsis))
|
||||
EllipsisLoc = ConsumeToken();
|
||||
|
||||
return Actions.ActOnMemInitializer(ConstructorDecl, getCurScope(), SS, II,
|
||||
TemplateTypeTy, IdLoc,
|
||||
LParenLoc, ArgExprs.take(),
|
||||
ArgExprs.size(), RParenLoc);
|
||||
ArgExprs.size(), RParenLoc,
|
||||
EllipsisLoc);
|
||||
}
|
||||
|
||||
/// ParseExceptionSpecification - Parse a C++ exception-specification
|
||||
|
|
|
@ -1057,7 +1057,8 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
|
|||
SourceLocation IdLoc,
|
||||
SourceLocation LParenLoc,
|
||||
ExprTy **Args, unsigned NumArgs,
|
||||
SourceLocation RParenLoc) {
|
||||
SourceLocation RParenLoc,
|
||||
SourceLocation EllipsisLoc) {
|
||||
if (!ConstructorD)
|
||||
return true;
|
||||
|
||||
|
@ -1093,15 +1094,26 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
|
|||
if (Result.first != Result.second) {
|
||||
Member = dyn_cast<FieldDecl>(*Result.first);
|
||||
|
||||
if (Member)
|
||||
if (Member) {
|
||||
if (EllipsisLoc.isValid())
|
||||
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
|
||||
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
|
||||
|
||||
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
|
||||
LParenLoc, RParenLoc);
|
||||
}
|
||||
|
||||
// Handle anonymous union case.
|
||||
if (IndirectFieldDecl* IndirectField
|
||||
= dyn_cast<IndirectFieldDecl>(*Result.first))
|
||||
= dyn_cast<IndirectFieldDecl>(*Result.first)) {
|
||||
if (EllipsisLoc.isValid())
|
||||
Diag(EllipsisLoc, diag::err_pack_expansion_member_init)
|
||||
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
|
||||
|
||||
return BuildMemberInitializer(IndirectField, (Expr**)Args,
|
||||
NumArgs, IdLoc,
|
||||
LParenLoc, RParenLoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
// It didn't name a member, so see if it names a class.
|
||||
|
@ -1210,7 +1222,7 @@ Sema::ActOnMemInitializer(Decl *ConstructorD,
|
|||
TInfo = Context.getTrivialTypeSourceInfo(BaseType, IdLoc);
|
||||
|
||||
return BuildBaseInitializer(BaseType, TInfo, (Expr **)Args, NumArgs,
|
||||
LParenLoc, RParenLoc, ClassDecl);
|
||||
LParenLoc, RParenLoc, ClassDecl, EllipsisLoc);
|
||||
}
|
||||
|
||||
/// Checks an initializer expression for use of uninitialized fields, such as
|
||||
|
@ -1383,7 +1395,8 @@ MemInitResult
|
|||
Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
|
||||
Expr **Args, unsigned NumArgs,
|
||||
SourceLocation LParenLoc, SourceLocation RParenLoc,
|
||||
CXXRecordDecl *ClassDecl) {
|
||||
CXXRecordDecl *ClassDecl,
|
||||
SourceLocation EllipsisLoc) {
|
||||
bool HasDependentArg = false;
|
||||
for (unsigned i = 0; i < NumArgs; i++)
|
||||
HasDependentArg |= Args[i]->isTypeDependent();
|
||||
|
@ -1403,6 +1416,24 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
|
|||
// name that denotes that base class type.
|
||||
bool Dependent = BaseType->isDependentType() || HasDependentArg;
|
||||
|
||||
if (EllipsisLoc.isValid()) {
|
||||
// This is a pack expansion.
|
||||
if (!BaseType->containsUnexpandedParameterPack()) {
|
||||
Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
|
||||
<< SourceRange(BaseLoc, RParenLoc);
|
||||
|
||||
EllipsisLoc = SourceLocation();
|
||||
}
|
||||
} else {
|
||||
// Check for any unexpanded parameter packs.
|
||||
if (DiagnoseUnexpandedParameterPack(BaseLoc, BaseTInfo, UPPC_Initializer))
|
||||
return true;
|
||||
|
||||
for (unsigned I = 0; I != NumArgs; ++I)
|
||||
if (DiagnoseUnexpandedParameterPack(Args[I]))
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for direct and virtual base classes.
|
||||
const CXXBaseSpecifier *DirectBaseSpec = 0;
|
||||
const CXXBaseSpecifier *VirtualBaseSpec = 0;
|
||||
|
@ -1447,7 +1478,8 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
|
|||
/*IsVirtual=*/false,
|
||||
LParenLoc,
|
||||
BaseInit.takeAs<Expr>(),
|
||||
RParenLoc);
|
||||
RParenLoc,
|
||||
EllipsisLoc);
|
||||
}
|
||||
|
||||
// C++ [base.class.init]p2:
|
||||
|
@ -1501,14 +1533,16 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
|
|||
BaseSpec->isVirtual(),
|
||||
LParenLoc,
|
||||
Init.takeAs<Expr>(),
|
||||
RParenLoc);
|
||||
RParenLoc,
|
||||
EllipsisLoc);
|
||||
}
|
||||
|
||||
return new (Context) CXXBaseOrMemberInitializer(Context, BaseTInfo,
|
||||
BaseSpec->isVirtual(),
|
||||
LParenLoc,
|
||||
BaseInit.takeAs<Expr>(),
|
||||
RParenLoc);
|
||||
RParenLoc,
|
||||
EllipsisLoc);
|
||||
}
|
||||
|
||||
/// ImplicitInitializerKind - How an implicit base or member initializer should
|
||||
|
@ -1586,6 +1620,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
|
|||
BaseSpec->isVirtual(),
|
||||
SourceLocation(),
|
||||
BaseInit.takeAs<Expr>(),
|
||||
SourceLocation(),
|
||||
SourceLocation());
|
||||
|
||||
return false;
|
||||
|
|
|
@ -1169,8 +1169,8 @@ Sema::SubstBaseSpecifiers(CXXRecordDecl *Instantiation,
|
|||
Unexpanded.data(), Unexpanded.size(),
|
||||
TemplateArgs, ShouldExpand,
|
||||
NumExpansions)) {
|
||||
continue;
|
||||
Invalid = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we should expand this pack expansion now, do so.
|
||||
|
|
|
@ -2362,6 +2362,69 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
|
|||
SourceLocation LParenLoc, RParenLoc;
|
||||
ASTOwningVector<Expr*> NewArgs(*this);
|
||||
|
||||
SourceLocation EllipsisLoc;
|
||||
|
||||
if (Init->isPackExpansion()) {
|
||||
// This is a pack expansion. We should expand it now.
|
||||
TypeLoc BaseTL = Init->getBaseClassInfo()->getTypeLoc();
|
||||
llvm::SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
collectUnexpandedParameterPacks(BaseTL, Unexpanded);
|
||||
bool ShouldExpand = false;
|
||||
unsigned NumExpansions = 0;
|
||||
if (CheckParameterPacksForExpansion(Init->getEllipsisLoc(),
|
||||
BaseTL.getSourceRange(),
|
||||
Unexpanded.data(),
|
||||
Unexpanded.size(),
|
||||
TemplateArgs, ShouldExpand,
|
||||
NumExpansions)) {
|
||||
AnyErrors = true;
|
||||
New->setInvalidDecl();
|
||||
continue;
|
||||
}
|
||||
assert(ShouldExpand && "Partial instantiation of base initializer?");
|
||||
|
||||
// Loop over all of the arguments in the argument pack(s),
|
||||
for (unsigned I = 0; I != NumExpansions; ++I) {
|
||||
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(*this, I);
|
||||
|
||||
// Instantiate the initializer.
|
||||
if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs,
|
||||
LParenLoc, NewArgs, RParenLoc)) {
|
||||
AnyErrors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Instantiate the base type.
|
||||
TypeSourceInfo *BaseTInfo = SubstType(Init->getBaseClassInfo(),
|
||||
TemplateArgs,
|
||||
Init->getSourceLocation(),
|
||||
New->getDeclName());
|
||||
if (!BaseTInfo) {
|
||||
AnyErrors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Build the initializer.
|
||||
MemInitResult NewInit = BuildBaseInitializer(BaseTInfo->getType(),
|
||||
BaseTInfo,
|
||||
(Expr **)NewArgs.data(),
|
||||
NewArgs.size(),
|
||||
Init->getLParenLoc(),
|
||||
Init->getRParenLoc(),
|
||||
New->getParent(),
|
||||
SourceLocation());
|
||||
if (NewInit.isInvalid()) {
|
||||
AnyErrors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
NewInits.push_back(NewInit.get());
|
||||
NewArgs.clear();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Instantiate the initializer.
|
||||
if (InstantiateInitializer(*this, Init->getInit(), TemplateArgs,
|
||||
LParenLoc, NewArgs, RParenLoc)) {
|
||||
|
@ -2386,7 +2449,8 @@ Sema::InstantiateMemInitializers(CXXConstructorDecl *New,
|
|||
NewArgs.size(),
|
||||
Init->getLParenLoc(),
|
||||
Init->getRParenLoc(),
|
||||
New->getParent());
|
||||
New->getParent(),
|
||||
EllipsisLoc);
|
||||
} else if (Init->isMemberInitializer()) {
|
||||
FieldDecl *Member = cast<FieldDecl>(FindInstantiatedDecl(
|
||||
Init->getMemberLocation(),
|
||||
|
|
|
@ -4325,7 +4325,7 @@ ASTReader::ReadCXXBaseOrMemberInitializers(PerFileData &F,
|
|||
else
|
||||
Member = cast<FieldDecl>(GetDecl(Record[Idx++]));
|
||||
}
|
||||
SourceLocation MemberLoc = ReadSourceLocation(F, Record, Idx);
|
||||
SourceLocation MemberOrEllipsisLoc = ReadSourceLocation(F, Record, Idx);
|
||||
Expr *Init = ReadExpr(F);
|
||||
SourceLocation LParenLoc = ReadSourceLocation(F, Record, Idx);
|
||||
SourceLocation RParenLoc = ReadSourceLocation(F, Record, Idx);
|
||||
|
@ -4345,18 +4345,22 @@ ASTReader::ReadCXXBaseOrMemberInitializers(PerFileData &F,
|
|||
if (IsBaseInitializer) {
|
||||
BOMInit = new (C) CXXBaseOrMemberInitializer(C, BaseClassInfo,
|
||||
IsBaseVirtual, LParenLoc,
|
||||
Init, RParenLoc);
|
||||
Init, RParenLoc,
|
||||
MemberOrEllipsisLoc);
|
||||
} else if (IsWritten) {
|
||||
if (Member)
|
||||
BOMInit = new (C) CXXBaseOrMemberInitializer(C, Member, MemberLoc,
|
||||
BOMInit = new (C) CXXBaseOrMemberInitializer(C, Member,
|
||||
MemberOrEllipsisLoc,
|
||||
LParenLoc, Init,
|
||||
RParenLoc);
|
||||
else
|
||||
BOMInit = new (C) CXXBaseOrMemberInitializer(C, IndirectMember,
|
||||
MemberLoc, LParenLoc,
|
||||
MemberOrEllipsisLoc,
|
||||
LParenLoc,
|
||||
Init, RParenLoc);
|
||||
} else {
|
||||
BOMInit = CXXBaseOrMemberInitializer::Create(C, Member, MemberLoc,
|
||||
BOMInit = CXXBaseOrMemberInitializer::Create(C, Member,
|
||||
MemberOrEllipsisLoc,
|
||||
LParenLoc, Init, RParenLoc,
|
||||
Indices.data(),
|
||||
Indices.size());
|
||||
|
|
|
@ -36,9 +36,14 @@ template void initializer_list_expansion<1, 2, 3, 4, 5, 6>(); // expected-note{{
|
|||
|
||||
// In a base-specifier-list (Clause 10); the pattern is a base-specifier.
|
||||
template<typename ...Mixins>
|
||||
struct HasMixins : public Mixins... { };
|
||||
struct HasMixins : public Mixins... {
|
||||
HasMixins();
|
||||
HasMixins(const HasMixins&);
|
||||
HasMixins(int i);
|
||||
};
|
||||
|
||||
struct A { };
|
||||
struct A { }; // expected-note{{candidate constructor (the implicit copy constructor) not viable: no known conversion from 'int' to 'const A' for 1st argument}} \
|
||||
// expected-note{{candidate constructor (the implicit default constructor) not viable: requires 0 arguments, but 1 was provided}}
|
||||
struct B { };
|
||||
struct C { };
|
||||
struct D { };
|
||||
|
@ -52,6 +57,29 @@ HasMixins<> *checkNone = new HasMixins<>;
|
|||
template<typename Mixins>
|
||||
struct BrokenMixins : public Mixins... { }; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
|
||||
|
||||
// In a mem-initializer-list (12.6.2); the pattern is a mem-initializer.
|
||||
template<typename ...Mixins>
|
||||
HasMixins<Mixins...>::HasMixins(): Mixins()... { }
|
||||
|
||||
template<typename ...Mixins>
|
||||
HasMixins<Mixins...>::HasMixins(const HasMixins &other): Mixins(other)... { }
|
||||
|
||||
template<typename ...Mixins>
|
||||
HasMixins<Mixins...>::HasMixins(int i): Mixins(i)... { } // expected-error{{no matching constructor for initialization of 'A'}}
|
||||
|
||||
void test_has_mixins() {
|
||||
HasMixins<A, B> ab;
|
||||
HasMixins<A, B> ab2 = ab;
|
||||
HasMixins<A, B> ab3(17); // expected-note{{in instantiation of member function 'HasMixins<A, B>::HasMixins' requested here}}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct X {
|
||||
T member;
|
||||
|
||||
X() : member()... { } // expected-error{{pack expansion for initialization of member 'member'}}
|
||||
};
|
||||
|
||||
// In a template-argument-list (14.3); the pattern is a template-argument.
|
||||
template<typename ...Types>
|
||||
struct tuple_of_refs {
|
||||
|
|
Loading…
Reference in New Issue