Skip to content

Commit 8549b32

Browse files
authored
[Clang] Don't assert non-empty packs for FunctionParmPackExprs (#107561)
`FunctionParmPackExpr`s are peculiar in that they have to be of unexpanded dependency while they don't introduce any unexpanded packs. So this patch rules them out in the non-empty pack assertion in `DiagnoseUnexpandedParameterPack()`. There was a fix #69224, but that turned out to be insufficient. I also moved the separate tests to a pre-existing file. Fixes #86361
1 parent 022b3c2 commit 8549b32

File tree

4 files changed

+56
-23
lines changed

4 files changed

+56
-23
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,8 @@ Bug Fixes to C++ Support
379379
- Fixed a bug in the substitution of empty pack indexing types. (#GH105903)
380380
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
381381
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)
382-
383382
- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
383+
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361)
384384

385385
Bug Fixes to AST Handling
386386
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaTemplateVariadic.cpp

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ namespace {
3939
bool InLambda = false;
4040
unsigned DepthLimit = (unsigned)-1;
4141

42+
#ifndef NDEBUG
43+
bool ContainsFunctionParmPackExpr = false;
44+
#endif
45+
4246
void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
4347
if (auto *VD = dyn_cast<VarDecl>(ND)) {
4448
// For now, the only problematic case is a generic lambda's templated
@@ -280,6 +284,17 @@ namespace {
280284

281285
return inherited::TraverseLambdaCapture(Lambda, C, Init);
282286
}
287+
288+
#ifndef NDEBUG
289+
bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) {
290+
ContainsFunctionParmPackExpr = true;
291+
return true;
292+
}
293+
294+
bool containsFunctionParmPackExpr() const {
295+
return ContainsFunctionParmPackExpr;
296+
}
297+
#endif
283298
};
284299
}
285300

@@ -414,16 +429,21 @@ bool Sema::DiagnoseUnexpandedParameterPack(Expr *E,
414429
if (!E->containsUnexpandedParameterPack())
415430
return false;
416431

417-
// CollectUnexpandedParameterPacksVisitor does not expect to see a
418-
// FunctionParmPackExpr, but diagnosing unexpected parameter packs may still
419-
// see such an expression in a lambda body.
420-
// We'll bail out early in this case to avoid triggering an assertion.
421-
if (isa<FunctionParmPackExpr>(E) && getEnclosingLambda())
422-
return false;
423-
432+
// FunctionParmPackExprs are special:
433+
//
434+
// 1) they're used to model DeclRefExprs to packs that have been expanded but
435+
// had that expansion held off in the process of transformation.
436+
//
437+
// 2) they always have the unexpanded dependencies but don't introduce new
438+
// unexpanded packs.
439+
//
440+
// We might encounter a FunctionParmPackExpr being a full expression, which a
441+
// larger CXXFoldExpr would expand.
424442
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
425-
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
426-
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
443+
CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded);
444+
Visitor.TraverseStmt(E);
445+
assert((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) &&
446+
"Unable to find unexpanded parameter packs");
427447
return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded);
428448
}
429449

clang/test/SemaCXX/lambda-pack-expansion.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,29 @@ void f() {
6868
}
6969

7070
}
71+
72+
namespace GH61460 {
73+
74+
template<typename... Ts>
75+
void f1(Ts... ts);
76+
77+
template <typename... Ts> void g(Ts... p1s) {
78+
(void)[&](auto... p2s) {
79+
(
80+
[&] {
81+
p1s;
82+
f1(p1s);
83+
sizeof(p1s);
84+
p2s;
85+
},
86+
...);
87+
};
88+
}
89+
90+
template <typename... Ts> void g2(Ts... p1s) {
91+
(void)[&](auto... p2s) { [&] { p1s; p2s; }; }; // expected-error {{unexpanded parameter pack 'p2s'}}
92+
}
93+
94+
void f1() { g(); }
95+
96+
} // namespace GH61460

clang/test/SemaCXX/pr61460.cpp

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)