From b09d17a44184cd4c0cd81f51af4db03db35983ff Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 3 Jan 2011 19:31:53 +0000 Subject: [PATCH] Implement support for pack expansions in initializer lists and expression lists. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122764 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Parse/ParseExpr.cpp | 14 +++--- lib/Parse/ParseInit.cpp | 7 ++- lib/Sema/TreeTransform.h | 65 +++++++++++++++++++++++++++ test/CXX/temp/temp.decls/temp.variadic/p4.cpp | 14 ++++++ 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 92bbbd7bf..be5c7d780 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -172,8 +172,8 @@ static prec::Level getBinOpPrecedence(tok::TokenKind Kind, /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] -/// assignment-expression -/// expression ',' assignment-expression +/// assignment-expression ...[opt] +/// expression ',' assignment-expression ...[opt] /// ExprResult Parser::ParseExpression() { ExprResult LHS(ParseAssignmentExpression()); @@ -1030,8 +1030,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] -/// argument-expression -/// argument-expression-list ',' assignment-expression +/// argument-expression ...[opt] +/// argument-expression-list ',' assignment-expression ...[opt] /// ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { @@ -1692,8 +1692,8 @@ ExprResult Parser::ParseStringLiteralExpression() { /// argument-expression-list , assignment-expression /// /// [C++] expression-list: -/// [C++] assignment-expression -/// [C++] expression-list , assignment-expression +/// [C++] assignment-expression ...[opt] +/// [C++] expression-list , assignment-expression ...[opt] /// bool Parser::ParseExpressionList(llvm::SmallVectorImpl &Exprs, llvm::SmallVectorImpl &CommaLocs, @@ -1710,6 +1710,8 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl &Exprs, } ExprResult Expr(ParseAssignmentExpression()); + if (Tok.is(tok::ellipsis)) + Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken()); if (Expr.isInvalid()) return true; diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp index c2675f33e..82dda2b79 100644 --- a/lib/Parse/ParseInit.cpp +++ b/lib/Parse/ParseInit.cpp @@ -310,8 +310,8 @@ ExprResult Parser::ParseInitializerWithPotentialDesignator() { /// [GNU] '{' '}' /// /// initializer-list: -/// designation[opt] initializer -/// initializer-list ',' designation[opt] initializer +/// designation[opt] initializer ...[opt] +/// initializer-list ',' designation[opt] initializer ...[opt] /// ExprResult Parser::ParseBraceInitializer() { InMessageExpressionRAIIObject InMessage(*this, false); @@ -344,6 +344,9 @@ ExprResult Parser::ParseBraceInitializer() { else SubElt = ParseInitializer(); + if (Tok.is(tok::ellipsis)) + SubElt = Actions.ActOnPackExpansion(SubElt.get(), ConsumeToken()); + // If we couldn't parse the subelement, bail out. if (!SubElt.isInvalid()) { InitExprs.push_back(SubElt.release()); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 03f5fc0c9..9088ae0fe 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -2103,6 +2103,8 @@ public: SourceLocation EllipsisLoc) { switch (Pattern.getArgument().getKind()) { case TemplateArgument::Expression: + // FIXME: We should be able to handle this now! + case TemplateArgument::Template: llvm_unreachable("Unsupported pack expansion of expressions/templates"); @@ -2124,6 +2126,15 @@ public: return TemplateArgumentLoc(); } + /// \brief Build a new expression pack expansion. + /// + /// By default, performs semantic analysis to build a new pack expansion + /// for an expression. Subclasses may override this routine to provide + /// different behavior. + ExprResult RebuildPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) { + return getSema().ActOnPackExpansion(Pattern, EllipsisLoc); + } + private: QualType TransformTypeInObjectScope(QualType T, QualType ObjectType, @@ -2200,6 +2211,60 @@ bool TreeTransform::TransformExprs(Expr **Inputs, break; } + if (PackExpansionExpr *Expansion = dyn_cast(Inputs[I])) { + Expr *Pattern = Expansion->getPattern(); + + llvm::SmallVector Unexpanded; + getSema().collectUnexpandedParameterPacks(Pattern, Unexpanded); + assert(!Unexpanded.empty() && "Pack expansion without parameter packs?"); + + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + unsigned NumExpansions = 0; + if (getDerived().TryExpandParameterPacks(Expansion->getEllipsisLoc(), + Pattern->getSourceRange(), + Unexpanded.data(), + Unexpanded.size(), + Expand, NumExpansions)) + return true; + + if (!Expand) { + // The transform has determined that we should perform a simple + // transformation on the pack expansion, producing another pack + // expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + ExprResult OutPattern = getDerived().TransformExpr(Pattern); + if (OutPattern.isInvalid()) + return true; + + ExprResult Out = getDerived().RebuildPackExpansion(OutPattern.get(), + Expansion->getEllipsisLoc()); + if (Out.isInvalid()) + return true; + + if (ArgChanged) + *ArgChanged = true; + Outputs.push_back(Out.get()); + continue; + } + + // The transform has determined that we should perform an elementwise + // expansion of the pattern. Do so. + for (unsigned I = 0; I != NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I); + ExprResult Out = getDerived().TransformExpr(Pattern); + if (Out.isInvalid()) + return true; + + if (ArgChanged) + *ArgChanged = true; + Outputs.push_back(Out.get()); + } + + continue; + } + ExprResult Result = getDerived().TransformExpr(Inputs[I]); if (Result.isInvalid()) return true; diff --git a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp index 06a7bf367..440bd4b5d 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/p4.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/p4.cpp @@ -20,6 +20,20 @@ struct is_same { // FIXME: Many more bullets to go +// In an initializer-list (8.5); the pattern is an initializer-clause. +// Note: this also covers expression-lists, since expression-list is +// just defined as initializer-list. +void five_args(int, int, int, int, int); // expected-note{{candidate function not viable: requires 5 arguments, but 6 were provided}} + +template +void initializer_list_expansion() { + int values[5] = { Values... }; // expected-error{{excess elements in array initializer}} + five_args(Values...); // expected-error{{no matching function for call to 'five_args'}} +} + +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 template-argument-list (14.3); the pattern is a template-argument. template struct tuple_of_refs { -- 2.11.4.GIT