Skip to content

Commit adc3d96

Browse files
committed
Correctly model const/mutable construction of Fn types
Test Into/From for Fn types from callables and function pointers. Attach clang::lifetimebound to all construction paths of Fn types.
1 parent 6353f31 commit adc3d96

File tree

2 files changed

+239
-71
lines changed

2 files changed

+239
-71
lines changed

subspace/fn/fn_defn.h

Lines changed: 59 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ concept FunctionPointer =
8787
};
8888

8989
template <class T>
90-
concept IsFunctionPointer = std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>;
90+
concept IsFunctionPointer =
91+
std::is_pointer_v<T> && std::is_function_v<std::remove_pointer_t<T>>;
9192

9293
template <class F>
9394
concept ConvertsToFunctionPointer = requires(F f) {
@@ -149,18 +150,18 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
149150
/// Construction from a non-capturing lambda.
150151
///
151152
/// #[doc.overloads=ctor.lambda]
152-
template <__private::CallableMut<R, CallArgs...> F>
153+
template <__private::CallableConst<R, CallArgs...> F>
153154
requires(__private::ConvertsToFunctionPointer<F>)
154-
constexpr Fn(F&& object) noexcept {
155+
constexpr Fn(F&& object sus_lifetimebound) noexcept {
155156
storage_.object = ::sus::mem::addressof(object);
156157
invoke_ = &__private::Invoker<
157158
std::remove_reference_t<F>>::template object_call_const<R, CallArgs...>;
158159
}
159160

160161
/// Construction from a capturing lambda or other callable object.
161162
///
162-
/// #[doc.overloads=ctor.lambda]
163-
template <__private::CallableMut<R, CallArgs...> F>
163+
/// #[doc.overloads=ctor.capturelambda]
164+
template <__private::CallableConst<R, CallArgs...> F>
164165
requires(!__private::ConvertsToFunctionPointer<F>)
165166
constexpr Fn(F&& object sus_lifetimebound) noexcept {
166167
storage_.object = ::sus::mem::addressof(object);
@@ -170,12 +171,12 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
170171

171172
~Fn() noexcept = default;
172173

173-
constexpr Fn(Fn&& o) noexcept
174+
constexpr Fn(Fn&& o sus_lifetimebound) noexcept
174175
: storage_(o.storage_),
175176
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
176177
::sus::check(invoke_); // Catch use-after-move.
177178
}
178-
constexpr Fn& operator=(Fn&& o) noexcept {
179+
constexpr Fn& operator=(Fn&& o sus_lifetimebound) noexcept {
179180
storage_ = o.storage_;
180181
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
181182
::sus::check(invoke_); // Catch use-after-move.
@@ -206,12 +207,16 @@ class [[sus_trivial_abi]] Fn<R(CallArgs...)> {
206207
}
207208

208209
/// `sus::construct::From` trait implementation.
210+
///
211+
/// Fn satisfies `From<T>` for the same types that it is constructible from:
212+
/// function pointers that exactly match its own signature, and const-callable
213+
/// objects (lambdas) that are compatible with its signature.
209214
constexpr static auto from(
210215
__private::FunctionPointer<R, CallArgs...> auto ptr) noexcept {
211216
return Fn(ptr);
212217
}
213-
template <__private::CallableMut<R, CallArgs...> F>
214-
constexpr static auto from(F&& object) noexcept {
218+
template <__private::CallableConst<R, CallArgs...> F>
219+
constexpr static auto from(F&& object sus_lifetimebound) noexcept {
215220
return Fn(::sus::forward<F>(object));
216221
}
217222

@@ -280,11 +285,23 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
280285
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
281286
}
282287

283-
/// Construction from a capturing lambda or other callable object.
288+
/// Construction from a non-capturing lambda.
284289
///
285290
/// #[doc.overloads=ctor.lambda]
286291
template <__private::CallableMut<R, CallArgs...> F>
287-
constexpr FnMut(F&& object) noexcept {
292+
requires(__private::ConvertsToFunctionPointer<F>)
293+
constexpr FnMut(F&& object sus_lifetimebound) noexcept {
294+
storage_.object = ::sus::mem::addressof(object);
295+
invoke_ = &__private::Invoker<
296+
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
297+
}
298+
299+
/// Construction from a capturing lambda or other callable object.
300+
///
301+
/// #[doc.overloads=ctor.capturelambda]
302+
template <__private::CallableMut<R, CallArgs...> F>
303+
requires(!__private::ConvertsToFunctionPointer<F>)
304+
constexpr FnMut(F&& object sus_lifetimebound) noexcept {
288305
storage_.object = ::sus::mem::addressof(object);
289306
invoke_ = &__private::Invoker<
290307
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
@@ -295,20 +312,20 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
295312
/// Since Fn is callable, FnMut is already constructible from it, but
296313
/// this constructor avoids extra indirections being inserted when converting,
297314
/// since otherwise an extra invoker call would be introduced.
298-
constexpr FnMut(Fn<R(CallArgs...)>&& o) noexcept
315+
constexpr FnMut(Fn<R(CallArgs...)>&& o sus_lifetimebound) noexcept
299316
: storage_(o.storage_),
300317
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
301318
::sus::check(invoke_); // Catch use-after-move.
302319
}
303320

304321
~FnMut() noexcept = default;
305322

306-
constexpr FnMut(FnMut&& o) noexcept
323+
constexpr FnMut(FnMut&& o sus_lifetimebound) noexcept
307324
: storage_(o.storage_),
308325
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
309326
::sus::check(invoke_); // Catch use-after-move.
310327
}
311-
constexpr FnMut& operator=(FnMut&& o) noexcept {
328+
constexpr FnMut& operator=(FnMut&& o sus_lifetimebound) noexcept {
312329
storage_ = o.storage_;
313330
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
314331
::sus::check(invoke_); // Catch use-after-move.
@@ -339,12 +356,16 @@ class [[sus_trivial_abi]] FnMut<R(CallArgs...)> {
339356
}
340357

341358
/// `sus::construct::From` trait implementation.
359+
///
360+
/// FnMut satisfies `From<T>` for the same types that it is constructible
361+
/// from: function pointers that exactly match its own signature, and callable
362+
/// objects (lambdas) that are compatible with its signature.
342363
constexpr static auto from(
343364
__private::FunctionPointer<R, CallArgs...> auto ptr) noexcept {
344365
return FnMut(ptr);
345366
}
346367
template <__private::CallableMut<R, CallArgs...> F>
347-
constexpr static auto from(F&& object) noexcept {
368+
constexpr static auto from(F&& object sus_lifetimebound) noexcept {
348369
return FnMut(::sus::forward<F>(object));
349370
}
350371

@@ -410,11 +431,23 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
410431
invoke_ = &__private::Invoker<F>::template fnptr_call_mut<R, CallArgs...>;
411432
}
412433

413-
/// Construction from a capturing lambda or other callable object.
434+
/// Construction from a non-capturing lambda.
414435
///
415436
/// #[doc.overloads=ctor.lambda]
416437
template <__private::CallableMut<R, CallArgs...> F>
417-
constexpr FnOnce(F&& object) noexcept {
438+
requires(__private::ConvertsToFunctionPointer<F>)
439+
constexpr FnOnce(F&& object sus_lifetimebound) noexcept {
440+
storage_.object = ::sus::mem::addressof(object);
441+
invoke_ = &__private::Invoker<
442+
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
443+
}
444+
445+
/// Construction from a capturing lambda or other callable object.
446+
///
447+
/// #[doc.overloads=ctor.capturelambda]
448+
template <__private::CallableMut<R, CallArgs...> F>
449+
requires(!__private::ConvertsToFunctionPointer<F>)
450+
constexpr FnOnce(F&& object sus_lifetimebound) noexcept {
418451
storage_.object = ::sus::mem::addressof(object);
419452
invoke_ = &__private::Invoker<
420453
std::remove_reference_t<F>>::template object_call_mut<R, CallArgs...>;
@@ -425,7 +458,7 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
425458
/// Since FnMut is callable, FnOnce is already constructible from it, but
426459
/// this constructor avoids extra indirections being inserted when converting,
427460
/// since otherwise an extra invoker call would be introduced.
428-
constexpr FnOnce(FnMut<R(CallArgs...)>&& o) noexcept
461+
constexpr FnOnce(FnMut<R(CallArgs...)>&& o sus_lifetimebound) noexcept
429462
: storage_(o.storage_),
430463
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
431464
::sus::check(invoke_); // Catch use-after-move.
@@ -436,20 +469,20 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
436469
/// Since Fn is callable, FnOnce is already constructible from it, but
437470
/// this constructor avoids extra indirections being inserted when converting,
438471
/// since otherwise an extra invoker call would be introduced.
439-
constexpr FnOnce(Fn<R(CallArgs...)>&& o) noexcept
472+
constexpr FnOnce(Fn<R(CallArgs...)>&& o sus_lifetimebound) noexcept
440473
: storage_(o.storage_),
441474
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
442475
::sus::check(invoke_); // Catch use-after-move.
443476
}
444477

445478
~FnOnce() noexcept = default;
446479

447-
constexpr FnOnce(FnOnce&& o) noexcept
480+
constexpr FnOnce(FnOnce&& o sus_lifetimebound) noexcept
448481
: storage_(o.storage_),
449482
invoke_(::sus::mem::replace_ptr(o.invoke_, nullptr)) {
450483
::sus::check(invoke_); // Catch use-after-move.
451484
}
452-
constexpr FnOnce& operator=(FnOnce&& o) noexcept {
485+
constexpr FnOnce& operator=(FnOnce&& o sus_lifetimebound) noexcept {
453486
storage_ = o.storage_;
454487
invoke_ = ::sus::mem::replace_ptr(o.invoke_, nullptr);
455488
::sus::check(invoke_); // Catch use-after-move.
@@ -468,12 +501,16 @@ class [[sus_trivial_abi]] FnOnce<R(CallArgs...)> {
468501
}
469502

470503
/// `sus::construct::From` trait implementation.
504+
///
505+
/// FnOnce satisfies `From<T>` for the same types that it is constructible
506+
/// from: function pointers that exactly match its own signature, and callable
507+
/// objects (lambdas) that are compatible with its signature.
471508
constexpr static auto from(
472509
__private::FunctionPointer<R, CallArgs...> auto ptr) noexcept {
473510
return FnOnce(ptr);
474511
}
475512
template <__private::CallableMut<R, CallArgs...> F>
476-
constexpr static auto from(F&& object) noexcept {
513+
constexpr static auto from(F&& object sus_lifetimebound) noexcept {
477514
return FnOnce(::sus::forward<F>(object));
478515
}
479516

0 commit comments

Comments
 (0)