From f2a694b71a70c258be93549464a686b5c8952da1 Mon Sep 17 00:00:00 2001 From: Haibo Huang Date: Tue, 29 Sep 2020 17:24:14 -0700 Subject: Upgrade rust/crates/proc-macro-error-attr to 1.0.4 Test: make Change-Id: I1b773559909dad75543a4d01fbadb69aaa9c05e8 --- .cargo_vcs_info.json | 2 +- .gitignore | 4 ++ Android.bp | 8 +-- Cargo.toml | 10 +--- Cargo.toml.orig | 5 +- METADATA | 8 +-- src/lib.rs | 153 ++++++++++++++++++++------------------------------- src/parse.rs | 89 ++++++++++++++++++++++++++++++ src/settings.rs | 72 ++++++++++++++++++++++++ 9 files changed, 234 insertions(+), 117 deletions(-) create mode 100644 .gitignore create mode 100644 src/parse.rs create mode 100644 src/settings.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 0b126fe..1561cb4 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "69743a4ceab6c8da1ddb473f54a6a01840de90d9" + "sha1": "e231741c47af1beda78d53aee29500cccb8266cd" } } diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e81b66 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/target +**/*.rs.bk +Cargo.lock +.fuse_hidden* diff --git a/Android.bp b/Android.bp index 4b2ac70..c2a35e2 100644 --- a/Android.bp +++ b/Android.bp @@ -8,8 +8,6 @@ rust_proc_macro { rustlibs: [ "libproc_macro2", "libquote", - "libsyn", - "libsyn_mid", ], compile_multilib: "first", } @@ -24,15 +22,11 @@ rust_test_host { rustlibs: [ "libproc_macro2", "libquote", - "libsyn", - "libsyn_mid", ], } // dependent_library ["feature_list"] -// proc-macro2-1.0.19 "default,proc-macro" +// proc-macro2-1.0.23 "default,proc-macro" // quote-1.0.7 "default,proc-macro" -// syn-1.0.36 "derive,parsing,printing,proc-macro,quote" -// syn-mid-0.5.0 // unicode-xid-0.2.1 "default" // version_check-0.9.2 diff --git a/Cargo.toml b/Cargo.toml index 1365dbb..a2c766d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "proc-macro-error-attr" -version = "1.0.2" +version = "1.0.4" authors = ["CreepySkeleton "] build = "build.rs" description = "Attribute macro for proc-macro-error crate" @@ -29,13 +29,5 @@ version = "1" [dependencies.quote] version = "1" - -[dependencies.syn] -version = "1" -features = ["derive", "parsing", "proc-macro", "printing"] -default-features = false - -[dependencies.syn-mid] -version = "0.5" [build-dependencies.version_check] version = "0.9" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 7414642..a6b7069 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "proc-macro-error-attr" -version = "1.0.2" +version = "1.0.4" authors = ["CreepySkeleton "] edition = "2018" description = "Attribute macro for proc-macro-error crate" @@ -18,9 +18,6 @@ targets = ["x86_64-unknown-linux-gnu"] [dependencies] quote = "1" proc-macro2 = "1" -syn-mid = "0.5" -# "derive" is for `Attribute`, "parsing" is for `Parse` -syn = { version = "1", default-features = false, features = ["derive", "parsing", "proc-macro", "printing"] } [build-dependencies] version_check = "0.9" diff --git a/METADATA b/METADATA index cdd4435..0864788 100644 --- a/METADATA +++ b/METADATA @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/proc-macro-error-attr/proc-macro-error-attr-1.0.2.crate" + value: "https://static.crates.io/crates/proc-macro-error-attr/proc-macro-error-attr-1.0.4.crate" } - version: "1.0.2" + version: "1.0.4" license_type: NOTICE last_upgrade_date { year: 2020 - month: 5 - day: 6 + month: 9 + day: 29 } } diff --git a/src/lib.rs b/src/lib.rs index 75953fe..ac0ac21 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,37 +3,59 @@ extern crate proc_macro; +use crate::parse::parse_input; +use crate::parse::Attribute; use proc_macro::TokenStream; -use proc_macro2::Ident; -use quote::quote; -use std::iter::FromIterator; -use syn::{ - parse::{Parse, ParseStream}, - parse_macro_input, - punctuated::Punctuated, - Attribute, Token, -}; -use syn_mid::{Block, ItemFn}; - -use self::Setting::*; +use proc_macro2::{Literal, Span, TokenStream as TokenStream2, TokenTree}; +use quote::{quote, quote_spanned}; + +use crate::settings::{Setting::*, *}; + +mod parse; +mod settings; + +type Result = std::result::Result; + +struct Error { + span: Span, + message: String, +} + +impl Error { + fn new(span: Span, message: String) -> Self { + Error { span, message } + } + + fn into_compile_error(self) -> TokenStream2 { + let mut message = Literal::string(&self.message); + message.set_span(self.span); + quote_spanned!(self.span=> compile_error!{#message}) + } +} #[proc_macro_attribute] pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as ItemFn); - let mut settings = match syn::parse::(attr) { - Ok(settings) => settings, - Err(err) => { - let err = err.to_compile_error(); - return quote!(#input #err).into(); + match impl_proc_macro_error(attr.into(), input.clone().into()) { + Ok(ts) => ts, + Err(e) => { + let error = e.into_compile_error(); + let input = TokenStream2::from(input); + + quote!(#input #error).into() } - }; + } +} - let is_proc_macro = is_proc_macro(&input.attrs); +fn impl_proc_macro_error(attr: TokenStream2, input: TokenStream2) -> Result { + let (attrs, signature, body) = parse_input(input)?; + let mut settings = parse_settings(attr)?; + + let is_proc_macro = is_proc_macro(&attrs); if is_proc_macro { settings.set(AssertUnwindSafe); } - if detect_proc_macro_hack(&input.attrs) { + if detect_proc_macro_hack(&attrs) { settings.set(ProcMacroHack); } @@ -42,80 +64,27 @@ pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream { } if !(settings.is_set(AllowNotMacro) || is_proc_macro) { - return quote!( - #input - compile_error!( - "#[proc_macro_error] attribute can be used only with a proc-macro\n\n \ - = hint: if you are really sure that #[proc_macro_error] should be applied \ - to this exact function use #[proc_macro_error(allow_not_macro)]\n"); - ) - .into(); + return Err(Error::new( + Span::call_site(), + "#[proc_macro_error] attribute can be used only with procedural macros\n\n \ + = hint: if you are really sure that #[proc_macro_error] should be applied \ + to this exact function, use #[proc_macro_error(allow_not_macro)]\n" + .into(), + )); } - let ItemFn { - attrs, - vis, - sig, - block, - } = input; - - let body = gen_body(*block, settings); + let body = gen_body(body, settings); - quote!( + let res = quote! { #(#attrs)* - #vis - #sig + #(#signature)* { #body } - ) - .into() -} - -#[derive(PartialEq)] -enum Setting { - AssertUnwindSafe, - AllowNotMacro, - ProcMacroHack, -} - -impl Parse for Setting { - fn parse(input: ParseStream) -> syn::Result { - let ident: Ident = input.parse()?; - match &*ident.to_string() { - "assert_unwind_safe" => Ok(AssertUnwindSafe), - "allow_not_macro" => Ok(AllowNotMacro), - "proc_macro_hack" => Ok(ProcMacroHack), - _ => Err(syn::Error::new( - ident.span(), - format!( - "unknown setting `{}`, expected one of \ - `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack`", - ident - ), - )), - } - } -} - -struct Settings(Vec); -impl Parse for Settings { - fn parse(input: ParseStream) -> syn::Result { - let punct = Punctuated::::parse_terminated(input)?; - Ok(Settings(Vec::from_iter(punct))) - } -} - -impl Settings { - fn is_set(&self, setting: Setting) -> bool { - self.0.iter().any(|s| *s == setting) - } - - fn set(&mut self, setting: Setting) { - self.0.push(setting) - } + }; + Ok(res.into()) } #[cfg(not(always_assert_unwind))] -fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream { +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { let is_proc_macro_hack = settings.is_set(ProcMacroHack); let closure = if settings.is_set(AssertUnwindSafe) { quote!(::std::panic::AssertUnwindSafe(|| #block )) @@ -131,7 +100,7 @@ fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream { // Considering this is the closure's return type the unwind safety check would fail // for virtually every closure possible, the check is meaningless. #[cfg(always_assert_unwind)] -fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream { +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { let is_proc_macro_hack = settings.is_set(ProcMacroHack); let closure = quote!(::std::panic::AssertUnwindSafe(|| #block )); quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) ) @@ -140,13 +109,13 @@ fn gen_body(block: Block, settings: Settings) -> proc_macro2::TokenStream { fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool { attrs .iter() - .any(|attr| attr.path.is_ident("proc_macro_hack")) + .any(|attr| attr.path_is_ident("proc_macro_hack")) } fn is_proc_macro(attrs: &[Attribute]) -> bool { attrs.iter().any(|attr| { - attr.path.is_ident("proc_macro") - || attr.path.is_ident("proc_macro_derive") - || attr.path.is_ident("proc_macro_attribute") + attr.path_is_ident("proc_macro") + || attr.path_is_ident("proc_macro_derive") + || attr.path_is_ident("proc_macro_attribute") }) } diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..6f4663f --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,89 @@ +use crate::{Error, Result}; +use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree}; +use quote::ToTokens; +use std::iter::Peekable; + +pub(crate) fn parse_input( + input: TokenStream, +) -> Result<(Vec, Vec, TokenTree)> { + let mut input = input.into_iter().peekable(); + let mut attrs = Vec::new(); + + while let Some(attr) = parse_next_attr(&mut input)? { + attrs.push(attr); + } + + let sig = parse_signature(&mut input); + let body = input.next().ok_or_else(|| { + Error::new( + Span::call_site(), + "`#[proc_macro_error]` can be applied only to functions".to_string(), + ) + })?; + + Ok((attrs, sig, body)) +} + +fn parse_next_attr( + input: &mut Peekable>, +) -> Result> { + let shebang = match input.peek() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => input.next().unwrap(), + _ => return Ok(None), + }; + + let group = match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => { + let res = group.clone(); + input.next(); + res + } + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `[`".to_string())); + } + }; + + let path = match group.stream().into_iter().next() { + Some(TokenTree::Ident(ident)) => Some(ident), + _ => None, + }; + + Ok(Some(Attribute { + shebang, + group: TokenTree::Group(group), + path, + })) +} + +fn parse_signature(input: &mut Peekable>) -> Vec { + let mut sig = Vec::new(); + loop { + match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Brace => { + return sig; + } + None => return sig, + _ => sig.push(input.next().unwrap()), + } + } +} + +pub(crate) struct Attribute { + pub(crate) shebang: TokenTree, + pub(crate) group: TokenTree, + pub(crate) path: Option, +} + +impl Attribute { + pub(crate) fn path_is_ident(&self, ident: &str) -> bool { + self.path.as_ref().map_or(false, |p| *p == ident) + } +} + +impl ToTokens for Attribute { + fn to_tokens(&self, ts: &mut TokenStream) { + self.shebang.to_tokens(ts); + self.group.to_tokens(ts); + } +} diff --git a/src/settings.rs b/src/settings.rs new file mode 100644 index 0000000..0b7ec76 --- /dev/null +++ b/src/settings.rs @@ -0,0 +1,72 @@ +use crate::{Error, Result}; +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; + +macro_rules! decl_settings { + ($($val:expr => $variant:ident),+ $(,)*) => { + #[derive(PartialEq)] + pub(crate) enum Setting { + $($variant),* + } + + fn ident_to_setting(ident: Ident) -> Result { + match &*ident.to_string() { + $($val => Ok(Setting::$variant),)* + _ => { + let possible_vals = [$($val),*] + .iter() + .map(|v| format!("`{}`", v)) + .collect::>() + .join(", "); + + Err(Error::new( + ident.span(), + format!("unknown setting `{}`, expected one of {}", ident, possible_vals))) + } + } + } + }; +} + +decl_settings! { + "assert_unwind_safe" => AssertUnwindSafe, + "allow_not_macro" => AllowNotMacro, + "proc_macro_hack" => ProcMacroHack, +} + +pub(crate) fn parse_settings(input: TokenStream) -> Result { + let mut input = input.into_iter(); + let mut res = Settings(Vec::new()); + loop { + match input.next() { + Some(TokenTree::Ident(ident)) => { + res.0.push(ident_to_setting(ident)?); + } + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected identifier".to_string())); + } + } + + match input.next() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => {} + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `,`".to_string())); + } + } + } +} + +pub(crate) struct Settings(Vec); + +impl Settings { + pub(crate) fn is_set(&self, setting: Setting) -> bool { + self.0.iter().any(|s| *s == setting) + } + + pub(crate) fn set(&mut self, setting: Setting) { + self.0.push(setting) + } +} -- cgit v1.2.3