From a614e697d0ab8f45c59e136ad5015cfdedac50c3 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 8 Mar 2023 01:59:06 +0100 Subject: [PATCH 1/3] macros: better validation of function signatures. Fixes #1266 --- embassy-macros/src/macros/main.rs | 21 +++++++++++++++++++++ embassy-macros/src/macros/task.rs | 23 ++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs index 18f7c36c..7af4ef83 100644 --- a/embassy-macros/src/macros/main.rs +++ b/embassy-macros/src/macros/main.rs @@ -1,6 +1,7 @@ use darling::FromMeta; use proc_macro2::TokenStream; use quote::quote; +use syn::{ReturnType, Type}; use crate::util::ctxt::Ctxt; @@ -76,6 +77,26 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Resul if !f.sig.generics.params.is_empty() { ctxt.error_spanned_by(&f.sig, "main function must not be generic"); } + if !f.sig.generics.where_clause.is_none() { + ctxt.error_spanned_by(&f.sig, "main function must not have `where` clauses"); + } + if !f.sig.abi.is_none() { + ctxt.error_spanned_by(&f.sig, "main function must not have an ABI qualifier"); + } + if !f.sig.variadic.is_none() { + ctxt.error_spanned_by(&f.sig, "main function must not be variadic"); + } + match &f.sig.output { + ReturnType::Default => {} + ReturnType::Type(_, ty) => match &**ty { + Type::Tuple(tuple) if tuple.elems.is_empty() => {} + Type::Never(_) => {} + _ => ctxt.error_spanned_by( + &f.sig, + "main function must either not return a value, return `()` or return `!`", + ), + }, + } if fargs.len() != 1 { ctxt.error_spanned_by(&f.sig, "main function must have 1 argument: the spawner."); diff --git a/embassy-macros/src/macros/task.rs b/embassy-macros/src/macros/task.rs index 90d2cd89..9f30cf43 100644 --- a/embassy-macros/src/macros/task.rs +++ b/embassy-macros/src/macros/task.rs @@ -1,7 +1,7 @@ use darling::FromMeta; use proc_macro2::TokenStream; use quote::{format_ident, quote}; -use syn::{parse_quote, ItemFn}; +use syn::{parse_quote, ItemFn, ReturnType, Type}; use crate::util::ctxt::Ctxt; @@ -24,6 +24,27 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn) -> Result {} + ReturnType::Type(_, ty) => match &**ty { + Type::Tuple(tuple) if tuple.elems.is_empty() => {} + Type::Never(_) => {} + _ => ctxt.error_spanned_by( + &f.sig, + "task functions must either not return a value, return `()` or return `!`", + ), + }, + } + if pool_size < 1 { ctxt.error_spanned_by(&f.sig, "pool_size must be 1 or greater"); } From e7a19a97259a5d3055db7164bc162ad7c7035420 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 8 Mar 2023 02:03:39 +0100 Subject: [PATCH 2/3] macros/main: copy fn return to task. This prevents this bad code from compiling. ```rust async fn main(_spawner: Spawner) -> ! { // not really noreturn! } ``` --- embassy-macros/src/macros/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/embassy-macros/src/macros/main.rs b/embassy-macros/src/macros/main.rs index 7af4ef83..6ae77398 100644 --- a/embassy-macros/src/macros/main.rs +++ b/embassy-macros/src/macros/main.rs @@ -105,10 +105,11 @@ pub fn run(args: syn::AttributeArgs, f: syn::ItemFn, main: TokenStream) -> Resul ctxt.check()?; let f_body = f.block; + let out = &f.sig.output; let result = quote! { #[::embassy_executor::task()] - async fn __embassy_main(#fargs) { + async fn __embassy_main(#fargs) #out { #f_body } From b2c6dc45e3d87c7254ac20440998aa9f559ae94e Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Wed, 8 Mar 2023 03:08:59 +0100 Subject: [PATCH 3/3] Fix examples broken by the macro fix. --- examples/stm32f4/src/bin/i2c.rs | 2 +- examples/stm32f4/src/bin/sdmmc.rs | 4 +--- examples/stm32f7/src/bin/eth.rs | 2 +- examples/stm32f7/src/bin/sdmmc.rs | 4 +--- examples/stm32h7/src/bin/eth.rs | 2 +- examples/stm32h7/src/bin/eth_client.rs | 2 +- examples/stm32h7/src/bin/i2c.rs | 2 +- examples/stm32l4/src/bin/i2c.rs | 2 +- examples/stm32l4/src/bin/i2c_blocking_async.rs | 2 +- examples/stm32l4/src/bin/i2c_dma.rs | 2 +- 10 files changed, 10 insertions(+), 14 deletions(-) diff --git a/examples/stm32f4/src/bin/i2c.rs b/examples/stm32f4/src/bin/i2c.rs index 6e51c211..f8ae0890 100644 --- a/examples/stm32f4/src/bin/i2c.rs +++ b/examples/stm32f4/src/bin/i2c.rs @@ -15,7 +15,7 @@ const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); diff --git a/examples/stm32f4/src/bin/sdmmc.rs b/examples/stm32f4/src/bin/sdmmc.rs index 1d0e60cb..ebdfdb22 100644 --- a/examples/stm32f4/src/bin/sdmmc.rs +++ b/examples/stm32f4/src/bin/sdmmc.rs @@ -14,7 +14,7 @@ use {defmt_rtt as _, panic_probe as _}; const ALLOW_WRITES: bool = false; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.sys_ck = Some(mhz(48)); config.rcc.pll48 = true; @@ -75,6 +75,4 @@ async fn main(_spawner: Spawner) -> ! { sdmmc.read_block(block_idx, &mut block).await.unwrap(); info!("Read: {=[u8]:X}...{=[u8]:X}", block[..8], block[512 - 8..]); - - loop {} } diff --git a/examples/stm32f7/src/bin/eth.rs b/examples/stm32f7/src/bin/eth.rs index 571a6c1b..9febb14e 100644 --- a/examples/stm32f7/src/bin/eth.rs +++ b/examples/stm32f7/src/bin/eth.rs @@ -106,7 +106,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(&buf).await; if let Err(e) = r { info!("write error: {:?}", e); - return; + continue; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32f7/src/bin/sdmmc.rs b/examples/stm32f7/src/bin/sdmmc.rs index cf8128e2..c050a400 100644 --- a/examples/stm32f7/src/bin/sdmmc.rs +++ b/examples/stm32f7/src/bin/sdmmc.rs @@ -10,7 +10,7 @@ use embassy_stm32::{interrupt, Config}; use {defmt_rtt as _, panic_probe as _}; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let mut config = Config::default(); config.rcc.sys_ck = Some(mhz(200)); config.rcc.pll48 = true; @@ -41,6 +41,4 @@ async fn main(_spawner: Spawner) -> ! { let card = unwrap!(sdmmc.card()); info!("Card: {:#?}", Debug2Format(card)); - - loop {} } diff --git a/examples/stm32h7/src/bin/eth.rs b/examples/stm32h7/src/bin/eth.rs index cb245c32..541e4976 100644 --- a/examples/stm32h7/src/bin/eth.rs +++ b/examples/stm32h7/src/bin/eth.rs @@ -106,7 +106,7 @@ async fn main(spawner: Spawner) -> ! { let r = socket.write_all(b"Hello\n").await; if let Err(e) = r { info!("write error: {:?}", e); - return; + continue; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h7/src/bin/eth_client.rs b/examples/stm32h7/src/bin/eth_client.rs index cce85a08..b609fa5d 100644 --- a/examples/stm32h7/src/bin/eth_client.rs +++ b/examples/stm32h7/src/bin/eth_client.rs @@ -108,7 +108,7 @@ async fn main(spawner: Spawner) -> ! { let r = connection.write_all(b"Hello\n").await; if let Err(e) = r { info!("write error: {:?}", e); - return; + continue; } Timer::after(Duration::from_secs(1)).await; } diff --git a/examples/stm32h7/src/bin/i2c.rs b/examples/stm32h7/src/bin/i2c.rs index d44319ae..78e03f01 100644 --- a/examples/stm32h7/src/bin/i2c.rs +++ b/examples/stm32h7/src/bin/i2c.rs @@ -14,7 +14,7 @@ const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { info!("Hello world!"); let p = embassy_stm32::init(Default::default()); diff --git a/examples/stm32l4/src/bin/i2c.rs b/examples/stm32l4/src/bin/i2c.rs index d54c080c..d40d6803 100644 --- a/examples/stm32l4/src/bin/i2c.rs +++ b/examples/stm32l4/src/bin/i2c.rs @@ -14,7 +14,7 @@ const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new( diff --git a/examples/stm32l4/src/bin/i2c_blocking_async.rs b/examples/stm32l4/src/bin/i2c_blocking_async.rs index 35a86660..d868cac0 100644 --- a/examples/stm32l4/src/bin/i2c_blocking_async.rs +++ b/examples/stm32l4/src/bin/i2c_blocking_async.rs @@ -16,7 +16,7 @@ const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let irq = interrupt::take!(I2C2_EV); let i2c = I2c::new( diff --git a/examples/stm32l4/src/bin/i2c_dma.rs b/examples/stm32l4/src/bin/i2c_dma.rs index 3ce9398a..7e62ee63 100644 --- a/examples/stm32l4/src/bin/i2c_dma.rs +++ b/examples/stm32l4/src/bin/i2c_dma.rs @@ -13,7 +13,7 @@ const ADDRESS: u8 = 0x5F; const WHOAMI: u8 = 0x0F; #[embassy_executor::main] -async fn main(_spawner: Spawner) -> ! { +async fn main(_spawner: Spawner) { let p = embassy_stm32::init(Default::default()); let irq = interrupt::take!(I2C2_EV); let mut i2c = I2c::new(