Author: NeKon69 Date: 2026-03-23T17:53:34+01:00 New Revision: b32b31e6a7d003a96d8110c3debd891ba6977d25
URL: https://github.com/llvm/llvm-project/commit/b32b31e6a7d003a96d8110c3debd891ba6977d25 DIFF: https://github.com/llvm/llvm-project/commit/b32b31e6a7d003a96d8110c3debd891ba6977d25.diff LOG: [LifetimeSafety] Fix compiler crash with `static operator()` (#187853) This PR removes the first argument from the `Args` list (which is `S()`) before doing lifetime safety checks to ensure correct indexing. It also adds a test to prevent regressions in the future Fixes #187426 <details> <summary>Bug details</summary> When calling a `static operator()` directly (with `S()(...)`), we also store `S()` in `Args` as the first argument, so all indexing is off by one. The most interesting part is that `S::operator()(...)` works correctly and does not add `S()` at the beginning of the argument list, so it does not crash during lifetime checks. This solution is probably not the cleanest, but I would love to hear feedback on where to put it! </details> Added: Modified: clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp clang/test/Sema/warn-lifetime-safety.cpp Removed: ################################################################################ diff --git a/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp b/clang/lib/Analysis/LifetimeSafety/FactsGenerator.cpp index 3259505584c9f..fc1e311b4920c 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" @@ -401,7 +402,13 @@ void FactsGenerator::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *OCE) { handleAssignment(OCE->getArg(0), OCE->getArg(1)); return; } - VisitCallExpr(OCE); + + ArrayRef Args = {OCE->getArgs(), OCE->getNumArgs()}; + // For `static operator()`, the first argument is the object argument, + // 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); } void FactsGenerator::VisitCXXFunctionalCastExpr( diff --git a/clang/test/Sema/warn-lifetime-safety.cpp b/clang/test/Sema/warn-lifetime-safety.cpp index bd09bb70e9a11..7013b8ceebdaa 100644 --- a/clang/test/Sema/warn-lifetime-safety.cpp +++ b/clang/test/Sema/warn-lifetime-safety.cpp @@ -2102,3 +2102,27 @@ void pointer_in_array_use_after_scope() { } } // namespace array + +namespace static_call_operator { +// 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() { + S()(1, 2); + S& x = S()("1", + 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}} + + (void)x; // expected-note 2 {{later used here}} + +} +} // namespace static_call_operator _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
