[libcxx-commits] [libcxx] [libc++] Fix ill-formed return in function_ref's static-call path (PR #228868)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Oct 4 06:31:24 PDT 2026
https://github.com/Kim-J-Smith updated https://github.com/llvm/llvm-project/pull/228868
>From e651fa36d0a56aa56689cd900737353e8222791f Mon Sep 17 00:00:00 2001
From: Kim-J-Smith <3440910457 at qq.com>
Date: Sun, 4 Oct 2026 17:20:21 +0800
Subject: [PATCH 1/2] [libc++] Fix ill-formed return in function_ref's
static-call path
---
.../include/__functional/function_ref_impl.h | 5 ++-
.../func.wrap.ref.inv/invoke.pass.cpp | 37 +++++++++++++++++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/libcxx/include/__functional/function_ref_impl.h b/libcxx/include/__functional/function_ref_impl.h
index ada14643ec496..b54d359853e9b 100644
--- a/libcxx/include/__functional/function_ref_impl.h
+++ b/libcxx/include/__functional/function_ref_impl.h
@@ -106,7 +106,10 @@ class function_ref<_Rp(_ArgTypes...) _LIBCPP_FUNCTION_REF_CV noexcept(__is_noexc
using _Dn = remove_cv_t<_Tp>;
if constexpr (__statically_callable<_Dn, __arg_t<_ArgTypes>...>) {
__call_ = [](__storage_t, __arg_t<_ArgTypes>... __args) static noexcept(__is_noexcept) -> _Rp {
- return _Dn::operator()(std::forward<__arg_t<_ArgTypes>>(__args)...);
+ if constexpr (is_void_v<_Rp>)
+ _Dn::operator()(std::forward<__arg_t<_ArgTypes>>(__args)...);
+ else
+ return _Dn::operator()(std::forward<__arg_t<_ArgTypes>>(__args)...);
};
} else {
__storage_ = __storage_t(std::addressof(__obj)),
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
index 820fed5fc76bc..f2aff57497da5 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
@@ -93,6 +93,11 @@ struct TrackCopyMove {
}
};
+struct StaticallyCallable {
+ static inline int static_call_count = 0;
+ static int operator()() noexcept { static_call_count++; return 42; }
+};
+
void test_default() {
{
std::function_ref<void()> f = [] {};
@@ -195,6 +200,14 @@ void test_default() {
std::function_ref<void(TrackCopyMove)> f = lambda;
f(TrackCopyMove{});
}
+ {
+ // Non-void static operator() can bind to function_ref<void()>
+ StaticallyCallable sc;
+ std::function_ref<void()> f = sc;
+ StaticallyCallable::static_call_count = 0;
+ f();
+ assert(StaticallyCallable::static_call_count == 1);
+ }
}
void test_const() {
@@ -299,6 +312,14 @@ void test_const() {
std::function_ref<void(TrackCopyMove) const> f = lambda;
f(TrackCopyMove{});
}
+ {
+ // Non-void static operator() can bind to function_ref<void()>
+ StaticallyCallable sc;
+ std::function_ref<void() const> f = sc;
+ StaticallyCallable::static_call_count = 0;
+ f();
+ assert(StaticallyCallable::static_call_count == 1);
+ }
}
void test_noexcept() {
@@ -404,6 +425,14 @@ void test_noexcept() {
std::function_ref<void(TrackCopyMove) noexcept> f = lambda;
f(TrackCopyMove{});
}
+ {
+ // Non-void static operator() can bind to function_ref<void()>
+ StaticallyCallable sc;
+ std::function_ref<void() noexcept> f = sc;
+ StaticallyCallable::static_call_count = 0;
+ f();
+ assert(StaticallyCallable::static_call_count == 1);
+ }
}
void test_const_noexcept() {
@@ -509,6 +538,14 @@ void test_const_noexcept() {
std::function_ref<void(TrackCopyMove) const noexcept> f = lambda;
f(TrackCopyMove{});
}
+ {
+ // Non-void static operator() can bind to function_ref<void()>
+ StaticallyCallable sc;
+ std::function_ref<void() const noexcept> f = sc;
+ StaticallyCallable::static_call_count = 0;
+ f();
+ assert(StaticallyCallable::static_call_count == 1);
+ }
}
void test() {
>From e623be792418a6798d914cdc255d27086549a144 Mon Sep 17 00:00:00 2001
From: Kim-J-Smith <3440910457 at qq.com>
Date: Sun, 4 Oct 2026 21:30:54 +0800
Subject: [PATCH 2/2] test: passing an argument to the operator() and mutate
the argument.
---
.../func.wrap.ref.inv/invoke.pass.cpp | 46 ++++++++++---------
1 file changed, 24 insertions(+), 22 deletions(-)
diff --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
index f2aff57497da5..2b87c92eaafac 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.ref/func.wrap.ref.inv/invoke.pass.cpp
@@ -94,8 +94,10 @@ struct TrackCopyMove {
};
struct StaticallyCallable {
- static inline int static_call_count = 0;
- static int operator()() noexcept { static_call_count++; return 42; }
+ static int operator()(int& out) noexcept {
+ out = 42;
+ return 42;
+ }
};
void test_default() {
@@ -201,12 +203,12 @@ void test_default() {
f(TrackCopyMove{});
}
{
- // Non-void static operator() can bind to function_ref<void()>
+ // Non-void static operator() can bind to function_ref<void(int&)>
+ int expect_42 = 0;
StaticallyCallable sc;
- std::function_ref<void()> f = sc;
- StaticallyCallable::static_call_count = 0;
- f();
- assert(StaticallyCallable::static_call_count == 1);
+ std::function_ref<void(int&)> f = sc;
+ f(expect_42);
+ assert(expect_42 == 42);
}
}
@@ -313,12 +315,12 @@ void test_const() {
f(TrackCopyMove{});
}
{
- // Non-void static operator() can bind to function_ref<void()>
+ // Non-void static operator() can bind to function_ref<void(int&) const>
+ int expect_42 = 0;
StaticallyCallable sc;
- std::function_ref<void() const> f = sc;
- StaticallyCallable::static_call_count = 0;
- f();
- assert(StaticallyCallable::static_call_count == 1);
+ std::function_ref<void(int&) const> f = sc;
+ f(expect_42);
+ assert(expect_42 == 42);
}
}
@@ -426,12 +428,12 @@ void test_noexcept() {
f(TrackCopyMove{});
}
{
- // Non-void static operator() can bind to function_ref<void()>
+ // Non-void static operator() can bind to function_ref<void(int&) noexcept>
+ int expect_42 = 0;
StaticallyCallable sc;
- std::function_ref<void() noexcept> f = sc;
- StaticallyCallable::static_call_count = 0;
- f();
- assert(StaticallyCallable::static_call_count == 1);
+ std::function_ref<void(int&) noexcept> f = sc;
+ f(expect_42);
+ assert(expect_42 == 42);
}
}
@@ -539,12 +541,12 @@ void test_const_noexcept() {
f(TrackCopyMove{});
}
{
- // Non-void static operator() can bind to function_ref<void()>
+ // Non-void static operator() can bind to function_ref<void(int&) const noexcept>
+ int expect_42 = 0;
StaticallyCallable sc;
- std::function_ref<void() const noexcept> f = sc;
- StaticallyCallable::static_call_count = 0;
- f();
- assert(StaticallyCallable::static_call_count == 1);
+ std::function_ref<void(int&) const noexcept> f = sc;
+ f(expect_42);
+ assert(expect_42 == 42);
}
}
More information about the libcxx-commits
mailing list