From be230c36e32142cbdcdbe9c97511d097beeecbab Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Mon, 3 Jan 2011 17:17:50 +0000 Subject: [PATCH] Implement support for pack expansions whose pattern is a non-type template argument (described by an expression, of course). For example: template struct int_tuple { }; template 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 --- include/clang/AST/ExprCXX.h | 55 +++++++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 1 + include/clang/Basic/DiagnosticSemaKinds.td | 2 +- include/clang/Basic/StmtNodes.td | 1 + include/clang/Sema/Sema.h | 11 +++- include/clang/Serialization/ASTBitCodes.h | 4 +- lib/AST/ExprCXX.cpp | 12 ++++ lib/AST/ExprClassification.cpp | 3 + lib/AST/ExprConstant.cpp | 1 + lib/AST/StmtPrinter.cpp | 5 ++ lib/AST/StmtProfile.cpp | 4 ++ lib/AST/TemplateBase.cpp | 18 ++++-- lib/CodeGen/Mangle.cpp | 6 +- lib/Sema/SemaTemplateDeduction.cpp | 4 ++ lib/Sema/SemaTemplateVariadic.cpp | 38 +++++++++---- lib/Sema/TreeTransform.h | 7 +++ lib/Serialization/ASTReaderStmt.cpp | 13 ++++- lib/Serialization/ASTWriterStmt.cpp | 9 ++- lib/StaticAnalyzer/Checkers/ExprEngine.cpp | 1 + .../temp.variadic/metafunctions.cpp | 49 +++++++++++++++++ tools/libclang/CXCursor.cpp | 1 + 21 files changed, 223 insertions(+), 22 deletions(-) diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index eea15effac..bd7d3f09c3 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -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 +/// void forward(F f, Types &&...args) { +/// f(static_cast(args)...); +/// } +/// \endcode +/// +/// Here, the argument to the function object \c f is a pack expansion whose +/// pattern is \c static_cast(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(Pattern); } + + /// \brief Retrieve the pattern of the pack expansion. + const Expr *getPattern() const { return reinterpret_cast(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(this)) return cast(this)->getExplicitTemplateArgs(); diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index 435ebc65ea..258e186b7a 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -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, { }) diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index f2d3c0085c..eb123b9fe9 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 0e2fb575e6..890f02b75d 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -111,6 +111,7 @@ def OverloadExpr : DStmt; def UnresolvedLookupExpr : DStmt; def UnresolvedMemberExpr : DStmt; def CXXNoexceptExpr : DStmt; +def PackExpansionExpr : DStmt; // Obj-C Expressions. def ObjCStringLiteral : DStmt; diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 57f480f95d..05bb1258c1 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -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. diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 8665fb6465..fcc8d53d42 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -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 diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index cbd33f2dc4..4592e5f571 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -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); +} diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 4cf393d788..f437804c29 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -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(E)->getPattern()); } llvm_unreachable("unhandled expression kind in classification"); diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 8797880411..c39b3983d3 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -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: diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 6bbe8f9cd9..cc90526736 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -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) { diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 66c067b7b1..820eb06416 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -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); } diff --git a/lib/AST/TemplateBase.cpp b/lib/AST/TemplateBase.cpp index 04e8a389cf..c971519961 100644 --- a/lib/AST/TemplateBase.cpp +++ b/lib/AST/TemplateBase.cpp @@ -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(getAsType()); + return isa(getAsType()); case Template: // FIXME: Template template pack expansions. break; case Expression: - // FIXME: Expansion pack expansions. - break; + return isa(getAsExpr()); } return false; @@ -199,9 +199,11 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const { return getAsType()->getAs()->getPattern(); case Expression: + return cast(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(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: diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp index a45403e467..0aa9f402f9 100644 --- a/lib/CodeGen/Mangle.cpp +++ b/lib/CodeGen/Mangle.cpp @@ -2043,7 +2043,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { Out << "LDnE"; break; } - + + case Expr::PackExpansionExprClass: + Out << "sp"; + mangleExpression(cast(E)->getPattern()); + break; } } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 4a667cdf57..99b6daceed 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -2926,6 +2926,10 @@ MarkUsedTemplateParameters(Sema &SemaRef, bool OnlyDeduced, unsigned Depth, llvm::SmallVectorImpl &Used) { + // We can deduce from a pack expansion. + if (const PackExpansionExpr *Expansion = dyn_cast(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(E); diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 3dac8a0408..030a0423f7 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -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, diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index de13084fbc..992b849904 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -6437,6 +6437,13 @@ TreeTransform::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) { return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get()); } +template +ExprResult +TreeTransform::TransformPackExpansionExpr(PackExpansionExpr *E) { + llvm_unreachable("pack expansion expression in unhandled context"); + return ExprError(); +} + template ExprResult TreeTransform::TransformObjCStringLiteral(ObjCStringLiteral *E) { diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index aa669b34b3..4703c633fb 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -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; diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index 89c293fe6c..27261dbb2a 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -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; diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp index c522e72210..9fef6d87be 100644 --- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp @@ -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 OldSink(Builder->BuildSinks); Builder->BuildSinks = true; diff --git a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp index 6a5e989d1a..d9a3b5c27f 100644 --- a/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp +++ b/test/CXX/temp/temp.decls/temp.variadic/metafunctions.cpp @@ -64,3 +64,52 @@ namespace Replace { int check0[is_same>::type, tuple>::value? 1 : -1]; } + +namespace Multiply { + template + struct double_values { + typedef int_tuple type; + }; + + int check0[is_same::type, + int_tuple<2, 4, -6>>::value? 1 : -1]; + + template + struct square { + typedef int_tuple<(Values*Values)...> type; + }; + + int check1[is_same::type, + int_tuple<1, 4, 9>>::value? 1 : -1]; + + template struct square_tuple; + + template + struct square_tuple> { + typedef int_tuple<(Values*Values)...> type; + }; + + int check2[is_same>::type, + int_tuple<1, 4, 9>>::value? 1 : -1]; +} + +namespace Indices { + template + struct build_indices_impl; + + template + struct build_indices_impl > + : build_indices_impl > { + }; + + template + struct build_indices_impl > { + typedef int_tuple type; + }; + + template + struct build_indices : build_indices_impl<0, N, int_tuple<> > { }; + + int check0[is_same::type, + int_tuple<0, 1, 2, 3, 4>>::value? 1 : -1]; +} diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 86b5ce1c4c..22758f9ba4 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -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; -- 2.40.0