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
This commit is contained in:
Douglas Gregor 2011-01-03 17:17:50 +00:00
Родитель 9917401b32
Коммит be230c36e3
21 изменённых файлов: 223 добавлений и 22 удалений

Просмотреть файл

@ -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<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();

Просмотреть файл

@ -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, { })

Просмотреть файл

@ -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<

Просмотреть файл

@ -111,6 +111,7 @@ def OverloadExpr : DStmt<Expr, 1>;
def UnresolvedLookupExpr : DStmt<OverloadExpr>;
def UnresolvedMemberExpr : DStmt<OverloadExpr>;
def CXXNoexceptExpr : DStmt<Expr>;
def PackExpansionExpr : DStmt<Expr>;
// Obj-C Expressions.
def ObjCStringLiteral : DStmt<Expr>;

Просмотреть файл

@ -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.

Просмотреть файл

@ -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

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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<PackExpansionExpr>(E)->getPattern());
}
llvm_unreachable("unhandled expression kind in classification");

Просмотреть файл

@ -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:

Просмотреть файл

@ -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) {

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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<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 @@ TemplateArgument TemplateArgument::getPackExpansionPattern() const {
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 @@ TemplateArgumentLoc::getPackExpansionPattern(SourceLocation &Ellipsis,
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:

Просмотреть файл

@ -2043,7 +2043,11 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) {
Out << "LDnE";
break;
}
case Expr::PackExpansionExprClass:
Out << "sp";
mangleExpression(cast<PackExpansionExpr>(E)->getPattern());
break;
}
}

Просмотреть файл

@ -2926,6 +2926,10 @@ MarkUsedTemplateParameters(Sema &SemaRef,
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);

Просмотреть файл

@ -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,

Просмотреть файл

@ -6437,6 +6437,13 @@ TreeTransform<Derived>::TransformCXXNoexceptExpr(CXXNoexceptExpr *E) {
return getDerived().RebuildCXXNoexceptExpr(E->getSourceRange(),SubExpr.get());
}
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) {

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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<bool> OldSink(Builder->BuildSinks);
Builder->BuildSinks = true;

Просмотреть файл

@ -64,3 +64,52 @@ namespace Replace {
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];
}

Просмотреть файл

@ -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;