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(DC); } -NamedDecl *Sema::getCurFunctionOrMethodDecl() const { - DeclContext *DC = getFunctionLevelDeclContext(); +NamedDecl *Sema::getCurFunctionOrMethodDecl(bool AllowLambda) const { + DeclContext *DC = getFunctionLevelDeclContext(AllowLambda); if (isa(DC) || isa(DC)) return cast(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 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..56af63d7eb35f 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()) SYCL().CheckSYCLEntryPointFunctionDecl(LSI.CallOperator); + // TODO: Find out if passing LSI.CallOperator->getDescribedFunctionTemplate() + // is better 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); @@ -2149,12 +2153,17 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, CleanupInfo LambdaCleanup = LSI->Cleanup; bool ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; bool IsGenericLambda = Class->isGenericLambda(); + sema::AnalysisBasedWarnings::Policy WP = + AnalysisWarnings.getPolicyInEffectAt(EndLoc); CallOperator->setLexicalDeclContext(Class); - Decl *TemplateOrNonTemplateCallOperatorDecl = - CallOperator->getDescribedFunctionTemplate() - ? CallOperator->getDescribedFunctionTemplate() - : cast(CallOperator); + Decl *TemplateOrNonTemplateCallOperatorDecl = CallOperator; + sema::AnalysisBasedWarnings::Policy *ActivePolicy = ℘ + if (IsGenericLambda) { + TemplateOrNonTemplateCallOperatorDecl = + CallOperator->getDescribedFunctionTemplate(); + ActivePolicy = nullptr; + } // FIXME: Is this really the best choice? Keeping the lexical decl context // set as CurContext seems more faithful to the source. @@ -2162,11 +2171,10 @@ 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 _ = + PopFunctionScopeInfo(ActivePolicy, 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..5f77c52c8ddc2 100644 --- a/clang/test/SemaCXX/warn-unused-value.cpp +++ b/clang/test/SemaCXX/warn-unused-value.cpp @@ -178,3 +178,41 @@ auto b() { } } // namespace test6 #endif + +#if __cplusplus >= 201402L +// 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 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}} + }; +} +} +#endif