[cfe-commits] r122793 - in /cfe/trunk: include/clang/AST/DeclCXX.h include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/AST/DeclCXX.cpp lib/Parse/ParseDeclCXX.cpp lib/Sema/SemaDeclCXX.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp lib/Serialization/ASTReader.cpp test/CXX/temp/temp.decls/temp.variadic/p4.cpp
Douglas Gregor
dgregor at apple.com
Mon Jan 3 16:32:56 PST 2011
Author: dgregor
Date: Mon Jan 3 18:32:56 2011
New Revision: 122793
URL: http://llvm.org/viewvc/llvm-project?rev=122793&view=rev
Log:
Implement pack expansion of base initializers, so that we can
initialize those lovely mixins that come from pack expansions of base
specifiers.
Modified:
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/include/clang/Sema/Sema.h
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Parse/ParseDeclCXX.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Serialization/ASTReader.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Mon Jan 3 18:32:56 2011
@@ -1122,11 +1122,14 @@
/// @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;
-
- /// \brief The source location for the field name.
- SourceLocation MemberLocation;
+ /// field (FieldDecl) or an anonymous field (IndirectFieldDecl*) being
+ /// initialized.
+ llvm::PointerUnion3<TypeSourceInfo *, FieldDecl *, IndirectFieldDecl *>
+ BaseOrMember;
+
+ /// \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 @@
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 @@
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 @@
}
SourceLocation getMemberLocation() const {
- return MemberLocation;
+ return MemberOrEllipsisLocation;
}
/// \brief Determine the source location of the initializer.
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Jan 3 18:32:56 2011
@@ -1862,6 +1862,8 @@
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 "
Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Mon Jan 3 18:32:56 2011
@@ -2541,7 +2541,8 @@
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 @@
Expr **Args, unsigned NumArgs,
SourceLocation LParenLoc,
SourceLocation RParenLoc,
- CXXRecordDecl *ClassDecl);
+ CXXRecordDecl *ClassDecl,
+ SourceLocation EllipsisLoc);
bool SetBaseOrMemberInitializers(CXXConstructorDecl *Constructor,
CXXBaseOrMemberInitializer **Initializers,
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Mon Jan 3 18:32:56 2011
@@ -1002,8 +1002,9 @@
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(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(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 @@
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)
{
Modified: cfe/trunk/lib/Parse/ParseDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDeclCXX.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseDeclCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDeclCXX.cpp Mon Jan 3 18:32:56 2011
@@ -1739,8 +1739,8 @@
/// ':' 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 @@
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
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Mon Jan 3 18:32:56 2011
@@ -1057,7 +1057,8 @@
SourceLocation IdLoc,
SourceLocation LParenLoc,
ExprTy **Args, unsigned NumArgs,
- SourceLocation RParenLoc) {
+ SourceLocation RParenLoc,
+ SourceLocation EllipsisLoc) {
if (!ConstructorD)
return true;
@@ -1093,15 +1094,26 @@
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 @@
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 @@
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 @@
// 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 @@
/*IsVirtual=*/false,
LParenLoc,
BaseInit.takeAs<Expr>(),
- RParenLoc);
+ RParenLoc,
+ EllipsisLoc);
}
// C++ [base.class.init]p2:
@@ -1501,14 +1533,16 @@
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 @@
BaseSpec->isVirtual(),
SourceLocation(),
BaseInit.takeAs<Expr>(),
+ SourceLocation(),
SourceLocation());
return false;
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Mon Jan 3 18:32:56 2011
@@ -1169,8 +1169,8 @@
Unexpanded.data(), Unexpanded.size(),
TemplateArgs, ShouldExpand,
NumExpansions)) {
- continue;
Invalid = true;
+ continue;
}
// If we should expand this pack expansion now, do so.
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Mon Jan 3 18:32:56 2011
@@ -2362,6 +2362,69 @@
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 @@
NewArgs.size(),
Init->getLParenLoc(),
Init->getRParenLoc(),
- New->getParent());
+ New->getParent(),
+ EllipsisLoc);
} else if (Init->isMemberInitializer()) {
FieldDecl *Member = cast<FieldDecl>(FindInstantiatedDecl(
Init->getMemberLocation(),
Modified: cfe/trunk/lib/Serialization/ASTReader.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReader.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReader.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReader.cpp Mon Jan 3 18:32:56 2011
@@ -4325,7 +4325,7 @@
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 @@
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());
Modified: cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp?rev=122793&r1=122792&r2=122793&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.variadic/p4.cpp Mon Jan 3 18:32:56 2011
@@ -36,9 +36,14 @@
// 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 @@
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 {
More information about the cfe-commits
mailing list