Skip to content

Commit 3733b0c

Browse files
authored
[Clang] Fix a DeclContext mismatch when parsing nested lambda parameters (#112177)
When parsing its function parameters, we don't change the CurContext to the lambda's function declaration. However, CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures() has not yet adapted to such behavior when nested lambdas come into play. Consider the following case, struct Foo {}; template <int, Foo f> struct Arr {}; constexpr void foo() { constexpr Foo F; [&]<int I>() { [&](Arr<I, F>) {}; }.template operator()<42>(); } As per [basic.def.odr]p5.2, the use of F constitutes an ODR-use. And per [basic.def.odr]p10, F should be ODR-usable in that interleaving scope. We failed to accept the case because the call to tryCaptureVariable() in getStackIndexOfNearestEnclosingCaptureCapableLambda() suggested that F is needlessly captureable. That was due to a missed handling for AfterParameterList in FunctionScopeIndexToStopAt, where it still presumed DC and LSI matched. Fixes #47400 Fixes #90896
1 parent bad04dc commit 3733b0c

File tree

4 files changed

+36
-2
lines changed

4 files changed

+36
-2
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,10 +509,12 @@ Bug Fixes to C++ Support
509509
a class template. (#GH102320)
510510
- Fix a crash when parsing a pseudo destructor involving an invalid type. (#GH111460)
511511
- Fixed an assertion failure when invoking recovery call expressions with explicit attributes
512-
and undeclared templates. (#GH107047, #GH49093)
512+
and undeclared templates. (#GH107047), (#GH49093)
513513
- Clang no longer crashes when a lambda contains an invalid block declaration that contains an unexpanded
514514
parameter pack. (#GH109148)
515515
- Fixed overload handling for object parameters with top-level cv-qualifiers in explicit member functions (#GH100394)
516+
- Fixed a bug in lambda captures where ``constexpr`` class-type objects were not properly considered ODR-used in
517+
certain situations. (#GH47400), (#GH90896)
516518

517519
Bug Fixes to AST Handling
518520
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaExpr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18865,7 +18865,17 @@ bool Sema::tryCaptureVariable(
1886518865
// We need to sync up the Declaration Context with the
1886618866
// FunctionScopeIndexToStopAt
1886718867
if (FunctionScopeIndexToStopAt) {
18868+
assert(!FunctionScopes.empty() && "No function scopes to stop at?");
1886818869
unsigned FSIndex = FunctionScopes.size() - 1;
18870+
// When we're parsing the lambda parameter list, the current DeclContext is
18871+
// NOT the lambda but its parent. So move away the current LSI before
18872+
// aligning DC and FunctionScopeIndexToStopAt.
18873+
if (auto *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[FSIndex]);
18874+
FSIndex && LSI && !LSI->AfterParameterList)
18875+
--FSIndex;
18876+
assert(MaxFunctionScopesIndex <= FSIndex &&
18877+
"FunctionScopeIndexToStopAt should be no greater than FSIndex into "
18878+
"FunctionScopes.");
1886918879
while (FSIndex != MaxFunctionScopesIndex) {
1887018880
DC = getLambdaAwareParentOfDeclContext(DC);
1887118881
--FSIndex;

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8686,7 +8686,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
86868686
while (isa_and_nonnull<CapturedDecl>(DC))
86878687
DC = DC->getParent();
86888688
assert(
8689-
CurrentLSI->CallOperator == DC &&
8689+
(CurrentLSI->CallOperator == DC || !CurrentLSI->AfterParameterList) &&
86908690
"The current call operator must be synchronized with Sema's CurContext");
86918691
#endif // NDEBUG
86928692

clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,3 +297,25 @@ void __trans_tmp_1() {
297297
}
298298

299299
}
300+
301+
namespace GH47400 {
302+
303+
struct Foo {};
304+
305+
template <int, Foo> struct Arr {};
306+
307+
template <int> struct S {};
308+
309+
constexpr void foo() {
310+
constexpr Foo f;
311+
[&]<int is>() {
312+
[&](Arr<is, f>) {}({}); // f constitutes an ODR-use
313+
}.template operator()<42>();
314+
315+
constexpr int C = 1;
316+
[] {
317+
[](S<C>) { }({}); // ... while C doesn't
318+
}();
319+
}
320+
321+
} // namespace GH47400

0 commit comments

Comments
 (0)