[llvm] [orc-rt] Make Expected's move operations conditionally noexcept. (PR #226393)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 25 01:11:42 PDT 2026
https://github.com/lhames created https://github.com/llvm/llvm-project/pull/226393
Expected<T>'s move constructor and move assignment operator are now noexcept whenever T's storage type is nothrow-move-constructible. Error's move operations are already noexcept, so this is the only condition under which moving an Expected can throw.
This allows callables that take Expected<T> by value to be stored in noexcept-qualified move_only_functions: is_nothrow_invocable includes the initialization of by-value parameters, which previously used Expected's potentially-throwing move constructor.
>From 1a077faf9a3c79dfebe0175626dcbb3493e90caa Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Fri, 25 Sep 2026 17:50:57 +1000
Subject: [PATCH] [orc-rt] Make Expected's move operations conditionally
noexcept.
Expected<T>'s move constructor and move assignment operator are now noexcept
whenever T's storage type is nothrow-move-constructible. Error's move
operations are already noexcept, so this is the only condition under which
moving an Expected can throw.
This allows callables that take Expected<T> by value to be stored in
noexcept-qualified move_only_functions: is_nothrow_invocable includes the
initialization of by-value parameters, which previously used Expected's
potentially-throwing move constructor.
---
orc-rt/include/orc-rt/support/Error.h | 8 ++++++--
orc-rt/test/unit/support/ErrorTest.cpp | 22 ++++++++++++++++++++++
2 files changed, 28 insertions(+), 2 deletions(-)
diff --git a/orc-rt/include/orc-rt/support/Error.h b/orc-rt/include/orc-rt/support/Error.h
index 3ff55b8cac74cf..b9cb1952c5ded9 100644
--- a/orc-rt/include/orc-rt/support/Error.h
+++ b/orc-rt/include/orc-rt/support/Error.h
@@ -403,7 +403,10 @@ template <typename T> class [[nodiscard]] Expected {
}
/// Move-construct an Expected<T> from an Expected<OtherT>.
- Expected(Expected &&Other) { moveConstruct(std::move(Other)); }
+ Expected(Expected &&Other) noexcept(
+ std::is_nothrow_move_constructible_v<storage_type>) {
+ moveConstruct(std::move(Other));
+ }
/// Move construct an Expected<T> value from an Expected<OtherT>, where OtherT
/// must be convertible to T.
@@ -423,7 +426,8 @@ template <typename T> class [[nodiscard]] Expected {
}
/// Move-assign from another Expected<T>.
- Expected &operator=(Expected &&Other) {
+ Expected &operator=(Expected &&Other) noexcept(
+ std::is_nothrow_move_constructible_v<storage_type>) {
moveAssign(std::move(Other));
return *this;
}
diff --git a/orc-rt/test/unit/support/ErrorTest.cpp b/orc-rt/test/unit/support/ErrorTest.cpp
index 92b71dc67fd0ff..1f077592c3b969 100644
--- a/orc-rt/test/unit/support/ErrorTest.cpp
+++ b/orc-rt/test/unit/support/ErrorTest.cpp
@@ -484,6 +484,28 @@ TEST(ErrorTest, ExpectedExpected) {
}
}
+// Test that Expected<T>'s move operations are noexcept iff T's move
+// constructor is.
+namespace {
+struct ThrowingMove {
+ ThrowingMove(ThrowingMove &&) noexcept(false);
+ ThrowingMove &operator=(ThrowingMove &&) noexcept(false);
+};
+} // namespace
+
+static_assert(std::is_nothrow_move_constructible_v<Expected<int>>);
+static_assert(std::is_nothrow_move_assignable_v<Expected<int>>);
+static_assert(std::is_nothrow_move_constructible_v<Expected<int &>>);
+static_assert(std::is_nothrow_move_assignable_v<Expected<int &>>);
+static_assert(std::is_nothrow_move_constructible_v<Expected<Error>>);
+static_assert(std::is_nothrow_move_assignable_v<Expected<Error>>);
+static_assert(std::is_nothrow_move_constructible_v<Expected<Expected<int>>>);
+static_assert(std::is_nothrow_move_assignable_v<Expected<Expected<int>>>);
+static_assert(!std::is_nothrow_move_constructible_v<Expected<ThrowingMove>>);
+static_assert(!std::is_nothrow_move_assignable_v<Expected<ThrowingMove>>);
+static_assert(
+ !std::is_nothrow_move_constructible_v<Expected<Expected<ThrowingMove>>>);
+
// Test that the ExitOnError utility works as expected.
TEST(ErrorTest, CantFailSuccess) {
cantFail(Error::success());
More information about the llvm-commits
mailing list