Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
----------------------------------

Expand Down
2 changes: 1 addition & 1 deletion clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
16 changes: 13 additions & 3 deletions clang/lib/Sema/SemaLambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

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

What do you mean? We don't call getDescribedFunctionTemplate here

ActOnFinishFunctionBody(LSI.CallOperator, Body, /*IsInstantiation=*/false,
/*RetainFunctionScopeInfo=*/true);

Expand Down Expand Up @@ -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);
}();
Copy link
Contributor

Choose a reason for hiding this comment

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

can we just

sema::AnalysisBasedWarnings::Policy *Policy = nullptr;
if (...)
  Policy = &...;

afaik Policy is a pretty small object to create on a stack anyway so we should avoid this nesting.


// True if the current capture has a used capture or default before it.
bool CurHasPreviousCapture = CaptureDefault != LCD_None;
Expand Down
36 changes: 36 additions & 0 deletions clang/test/SemaCXX/warn-unused-value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't we have warnings for non-generic lambdas? Is that pre-existing issue?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have warnings controlled by -Wunreachable-code but it isn't enabled by default.

Copy link
Contributor

@zyn0217 zyn0217 Sep 18, 2025

Choose a reason for hiding this comment

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

But with your patch, we do have after-return warnings surfaced for generic-lambdas.

This makes us inconsistent.

Edit: I see we are already inconsistent with non-templates: https://gcc.godbolt.org/z/PsqYTrMEv

Does -Wunreachable-code change anything? The warnings are still not very great to me.

}
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}}
};
}
}
Loading