Author: Younan Zhang
Date: 2024-10-15T12:52:31+08:00
New Revision: 3733b0cff314e1427b1a905e6e7438b536f9a96d

URL: 
https://github.com/llvm/llvm-project/commit/3733b0cff314e1427b1a905e6e7438b536f9a96d
DIFF: 
https://github.com/llvm/llvm-project/commit/3733b0cff314e1427b1a905e6e7438b536f9a96d.diff

LOG: [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

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaExpr.cpp
    clang/lib/Sema/SemaExprCXX.cpp
    clang/test/SemaCXX/lambda-capture-type-deduction.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index b430b2b0ee3187..21e25fc71bbb17 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -509,10 +509,12 @@ Bug Fixes to C++ Support
   a class template. (#GH102320)
 - Fix a crash when parsing a pseudo destructor involving an invalid type. 
(#GH111460)
 - Fixed an assertion failure when invoking recovery call expressions with 
explicit attributes
-  and undeclared templates. (#GH107047, #GH49093)
+  and undeclared templates. (#GH107047), (#GH49093)
 - Clang no longer crashes when a lambda contains an invalid block declaration 
that contains an unexpanded
   parameter pack. (#GH109148)
 - Fixed overload handling for object parameters with top-level cv-qualifiers 
in explicit member functions (#GH100394)
+- Fixed a bug in lambda captures where ``constexpr`` class-type objects were 
not properly considered ODR-used in
+  certain situations. (#GH47400), (#GH90896)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 48f4029d873b94..044f56f2af71bf 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18865,7 +18865,17 @@ bool Sema::tryCaptureVariable(
   // We need to sync up the Declaration Context with the
   // FunctionScopeIndexToStopAt
   if (FunctionScopeIndexToStopAt) {
+    assert(!FunctionScopes.empty() && "No function scopes to stop at?");
     unsigned FSIndex = FunctionScopes.size() - 1;
+    // When we're parsing the lambda parameter list, the current DeclContext is
+    // NOT the lambda but its parent. So move away the current LSI before
+    // aligning DC and FunctionScopeIndexToStopAt.
+    if (auto *LSI = dyn_cast<LambdaScopeInfo>(FunctionScopes[FSIndex]);
+        FSIndex && LSI && !LSI->AfterParameterList)
+      --FSIndex;
+    assert(MaxFunctionScopesIndex <= FSIndex &&
+           "FunctionScopeIndexToStopAt should be no greater than FSIndex into "
+           "FunctionScopes.");
     while (FSIndex != MaxFunctionScopesIndex) {
       DC = getLambdaAwareParentOfDeclContext(DC);
       --FSIndex;

diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index d39a545b66c151..90e06b5411da77 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -8686,7 +8686,7 @@ static void 
CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
   while (isa_and_nonnull<CapturedDecl>(DC))
     DC = DC->getParent();
   assert(
-      CurrentLSI->CallOperator == DC &&
+      (CurrentLSI->CallOperator == DC || !CurrentLSI->AfterParameterList) &&
       "The current call operator must be synchronized with Sema's CurContext");
 #endif // NDEBUG
 

diff  --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp 
b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
index 7bf36a6a9cab73..a86f3018989927 100644
--- a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+++ b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -297,3 +297,25 @@ void __trans_tmp_1() {
 }
 
 }
+
+namespace GH47400 {
+
+struct Foo {};
+
+template <int, Foo> struct Arr {};
+
+template <int> struct S {};
+
+constexpr void foo() {
+  constexpr Foo f;
+  [&]<int is>() {
+    [&](Arr<is, f>) {}({}); // f constitutes an ODR-use
+  }.template operator()<42>();
+
+  constexpr int C = 1;
+  [] {
+    [](S<C>) { }({}); // ... while C doesn't
+  }();
+}
+
+} // namespace GH47400


        
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to