From ee8aff06f6a96214731de17b2cb6df407c6c1820 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 4 Jan 2011 17:33:58 +0000 Subject: [PATCH] Implement the sizeof...(pack) expression to compute the length of a 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 --- include/clang/AST/ExprCXX.h | 90 +++++++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/Basic/DiagnosticParseKinds.td | 7 ++ include/clang/Basic/DiagnosticSemaKinds.td | 6 ++ include/clang/Basic/StmtNodes.td | 1 + include/clang/Sema/Sema.h | 6 +- include/clang/Serialization/ASTBitCodes.h | 3 +- lib/AST/ExprCXX.cpp | 12 +++ lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 10 ++- lib/AST/StmtPrinter.cpp | 6 +- lib/AST/StmtProfile.cpp | 5 ++ lib/Parse/ParseExpr.cpp | 42 +++++++++ lib/Sema/SemaTemplateVariadic.cpp | 69 ++++++++++++++ lib/Sema/TreeTransform.h | 39 ++++++++ lib/Serialization/ASTReaderStmt.cpp | 14 +++ lib/Serialization/ASTWriterStmt.cpp | 11 +++ .../CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp | 26 ++++++ tools/libclang/CIndex.cpp | 3 +- tools/libclang/CXCursor.cpp | 1 + 20 files changed, 348 insertions(+), 5 deletions(-) create mode 100644 test/CXX/expr/expr.unary/expr.sizeof/p5-0x.cpp 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(this)->getExplicitTemplateArgs(); } +/// \brief Represents an expression that computes the length of a parameter +/// pack. +/// +/// \code +/// template +/// 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; def UnresolvedMemberExpr : DStmt; def CXXNoexceptExpr : DStmt; def PackExpansionExpr : DStmt; +def SizeOfPackExpr : DStmt; // Obj-C Expressions. def ObjCStringLiteral : DStmt; 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 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()) + 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::TransformPackExpansionExpr(PackExpansionExpr *E) { llvm_unreachable("pack expansion expression in unhandled context"); return ExprError(); } + +template +ExprResult +TreeTransform::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 ExprResult TreeTransform::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(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 struct count_types { + static const unsigned value = sizeof...(Types); +}; + +template struct count_ints { + static const unsigned value = sizeof...(Values); +}; + +// Test instantiation +int check_types[count_types::value == 3? 1 : -1]; +int check_ints[count_ints<1, 2, 3, 4, 5>::value == 5? 1 : -1]; + +// Test parser and semantic recovery. +template struct count_ints_2 { + static const unsigned value = sizeof...(Value); // expected-error{{'Value' does not refer to the name of a parameter pack}} +}; + +template // 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; -- 2.40.0