forked from OSchip/llvm-project
PR12057: Allow variadic template pack expansions to cross lambda boundaries.
Rather than adding a ContainsUnexpandedParameterPack bit to essentially every AST node, we tunnel the bit directly up to the surrounding lambda expression when we reach a context where an unexpanded pack can not normally appear. Thus any statement or declaration within a lambda can now potentially contain an unexpanded parameter pack. llvm-svn: 160705
This commit is contained in:
parent
c42d243ace
commit
2589b9808e
|
@ -1254,7 +1254,8 @@ private:
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace);
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// \brief Construct an empty lambda expression.
|
||||
LambdaExpr(EmptyShell Empty, unsigned NumCaptures, bool HasArrayIndexVars)
|
||||
|
@ -1292,7 +1293,8 @@ public:
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace);
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack);
|
||||
|
||||
/// \brief Construct a new lambda expression that will be deserialized from
|
||||
/// an external source.
|
||||
|
|
|
@ -344,6 +344,9 @@ public:
|
|||
/// \brief Whether any of the capture expressions requires cleanups.
|
||||
bool ExprNeedsCleanups;
|
||||
|
||||
/// \brief Whether the lambda contains an unexpanded parameter pack.
|
||||
bool ContainsUnexpandedParameterPack;
|
||||
|
||||
/// \brief Variables used to index into by-copy array captures.
|
||||
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
|
||||
|
||||
|
@ -355,7 +358,7 @@ public:
|
|||
CXXMethodDecl *CallOperator)
|
||||
: CapturingScopeInfo(Diag, ImpCap_None), Lambda(Lambda),
|
||||
CallOperator(CallOperator), NumExplicitCaptures(0), Mutable(false),
|
||||
ExprNeedsCleanups(false)
|
||||
ExprNeedsCleanups(false), ContainsUnexpandedParameterPack(false)
|
||||
{
|
||||
Kind = SK_Lambda;
|
||||
}
|
||||
|
|
|
@ -5003,7 +5003,9 @@ public:
|
|||
/// parameter packs.
|
||||
///
|
||||
/// \param Unexpanded the set of unexpanded parameter packs.
|
||||
void DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
||||
///
|
||||
/// \returns true if an error occurred, false otherwise.
|
||||
bool DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
||||
UnexpandedParameterPackContext UPPC,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded);
|
||||
|
||||
|
|
|
@ -372,8 +372,10 @@ namespace clang {
|
|||
public:
|
||||
TemplateDeclInstantiator(Sema &SemaRef, DeclContext *Owner,
|
||||
const MultiLevelTemplateArgumentList &TemplateArgs)
|
||||
: SemaRef(SemaRef), SubstIndex(SemaRef, -1), Owner(Owner),
|
||||
TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0) { }
|
||||
: SemaRef(SemaRef),
|
||||
SubstIndex(SemaRef, SemaRef.ArgumentPackSubstitutionIndex),
|
||||
Owner(Owner), TemplateArgs(TemplateArgs), LateAttrs(0), StartingScope(0)
|
||||
{ }
|
||||
|
||||
// FIXME: Once we get closer to completion, replace these manually-written
|
||||
// declarations with automatically-generated ones from
|
||||
|
|
|
@ -790,10 +790,11 @@ LambdaExpr::LambdaExpr(QualType T,
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace)
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack)
|
||||
: Expr(LambdaExprClass, T, VK_RValue, OK_Ordinary,
|
||||
T->isDependentType(), T->isDependentType(), T->isDependentType(),
|
||||
/*ContainsUnexpandedParameterPack=*/false),
|
||||
ContainsUnexpandedParameterPack),
|
||||
IntroducerRange(IntroducerRange),
|
||||
NumCaptures(Captures.size()),
|
||||
CaptureDefault(CaptureDefault),
|
||||
|
@ -850,7 +851,8 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
|
|||
ArrayRef<Expr *> CaptureInits,
|
||||
ArrayRef<VarDecl *> ArrayIndexVars,
|
||||
ArrayRef<unsigned> ArrayIndexStarts,
|
||||
SourceLocation ClosingBrace) {
|
||||
SourceLocation ClosingBrace,
|
||||
bool ContainsUnexpandedParameterPack) {
|
||||
// Determine the type of the expression (i.e., the type of the
|
||||
// function object we're creating).
|
||||
QualType T = Context.getTypeDeclType(Class);
|
||||
|
@ -863,7 +865,7 @@ LambdaExpr *LambdaExpr::Create(ASTContext &Context,
|
|||
return new (Mem) LambdaExpr(T, IntroducerRange, CaptureDefault,
|
||||
Captures, ExplicitParams, ExplicitResultType,
|
||||
CaptureInits, ArrayIndexVars, ArrayIndexStarts,
|
||||
ClosingBrace);
|
||||
ClosingBrace, ContainsUnexpandedParameterPack);
|
||||
}
|
||||
|
||||
LambdaExpr *LambdaExpr::CreateDeserialized(ASTContext &C, unsigned NumCaptures,
|
||||
|
|
|
@ -375,6 +375,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
TypeSourceInfo *MethodTyInfo;
|
||||
bool ExplicitParams = true;
|
||||
bool ExplicitResultType = true;
|
||||
bool ContainsUnexpandedParameterPack = false;
|
||||
SourceLocation EndLoc;
|
||||
llvm::ArrayRef<ParmVarDecl *> Params;
|
||||
if (ParamInfo.getNumTypeObjects() == 0) {
|
||||
|
@ -416,21 +417,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
Proto.getNumArgs());
|
||||
|
||||
// Check for unexpanded parameter packs in the method type.
|
||||
// FIXME: We should allow unexpanded parameter packs here, but that would,
|
||||
// in turn, make the lambda expression contain unexpanded parameter packs.
|
||||
if (DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
|
||||
UPPC_Lambda)) {
|
||||
// Drop the parameters.
|
||||
Params = llvm::ArrayRef<ParmVarDecl *>();
|
||||
FunctionProtoType::ExtProtoInfo EPI;
|
||||
EPI.HasTrailingReturn = false;
|
||||
EPI.TypeQuals |= DeclSpec::TQ_const;
|
||||
QualType MethodTy = Context.getFunctionType(Context.DependentTy,
|
||||
/*Args=*/0, /*NumArgs=*/0, EPI);
|
||||
MethodTyInfo = Context.getTrivialTypeSourceInfo(MethodTy);
|
||||
ExplicitParams = false;
|
||||
ExplicitResultType = false;
|
||||
}
|
||||
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
|
||||
ContainsUnexpandedParameterPack = true;
|
||||
}
|
||||
|
||||
CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
|
||||
|
@ -571,8 +559,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
// Just ignore the ellipsis.
|
||||
}
|
||||
} else if (Var->isParameterPack()) {
|
||||
Diag(C->Loc, diag::err_lambda_unexpanded_pack);
|
||||
continue;
|
||||
ContainsUnexpandedParameterPack = true;
|
||||
}
|
||||
|
||||
TryCaptureKind Kind = C->Kind == LCK_ByRef ? TryCapture_ExplicitByRef :
|
||||
|
@ -581,6 +568,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
|
|||
}
|
||||
finishLambdaExplicitCaptures(LSI);
|
||||
|
||||
LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
|
||||
|
||||
// Add lambda parameters into scope.
|
||||
addLambdaParameters(Method, CurScope);
|
||||
|
||||
|
@ -743,6 +732,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
|||
bool ExplicitParams;
|
||||
bool ExplicitResultType;
|
||||
bool LambdaExprNeedsCleanups;
|
||||
bool ContainsUnexpandedParameterPack;
|
||||
llvm::SmallVector<VarDecl *, 4> ArrayIndexVars;
|
||||
llvm::SmallVector<unsigned, 4> ArrayIndexStarts;
|
||||
{
|
||||
|
@ -753,6 +743,7 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
|||
ExplicitParams = LSI->ExplicitParams;
|
||||
ExplicitResultType = !LSI->HasImplicitReturnType;
|
||||
LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
|
||||
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
|
||||
ArrayIndexVars.swap(LSI->ArrayIndexVars);
|
||||
ArrayIndexStarts.swap(LSI->ArrayIndexStarts);
|
||||
|
||||
|
@ -867,7 +858,8 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body,
|
|||
CaptureDefault, Captures,
|
||||
ExplicitParams, ExplicitResultType,
|
||||
CaptureInits, ArrayIndexVars,
|
||||
ArrayIndexStarts, Body->getLocEnd());
|
||||
ArrayIndexStarts, Body->getLocEnd(),
|
||||
ContainsUnexpandedParameterPack);
|
||||
|
||||
// C++11 [expr.prim.lambda]p2:
|
||||
// A lambda-expression shall not appear in an unevaluated operand
|
||||
|
|
|
@ -838,6 +838,19 @@ namespace {
|
|||
return move(Result);
|
||||
}
|
||||
|
||||
ExprResult TransformLambdaExpr(LambdaExpr *E) {
|
||||
LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true);
|
||||
return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E);
|
||||
}
|
||||
|
||||
ExprResult TransformLambdaScope(LambdaExpr *E,
|
||||
CXXMethodDecl *CallOperator) {
|
||||
CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
|
||||
TSK_ImplicitInstantiation);
|
||||
return TreeTransform<TemplateInstantiator>::
|
||||
TransformLambdaScope(E, CallOperator);
|
||||
}
|
||||
|
||||
private:
|
||||
ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm,
|
||||
SourceLocation loc,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "clang/Sema/Sema.h"
|
||||
#include "clang/Sema/Lookup.h"
|
||||
#include "clang/Sema/ParsedTemplate.h"
|
||||
#include "clang/Sema/ScopeInfo.h"
|
||||
#include "clang/Sema/SemaInternal.h"
|
||||
#include "clang/Sema/Template.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
|
@ -34,10 +35,12 @@ namespace {
|
|||
|
||||
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
|
||||
|
||||
bool InLambda;
|
||||
|
||||
public:
|
||||
explicit CollectUnexpandedParameterPacksVisitor(
|
||||
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
|
||||
: Unexpanded(Unexpanded) { }
|
||||
: Unexpanded(Unexpanded), InLambda(false) { }
|
||||
|
||||
bool shouldWalkTypesOfTypeLocs() const { return false; }
|
||||
|
||||
|
@ -107,17 +110,17 @@ namespace {
|
|||
/// \brief Suppress traversal into statements and expressions that
|
||||
/// do not contain unexpanded parameter packs.
|
||||
bool TraverseStmt(Stmt *S) {
|
||||
if (Expr *E = dyn_cast_or_null<Expr>(S))
|
||||
if (E->containsUnexpandedParameterPack())
|
||||
return inherited::TraverseStmt(E);
|
||||
Expr *E = dyn_cast_or_null<Expr>(S);
|
||||
if ((E && E->containsUnexpandedParameterPack()) || InLambda)
|
||||
return inherited::TraverseStmt(S);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Suppress traversal into types that do not contain
|
||||
/// unexpanded parameter packs.
|
||||
bool TraverseType(QualType T) {
|
||||
if (!T.isNull() && T->containsUnexpandedParameterPack())
|
||||
if ((!T.isNull() && T->containsUnexpandedParameterPack()) || InLambda)
|
||||
return inherited::TraverseType(T);
|
||||
|
||||
return true;
|
||||
|
@ -126,8 +129,9 @@ namespace {
|
|||
/// \brief Suppress traversel into types with location information
|
||||
/// that do not contain unexpanded parameter packs.
|
||||
bool TraverseTypeLoc(TypeLoc TL) {
|
||||
if (!TL.getType().isNull() &&
|
||||
TL.getType()->containsUnexpandedParameterPack())
|
||||
if ((!TL.getType().isNull() &&
|
||||
TL.getType()->containsUnexpandedParameterPack()) ||
|
||||
InLambda)
|
||||
return inherited::TraverseTypeLoc(TL);
|
||||
|
||||
return true;
|
||||
|
@ -136,10 +140,10 @@ namespace {
|
|||
/// \brief Suppress traversal of non-parameter declarations, since
|
||||
/// they cannot contain unexpanded parameter packs.
|
||||
bool TraverseDecl(Decl *D) {
|
||||
if (D && isa<ParmVarDecl>(D))
|
||||
if ((D && isa<ParmVarDecl>(D)) || InLambda)
|
||||
return inherited::TraverseDecl(D);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Suppress traversal of template argument pack expansions.
|
||||
|
@ -157,17 +161,57 @@ namespace {
|
|||
|
||||
return inherited::TraverseTemplateArgumentLoc(ArgLoc);
|
||||
}
|
||||
|
||||
/// \brief Note whether we're traversing a lambda containing an unexpanded
|
||||
/// parameter pack. In this case, the unexpanded pack can occur anywhere,
|
||||
/// including all the places where we normally wouldn't look. Within a
|
||||
/// lambda, we don't propagate the 'contains unexpanded parameter pack' bit
|
||||
/// outside an expression.
|
||||
bool TraverseLambdaExpr(LambdaExpr *Lambda) {
|
||||
// The ContainsUnexpandedParameterPack bit on a lambda is always correct,
|
||||
// even if it's contained within another lambda.
|
||||
if (!Lambda->containsUnexpandedParameterPack())
|
||||
return true;
|
||||
|
||||
bool WasInLambda = InLambda;
|
||||
InLambda = true;
|
||||
|
||||
// If any capture names a function parameter pack, that pack is expanded
|
||||
// when the lambda is expanded.
|
||||
for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
|
||||
E = Lambda->capture_end(); I != E; ++I)
|
||||
if (VarDecl *VD = I->getCapturedVar())
|
||||
if (VD->isParameterPack())
|
||||
Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
|
||||
|
||||
inherited::TraverseLambdaExpr(Lambda);
|
||||
|
||||
InLambda = WasInLambda;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Diagnose all of the unexpanded parameter packs in the given
|
||||
/// vector.
|
||||
void
|
||||
bool
|
||||
Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
||||
UnexpandedParameterPackContext UPPC,
|
||||
ArrayRef<UnexpandedParameterPack> Unexpanded) {
|
||||
if (Unexpanded.empty())
|
||||
return;
|
||||
return false;
|
||||
|
||||
// If we are within a lambda expression, that lambda contains an unexpanded
|
||||
// parameter pack, and we are done.
|
||||
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
|
||||
// later.
|
||||
for (unsigned N = FunctionScopes.size(); N; --N) {
|
||||
if (sema::LambdaScopeInfo *LSI =
|
||||
dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
|
||||
LSI->ContainsUnexpandedParameterPack = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
SmallVector<SourceLocation, 4> Locations;
|
||||
SmallVector<IdentifierInfo *, 4> Names;
|
||||
|
@ -200,6 +244,7 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
|
|||
|
||||
for (unsigned I = 0, N = Locations.size(); I != N; ++I)
|
||||
DB << SourceRange(Locations[I]);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
||||
|
@ -215,8 +260,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
|||
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(
|
||||
T->getTypeLoc());
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
|
||||
|
@ -230,8 +274,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
|
|||
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
|
||||
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(E->getLocStart(), UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
|
||||
|
@ -247,9 +290,8 @@ bool Sema::DiagnoseUnexpandedParameterPack(const CXXScopeSpec &SS,
|
|||
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
||||
.TraverseNestedNameSpecifier(SS.getScopeRep());
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
|
||||
UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(SS.getRange().getBegin(),
|
||||
UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
|
||||
|
@ -284,8 +326,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(const DeclarationNameInfo &NameInfo,
|
|||
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
||||
.TraverseType(NameInfo.getName().getCXXNameType());
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(NameInfo.getLoc(), UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
||||
|
@ -299,8 +340,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(SourceLocation Loc,
|
|||
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
||||
.TraverseTemplateName(Template);
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(Loc, UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
|
||||
|
@ -313,8 +353,7 @@ bool Sema::DiagnoseUnexpandedParameterPack(TemplateArgumentLoc Arg,
|
|||
CollectUnexpandedParameterPacksVisitor(Unexpanded)
|
||||
.TraverseTemplateArgumentLoc(Arg);
|
||||
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
|
||||
DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
|
||||
return true;
|
||||
return DiagnoseUnexpandedParameterPacks(Arg.getLocation(), UPPC, Unexpanded);
|
||||
}
|
||||
|
||||
void Sema::collectUnexpandedParameterPacks(TemplateArgument Arg,
|
||||
|
|
|
@ -571,6 +571,9 @@ public:
|
|||
StmtResult TransformCompoundStmt(CompoundStmt *S, bool IsStmtExpr);
|
||||
ExprResult TransformCXXNamedCastExpr(CXXNamedCastExpr *E);
|
||||
|
||||
/// \brief Transform the captures and body of a lambda expression.
|
||||
ExprResult TransformLambdaScope(LambdaExpr *E, CXXMethodDecl *CallOperator);
|
||||
|
||||
#define STMT(Node, Parent) \
|
||||
StmtResult Transform##Node(Node *S);
|
||||
#define EXPR(Node, Parent) \
|
||||
|
@ -7894,14 +7897,13 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
return ExprError();
|
||||
|
||||
// Transform lambda parameters.
|
||||
bool Invalid = false;
|
||||
llvm::SmallVector<QualType, 4> ParamTypes;
|
||||
llvm::SmallVector<ParmVarDecl *, 4> Params;
|
||||
if (getDerived().TransformFunctionTypeParams(E->getLocStart(),
|
||||
E->getCallOperator()->param_begin(),
|
||||
E->getCallOperator()->param_size(),
|
||||
0, ParamTypes, &Params))
|
||||
Invalid = true;
|
||||
return ExprError();
|
||||
|
||||
// Build the call operator.
|
||||
CXXMethodDecl *CallOperator
|
||||
|
@ -7910,11 +7912,14 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
E->getCallOperator()->getLocEnd(),
|
||||
Params);
|
||||
getDerived().transformAttrs(E->getCallOperator(), CallOperator);
|
||||
|
||||
// FIXME: Instantiation-specific.
|
||||
CallOperator->setInstantiationOfMemberFunction(E->getCallOperator(),
|
||||
TSK_ImplicitInstantiation);
|
||||
|
||||
return getDerived().TransformLambdaScope(E, CallOperator);
|
||||
}
|
||||
|
||||
template<typename Derived>
|
||||
ExprResult
|
||||
TreeTransform<Derived>::TransformLambdaScope(LambdaExpr *E,
|
||||
CXXMethodDecl *CallOperator) {
|
||||
// Introduce the context of the call operator.
|
||||
Sema::ContextRAII SavedContext(getSema(), CallOperator);
|
||||
|
||||
|
@ -7927,6 +7932,7 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
|
|||
E->isMutable());
|
||||
|
||||
// Transform captures.
|
||||
bool Invalid = false;
|
||||
bool FinishedExplicitCaptures = false;
|
||||
for (LambdaExpr::capture_iterator C = E->capture_begin(),
|
||||
CEnd = E->capture_end();
|
||||
|
|
|
@ -89,6 +89,8 @@ namespace overloading {
|
|||
|
||||
namespace PR13117 {
|
||||
struct A {
|
||||
template<typename ... Args> static void f(Args...);
|
||||
|
||||
template<typename ... Args> static void f1()
|
||||
{
|
||||
(void)^(Args args) { // expected-error{{block contains unexpanded parameter pack 'Args'}}
|
||||
|
@ -97,9 +99,24 @@ namespace PR13117 {
|
|||
|
||||
template<typename ... Args> static void f2()
|
||||
{
|
||||
(void)[](Args args) { // expected-error{{lambda contains unexpanded parameter pack 'Args'}}
|
||||
// FIXME: Allow this.
|
||||
f(
|
||||
^(Args args) // expected-error{{block contains unexpanded parameter pack 'Args'}}
|
||||
{ }
|
||||
... // expected-error{{pack expansion does not contain any unexpanded parameter packs}}
|
||||
);
|
||||
}
|
||||
|
||||
template<typename ... Args> static void f3()
|
||||
{
|
||||
(void)[](Args args) { // expected-error{{expression contains unexpanded parameter pack 'Args'}}
|
||||
};
|
||||
}
|
||||
|
||||
template<typename ... Args> static void f4()
|
||||
{
|
||||
f([](Args args) { } ...);
|
||||
}
|
||||
};
|
||||
|
||||
void g() {
|
||||
|
|
|
@ -9,8 +9,8 @@ void print(T first, Ts... rest) {
|
|||
}
|
||||
|
||||
template<typename... Ts>
|
||||
void unsupported(Ts ...values) {
|
||||
auto unsup = [values] {}; // expected-error{{unexpanded function parameter pack capture is unsupported}}
|
||||
void unexpanded_capture(Ts ...values) {
|
||||
auto unexp = [values] {}; // expected-error{{initializer contains unexpanded parameter pack 'values'}}
|
||||
}
|
||||
|
||||
template<typename... Ts>
|
||||
|
|
|
@ -145,3 +145,79 @@ namespace ModifyingCapture {
|
|||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace VariadicPackExpansion {
|
||||
template<typename T, typename U> using Fst = T;
|
||||
template<typename...Ts> bool g(Fst<bool, Ts> ...bools);
|
||||
template<typename...Ts> bool f(Ts &&...ts) {
|
||||
return g<Ts...>([&ts] {
|
||||
if (!ts)
|
||||
return false;
|
||||
--ts;
|
||||
return true;
|
||||
} () ...);
|
||||
}
|
||||
void h() {
|
||||
int a = 5, b = 2, c = 3;
|
||||
while (f(a, b, c)) {
|
||||
}
|
||||
}
|
||||
|
||||
struct sink {
|
||||
template<typename...Ts> sink(Ts &&...) {}
|
||||
};
|
||||
|
||||
template<typename...Ts> void local_class() {
|
||||
sink {
|
||||
[] (Ts t) {
|
||||
struct S : Ts {
|
||||
void f(Ts t) {
|
||||
Ts &that = *this;
|
||||
that = t;
|
||||
}
|
||||
Ts g() { return *this; };
|
||||
};
|
||||
S s;
|
||||
s.f(t);
|
||||
return s;
|
||||
} (Ts()).g() ...
|
||||
};
|
||||
};
|
||||
struct X {}; struct Y {};
|
||||
template void local_class<X, Y>();
|
||||
|
||||
template<typename...Ts> void nested(Ts ...ts) {
|
||||
f(
|
||||
// Each expansion of this lambda implicitly captures all of 'ts', because
|
||||
// the inner lambda also expands 'ts'.
|
||||
[&] {
|
||||
return ts + [&] { return f(ts...); } ();
|
||||
} () ...
|
||||
);
|
||||
}
|
||||
template void nested(int, int, int);
|
||||
|
||||
template<typename...Ts> void nested2(Ts ...ts) { // expected-note 2{{here}}
|
||||
// Capture all 'ts', use only one.
|
||||
f([&ts...] { return ts; } ()...);
|
||||
// Capture each 'ts', use it.
|
||||
f([&ts] { return ts; } ()...);
|
||||
// Capture all 'ts', use all of them.
|
||||
f([&ts...] { return (int)f(ts...); } ());
|
||||
// Capture each 'ts', use all of them. Ill-formed. In more detail:
|
||||
//
|
||||
// We instantiate two lambdas here; the first captures ts$0, the second
|
||||
// captures ts$1. Both of them reference both ts parameters, so both are
|
||||
// ill-formed because ts can't be implicitly captured.
|
||||
//
|
||||
// FIXME: This diagnostic does not explain what's happening. We should
|
||||
// specify which 'ts' we're referring to in its diagnostic name. We should
|
||||
// also say which slice of the pack expansion is being performed in the
|
||||
// instantiation backtrace.
|
||||
f([&ts] { return (int)f(ts...); } ()...); // \
|
||||
// expected-error 2{{'ts' cannot be implicitly captured}} \
|
||||
// expected-note 2{{lambda expression begins here}}
|
||||
}
|
||||
template void nested2(int); // ok
|
||||
template void nested2(int, int); // expected-note {{in instantiation of}}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue