aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/AST/ExprCXX.h90
-rw-r--r--include/clang/AST/RecursiveASTVisitor.h1
-rw-r--r--include/clang/Basic/DiagnosticParseKinds.td7
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td6
-rw-r--r--include/clang/Basic/StmtNodes.td1
-rw-r--r--include/clang/Sema/Sema.h6
-rw-r--r--include/clang/Serialization/ASTBitCodes.h3
-rw-r--r--lib/AST/ExprCXX.cpp12
-rw-r--r--lib/AST/ExprClassification.cpp1
-rw-r--r--lib/AST/ExprConstant.cpp10
-rw-r--r--lib/AST/StmtPrinter.cpp6
-rw-r--r--lib/AST/StmtProfile.cpp5
-rw-r--r--lib/Parse/ParseExpr.cpp42
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp69
-rw-r--r--lib/Sema/TreeTransform.h39
-rw-r--r--lib/Serialization/ASTReaderStmt.cpp14
-rw-r--r--lib/Serialization/ASTWriterStmt.cpp11
-rw-r--r--test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp26
-rw-r--r--tools/libclang/CIndex.cpp3
-rw-r--r--tools/libclang/CXCursor.cpp1
20 files changed, 348 insertions, 5 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index 5311d9c3a8..619a21245f 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -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
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 258e186b7a..894ecdd29a 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -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, { })
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index e8eb111795..59ce1ce0a3 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -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<
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 2559464298..cc405ee82a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -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.
diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td
index 890f02b75d..9322db12c5 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -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>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 13b440c8ab..c11ab161a5 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -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);
diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h
index fcc8d53d42..bbe7c1d2f8 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -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
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index 4592e5f571..fcedb8e7bb 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -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();
+}
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index f437804c29..a9ebe6fdb3 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -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.
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index c39b3983d3..23a4b09cb3 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -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();
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index cc90526736..2c8504357e 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -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) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 820eb06416..ab24a69124 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -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);
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index be5c7d7808..7133b61022 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -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;
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 92df1fd863..4e01ec2407 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -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);
+}
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index c38902a3e9..27fbf939f9 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -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) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 4703c633fb..5ed6f8e4d5 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -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;
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 27261dbb2a..af066bb425 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -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
index 0000000000..6ab93db77f
--- /dev/null
+++ b/test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp
@@ -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'?}}
+};
+
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index 7e3c3432d5..f28115418b 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -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);
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 22758f9ba4..1a75284de3 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -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;