aboutsummaryrefslogtreecommitdiff
path: root/embassy-executor/tests
diff options
context:
space:
mode:
author1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
committer1-rafael-1 <[email protected]>2025-09-15 20:07:18 +0200
commit6bb3d2c0720fa082f27d3cdb70f516058497ec87 (patch)
tree5a1e255cff999b00800f203b91a759c720c973e5 /embassy-executor/tests
parenteb685574601d98c44faed9a3534d056199b46e20 (diff)
parent92a6fd2946f2cbb15359290f68aa360953da2ff7 (diff)
Merge branch 'main' into rp2040-rtc-alarm
Diffstat (limited to 'embassy-executor/tests')
-rw-r--r--embassy-executor/tests/test.rs93
-rw-r--r--embassy-executor/tests/ui.rs14
-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/nonstatic_struct_elided.stderr14
-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
-rw-r--r--embassy-executor/tests/ui/task_safety_attribute.rs25
-rw-r--r--embassy-executor/tests/ui/unsafe_op_in_unsafe_task.rs10
-rw-r--r--embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr18
18 files changed, 566 insertions, 10 deletions
diff --git a/embassy-executor/tests/test.rs b/embassy-executor/tests/test.rs
index 78c49c071..6baf3dc21 100644
--- a/embassy-executor/tests/test.rs
+++ b/embassy-executor/tests/test.rs
@@ -1,12 +1,13 @@
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
8use embassy_executor::raw::Executor; 9use embassy_executor::raw::Executor;
9use embassy_executor::task; 10use embassy_executor::{task, Spawner};
10 11
11#[export_name = "__pender"] 12#[export_name = "__pender"]
12fn __pender(context: *mut ()) { 13fn __pender(context: *mut ()) {
@@ -58,8 +59,41 @@ 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
61 let (executor, trace) = setup(); 67 let (executor, trace) = setup();
62 executor.spawner().spawn(task1(trace.clone())).unwrap(); 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
95 let (executor, trace) = setup();
96 executor.spawner().spawn(task1(trace.clone()).unwrap());
63 97
64 unsafe { executor.poll() }; 98 unsafe { executor.poll() };
65 unsafe { executor.poll() }; 99 unsafe { executor.poll() };
@@ -86,7 +120,7 @@ fn executor_task_self_wake() {
86 } 120 }
87 121
88 let (executor, trace) = setup(); 122 let (executor, trace) = setup();
89 executor.spawner().spawn(task1(trace.clone())).unwrap(); 123 executor.spawner().spawn(task1(trace.clone()).unwrap());
90 124
91 unsafe { executor.poll() }; 125 unsafe { executor.poll() };
92 unsafe { executor.poll() }; 126 unsafe { executor.poll() };
@@ -118,7 +152,7 @@ fn executor_task_self_wake_twice() {
118 } 152 }
119 153
120 let (executor, trace) = setup(); 154 let (executor, trace) = setup();
121 executor.spawner().spawn(task1(trace.clone())).unwrap(); 155 executor.spawner().spawn(task1(trace.clone()).unwrap());
122 156
123 unsafe { executor.poll() }; 157 unsafe { executor.poll() };
124 unsafe { executor.poll() }; 158 unsafe { executor.poll() };
@@ -154,7 +188,7 @@ fn waking_after_completion_does_not_poll() {
154 let waker = Box::leak(Box::new(AtomicWaker::new())); 188 let waker = Box::leak(Box::new(AtomicWaker::new()));
155 189
156 let (executor, trace) = setup(); 190 let (executor, trace) = setup();
157 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 191 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
158 192
159 unsafe { executor.poll() }; 193 unsafe { executor.poll() };
160 waker.wake(); 194 waker.wake();
@@ -166,7 +200,7 @@ fn waking_after_completion_does_not_poll() {
166 unsafe { executor.poll() }; // Clears running status 200 unsafe { executor.poll() }; // Clears running status
167 201
168 // Can respawn waken-but-dead task 202 // Can respawn waken-but-dead task
169 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 203 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
170 204
171 unsafe { executor.poll() }; 205 unsafe { executor.poll() };
172 206
@@ -216,7 +250,7 @@ fn waking_with_old_waker_after_respawn() {
216 let waker = Box::leak(Box::new(AtomicWaker::new())); 250 let waker = Box::leak(Box::new(AtomicWaker::new()));
217 251
218 let (executor, trace) = setup(); 252 let (executor, trace) = setup();
219 executor.spawner().spawn(task1(trace.clone(), waker)).unwrap(); 253 executor.spawner().spawn(task1(trace.clone(), waker).unwrap());
220 254
221 unsafe { executor.poll() }; 255 unsafe { executor.poll() };
222 unsafe { executor.poll() }; // progress to registering the waker 256 unsafe { executor.poll() }; // progress to registering the waker
@@ -239,8 +273,7 @@ fn waking_with_old_waker_after_respawn() {
239 let (other_executor, other_trace) = setup(); 273 let (other_executor, other_trace) = setup();
240 other_executor 274 other_executor
241 .spawner() 275 .spawner()
242 .spawn(task1(other_trace.clone(), waker)) 276 .spawn(task1(other_trace.clone(), waker).unwrap());
243 .unwrap();
244 277
245 unsafe { other_executor.poll() }; // just run to the yield_now 278 unsafe { other_executor.poll() }; // just run to the yield_now
246 waker.wake(); // trigger old waker registration 279 waker.wake(); // trigger old waker registration
@@ -283,3 +316,43 @@ fn executor_task_cfg_args() {
283 let (_, _, _) = (a, b, c); 316 let (_, _, _) = (a, b, c);
284 } 317 }
285} 318}
319
320#[test]
321fn recursive_task() {
322 #[embassy_executor::task(pool_size = 2)]
323 async fn task1() {
324 let spawner = unsafe { Spawner::for_current_executor().await };
325 spawner.spawn(task1().unwrap());
326 }
327}
328
329#[cfg(feature = "metadata-name")]
330#[test]
331fn task_metadata() {
332 #[task]
333 async fn task1(expected_name: Option<&'static str>) {
334 use embassy_executor::Metadata;
335 assert_eq!(Metadata::for_current_task().await.name(), expected_name);
336 }
337
338 // check no task name
339 let (executor, _) = setup();
340 executor.spawner().spawn(task1(None).unwrap());
341 unsafe { executor.poll() };
342
343 // check setting task name
344 let token = task1(Some("foo")).unwrap();
345 token.metadata().set_name("foo");
346 executor.spawner().spawn(token);
347 unsafe { executor.poll() };
348
349 let token = task1(Some("bar")).unwrap();
350 token.metadata().set_name("bar");
351 executor.spawner().spawn(token);
352 unsafe { executor.poll() };
353
354 // check name is cleared if the task pool slot is recycled.
355 let (executor, _) = setup();
356 executor.spawner().spawn(task1(None).unwrap());
357 unsafe { executor.poll() };
358}
diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs
index 278a4b903..5486a0624 100644
--- a/embassy-executor/tests/ui.rs
+++ b/embassy-executor/tests/ui.rs
@@ -17,8 +17,22 @@ 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");
23 t.compile_fail("tests/ui/where_clause.rs"); 34 t.compile_fail("tests/ui/where_clause.rs");
35 t.compile_fail("tests/ui/unsafe_op_in_unsafe_task.rs");
36
37 t.pass("tests/ui/task_safety_attribute.rs");
24} 38}
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..3c3c9503b
--- /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 HasOutput>::Output
diff --git a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr
index 099ef8b4e..0ee1bfe0c 100644
--- a/embassy-executor/tests/ui/nonstatic_struct_elided.stderr
+++ b/embassy-executor/tests/ui/nonstatic_struct_elided.stderr
@@ -8,3 +8,17 @@ help: indicate the anonymous lifetime
8 | 8 |
96 | async fn task(_x: Foo<'_>) {} 96 | async fn task(_x: Foo<'_>) {}
10 | ++++ 10 | ++++
11
12error[E0700]: hidden type for `impl Sized` captures lifetime that does not appear in bounds
13 --> tests/ui/nonstatic_struct_elided.rs:5:1
14 |
155 | #[embassy_executor::task]
16 | ^^^^^^^^^^^^^^^^^^^^^^^^^ opaque type defined here
176 | async fn task(_x: Foo) {}
18 | --- hidden type `impl Sized` captures the anonymous lifetime defined here
19 |
20 = note: this error originates in the attribute macro `embassy_executor::task` (in Nightly builds, run with -Z macro-backtrace for more info)
21help: add a `use<...>` bound to explicitly capture `'_`
22 |
235 | #[embassy_executor::task] + use<'_>
24 | +++++++++
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..77b3119d6
--- /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..51944ad65
--- /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>) {
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..5d19465ec
--- /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) -> Result<SpawnToken<impl Sized>, SpawnError> {
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..601041941
--- /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..25bd7d78d
--- /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) -> Result<SpawnToken<impl Sized>, SpawnError>
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>) {
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)
diff --git a/embassy-executor/tests/ui/task_safety_attribute.rs b/embassy-executor/tests/ui/task_safety_attribute.rs
new file mode 100644
index 000000000..ab5a2f99f
--- /dev/null
+++ b/embassy-executor/tests/ui/task_safety_attribute.rs
@@ -0,0 +1,25 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2#![deny(unused_unsafe)]
3
4use std::mem;
5
6#[embassy_executor::task]
7async fn safe() {}
8
9#[embassy_executor::task]
10async unsafe fn not_safe() {}
11
12#[export_name = "__pender"]
13fn pender(_: *mut ()) {
14 // The test doesn't link if we don't include this.
15 // We never call this anyway.
16}
17
18fn main() {
19 let _forget_me = safe();
20 // SAFETY: not_safe has not safety preconditions
21 let _forget_me2 = unsafe { not_safe() };
22
23 mem::forget(_forget_me);
24 mem::forget(_forget_me2);
25}
diff --git a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.rs b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.rs
new file mode 100644
index 000000000..ee7924838
--- /dev/null
+++ b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.rs
@@ -0,0 +1,10 @@
1#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
2#![deny(unsafe_op_in_unsafe_fn)]
3
4#[embassy_executor::task]
5async unsafe fn task() {
6 let x = 5;
7 (&x as *const i32).read();
8}
9
10fn main() {}
diff --git a/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr
new file mode 100644
index 000000000..d987a4b95
--- /dev/null
+++ b/embassy-executor/tests/ui/unsafe_op_in_unsafe_task.stderr
@@ -0,0 +1,18 @@
1error[E0133]: call to unsafe function `std::ptr::const_ptr::<impl *const T>::read` is unsafe and requires unsafe block
2 --> tests/ui/unsafe_op_in_unsafe_task.rs:7:5
3 |
47 | (&x as *const i32).read();
5 | ^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function
6 |
7 = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html>
8 = note: consult the function's documentation for information on how to avoid undefined behavior
9note: an unsafe function restricts its caller, but its body is safe by default
10 --> tests/ui/unsafe_op_in_unsafe_task.rs:5:1
11 |
125 | async unsafe fn task() {
13 | ^^^^^^^^^^^^^^^^^^^^^^
14note: the lint level is defined here
15 --> tests/ui/unsafe_op_in_unsafe_task.rs:2:9
16 |
172 | #![deny(unsafe_op_in_unsafe_fn)]
18 | ^^^^^^^^^^^^^^^^^^^^^^