Skip to content

[Clang] Recover GLTemplateParameterList for generic lambdas in RebuildLambdaScopeInfo #118176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 3, 2024

Conversation

zyn0217
Copy link
Contributor

@zyn0217 zyn0217 commented Nov 30, 2024

The NTTP argument appearing inside a trailing return type of a generic lambda would have to check for potential lambda captures, where the function needs GLTemplateParameterList of the current LSI to tell whether the lambda is generic.

The lambda scope in this context is rebuilt by the LambdaScopeForCallOperatorInstantiationRAII when substituting the lambda operator during template argument deduction. Thus, I think the template parameter list should be preserved in the rebuilding process, as it seems otherwise innocuous to me.

Fixes #115931

@zyn0217 zyn0217 marked this pull request as ready for review December 2, 2024 01:29
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Dec 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2024

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

Changes

The NTTP argument appearing inside a trailing return type of a generic lambda would have to check for potential lambda captures, where the function needs GLTemplateParameterList of the current LSI to tell whether the lambda is generic.

The lambda scope in this context is rebuilt by the LambdaScopeForCallOperatorInstantiationRAII when substituting the lambda operator during template argument deduction. Thus, I think the template parameter list should be preserved in the rebuilding process, as it seems otherwise innocuous to me.

Fixes #115931


Full diff: https://github.com/llvm/llvm-project/pull/118176.diff

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+2)
  • (modified) clang/lib/Sema/SemaDecl.cpp (+18-3)
  • (modified) clang/test/SemaCXX/lambda-capture-type-deduction.cpp (+16)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 8bd06fadfdc984..e8e8a8cff76e45 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -714,6 +714,8 @@ Bug Fixes to C++ Support
   assumption if they also occur inside of a dependent lambda. (#GH114787)
 - Clang now uses valid deduced type locations when diagnosing functions with trailing return type
   missing placeholder return type. (#GH78694)
+- Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda
+  captures at the end of a full expression. (#GH115931)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 74b0e5ad23bd48..75389d6ba7bfd8 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -15504,10 +15504,25 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
   LSI->CallOperator = CallOperator;
   LSI->Lambda = LambdaClass;
   LSI->ReturnType = CallOperator->getReturnType();
-  // This function in calls in situation where the context of the call operator
-  // is not entered, so we set AfterParameterList to false, so that
+  // When this function is called in situation where the context of the call
+  // operator is not entered, we set AfterParameterList to false, so that
   // `tryCaptureVariable` finds explicit captures in the appropriate context.
-  LSI->AfterParameterList = false;
+  //
+  // There is also at least a situation as in FinishTemplateArgumentDeduction(),
+  // where we would set the CurContext to the lambda operator before
+  // substituting into it. In this case the flag needs to be true such that
+  // tryCaptureVariable can correctly handle potential captures thereof.
+  LSI->AfterParameterList = CurContext == CallOperator;
+  // GLTemplateParameterList is necessary for getCurGenericLambda() which is
+  // used at the point of dealing with potential captures.
+  //
+  // We don't use LambdaClass->isGenericLambda() because this value doesn't
+  // flip for instantiated generic lambdas, where no FunctionTemplateDecls are
+  // associated. (Technically, we could recover that list from their
+  // instantiation patterns, but for now, the GLTemplateParameterList seems
+  // unnecessary in these cases.)
+  if (FunctionTemplateDecl *FTD = CallOperator->getDescribedFunctionTemplate())
+    LSI->GLTemplateParameterList = FTD->getTemplateParameters();
   const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();
 
   if (LCD == LCD_None)
diff --git a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
index a86f3018989927..234cb6806f041a 100644
--- a/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
+++ b/clang/test/SemaCXX/lambda-capture-type-deduction.cpp
@@ -298,6 +298,22 @@ void __trans_tmp_1() {
 
 }
 
+namespace GH115931 {
+
+struct Range {};
+
+template <Range>
+struct LengthPercentage {};
+
+void reflectSum() {
+  Range resultR;
+  [&] (auto) -> LengthPercentage<resultR> { 
+    return {};
+  }(0);
+}
+
+} // namespace GH115931
+
 namespace GH47400 {
 
 struct Foo {};

Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Collaborator

@erichkeane erichkeane left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few nits on the comment, else feel free to commit once those are fixed.

@zyn0217
Copy link
Contributor Author

zyn0217 commented Dec 3, 2024

thanks for the review :)

@zyn0217 zyn0217 merged commit 9ea993f into llvm:main Dec 3, 2024
9 checks passed
@zyn0217 zyn0217 deleted the GH115931 branch December 3, 2024 02:10
@llvm-ci
Copy link
Collaborator

llvm-ci commented Dec 3, 2024

LLVM Buildbot has detected a new failure on builder lldb-aarch64-ubuntu running on linaro-lldb-aarch64-ubuntu while building clang at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/9095

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentSignalWatch.py (623 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentSignalNWatchNBreak.py (624 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentSignalWatchBreak.py (625 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointThreads.py (626 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentSignalDelayWatch.py (627 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneSignal.py (628 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoWatchpointThreads.py (629 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoWatchpointsOneBreakpoint.py (630 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneWatchpoint.py (631 of 2055)
PASS: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoBreakpointsOneDelaySignal.py (632 of 2055)
FAIL: lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoWatchpointsOneSignal.py (633 of 2055)
******************** TEST 'lldb-api :: functionalities/thread/concurrent_events/TestConcurrentTwoWatchpointsOneSignal.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/make --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/thread/concurrent_events -p TestConcurrentTwoWatchpointsOneSignal.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 20.0.0git (https://github.com/llvm/llvm-project.git revision 9ea993f975b045679907a0789d6fd4d7180593a0)
  clang revision 9ea993f975b045679907a0789d6fd4d7180593a0
  llvm revision 9ea993f975b045679907a0789d6fd4d7180593a0
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

Watchpoint 1 hit:
old value: 0
new value: 1

Watchpoint 1 hit:
old value: 1
new value: 1

--
Command Output (stderr):
--
FAIL: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test (TestConcurrentTwoWatchpointsOneSignal.ConcurrentTwoWatchpointsOneSignal)
======================================================================
FAIL: test (TestConcurrentTwoWatchpointsOneSignal.ConcurrentTwoWatchpointsOneSignal)
   Test two threads that trigger a watchpoint and one signal thread.
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/decorators.py", line 148, in wrapper
    return func(*args, **kwargs)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/functionalities/thread/concurrent_events/TestConcurrentTwoWatchpointsOneSignal.py", line 15, in test
    self.do_thread_actions(num_watchpoint_threads=2, num_signal_threads=1)
  File "/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/packages/Python/lldbsuite/test/concurrent_base.py", line 333, in do_thread_actions
    self.assertEqual(
AssertionError: 1 != 2 : Expected 1 stops due to signal delivery, but got 2

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
5 participants