[llvm] [orc-rt] Rename unique_function to move_only_function. (PR #154888)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 21 22:15:41 PDT 2025


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/154888

This will allow the ORC runtime and its clients to easily adopt the c++-23 std::move_only_function type.

>From 3f09d8db5bf278cfeadb3ff0d4fd083eef296a00 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 22 Aug 2025 14:34:45 +1000
Subject: [PATCH] [orc-rt] Rename unique_function to move_only_function to
 align with c++-23 API.

This will allow the ORC runtime and its clients to easily adopt the c++-23
std::move_only_function type.
---
 orc-rt/include/CMakeLists.txt                 |  2 +-
 orc-rt/include/orc-rt/move_only_function.h    | 84 +++++++++++++++++++
 orc-rt/include/orc-rt/unique-function.h       | 80 ------------------
 orc-rt/unittests/CMakeLists.txt               |  2 +-
 ...n-test.cpp => move_only_function-test.cpp} | 60 ++++++-------
 5 files changed, 117 insertions(+), 111 deletions(-)
 create mode 100644 orc-rt/include/orc-rt/move_only_function.h
 delete mode 100644 orc-rt/include/orc-rt/unique-function.h
 rename orc-rt/unittests/{unique-function-test.cpp => move_only_function-test.cpp} (65%)

diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index 33545547e17d7..ed90a7a45e2fa 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -5,8 +5,8 @@ set(ORC_RT_HEADERS
     orc-rt/Error.h
     orc-rt/Math.h
     orc-rt/RTTI.h
+    orc-rt/move_only_function.h
     orc-rt/span.h
-    orc-rt/unique-function.h
 )
 
 # TODO: Switch to filesets when we move to cmake-3.23.
diff --git a/orc-rt/include/orc-rt/move_only_function.h b/orc-rt/include/orc-rt/move_only_function.h
new file mode 100644
index 0000000000000..d37801b4a97af
--- /dev/null
+++ b/orc-rt/include/orc-rt/move_only_function.h
@@ -0,0 +1,84 @@
+//===-- move_only_function.h - moveable, type-erasing function --*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// A substitute for std::move_only_function that can be used until the ORC
+/// runtime is allowed to assume c++-23.
+///
+/// TODO: Replace all uses with std::move_only_function once we can assume
+///       c++-23.
+///
+/// TODO: Re-implement using techniques from LLVM's unique_function
+///       (llvm/include/llvm/ADT/FunctionExtras.h), which uses some extra
+///       inline storage to avoid heap allocations for small objects. This
+///       would require first porting some other LLVM utilities like
+///       PointerIntPair, PointerUnion, and PointerLikeTypeTraits. (These are
+///       likely to be independently useful in the orc runtime, so porting will
+///       have additional benefits).
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_MOVE_ONLY_FUNCTION_H
+#define ORC_RT_MOVE_ONLY_FUNCTION_H
+
+#include <memory>
+
+namespace orc_rt {
+
+namespace move_only_function_detail {
+
+template <typename RetT, typename... ArgTs> class Callable {
+public:
+  virtual ~Callable() = default;
+  virtual RetT call(ArgTs &&...Args) = 0;
+};
+
+template <typename CallableT, typename RetT, typename... ArgTs>
+class CallableImpl : public Callable<RetT, ArgTs...> {
+public:
+  CallableImpl(CallableT &&Callable) : Callable(std::move(Callable)) {}
+  RetT call(ArgTs &&...Args) override {
+    return Callable(std::forward<ArgTs>(Args)...);
+  }
+
+private:
+  CallableT Callable;
+};
+
+} // namespace move_only_function_detail
+
+template <typename FnT> class move_only_function;
+
+template <typename RetT, typename... ArgTs>
+class move_only_function<RetT(ArgTs...)> {
+public:
+  move_only_function() = default;
+  move_only_function(std::nullptr_t) {}
+  move_only_function(move_only_function &&) = default;
+  move_only_function(const move_only_function &&) = delete;
+  move_only_function &operator=(move_only_function &&) = default;
+  move_only_function &operator=(const move_only_function &&) = delete;
+
+  template <typename CallableT>
+  move_only_function(CallableT &&Callable)
+      : C(std::make_unique<
+            move_only_function_detail::CallableImpl<CallableT, RetT, ArgTs...>>(
+            std::forward<CallableT>(Callable))) {}
+
+  RetT operator()(ArgTs... Params) {
+    return C->call(std::forward<ArgTs>(Params)...);
+  }
+
+  explicit operator bool() const { return !!C; }
+
+private:
+  std::unique_ptr<move_only_function_detail::Callable<RetT, ArgTs...>> C;
+};
+
+} // namespace orc_rt
+
+#endif // ORC_RT_MOVE_ONLY_FUNCTION_H
diff --git a/orc-rt/include/orc-rt/unique-function.h b/orc-rt/include/orc-rt/unique-function.h
deleted file mode 100644
index 467476c7623cd..0000000000000
--- a/orc-rt/include/orc-rt/unique-function.h
+++ /dev/null
@@ -1,80 +0,0 @@
-//===----- unique_function.h - moveable type-erasing function ---*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-///
-/// unique_function works like std::function, but supports move-only callable
-/// objects.
-///
-/// TODO: Use LLVM's unique_function (llvm/include/llvm/ADT/FunctionExtras.h),
-///       which uses some extra inline storage to avoid heap allocations for
-///       small objects. Using LLVM's unique_function will require first
-///       porting some other utilities like PointerIntPair, PointerUnion, and
-///       PointerLikeTypeTraits. (These are likely to be independently useful
-///       in the orc runtime, so porting will have additional benefits).
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef ORC_RT_UNIQUE_FUNCTION_H
-#define ORC_RT_UNIQUE_FUNCTION_H
-
-#include <memory>
-
-namespace orc_rt {
-
-namespace unique_function_detail {
-
-template <typename RetT, typename... ArgTs> class Callable {
-public:
-  virtual ~Callable() = default;
-  virtual RetT call(ArgTs &&...Args) = 0;
-};
-
-template <typename CallableT, typename RetT, typename... ArgTs>
-class CallableImpl : public Callable<RetT, ArgTs...> {
-public:
-  CallableImpl(CallableT &&Callable) : Callable(std::move(Callable)) {}
-  RetT call(ArgTs &&...Args) override {
-    return Callable(std::forward<ArgTs>(Args)...);
-  }
-
-private:
-  CallableT Callable;
-};
-
-} // namespace unique_function_detail
-
-template <typename FnT> class unique_function;
-
-template <typename RetT, typename... ArgTs>
-class unique_function<RetT(ArgTs...)> {
-public:
-  unique_function() = default;
-  unique_function(std::nullptr_t) {}
-  unique_function(unique_function &&) = default;
-  unique_function(const unique_function &&) = delete;
-  unique_function &operator=(unique_function &&) = default;
-  unique_function &operator=(const unique_function &&) = delete;
-
-  template <typename CallableT>
-  unique_function(CallableT &&Callable)
-      : C(std::make_unique<
-            unique_function_detail::CallableImpl<CallableT, RetT, ArgTs...>>(
-            std::forward<CallableT>(Callable))) {}
-
-  RetT operator()(ArgTs... Params) {
-    return C->call(std::forward<ArgTs>(Params)...);
-  }
-
-  explicit operator bool() const { return !!C; }
-
-private:
-  std::unique_ptr<unique_function_detail::Callable<RetT, ArgTs...>> C;
-};
-
-} // namespace orc_rt
-
-#endif // ORC_RT_UNIQUE_FUNCTION_H
diff --git a/orc-rt/unittests/CMakeLists.txt b/orc-rt/unittests/CMakeLists.txt
index 09696da982ed2..6a1f5d6f8bce2 100644
--- a/orc-rt/unittests/CMakeLists.txt
+++ b/orc-rt/unittests/CMakeLists.txt
@@ -16,8 +16,8 @@ add_orc_rt_unittest(CoreTests
   ErrorTest.cpp
   MathTest.cpp
   RTTITest.cpp
+  move_only_function-test.cpp
   span-test.cpp
-  unique-function-test.cpp
   DISABLE_LLVM_LINK_LLVM_DYLIB
   )
 target_link_libraries(CoreTests PRIVATE orc-rt-executor)
diff --git a/orc-rt/unittests/unique-function-test.cpp b/orc-rt/unittests/move_only_function-test.cpp
similarity index 65%
rename from orc-rt/unittests/unique-function-test.cpp
rename to orc-rt/unittests/move_only_function-test.cpp
index 03cb924a83673..95194edc69f6d 100644
--- a/orc-rt/unittests/unique-function-test.cpp
+++ b/orc-rt/unittests/move_only_function-test.cpp
@@ -1,4 +1,4 @@
-//===-- unique-function-test.cpp ------------------------------------------===//
+//===- move_only_function-test.cpp ----------------------------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,41 +6,41 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "orc-rt/unique-function.h"
+#include "orc-rt/move_only_function.h"
 #include "gtest/gtest.h"
 
 using namespace orc_rt;
 
-TEST(UniqueFunctionTest, Basic) {
-  unique_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
+TEST(MoveOnlyFunctionTest, Basic) {
+  move_only_function<int(int, int)> Sum = [](int A, int B) { return A + B; };
   EXPECT_EQ(Sum(1, 2), 3);
 
-  unique_function<int(int, int)> Sum2 = std::move(Sum);
+  move_only_function<int(int, int)> Sum2 = std::move(Sum);
   EXPECT_EQ(Sum2(1, 2), 3);
 
-  unique_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
+  move_only_function<int(int, int)> Sum3 = [](int A, int B) { return A + B; };
   Sum2 = std::move(Sum3);
   EXPECT_EQ(Sum2(1, 2), 3);
 
-  Sum2 = unique_function<int(int, int)>([](int A, int B) { return A + B; });
+  Sum2 = move_only_function<int(int, int)>([](int A, int B) { return A + B; });
   EXPECT_EQ(Sum2(1, 2), 3);
 
   // Explicit self-move test.
   *&Sum2 = std::move(Sum2);
   EXPECT_EQ(Sum2(1, 2), 3);
 
-  Sum2 = unique_function<int(int, int)>();
+  Sum2 = move_only_function<int(int, int)>();
   EXPECT_FALSE(Sum2);
 
   // Make sure we can forward through l-value reference parameters.
-  unique_function<void(int &)> Inc = [](int &X) { ++X; };
+  move_only_function<void(int &)> Inc = [](int &X) { ++X; };
   int X = 42;
   Inc(X);
   EXPECT_EQ(X, 43);
 
   // Make sure we can forward through r-value reference parameters with
   // move-only types.
-  unique_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
+  move_only_function<int(std::unique_ptr<int> &&)> ReadAndDeallocByRef =
       [](std::unique_ptr<int> &&Ptr) {
         int V = *Ptr;
         Ptr.reset();
@@ -54,7 +54,7 @@ TEST(UniqueFunctionTest, Basic) {
   EXPECT_EQ(ReadAndDeallocByRef(std::unique_ptr<int>(new int(42))), 42);
 
   // Make sure we can pass a move-only type by-value.
-  unique_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
+  move_only_function<int(std::unique_ptr<int>)> ReadAndDeallocByVal =
       [](std::unique_ptr<int> Ptr) {
         int V = *Ptr;
         Ptr.reset();
@@ -67,50 +67,52 @@ TEST(UniqueFunctionTest, Basic) {
   EXPECT_EQ(ReadAndDeallocByVal(std::unique_ptr<int>(new int(42))), 42);
 }
 
-TEST(UniqueFunctionTest, Captures) {
+TEST(MoveOnlyFunctionTest, Captures) {
   long A = 1, B = 2, C = 3, D = 4, E = 5;
 
-  unique_function<long()> Tmp;
+  move_only_function<long()> Tmp;
 
-  unique_function<long()> C1 = [A]() { return A; };
+  move_only_function<long()> C1 = [A]() { return A; };
   EXPECT_EQ(C1(), 1);
   Tmp = std::move(C1);
   EXPECT_EQ(Tmp(), 1);
 
-  unique_function<long()> C2 = [A, B]() { return A + B; };
+  move_only_function<long()> C2 = [A, B]() { return A + B; };
   EXPECT_EQ(C2(), 3);
   Tmp = std::move(C2);
   EXPECT_EQ(Tmp(), 3);
 
-  unique_function<long()> C3 = [A, B, C]() { return A + B + C; };
+  move_only_function<long()> C3 = [A, B, C]() { return A + B + C; };
   EXPECT_EQ(C3(), 6);
   Tmp = std::move(C3);
   EXPECT_EQ(Tmp(), 6);
 
-  unique_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
+  move_only_function<long()> C4 = [A, B, C, D]() { return A + B + C + D; };
   EXPECT_EQ(C4(), 10);
   Tmp = std::move(C4);
   EXPECT_EQ(Tmp(), 10);
 
-  unique_function<long()> C5 = [A, B, C, D, E]() { return A + B + C + D + E; };
+  move_only_function<long()> C5 = [A, B, C, D, E]() {
+    return A + B + C + D + E;
+  };
   EXPECT_EQ(C5(), 15);
   Tmp = std::move(C5);
   EXPECT_EQ(Tmp(), 15);
 }
 
-TEST(UniqueFunctionTest, MoveOnly) {
+TEST(MoveOnlyFunctionTest, MoveOnly) {
   struct SmallCallable {
     std::unique_ptr<int> A = std::make_unique<int>(1);
     int operator()(int B) { return *A + B; }
   };
 
-  unique_function<int(int)> Small = SmallCallable();
+  move_only_function<int(int)> Small = SmallCallable();
   EXPECT_EQ(Small(2), 3);
-  unique_function<int(int)> Small2 = std::move(Small);
+  move_only_function<int(int)> Small2 = std::move(Small);
   EXPECT_EQ(Small2(2), 3);
 }
 
-TEST(UniqueFunctionTest, CountForwardingCopies) {
+TEST(MoveOnlyFunctionTest, CountForwardingCopies) {
   struct CopyCounter {
     int &CopyCount;
 
@@ -120,7 +122,7 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
     }
   };
 
-  unique_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
+  move_only_function<void(CopyCounter)> ByValF = [](CopyCounter) {};
   int CopyCount = 0;
   ByValF(CopyCounter(CopyCount));
   EXPECT_EQ(1, CopyCount);
@@ -134,8 +136,8 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
 
   // Check that we don't generate a copy at all when we can bind a reference all
   // the way down, even if that reference could *in theory* allow copies.
-  unique_function<void(const CopyCounter &)> ByRefF = [](const CopyCounter &) {
-  };
+  move_only_function<void(const CopyCounter &)> ByRefF =
+      [](const CopyCounter &) {};
   CopyCount = 0;
   ByRefF(CopyCounter(CopyCount));
   EXPECT_EQ(0, CopyCount);
@@ -153,17 +155,17 @@ TEST(UniqueFunctionTest, CountForwardingCopies) {
     Uncopyable() = default;
     Uncopyable(const Uncopyable &) = delete;
   };
-  unique_function<void(const Uncopyable &)> UncopyableF =
+  move_only_function<void(const Uncopyable &)> UncopyableF =
       [](const Uncopyable &) {};
   UncopyableF(Uncopyable());
   Uncopyable X;
   UncopyableF(X);
 }
 
-TEST(UniqueFunctionTest, BooleanConversion) {
-  unique_function<void()> D;
+TEST(MoveOnlyFunctionTest, BooleanConversion) {
+  move_only_function<void()> D;
   EXPECT_FALSE(D);
 
-  unique_function<void()> F = []() {};
+  move_only_function<void()> F = []() {};
   EXPECT_TRUE(F);
 }



More information about the llvm-commits mailing list