embassy-executor: unsafe tasks as unsafe

This commit is contained in:
Brezak 2025-07-22 20:56:46 +02:00
parent a5984a8298
commit a52965dc5d
No known key found for this signature in database
GPG Key ID: CB3891E2B1279D7C
4 changed files with 41 additions and 1 deletions

View File

@ -120,6 +120,18 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
task_inner.vis = syn::Visibility::Inherited;
task_inner.sig.ident = task_inner_ident.clone();
// Forcefully mark the inner task as safe.
// SAFETY: We only ever call task_inner in functions
// with the same safety preconditions as task_inner
task_inner.sig.unsafety = None;
let task_body = task_inner.body;
task_inner.body = quote! {
#[allow(unused_unsafe, reason = "Not all function bodies may require being in an unsafe block")]
unsafe {
#task_body
}
};
// assemble the original input arguments,
// including any attributes that may have
// been applied previously
@ -186,6 +198,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
// Copy the generics + where clause to avoid more spurious errors.
let generics = &f.sig.generics;
let where_clause = &f.sig.generics.where_clause;
let unsafety = &f.sig.unsafety;
let result = quote! {
// This is the user's task function, renamed.
@ -196,7 +209,7 @@ pub fn run(args: TokenStream, item: TokenStream) -> TokenStream {
#task_inner
#(#task_outer_attrs)*
#visibility fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{
#visibility #unsafety fn #task_ident #generics (#fargs) -> #embassy_executor::SpawnToken<impl Sized> #where_clause{
#task_outer_body
}

View File

@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for `-> impl Future<Output = ()>` in `#[task]`
- Fixed `Send` unsoundness with `-> impl Future` tasks
- Marked `Spawner::for_current_executor` as `unsafe`
- `#[task]` now properly marks the generated function as unsafe if the task is marked unsafe
## 0.7.0 - 2025-01-02

View File

@ -32,4 +32,5 @@ fn ui() {
t.compile_fail("tests/ui/self.rs");
t.compile_fail("tests/ui/type_error.rs");
t.compile_fail("tests/ui/where_clause.rs");
t.pass("tests/ui/task_safety_attribute.rs");
}

View File

@ -0,0 +1,25 @@
#![cfg_attr(feature = "nightly", feature(impl_trait_in_assoc_type))]
#![deny(unused_unsafe)]
use std::mem;
#[embassy_executor::task]
async fn safe() {}
#[embassy_executor::task]
async unsafe fn not_safe() {}
#[export_name = "__pender"]
fn pender(_: *mut ()) {
// The test doesn't link if we don't include this.
// We never call this anyway.
}
fn main() {
let _forget_me = safe();
// SAFETY: not_safe has not safety preconditions
let _forget_me2 = unsafe { not_safe() };
mem::forget(_forget_me);
mem::forget(_forget_me2);
}