Skip to content

Commit 712c406

Browse files
snarkmasterfacebook-github-bot
authored andcommitted
non_value_result::from_current_exception() + minor fixes
Reviewed By: ispeters Differential Revision: D79969518 fbshipit-source-id: ed3928c6d56b6d6ac2aacc7b8131547ca7b0c50e
1 parent 7645fdb commit 712c406

File tree

2 files changed

+42
-29
lines changed

2 files changed

+42
-29
lines changed

third-party/folly/src/folly/result/result.h

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ class non_value_result {
226226
return std::move(ew_);
227227
}
228228

229+
/// AVOID. Most code should use `result` coros, which catch most exceptions
230+
/// automatically. Or, for a stronger guarantee, see `result_catch_all`.
231+
static non_value_result from_current_exception() {
232+
// Something was already thrown, and the user likely wants a result, so
233+
// it's appropriate to accept even `OperationCancelled` here.
234+
return non_value_result::make_legacy_error_or_cancellation(
235+
exception_wrapper{current_exception()});
236+
}
237+
229238
friend inline bool operator==(
230239
const non_value_result& lhs, const non_value_result& rhs) {
231240
return lhs.ew_ == rhs.ew_;
@@ -294,7 +303,7 @@ class result_crtp {
294303
static_assert(!std::is_same_v<stopped_result_t, std::remove_cvref_t<T>>);
295304

296305
public:
297-
using value_type = T;
306+
using value_type = T; // NB: can be a reference
298307

299308
protected:
300309
using storage_type = detail::result_ref_wrap<lift_unit_t<T>>;
@@ -691,9 +700,8 @@ template <typename T>
691700
struct is_result<result<T>> : std::true_type {};
692701

693702
// This short-circuiting coroutine implementation was modeled on
694-
// `folly/Expected.h`, which is likely to follow the state of the art in
695-
// compiler support & optimizations. So, if you're looking at this, please
696-
// compare it to the original, and backport any improvements here.
703+
// `folly/Expected.h`. Please try to port any compiler fixes or
704+
// optimizations across both.
697705
namespace detail {
698706

699707
template <typename>
@@ -712,12 +720,13 @@ struct result_promise_return {
712720
void operator=(result_promise_return const&) = delete;
713721
result_promise_return(result_promise_return&&) = delete;
714722
void operator=(result_promise_return&&) = delete;
723+
// Remove this once clang 15 is well-forgotten. From D42260201:
715724
// letting dtor be trivial makes the coroutine crash
716-
// TODO: fix clang/llvm codegen
717725
~result_promise_return() {}
718726

719727
/* implicit */ operator result<T>() {
720-
// D42260201: handle both deferred and eager return-object conversion
728+
// Simplify this once clang 15 is well-forgotten. From D42260201:
729+
// handle both deferred and eager return-object conversion
721730
// behaviors see docs for detect_promise_return_object_eager_conversion
722731
if (coro::detect_promise_return_object_eager_conversion()) {
723732
assert(storage_.is_expected_empty());
@@ -747,10 +756,7 @@ struct result_promise_base {
747756
return {};
748757
}
749758
void unhandled_exception() noexcept {
750-
// We're making a `result`, so it's OK to forward all exceptions into it,
751-
// including `OperationCancelled`.
752-
*value_ = non_value_result::make_legacy_error_or_cancellation(
753-
exception_wrapper{std::current_exception()});
759+
*value_ = non_value_result::from_current_exception();
754760
}
755761

756762
result_promise_return<T> get_return_object() noexcept { return *this; }
@@ -781,7 +787,8 @@ struct result_promise<T, typename std::enable_if<std::is_void_v<T>>::type>
781787
template <typename T>
782788
using result_promise_handle = folly::coro::coroutine_handle<result_promise<T>>;
783789

784-
// This is separate to let `result_generator` reuse the awaitables below.
790+
// This is separate to let future https://fburl.com/result-generator-impl reuse
791+
// the awaitables below.
785792
struct result_await_suspender {
786793
// Future: check if all these `FOLLY_ALWAYS_INLINE`s aren't a pessimization.
787794
template <typename T, typename U>
@@ -934,10 +941,7 @@ result_catch_all(F&& fn) noexcept {
934941
return static_cast<F&&>(fn)();
935942
}
936943
} catch (...) {
937-
// We're a making `result`, so it's OK to forward all exceptions into it,
938-
// including `OperationCancelled`.
939-
return non_value_result::make_legacy_error_or_cancellation(
940-
exception_wrapper{std::current_exception()});
944+
return non_value_result::from_current_exception();
941945
}
942946
}
943947

third-party/folly/src/folly/result/value_only_result.h

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
* limitations under the License.
1515
*/
1616

17-
// Could cut the dep, they only share some implementation helpers.
1817
#include <folly/result/result.h>
1918

2019
#pragma once
@@ -44,8 +43,18 @@
4443
/// - `co_yield co_result()`
4544
/// - `co_await co_ready()`
4645
///
47-
/// In contrast, it's hard to imagine a use-case that requires
48-
/// `value_only_result` to **be** a coroutine.
46+
/// It's a good idea add a linter that errors whenever a function returning
47+
/// `value_only_result` is not `noexcept`.
48+
///
49+
/// While it is hard to imagine a use-case that requires `value_only_result` to
50+
/// **be** a coroutine, here are some notes:
51+
/// - The `noexcept` linter above becomes more important, since writing
52+
/// `unhandled_exception() { throw; }` neither makes sense, nor bodes well
53+
/// for well-optimized code. But writing `unhandled_exception() noexcept`
54+
/// definitely requires a pervasive linter.
55+
/// - You may want to add a `::template apply<>` to `result`-like types
56+
/// to make it easier for users to write generic coros that are
57+
/// either-`result`-or-`value_only_result`.
4958
///
5059
/// Implementation note: It wouldn't be hard to deduplicate most of the API
5160
/// implementation with `result.h`, but I went with the "copy" route since it
@@ -85,13 +94,8 @@ class value_only_result_crtp {
8594

8695
~value_only_result_crtp() = default;
8796

88-
friend inline bool operator==(
89-
const value_only_result_crtp& a, const value_only_result_crtp& b) {
90-
return a.value_ == b.value_;
91-
}
92-
9397
public:
94-
using value_type = T;
98+
using value_type = T; // NB: can be a reference
9599

96100
/// Movable, so long as `T` is.
97101
value_only_result_crtp(value_only_result_crtp&&) = default;
@@ -110,6 +114,9 @@ class value_only_result_crtp {
110114

111115
bool has_value() const { return true; }
112116
bool has_stopped() const { return false; }
117+
118+
// Only provide `==` since less/greater doesn't make sense for `result`.
119+
bool operator==(const value_only_result_crtp&) const = default;
113120
};
114121

115122
} // namespace detail
@@ -118,7 +125,7 @@ class value_only_result_crtp {
118125
// to `void`.
119126
template <typename T>
120127
class FOLLY_NODISCARD
121-
// Not yet a coroutine, but if we make it one, it SHOULD be elidable.
128+
// Not a coroutine, but any reasonable implementation would be elidable.
122129
[[FOLLY_ATTR_CLANG_CORO_AWAIT_ELIDABLE]] value_only_result final
123130
: public detail::value_only_result_crtp<value_only_result<T>, T> {
124131
private:
@@ -274,8 +281,8 @@ class FOLLY_NODISCARD
274281

275282
value_only_result() : base(std::in_place, unit) {}
276283

277-
void value_or_throw() const {}
278-
void value_only() const {}
284+
void value_or_throw() const noexcept {}
285+
void value_only() const noexcept {}
279286
};
280287

281288
namespace detail {
@@ -287,7 +294,8 @@ struct value_only_result_owning_awaitable {
287294
typename VOR::value_type await_resume() {
288295
return std::move(storage_).value_only();
289296
}
290-
void await_suspend(auto) {}
297+
template <typename U>
298+
void await_suspend(result_promise_handle<U>) {}
291299
};
292300

293301
// As with `result<>`, no `folly::rvalue_reference_wrapper` counterpart because
@@ -321,7 +329,8 @@ struct value_only_result_ref_awaitable {
321329
return storage_.get().value_only();
322330
}
323331

324-
void await_suspend(auto) {}
332+
template <typename U>
333+
void await_suspend(result_promise_handle<U>) {}
325334
};
326335

327336
} // namespace detail

0 commit comments

Comments
 (0)