[llvm] [orc-rt] Make more Session callbacks noexcept. (PR #226385)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 25 01:54:05 PDT 2026


https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/226385

>From 2f539a4452a3d5a886499be7662643da83cc4e9a Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 25 Sep 2026 17:13:59 +1000
Subject: [PATCH] [orc-rt] Make more Session callbacks noexcept.

Session's OnDisconnectFn, OnDetachFn, and OnShutdownFn callbacks should
not throw exceptions.
---
 orc-rt/include/orc-rt/bedrock/Session.h       |  6 +--
 orc-rt/lib/bedrock/NativeDylibManager.cpp     |  2 +-
 orc-rt/test/unit/CommonTestUtils.h            | 11 +++--
 orc-rt/test/unit/bedrock/SessionTest.cpp      | 43 ++++++++++---------
 .../sps/SimpleRemoteCAOverSocketTest.cpp      |  2 +-
 .../unit/bedrock/sps/SimpleRemoteCATest.cpp   | 10 ++---
 orc-rt/tools/ogre/ogre.cpp                    |  2 +-
 7 files changed, 41 insertions(+), 35 deletions(-)

diff --git a/orc-rt/include/orc-rt/bedrock/Session.h b/orc-rt/include/orc-rt/bedrock/Session.h
index 66128643d3f0ca..d9bc61359ccc6d 100644
--- a/orc-rt/include/orc-rt/bedrock/Session.h
+++ b/orc-rt/include/orc-rt/bedrock/Session.h
@@ -72,9 +72,9 @@ class Session {
 
 public:
   using ErrorReporterFn = move_only_function<void(Error) noexcept>;
-  using OnDisconnectFn = move_only_function<void(Error)>;
-  using OnDetachFn = move_only_function<void()>;
-  using OnShutdownFn = move_only_function<void()>;
+  using OnDisconnectFn = move_only_function<void(Error) noexcept>;
+  using OnDetachFn = move_only_function<void() noexcept>;
+  using OnShutdownFn = move_only_function<void() noexcept>;
 
   /// Return value callback used to return results from callController.
   using OnControllerCallReturnFn =
diff --git a/orc-rt/lib/bedrock/NativeDylibManager.cpp b/orc-rt/lib/bedrock/NativeDylibManager.cpp
index d26f92e24851ec..72201d3866dafe 100644
--- a/orc-rt/lib/bedrock/NativeDylibManager.cpp
+++ b/orc-rt/lib/bedrock/NativeDylibManager.cpp
@@ -50,7 +50,7 @@ void NativeDylibManager::load(OnLoadCompleteFn &&OnComplete, std::string Path) {
 
   // Capture S by reference, rather than this, so that the callback remains
   // valid even if the NativeDylibManager is destroyed prior to shutdown.
-  S.addOnShutdown([&S = this->S, Handle = *H]() {
+  S.addOnShutdown([&S = this->S, Handle = *H]() noexcept {
     if (auto Err = sys::unloadLibrary(Handle))
       S.reportError(std::move(Err));
   });
diff --git a/orc-rt/test/unit/CommonTestUtils.h b/orc-rt/test/unit/CommonTestUtils.h
index 7bbe91d982a22a..a54a2055c29e15 100644
--- a/orc-rt/test/unit/CommonTestUtils.h
+++ b/orc-rt/test/unit/CommonTestUtils.h
@@ -100,16 +100,19 @@ template <size_t Idx> size_t OpCounter<Idx>::MoveConstructions = 0;
 template <size_t Idx> size_t OpCounter<Idx>::MoveAssignments = 0;
 template <size_t Idx> size_t OpCounter<Idx>::Destructions = 0;
 
-template <typename T> move_only_function<void(T)> waitFor(std::future<T> &F) {
+template <typename T>
+move_only_function<void(T) noexcept> waitFor(std::future<T> &F) {
   std::promise<T> P;
   F = P.get_future();
-  return [P = std::move(P)](T Val) mutable { P.set_value(std::move(Val)); };
+  return [P = std::move(P)](T Val) mutable noexcept {
+    P.set_value(std::move(Val));
+  };
 }
 
-inline move_only_function<void()> waitFor(std::future<void> &F) {
+inline move_only_function<void() noexcept> waitFor(std::future<void> &F) {
   std::promise<void> P;
   F = P.get_future();
-  return [P = std::move(P)]() mutable { P.set_value(); };
+  return [P = std::move(P)]() mutable noexcept { P.set_value(); };
 }
 
 } // namespace orc_rt::test
diff --git a/orc-rt/test/unit/bedrock/SessionTest.cpp b/orc-rt/test/unit/bedrock/SessionTest.cpp
index 41fc8738696e0a..493249ad556896 100644
--- a/orc-rt/test/unit/bedrock/SessionTest.cpp
+++ b/orc-rt/test/unit/bedrock/SessionTest.cpp
@@ -327,7 +327,7 @@ inline MockControllerAccess::PostFn postOnto(QueueingRunner<>::WorkQueue &Q) {
 void waitForShutdown(Session &S) {
   std::promise<void> P;
   auto F = P.get_future();
-  S.shutdown([P = std::move(P)]() mutable { P.set_value(); });
+  S.shutdown([P = std::move(P)]() mutable noexcept { P.set_value(); });
   F.get();
 }
 
@@ -404,10 +404,10 @@ TEST(SessionTest, ScheduleShutdownFromOnDetachHandler) {
   int OnDetachHandlersRun = 0;
   bool OnShutdownHandlerRun = false;
 
-  S.addOnDetach([&]() { ++OnDetachHandlersRun; });
-  S.addOnDetach([&]() { S.shutdown(); });
-  S.addOnDetach([&]() { ++OnDetachHandlersRun; });
-  S.addOnShutdown([&]() {
+  S.addOnDetach([&]() noexcept { ++OnDetachHandlersRun; });
+  S.addOnDetach([&]() noexcept { S.shutdown(); });
+  S.addOnDetach([&]() noexcept { ++OnDetachHandlersRun; });
+  S.addOnShutdown([&]() noexcept {
     EXPECT_EQ(OnDetachHandlersRun, 2);
     OnShutdownHandlerRun = true;
   });
@@ -428,7 +428,7 @@ TEST(SessionTest, RedundantAsyncShutdown) {
 
   // Now try to add a new on-shutdown callback and verify that it runs.
   bool RedundantCallbackRan = false;
-  S.shutdown([&]() { RedundantCallbackRan = true; });
+  S.shutdown([&]() noexcept { RedundantCallbackRan = true; });
   EXPECT_TRUE(RedundantCallbackRan);
 }
 
@@ -448,7 +448,7 @@ TEST(SessionTest, ExpectedShutdownSequenceWithNoOutstandingKeepalives) {
     S.addService(
         std::make_unique<MockService>(DetachOpIdx, ShutdownOpIdx, OpIdx));
 
-    S.shutdown([&]() {
+    S.shutdown([&]() noexcept {
       EXPECT_TRUE(ShutdownOpIdx);
       EXPECT_EQ(*ShutdownOpIdx, 1);
       SessionShutdownComplete = true;
@@ -476,7 +476,7 @@ TEST(SessionTest, OutstandingKeepalivesDelayShutdown) {
 
   // We expect shutdown to wait for any outstanding keepalives to be released.
   bool ShutdownComplete = false;
-  S.shutdown([&]() { ShutdownComplete = true; });
+  S.shutdown([&]() noexcept { ShutdownComplete = true; });
 
   // Detach should have happened, but shutdown should be waiting on token.
   EXPECT_EQ(DetachOpIdx, 0U);
@@ -846,7 +846,7 @@ TEST(ControllerAccessTest, WrapperCallTokenReleasedWhenFnReturns) {
   // drain phase should therefore complete without waiting on the deferred
   // Return call.
   bool ShutdownComplete = false;
-  S.shutdown([&] { ShutdownComplete = true; });
+  S.shutdown([&]() noexcept { ShutdownComplete = true; });
   EXPECT_TRUE(ShutdownComplete);
 }
 
@@ -1008,7 +1008,7 @@ TEST(ControllerAccessTest, OnDisconnectReportsOrderlyDisconnect) {
   size_t HandlerRuns = 0;
   std::string ErrMsg = "<not run>";
   Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
-  S.setOnDisconnect([&](Error Err) {
+  S.setOnDisconnect([&](Error Err) noexcept {
     ++HandlerRuns;
     ErrMsg = errMsgOrEmpty(std::move(Err));
   });
@@ -1024,7 +1024,8 @@ TEST(ControllerAccessTest, OnDisconnectReportsAbnormalDisconnect) {
   // An abnormal disconnection reports the ControllerAccess's Error unchanged.
   std::optional<std::string> ErrMsg;
   Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
-  S.setOnDisconnect([&](Error Err) { ErrMsg = errMsgOrEmpty(std::move(Err)); });
+  S.setOnDisconnect(
+      [&](Error Err) noexcept { ErrMsg = errMsgOrEmpty(std::move(Err)); });
   S.attach<DisconnectingControllerAccess>(BootstrapInfo(S),
                                           "connection closed without hangup");
 
@@ -1065,8 +1066,9 @@ TEST(ControllerAccessTest, OnDisconnectSuppressesErrorReporterRouting) {
   std::vector<std::string> ErrMsgs;
   std::optional<std::string> HandlerErrMsg;
   Session S(mockExecutorProcessInfo(), noDispatch, AccumulateErrors(ErrMsgs));
-  S.setOnDisconnect(
-      [&](Error Err) { HandlerErrMsg = errMsgOrEmpty(std::move(Err)); });
+  S.setOnDisconnect([&](Error Err) noexcept {
+    HandlerErrMsg = errMsgOrEmpty(std::move(Err));
+  });
   S.attach<DisconnectingControllerAccess>(BootstrapInfo(S),
                                           "connection closed without hangup");
 
@@ -1088,7 +1090,8 @@ TEST(ControllerAccessTest, OnDisconnectReportsConnectFailure) {
   // would still pass if a failed connect were reported as success.
   std::optional<std::string> ErrMsg;
   Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
-  S.setOnDisconnect([&](Error Err) { ErrMsg = errMsgOrEmpty(std::move(Err)); });
+  S.setOnDisconnect(
+      [&](Error Err) noexcept { ErrMsg = errMsgOrEmpty(std::move(Err)); });
 
   S.attach<MockControllerAccess>(
       BootstrapInfo(S), MockControllerAccess::PostFn{},
@@ -1110,7 +1113,7 @@ TEST(ControllerAccessTest, OnDisconnectReportsSuccessWithoutAttach) {
   std::string ErrMsg = "<not run>";
   {
     Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
-    S.setOnDisconnect([&](Error Err) {
+    S.setOnDisconnect([&](Error Err) noexcept {
       ++HandlerRuns;
       ErrMsg = errMsgOrEmpty(std::move(Err));
     });
@@ -1130,7 +1133,7 @@ TEST(ControllerAccessTest, OnDisconnectRunsBeforeDetachAndShutdown) {
 
   {
     Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
-    S.setOnDisconnect([&](Error Err) {
+    S.setOnDisconnect([&](Error Err) noexcept {
       DisconnectOpIdx = OpIdx++;
       cantFail(std::move(Err));
     });
@@ -1161,9 +1164,9 @@ TEST(ControllerAccessTest, ShutdownFromOnDisconnectHandler) {
     Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
     S.addService(
         std::make_unique<MockService>(DetachOpIdx, ShutdownOpIdx, OpIdx));
-    S.setOnDisconnect([&](Error Err) {
+    S.setOnDisconnect([&](Error Err) noexcept {
       cantFail(std::move(Err));
-      S.shutdown([&]() { OnShutdownRan = true; });
+      S.shutdown([&]() noexcept { OnShutdownRan = true; });
     });
     S.attach<DisconnectingControllerAccess>(BootstrapInfo(S));
 
@@ -1192,9 +1195,9 @@ TEST(ControllerAccessTest, ShutdownFromOnDisconnectHandlerAfterRemoteHangup) {
     Session S(mockExecutorProcessInfo(), noDispatch, noErrors);
     S.addService(
         std::make_unique<MockService>(DetachOpIdx, ShutdownOpIdx, OpIdx));
-    S.setOnDisconnect([&](Error Err) {
+    S.setOnDisconnect([&](Error Err) noexcept {
       cantFail(std::move(Err));
-      S.shutdown([&]() { OnShutdownRan = true; });
+      S.shutdown([&]() noexcept { OnShutdownRan = true; });
     });
     S.attach<DisconnectingControllerAccess>(BootstrapInfo(S), "", &CA);
     ASSERT_TRUE(CA);
diff --git a/orc-rt/test/unit/bedrock/sps/SimpleRemoteCAOverSocketTest.cpp b/orc-rt/test/unit/bedrock/sps/SimpleRemoteCAOverSocketTest.cpp
index 48b5214ecd5939..aece4eac1c647c 100644
--- a/orc-rt/test/unit/bedrock/sps/SimpleRemoteCAOverSocketTest.cpp
+++ b/orc-rt/test/unit/bedrock/sps/SimpleRemoteCAOverSocketTest.cpp
@@ -539,7 +539,7 @@ TEST_F(SimpleRemoteCAOverSocketTest, NothingIsQueuedBehindTheHangup) {
 
   // Queues the hang-up and latches the queue. Returns without waiting for the
   // reactor, which is still stalled.
-  S.detach([] {});
+  S.detach();
 
   // Too late: this must not reach the wire.
   DeferredReturn(Deferred.S, Deferred.ArgBytes, Deferred.CallId);
diff --git a/orc-rt/test/unit/bedrock/sps/SimpleRemoteCATest.cpp b/orc-rt/test/unit/bedrock/sps/SimpleRemoteCATest.cpp
index f434575b10b307..4f4d6c253d72bf 100644
--- a/orc-rt/test/unit/bedrock/sps/SimpleRemoteCATest.cpp
+++ b/orc-rt/test/unit/bedrock/sps/SimpleRemoteCATest.cpp
@@ -133,7 +133,7 @@ TEST(SimpleRemoteCATest, SetupMessageRoundTrips) {
   // controller would be left to interpret.
   EXPECT_EQ(static_cast<size_t>(IB.data() - Payload.data()), Payload.size());
 
-  S.detach([] {});
+  S.detach();
 }
 
 TEST(SimpleRemoteCATest, MessageHeaderRoundTrips) {
@@ -245,7 +245,7 @@ TEST(SimpleRemoteCATest, ResultWithAnUnknownKindIsRejected) {
   EXPECT_EQ(toString(A.takeError()),
             "Malformed result message: invalid kind 2");
 
-  S.detach([] {});
+  S.detach();
 }
 
 TEST(SimpleRemoteCATest, DecodeResultOfMalformedOutOfBandErrorIsNotTerminal) {
@@ -274,7 +274,7 @@ TEST(SimpleRemoteCATest, RegisterCallReturnsDistinctNonZeroSequenceNumbers) {
   EXPECT_NE(Second, 0u);
   EXPECT_NE(First, Second);
 
-  S.detach([] {});
+  S.detach();
 }
 
 TEST(SimpleRemoteCATest, TakeCallYieldsTheHandlerExactlyOnce) {
@@ -293,7 +293,7 @@ TEST(SimpleRemoteCATest, TakeCallYieldsTheHandlerExactlyOnce) {
   EXPECT_FALSE(!!CA->takeCall(/*SeqNo=*/9999)) << "never registered";
 
   CA->failPendingControllerCall(std::move(Taken));
-  S.detach([] {});
+  S.detach();
 }
 
 TEST(SimpleRemoteCATest, TakeAllCallsEmptiesTheTable) {
@@ -316,5 +316,5 @@ TEST(SimpleRemoteCATest, TakeAllCallsEmptiesTheTable) {
 
   for (auto &[SeqNo, OnComplete] : All)
     CA->failPendingControllerCall(std::move(OnComplete));
-  S.detach([] {});
+  S.detach();
 }
diff --git a/orc-rt/tools/ogre/ogre.cpp b/orc-rt/tools/ogre/ogre.cpp
index 1fbef3087e79c9..c98da66fba3194 100644
--- a/orc-rt/tools/ogre/ogre.cpp
+++ b/orc-rt/tools/ogre/ogre.cpp
@@ -140,7 +140,7 @@ Expected<int> runOgre(const Options &Opts) noexcept {
 
   std::promise<void> StopP;
   auto StopF = StopP.get_future();
-  S.setOnDisconnect([StopP = std::move(StopP)](Error Err) mutable {
+  S.setOnDisconnect([StopP = std::move(StopP)](Error Err) mutable noexcept {
     if (Err)
       reportError(std::move(Err));
     StopP.set_value();



More information about the llvm-commits mailing list