https://github.com/NeKon69 updated https://github.com/llvm/llvm-project/pull/187853
>From 43a4f3b73d719a30a65d2ee3f033953566b6c9e7 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sat, 21 Mar 2026 11:57:27 +0300 Subject: [PATCH 1/7] apply basic fix --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 3259505584c9f..954f051914989 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -20,6 +20,7 @@ #include "clang/Analysis/Analyses/LifetimeSafety/Origins.h" #include "clang/Analysis/Analyses/PostOrderCFGView.h" #include "clang/Analysis/CFG.h" +#include "clang/Basic/OperatorKinds.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" @@ -655,6 +656,13 @@ void FactsGenerator::handleFunctionCall(const Expr *Call, // All arguments to a function are a use of the corresponding expressions. for (const Expr *Arg : Args) handleUse(Arg); + + if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call); + OCE && OCE->getOperator() == OO_Call && FD->isStatic()) { + // Ignore first element + Args = Args.slice(1); + } + handleInvalidatingCall(Call, FD, Args); handleMovedArgsInCall(FD, Args); if (!CallList) >From 8a828b75150c4f05ab0e33df93495e78298d7b2b Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sat, 21 Mar 2026 13:33:40 +0300 Subject: [PATCH 2/7] add test --- clang/test/Sema/warn-lifetime-safety.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index bd09bb70e9a11..974a0b4a32b2a 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2101,4 +2101,13 @@ void pointer_in_array_use_after_scope() { (void)*arr[0]; // Should warn. } +struct S { + static S operator()(int, int&&); +}; + +void indexing_with_static_operator() { + // no warnings expected + S()(1, 2); +} + } // namespace array >From c9ee4ef628214ef55c01bd7ee010931b54591ddf Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Sat, 21 Mar 2026 14:36:27 +0300 Subject: [PATCH 3/7] move test to a new file --- .../warn-lifetime-safety-static-call-operator.cpp | 11 +++++++++++ clang/test/Sema/warn-lifetime-safety.cpp | 9 --------- 2 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp diff --git a/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp b/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp new file mode 100644 index 0000000000000..68016aa7bf564 --- /dev/null +++ b/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wlifetime-safety -Wno-dangling -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify %s + +// expected-no-diagnostics +struct S { + static S operator()(int, int&&); +}; + +void indexing_with_static_operator() { + S()(1, 2); +} diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 974a0b4a32b2a..bd09bb70e9a11 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2101,13 +2101,4 @@ void pointer_in_array_use_after_scope() { (void)*arr[0]; // Should warn. } -struct S { - static S operator()(int, int&&); -}; - -void indexing_with_static_operator() { - // no warnings expected - S()(1, 2); -} - } // namespace array >From 9c779d6862301e05fc8807050496d257cb497f86 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 23 Mar 2026 18:27:09 +0300 Subject: [PATCH 4/7] update tests --- ...n-lifetime-safety-static-call-operator.cpp | 11 ------- clang/test/Sema/warn-lifetime-safety.cpp | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 11 deletions(-) delete mode 100644 clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp diff --git a/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp b/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp deleted file mode 100644 index 68016aa7bf564..0000000000000 --- a/clang/test/Sema/warn-lifetime-safety-static-call-operator.cpp +++ /dev/null @@ -1,11 +0,0 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++23 -Wlifetime-safety -Wno-dangling -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++23 -flifetime-safety-inference -fexperimental-lifetime-safety-tu-analysis -Wlifetime-safety -Wno-dangling -verify %s - -// expected-no-diagnostics -struct S { - static S operator()(int, int&&); -}; - -void indexing_with_static_operator() { - S()(1, 2); -} diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index bd09bb70e9a11..30eec91e0ce84 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2102,3 +2102,35 @@ void pointer_in_array_use_after_scope() { } } // namespace array + +namespace GH187426 { +// https://github.com/llvm/llvm-project/issues/187426 + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++23-extensions" + +struct S { + static S operator()(int, int&&); + static S& operator()(std::string&&, + const int& a [[clang::lifetimebound]], + const int& b [[clang::lifetimebound]]); +}; + +void indexing_with_static_operator() { + // should not crash + S()(1, 2); + S& x = S()("1", + 2, // #argone + 3); // #argtwo + // expected-warning@#argone {{object whose reference is captured does not live long enough}} + // expected-note@#argone {{destroyed here}} + + // expected-warning@#argtwo {{object whose reference is captured does not live long enough}} + // expected-note@#argtwo {{destroyed here}} + + (void)x; // #useline + // expected-note@#useline {{later used here}} + // expected-note@#useline {{later used here}} + +} +} // namespace GH187426 >From 022bd893d6399c3d83f24acc70bb1db3e38c1312 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 23 Mar 2026 18:37:11 +0300 Subject: [PATCH 5/7] move argument handling logic to `VisitCallExpr` --- .../lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 954f051914989..de330219298c7 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -402,7 +402,12 @@ void FactsGenerator::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) { handleAssignment(OCE->getArg(0), OCE->getArg(1)); return; } - VisitCallExpr(OCE); + + ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()}; + if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic()) { + Args = Args.slice(1); + } + handleFunctionCall(OCE, OCE->getDirectCallee(), Args); } void FactsGenerator::VisitCXXFunctionalCastExpr( @@ -657,12 +662,6 @@ void FactsGenerator::handleFunctionCall(const Expr *Call, for (const Expr *Arg : Args) handleUse(Arg); - if (const auto *OCE = dyn_cast<CXXOperatorCallExpr>(Call); - OCE && OCE->getOperator() == OO_Call && FD->isStatic()) { - // Ignore first element - Args = Args.slice(1); - } - handleInvalidatingCall(Call, FD, Args); handleMovedArgsInCall(FD, Args); if (!CallList) >From 925c10e50a6712a6e026db0dfdd841b111661fe5 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 23 Mar 2026 18:50:26 +0300 Subject: [PATCH 6/7] apply suggestions --- .../LifetimeSafety/FactsGenerator.cpp | 4 +--- clang/test/Sema/warn-lifetime-safety.cpp | 22 ++++++------------- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index de330219298c7..3b0ebc479e2d0 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -404,9 +404,8 @@ void FactsGenerator::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) { } ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()}; - if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic()) { + if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic()) Args = Args.slice(1); - } handleFunctionCall(OCE, OCE->getDirectCallee(), Args); } @@ -661,7 +660,6 @@ void FactsGenerator::handleFunctionCall(const Expr *Call, // All arguments to a function are a use of the corresponding expressions. for (const Expr *Arg : Args) handleUse(Arg); - handleInvalidatingCall(Call, FD, Args); handleMovedArgsInCall(FD, Args); if (!CallList) diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index 30eec91e0ce84..7013b8ceebdaa 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2103,7 +2103,7 @@ void pointer_in_array_use_after_scope() { } // namespace array -namespace GH187426 { +namespace static_call_operator { // https://github.com/llvm/llvm-project/issues/187426 #pragma clang diagnostic push @@ -2112,25 +2112,17 @@ namespace GH187426 { struct S { static S operator()(int, int&&); static S& operator()(std::string&&, - const int& a [[clang::lifetimebound]], - const int& b [[clang::lifetimebound]]); + const int& a [[clang::lifetimebound]], + const int& b [[clang::lifetimebound]]); }; void indexing_with_static_operator() { - // should not crash S()(1, 2); S& x = S()("1", - 2, // #argone - 3); // #argtwo - // expected-warning@#argone {{object whose reference is captured does not live long enough}} - // expected-note@#argone {{destroyed here}} + 2, // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}} + 3); // expected-warning {{object whose reference is captured does not live long enough}} expected-note {{destroyed here}} - // expected-warning@#argtwo {{object whose reference is captured does not live long enough}} - // expected-note@#argtwo {{destroyed here}} - - (void)x; // #useline - // expected-note@#useline {{later used here}} - // expected-note@#useline {{later used here}} + (void)x; // expected-note 2 {{later used here}} } -} // namespace GH187426 +} // namespace static_call_operator >From 393c834ac92bc5b3f36013ab55a555181fa8d8d1 Mon Sep 17 00:00:00 2001 From: NeKon69 <[email protected]> Date: Mon, 23 Mar 2026 18:56:07 +0300 Subject: [PATCH 7/7] add a comment explaining why the check is needed --- clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 3b0ebc479e2d0..c419a6ffd2560 100644 --- a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp +++ b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp @@ -404,6 +404,8 @@ void FactsGenerator::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) { } ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()}; + // For `static operator()`, the first argument is the call expression itself, + // remove it from the argument list to avoid off-by-one errors. if (OCE->getOperator() == OO_Call && OCE->getDirectCallee()->isStatic()) Args = Args.slice(1); handleFunctionCall(OCE, OCE->getDirectCallee(), Args); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
