aboutsummaryrefslogtreecommitdiff
path: root/proc-macro-error/proc-macro-error-attr
diff options
context:
space:
mode:
authorRobin Krahl <robin.krahl@ireas.org>2020-01-07 11:18:04 +0000
committerDaniel Mueller <deso@posteo.net>2020-01-08 09:20:25 -0800
commit5e20a29b4fdc8a2d442d1093681b396dcb4b816b (patch)
tree55ab083fa8999d2ccbb5e921c1ffe52560dca152 /proc-macro-error/proc-macro-error-attr
parent203e691f46d591a2cc8acdfd850fa9f5b0fb8a98 (diff)
downloadnitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.gz
nitrocli-5e20a29b4fdc8a2d442d1093681b396dcb4b816b.tar.bz2
Add structopt dependency in version 0.3.7
This patch series replaces argparse with structopt in the argument handling code. As a first step, we need structopt as a dependency. Import subrepo structopt/:structopt at efbdda4753592e27bc430fb01f7b9650b2f3174d Import subrepo bitflags/:bitflags at 30668016aca6bd3b02c766e8347e0b4080d4c296 Import subrepo clap/:clap at 784524f7eb193e35f81082cc69454c8c21b948f7 Import subrepo heck/:heck at 093d56fbf001e1506e56dbfa38631d99b1066df1 Import subrepo proc-macro-error/:proc-macro-error at 6c4cfe79a622c5de8ae68557993542be46eacae2 Import subrepo proc-macro2/:proc-macro2 at d5d48eddca4566e5438e8a2cbed4a74e049544de Import subrepo quote/:quote at 727436c6c137b20f0f34dde5d8fda2679b9747ad Import subrepo rustversion/:rustversion at 0c5663313516263059ce9059ef81fc7a1cf655ca Import subrepo syn-mid/:syn-mid at 5d3d85414a9e6674e1857ec22a87b96e04a6851a Import subrepo syn/:syn at e87c27e87f6f4ef8919d0372bdb056d53ef0d8f3 Import subrepo textwrap/:textwrap at abcd618beae3f74841032aa5b53c1086b0a57ca2 Import subrepo unicode-segmentation/:unicode-segmentation at 637c9874c4fe0c205ff27787faf150a40295c6c3 Import subrepo unicode-width/:unicode-width at 3033826f8bf05e82724140a981d5941e48fce393 Import subrepo unicode-xid/:unicode-xid at 4baae9fffb156ba229665b972a9cd5991787ceb7
Diffstat (limited to 'proc-macro-error/proc-macro-error-attr')
-rw-r--r--proc-macro-error/proc-macro-error-attr/Cargo.toml18
-rw-r--r--proc-macro-error/proc-macro-error-attr/src/lib.rs162
2 files changed, 180 insertions, 0 deletions
diff --git a/proc-macro-error/proc-macro-error-attr/Cargo.toml b/proc-macro-error/proc-macro-error-attr/Cargo.toml
new file mode 100644
index 0000000..6dee68e
--- /dev/null
+++ b/proc-macro-error/proc-macro-error-attr/Cargo.toml
@@ -0,0 +1,18 @@
+[package]
+name = "proc-macro-error-attr"
+version = "0.4.3"
+authors = ["CreepySkeleton <creepy-skeleton@yandex.ru>"]
+edition = "2018"
+description = "attribute macro for proc-macro-error crate"
+license = "MIT OR Apache-2.0"
+repository = "https://gitlab.com/CreepySkeleton/proc-macro-error"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+quote = "1"
+proc-macro2 = "1"
+syn = { version = "1", default-features = false, features = ["derive", "parsing", "proc-macro"] }
+syn-mid = "0.4"
+rustversion = "1.0"
diff --git a/proc-macro-error/proc-macro-error-attr/src/lib.rs b/proc-macro-error/proc-macro-error-attr/src/lib.rs
new file mode 100644
index 0000000..3c1013b
--- /dev/null
+++ b/proc-macro-error/proc-macro-error-attr/src/lib.rs
@@ -0,0 +1,162 @@
+extern crate proc_macro;
+
+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::*;
+
+#[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();
+ }
+ };
+
+ let is_proc_macro = is_proc_macro(&input.attrs);
+ if is_proc_macro {
+ settings.set(AssertUnwindSafe);
+ }
+
+ if detect_proc_macro_hack(&input.attrs) {
+ settings.set(ProcMacroHack);
+ }
+
+ 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();
+ }
+
+ let ItemFn {
+ attrs,
+ vis,
+ constness,
+ asyncness,
+ unsafety,
+ abi,
+ fn_token,
+ ident,
+ generics,
+ inputs,
+ output,
+ block,
+ ..
+ } = input;
+
+ let body = gen_body(block, settings);
+
+ quote!(
+ #(#attrs)*
+ #vis
+ #constness
+ #asyncness
+ #unsafety
+ #abi
+ #fn_token
+ #ident
+ #generics
+ (#inputs)
+ #output
+
+ { #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)
+ }
+}
+
+#[rustversion::since(1.37)]
+fn gen_body(block: Block, 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 ))
+ } else {
+ quote!(|| #block)
+ };
+
+ quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) )
+}
+
+// FIXME:
+// proc_macro::TokenStream does not implement UnwindSafe until 1.37.0.
+// Considering this is the closure's return type the unwind safety check would fail
+// for virtually every closure possible, the check is meaningless.
+#[rustversion::before(1.37)]
+fn gen_body(block: Block, 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) )
+}
+
+fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool {
+ attrs
+ .iter()
+ .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")
+ })
+}