Upgrade rust/crates/proc-macro-error-attr to 1.0.4

Test: make
Change-Id: I1b773559909dad75543a4d01fbadb69aaa9c05e8
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 @@
     rustlibs: [
         "libproc_macro2",
         "libquote",
-        "libsyn",
-        "libsyn_mid",
     ],
     compile_multilib: "first",
 }
@@ -24,15 +22,11 @@
     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 <creepy-skeleton@yandex.ru>"]
 build = "build.rs"
 description = "Attribute macro for proc-macro-error crate"
@@ -29,13 +29,5 @@
 
 [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 <creepy-skeleton@yandex.ru>"]
 edition = "2018"
 description = "Attribute macro for proc-macro-error crate"
@@ -18,9 +18,6 @@
 [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 @@
   }
   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 proc_macro2::{Literal, Span, TokenStream as TokenStream2, TokenTree};
+use quote::{quote, quote_spanned};
 
-use self::Setting::*;
+use crate::settings::{Setting::*, *};
+
+mod parse;
+mod settings;
+
+type Result<T> = std::result::Result<T, Error>;
+
+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::<Settings>(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);
 
-    let is_proc_macro = is_proc_macro(&input.attrs);
+            quote!(#input #error).into()
+        }
+    }
+}
+
+fn impl_proc_macro_error(attr: TokenStream2, input: TokenStream2) -> Result<TokenStream> {
+    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 @@
     }
 
     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(body, settings);
 
-    let body = gen_body(*block, 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<Self> {
-        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<Setting>);
-impl Parse for Settings {
-    fn parse(input: ParseStream) -> syn::Result<Self> {
-        let punct = Punctuated::<Setting, Token![,]>::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 @@
 // 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 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<Attribute>, Vec<TokenTree>, 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<impl Iterator<Item = TokenTree>>,
+) -> Result<Option<Attribute>> {
+    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<impl Iterator<Item = TokenTree>>) -> Vec<TokenTree> {
+    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<Ident>,
+}
+
+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<Setting> {
+            match &*ident.to_string() {
+                $($val => Ok(Setting::$variant),)*
+                _ => {
+                    let possible_vals = [$($val),*]
+                        .iter()
+                        .map(|v| format!("`{}`", v))
+                        .collect::<Vec<_>>()
+                        .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<Settings> {
+    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<Setting>);
+
+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)
+    }
+}