diff -Nru rust-syn-0.15.26/benches/file.rs rust-syn-0.15.39/benches/file.rs --- rust-syn-0.15.26/benches/file.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/benches/file.rs 2019-06-26 04:29:09.000000000 +0000 @@ -0,0 +1,28 @@ +// $ cargo bench --features full --bench file + +#![recursion_limit = "256"] +#![feature(rustc_private, test)] + +extern crate test; + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[path = "../tests/common/mod.rs"] +mod common; + +use proc_macro2::TokenStream; +use std::fs; +use std::str::FromStr; +use test::Bencher; + +const FILE: &str = "tests/rust/src/libcore/str/mod.rs"; + +#[bench] +fn parse_file(b: &mut Bencher) { + common::clone_rust(); + let content = fs::read_to_string(FILE).unwrap(); + let tokens = TokenStream::from_str(&content).unwrap(); + b.iter(|| syn::parse2::(tokens.clone())); +} diff -Nru rust-syn-0.15.26/benches/rust.rs rust-syn-0.15.39/benches/rust.rs --- rust-syn-0.15.26/benches/rust.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/benches/rust.rs 2019-06-27 09:17:32.000000000 +0000 @@ -0,0 +1,129 @@ +// $ cargo bench --features full --bench rust + +#![recursion_limit = "256"] +#![feature(rustc_private)] + +extern crate rustc_data_structures; +extern crate syntax; +extern crate syntax_pos; + +#[macro_use] +#[path = "../tests/macros/mod.rs"] +mod macros; + +#[path = "../tests/common/mod.rs"] +mod common; + +use proc_macro2::TokenStream; +use rustc_data_structures::sync::Lrc; +use std::fs; +use std::str::FromStr; +use std::time::{Duration, Instant}; +use syntax::edition::Edition; +use syntax::errors::{emitter::Emitter, DiagnosticBuilder, Handler}; +use syntax::parse::ParseSess; +use syntax::source_map::{FilePathMapping, SourceMap}; +use syntax_pos::FileName; + +fn tokenstream_parse(content: &str) -> Result<(), ()> { + TokenStream::from_str(content).map(drop).map_err(drop) +} + +fn syn_parse(content: &str) -> Result<(), ()> { + syn::parse_file(content).map(drop).map_err(drop) +} + +fn libsyntax_parse(content: &str) -> Result<(), ()> { + struct SilentEmitter; + + impl Emitter for SilentEmitter { + fn emit_diagnostic(&mut self, _db: &DiagnosticBuilder) {} + } + + syntax::with_globals(Edition::Edition2018, || { + let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let emitter = Box::new(SilentEmitter); + let handler = Handler::with_emitter(false, None, emitter); + let sess = ParseSess::with_span_handler(handler, cm); + if let Err(mut diagnostic) = syntax::parse::parse_crate_from_source_str( + FileName::Custom("bench".to_owned()), + content.to_owned(), + &sess, + ) { + diagnostic.cancel(); + return Err(()); + }; + Ok(()) + }) +} + +fn read_from_disk(content: &str) -> Result<(), ()> { + let _ = content; + Ok(()) +} + +fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration { + let begin = Instant::now(); + let mut success = 0; + let mut total = 0; + + walkdir::WalkDir::new("tests/rust/src") + .into_iter() + .filter_entry(common::base_dir_filter) + .for_each(|entry| { + let entry = entry.unwrap(); + let path = entry.path(); + if path.is_dir() { + return; + } + let content = fs::read_to_string(path).unwrap(); + let ok = codepath(&content).is_ok(); + success += ok as usize; + total += 1; + if !ok { + eprintln!("FAIL {}", path.display()); + } + }); + + assert_eq!(success, total); + begin.elapsed() +} + +fn main() { + common::clone_rust(); + + macro_rules! testcases { + ($($name:ident,)*) => { + vec![ + $( + (stringify!($name), $name as fn(&str) -> Result<(), ()>), + )* + ] + }; + } + + let mut lines = 0; + let mut files = 0; + exec(|content| { + lines += content.lines().count(); + files += 1; + Ok(()) + }); + eprintln!("\n{} lines in {} files", lines, files); + + for (name, f) in testcases!( + read_from_disk, + tokenstream_parse, + syn_parse, + libsyntax_parse, + ) { + eprint!("{:20}", format!("{}:", name)); + let elapsed = exec(f); + eprintln!( + "elapsed={}.{:03}s", + elapsed.as_secs(), + elapsed.subsec_millis(), + ); + } + eprintln!(); +} diff -Nru rust-syn-0.15.26/build.rs rust-syn-0.15.39/build.rs --- rust-syn-0.15.26/build.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/build.rs 2019-06-27 06:12:39.000000000 +0000 @@ -0,0 +1,76 @@ +use std::env; +use std::process::Command; +use std::str::{self, FromStr}; + +// The rustc-cfg strings below are *not* public API. Please let us know by +// opening a GitHub issue if your build environment requires some way to enable +// these cfgs other than by executing our build script. +fn main() { + let compiler = match rustc_version() { + Some(compiler) => compiler, + None => return, + }; + + if compiler.minor >= 17 { + println!("cargo:rustc-cfg=syn_can_match_trailing_dollar"); + } + + if compiler.minor >= 19 { + println!("cargo:rustc-cfg=syn_can_use_thread_id"); + } + + if compiler.minor >= 20 { + println!("cargo:rustc-cfg=syn_can_use_associated_constants"); + } + + // Macro modularization allows re-exporting the `quote!` macro in 1.30+. + if compiler.minor >= 30 { + println!("cargo:rustc-cfg=syn_can_call_macro_by_path"); + } + + if !compiler.nightly { + println!("cargo:rustc-cfg=syn_disable_nightly_tests"); + } +} + +struct Compiler { + minor: u32, + nightly: bool, +} + +fn rustc_version() -> Option { + let rustc = match env::var_os("RUSTC") { + Some(rustc) => rustc, + None => return None, + }; + + let output = match Command::new(rustc).arg("--version").output() { + Ok(output) => output, + Err(_) => return None, + }; + + let version = match str::from_utf8(&output.stdout) { + Ok(version) => version, + Err(_) => return None, + }; + + let mut pieces = version.split('.'); + if pieces.next() != Some("rustc 1") { + return None; + } + + let next = match pieces.next() { + Some(next) => next, + None => return None, + }; + + let minor = match u32::from_str(next) { + Ok(minor) => minor, + Err(_) => return None, + }; + + Some(Compiler { + minor: minor, + nightly: version.contains("nightly"), + }) +} diff -Nru rust-syn-0.15.26/Cargo.toml rust-syn-0.15.39/Cargo.toml --- rust-syn-0.15.26/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/Cargo.toml 1970-01-01 00:00:00.000000000 +0000 @@ -3,7 +3,7 @@ # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g. crates.io) dependencies +# to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're @@ -12,14 +12,14 @@ [package] name = "syn" -version = "0.15.26" +version = "0.15.39" authors = ["David Tolnay "] -include = ["/Cargo.toml", "/src/**/*.rs", "/README.md", "/LICENSE-APACHE", "/LICENSE-MIT"] +include = ["/benches/**", "/build.rs", "/Cargo.toml", "/LICENSE-APACHE", "/LICENSE-MIT", "/README.md", "/src/**", "/tests/**"] description = "Parser for Rust source code" documentation = "https://docs.rs/syn" readme = "README.md" categories = ["development-tools::procedural-macro-helpers"] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/syn" [package.metadata.docs.rs] all-features = true @@ -27,13 +27,16 @@ [package.metadata.playground] all-features = true -[lib] -name = "syn" - -[[example]] -name = "dump-syntax" -path = "examples/dump-syntax/main.rs" -required-features = ["full", "parsing", "extra-traits"] +[[bench]] +name = "rust" +harness = false +required-features = ["full", "parsing"] +edition = "2018" + +[[bench]] +name = "file" +required-features = ["full", "parsing"] +edition = "2018" [dependencies.proc-macro2] version = "0.4.4" default-features = false @@ -45,12 +48,21 @@ [dependencies.unicode-xid] version = "0.1" +[dev-dependencies.insta] +version = "0.8" + [dev-dependencies.rayon] version = "1.0" +[dev-dependencies.ref-cast] +version = "0.2" + [dev-dependencies.regex] version = "1.0" +[dev-dependencies.termcolor] +version = "1.0" + [dev-dependencies.walkdir] version = "2.1" diff -Nru rust-syn-0.15.26/Cargo.toml.orig rust-syn-0.15.39/Cargo.toml.orig --- rust-syn-0.15.26/Cargo.toml.orig 2019-01-16 05:14:57.000000000 +0000 +++ rust-syn-0.15.39/Cargo.toml.orig 2019-06-27 16:08:20.000000000 +0000 @@ -1,22 +1,23 @@ [package] name = "syn" -version = "0.15.26" # don't forget to update html_root_url +version = "0.15.39" # don't forget to update html_root_url and syn.json authors = ["David Tolnay "] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" description = "Parser for Rust source code" repository = "https://github.com/dtolnay/syn" documentation = "https://docs.rs/syn" categories = ["development-tools::procedural-macro-helpers"] readme = "README.md" -include = ["/Cargo.toml", "/src/**/*.rs", "/README.md", "/LICENSE-APACHE", "/LICENSE-MIT"] - -[lib] -name = "syn" - -[[example]] -name = "dump-syntax" -path = "examples/dump-syntax/main.rs" -required-features = ["full", "parsing", "extra-traits"] +include = [ + "/benches/**", + "/build.rs", + "/Cargo.toml", + "/LICENSE-APACHE", + "/LICENSE-MIT", + "/README.md", + "/src/**", + "/tests/**", +] [features] default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"] @@ -37,10 +38,24 @@ unicode-xid = "0.1" [dev-dependencies] +insta = "0.8" rayon = "1.0" +ref-cast = "0.2" regex = "1.0" +termcolor = "1.0" walkdir = "2.1" +[[bench]] +name = "rust" +edition = "2018" +harness = false +required-features = ["full", "parsing"] + +[[bench]] +name = "file" +edition = "2018" +required-features = ["full", "parsing"] + [package.metadata.docs.rs] all-features = true @@ -49,3 +64,6 @@ [badges] travis-ci = { repository = "dtolnay/syn" } + +[workspace] +members = ["dev", "json"] diff -Nru rust-syn-0.15.26/.cargo_vcs_info.json rust-syn-0.15.39/.cargo_vcs_info.json --- rust-syn-0.15.26/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/.cargo_vcs_info.json 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +1,5 @@ { "git": { - "sha1": "64e7a83e316cb023a2daa2810b1a03f1f96e026e" + "sha1": "49a674c76e19c41a26210b47f72ddad1e425ff34" } } diff -Nru rust-syn-0.15.26/debian/cargo-checksum.json rust-syn-0.15.39/debian/cargo-checksum.json --- rust-syn-0.15.26/debian/cargo-checksum.json 2019-01-21 18:15:37.000000000 +0000 +++ rust-syn-0.15.39/debian/cargo-checksum.json 2019-07-11 07:12:11.000000000 +0000 @@ -1 +1 @@ -{"package":"f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9","files":{}} +{"package":"Could not get crate checksum","files":{}} diff -Nru rust-syn-0.15.26/debian/changelog rust-syn-0.15.39/debian/changelog --- rust-syn-0.15.26/debian/changelog 2019-01-21 18:15:37.000000000 +0000 +++ rust-syn-0.15.39/debian/changelog 2019-07-11 07:12:11.000000000 +0000 @@ -1,3 +1,9 @@ +rust-syn (0.15.39-1) unstable; urgency=medium + + * Package syn 0.15.39 from crates.io using debcargo 2.3.1-alpha.0 + + -- Wolfgang Silbermayr Thu, 11 Jul 2019 09:12:11 +0200 + rust-syn (0.15.26-1) unstable; urgency=medium * Package syn 0.15.26 from crates.io using debcargo 2.2.9 diff -Nru rust-syn-0.15.26/debian/control rust-syn-0.15.39/debian/control --- rust-syn-0.15.26/debian/control 2019-01-21 18:15:37.000000000 +0000 +++ rust-syn-0.15.39/debian/control 2019-07-11 07:12:11.000000000 +0000 @@ -2,7 +2,7 @@ Section: rust Priority: optional Build-Depends: debhelper (>= 11), - dh-cargo (>= 10), + dh-cargo (>= 18), cargo:native , rustc:native , libstd-rust-dev , @@ -30,8 +30,7 @@ librust-syn+default-dev (= ${binary:Version}) Suggests: librust-syn+printing-dev (= ${binary:Version}), - librust-syn+proc-macro-dev (= ${binary:Version}), - librust-syn+quote-dev (= ${binary:Version}) + librust-syn+proc-macro-dev (= ${binary:Version}) Provides: librust-syn+clone-impls-dev (= ${binary:Version}), librust-syn+derive-dev (= ${binary:Version}), @@ -59,15 +58,15 @@ librust-syn-0.15+parsing-dev (= ${binary:Version}), librust-syn-0.15+visit-dev (= ${binary:Version}), librust-syn-0.15+visit-mut-dev (= ${binary:Version}), - librust-syn-0.15.26-dev (= ${binary:Version}), - librust-syn-0.15.26+clone-impls-dev (= ${binary:Version}), - librust-syn-0.15.26+derive-dev (= ${binary:Version}), - librust-syn-0.15.26+extra-traits-dev (= ${binary:Version}), - librust-syn-0.15.26+fold-dev (= ${binary:Version}), - librust-syn-0.15.26+full-dev (= ${binary:Version}), - librust-syn-0.15.26+parsing-dev (= ${binary:Version}), - librust-syn-0.15.26+visit-dev (= ${binary:Version}), - librust-syn-0.15.26+visit-mut-dev (= ${binary:Version}) + librust-syn-0.15.39-dev (= ${binary:Version}), + librust-syn-0.15.39+clone-impls-dev (= ${binary:Version}), + librust-syn-0.15.39+derive-dev (= ${binary:Version}), + librust-syn-0.15.39+extra-traits-dev (= ${binary:Version}), + librust-syn-0.15.39+fold-dev (= ${binary:Version}), + librust-syn-0.15.39+full-dev (= ${binary:Version}), + librust-syn-0.15.39+parsing-dev (= ${binary:Version}), + librust-syn-0.15.39+visit-dev (= ${binary:Version}), + librust-syn-0.15.39+visit-mut-dev (= ${binary:Version}) Description: Parser for Rust source code - Rust source code This package contains the source for the Rust syn crate, packaged by debcargo for use with cargo and dh-cargo. @@ -86,10 +85,10 @@ Provides: librust-syn-0+default-dev (= ${binary:Version}), librust-syn-0.15+default-dev (= ${binary:Version}), - librust-syn-0.15.26+default-dev (= ${binary:Version}) + librust-syn-0.15.39+default-dev (= ${binary:Version}) Description: Parser for Rust source code - feature "default" - This metapackage enables feature default for the Rust syn crate, by pulling in - any additional dependencies needed by that feature. + This metapackage enables feature "default" for the Rust syn crate, by pulling + in any additional dependencies needed by that feature. Package: librust-syn+printing-dev Architecture: any @@ -99,12 +98,18 @@ librust-syn-dev (= ${binary:Version}), librust-quote-0.6-dev Provides: + librust-syn+quote-dev (= ${binary:Version}), librust-syn-0+printing-dev (= ${binary:Version}), + librust-syn-0+quote-dev (= ${binary:Version}), librust-syn-0.15+printing-dev (= ${binary:Version}), - librust-syn-0.15.26+printing-dev (= ${binary:Version}) -Description: Parser for Rust source code - feature "printing" - This metapackage enables feature printing for the Rust syn crate, by pulling in - any additional dependencies needed by that feature. + librust-syn-0.15+quote-dev (= ${binary:Version}), + librust-syn-0.15.39+printing-dev (= ${binary:Version}), + librust-syn-0.15.39+quote-dev (= ${binary:Version}) +Description: Parser for Rust source code - feature "printing" and 1 more + This metapackage enables feature "printing" for the Rust syn crate, by pulling + in any additional dependencies needed by that feature. + . + Additionally, this package also provides the "quote" feature. Package: librust-syn+proc-macro-dev Architecture: any @@ -117,22 +122,7 @@ Provides: librust-syn-0+proc-macro-dev (= ${binary:Version}), librust-syn-0.15+proc-macro-dev (= ${binary:Version}), - librust-syn-0.15.26+proc-macro-dev (= ${binary:Version}) + librust-syn-0.15.39+proc-macro-dev (= ${binary:Version}) Description: Parser for Rust source code - feature "proc-macro" - This metapackage enables feature proc-macro for the Rust syn crate, by pulling - in any additional dependencies needed by that feature. - -Package: librust-syn+quote-dev -Architecture: any -Multi-Arch: same -Depends: - ${misc:Depends}, - librust-syn-dev (= ${binary:Version}), - librust-quote-0.6-dev -Provides: - librust-syn-0+quote-dev (= ${binary:Version}), - librust-syn-0.15+quote-dev (= ${binary:Version}), - librust-syn-0.15.26+quote-dev (= ${binary:Version}) -Description: Parser for Rust source code - feature "quote" - This metapackage enables feature quote for the Rust syn crate, by pulling in - any additional dependencies needed by that feature. + This metapackage enables feature "proc-macro" for the Rust syn crate, by + pulling in any additional dependencies needed by that feature. diff -Nru rust-syn-0.15.26/debian/tests/control rust-syn-0.15.39/debian/tests/control --- rust-syn-0.15.26/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/debian/tests/control 2019-07-11 07:12:11.000000000 +0000 @@ -0,0 +1,19 @@ +Test-Command: /usr/share/cargo/bin/cargo-auto-test syn 0.15.39 --all-targets --all-features +Depends: dh-cargo (>= 18), librust-insta-0.8+default-dev, librust-rayon-1+default-dev, librust-ref-cast-0.2+default-dev, librust-regex-1+default-dev, librust-termcolor-1+default-dev, librust-walkdir-2+default-dev (>= 2.1-~~), @ +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test syn 0.15.39 --all-targets --no-default-features +Depends: dh-cargo (>= 18), librust-insta-0.8+default-dev, librust-rayon-1+default-dev, librust-ref-cast-0.2+default-dev, librust-regex-1+default-dev, librust-termcolor-1+default-dev, librust-walkdir-2+default-dev (>= 2.1-~~), librust-syn-dev +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test syn 0.15.39 --all-targets --features default +Depends: dh-cargo (>= 18), librust-insta-0.8+default-dev, librust-rayon-1+default-dev, librust-ref-cast-0.2+default-dev, librust-regex-1+default-dev, librust-termcolor-1+default-dev, librust-walkdir-2+default-dev (>= 2.1-~~), librust-syn+default-dev +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test syn 0.15.39 --all-targets --features printing +Depends: dh-cargo (>= 18), librust-insta-0.8+default-dev, librust-rayon-1+default-dev, librust-ref-cast-0.2+default-dev, librust-regex-1+default-dev, librust-termcolor-1+default-dev, librust-walkdir-2+default-dev (>= 2.1-~~), librust-syn+printing-dev +Restrictions: allow-stderr, skip-not-installable + +Test-Command: /usr/share/cargo/bin/cargo-auto-test syn 0.15.39 --all-targets --features proc-macro +Depends: dh-cargo (>= 18), librust-insta-0.8+default-dev, librust-rayon-1+default-dev, librust-ref-cast-0.2+default-dev, librust-regex-1+default-dev, librust-termcolor-1+default-dev, librust-walkdir-2+default-dev (>= 2.1-~~), librust-syn+proc-macro-dev +Restrictions: allow-stderr, skip-not-installable diff -Nru rust-syn-0.15.26/README.md rust-syn-0.15.39/README.md --- rust-syn-0.15.26/README.md 2018-12-31 23:04:24.000000000 +0000 +++ rust-syn-0.15.39/README.md 2019-06-05 05:53:25.000000000 +0000 @@ -182,6 +182,18 @@ | ^^^ ``` +## Testing + +When testing macros, we often care not just that the macro can be used +successfully but also that when the macro is provided with invalid input it +produces maximally helpful error messages. Consider using the [`trybuild`] crate +to write tests for errors that are emitted by your macro or errors detected by +the Rust compiler in the expanded code following misuse of the macro. Such tests +help avoid regressions from later refactors that mistakenly make an error no +longer trigger or be less helpful than it used to be. + +[`trybuild`]: https://github.com/dtolnay/trybuild + ## Debugging When developing a procedural macro it can be helpful to look at what the @@ -240,17 +252,19 @@ [proc-macro2]: https://github.com/alexcrichton/proc-macro2 -## License - -Licensed under either of +
- * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) +#### License -at your option. + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + -### Contribution +
+ Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. + diff -Nru rust-syn-0.15.26/src/attr.rs rust-syn-0.15.39/src/attr.rs --- rust-syn-0.15.26/src/attr.rs 2019-01-01 20:07:03.000000000 +0000 +++ rust-syn-0.15.39/src/attr.rs 2019-06-26 04:29:09.000000000 +0000 @@ -133,8 +133,8 @@ } impl Attribute { - /// Parses the tokens after the path as a [`Meta`](enum.Meta.html) if - /// possible. + /// Parses the content of the attribute, consisting of the path and tts, as + /// a [`Meta`](enum.Meta.html) if possible. /// /// Deprecated; use `parse_meta` instead. #[doc(hidden)] @@ -174,8 +174,8 @@ } } - /// Parses the tokens after the path as a [`Meta`](enum.Meta.html) if - /// possible. + /// Parses the content of the attribute, consisting of the path and tts, as + /// a [`Meta`](enum.Meta.html) if possible. #[cfg(feature = "parsing")] pub fn parse_meta(&self) -> Result { if let Some(ref colon) = self.path.leading_colon { @@ -600,11 +600,9 @@ impl Parse for NestedMeta { fn parse(input: ParseStream) -> Result { - let ahead = input.fork(); - - if ahead.peek(Lit) && !(ahead.peek(LitBool) && ahead.peek2(Token![=])) { + if input.peek(Lit) && !(input.peek(LitBool) && input.peek2(Token![=])) { input.parse().map(NestedMeta::Literal) - } else if ahead.call(Ident::parse_any).is_ok() { + } else if private::peek_any_ident(input) { input.parse().map(NestedMeta::Meta) } else { Err(input.error("expected identifier or literal")) diff -Nru rust-syn-0.15.26/src/buffer.rs rust-syn-0.15.39/src/buffer.rs --- rust-syn-0.15.26/src/buffer.rs 2019-01-05 21:25:17.000000000 +0000 +++ rust-syn-0.15.39/src/buffer.rs 2019-06-26 04:29:09.000000000 +0000 @@ -348,6 +348,10 @@ } impl private { + pub fn same_scope(a: Cursor, b: Cursor) -> bool { + a.scope == b.scope + } + #[cfg(procmacro2_semver_exempt)] pub fn open_span_of_group(cursor: Cursor) -> Span { match *cursor.entry() { diff -Nru rust-syn-0.15.26/src/custom_keyword.rs rust-syn-0.15.39/src/custom_keyword.rs --- rust-syn-0.15.26/src/custom_keyword.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/src/custom_keyword.rs 2019-06-05 05:53:25.000000000 +0000 @@ -0,0 +1,252 @@ +/// Define a type that supports parsing and printing a given identifier as if it +/// were a keyword. +/// +/// # Usage +/// +/// As a convention, it is recommended that this macro be invoked within a +/// module called `kw` or `keyword` and that the resulting parser be invoked +/// with a `kw::` or `keyword::` prefix. +/// +/// ```edition2018 +/// mod kw { +/// syn::custom_keyword!(whatever); +/// } +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in keyword token. +/// +/// - [Peeking] — `input.peek(kw::whatever)` +/// +/// - [Parsing] — `input.parse::()?` +/// +/// - [Printing] — `quote!( ... #whatever_token ... )` +/// +/// - Construction from a [`Span`] — `let whatever_token = kw::whatever(sp)` +/// +/// - Field access to its span — `let sp = whatever_token.span` +/// +/// [Peeking]: parse/struct.ParseBuffer.html#method.peek +/// [Parsing]: parse/struct.ParseBuffer.html#method.parse +/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html +/// +/// # Example +/// +/// This example parses input that looks like `bool = true` or `str = "value"`. +/// The key must be either the identifier `bool` or the identifier `str`. If +/// `bool`, the value may be either `true` or `false`. If `str`, the value may +/// be any string literal. +/// +/// The symbols `bool` and `str` are not reserved keywords in Rust so these are +/// not considered keywords in the `syn::token` module. Like any other +/// identifier that is not a keyword, these can be declared as custom keywords +/// by crates that need to use them as such. +/// +/// ```edition2018 +/// use syn::{LitBool, LitStr, Result, Token}; +/// use syn::parse::{Parse, ParseStream}; +/// +/// mod kw { +/// syn::custom_keyword!(bool); +/// syn::custom_keyword!(str); +/// } +/// +/// enum Argument { +/// Bool { +/// bool_token: kw::bool, +/// eq_token: Token![=], +/// value: LitBool, +/// }, +/// Str { +/// str_token: kw::str, +/// eq_token: Token![=], +/// value: LitStr, +/// }, +/// } +/// +/// impl Parse for Argument { +/// fn parse(input: ParseStream) -> Result { +/// let lookahead = input.lookahead1(); +/// if lookahead.peek(kw::bool) { +/// Ok(Argument::Bool { +/// bool_token: input.parse::()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else if lookahead.peek(kw::str) { +/// Ok(Argument::Str { +/// str_token: input.parse::()?, +/// eq_token: input.parse()?, +/// value: input.parse()?, +/// }) +/// } else { +/// Err(lookahead.error()) +/// } +/// } +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_keyword { + ($ident:ident) => { + #[allow(non_camel_case_types)] + pub struct $ident { + pub span: $crate::export::Span, + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans<[$crate::export::Span; 1]>>( + span: __S, + ) -> $ident { + $ident { + span: $crate::export::IntoSpans::into_spans(span)[0], + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident { + span: $crate::export::Span::call_site(), + } + } + } + + impl_parse_for_custom_keyword!($ident); + impl_to_tokens_for_custom_keyword!($ident); + impl_clone_for_custom_keyword!($ident); + impl_extra_traits_for_custom_keyword!($ident); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export] +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 { + if let Some((ident, _rest)) = cursor.ident() { + ident == stringify!($ident) + } else { + false + } + } + + fn display() -> &'static $crate::export::str { + concat!("`", stringify!($ident), "`") + } + } + + 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 ident == stringify!($ident) { + return $crate::export::Ok(($ident { span: ident.span() }, rest)); + } + } + $crate::export::Err(cursor.error(concat!( + "expected `", + stringify!($ident), + "`" + ))) + }) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[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) { + let ident = $crate::Ident::new(stringify!($ident), self.span); + $crate::export::TokenStreamExt::append(tokens, ident); + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_keyword { + ($ident:ident) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[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( + f, + concat!("Keyword [", stringify!($ident), "]"), + ) + } + } + + impl $crate::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_keyword { + ($ident:ident) => {}; +} diff -Nru rust-syn-0.15.26/src/custom_punctuation.rs rust-syn-0.15.39/src/custom_punctuation.rs --- rust-syn-0.15.26/src/custom_punctuation.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/src/custom_punctuation.rs 2019-06-05 05:53:25.000000000 +0000 @@ -0,0 +1,309 @@ +/// Define a type that supports parsing and printing a multi-character symbol +/// as if it were a punctuation token. +/// +/// # Usage +/// +/// ```edition2018 +/// syn::custom_punctuation!(LeftRightArrow, <=>); +/// ``` +/// +/// The generated syntax tree node supports the following operations just like +/// any built-in punctuation token. +/// +/// - [Peeking] — `input.peek(LeftRightArrow)` +/// +/// - [Parsing] — `input.parse::()?` +/// +/// - [Printing] — `quote!( ... #lrarrow ... )` +/// +/// - Construction from a [`Span`] — `let lrarrow = LeftRightArrow(sp)` +/// +/// - Construction from multiple [`Span`] — `let lrarrow = LeftRightArrow([sp, sp, sp])` +/// +/// - Field access to its spans — `let spans = lrarrow.spans` +/// +/// [Peeking]: parse/struct.ParseBuffer.html#method.peek +/// [Parsing]: parse/struct.ParseBuffer.html#method.parse +/// [Printing]: https://docs.rs/quote/0.6/quote/trait.ToTokens.html +/// [`Span`]: https://docs.rs/proc-macro2/0.4/proc_macro2/struct.Span.html +/// +/// # Example +/// +/// ```edition2018 +/// use proc_macro2::{TokenStream, TokenTree}; +/// use syn::parse::{Parse, ParseStream, Peek, Result}; +/// use syn::punctuated::Punctuated; +/// use syn::Expr; +/// +/// syn::custom_punctuation!(PathSeparator, ); +/// +/// // expr expr expr ... +/// struct PathSegments { +/// segments: Punctuated, +/// } +/// +/// impl Parse for PathSegments { +/// fn parse(input: ParseStream) -> Result { +/// let mut segments = Punctuated::new(); +/// +/// let first = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(first)?); +/// +/// while input.peek(PathSeparator) { +/// segments.push_punct(input.parse()?); +/// +/// let next = parse_until(input, PathSeparator)?; +/// segments.push_value(syn::parse2(next)?); +/// } +/// +/// Ok(PathSegments { segments }) +/// } +/// } +/// +/// fn parse_until(input: ParseStream, end: E) -> Result { +/// let mut tokens = TokenStream::new(); +/// while !input.is_empty() && !input.peek(end) { +/// let next: TokenTree = input.parse()?; +/// tokens.extend(Some(next)); +/// } +/// Ok(tokens) +/// } +/// +/// fn main() { +/// let input = r#" a::b c::d::e "#; +/// let _: PathSegments = syn::parse_str(input).unwrap(); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + pub struct $ident { + pub spans: custom_punctuation_repr!($($tt)+), + } + + #[doc(hidden)] + #[allow(non_snake_case)] + pub fn $ident<__S: $crate::export::IntoSpans>( + spans: __S, + ) -> $ident { + let _validate_len = 0 $(+ custom_punctuation_len!(strict, $tt))*; + $ident { + spans: $crate::export::IntoSpans::into_spans(spans) + } + } + + impl $crate::export::Default for $ident { + fn default() -> Self { + $ident($crate::export::Span::call_site()) + } + } + + impl_parse_for_custom_punctuation!($ident, $($tt)+); + impl_to_tokens_for_custom_punctuation!($ident, $($tt)+); + impl_clone_for_custom_punctuation!($ident, $($tt)+); + impl_extra_traits_for_custom_punctuation!($ident, $($tt)+); + }; +} + +// Not public API. +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::token::CustomToken for $ident { + fn peek(cursor: $crate::buffer::Cursor) -> bool { + $crate::token::parsing::peek_punct(cursor, stringify_punct!($($tt)+)) + } + + fn display() -> &'static $crate::export::str { + custom_punctuation_concat!("`", stringify_punct!($($tt)+), "`") + } + } + + impl $crate::parse::Parse for $ident { + fn parse(input: $crate::parse::ParseStream) -> $crate::parse::Result<$ident> { + let spans: custom_punctuation_repr!($($tt)+) = + $crate::token::parsing::punct(input, stringify_punct!($($tt)+))?; + Ok($ident(spans)) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "parsing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_parse_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "printing")] +#[doc(hidden)] +#[macro_export(local_inner_macros)] +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) { + $crate::token::printing::punct(stringify_punct!($($tt)+), &self.spans, tokens) + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "printing"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_to_tokens_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "clone-impls")] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => { + impl $crate::export::Copy for $ident {} + + impl $crate::export::Clone for $ident { + fn clone(&self) -> Self { + *self + } + } + }; +} + +// Not public API. +#[cfg(not(feature = "clone-impls"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_clone_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[cfg(feature = "extra-traits")] +#[doc(hidden)] +#[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::export::Eq for $ident {} + + impl $crate::export::PartialEq for $ident { + fn eq(&self, _other: &Self) -> $crate::export::bool { + true + } + } + + impl $crate::export::Hash for $ident { + fn hash<__H: $crate::export::Hasher>(&self, _state: &mut __H) {} + } + }; +} + +// Not public API. +#[cfg(not(feature = "extra-traits"))] +#[doc(hidden)] +#[macro_export] +macro_rules! impl_extra_traits_for_custom_punctuation { + ($ident:ident, $($tt:tt)+) => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! custom_punctuation_repr { + ($($tt:tt)+) => { + [$crate::export::Span; 0 $(+ custom_punctuation_len!(lenient, $tt))+] + }; +} + +// Not public API. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +#[cfg_attr(rustfmt, rustfmt_skip)] +macro_rules! custom_punctuation_len { + ($mode:ident, +) => { 1 }; + ($mode:ident, +=) => { 2 }; + ($mode:ident, &) => { 1 }; + ($mode:ident, &&) => { 2 }; + ($mode:ident, &=) => { 2 }; + ($mode:ident, @) => { 1 }; + ($mode:ident, !) => { 1 }; + ($mode:ident, ^) => { 1 }; + ($mode:ident, ^=) => { 2 }; + ($mode:ident, :) => { 1 }; + ($mode:ident, ::) => { 2 }; + ($mode:ident, ,) => { 1 }; + ($mode:ident, /) => { 1 }; + ($mode:ident, /=) => { 2 }; + ($mode:ident, .) => { 1 }; + ($mode:ident, ..) => { 2 }; + ($mode:ident, ...) => { 3 }; + ($mode:ident, ..=) => { 3 }; + ($mode:ident, =) => { 1 }; + ($mode:ident, ==) => { 2 }; + ($mode:ident, >=) => { 2 }; + ($mode:ident, >) => { 1 }; + ($mode:ident, <=) => { 2 }; + ($mode:ident, <) => { 1 }; + ($mode:ident, *=) => { 2 }; + ($mode:ident, !=) => { 2 }; + ($mode:ident, |) => { 1 }; + ($mode:ident, |=) => { 2 }; + ($mode:ident, ||) => { 2 }; + ($mode:ident, #) => { 1 }; + ($mode:ident, ?) => { 1 }; + ($mode:ident, ->) => { 2 }; + ($mode:ident, <-) => { 2 }; + ($mode:ident, %) => { 1 }; + ($mode:ident, %=) => { 2 }; + ($mode:ident, =>) => { 2 }; + ($mode:ident, ;) => { 1 }; + ($mode:ident, <<) => { 2 }; + ($mode:ident, <<=) => { 3 }; + ($mode:ident, >>) => { 2 }; + ($mode:ident, >>=) => { 3 }; + ($mode:ident, *) => { 1 }; + ($mode:ident, -) => { 1 }; + ($mode:ident, -=) => { 2 }; + ($mode:ident, ~) => { 1 }; + (lenient, $tt:tt) => { 0 }; + (strict, $tt:tt) => {{ custom_punctuation_unexpected!($tt); 0 }}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_unexpected { + () => {}; +} + +// Not public API. +#[doc(hidden)] +#[macro_export] +macro_rules! stringify_punct { + ($($tt:tt)+) => { + concat!($(stringify!($tt)),+) + }; +} + +// Not public API. +// Without this, local_inner_macros breaks when looking for concat! +#[doc(hidden)] +#[macro_export] +macro_rules! custom_punctuation_concat { + ($($tt:tt)*) => { + concat!($($tt)*) + }; +} diff -Nru rust-syn-0.15.26/src/data.rs rust-syn-0.15.39/src/data.rs --- rust-syn-0.15.26/src/data.rs 2018-12-23 04:37:27.000000000 +0000 +++ rust-syn-0.15.39/src/data.rs 2019-06-26 04:29:09.000000000 +0000 @@ -268,6 +268,7 @@ let pub_token = input.parse::()?; if input.peek(token::Paren) { + // TODO: optimize using advance_to let ahead = input.fork(); let mut content; parenthesized!(content in ahead); diff -Nru rust-syn-0.15.26/src/discouraged.rs rust-syn-0.15.39/src/discouraged.rs --- rust-syn-0.15.26/src/discouraged.rs 1970-01-01 00:00:00.000000000 +0000 +++ rust-syn-0.15.39/src/discouraged.rs 2019-06-26 04:29:09.000000000 +0000 @@ -0,0 +1,171 @@ +//! Extensions to the parsing API with niche applicability. + +use super::*; + +/// Extensions to the `ParseStream` API to support speculative parsing. +pub trait Speculative { + /// Advance this parse stream to the position of a forked parse stream. + /// + /// This is the opposite operation to [`ParseStream::fork`]. You can fork a + /// parse stream, perform some speculative parsing, then join the original + /// stream to the fork to "commit" the parsing from the fork to the main + /// stream. + /// + /// If you can avoid doing this, you should, as it limits the ability to + /// generate useful errors. That said, it is often the only way to parse + /// syntax of the form `A* B*` for arbitrary syntax `A` and `B`. The problem + /// is that when the fork fails to parse an `A`, it's impossible to tell + /// whether that was because of a syntax error and the user meant to provide + /// an `A`, or that the `A`s are finished and its time to start parsing + /// `B`s. Use with care. + /// + /// Also note that if `A` is a subset of `B`, `A* B*` can be parsed by + /// parsing `B*` and removing the leading members of `A` from the + /// repetition, bypassing the need to involve the downsides associated with + /// speculative parsing. + /// + /// [`ParseStream::fork`]: ../struct.ParseBuffer.html#method.fork + /// + /// # Example + /// + /// There has been chatter about the possibility of making the colons in the + /// turbofish syntax like `path::to::` no longer required by accepting + /// `path::to` in expression position. Specifically, according to [RFC + /// 2544], [`PathSegment`] parsing should always try to consume a following + /// `<` token as the start of generic arguments, and reset to the `<` if + /// that fails (e.g. the token is acting as a less-than operator). + /// + /// This is the exact kind of parsing behavior which requires the "fork, + /// try, commit" behavior that [`ParseStream::fork`] discourages. With + /// `advance_to`, we can avoid having to parse the speculatively parsed + /// content a second time. + /// + /// This change in behavior can be implemented in syn by replacing just the + /// `Parse` implementation for `PathSegment`: + /// + /// ```edition2018 + /// # use syn::ext::IdentExt; + /// use syn::parse::discouraged::Speculative; + /// # use syn::parse::{Parse, ParseStream}; + /// # use syn::{Ident, PathArguments, Result, Token}; + /// + /// pub struct PathSegment { + /// pub ident: Ident, + /// pub arguments: PathArguments, + /// } + /// # + /// # impl From for PathSegment + /// # where + /// # T: Into, + /// # { + /// # fn from(ident: T) -> Self { + /// # PathSegment { + /// # ident: ident.into(), + /// # arguments: PathArguments::None, + /// # } + /// # } + /// # } + /// + /// impl Parse for PathSegment { + /// fn parse(input: ParseStream) -> Result { + /// if input.peek(Token![super]) + /// || input.peek(Token![self]) + /// || input.peek(Token![Self]) + /// || input.peek(Token![crate]) + /// || input.peek(Token![extern]) + /// { + /// let ident = input.call(Ident::parse_any)?; + /// return Ok(PathSegment::from(ident)); + /// } + /// + /// let ident = input.parse()?; + /// if input.peek(Token![::]) && input.peek3(Token![<]) { + /// return Ok(PathSegment { + /// ident: ident, + /// arguments: PathArguments::AngleBracketed(input.parse()?), + /// }); + /// } + /// if input.peek(Token![<]) && !input.peek(Token![<=]) { + /// let fork = input.fork(); + /// if let Ok(arguments) = fork.parse() { + /// input.advance_to(&fork); + /// return Ok(PathSegment { + /// ident: ident, + /// arguments: PathArguments::AngleBracketed(arguments), + /// }); + /// } + /// } + /// Ok(PathSegment::from(ident)) + /// } + /// } + /// + /// # syn::parse_str::("a").unwrap(); + /// ``` + /// + /// # Drawbacks + /// + /// The main drawback of this style of speculative parsing is in error + /// presentation. Even if the lookahead is the "correct" parse, the error + /// that is shown is that of the "fallback" parse. To use the same example + /// as the turbofish above, take the following unfinished "turbofish": + /// + /// ```text + /// let _ = f<&'a fn(), for<'a> serde::>(); + /// ``` + /// + /// If this is parsed as generic arguments, we can provide the error message + /// + /// ```text + /// error: expected identifier + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^ + /// ``` + /// + /// but if parsed using the above speculative parsing, it falls back to + /// assuming that the `<` is a less-than when it fails to parse the generic + /// arguments, and tries to interpret the `&'a` as the start of a labelled + /// loop, resulting in the much less helpful error + /// + /// ```text + /// error: expected `:` + /// --> src.rs:L:C + /// | + /// L | let _ = f<&'a fn(), for<'a> serde::>(); + /// | ^^ + /// ``` + /// + /// This can be mitigated with various heuristics (two examples: show both + /// forks' parse errors, or show the one that consumed more tokens), but + /// when you can control the grammar, sticking to something that can be + /// parsed LL(3) and without the LL(*) speculative parsing this makes + /// possible, displaying reasonable errors becomes much more simple. + /// + /// [RFC 2544]: https://github.com/rust-lang/rfcs/pull/2544 + /// [`PathSegment`]: ../../struct.PathSegment.html + /// + /// # Performance + /// + /// This method performs a cheap fixed amount of work that does not depend + /// on how far apart the two streams are positioned. + /// + /// # Panics + /// + /// The forked stream in the argument of `advance_to` must have been + /// obtained by forking `self`. Attempting to advance to any other stream + /// will cause a panic. + fn advance_to(&self, fork: &Self); +} + +impl<'a> Speculative for ParseBuffer<'a> { + fn advance_to(&self, fork: &Self) { + if !private::same_scope(self.cursor(), fork.cursor()) { + panic!("Fork was not derived from the advancing parse stream"); + } + + // See comment on `cell` in the struct definition. + self.cell + .set(unsafe { mem::transmute::>(fork.cursor()) }) + } +} diff -Nru rust-syn-0.15.26/src/error.rs rust-syn-0.15.39/src/error.rs --- rust-syn-0.15.26/src/error.rs 2019-01-05 21:33:35.000000000 +0000 +++ rust-syn-0.15.39/src/error.rs 2019-06-05 05:53:25.000000000 +0000 @@ -1,5 +1,5 @@ use std; -use std::fmt::{self, Display}; +use std::fmt::{self, Debug, Display}; use std::iter::FromIterator; use proc_macro2::{ @@ -24,7 +24,6 @@ /// [module documentation]: index.html /// /// *This type is available if Syn is built with the `"parsing"` feature.* -#[derive(Debug)] pub struct Error { // Span is implemented as an index into a thread-local interner to keep the // size small. It is not safe to access from a different thread. We want @@ -181,6 +180,12 @@ } } +impl Debug for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.debug_tuple("Error").field(&self.message).finish() + } +} + impl Display for Error { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str(&self.message) diff -Nru rust-syn-0.15.26/src/expr.rs rust-syn-0.15.39/src/expr.rs --- rust-syn-0.15.26/src/expr.rs 2019-01-16 04:55:05.000000000 +0000 +++ rust-syn-0.15.39/src/expr.rs 2019-06-26 04:29:09.000000000 +0000 @@ -36,9 +36,10 @@ /// Expr::If(expr) => { /// /* ... */ /// } + /// /// /* ... */ /// # _ => {} - /// } + /// # } /// # } /// ``` /// @@ -50,28 +51,15 @@ /// `expr.receiver`, `expr.args` etc; if we ended up in the `If` case we get /// to use `expr.cond`, `expr.then_branch`, `expr.else_branch`. /// - /// The pattern is similar if the input expression is borrowed: - /// - /// ```edition2018 - /// # use syn::Expr; - /// # - /// # fn example(expr: &Expr) { - /// match *expr { - /// Expr::MethodCall(ref expr) => { - /// # } - /// # _ => {} - /// # } - /// # } - /// ``` - /// /// This approach avoids repeating the variant names twice on every line. /// /// ```edition2018 /// # use syn::{Expr, ExprMethodCall}; /// # /// # fn example(expr: Expr) { - /// # match expr { - /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { // repetitive + /// // Repetitive; recommend not doing this. + /// match expr { + /// Expr::MethodCall(ExprMethodCall { method, args, .. }) => { /// # } /// # _ => {} /// # } @@ -84,10 +72,10 @@ /// ```edition2018 /// # use syn::{Expr, ExprField}; /// # - /// # fn example(discriminant: &ExprField) { + /// # fn example(discriminant: ExprField) { /// // Binding is called `base` which is the name I would use if I were /// // assigning `*discriminant.base` without an `if let`. - /// if let Expr::Tuple(ref base) = *discriminant.base { + /// if let Expr::Tuple(base) = *discriminant.base { /// # } /// # } /// ``` @@ -799,8 +787,8 @@ /// A path pattern like `Color::Red`, optionally qualified with a /// self-type. /// - /// Unquailfied path patterns can legally refer to variants, structs, - /// constants or associated constants. Quailfied path patterns like + /// Unqualified path patterns can legally refer to variants, structs, + /// constants or associated constants. Qualified path patterns like /// `::B::C` and `::B::C` can only legally refer to /// associated constants. /// @@ -1006,7 +994,6 @@ enum Precedence { Any, Assign, - Placement, Range, Or, And, @@ -1123,23 +1110,6 @@ eq_token: eq_token, right: Box::new(rhs), }); - } else if Precedence::Placement >= base && input.peek(Token![<-]) { - let arrow_token: Token![<-] = input.parse()?; - let mut rhs = unary_expr(input, allow_struct)?; - loop { - let next = peek_precedence(input); - if next > Precedence::Placement { - rhs = parse_expr(input, rhs, allow_struct, next)?; - } else { - break; - } - } - lhs = Expr::InPlace(ExprInPlace { - attrs: Vec::new(), - place: Box::new(lhs), - arrow_token: arrow_token, - value: Box::new(rhs), - }); } else if Precedence::Range >= base && input.peek(Token![..]) { let limits: RangeLimits = input.parse()?; let rhs = if input.is_empty() @@ -1243,8 +1213,6 @@ Precedence::of(&op) } else if input.peek(Token![=]) && !input.peek(Token![=>]) { Precedence::Assign - } else if input.peek(Token![<-]) { - Precedence::Placement } else if input.peek(Token![..]) { Precedence::Range } else if input.peek(Token![as]) || input.peek(Token![:]) && !input.peek(Token![::]) { @@ -1266,6 +1234,7 @@ // box #[cfg(feature = "full")] fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result { + // TODO: optimize using advance_to let ahead = input.fork(); ahead.call(Attribute::parse_outer)?; if ahead.peek(Token![&]) @@ -1302,6 +1271,7 @@ #[cfg(not(feature = "full"))] fn unary_expr(input: ParseStream, allow_struct: AllowStruct) -> Result { + // TODO: optimize using advance_to let ahead = input.fork(); ahead.call(Attribute::parse_outer)?; if ahead.peek(Token![*]) || ahead.peek(Token![!]) || ahead.peek(Token![-]) { @@ -1464,7 +1434,7 @@ if input.peek(token::Group) { input.call(expr_group).map(Expr::Group) } else if input.peek(Lit) { - input.call(expr_lit).map(Expr::Lit) + input.parse().map(Expr::Lit) } else if input.peek(Token![async]) && (input.peek2(token::Brace) || input.peek2(Token![move]) && input.peek3(token::Brace)) { @@ -1500,15 +1470,15 @@ } else if input.peek(Token![let]) { input.call(expr_let).map(Expr::Let) } else if input.peek(Token![if]) { - input.call(expr_if).map(Expr::If) + input.parse().map(Expr::If) } else if input.peek(Token![while]) { - input.call(expr_while).map(Expr::While) + input.parse().map(Expr::While) } else if input.peek(Token![for]) { - input.call(expr_for_loop).map(Expr::ForLoop) + input.parse().map(Expr::ForLoop) } else if input.peek(Token![loop]) { - input.call(expr_loop).map(Expr::Loop) + input.parse().map(Expr::Loop) } else if input.peek(Token![match]) { - input.call(expr_match).map(Expr::Match) + input.parse().map(Expr::Match) } else if input.peek(Token![yield]) { input.call(expr_yield).map(Expr::Yield) } else if input.peek(Token![unsafe]) { @@ -1520,11 +1490,11 @@ } else if input.peek(Lifetime) { let the_label: Label = input.parse()?; let mut expr = if input.peek(Token![while]) { - Expr::While(input.call(expr_while)?) + Expr::While(input.parse()?) } else if input.peek(Token![for]) { - Expr::ForLoop(input.call(expr_for_loop)?) + Expr::ForLoop(input.parse()?) } else if input.peek(Token![loop]) { - Expr::Loop(input.call(expr_loop)?) + Expr::Loop(input.parse()?) } else if input.peek(token::Brace) { Expr::Block(input.call(expr_block)?) } else { @@ -1546,7 +1516,7 @@ #[cfg(not(feature = "full"))] fn atom_expr(input: ParseStream, _allow_struct: AllowStruct) -> Result { if input.peek(Lit) { - input.call(expr_lit).map(Expr::Lit) + input.parse().map(Expr::Lit) } else if input.peek(token::Paren) { input.call(expr_paren).map(Expr::Paren) } else if input.peek(Ident) @@ -1695,15 +1665,15 @@ fn expr_early(input: ParseStream) -> Result { let mut attrs = input.call(Attribute::parse_outer)?; let mut expr = if input.peek(Token![if]) { - Expr::If(input.call(expr_if)?) + Expr::If(input.parse()?) } else if input.peek(Token![while]) { - Expr::While(input.call(expr_while)?) + Expr::While(input.parse()?) } else if input.peek(Token![for]) { - Expr::ForLoop(input.call(expr_for_loop)?) + Expr::ForLoop(input.parse()?) } else if input.peek(Token![loop]) { - Expr::Loop(input.call(expr_loop)?) + Expr::Loop(input.parse()?) } else if input.peek(Token![match]) { - Expr::Match(input.call(expr_match)?) + Expr::Match(input.parse()?) } else if input.peek(Token![try]) && input.peek2(token::Brace) { Expr::TryBlock(input.call(expr_try_block)?) } else if input.peek(Token![unsafe]) { @@ -1735,11 +1705,13 @@ Ok(expr) } - pub fn expr_lit(input: ParseStream) -> Result { - Ok(ExprLit { - attrs: Vec::new(), - lit: input.parse()?, - }) + impl Parse for ExprLit { + fn parse(input: ParseStream) -> Result { + Ok(ExprLit { + attrs: Vec::new(), + lit: input.parse()?, + }) + } } #[cfg(feature = "full")] @@ -1792,20 +1764,22 @@ } #[cfg(feature = "full")] - fn expr_if(input: ParseStream) -> Result { - Ok(ExprIf { - attrs: Vec::new(), - if_token: input.parse()?, - cond: Box::new(input.call(expr_no_struct)?), - then_branch: input.parse()?, - else_branch: { - if input.peek(Token![else]) { - Some(input.call(else_block)?) - } else { - None - } - }, - }) + impl Parse for ExprIf { + fn parse(input: ParseStream) -> Result { + Ok(ExprIf { + attrs: Vec::new(), + if_token: input.parse()?, + cond: Box::new(input.call(expr_no_struct)?), + then_branch: input.parse()?, + else_branch: { + if input.peek(Token![else]) { + Some(input.call(else_block)?) + } else { + None + } + }, + }) + } } #[cfg(feature = "full")] @@ -1814,7 +1788,7 @@ let lookahead = input.lookahead1(); let else_branch = if input.peek(Token![if]) { - input.call(expr_if).map(Expr::If)? + input.parse().map(Expr::If)? } else if input.peek(token::Brace) { Expr::Block(ExprBlock { attrs: Vec::new(), @@ -1829,74 +1803,145 @@ } #[cfg(feature = "full")] - fn expr_for_loop(input: ParseStream) -> Result { - let label: Option