зеркало из https://github.com/microsoft/clang-1.git
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:
Родитель
63aae82bb1
Коммит
a73652465b
|
@ -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*);
|
Загрузка…
Ссылка в новой задаче