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