summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Sema/ScopeInfo.h3
-rw-r--r--include/clang/Sema/Sema.h5
-rw-r--r--lib/Parse/ParseInit.cpp1
-rw-r--r--lib/Sema/Sema.cpp17
-rw-r--r--lib/Sema/SemaDecl.cpp7
-rw-r--r--lib/Sema/SemaLambda.cpp15
-rw-r--r--lib/Sema/SemaTemplate.cpp12
-rw-r--r--lib/Sema/SemaTemplateVariadic.cpp72
-rw-r--r--test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp13
9 files changed, 111 insertions, 34 deletions
diff --git a/include/clang/Sema/ScopeInfo.h b/include/clang/Sema/ScopeInfo.h
index 344ef78230..4f7534f9ef 100644
--- a/include/clang/Sema/ScopeInfo.h
+++ b/include/clang/Sema/ScopeInfo.h
@@ -820,6 +820,9 @@ public:
/// Whether the lambda contains an unexpanded parameter pack.
bool ContainsUnexpandedParameterPack = false;
+ /// Packs introduced by this lambda, if any.
+ SmallVector<NamedDecl*, 4> LocalPacks;
+
/// If this is a generic lambda, use this as the depth of
/// each 'auto' parameter, during initial AST construction.
unsigned AutoTemplateParameterDepth = 0;
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 19cf8041dd..624238c00e 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -1474,6 +1474,11 @@ public:
/// Retrieve the current block, if any.
sema::BlockScopeInfo *getCurBlock();
+ /// Get the innermost lambda enclosing the current location, if any. This
+ /// looks through intervening non-lambda scopes such as local functions and
+ /// blocks.
+ sema::LambdaScopeInfo *getEnclosingLambda() const;
+
/// Retrieve the current lambda scope info, if any.
/// \param IgnoreNonLambdaCapturingScope true if should find the top-most
/// lambda scope info ignoring all inner capturing scopes that are not
diff --git a/lib/Parse/ParseInit.cpp b/lib/Parse/ParseInit.cpp
index 769140f2d3..eaf31e81b9 100644
--- a/lib/Parse/ParseInit.cpp
+++ b/lib/Parse/ParseInit.cpp
@@ -39,6 +39,7 @@ bool Parser::MayBeDesignationStart() {
// cases here, and fall back to tentative parsing if those fail.
switch (PP.LookAhead(0).getKind()) {
case tok::equal:
+ case tok::ellipsis:
case tok::r_square:
// Definitely starts a lambda expression.
return false;
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index d4be3e9242..152cc7d9a2 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -1804,6 +1804,22 @@ FunctionScopeInfo *Sema::getEnclosingFunction() const {
return nullptr;
}
+LambdaScopeInfo *Sema::getEnclosingLambda() const {
+ for (auto *Scope : llvm::reverse(FunctionScopes)) {
+ if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Scope)) {
+ if (LSI->Lambda && !LSI->Lambda->Encloses(CurContext)) {
+ // We have switched contexts due to template instantiation.
+ // FIXME: We should swap out the FunctionScopes during code synthesis
+ // so that we don't need to check for this.
+ assert(!CodeSynthesisContexts.empty());
+ return nullptr;
+ }
+ return LSI;
+ }
+ }
+ return nullptr;
+}
+
LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
if (FunctionScopes.empty())
return nullptr;
@@ -1826,6 +1842,7 @@ LambdaScopeInfo *Sema::getCurLambda(bool IgnoreNonLambdaCapturingScope) {
return CurLSI;
}
+
// We have a generic lambda if we parsed auto parameters, or we have
// an associated template parameter list.
LambdaScopeInfo *Sema::getCurGenericLambda() {
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index b0d610401a..a96f0d28e8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -12706,6 +12706,13 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
+ // Make a note if we created a new pack in the scope of a lambda, so that
+ // we know that references to that pack must also be expanded within the
+ // lambda scope.
+ if (New->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(New);
+
// Parameters can not be abstract class types.
// For record types, this is done by the AbstractClassUsageDiagnoser once
// the class has been completely parsed.
diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp
index e7c51a3e3d..a808854ed9 100644
--- a/lib/Sema/SemaLambda.cpp
+++ b/lib/Sema/SemaLambda.cpp
@@ -824,8 +824,11 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
// FIXME: Retain the TypeSourceInfo from buildLambdaInitCaptureInitialization
// rather than reconstructing it here.
TypeSourceInfo *TSI = Context.getTrivialTypeSourceInfo(InitCaptureType, Loc);
- if (auto PETL = TSI->getTypeLoc().getAs<PackExpansionTypeLoc>())
+ bool IsInitCapturePack = false;
+ if (auto PETL = TSI->getTypeLoc().getAs<PackExpansionTypeLoc>()) {
PETL.setEllipsisLoc(EllipsisLoc);
+ IsInitCapturePack = true;
+ }
// Create a dummy variable representing the init-capture. This is not actually
// used as a variable, and only exists as a way to name and refer to the
@@ -839,6 +842,8 @@ VarDecl *Sema::createLambdaInitCaptureVarDecl(SourceLocation Loc,
NewVD->setInitStyle(static_cast<VarDecl::InitializationStyle>(InitStyle));
NewVD->markUsed(Context);
NewVD->setInit(Init);
+ if (NewVD->isParameterPack())
+ getCurLambda()->LocalPacks.push_back(NewVD);
return NewVD;
}
@@ -928,12 +933,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
// Check for unexpanded parameter packs in the method type.
if (MethodTyInfo->getType()->containsUnexpandedParameterPack())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(Intro.Range.getBegin(), MethodTyInfo,
+ UPPC_DeclarationType);
}
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
KnownDependent, Intro.Default);
-
CXXMethodDecl *Method =
startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
ParamInfo.getDeclSpec().getConstexprSpecifier());
@@ -1053,7 +1058,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
if (C->Init.get()->containsUnexpandedParameterPack() &&
!C->InitCaptureType.get()->getAs<PackExpansionType>())
- ContainsUnexpandedParameterPack = true;
+ DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
unsigned InitStyle;
switch (C->InitKind) {
@@ -1184,7 +1189,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
}
finishLambdaExplicitCaptures(LSI);
- LSI->ContainsUnexpandedParameterPack = ContainsUnexpandedParameterPack;
+ LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;
// Add lambda parameters into scope.
addLambdaParameters(Intro.Captures, Method, CurScope);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 00771e2246..d7a1d9ea1b 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1013,6 +1013,10 @@ NamedDecl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
Typename, IsParameterPack);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
@@ -1211,6 +1215,10 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D,
if (Invalid)
Param->setInvalidDecl();
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, D.getIdentifierLoc(),
ParamName);
@@ -1274,6 +1282,10 @@ NamedDecl *Sema::ActOnTemplateTemplateParameter(Scope* S,
Name, Params);
Param->setAccess(AS_public);
+ if (Param->isParameterPack())
+ if (auto *LSI = getEnclosingLambda())
+ LSI->LocalPacks.push_back(Param);
+
// If the template template parameter has a name, then link the identifier
// into the scope and lookup mechanisms.
if (Name) {
diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp
index f90bff6e7a..975d6620c0 100644
--- a/lib/Sema/SemaTemplateVariadic.cpp
+++ b/lib/Sema/SemaTemplateVariadic.cpp
@@ -294,44 +294,58 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
return false;
// If we are within a lambda expression and referencing a pack that is not
- // a parameter of the lambda itself, that lambda contains an unexpanded
+ // declared within the lambda itself, 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.
SmallVector<UnexpandedParameterPack, 4> LambdaParamPackReferences;
- for (unsigned N = FunctionScopes.size(); N; --N) {
- sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
- // We do not permit pack expansion that would duplicate a statement
- // expression, not even within a lambda.
- // FIXME: We could probably support this for statement expressions that do
- // not contain labels, and for pack expansions that expand both the stmt
- // expr and the enclosing lambda.
- if (std::any_of(
- Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
- [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; }))
- break;
+ if (auto *LSI = getEnclosingLambda()) {
+ for (auto &Pack : Unexpanded) {
+ auto DeclaresThisPack = [&](NamedDecl *LocalPack) {
+ if (auto *TTPT = Pack.first.dyn_cast<const TemplateTypeParmType *>()) {
+ auto *TTPD = dyn_cast<TemplateTypeParmDecl>(LocalPack);
+ return TTPD && TTPD->getTypeForDecl() == TTPT;
+ }
+ return declaresSameEntity(Pack.first.get<NamedDecl *>(), LocalPack);
+ };
+ if (std::find_if(LSI->LocalPacks.begin(), LSI->LocalPacks.end(),
+ DeclaresThisPack) != LSI->LocalPacks.end())
+ LambdaParamPackReferences.push_back(Pack);
+ }
- if (auto *LSI = dyn_cast<sema::LambdaScopeInfo>(Func)) {
- if (N == FunctionScopes.size()) {
- for (auto &Pack : Unexpanded) {
- auto *VD = dyn_cast_or_null<VarDecl>(
- Pack.first.dyn_cast<NamedDecl *>());
- if (VD && VD->getDeclContext() == LSI->CallOperator)
- LambdaParamPackReferences.push_back(Pack);
+ if (LambdaParamPackReferences.empty()) {
+ // Construct in lambda only references packs declared outside the lambda.
+ // That's OK for now, but the lambda itself is considered to contain an
+ // unexpanded pack in this case, which will require expansion outside the
+ // lambda.
+
+ // We do not permit pack expansion that would duplicate a statement
+ // expression, not even within a lambda.
+ // FIXME: We could probably support this for statement expressions that
+ // do not contain labels.
+ // FIXME: This is insufficient to detect this problem; consider
+ // f( ({ bad: 0; }) + pack ... );
+ bool EnclosingStmtExpr = false;
+ for (unsigned N = FunctionScopes.size(); N; --N) {
+ sema::FunctionScopeInfo *Func = FunctionScopes[N-1];
+ if (std::any_of(
+ Func->CompoundScopes.begin(), Func->CompoundScopes.end(),
+ [](sema::CompoundScopeInfo &CSI) { return CSI.IsStmtExpr; })) {
+ EnclosingStmtExpr = true;
+ break;
}
+ // Coumpound-statements outside the lambda are OK for now; we'll check
+ // for those when we finish handling the lambda.
+ if (Func == LSI)
+ break;
}
- // If we have references to a parameter pack of the innermost enclosing
- // lambda, only diagnose those ones. We don't know whether any other
- // unexpanded parameters referenced herein are actually unexpanded;
- // they might be expanded at an outer level.
- if (!LambdaParamPackReferences.empty()) {
- Unexpanded = LambdaParamPackReferences;
- break;
+ if (!EnclosingStmtExpr) {
+ LSI->ContainsUnexpandedParameterPack = true;
+ return false;
}
-
- LSI->ContainsUnexpandedParameterPack = true;
- return false;
+ } else {
+ Unexpanded = LambdaParamPackReferences;
}
}
diff --git a/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
index b8022d2091..5c1eb32ad2 100644
--- a/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
+++ b/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
@@ -122,3 +122,16 @@ namespace PR33082 {
b(Pack<int*, float*>(), 1, 2, 3); // expected-note {{instantiation of}}
}
}
+
+void pr42587() {
+ (void)[](auto... args) -> decltype(args) {}; // expected-error {{type contains unexpanded parameter pack}}
+ (void)[](auto... args, int = args) {}; // expected-error {{default argument contains unexpanded parameter pack}}
+ (void)[](auto... args, decltype(args)) {}; // expected-error {{type contains unexpanded parameter pack}}
+ (void)[](auto... args, decltype(args)...) {}; // (ok)
+ (void)[](auto... args, int = [=] { return args; }()) {}; // expected-error {{default argument contains unexpanded parameter pack}}
+ (void)([]<typename ...T> (T t) {} + ...); // expected-error {{contains unexpanded parameter pack 'T'}} expected-error {{does not contain any unexpanded}} expected-warning 0-2{{extension}}
+ (void)([]<int ...N> (int k = N) {} + ...); // expected-error {{contains unexpanded parameter pack 'N'}} expected-error {{does not contain any unexpanded}} expected-warning 0-2{{extension}}
+ (void)([]<template<typename> typename ...T> (T<int>) {} + ...); // expected-error {{contains unexpanded parameter pack 'T'}} expected-error {{does not contain any unexpanded}} expected-warning 0-3{{extension}}
+}
+
+template<typename ...T> int v = {[...x = T()] { int k = x; } ...}; // expected-error {{contains unexpanded parameter pack 'x'}} expected-error {{does not contain any unexpanded}} expected-warning 0-1{{extension}}