diff options
author | Haibo Huang <hhb@google.com> | 2020-10-28 22:33:04 -0700 |
---|---|---|
committer | Haibo Huang <hhb@google.com> | 2020-10-28 22:33:04 -0700 |
commit | b0dbc7637be15ee10fab9306685e0d71cf20a76c (patch) | |
tree | a4cc72b6549946f213f519a74047c500a6da8d10 | |
parent | 01d450bf111715e8ad26bb0e3cec6b2dcbb88ce1 (diff) | |
download | proc-macro-hack-b0dbc7637be15ee10fab9306685e0d71cf20a76c.tar.gz |
Upgrade rust/crates/proc-macro-hack to 0.5.19
Test: make
Change-Id: I3ca9b7f663f7fa6b81473e30e37940593c0c4af9
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | .github/workflows/ci.yml | 2 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | Cargo.toml.orig | 2 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README.md | 7 | ||||
-rw-r--r-- | build.rs | 31 | ||||
-rw-r--r-- | src/lib.rs | 128 | ||||
-rw-r--r-- | src/parse.rs | 23 | ||||
-rw-r--r-- | tests/ui/unexpected-arg.rs | 8 | ||||
-rw-r--r-- | tests/ui/unexpected-arg.stderr | 5 | ||||
-rw-r--r-- | tests/ui/unknown-arg.stderr | 2 |
12 files changed, 166 insertions, 54 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 24bc86c..083f3c7 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "3da1be8f9519c725b1f425a954b06a1a0a8b25ac" + "sha1": "758784bb05c3d68569ca5001972fe5c31b8175c5" } } diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca24eac..c4d0fa9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [nightly, beta, stable, 1.42.0, 1.31.0] + rust: [nightly, beta, stable, 1.45.0, 1.42.0, 1.31.0] steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@master @@ -13,7 +13,7 @@ [package] edition = "2018" name = "proc-macro-hack" -version = "0.5.18" +version = "0.5.19" authors = ["David Tolnay <dtolnay@gmail.com>"] description = "Procedural macros in expression position" readme = "README.md" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 153d880..61150b4 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "proc-macro-hack" -version = "0.5.18" +version = "0.5.19" authors = ["David Tolnay <dtolnay@gmail.com>"] edition = "2018" license = "MIT OR Apache-2.0" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/proc-macro-hack/proc-macro-hack-0.5.18.crate" + value: "https://static.crates.io/crates/proc-macro-hack/proc-macro-hack-0.5.19.crate" } - version: "0.5.18" + version: "0.5.19" license_type: NOTICE last_upgrade_date { year: 2020 - month: 7 - day: 26 + month: 10 + day: 28 } } @@ -126,6 +126,13 @@ fn main() { macro input, use `#[proc_macro_hack(fake_call_site)]` on the re-export in your declaration crate. *Most macros won't need this.* +- On compilers that are new enough to natively support proc macros in expression + position, proc-macro-hack does not automatically use that support, since the + hygiene can be subtly different between the two implementations. To opt in to + compiling your macro to native `#[proc_macro]` on sufficiently new compilers, + use `#[proc_macro_hack(only_hack_old_rustc)]` on the re-export in your + declaration crate. + [#10]: https://github.com/dtolnay/proc-macro-hack/issues/10 [#20]: https://github.com/dtolnay/proc-macro-hack/issues/20 [`proc-macro-nested`]: https://docs.rs/proc-macro-nested diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..6ab4098 --- /dev/null +++ b/build.rs @@ -0,0 +1,31 @@ +use std::env; +use std::process::Command; +use std::str; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let minor = match rustc_minor_version() { + Some(minor) => minor, + None => return, + }; + + // Function-like procedural macros in expressions, patterns, and statements + // stabilized in Rust 1.45: + // https://blog.rust-lang.org/2020/07/16/Rust-1.45.0.html#stabilizing-function-like-procedural-macros-in-expressions-patterns-and-statements + if minor < 45 { + println!("cargo:rustc-cfg=need_proc_macro_hack"); + } +} + +fn rustc_minor_version() -> Option<u32> { + let rustc = env::var_os("RUSTC")?; + let output = Command::new(rustc).arg("--version").output().ok()?; + let version = str::from_utf8(&output.stdout).ok()?; + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + pieces.next()?.parse().ok() +} @@ -132,6 +132,14 @@ //! in the macro input, use `#[proc_macro_hack(fake_call_site)]` on the //! re-export in your declaration crate. *Most macros won't need this.* //! +//! - On compilers that are new enough to natively support proc macros in +//! expression position, proc-macro-hack does not automatically use that +//! support, since the hygiene can be subtly different between the two +//! implementations. To opt in to compiling your macro to native +//! `#[proc_macro]` on sufficiently new compilers, use +//! `#[proc_macro_hack(only_hack_old_rustc)]` on the re-export in your +//! declaration crate. +//! //! [#10]: https://github.com/dtolnay/proc-macro-hack/issues/10 //! [#20]: https://github.com/dtolnay/proc-macro-hack/issues/20 //! [`proc-macro-nested`]: https://docs.rs/proc-macro-nested @@ -156,7 +164,7 @@ use crate::parse::{ use proc_macro::{Ident, Punct, Spacing, Span, TokenStream, TokenTree}; use std::fmt::Write; -type Visibility = Option<Span>; +type Visibility = Option<Ident>; enum Input { Export(Export), @@ -244,13 +252,18 @@ struct ExportArgs { support_nested: bool, internal_macro_calls: u16, fake_call_site: bool, + only_hack_old_rustc: bool, } fn expand_export(export: Export, args: ExportArgs) -> TokenStream { + if args.only_hack_old_rustc && cfg!(not(need_proc_macro_hack)) { + return expand_export_nohack(export); + } + let dummy = dummy_name_for_export(&export); let attrs = export.attrs; - let ref vis = export.vis.map(|span| Ident::new("pub", span)); + let vis = export.vis; let macro_export = match vis { Some(_) => quote!(#[macro_export]), None => quote!(), @@ -273,14 +286,14 @@ fn expand_export(export: Export, args: ExportArgs) -> TokenStream { let mut export_call_site = TokenStream::new(); let mut macro_rules = TokenStream::new(); for Macro { name, export_as } in &export.macros { - let actual_name = actual_proc_macro_name(&name); + let hacked = hacked_proc_macro_name(&name); let dispatch = dispatch_macro_name(&name); let call_site = call_site_macro_name(&name); if !actual_names.is_empty() { actual_names.extend(quote!(,)); } - actual_names.extend(quote!(#actual_name)); + actual_names.extend(quote!(#hacked)); if !export_dispatch.is_empty() { export_dispatch.extend(quote!(,)); @@ -294,18 +307,18 @@ fn expand_export(export: Export, args: ExportArgs) -> TokenStream { let do_derive = if !args.fake_call_site { quote! { - #[derive(#crate_prefix #actual_name)] + #[derive(#crate_prefix #hacked)] } } else if crate_prefix.is_some() { quote! { - use #crate_prefix #actual_name; + use #crate_prefix #hacked; #[#crate_prefix #call_site ($($proc_macro)*)] - #[derive(#actual_name)] + #[derive(#hacked)] } } else { quote! { #[#call_site ($($proc_macro)*)] - #[derive(#actual_name)] + #[derive(#hacked)] } }; @@ -375,21 +388,47 @@ fn expand_export(export: Export, args: ExportArgs) -> TokenStream { wrap_in_enum_hack(dummy, expanded) } +fn expand_export_nohack(export: Export) -> TokenStream { + let attrs = export.attrs; + let vis = export.vis; + let from = export.from; + let mut names = TokenStream::new(); + + for Macro { name, export_as } in &export.macros { + let pub_name = pub_proc_macro_name(&name); + if !names.is_empty() { + names.extend(quote!(,)); + } + names.extend(quote!(#pub_name as #export_as)); + } + + if export.macros.len() != 1 { + names = quote!({#names}); + } + + quote! { + #attrs + #vis use #from::#names; + } +} + fn expand_define(define: Define) -> TokenStream { let attrs = define.attrs; let name = define.name; - let dummy = actual_proc_macro_name(&name); + let pub_name = pub_proc_macro_name(&name); + let hacked = hacked_proc_macro_name(&name); let body = define.body; quote! { - mod #dummy { + mod #pub_name { extern crate proc_macro; pub use self::proc_macro::*; } #attrs - #[proc_macro_derive(#dummy)] - pub fn #dummy(input: #dummy::TokenStream) -> #dummy::TokenStream { + #[doc(hidden)] + #[proc_macro_derive(#hacked)] + pub fn #hacked(input: #pub_name::TokenStream) -> #pub_name::TokenStream { use std::iter::FromIterator; let mut iter = input.into_iter(); @@ -399,7 +438,7 @@ fn expand_define(define: Define) -> TokenStream { iter.next().unwrap(); // `[allow(dead_code)]` let mut braces = match iter.next().unwrap() { - #dummy::TokenTree::Group(group) => group.stream().into_iter(), + #pub_name::TokenTree::Group(group) => group.stream().into_iter(), _ => unimplemented!(), }; let variant = braces.next().unwrap(); // `Value` or `Nested` @@ -408,29 +447,29 @@ fn expand_define(define: Define) -> TokenStream { braces.next().unwrap(); // `=` let mut parens = match braces.next().unwrap() { - #dummy::TokenTree::Group(group) => group.stream().into_iter(), + #pub_name::TokenTree::Group(group) => group.stream().into_iter(), _ => unimplemented!(), }; parens.next().unwrap(); // `stringify` parens.next().unwrap(); // `!` let inner = match parens.next().unwrap() { - #dummy::TokenTree::Group(group) => group.stream(), + #pub_name::TokenTree::Group(group) => group.stream(), _ => unimplemented!(), }; - let output: #dummy::TokenStream = #name(inner.clone()); + let output: #pub_name::TokenStream = #name(inner.clone()); - fn count_bangs(input: #dummy::TokenStream) -> usize { + fn count_bangs(input: #pub_name::TokenStream) -> usize { let mut count = 0; for token in input { match token { - #dummy::TokenTree::Punct(punct) => { + #pub_name::TokenTree::Punct(punct) => { if punct.as_char() == '!' { count += 1; } } - #dummy::TokenTree::Group(group) => { + #pub_name::TokenTree::Group(group) => { count += count_bangs(group.stream()); } _ => {} @@ -442,15 +481,15 @@ fn expand_define(define: Define) -> TokenStream { // macro_rules! proc_macro_call { // () => { #output } // } - #dummy::TokenStream::from_iter(vec![ - #dummy::TokenTree::Ident( - #dummy::Ident::new("macro_rules", #dummy::Span::call_site()), + #pub_name::TokenStream::from_iter(vec![ + #pub_name::TokenTree::Ident( + #pub_name::Ident::new("macro_rules", #pub_name::Span::call_site()), ), - #dummy::TokenTree::Punct( - #dummy::Punct::new('!', #dummy::Spacing::Alone), + #pub_name::TokenTree::Punct( + #pub_name::Punct::new('!', #pub_name::Spacing::Alone), ), - #dummy::TokenTree::Ident( - #dummy::Ident::new( + #pub_name::TokenTree::Ident( + #pub_name::Ident::new( &if support_nested { let extra_bangs = if varname == "Nested" { 0 @@ -461,39 +500,52 @@ fn expand_define(define: Define) -> TokenStream { } else { String::from("proc_macro_call") }, - #dummy::Span::call_site(), + #pub_name::Span::call_site(), ), ), - #dummy::TokenTree::Group( - #dummy::Group::new(#dummy::Delimiter::Brace, #dummy::TokenStream::from_iter(vec![ - #dummy::TokenTree::Group( - #dummy::Group::new(#dummy::Delimiter::Parenthesis, #dummy::TokenStream::new()), + #pub_name::TokenTree::Group( + #pub_name::Group::new(#pub_name::Delimiter::Brace, #pub_name::TokenStream::from_iter(vec![ + #pub_name::TokenTree::Group( + #pub_name::Group::new(#pub_name::Delimiter::Parenthesis, #pub_name::TokenStream::new()), ), - #dummy::TokenTree::Punct( - #dummy::Punct::new('=', #dummy::Spacing::Joint), + #pub_name::TokenTree::Punct( + #pub_name::Punct::new('=', #pub_name::Spacing::Joint), ), - #dummy::TokenTree::Punct( - #dummy::Punct::new('>', #dummy::Spacing::Alone), + #pub_name::TokenTree::Punct( + #pub_name::Punct::new('>', #pub_name::Spacing::Alone), ), - #dummy::TokenTree::Group( - #dummy::Group::new(#dummy::Delimiter::Brace, output), + #pub_name::TokenTree::Group( + #pub_name::Group::new(#pub_name::Delimiter::Brace, output), ), ])), ), ]) } + #attrs + #[proc_macro] + pub fn #pub_name(input: #pub_name::TokenStream) -> #pub_name::TokenStream { + #name(input) + } + fn #name #body } } -fn actual_proc_macro_name(conceptual: &Ident) -> Ident { +fn pub_proc_macro_name(conceptual: &Ident) -> Ident { Ident::new( &format!("proc_macro_hack_{}", conceptual), conceptual.span(), ) } +fn hacked_proc_macro_name(conceptual: &Ident) -> Ident { + Ident::new( + &format!("_proc_macro_hack_{}", conceptual), + conceptual.span(), + ) +} + fn dispatch_macro_name(conceptual: &Ident) -> Ident { Ident::new( &format!("proc_macro_call_{}", conceptual), diff --git a/src/parse.rs b/src/parse.rs index de7c599..fe074f1 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -139,7 +139,10 @@ fn parse_group(tokens: Iter, delimiter: Delimiter) -> Result<IterImpl, Error> { fn parse_visibility(tokens: Iter) -> Result<Visibility, Error> { if let Some(TokenTree::Ident(ident)) = tokens.peek() { if ident.to_string() == "pub" { - return Ok(Some(tokens.next().unwrap().span())); + match tokens.next().unwrap() { + TokenTree::Ident(vis) => return Ok(Some(vis)), + _ => unreachable!(), + } } } Ok(None) @@ -168,6 +171,7 @@ pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> { support_nested: false, internal_macro_calls: 0, fake_call_site: false, + only_hack_old_rustc: false, }; while let Some(tt) = tokens.next() { @@ -185,11 +189,14 @@ pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> { TokenTree::Ident(ident) if ident.to_string() == "fake_call_site" => { args.fake_call_site = true; } + TokenTree::Ident(ident) if ident.to_string() == "only_hack_old_rustc" => { + args.only_hack_old_rustc = true; + } _ => { return Err(Error::new( tt.span(), - "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`", - )) + "expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`, `only_hack_old_rustc`", + )); } } if tokens.peek().is_none() { @@ -202,10 +209,12 @@ pub(crate) fn parse_export_args(tokens: Iter) -> Result<ExportArgs, Error> { } pub(crate) fn parse_define_args(tokens: Iter) -> Result<(), Error> { - if tokens.peek().is_none() { - Ok(()) - } else { - Err(Error::new(Span::call_site(), "unexpected input")) + match tokens.peek() { + None => Ok(()), + Some(token) => Err(Error::new( + token.span(), + "unexpected argument to proc_macro_hack macro implementation; args are only accepted on the macro declaration (the `pub use`)", + )), } } diff --git a/tests/ui/unexpected-arg.rs b/tests/ui/unexpected-arg.rs new file mode 100644 index 0000000..376fc0d --- /dev/null +++ b/tests/ui/unexpected-arg.rs @@ -0,0 +1,8 @@ +use proc_macro_hack::proc_macro_hack; + +#[proc_macro_hack(fake_call_site)] +pub fn my_macro(input: TokenStream) -> TokenStream { + unimplemented!() +} + +fn main() {} diff --git a/tests/ui/unexpected-arg.stderr b/tests/ui/unexpected-arg.stderr new file mode 100644 index 0000000..6895e82 --- /dev/null +++ b/tests/ui/unexpected-arg.stderr @@ -0,0 +1,5 @@ +error: unexpected argument to proc_macro_hack macro implementation; args are only accepted on the macro declaration (the `pub use`) + --> $DIR/unexpected-arg.rs:3:19 + | +3 | #[proc_macro_hack(fake_call_site)] + | ^^^^^^^^^^^^^^ diff --git a/tests/ui/unknown-arg.stderr b/tests/ui/unknown-arg.stderr index d3cd8c9..ffe3705 100644 --- a/tests/ui/unknown-arg.stderr +++ b/tests/ui/unknown-arg.stderr @@ -1,4 +1,4 @@ -error: expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site` +error: expected one of: `support_nested`, `internal_macro_calls`, `fake_call_site`, `only_hack_old_rustc` --> $DIR/unknown-arg.rs:3:35 | 3 | #[proc_macro_hack(fake_call_site, support_nexted)] |