Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 1d3c480

Browse files
committed
PR33082: Improve tracking of unexpanded parameter packs within variadic generic lambdas.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@310946 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent df98b8f commit 1d3c480

File tree

3 files changed

+117
-39
lines changed

3 files changed

+117
-39
lines changed

Diff for: include/clang/Sema/ScopeInfo.h

+6
Original file line numberDiff line numberDiff line change
@@ -833,6 +833,12 @@ class LambdaScopeInfo final : public CapturingScopeInfo {
833833
return FSI->Kind == SK_Lambda;
834834
}
835835

836+
/// Is this scope known to be for a generic lambda? (This will be false until
837+
/// we parse the first 'auto'-typed parameter.
838+
bool isGenericLambda() const {
839+
return !AutoTemplateParams.empty() || GLTemplateParameterList;
840+
}
841+
836842
///
837843
/// \brief Add a variable that might potentially be captured by the
838844
/// lambda and therefore the enclosing lambdas.

Diff for: lib/Sema/SemaTemplateVariadic.cpp

+87-39
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ using namespace clang;
2626
// Visitor that collects unexpanded parameter packs
2727
//----------------------------------------------------------------------------
2828

29+
/// \brief Retrieve the depth and index of a parameter pack.
30+
static std::pair<unsigned, unsigned>
31+
getDepthAndIndex(NamedDecl *ND) {
32+
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
33+
return std::make_pair(TTP->getDepth(), TTP->getIndex());
34+
35+
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
36+
return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
37+
38+
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
39+
return std::make_pair(TTP->getDepth(), TTP->getIndex());
40+
}
41+
2942
namespace {
3043
/// \brief A class that collects unexpanded parameter packs.
3144
class CollectUnexpandedParameterPacksVisitor :
@@ -36,23 +49,44 @@ namespace {
3649

3750
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded;
3851

39-
bool InLambda;
40-
52+
bool InLambda = false;
53+
unsigned DepthLimit = (unsigned)-1;
54+
55+
void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
56+
if (auto *PVD = dyn_cast<ParmVarDecl>(ND)) {
57+
// For now, the only problematic case is a generic lambda's templated
58+
// call operator, so we don't need to look for all the other ways we
59+
// could have reached a dependent parameter pack.
60+
auto *FD = dyn_cast<FunctionDecl>(PVD->getDeclContext());
61+
auto *FTD = FD ? FD->getDescribedFunctionTemplate() : nullptr;
62+
if (FTD && FTD->getTemplateParameters()->getDepth() >= DepthLimit)
63+
return;
64+
} else if (getDepthAndIndex(ND).first >= DepthLimit)
65+
return;
66+
67+
Unexpanded.push_back({ND, Loc});
68+
}
69+
void addUnexpanded(const TemplateTypeParmType *T,
70+
SourceLocation Loc = SourceLocation()) {
71+
if (T->getDepth() < DepthLimit)
72+
Unexpanded.push_back({T, Loc});
73+
}
74+
4175
public:
4276
explicit CollectUnexpandedParameterPacksVisitor(
43-
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
44-
: Unexpanded(Unexpanded), InLambda(false) { }
77+
SmallVectorImpl<UnexpandedParameterPack> &Unexpanded)
78+
: Unexpanded(Unexpanded) {}
4579

4680
bool shouldWalkTypesOfTypeLocs() const { return false; }
47-
81+
4882
//------------------------------------------------------------------------
4983
// Recording occurrences of (unexpanded) parameter packs.
5084
//------------------------------------------------------------------------
5185

5286
/// \brief Record occurrences of template type parameter packs.
5387
bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) {
5488
if (TL.getTypePtr()->isParameterPack())
55-
Unexpanded.push_back(std::make_pair(TL.getTypePtr(), TL.getNameLoc()));
89+
addUnexpanded(TL.getTypePtr(), TL.getNameLoc());
5690
return true;
5791
}
5892

@@ -63,7 +97,7 @@ namespace {
6397
/// Ideally, this routine would never be used.
6498
bool VisitTemplateTypeParmType(TemplateTypeParmType *T) {
6599
if (T->isParameterPack())
66-
Unexpanded.push_back(std::make_pair(T, SourceLocation()));
100+
addUnexpanded(T);
67101

68102
return true;
69103
}
@@ -72,18 +106,18 @@ namespace {
72106
/// parameter packs in an expression.
73107
bool VisitDeclRefExpr(DeclRefExpr *E) {
74108
if (E->getDecl()->isParameterPack())
75-
Unexpanded.push_back(std::make_pair(E->getDecl(), E->getLocation()));
109+
addUnexpanded(E->getDecl(), E->getLocation());
76110

77111
return true;
78112
}
79113

80114
/// \brief Record occurrences of template template parameter packs.
81115
bool TraverseTemplateName(TemplateName Template) {
82-
if (TemplateTemplateParmDecl *TTP
83-
= dyn_cast_or_null<TemplateTemplateParmDecl>(
84-
Template.getAsTemplateDecl()))
116+
if (auto *TTP = dyn_cast_or_null<TemplateTemplateParmDecl>(
117+
Template.getAsTemplateDecl())) {
85118
if (TTP->isParameterPack())
86-
Unexpanded.push_back(std::make_pair(TTP, SourceLocation()));
119+
addUnexpanded(TTP);
120+
}
87121

88122
return inherited::TraverseTemplateName(Template);
89123
}
@@ -141,7 +175,13 @@ namespace {
141175
/// \brief Suppress traversal of non-parameter declarations, since
142176
/// they cannot contain unexpanded parameter packs.
143177
bool TraverseDecl(Decl *D) {
144-
if ((D && isa<ParmVarDecl>(D)) || InLambda)
178+
auto *PVD = dyn_cast_or_null<ParmVarDecl>(D);
179+
// A function parameter pack is a pack expansion, so cannot contain
180+
// an unexpanded parameter pack.
181+
if (PVD && PVD->isParameterPack())
182+
return true;
183+
184+
if (PVD || InLambda)
145185
return inherited::TraverseDecl(D);
146186

147187
return true;
@@ -175,25 +215,26 @@ namespace {
175215
return true;
176216

177217
bool WasInLambda = InLambda;
178-
InLambda = true;
218+
unsigned OldDepthLimit = DepthLimit;
179219

180-
// If any capture names a function parameter pack, that pack is expanded
181-
// when the lambda is expanded.
182-
for (LambdaExpr::capture_iterator I = Lambda->capture_begin(),
183-
E = Lambda->capture_end();
184-
I != E; ++I) {
185-
if (I->capturesVariable()) {
186-
VarDecl *VD = I->getCapturedVar();
187-
if (VD->isParameterPack())
188-
Unexpanded.push_back(std::make_pair(VD, I->getLocation()));
189-
}
190-
}
220+
InLambda = true;
221+
if (auto *TPL = Lambda->getTemplateParameterList())
222+
DepthLimit = TPL->getDepth();
191223

192224
inherited::TraverseLambdaExpr(Lambda);
193225

194226
InLambda = WasInLambda;
227+
DepthLimit = OldDepthLimit;
195228
return true;
196229
}
230+
231+
/// Suppress traversal within pack expansions in lambda captures.
232+
bool TraverseLambdaCapture(LambdaExpr *Lambda, const LambdaCapture *C,
233+
Expr *Init) {
234+
if (C->isPackExpansion())
235+
return true;
236+
return inherited::TraverseLambdaCapture(Lambda, C, Init);
237+
}
197238
};
198239
}
199240

@@ -220,13 +261,33 @@ Sema::DiagnoseUnexpandedParameterPacks(SourceLocation Loc,
220261
if (Unexpanded.empty())
221262
return false;
222263

223-
// If we are within a lambda expression, that lambda contains an unexpanded
264+
// If we are within a lambda expression and referencing a pack that is not
265+
// a parameter of the lambda itself, that lambda contains an unexpanded
224266
// parameter pack, and we are done.
225267
// FIXME: Store 'Unexpanded' on the lambda so we don't need to recompute it
226268
// later.
269+
SmallVector<UnexpandedParameterPack, 4> GenericLambdaParamReferences;
227270
for (unsigned N = FunctionScopes.size(); N; --N) {
228271
if (sema::LambdaScopeInfo *LSI =
229272
dyn_cast<sema::LambdaScopeInfo>(FunctionScopes[N-1])) {
273+
if (LSI->isGenericLambda()) {
274+
for (auto &Param : Unexpanded) {
275+
auto *PD = dyn_cast_or_null<ParmVarDecl>(
276+
Param.first.dyn_cast<NamedDecl *>());
277+
if (PD && PD->getDeclContext() == LSI->CallOperator)
278+
GenericLambdaParamReferences.push_back(Param);
279+
}
280+
}
281+
282+
// If we have references to a parameter of a generic lambda, only
283+
// diagnose those ones. We don't know whether any other unexpanded
284+
// parameters referenced herein are actually unexpanded; they might
285+
// be expanded at an outer level.
286+
if (!GenericLambdaParamReferences.empty()) {
287+
Unexpanded = GenericLambdaParamReferences;
288+
break;
289+
}
290+
230291
LSI->ContainsUnexpandedParameterPack = true;
231292
return false;
232293
}
@@ -520,19 +581,6 @@ ExprResult Sema::CheckPackExpansion(Expr *Pattern, SourceLocation EllipsisLoc,
520581
PackExpansionExpr(Context.DependentTy, Pattern, EllipsisLoc, NumExpansions);
521582
}
522583

523-
/// \brief Retrieve the depth and index of a parameter pack.
524-
static std::pair<unsigned, unsigned>
525-
getDepthAndIndex(NamedDecl *ND) {
526-
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(ND))
527-
return std::make_pair(TTP->getDepth(), TTP->getIndex());
528-
529-
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(ND))
530-
return std::make_pair(NTTP->getDepth(), NTTP->getIndex());
531-
532-
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(ND);
533-
return std::make_pair(TTP->getDepth(), TTP->getIndex());
534-
}
535-
536584
bool Sema::CheckParameterPacksForExpansion(
537585
SourceLocation EllipsisLoc, SourceRange PatternRange,
538586
ArrayRef<UnexpandedParameterPack> Unexpanded,

Diff for: test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp

+24
Original file line numberDiff line numberDiff line change
@@ -98,3 +98,27 @@ namespace variadic_expansion {
9898
}
9999
#endif
100100

101+
namespace PR33082 {
102+
template<int ...I> void a() {
103+
int arr[] = { [](auto ...K) { (void)I; } ... }; // expected-error {{no viable conversion}} expected-note {{candidate}}
104+
}
105+
106+
template<typename ...T> struct Pack {};
107+
template<typename ...T, typename ...U> void b(Pack<U...>, T ...t) {
108+
int arr[] = {[t...]() { // expected-error 2{{cannot initialize an array element of type 'int' with}}
109+
U u;
110+
return u;
111+
}()...};
112+
}
113+
114+
void c() {
115+
int arr[] = {[](auto... v) {
116+
v; // expected-error {{unexpanded parameter pack 'v'}}
117+
}...}; // expected-error {{pack expansion does not contain any unexpanded parameter packs}}
118+
}
119+
120+
void run() {
121+
a<1>(); // expected-note {{instantiation of}}
122+
b(Pack<int*, float*>(), 1, 2, 3); // expected-note {{instantiation of}}
123+
}
124+
}

0 commit comments

Comments
 (0)