Skip to content

Conversation

@katzdm
Copy link
Contributor

@katzdm katzdm commented Jul 16, 2025

Fixes #118187
Fixes #156579

An instantiated LambdaExpr can currently be marked as LDK_NeverDependent if it's nested within a generic lambda. If that LambdaExpr in fact depends on template parameters introduced by the enclosing generic lambda, then its dependence will be misreported as "never dependent" and spurious diagnostics can result.

The fix here proposed is a bit ugly, but the condition that it's being bolted onto already seems like a bit of a hack, so this seems no worse for wear.

Note that #89702 surfaced this change because it caused the inner lambda expression to (correctly) be considered in a constant-evaluated context. The affected check for whether to mark the inner lambda as LDK_NeverDependent therefore started to apply, whereas it didn't before.

Tested: check-clang and check-cxx.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 16, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 16, 2025

@llvm/pr-subscribers-clang

Author: Daniel M. Katz (katzdm)

Changes

Fixes #118187.

An instantiated LambdaExpr can currently be marked as LDK_NeverDependent if it's nested within a generic lambda. If that LambdaExpr in fact depends on template parameters introduced by the enclosing generic lambda, then its dependence will be misreported as "never dependent" and spurious diagnostics can result.

The fix here proposed is a bit ugly, but the condition that it's being bolted onto already seems like a bit of a hack, so this seems no worse for wear.

Note that #89702 surfaced this change because it caused the inner lambda expression to (correctly) be considered in a constant-evaluated context. The affected check for whether to mark the inner lambda as LDK_NeverDependent therefore started to apply, whereas it didn't before.

Tested: check-clang and check-cxx.


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

3 Files Affected:

  • (modified) clang/docs/ReleaseNotes.rst (+1)
  • (modified) clang/lib/Sema/TreeTransform.h (+2)
  • (modified) clang/test/SemaCXX/cxx2a-consteval.cpp (+10-1)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 970825c98fec1..4c902d2ab6d83 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -963,6 +963,7 @@ Bug Fixes to C++ Support
 - Fix a crash with NTTP when instantiating local class.
 - Fixed a crash involving list-initialization of an empty class with a
   non-empty initializer list. (#GH147949)
+- Fixed spurious diagnoses of certain nested lambda expressions. (#GH149121)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 758012f894a41..5f2b93680cc3d 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -15512,6 +15512,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
     DC = DC->getParent();
   if ((getSema().isUnevaluatedContext() ||
        getSema().isConstantEvaluatedContext()) &&
+      !(dyn_cast_or_null<CXXRecordDecl>(DC->getParent()) &&
+        cast<CXXRecordDecl>(DC->getParent())->isGenericLambda()) &&
       (DC->isFileContext() || !DC->getParent()->isDependentContext()))
     DependencyKind = CXXRecordDecl::LDK_NeverDependent;
 
diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp
index 1474c48cda3c1..d92529b465c6f 100644
--- a/clang/test/SemaCXX/cxx2a-consteval.cpp
+++ b/clang/test/SemaCXX/cxx2a-consteval.cpp
@@ -1319,6 +1319,15 @@ namespace GH139160{
   B result = (B){10, get_value(make_struct())}; // expected-error {{initializer element is not a compile-time constant}} 
                                                 // expected-error@-1 {{call to consteval function 'GH139160::get_value' is not a constant expression}}
                                                 // expected-note@-2  {{non-constexpr function 'make_struct' cannot be used in a constant expression}}
-};
+}  // namespace GH139160
+
+namespace GH118187 {
 
+template <typename T> int t() {
+  return []<typename U> consteval {
+    return [](U v) { return v; }(123);
+  }.template operator()<int>();
+}
 
+int v = t<int>();
+}  // namespace GH118187

DC = DC->getParent();
if ((getSema().isUnevaluatedContext() ||
getSema().isConstantEvaluatedContext()) &&
!(dyn_cast_or_null<CXXRecordDecl>(DC->getParent()) &&
Copy link
Collaborator

Choose a reason for hiding this comment

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

We'd want to use isa_and_present (or isa_and_nonnull or w/e it is called) in this case.

That said, we probably would prefer to do something like extracting above the if a const auto *RD = dyn_cast_if_present<CXXRecordDecl>(DC->getParent()); then changing the check to RD && RD->isGenericLambda()` (or perhaps BETTER, pulling that whole thing out to a separate boolean with a reasonable name, so you have a place to put a comment).

Which brings me to the last thing, I'd like a comment explaining WHY this check should be here, it looks enough out of place as to why this cannot be dependent.

@zyn0217 zyn0217 requested a review from cor3ntin July 16, 2025 16:20
Copy link
Contributor

@mizvekov mizvekov left a comment

Choose a reason for hiding this comment

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

FYI this fix and surrounding code should become obsolete when I get around to finishing #107942

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

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

@katzdm

I apologize for the long delay. After a second thought, I think the patch should work as expected.

Can you please rebase the patch and also add a test case for #156579? The added constant evaluation context reveals another bug, where we considered lambdas non-dependent too eagerly, causing template argument deduction to occur on mismatched template depths.

cc @cor3ntin we should backport this too

@katzdm
Copy link
Contributor Author

katzdm commented Sep 5, 2025

@katzdm

I apologize for the long delay. After a second thought, I think the patch should work as expected.

Can you please rebase the patch and also add a test case for #156579? The added constant evaluation context reveals another bug, where we considered lambdas non-dependent too eagerly, causing template argument deduction to occur on mismatched template depths.

cc @cor3ntin we should backport this too

Thanks for taking a look! I'll try to circle back to this in the next week or so.

@cor3ntin
Copy link
Contributor

@katzdm ping

@github-actions
Copy link

github-actions bot commented Nov 22, 2025

🐧 Linux x64 Test Results

  • 111353 tests passed
  • 4443 tests skipped

@katzdm
Copy link
Contributor Author

katzdm commented Nov 22, 2025

@cor3ntin @zyn0217 Rebased and added the #156579 test.

Copy link
Contributor

@zyn0217 zyn0217 left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@katzdm
Copy link
Contributor Author

katzdm commented Nov 22, 2025

LGTM, thanks!

Thanks! FYI for any other reviewers, I don't have merge access - would appreciate somebody helping out, if it looks good :-)

@zyn0217 zyn0217 merged commit 525e68e into llvm:main Nov 23, 2025
11 checks passed
@katzdm katzdm deleted the gh-118187 branch November 23, 2025 03:13
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 23, 2025

LLVM Buildbot has detected a new failure on builder openmp-s390x-linux running on systemz-1 while building clang at step 6 "test-openmp".

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

Here is the relevant piece of the build log for the reference
Step 6 (test-openmp) failure: test (failure)
******************** TEST 'libomp :: tasking/issue-94260-2.c' FAILED ********************
Exit Code: -11

Command Output (stdout):
--
# RUN: at line 1
/home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp   -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src  -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic && /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/./bin/clang -fopenmp -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test -L /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/src -fno-omit-frame-pointer -mbackchain -I /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/ompt /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.src/openmp/runtime/test/tasking/issue-94260-2.c -o /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp -lm -latomic
# executed command: /home/uweigand/sandbox/buildbot/openmp-s390x-linux/llvm.build/runtimes/runtimes-bins/openmp/runtime/test/tasking/Output/issue-94260-2.c.tmp
# note: command had no output on stdout or stderr
# error: command failed with exit status: -11

--

********************


aadeshps-mcw pushed a commit to aadeshps-mcw/llvm-project that referenced this pull request Nov 26, 2025
…149121)

Fixes llvm#118187
Fixes llvm#156579

An instantiated `LambdaExpr` can currently be marked as
`LDK_NeverDependent` if it's nested within a generic lambda. If that
`LambdaExpr` in fact depends on template parameters introduced by the
enclosing generic lambda, then its dependence will be misreported as
"never dependent" and spurious diagnostics can result.

The fix here proposed is a bit ugly, but the condition that it's being
bolted onto already seems like a bit of a hack, so this seems no worse
for wear.

Note that llvm#89702 surfaced this change because it caused the inner lambda
expression to (correctly) be considered in a constant-evaluated context.
The affected check for whether to mark the inner lambda as
`LDK_NeverDependent` therefore started to apply, whereas it didn't
before.

**Tested**: `check-clang` and `check-cxx`.
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Nov 26, 2025
…149121)

Fixes llvm#118187
Fixes llvm#156579

An instantiated `LambdaExpr` can currently be marked as
`LDK_NeverDependent` if it's nested within a generic lambda. If that
`LambdaExpr` in fact depends on template parameters introduced by the
enclosing generic lambda, then its dependence will be misreported as
"never dependent" and spurious diagnostics can result.

The fix here proposed is a bit ugly, but the condition that it's being
bolted onto already seems like a bit of a hack, so this seems no worse
for wear.

Note that llvm#89702 surfaced this change because it caused the inner lambda
expression to (correctly) be considered in a constant-evaluated context.
The affected check for whether to mark the inner lambda as
`LDK_NeverDependent` therefore started to apply, whereas it didn't
before.

**Tested**: `check-clang` and `check-cxx`.
augusto2112 pushed a commit to augusto2112/llvm-project that referenced this pull request Dec 3, 2025
…149121)

Fixes llvm#118187
Fixes llvm#156579

An instantiated `LambdaExpr` can currently be marked as
`LDK_NeverDependent` if it's nested within a generic lambda. If that
`LambdaExpr` in fact depends on template parameters introduced by the
enclosing generic lambda, then its dependence will be misreported as
"never dependent" and spurious diagnostics can result.

The fix here proposed is a bit ugly, but the condition that it's being
bolted onto already seems like a bit of a hack, so this seems no worse
for wear.

Note that llvm#89702 surfaced this change because it caused the inner lambda
expression to (correctly) be considered in a constant-evaluated context.
The affected check for whether to mark the inner lambda as
`LDK_NeverDependent` therefore started to apply, whereas it didn't
before.

**Tested**: `check-clang` and `check-cxx`.
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

Development

Successfully merging this pull request may close these issues.

[Clang][Regression:21] Rejects valid lambda invocation in constexpr if Cannot call lambda defined in immediate lambda

7 participants