aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrezak <[email protected]>2025-07-22 20:56:46 +0200
committerBrezak <[email protected]>2025-07-23 19:19:02 +0200
commita52965dc5d3d0c706310998d3eda8bc15cd45b02 (patch)
tree64087a9a6391c6ded8c7ddfb06652152b1b0759e
parenta5984a8298491ea748693783275d95286a481394 (diff)
embassy-executor: unsafe tasks as unsafe
-rw-r--r--embassy-executor-macros/src/macros/task.rs15
-rw-r--r--embassy-executor/CHANGELOG.md1
-rw-r--r--embassy-executor/tests/ui.rs1
-rw-r--r--embassy-executor/tests/ui/task_safety_attribute.rs25
4 files changed, 41 insertions, 1 deletions
diff --git a/embassy-executor-macros/src/macros/task.rs b/embassy-executor-macros/src/macros/task.rs
index 1c5e3571d..f01cc3b6c 100644
--- a/embassy-executor-macros/src/macros/task.rs
+++ b/embassy-executor-macros/src/macros/task.rs
@@ -120,6 +120,18 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
120 task_inner.vis = syn::Visibility::Inherited; 120 task_inner.vis = syn::Visibility::Inherited;
121 task_inner.sig.ident = task_inner_ident.clone(); 121 task_inner.sig.ident = task_inner_ident.clone();
122 122
123 // Forcefully mark the inner task as safe.
124 // SAFETY: We only ever call task_inner in functions
125 // with the same safety preconditions as task_inner
126 task_inner.sig.unsafety = None;
127 let task_body = task_inner.body;
128 task_inner.body = quote! {
129 #[allow(unused_unsafe, reason = "Not all function bodies may require being in an unsafe block")]
130 unsafe {
131 #task_body
132 }
133 };
134
123 // assemble the original input arguments, 135 // assemble the original input arguments,
124 // including any attributes that may have 136 // including any attributes that may have
125 // been applied previously 137 // been applied previously
@@ -186,6 +198,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
186 // Copy the generics + where clause to avoid more spurious errors. 198 // Copy the generics + where clause to avoid more spurious errors.
187 let generics = &f.sig.generics; 199 let generics = &f.sig.generics;
188 let where_clause = &f.sig.generics.where_clause; 200 let where_clause = &f.sig.generics.where_clause;
201 let unsafety = &f.sig.unsafety;
189 202
190 let result = quote! { 203 let result = quote! {
191 // This is the user's task function, renamed. 204 // This is the user's task function, renamed.
@@ -196,7 +209,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
196 #task_inner 209 #task_inner
197 210
198 #(#task_outer_attrs)* 211 #(#task_outer_attrs)*
199 #visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{ 212 #visibility #unsafety fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{
200 #task_outer_body 213 #task_outer_body
201 } 214 }
202 215
diff --git a/embassy-executor/CHANGELOG.md b/embassy-executor/CHANGELOG.md
index 914863a83..7404961f3 100644
--- a/embassy-executor/CHANGELOG.md
+++ b/embassy-executor/CHANGELOG.md
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
21- Added support for `-> impl Future<Output = ()>` in `#[task]` 21- Added support for `-> impl Future<Output = ()>` in `#[task]`
22- Fixed `Send` unsoundness with `-> impl Future` tasks 22- Fixed `Send` unsoundness with `-> impl Future` tasks
23- Marked `Spawner::for_current_executor` as `unsafe` 23- Marked `Spawner::for_current_executor` as `unsafe`
24- `#[task]` now properly marks the generated function as unsafe if the task is marked unsafe
24 25
25## 0.7.0 - 2025-01-02 26## 0.7.0 - 2025-01-02
26 27
diff --git a/embassy-executor/tests/ui.rs b/embassy-executor/tests/ui.rs
index 7757775ee..8b83cd368 100644
--- a/embassy-executor/tests/ui.rs
+++ b/embassy-executor/tests/ui.rs
@@ -32,4 +32,5 @@ fn ui() {
32 t.compile_fail("tests/ui/self.rs"); 32 t.compile_fail("tests/ui/self.rs");
33 t.compile_fail("tests/ui/type_error.rs"); 33 t.compile_fail("tests/ui/type_error.rs");
34 t.compile_fail("tests/ui/where_clause.rs"); 34 t.compile_fail("tests/ui/where_clause.rs");
35 t.pass("tests/ui/task_safety_attribute.rs");
35} 36}
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}