diff options
author | Jeff Vander Stoep <jeffv@google.com> | 2021-11-16 19:09:49 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-11-16 19:09:49 +0000 |
commit | 5c7b707d86c16ec1306b46916ac00220f0d6dc7f (patch) | |
tree | e55bd1baa609402989c9a7586721f605703c6435 | |
parent | c112b3af02ed25099e41c07ac3c8e2bdf3671862 (diff) | |
parent | dd93953c413c71b0e395fcc849c1e59e95c05a1d (diff) | |
download | tokio-macros-5c7b707d86c16ec1306b46916ac00220f0d6dc7f.tar.gz |
Update to 1.6.0 am: 8fd151bbe2 am: 27a6d60a59 am: 7b7b971325 am: dd93953c41
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/tokio-macros/+/1892676
Change-Id: I995a6a57534ecddd301677d6c9ff7e6ab463fb59
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 18 | ||||
-rw-r--r-- | Cargo.toml | 4 | ||||
-rw-r--r-- | Cargo.toml.orig | 4 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | src/entry.rs | 109 | ||||
-rw-r--r-- | src/lib.rs | 8 | ||||
-rw-r--r-- | 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" } } @@ -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]) @@ -12,11 +12,11 @@ [package] edition = "2018" name = "tokio-macros" -version = "1.4.1" +version = "1.6.0" authors = ["Tokio Contributors <team@tokio.rs>"] 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 <team@tokio.rs>"] 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. """ @@ -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<syn::NestedMeta, syn::Token![,]>; #[derive(Clone, Copy, PartialEq)] enum RuntimeFlavor { @@ -27,6 +31,13 @@ struct FinalConfig { start_paused: Option<bool>, } +/// 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<bool, syn::Erro } } -fn parse_knobs( - mut input: syn::ItemFn, - args: syn::AttributeArgs, +fn build_config( + input: syn::ItemFn, + args: AttributeArgs, is_test: bool, rt_multi_thread: bool, -) -> Result<TokenStream, syn::Error> { - if input.sig.asyncness.take().is_none() { +) -> Result<FinalConfig, syn::Error> { + 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), + } } @@ -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); + } + _ => {} + } +} |