Implement support for lambda capture pack expansions, e.g.,

[&values...] { print(values...); }




git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150497 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2012-02-14 19:27:52 +00:00
Родитель 63aae82bb1
Коммит a73652465b
9 изменённых файлов: 158 добавлений и 26 удалений

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

@ -4032,7 +4032,9 @@ def err_lambda_return_init_list : Error<
"cannot deduce lambda return type from initializer list">;
def err_lambda_capture_default_arg : Error<
"lambda expression in default argument cannot capture any entity">;
def err_lambda_unexpanded_pack : Error<
"unexpanded function parameter pack capture is unsupported">;
def err_operator_arrow_circular : Error<
"circular pointer delegation detected">;
def err_pseudo_dtor_base_not_scalar : Error<

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

@ -1923,10 +1923,12 @@ struct LambdaCapture {
LambdaCaptureKind Kind;
SourceLocation Loc;
IdentifierInfo* Id;
SourceLocation EllipsisLoc;
LambdaCapture(LambdaCaptureKind Kind, SourceLocation Loc,
IdentifierInfo* Id = 0)
: Kind(Kind), Loc(Loc), Id(Id)
IdentifierInfo* Id = 0,
SourceLocation EllipsisLoc = SourceLocation())
: Kind(Kind), Loc(Loc), Id(Id), EllipsisLoc(EllipsisLoc)
{}
};
@ -1943,8 +1945,9 @@ struct LambdaIntroducer {
/// addCapture - Append a capture in a lambda introducer.
void addCapture(LambdaCaptureKind Kind,
SourceLocation Loc,
IdentifierInfo* Id = 0) {
Captures.push_back(LambdaCapture(Kind, Loc, Id));
IdentifierInfo* Id = 0,
SourceLocation EllipsisLoc = SourceLocation()) {
Captures.push_back(LambdaCapture(Kind, Loc, Id, EllipsisLoc));
}
};

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

@ -151,16 +151,19 @@ public:
/// \brief The source location at which the first capture occurred..
SourceLocation Loc;
/// \brief The location of the ellipsis that expands a parameter pack.
SourceLocation EllipsisLoc;
public:
Capture(VarDecl *Var, bool block, bool byRef, bool isNested,
SourceLocation Loc, Expr *Cpy)
SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy)
: VarAndKind(Var, block ? Cap_Block : byRef ? Cap_ByRef : Cap_ByCopy),
CopyExprAndNested(Cpy, isNested) {}
CopyExprAndNested(Cpy, isNested), Loc(Loc), EllipsisLoc(EllipsisLoc) {}
enum IsThisCapture { ThisCapture };
Capture(IsThisCapture, bool isNested, SourceLocation Loc, Expr *Cpy)
: VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc) {
}
: VarAndKind(0, Cap_This), CopyExprAndNested(Cpy, isNested), Loc(Loc),
EllipsisLoc() { }
bool isThisCapture() const { return VarAndKind.getInt() == Cap_This; }
bool isVariableCapture() const { return !isThisCapture(); }
@ -176,6 +179,10 @@ public:
/// \brief Retrieve the location at which this variable was captured.
SourceLocation getLocation() const { return Loc; }
/// \brief Retrieve the source location of the ellipsis, whose presence
/// indicates that the capture is a pack expansion.
SourceLocation getEllipsisLoc() const { return EllipsisLoc; }
Expr *getCopyExpr() const {
return CopyExprAndNested.getPointer();
}
@ -205,8 +212,9 @@ public:
QualType ReturnType;
void AddCapture(VarDecl *Var, bool isBlock, bool isByref, bool isNested,
SourceLocation Loc, Expr *Cpy) {
Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc, Cpy));
SourceLocation Loc, SourceLocation EllipsisLoc, Expr *Cpy) {
Captures.push_back(Capture(Var, isBlock, isByref, isNested, Loc,
EllipsisLoc, Cpy));
CaptureMap[Var] = Captures.size();
}

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

@ -2298,7 +2298,8 @@ public:
TryCapture_Implicit, TryCapture_ExplicitByVal, TryCapture_ExplicitByRef
};
void TryCaptureVar(VarDecl *var, SourceLocation loc,
TryCaptureKind Kind = TryCapture_Implicit);
TryCaptureKind Kind = TryCapture_Implicit,
SourceLocation EllipsisLoc = SourceLocation());
void MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T);
void MarkDeclarationsReferencedInExpr(Expr *E);

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

@ -651,7 +651,8 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
LambdaCaptureKind Kind = LCK_ByCopy;
SourceLocation Loc;
IdentifierInfo* Id = 0;
SourceLocation EllipsisLoc;
if (Tok.is(tok::kw_this)) {
Kind = LCK_This;
Loc = ConsumeToken();
@ -664,6 +665,9 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
if (Tok.is(tok::identifier)) {
Id = Tok.getIdentifierInfo();
Loc = ConsumeToken();
if (Tok.is(tok::ellipsis))
EllipsisLoc = ConsumeToken();
} else if (Tok.is(tok::kw_this)) {
// FIXME: If we want to suggest a fixit here, will need to return more
// than just DiagnosticID. Perhaps full DiagnosticBuilder that can be
@ -674,7 +678,7 @@ llvm::Optional<unsigned> Parser::ParseLambdaIntroducer(LambdaIntroducer &Intro)
}
}
Intro.addCapture(Kind, Loc, Id);
Intro.addCapture(Kind, Loc, Id, EllipsisLoc);
}
T.consumeClose();

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

@ -9831,7 +9831,7 @@ bool Sema::canCaptureVariable(VarDecl *Var, SourceLocation Loc, bool Explicit,
// Check if the variable needs to be captured; if so, try to perform
// the capture.
void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
TryCaptureKind Kind) {
TryCaptureKind Kind, SourceLocation EllipsisLoc) {
QualType type;
unsigned functionScopesIndex;
bool Nested;
@ -9909,7 +9909,8 @@ void Sema::TryCaptureVar(VarDecl *var, SourceLocation loc,
}
}
CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, copyExpr);
CSI->AddCapture(var, hasBlocksAttr, byRef, Nested, loc, EllipsisLoc,
copyExpr);
Nested = true;
if (shouldAddConstForScope(CSI, var))

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

@ -291,9 +291,26 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
// C++11 [expr.prim.lambda]p23:
// A capture followed by an ellipsis is a pack expansion (14.5.3).
SourceLocation EllipsisLoc;
if (C->EllipsisLoc.isValid()) {
if (Var->isParameterPack()) {
EllipsisLoc = C->EllipsisLoc;
} else {
Diag(C->EllipsisLoc, diag::err_pack_expansion_without_parameter_packs)
<< SourceRange(C->Loc);
// Just ignore the ellipsis.
}
} else if (Var->isParameterPack()) {
Diag(C->Loc, diag::err_lambda_unexpanded_pack);
continue;
}
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
TryCapture_ExplicitByVal;
TryCaptureVar(Var, C->Loc, Kind);
TryCaptureVar(Var, C->Loc, Kind, EllipsisLoc);
}
finishLambdaExplicitCaptures(LSI);
@ -380,10 +397,9 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
}
VarDecl *Var = From.getVariable();
// FIXME: Handle pack expansions.
LambdaCaptureKind Kind = From.isCopyCapture()? LCK_ByCopy : LCK_ByRef;
Captures.push_back(LambdaExpr::Capture(From.getLocation(), IsImplicit,
Kind, Var));
Kind, Var, From.getEllipsisLoc()));
CaptureInits.push_back(From.getCopyExpr());
}

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

@ -7706,6 +7706,49 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
continue;
}
// Determine the capture kind for Sema.
Sema::TryCaptureKind Kind
= C->isImplicit()? Sema::TryCapture_Implicit
: C->getCaptureKind() == LCK_ByCopy
? Sema::TryCapture_ExplicitByVal
: Sema::TryCapture_ExplicitByRef;
SourceLocation EllipsisLoc;
if (C->isPackExpansion()) {
UnexpandedParameterPack Unexpanded(C->getCapturedVar(), C->getLocation());
bool ShouldExpand = false;
bool RetainExpansion = false;
llvm::Optional<unsigned> NumExpansions;
if (getDerived().TryExpandParameterPacks(C->getEllipsisLoc(),
C->getLocation(),
Unexpanded,
ShouldExpand, RetainExpansion,
NumExpansions))
return ExprError();
if (ShouldExpand) {
// The transform has determined that we should perform an expansion;
// transform and capture each of the arguments.
// expansion of the pattern. Do so.
VarDecl *Pack = C->getCapturedVar();
for (unsigned I = 0; I != *NumExpansions; ++I) {
Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), I);
VarDecl *CapturedVar
= cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
Pack));
if (!CapturedVar) {
Invalid = true;
continue;
}
// Capture the transformed variable.
getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind);
}
continue;
}
EllipsisLoc = C->getEllipsisLoc();
}
// Transform the captured variable.
VarDecl *CapturedVar
= cast_or_null<VarDecl>(getDerived().TransformDecl(C->getLocation(),
@ -7714,13 +7757,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
Invalid = true;
continue;
}
// Capture the transformed variable.
getSema().TryCaptureVar(CapturedVar, C->getLocation(),
C->isImplicit()? Sema::TryCapture_Implicit
: C->getCaptureKind() == LCK_ByCopy
? Sema::TryCapture_ExplicitByVal
: Sema::TryCapture_ExplicitByRef);
getSema().TryCaptureVar(CapturedVar, C->getLocation(), Kind);
}
if (!FinishedExplicitCaptures)
getSema().finishLambdaExplicitCaptures(LSI);

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

@ -0,0 +1,58 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 %s -verify
void print();
template<typename T, typename... Ts>
void print(T first, Ts... rest) {
(void)first;
print(rest...);
}
template<typename... Ts>
void unsupported(Ts ...values) {
auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}}
}
template<typename... Ts>
void implicit_capture(Ts ...values) {
auto implicit = [&] { print(values...); };
implicit();
}
template<typename... Ts>
void do_print(Ts... values) {
auto bycopy = [values...]() { print(values...); };
bycopy();
auto byref = [&values...]() { print(values...); };
byref();
auto bycopy2 = [=]() { print(values...); };
bycopy2();
auto byref2 = [&]() { print(values...); };
byref2();
}
template void do_print(int, float, double);
template<typename T, int... Values>
void bogus_expansions(T x) {
auto l1 = [x...] {}; // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
auto l2 = [Values...] {}; // expected-error{{'Values' in capture list does not name a variable}}
}
void g(int*, float*, double*);
template<class... Args>
void std_example(Args... args) {
auto lm = [&, args...] { return g(args...); };
};
template void std_example(int*, float*, double*);
template<typename ...Args>
void variadic_lambda(Args... args) {
auto lambda = [](Args... inner_args) { return g(inner_args...); };
lambda(args...);
}
template void variadic_lambda(int*, float*, double*);