]> granicus.if.org Git - clang/commitdiff
Implement support for pack expansions whose pattern is a non-type
authorDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 17:17:50 +0000 (17:17 +0000)
committerDouglas Gregor <dgregor@apple.com>
Mon, 3 Jan 2011 17:17:50 +0000 (17:17 +0000)
template argument (described by an expression, of course). For
example:

  template<int...> struct int_tuple { };

  template<int ...Values>
  struct square {
    typedef int_tuple<(Values*Values)...> type;
  };

It also lays the foundation for pack expansions in an initializer-list.

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

21 files changed:
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/StmtNodes.td
include/clang/Sema/Sema.h
include/clang/Serialization/ASTBitCodes.h
lib/AST/ExprCXX.cpp
lib/AST/ExprClassification.cpp
lib/AST/ExprConstant.cpp
lib/AST/StmtPrinter.cpp
lib/AST/StmtProfile.cpp
lib/AST/TemplateBase.cpp
lib/CodeGen/Mangle.cpp
lib/Sema/SemaTemplateDeduction.cpp
lib/Sema/SemaTemplateVariadic.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Checkers/ExprEngine.cpp
test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp
tools/libclang/CXCursor.cpp

index eea15effac3275ba8c98f406ba71758145fc9db5..bd7d3f09c386d82ab5cef8352a85fd1789a2b109 100644 (file)
@@ -2571,6 +2571,61 @@ public:
   virtual child_iterator child_end();
 };
 
+/// \brief Represents a C++0x pack expansion that produces a sequence of 
+/// expressions.
+///
+/// A pack expansion expression contains a pattern (which itself is an
+/// expression) followed by an ellipsis. For example:
+///
+/// \code
+/// template<typename F, typename ...Types>
+/// void forward(F f, Types &&...args) {
+///   f(static_cast<Types&&>(args)...);
+/// }
+/// \endcode
+///
+/// Here, the argument to the function object \c f is a pack expansion whose
+/// pattern is \c static_cast<Types&&>(args). When the \c forward function 
+/// template is instantiated, the pack expansion will instantiate to zero or
+/// or more function arguments to the function object \c f.
+class PackExpansionExpr : public Expr {
+  SourceLocation EllipsisLoc;
+  Stmt *Pattern;
+  
+  friend class ASTStmtReader;
+  
+public:
+  PackExpansionExpr(QualType T, Expr *Pattern, SourceLocation EllipsisLoc)
+    : Expr(PackExpansionExprClass, T, Pattern->getValueKind(), 
+           Pattern->getObjectKind(), /*TypeDependent=*/true, 
+           /*ValueDependent=*/true, /*ContainsUnexpandedParameterPack=*/false),
+      EllipsisLoc(EllipsisLoc),
+      Pattern(Pattern) { }
+
+  PackExpansionExpr(EmptyShell Empty) : Expr(PackExpansionExprClass, Empty) { }
+  
+  /// \brief Retrieve the pattern of the pack expansion.
+  Expr *getPattern() { return reinterpret_cast<Expr *>(Pattern); }
+
+  /// \brief Retrieve the pattern of the pack expansion.
+  const Expr *getPattern() const { return reinterpret_cast<Expr *>(Pattern); }
+
+  /// \brief Retrieve the location of the ellipsis that describes this pack
+  /// expansion.
+  SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
+  
+  virtual SourceRange getSourceRange() const;
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == PackExpansionExprClass;
+  }
+  static bool classof(const PackExpansionExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+};
+  
 inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() {
   if (isa<UnresolvedLookupExpr>(this))
     return cast<UnresolvedLookupExpr>(this)->getExplicitTemplateArgs();
index 435ebc65ea497bbe12e64939e024e4ad5e429913..258e186b7aca2ba66baacd0c20094a4ef002fcf5 100644 (file)
@@ -1820,6 +1820,7 @@ DEF_TRAVERSE_STMT(UnaryOperator, { })
 DEF_TRAVERSE_STMT(BinaryOperator, { })
 DEF_TRAVERSE_STMT(CompoundAssignOperator, { })
 DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
+DEF_TRAVERSE_STMT(PackExpansionExpr, { })
 
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, { })
index f2d3c0085cd572690ca0a8fb4aae052362cc7231..eb123b9fe9f32a7ba45946c73d558f87a6628e21 100644 (file)
@@ -1871,7 +1871,7 @@ def err_ellipsis_in_declarator_not_parameter : Error<
 
 // Unsupported variadic templates features
 def err_pack_expansion_unsupported : Error<
-  "clang does not yet support %select{non-type|template}0 pack expansions">;
+  "clang does not yet support template pack expansions">;
 def err_pack_expansion_instantiation_unsupported : Error<
   "clang cannot yet instantiate pack expansions">;
 def err_pack_expansion_mismatch_unsupported : Error<
index 0e2fb575e64a4274cf15500687fab6cec8389b54..890f02b75d3af6ba5541bc295eee8241176be5f0 100644 (file)
@@ -111,6 +111,7 @@ def OverloadExpr : DStmt<Expr, 1>;
 def UnresolvedLookupExpr : DStmt<OverloadExpr>;
 def UnresolvedMemberExpr : DStmt<OverloadExpr>;
 def CXXNoexceptExpr : DStmt<Expr>;
+def PackExpansionExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
index 57f480f95df1b06d5ef7c07df549cc01e9a81fba..05bb1258c1b3fb2567035ff179b119acf9ea8d98 100644 (file)
@@ -3279,7 +3279,7 @@ public:
   ParsedTemplateArgument ActOnPackExpansion(const ParsedTemplateArgument &Arg,
                                             SourceLocation EllipsisLoc);
 
-  /// \brief Invoked when parsing a type follows by an ellipsis, which
+  /// \brief Invoked when parsing a type followed by an ellipsis, which
   /// creates a pack expansion.
   ///
   /// \param Type The type preceding the ellipsis, which will become
@@ -3293,6 +3293,15 @@ public:
   TypeSourceInfo *CheckPackExpansion(TypeSourceInfo *Pattern,
                                      SourceLocation EllipsisLoc);
   
+  /// \brief Invoked when parsing an expression followed by an ellipsis, which
+  /// creates a pack expansion.
+  ///
+  /// \param Pattern The expression preceding the ellipsis, which will become
+  /// the pattern of the pack expansion.
+  ///
+  /// \param EllipsisLoc The location of the ellipsis.
+  ExprResult ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc);
+  
   /// \brief Determine whether we could expand a pack expansion with the
   /// given set of parameter packs into separate arguments by repeatedly
   /// transforming the pattern.
index 8665fb646561effcc5b3b78bbde4f10da63d2d80..fcc8d53d42bd04deaa9737576fa55486cd21d0e7 100644 (file)
@@ -929,7 +929,9 @@ namespace clang {
       EXPR_CXX_NOEXCEPT,          // CXXNoexceptExpr
 
       EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
-      EXPR_BINARY_TYPE_TRAIT      // BinaryTypeTraitExpr
+      EXPR_BINARY_TYPE_TRAIT,     // BinaryTypeTraitExpr
+      
+      EXPR_PACK_EXPANSION         // PackExpansionExpr
     };
 
     /// \brief The kinds of designators that can occur in a
index cbd33f2dc4f9612bd26a44af68cbbbcc90822443..4592e5f5715d12f85e12abeb35d254742a2b4167 100644 (file)
@@ -1025,3 +1025,15 @@ Stmt::child_iterator CXXNoexceptExpr::child_begin() {
 Stmt::child_iterator CXXNoexceptExpr::child_end() {
   return child_iterator(&Operand + 1);
 }
+
+SourceRange PackExpansionExpr::getSourceRange() const {
+  return SourceRange(Pattern->getLocStart(), EllipsisLoc);
+}
+
+Stmt::child_iterator PackExpansionExpr::child_begin() {
+  return child_iterator(&Pattern);
+}
+
+Stmt::child_iterator PackExpansionExpr::child_end() {
+  return child_iterator(&Pattern + 1);
+}
index 4cf393d788fdf90ac48e95555a6e481c0b7fa968..f437804c2915e941f3053f015f8744290acc0c1f 100644 (file)
@@ -304,6 +304,9 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
       
   case Expr::CXXUuidofExprClass:
     return Cl::CL_LValue;
+      
+  case Expr::PackExpansionExprClass:
+    return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
   }
   
   llvm_unreachable("unhandled expression kind in classification");
index 8797880411c53ed0ad9ebed5c0a115ce2dce4438..c39b3983d37d1e082d0803e68a10645ba76d5243 100644 (file)
@@ -2634,6 +2634,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::BlockDeclRefExprClass:
   case Expr::NoStmtClass:
   case Expr::OpaqueValueExprClass:
+  case Expr::PackExpansionExprClass:
     return ICEDiag(2, E->getLocStart());
 
   case Expr::GNUNullExprClass:
index 6bbe8f9cd9b3f6615d02b6ddf7b190383ce52b00..cc905267369857e555da751de1f9e7cd0217a342 100644 (file)
@@ -1246,6 +1246,11 @@ void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   OS << ")";
 }
 
+void StmtPrinter::VisitPackExpansionExpr(clang::PackExpansionExpr *E) {
+  PrintExpr(E->getPattern());
+  OS << "...";
+}
+
 // Obj-C
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
index 66c067b7b13940c64461bdc3e0179885b945b66b..820eb0641681c5ee0133ee894c42cffed9d59d7d 100644 (file)
@@ -832,6 +832,10 @@ void StmtProfiler::VisitCXXNoexceptExpr(CXXNoexceptExpr *S) {
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) {
+  VisitExpr(S);
+}
+
 void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);  
 }
index 04e8a389cfb030189bd013e3989f1d9b43cfa080..c9715199612b0d1670c10c5350c74d8bb9a4da22 100644 (file)
@@ -17,6 +17,7 @@
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
 #include "clang/AST/TypeLoc.h"
 #include "clang/Basic/Diagnostic.h"
 #include "llvm/ADT/FoldingSet.h"
@@ -72,15 +73,14 @@ bool TemplateArgument::isPackExpansion() const {
     return false;
       
   case Type:
-    return llvm::isa<PackExpansionType>(getAsType());
+    return isa<PackExpansionType>(getAsType());
       
   case Template:
     // FIXME: Template template pack expansions.
     break;
     
   case Expression:
-    // FIXME: Expansion pack expansions.
-    break;  
+    return isa<PackExpansionExpr>(getAsExpr());
   }
   
   return false;
@@ -199,9 +199,11 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
       return getAsType()->getAs<PackExpansionType>()->getPattern();
       
     case Expression:
+      return cast<PackExpansionExpr>(getAsExpr())->getPattern();
+      
     case Template:
       // FIXME: Variadic templates.
-      llvm_unreachable("Expression and template pack expansions unsupported");
+      llvm_unreachable("Template pack expansions unsupported");
       
     case Declaration:
     case Integral:
@@ -343,10 +345,14 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
                                PatternTSInfo);
   }
       
-  case TemplateArgument::Expression:
+  case TemplateArgument::Expression: {
+    Expr *Pattern = cast<PackExpansionExpr>(Argument.getAsExpr())->getPattern();
+    return TemplateArgumentLoc(Pattern, Pattern);
+  }
+      
   case TemplateArgument::Template:
     // FIXME: Variadic templates.
-      llvm_unreachable("Expression and template pack expansions unsupported");
+      llvm_unreachable("Template pack expansions unsupported");
     
   case TemplateArgument::Declaration:
   case TemplateArgument::Integral:
index a45403e467e226e9e6fd035e61848affd62f9c67..0aa9f402f96a426a418a911325fcc204a60b44d7 100644 (file)
@@ -2043,7 +2043,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
     Out << "LDnE";
     break;
   }
-
+      
+  case Expr::PackExpansionExprClass:
+    Out << "sp";
+    mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
+    break;
   }
 }
 
index 4a667cdf57ce34dabb0029c5239677f5d7cad24e..99b6daceed92502d6ab2813072d7202935e114fc 100644 (file)
@@ -2926,6 +2926,10 @@ MarkUsedTemplateParameters(Sema &SemaRef,
                            bool OnlyDeduced,
                            unsigned Depth,
                            llvm::SmallVectorImpl<bool> &Used) {
+  // We can deduce from a pack expansion.
+  if (const PackExpansionExpr *Expansion = dyn_cast<PackExpansionExpr>(E))
+    E = Expansion->getPattern();
+      
   // FIXME: if !OnlyDeduced, we have to walk the whole subexpression to 
   // find other occurrences of template parameters.
   const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E);
index 3dac8a0408089b58abd865a41dda3b75913ce13a..030a0423f74b80c63670b2be1f4125f34fad3835 100644 (file)
@@ -79,9 +79,6 @@ namespace {
     
     // FIXME: Record occurrences of template template parameter packs.
 
-    // FIXME: Once we have pack expansions in the AST, block their
-    // traversal.
-
     //------------------------------------------------------------------------
     // Pruning the search for unexpanded parameter packs.
     //------------------------------------------------------------------------
@@ -299,14 +296,17 @@ Sema::ActOnPackExpansion(const ParsedTemplateArgument &Arg,
                                   Arg.getLocation());
   }
 
-  case ParsedTemplateArgument::NonType:
-    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
-      << 0;
-    return ParsedTemplateArgument();
-
+  case ParsedTemplateArgument::NonType: {
+    ExprResult Result = ActOnPackExpansion(Arg.getAsExpr(), EllipsisLoc);
+    if (Result.isInvalid())
+      return ParsedTemplateArgument();
+    
+    return ParsedTemplateArgument(Arg.getKind(), Result.get(), 
+                                  Arg.getLocation());
+  }
+    
   case ParsedTemplateArgument::Template:
-    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported)
-      << 1;
+    Diag(EllipsisLoc, diag::err_pack_expansion_unsupported);
     return ParsedTemplateArgument();
   }
   llvm_unreachable("Unhandled template argument kind?");
@@ -352,6 +352,24 @@ TypeSourceInfo *Sema::CheckPackExpansion(TypeSourceInfo *Pattern,
   return TSResult;
 }
 
+ExprResult Sema::ActOnPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc) {
+  if (!Pattern)
+    return ExprError();
+  
+  // C++0x [temp.variadic]p5:
+  //   The pattern of a pack expansion shall name one or more
+  //   parameter packs that are not expanded by a nested pack
+  //   expansion.
+  if (!Pattern->containsUnexpandedParameterPack()) {
+    Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
+    << Pattern->getSourceRange();
+    return ExprError();
+  }
+  
+  // Create the pack expansion expression and source-location information.
+  return Owned(new (Context) PackExpansionExpr(Context.DependentTy, Pattern,
+                                               EllipsisLoc));
+}
 
 bool Sema::CheckParameterPacksForExpansion(SourceLocation EllipsisLoc,
                                            SourceRange PatternRange,
index de13084fbc925ff079e41e66a7db36fc15687757..992b8499046867911dbf249b3d816bce3ab74ab2 100644 (file)
@@ -6437,6 +6437,13 @@ TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
   return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get());
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformPackExpansionExpr(PackExpansionExpr *E) {
+  llvm_unreachable("pack expansion expression in unhandled context");
+  return ExprError();
+}
+  
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
index aa669b34b3d1f4ce8c22ce688f42b16cf80c171b..4703c633fbeee500fed68df11a7e66359d3a79b5 100644 (file)
@@ -176,7 +176,8 @@ namespace clang {
     void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
-
+    void VisitPackExpansionExpr(PackExpansionExpr *E);
+    
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   };
 }
@@ -1287,6 +1288,12 @@ void ASTStmtReader::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   E->Operand = Reader.ReadSubExpr();
 }
 
+void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
+  VisitExpr(E);
+  E->EllipsisLoc = ReadSourceLocation(Record, Idx);
+  E->Pattern = Reader.ReadSubExpr();  
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
 }
@@ -1809,6 +1816,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) CXXNoexceptExpr(Empty);
       break;
 
+    case EXPR_PACK_EXPANSION:
+      S = new (Context) PackExpansionExpr(Empty);
+      break;
+        
     case EXPR_OPAQUE_VALUE:
       S = new (Context) OpaqueValueExpr(Empty);
       break;
index 89c293fe6caaf988da7a75a177f38f68c5bf2012..27261dbb2a9c512a876b898755ec707ee4bef42d 100644 (file)
@@ -150,7 +150,7 @@ namespace clang {
     void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
-
+    void VisitPackExpansionExpr(PackExpansionExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   };
 }
@@ -1296,6 +1296,13 @@ void ASTStmtWriter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   Code = serialization::EXPR_CXX_NOEXCEPT;
 }
 
+void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) {
+  VisitExpr(E);
+  Writer.AddSourceLocation(E->getEllipsisLoc(), Record);
+  Writer.AddStmt(E->getPattern());
+  Code = serialization::EXPR_PACK_EXPANSION;
+}
+
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   Code = serialization::EXPR_OPAQUE_VALUE;
index c522e72210feef2765454eee41e761ad201cdc08..9fef6d87bede82f2a2ab50203f8872d5ef43e85b 100644 (file)
@@ -771,6 +771,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred,
     case Stmt::UnresolvedLookupExprClass:
     case Stmt::UnresolvedMemberExprClass:
     case Stmt::CXXNoexceptExprClass:
+    case Stmt::PackExpansionExprClass:
     {
       SaveAndRestore<bool> OldSink(Builder->BuildSinks);
       Builder->BuildSinks = true;
index 6a5e989d1a1889daeabd65664993c2324a353ec0..d9a3b5c27fbf98fd048166ded2aa6c96406b546e 100644 (file)
@@ -64,3 +64,52 @@ namespace Replace {
   int check0[is_same<EverythingToInt<tuple<double, float>>::type, 
              tuple<int, int>>::value? 1 : -1];
 }
+
+namespace Multiply {
+  template<int ...Values>
+  struct double_values {
+    typedef int_tuple<Values*2 ...> type;
+  };
+
+  int check0[is_same<double_values<1, 2, -3>::type, 
+                     int_tuple<2, 4, -6>>::value? 1 : -1];
+
+  template<int ...Values>
+  struct square {
+    typedef int_tuple<(Values*Values)...> type;
+  };
+
+  int check1[is_same<square<1, 2, -3>::type, 
+                     int_tuple<1, 4, 9>>::value? 1 : -1];
+
+  template<typename IntTuple> struct square_tuple;
+
+  template<int ...Values>
+  struct square_tuple<int_tuple<Values...>> {
+    typedef int_tuple<(Values*Values)...> type;
+  };
+
+  int check2[is_same<square_tuple<int_tuple<1, 2, -3>>::type, 
+                     int_tuple<1, 4, 9>>::value? 1 : -1];
+}
+
+namespace Indices {
+  template<unsigned I, unsigned N, typename IntTuple>
+  struct build_indices_impl;
+
+  template<unsigned I, unsigned N, int ...Indices>
+  struct build_indices_impl<I, N, int_tuple<Indices...> >
+    : build_indices_impl<I+1, N, int_tuple<Indices..., I> > {
+  };
+
+  template<unsigned N, int ...Indices> 
+  struct build_indices_impl<N, N, int_tuple<Indices...> > {
+    typedef int_tuple<Indices...> type;
+  };
+
+  template<unsigned N>
+  struct build_indices : build_indices_impl<0, N, int_tuple<> > { };
+
+  int check0[is_same<build_indices<5>::type,
+                     int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1];
+}
index 86b5ce1c4c7811a18ec675aa585018ad8e102daf..22758f9ba4b32ccc32440aaf2bfb5d5f6e9b1d9e 100644 (file)
@@ -164,6 +164,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::ShuffleVectorExprClass: 
   case Stmt::BlockExprClass:  
   case Stmt::OpaqueValueExprClass:
+  case Stmt::PackExpansionExprClass:
     K = CXCursor_UnexposedExpr;
     break;