[clang] [LifetimeSafety] Fix compiler crash with `static operator()` (PR #187853)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 23 08:51:30 PDT 2026
https://github.com/NeKon69 updated https://github.com/llvm/llvm-project/pull/187853
>From 43a4f3b73d719a30a65d2ee3f033953566b6c9e7 Mon Sep 17 00:00:00 2001
From: NeKon69 <nobodqwe at gmail.com>
Date: Sat, 21 Mar 2026 11:57:27 +0300
Subject: [PATCH 1/6] 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 <nobodqwe at gmail.com>
Date: Sat, 21 Mar 2026 13:33:40 +0300
Subject: [PATCH 2/6] 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 <nobodqwe at gmail.com>
Date: Sat, 21 Mar 2026 14:36:27 +0300
Subject: [PATCH 3/6] 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 <nobodqwe at gmail.com>
Date: Mon, 23 Mar 2026 18:27:09 +0300
Subject: [PATCH 4/6] 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 <nobodqwe at gmail.com>
Date: Mon, 23 Mar 2026 18:37:11 +0300
Subject: [PATCH 5/6] 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 <nobodqwe at gmail.com>
Date: Mon, 23 Mar 2026 18:50:26 +0300
Subject: [PATCH 6/6] 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
More information about the cfe-commits
mailing list