Implement support for pack expansions whose pattern is a non-type
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
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h
index eea15ef..bd7d3f0 100644
--- a/include/clang/AST/ExprCXX.h
+++ b/include/clang/AST/ExprCXX.h
@@ -2571,6 +2571,61 @@
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();
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index 435ebc6..258e186 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -1820,6 +1820,7 @@
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 f2d3c00..eb123b9 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1871,7 +1871,7 @@
// 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 0e2fb57..890f02b 100644
--- a/include/clang/Basic/StmtNodes.td
+++ b/include/clang/Basic/StmtNodes.td
@@ -111,6 +111,7 @@
def UnresolvedLookupExpr : DStmt<OverloadExpr>;
def UnresolvedMemberExpr : DStmt<OverloadExpr>;
def CXXNoexceptExpr : DStmt<Expr>;
+def PackExpansionExpr : DStmt<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 57f480f..05bb125 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -3279,7 +3279,7 @@
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 @@
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 8665fb6..fcc8d53 100644
--- a/include/clang/Serialization/ASTBitCodes.h
+++ b/include/clang/Serialization/ASTBitCodes.h
@@ -929,7 +929,9 @@
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 cbd33f2..4592e5f 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -1025,3 +1025,15 @@
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 4cf393d..f437804 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -304,6 +304,9 @@
case Expr::CXXUuidofExprClass:
return Cl::CL_LValue;
+
+ case Expr::PackExpansionExprClass:
+ return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern());
}
llvm_unreachable("unhandled expression kind in classification");
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 8797880..c39b398 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2634,6 +2634,7 @@
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 6bbe8f9..cc90526 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1246,6 +1246,11 @@
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 66c067b..820eb06 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -832,6 +832,10 @@
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 04e8a38..c971519 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 @@
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 @@
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 @@
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:
diff --git a/lib/CodeGen/Mangle.cpp b/lib/CodeGen/Mangle.cpp
index a45403e..0aa9f40 100644
--- a/lib/CodeGen/Mangle.cpp
+++ b/lib/CodeGen/Mangle.cpp
@@ -2043,7 +2043,11 @@
Out << "LDnE";
break;
}
-
+
+ case Expr::PackExpansionExprClass:
+ Out << "sp";
+ mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
+ break;
}
}
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 4a667cd..99b6dac 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -2926,6 +2926,10 @@
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);
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index 3dac8a0..030a042 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -79,9 +79,6 @@
// 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 @@
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 @@
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 de13084..992b849 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -6439,6 +6439,13 @@
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) {
return SemaRef.Owned(E);
}
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index aa669b3..4703c63 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -176,7 +176,8 @@
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
-
+ void VisitPackExpansionExpr(PackExpansionExpr *E);
+
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
};
}
@@ -1287,6 +1288,12 @@
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 @@
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 89c293f..27261db 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -150,7 +150,7 @@
void VisitUnaryTypeTraitExpr(UnaryTypeTraitExpr *E);
void VisitBinaryTypeTraitExpr(BinaryTypeTraitExpr *E);
void VisitCXXNoexceptExpr(CXXNoexceptExpr *E);
-
+ void VisitPackExpansionExpr(PackExpansionExpr *E);
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
};
}
@@ -1296,6 +1296,13 @@
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 c522e72..9fef6d8 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -771,6 +771,7 @@
case Stmt::UnresolvedLookupExprClass:
case Stmt::UnresolvedMemberExprClass:
case Stmt::CXXNoexceptExprClass:
+ case Stmt::PackExpansionExprClass:
{
SaveAndRestore<bool> 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 6a5e989..d9a3b5c 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 @@
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];
+}
diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp
index 86b5ce1..22758f9 100644
--- a/tools/libclang/CXCursor.cpp
+++ b/tools/libclang/CXCursor.cpp
@@ -164,6 +164,7 @@
case Stmt::ShuffleVectorExprClass:
case Stmt::BlockExprClass:
case Stmt::OpaqueValueExprClass:
+ case Stmt::PackExpansionExprClass:
K = CXCursor_UnexposedExpr;
break;