aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor
diff options
context:
space:
mode:
Diffstat (limited to 'embassy-executor')
-rw-r--r--embassy-executor/CHANGELOG.md17
-rw-r--r--embassy-executor/Cargo.toml1
-rw-r--r--embassy-executor/build_common.rs32
-rw-r--r--embassy-executor/release.toml5
-rw-r--r--embassy-executor/src/lib.rs51
-rw-r--r--embassy-executor/src/raw/trace.rs12
-rw-r--r--embassy-executor/src/spawner.rs18
-rw-r--r--embassy-executor/tests/test.rs36
-rw-r--r--embassy-executor/tests/ui.rs11
-rw-r--r--embassy-executor/tests/ui/bad_return_impl_future.rs9
-rw-r--r--embassy-executor/tests/ui/bad_return_impl_future.stderr120
-rw-r--r--embassy-executor/tests/ui/bad_return_impl_future_nightly.rs9
-rw-r--r--embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr10
-rw-r--r--embassy-executor/tests/ui/return_impl_future_nonsend.rs21
-rw-r--r--embassy-executor/tests/ui/return_impl_future_nonsend.stderr17
-rw-r--r--embassy-executor/tests/ui/return_impl_send.rs6
-rw-r--r--embassy-executor/tests/ui/return_impl_send.stderr137
-rw-r--r--embassy-executor/tests/ui/return_impl_send_nightly.rs6
-rw-r--r--embassy-executor/tests/ui/return_impl_send_nightly.stderr10
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.rs16
-rw-r--r--embassy-executor/tests/ui/spawn_nonsend.stderr41
21 files changed, 546 insertions, 39 deletions
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 608c67724..914863a83 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -5,9 +5,22 @@ All notable changes to this project will be documented in this file.
5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 5The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 6and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7 7
8## unreleased 8<!-- next-header -->
9 9## Unreleased - ReleaseDate
10
11- Added `SpawnToken::id`
12- Task pools are now statically allocated on stable rust. All `task-arena-size-*` features have been removed and are no longer necessary.
13- New trace hooks: `_embassy_trace_poll_start` & `_embassy_trace_task_end`
14- Added task naming capability to tracing infrastructure
15- Added `Executor::id` & `Spawner::executor_id`
16- Disable `critical-section/std` for arch-std
17- Added possibility to select an executor in `#[embassy_executor::main]`
18- Fix AVR executor
19- executor: Make state implementations and their conditions match
10- Added support for Cortex-A and Cortex-R 20- Added support for Cortex-A and Cortex-R
21- Added support for `-> impl Future<Output = ()>` in `#[task]`
22- Fixed `Send` unsoundness with `-> impl Future` tasks
23- Marked `Spawner::for_current_executor` as `unsafe`
11 24
12## 0.7.0 - 2025-01-02 25## 0.7.0 - 2025-01-02
13 26
diff --git a/embassy-executor/Cargo.toml b/embassy-executor/Cargo.toml
index f014ccf30..2dbf2c29a 100644
--- a/embassy-executor/Cargo.toml
+++ b/embassy-executor/Cargo.toml
@@ -59,6 +59,7 @@ avr-device = { version = "0.7.0", optional = true }
59critical-section = { version = "1.1", features = ["std"] } 59critical-section = { version = "1.1", features = ["std"] }
60trybuild = "1.0" 60trybuild = "1.0"
61embassy-sync = { path = "../embassy-sync" } 61embassy-sync = { path = "../embassy-sync" }
62rustversion = "1.0.21"
62 63
63[features] 64[features]
64 65
diff --git a/embassy-executor/build_common.rs b/embassy-executor/build_common.rs
index b15a8369f..4f24e6d37 100644
--- a/embassy-executor/build_common.rs
+++ b/embassy-executor/build_common.rs
@@ -92,35 +92,3 @@ pub fn set_target_cfgs(cfgs: &mut CfgSet) {
92 92
93 cfgs.set("has_fpu", target.ends_with("-eabihf")); 93 cfgs.set("has_fpu", target.ends_with("-eabihf"));
94} 94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
97pub struct CompilerDate {
98 year: u16,
99 month: u8,
100 day: u8,
101}
102
103impl CompilerDate {
104 fn parse(date: &str) -> Option<Self> {
105 let mut parts = date.split('-');
106 let year = parts.next()?.parse().ok()?;
107 let month = parts.next()?.parse().ok()?;
108 let day = parts.next()?.parse().ok()?;
109 Some(Self { year, month, day })
110 }
111}
112
113impl PartialEq<&str> for CompilerDate {
114 fn eq(&self, other: &&str) -> bool {
115 let Some(other) = Self::parse(other) else {
116 return false;
117 };
118 self.eq(&other)
119 }
120}
121
122impl PartialOrd<&str> for CompilerDate {
123 fn partial_cmp(&self, other: &&str) -> Option<std::cmp::Ordering> {
124 Self::parse(other).map(|other| self.cmp(&other))
125 }
126}
diff --git a/embassy-executor/release.toml b/embassy-executor/release.toml
new file mode 100644
index 000000000..fb6feaf21
--- /dev/null
+++ b/embassy-executor/release.toml
@@ -0,0 +1,5 @@
1pre-release-replacements = [
2 {file="CHANGELOG.md", search="Unreleased", replace="{{version}}", min=1},
3 {file="CHANGELOG.md", search="ReleaseDate", replace="{{date}}", min=1},
4 {file="CHANGELOG.md", search="<!-- next-header -->", replace="<!-- next-header -->\n## Unreleased - ReleaseDate\n", exactly=1},
5]
diff --git a/embassy-executor/src/lib.rs b/embassy-executor/src/lib.rs
index dfe420bab..e174a0594 100644
--- a/embassy-executor/src/lib.rs
+++ b/embassy-executor/src/lib.rs
@@ -65,8 +65,17 @@ pub mod _export {
65 65
66 use crate::raw::TaskPool; 66 use crate::raw::TaskPool;
67 67
68 trait TaskReturnValue {}
69 impl TaskReturnValue for () {}
70 impl TaskReturnValue for Never {}
71
72 #[diagnostic::on_unimplemented(
73 message = "task futures must resolve to `()` or `!`",
74 note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
75 )]
76 #[allow(private_bounds)]
68 pub trait TaskFn<Args>: Copy { 77 pub trait TaskFn<Args>: Copy {
69 type Fut: Future + 'static; 78 type Fut: Future<Output: TaskReturnValue> + 'static;
70 } 79 }
71 80
72 macro_rules! task_fn_impl { 81 macro_rules! task_fn_impl {
@@ -74,7 +83,7 @@ pub mod _export {
74 impl<F, Fut, $($Tn,)*> TaskFn<($($Tn,)*)> for F 83 impl<F, Fut, $($Tn,)*> TaskFn<($($Tn,)*)> for F
75 where 84 where
76 F: Copy + FnOnce($($Tn,)*) -> Fut, 85 F: Copy + FnOnce($($Tn,)*) -> Fut,
77 Fut: Future + 'static, 86 Fut: Future<Output: TaskReturnValue> + 'static,
78 { 87 {
79 type Fut = Fut; 88 type Fut = Fut;
80 } 89 }
@@ -205,4 +214,42 @@ pub mod _export {
205 Align268435456: 268435456, 214 Align268435456: 268435456,
206 Align536870912: 536870912, 215 Align536870912: 536870912,
207 ); 216 );
217
218 #[allow(dead_code)]
219 trait HasOutput {
220 type Output;
221 }
222
223 impl<O> HasOutput for fn() -> O {
224 type Output = O;
225 }
226
227 #[allow(dead_code)]
228 type Never = <fn() -> ! as HasOutput>::Output;
229}
230
231/// Implementation details for embassy macros.
232/// Do not use. Used for macros and HALs only. Not covered by semver guarantees.
233#[doc(hidden)]
234#[cfg(feature = "nightly")]
235pub mod _export {
236 #[diagnostic::on_unimplemented(
237 message = "task futures must resolve to `()` or `!`",
238 note = "use `async fn` or change the return type to `impl Future<Output = ()>`"
239 )]
240 pub trait TaskReturnValue {}
241 impl TaskReturnValue for () {}
242 impl TaskReturnValue for Never {}
243
244 #[allow(dead_code)]
245 trait HasOutput {
246 type Output;
247 }
248
249 impl<O> HasOutput for fn() -> O {
250 type Output = O;
251 }
252
253 #[allow(dead_code)]
254 type Never = <fn() -> ! as HasOutput>::Output;
208} 255}
diff --git a/embassy-executor/src/raw/trace.rs b/embassy-executor/src/raw/trace.rs
index 6c9cfda25..aa27ab37e 100644
--- a/embassy-executor/src/raw/trace.rs
+++ b/embassy-executor/src/raw/trace.rs
@@ -283,7 +283,17 @@ pub(crate) fn task_new(executor: &SyncExecutor, task: &TaskRef) {
283 } 283 }
284 284
285 #[cfg(feature = "rtos-trace")] 285 #[cfg(feature = "rtos-trace")]
286 rtos_trace::trace::task_new(task.as_ptr() as u32); 286 {
287 rtos_trace::trace::task_new(task.as_ptr() as u32);
288 let name = task.name().unwrap_or("unnamed task\0");
289 let info = rtos_trace::TaskInfo {
290 name,
291 priority: 0,
292 stack_base: 0,
293 stack_size: 0,
294 };
295 rtos_trace::trace::task_send_info(task.id(), info);
296 }
287 297
288 #[cfg(feature = "rtos-trace")] 298 #[cfg(feature = "rtos-trace")]
289 TASK_TRACKER.add(*task); 299 TASK_TRACKER.add(*task);
diff --git a/embassy-executor/src/spawner.rs b/embassy-executor/src/spawner.rs
index 522d97db3..2909d19a0 100644
--- a/embassy-executor/src/spawner.rs
+++ b/embassy-executor/src/spawner.rs
@@ -122,10 +122,26 @@ impl Spawner {
122 /// This function is `async` just to get access to the current async 122 /// This function is `async` just to get access to the current async
123 /// context. It returns instantly, it does not block/yield. 123 /// context. It returns instantly, it does not block/yield.
124 /// 124 ///
125 /// Using this method is discouraged due to it being unsafe. Consider the following
126 /// alternatives instead:
127 ///
128 /// - Pass the initial `Spawner` as an argument to tasks. Note that it's `Copy`, so you can
129 /// make as many copies of it as you want.
130 /// - Use `SendSpawner::for_current_executor()` instead, which is safe but can only be used
131 /// if task arguments are `Send`.
132 ///
133 /// The only case where using this method is absolutely required is obtaining the `Spawner`
134 /// for an `InterruptExecutor`.
135 ///
136 /// # Safety
137 ///
138 /// You must only execute this with an async `Context` created by the Embassy executor.
139 /// You must not execute it with manually-created `Context`s.
140 ///
125 /// # Panics 141 /// # Panics
126 /// 142 ///
127 /// Panics if the current executor is not an Embassy executor. 143 /// Panics if the current executor is not an Embassy executor.
128 pub fn for_current_executor() -> impl Future<Output = Self> { 144 pub unsafe fn for_current_executor() -> impl Future<Output = Self> {
129 poll_fn(|cx| { 145 poll_fn(|cx| {
130 let task = raw::task_from_waker(cx.waker()); 146 let task = raw::task_from_waker(cx.waker());
131 let executor = unsafe { 147 let executor = unsafe {
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 78c49c071..c1e7ec5d7 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -1,7 +1,8 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))] 1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2#![cfg_attr(feature = "nightly", feature(never_type))]
2 3
3use std::boxed::Box; 4use std::boxed::Box;
4use std::future::poll_fn; 5use std::future::{poll_fn, Future};
5use std::sync::{Arc, Mutex}; 6use std::sync::{Arc, Mutex};
6use std::task::Poll; 7use std::task::Poll;
7 8
@@ -58,6 +59,39 @@ fn executor_task() {
58 trace.push("poll task1") 59 trace.push("poll task1")
59 } 60 }
60 61
62 #[task]
63 async fn task2() -> ! {
64 panic!()
65 }
66
67 let (executor, trace) = setup();
68 executor.spawner().spawn(task1(trace.clone())).unwrap();
69
70 unsafe { executor.poll() };
71 unsafe { executor.poll() };
72
73 assert_eq!(
74 trace.get(),
75 &[
76 "pend", // spawning a task pends the executor
77 "poll task1", // poll only once.
78 ]
79 )
80}
81
82#[test]
83fn executor_task_rpit() {
84 #[task]
85 fn task1(trace: Trace) -> impl Future<Output = ()> {
86 async move { trace.push("poll task1") }
87 }
88
89 #[cfg(feature = "nightly")]
90 #[task]
91 fn task2() -> impl Future<Output = !> {
92 async { panic!() }
93 }
94
61 let (executor, trace) = setup(); 95 let (executor, trace) = setup();
62 executor.spawner().spawn(task1(trace.clone())).unwrap(); 96 executor.spawner().spawn(task1(trace.clone())).unwrap();
63 97
diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs
index 278a4b903..7757775ee 100644
--- a/embassy-executor/tests/ui.rs
+++ b/embassy-executor/tests/ui.rs
@@ -17,6 +17,17 @@ fn ui() {
17 t.compile_fail("tests/ui/nonstatic_struct_elided.rs"); 17 t.compile_fail("tests/ui/nonstatic_struct_elided.rs");
18 t.compile_fail("tests/ui/nonstatic_struct_generic.rs"); 18 t.compile_fail("tests/ui/nonstatic_struct_generic.rs");
19 t.compile_fail("tests/ui/not_async.rs"); 19 t.compile_fail("tests/ui/not_async.rs");
20 t.compile_fail("tests/ui/spawn_nonsend.rs");
21 t.compile_fail("tests/ui/return_impl_future_nonsend.rs");
22 if rustversion::cfg!(stable) {
23 // output is slightly different on nightly
24 t.compile_fail("tests/ui/bad_return_impl_future.rs");
25 t.compile_fail("tests/ui/return_impl_send.rs");
26 }
27 if cfg!(feature = "nightly") {
28 t.compile_fail("tests/ui/bad_return_impl_future_nightly.rs");
29 t.compile_fail("tests/ui/return_impl_send_nightly.rs");
30 }
20 t.compile_fail("tests/ui/self_ref.rs"); 31 t.compile_fail("tests/ui/self_ref.rs");
21 t.compile_fail("tests/ui/self.rs"); 32 t.compile_fail("tests/ui/self.rs");
22 t.compile_fail("tests/ui/type_error.rs"); 33 t.compile_fail("tests/ui/type_error.rs");
diff --git a/embassy-executor/tests/ui/bad_return_impl_future.rs b/embassy-executor/tests/ui/bad_return_impl_future.rs
new file mode 100644
index 000000000..baaa7dc5a
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future.rs
@@ -0,0 +1,9 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2use core::future::Future;
3
4#[embassy_executor::task]
5fn task() -> impl Future<Output = u32> {
6 async { 5 }
7}
8
9fn main() {}
diff --git a/embassy-executor/tests/ui/bad_return_impl_future.stderr b/embassy-executor/tests/ui/bad_return_impl_future.stderr
new file mode 100644
index 000000000..57f147714
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future.stderr
@@ -0,0 +1,120 @@
1error[E0277]: task futures must resolve to `()` or `!`
2 --> tests/ui/bad_return_impl_future.rs:5:4
3 |
44 | #[embassy_executor::task]
5 | ------------------------- required by a bound introduced by this call
65 | fn task() -> impl Future<Output = u32> {
7 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
8 |
9 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
10note: required by a bound in `task_pool_size`
11 --> src/lib.rs
12 |
13 | pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
14 | -------------- required by a bound in this function
15 | where
16 | F: TaskFn<Args, Fut = Fut>,
17 | ^^^^^^^^^ required by this bound in `task_pool_size`
18
19error[E0277]: task futures must resolve to `()` or `!`
20 --> tests/ui/bad_return_impl_future.rs:4:1
21 |
224 | #[embassy_executor::task]
23 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
24 |
25 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
26note: required by a bound in `task_pool_size`
27 --> src/lib.rs
28 |
29 | pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
30 | -------------- required by a bound in this function
31 | where
32 | F: TaskFn<Args, Fut = Fut>,
33 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_size`
34 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
35
36error[E0277]: task futures must resolve to `()` or `!`
37 --> tests/ui/bad_return_impl_future.rs:5:4
38 |
394 | #[embassy_executor::task]
40 | ------------------------- required by a bound introduced by this call
415 | fn task() -> impl Future<Output = u32> {
42 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
43 |
44 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
45note: required by a bound in `task_pool_align`
46 --> src/lib.rs
47 |
48 | pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
49 | --------------- required by a bound in this function
50 | where
51 | F: TaskFn<Args, Fut = Fut>,
52 | ^^^^^^^^^ required by this bound in `task_pool_align`
53
54error[E0277]: task futures must resolve to `()` or `!`
55 --> tests/ui/bad_return_impl_future.rs:4:1
56 |
574 | #[embassy_executor::task]
58 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
59 |
60 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
61note: required by a bound in `task_pool_align`
62 --> src/lib.rs
63 |
64 | pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
65 | --------------- required by a bound in this function
66 | where
67 | F: TaskFn<Args, Fut = Fut>,
68 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_align`
69 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
70
71error[E0277]: task futures must resolve to `()` or `!`
72 --> tests/ui/bad_return_impl_future.rs:5:4
73 |
744 | #[embassy_executor::task]
75 | ------------------------- required by a bound introduced by this call
765 | fn task() -> impl Future<Output = u32> {
77 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
78 |
79 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
80note: required by a bound in `__task_pool_get`
81 --> tests/ui/bad_return_impl_future.rs:4:1
82 |
834 | #[embassy_executor::task]
84 | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `__task_pool_get`
85 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
86
87error[E0277]: task futures must resolve to `()` or `!`
88 --> tests/ui/bad_return_impl_future.rs:5:4
89 |
904 | #[embassy_executor::task]
91 | ------------------------- required by a bound introduced by this call
925 | fn task() -> impl Future<Output = u32> {
93 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
94 |
95 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
96note: required by a bound in `task_pool_new`
97 --> src/lib.rs
98 |
99 | pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
100 | ------------- required by a bound in this function
101 | where
102 | F: TaskFn<Args, Fut = Fut>,
103 | ^^^^^^^^^ required by this bound in `task_pool_new`
104
105error[E0277]: task futures must resolve to `()` or `!`
106 --> tests/ui/bad_return_impl_future.rs:4:1
107 |
1084 | #[embassy_executor::task]
109 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Future<Output = u32> {__task_task}`
110 |
111 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
112note: required by a bound in `task_pool_new`
113 --> src/lib.rs
114 |
115 | pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
116 | ------------- required by a bound in this function
117 | where
118 | F: TaskFn<Args, Fut = Fut>,
119 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_new`
120 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs b/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs
new file mode 100644
index 000000000..baaa7dc5a
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future_nightly.rs
@@ -0,0 +1,9 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2use core::future::Future;
3
4#[embassy_executor::task]
5fn task() -> impl Future<Output = u32> {
6 async { 5 }
7}
8
9fn main() {}
diff --git a/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
new file mode 100644
index 000000000..73ceb989d
--- /dev/null
+++ b/embassy-executor/tests/ui/bad_return_impl_future_nightly.stderr
@@ -0,0 +1,10 @@
1error[E0277]: task futures must resolve to `()` or `!`
2 --> tests/ui/bad_return_impl_future_nightly.rs:4:1
3 |
44 | #[embassy_executor::task]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskReturnValue` is not implemented for `u32`
6 |
7 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
8 = help: the following other types implement trait `TaskReturnValue`:
9 ()
10 <fn() -> ! as _export::HasOutput>::Output
diff --git a/embassy-executor/tests/ui/return_impl_future_nonsend.rs b/embassy-executor/tests/ui/return_impl_future_nonsend.rs
new file mode 100644
index 000000000..b8c184b21
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_future_nonsend.rs
@@ -0,0 +1,21 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2
3use core::future::Future;
4
5use embassy_executor::SendSpawner;
6
7#[embassy_executor::task]
8fn task() -> impl Future<Output = ()> {
9 // runs in spawning thread
10 let non_send: *mut () = core::ptr::null_mut();
11 async move {
12 // runs in executor thread
13 println!("{}", non_send as usize);
14 }
15}
16
17fn send_spawn(s: SendSpawner) {
18 s.spawn(task()).unwrap();
19}
20
21fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_future_nonsend.stderr b/embassy-executor/tests/ui/return_impl_future_nonsend.stderr
new file mode 100644
index 000000000..8aeb9738a
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_future_nonsend.stderr
@@ -0,0 +1,17 @@
1error: future cannot be sent between threads safely
2 --> tests/ui/return_impl_future_nonsend.rs:18:13
3 |
418 | s.spawn(task()).unwrap();
5 | ^^^^^^ future created by async block is not `Send`
6 |
7 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`
8note: captured value is not `Send`
9 --> tests/ui/return_impl_future_nonsend.rs:13:24
10 |
1113 | println!("{}", non_send as usize);
12 | ^^^^^^^^ has type `*mut ()` which is not `Send`
13note: required by a bound in `SendSpawner::spawn`
14 --> src/spawner.rs
15 |
16 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> {
17 | ^^^^ required by this bound in `SendSpawner::spawn`
diff --git a/embassy-executor/tests/ui/return_impl_send.rs b/embassy-executor/tests/ui/return_impl_send.rs
new file mode 100644
index 000000000..6ddb0e722
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send.rs
@@ -0,0 +1,6 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2
3#[embassy_executor::task]
4fn task() -> impl Send {}
5
6fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_send.stderr b/embassy-executor/tests/ui/return_impl_send.stderr
new file mode 100644
index 000000000..759be1cde
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send.stderr
@@ -0,0 +1,137 @@
1error[E0277]: task futures must resolve to `()` or `!`
2 --> tests/ui/return_impl_send.rs:4:4
3 |
43 | #[embassy_executor::task]
5 | ------------------------- required by a bound introduced by this call
64 | fn task() -> impl Send {}
7 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
8 |
9 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
10note: required by a bound in `task_pool_size`
11 --> src/lib.rs
12 |
13 | pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
14 | -------------- required by a bound in this function
15 | where
16 | F: TaskFn<Args, Fut = Fut>,
17 | ^^^^^^^^^ required by this bound in `task_pool_size`
18
19error[E0277]: task futures must resolve to `()` or `!`
20 --> tests/ui/return_impl_send.rs:3:1
21 |
223 | #[embassy_executor::task]
23 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
24 |
25 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
26note: required by a bound in `task_pool_size`
27 --> src/lib.rs
28 |
29 | pub const fn task_pool_size<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
30 | -------------- required by a bound in this function
31 | where
32 | F: TaskFn<Args, Fut = Fut>,
33 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_size`
34 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
35
36error[E0277]: task futures must resolve to `()` or `!`
37 --> tests/ui/return_impl_send.rs:4:4
38 |
393 | #[embassy_executor::task]
40 | ------------------------- required by a bound introduced by this call
414 | fn task() -> impl Send {}
42 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
43 |
44 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
45note: required by a bound in `task_pool_align`
46 --> src/lib.rs
47 |
48 | pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
49 | --------------- required by a bound in this function
50 | where
51 | F: TaskFn<Args, Fut = Fut>,
52 | ^^^^^^^^^ required by this bound in `task_pool_align`
53
54error[E0277]: task futures must resolve to `()` or `!`
55 --> tests/ui/return_impl_send.rs:3:1
56 |
573 | #[embassy_executor::task]
58 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
59 |
60 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
61note: required by a bound in `task_pool_align`
62 --> src/lib.rs
63 |
64 | pub const fn task_pool_align<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> usize
65 | --------------- required by a bound in this function
66 | where
67 | F: TaskFn<Args, Fut = Fut>,
68 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_align`
69 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
70
71error[E0277]: task futures must resolve to `()` or `!`
72 --> tests/ui/return_impl_send.rs:4:4
73 |
743 | #[embassy_executor::task]
75 | ------------------------- required by a bound introduced by this call
764 | fn task() -> impl Send {}
77 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
78 |
79 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
80note: required by a bound in `__task_pool_get`
81 --> tests/ui/return_impl_send.rs:3:1
82 |
833 | #[embassy_executor::task]
84 | ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `__task_pool_get`
85 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
86
87error[E0277]: `impl Send` is not a future
88 --> tests/ui/return_impl_send.rs:3:1
89 |
903 | #[embassy_executor::task]
91 | ^^^^^^^^^^^^^^^^^^^^^^^^^ `impl Send` is not a future
92 |
93 = help: the trait `Future` is not implemented for `impl Send`
94note: required by a bound in `TaskPool::<F, N>::spawn`
95 --> src/raw/mod.rs
96 |
97 | impl<F: Future + 'static, const N: usize> TaskPool<F, N> {
98 | ^^^^^^ required by this bound in `TaskPool::<F, N>::spawn`
99...
100 | pub fn spawn(&'static self, future: impl FnOnce() -> F) -> SpawnToken<impl Sized> {
101 | ----- required by a bound in this associated function
102 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
103
104error[E0277]: task futures must resolve to `()` or `!`
105 --> tests/ui/return_impl_send.rs:4:4
106 |
1073 | #[embassy_executor::task]
108 | ------------------------- required by a bound introduced by this call
1094 | fn task() -> impl Send {}
110 | ^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
111 |
112 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
113note: required by a bound in `task_pool_new`
114 --> src/lib.rs
115 |
116 | pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
117 | ------------- required by a bound in this function
118 | where
119 | F: TaskFn<Args, Fut = Fut>,
120 | ^^^^^^^^^ required by this bound in `task_pool_new`
121
122error[E0277]: task futures must resolve to `()` or `!`
123 --> tests/ui/return_impl_send.rs:3:1
124 |
1253 | #[embassy_executor::task]
126 | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `TaskFn<_>` is not implemented for fn item `fn() -> impl Send {__task_task}`
127 |
128 = note: use `async fn` or change the return type to `impl Future<Output = ()>`
129note: required by a bound in `task_pool_new`
130 --> src/lib.rs
131 |
132 | pub const fn task_pool_new<F, Args, Fut, const POOL_SIZE: usize>(_: F) -> TaskPool<Fut, POOL_SIZE>
133 | ------------- required by a bound in this function
134 | where
135 | F: TaskFn<Args, Fut = Fut>,
136 | ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `task_pool_new`
137 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/embassy-executor/tests/ui/return_impl_send_nightly.rs b/embassy-executor/tests/ui/return_impl_send_nightly.rs
new file mode 100644
index 000000000..6ddb0e722
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send_nightly.rs
@@ -0,0 +1,6 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2
3#[embassy_executor::task]
4fn task() -> impl Send {}
5
6fn main() {}
diff --git a/embassy-executor/tests/ui/return_impl_send_nightly.stderr b/embassy-executor/tests/ui/return_impl_send_nightly.stderr
new file mode 100644
index 000000000..de9ba6243
--- /dev/null
+++ b/embassy-executor/tests/ui/return_impl_send_nightly.stderr
@@ -0,0 +1,10 @@
1error[E0277]: `impl Send` is not a future
2 --> tests/ui/return_impl_send_nightly.rs:3:1
3 |
43 | #[embassy_executor::task]
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^
6 | |
7 | `impl Send` is not a future
8 | return type was inferred to be `impl Send` here
9 |
10 = help: the trait `Future` is not implemented for `impl Send`
diff --git a/embassy-executor/tests/ui/spawn_nonsend.rs b/embassy-executor/tests/ui/spawn_nonsend.rs
new file mode 100644
index 000000000..4c4cc7697
--- /dev/null
+++ b/embassy-executor/tests/ui/spawn_nonsend.rs
@@ -0,0 +1,16 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2
3use core::future::Future;
4
5use embassy_executor::SendSpawner;
6
7#[embassy_executor::task]
8async fn task(non_send: *mut ()) {
9 println!("{}", non_send as usize);
10}
11
12fn send_spawn(s: SendSpawner) {
13 s.spawn(task(core::ptr::null_mut())).unwrap();
14}
15
16fn main() {}
diff --git a/embassy-executor/tests/ui/spawn_nonsend.stderr b/embassy-executor/tests/ui/spawn_nonsend.stderr
new file mode 100644
index 000000000..2a06c8b94
--- /dev/null
+++ b/embassy-executor/tests/ui/spawn_nonsend.stderr
@@ -0,0 +1,41 @@
1warning: unused import: `core::future::Future`
2 --> tests/ui/spawn_nonsend.rs:3:5
3 |
43 | use core::future::Future;
5 | ^^^^^^^^^^^^^^^^^^^^
6 |
7 = note: `#[warn(unused_imports)]` on by default
8
9error[E0277]: `*mut ()` cannot be sent between threads safely
10 --> tests/ui/spawn_nonsend.rs:13:13
11 |
127 | #[embassy_executor::task]
13 | ------------------------- within this `impl Sized`
14...
1513 | s.spawn(task(core::ptr::null_mut())).unwrap();
16 | ----- ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut ()` cannot be sent between threads safely
17 | |
18 | required by a bound introduced by this call
19 |
20 = help: within `impl Sized`, the trait `Send` is not implemented for `*mut ()`
21note: required because it's used within this closure
22 --> tests/ui/spawn_nonsend.rs:7:1
23 |
247 | #[embassy_executor::task]
25 | ^^^^^^^^^^^^^^^^^^^^^^^^^
26note: required because it appears within the type `impl Sized`
27 --> src/raw/mod.rs
28 |
29 | pub unsafe fn _spawn_async_fn<FutFn>(&'static self, future: FutFn) -> SpawnToken<impl Sized>
30 | ^^^^^^^^^^
31note: required because it appears within the type `impl Sized`
32 --> tests/ui/spawn_nonsend.rs:7:1
33 |
347 | #[embassy_executor::task]
35 | ^^^^^^^^^^^^^^^^^^^^^^^^^
36note: required by a bound in `SendSpawner::spawn`
37 --> src/spawner.rs
38 |
39 | pub fn spawn<S: Send>(&self, token: SpawnToken<S>) -> Result<(), SpawnError> {
40 | ^^^^ required by this bound in `SendSpawner::spawn`
41 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)