https://github.com/zwuis created 
https://github.com/llvm/llvm-project/pull/159364

This patch fixes following two issues:

- When handling warnings which should be emitted if reachable, expressions in 
global lambdas aren't treated as if in functions, so warnings are emitted 
immediately without being filtered by reachability analysis.

```cpp
auto L = [] {
  return;

  // previous: warning: left operand of comma operator has no effect
  // expected: no warning, same as in functions
  0, 0;
};
```

- Reachability analysis doesn't emit warnings if it's a dependent context. 
Non-null warning policy is passed to `Sema::PopFunctionScopeInfo` and warnings 
disappear if it's a generic lambda. Global generic lambdas don't suffer from 
this issue because of the issue above.

   Before #154458, `Sema::PopFunctionScopeInfo` for lambda is called by 
`Sema::ActOnFinishFunctionBody`. This patch modifies arguments of 
`Sema::PopFunctionScopeInfo` only because I didn't find behaviour changes of 
modifying arguments of `Sema::ActOnFinishFunctionBody` in regression tests.

```cpp
void f() {
  auto L = [](auto) {
    // previous: no warning
    // expected: warning emitted same as in function templates
    0, 0;
  };
}
```

>From 06b010d27dcfbd3a03453d6aab04f854ed734891 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zw...@outlook.com>
Date: Wed, 17 Sep 2025 21:54:01 +0800
Subject: [PATCH] Make lambda in non-dependent context generate same
 analysis-based warnings as function[ template]

---
 clang/docs/ReleaseNotes.rst              |  3 ++
 clang/include/clang/Sema/Sema.h          |  2 +-
 clang/lib/Sema/Sema.cpp                  |  4 +--
 clang/lib/Sema/SemaExpr.cpp              |  2 +-
 clang/lib/Sema/SemaLambda.cpp            | 16 +++++++++--
 clang/test/SemaCXX/warn-unused-value.cpp | 36 ++++++++++++++++++++++++
 6 files changed, 56 insertions(+), 7 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 518ed9e0f4b3e..0b68512d0c872 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -312,6 +312,9 @@ Improvements to Clang's diagnostics
   properly being rejected when used at compile-time. It was not implemented
   and caused assertion failures before (#GH158471).
 
+- Some reachability-analysis-based warnings in lambda expression which is in
+  non-templated context are emitted same as in function[ template].
+
 Improvements to Clang's time-trace
 ----------------------------------
 
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index d017d1f829015..197b1eedc906d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1166,7 +1166,7 @@ class Sema final : public SemaBase {
   /// getCurFunctionOrMethodDecl - Return the Decl for the current ObjC method
   /// or C function we're in, otherwise return null.  If we're currently
   /// in a 'block', this returns the containing context.
-  NamedDecl *getCurFunctionOrMethodDecl() const;
+  NamedDecl *getCurFunctionOrMethodDecl(bool AllowLambda = false) const;
 
   /// Warn if we're implicitly casting from a _Nullable pointer type to a
   /// _Nonnull one.
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 39fa25f66f3b7..913a11bedc55d 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1656,8 +1656,8 @@ ObjCMethodDecl *Sema::getCurMethodDecl() {
   return dyn_cast<ObjCMethodDecl>(DC);
 }
 
-NamedDecl *Sema::getCurFunctionOrMethodDecl() const {
-  DeclContext *DC = getFunctionLevelDeclContext();
+NamedDecl *Sema::getCurFunctionOrMethodDecl(bool AllowLambda) const {
+  DeclContext *DC = getFunctionLevelDeclContext(AllowLambda);
   if (isa<ObjCMethodDecl>(DC) || isa<FunctionDecl>(DC))
     return cast<NamedDecl>(DC);
   return nullptr;
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 73b16ae09e922..b6fdcfb646cb0 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20542,7 +20542,7 @@ void Sema::MarkDeclarationsReferencedInExpr(Expr *E,
 ///        namespace { auto *p = new double[3][false ? (1, 2) : 3]; }
 bool Sema::DiagIfReachable(SourceLocation Loc, ArrayRef<const Stmt *> Stmts,
                            const PartialDiagnostic &PD) {
-  if (!Stmts.empty() && getCurFunctionOrMethodDecl()) {
+  if (!Stmts.empty() && getCurFunctionOrMethodDecl(/*AllowLambda=*/true)) {
     if (!FunctionScopes.empty())
       FunctionScopes.back()->PossiblyUnreachableDiags.push_back(
           sema::PossiblyUnreachableDiag(PD, Loc, Stmts));
diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index fbc2e7eb30676..2a6d0b5b4a9de 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1972,6 +1972,10 @@ ExprResult Sema::ActOnLambdaExpr(SourceLocation 
StartLoc, Stmt *Body) {
   if (LSI.CallOperator->hasAttr<SYCLKernelEntryPointAttr>())
     SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator);
 
+  // TODO: Find out if passing LSI.CallOperator->getDescribedFunctionTemplate()
+  //       is necessary when it is a generic lambda. Are there any behaviour
+  //       changes? `FunctionTemplateDecl` is always passed when handling 
simple
+  //       function templates.
   ActOnFinishFunctionBody(LSI.CallOperator, Body, /*IsInstantiation=*/false,
                           /*RetainFunctionScopeInfo=*/true);
 
@@ -2162,11 +2166,17 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation 
StartLoc,
 
   PopExpressionEvaluationContext();
 
-  sema::AnalysisBasedWarnings::Policy WP =
-      AnalysisWarnings.getPolicyInEffectAt(EndLoc);
   // We cannot release LSI until we finish computing captures, which
   // requires the scope to be popped.
-  Sema::PoppedFunctionScopePtr _ = PopFunctionScopeInfo(&WP, 
LSI->CallOperator);
+  Sema::PoppedFunctionScopePtr _ = [&] {
+    if (LSI->CallOperator->getDescribedFunctionTemplate())
+      return PopFunctionScopeInfo(/*WP=*/nullptr,
+                                  TemplateOrNonTemplateCallOperatorDecl);
+
+    sema::AnalysisBasedWarnings::Policy WP =
+        AnalysisWarnings.getPolicyInEffectAt(EndLoc);
+    return PopFunctionScopeInfo(&WP, TemplateOrNonTemplateCallOperatorDecl);
+  }();
 
   // True if the current capture has a used capture or default before it.
   bool CurHasPreviousCapture = CaptureDefault != LCD_None;
diff --git a/clang/test/SemaCXX/warn-unused-value.cpp 
b/clang/test/SemaCXX/warn-unused-value.cpp
index 2a07a0324f3f0..7a2cbab275e0c 100644
--- a/clang/test/SemaCXX/warn-unused-value.cpp
+++ b/clang/test/SemaCXX/warn-unused-value.cpp
@@ -178,3 +178,39 @@ auto b() {
 }
 } // namespace test6
 #endif
+
+// ensure lambda in non-dependent context generate same diagnostics as 
function[ template]
+namespace lambda_in_non_dependent_context {
+void f1() {
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+  return;
+  0, 0;
+}
+template <typename T> void f2(T) {
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+  return;
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+}
+auto L1 = [] {
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+  return;
+  0, 0;
+};
+auto L2 = [](auto) {
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+  return;
+  0, 0; // expected-warning {{left operand of comma operator has no effect}}
+};
+void f() {
+  auto L1 = [] {
+    0, 0; // expected-warning {{left operand of comma operator has no effect}}
+    return;
+    0, 0;
+  };
+  auto L2 = [](auto) {
+    0, 0; // expected-warning {{left operand of comma operator has no effect}}
+    return;
+    0, 0; // expected-warning {{left operand of comma operator has no effect}}
+  };
+}
+}

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

Reply via email to