From e60a0dcec96cc383f134b8c9bb06c5cbc895a465 Mon Sep 17 00:00:00 2001 From: Hai-Hsin Date: Tue, 28 May 2024 23:52:47 +0800 Subject: [PATCH 1/5] macros: allow setting unhandled_panic behavior in tokio::main and tokio::test --- .../tests/fail/macros_invalid_input.stderr | 44 ++++++------- tokio-macros/src/entry.rs | 63 ++++++++++++++++++- tokio/tests/macros_test.rs | 25 ++++++++ 3 files changed, 107 insertions(+), 25 deletions(-) diff --git a/tests-build/tests/fail/macros_invalid_input.stderr b/tests-build/tests/fail/macros_invalid_input.stderr index 11f95315cdf..a7e61adf487 100644 --- a/tests-build/tests/fail/macros_invalid_input.stderr +++ b/tests-build/tests/fail/macros_invalid_input.stderr @@ -1,113 +1,113 @@ error: the `async` keyword is missing from the function declaration - --> $DIR/macros_invalid_input.rs:6:1 + --> tests/fail/macros_invalid_input.rs:6:1 | 6 | fn main_is_not_async() {} | ^^ -error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate` - --> $DIR/macros_invalid_input.rs:8:15 +error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`. + --> tests/fail/macros_invalid_input.rs:8:15 | 8 | #[tokio::main(foo)] | ^^^ error: Must have specified ident - --> $DIR/macros_invalid_input.rs:11:15 + --> tests/fail/macros_invalid_input.rs:11:15 | 11 | #[tokio::main(threadpool::bar)] | ^^^^^^^^^^^^^^^ error: the `async` keyword is missing from the function declaration - --> $DIR/macros_invalid_input.rs:15:1 + --> tests/fail/macros_invalid_input.rs:15:1 | 15 | fn test_is_not_async() {} | ^^ -error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate` - --> $DIR/macros_invalid_input.rs:17:15 +error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`. + --> tests/fail/macros_invalid_input.rs:17:15 | 17 | #[tokio::test(foo)] | ^^^ -error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate` - --> $DIR/macros_invalid_input.rs:20:15 +error: Unknown attribute foo is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic` + --> tests/fail/macros_invalid_input.rs:20:15 | 20 | #[tokio::test(foo = 123)] | ^^^^^^^^^ error: Failed to parse value of `flavor` as string. - --> $DIR/macros_invalid_input.rs:23:24 + --> tests/fail/macros_invalid_input.rs:23:24 | 23 | #[tokio::test(flavor = 123)] | ^^^ error: No such runtime flavor `foo`. The runtime flavors are `current_thread` and `multi_thread`. - --> $DIR/macros_invalid_input.rs:26:24 + --> tests/fail/macros_invalid_input.rs:26:24 | 26 | #[tokio::test(flavor = "foo")] | ^^^^^ error: The `start_paused` option requires the `current_thread` runtime flavor. Use `#[tokio::test(flavor = "current_thread")]` - --> $DIR/macros_invalid_input.rs:29:55 + --> tests/fail/macros_invalid_input.rs:29:55 | 29 | #[tokio::test(flavor = "multi_thread", start_paused = false)] | ^^^^^ error: Failed to parse value of `worker_threads` as integer. - --> $DIR/macros_invalid_input.rs:32:57 + --> tests/fail/macros_invalid_input.rs:32:57 | 32 | #[tokio::test(flavor = "multi_thread", worker_threads = "foo")] | ^^^^^ error: The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[tokio::test(flavor = "multi_thread")]` - --> $DIR/macros_invalid_input.rs:35:59 + --> tests/fail/macros_invalid_input.rs:35:59 | 35 | #[tokio::test(flavor = "current_thread", worker_threads = 4)] | ^ error: Failed to parse value of `crate` as path. - --> $DIR/macros_invalid_input.rs:38:23 + --> tests/fail/macros_invalid_input.rs:38:23 | 38 | #[tokio::test(crate = 456)] | ^^^ error: Failed to parse value of `crate` as path: "456" - --> $DIR/macros_invalid_input.rs:41:23 + --> tests/fail/macros_invalid_input.rs:41:23 | 41 | #[tokio::test(crate = "456")] | ^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:45:1 + --> tests/fail/macros_invalid_input.rs:45:1 | 45 | #[test] | ^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:49:1 + --> tests/fail/macros_invalid_input.rs:49:1 | 49 | #[::core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:53:1 + --> tests/fail/macros_invalid_input.rs:53:1 | 53 | #[core::prelude::rust_2015::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:57:1 + --> tests/fail/macros_invalid_input.rs:57:1 | 57 | #[::std::prelude::rust_2018::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:61:1 + --> tests/fail/macros_invalid_input.rs:61:1 | 61 | #[std::prelude::rust_2021::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> $DIR/macros_invalid_input.rs:64:1 + --> tests/fail/macros_invalid_input.rs:64:1 | 64 | #[tokio::test] | ^^^^^^^^^^^^^^ diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 8858c8a1674..52209a76b22 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -25,11 +25,37 @@ impl RuntimeFlavor { } } +#[derive(Clone, Copy, PartialEq)] +enum UnhandledPanic { + Ignore, + ShutdownRuntime, +} + +impl UnhandledPanic { + fn from_str(s: &str) -> Result { + match s { + "ignore" => Ok(UnhandledPanic::Ignore), + "shutdown_runtime" => Ok(UnhandledPanic::ShutdownRuntime), + _ => Err(format!("No such unhandled panic behavior `{}`. The unhandled panic behaviors are `ignore` and `shutdown_runtime`.", s)), + } + } + + fn into_tokens(self, crate_path: &TokenStream) -> TokenStream { + match self { + UnhandledPanic::Ignore => quote! { #crate_path::runtime::UnhandledPanic::Ignore }, + UnhandledPanic::ShutdownRuntime => { + quote! { #crate_path::runtime::UnhandledPanic::ShutdownRuntime } + } + } + } +} + struct FinalConfig { flavor: RuntimeFlavor, worker_threads: Option, start_paused: Option, crate_name: Option, + unhandled_panic: Option, } /// Config used in case of the attribute not being able to build a valid config @@ -38,6 +64,7 @@ const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig { worker_threads: None, start_paused: None, crate_name: None, + unhandled_panic: None, }; struct Configuration { @@ -48,6 +75,7 @@ struct Configuration { start_paused: Option<(bool, Span)>, is_test: bool, crate_name: Option, + unhandled_panic: Option, } impl Configuration { @@ -63,6 +91,7 @@ impl Configuration { start_paused: None, is_test, crate_name: None, + unhandled_panic: None, } } @@ -117,6 +146,25 @@ impl Configuration { Ok(()) } + fn set_unhandled_panic( + &mut self, + unhandled_panic: syn::Lit, + span: Span, + ) -> Result<(), syn::Error> { + if self.unhandled_panic.is_some() { + return Err(syn::Error::new( + span, + "`unhandled_panic` set multiple times.", + )); + } + + let unhandled_panic = parse_string(unhandled_panic, span, "unhandled_panic")?; + let unhandled_panic = + UnhandledPanic::from_str(&unhandled_panic).map_err(|err| syn::Error::new(span, err))?; + self.unhandled_panic = Some(unhandled_panic); + Ok(()) + } + fn macro_name(&self) -> &'static str { if self.is_test { "tokio::test" @@ -165,6 +213,7 @@ impl Configuration { Ok(FinalConfig { crate_name: self.crate_name.clone(), + unhandled_panic: self.unhandled_panic, flavor, worker_threads, start_paused, @@ -275,9 +324,13 @@ fn build_config( "crate" => { config.set_crate_name(lit.clone(), syn::spanned::Spanned::span(lit))?; } + "unhandled_panic" => { + config + .set_unhandled_panic(lit.clone(), syn::spanned::Spanned::span(lit))?; + } name => { let msg = format!( - "Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`", + "Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`", name, ); return Err(syn::Error::new_spanned(namevalue, msg)); @@ -303,11 +356,11 @@ fn build_config( macro_name ) } - "flavor" | "worker_threads" | "start_paused" => { + "flavor" | "worker_threads" | "start_paused" | "crate" | "unhandled_panic" => { format!("The `{}` attribute requires an argument.", name) } name => { - format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`", name) + format!("Unknown attribute {} is specified; expected one of: `flavor`, `worker_threads`, `start_paused`, `crate`, `unhandled_panic`.", name) } }; return Err(syn::Error::new_spanned(path, msg)); @@ -359,6 +412,10 @@ fn parse_knobs(mut input: ItemFn, is_test: bool, config: FinalConfig) -> TokenSt if let Some(v) = config.start_paused { rt = quote_spanned! {last_stmt_start_span=> #rt.start_paused(#v) }; } + if let Some(v) = config.unhandled_panic { + let unhandled_panic = v.into_tokens(&crate_path); + rt = quote_spanned! {last_stmt_start_span=> #rt.unhandled_panic(#unhandled_panic) }; + } let generated_attrs = if is_test { quote! { diff --git a/tokio/tests/macros_test.rs b/tokio/tests/macros_test.rs index 69ee30b36ce..ef91ffd1732 100644 --- a/tokio/tests/macros_test.rs +++ b/tokio/tests/macros_test.rs @@ -1,3 +1,4 @@ +#![allow(unknown_lints, unexpected_cfgs)] #![cfg(all(feature = "full", not(target_os = "wasi")))] // Wasi doesn't support threading use tokio::test; @@ -92,3 +93,27 @@ pub mod issue_5243 { async fn foo() {} ); } + +#[cfg(tokio_unstable)] +pub mod macro_rt_arg_unhandled_panic { + use tokio_test::assert_err; + + #[tokio::test(unhandled_panic = "shutdown_runtime")] + #[should_panic] + async fn unhandled_panic_shutdown_runtime() { + let rt = tokio::spawn(async { + panic!("This panic should shutdown the runtime."); + }) + .await; + assert_err!(rt); + } + + #[tokio::test(unhandled_panic = "ignore")] + async fn unhandled_panic_ignore() { + let rt = tokio::spawn(async { + panic!("This panic should be forwarded to rt as an error."); + }) + .await; + assert_err!(rt); + } +} From 71d55fdec7e0eb7700b3b62bd27a562335081b84 Mon Sep 17 00:00:00 2001 From: Hai-Hsin Date: Thu, 30 May 2024 16:45:48 +0800 Subject: [PATCH 2/5] macros: add docs for unhandled_panic --- tokio-macros/src/lib.rs | 77 ++++++++++++++++++++++++++++++++++++++ tokio/tests/macros_test.rs | 3 +- 2 files changed, 78 insertions(+), 2 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index c108d8c46a2..4cc1c402328 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -202,6 +202,44 @@ use proc_macro::TokenStream; /// }) /// } /// ``` +/// +/// ### Configure unhandled panic behavior +/// +/// Available options are `shutdown_runtime` and `ignore`. For more details, see +/// [`Builder::unhandled_panic`]. +/// +/// ```ignore +/// #[tokio::main(unhandled_panic = "shutdown_runtime")] +/// async fn main() { +/// let _ = tokio::spawn(async { +/// panic!("This panic will shutdown the runtime."); +/// }).await; +/// } +/// ``` +/// +/// Equivalent code not using `#[tokio::test]` +/// +/// ```ignore +/// fn main() { +/// tokio::runtime::Builder::new_current_thread() +/// .enable_all() +/// .unhandled_panic(UnhandledPanic::ShutdownRuntime) +/// .build() +/// .unwrap() +/// .block_on(async { +/// let _ = tokio::spawn(async { +/// panic!("This panic will shutdown the runtime."); +/// }).await; +/// }) +/// } +/// ``` +/// +/// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the +/// documentation on unstable features][unstable] for details on how to enable +/// Tokio's unstable features. +/// +/// [`Builder::unhandled_panic`]: ../tokio/runtime/struct.Builder.html#method.unhandled_panic +/// [unstable]: ../tokio/index.html#unstable-features #[proc_macro_attribute] pub fn main(args: TokenStream, item: TokenStream) -> TokenStream { entry::main(args.into(), item.into(), true).into() @@ -423,6 +461,45 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream { /// println!("Hello world"); /// } /// ``` +/// +/// ### Configure unhandled panic behavior +/// +/// Available options are `shutdown_runtime` and `ignore`. For more details, see +/// [`Builder::unhandled_panic`]. +/// +/// ```ignore +/// #[tokio::test(unhandled_panic = "shutdown_runtime")] +/// async fn my_test() { +/// let _ = tokio::spawn(async { +/// panic!("This panic will shutdown the runtime."); +/// }).await; +/// } +/// ``` +/// +/// Equivalent code not using `#[tokio::test]` +/// +/// ```ignore +/// #[test] +/// fn my_test() { +/// tokio::runtime::Builder::new_current_thread() +/// .enable_all() +/// .unhandled_panic(UnhandledPanic::ShutdownRuntime) +/// .build() +/// .unwrap() +/// .block_on(async { +/// let _ = tokio::spawn(async { +/// panic!("This panic will shutdown the runtime."); +/// }).await; +/// }) +/// } +/// ``` +/// +/// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the +/// documentation on unstable features][unstable] for details on how to enable +/// Tokio's unstable features. +/// +/// [`Builder::unhandled_panic`]: ../tokio/runtime/struct.Builder.html#method.unhandled_panic +/// [unstable]: ../tokio/index.html#unstable-features #[proc_macro_attribute] pub fn test(args: TokenStream, item: TokenStream) -> TokenStream { entry::test(args.into(), item.into(), true).into() diff --git a/tokio/tests/macros_test.rs b/tokio/tests/macros_test.rs index ef91ffd1732..cfb4d6c22f2 100644 --- a/tokio/tests/macros_test.rs +++ b/tokio/tests/macros_test.rs @@ -101,11 +101,10 @@ pub mod macro_rt_arg_unhandled_panic { #[tokio::test(unhandled_panic = "shutdown_runtime")] #[should_panic] async fn unhandled_panic_shutdown_runtime() { - let rt = tokio::spawn(async { + let _ = tokio::spawn(async { panic!("This panic should shutdown the runtime."); }) .await; - assert_err!(rt); } #[tokio::test(unhandled_panic = "ignore")] From 00ca9c73b466c9a91d4e23608063062f8fc002ef Mon Sep 17 00:00:00 2001 From: Hai-Hsin Date: Sat, 1 Jun 2024 21:11:01 +0800 Subject: [PATCH 3/5] macros: docs: only current_thread implements unhandled_panic for now --- tokio-macros/src/lib.rs | 6 +++--- tokio/tests/macros_test.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 4cc1c402328..0ef745c9396 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -209,7 +209,7 @@ use proc_macro::TokenStream; /// [`Builder::unhandled_panic`]. /// /// ```ignore -/// #[tokio::main(unhandled_panic = "shutdown_runtime")] +/// #[tokio::main(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn main() { /// let _ = tokio::spawn(async { /// panic!("This panic will shutdown the runtime."); @@ -217,7 +217,7 @@ use proc_macro::TokenStream; /// } /// ``` /// -/// Equivalent code not using `#[tokio::test]` +/// Equivalent code not using `#[tokio::main]` /// /// ```ignore /// fn main() { @@ -468,7 +468,7 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream { /// [`Builder::unhandled_panic`]. /// /// ```ignore -/// #[tokio::test(unhandled_panic = "shutdown_runtime")] +/// #[tokio::test(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn my_test() { /// let _ = tokio::spawn(async { /// panic!("This panic will shutdown the runtime."); diff --git a/tokio/tests/macros_test.rs b/tokio/tests/macros_test.rs index cfb4d6c22f2..bed443cf293 100644 --- a/tokio/tests/macros_test.rs +++ b/tokio/tests/macros_test.rs @@ -98,7 +98,7 @@ pub mod issue_5243 { pub mod macro_rt_arg_unhandled_panic { use tokio_test::assert_err; - #[tokio::test(unhandled_panic = "shutdown_runtime")] + #[tokio::test(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] #[should_panic] async fn unhandled_panic_shutdown_runtime() { let _ = tokio::spawn(async { @@ -107,7 +107,7 @@ pub mod macro_rt_arg_unhandled_panic { .await; } - #[tokio::test(unhandled_panic = "ignore")] + #[tokio::test(flavor = "current_thread", unhandled_panic = "ignore")] async fn unhandled_panic_ignore() { let rt = tokio::spawn(async { panic!("This panic should be forwarded to rt as an error."); From c886cdeb2a0c0ad6035e7a05eda928929c746a20 Mon Sep 17 00:00:00 2001 From: Hai-Hsin Date: Sun, 2 Jun 2024 22:24:35 +0800 Subject: [PATCH 4/5] macros: make unhandled_panic bails with multi_thread runtime --- .../tests/fail/macros_invalid_input.rs | 3 ++ .../tests/fail/macros_invalid_input.stderr | 30 +++++++++++-------- tokio-macros/src/entry.rs | 18 +++++++++-- tokio-macros/src/lib.rs | 4 +++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/tests-build/tests/fail/macros_invalid_input.rs b/tests-build/tests/fail/macros_invalid_input.rs index 85b4924f225..425b274ff7f 100644 --- a/tests-build/tests/fail/macros_invalid_input.rs +++ b/tests-build/tests/fail/macros_invalid_input.rs @@ -41,6 +41,9 @@ async fn test_crate_not_path_int() {} #[tokio::test(crate = "456")] async fn test_crate_not_path_invalid() {} +#[tokio::test(flavor = "multi_thread", unhandled_panic = "shutdown_runtime")] +async fn test_multi_thread_with_unhandled_panic() {} + #[tokio::test] #[test] async fn test_has_second_test_attr() {} diff --git a/tests-build/tests/fail/macros_invalid_input.stderr b/tests-build/tests/fail/macros_invalid_input.stderr index a7e61adf487..e6e80e8114a 100644 --- a/tests-build/tests/fail/macros_invalid_input.stderr +++ b/tests-build/tests/fail/macros_invalid_input.stderr @@ -76,40 +76,46 @@ error: Failed to parse value of `crate` as path: "456" 41 | #[tokio::test(crate = "456")] | ^^^^^ +error: The `unhandled_panic` option requires the `current_thread` runtime flavor. Use `#[tokio::test(flavor = "current_thread")]` + --> tests/fail/macros_invalid_input.rs:44:58 + | +44 | #[tokio::test(flavor = "multi_thread", unhandled_panic = "shutdown_runtime")] + | ^^^^^^^^^^^^^^^^^^ + error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:45:1 + --> tests/fail/macros_invalid_input.rs:48:1 | -45 | #[test] +48 | #[test] | ^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:49:1 + --> tests/fail/macros_invalid_input.rs:52:1 | -49 | #[::core::prelude::v1::test] +52 | #[::core::prelude::v1::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:53:1 + --> tests/fail/macros_invalid_input.rs:56:1 | -53 | #[core::prelude::rust_2015::test] +56 | #[core::prelude::rust_2015::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:57:1 + --> tests/fail/macros_invalid_input.rs:60:1 | -57 | #[::std::prelude::rust_2018::test] +60 | #[::std::prelude::rust_2018::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:61:1 + --> tests/fail/macros_invalid_input.rs:64:1 | -61 | #[std::prelude::rust_2021::test] +64 | #[std::prelude::rust_2021::test] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: second test attribute is supplied, consider removing or changing the order of your test attributes - --> tests/fail/macros_invalid_input.rs:64:1 + --> tests/fail/macros_invalid_input.rs:67:1 | -64 | #[tokio::test] +67 | #[tokio::test] | ^^^^^^^^^^^^^^ | = note: this error originates in the attribute macro `tokio::test` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index 52209a76b22..acdc2610f44 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -75,7 +75,7 @@ struct Configuration { start_paused: Option<(bool, Span)>, is_test: bool, crate_name: Option, - unhandled_panic: Option, + unhandled_panic: Option<(UnhandledPanic, Span)>, } impl Configuration { @@ -161,7 +161,7 @@ impl Configuration { let unhandled_panic = parse_string(unhandled_panic, span, "unhandled_panic")?; let unhandled_panic = UnhandledPanic::from_str(&unhandled_panic).map_err(|err| syn::Error::new(span, err))?; - self.unhandled_panic = Some(unhandled_panic); + self.unhandled_panic = Some((unhandled_panic, span)); Ok(()) } @@ -211,12 +211,24 @@ impl Configuration { (_, None) => None, }; + let unhandled_panic = match (flavor, self.unhandled_panic) { + (F::Threaded, Some((_, unhandled_panic_span))) => { + let msg = format!( + "The `unhandled_panic` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \"current_thread\")]`", + self.macro_name(), + ); + return Err(syn::Error::new(unhandled_panic_span, msg)); + } + (F::CurrentThread, Some((unhandled_panic, _))) => Some(unhandled_panic), + (_, None) => None, + }; + Ok(FinalConfig { crate_name: self.crate_name.clone(), - unhandled_panic: self.unhandled_panic, flavor, worker_threads, start_paused, + unhandled_panic, }) } } diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 0ef745c9396..4b7072943cf 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -208,6 +208,8 @@ use proc_macro::TokenStream; /// Available options are `shutdown_runtime` and `ignore`. For more details, see /// [`Builder::unhandled_panic`]. /// +/// This option is only compatible with the `current_thread` runtime. +/// /// ```ignore /// #[tokio::main(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn main() { @@ -467,6 +469,8 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream { /// Available options are `shutdown_runtime` and `ignore`. For more details, see /// [`Builder::unhandled_panic`]. /// +/// This option is only compatible with the `current_thread` runtime. +/// /// ```ignore /// #[tokio::test(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn my_test() { From 30d9d22e6a3630356eb00c9e6a28d0bef5b18cd9 Mon Sep 17 00:00:00 2001 From: Hai-Hsin Date: Thu, 6 Jun 2024 22:18:18 +0800 Subject: [PATCH 5/5] macros: docs: make examples for unhandled_panic testable --- tokio-macros/src/lib.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/tokio-macros/src/lib.rs b/tokio-macros/src/lib.rs index 4b7072943cf..860a0929952 100644 --- a/tokio-macros/src/lib.rs +++ b/tokio-macros/src/lib.rs @@ -210,18 +210,22 @@ use proc_macro::TokenStream; /// /// This option is only compatible with the `current_thread` runtime. /// -/// ```ignore +/// ```no_run +/// #[cfg(tokio_unstable)] /// #[tokio::main(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn main() { /// let _ = tokio::spawn(async { /// panic!("This panic will shutdown the runtime."); /// }).await; /// } +/// # #[cfg(not(tokio_unstable))] +/// # fn main() { } /// ``` /// /// Equivalent code not using `#[tokio::main]` /// -/// ```ignore +/// ```no_run +/// #[cfg(tokio_unstable)] /// fn main() { /// tokio::runtime::Builder::new_current_thread() /// .enable_all() @@ -234,6 +238,8 @@ use proc_macro::TokenStream; /// }).await; /// }) /// } +/// # #[cfg(not(tokio_unstable))] +/// # fn main() { } /// ``` /// /// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the @@ -471,18 +477,22 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream { /// /// This option is only compatible with the `current_thread` runtime. /// -/// ```ignore +/// ```no_run +/// #[cfg(tokio_unstable)] /// #[tokio::test(flavor = "current_thread", unhandled_panic = "shutdown_runtime")] /// async fn my_test() { /// let _ = tokio::spawn(async { /// panic!("This panic will shutdown the runtime."); /// }).await; /// } +/// # #[cfg(not(tokio_unstable))] +/// # fn main() { } /// ``` /// /// Equivalent code not using `#[tokio::test]` /// -/// ```ignore +/// ```no_run +/// #[cfg(tokio_unstable)] /// #[test] /// fn my_test() { /// tokio::runtime::Builder::new_current_thread() @@ -496,6 +506,8 @@ pub fn main_rt(args: TokenStream, item: TokenStream) -> TokenStream { /// }).await; /// }) /// } +/// # #[cfg(not(tokio_unstable))] +/// # fn main() { } /// ``` /// /// **Note**: This option depends on Tokio's [unstable API][unstable]. See [the