From 41329d7dfc39dec0f252273df6aece5720fb492b Mon Sep 17 00:00:00 2001 From: Kestrer Date: Fri, 5 Mar 2021 13:50:53 +0000 Subject: [PATCH 1/3] macros: preserve none-delimiters in function body When user-generated token streams are returned from proc macros, all none-delimited groups are flattened. This can cause compilation errors as shown in the issue below. By instead passing the function body token stream straight through from the input of the proc macro to its output, it does not get deconstructed and reconstructed, and so the none-delimited groups are not lost. Fixes: #3579 --- tests-integration/tests/macros_main.rs | 22 ++++++++++ tokio-macros/src/entry.rs | 57 ++++++++++++-------------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/tests-integration/tests/macros_main.rs b/tests-integration/tests/macros_main.rs index efe1ea9b49f..6569047d3ef 100644 --- a/tests-integration/tests/macros_main.rs +++ b/tests-integration/tests/macros_main.rs @@ -26,3 +26,25 @@ fn shell() { assert_eq!(1, basic_main()); assert_eq!(bool::default(), generic_fun::()) } + +macro_rules! generate_preserve_none_delimiters_tests { + ($e:expr) => { + #[test] + #[allow(clippy::redundant_closure_call)] + fn preserve_none_delimiters_in_main() { + #[tokio::main] + async fn f() -> i32 { + $e() + } + + assert_eq!(f(), ($e)()); + } + + #[tokio::test] + #[allow(clippy::redundant_closure_call)] + async fn preserve_none_delimiters_in_test() { + assert_eq!($e(), ($e)()); + } + }; +} +generate_preserve_none_delimiters_tests!(|| 5); diff --git a/tokio-macros/src/entry.rs b/tokio-macros/src/entry.rs index f82a329af16..49476e4af5c 100644 --- a/tokio-macros/src/entry.rs +++ b/tokio-macros/src/entry.rs @@ -174,13 +174,29 @@ fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result Result { + let mut input: syn::ItemFn = syn::parse(input_tokens.clone())?; + + if (is_test || input.sig.ident == "main") && !input.sig.inputs.is_empty() { + let function = if is_test { "test" } else { "main" }; + + return Err(syn::Error::new_spanned( + &input.sig.inputs, + format_args!("the {} function cannot accept arguments", function), + )); + } + if is_test { + if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) { + let msg = "second test attribute is supplied"; + return Err(syn::Error::new_spanned(attr, msg)); + } + } + let sig = &mut input.sig; - let body = &input.block; let attrs = &input.attrs; let vis = input.vis; @@ -291,6 +307,12 @@ fn parse_knobs( } }; + // The last token of a function item is always its body. We use the input token stream directly + // instead of printing the parsed function to make sure that Rust preserves None-delimited + // groups inside the function body; see . + let body = + proc_macro2::TokenStream::from(TokenStream::from(input_tokens.into_iter().last().unwrap())); + let result = quote! { #header #(#attrs)* @@ -308,38 +330,11 @@ fn parse_knobs( #[cfg(not(test))] // Work around for rust-lang/rust#62127 pub(crate) fn main(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream { - let input = syn::parse_macro_input!(item as syn::ItemFn); let args = syn::parse_macro_input!(args as syn::AttributeArgs); - - if input.sig.ident == "main" && !input.sig.inputs.is_empty() { - let msg = "the main function cannot accept arguments"; - return syn::Error::new_spanned(&input.sig.ident, msg) - .to_compile_error() - .into(); - } - - parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) + parse_knobs(item, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) } pub(crate) fn test(args: TokenStream, item: TokenStream, rt_multi_thread: bool) -> TokenStream { - let input = syn::parse_macro_input!(item as syn::ItemFn); let args = syn::parse_macro_input!(args as syn::AttributeArgs); - - for attr in &input.attrs { - if attr.path.is_ident("test") { - let msg = "second test attribute is supplied"; - return syn::Error::new_spanned(&attr, msg) - .to_compile_error() - .into(); - } - } - - if !input.sig.inputs.is_empty() { - let msg = "the test function cannot accept arguments"; - return syn::Error::new_spanned(&input.sig.inputs, msg) - .to_compile_error() - .into(); - } - - parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) + parse_knobs(item, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) } From d5c581ccd2fb9e315747844bd100eada926a78c9 Mon Sep 17 00:00:00 2001 From: Kestrer Date: Thu, 8 Apr 2021 15:39:10 +0100 Subject: [PATCH 2/3] Bump MSRV to 1.47.0 --- .github/workflows/ci.yml | 2 +- README.md | 2 +- tokio/README.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b68bfb2be06..a2c33208692 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 nightly: nightly-2020-09-21 - minrust: 1.45.2 + minrust: 1.47.0 jobs: # Depends on all action sthat are required for a "successful" CI run. diff --git a/README.md b/README.md index 9250e9afcc8..296b662e859 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ several other libraries, including: ## Supported Rust Versions -Tokio is built against the latest stable release. The minimum supported version is 1.45. +Tokio is built against the latest stable release. The minimum supported version is 1.47. The current Tokio version is not guaranteed to build on Rust versions earlier than the minimum supported version. diff --git a/tokio/README.md b/tokio/README.md index 8ee7bbda1b0..099c09ba6b4 100644 --- a/tokio/README.md +++ b/tokio/README.md @@ -155,7 +155,7 @@ several other libraries, including: ## Supported Rust Versions -Tokio is built against the latest stable release. The minimum supported version is 1.45. +Tokio is built against the latest stable release. The minimum supported version is 1.47. The current Tokio version is not guaranteed to build on Rust versions earlier than the minimum supported version. From 8e9c86432813b804e208477ddf8724d48998bb36 Mon Sep 17 00:00:00 2001 From: Kestrer Date: Fri, 7 May 2021 19:48:24 +0100 Subject: [PATCH 3/3] only require MSRV of 1.47.0 when running tests --- .github/workflows/ci.yml | 8 ++++++-- README.md | 2 +- tokio/README.md | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2c33208692..3d422635249 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,11 @@ env: RUSTFLAGS: -Dwarnings RUST_BACKTRACE: 1 nightly: nightly-2020-09-21 - minrust: 1.47.0 + minrust: 1.45.2 + # Tokio's tests require a higher minimum Rust version than Tokio itself. + # + # See https://github.com/tokio-rs/tokio/pull/3583 for more info. + minrust-tests: 1.47.0 jobs: # Depends on all action sthat are required for a "successful" CI run. @@ -249,7 +253,7 @@ jobs: steps: - uses: actions/checkout@v2 - name: Install Rust - run: rustup update ${{ env.minrust }} && rustup default ${{ env.minrust }} + run: rustup update ${{ env.minrust-tests }} && rustup default ${{ env.minrust-tests }} - name: Install clippy run: rustup component add clippy diff --git a/README.md b/README.md index 296b662e859..9250e9afcc8 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ several other libraries, including: ## Supported Rust Versions -Tokio is built against the latest stable release. The minimum supported version is 1.47. +Tokio is built against the latest stable release. The minimum supported version is 1.45. The current Tokio version is not guaranteed to build on Rust versions earlier than the minimum supported version. diff --git a/tokio/README.md b/tokio/README.md index 099c09ba6b4..8ee7bbda1b0 100644 --- a/tokio/README.md +++ b/tokio/README.md @@ -155,7 +155,7 @@ several other libraries, including: ## Supported Rust Versions -Tokio is built against the latest stable release. The minimum supported version is 1.47. +Tokio is built against the latest stable release. The minimum supported version is 1.45. The current Tokio version is not guaranteed to build on Rust versions earlier than the minimum supported version.