From 46529f788f1b49cc21250e176635271e0e54801c Mon Sep 17 00:00:00 2001 From: Folyd Date: Sun, 6 Dec 2020 20:56:39 +0800 Subject: [PATCH 01/66] Fix intra rustdoc link todos --- src/attr.rs | 5 +---- src/data.rs | 10 ++-------- src/derive.rs | 5 +---- src/error.rs | 4 ++-- src/generics.rs | 4 ++-- src/item.rs | 25 +++++-------------------- src/lib.rs | 16 ++++++++-------- src/lit.rs | 5 +---- src/parse.rs | 23 ++++++++++------------- src/pat.rs | 5 +---- src/punctuated.rs | 2 +- src/spanned.rs | 4 ++-- src/token.rs | 16 ++++++++-------- src/ty.rs | 5 +---- 14 files changed, 45 insertions(+), 84 deletions(-) diff --git a/src/attr.rs b/src/attr.rs index 2db1364bb7..1d82190ea1 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -357,10 +357,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Meta { Path(Path), diff --git a/src/data.rs b/src/data.rs index 93d8119cc0..731f5a0a7e 100644 --- a/src/data.rs +++ b/src/data.rs @@ -32,10 +32,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Fields { /// Named fields of a struct or struct variant such as `Point { x: f64, @@ -184,10 +181,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Visibility { /// A public visibility level: `pub`. diff --git a/src/derive.rs b/src/derive.rs index 835fbda630..af9bb91b7a 100644 --- a/src/derive.rs +++ b/src/derive.rs @@ -33,10 +33,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "derive")))] pub enum Data { /// A struct input to a `proc_macro_derive` macro. diff --git a/src/error.rs b/src/error.rs index cc74c74459..803b6feac5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -23,7 +23,7 @@ pub type Result = std::result::Result; /// [`compile_error!`] in the generated code. This produces a better diagnostic /// message than simply panicking the macro. /// -/// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html +/// [`compile_error!`]: std::compile_error! /// /// When parsing macro input, the [`parse_macro_input!`] macro handles the /// conversion to `compile_error!` automatically. @@ -189,7 +189,7 @@ impl Error { /// The [`parse_macro_input!`] macro provides a convenient way to invoke /// this method correctly in a procedural macro. /// - /// [`compile_error!`]: https://doc.rust-lang.org/std/macro.compile_error.html + /// [`compile_error!`]: std::compile_error! pub fn to_compile_error(&self) -> TokenStream { self.messages .iter() diff --git a/src/generics.rs b/src/generics.rs index 64228f81b1..a78af22ec6 100644 --- a/src/generics.rs +++ b/src/generics.rs @@ -31,7 +31,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum GenericParam { /// A generic type parameter: `T: Into`. @@ -538,7 +538,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum WherePredicate { /// A type predicate in a `where` clause: `for<'c> Foo<'c>: Trait<'c>`. diff --git a/src/item.rs b/src/item.rs index 4041c53950..5ac75537fa 100644 --- a/src/item.rs +++ b/src/item.rs @@ -15,10 +15,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum Item { /// A constant item: `const MAX: u16 = 65535`. @@ -454,10 +451,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum UseTree { /// A path prefix of imports in a `use` item: `std::...`. @@ -541,10 +535,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum ForeignItem { /// A foreign function in an `extern` block. @@ -632,10 +623,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum TraitItem { /// An associated constant within the definition of a trait. @@ -725,10 +713,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum ImplItem { /// An associated constant within an impl block. diff --git a/src/lib.rs b/src/lib.rs index 8c3ea217e0..f792974036 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](https://docs.rs/syn) +//! [![github]](https://github.com/dtolnay/syn) [![crates-io]](https://crates.io/crates/syn) [![docs-rs]](crate) //! //! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github //! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust @@ -39,12 +39,12 @@ //! procedural macros enable only what they need, and do not pay in compile //! time for all the rest. //! -//! [`syn::File`]: struct.File.html -//! [`syn::Item`]: enum.Item.html -//! [`syn::Expr`]: enum.Expr.html -//! [`syn::Type`]: enum.Type.html -//! [`syn::DeriveInput`]: struct.DeriveInput.html -//! [parser functions]: parse/index.html +//! [`syn::File`]: File +//! [`syn::Item`]: Item +//! [`syn::Expr`]: Expr +//! [`syn::Type`]: Type +//! [`syn::DeriveInput`]: DeriveInput +//! [parser functions]: mod@parse //! //!
//! @@ -58,7 +58,7 @@ //! tokens, then hand some tokens back to the compiler to compile into the //! user's crate. //! -//! [`TokenStream`]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html +//! [`TokenStream`]: proc_macro::TokenStream //! //! ```toml //! [dependencies] diff --git a/src/lit.rs b/src/lit.rs index 3780648665..3e170a996b 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -21,10 +21,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums pub enum Lit { /// A UTF-8 string literal: `"foo"`. Str(LitStr), diff --git a/src/parse.rs b/src/parse.rs index f771daf367..d85968bd24 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -6,9 +6,8 @@ //! [`Cursor`] type. `Cursor` is a cheaply copyable cursor over a range of //! tokens in a token stream. //! -//! [`ParseStream`]: type.ParseStream.html -//! [`Result`]: type.Result.html -//! [`Cursor`]: ../buffer/index.html +//! [`Result`]: Result +//! [`Cursor`]: crate::buffer::Cursor //! //! # Example //! @@ -23,7 +22,7 @@ //! procedural macro, they will receive a helpful compiler error message //! pointing out the exact token that triggered the failure to parse. //! -//! [`parse_macro_input!`]: ../macro.parse_macro_input.html +//! [`parse_macro_input!`]: crate::parse_macro_input! //! //! ``` //! # extern crate proc_macro; @@ -96,10 +95,9 @@ //! obvious default way. These functions can return any syntax tree node that //! implements the [`Parse`] trait, which includes most types in Syn. //! -//! [`syn::parse`]: ../fn.parse.html -//! [`syn::parse2`]: ../fn.parse2.html -//! [`syn::parse_str`]: ../fn.parse_str.html -//! [`Parse`]: trait.Parse.html +//! [`syn::parse`]: crate::parse() +//! [`syn::parse2`]: crate::parse2() +//! [`syn::parse_str`]: crate::parse_str() //! //! ``` //! use syn::Type; @@ -114,7 +112,7 @@ //! //! The [`parse_quote!`] macro also uses this approach. //! -//! [`parse_quote!`]: ../macro.parse_quote.html +//! [`parse_quote!`]: crate::parse_quote! //! //! # The `Parser` trait //! @@ -124,8 +122,8 @@ //! may or may not allow trailing punctuation, and parsing it the wrong way //! would either reject valid input or accept invalid input. //! -//! [`Attribute`]: ../struct.Attribute.html -//! [`Punctuated`]: ../punctuated/index.html +//! [`Attribute`]: crate::Attribute +//! [`Punctuated`]: crate::punctuated //! //! The `Parse` trait is not implemented in these cases because there is no good //! behavior to consider the default. @@ -150,7 +148,6 @@ //! single `Parse` implementation, and those parser functions can be invoked //! through the [`Parser`] trait. //! -//! [`Parser`]: trait.Parser.html //! //! ``` //! # extern crate proc_macro; @@ -248,7 +245,7 @@ pub type ParseStream<'a> = &'a ParseBuffer<'a>; /// - One of [the `syn::parse*` functions][syn-parse]; or /// - A method of the [`Parser`] trait. /// -/// [syn-parse]: index.html#the-synparse-functions +/// [syn-parse]: self#the-synparse-functions pub struct ParseBuffer<'a> { scope: Span, // Instead of Cell> so that ParseBuffer<'a> is covariant in 'a. diff --git a/src/pat.rs b/src/pat.rs index 541e9823c3..5381076944 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -12,10 +12,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(feature = "full")))] pub enum Pat { /// A box pattern: `box v`. diff --git a/src/punctuated.rs b/src/punctuated.rs index 595922c61e..a026b8e2d7 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -13,7 +13,7 @@ //! syntax tree node + punctuation, where every node in the sequence is followed //! by punctuation except for possibly the final one. //! -//! [`Punctuated`]: struct.Punctuated.html +//! [`Punctuated`]: Punctuated //! //! ```text //! a_function_call(arg1, arg2, arg3); diff --git a/src/spanned.rs b/src/spanned.rs index 01591cedcb..d51ffb3fa5 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -13,8 +13,8 @@ //! of a struct for which we are deriving a trait implementation, and we need to //! be able to pass a reference to one of those fields across threads. //! -//! [`Type`]: ../enum.Type.html -//! [`Sync`]: https://doc.rust-lang.org/std/marker/trait.Sync.html +//! [`Type`]: crate::Type +//! [`Sync`]: std::marker::Sync //! //! If the field type does *not* implement `Sync` as required, we want the //! compiler to report an error pointing out exactly which type it was. diff --git a/src/token.rs b/src/token.rs index 4bedbbb0ac..2208b07d04 100644 --- a/src/token.rs +++ b/src/token.rs @@ -4,13 +4,13 @@ //! prefer to use the [`Token!`] macro instead. This is a type-macro that //! expands to the token type of the given token. //! -//! [`Token!`]: ../macro.Token.html +//! [`Token!`]: crate::Token //! //! # Example //! //! The [`ItemStatic`] syntax tree node is defined like this. //! -//! [`ItemStatic`]: ../struct.ItemStatic.html +//! [`ItemStatic`]: crate::ItemStatic //! //! ``` //! # use syn::{Attribute, Expr, Ident, Token, Type, Visibility}; @@ -35,10 +35,10 @@ //! method. Delimiter tokens are parsed using the [`parenthesized!`], //! [`bracketed!`] and [`braced!`] macros. //! -//! [`ParseStream::parse`]: ../parse/struct.ParseBuffer.html#method.parse -//! [`parenthesized!`]: ../macro.parenthesized.html -//! [`bracketed!`]: ../macro.bracketed.html -//! [`braced!`]: ../macro.braced.html +//! [`ParseStream::parse`]: crate::parse::ParseBuffer::parse() +//! [`parenthesized!`]: crate::parenthesized! +//! [`bracketed!`]: crate::bracketed! +//! [`braced!`]: crate::braced! //! //! ``` //! use syn::{Attribute, Result}; @@ -83,8 +83,8 @@ //! //! - Field access to its span — `let sp = the_token.span` //! -//! [Peeking]: ../parse/struct.ParseBuffer.html#method.peek -//! [Parsing]: ../parse/struct.ParseBuffer.html#method.parse +//! [Peeking]: crate::parse::ParseBuffer::peek() +//! [Parsing]: crate::parse::ParseBuffer::parse() //! [Printing]: https://docs.rs/quote/1.0/quote/trait.ToTokens.html //! [`Span`]: https://docs.rs/proc-macro2/1.0/proc_macro2/struct.Span.html diff --git a/src/ty.rs b/src/ty.rs index 4f995d5a19..6e493e05b7 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -12,10 +12,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: enum.Expr.html#syntax-tree-enums - // - // TODO: change syntax-tree-enum link to an intra rustdoc link, currently - // blocked on https://github.com/rust-lang/rust/issues/62833 + /// [syntax tree enum]: Expr#syntax-tree-enums #[cfg_attr(doc_cfg, doc(cfg(any(feature = "full", feature = "derive"))))] pub enum Type { /// A fixed size array type: `[T; n]`. From 69148aa2ff558bb4f10322ecc9ab505c4b835aba Mon Sep 17 00:00:00 2001 From: Folyd Date: Mon, 7 Dec 2020 11:36:49 +0800 Subject: [PATCH 02/66] Fix broken Expr intra-doc link --- src/lit.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lit.rs b/src/lit.rs index 3e170a996b..d67ee88426 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -21,7 +21,7 @@ ast_enum_of_structs! { /// /// This type is a [syntax tree enum]. /// - /// [syntax tree enum]: Expr#syntax-tree-enums + /// [syntax tree enum]: crate::Expr#syntax-tree-enums pub enum Lit { /// A UTF-8 string literal: `"foo"`. Str(LitStr), From 824453c5e16db856be98b1302f02e3dec8bf46b5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 6 Dec 2020 19:45:13 -0800 Subject: [PATCH 03/66] Add a rustdoc job to CI --- .github/workflows/ci.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ebf7161687..83d99c3a31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,6 +74,16 @@ jobs: - run: cargo check --manifest-path examples/lazy-static/example/Cargo.toml - run: cargo check --manifest-path examples/trace-var/example/Cargo.toml + docs: + name: Docs + runs-on: ubuntu-latest + env: + RUSTDOCFLAGS: --cfg=doc_cfg -Dbroken_intra_doc_links + steps: + - uses: actions/checkout@v2 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo doc --all-features + codegen: name: Codegen runs-on: ubuntu-latest From 1cf44e4ec8ccd77c8a81b3bb4f03731517bbdd61 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 7 Dec 2020 10:31:06 -0800 Subject: [PATCH 04/66] Add test of impl containing macro variables --- tests/test_item.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/tests/test_item.rs b/tests/test_item.rs index 74ac4baec6..790e8a7f52 100644 --- a/tests/test_item.rs +++ b/tests/test_item.rs @@ -43,3 +43,44 @@ fn test_macro_variable_attr() { } "###); } + +#[test] +fn test_macro_variable_impl() { + // mimics the token stream corresponding to `impl $trait for $ty {}` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("impl", Span::call_site())), + TokenTree::Group(Group::new(Delimiter::None, quote!(Trait))), + TokenTree::Ident(Ident::new("for", Span::call_site())), + TokenTree::Group(Group::new(Delimiter::None, quote!(Type))), + TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new())), + ]); + + snapshot!(tokens as Item, @r###" + Item::Impl { + generics: Generics, + trait_: Some(( + None, + Path { + segments: [ + PathSegment { + ident: "Trait", + arguments: None, + }, + ], + }, + )), + self_ty: Type::Group { + elem: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Type", + arguments: None, + }, + ], + }, + }, + }, + } + "###); +} From 856192f32198ccaff23d978f6a7eb83528dbc25a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 7 Dec 2020 10:37:56 -0800 Subject: [PATCH 05/66] Fix impl parsing with None-delimited grouped path --- src/item.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/item.rs b/src/item.rs index 5ac75537fa..883ecc799f 100644 --- a/src/item.rs +++ b/src/item.rs @@ -2372,15 +2372,26 @@ pub mod parsing { None }; - let first_ty: Type = input.parse()?; + let mut first_ty: Type = input.parse()?; let self_ty: Type; let trait_; let is_impl_for = input.peek(Token![for]); if is_impl_for { let for_token: Token![for] = input.parse()?; - if let Type::Path(TypePath { qself: None, path }) = first_ty { - trait_ = Some((polarity, path, for_token)); + let mut first_ty_ref = &first_ty; + while let Type::Group(ty) = first_ty_ref { + first_ty_ref = &ty.elem; + } + if let Type::Path(_) = first_ty_ref { + while let Type::Group(ty) = first_ty { + first_ty = *ty.elem; + } + if let Type::Path(TypePath { qself: None, path }) = first_ty { + trait_ = Some((polarity, path, for_token)); + } else { + unreachable!() + } } else { trait_ = None; } From 46987a504bc9aa7c4af952dc4fcd96676fa73251 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 7 Dec 2020 10:48:20 -0800 Subject: [PATCH 06/66] Release 1.0.54 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 32b27eeb8d..d82d69c6d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.53" # don't forget to update html_root_url and syn.json +version = "1.0.54" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index f792974036..b052b59255 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.53")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.54")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index 7e7a659b52..abab356d0b 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.53", + "version": "1.0.54", "types": [ { "ident": "Abi", From 4dd4ecf0be2ba0ed0df708e818ff47400bcbbe64 Mon Sep 17 00:00:00 2001 From: sharnoff Date: Thu, 10 Dec 2020 19:06:18 +0000 Subject: [PATCH 07/66] update `File` example program output --- src/file.rs | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/file.rs b/src/file.rs index 6216016145..280484f980 100644 --- a/src/file.rs +++ b/src/file.rs @@ -51,21 +51,29 @@ ast_struct! { /// shebang: None, /// attrs: [], /// items: [ - /// ExternCrate( - /// ItemExternCrate { + /// Use( + /// ItemUse { /// attrs: [], /// vis: Inherited, - /// extern_token: Extern, - /// crate_token: Crate, - /// ident: Ident { - /// term: Term( - /// "syn" - /// ), - /// span: Span - /// }, - /// rename: None, - /// semi_token: Semi - /// } + /// use_token: Use, + /// leading_colon: None, + /// tree: Path( + /// UsePath { + /// ident: Ident( + /// std, + /// ), + /// colon2_token: Colon2, + /// tree: Name( + /// UseName { + /// ident: Ident( + /// env, + /// ), + /// }, + /// ), + /// }, + /// ), + /// semi_token: Semi, + /// }, /// ), /// ... /// ``` From 48d89ef80dc5352a938fae6ba9fa26b7e8d74b3b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 10 Dec 2020 18:49:10 -0800 Subject: [PATCH 08/66] Fix interpolated NtExpr comparison for nightly-2020-12-11 --- tests/common/eq.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 4783dd8367..8c33aa60da 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -20,7 +20,7 @@ use rustc_ast::ast::{ WherePredicate, WhereRegionPredicate, }; use rustc_ast::ptr::P; -use rustc_ast::token::{self, CommentKind, DelimToken, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, DelimToken, Nonterminal, Token, TokenKind}; use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::thin_vec::ThinVec; @@ -452,6 +452,14 @@ impl SpanlessEq for TokenKind { TokenKind::DotDotEq | TokenKind::DotDotDot => true, _ => false, }, + (TokenKind::Interpolated(this), TokenKind::Interpolated(other)) => { + match (this.as_ref(), other.as_ref()) { + (Nonterminal::NtExpr(this), Nonterminal::NtExpr(other)) => { + SpanlessEq::eq(this, other) + } + _ => this == other, + } + } _ => self == other, } } From f0308cb9132e177de1b644a9d9f0580d7cdde369 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 10 Dec 2020 18:58:55 -0800 Subject: [PATCH 09/66] Fix DocComment vs Token comparison for nightly-2020-12-11 --- tests/common/eq.rs | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 8c33aa60da..fc35b82712 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -542,7 +542,7 @@ fn doc_comment<'a>( } fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> bool { - match trees.next() { + match match trees.next() { Some(TokenTree::Token(Token { kind: TokenKind::Literal( @@ -555,17 +555,27 @@ fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> b }, ), span: _, - })) => match Lit::from_lit_token(*lit, DUMMY_SP) { - Ok(Lit { - token: _, - kind: LitKind::Str(symbol, StrStyle::Cooked), - span: _, - }) => { - symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', "") - && trees.next().is_none() - } - _ => false, + })) => Lit::from_lit_token(*lit, DUMMY_SP), + Some(TokenTree::Token(Token { + kind: TokenKind::Interpolated(nonterminal), + span: _, + })) => match nonterminal.as_ref() { + Nonterminal::NtExpr(expr) => match &expr.kind { + ExprKind::Lit(lit) => Ok(lit.clone()), + _ => return false, + }, + _ => return false, }, + _ => return false, + } { + Ok(Lit { + token: _, + kind: LitKind::Str(symbol, StrStyle::Cooked), + span: _, + }) => { + symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', "") + && trees.next().is_none() + } _ => false, } } From 5c2886db9b7d59fdd54cd4a1576629c3ffee9972 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 10 Dec 2020 19:11:04 -0800 Subject: [PATCH 10/66] Simplify Str token identification --- tests/common/eq.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index fc35b82712..2f72182755 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -544,16 +544,7 @@ fn doc_comment<'a>( fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> bool { match match trees.next() { Some(TokenTree::Token(Token { - kind: - TokenKind::Literal( - lit - @ - token::Lit { - kind: token::LitKind::Str, - symbol: _, - suffix: None, - }, - ), + kind: TokenKind::Literal(lit), span: _, })) => Lit::from_lit_token(*lit, DUMMY_SP), Some(TokenTree::Token(Token { @@ -569,7 +560,12 @@ fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> b _ => return false, } { Ok(Lit { - token: _, + token: + token::Lit { + kind: token::LitKind::Str, + symbol: _, + suffix: None, + }, kind: LitKind::Str(symbol, StrStyle::Cooked), span: _, }) => { From 1eabf0e4596938108428b6cccc8b4dc105fd2f46 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 12 Dec 2020 09:05:15 -0800 Subject: [PATCH 11/66] Force tar dependency >=0.4.16 That patch release fixes this vulnerability: https://rustsec.org/advisories/RUSTSEC-2018-0002.html --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d82d69c6d3..33f65f35d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,7 +48,7 @@ ref-cast = "1.0" regex = "1.0" reqwest = { version = "0.10", features = ["blocking"] } syn-test-suite = { version = "0", path = "tests/features" } -tar = "0.4" +tar = "0.4.16" termcolor = "1.0" walkdir = "2.1" From ac3905b23711cc9729d8138fa72073692dfac7fb Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 12 Dec 2020 16:08:08 -0500 Subject: [PATCH 12/66] Fix parsing of path type wrapped in a `None`-delimited group Previously, `peek2` was used to check for `::` or `<` following a `None`-delimited group. However, `peek2` will look *inside*` a `None`-delimited group, so this code would treat input like `{{ Vec }}` as having an angle bracket *after* the `None`-delimited group. We now consume the `None`-delimited group by parsing it, and then use `peek` to check for tokens that occur *after* the `None`-delimited group. --- src/ty.rs | 13 ++++++++++-- tests/test_ty.rs | 52 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/ty.rs b/src/ty.rs index 6e493e05b7..bbacd8487b 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -342,8 +342,17 @@ pub mod parsing { } fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result { - if input.peek(token::Group) && !input.peek2(Token![::]) && !input.peek2(Token![<]) { - return input.parse().map(Type::Group); + if input.peek(token::Group) { + let forked = input.fork(); + // Consume the group, and check for a `::` or `<` *after* it + // This ensure that we match `$ty`, and not `$ty` + // where `$ty` is `SomeType. + // We cannot use `peek2`, since it looks *inside* a `None`-delimited + // group + let _ = forked.parse().map(Type::Group); + if !forked.peek(Token![::]) && !forked.peek(Token![<]) { + return input.parse().map(Type::Group); + } } let begin = input.fork(); diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 9cbdcd6b99..1523391222 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -51,3 +51,55 @@ fn test_macro_variable_type() { } "###); } + +#[test] +fn test_group_angle_brackets() { + // mimics the token stream corresponding to `$ty` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("Option", Span::call_site())), + TokenTree::Punct(Punct::new('<', Spacing::Alone)), + TokenTree::Group(Group::new(Delimiter::None, quote! { Vec })), + TokenTree::Punct(Punct::new('>', Spacing::Alone)), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Option", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Group { + elem: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + ], + }, + }, + }), + ], + }, + }, + ], + }, + } + "###); +} From 5822aeabaad20a71262bef3405cd945398d44dcc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 18 Dec 2020 18:35:02 -0800 Subject: [PATCH 13/66] Add test of path type wrapped in None-delimited group --- tests/test_ty.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 9cbdcd6b99..47c20041f3 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -51,3 +51,53 @@ fn test_macro_variable_type() { } "###); } + +#[test] +fn test_group_angle_brackets() { + // mimics the token stream corresponding to `Option<$ty>` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("Option", Span::call_site())), + TokenTree::Punct(Punct::new('<', Spacing::Alone)), + TokenTree::Group(Group::new(Delimiter::None, quote! { Vec })), + TokenTree::Punct(Punct::new('>', Spacing::Alone)), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Option", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + ], + }, + }), + ], + }, + }, + ], + }, + } + "###); +} From f492305aa019aaa0b1f4d89eb37e5c469cd20e11 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 18 Dec 2020 18:38:02 -0800 Subject: [PATCH 14/66] Preserve None-delimited group around path type --- src/path.rs | 28 +++++++++++++++++++--------- src/ty.rs | 36 +++++++++++++++++++++++++++++++++--- tests/test_ty.rs | 42 ++++++++++++++++++++++-------------------- 3 files changed, 74 insertions(+), 32 deletions(-) diff --git a/src/path.rs b/src/path.rs index a2b42241e1..31a80e59f6 100644 --- a/src/path.rs +++ b/src/path.rs @@ -499,22 +499,32 @@ pub mod parsing { } } - fn parse_helper(input: ParseStream, expr_style: bool) -> Result { - Ok(Path { + pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result { + let mut path = Path { leading_colon: input.parse()?, segments: { let mut segments = Punctuated::new(); let value = PathSegment::parse_helper(input, expr_style)?; segments.push_value(value); - while input.peek(Token![::]) { - let punct: Token![::] = input.parse()?; - segments.push_punct(punct); - let value = PathSegment::parse_helper(input, expr_style)?; - segments.push_value(value); - } segments }, - }) + }; + Path::parse_rest(input, &mut path, expr_style)?; + Ok(path) + } + + pub(crate) fn parse_rest( + input: ParseStream, + path: &mut Self, + expr_style: bool, + ) -> Result<()> { + while input.peek(Token![::]) { + let punct: Token![::] = input.parse()?; + path.segments.push_punct(punct); + let value = PathSegment::parse_helper(input, expr_style)?; + path.segments.push_value(value); + } + Ok(()) } } diff --git a/src/ty.rs b/src/ty.rs index 6e493e05b7..d9a75b15d2 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -342,11 +342,41 @@ pub mod parsing { } fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result { - if input.peek(token::Group) && !input.peek2(Token![::]) && !input.peek2(Token![<]) { - return input.parse().map(Type::Group); + let begin = input.fork(); + + if input.peek(token::Group) { + let mut group: TypeGroup = input.parse()?; + if input.peek(Token![::]) && input.peek3(Ident::peek_any) { + if let Type::Path(mut ty) = *group.elem { + Path::parse_rest(input, &mut ty.path, false)?; + return Ok(Type::Path(ty)); + } else { + return Ok(Type::Path(TypePath { + qself: Some(QSelf { + lt_token: Token![<](group.group_token.span), + position: 0, + as_token: None, + gt_token: Token![>](group.group_token.span), + ty: group.elem, + }), + path: Path::parse_helper(input, false)?, + })); + } + } else if input.peek(Token![<]) { + if let Type::Path(mut ty) = *group.elem { + let arguments = &mut ty.path.segments.last_mut().unwrap().arguments; + if let PathArguments::None = arguments { + *arguments = PathArguments::AngleBracketed(input.parse()?); + Path::parse_rest(input, &mut ty.path, false)?; + return Ok(Type::Path(ty)); + } else { + group.elem = Box::new(Type::Path(ty)); + } + } + } + return Ok(Type::Group(group)); } - let begin = input.fork(); let mut lifetimes = None::; let mut lookahead = input.lookahead1(); if lookahead.peek(Token![for]) { diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 47c20041f3..546ff88290 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -70,27 +70,29 @@ fn test_group_angle_brackets() { ident: "Option", arguments: PathArguments::AngleBracketed { args: [ - Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "Vec", - arguments: PathArguments::AngleBracketed { - args: [ - Type(Type::Path { - path: Path { - segments: [ - PathSegment { - ident: "u8", - arguments: None, - }, - ], - }, - }), - ], + Type(Type::Group { + elem: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }), + ], + }, }, - }, - ], + ], + }, }, }), ], From 0a2e4e38b3f598e96125bd2c29df158894ab4990 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 20 Dec 2020 12:22:20 -0800 Subject: [PATCH 15/66] Add test of $ty::Item --- tests/test_ty.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 546ff88290..12eb81b35d 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -103,3 +103,80 @@ fn test_group_angle_brackets() { } "###); } + +#[test] +fn test_group_colons() { + // mimics the token stream corresponding to `$ty::Item` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Group(Group::new(Delimiter::None, quote! { Vec })), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("Item", Span::call_site())), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + PathSegment { + ident: "Item", + arguments: None, + }, + ], + }, + } + "###); + + let tokens = TokenStream::from_iter(vec![ + TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("Element", Span::call_site())), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + qself: Some(QSelf { + ty: Type::Slice { + elem: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "T", + arguments: None, + }, + ], + }, + }, + }, + position: 0, + }), + path: Path { + leading_colon: Some, + segments: [ + PathSegment { + ident: "Element", + arguments: None, + }, + ], + }, + } + "###); +} From d5d299017269092c4f4186c3d644deb6df1f0d0f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 20 Dec 2020 12:52:13 -0800 Subject: [PATCH 16/66] Add test of $ty:: --- src/ty.rs | 2 +- tests/test_ty.rs | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/ty.rs b/src/ty.rs index d9a75b15d2..eacae3b5db 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -362,7 +362,7 @@ pub mod parsing { path: Path::parse_helper(input, false)?, })); } - } else if input.peek(Token![<]) { + } else if input.peek(Token![<]) || input.peek(Token![::]) && input.peek3(Token![<]) { if let Type::Path(mut ty) = *group.elem { let arguments = &mut ty.path.segments.last_mut().unwrap().arguments; if let PathArguments::None = arguments { diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 12eb81b35d..7e20dd9936 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -50,6 +50,43 @@ fn test_macro_variable_type() { }, } "###); + + // mimics the token stream corresponding to `$ty::` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Group(Group::new(Delimiter::None, quote! { ty })), + TokenTree::Punct(Punct::new(':', Spacing::Joint)), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Punct(Punct::new('<', Spacing::Alone)), + TokenTree::Ident(Ident::new("T", Span::call_site())), + TokenTree::Punct(Punct::new('>', Spacing::Alone)), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "ty", + arguments: PathArguments::AngleBracketed { + colon2_token: Some, + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "T", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + ], + }, + } + "###); } #[test] From 81a3d51dc1eda49c9bbe2190c77a6aef84898895 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 20 Dec 2020 13:06:04 -0800 Subject: [PATCH 17/66] Release 1.0.55 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33f65f35d8..12c810422d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.54" # don't forget to update html_root_url and syn.json +version = "1.0.55" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index b052b59255..6b6293e704 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.54")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.55")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index abab356d0b..9d06f086b1 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.54", + "version": "1.0.55", "types": [ { "ident": "Abi", From b341361011acf8fe93082e795864ad797f83e608 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 21 Dec 2020 19:09:20 -0800 Subject: [PATCH 18/66] Ignore redundant_else pedantic clippy lint --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 6b6293e704..dbd1f87c62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -286,6 +286,7 @@ clippy::module_name_repetitions, clippy::must_use_candidate, clippy::option_if_let_else, + clippy::redundant_else, clippy::shadow_unrelated, clippy::similar_names, clippy::single_match_else, From 50c77c660756037c6e8f4293a5b0c60f96dbb9fb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Dec 2020 11:41:42 -0800 Subject: [PATCH 19/66] Add Error::into_compile_error Closes #702. --- src/error.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/error.rs b/src/error.rs index 803b6feac5..6051f3b686 100644 --- a/src/error.rs +++ b/src/error.rs @@ -197,6 +197,42 @@ impl Error { .collect() } + /// Render the error as an invocation of [`compile_error!`]. + /// + /// [`compile_error!`]: std::compile_error! + /// + /// # Example + /// + /// ``` + /// # extern crate proc_macro; + /// # + /// use proc_macro::TokenStream; + /// use syn::{parse_macro_input, DeriveInput, Error}; + /// + /// # const _: &str = stringify! { + /// #[proc_macro_derive(MyTrait)] + /// # }; + /// pub fn derive_my_trait(input: TokenStream) -> TokenStream { + /// let input = parse_macro_input!(input as DeriveInput); + /// my_trait::expand(input) + /// .unwrap_or_else(Error::into_compile_error) + /// .into() + /// } + /// + /// mod my_trait { + /// use proc_macro2::TokenStream; + /// use syn::{DeriveInput, Result}; + /// + /// pub(crate) fn expand(input: DeriveInput) -> Result { + /// /* ... */ + /// # unimplemented!() + /// } + /// } + /// ``` + pub fn into_compile_error(self) -> TokenStream { + self.to_compile_error() + } + /// Add another error message to self such that when `to_compile_error()` is /// called, both errors will be emitted together. pub fn combine(&mut self, another: Error) { From dd1b74fa52a54c689ad1d50d9c7a3d75139851f1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 26 Dec 2020 11:43:00 -0800 Subject: [PATCH 20/66] Release 1.0.56 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12c810422d..6bd3cba537 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.55" # don't forget to update html_root_url and syn.json +version = "1.0.56" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index dbd1f87c62..c40ae79dab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.55")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.56")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index 9d06f086b1..74592a4dc6 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.55", + "version": "1.0.56", "types": [ { "ident": "Abi", From 5f575b979b9d493faedbb164b1764a36bf441f13 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 29 Dec 2020 17:16:40 -0800 Subject: [PATCH 21/66] Move clippy lint level to CI job --- .github/workflows/ci.yml | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 83d99c3a31..b83f1df553 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -110,4 +110,4 @@ jobs: steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy --all-features + - run: cargo clippy --all-features -- -Dclippy::pedantic diff --git a/src/lib.rs b/src/lib.rs index c40ae79dab..2881119962 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -252,7 +252,6 @@ // Syn types in rustdoc of other crates get linked to here. #![doc(html_root_url = "https://docs.rs/syn/1.0.56")] #![cfg_attr(doc_cfg, feature(doc_cfg))] -#![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. #![allow( clippy::blocks_in_if_conditions, From e220fffd871957a00a95e9a93d41e695179e1fac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 29 Dec 2020 17:18:25 -0800 Subject: [PATCH 22/66] Inform clippy of supported compiler version in clippy.toml --- .clippy.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .clippy.toml diff --git a/.clippy.toml b/.clippy.toml new file mode 100644 index 0000000000..3d30690f12 --- /dev/null +++ b/.clippy.toml @@ -0,0 +1 @@ +msrv = "1.31.0" From 71f401cb02c1f246585a0953d558b7908558b1f2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 31 Dec 2020 14:07:05 -0800 Subject: [PATCH 23/66] Resolve redundant_semicolons lint in test suite --- tests/test_precedence.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index f8027b19c4..4b4cb2fb9d 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -205,7 +205,7 @@ fn librustc_brackets(mut librustc_expr: P) -> Option> { struct BracketsVisitor { failed: bool, - }; + } fn flat_map_field(mut f: Field, vis: &mut T) -> Vec { if f.is_shorthand { From a632de1ad99ba9edd740387dff980cd9f12f9cbd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 31 Dec 2020 21:27:05 -0800 Subject: [PATCH 24/66] Update internal code generator to rustfmt 2.0.0-rc.2 The previously pinned rustfmt commit + toolchain have no longer been compiling as of servo/rust-smallvec#248. error[E0658]: unions with non-`Copy` fields are unstable --> /home/david/.cargo/registry/src/github.amrom.workers.dev-1ecc6299db9ec823/smallvec-1.6.0/src/lib.rs:353:1 | 353 | / union SmallVecData { 354 | | inline: core::mem::ManuallyDrop>, 355 | | heap: (*mut A::Item, usize), 356 | | } | |_^ | = note: see issue #55149 for more information = help: add `#![feature(untagged_unions)]` to the crate attributes to enable --- .github/workflows/ci.yml | 5 ++++- codegen/Cargo.toml | 6 +++--- codegen/rust-toolchain | 2 +- codegen/src/file.rs | 17 ++++++++++++----- tests/debug/gen.rs | 24 ++++++++++++++++++------ 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b83f1df553..1984476cbd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,11 +87,14 @@ jobs: codegen: name: Codegen runs-on: ubuntu-latest + env: + CFG_RELEASE_CHANNEL: dev + CFG_RELEASE: 1.51.0 steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@master with: - toolchain: nightly-2020-05-15 + toolchain: nightly-2021-01-01 - run: cd codegen && cargo run - run: git diff --exit-code diff --git a/codegen/Cargo.toml b/codegen/Cargo.toml index 39fa27fa0f..47928f6e0b 100644 --- a/codegen/Cargo.toml +++ b/codegen/Cargo.toml @@ -22,9 +22,9 @@ thiserror = "1.0" toml = "0.5" [dependencies.rustfmt] -package = "rustfmt_lib" -git = "https://github.com/rust-lang-nursery/rustfmt" -rev = "99edc8826ee6d7a5d529e8749cdf4ac999dfd954" +package = "rustfmt-nightly" +git = "https://github.com/rust-lang/rustfmt" +rev = "367a874d04abfb2269ff1ea1974f06640546b7c5" [workspace] # Prefer that `cargo clean` in syn's directory does not require a rebuild of diff --git a/codegen/rust-toolchain b/codegen/rust-toolchain index 8737a7eb56..a2b82fb1f4 100644 --- a/codegen/rust-toolchain +++ b/codegen/rust-toolchain @@ -1 +1 @@ -nightly-2020-05-15 +nightly-2021-01-01 diff --git a/codegen/src/file.rs b/codegen/src/file.rs index 5521d75984..0eeb0c74c1 100644 --- a/codegen/src/file.rs +++ b/codegen/src/file.rs @@ -14,14 +14,21 @@ pub fn write>(path: P, content: TokenStream) -> Result<()> { writeln!(formatted)?; let mut config = rustfmt::Config::default(); - config.set().emit_mode(rustfmt::EmitMode::Stdout); - config.set().verbose(rustfmt::Verbosity::Quiet); config.set().format_macro_matchers(true); config.set().normalize_doc_attributes(true); - let mut session = rustfmt::Session::new(config, Some(&mut formatted)); - session.format(rustfmt::Input::Text(content.to_string()))?; - drop(session); + let format_report = rustfmt::format( + rustfmt::Input::Text(content.to_string()), + &config, + rustfmt::OperationSetting { + recursive: false, + verbosity: rustfmt::emitter::Verbosity::Normal, + }, + )?; + + for (_filename, format_result) in format_report.format_result() { + write!(formatted, "{}", format_result.formatted_text())?; + } if path.as_ref().is_file() && fs::read(&path)? == formatted { return Ok(()); diff --git a/tests/debug/gen.rs b/tests/debug/gen.rs index 85a1a39079..1eae327bb1 100644 --- a/tests/debug/gen.rs +++ b/tests/debug/gen.rs @@ -3424,12 +3424,24 @@ impl Debug for Lite { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { let _val = &self.value; match _val { - syn::Lit::Str(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::ByteStr(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Byte(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Char(_val) => write!(formatter, "{:?}", _val.value()), - syn::Lit::Int(_val) => write!(formatter, "{}", _val), - syn::Lit::Float(_val) => write!(formatter, "{}", _val), + syn::Lit::Str(_val) => { + write!(formatter, "{:?}", _val.value()) + } + syn::Lit::ByteStr(_val) => { + write!(formatter, "{:?}", _val.value()) + } + syn::Lit::Byte(_val) => { + write!(formatter, "{:?}", _val.value()) + } + syn::Lit::Char(_val) => { + write!(formatter, "{:?}", _val.value()) + } + syn::Lit::Int(_val) => { + write!(formatter, "{}", _val) + } + syn::Lit::Float(_val) => { + write!(formatter, "{}", _val) + } syn::Lit::Bool(_val) => { let mut formatter = formatter.debug_struct("Lit::Bool"); formatter.field("value", Lite(&_val.value)); From f2b69c4c0aa5a575ea1eb3298b25aa52e6a2477a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 00:27:06 -0800 Subject: [PATCH 25/66] Make Punctuated::new const fn on rustc 1.39+ --- build.rs | 4 ++++ src/punctuated.rs | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/build.rs b/build.rs index cf7681c3f9..25190f4c87 100644 --- a/build.rs +++ b/build.rs @@ -15,6 +15,10 @@ fn main() { println!("cargo:rustc-cfg=syn_omit_await_from_token_macro"); } + if compiler.minor < 39 { + println!("cargo:rustc-cfg=syn_no_const_vec_new"); + } + if !compiler.nightly { println!("cargo:rustc-cfg=syn_disable_nightly_tests"); } diff --git a/src/punctuated.rs b/src/punctuated.rs index a026b8e2d7..2088f67b2c 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -50,6 +50,16 @@ pub struct Punctuated { impl Punctuated { /// Creates an empty punctuated sequence. + #[cfg(not(syn_no_const_vec_new))] + pub const fn new() -> Punctuated { + Punctuated { + inner: Vec::new(), + last: None, + } + } + + /// Creates an empty punctuated sequence. + #[cfg(syn_no_const_vec_new)] pub fn new() -> Punctuated { Punctuated { inner: Vec::new(), From 875eb74f8c57b60e0f776b34c808e6e8801df30c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 00:40:40 -0800 Subject: [PATCH 26/66] Format with rustfmt 1.4.30-nightly --- tests/test_visibility.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/test_visibility.rs b/tests/test_visibility.rs index c3d0ac7a5b..7b2c00ba34 100644 --- a/tests/test_visibility.rs +++ b/tests/test_visibility.rs @@ -92,7 +92,10 @@ fn test_missing_in_path() { #[test] fn test_crate_path() { - assert_vis_parse!("pub(crate::A, crate::B)", Ok(Visibility::Public(_)) + "(crate::A, crate::B)"); + assert_vis_parse!( + "pub(crate::A, crate::B)", + Ok(Visibility::Public(_)) + "(crate::A, crate::B)" + ); } #[test] From 7ca569162405cb2cbf8a3a52f33e140c52352a13 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 00:35:09 -0800 Subject: [PATCH 27/66] Remove no longer triggered clippy lints --- src/lib.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2881119962..09895afef4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -254,20 +254,14 @@ #![cfg_attr(doc_cfg, feature(doc_cfg))] // Ignored clippy lints. #![allow( - clippy::blocks_in_if_conditions, - clippy::cognitive_complexity, clippy::doc_markdown, clippy::eval_order_dependence, clippy::inherent_to_string, clippy::large_enum_variant, - clippy::manual_non_exhaustive, - clippy::manual_strip, - clippy::match_like_matches_macro, clippy::match_on_vec_items, clippy::needless_doctest_main, clippy::needless_pass_by_value, clippy::never_loop, - clippy::suspicious_op_assign_impl, clippy::too_many_arguments, clippy::trivially_copy_pass_by_ref, clippy::unnecessary_unwrap @@ -279,7 +273,6 @@ clippy::empty_enum, clippy::expl_impl_clone_on_copy, clippy::if_not_else, - clippy::items_after_statements, clippy::match_same_arms, clippy::missing_errors_doc, clippy::module_name_repetitions, From a43539cf58615ee2ba779512781a9e1381c90945 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 00:41:45 -0800 Subject: [PATCH 28/66] Resolve use_self clippy lint --- src/lib.rs | 1 - src/punctuated.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 09895afef4..73a6d6dcaa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -284,7 +284,6 @@ clippy::single_match_else, clippy::too_many_lines, clippy::unseparated_literal_suffix, - clippy::use_self, clippy::used_underscore_binding, clippy::wildcard_imports )] diff --git a/src/punctuated.rs b/src/punctuated.rs index 2088f67b2c..4d3496976c 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -51,7 +51,7 @@ pub struct Punctuated { impl Punctuated { /// Creates an empty punctuated sequence. #[cfg(not(syn_no_const_vec_new))] - pub const fn new() -> Punctuated { + pub const fn new() -> Self { Punctuated { inner: Vec::new(), last: None, @@ -60,7 +60,7 @@ impl Punctuated { /// Creates an empty punctuated sequence. #[cfg(syn_no_const_vec_new)] - pub fn new() -> Punctuated { + pub fn new() -> Self { Punctuated { inner: Vec::new(), last: None, From d58d7cbe55a3160045db000802ca4c097bf774a1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 12:54:54 -0800 Subject: [PATCH 29/66] Release 1.0.57 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6bd3cba537..b6090992e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.56" # don't forget to update html_root_url and syn.json +version = "1.0.57" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 73a6d6dcaa..192c26a29d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.56")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.57")] #![cfg_attr(doc_cfg, feature(doc_cfg))] // Ignored clippy lints. #![allow( diff --git a/syn.json b/syn.json index 74592a4dc6..34be911889 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.56", + "version": "1.0.57", "types": [ { "ident": "Abi", From d4463e7e00f8383b8d4fd44e04fd319785bc403c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 1 Jan 2021 19:08:52 -0800 Subject: [PATCH 30/66] Update test suite to nightly-2021-01-02 --- tests/common/eq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 2f72182755..8690769bb1 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -347,7 +347,7 @@ spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) Ma spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0)); spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0)); spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0)); -spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span)); +spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span default)); spanless_eq_enum!(ImplPolarity; Positive Negative(0)); spanless_eq_enum!(InlineAsmRegOrRegClass; Reg(0) RegClass(0)); spanless_eq_enum!(InlineAsmTemplatePiece; String(0) Placeholder(operand_idx modifier span)); From 5e23a9b9ac13733a56cf55777dc42bb23ee00bbc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 4 Jan 2021 23:52:10 -0800 Subject: [PATCH 31/66] Fix catching clippy warnings as CI failures --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1984476cbd..071aee790d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -113,4 +113,4 @@ jobs: steps: - uses: actions/checkout@v2 - uses: dtolnay/rust-toolchain@clippy - - run: cargo clippy --all-features -- -Dclippy::pedantic + - run: cargo clippy --all-features -- -Dclippy::all -Dclippy::pedantic From ebfb8f2c1a9e1113cd50342e186aac1f19a9a4d9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Jan 2021 12:59:54 -0800 Subject: [PATCH 32/66] Handle path attr in internal code generator --- codegen/src/parse.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs index 1e0284bcf9..503d65fe22 100644 --- a/codegen/src/parse.rs +++ b/codegen/src/parse.rs @@ -252,7 +252,7 @@ mod parsing { use proc_macro2::{TokenStream, TokenTree}; use quote::quote; use std::collections::{BTreeMap, BTreeSet}; - use syn::parse::{ParseStream, Result}; + use syn::parse::{ParseStream, Parser, Result}; use syn::{ braced, bracketed, parenthesized, parse_quote, token, Attribute, Ident, LitStr, Path, Token, }; @@ -475,6 +475,20 @@ mod parsing { Ok(types::Features { any: features }) } + + pub fn path_attr(attrs: &[Attribute]) -> Result> { + for attr in attrs { + if attr.path.is_ident("path") { + fn parser(input: ParseStream) -> Result { + input.parse::()?; + input.parse() + } + let filename = parser.parse2(attr.tokens.clone())?; + return Ok(Some(filename)); + } + } + Ok(None) + } } fn clone_features(features: &[Attribute]) -> Vec { @@ -565,7 +579,11 @@ fn do_load_file>( // Look up the submodule file, and recursively parse it. // Only handles same-directory .rs file submodules for now. - let path = parent.join(&format!("{}.rs", item.ident)); + let filename = match parsing::path_attr(&item.attrs)? { + Some(filename) => filename.value(), + None => format!("{}.rs", item.ident), + }; + let path = parent.join(filename); load_file(path, &features, lookup)?; } Item::Macro(item) => { From 957840eba2c7f11c95e0227760d78dc481a91de7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Jan 2021 12:29:57 -0800 Subject: [PATCH 33/66] Make it clearer that the private implementation details are private This was doc(hidden) and commented "Not public API but occasionally people still try to refer to it anyway. --- src/custom_keyword.rs | 46 +++++++++++++++++++-------------------- src/custom_punctuation.rs | 36 +++++++++++++++--------------- src/group.rs | 18 +++++++-------- src/lib.rs | 3 ++- src/parse_macro_input.rs | 12 +++++----- src/parse_quote.rs | 4 ++-- 6 files changed, 60 insertions(+), 59 deletions(-) diff --git a/src/custom_keyword.rs b/src/custom_keyword.rs index eb9726ede6..a21842efa9 100644 --- a/src/custom_keyword.rs +++ b/src/custom_keyword.rs @@ -91,23 +91,23 @@ macro_rules! custom_keyword { ($ident:ident) => { #[allow(non_camel_case_types)] pub struct $ident { - pub span: $crate::export::Span, + pub span: $crate::__private::Span, } #[doc(hidden)] #[allow(dead_code, non_snake_case)] - pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>( + pub fn $ident<__S: $crate::__private::IntoSpans<[$crate::__private::Span; 1]>>( span: __S, ) -> $ident { $ident { - span: $crate::export::IntoSpans::into_spans(span)[0], + span: $crate::__private::IntoSpans::into_spans(span)[0], } } - impl $crate::export::Default for $ident { + impl $crate::__private::Default for $ident { fn default() -> Self { $ident { - span: $crate::export::Span::call_site(), + span: $crate::__private::Span::call_site(), } } } @@ -127,7 +127,7 @@ macro_rules! impl_parse_for_custom_keyword { ($ident:ident) => { // For peek. impl $crate::token::CustomToken for $ident { - fn peek(cursor: $crate::buffer::Cursor) -> $crate::export::bool { + fn peek(cursor: $crate::buffer::Cursor) -> $crate::__private::bool { if let Some((ident, _rest)) = cursor.ident() { ident == stringify!($ident) } else { @@ -135,7 +135,7 @@ macro_rules! impl_parse_for_custom_keyword { } } - fn display() -> &'static $crate::export::str { + fn display() -> &'static $crate::__private::str { concat!("`", stringify!($ident), "`") } } @@ -143,12 +143,12 @@ macro_rules! impl_parse_for_custom_keyword { impl $crate::parse::Parse for $ident { fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { input.step(|cursor| { - if let $crate::export::Some((ident, rest)) = cursor.ident() { + if let $crate::__private::Some((ident, rest)) = cursor.ident() { if ident == stringify!($ident) { - return $crate::export::Ok(($ident { span: ident.span() }, rest)); + return $crate::__private::Ok(($ident { span: ident.span() }, rest)); } } - $crate::export::Err(cursor.error(concat!( + $crate::__private::Err(cursor.error(concat!( "expected `", stringify!($ident), "`" @@ -173,10 +173,10 @@ macro_rules! impl_parse_for_custom_keyword { #[macro_export] macro_rules! impl_to_tokens_for_custom_keyword { ($ident:ident) => { - impl $crate::export::ToTokens for $ident { - fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + impl $crate::__private::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { let ident = $crate::Ident::new(stringify!($ident), self.span); - $crate::export::TokenStreamExt::append(tokens, ident); + $crate::__private::TokenStreamExt::append(tokens, ident); } } }; @@ -196,9 +196,9 @@ macro_rules! impl_to_tokens_for_custom_keyword { #[macro_export] macro_rules! impl_clone_for_custom_keyword { ($ident:ident) => { - impl $crate::export::Copy for $ident {} + impl $crate::__private::Copy for $ident {} - impl $crate::export::Clone for $ident { + impl $crate::__private::Clone for $ident { fn clone(&self) -> Self { *self } @@ -220,25 +220,25 @@ macro_rules! impl_clone_for_custom_keyword { #[macro_export] macro_rules! impl_extra_traits_for_custom_keyword { ($ident:ident) => { - impl $crate::export::Debug for $ident { - fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { - $crate::export::Formatter::write_str( + impl $crate::__private::Debug for $ident { + fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::fmt::Result { + $crate::__private::Formatter::write_str( f, concat!("Keyword [", stringify!($ident), "]"), ) } } - impl $crate::export::Eq for $ident {} + impl $crate::__private::Eq for $ident {} - impl $crate::export::PartialEq for $ident { - fn eq(&self, _other: &Self) -> $crate::export::bool { + impl $crate::__private::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::__private::bool { true } } - impl $crate::export::Hash for $ident { - fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + impl $crate::__private::Hash for $ident { + fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} } }; } diff --git a/src/custom_punctuation.rs b/src/custom_punctuation.rs index 2156ec2c64..128185da01 100644 --- a/src/custom_punctuation.rs +++ b/src/custom_punctuation.rs @@ -83,18 +83,18 @@ macro_rules! custom_punctuation { #[doc(hidden)] #[allow(dead_code, non_snake_case)] - pub fn $ident<__S: $crate::export::IntoSpans<$crate::custom_punctuation_repr!($($tt)+)>>( + pub fn $ident<__S: $crate::__private::IntoSpans<$crate::custom_punctuation_repr!($($tt)+)>>( spans: __S, ) -> $ident { let _validate_len = 0 $(+ $crate::custom_punctuation_len!(strict, $tt))*; $ident { - spans: $crate::export::IntoSpans::into_spans(spans) + spans: $crate::__private::IntoSpans::into_spans(spans) } } - impl $crate::export::Default for $ident { + impl $crate::__private::Default for $ident { fn default() -> Self { - $ident($crate::export::Span::call_site()) + $ident($crate::__private::Span::call_site()) } } @@ -116,7 +116,7 @@ macro_rules! impl_parse_for_custom_punctuation { $crate::token::parsing::peek_punct(cursor, $crate::stringify_punct!($($tt)+)) } - fn display() -> &'static $crate::export::str { + fn display() -> &'static $crate::__private::str { concat!("`", $crate::stringify_punct!($($tt)+), "`") } } @@ -145,8 +145,8 @@ macro_rules! impl_parse_for_custom_punctuation { #[macro_export] macro_rules! impl_to_tokens_for_custom_punctuation { ($ident:ident, $($tt:tt)+) => { - impl $crate::export::ToTokens for $ident { - fn to_tokens(&self, tokens: &mut $crate::export::TokenStream2) { + impl $crate::__private::ToTokens for $ident { + fn to_tokens(&self, tokens: &mut $crate::__private::TokenStream2) { $crate::token::printing::punct($crate::stringify_punct!($($tt)+), &self.spans, tokens) } } @@ -167,9 +167,9 @@ macro_rules! impl_to_tokens_for_custom_punctuation { #[macro_export] macro_rules! impl_clone_for_custom_punctuation { ($ident:ident, $($tt:tt)+) => { - impl $crate::export::Copy for $ident {} + impl $crate::__private::Copy for $ident {} - impl $crate::export::Clone for $ident { + impl $crate::__private::Clone for $ident { fn clone(&self) -> Self { *self } @@ -191,22 +191,22 @@ macro_rules! impl_clone_for_custom_punctuation { #[macro_export] macro_rules! impl_extra_traits_for_custom_punctuation { ($ident:ident, $($tt:tt)+) => { - impl $crate::export::Debug for $ident { - fn fmt(&self, f: &mut $crate::export::Formatter) -> $crate::export::fmt::Result { - $crate::export::Formatter::write_str(f, stringify!($ident)) + impl $crate::__private::Debug for $ident { + fn fmt(&self, f: &mut $crate::__private::Formatter) -> $crate::__private::fmt::Result { + $crate::__private::Formatter::write_str(f, stringify!($ident)) } } - impl $crate::export::Eq for $ident {} + impl $crate::__private::Eq for $ident {} - impl $crate::export::PartialEq for $ident { - fn eq(&self, _other: &Self) -> $crate::export::bool { + impl $crate::__private::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::__private::bool { true } } - impl $crate::export::Hash for $ident { - fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + impl $crate::__private::Hash for $ident { + fn hash<__H: $crate::__private::Hasher>(&self, _state: &mut __H) {} } }; } @@ -224,7 +224,7 @@ macro_rules! impl_extra_traits_for_custom_punctuation { #[macro_export] macro_rules! custom_punctuation_repr { ($($tt:tt)+) => { - [$crate::export::Span; 0 $(+ $crate::custom_punctuation_len!(lenient, $tt))+] + [$crate::__private::Span; 0 $(+ $crate::custom_punctuation_len!(lenient, $tt))+] }; } diff --git a/src/group.rs b/src/group.rs index 2099906dca..6b05710154 100644 --- a/src/group.rs +++ b/src/group.rs @@ -137,12 +137,12 @@ fn parse_delimited<'a>( macro_rules! parenthesized { ($content:ident in $cursor:expr) => { match $crate::group::parse_parens(&$cursor) { - $crate::export::Ok(parens) => { + $crate::__private::Ok(parens) => { $content = parens.content; parens.token } - $crate::export::Err(error) => { - return $crate::export::Err(error); + $crate::__private::Err(error) => { + return $crate::__private::Err(error); } } }; @@ -215,12 +215,12 @@ macro_rules! parenthesized { macro_rules! braced { ($content:ident in $cursor:expr) => { match $crate::group::parse_braces(&$cursor) { - $crate::export::Ok(braces) => { + $crate::__private::Ok(braces) => { $content = braces.content; braces.token } - $crate::export::Err(error) => { - return $crate::export::Err(error); + $crate::__private::Err(error) => { + return $crate::__private::Err(error); } } }; @@ -270,12 +270,12 @@ macro_rules! braced { macro_rules! bracketed { ($content:ident in $cursor:expr) => { match $crate::group::parse_brackets(&$cursor) { - $crate::export::Ok(brackets) => { + $crate::__private::Ok(brackets) => { $content = brackets.content; brackets.token } - $crate::export::Err(error) => { - return $crate::export::Err(error); + $crate::__private::Err(error) => { + return $crate::__private::Err(error); } } }; diff --git a/src/lib.rs b/src/lib.rs index 192c26a29d..36bb5b1b8d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -788,7 +788,8 @@ pub use crate::gen::*; // Not public API. #[doc(hidden)] -pub mod export; +#[path = "export.rs"] +pub mod __private; mod custom_keyword; mod custom_punctuation; diff --git a/src/parse_macro_input.rs b/src/parse_macro_input.rs index 6135b45c1b..8e1a5ec6b9 100644 --- a/src/parse_macro_input.rs +++ b/src/parse_macro_input.rs @@ -108,17 +108,17 @@ macro_rules! parse_macro_input { ($tokenstream:ident as $ty:ty) => { match $crate::parse_macro_input::parse::<$ty>($tokenstream) { - $crate::export::Ok(data) => data, - $crate::export::Err(err) => { - return $crate::export::TokenStream::from(err.to_compile_error()); + $crate::__private::Ok(data) => data, + $crate::__private::Err(err) => { + return $crate::__private::TokenStream::from(err.to_compile_error()); } } }; ($tokenstream:ident with $parser:path) => { match $crate::parse::Parser::parse($parser, $tokenstream) { - $crate::export::Ok(data) => data, - $crate::export::Err(err) => { - return $crate::export::TokenStream::from(err.to_compile_error()); + $crate::__private::Ok(data) => data, + $crate::__private::Err(err) => { + return $crate::__private::TokenStream::from(err.to_compile_error()); } } }; diff --git a/src/parse_quote.rs b/src/parse_quote.rs index 412b06f35f..ec551ef973 100644 --- a/src/parse_quote.rs +++ b/src/parse_quote.rs @@ -74,8 +74,8 @@ macro_rules! parse_quote { ($($tt:tt)*) => { $crate::parse_quote::parse( - $crate::export::From::from( - $crate::export::quote::quote!($($tt)*) + $crate::__private::From::from( + $crate::__private::quote::quote!($($tt)*) ) ) }; From 272ab5df9bcb1e71faa867ec598f71cfc531b5ee Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Jan 2021 12:36:16 -0800 Subject: [PATCH 34/66] Parse simple literal const generic path args even without "full" --- src/path.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/path.rs b/src/path.rs index 31a80e59f6..601891e1db 100644 --- a/src/path.rs +++ b/src/path.rs @@ -241,12 +241,15 @@ pub mod parsing { if input.peek(Ident) && input.peek2(Token![:]) && !input.peek2(Token![::]) { return Ok(GenericArgument::Constraint(input.parse()?)); } + } - if input.peek(Lit) { - let lit = input.parse()?; - return Ok(GenericArgument::Const(Expr::Lit(lit))); - } + if input.peek(Lit) { + let lit = input.parse()?; + return Ok(GenericArgument::Const(Expr::Lit(lit))); + } + #[cfg(feature = "full")] + { if input.peek(token::Brace) { let block = input.call(expr::parsing::expr_block)?; return Ok(GenericArgument::Const(Expr::Block(block))); From 3414ed627f05dab27d951ce4868f08e3459a3fb8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 5 Jan 2021 13:48:45 -0800 Subject: [PATCH 35/66] Release 1.0.58 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6090992e1..e24f96a23b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.57" # don't forget to update html_root_url and syn.json +version = "1.0.58" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 36bb5b1b8d..5cc385002d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.57")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.58")] #![cfg_attr(doc_cfg, feature(doc_cfg))] // Ignored clippy lints. #![allow( diff --git a/syn.json b/syn.json index 34be911889..bfe249f854 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.57", + "version": "1.0.58", "types": [ { "ident": "Abi", From d530864dcc6df62711ef4b74878d9f48d47b2374 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 6 Jan 2021 05:06:30 -0800 Subject: [PATCH 36/66] Parse empty supertrait list --- src/item.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/item.rs b/src/item.rs index 883ecc799f..c5083d0501 100644 --- a/src/item.rs +++ b/src/item.rs @@ -2032,14 +2032,14 @@ pub mod parsing { let mut supertraits = Punctuated::new(); if colon_token.is_some() { loop { - supertraits.push_value(input.parse()?); if input.peek(Token![where]) || input.peek(token::Brace) { break; } - supertraits.push_punct(input.parse()?); + supertraits.push_value(input.parse()?); if input.peek(Token![where]) || input.peek(token::Brace) { break; } + supertraits.push_punct(input.parse()?); } } From d8c39a8247bc42be35bdc27f0c4fd1f6a0817fb7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 6 Jan 2021 05:06:38 -0800 Subject: [PATCH 37/66] Add test of empty supertrait list --- tests/test_item.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 83 insertions(+), 1 deletion(-) diff --git a/tests/test_item.rs b/tests/test_item.rs index c28fc87fdc..7695f19906 100644 --- a/tests/test_item.rs +++ b/tests/test_item.rs @@ -4,7 +4,7 @@ mod macros; use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; use quote::quote; use std::iter::FromIterator; -use syn::Item; +use syn::{Item, ItemTrait}; #[test] fn test_macro_variable_attr() { @@ -159,3 +159,85 @@ fn test_macro_variable_impl() { } "###); } + +#[test] +fn test_supertraits() { + // Rustc parses all of the following. + + #[rustfmt::skip] + let tokens = quote!(trait Trait where {}); + snapshot!(tokens as ItemTrait, @r###" + ItemTrait { + vis: Inherited, + ident: "Trait", + generics: Generics { + where_clause: Some(WhereClause), + }, + } + "###); + + #[rustfmt::skip] + let tokens = quote!(trait Trait: where {}); + snapshot!(tokens as ItemTrait, @r###" + ItemTrait { + vis: Inherited, + ident: "Trait", + generics: Generics { + where_clause: Some(WhereClause), + }, + colon_token: Some, + } + "###); + + #[rustfmt::skip] + let tokens = quote!(trait Trait: Sized where {}); + snapshot!(tokens as ItemTrait, @r###" + ItemTrait { + vis: Inherited, + ident: "Trait", + generics: Generics { + where_clause: Some(WhereClause), + }, + colon_token: Some, + supertraits: [ + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "Sized", + arguments: None, + }, + ], + }, + }), + ], + } + "###); + + #[rustfmt::skip] + let tokens = quote!(trait Trait: Sized + where {}); + snapshot!(tokens as ItemTrait, @r###" + ItemTrait { + vis: Inherited, + ident: "Trait", + generics: Generics { + where_clause: Some(WhereClause), + }, + colon_token: Some, + supertraits: [ + Trait(TraitBound { + modifier: None, + path: Path { + segments: [ + PathSegment { + ident: "Sized", + arguments: None, + }, + ], + }, + }), + ], + } + "###); +} From 58bbe7f5a4568cdda7e761ee649945283ca8417d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 6 Jan 2021 20:04:19 -0800 Subject: [PATCH 38/66] Parse braced block generic argument as verbatim in non-full --- src/path.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/path.rs b/src/path.rs index 601891e1db..96448e0a2f 100644 --- a/src/path.rs +++ b/src/path.rs @@ -248,12 +248,22 @@ pub mod parsing { return Ok(GenericArgument::Const(Expr::Lit(lit))); } - #[cfg(feature = "full")] - { - if input.peek(token::Brace) { + if input.peek(token::Brace) { + #[cfg(feature = "full")] + { let block = input.call(expr::parsing::expr_block)?; return Ok(GenericArgument::Const(Expr::Block(block))); } + + #[cfg(not(feature = "full"))] + { + let begin = input.fork(); + let content; + braced!(content in input); + content.parse::()?; + let verbatim = verbatim::between(begin, input); + return Ok(GenericArgument::Const(Expr::Verbatim(verbatim))); + } } input.parse().map(GenericArgument::Type) From 57c131acff3dfb162dc13b080bf2e70e64384394 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 10 Jan 2021 19:44:08 -0800 Subject: [PATCH 39/66] Update test suite to nightly-2021-01-11 --- tests/common/eq.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 8690769bb1..7721dd70d0 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -21,7 +21,7 @@ use rustc_ast::ast::{ }; use rustc_ast::ptr::P; use rustc_ast::token::{self, CommentKind, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, DelimSpan, LazyTokenStream, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{DelimSpan, LazyTokenStream, TokenStream, TokenTree}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; @@ -538,19 +538,24 @@ fn doc_comment<'a>( })) => {} _ => return false, } - is_escaped_literal(trees, unescaped) + match trees.next() { + Some(TokenTree::Token(token)) => { + is_escaped_literal(token, unescaped) && trees.next().is_none() + } + _ => false, + } } -fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> bool { - match match trees.next() { - Some(TokenTree::Token(Token { +fn is_escaped_literal(token: &Token, unescaped: Symbol) -> bool { + match match token { + Token { kind: TokenKind::Literal(lit), span: _, - })) => Lit::from_lit_token(*lit, DUMMY_SP), - Some(TokenTree::Token(Token { + } => Lit::from_lit_token(*lit, DUMMY_SP), + Token { kind: TokenKind::Interpolated(nonterminal), span: _, - })) => match nonterminal.as_ref() { + } => match nonterminal.as_ref() { Nonterminal::NtExpr(expr) => match &expr.kind { ExprKind::Lit(lit) => Ok(lit.clone()), _ => return false, @@ -568,10 +573,7 @@ fn is_escaped_literal(mut trees: tokenstream::CursorRef, unescaped: Symbol) -> b }, kind: LitKind::Str(symbol, StrStyle::Cooked), span: _, - }) => { - symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', "") - && trees.next().is_none() - } + }) => symbol.as_str().replace('\r', "") == unescaped.as_str().replace('\r', ""), _ => false, } } @@ -601,9 +603,7 @@ impl SpanlessEq for AttrKind { SpanlessEq::eq(&path, &item2.path) && match &item2.args { MacArgs::Empty | MacArgs::Delimited(..) => false, - MacArgs::Eq(_span, tokens) => { - is_escaped_literal(tokens.trees_ref(), *unescaped) - } + MacArgs::Eq(_span, token) => is_escaped_literal(token, *unescaped), } } (AttrKind::Normal(..), AttrKind::DocComment(..)) => SpanlessEq::eq(other, self), From 80a6006dabe7b4861e404c95ef6ad8392c3734d5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 13 Jan 2021 19:38:53 -0800 Subject: [PATCH 40/66] Update test suite to nightly-2021-01-14 --- tests/common/eq.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 7721dd70d0..7830163d55 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -307,7 +307,7 @@ spanless_eq_struct!(MacCallStmt; mac style attrs tokens); spanless_eq_struct!(MacroDef; body macro_rules); spanless_eq_struct!(Mod; inner unsafety items inline); spanless_eq_struct!(MutTy; ty mutbl); -spanless_eq_struct!(ParenthesizedArgs; span inputs output); +spanless_eq_struct!(ParenthesizedArgs; span inputs inputs_span output); spanless_eq_struct!(Pat; id kind span tokens); spanless_eq_struct!(Path; span segments tokens); spanless_eq_struct!(PathSegment; ident id args); From f005b7f3f277b747cbf14d1cae14a3c67b671108 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 22 Jan 2021 23:42:21 -0800 Subject: [PATCH 41/66] Fix loss of punctuation spans on TypeTuple parse The original implementation was going through Punctuated's impl IntoIterator followed by Extend, which throws away the old punctuation tokens P and creates brand new Default ones, losing the spans. --- src/ty.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/ty.rs b/src/ty.rs index eacae3b5db..c9546a1283 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -435,9 +435,13 @@ pub mod parsing { let mut elems = Punctuated::new(); elems.push_value(first); elems.push_punct(content.parse()?); - let rest: Punctuated = - content.parse_terminated(Parse::parse)?; - elems.extend(rest); + while !content.is_empty() { + elems.push_value(content.parse()?); + if content.is_empty() { + break; + } + elems.push_punct(content.parse()?); + } elems }, })); @@ -770,9 +774,13 @@ pub mod parsing { let mut elems = Punctuated::new(); elems.push_value(first); elems.push_punct(content.parse()?); - let rest: Punctuated = - content.parse_terminated(Parse::parse)?; - elems.extend(rest); + while !content.is_empty() { + elems.push_value(content.parse()?); + if content.is_empty() { + break; + } + elems.push_punct(content.parse()?); + } elems }, }) From 72c006c121036385d11bb1962c550e11404af71d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 22 Jan 2021 23:55:21 -0800 Subject: [PATCH 42/66] Release 1.0.59 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e24f96a23b..1f3804cdfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.58" # don't forget to update html_root_url and syn.json +version = "1.0.59" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 5cc385002d..6ee656ea87 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.58")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.59")] #![cfg_attr(doc_cfg, feature(doc_cfg))] // Ignored clippy lints. #![allow( diff --git a/syn.json b/syn.json index bfe249f854..cf12706c13 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.58", + "version": "1.0.59", "types": [ { "ident": "Abi", From f30253a22c265a9e6276c195ded4e355edc6e2cf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 00:12:14 -0800 Subject: [PATCH 43/66] Parse variant attributes from ast_enum_of_structs --- codegen/src/parse.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs index 503d65fe22..34803c0ca1 100644 --- a/codegen/src/parse.rs +++ b/codegen/src/parse.rs @@ -331,11 +331,12 @@ mod parsing { // A single variant of an ast_enum_of_structs! struct EosVariant { + attrs: Vec, name: Ident, member: Option, } fn eos_variant(input: ParseStream) -> Result { - input.call(Attribute::parse_outer)?; + let attrs = input.call(Attribute::parse_outer)?; let variant: Ident = input.parse()?; let member = if input.peek(token::Paren) { let content; @@ -347,6 +348,7 @@ mod parsing { }; input.parse::()?; Ok(EosVariant { + attrs, name: variant, member, }) @@ -371,10 +373,11 @@ mod parsing { let enum_item = { let variants = variants.iter().map(|v| { - let name = v.name.clone(); + let attrs = &v.attrs; + let name = &v.name; match v.member { - Some(ref member) => quote!(#name(#member)), - None => quote!(#name), + Some(ref member) => quote!(#(#attrs)* #name(#member)), + None => quote!(#(#attrs)* #name), } }); parse_quote! { From dffc40d1c7efbeed89f33f60b982a95621f8db7d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 23 Jan 2021 23:45:57 -0800 Subject: [PATCH 44/66] Do nonexhaustive detection based on doc(hidden) attribute --- codegen/src/parse.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/codegen/src/parse.rs b/codegen/src/parse.rs index 34803c0ca1..716ba0dc7c 100644 --- a/codegen/src/parse.rs +++ b/codegen/src/parse.rs @@ -17,7 +17,6 @@ const SYN_CRATE_ROOT: &str = "../src/lib.rs"; const TOKEN_SRC: &str = "../src/token.rs"; const IGNORED_MODS: &[&str] = &["fold", "visit", "visit_mut"]; const EXTRA_TYPES: &[&str] = &["Lifetime"]; -const NONEXHAUSTIVE: &str = "__Nonexhaustive"; // NOTE: BTreeMap is used here instead of HashMap to have deterministic output. type ItemLookup = BTreeMap; @@ -63,7 +62,7 @@ fn introspect_item(item: &AstItem, items: &ItemLookup, tokens: &TokenLookup) -> ident: item.ast.ident.to_string(), features, data: types::Data::Enum(introspect_enum(data, items, tokens)), - exhaustive: data.variants.iter().all(|v| v.ident != NONEXHAUSTIVE), + exhaustive: !data.variants.iter().any(|v| is_doc_hidden(&v.attrs)), }, Data::Struct(ref data) => types::Node { ident: item.ast.ident.to_string(), @@ -85,7 +84,7 @@ fn introspect_enum(item: &DataEnum, items: &ItemLookup, tokens: &TokenLookup) -> item.variants .iter() .filter_map(|variant| { - if variant.ident == NONEXHAUSTIVE { + if is_doc_hidden(&variant.attrs) { return None; } let fields = match &variant.fields { @@ -215,6 +214,20 @@ fn is_pub(vis: &Visibility) -> bool { } } +fn is_doc_hidden(attrs: &[Attribute]) -> bool { + for attr in attrs { + if attr.path.is_ident("doc") { + if parsing::parse_doc_hidden_attr + .parse2(attr.tokens.clone()) + .is_ok() + { + return true; + } + } + } + false +} + fn first_arg(params: &PathArguments) -> &syn::Type { let data = match *params { PathArguments::AngleBracketed(ref data) => data, @@ -393,6 +406,7 @@ mod parsing { } mod kw { + syn::custom_keyword!(hidden); syn::custom_keyword!(macro_rules); syn::custom_keyword!(Token); } @@ -492,6 +506,13 @@ mod parsing { } Ok(None) } + + pub fn parse_doc_hidden_attr(input: ParseStream) -> Result<()> { + let content; + parenthesized!(content in input); + content.parse::()?; + Ok(()) + } } fn clone_features(features: &[Attribute]) -> Vec { From 8b70266584a262674533f7f831e9505c1a4cede4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 00:21:28 -0800 Subject: [PATCH 45/66] Provide an exhaustive matching idiom for syntax tree enums --- src/expr.rs | 27 +++++++++++++--- src/item.rs | 92 ++++++++++++++++++++++++++++++++++++++++++++++++----- src/pat.rs | 21 +++++++++++- src/ty.rs | 21 +++++++++++- 4 files changed, 147 insertions(+), 14 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 8417475cab..3d89cdd01d 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -224,8 +224,27 @@ ast_enum_of_structs! { /// A yield expression: `yield expr`. Yield(ExprYield), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // Expr::Array(e) => {...} + // Expr::Assign(e) => {...} + // ... + // Expr::Yield(e) => {...} + // + // #[cfg(test)] + // Expr::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } @@ -804,7 +823,7 @@ impl Expr { | Expr::TryBlock(ExprTryBlock { attrs, .. }) | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), Expr::Verbatim(_) => Vec::new(), - Expr::__Nonexhaustive => unreachable!(), + Expr::TestExhaustive => unreachable!(), } } } @@ -2303,7 +2322,7 @@ pub(crate) mod parsing { Pat::Type(_) => unreachable!(), Pat::Verbatim(_) => {} Pat::Wild(pat) => pat.attrs = attrs, - Pat::__Nonexhaustive => unreachable!(), + Pat::TestExhaustive => unreachable!(), } Ok(pat) } @@ -2654,7 +2673,7 @@ pub(crate) mod parsing { } for part in float_repr.split('.') { let index = crate::parse_str(part).map_err(|err| Error::new(float.span(), err))?; - let base = mem::replace(e, Expr::__Nonexhaustive); + let base = mem::replace(e, Expr::TestExhaustive); *e = Expr::Field(ExprField { attrs: Vec::new(), base: Box::new(base), diff --git a/src/item.rs b/src/item.rs index c5083d0501..349a096192 100644 --- a/src/item.rs +++ b/src/item.rs @@ -71,8 +71,27 @@ ast_enum_of_structs! { /// Tokens forming an item not interpreted by Syn. Verbatim(TokenStream), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // Item::Const(e) => {...} + // Item::Enum(e) => {...} + // ... + // Item::Verbatim(e) => {...} + // + // #[cfg(test)] + // Item::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } @@ -357,7 +376,7 @@ impl Item { | Item::Macro(ItemMacro { attrs, .. }) | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), Item::Verbatim(_) => Vec::new(), - Item::__Nonexhaustive => unreachable!(), + Item::TestExhaustive => unreachable!(), } } } @@ -553,8 +572,27 @@ ast_enum_of_structs! { /// Tokens in an `extern` block not interpreted by Syn. Verbatim(TokenStream), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // ForeignItem::Fn(e) => {...} + // ForeignItem::Static(e) => {...} + // ... + // ForeignItem::Verbatim(e) => {...} + // + // #[cfg(test)] + // ForeignItem::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } @@ -641,8 +679,27 @@ ast_enum_of_structs! { /// Tokens within the definition of a trait not interpreted by Syn. Verbatim(TokenStream), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // TraitItem::Const(e) => {...} + // TraitItem::Method(e) => {...} + // ... + // TraitItem::Verbatim(e) => {...} + // + // #[cfg(test)] + // TraitItem::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } @@ -731,8 +788,27 @@ ast_enum_of_structs! { /// Tokens within an impl block not interpreted by Syn. Verbatim(TokenStream), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // ImplItem::Const(e) => {...} + // ImplItem::Method(e) => {...} + // ... + // ImplItem::Verbatim(e) => {...} + // + // #[cfg(test)] + // ImplItem::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } @@ -1695,7 +1771,7 @@ pub mod parsing { ForeignItem::Type(item) => &mut item.attrs, ForeignItem::Macro(item) => &mut item.attrs, ForeignItem::Verbatim(_) => return Ok(item), - ForeignItem::__Nonexhaustive => unreachable!(), + ForeignItem::TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2173,7 +2249,7 @@ pub mod parsing { TraitItem::Method(item) => &mut item.attrs, TraitItem::Type(item) => &mut item.attrs, TraitItem::Macro(item) => &mut item.attrs, - TraitItem::Verbatim(_) | TraitItem::__Nonexhaustive => unreachable!(), + TraitItem::Verbatim(_) | TraitItem::TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2504,7 +2580,7 @@ pub mod parsing { ImplItem::Type(item) => &mut item.attrs, ImplItem::Macro(item) => &mut item.attrs, ImplItem::Verbatim(_) => return Ok(item), - ImplItem::__Nonexhaustive => unreachable!(), + ImplItem::TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; diff --git a/src/pat.rs b/src/pat.rs index 5381076944..0b7de0b746 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -72,8 +72,27 @@ ast_enum_of_structs! { /// A pattern that matches any value: `_`. Wild(PatWild), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // Pat::Box(e) => {...} + // Pat::Ident(e) => {...} + // ... + // Pat::Wild(e) => {...} + // + // #[cfg(test)] + // Pat::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } diff --git a/src/ty.rs b/src/ty.rs index c9546a1283..5f1ac54726 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -63,8 +63,27 @@ ast_enum_of_structs! { /// Tokens in type position not interpreted by Syn. Verbatim(TokenStream), + // The following is the only supported idiom for exhaustive matching of + // this enum. + // + // match expr { + // Type::Array(e) => {...} + // Type::BareFn(e) => {...} + // ... + // Type::Verbatim(e) => {...} + // + // #[cfg(test)] + // Type::TestExhaustive => unimplemented!(), + // #[cfg(not(test))] + // _ => { /* some sane fallback */ } + // } + // + // This way we fail your tests but don't break your library when adding + // a variant. You will be notified by a test failure when a variant is + // added, so that you can add code to handle it, but your library will + // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __Nonexhaustive, + TestExhaustive, } } From 13688673fc2b20a0de9241e065065287116c4985 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 11:53:40 -0800 Subject: [PATCH 46/66] Rename to __TestExhaustive This calls attention in review that it's not meant to be used the same as a typical variant. --- src/expr.rs | 10 +++++----- src/item.rs | 24 ++++++++++++------------ src/pat.rs | 4 ++-- src/ty.rs | 4 ++-- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 3d89cdd01d..6a8ba75e1a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -234,7 +234,7 @@ ast_enum_of_structs! { // Expr::Yield(e) => {...} // // #[cfg(test)] - // Expr::TestExhaustive => unimplemented!(), + // Expr::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -244,7 +244,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } @@ -823,7 +823,7 @@ impl Expr { | Expr::TryBlock(ExprTryBlock { attrs, .. }) | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), Expr::Verbatim(_) => Vec::new(), - Expr::TestExhaustive => unreachable!(), + Expr::__TestExhaustive => unreachable!(), } } } @@ -2322,7 +2322,7 @@ pub(crate) mod parsing { Pat::Type(_) => unreachable!(), Pat::Verbatim(_) => {} Pat::Wild(pat) => pat.attrs = attrs, - Pat::TestExhaustive => unreachable!(), + Pat::__TestExhaustive => unreachable!(), } Ok(pat) } @@ -2673,7 +2673,7 @@ pub(crate) mod parsing { } for part in float_repr.split('.') { let index = crate::parse_str(part).map_err(|err| Error::new(float.span(), err))?; - let base = mem::replace(e, Expr::TestExhaustive); + let base = mem::replace(e, Expr::__TestExhaustive); *e = Expr::Field(ExprField { attrs: Vec::new(), base: Box::new(base), diff --git a/src/item.rs b/src/item.rs index 349a096192..907d73883e 100644 --- a/src/item.rs +++ b/src/item.rs @@ -81,7 +81,7 @@ ast_enum_of_structs! { // Item::Verbatim(e) => {...} // // #[cfg(test)] - // Item::TestExhaustive => unimplemented!(), + // Item::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -91,7 +91,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } @@ -376,7 +376,7 @@ impl Item { | Item::Macro(ItemMacro { attrs, .. }) | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), Item::Verbatim(_) => Vec::new(), - Item::TestExhaustive => unreachable!(), + Item::__TestExhaustive => unreachable!(), } } } @@ -582,7 +582,7 @@ ast_enum_of_structs! { // ForeignItem::Verbatim(e) => {...} // // #[cfg(test)] - // ForeignItem::TestExhaustive => unimplemented!(), + // ForeignItem::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -592,7 +592,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } @@ -689,7 +689,7 @@ ast_enum_of_structs! { // TraitItem::Verbatim(e) => {...} // // #[cfg(test)] - // TraitItem::TestExhaustive => unimplemented!(), + // TraitItem::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -699,7 +699,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } @@ -798,7 +798,7 @@ ast_enum_of_structs! { // ImplItem::Verbatim(e) => {...} // // #[cfg(test)] - // ImplItem::TestExhaustive => unimplemented!(), + // ImplItem::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -808,7 +808,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } @@ -1771,7 +1771,7 @@ pub mod parsing { ForeignItem::Type(item) => &mut item.attrs, ForeignItem::Macro(item) => &mut item.attrs, ForeignItem::Verbatim(_) => return Ok(item), - ForeignItem::TestExhaustive => unreachable!(), + ForeignItem::__TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2249,7 +2249,7 @@ pub mod parsing { TraitItem::Method(item) => &mut item.attrs, TraitItem::Type(item) => &mut item.attrs, TraitItem::Macro(item) => &mut item.attrs, - TraitItem::Verbatim(_) | TraitItem::TestExhaustive => unreachable!(), + TraitItem::Verbatim(_) | TraitItem::__TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2580,7 +2580,7 @@ pub mod parsing { ImplItem::Type(item) => &mut item.attrs, ImplItem::Macro(item) => &mut item.attrs, ImplItem::Verbatim(_) => return Ok(item), - ImplItem::TestExhaustive => unreachable!(), + ImplItem::__TestExhaustive => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; diff --git a/src/pat.rs b/src/pat.rs index 0b7de0b746..d6549da428 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -82,7 +82,7 @@ ast_enum_of_structs! { // Pat::Wild(e) => {...} // // #[cfg(test)] - // Pat::TestExhaustive => unimplemented!(), + // Pat::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -92,7 +92,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } diff --git a/src/ty.rs b/src/ty.rs index 5f1ac54726..abebdfc316 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -73,7 +73,7 @@ ast_enum_of_structs! { // Type::Verbatim(e) => {...} // // #[cfg(test)] - // Type::TestExhaustive => unimplemented!(), + // Type::__TestExhaustive => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -83,7 +83,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - TestExhaustive, + __TestExhaustive, } } From 269b42243a6afb58a5f9714bdd486b2929cef8b8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 12:03:51 -0800 Subject: [PATCH 47/66] Prevent external instantiation of the nonexhaustive variants --- src/attr.rs | 2 +- src/export.rs | 2 ++ src/expr.rs | 10 +++++----- src/item.rs | 24 ++++++++++++------------ src/lib.rs | 6 +++--- src/macros.rs | 16 +++++++++++++--- src/pat.rs | 4 ++-- src/path.rs | 2 +- src/ty.rs | 4 ++-- 9 files changed, 41 insertions(+), 29 deletions(-) diff --git a/src/attr.rs b/src/attr.rs index 1d82190ea1..794a3104f7 100644 --- a/src/attr.rs +++ b/src/attr.rs @@ -530,7 +530,7 @@ pub mod parsing { #[cfg(feature = "full")] impl private { - pub fn attrs(outer: Vec, inner: Vec) -> Vec { + pub(crate) fn attrs(outer: Vec, inner: Vec) -> Vec { let mut attrs = outer; attrs.extend(inner); attrs diff --git a/src/export.rs b/src/export.rs index 37dc467a7f..601a214b1e 100644 --- a/src/export.rs +++ b/src/export.rs @@ -33,3 +33,5 @@ mod help { pub type Bool = bool; pub type Str = str; } + +pub struct private(pub(crate) ()); diff --git a/src/expr.rs b/src/expr.rs index 6a8ba75e1a..f18ef06b32 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -234,7 +234,7 @@ ast_enum_of_structs! { // Expr::Yield(e) => {...} // // #[cfg(test)] - // Expr::__TestExhaustive => unimplemented!(), + // Expr::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -244,7 +244,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } @@ -823,7 +823,7 @@ impl Expr { | Expr::TryBlock(ExprTryBlock { attrs, .. }) | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), Expr::Verbatim(_) => Vec::new(), - Expr::__TestExhaustive => unreachable!(), + Expr::__TestExhaustive(_) => unreachable!(), } } } @@ -2322,7 +2322,7 @@ pub(crate) mod parsing { Pat::Type(_) => unreachable!(), Pat::Verbatim(_) => {} Pat::Wild(pat) => pat.attrs = attrs, - Pat::__TestExhaustive => unreachable!(), + Pat::__TestExhaustive(_) => unreachable!(), } Ok(pat) } @@ -2673,7 +2673,7 @@ pub(crate) mod parsing { } for part in float_repr.split('.') { let index = crate::parse_str(part).map_err(|err| Error::new(float.span(), err))?; - let base = mem::replace(e, Expr::__TestExhaustive); + let base = mem::replace(e, Expr::__TestExhaustive(crate::private(()))); *e = Expr::Field(ExprField { attrs: Vec::new(), base: Box::new(base), diff --git a/src/item.rs b/src/item.rs index 907d73883e..95b4617ad7 100644 --- a/src/item.rs +++ b/src/item.rs @@ -81,7 +81,7 @@ ast_enum_of_structs! { // Item::Verbatim(e) => {...} // // #[cfg(test)] - // Item::__TestExhaustive => unimplemented!(), + // Item::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -91,7 +91,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } @@ -376,7 +376,7 @@ impl Item { | Item::Macro(ItemMacro { attrs, .. }) | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), Item::Verbatim(_) => Vec::new(), - Item::__TestExhaustive => unreachable!(), + Item::__TestExhaustive(_) => unreachable!(), } } } @@ -582,7 +582,7 @@ ast_enum_of_structs! { // ForeignItem::Verbatim(e) => {...} // // #[cfg(test)] - // ForeignItem::__TestExhaustive => unimplemented!(), + // ForeignItem::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -592,7 +592,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } @@ -689,7 +689,7 @@ ast_enum_of_structs! { // TraitItem::Verbatim(e) => {...} // // #[cfg(test)] - // TraitItem::__TestExhaustive => unimplemented!(), + // TraitItem::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -699,7 +699,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } @@ -798,7 +798,7 @@ ast_enum_of_structs! { // ImplItem::Verbatim(e) => {...} // // #[cfg(test)] - // ImplItem::__TestExhaustive => unimplemented!(), + // ImplItem::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -808,7 +808,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } @@ -1771,7 +1771,7 @@ pub mod parsing { ForeignItem::Type(item) => &mut item.attrs, ForeignItem::Macro(item) => &mut item.attrs, ForeignItem::Verbatim(_) => return Ok(item), - ForeignItem::__TestExhaustive => unreachable!(), + ForeignItem::__TestExhaustive(_) => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2249,7 +2249,7 @@ pub mod parsing { TraitItem::Method(item) => &mut item.attrs, TraitItem::Type(item) => &mut item.attrs, TraitItem::Macro(item) => &mut item.attrs, - TraitItem::Verbatim(_) | TraitItem::__TestExhaustive => unreachable!(), + TraitItem::Verbatim(_) | TraitItem::__TestExhaustive(_) => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2580,7 +2580,7 @@ pub mod parsing { ImplItem::Type(item) => &mut item.attrs, ImplItem::Macro(item) => &mut item.attrs, ImplItem::Verbatim(_) => return Ok(item), - ImplItem::__TestExhaustive => unreachable!(), + ImplItem::__TestExhaustive(_) => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; diff --git a/src/lib.rs b/src/lib.rs index 6ee656ea87..6096bb6c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -252,6 +252,7 @@ // Syn types in rustdoc of other crates get linked to here. #![doc(html_root_url = "https://docs.rs/syn/1.0.59")] #![cfg_attr(doc_cfg, feature(doc_cfg))] +#![allow(non_camel_case_types)] // Ignored clippy lints. #![allow( clippy::doc_markdown, @@ -813,10 +814,9 @@ mod verbatim; #[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] mod print; -//////////////////////////////////////////////////////////////////////////////// +use crate::__private::private; -#[allow(dead_code, non_camel_case_types)] -struct private; +//////////////////////////////////////////////////////////////////////////////// // https://github.com/rust-lang/rust/issues/62830 #[cfg(feature = "parsing")] diff --git a/src/macros.rs b/src/macros.rs index e0d0b81f88..5097da9481 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -77,7 +77,7 @@ macro_rules! ast_enum_of_structs_impl { $pub:ident $enum:ident $name:ident { $( $(#[$variant_attr:meta])* - $variant:ident $( ($member:ident) )*, + $variant:ident $( ($($member:ident)::+) )*, )* } @@ -87,7 +87,7 @@ macro_rules! ast_enum_of_structs_impl { check_keyword_matches!(enum $enum); $($( - ast_enum_from_struct!($name::$variant, $member); + ast_enum_from_struct!($name::$variant, $($member)::+); )*)* #[cfg(feature = "printing")] @@ -95,7 +95,7 @@ macro_rules! ast_enum_of_structs_impl { $($remaining)* () tokens - $name { $($variant $($member)*,)* } + $name { $($variant $($($member)::+)*,)* } } }; } @@ -104,6 +104,9 @@ macro_rules! ast_enum_from_struct { // No From for verbatim variants. ($name:ident::Verbatim, $member:ident) => {}; + // No From for private variants. + ($name:ident::$variant:ident, crate::private) => {}; + ($name:ident::$variant:ident, $member:ident) => { impl From<$member> for $name { fn from(e: $member) -> $name { @@ -131,6 +134,13 @@ macro_rules! generate_to_tokens { ); }; + (($($arms:tt)*) $tokens:ident $name:ident { $variant:ident crate::private, $($next:tt)*}) => { + generate_to_tokens!( + ($($arms)* $name::$variant(_) => unreachable!(),) + $tokens $name { $($next)* } + ); + }; + (($($arms:tt)*) $tokens:ident $name:ident {}) => { #[cfg_attr(doc_cfg, doc(cfg(feature = "printing")))] impl ::quote::ToTokens for $name { diff --git a/src/pat.rs b/src/pat.rs index d6549da428..a7e988f346 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -82,7 +82,7 @@ ast_enum_of_structs! { // Pat::Wild(e) => {...} // // #[cfg(test)] - // Pat::__TestExhaustive => unimplemented!(), + // Pat::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -92,7 +92,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } diff --git a/src/path.rs b/src/path.rs index 96448e0a2f..3f668c9deb 100644 --- a/src/path.rs +++ b/src/path.rs @@ -747,7 +747,7 @@ mod printing { } impl private { - pub fn print_path(tokens: &mut TokenStream, qself: &Option, path: &Path) { + pub(crate) fn print_path(tokens: &mut TokenStream, qself: &Option, path: &Path) { let qself = match qself { Some(qself) => qself, None => { diff --git a/src/ty.rs b/src/ty.rs index abebdfc316..d8631cd6b1 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -73,7 +73,7 @@ ast_enum_of_structs! { // Type::Verbatim(e) => {...} // // #[cfg(test)] - // Type::__TestExhaustive => unimplemented!(), + // Type::__TestExhaustive(_) => unimplemented!(), // #[cfg(not(test))] // _ => { /* some sane fallback */ } // } @@ -83,7 +83,7 @@ ast_enum_of_structs! { // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. #[doc(hidden)] - __TestExhaustive, + __TestExhaustive(crate::private), } } From 66a90475d7964e3206f1dab6eb7e7fc105c1f4fb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 12:22:40 -0800 Subject: [PATCH 48/66] Link to rust-lang/rust#44109 --- src/expr.rs | 4 ++++ src/item.rs | 16 ++++++++++++++++ src/pat.rs | 4 ++++ src/ty.rs | 4 ++++ 4 files changed, 28 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index f18ef06b32..8e054cc7a5 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -243,6 +243,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, Expr will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } diff --git a/src/item.rs b/src/item.rs index 95b4617ad7..d5c3b277bd 100644 --- a/src/item.rs +++ b/src/item.rs @@ -90,6 +90,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, Item will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } @@ -591,6 +595,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, ForeignItem will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } @@ -698,6 +706,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, TraitItem will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } @@ -807,6 +819,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, ImplItem will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } diff --git a/src/pat.rs b/src/pat.rs index a7e988f346..312d3c08de 100644 --- a/src/pat.rs +++ b/src/pat.rs @@ -91,6 +91,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, Pat will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } diff --git a/src/ty.rs b/src/ty.rs index d8631cd6b1..b60109f9ee 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -82,6 +82,10 @@ ast_enum_of_structs! { // a variant. You will be notified by a test failure when a variant is // added, so that you can add code to handle it, but your library will // continue to compile and work for downstream users in the interim. + // + // Once `deny(reachable)` is available in rustc, Type will be + // reimplemented as a non_exhaustive enum. + // https://github.com/rust-lang/rust/issues/44109#issuecomment-521781237 #[doc(hidden)] __TestExhaustive(crate::private), } From 5b4a2d29d6bada9ca16b79718f93baafd77db736 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 12:29:26 -0800 Subject: [PATCH 49/66] Release 1.0.60 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1f3804cdfe..11d01b11fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.59" # don't forget to update html_root_url and syn.json +version = "1.0.60" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 6096bb6c9a..2c201c9900 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.59")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.60")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow(non_camel_case_types)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index cf12706c13..aac573cdf5 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.59", + "version": "1.0.60", "types": [ { "ident": "Abi", From 133a053fe67d5f360c0ad24370216e0052624dfc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 24 Jan 2021 22:53:43 -0800 Subject: [PATCH 50/66] Add cfgs to matches in case people are copying into their code --- src/expr.rs | 12 ++++++++++-- src/item.rs | 25 +++++++++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 8e054cc7a5..510592de26 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -827,7 +827,11 @@ impl Expr { | Expr::TryBlock(ExprTryBlock { attrs, .. }) | Expr::Yield(ExprYield { attrs, .. }) => mem::replace(attrs, new), Expr::Verbatim(_) => Vec::new(), - Expr::__TestExhaustive(_) => unreachable!(), + + #[cfg(test)] + Expr::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), } } } @@ -2326,7 +2330,11 @@ pub(crate) mod parsing { Pat::Type(_) => unreachable!(), Pat::Verbatim(_) => {} Pat::Wild(pat) => pat.attrs = attrs, - Pat::__TestExhaustive(_) => unreachable!(), + + #[cfg(test)] + Pat::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), } Ok(pat) } diff --git a/src/item.rs b/src/item.rs index d5c3b277bd..d943debd5f 100644 --- a/src/item.rs +++ b/src/item.rs @@ -380,7 +380,11 @@ impl Item { | Item::Macro(ItemMacro { attrs, .. }) | Item::Macro2(ItemMacro2 { attrs, .. }) => mem::replace(attrs, new), Item::Verbatim(_) => Vec::new(), - Item::__TestExhaustive(_) => unreachable!(), + + #[cfg(test)] + Item::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), } } } @@ -1787,7 +1791,11 @@ pub mod parsing { ForeignItem::Type(item) => &mut item.attrs, ForeignItem::Macro(item) => &mut item.attrs, ForeignItem::Verbatim(_) => return Ok(item), - ForeignItem::__TestExhaustive(_) => unreachable!(), + + #[cfg(test)] + ForeignItem::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2265,7 +2273,12 @@ pub mod parsing { TraitItem::Method(item) => &mut item.attrs, TraitItem::Type(item) => &mut item.attrs, TraitItem::Macro(item) => &mut item.attrs, - TraitItem::Verbatim(_) | TraitItem::__TestExhaustive(_) => unreachable!(), + TraitItem::Verbatim(_) => unreachable!(), + + #[cfg(test)] + TraitItem::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; @@ -2596,7 +2609,11 @@ pub mod parsing { ImplItem::Type(item) => &mut item.attrs, ImplItem::Macro(item) => &mut item.attrs, ImplItem::Verbatim(_) => return Ok(item), - ImplItem::__TestExhaustive(_) => unreachable!(), + + #[cfg(test)] + ImplItem::__TestExhaustive(_) => unimplemented!(), + #[cfg(not(test))] + _ => unreachable!(), }; attrs.extend(item_attrs.drain(..)); *item_attrs = attrs; From 5c10cfdf85bd870a607b18cf041bddd90dd46f9b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 2 Feb 2021 19:08:05 -0800 Subject: [PATCH 51/66] Handle tuple structs in spanless_eq_struct --- tests/common/eq.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 7830163d55..81bfe6e3fe 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -129,47 +129,47 @@ spanless_eq_partial_eq!(token::LitKind); macro_rules! spanless_eq_struct { { - $($name:ident)::+ $(<$param:ident>)?; - $([$field:ident $other:ident])* - $(![$ignore:ident])* + $($name:ident)::+ $(<$param:ident>)? + $([$field:tt $this:ident $other:ident])* + $(![$ignore:tt])*; } => { impl $(<$param: SpanlessEq>)* SpanlessEq for $($name)::+ $(<$param>)* { fn eq(&self, other: &Self) -> bool { - let $($name)::+ { $($field,)* $($ignore: _,)* } = self; + let $($name)::+ { $($field: $this,)* $($ignore: _,)* } = self; let $($name)::+ { $($field: $other,)* $($ignore: _,)* } = other; - true $(&& SpanlessEq::eq($field, $other))* + true $(&& SpanlessEq::eq($this, $other))* } } }; { - $($name:ident)::+ $(<$param:ident>)?; - $([$field:ident $other:ident])* - $(![$ignore:ident])* - $next:ident + $($name:ident)::+ $(<$param:ident>)? + $([$field:tt $this:ident $other:ident])* + $(![$ignore:tt])*; + !$next:tt $($rest:tt)* } => { spanless_eq_struct! { - $($name)::+ $(<$param>)*; - $([$field $other])* - [$next other] + $($name)::+ $(<$param>)* + $([$field $this $other])* $(![$ignore])* + ![$next]; $($rest)* } }; { - $($name:ident)::+ $(<$param:ident>)?; - $([$field:ident $other:ident])* - $(![$ignore:ident])* - !$next:ident + $($name:ident)::+ $(<$param:ident>)? + $([$field:tt $this:ident $other:ident])* + $(![$ignore:tt])*; + $next:tt $($rest:tt)* } => { spanless_eq_struct! { - $($name)::+ $(<$param>)*; - $([$field $other])* - $(![$ignore])* - ![$next] + $($name)::+ $(<$param>)* + $([$field $this $other])* + [$next this other] + $(![$ignore])*; $($rest)* } }; From a7beb3d3b60ede1ee0a5d18572c363983d0b60f3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 2 Feb 2021 19:08:34 -0800 Subject: [PATCH 52/66] SpanlessEq for Box --- tests/common/eq.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 81bfe6e3fe..5aeac33eb1 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -32,6 +32,12 @@ pub trait SpanlessEq { fn eq(&self, other: &Self) -> bool; } +impl SpanlessEq for Box { + fn eq(&self, other: &Self) -> bool { + SpanlessEq::eq(&**self, &**other) + } +} + impl SpanlessEq for P { fn eq(&self, other: &Self) -> bool { SpanlessEq::eq(&**self, &**other) From dd32a880b7bb6af4ff59d3658ae95f0551c856f3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 2 Feb 2021 19:08:40 -0800 Subject: [PATCH 53/66] Update test suite to nightly-2021-02-03 --- tests/common/eq.rs | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 5aeac33eb1..dd15106746 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -7,17 +7,17 @@ use rustc_ast::ast::{ AssocTyConstraintKind, Async, AttrId, AttrItem, AttrKind, AttrStyle, Attribute, BareFnTy, BinOpKind, BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Const, Crate, CrateSugar, Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader, - FnRetTy, FnSig, ForeignItemKind, ForeignMod, GenericArg, GenericArgs, GenericBound, - GenericParam, GenericParamKind, Generics, GlobalAsm, ImplPolarity, InlineAsm, InlineAsmOperand, - InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, IntTy, IsAuto, Item, - ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType, LitKind, LlvmAsmDialect, - LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacCallStmt, MacDelimiter, - MacStmtStyle, MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, - Pat, PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, - StmtKind, StrLit, StrStyle, StructField, StructRest, TraitBoundModifier, TraitObjectSyntax, - TraitRef, Ty, TyKind, UintTy, UnOp, Unsafe, UnsafeSource, UseTree, UseTreeKind, Variant, - VariantData, Visibility, VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate, - WherePredicate, WhereRegionPredicate, + FnKind, FnRetTy, FnSig, ForeignItemKind, ForeignMod, GenericArg, GenericArgs, GenericBound, + GenericParam, GenericParamKind, Generics, GlobalAsm, ImplKind, ImplPolarity, InlineAsm, + InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, IntTy, + IsAuto, Item, ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType, LitKind, + LlvmAsmDialect, LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacCallStmt, + MacDelimiter, MacStmtStyle, MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, + ParenthesizedArgs, Pat, PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, + RangeSyntax, Stmt, StmtKind, StrLit, StrStyle, StructField, StructRest, TraitBoundModifier, + TraitKind, TraitObjectSyntax, TraitRef, Ty, TyAliasKind, TyKind, UintTy, UnOp, Unsafe, + UnsafeSource, UseTree, UseTreeKind, Variant, VariantData, Visibility, VisibilityKind, + WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate, }; use rustc_ast::ptr::P; use rustc_ast::token::{self, CommentKind, DelimToken, Nonterminal, Token, TokenKind}; @@ -295,11 +295,13 @@ spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder) spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder); spanless_eq_struct!(FnDecl; inputs output); spanless_eq_struct!(FnHeader; constness asyncness unsafety ext); +spanless_eq_struct!(FnKind; 0 1 2 3); spanless_eq_struct!(FnSig; header decl span); spanless_eq_struct!(ForeignMod; unsafety abi items); spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind); spanless_eq_struct!(Generics; params where_clause span); spanless_eq_struct!(GlobalAsm; asm); +spanless_eq_struct!(ImplKind; unsafety polarity defaultness constness generics of_trait self_ty items); spanless_eq_struct!(InlineAsm; template operands options line_spans); spanless_eq_struct!(Item; attrs id span vis ident kind !tokens); spanless_eq_struct!(Label; ident); @@ -323,8 +325,10 @@ spanless_eq_struct!(Stmt; id kind span); spanless_eq_struct!(StrLit; style symbol suffix span symbol_unescaped); spanless_eq_struct!(StructField; attrs id span vis ident ty is_placeholder); spanless_eq_struct!(Token; kind span); +spanless_eq_struct!(TraitKind; 0 1 2 3 4); spanless_eq_struct!(TraitRef; path ref_id); spanless_eq_struct!(Ty; id kind span tokens); +spanless_eq_struct!(TyAliasKind; 0 1 2 3); spanless_eq_struct!(UseTree; prefix kind span); spanless_eq_struct!(Variant; attrs id span !vis ident data disr_expr is_placeholder); spanless_eq_struct!(Visibility; kind span tokens); @@ -334,7 +338,7 @@ spanless_eq_struct!(WhereEqPredicate; id span lhs_ty rhs_ty); spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds); spanless_eq_struct!(token::Lit; kind symbol suffix); spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0)); -spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0)); +spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0) TyAlias(0) MacCall(0)); spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds)); spanless_eq_enum!(Async; Yes(span closure_id return_impl_trait_id) No); spanless_eq_enum!(AttrStyle; Outer Inner); @@ -349,7 +353,7 @@ spanless_eq_enum!(Defaultness; Default(0) Final); spanless_eq_enum!(Extern; None Implicit Explicit(0)); spanless_eq_enum!(FloatTy; F32 F64); spanless_eq_enum!(FnRetTy; Default(0) Ty(0)); -spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0)); +spanless_eq_enum!(ForeignItemKind; Static(0 1 2) Fn(0) TyAlias(0) MacCall(0)); spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0)); spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0)); spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0)); @@ -395,10 +399,8 @@ spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr) InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(expr) Sym(expr)); spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1 2) - Fn(0 1 2 3) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0 1 2 3) Enum(0 1) - Struct(0 1) Union(0 1) Trait(0 1 2 3 4) TraitAlias(0 1) - Impl(unsafety polarity defaultness constness generics of_trait self_ty items) - MacCall(0) MacroDef(0)); + Fn(0) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1) Struct(0 1) + Union(0 1) Trait(0) TraitAlias(0 1) Impl(0) MacCall(0) MacroDef(0)); spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1) Float(0 1) Bool(0) Err(0)); spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2) TupleStruct(0 1) From 146965a7de98c28807e0b51e5c0b2407599a5f6f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 3 Feb 2021 20:17:26 -0800 Subject: [PATCH 54/66] Ignore new missing_panics_doc pedantic clippy lint --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 2c201c9900..91f6163b1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -260,6 +260,7 @@ clippy::inherent_to_string, clippy::large_enum_variant, clippy::match_on_vec_items, + clippy::missing_panics_doc, clippy::needless_doctest_main, clippy::needless_pass_by_value, clippy::never_loop, From 8c92202c3a50273c81a1bec136dc5c7b023d19a8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Feb 2021 11:19:20 -0800 Subject: [PATCH 55/66] Update test suite to nightly-2021-02-04 --- tests/repo/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index afb712731d..1aec125535 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -8,7 +8,7 @@ use std::path::Path; use tar::Archive; use walkdir::DirEntry; -const REVISION: &str = "72da5a9d85a522b11e80d0fdd1fd95247d442604"; +const REVISION: &str = "e708cbd91c9cae4426d69270248362b423324556"; #[rustfmt::skip] static EXCLUDE: &[&str] = &[ @@ -27,11 +27,11 @@ static EXCLUDE: &[&str] = &[ "src/test/rustdoc-ui/test-compile-fail3.rs", "src/test/ui/include-single-expr-helper.rs", "src/test/ui/include-single-expr-helper-1.rs", - "src/test/ui/issues/auxiliary/issue-21146-inc.rs", "src/test/ui/json-bom-plus-crlf-multifile-aux.rs", "src/test/ui/lint/expansion-time-include.rs", "src/test/ui/macros/auxiliary/macro-comma-support.rs", "src/test/ui/macros/auxiliary/macro-include-items-expr.rs", + "src/test/ui/parser/auxiliary/issue-21146-inc.rs", ]; pub fn base_dir_filter(entry: &DirEntry) -> bool { From a54fb0098c6679f1312113ae2eec0305c51c7390 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 19 Feb 2021 18:35:00 -0800 Subject: [PATCH 56/66] Update test suite to nightly-2021-02-20 --- tests/common/eq.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index dd15106746..51fb7c77cd 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -8,11 +8,11 @@ use rustc_ast::ast::{ BinOpKind, BindingMode, Block, BlockCheckMode, BorrowKind, CaptureBy, Const, Crate, CrateSugar, Defaultness, EnumDef, Expr, ExprKind, Extern, Field, FieldPat, FloatTy, FnDecl, FnHeader, FnKind, FnRetTy, FnSig, ForeignItemKind, ForeignMod, GenericArg, GenericArgs, GenericBound, - GenericParam, GenericParamKind, Generics, GlobalAsm, ImplKind, ImplPolarity, InlineAsm, + GenericParam, GenericParamKind, Generics, GlobalAsm, ImplKind, ImplPolarity, Inline, InlineAsm, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, IntTy, IsAuto, Item, ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType, LitKind, LlvmAsmDialect, LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacCallStmt, - MacDelimiter, MacStmtStyle, MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, + MacDelimiter, MacStmtStyle, MacroDef, ModKind, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, StrLit, StrStyle, StructField, StructRest, TraitBoundModifier, TraitKind, TraitObjectSyntax, TraitRef, Ty, TyAliasKind, TyKind, UintTy, UnOp, Unsafe, @@ -288,7 +288,7 @@ spanless_eq_struct!(AttrItem; path args tokens); spanless_eq_struct!(Attribute; kind id style span); spanless_eq_struct!(BareFnTy; unsafety ext generic_params decl); spanless_eq_struct!(Block; stmts id rules span tokens); -spanless_eq_struct!(Crate; module attrs span proc_macros); +spanless_eq_struct!(Crate; attrs items span proc_macros); spanless_eq_struct!(EnumDef; variants); spanless_eq_struct!(Expr; id kind span attrs !tokens); spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder); @@ -313,7 +313,6 @@ spanless_eq_struct!(Local; pat ty init id span attrs !tokens); spanless_eq_struct!(MacCall; path args prior_type_ascription); spanless_eq_struct!(MacCallStmt; mac style attrs tokens); spanless_eq_struct!(MacroDef; body macro_rules); -spanless_eq_struct!(Mod; inner unsafety items inline); spanless_eq_struct!(MutTy; ty mutbl); spanless_eq_struct!(ParenthesizedArgs; span inputs inputs_span output); spanless_eq_struct!(Pat; id kind span tokens); @@ -359,6 +358,7 @@ spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0)); spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0)); spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span default)); spanless_eq_enum!(ImplPolarity; Positive Negative(0)); +spanless_eq_enum!(Inline; Yes No); spanless_eq_enum!(InlineAsmRegOrRegClass; Reg(0) RegClass(0)); spanless_eq_enum!(InlineAsmTemplatePiece; String(0) Placeholder(operand_idx modifier span)); spanless_eq_enum!(IntTy; Isize I8 I16 I32 I64 I128); @@ -369,6 +369,7 @@ spanless_eq_enum!(LlvmAsmDialect; Att Intel); spanless_eq_enum!(MacArgs; Empty Delimited(0 1 2) Eq(0 1)); spanless_eq_enum!(MacDelimiter; Parenthesis Bracket Brace); spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces); +spanless_eq_enum!(ModKind; Loaded(0 1 2) Unloaded); spanless_eq_enum!(Movability; Static Movable); spanless_eq_enum!(Mutability; Mut Not); spanless_eq_enum!(RangeEnd; Included(0) Excluded); @@ -399,7 +400,7 @@ spanless_eq_enum!(InlineAsmOperand; In(reg expr) Out(reg late expr) InOut(reg late expr) SplitInOut(reg late in_expr out_expr) Const(expr) Sym(expr)); spanless_eq_enum!(ItemKind; ExternCrate(0) Use(0) Static(0 1 2) Const(0 1 2) - Fn(0) Mod(0) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1) Struct(0 1) + Fn(0) Mod(0 1) ForeignMod(0) GlobalAsm(0) TyAlias(0) Enum(0 1) Struct(0 1) Union(0 1) Trait(0) TraitAlias(0 1) Impl(0) MacCall(0) MacroDef(0)); spanless_eq_enum!(LitKind; Str(0 1) ByteStr(0) Byte(0) Char(0) Int(0 1) Float(0 1) Bool(0) Err(0)); From 8a75e4581c8f05ef74dbaccf272e8391cf0ec579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Tue, 23 Feb 2021 16:06:29 +0300 Subject: [PATCH 57/66] Replace assertions in Puctuated with more helpful panic messages Debugging proc macros is very difficult as we can't easily get backtraces into the proc macro code. Improved error messages will hopefully give some hint to the user on what the problem is. --- src/punctuated.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/punctuated.rs b/src/punctuated.rs index 4d3496976c..b86cf8d160 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -162,7 +162,12 @@ impl Punctuated { /// Panics if the sequence does not already have a trailing punctuation when /// this method is called. pub fn push_value(&mut self, value: T) { - assert!(self.empty_or_trailing()); + assert!( + self.empty_or_trailing(), + "Punctuated::push_value: Punctuated is not empty or \ + does not have a trailing punctuation" + ); + self.last = Some(Box::new(value)); } @@ -174,7 +179,10 @@ impl Punctuated { /// /// Panics if the sequence is empty or already has a trailing punctuation. pub fn push_punct(&mut self, punctuation: P) { - assert!(self.last.is_some()); + assert!( + self.last.is_some(), + "Punctuated::push_punct: Punctuated doesn't have any items" + ); let last = self.last.take().unwrap(); self.inner.push((*last, punctuation)); } @@ -228,7 +236,10 @@ impl Punctuated { where P: Default, { - assert!(index <= self.len()); + assert!( + index <= self.len(), + "Punctuated::insert: index out of range" + ); if index == self.len() { self.push(value); @@ -454,7 +465,12 @@ impl FromIterator> for Punctuated { impl Extend> for Punctuated { fn extend>>(&mut self, i: I) { - assert!(self.empty_or_trailing()); + assert!( + self.empty_or_trailing(), + "Punctuated::extend: Punctuated is not empty or \ + does not have a trailing punctuation" + ); + let mut nomore = false; for pair in i { if nomore { From 799c21b07b71c4bf9555f9551fa7042796add97f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Feb 2021 20:40:01 -0800 Subject: [PATCH 58/66] Resolve inconsistent_struct_constructor style lint error: inconsistent struct constructor --> src/item.rs:1497:16 | 1497 | Ok(Signature { | ________________^ 1498 | | constness, 1499 | | asyncness, 1500 | | unsafety, ... | 1508 | | generics, 1509 | | }) | |_____________^ help: try: `Signature { constness, asyncness, unsafety, abi, fn_token, ident, generics, paren_token, inputs, variadic, output }` | = note: `-D clippy::inconsistent-struct-constructor` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#inconsistent_struct_constructor --- src/item.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/item.rs b/src/item.rs index d943debd5f..5cf501b92a 100644 --- a/src/item.rs +++ b/src/item.rs @@ -1501,11 +1501,11 @@ pub mod parsing { abi, fn_token, ident, + generics, paren_token, inputs, - output, variadic, - generics, + output, }) } } From 0bd6d57baa589331e0306d76fae42324aa13039c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 25 Feb 2021 20:40:41 -0800 Subject: [PATCH 59/66] Ignore incorrect suggestion from manual_map lint https://github.com/rust-lang/rust-clippy/issues/6795 error: manual implementation of `Option::map` --> src/item.rs:1194:22 | 1194 | let ty = if let Some(eq_token) = input.parse()? { | ______________________^ 1195 | | Some((eq_token, input.parse::()?)) 1196 | | } else { 1197 | | None 1198 | | }; | |_____________^ help: try this: `input.parse()?.map(|eq_token| (eq_token, input.parse::()?))` | = note: `-D clippy::manual-map` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#manual_map --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 91f6163b1c..1a5b082b83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -259,6 +259,7 @@ clippy::eval_order_dependence, clippy::inherent_to_string, clippy::large_enum_variant, + clippy::manual_map, // https://github.com/rust-lang/rust-clippy/issues/6795 clippy::match_on_vec_items, clippy::missing_panics_doc, clippy::needless_doctest_main, From 2b0c9bda9bfc1f05a985ae34f4f94af58d352b6d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 17:43:06 -0800 Subject: [PATCH 60/66] Format PR 970 in rustfmt style --- src/punctuated.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/punctuated.rs b/src/punctuated.rs index b86cf8d160..8e676abd58 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -165,7 +165,7 @@ impl Punctuated { assert!( self.empty_or_trailing(), "Punctuated::push_value: Punctuated is not empty or \ - does not have a trailing punctuation" + does not have a trailing punctuation", ); self.last = Some(Box::new(value)); @@ -181,7 +181,7 @@ impl Punctuated { pub fn push_punct(&mut self, punctuation: P) { assert!( self.last.is_some(), - "Punctuated::push_punct: Punctuated doesn't have any items" + "Punctuated::push_punct: Punctuated doesn't have any items", ); let last = self.last.take().unwrap(); self.inner.push((*last, punctuation)); @@ -238,7 +238,7 @@ impl Punctuated { { assert!( index <= self.len(), - "Punctuated::insert: index out of range" + "Punctuated::insert: index out of range", ); if index == self.len() { @@ -468,7 +468,7 @@ impl Extend> for Punctuated { assert!( self.empty_or_trailing(), "Punctuated::extend: Punctuated is not empty or \ - does not have a trailing punctuation" + does not have a trailing punctuation", ); let mut nomore = false; From f6460f4fb1190a185d1bcfba007a901a2c1fb6ed Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 17:43:53 -0800 Subject: [PATCH 61/66] Eliminate line break in middle of panic message from PR 970 This makes the complete error message more easily greppable. --- src/punctuated.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/punctuated.rs b/src/punctuated.rs index 8e676abd58..299548c68c 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -164,8 +164,7 @@ impl Punctuated { pub fn push_value(&mut self, value: T) { assert!( self.empty_or_trailing(), - "Punctuated::push_value: Punctuated is not empty or \ - does not have a trailing punctuation", + "Punctuated::push_value: Punctuated is not empty or does not have a trailing punctuation", ); self.last = Some(Box::new(value)); @@ -467,8 +466,7 @@ impl Extend> for Punctuated { fn extend>>(&mut self, i: I) { assert!( self.empty_or_trailing(), - "Punctuated::extend: Punctuated is not empty or \ - does not have a trailing punctuation", + "Punctuated::extend: Punctuated is not empty or does not have a trailing punctuation", ); let mut nomore = false; From 38d99a7f8cbc1cceb06eab8378348a988561c84e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 17:47:01 -0800 Subject: [PATCH 62/66] Touch up assertion messages from PR 970 --- src/punctuated.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/punctuated.rs b/src/punctuated.rs index 299548c68c..f94edc2915 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -164,7 +164,7 @@ impl Punctuated { pub fn push_value(&mut self, value: T) { assert!( self.empty_or_trailing(), - "Punctuated::push_value: Punctuated is not empty or does not have a trailing punctuation", + "Punctuated::push_value: cannot push value if Punctuated is missing trailing punctuation", ); self.last = Some(Box::new(value)); @@ -180,8 +180,9 @@ impl Punctuated { pub fn push_punct(&mut self, punctuation: P) { assert!( self.last.is_some(), - "Punctuated::push_punct: Punctuated doesn't have any items", + "Punctuated::push_punct: cannot push punctuation if Punctuated is empty or already has trailing punctuation", ); + let last = self.last.take().unwrap(); self.inner.push((*last, punctuation)); } From 9001d9fa02b850e9339b66fb5bbf4a30b4e18d53 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 17:50:11 -0800 Subject: [PATCH 63/66] Add Lifetime span getter and setter --- src/lifetime.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lifetime.rs b/src/lifetime.rs index 9cec5eec3a..28cd7e3622 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -57,6 +57,17 @@ impl Lifetime { ident: Ident::new(&symbol[1..], span), } } + + pub fn span(&self) -> Span { + self.apostrophe + .join(self.ident.span()) + .unwrap_or(self.apostrophe) + } + + pub fn set_span(&mut self, span: Span) { + self.apostrophe = span; + self.ident.set_span(span); + } } impl Display for Lifetime { From b2f1da284d666ec59571033807f46a8c082330cb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 18:01:58 -0800 Subject: [PATCH 64/66] Expose accessors on LitBool consistent with other Lit variants --- src/lit.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/lit.rs b/src/lit.rs index d67ee88426..0aa50a590c 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -505,6 +505,24 @@ impl Display for LitFloat { } } +impl LitBool { + pub fn new(value: bool, span: Span) -> Self { + LitBool { value, span } + } + + pub fn value(&self) -> bool { + self.value + } + + pub fn span(&self) -> Span { + self.span + } + + pub fn set_span(&mut self, span: Span) { + self.span = span; + } +} + #[cfg(feature = "extra-traits")] mod debug_impls { use super::*; From d131635ed57c81f3548e377c100dec30b497bf21 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Mar 2021 18:14:25 -0800 Subject: [PATCH 65/66] Release 1.0.61 --- Cargo.toml | 2 +- src/lib.rs | 2 +- syn.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 11d01b11fd..27e3bd64e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.60" # don't forget to update html_root_url and syn.json +version = "1.0.61" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 1a5b082b83..89ab01178a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.60")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.61")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow(non_camel_case_types)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index aac573cdf5..0c396eac56 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.60", + "version": "1.0.61", "types": [ { "ident": "Abi", From 5532e28bc2c9fb0ee20cf1fab63958bdce6c2435 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Mar 2021 12:46:46 -0800 Subject: [PATCH 66/66] Release 1.0.62 --- Cargo.toml | 2 +- dev/main.rs | 546 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 2 +- syn.json | 2 +- 4 files changed, 549 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 27e3bd64e0..0737d18f1d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "1.0.61" # don't forget to update html_root_url and syn.json +version = "1.0.62" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] license = "MIT OR Apache-2.0" description = "Parser for Rust source code" diff --git a/dev/main.rs b/dev/main.rs index eb675465f0..8ef674bcd8 100644 --- a/dev/main.rs +++ b/dev/main.rs @@ -1,4 +1,550 @@ syn_dev::r#mod! { // Write Rust code here and run `cargo check` to have Syn parse it. +//! Ergonomic, checked cast functions for primitive types +//! +//! This crate provides one checked cast function for each numeric primitive. +//! Use these functions to perform a cast from any other numeric primitive: +//! +//! ``` +//! extern crate cast; +//! +//! use cast::{u8, u16, Error}; +//! +//! # fn main() { +//! // Infallible operations, like integer promotion, are equivalent to a normal +//! // cast with `as` +//! assert_eq!(u16(0u8), 0u16); +//! +//! // Everything else will return a `Result` depending on the success of the +//! // operation +//! assert_eq!(u8(0u16), Ok(0u8)); +//! assert_eq!(u8(256u16), Err(Error::Overflow)); +//! assert_eq!(u8(-1i8), Err(Error::Underflow)); +//! assert_eq!(u8(1. / 0.), Err(Error::Infinite)); +//! assert_eq!(u8(0. / 0.), Err(Error::NaN)); +//! # } +//! ``` +//! +//! There are no namespace problems between these functions, the "primitive +//! modules" in `core`/`std` and the built-in primitive types, so all them can +//! be in the same scope: +//! +//! ``` +//! extern crate cast; +//! +//! use std::u8; +//! use cast::{u8, u16}; +//! +//! # fn main() { +//! // `u8` as a type +//! let x: u8 = 0; +//! // `u8` as a module +//! let y = u16(u8::MAX); +//! // `u8` as a function +//! let z = u8(y).unwrap(); +//! # } +//! ``` +//! +//! The checked cast functionality is also usable with type aliases via the +//! `cast` static method: +//! +//! ``` +//! extern crate cast; +//! +//! use std::os::raw::c_ulonglong; +//! // NOTE avoid shadowing `std::convert::From` - cf. rust-lang/rfcs#1311 +//! use cast::From as _0; +//! +//! # fn main() { +//! assert_eq!(c_ulonglong::cast(0u8), 0u64); +//! # } +//! ``` +//! +//! This crate also provides a `From` trait that can be used, for example, +//! to create a generic function that accepts any type that can be infallibly +//! casted to `u32`. +//! +//! ``` +//! extern crate cast; +//! +//! fn to_u32(x: T) -> u32 +//! // reads as: "where u32 can be casted from T with output u32" +//! where u32: cast::From, +//! { +//! cast::u32(x) +//! } +//! +//! # fn main() { +//! assert_eq!(to_u32(0u8), 0u32); +//! assert_eq!(to_u32(1u16), 1u32); +//! assert_eq!(to_u32(2u32), 2u32); +//! +//! // to_u32(-1i32); // Compile error +//! # } +//! ``` +//! +//! ## Minimal Supported Rust Version +//! +//! This crate is guaranteed to compile on stable Rust 1.13 and up. It *might* compile on older +//! versions but that may change in any new patch release. +//! +//! ## Building without `std` +//! +//! This crate can be used without Rust's `std` crate by declaring it as +//! follows in your `Cargo.toml`: +//! +//! ``` toml +//! cast = { version = "*", default-features = false } +//! ``` + +#![deny(missing_docs)] +#![deny(warnings)] +#![allow(const_err)] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(all(feature = "x128", not(stable_i128)), feature(i128_type, i128))] + +#[cfg(feature = "std")] +extern crate core; + +#[cfg(test)] +#[macro_use] +extern crate quickcheck; + +use core::fmt; +#[cfg(feature = "std")] +use std::error; + +#[cfg(test)] +mod test; + +/// Cast errors +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Error { + /// Infinite value casted to a type that can only represent finite values + Infinite, + /// NaN value casted to a type that can't represent a NaN value + NaN, + /// Source value is greater than the maximum value that the destination type + /// can hold + Overflow, + /// Source value is smaller than the minimum value that the destination type + /// can hold + Underflow, +} + +impl Error { + /// A private helper function that implements `description`, because + /// `description` is only available when we have `std` enabled. + fn description_helper(&self) -> &str { + match *self { + Error::Infinite => "Cannot store infinite value in finite type", + Error::NaN => "Cannot store NaN in type which does not support it", + Error::Overflow => "Overflow during numeric conversion", + Error::Underflow => "Underflow during numeric conversion", + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.description_helper()) + } +} + +#[cfg(feature = "std")] +impl error::Error for Error { + fn description(&self) -> &str { + self.description_helper() + } +} + +/// The "cast from" operation +pub trait From { + /// The result of the cast operation: either `Self` or `Result` + type Output; + + /// Checked cast from `Src` to `Self` + fn cast(Src) -> Self::Output; +} + +macro_rules! fns { + ($($ty:ident),+) => { + $( + /// Checked cast function + #[inline] + pub fn $ty(x: T) -> <$ty as From>::Output + where $ty: From + { + <$ty as From>::cast(x) + } + )+ + } +} + +fns!(f32, f64, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); + +#[cfg(feature = "x128")] +fns!(i128, u128); + +/// `$dst` can hold any value of `$src` +macro_rules! promotion { + ($($src:ty => $($dst: ty),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = $dst; + + #[inline] + fn cast(src: $src) -> $dst { + src as $dst + } + } + )+ + )+ + } +} + +/// `$dst` can hold any positive value of `$src` +macro_rules! half_promotion { + ($($src:ty => $($dst:ty),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = Result<$dst, Error>; + + #[inline] + fn cast(src: $src) -> Self::Output { + if src < 0 { + Err(Error::Underflow) + } else { + Ok(src as $dst) + } + } + } + )+ + )+ + } +} + +/// From an unsigned `$src` to a smaller `$dst` +macro_rules! from_unsigned { + ($($src:ident => $($dst:ident),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = Result<$dst, Error>; + + #[inline] + fn cast(src: $src) -> Self::Output { + use core::$dst; + + if src > $dst::MAX as $src { + Err(Error::Overflow) + } else { + Ok(src as $dst) + } + } + } + )+ + )+ + } +} + +/// From a signed `$src` to a smaller `$dst` +macro_rules! from_signed { + ($($src:ident => $($dst:ident),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = Result<$dst, Error>; + + #[inline] + fn cast(src: $src) -> Self::Output { + use core::$dst; + + Err(if src < $dst::MIN as $src { + Error::Underflow + } else if src > $dst::MAX as $src { + Error::Overflow + } else { + return Ok(src as $dst); + }) + } + } + )+ + )+ + } +} + +/// From a float `$src` to an integer `$dst` +macro_rules! from_float { + ($($src:ident, $usrc:ident => $($dst:ident),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = Result<$dst, Error>; + + #[inline] + fn cast(src: $src) -> Self::Output { + use core::{$dst, $src}; + + Err(if src != src { + Error::NaN + } else if src == $src::INFINITY || + src == $src::NEG_INFINITY { + Error::Infinite + } else if { + // we subtract 1 ULP (unit of least precision) here because some + // lossy conversions like `u64::MAX as f64` round *up* and we want + // to avoid this evaluating to false in that case + use core::mem::transmute; + let max = unsafe { + transmute::<_, $src>(transmute::<_, $usrc>($dst::MAX as $src) - 1) + }; + src > max + } { + Error::Overflow + } else if $dst::MIN == 0 { + // when casting to unsigned integer, negative values close to 0 but + // larger than 1.0 should be truncated to 0; this behavior matches + // casting from a float to a signed integer + if src <= -1.0 { + Error::Underflow + } else { + return Ok(src as $dst); + } + } else if src < $dst::MIN as $src { + Error::Underflow + } else { + return Ok(src as $dst); + }) + } + } + )+ + )+ + } +} + +/// From a float `$src` to an integer `$dst`, where $dst is large enough to contain +/// all values of `$src`. We can't ever overflow here +#[cfg(feature = "x128")] +macro_rules! from_float_dst { + ($($src:ident => $($dst:ident),+);+;) => { + $( + $( + impl From<$src> for $dst { + type Output = Result<$dst, Error>; + + #[inline] + #[allow(unused_comparisons)] + fn cast(src: $src) -> Self::Output { + use core::{$dst, $src}; + + Err(if src != src { + Error::NaN + } else if src == $src::INFINITY || + src == $src::NEG_INFINITY { + Error::Infinite + } else if ($dst::MIN == 0) && src <= -1.0 { + Error::Underflow + } else { + return Ok(src as $dst); + }) + } + } + )+ + )+ + } +} + +// PLAY TETRIS! ;-) + +#[cfg(target_pointer_width = "32")] +mod _32 { + use {Error, From}; + + // Signed + promotion! { + i8 => f32, f64, i8, i16, i32, isize, i64; + i16 => f32, f64, i16, i32, isize, i64; + i32 => f32, f64, i32, isize, i64; + isize => f32, f64, i32, isize, i64; + i64 => f32, f64, i64; + } + + half_promotion! { + i8 => u8, u16, u32, usize, u64; + i16 => u16, u32, usize, u64; + i32 => u32, usize, u64; + isize => u32, usize, u64; + i64 => u64; + } + + from_signed! { + + i16 => i8, u8; + i32 => i8, i16, u8, u16; + isize => i8, i16, u8, u16; + i64 => i8, i16, i32, isize, u8, u16, u32, usize; + } + + // Unsigned + promotion! { + u8 => f32, f64, i16, i32, isize, i64, u8, u16, u32, usize, u64; + u16 => f32, f64, i32, isize, i64, u16, u32, usize, u64; + u32 => f32, f64, i64, u32, usize, u64; + usize => f32, f64, i64, u32, usize, u64; + u64 => f32, f64, u64; + } + + from_unsigned! { + u8 => i8; + u16 => i8, i16, u8; + u32 => i8, i16, i32, isize, u8, u16; + usize => i8, i16, i32, isize, u8, u16; + u64 => i8, i16, i32, isize, i64, u8, u16, u32, usize; + } + + // Float + promotion! { + f32 => f32, f64; + f64 => f64; + } + + from_float! { + f32, u32 => i8, i16, i32, isize, i64, u8, u16, u32, usize, u64; + f64, u64 => i8, i16, i32, isize, i64, u8, u16, u32, usize, u64; + } +} + +#[cfg(target_pointer_width = "64")] +mod _64 { + use {Error, From}; + + // Signed + promotion! { + i8 => f32, f64, i8, i16, i32, i64, isize; + i16 => f32, f64, i16, i32, i64, isize; + i32 => f32, f64, i32, i64, isize; + i64 => f32, f64, i64, isize; + isize => f32, f64, i64, isize; + } + + half_promotion! { + i8 => u8, u16, u32, u64, usize; + i16 => u16, u32, u64, usize; + i32 => u32, u64, usize; + i64 => u64, usize; + isize => u64, usize; + } + + from_signed! { + + i16 => i8, u8; + i32 => i8, i16, u8, u16; + i64 => i8, i16, i32, u8, u16, u32; + isize => i8, i16, i32, u8, u16, u32; + } + + // Unsigned + promotion! { + u8 => f32, f64, i16, i32, i64, isize, u8, u16, u32, u64, usize; + u16 => f32, f64, i32, i64, isize, u16, u32, u64, usize; + u32 => f32, f64, i64, isize, u32, u64, usize; + u64 => f32, f64, u64, usize; + usize => f32, f64, u64, usize; + } + + from_unsigned! { + u8 => i8; + u16 => i8, i16, u8; + u32 => i8, i16, i32, u8, u16; + u64 => i8, i16, i32, i64, isize, u8, u16, u32; + usize => i8, i16, i32, i64, isize, u8, u16, u32; + } + + // Float + promotion! { + f32 => f32, f64; + f64 => f64; + } + + from_float! { + f32, u32 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; + f64, u64 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; + } +} + +#[cfg(feature = "x128")] +mod _x128 { + use {Error, From}; + + // Signed + promotion! { + i8 => i128; + i16 => i128; + i32 => i128; + i64 => i128; + isize => i128; + i128 => f32, f64, i128; + } + + half_promotion! { + i8 => u128; + i16 => u128; + i32 => u128; + i64 => u128; + isize => u128; + i128 => u128; + } + + from_signed! { + i128 => i8, i16, i32, i64, isize, u8, u16, u32, u64, usize; + } + + // Unsigned + promotion! { + u8 => i128, u128; + u16 => i128, u128; + u32 => i128, u128; + u64 => i128, u128; + usize => i128, u128; + u128 => f64, u128; + } + + from_unsigned! { + u128 => f32, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, usize; + } + + // Float + from_float! { + f32, u32 => i128; + f64, u64 => i128, u128; + } + + from_float_dst! { + f32 => u128; + } +} + +// The missing piece +impl From for f32 { + type Output = Result; + + #[inline] + fn cast(src: f64) -> Self::Output { + use core::{f32, f64}; + + if src != src || src == f64::INFINITY || src == f64::NEG_INFINITY { + Ok(src as f32) + } else if src < f32::MIN as f64 { + Err(Error::Underflow) + } else if src > f32::MAX as f64 { + Err(Error::Overflow) + } else { + Ok(src as f32) + } + } +} } diff --git a/src/lib.rs b/src/lib.rs index 89ab01178a..0d5ff42708 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.61")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.62")] #![cfg_attr(doc_cfg, feature(doc_cfg))] #![allow(non_camel_case_types)] // Ignored clippy lints. diff --git a/syn.json b/syn.json index 0c396eac56..e82cdc1fc4 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "1.0.61", + "version": "1.0.62", "types": [ { "ident": "Abi",