Skip to content

Commit

Permalink
[Clang] Don't assert non-empty packs for FunctionParmPackExprs (#107561)
Browse files Browse the repository at this point in the history
`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
  • Loading branch information
zyn0217 authored Sep 9, 2024
1 parent 022b3c2 commit 8549b32
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 23 deletions.
2 changes: 1 addition & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -379,8 +379,8 @@ Bug Fixes to C++ Support
- Fixed a bug in the substitution of empty pack indexing types. (#GH105903)
- Clang no longer tries to capture non-odr used default arguments of template parameters of generic lambdas (#GH107048)
- Fixed a bug where defaulted comparison operators would remove ``const`` from base classes. (#GH102588)

- Fix a crash when using ``source_location`` in the trailing return type of a lambda expression. (#GH67134)
- A follow-up fix was added for (#GH61460), as the previous fix was not entirely correct. (#GH86361)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
38 changes: 29 additions & 9 deletions clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ namespace {
bool InLambda = false;
unsigned DepthLimit = (unsigned)-1;

#ifndef NDEBUG
bool ContainsFunctionParmPackExpr = false;
#endif

void addUnexpanded(NamedDecl *ND, SourceLocation Loc = SourceLocation()) {
if (auto *VD = dyn_cast<VarDecl>(ND)) {
// For now, the only problematic case is a generic lambda's templated
Expand Down Expand Up @@ -280,6 +284,17 @@ namespace {

return inherited::TraverseLambdaCapture(Lambda, C, Init);
}

#ifndef NDEBUG
bool TraverseFunctionParmPackExpr(FunctionParmPackExpr *) {
ContainsFunctionParmPackExpr = true;
return true;
}

bool containsFunctionParmPackExpr() const {
return ContainsFunctionParmPackExpr;
}
#endif
};
}

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

// CollectUnexpandedParameterPacksVisitor does not expect to see a
// FunctionParmPackExpr, but diagnosing unexpected parameter packs may still
// see such an expression in a lambda body.
// We'll bail out early in this case to avoid triggering an assertion.
if (isa<FunctionParmPackExpr>(E) && getEnclosingLambda())
return false;

// FunctionParmPackExprs are special:
//
// 1) they're used to model DeclRefExprs to packs that have been expanded but
// had that expansion held off in the process of transformation.
//
// 2) they always have the unexpanded dependencies but don't introduce new
// unexpanded packs.
//
// We might encounter a FunctionParmPackExpr being a full expression, which a
// larger CXXFoldExpr would expand.
SmallVector<UnexpandedParameterPack, 2> Unexpanded;
CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseStmt(E);
assert(!Unexpanded.empty() && "Unable to find unexpanded parameter packs");
CollectUnexpandedParameterPacksVisitor Visitor(Unexpanded);
Visitor.TraverseStmt(E);
assert((!Unexpanded.empty() || Visitor.containsFunctionParmPackExpr()) &&
"Unable to find unexpanded parameter packs");
return DiagnoseUnexpandedParameterPacks(E->getBeginLoc(), UPPC, Unexpanded);
}

Expand Down
26 changes: 26 additions & 0 deletions clang/test/SemaCXX/lambda-pack-expansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,29 @@ void f() {
}

}

namespace GH61460 {

template<typename... Ts>
void f1(Ts... ts);

template <typename... Ts> void g(Ts... p1s) {
(void)[&](auto... p2s) {
(
[&] {
p1s;
f1(p1s);
sizeof(p1s);
p2s;
},
...);
};
}

template <typename... Ts> void g2(Ts... p1s) {
(void)[&](auto... p2s) { [&] { p1s; p2s; }; }; // expected-error {{unexpanded parameter pack 'p2s'}}
}

void f1() { g(); }

} // namespace GH61460
13 changes: 0 additions & 13 deletions clang/test/SemaCXX/pr61460.cpp

This file was deleted.

0 comments on commit 8549b32

Please sign in to comment.