]> granicus.if.org Git - clang/commitdiff
Implement the sizeof...(pack) expression to compute the length of a
authorDouglas Gregor <dgregor@apple.com>
Tue, 4 Jan 2011 17:33:58 +0000 (17:33 +0000)
committerDouglas Gregor <dgregor@apple.com>
Tue, 4 Jan 2011 17:33:58 +0000 (17:33 +0000)
parameter pack.

Note that we're missing proper libclang support for the new
SizeOfPackExpr expression node.

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

20 files changed:
include/clang/AST/ExprCXX.h
include/clang/AST/RecursiveASTVisitor.h
include/clang/Basic/DiagnosticParseKinds.td
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/Parse/ParseExpr.cpp
lib/Sema/SemaTemplateVariadic.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp [new file with mode: 0644]
tools/libclang/CIndex.cpp
tools/libclang/CXCursor.cpp

index 5311d9c3a83e1faa2aedd87c95fc1cd5eddb03c9..619a21245faa639106d9489013fb5675794271ae 100644 (file)
@@ -2642,6 +2642,96 @@ inline ExplicitTemplateArgumentList &OverloadExpr::getExplicitTemplateArgs() {
     return cast<UnresolvedMemberExpr>(this)->getExplicitTemplateArgs();
 }
 
+/// \brief Represents an expression that computes the length of a parameter 
+/// pack.
+///
+/// \code
+/// template<typename ...Types>
+/// struct count {
+///   static const unsigned value = sizeof...(Types);
+/// };
+/// \endcode
+class SizeOfPackExpr : public Expr {
+  /// \brief The location of the 'sizeof' keyword.
+  SourceLocation OperatorLoc;
+  
+  /// \brief The location of the name of the parameter pack.
+  SourceLocation PackLoc;
+  
+  /// \brief The location of the closing parenthesis.
+  SourceLocation RParenLoc;
+  
+  /// \brief The length of the parameter pack, if known.
+  ///
+  /// When this expression is value-dependent, the length of the parameter pack
+  /// is unknown. When this expression is not value-dependent, the length is
+  /// known.
+  unsigned Length;
+  
+  /// \brief The parameter pack itself.
+  NamedDecl *Pack;
+  
+  friend class ASTStmtReader;
+  friend class ASTStmtWriter;
+  
+public:
+  /// \brief Creates a value-dependent expression that computes the length of
+  /// the given parameter pack.
+  SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, 
+                 SourceLocation PackLoc, SourceLocation RParenLoc)
+    : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
+           /*TypeDependent=*/false, /*ValueDependent=*/true,
+           /*ContainsUnexpandedParameterPack=*/false),
+      OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
+      Length(0), Pack(Pack) { }
+
+  /// \brief Creates an expression that computes the length of
+  /// the given parameter pack, which is already known.
+  SizeOfPackExpr(QualType SizeType, SourceLocation OperatorLoc, NamedDecl *Pack, 
+                 SourceLocation PackLoc, SourceLocation RParenLoc,
+                 unsigned Length)
+  : Expr(SizeOfPackExprClass, SizeType, VK_RValue, OK_Ordinary,
+         /*TypeDependent=*/false, /*ValueDependent=*/false,
+         /*ContainsUnexpandedParameterPack=*/false),
+    OperatorLoc(OperatorLoc), PackLoc(PackLoc), RParenLoc(RParenLoc),
+    Length(Length), Pack(Pack) { }
+
+  /// \brief Create an empty expression.
+  SizeOfPackExpr(EmptyShell Empty) : Expr(SizeOfPackExprClass, Empty) { }
+  
+  /// \brief Determine the location of the 'sizeof' keyword.
+  SourceLocation getOperatorLoc() const { return OperatorLoc; }
+
+  /// \brief Determine the location of the parameter pack.
+  SourceLocation getPackLoc() const { return PackLoc; }
+  
+  /// \brief Determine the location of the right parenthesis.
+  SourceLocation getRParenLoc() const { return RParenLoc; }
+  
+  /// \brief Retrieve the parameter pack.
+  NamedDecl *getPack() const { return Pack; }
+  
+  /// \brief Retrieve the length of the parameter pack.
+  ///
+  /// This routine may only be invoked when 
+  unsigned getPackLength() const {
+    assert(!isValueDependent() && 
+           "Cannot get the length of a value-dependent pack size expression");
+    return Length;
+  }
+  
+  virtual SourceRange getSourceRange() const;
+  
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == SizeOfPackExprClass;
+  }
+  static bool classof(const SizeOfPackExpr *) { return true; }
+  
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+};
+  
 }  // end namespace clang
 
 #endif
index 258e186b7aca2ba66baacd0c20094a4ef002fcf5..894ecdd29abc368e32608a8a4bc8fee43ac00929 100644 (file)
@@ -1821,6 +1821,7 @@ DEF_TRAVERSE_STMT(BinaryOperator, { })
 DEF_TRAVERSE_STMT(CompoundAssignOperator, { })
 DEF_TRAVERSE_STMT(CXXNoexceptExpr, { })
 DEF_TRAVERSE_STMT(PackExpansionExpr, { })
+DEF_TRAVERSE_STMT(SizeOfPackExpr, { })
 
 // These literals (all of them) do not need any action.
 DEF_TRAVERSE_STMT(IntegerLiteral, { })
index e8eb111795903ee10cc6a2e68753b2a873982728..59ce1ce0a358f50aa54825105999b685b38e3ac1 100644 (file)
@@ -392,6 +392,13 @@ def warn_deleted_function_accepted_as_extension: ExtWarn<
 def err_scoped_enum_missing_identifier : Error<
   "scoped enumeration requires a name">;
 
+def err_expected_parameter_pack : Error<
+  "expected the name of a parameter pack">;
+def err_paren_sizeof_parameter_pack : Error<
+  "missing parentheses around the size of parameter pack %0">;
+def err_sizeof_parameter_pack : Error<
+  "expected parenthesized parameter pack name in 'sizeof...' expression">;
+
 // Language specific pragmas
 // - Generic warnings
 def warn_pragma_expected_lparen : Warning<
index 25594642987cd174b595658435c40ab085090f0f..cc405ee82a7aea6e3b77def8b5fccde7689135c7 100644 (file)
@@ -1871,6 +1871,9 @@ def err_function_parameter_pack_without_parameter_packs : Error<
 def err_ellipsis_in_declarator_not_parameter : Error<
   "only function and template parameters can be parameter packs">;
 
+def err_sizeof_pack_no_pack_name : Error<
+  "%0 does not refer to the name of a parameter pack">;
+
 // Unsupported variadic templates features
 def err_pack_expansion_unsupported : Error<
   "clang does not yet support template pack expansions">;
@@ -3568,6 +3571,9 @@ def err_using_directive_suggest : Error<
 def err_using_directive_member_suggest : Error<
   "no namespace named %0 in %1; did you mean %2?">;
 def note_namespace_defined_here : Note<"namespace %0 defined here">;
+def err_sizeof_pack_no_pack_name_suggest : Error<
+  "%0 does not refer to the name of a parameter pack; did you mean %1?">;
+def note_parameter_pack_here : Note<"parameter pack %0 declared here">;
 
 } // end of sema category
 } // end of sema component.
index 890f02b75d3af6ba5541bc295eee8241176be5f0..9322db12c59a4bff3b0a578cd88131c0d04d811a 100644 (file)
@@ -112,6 +112,7 @@ def UnresolvedLookupExpr : DStmt<OverloadExpr>;
 def UnresolvedMemberExpr : DStmt<OverloadExpr>;
 def CXXNoexceptExpr : DStmt<Expr>;
 def PackExpansionExpr : DStmt<Expr>;
+def SizeOfPackExpr : DStmt<Expr>;
 
 // Obj-C Expressions.
 def ObjCStringLiteral : DStmt<Expr>;
index 13b440c8ab2e3b600e43be0e5438752869270ac6..c11ab161a5a6828856dfd6547c954f25edbbe3b6 100644 (file)
@@ -1817,7 +1817,11 @@ public:
 
   bool CheckSizeOfAlignOfOperand(QualType type, SourceLocation OpLoc,
                                  SourceRange R, bool isSizeof);
-
+  ExprResult ActOnSizeofParameterPackExpr(Scope *S,
+                                          SourceLocation OpLoc,
+                                          IdentifierInfo &Name,
+                                          SourceLocation NameLoc,
+                                          SourceLocation RParenLoc);
   ExprResult ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
                                  tok::TokenKind Kind, Expr *Input);
 
index fcc8d53d42bd04deaa9737576fa55486cd21d0e7..bbe7c1d2f816a7a43596b220eeb1871198786917 100644 (file)
@@ -931,7 +931,8 @@ namespace clang {
       EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
       EXPR_BINARY_TYPE_TRAIT,     // BinaryTypeTraitExpr
       
-      EXPR_PACK_EXPANSION         // PackExpansionExpr
+      EXPR_PACK_EXPANSION,        // PackExpansionExpr
+      EXPR_SIZEOF_PACK            // SizeOfPackExpr
     };
 
     /// \brief The kinds of designators that can occur in a
index 4592e5f5715d12f85e12abeb35d254742a2b4167..fcedb8e7bb64b88b70c7d06d0f52626441b1b563 100644 (file)
@@ -1037,3 +1037,15 @@ Stmt::child_iterator PackExpansionExpr::child_begin() {
 Stmt::child_iterator PackExpansionExpr::child_end() {
   return child_iterator(&Pattern + 1);
 }
+
+SourceRange SizeOfPackExpr::getSourceRange() const {
+  return SourceRange(OperatorLoc, RParenLoc);
+}
+
+Stmt::child_iterator SizeOfPackExpr::child_begin() {
+  return child_iterator();
+}
+
+Stmt::child_iterator SizeOfPackExpr::child_end() {
+  return child_iterator();
+}
index f437804c2915e941f3053f015f8744290acc0c1f..a9ebe6fdb3cf963962ad33ce0a61934cf5641a89 100644 (file)
@@ -151,6 +151,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) {
   case Expr::ObjCStringLiteralClass:
   case Expr::ParenListExprClass:
   case Expr::InitListExprClass:
+  case Expr::SizeOfPackExprClass:
     return Cl::CL_PRValue;
 
     // Next come the complicated cases.
index c39b3983d37d1e082d0803e68a10645ba76d5243..23a4b09cb35b7c493bf90d4678a4ea8b4e84f84f 100644 (file)
@@ -291,6 +291,8 @@ public:
       if (Visit(E->getInit(i))) return true;
     return false;
   }
+    
+  bool VisitSizeOfPackExpr(SizeOfPackExpr *) { return false; }
 };
 
 } // end anonymous namespace
@@ -965,7 +967,8 @@ public:
   bool VisitUnaryImag(const UnaryOperator *E);
 
   bool VisitCXXNoexceptExpr(const CXXNoexceptExpr *E);
-
+  bool VisitSizeOfPackExpr(const SizeOfPackExpr *E);
+    
 private:
   CharUnits GetAlignOfExpr(const Expr *E);
   CharUnits GetAlignOfType(QualType T);
@@ -1761,6 +1764,10 @@ bool IntExprEvaluator::VisitUnaryImag(const UnaryOperator *E) {
   return Success(0, E);
 }
 
+bool IntExprEvaluator::VisitSizeOfPackExpr(const SizeOfPackExpr *E) {
+  return Success(E->getPackLength(), E);
+}
+
 bool IntExprEvaluator::VisitCXXNoexceptExpr(const CXXNoexceptExpr *E) {
   return Success(E->getValue(), E);
 }
@@ -2637,6 +2644,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
   case Expr::PackExpansionExprClass:
     return ICEDiag(2, E->getLocStart());
 
+  case Expr::SizeOfPackExprClass:
   case Expr::GNUNullExprClass:
     // GCC considers the GNU __null value to be an integral constant expression.
     return NoDiag();
index cc905267369857e555da751de1f9e7cd0217a342..2c8504357ef0d031ffcb9d78522d7f9de3941c9f 100644 (file)
@@ -1246,11 +1246,15 @@ void StmtPrinter::VisitCXXNoexceptExpr(CXXNoexceptExpr *E) {
   OS << ")";
 }
 
-void StmtPrinter::VisitPackExpansionExpr(clang::PackExpansionExpr *E) {
+void StmtPrinter::VisitPackExpansionExpr(PackExpansionExpr *E) {
   PrintExpr(E->getPattern());
   OS << "...";
 }
 
+void StmtPrinter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+  OS << "sizeof...(" << E->getPack()->getNameAsString() << ")";
+}
+
 // Obj-C
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
index 820eb0641681c5ee0133ee894c42cffed9d59d7d..ab24a69124082b001e65521c866f1c42e53196d3 100644 (file)
@@ -836,6 +836,11 @@ void StmtProfiler::VisitPackExpansionExpr(PackExpansionExpr *S) {
   VisitExpr(S);
 }
 
+void StmtProfiler::VisitSizeOfPackExpr(SizeOfPackExpr *S) {
+  VisitExpr(S);
+  VisitDecl(S->getPack());
+}
+
 void StmtProfiler::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);  
 }
index be5c7d7808f8350dcdc6eecd779f02b30a642473..7133b610225618a05cb9323c3d5ec5782dba2a32 100644 (file)
@@ -444,6 +444,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
 ///         unary-operator cast-expression
 ///         'sizeof' unary-expression
 ///         'sizeof' '(' type-name ')'
+/// [C++0x] 'sizeof' '...' '(' identifier ')'
 /// [GNU]   '__alignof' unary-expression
 /// [GNU]   '__alignof' '(' type-name ')'
 /// [C++0x] 'alignof' '(' type-id ')'
@@ -1291,6 +1292,7 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
 ///       unary-expression:  [C99 6.5.3]
 ///         'sizeof' unary-expression
 ///         'sizeof' '(' type-name ')'
+/// [C++0x] 'sizeof' '...' '(' identifier ')'
 /// [GNU]   '__alignof' unary-expression
 /// [GNU]   '__alignof' '(' type-name ')'
 /// [C++0x] 'alignof' '(' type-id ')'
@@ -1301,6 +1303,46 @@ ExprResult Parser::ParseSizeofAlignofExpression() {
   Token OpTok = Tok;
   ConsumeToken();
 
+  // [C++0x] 'sizeof' '...' '(' identifier ')'
+  if (Tok.is(tok::ellipsis) && OpTok.is(tok::kw_sizeof)) {
+    SourceLocation EllipsisLoc = ConsumeToken();
+    SourceLocation LParenLoc, RParenLoc;
+    IdentifierInfo *Name = 0;
+    SourceLocation NameLoc;
+    if (Tok.is(tok::l_paren)) {
+      LParenLoc = ConsumeParen();
+      if (Tok.is(tok::identifier)) {
+        Name = Tok.getIdentifierInfo();
+        NameLoc = ConsumeToken();
+        RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
+        if (RParenLoc.isInvalid())
+          RParenLoc = PP.getLocForEndOfToken(NameLoc);
+      } else {
+        Diag(Tok, diag::err_expected_parameter_pack);
+        SkipUntil(tok::r_paren);
+      }
+    } else if (Tok.is(tok::identifier)) {
+      Name = Tok.getIdentifierInfo();
+      NameLoc = ConsumeToken();
+      LParenLoc = PP.getLocForEndOfToken(EllipsisLoc);
+      RParenLoc = PP.getLocForEndOfToken(NameLoc);
+      Diag(LParenLoc, diag::err_paren_sizeof_parameter_pack)
+        << Name
+        << FixItHint::CreateInsertion(LParenLoc, "(")
+        << FixItHint::CreateInsertion(RParenLoc, ")");
+    } else {
+      Diag(Tok, diag::err_sizeof_parameter_pack);
+    }
+    
+    if (!Name)
+      return ExprError();
+    
+    return Actions.ActOnSizeofParameterPackExpr(getCurScope(),
+                                                OpTok.getLocation(), 
+                                                *Name, NameLoc,
+                                                RParenLoc);
+  }
+  
   bool isCastExpr;
   ParsedType CastTy;
   SourceRange CastRange;
index 92df1fd86368ec076acd7cf838944fcc9a8ca6f4..4e01ec2407dc576fcf4650c3941e1729d1761e5c 100644 (file)
@@ -10,6 +10,7 @@
 //===----------------------------------------------------------------------===/
 
 #include "clang/Sema/Sema.h"
+#include "clang/Sema/Lookup.h"
 #include "clang/Sema/ParsedTemplate.h"
 #include "clang/Sema/SemaInternal.h"
 #include "clang/Sema/Template.h"
@@ -533,3 +534,71 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
   
   return false;
 }
+
+/// \brief Called when an expression computing the size of a parameter pack
+/// is parsed.
+///
+/// \code
+/// template<typename ...Types> struct count {
+///   static const unsigned value = sizeof...(Types);
+/// };
+/// \endcode
+///
+//
+/// \param OpLoc The location of the "sizeof" keyword.
+/// \param Name The name of the parameter pack whose size will be determined.
+/// \param NameLoc The source location of the name of the parameter pack.
+/// \param RParenLoc The location of the closing parentheses.
+ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
+                                              SourceLocation OpLoc,
+                                              IdentifierInfo &Name,
+                                              SourceLocation NameLoc,
+                                              SourceLocation RParenLoc) {
+  // C++0x [expr.sizeof]p5:
+  //   The identifier in a sizeof... expression shall name a parameter pack.
+  
+  LookupResult R(*this, &Name, NameLoc, LookupOrdinaryName);
+  LookupName(R, S);
+  
+  NamedDecl *ParameterPack = 0;
+  switch (R.getResultKind()) {
+  case LookupResult::Found:
+    ParameterPack = R.getFoundDecl();
+    break;
+    
+  case LookupResult::NotFound:
+  case LookupResult::NotFoundInCurrentInstantiation:
+    if (DeclarationName CorrectedName = CorrectTypo(R, S, 0, 0, false, 
+                                                    CTC_NoKeywords)) {
+      // FIXME: Variadic templates function parameter packs.
+      if (NamedDecl *CorrectedResult = R.getAsSingle<NamedDecl>())
+        if (CorrectedResult->isTemplateParameterPack()) {
+          ParameterPack = CorrectedResult;
+          Diag(NameLoc, diag::err_sizeof_pack_no_pack_name_suggest)
+            << &Name << CorrectedName
+            << FixItHint::CreateReplacement(NameLoc, 
+                                            CorrectedName.getAsString());
+          Diag(ParameterPack->getLocation(), diag::note_parameter_pack_here)
+            << CorrectedName;
+        }
+    }
+      
+  case LookupResult::FoundOverloaded:
+  case LookupResult::FoundUnresolvedValue:
+    break;
+    
+  case LookupResult::Ambiguous:
+    DiagnoseAmbiguousLookup(R);
+    return ExprError();
+  }
+  
+  // FIXME: Variadic templates function parameter packs.
+  if (!ParameterPack || !ParameterPack->isTemplateParameterPack()) {
+    Diag(NameLoc, diag::err_sizeof_pack_no_pack_name)
+      << &Name;
+    return ExprError();
+  }
+
+  return new (Context) SizeOfPackExpr(Context.getSizeType(), OpLoc, 
+                                      ParameterPack, NameLoc, RParenLoc);
+}
index c38902a3e99c9331f30a4b88b7e58638e46c42d3..27fbf939f95118b9a8e502291aa7df45a532316c 100644 (file)
@@ -1913,6 +1913,16 @@ public:
     return SemaRef.BuildCXXNoexceptExpr(Range.getBegin(), Arg, Range.getEnd());
   }
 
+  /// \brief Build a new expression to compute the length of a parameter pack.
+  ExprResult RebuildSizeOfPackExpr(SourceLocation OperatorLoc, NamedDecl *Pack, 
+                                   SourceLocation PackLoc, 
+                                   SourceLocation RParenLoc,
+                                   unsigned Length) {
+    return new (SemaRef.Context) SizeOfPackExpr(SemaRef.Context.getSizeType(), 
+                                                OperatorLoc, Pack, PackLoc, 
+                                                RParenLoc, Length);
+  }
+                                   
   /// \brief Build a new Objective-C @encode expression.
   ///
   /// By default, performs semantic analysis to build the new expression.
@@ -6499,7 +6509,36 @@ TreeTransform<Derived>::TransformPackExpansionExpr(PackExpansionExpr *E) {
   llvm_unreachable("pack expansion expression in unhandled context");
   return ExprError();
 }
+
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) {
+  // If E is not value-dependent, then nothing will change when we transform it.
+  // Note: This is an instantiation-centric view.
+  if (!E->isValueDependent())
+    return SemaRef.Owned(E);
+
+  // Note: None of the implementations of TryExpandParameterPacks can ever
+  // produce a diagnostic when given only a single unexpanded parameter pack,
+  // so 
+  UnexpandedParameterPack Unexpanded(E->getPack(), E->getPackLoc());
+  bool ShouldExpand = false;
+  unsigned NumExpansions = 0;
+  if (getDerived().TryExpandParameterPacks(E->getOperatorLoc(), E->getPackLoc(), 
+                                           &Unexpanded, 1, 
+                                           ShouldExpand, NumExpansions))
+    return ExprError();
+  
+  if (!ShouldExpand)
+    return SemaRef.Owned(E);
   
+  // We now know the length of the parameter pack, so build a new expression
+  // that stores that length.
+  return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), 
+                                            E->getPackLoc(), E->getRParenLoc(), 
+                                            NumExpansions);
+}
+
 template<typename Derived>
 ExprResult
 TreeTransform<Derived>::TransformObjCStringLiteral(ObjCStringLiteral *E) {
index 4703c633fbeee500fed68df11a7e66359d3a79b5..5ed6f8e4d5e0c51a6b1cd1257a0306b3bcc4f3fa 100644 (file)
@@ -177,6 +177,7 @@ namespace clang {
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
     void VisitPackExpansionExpr(PackExpansionExpr *E);
+    void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   };
@@ -1294,6 +1295,15 @@ void ASTStmtReader::VisitPackExpansionExpr(PackExpansionExpr *E) {
   E->Pattern = Reader.ReadSubExpr();  
 }
 
+void ASTStmtReader::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+  VisitExpr(E);
+  E->OperatorLoc = ReadSourceLocation(Record, Idx);
+  E->PackLoc = ReadSourceLocation(Record, Idx);
+  E->RParenLoc = ReadSourceLocation(Record, Idx);
+  E->Length = Record[Idx++];
+  E->Pack = cast_or_null<NamedDecl>(Reader.GetDecl(Record[Idx++]));
+}
+
 void ASTStmtReader::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
 }
@@ -1820,6 +1830,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) {
       S = new (Context) PackExpansionExpr(Empty);
       break;
         
+    case EXPR_SIZEOF_PACK:
+      S = new (Context) SizeOfPackExpr(Empty);
+      break;
+        
     case EXPR_OPAQUE_VALUE:
       S = new (Context) OpaqueValueExpr(Empty);
       break;
index 27261dbb2a9c512a876b898755ec707ee4bef42d..af066bb425780dcd6940c810731a67299306336d 100644 (file)
@@ -151,6 +151,7 @@ namespace clang {
     void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
     void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
     void VisitPackExpansionExpr(PackExpansionExpr *E);
+    void VisitSizeOfPackExpr(SizeOfPackExpr *E);
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
   };
 }
@@ -1303,6 +1304,16 @@ void ASTStmtWriter::VisitPackExpansionExpr(PackExpansionExpr *E) {
   Code = serialization::EXPR_PACK_EXPANSION;
 }
 
+void ASTStmtWriter::VisitSizeOfPackExpr(SizeOfPackExpr *E) {
+  VisitExpr(E);
+  Writer.AddSourceLocation(E->OperatorLoc, Record);
+  Writer.AddSourceLocation(E->PackLoc, Record);
+  Writer.AddSourceLocation(E->RParenLoc, Record);
+  Record.push_back(E->Length);
+  Writer.AddDeclRef(E->Pack, Record);
+  Code = serialization::EXPR_SIZEOF_PACK;
+}
+
 void ASTStmtWriter::VisitOpaqueValueExpr(OpaqueValueExpr *E) {
   VisitExpr(E);
   Code = serialization::EXPR_OPAQUE_VALUE;
diff --git a/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp b/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
new file mode 100644 (file)
index 0000000..6ab93db
--- /dev/null
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
+
+// Test parsing + semantic analysis
+template<typename ...Types> struct count_types {
+  static const unsigned value = sizeof...(Types);
+};
+
+template<int ...Values> struct count_ints {
+  static const unsigned value = sizeof...(Values);
+};
+
+// Test instantiation
+int check_types[count_types<short, int, long>::value == 3? 1 : -1];
+int check_ints[count_ints<1, 2, 3, 4, 5>::value == 5? 1 : -1];
+
+// Test parser and semantic recovery.
+template<int Value> struct count_ints_2 {
+  static const unsigned value = sizeof...(Value); // expected-error{{'Value' does not refer to the name of a parameter pack}}
+};
+
+template<typename ...Types> // expected-note{{parameter pack 'Types' declared here}}
+struct count_types_2 {
+  static const unsigned value = sizeof... Type; // expected-error{{missing parentheses around the size of parameter pack 'Type'}} \
+  // expected-error{{Type' does not refer to the name of a parameter pack; did you mean 'Types'?}}
+};
+
index 7e3c3432d5660e191117e4941e408ca110d30c63..f28115418bdc38802c79c76ea534f657b364dd9a 100644 (file)
@@ -1631,7 +1631,8 @@ public:
   void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
   void VisitUnresolvedMemberExpr(UnresolvedMemberExpr *U);
   void VisitVAArgExpr(VAArgExpr *E);
-
+  // FIXME: Variadic templates SizeOfPackExpr!
+  
 private:
   void AddDeclarationNameInfo(Stmt *S);
   void AddNestedNameSpecifier(NestedNameSpecifier *NS, SourceRange R);
index 22758f9ba4b32ccc32440aaf2bfb5d5f6e9b1d9e..1a75284de389ca2e698e0d90d8011d9a5cf12e71 100644 (file)
@@ -165,6 +165,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent,
   case Stmt::BlockExprClass:  
   case Stmt::OpaqueValueExprClass:
   case Stmt::PackExpansionExprClass:
+  case Stmt::SizeOfPackExprClass:
     K = CXCursor_UnexposedExpr;
     break;