From 8fd151bbe24630f9b7b4993dc3deb3e170a0f768 Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Tue, 16 Nov 2021 11:18:00 +0100 Subject: Update to 1.6.0 Test: atest Change-Id: Iffed8e417e0f53d281f6bc294d434c341e0af9fa --- .cargo_vcs_info.json | 2 +- Android.bp | 2 +- CHANGELOG.md | 18 +++++++++ Cargo.toml | 4 +- Cargo.toml.orig | 4 +- METADATA | 8 ++-- src/entry.rs | 109 ++++++++++++++++++++++++++++++++++----------------- src/lib.rs | 8 ++++ src/select.rs | 67 +++++++++++++++++++++++++++++++ 9 files changed, 177 insertions(+), 45 deletions(-) diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 1131041..92e2ebe 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "d39c9ed9dc29627ce3f2e134502ee24b4b537a04" + "sha1": "623c09c52c2c38a8d75e94c166593547e8477707" } } diff --git a/Android.bp b/Android.bp index bf2ead9..57ae14e 100644 --- a/Android.bp +++ b/Android.bp @@ -22,7 +22,7 @@ rust_proc_macro { name: "libtokio_macros", crate_name: "tokio_macros", cargo_env_compat: true, - cargo_pkg_version: "1.4.1", + cargo_pkg_version: "1.6.0", srcs: ["src/lib.rs"], edition: "2018", rustlibs: [ diff --git a/CHANGELOG.md b/CHANGELOG.md index de94e3d..eb5504c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,21 @@ +# 1.6.0 (November 16th, 2021) + +- macros: fix mut patterns in `select!` macro ([#4211]) + +[#4211]: https://github.com/tokio-rs/tokio/pull/4211 + +# 1.5.1 (October 29th, 2021) + +- macros: fix type resolution error in `#[tokio::main]` ([#4176]) + +[#4176]: https://github.com/tokio-rs/tokio/pull/4176 + +# 1.5.0 (October 13th, 2021) + +- macros: make tokio-macros attributes more IDE friendly ([#4162]) + +[#4162]: https://github.com/tokio-rs/tokio/pull/4162 + # 1.4.1 (September 30th, 2021) Reverted: run `current_thread` inside `LocalSet` ([#4027]) diff --git a/Cargo.toml b/Cargo.toml index 051c274..818e827 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,11 +12,11 @@ [package] edition = "2018" name = "tokio-macros" -version = "1.4.1" +version = "1.6.0" authors = ["Tokio Contributors "] description = "Tokio's proc macros.\n" homepage = "https://tokio.rs" -documentation = "https://docs.rs/tokio-macros/1.4.1/tokio_macros" +documentation = "https://docs.rs/tokio-macros/1.6.0/tokio_macros" categories = ["asynchronous"] license = "MIT" repository = "https://github.com/tokio-rs/tokio" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index c394735..2114cd2 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -6,13 +6,13 @@ name = "tokio-macros" # - Cargo.toml # - Update CHANGELOG.md. # - Create "tokio-macros-1.0.x" git tag. -version = "1.4.1" +version = "1.6.0" edition = "2018" authors = ["Tokio Contributors "] license = "MIT" repository = "https://github.com/tokio-rs/tokio" homepage = "https://tokio.rs" -documentation = "https://docs.rs/tokio-macros/1.4.1/tokio_macros" +documentation = "https://docs.rs/tokio-macros/1.6.0/tokio_macros" description = """ Tokio's proc macros. """ diff --git a/METADATA b/METADATA index 0bae6e6..cd7a398 100644 --- a/METADATA +++ b/METADATA @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/tokio-macros/tokio-macros-1.4.1.crate" + value: "https://static.crates.io/crates/tokio-macros/tokio-macros-1.6.0.crate" } - version: "1.4.1" + version: "1.6.0" license_type: NOTICE last_upgrade_date { year: 2021 - month: 9 - day: 30 + month: 11 + day: 16 } } diff --git a/src/entry.rs b/src/entry.rs index 9da0d61..01f8ee4 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1,6 +1,10 @@ use proc_macro::TokenStream; use proc_macro2::Span; use quote::{quote, quote_spanned, ToTokens}; +use syn::parse::Parser; + +// syn::AttributeArgs does not implement syn::Parse +type AttributeArgs = syn::punctuated::Punctuated; #[derive(Clone, Copy, PartialEq)] enum RuntimeFlavor { @@ -27,6 +31,13 @@ struct FinalConfig { start_paused: Option, } +/// Config used in case of the attribute not being able to build a valid config +const DEFAULT_ERROR_CONFIG: FinalConfig = FinalConfig { + flavor: RuntimeFlavor::CurrentThread, + worker_threads: None, + start_paused: None, +}; + struct Configuration { rt_multi_thread_available: bool, default_flavor: RuntimeFlavor, @@ -184,13 +195,13 @@ fn parse_bool(bool: syn::Lit, span: Span, field: &str) -> Result Result { - if input.sig.asyncness.take().is_none() { +) -> Result { + if input.sig.asyncness.is_none() { let msg = "the `async` keyword is missing from the function declaration"; return Err(syn::Error::new_spanned(input.sig.fn_token, msg)); } @@ -278,7 +289,11 @@ fn parse_knobs( } } - let config = config.build()?; + config.build() +} + +fn parse_knobs(mut input: syn::ItemFn, is_test: bool, config: FinalConfig) -> TokenStream { + input.sig.asyncness = None; // If type mismatch occurs, the current rustc points to the last statement. let (last_stmt_start_span, last_stmt_end_span) = { @@ -324,15 +339,17 @@ fn parse_knobs( let body = &input.block; let brace_token = input.block.brace_token; let (tail_return, tail_semicolon) = match body.stmts.last() { - Some(syn::Stmt::Semi(expr, _)) => ( - match expr { - syn::Expr::Return(_) => quote! { return }, - _ => quote! {}, - }, - quote! { - ; + Some(syn::Stmt::Semi(expr, _)) => match expr { + syn::Expr::Return(_) => (quote! { return }, quote! { ; }), + _ => match &input.sig.output { + syn::ReturnType::Type(_, ty) if matches!(&**ty, syn::Type::Tuple(ty) if ty.elems.is_empty()) => + { + (quote! {}, quote! { ; }) // unit + } + syn::ReturnType::Default => (quote! {}, quote! { ; }), // unit + syn::ReturnType::Type(..) => (quote! {}, quote! {}), // ! or another }, - ), + }, _ => (quote! {}, quote! {}), }; input.block = syn::parse2(quote_spanned! {last_stmt_end_span=> @@ -354,36 +371,58 @@ fn parse_knobs( #input }; - Ok(result.into()) + result.into() +} + +fn token_stream_with_error(mut tokens: TokenStream, error: syn::Error) -> TokenStream { + tokens.extend(TokenStream::from(error.into_compile_error())); + tokens } #[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 any of the steps for this macro fail, we still want to expand to an item that is as close + // to the expected output as possible. This helps out IDEs such that completions and other + // related features keep working. + let input: syn::ItemFn = match syn::parse(item.clone()) { + Ok(it) => it, + Err(e) => return token_stream_with_error(item, e), + }; - if input.sig.ident == "main" && !input.sig.inputs.is_empty() { + let config = 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(); - } + Err(syn::Error::new_spanned(&input.sig.ident, msg)) + } else { + AttributeArgs::parse_terminated + .parse(args) + .and_then(|args| build_config(input.clone(), args, false, rt_multi_thread)) + }; - parse_knobs(input, args, false, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) + match config { + Ok(config) => parse_knobs(input, false, config), + Err(e) => token_stream_with_error(parse_knobs(input, false, DEFAULT_ERROR_CONFIG), e), + } } 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 any of the steps for this macro fail, we still want to expand to an item that is as close + // to the expected output as possible. This helps out IDEs such that completions and other + // related features keep working. + let input: syn::ItemFn = match syn::parse(item.clone()) { + Ok(it) => it, + Err(e) => return token_stream_with_error(item, e), + }; + let config = if let Some(attr) = input.attrs.iter().find(|attr| attr.path.is_ident("test")) { + let msg = "second test attribute is supplied"; + Err(syn::Error::new_spanned(&attr, msg)) + } else { + AttributeArgs::parse_terminated + .parse(args) + .and_then(|args| build_config(input.clone(), args, true, rt_multi_thread)) + }; - parse_knobs(input, args, true, rt_multi_thread).unwrap_or_else(|e| e.to_compile_error().into()) + match config { + Ok(config) => parse_knobs(input, true, config), + Err(e) => token_stream_with_error(parse_knobs(input, true, DEFAULT_ERROR_CONFIG), e), + } } diff --git a/src/lib.rs b/src/lib.rs index df18616..f8ba8ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -329,3 +329,11 @@ pub fn test_fail(_args: TokenStream, _item: TokenStream) -> TokenStream { pub fn select_priv_declare_output_enum(input: TokenStream) -> TokenStream { select::declare_output_enum(input) } + +/// Implementation detail of the `select!` macro. This macro is **not** intended +/// to be used as part of the public API and is permitted to change. +#[proc_macro] +#[doc(hidden)] +pub fn select_priv_clean_pattern(input: TokenStream) -> TokenStream { + select::clean_pattern_macro(input) +} diff --git a/src/select.rs b/src/select.rs index ddb2e6a..23e280a 100644 --- a/src/select.rs +++ b/src/select.rs @@ -41,3 +41,70 @@ pub(crate) fn declare_output_enum(input: TokenStream) -> TokenStream { pub(super) type Mask = #mask; }) } + +pub(crate) fn clean_pattern_macro(input: TokenStream) -> TokenStream { + // If this isn't a pattern, we return the token stream as-is. The select! + // macro is using it in a location requiring a pattern, so an error will be + // emitted there. + let mut input: syn::Pat = match syn::parse(input.clone()) { + Ok(it) => it, + Err(_) => return input, + }; + + clean_pattern(&mut input); + quote::ToTokens::into_token_stream(input).into() +} + +// Removes any occurrences of ref or mut in the provided pattern. +fn clean_pattern(pat: &mut syn::Pat) { + match pat { + syn::Pat::Box(_box) => {} + syn::Pat::Lit(_literal) => {} + syn::Pat::Macro(_macro) => {} + syn::Pat::Path(_path) => {} + syn::Pat::Range(_range) => {} + syn::Pat::Rest(_rest) => {} + syn::Pat::Verbatim(_tokens) => {} + syn::Pat::Wild(_underscore) => {} + syn::Pat::Ident(ident) => { + ident.by_ref = None; + ident.mutability = None; + if let Some((_at, pat)) = &mut ident.subpat { + clean_pattern(&mut *pat); + } + } + syn::Pat::Or(or) => { + for case in or.cases.iter_mut() { + clean_pattern(case); + } + } + syn::Pat::Slice(slice) => { + for elem in slice.elems.iter_mut() { + clean_pattern(elem); + } + } + syn::Pat::Struct(struct_pat) => { + for field in struct_pat.fields.iter_mut() { + clean_pattern(&mut field.pat); + } + } + syn::Pat::Tuple(tuple) => { + for elem in tuple.elems.iter_mut() { + clean_pattern(elem); + } + } + syn::Pat::TupleStruct(tuple) => { + for elem in tuple.pat.elems.iter_mut() { + clean_pattern(elem); + } + } + syn::Pat::Reference(reference) => { + reference.mutability = None; + clean_pattern(&mut *reference.pat); + } + syn::Pat::Type(type_pat) => { + clean_pattern(&mut *type_pat.pat); + } + _ => {} + } +} -- cgit v1.2.3