[libcxx-commits] [libcxx] [libc++] Implement `std::function_ref` (PR #186692)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Jul 3 10:27:53 PDT 2026
================
@@ -0,0 +1,138 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// In case the function signature is taking an argument by value,
+// when the type is small and trivial, we pass it internally by value,
+// otherwise, we pass it by rvalue reference
+
+#include <cassert>
+#include <functional>
+#include <utility>
+#include <type_traits>
+
+struct Small {};
+
+struct Big {
+ char c[128];
+};
+
+struct SmallButNonTrivial {
+ Small s;
+ SmallButNonTrivial() = default;
+ SmallButNonTrivial(const SmallButNonTrivial&) {}
+};
+
+// Need to inspect the internal state of function_ref, and our implementation friend-ed all the function_ref
+// specializations, so we can just specialize an undefined function_ref here to inspect the defined ones
+template <>
+class std::function_ref<int> {
+ using storage = std::__function_ref_storage;
+ void test() {
+ {
+ // by value small argument
+ // the internal function should pass by value
+ using call = std::function_ref<void(Small)>::__call_t;
+ static_assert(std::is_same_v<call, void (*)(storage, Small)>);
+ }
+ {
+ // by value big argument
+ // the internal function should pass by rvalue reference
+ using call = std::function_ref<void(Big)>::__call_t;
+ static_assert(std::is_same_v<call, void (*)(storage, Big&&)>);
+ }
+ {
+ // by value non-trivial small argument
+ // the internal function should pass by rvalue reference to avoid unnecessary copy/move
+ using call = std::function_ref<void(SmallButNonTrivial)>::__call_t;
+ static_assert(std::is_same_v<call, void (*)(storage, SmallButNonTrivial&&)>);
+ }
+ {
+ // by lvalue reference argument
+ // the internal function should pass by lvalue reference
+ using call = std::function_ref<void(Small&)>::__call_t;
+ static_assert(std::is_same_v<call, void (*)(storage, Small&)>);
+ }
+ {
+ // by rvalue reference argument
+ // the internal function should pass by rvalue reference
+ using call = std::function_ref<void(Small&&)>::__call_t;
+ static_assert(std::is_same_v<call, void (*)(storage, Small&&)>);
+ }
+ }
+};
+
+struct TrackCopyMove {
+ mutable int copy_count = 0;
+ int move_count = 0;
+
+ TrackCopyMove() = default;
+ TrackCopyMove(const TrackCopyMove& other) : copy_count(other.copy_count), move_count(other.move_count) {
+ ++copy_count;
+ ++other.copy_count;
+ }
+
+ TrackCopyMove(TrackCopyMove&& other) noexcept : copy_count(other.copy_count), move_count(other.move_count) {
+ ++move_count;
+ ++other.move_count;
+ }
+ TrackCopyMove& operator=(const TrackCopyMove& other) {
+ ++copy_count;
+ ++other.copy_count;
+ return *this;
+ }
+ TrackCopyMove& operator=(TrackCopyMove&& other) noexcept {
+ ++move_count;
+ ++other.move_count;
+ return *this;
+ }
+};
+
+void test() {
----------------
ldionne wrote:
So, after discussing this further, it turns out that `FileCheck` tests that check codegen are a lot more tricky than we expected. Indeed, unlike most Clang tests where TUs are self-contained, libc++ tests require stuff from the platform. That means you either:
1. Fix the target triple, but then you end up cross-compiling most of the time (e.g. you run a Filecheck test baked for linux on a macOS host), or
2. You don't fix the target triple in the FileCheck test, but then testing for the actual codegen is really difficult because codegen depends heavily on the target
So, for the time being, I think it's reasonable just not to test that property. It would have been nice to have a test on it, but it's acceptable not to.
CC @philnik777 since the insight about FileCheck difficulties is IMO interesting -- I assumed it would be easier.
https://github.com/llvm/llvm-project/pull/186692
More information about the libcxx-commits
mailing list