Implement support for pack expansions in initializer lists and
authorDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 19:31:53 +0000 (19:31 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 19:31:53 +0000 (19:31 +0000)
expression lists.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@122764 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Parse/ParseExpr.cpp
lib/Parse/ParseInit.cpp
lib/Sema/TreeTransform.h
test/CXX/temp/temp.decls/temp.variadic/p4.cpp

index 92bbbd7bf9ac9c107640fca30f30ee5bcea3e744..be5c7d7808f8350dcdc6eecd779f02b30a642473 100644 (file)
@@ -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<Expr*> &Exprs,
                             llvm::SmallVectorImpl<SourceLocation> &CommaLocs,
@@ -1710,6 +1710,8 @@ bool Parser::ParseExpressionList(llvm::SmallVectorImpl<Expr*> &Exprs,
     }
     
     ExprResult Expr(ParseAssignmentExpression());
+    if (Tok.is(tok::ellipsis))
+      Expr = Actions.ActOnPackExpansion(Expr.get(), ConsumeToken());    
     if (Expr.isInvalid())
       return true;
 
index c2675f33e78d08bd2eb626cf2996faf1b0cacfdf..82dda2b793d3a366c9aa201d7c307cf8f1baae9d 100644 (file)
@@ -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());
index 03f5fc0c9a037907b1a1c5b3eae2dd47ce9b1639..9088ae0fef26b8c6555b18b114b5c3bd6c4cd77e 100644 (file)
@@ -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<Derived>::TransformExprs(Expr **Inputs,
       break;
     }
     
+    if (PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(Inputs[I])) {
+      Expr *Pattern = Expansion->getPattern();
+        
+      llvm::SmallVector<UnexpandedParameterPack, 2> 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;
index 06a7bf3679394ffec1d44d0c23418d11033c6167..440bd4b5dbfed338748dbf0b830a6b91dd4f8bbf 100644 (file)
@@ -20,6 +20,20 @@ struct is_same<T, T> {
 
 // 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<int ...Values>
+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<typename ...Types>
 struct tuple_of_refs {