From f7b2e9daad3baaeab177fd463512c258213e960f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jun 2024 08:59:43 -0700 Subject: [PATCH 01/66] Update test suite to nightly-2024-06-01 --- tests/common/eq.rs | 8 ++++---- tests/test_round_trip.rs | 4 +++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index b44ea3660d..17c00dc75e 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -10,8 +10,8 @@ use rustc_ast::ast::AngleBracketedArg; use rustc_ast::ast::AngleBracketedArgs; use rustc_ast::ast::AnonConst; use rustc_ast::ast::Arm; -use rustc_ast::ast::AssocConstraint; -use rustc_ast::ast::AssocConstraintKind; +use rustc_ast::ast::AssocItemConstraint; +use rustc_ast::ast::AssocItemConstraintKind; use rustc_ast::ast::AssocItemKind; use rustc_ast::ast::AttrArgs; use rustc_ast::ast::AttrArgsEq; @@ -464,7 +464,7 @@ macro_rules! spanless_eq_enum { spanless_eq_struct!(AngleBracketedArgs; span args); spanless_eq_struct!(AnonConst; id value); spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder); -spanless_eq_struct!(AssocConstraint; id ident gen_args kind span); +spanless_eq_struct!(AssocItemConstraint; id ident gen_args kind span); spanless_eq_struct!(AttrItem; path args tokens); spanless_eq_struct!(AttrTokenStream; 0); spanless_eq_struct!(Attribute; kind id style span); @@ -539,7 +539,7 @@ spanless_eq_struct!(WhereClause; has_where_token predicates span); spanless_eq_struct!(WhereEqPredicate; span lhs_ty rhs_ty); spanless_eq_struct!(WhereRegionPredicate; span lifetime bounds); spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0)); -spanless_eq_enum!(AssocConstraintKind; Equality(term) Bound(bounds)); +spanless_eq_enum!(AssocItemConstraintKind; Equality(term) Bound(bounds)); spanless_eq_enum!(AssocItemKind; Const(0) Fn(0) Type(0) MacCall(0) Delegation(0) DelegationMac(0)); spanless_eq_enum!(AttrArgs; Empty Delimited(0) Eq(0 1)); spanless_eq_enum!(AttrArgsEq; Ast(0) Hir(0)); diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs index 9b089036d0..56f40dbaac 100644 --- a/tests/test_round_trip.rs +++ b/tests/test_round_trip.rs @@ -220,7 +220,9 @@ fn normalize(krate: &mut Crate) { for arg in &mut e.args { match arg { AngleBracketedArg::Arg(arg) => self.visit_generic_arg(arg), - AngleBracketedArg::Constraint(constraint) => self.visit_constraint(constraint), + AngleBracketedArg::Constraint(constraint) => { + self.visit_assoc_item_constraint(constraint); + } } } } From 18fbe925d375ae117b3ea55a2ada488c06d26e9c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jun 2024 09:08:36 -0700 Subject: [PATCH 02/66] Do not format gen module because of rustfmt bug --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index a8372e8079..1b2b805a48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -536,6 +536,7 @@ mod verbatim; #[cfg(all(feature = "parsing", feature = "full"))] mod whitespace; +#[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/6176 mod gen { /// Syntax tree traversal to transform the nodes of an owned syntax tree. /// From 18cb85d58e6858512949cbb3fea1b41ba434e83a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jun 2024 20:50:33 -0700 Subject: [PATCH 03/66] Prune dev-dependencies when testing with miri --- Cargo.toml | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index edced6541a..40abe87aa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,15 +42,17 @@ unicode-ident = "1" [dev-dependencies] anyhow = "1" automod = "1" -flate2 = "1" insta = "1" -rayon = "1" ref-cast = "1" -reqwest = { version = "0.12", features = ["blocking"] } rustversion = "1" syn-test-suite = { version = "0", path = "tests/features" } -tar = "0.4.16" termcolor = "1" + +[target.'cfg(not(miri))'.dev-dependencies] +flate2 = "1" +rayon = "1" +reqwest = { version = "0.12", features = ["blocking"] } +tar = "0.4.16" walkdir = "2.3.2" [lib] From a0967ad273e98909c2585c8b1e629ed08f7ba26c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jun 2024 20:47:02 -0700 Subject: [PATCH 04/66] Make size tests ignored on 32-bit, not compiled out --- tests/test_size.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/test_size.rs b/tests/test_size.rs index 32e6119c98..7f4d187c4d 100644 --- a/tests/test_size.rs +++ b/tests/test_size.rs @@ -1,35 +1,38 @@ // Assumes proc-macro2's "span-locations" feature is off. -#![cfg(target_pointer_width = "64")] - use std::mem; use syn::{Expr, Item, Lit, Pat, Type}; #[rustversion::attr(before(2022-11-24), ignore)] +#[rustversion::attr(since(2022-11-24), cfg_attr(not(target_pointer_width = "64"), ignore))] #[test] fn test_expr_size() { assert_eq!(mem::size_of::(), 176); } #[rustversion::attr(before(2022-09-09), ignore)] +#[rustversion::attr(since(2022-09-09), cfg_attr(not(target_pointer_width = "64"), ignore))] #[test] fn test_item_size() { assert_eq!(mem::size_of::(), 352); } #[rustversion::attr(before(2023-04-29), ignore)] +#[rustversion::attr(since(2023-04-29), cfg_attr(not(target_pointer_width = "64"), ignore))] #[test] fn test_type_size() { assert_eq!(mem::size_of::(), 224); } #[rustversion::attr(before(2023-04-29), ignore)] +#[rustversion::attr(since(2023-04-29), cfg_attr(not(target_pointer_width = "64"), ignore))] #[test] fn test_pat_size() { assert_eq!(mem::size_of::(), 184); } #[rustversion::attr(before(2023-12-20), ignore)] +#[rustversion::attr(since(2023-12-20), cfg_attr(not(target_pointer_width = "64"), ignore))] #[test] fn test_lit_size() { assert_eq!(mem::size_of::(), 24); From bcba9739560461c941aa9d4623536abe92a9d83d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 1 Jun 2024 21:15:02 -0700 Subject: [PATCH 05/66] Fill in test ignore reasons --- tests/test_size.rs | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/tests/test_size.rs b/tests/test_size.rs index 7f4d187c4d..29fd43589d 100644 --- a/tests/test_size.rs +++ b/tests/test_size.rs @@ -3,36 +3,51 @@ use std::mem; use syn::{Expr, Item, Lit, Pat, Type}; -#[rustversion::attr(before(2022-11-24), ignore)] -#[rustversion::attr(since(2022-11-24), cfg_attr(not(target_pointer_width = "64"), ignore))] +#[rustversion::attr(before(2022-11-24), ignore = "requires nightly-2022-11-24 or newer")] +#[rustversion::attr( + since(2022-11-24), + cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") +)] #[test] fn test_expr_size() { assert_eq!(mem::size_of::(), 176); } -#[rustversion::attr(before(2022-09-09), ignore)] -#[rustversion::attr(since(2022-09-09), cfg_attr(not(target_pointer_width = "64"), ignore))] +#[rustversion::attr(before(2022-09-09), ignore = "requires nightly-2022-09-09 or newer")] +#[rustversion::attr( + since(2022-09-09), + cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") +)] #[test] fn test_item_size() { assert_eq!(mem::size_of::(), 352); } -#[rustversion::attr(before(2023-04-29), ignore)] -#[rustversion::attr(since(2023-04-29), cfg_attr(not(target_pointer_width = "64"), ignore))] +#[rustversion::attr(before(2023-04-29), ignore = "requires nightly-2023-04-29 or newer")] +#[rustversion::attr( + since(2023-04-29), + cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") +)] #[test] fn test_type_size() { assert_eq!(mem::size_of::(), 224); } -#[rustversion::attr(before(2023-04-29), ignore)] -#[rustversion::attr(since(2023-04-29), cfg_attr(not(target_pointer_width = "64"), ignore))] +#[rustversion::attr(before(2023-04-29), ignore = "requires nightly-2023-04-29 or newer")] +#[rustversion::attr( + since(2023-04-29), + cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") +)] #[test] fn test_pat_size() { assert_eq!(mem::size_of::(), 184); } -#[rustversion::attr(before(2023-12-20), ignore)] -#[rustversion::attr(since(2023-12-20), cfg_attr(not(target_pointer_width = "64"), ignore))] +#[rustversion::attr(before(2023-12-20), ignore = "requires nightly-2023-12-20 or newer")] +#[rustversion::attr( + since(2023-12-20), + cfg_attr(not(target_pointer_width = "64"), ignore = "only applicable to 64-bit") +)] #[test] fn test_lit_size() { assert_eq!(mem::size_of::(), 24); From b1e9aba7d04b372fd394690165a938a4a52f9a81 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 5 Jun 2024 21:57:39 -0700 Subject: [PATCH 06/66] Update test suite to nightly-2024-06-06 --- tests/common/parse.rs | 11 ++++------- tests/test_round_trip.rs | 3 ++- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/common/parse.rs b/tests/common/parse.rs index 2d00a62f46..cc724c4258 100644 --- a/tests/common/parse.rs +++ b/tests/common/parse.rs @@ -15,13 +15,10 @@ pub fn librustc_expr(input: &str) -> Option> { match panic::catch_unwind(|| { let locale_resources = rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(); let sess = ParseSess::new(locale_resources); - let e = parse::new_parser_from_source_str( - &sess, - FileName::Custom("test_precedence".to_string()), - input.to_string(), - ) - .parse_expr(); - match e { + let name = FileName::Custom("test_precedence".to_string()); + let mut parser = parse::new_parser_from_source_str(&sess, name, input.to_string()).unwrap(); + let presult = parser.parse_expr(); + match presult { Ok(expr) => Some(expr), Err(diagnostic) => { diagnostic.emit(); diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs index 56f40dbaac..1a79b3298e 100644 --- a/tests/test_round_trip.rs +++ b/tests/test_round_trip.rs @@ -160,7 +160,8 @@ fn librustc_parse(content: String, sess: &ParseSess) -> PResult { static COUNTER: AtomicUsize = AtomicUsize::new(0); let counter = COUNTER.fetch_add(1, Ordering::Relaxed); let name = FileName::Custom(format!("test_round_trip{}", counter)); - parse::parse_crate_from_source_str(name, content, sess) + let mut parser = parse::new_parser_from_source_str(sess, name, content).unwrap(); + parser.parse_crate_mod() } fn translate_message(diagnostic: &Diag) -> Cow<'static, str> { From cc7c06ba23f33606d66beb268c482841affb05f2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 5 Jun 2024 22:06:14 -0700 Subject: [PATCH 07/66] Update benchmark to nightly-2024-06-06 --- benches/rust.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/benches/rust.rs b/benches/rust.rs index bfa3a17f4a..fa773da651 100644 --- a/benches/rust.rs +++ b/benches/rust.rs @@ -83,11 +83,10 @@ mod librustc_parse { let emitter = Box::new(SilentEmitter); let handler = DiagCtxt::new(emitter); let sess = ParseSess::with_dcx(handler, source_map); - if let Err(diagnostic) = rustc_parse::parse_crate_from_source_str( - FileName::Custom("bench".to_owned()), - content.to_owned(), - &sess, - ) { + let name = FileName::Custom("bench".to_owned()); + let mut parser = + rustc_parse::new_parser_from_source_str(&sess, name, content.to_owned()).unwrap(); + if let Err(diagnostic) = parser.parse_crate_mod() { diagnostic.cancel(); return Err(()); }; From 06fe81821459e13cfc80c3ef7cb430ec5c835d8e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 6 Jun 2024 18:38:33 -0700 Subject: [PATCH 08/66] Update test suite to nightly-2024-06-07 --- tests/common/eq.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 17c00dc75e..715eef44c5 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -518,8 +518,8 @@ spanless_eq_struct!(Path; span segments tokens); spanless_eq_struct!(PathSegment; ident id args); spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span); spanless_eq_struct!(QSelf; ty path_span position); -spanless_eq_struct!(StaticForeignItem; ty mutability expr); -spanless_eq_struct!(StaticItem; ty mutability expr); +spanless_eq_struct!(StaticForeignItem; ty safety mutability expr); +spanless_eq_struct!(StaticItem; ty safety mutability expr); spanless_eq_struct!(Stmt; id kind span); spanless_eq_struct!(StrLit; symbol suffix symbol_unescaped style span); spanless_eq_struct!(StructExpr; qself path fields rest); @@ -593,7 +593,7 @@ spanless_eq_enum!(PreciseCapturingArg; Lifetime(0) Arg(0 1)); spanless_eq_enum!(RangeEnd; Included(0) Excluded); spanless_eq_enum!(RangeLimits; HalfOpen Closed); spanless_eq_enum!(Recovered; No Yes(0)); -spanless_eq_enum!(Safety; Unsafe(0) Default); +spanless_eq_enum!(Safety; Unsafe(0) Safe(0) Default); spanless_eq_enum!(StmtKind; Let(0) Item(0) Expr(0) Semi(0) Empty MacCall(0)); spanless_eq_enum!(StrStyle; Cooked Raw(0)); spanless_eq_enum!(StructRest; Base(0) Rest(0) None); From cd2fdc04101076bc7ee4dbbdb3640267d40a41ef Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 6 Jun 2024 18:36:57 -0700 Subject: [PATCH 09/66] Parse rust repo using 2021 edition in benchmark --- benches/rust.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/rust.rs b/benches/rust.rs index fa773da651..32fe3de245 100644 --- a/benches/rust.rs +++ b/benches/rust.rs @@ -78,7 +78,7 @@ mod librustc_parse { } } - rustc_span::create_session_if_not_set_then(Edition::Edition2018, |_| { + rustc_span::create_session_if_not_set_then(Edition::Edition2021, |_| { let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new(SilentEmitter); let handler = DiagCtxt::new(emitter); From e0a502d24a1b4cf8e93f8bc8407e4e8f73dd6fea Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 6 Jun 2024 18:50:28 -0700 Subject: [PATCH 10/66] Use same choice of edition in benchmarks as in tests --- benches/rust.rs | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/benches/rust.rs b/benches/rust.rs index 32fe3de245..09917e7cbe 100644 --- a/benches/rust.rs +++ b/benches/rust.rs @@ -24,20 +24,24 @@ mod macros; mod repo; use std::fs; +use std::path::Path; use std::time::{Duration, Instant}; #[cfg(not(syn_only))] mod tokenstream_parse { use proc_macro2::TokenStream; + use std::path::Path; use std::str::FromStr; - pub fn bench(content: &str) -> Result<(), ()> { + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { TokenStream::from_str(content).map(drop).map_err(drop) } } mod syn_parse { - pub fn bench(content: &str) -> Result<(), ()> { + use std::path::Path; + + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { syn::parse_file(content).map(drop).map_err(drop) } } @@ -52,14 +56,16 @@ mod librustc_parse { extern crate rustc_session; extern crate rustc_span; + use crate::repo; use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentBundle; use rustc_errors::{emitter::Emitter, translation::Translate, DiagCtxt, DiagInner}; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; - use rustc_span::{edition::Edition, FileName}; + use rustc_span::FileName; + use std::path::Path; - pub fn bench(content: &str) -> Result<(), ()> { + pub fn bench(path: &Path, content: &str) -> Result<(), ()> { struct SilentEmitter; impl Emitter for SilentEmitter { @@ -78,7 +84,8 @@ mod librustc_parse { } } - rustc_span::create_session_if_not_set_then(Edition::Edition2021, |_| { + let edition = repo::edition(path).parse().unwrap(); + rustc_span::create_session_if_not_set_then(edition, |_| { let source_map = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new(SilentEmitter); let handler = DiagCtxt::new(emitter); @@ -97,13 +104,15 @@ mod librustc_parse { #[cfg(not(syn_only))] mod read_from_disk { - pub fn bench(content: &str) -> Result<(), ()> { + use std::path::Path; + + pub fn bench(_path: &Path, content: &str) -> Result<(), ()> { let _ = content; Ok(()) } } -fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration { +fn exec(mut codepath: impl FnMut(&Path, &str) -> Result<(), ()>) -> Duration { let begin = Instant::now(); let mut success = 0; let mut total = 0; @@ -122,7 +131,7 @@ fn exec(mut codepath: impl FnMut(&str) -> Result<(), ()>) -> Duration { return; } let content = fs::read_to_string(path).unwrap(); - let ok = codepath(&content).is_ok(); + let ok = codepath(path, &content).is_ok(); success += ok as usize; total += 1; if !ok { @@ -142,7 +151,7 @@ fn main() { [ $( $(#[$cfg])* - (stringify!($name), $name::bench as fn(&str) -> Result<(), ()>), + (stringify!($name), $name::bench as fn(&Path, &str) -> Result<(), ()>), )* ] }; @@ -152,7 +161,7 @@ fn main() { { let mut lines = 0; let mut files = 0; - exec(|content| { + exec(|_path, content| { lines += content.lines().count(); files += 1; Ok(()) From 2a73feaf6c4775c1a56f7cfb753f6dcf86517711 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 7 Jun 2024 20:06:44 -0700 Subject: [PATCH 11/66] Update test suite to nightly-2024-06-08 --- 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 715eef44c5..b2e5b759b6 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -465,7 +465,7 @@ spanless_eq_struct!(AngleBracketedArgs; span args); spanless_eq_struct!(AnonConst; id value); spanless_eq_struct!(Arm; attrs pat guard body span id is_placeholder); spanless_eq_struct!(AssocItemConstraint; id ident gen_args kind span); -spanless_eq_struct!(AttrItem; path args tokens); +spanless_eq_struct!(AttrItem; unsafety path args tokens); spanless_eq_struct!(AttrTokenStream; 0); spanless_eq_struct!(Attribute; kind id style span); spanless_eq_struct!(AttributesData; attrs tokens); From b9314ca3583c2cd10f92b2dc2a5999492aa56bb1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 7 Jun 2024 20:09:01 -0700 Subject: [PATCH 12/66] Add rustc_ast MetaItem nodes to test --- tests/common/eq.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index b2e5b759b6..0fc8982faa 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -102,6 +102,8 @@ use rustc_ast::ast::MacCallStmt; use rustc_ast::ast::MacStmtStyle; use rustc_ast::ast::MacroDef; use rustc_ast::ast::MatchKind; +use rustc_ast::ast::MetaItem; +use rustc_ast::ast::MetaItemKind; use rustc_ast::ast::MetaItemLit; use rustc_ast::ast::MethodCall; use rustc_ast::ast::ModKind; @@ -109,6 +111,7 @@ use rustc_ast::ast::ModSpans; use rustc_ast::ast::Movability; use rustc_ast::ast::MutTy; use rustc_ast::ast::Mutability; +use rustc_ast::ast::NestedMetaItem; use rustc_ast::ast::NodeId; use rustc_ast::ast::NormalAttr; use rustc_ast::ast::Param; @@ -506,6 +509,7 @@ spanless_eq_struct!(Local; id pat ty kind span colon_sp attrs !tokens); spanless_eq_struct!(MacCall; path args); spanless_eq_struct!(MacCallStmt; mac style attrs tokens); spanless_eq_struct!(MacroDef; body macro_rules); +spanless_eq_struct!(MetaItem; unsafety path kind span); spanless_eq_struct!(MetaItemLit; symbol suffix kind span); spanless_eq_struct!(MethodCall; seg receiver args !span); spanless_eq_struct!(ModSpans; !inner_span !inject_use_span); @@ -585,9 +589,11 @@ spanless_eq_enum!(LitIntType; Signed(0) Unsigned(0) Unsuffixed); spanless_eq_enum!(LocalKind; Decl Init(0) InitElse(0 1)); spanless_eq_enum!(MacStmtStyle; Semicolon Braces NoBraces); spanless_eq_enum!(MatchKind; Prefix Postfix); +spanless_eq_enum!(MetaItemKind; Word List(0) NameValue(0)); spanless_eq_enum!(ModKind; Loaded(0 1 2) Unloaded); spanless_eq_enum!(Movability; Static Movable); spanless_eq_enum!(Mutability; Mut Not); +spanless_eq_enum!(NestedMetaItem; MetaItem(0) Lit(0)); spanless_eq_enum!(PatFieldsRest; Rest None); spanless_eq_enum!(PreciseCapturingArg; Lifetime(0) Arg(0 1)); spanless_eq_enum!(RangeEnd; Included(0) Excluded); From f3e23aef7c23b6e122a46674d8263f92291380a5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 18 Jun 2024 19:59:49 -0700 Subject: [PATCH 13/66] Update test suite to nightly-2024-06-19 --- tests/common/eq.rs | 4 ++-- tests/test_precedence.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 0fc8982faa..dba2cbdce1 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -576,7 +576,7 @@ spanless_eq_enum!(FormatTrait; Display Debug LowerExp UpperExp Octal Pointer Bin spanless_eq_enum!(GenBlockKind; Async Gen AsyncGen); 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!(GenericBound; Trait(0 1) Outlives(0) Use(0 1)); 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); @@ -638,7 +638,7 @@ spanless_eq_enum!(PatKind; Wild Ident(0 1 2) Struct(0 1 2 3) TupleStruct(0 1 2) Slice(0) Rest Never Paren(0) MacCall(0) Err(0)); spanless_eq_enum!(TyKind; Slice(0) Array(0 1) Ptr(0) Ref(0 1) BareFn(0) Never Tup(0) AnonStruct(0 1) AnonUnion(0 1) Path(0 1) TraitObject(0 1) - ImplTrait(0 1 2) Paren(0) Typeof(0) Infer ImplicitSelf MacCall(0) CVarArgs + ImplTrait(0 1) Paren(0) Typeof(0) Infer ImplicitSelf MacCall(0) CVarArgs Pat(0 1) Dummy Err(0)); impl SpanlessEq for Ident { diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index 02b87f37d8..2b543a28e3 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -303,6 +303,7 @@ fn librustc_parenthesize(mut librustc_expr: P) -> P { ) => {} GenericBound::Trait(ty, _modifier) => self.visit_poly_trait_ref(ty), GenericBound::Outlives(_lifetime) => {} + GenericBound::Use(..) => {} } } From 1be870bd7d3378fe52903cefe43240f348810a27 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 18 Jun 2024 20:18:48 -0700 Subject: [PATCH 14/66] Resolve match_same_arms pedantic clippy lint in test warning: this match arm has an identical body to another arm --> tests/test_precedence.rs:297:17 | 297 | / GenericBound::Trait( 298 | | _, 299 | | TraitBoundModifiers { 300 | | constness: BoundConstness::Maybe(_), 301 | | .. 302 | | }, 303 | | ) => {} | |_______________________^ | = help: try changing either arm body = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#match_same_arms = note: `-W clippy::match-same-arms` implied by `-W clippy::pedantic` = help: to override `-W clippy::pedantic` add `#[allow(clippy::match_same_arms)]` help: or try merging the arm patterns | 297 ~ GenericBound::Trait( 298 + _, 299 + TraitBoundModifiers { 300 + constness: BoundConstness::Maybe(_), 301 + .. 302 + }, 303 ~ ) | GenericBound::Use(..) => {} | help: and remove this obsolete arm | 306 - GenericBound::Use(..) => {} 307 - } 306 + } | --- tests/test_precedence.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index 2b543a28e3..57686c3d2a 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -300,10 +300,10 @@ fn librustc_parenthesize(mut librustc_expr: P) -> P { constness: BoundConstness::Maybe(_), .. }, - ) => {} + ) + | GenericBound::Outlives(..) + | GenericBound::Use(..) => {} GenericBound::Trait(ty, _modifier) => self.visit_poly_trait_ref(ty), - GenericBound::Outlives(_lifetime) => {} - GenericBound::Use(..) => {} } } From 08243534976cce4f4feba9148ae20d223ec1c586 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 16:26:00 -0700 Subject: [PATCH 15/66] Use span from the correct Group token when parsing delimited content --- src/buffer.rs | 7 ------- src/discouraged.rs | 2 +- src/group.rs | 2 +- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index 1686e28209..f8f7d9aff8 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -425,10 +425,3 @@ pub(crate) fn open_span_of_group(cursor: Cursor) -> Span { _ => cursor.span(), } } - -pub(crate) fn close_span_of_group(cursor: Cursor) -> Span { - match cursor.entry() { - Entry::Group(group, _) => group.span_close(), - _ => cursor.span(), - } -} diff --git a/src/discouraged.rs b/src/discouraged.rs index 4109c670e7..71c78c8c65 100644 --- a/src/discouraged.rs +++ b/src/discouraged.rs @@ -212,7 +212,7 @@ impl<'a> AnyDelimiter for ParseBuffer<'a> { fn parse_any_delimiter(&self) -> Result<(Delimiter, DelimSpan, ParseBuffer)> { self.step(|cursor| { if let Some((content, delimiter, span, rest)) = cursor.any_group() { - let scope = crate::buffer::close_span_of_group(*cursor); + let scope = span.close(); let nested = crate::parse::advance_step_cursor(cursor, content); let unexpected = crate::parse::get_unexpected(self); let content = crate::parse::new_parse_buffer(scope, nested, unexpected); diff --git a/src/group.rs b/src/group.rs index b742927eef..1534ae995d 100644 --- a/src/group.rs +++ b/src/group.rs @@ -82,7 +82,7 @@ fn parse_delimited<'a>( ) -> Result<(DelimSpan, ParseBuffer<'a>)> { input.step(|cursor| { if let Some((content, span, rest)) = cursor.group(delimiter) { - let scope = crate::buffer::close_span_of_group(*cursor); + let scope = span.close(); let nested = crate::parse::advance_step_cursor(cursor, content); let unexpected = crate::parse::get_unexpected(input); let content = crate::parse::new_parse_buffer(scope, nested, unexpected); From 4e178ee9cc9e38778cbefb812a648a52725f5f17 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 15:43:12 -0700 Subject: [PATCH 16/66] Improve span returned by Cursor::span at end of a Group's contents --- src/buffer.rs | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index f8f7d9aff8..a966573ad1 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -309,13 +309,31 @@ impl<'a> Cursor<'a> { /// Returns the `Span` of the current token, or `Span::call_site()` if this /// cursor points to eof. - pub fn span(self) -> Span { + pub fn span(mut self) -> Span { match self.entry() { Entry::Group(group, _) => group.span(), Entry::Literal(literal) => literal.span(), Entry::Ident(ident) => ident.span(), Entry::Punct(punct) => punct.span(), - Entry::End(_) => Span::call_site(), + Entry::End(offset) => { + let start_of_buffer = unsafe { self.ptr.offset(*offset) }; + // Locate the matching Group begin token. + let mut depth = 1; + while start_of_buffer < self.ptr { + self.ptr = unsafe { self.ptr.offset(-1) }; + match self.entry() { + Entry::Group(group, _) => { + depth -= 1; + if depth == 0 { + return group.span_close(); + } + } + Entry::End(_) => depth += 1, + Entry::Literal(_) | Entry::Ident(_) | Entry::Punct(_) => {} + } + } + Span::call_site() + } } } From e86538ccd80494c8bf239b36550c0f9e298b50c5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 17:19:36 -0700 Subject: [PATCH 17/66] Optimize reverse iteration of TokenBuffer --- src/buffer.rs | 68 +++++++++++++++++---------------------------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/src/buffer.rs b/src/buffer.rs index a966573ad1..b7657bebc2 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -20,8 +20,9 @@ enum Entry { Ident(Ident), Punct(Punct), Literal(Literal), - // End entries contain the offset (negative) to the start of the buffer. - End(isize), + // End entries contain the offset (negative) to the start of the buffer, and + // offset (negative) to the matching Group entry. + End(isize, isize), } /// A buffer that can be efficiently traversed multiple times, unlike @@ -42,12 +43,15 @@ impl TokenBuffer { TokenTree::Literal(literal) => entries.push(Entry::Literal(literal)), TokenTree::Group(group) => { let group_start_index = entries.len(); - entries.push(Entry::End(0)); // we replace this below + entries.push(Entry::End(0, 0)); // we replace this below Self::recursive_new(entries, group.stream()); let group_end_index = entries.len(); - entries.push(Entry::End(-(group_end_index as isize))); - let group_end_offset = group_end_index - group_start_index; - entries[group_start_index] = Entry::Group(group, group_end_offset); + let group_offset = group_end_index - group_start_index; + entries.push(Entry::End( + -(group_end_index as isize), + -(group_offset as isize), + )); + entries[group_start_index] = Entry::Group(group, group_offset); } } } @@ -66,7 +70,7 @@ impl TokenBuffer { pub fn new2(stream: TokenStream) -> Self { let mut entries = Vec::new(); Self::recursive_new(&mut entries, stream); - entries.push(Entry::End(-(entries.len() as isize))); + entries.push(Entry::End(-(entries.len() as isize), 0)); Self { entries: entries.into_boxed_slice(), } @@ -111,7 +115,7 @@ impl<'a> Cursor<'a> { // object in global storage. struct UnsafeSyncEntry(Entry); unsafe impl Sync for UnsafeSyncEntry {} - static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0)); + static EMPTY_ENTRY: UnsafeSyncEntry = UnsafeSyncEntry(Entry::End(0, 0)); Cursor { ptr: &EMPTY_ENTRY.0, @@ -128,7 +132,7 @@ impl<'a> Cursor<'a> { // past it, unless `ptr == scope`, which means that we're at the edge of // our cursor's scope. We should only have `ptr != scope` at the exit // from None-delimited groups entered with `ignore_none`. - while let Entry::End(_) = unsafe { &*ptr } { + while let Entry::End(..) = unsafe { &*ptr } { if ptr == scope { break; } @@ -300,7 +304,7 @@ impl<'a> Cursor<'a> { Entry::Literal(literal) => (literal.clone().into(), 1), Entry::Ident(ident) => (ident.clone().into(), 1), Entry::Punct(punct) => (punct.clone().into(), 1), - Entry::End(_) => return None, + Entry::End(..) => return None, }; let rest = unsafe { Cursor::create(self.ptr.add(len), self.scope) }; @@ -315,24 +319,13 @@ impl<'a> Cursor<'a> { Entry::Literal(literal) => literal.span(), Entry::Ident(ident) => ident.span(), Entry::Punct(punct) => punct.span(), - Entry::End(offset) => { - let start_of_buffer = unsafe { self.ptr.offset(*offset) }; - // Locate the matching Group begin token. - let mut depth = 1; - while start_of_buffer < self.ptr { - self.ptr = unsafe { self.ptr.offset(-1) }; - match self.entry() { - Entry::Group(group, _) => { - depth -= 1; - if depth == 0 { - return group.span_close(); - } - } - Entry::End(_) => depth += 1, - Entry::Literal(_) | Entry::Ident(_) | Entry::Punct(_) => {} - } + Entry::End(_, offset) => { + self.ptr = unsafe { self.ptr.offset(*offset) }; + if let Entry::Group(group, _) = self.entry() { + group.span_close() + } else { + Span::call_site() } - Span::call_site() } } } @@ -343,23 +336,6 @@ impl<'a> Cursor<'a> { pub(crate) fn prev_span(mut self) -> Span { if start_of_buffer(self) < self.ptr { self.ptr = unsafe { self.ptr.offset(-1) }; - if let Entry::End(_) = self.entry() { - // Locate the matching Group begin token. - let mut depth = 1; - loop { - self.ptr = unsafe { self.ptr.offset(-1) }; - match self.entry() { - Entry::Group(group, _) => { - depth -= 1; - if depth == 0 { - return group.span(); - } - } - Entry::End(_) => depth += 1, - Entry::Literal(_) | Entry::Ident(_) | Entry::Punct(_) => {} - } - } - } } self.span() } @@ -372,7 +348,7 @@ impl<'a> Cursor<'a> { self.ignore_none(); let len = match self.entry() { - Entry::End(_) => return None, + Entry::End(..) => return None, // Treat lifetimes as a single tt for the purposes of 'skip'. Entry::Punct(punct) if punct.as_char() == '\'' && punct.spacing() == Spacing::Joint => { @@ -427,7 +403,7 @@ pub(crate) fn same_buffer(a: Cursor, b: Cursor) -> bool { fn start_of_buffer(cursor: Cursor) -> *const Entry { unsafe { match &*cursor.scope { - Entry::End(offset) => cursor.scope.offset(*offset), + Entry::End(offset, _) => cursor.scope.offset(*offset), _ => unreachable!(), } } From 7cc7eac262467d4c1e6cac8f9beeb20d256f7d49 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 22:02:32 -0700 Subject: [PATCH 18/66] Inline lookahead::is_delimiter into delimiter Token impls --- src/lookahead.rs | 6 +----- src/token.rs | 10 ++++------ 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/lookahead.rs b/src/lookahead.rs index 2ca1471472..75e3a658a3 100644 --- a/src/lookahead.rs +++ b/src/lookahead.rs @@ -3,7 +3,7 @@ use crate::error::{self, Error}; use crate::sealed::lookahead::Sealed; use crate::span::IntoSpans; use crate::token::Token; -use proc_macro2::{Delimiter, Span}; +use proc_macro2::Span; use std::cell::RefCell; /// Support for checking the next token in a stream to decide how to parse. @@ -162,8 +162,4 @@ impl IntoSpans for TokenMarker { } } -pub(crate) fn is_delimiter(cursor: Cursor, delimiter: Delimiter) -> bool { - cursor.group(delimiter).is_some() -} - impl T, T: Token> Sealed for F {} diff --git a/src/token.rs b/src/token.rs index e04f105747..a39a1af67d 100644 --- a/src/token.rs +++ b/src/token.rs @@ -100,8 +100,6 @@ use crate::lifetime::Lifetime; #[cfg(feature = "parsing")] use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; #[cfg(feature = "parsing")] -use crate::lookahead; -#[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream}; use crate::span::IntoSpans; use proc_macro2::extra::DelimSpan; @@ -692,7 +690,7 @@ impl private::Sealed for Group {} #[cfg(feature = "parsing")] impl Token for Paren { fn peek(cursor: Cursor) -> bool { - lookahead::is_delimiter(cursor, Delimiter::Parenthesis) + cursor.group(Delimiter::Parenthesis).is_some() } fn display() -> &'static str { @@ -703,7 +701,7 @@ impl Token for Paren { #[cfg(feature = "parsing")] impl Token for Brace { fn peek(cursor: Cursor) -> bool { - lookahead::is_delimiter(cursor, Delimiter::Brace) + cursor.group(Delimiter::Brace).is_some() } fn display() -> &'static str { @@ -714,7 +712,7 @@ impl Token for Brace { #[cfg(feature = "parsing")] impl Token for Bracket { fn peek(cursor: Cursor) -> bool { - lookahead::is_delimiter(cursor, Delimiter::Bracket) + cursor.group(Delimiter::Bracket).is_some() } fn display() -> &'static str { @@ -725,7 +723,7 @@ impl Token for Bracket { #[cfg(feature = "parsing")] impl Token for Group { fn peek(cursor: Cursor) -> bool { - lookahead::is_delimiter(cursor, Delimiter::None) + cursor.group(Delimiter::None).is_some() } fn display() -> &'static str { From 8cb56cc59d8ea0117dd6df3915f4c730249618bc Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 22:22:04 -0700 Subject: [PATCH 19/66] Update test suite to nightly-2024-06-20 --- 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 dba2cbdce1..1ad36b7598 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -478,7 +478,7 @@ spanless_eq_struct!(Block; stmts id rules span tokens could_be_bare_literal); spanless_eq_struct!(Closure; binder capture_clause constness coroutine_kind movability fn_decl body !fn_decl_span !fn_arg_span); spanless_eq_struct!(ConstItem; defaultness generics ty expr); spanless_eq_struct!(Crate; attrs items spans id is_placeholder); -spanless_eq_struct!(Delegation; id qself path rename body); +spanless_eq_struct!(Delegation; id qself path rename body from_glob); spanless_eq_struct!(DelegationMac; qself prefix suffixes body); spanless_eq_struct!(DelimArgs; dspan delim tokens); spanless_eq_struct!(DelimSpacing; open close); From ec0c84b282c8ade12f6afaad7425b90ec5a1fd7d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 22:17:06 -0700 Subject: [PATCH 20/66] Make LitCStr peekable --- src/token.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/token.rs b/src/token.rs index a39a1af67d..2ac6b83478 100644 --- a/src/token.rs +++ b/src/token.rs @@ -98,7 +98,7 @@ use crate::error::Result; #[cfg(feature = "parsing")] use crate::lifetime::Lifetime; #[cfg(feature = "parsing")] -use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitChar, LitFloat, LitInt, LitStr}; +use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr}; #[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream}; use crate::span::IntoSpans; @@ -199,6 +199,7 @@ impl_token!("lifetime" Lifetime); impl_token!("literal" Lit); impl_token!("string literal" LitStr); impl_token!("byte string literal" LitByteStr); +impl_token!("C-string literal" LitCStr); impl_token!("byte literal" LitByte); impl_token!("character literal" LitChar); impl_token!("integer literal" LitInt); From 0c902919850353ddfe4d90f5ba0474e6ac8aaaa8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 22:13:16 -0700 Subject: [PATCH 21/66] List peekable token types in documentation of Peek trait --- src/ext.rs | 4 ++-- src/ident.rs | 7 +++++++ src/lifetime.rs | 5 +++++ src/lit.rs | 15 +++++++++++++++ src/lookahead.rs | 1 + src/sealed.rs | 7 +++++++ src/token.rs | 15 +++++++++++++++ 7 files changed, 52 insertions(+), 2 deletions(-) diff --git a/src/ext.rs b/src/ext.rs index 5cd79e863a..9284001ce5 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -4,7 +4,6 @@ use crate::buffer::Cursor; use crate::error::Result; use crate::parse::ParseStream; use crate::parse::Peek; -use crate::sealed::lookahead; use crate::token::CustomToken; use proc_macro2::Ident; @@ -115,7 +114,8 @@ impl CustomToken for private::IdentAny { } } -impl lookahead::Sealed for private::PeekFn {} +#[cfg(not(docsrs))] +impl crate::sealed::lookahead::Sealed for private::PeekFn {} mod private { use proc_macro2::Ident; diff --git a/src/ident.rs b/src/ident.rs index 8a8e8a50d9..673dd690c5 100644 --- a/src/ident.rs +++ b/src/ident.rs @@ -1,5 +1,7 @@ #[cfg(feature = "parsing")] use crate::lookahead; +#[cfg(all(feature = "parsing", docsrs))] +use crate::lookahead::Peek; pub use proc_macro2::Ident; @@ -12,6 +14,11 @@ pub_if_not_doc! { } } +#[cfg(all(feature = "parsing", docsrs))] +impl Peek for Ident { + type Token = Self; +} + macro_rules! ident_from_token { ($token:ident) => { impl From for Ident { diff --git a/src/lifetime.rs b/src/lifetime.rs index cc189d1ac9..71918ac51d 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -120,6 +120,11 @@ pub_if_not_doc! { } } +#[cfg(all(feature = "parsing", docsrs))] +impl lookahead::Peek for Lifetime { + type Token = Self; +} + #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::error::Result; diff --git a/src/lit.rs b/src/lit.rs index a37aa2a9e7..8698b975f4 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -807,6 +807,11 @@ macro_rules! lit_extra_traits { match marker {} } } + + #[cfg(all(feature = "parsing", docsrs))] + impl lookahead::Peek for $ty { + type Token = Self; + } }; } @@ -827,6 +832,11 @@ pub_if_not_doc! { } } +#[cfg(all(feature = "parsing", docsrs))] +impl lookahead::Peek for LitBool { + type Token = Self; +} + /// The style of a string literal, either plain quoted or a raw string like /// `r##"data"##`. #[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566 @@ -848,6 +858,11 @@ pub_if_not_doc! { } } +#[cfg(all(feature = "parsing", docsrs))] +impl lookahead::Peek for Lit { + type Token = Self; +} + #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::buffer::Cursor; diff --git a/src/lookahead.rs b/src/lookahead.rs index 75e3a658a3..912a5ad866 100644 --- a/src/lookahead.rs +++ b/src/lookahead.rs @@ -162,4 +162,5 @@ impl IntoSpans for TokenMarker { } } +#[cfg(not(docsrs))] impl T, T: Token> Sealed for F {} diff --git a/src/sealed.rs b/src/sealed.rs index dc804742d1..fd5eed8cf4 100644 --- a/src/sealed.rs +++ b/src/sealed.rs @@ -1,4 +1,11 @@ #[cfg(feature = "parsing")] pub(crate) mod lookahead { + #[cfg(not(docsrs))] pub trait Sealed: Copy {} + + #[cfg(docsrs)] + pub trait Sealed {} + + #[cfg(docsrs)] + impl Sealed for T {} } diff --git a/src/token.rs b/src/token.rs index 2ac6b83478..5884cbe00f 100644 --- a/src/token.rs +++ b/src/token.rs @@ -264,6 +264,11 @@ macro_rules! define_keywords { } } + #[cfg(all(feature = "parsing", docsrs))] + impl crate::lookahead::Peek for $name { + type Token = Self; + } + impl std::default::Default for $name { fn default() -> Self { $name { @@ -391,6 +396,11 @@ macro_rules! define_punctuation_structs { } } + #[cfg(all(feature = "parsing", docsrs))] + impl crate::lookahead::Peek for $name { + type Token = Self; + } + impl std::default::Default for $name { fn default() -> Self { $name { @@ -500,6 +510,11 @@ macro_rules! define_delimiters { } } + #[cfg(all(feature = "parsing", docsrs))] + impl crate::lookahead::Peek for $name { + type Token = Self; + } + impl std::default::Default for $name { fn default() -> Self { $name(Span::call_site()) From 666e15e95ff3763571f14af93be2641eecc5c2d9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 19 Jun 2024 22:41:52 -0700 Subject: [PATCH 22/66] Revert "List peekable token types in documentation of Peek trait" This reverts commit 0c902919850353ddfe4d90f5ba0474e6ac8aaaa8. --- src/ext.rs | 4 ++-- src/ident.rs | 7 ------- src/lifetime.rs | 5 ----- src/lit.rs | 15 --------------- src/lookahead.rs | 1 - src/sealed.rs | 7 ------- src/token.rs | 15 --------------- 7 files changed, 2 insertions(+), 52 deletions(-) diff --git a/src/ext.rs b/src/ext.rs index 9284001ce5..5cd79e863a 100644 --- a/src/ext.rs +++ b/src/ext.rs @@ -4,6 +4,7 @@ use crate::buffer::Cursor; use crate::error::Result; use crate::parse::ParseStream; use crate::parse::Peek; +use crate::sealed::lookahead; use crate::token::CustomToken; use proc_macro2::Ident; @@ -114,8 +115,7 @@ impl CustomToken for private::IdentAny { } } -#[cfg(not(docsrs))] -impl crate::sealed::lookahead::Sealed for private::PeekFn {} +impl lookahead::Sealed for private::PeekFn {} mod private { use proc_macro2::Ident; diff --git a/src/ident.rs b/src/ident.rs index 673dd690c5..8a8e8a50d9 100644 --- a/src/ident.rs +++ b/src/ident.rs @@ -1,7 +1,5 @@ #[cfg(feature = "parsing")] use crate::lookahead; -#[cfg(all(feature = "parsing", docsrs))] -use crate::lookahead::Peek; pub use proc_macro2::Ident; @@ -14,11 +12,6 @@ pub_if_not_doc! { } } -#[cfg(all(feature = "parsing", docsrs))] -impl Peek for Ident { - type Token = Self; -} - macro_rules! ident_from_token { ($token:ident) => { impl From for Ident { diff --git a/src/lifetime.rs b/src/lifetime.rs index 71918ac51d..cc189d1ac9 100644 --- a/src/lifetime.rs +++ b/src/lifetime.rs @@ -120,11 +120,6 @@ pub_if_not_doc! { } } -#[cfg(all(feature = "parsing", docsrs))] -impl lookahead::Peek for Lifetime { - type Token = Self; -} - #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::error::Result; diff --git a/src/lit.rs b/src/lit.rs index 8698b975f4..a37aa2a9e7 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -807,11 +807,6 @@ macro_rules! lit_extra_traits { match marker {} } } - - #[cfg(all(feature = "parsing", docsrs))] - impl lookahead::Peek for $ty { - type Token = Self; - } }; } @@ -832,11 +827,6 @@ pub_if_not_doc! { } } -#[cfg(all(feature = "parsing", docsrs))] -impl lookahead::Peek for LitBool { - type Token = Self; -} - /// The style of a string literal, either plain quoted or a raw string like /// `r##"data"##`. #[doc(hidden)] // https://github.com/dtolnay/syn/issues/1566 @@ -858,11 +848,6 @@ pub_if_not_doc! { } } -#[cfg(all(feature = "parsing", docsrs))] -impl lookahead::Peek for Lit { - type Token = Self; -} - #[cfg(feature = "parsing")] pub(crate) mod parsing { use crate::buffer::Cursor; diff --git a/src/lookahead.rs b/src/lookahead.rs index 912a5ad866..75e3a658a3 100644 --- a/src/lookahead.rs +++ b/src/lookahead.rs @@ -162,5 +162,4 @@ impl IntoSpans for TokenMarker { } } -#[cfg(not(docsrs))] impl T, T: Token> Sealed for F {} diff --git a/src/sealed.rs b/src/sealed.rs index fd5eed8cf4..dc804742d1 100644 --- a/src/sealed.rs +++ b/src/sealed.rs @@ -1,11 +1,4 @@ #[cfg(feature = "parsing")] pub(crate) mod lookahead { - #[cfg(not(docsrs))] pub trait Sealed: Copy {} - - #[cfg(docsrs)] - pub trait Sealed {} - - #[cfg(docsrs)] - impl Sealed for T {} } diff --git a/src/token.rs b/src/token.rs index 5884cbe00f..2ac6b83478 100644 --- a/src/token.rs +++ b/src/token.rs @@ -264,11 +264,6 @@ macro_rules! define_keywords { } } - #[cfg(all(feature = "parsing", docsrs))] - impl crate::lookahead::Peek for $name { - type Token = Self; - } - impl std::default::Default for $name { fn default() -> Self { $name { @@ -396,11 +391,6 @@ macro_rules! define_punctuation_structs { } } - #[cfg(all(feature = "parsing", docsrs))] - impl crate::lookahead::Peek for $name { - type Token = Self; - } - impl std::default::Default for $name { fn default() -> Self { $name { @@ -510,11 +500,6 @@ macro_rules! define_delimiters { } } - #[cfg(all(feature = "parsing", docsrs))] - impl crate::lookahead::Peek for $name { - type Token = Self; - } - impl std::default::Default for $name { fn default() -> Self { $name(Span::call_site()) From 25f6299c982276bf55faac834538d78ea61d6bad Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 20 Jun 2024 16:42:46 -0700 Subject: [PATCH 23/66] Release 2.0.67 --- 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 40abe87aa9..119621d93d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.66" +version = "2.0.67" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 1b2b805a48..851c4b452f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.66")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.67")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 19e97f4f1b..7e8b40f8a2 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.66", + "version": "2.0.67", "types": [ { "ident": "Abi", From bbb63d64c96fd6e875430df48ab711444b8ee6e8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 20 Jun 2024 17:14:05 -0700 Subject: [PATCH 24/66] Raise required compiler to rust 1.61 --- .github/workflows/ci.yml | 4 ++-- Cargo.toml | 2 +- README.md | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7ce2146da0..6ab024b5a8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: strategy: fail-fast: false matrix: - rust: [stable, beta, 1.63.0, 1.60.0] + rust: [stable, beta, 1.63.0, 1.61.0] include: - rust: nightly components: rustc-dev @@ -77,7 +77,7 @@ jobs: - run: cargo check ${{env.target}} --no-default-features --features 'full fold visit visit-mut parsing printing' - if: matrix.components == 'rustc-dev' run: cargo check --benches --all-features --release - - if: matrix.rust != '1.60.0' + - if: matrix.rust != '1.61.0' run: cargo check ${{env.target}} --manifest-path json/Cargo.toml --no-default-features examples: diff --git a/Cargo.toml b/Cargo.toml index 119621d93d..89bba0efbc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,7 @@ include = [ keywords = ["macros", "syn"] license = "MIT OR Apache-2.0" repository = "https://github.com/dtolnay/syn" -rust-version = "1.60" +rust-version = "1.61" [features] default = ["derive", "parsing", "printing", "clone-impls", "proc-macro"] diff --git a/README.md b/README.md index 04f9bf6cb1..16a393b9f0 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ contains some APIs that may be useful more generally. [`syn::DeriveInput`]: https://docs.rs/syn/2.0/syn/struct.DeriveInput.html [parser functions]: https://docs.rs/syn/2.0/syn/parse/index.html -*Version requirement: Syn supports rustc 1.60 and up.* +*Version requirement: Syn supports rustc 1.61 and up.* [*Release notes*](https://github.com/dtolnay/syn/releases) From 87d57920513951b05a4dd64a39d1d8a39c314624 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 20 Jun 2024 17:31:53 -0700 Subject: [PATCH 25/66] Reword explanation of ParseBuffer::is_empty --- src/parse.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/parse.rs b/src/parse.rs index a80a914760..9495c6fc02 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -743,10 +743,12 @@ impl<'a> ParseBuffer<'a> { Punctuated::parse_terminated_with(self, parser) } - /// Returns whether there are tokens remaining in this stream. + /// Returns whether there are no more tokens remaining to be parsed from + /// this stream. /// - /// This method returns true at the end of the content of a set of - /// delimiters, as well as at the very end of the complete macro input. + /// This method returns true upon reaching the end of the content within a + /// set of delimiters, as well as at the end of the tokens provided to the + /// outermost parsing entry point. /// /// # Example /// From ef20bfdfbf32c06a4930b26d683b61defb34b043 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jun 2024 13:13:47 -0700 Subject: [PATCH 26/66] Optimize the peek impl of Group and Lifetime --- src/token.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/token.rs b/src/token.rs index 2ac6b83478..37c3826872 100644 --- a/src/token.rs +++ b/src/token.rs @@ -195,7 +195,6 @@ macro_rules! impl_token { }; } -impl_token!("lifetime" Lifetime); impl_token!("literal" Lit); impl_token!("string literal" LitStr); impl_token!("byte string literal" LitByteStr); @@ -205,12 +204,11 @@ impl_token!("character literal" LitChar); impl_token!("integer literal" LitInt); impl_token!("floating point literal" LitFloat); impl_token!("boolean literal" LitBool); -impl_token!("group token" proc_macro2::Group); macro_rules! impl_low_level_token { - ($display:literal $ty:ident $get:ident) => { + ($display:literal $($path:ident)::+ $get:ident) => { #[cfg(feature = "parsing")] - impl Token for $ty { + impl Token for $($path)::+ { fn peek(cursor: Cursor) -> bool { cursor.$get().is_some() } @@ -221,13 +219,15 @@ macro_rules! impl_low_level_token { } #[cfg(feature = "parsing")] - impl private::Sealed for $ty {} + impl private::Sealed for $($path)::+ {} }; } impl_low_level_token!("punctuation token" Punct punct); impl_low_level_token!("literal" Literal literal); impl_low_level_token!("token" TokenTree token_tree); +impl_low_level_token!("group token" proc_macro2::Group any_group); +impl_low_level_token!("lifetime" Lifetime lifetime); #[cfg(feature = "parsing")] impl private::Sealed for T {} From 9b4e478a98aeb90a113eeac2bf882402c8574dfb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jun 2024 13:22:17 -0700 Subject: [PATCH 27/66] Relocate Lit peek impls into lit module --- src/lit.rs | 43 +++++++++++++++++++++++++++++++++++++++++-- src/token.rs | 45 --------------------------------------------- 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/src/lit.rs b/src/lit.rs index a37aa2a9e7..103c0f6ed7 100644 --- a/src/lit.rs +++ b/src/lit.rs @@ -856,8 +856,11 @@ pub(crate) mod parsing { value, Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitFloatRepr, LitInt, LitIntRepr, LitStr, }; - use crate::parse::{Parse, ParseStream}; - use proc_macro2::{Literal, Punct}; + use crate::parse::{Parse, ParseStream, Unexpected}; + use crate::token::{self, Token}; + use proc_macro2::{Literal, Punct, Span}; + use std::cell::Cell; + use std::rc::Rc; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] impl Parse for Lit { @@ -1017,6 +1020,42 @@ pub(crate) mod parsing { } } } + + fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { + let scope = Span::call_site(); + let unexpected = Rc::new(Cell::new(Unexpected::None)); + let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected); + peek(&buffer) + } + + macro_rules! impl_token { + ($display:literal $name:ty) => { + impl Token for $name { + fn peek(cursor: Cursor) -> bool { + fn peek(input: ParseStream) -> bool { + <$name as Parse>::parse(input).is_ok() + } + peek_impl(cursor, peek) + } + + fn display() -> &'static str { + $display + } + } + + impl token::private::Sealed for $name {} + }; + } + + impl_token!("literal" Lit); + impl_token!("string literal" LitStr); + impl_token!("byte string literal" LitByteStr); + impl_token!("C-string literal" LitCStr); + impl_token!("byte literal" LitByte); + impl_token!("character literal" LitChar); + impl_token!("integer literal" LitInt); + impl_token!("floating point literal" LitFloat); + impl_token!("boolean literal" LitBool); } #[cfg(feature = "printing")] diff --git a/src/token.rs b/src/token.rs index 37c3826872..061e8806ca 100644 --- a/src/token.rs +++ b/src/token.rs @@ -98,8 +98,6 @@ use crate::error::Result; #[cfg(feature = "parsing")] use crate::lifetime::Lifetime; #[cfg(feature = "parsing")] -use crate::lit::{Lit, LitBool, LitByte, LitByteStr, LitCStr, LitChar, LitFloat, LitInt, LitStr}; -#[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream}; use crate::span::IntoSpans; use proc_macro2::extra::DelimSpan; @@ -162,49 +160,6 @@ pub(crate) mod private { #[cfg(feature = "parsing")] impl private::Sealed for Ident {} -#[cfg(feature = "parsing")] -fn peek_impl(cursor: Cursor, peek: fn(ParseStream) -> bool) -> bool { - use crate::parse::Unexpected; - use std::cell::Cell; - use std::rc::Rc; - - let scope = Span::call_site(); - let unexpected = Rc::new(Cell::new(Unexpected::None)); - let buffer = crate::parse::new_parse_buffer(scope, cursor, unexpected); - peek(&buffer) -} - -macro_rules! impl_token { - ($display:literal $name:ty) => { - #[cfg(feature = "parsing")] - impl Token for $name { - fn peek(cursor: Cursor) -> bool { - fn peek(input: ParseStream) -> bool { - <$name as Parse>::parse(input).is_ok() - } - peek_impl(cursor, peek) - } - - fn display() -> &'static str { - $display - } - } - - #[cfg(feature = "parsing")] - impl private::Sealed for $name {} - }; -} - -impl_token!("literal" Lit); -impl_token!("string literal" LitStr); -impl_token!("byte string literal" LitByteStr); -impl_token!("C-string literal" LitCStr); -impl_token!("byte literal" LitByte); -impl_token!("character literal" LitChar); -impl_token!("integer literal" LitInt); -impl_token!("floating point literal" LitFloat); -impl_token!("boolean literal" LitBool); - macro_rules! impl_low_level_token { ($display:literal $($path:ident)::+ $get:ident) => { #[cfg(feature = "parsing")] From 537b0c58f4d00c1f412fb83d258900843f65814e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 21 Jun 2024 23:59:47 -0700 Subject: [PATCH 28/66] Update test suite to nightly-2024-06-22 --- tests/common/eq.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 1ad36b7598..121e61f05d 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -130,7 +130,6 @@ use rustc_ast::ast::RangeLimits; use rustc_ast::ast::RangeSyntax; use rustc_ast::ast::Recovered; use rustc_ast::ast::Safety; -use rustc_ast::ast::StaticForeignItem; use rustc_ast::ast::StaticItem; use rustc_ast::ast::Stmt; use rustc_ast::ast::StmtKind; @@ -522,7 +521,6 @@ spanless_eq_struct!(Path; span segments tokens); spanless_eq_struct!(PathSegment; ident id args); spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span); spanless_eq_struct!(QSelf; ty path_span position); -spanless_eq_struct!(StaticForeignItem; ty safety mutability expr); spanless_eq_struct!(StaticItem; ty safety mutability expr); spanless_eq_struct!(Stmt; id kind span); spanless_eq_struct!(StrLit; symbol suffix symbol_unescaped style span); From 43387720a3d52db3c148e5383cd6d9ef3b766611 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Sun, 23 Jun 2024 21:02:08 +0100 Subject: [PATCH 29/66] track-caller in parse_quote_spanned When `parse_quote!` fails, show the location in user crate, not in `syn`. --- src/parse_quote.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/parse_quote.rs b/src/parse_quote.rs index c4f47e16d1..22cd98effb 100644 --- a/src/parse_quote.rs +++ b/src/parse_quote.rs @@ -113,6 +113,7 @@ use proc_macro2::TokenStream; // Not public API. #[doc(hidden)] +#[track_caller] pub fn parse(token_stream: TokenStream) -> T { let parser = T::parse; match parser.parse2(token_stream) { From ecb0429297d3da2f20ab8559e41ddf8a2137d83b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 23 Jun 2024 14:00:55 -0700 Subject: [PATCH 30/66] Release 2.0.68 --- 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 89bba0efbc..3e37186558 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.67" +version = "2.0.68" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 851c4b452f..94b9bc18d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.67")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.68")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 7e8b40f8a2..58fc2bb2ff 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.67", + "version": "2.0.68", "types": [ { "ident": "Abi", From c29fb6a3b7585ef3c8204959603eaae855b7925a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 24 Jun 2024 19:47:05 -0700 Subject: [PATCH 31/66] Eliminate Postfix precedence level --- src/expr.rs | 12 ++++++------ src/precedence.rs | 18 +++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index c60bcf4771..30bf9c76c6 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3180,7 +3180,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.base, - Precedence::of(&e.base) < Precedence::Postfix, + Precedence::of(&e.base) < Precedence::Unambiguous, tokens, fixup.leftmost_subexpression_with_dot(), ); @@ -3313,7 +3313,7 @@ pub(crate) mod printing { let precedence = if let Expr::Field(_) = &*e.func { Precedence::Any } else { - Precedence::Postfix + Precedence::Unambiguous }; print_subexpression( &e.func, @@ -3424,7 +3424,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.base, - Precedence::of(&e.base) < Precedence::Postfix, + Precedence::of(&e.base) < Precedence::Unambiguous, tokens, #[cfg(feature = "full")] fixup.leftmost_subexpression_with_dot(), @@ -3519,7 +3519,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.expr, - Precedence::of(&e.expr) < Precedence::Postfix, + Precedence::of(&e.expr) < Precedence::Unambiguous, tokens, #[cfg(feature = "full")] fixup.leftmost_subexpression(), @@ -3635,7 +3635,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.receiver, - Precedence::of(&e.receiver) < Precedence::Postfix, + Precedence::of(&e.receiver) < Precedence::Unambiguous, tokens, #[cfg(feature = "full")] fixup.leftmost_subexpression_with_dot(), @@ -3785,7 +3785,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.expr, - Precedence::of(&e.expr) < Precedence::Postfix, + Precedence::of(&e.expr) < Precedence::Unambiguous, tokens, fixup.leftmost_subexpression_with_dot(), ); diff --git a/src/precedence.rs b/src/precedence.rs index 450958ad34..28202a5483 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -36,10 +36,7 @@ pub(crate) enum Precedence { // unary - * ! & &mut #[cfg(feature = "printing")] Prefix, - // function calls, array indexing, field expressions, method calls, ? - #[cfg(feature = "printing")] - Postfix, - // paths, loops + // paths, loops, function calls, array indexing, field expressions, method calls #[cfg(feature = "printing")] Unambiguous, } @@ -92,30 +89,29 @@ impl Precedence { Expr::Cast(_) => Precedence::Cast, Expr::Let(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, - Expr::Await(_) - | Expr::Call(_) - | Expr::MethodCall(_) - | Expr::Field(_) - | Expr::Index(_) - | Expr::Try(_) => Precedence::Postfix, - Expr::Array(_) | Expr::Async(_) + | Expr::Await(_) | Expr::Block(_) + | Expr::Call(_) | Expr::Const(_) | Expr::Continue(_) + | Expr::Field(_) | Expr::ForLoop(_) | Expr::Group(_) | Expr::If(_) + | Expr::Index(_) | Expr::Infer(_) | Expr::Lit(_) | Expr::Loop(_) | Expr::Macro(_) | Expr::Match(_) + | Expr::MethodCall(_) | Expr::Paren(_) | Expr::Path(_) | Expr::Repeat(_) | Expr::Struct(_) + | Expr::Try(_) | Expr::TryBlock(_) | Expr::Tuple(_) | Expr::Unsafe(_) From cc5e64e4143099699c5c7f20791c563e71395455 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 30 Jun 2024 11:05:32 -0700 Subject: [PATCH 32/66] Update test suite to nightly-2024-06-29 --- 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 121e61f05d..5eb835bcd7 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -617,7 +617,7 @@ spanless_eq_enum!(CoroutineKind; Async(span closure_id return_impl_trait_id) spanless_eq_enum!(ExprKind; Array(0) ConstBlock(0) Call(0 1) MethodCall(0) Tup(0) Binary(0 1 2) Unary(0 1) Lit(0) Cast(0 1) Type(0 1) Let(0 1 2 3) If(0 1 2) While(0 1 2) ForLoop(pat iter body label kind) Loop(0 1 2) - Match(0 1 2) Closure(0) Block(0 1) Gen(0 1 2) Await(0 1) TryBlock(0) + Match(0 1 2) Closure(0) Block(0 1) Gen(0 1 2 3) Await(0 1) TryBlock(0) Assign(0 1 2) AssignOp(0 1 2) Field(0 1) Index(0 1 2) Underscore Range(0 1 2) Path(0 1) AddrOf(0 1 2) Break(0 1) Continue(0) Ret(0) InlineAsm(0) OffsetOf(0 1) MacCall(0) Struct(0) Repeat(0 1) Paren(0) Try(0) From 93931a4f243665a1e50748072b9fac1adbcebb7c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 1 Jul 2024 19:42:22 -0700 Subject: [PATCH 33/66] Add fixup test for break with leading label --- tests/test_expr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 961e3c4ea3..364386c5f8 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -672,6 +672,7 @@ fn test_fixup() { quote! { match m { _ => ({}) - 1 } }, quote! { if let _ = (a && b) && c {} }, quote! { if let _ = (S {}) {} }, + quote! { break ('a: loop { break 'a 1 } + 1) }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From 4e71c1caa413122a644f9e3fcb8222dfc20d9f8d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 May 2024 20:17:44 -0700 Subject: [PATCH 34/66] Parenthesize labeled loops inside break value --- src/classify.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ src/expr.rs | 11 ++++++++-- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/classify.rs b/src/classify.rs index 1b0ff30040..cc176d06dc 100644 --- a/src/classify.rs +++ b/src/classify.rs @@ -248,6 +248,59 @@ pub(crate) fn confusable_with_adjacent_lt(mut expr: &Expr) -> bool { } } +/// Whether the expression's first token is the label of a loop/block. +#[cfg(all(feature = "printing", feature = "full"))] +pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { + loop { + match expr { + Expr::Block(e) => return e.label.is_some(), + Expr::ForLoop(e) => return e.label.is_some(), + Expr::Loop(e) => return e.label.is_some(), + Expr::While(e) => return e.label.is_some(), + + Expr::Assign(e) => expr = &e.left, + Expr::Await(e) => expr = &e.base, + Expr::Binary(e) => expr = &e.left, + Expr::Call(e) => expr = &e.func, + Expr::Cast(e) => expr = &e.expr, + Expr::Field(e) => expr = &e.base, + Expr::Index(e) => expr = &e.expr, + Expr::MethodCall(e) => expr = &e.receiver, + Expr::Range(e) => match &e.start { + Some(start) => expr = start, + None => return false, + }, + Expr::Try(e) => expr = &e.expr, + + Expr::Array(_) + | Expr::Async(_) + | Expr::Break(_) + | Expr::Closure(_) + | Expr::Const(_) + | Expr::Continue(_) + | Expr::Group(_) + | Expr::If(_) + | Expr::Infer(_) + | Expr::Let(_) + | Expr::Lit(_) + | Expr::Macro(_) + | Expr::Match(_) + | Expr::Paren(_) + | Expr::Path(_) + | Expr::Reference(_) + | Expr::Repeat(_) + | Expr::Return(_) + | Expr::Struct(_) + | Expr::TryBlock(_) + | Expr::Tuple(_) + | Expr::Unary(_) + | Expr::Unsafe(_) + | Expr::Verbatim(_) + | Expr::Yield(_) => return false, + } + } +} + /// Whether the expression's last token is `}`. #[cfg(feature = "full")] pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { diff --git a/src/expr.rs b/src/expr.rs index 30bf9c76c6..e684068caa 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3286,8 +3286,15 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); e.break_token.to_tokens(tokens); e.label.to_tokens(tokens); - if let Some(expr) = &e.expr { - print_expr(expr, tokens, fixup.subsequent_subexpression()); + if let Some(value) = &e.expr { + print_subexpression( + value, + // Parenthesize `break 'inner: loop { break 'inner 1 } + 1` + // ^---------------------------------^ + e.label.is_none() && classify::expr_leading_label(value), + tokens, + fixup.subsequent_subexpression(), + ); } } From f0dfdbd9af41fe75ee6054daca545d80a4374a32 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Jul 2024 20:05:32 -0700 Subject: [PATCH 35/66] Update test suite to nightly-2024-07-05 --- 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 5eb835bcd7..4ce3f05027 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -573,7 +573,7 @@ spanless_eq_enum!(FormatSign; Plus Minus); spanless_eq_enum!(FormatTrait; Display Debug LowerExp UpperExp Octal Pointer Binary LowerHex UpperHex); spanless_eq_enum!(GenBlockKind; Async Gen AsyncGen); spanless_eq_enum!(GenericArg; Lifetime(0) Type(0) Const(0)); -spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0)); +spanless_eq_enum!(GenericArgs; AngleBracketed(0) Parenthesized(0) ParenthesizedElided(0)); spanless_eq_enum!(GenericBound; Trait(0 1) Outlives(0) Use(0 1)); spanless_eq_enum!(GenericParamKind; Lifetime Type(default) Const(ty kw_span default)); spanless_eq_enum!(ImplPolarity; Positive Negative(0)); From a4438571c902aae659ff568419fa4af029b5c0b0 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 4 Jul 2024 21:12:09 -0700 Subject: [PATCH 36/66] Add Punctuated::get and get_mut --- src/punctuated.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/punctuated.rs b/src/punctuated.rs index 29e8dce15f..ab2e7d9879 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -92,6 +92,29 @@ impl Punctuated { self.iter_mut().next_back() } + /// Borrows the element at the given index. + pub fn get(&mut self, index: usize) -> Option<&T> { + if let Some((value, _punct)) = self.inner.get(index) { + Some(value) + } else if index == self.inner.len() { + self.last.as_deref() + } else { + None + } + } + + /// Mutably borrows the element at the given index. + pub fn get_mut(&mut self, index: usize) -> Option<&mut T> { + let inner_len = self.inner.len(); + if let Some((value, _punct)) = self.inner.get_mut(index) { + Some(value) + } else if index == inner_len { + self.last.as_deref_mut() + } else { + None + } + } + /// Returns an iterator over borrowed syntax tree nodes of type `&T`. pub fn iter(&self) -> Iter { Iter { From 0f7213407fb59cca90a1097747868b68b32ff020 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 14:59:17 -0700 Subject: [PATCH 37/66] Improve precedence variant name of sum and product operators --- src/precedence.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/precedence.rs b/src/precedence.rs index 28202a5483..a708e291d0 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -28,9 +28,9 @@ pub(crate) enum Precedence { // << >> Shift, // + - - Arithmetic, + Sum, // * / % - Term, + Product, // as Cast, // unary - * ! & &mut @@ -44,8 +44,8 @@ pub(crate) enum Precedence { impl Precedence { pub(crate) fn of_binop(op: &BinOp) -> Self { match op { - BinOp::Add(_) | BinOp::Sub(_) => Precedence::Arithmetic, - BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Term, + BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum, + BinOp::Mul(_) | BinOp::Div(_) | BinOp::Rem(_) => Precedence::Product, BinOp::And(_) => Precedence::And, BinOp::Or(_) => Precedence::Or, BinOp::BitXor(_) => Precedence::BitXor, From d4a0ff556fe1bbcaa77ebc37d24cc1bdaf5eac3a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 15:38:10 -0700 Subject: [PATCH 38/66] Release 2.0.69 --- 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 3e37186558..0aa7899ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.68" +version = "2.0.69" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 94b9bc18d5..96596844a3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.68")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.69")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 58fc2bb2ff..0889f26734 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.68", + "version": "2.0.69", "types": [ { "ident": "Abi", From 9cd47ea9f024bdc91c0bb9bd4d880eb8cc224215 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 16:09:34 -0700 Subject: [PATCH 39/66] Add fixup test with closure that is not a rightmost subexpression --- tests/test_expr.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 364386c5f8..a40c0f5d40 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -673,6 +673,7 @@ fn test_fixup() { quote! { if let _ = (a && b) && c {} }, quote! { if let _ = (S {}) {} }, quote! { break ('a: loop { break 'a 1 } + 1) }, + quote! { a + (|| b) + c }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From 30abbd3f6e3053e65e2e4f51bf45d6d2f4da93e9 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 16:12:10 -0700 Subject: [PATCH 40/66] Parenthesize closures and jumps which are not rightmost subexpressions --- src/expr.rs | 31 ++++++++++++++++++++++++++----- src/fixup.rs | 29 ++++++++++++++++++++++++++++- src/precedence.rs | 12 ------------ 3 files changed, 54 insertions(+), 18 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index e684068caa..2285084e15 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3119,6 +3119,13 @@ pub(crate) mod printing { } } + fn precedence_of_rhs(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { + #[cfg(feature = "full")] + return fixup.precedence_of_rhs(e); + #[cfg(not(feature = "full"))] + return Precedence::of(e); + } + #[cfg(feature = "full")] #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprArray { @@ -3150,7 +3157,7 @@ pub(crate) mod printing { e.eq_token.to_tokens(tokens); print_subexpression( &e.right, - Precedence::of_rhs(&e.right) < Precedence::Assign, + precedence_of_rhs(&e.right, fixup) < Precedence::Assign, tokens, fixup.subsequent_subexpression(), ); @@ -3209,7 +3216,11 @@ pub(crate) mod printing { let binop_prec = Precedence::of_binop(&e.op); let left_prec = Precedence::of(&e.left); - let right_prec = Precedence::of_rhs(&e.right); + let right_prec = precedence_of_rhs( + &e.right, + #[cfg(feature = "full")] + fixup, + ); let (mut left_needs_group, right_needs_group) = if let Precedence::Assign = binop_prec { (left_prec <= binop_prec, right_prec < binop_prec) } else { @@ -3696,7 +3707,7 @@ pub(crate) mod printing { if let Some(end) = &e.end { print_subexpression( end, - Precedence::of_rhs(end) <= Precedence::Range, + precedence_of_rhs(end, fixup) <= Precedence::Range, tokens, fixup.subsequent_subexpression(), ); @@ -3723,9 +3734,14 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); e.and_token.to_tokens(tokens); e.mutability.to_tokens(tokens); + let prec = precedence_of_rhs( + &e.expr, + #[cfg(feature = "full")] + fixup, + ); print_subexpression( &e.expr, - Precedence::of_rhs(&e.expr) < Precedence::Prefix, + prec < Precedence::Prefix, tokens, #[cfg(feature = "full")] fixup.subsequent_subexpression(), @@ -3844,9 +3860,14 @@ pub(crate) mod printing { ) { outer_attrs_to_tokens(&e.attrs, tokens); e.op.to_tokens(tokens); + let prec = precedence_of_rhs( + &e.expr, + #[cfg(feature = "full")] + fixup, + ); print_subexpression( &e.expr, - Precedence::of_rhs(&e.expr) < Precedence::Prefix, + prec < Precedence::Prefix, tokens, #[cfg(feature = "full")] fixup.subsequent_subexpression(), diff --git a/src/fixup.rs b/src/fixup.rs index 5407c9fdf3..4b9fe5644c 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -85,6 +85,14 @@ pub(crate) struct FixupContext { // } // parenthesize_exterior_struct_lit: bool, + + // This is the difference between: + // + // let _ = 1 + return 1; // no parens if rightmost subexpression + // + // let _ = 1 + (return 1) + 1; // needs parens + // + parenthesize_exterior_jump: bool, } impl FixupContext { @@ -96,6 +104,7 @@ impl FixupContext { match_arm: false, leftmost_subexpression_in_match_arm: false, parenthesize_exterior_struct_lit: false, + parenthesize_exterior_jump: false, }; /// Create the initial fixup for printing an expression in statement @@ -145,6 +154,7 @@ impl FixupContext { match_arm: false, leftmost_subexpression_in_match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + parenthesize_exterior_jump: true, ..self } } @@ -159,6 +169,7 @@ impl FixupContext { leftmost_subexpression_in_stmt: false, match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, leftmost_subexpression_in_match_arm: false, + parenthesize_exterior_jump: true, ..self } } @@ -205,7 +216,23 @@ impl FixupContext { /// "let chain". pub fn needs_group_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && classify::confusable_with_adjacent_block(expr) - || Precedence::of_rhs(expr) <= Precedence::And + || self.precedence_of_rhs(expr) <= Precedence::And + } + + /// Determines the effective precedence of a subexpression. Some expressions + /// have higher precedence on the right side of a binary operator than on + /// the left. + pub fn precedence_of_rhs(self, expr: &Expr) -> Precedence { + if !self.parenthesize_exterior_jump { + match expr { + Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => { + return Precedence::Prefix; + } + Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, + _ => {} + } + } + Precedence::of(expr) } } diff --git a/src/precedence.rs b/src/precedence.rs index a708e291d0..14320be80a 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -122,18 +122,6 @@ impl Precedence { Expr::Closure(_) => unreachable!(), } } - - #[cfg(feature = "printing")] - pub(crate) fn of_rhs(e: &Expr) -> Self { - match e { - Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => { - Precedence::Prefix - } - #[cfg(feature = "full")] - Expr::Range(e) if e.start.is_none() => Precedence::Prefix, - _ => Precedence::of(e), - } - } } impl Copy for Precedence {} From a89a1b69efc003fd6b3b309a5317160dd0e90376 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 15:29:13 -0700 Subject: [PATCH 41/66] Add new fixup tests for continuation of a jump expr --- tests/test_expr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_expr.rs b/tests/test_expr.rs index a40c0f5d40..cdcb5c6219 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -674,6 +674,8 @@ fn test_fixup() { quote! { if let _ = (S {}) {} }, quote! { break ('a: loop { break 'a 1 } + 1) }, quote! { a + (|| b) + c }, + quote! { if let _ = ((break) - 1 || true) {} }, + quote! { if let _ = ((break) + 1 || true) {} }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From ffaca82d0e33d7aa732e1f75bba55407230dbcfa Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 17:13:57 -0700 Subject: [PATCH 42/66] Improve precision of jump parentheses when next token cannot begin expr --- src/expr.rs | 69 ++++++++++++++++++++++++++++++++++++---------- src/fixup.rs | 49 ++++++++++++++++++++++++++++---- src/precedence.rs | 13 +++++++-- tests/test_expr.rs | 3 +- 4 files changed, 111 insertions(+), 23 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 2285084e15..9f2cd8b12c 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3119,9 +3119,16 @@ pub(crate) mod printing { } } - fn precedence_of_rhs(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { + fn leading_precedence(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { #[cfg(feature = "full")] - return fixup.precedence_of_rhs(e); + return fixup.leading_precedence(e); + #[cfg(not(feature = "full"))] + return Precedence::of(e); + } + + fn trailing_precedence(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { + #[cfg(feature = "full")] + return fixup.trailing_precedence(e); #[cfg(not(feature = "full"))] return Precedence::of(e); } @@ -3157,7 +3164,7 @@ pub(crate) mod printing { e.eq_token.to_tokens(tokens); print_subexpression( &e.right, - precedence_of_rhs(&e.right, fixup) < Precedence::Assign, + trailing_precedence(&e.right, fixup) < Precedence::Assign, tokens, fixup.subsequent_subexpression(), ); @@ -3214,13 +3221,31 @@ pub(crate) mod printing { ) { outer_attrs_to_tokens(&e.attrs, tokens); - let binop_prec = Precedence::of_binop(&e.op); - let left_prec = Precedence::of(&e.left); - let right_prec = precedence_of_rhs( + #[cfg(feature = "full")] + let left_fixup = fixup.leftmost_subexpression_with_begin_operator(match &e.op { + BinOp::Sub(_) + | BinOp::Mul(_) + | BinOp::And(_) + | BinOp::Or(_) + | BinOp::BitAnd(_) + | BinOp::BitOr(_) + | BinOp::Shl(_) + | BinOp::Lt(_) => true, + _ => false, + }); + let left_prec = leading_precedence( + &e.left, + #[cfg(feature = "full")] + left_fixup, + ); + + let right_prec = trailing_precedence( &e.right, #[cfg(feature = "full")] fixup, ); + + let binop_prec = Precedence::of_binop(&e.op); let (mut left_needs_group, right_needs_group) = if let Precedence::Assign = binop_prec { (left_prec <= binop_prec, right_prec < binop_prec) } else { @@ -3259,7 +3284,7 @@ pub(crate) mod printing { left_needs_group, tokens, #[cfg(feature = "full")] - fixup.leftmost_subexpression(), + left_fixup, ); e.op.to_tokens(tokens); print_subexpression( @@ -3328,17 +3353,24 @@ pub(crate) mod printing { ) { outer_attrs_to_tokens(&e.attrs, tokens); - let precedence = if let Expr::Field(_) = &*e.func { + let call_precedence = if let Expr::Field(_) = &*e.func { Precedence::Any } else { Precedence::Unambiguous }; + #[cfg(feature = "full")] + let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true); + let func_precedence = leading_precedence( + &e.func, + #[cfg(feature = "full")] + func_fixup, + ); print_subexpression( &e.func, - Precedence::of(&e.func) < precedence, + func_precedence < call_precedence, tokens, #[cfg(feature = "full")] - fixup.leftmost_subexpression(), + func_fixup, ); e.paren_token.surround(tokens, |tokens| { @@ -3535,12 +3567,19 @@ pub(crate) mod printing { #[cfg(feature = "full")] fixup: FixupContext, ) { outer_attrs_to_tokens(&e.attrs, tokens); + #[cfg(feature = "full")] + let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true); + let obj_precedence = leading_precedence( + &e.expr, + #[cfg(feature = "full")] + obj_fixup, + ); print_subexpression( &e.expr, - Precedence::of(&e.expr) < Precedence::Unambiguous, + obj_precedence < Precedence::Unambiguous, tokens, #[cfg(feature = "full")] - fixup.leftmost_subexpression(), + obj_fixup, ); e.bracket_token.surround(tokens, |tokens| { e.index.to_tokens(tokens); @@ -3707,7 +3746,7 @@ pub(crate) mod printing { if let Some(end) = &e.end { print_subexpression( end, - precedence_of_rhs(end, fixup) <= Precedence::Range, + trailing_precedence(end, fixup) <= Precedence::Range, tokens, fixup.subsequent_subexpression(), ); @@ -3734,7 +3773,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); e.and_token.to_tokens(tokens); e.mutability.to_tokens(tokens); - let prec = precedence_of_rhs( + let prec = trailing_precedence( &e.expr, #[cfg(feature = "full")] fixup, @@ -3860,7 +3899,7 @@ pub(crate) mod printing { ) { outer_attrs_to_tokens(&e.attrs, tokens); e.op.to_tokens(tokens); - let prec = precedence_of_rhs( + let prec = trailing_precedence( &e.expr, #[cfg(feature = "full")] fixup, diff --git a/src/fixup.rs b/src/fixup.rs index 4b9fe5644c..63b79aac88 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -93,6 +93,14 @@ pub(crate) struct FixupContext { // let _ = 1 + (return 1) + 1; // needs parens // parenthesize_exterior_jump: bool, + + // This is the difference between: + // + // let _ = (return) - 1; // without paren, this would return -1 + // + // let _ = return + 1; // no paren because '+' cannot begin expr + // + next_operator_can_begin_expr: bool, } impl FixupContext { @@ -105,6 +113,7 @@ impl FixupContext { leftmost_subexpression_in_match_arm: false, parenthesize_exterior_struct_lit: false, parenthesize_exterior_jump: false, + next_operator_can_begin_expr: false, }; /// Create the initial fixup for printing an expression in statement @@ -174,6 +183,19 @@ impl FixupContext { } } + /// Transform this fixup into the one that should apply when printing a + /// leftmost subexpression followed by punctuation that is legal as the + /// first token of an expression. + pub fn leftmost_subexpression_with_begin_operator( + self, + next_operator_can_begin_expr: bool, + ) -> Self { + FixupContext { + next_operator_can_begin_expr, + ..self.leftmost_subexpression() + } + } + /// Transform this fixup into the one that should apply when printing any /// subexpression that is neither a leftmost subexpression nor surrounded in /// delimiters. @@ -216,15 +238,32 @@ impl FixupContext { /// "let chain". pub fn needs_group_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && classify::confusable_with_adjacent_block(expr) - || self.precedence_of_rhs(expr) <= Precedence::And + || self.trailing_precedence(expr) <= Precedence::And + } + + /// Determines the effective precedence of a left subexpression. Some + /// expressions have lower precedence when adjacent to particular operators. + pub fn leading_precedence(self, expr: &Expr) -> Precedence { + if self.next_operator_can_begin_expr { + match expr { + // Decrease precedence of value-less jumps when followed by an + // operator that would otherwise get interpreted as beginning a + // value for the jump. + Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => return Precedence::Any, + _ => {} + } + } + Precedence::of(expr) } - /// Determines the effective precedence of a subexpression. Some expressions - /// have higher precedence on the right side of a binary operator than on - /// the left. - pub fn precedence_of_rhs(self, expr: &Expr) -> Precedence { + /// Determines the effective precedence of a right subexpression. Some + /// expressions have higher precedence on the right side of a binary + /// operator than on the left. + pub fn trailing_precedence(self, expr: &Expr) -> Precedence { if !self.parenthesize_exterior_jump { match expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => { return Precedence::Prefix; } diff --git a/src/precedence.rs b/src/precedence.rs index 14320be80a..5f872aab7b 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -1,5 +1,7 @@ #[cfg(feature = "printing")] use crate::expr::Expr; +#[cfg(all(feature = "printing", feature = "full"))] +use crate::expr::{ExprBreak, ExprReturn, ExprYield}; use crate::op::BinOp; #[cfg(all(feature = "printing", feature = "full"))] use crate::ty::ReturnType; @@ -82,7 +84,14 @@ impl Precedence { ReturnType::Type(..) => Precedence::Unambiguous, }, - Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => Precedence::Any, + #[cfg(feature = "full")] + Expr::Break(ExprBreak { expr, .. }) + | Expr::Return(ExprReturn { expr, .. }) + | Expr::Yield(ExprYield { expr, .. }) => match expr { + Some(_) => Precedence::Any, + None => Precedence::Unambiguous, + }, + Expr::Assign(_) => Precedence::Assign, Expr::Range(_) => Precedence::Range, Expr::Binary(e) => Precedence::of_binop(&e.op), @@ -119,7 +128,7 @@ impl Precedence { | Expr::While(_) => Precedence::Unambiguous, #[cfg(not(feature = "full"))] - Expr::Closure(_) => unreachable!(), + Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => unreachable!(), } } } diff --git a/tests/test_expr.rs b/tests/test_expr.rs index cdcb5c6219..f48f8ed113 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -675,7 +675,8 @@ fn test_fixup() { quote! { break ('a: loop { break 'a 1 } + 1) }, quote! { a + (|| b) + c }, quote! { if let _ = ((break) - 1 || true) {} }, - quote! { if let _ = ((break) + 1 || true) {} }, + quote! { if let _ = (break + 1 || true) {} }, + quote! { (break)() }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From 9b76de720a3e44fd27ebec65faf1d556e2be5bf8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 18:36:28 -0700 Subject: [PATCH 43/66] Add associated const for the lowest precedence level --- src/expr.rs | 10 +++++----- src/precedence.rs | 2 ++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 9f2cd8b12c..f92954ac59 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -1216,7 +1216,7 @@ pub(crate) mod parsing { expr.replace_attrs(attrs); let allow_struct = AllowStruct(true); - return parse_expr(input, expr, allow_struct, Precedence::Any); + return parse_expr(input, expr, allow_struct, Precedence::MIN); } if input.peek(Token![.]) && !input.peek(Token![..]) || input.peek(Token![?]) { @@ -1226,7 +1226,7 @@ pub(crate) mod parsing { expr.replace_attrs(attrs); let allow_struct = AllowStruct(true); - return parse_expr(input, expr, allow_struct, Precedence::Any); + return parse_expr(input, expr, allow_struct, Precedence::MIN); } attrs.extend(expr.replace_attrs(Vec::new())); @@ -1413,7 +1413,7 @@ pub(crate) mod parsing { } else if input.peek(Token![as]) { Precedence::Cast } else { - Precedence::Any + Precedence::MIN } } @@ -1432,7 +1432,7 @@ pub(crate) mod parsing { lhs, #[cfg(feature = "full")] allow_struct, - Precedence::Any, + Precedence::MIN, ) } @@ -3354,7 +3354,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); let call_precedence = if let Expr::Field(_) = &*e.func { - Precedence::Any + Precedence::MIN } else { Precedence::Unambiguous }; diff --git a/src/precedence.rs b/src/precedence.rs index 5f872aab7b..523f0544ad 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -44,6 +44,8 @@ pub(crate) enum Precedence { } impl Precedence { + pub(crate) const MIN: Self = Precedence::Any; + pub(crate) fn of_binop(op: &BinOp) -> Self { match op { BinOp::Add(_) | BinOp::Sub(_) => Precedence::Sum, From e1c03c9fea7ce04dbbd110befaae7c1a2ad3122c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 18:39:08 -0700 Subject: [PATCH 44/66] Improve name of precedence variant for jumps --- src/fixup.rs | 2 +- src/precedence.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fixup.rs b/src/fixup.rs index 63b79aac88..9423e36954 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -249,7 +249,7 @@ impl FixupContext { // Decrease precedence of value-less jumps when followed by an // operator that would otherwise get interpreted as beginning a // value for the jump. - Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => return Precedence::Any, + Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => return Precedence::Jump, _ => {} } } diff --git a/src/precedence.rs b/src/precedence.rs index 523f0544ad..354ea90812 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -10,7 +10,7 @@ use std::cmp::Ordering; // Reference: https://doc.rust-lang.org/reference/expressions.html#expression-precedence pub(crate) enum Precedence { // return, break, closures - Any, + Jump, // = += -= *= /= %= &= |= ^= <<= >>= Assign, // .. ..= @@ -44,7 +44,7 @@ pub(crate) enum Precedence { } impl Precedence { - pub(crate) const MIN: Self = Precedence::Any; + pub(crate) const MIN: Self = Precedence::Jump; pub(crate) fn of_binop(op: &BinOp) -> Self { match op { @@ -82,7 +82,7 @@ impl Precedence { match e { #[cfg(feature = "full")] Expr::Closure(e) => match e.output { - ReturnType::Default => Precedence::Any, + ReturnType::Default => Precedence::Jump, ReturnType::Type(..) => Precedence::Unambiguous, }, @@ -90,7 +90,7 @@ impl Precedence { Expr::Break(ExprBreak { expr, .. }) | Expr::Return(ExprReturn { expr, .. }) | Expr::Yield(ExprYield { expr, .. }) => match expr { - Some(_) => Precedence::Any, + Some(_) => Precedence::Jump, None => Precedence::Unambiguous, }, From a6fdf8b340456a1037773341c3cdda2c44a913f1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 19:00:13 -0700 Subject: [PATCH 45/66] Switch to AtomicUsize::into_inner for reading final state of counters --- tests/test_precedence.rs | 4 ++-- tests/test_round_trip.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index 57686c3d2a..7961bc4cca 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -97,8 +97,8 @@ fn test_rustc_precedence() { } }); - let passed = passed.load(Ordering::Relaxed); - let failed = failed.load(Ordering::Relaxed); + let passed = passed.into_inner(); + let failed = failed.into_inner(); errorf!("\n===== Precedence Test Results =====\n"); errorf!("{} passed | {} failed\n", passed, failed); diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs index 1a79b3298e..3d06d9785a 100644 --- a/tests/test_round_trip.rs +++ b/tests/test_round_trip.rs @@ -61,7 +61,7 @@ fn test_round_trip() { repo::for_each_rust_file(|path| test(path, &failed, abort_after)); - let failed = failed.load(Ordering::Relaxed); + let failed = failed.into_inner(); if failed > 0 { panic!("{} failures", failed); } From 185d98814ebc0b4b2054b7977109e24e5e40e2ce Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 19:44:04 -0700 Subject: [PATCH 46/66] Parenthesize ranges on left-hand side of assignment operator --- src/expr.rs | 4 ++-- tests/test_expr.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index f92954ac59..6d1df7955c 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3157,7 +3157,7 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.left, - Precedence::of(&e.left) <= Precedence::Assign, + Precedence::of(&e.left) <= Precedence::Range, tokens, fixup.leftmost_subexpression(), ); @@ -3247,7 +3247,7 @@ pub(crate) mod printing { let binop_prec = Precedence::of_binop(&e.op); let (mut left_needs_group, right_needs_group) = if let Precedence::Assign = binop_prec { - (left_prec <= binop_prec, right_prec < binop_prec) + (left_prec <= Precedence::Range, right_prec < binop_prec) } else { (left_prec < binop_prec, right_prec <= binop_prec) }; diff --git a/tests/test_expr.rs b/tests/test_expr.rs index f48f8ed113..3bd2687748 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -677,6 +677,8 @@ fn test_fixup() { quote! { if let _ = ((break) - 1 || true) {} }, quote! { if let _ = (break + 1 || true) {} }, quote! { (break)() }, + quote! { (..) = () }, + quote! { (..) += () }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From bd5d7984a4f36a2803890546507e23a2344b7d6a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 19:53:09 -0700 Subject: [PATCH 47/66] Parenthesize chained comparison on both sides --- src/expr.rs | 8 ++++---- tests/test_expr.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 6d1df7955c..9493822f5a 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3246,10 +3246,10 @@ pub(crate) mod printing { ); let binop_prec = Precedence::of_binop(&e.op); - let (mut left_needs_group, right_needs_group) = if let Precedence::Assign = binop_prec { - (left_prec <= Precedence::Range, right_prec < binop_prec) - } else { - (left_prec < binop_prec, right_prec <= binop_prec) + let (mut left_needs_group, right_needs_group) = match binop_prec { + Precedence::Assign => (left_prec <= Precedence::Range, right_prec < binop_prec), + Precedence::Compare => (left_prec <= binop_prec, right_prec <= binop_prec), + _ => (left_prec < binop_prec, right_prec <= binop_prec), }; // These cases require parenthesization independently of precedence. diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 3bd2687748..3849286431 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -679,6 +679,7 @@ fn test_fixup() { quote! { (break)() }, quote! { (..) = () }, quote! { (..) += () }, + quote! { (1 < 2) == (3 < 4) }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From f6cd75fb1bb20d75fff2dba560a124fa1b10f1cd Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 19:59:41 -0700 Subject: [PATCH 48/66] Parenthesize leading Expr::Let in statement --- src/fixup.rs | 1 + tests/test_expr.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/fixup.rs b/src/fixup.rs index 9423e36954..ddee906fb5 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -221,6 +221,7 @@ impl FixupContext { /// examples. pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool { (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr)) + || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_))) || (self.leftmost_subexpression_in_match_arm && !classify::requires_comma_to_be_match_arm(expr)) } diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 3849286431..11d0f86c50 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -680,6 +680,7 @@ fn test_fixup() { quote! { (..) = () }, quote! { (..) += () }, quote! { (1 < 2) == (3 < 4) }, + quote! { { (let _ = ()) } }, ] { let original: Expr = syn::parse2(tokens).unwrap(); From d0f0e27bac11738d7a4d6bfd4822854a9d6ad8b1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 20:13:00 -0700 Subject: [PATCH 49/66] Move rayon_init and abort_after into repo module Both of these are only applicable to tests that operate on the rustc repo. --- tests/common/mod.rs | 23 ----------------------- tests/repo/mod.rs | 20 ++++++++++++++++++++ tests/test_precedence.rs | 4 ++-- tests/test_round_trip.rs | 4 ++-- 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index f29d800c72..c85ac0b4c9 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,28 +1,5 @@ #![allow(dead_code)] #![allow(clippy::module_name_repetitions, clippy::shadow_unrelated)] -use rayon::ThreadPoolBuilder; -use std::env; - pub mod eq; pub mod parse; - -/// Read the `ABORT_AFTER_FAILURE` environment variable, and parse it. -pub fn abort_after() -> usize { - match env::var("ABORT_AFTER_FAILURE") { - Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"), - Err(_) => usize::MAX, - } -} - -/// Configure Rayon threadpool. -pub fn rayon_init() { - let stack_size = match env::var("RUST_MIN_STACK") { - Ok(s) => s.parse().expect("failed to parse RUST_MIN_STACK"), - Err(_) => 1024 * 1024 * if cfg!(debug_assertions) { 40 } else { 20 }, - }; - ThreadPoolBuilder::new() - .stack_size(stack_size) - .build_global() - .unwrap(); -} diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index c8400288d9..2db48ee2fb 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -6,7 +6,9 @@ use self::progress::Progress; use anyhow::Result; use flate2::read::GzDecoder; use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; +use rayon::ThreadPoolBuilder; use std::collections::BTreeSet; +use std::env; use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; @@ -384,6 +386,24 @@ pub fn edition(path: &Path) -> &'static str { } } +pub fn abort_after() -> usize { + match env::var("ABORT_AFTER_FAILURE") { + Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"), + Err(_) => usize::MAX, + } +} + +pub fn rayon_init() { + let stack_size = match env::var("RUST_MIN_STACK") { + Ok(s) => s.parse().expect("failed to parse RUST_MIN_STACK"), + Err(_) => 1024 * 1024 * if cfg!(debug_assertions) { 40 } else { 20 }, + }; + ThreadPoolBuilder::new() + .stack_size(stack_size) + .build_global() + .unwrap(); +} + pub fn clone_rust() { let needs_clone = match fs::read_to_string("tests/rust/COMMIT") { Err(_) => true, diff --git a/tests/test_precedence.rs b/tests/test_precedence.rs index 7961bc4cca..40b0bfad03 100644 --- a/tests/test_precedence.rs +++ b/tests/test_precedence.rs @@ -57,9 +57,9 @@ mod repo; #[test] fn test_rustc_precedence() { - common::rayon_init(); + repo::rayon_init(); repo::clone_rust(); - let abort_after = common::abort_after(); + let abort_after = repo::abort_after(); if abort_after == 0 { panic!("skipping all precedence tests"); } diff --git a/tests/test_round_trip.rs b/tests/test_round_trip.rs index 3d06d9785a..9d459d9e1f 100644 --- a/tests/test_round_trip.rs +++ b/tests/test_round_trip.rs @@ -50,9 +50,9 @@ mod repo; #[test] fn test_round_trip() { - common::rayon_init(); + repo::rayon_init(); repo::clone_rust(); - let abort_after = common::abort_after(); + let abort_after = repo::abort_after(); if abort_after == 0 { panic!("skipping all round_trip tests"); } From 5acf65da7ffcc62a8e1960de0ceb2e4c8e76fef3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 18:58:59 -0700 Subject: [PATCH 50/66] Test parenthesis insertion against rustc repo --- tests/repo/mod.rs | 1 + tests/test_unparenthesize.rs | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tests/test_unparenthesize.rs diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index 2db48ee2fb..9c9088ae1a 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -386,6 +386,7 @@ pub fn edition(path: &Path) -> &'static str { } } +#[allow(dead_code)] pub fn abort_after() -> usize { match env::var("ABORT_AFTER_FAILURE") { Ok(s) => s.parse().expect("failed to parse ABORT_AFTER_FAILURE"), diff --git a/tests/test_unparenthesize.rs b/tests/test_unparenthesize.rs new file mode 100644 index 0000000000..69166aca20 --- /dev/null +++ b/tests/test_unparenthesize.rs @@ -0,0 +1,63 @@ +#![cfg(not(miri))] +#![allow(clippy::manual_assert, clippy::uninlined_format_args)] + +use quote::ToTokens as _; +use std::fs; +use std::mem; +use std::panic; +use std::path::Path; +use std::sync::atomic::{AtomicUsize, Ordering}; +use syn::visit_mut::{self, VisitMut}; +use syn::Expr; + +#[macro_use] +mod macros; + +mod repo; + +#[test] +fn test_unparenthesize() { + repo::rayon_init(); + repo::clone_rust(); + + let failed = AtomicUsize::new(0); + + repo::for_each_rust_file(|path| test(path, &failed)); + + let failed = failed.into_inner(); + if failed > 0 { + panic!("{} failures", failed); + } +} + +struct FlattenParens; + +impl VisitMut for FlattenParens { + fn visit_expr_mut(&mut self, e: &mut Expr) { + while let Expr::Paren(paren) = e { + *e = mem::replace(&mut *paren.expr, Expr::PLACEHOLDER); + } + visit_mut::visit_expr_mut(self, e); + } +} + +fn test(path: &Path, failed: &AtomicUsize) { + let content = fs::read_to_string(path).unwrap(); + + match panic::catch_unwind(|| -> syn::Result<()> { + let mut syntax_tree = syn::parse_file(&content)?; + FlattenParens.visit_file_mut(&mut syntax_tree); + syn::parse2::(syntax_tree.to_token_stream())?; + Ok(()) + }) { + Err(_) => { + errorf!("=== {}: syn panic\n", path.display()); + failed.fetch_add(1, Ordering::Relaxed); + } + Ok(Err(msg)) => { + errorf!("=== {}: syn failed to parse\n{:?}\n", path.display(), msg); + failed.fetch_add(1, Ordering::Relaxed); + } + Ok(Ok(())) => {} + } +} From 1f9e0823897a0975f16474a2f7ac776265ee0f15 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 21:21:02 -0700 Subject: [PATCH 51/66] Create a new precedence level for Expr::Let --- src/expr.rs | 22 ++-------------------- src/fixup.rs | 8 ++++++-- src/precedence.rs | 6 +++++- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/expr.rs b/src/expr.rs index 9493822f5a..80a4b1a1e0 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3253,30 +3253,12 @@ pub(crate) mod printing { }; // These cases require parenthesization independently of precedence. - match (&*e.left, &e.op) { + if let BinOp::Lt(_) | BinOp::Shl(_) = &e.op { // `x as i32 < y` has the parser thinking that `i32 < y` is the // beginning of a path type. It starts trying to parse `x as (i32 < // y ...` instead of `(x as i32) < ...`. We need to convince it // _not_ to do that. - (_, BinOp::Lt(_) | BinOp::Shl(_)) if classify::confusable_with_adjacent_lt(&e.left) => { - left_needs_group = true; - } - - // We are given `(let _ = a) OP b`. - // - // - When `OP <= LAnd` we should print `let _ = a OP b` to avoid - // redundant parens as the parser will interpret this as `(let _ = - // a) OP b`. - // - // - Otherwise, e.g. when we have `(let a = b) < c` in AST, parens - // are required since the parser would interpret `let a = b < c` - // as `let a = (b < c)`. To achieve this, we force parens. - #[cfg(feature = "full")] - (Expr::Let(_), _) if binop_prec > Precedence::And => { - left_needs_group = true; - } - - _ => {} + left_needs_group |= classify::confusable_with_adjacent_lt(&e.left); } print_subexpression( diff --git a/src/fixup.rs b/src/fixup.rs index ddee906fb5..536da4e499 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -239,7 +239,7 @@ impl FixupContext { /// "let chain". pub fn needs_group_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && classify::confusable_with_adjacent_block(expr) - || self.trailing_precedence(expr) <= Precedence::And + || self.trailing_precedence(expr) < Precedence::Let } /// Determines the effective precedence of a left subexpression. Some @@ -265,7 +265,11 @@ impl FixupContext { match expr { // Increase precedence of expressions that extend to the end of // current statement or group. - Expr::Break(_) | Expr::Closure(_) | Expr::Return(_) | Expr::Yield(_) => { + Expr::Break(_) + | Expr::Closure(_) + | Expr::Let(_) + | Expr::Return(_) + | Expr::Yield(_) => { return Precedence::Prefix; } Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, diff --git a/src/precedence.rs b/src/precedence.rs index 354ea90812..1a26f195db 100644 --- a/src/precedence.rs +++ b/src/precedence.rs @@ -19,6 +19,9 @@ pub(crate) enum Precedence { Or, // && And, + // let + #[cfg(feature = "printing")] + Let, // == != < > <= >= Compare, // | @@ -97,8 +100,9 @@ impl Precedence { Expr::Assign(_) => Precedence::Assign, Expr::Range(_) => Precedence::Range, Expr::Binary(e) => Precedence::of_binop(&e.op), + Expr::Let(_) => Precedence::Let, Expr::Cast(_) => Precedence::Cast, - Expr::Let(_) | Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, + Expr::Reference(_) | Expr::Unary(_) => Precedence::Prefix, Expr::Array(_) | Expr::Async(_) From 9809f716e3aa0b3223489860f29385afcd04b5f8 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 22:13:10 -0700 Subject: [PATCH 52/66] Incorporate parenthesization of casts into FixupContext --- src/classify.rs | 113 +++++++++++++-------------------------------- src/expr.rs | 45 +++++++++--------- src/fixup.rs | 66 +++++++++++++++++--------- src/lib.rs | 5 +- tests/test_expr.rs | 2 +- 5 files changed, 99 insertions(+), 132 deletions(-) diff --git a/src/classify.rs b/src/classify.rs index cc176d06dc..ab735f142c 100644 --- a/src/classify.rs +++ b/src/classify.rs @@ -3,11 +3,9 @@ use crate::generics::TypeParamBound; use crate::path::{Path, PathArguments}; use crate::punctuated::Punctuated; use crate::ty::{ReturnType, Type}; -#[cfg(feature = "full")] use proc_macro2::{Delimiter, TokenStream, TokenTree}; use std::ops::ControlFlow; -#[cfg(feature = "full")] pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { match expr { Expr::Macro(expr) => !expr.mac.delimiter.is_brace(), @@ -15,7 +13,6 @@ pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { } } -#[cfg(feature = "full")] pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { match expr { Expr::If(_) @@ -60,7 +57,7 @@ pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { } } -#[cfg(all(feature = "printing", feature = "full"))] +#[cfg(feature = "printing")] pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool { let mut stack = Vec::new(); @@ -146,84 +143,37 @@ pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool { } #[cfg(feature = "printing")] -pub(crate) fn confusable_with_adjacent_lt(mut expr: &Expr) -> bool { +pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool { loop { - match expr { - Expr::Binary(e) => expr = &e.right, - Expr::Cast(e) => return trailing_unparameterized_path(&e.ty), - Expr::Reference(e) => expr = &e.expr, - Expr::Unary(e) => expr = &e.expr, - - Expr::Array(_) - | Expr::Assign(_) - | Expr::Async(_) - | Expr::Await(_) - | Expr::Block(_) - | Expr::Break(_) - | Expr::Call(_) - | Expr::Closure(_) - | Expr::Const(_) - | Expr::Continue(_) - | Expr::Field(_) - | Expr::ForLoop(_) - | Expr::Group(_) - | Expr::If(_) - | Expr::Index(_) - | Expr::Infer(_) - | Expr::Let(_) - | Expr::Lit(_) - | Expr::Loop(_) - | Expr::Macro(_) - | Expr::Match(_) - | Expr::MethodCall(_) - | Expr::Paren(_) - | Expr::Path(_) - | Expr::Range(_) - | Expr::Repeat(_) - | Expr::Return(_) - | Expr::Struct(_) - | Expr::Try(_) - | Expr::TryBlock(_) - | Expr::Tuple(_) - | Expr::Unsafe(_) - | Expr::Verbatim(_) - | Expr::While(_) - | Expr::Yield(_) => return false, - } - } - - fn trailing_unparameterized_path(mut ty: &Type) -> bool { - loop { - match ty { - Type::BareFn(t) => match &t.output { - ReturnType::Default => return false, - ReturnType::Type(_, ret) => ty = ret, - }, - Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, - Type::Path(t) => match last_type_in_path(&t.path) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, - Type::Ptr(t) => ty = &t.elem, - Type::Reference(t) => ty = &t.elem, - Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { - ControlFlow::Break(trailing_path) => return trailing_path, - ControlFlow::Continue(t) => ty = t, - }, + match ty { + Type::BareFn(t) => match &t.output { + ReturnType::Default => return false, + ReturnType::Type(_, ret) => ty = ret, + }, + Type::ImplTrait(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Path(t) => match last_type_in_path(&t.path) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, + Type::Ptr(t) => ty = &t.elem, + Type::Reference(t) => ty = &t.elem, + Type::TraitObject(t) => match last_type_in_bounds(&t.bounds) { + ControlFlow::Break(trailing_path) => return trailing_path, + ControlFlow::Continue(t) => ty = t, + }, - Type::Array(_) - | Type::Group(_) - | Type::Infer(_) - | Type::Macro(_) - | Type::Never(_) - | Type::Paren(_) - | Type::Slice(_) - | Type::Tuple(_) - | Type::Verbatim(_) => return false, - } + Type::Array(_) + | Type::Group(_) + | Type::Infer(_) + | Type::Macro(_) + | Type::Never(_) + | Type::Paren(_) + | Type::Slice(_) + | Type::Tuple(_) + | Type::Verbatim(_) => return false, } } @@ -249,7 +199,7 @@ pub(crate) fn confusable_with_adjacent_lt(mut expr: &Expr) -> bool { } /// Whether the expression's first token is the label of a loop/block. -#[cfg(all(feature = "printing", feature = "full"))] +#[cfg(feature = "printing")] pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { loop { match expr { @@ -302,7 +252,6 @@ pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { } /// Whether the expression's last token is `}`. -#[cfg(feature = "full")] pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { loop { match expr { diff --git a/src/expr.rs b/src/expr.rs index 80a4b1a1e0..c130fa9285 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -2981,6 +2981,7 @@ pub(crate) mod printing { use crate::attr::Attribute; #[cfg(feature = "full")] use crate::attr::FilterAttrs; + #[cfg(feature = "full")] use crate::classify; #[cfg(feature = "full")] use crate::expr::{ @@ -2996,6 +2997,7 @@ pub(crate) mod printing { }; #[cfg(feature = "full")] use crate::fixup::FixupContext; + #[cfg(feature = "full")] use crate::op::BinOp; use crate::path; use crate::precedence::Precedence; @@ -3222,17 +3224,23 @@ pub(crate) mod printing { outer_attrs_to_tokens(&e.attrs, tokens); #[cfg(feature = "full")] - let left_fixup = fixup.leftmost_subexpression_with_begin_operator(match &e.op { - BinOp::Sub(_) - | BinOp::Mul(_) - | BinOp::And(_) - | BinOp::Or(_) - | BinOp::BitAnd(_) - | BinOp::BitOr(_) - | BinOp::Shl(_) - | BinOp::Lt(_) => true, - _ => false, - }); + let left_fixup = fixup.leftmost_subexpression_with_begin_operator( + match &e.op { + BinOp::Sub(_) + | BinOp::Mul(_) + | BinOp::And(_) + | BinOp::Or(_) + | BinOp::BitAnd(_) + | BinOp::BitOr(_) + | BinOp::Shl(_) + | BinOp::Lt(_) => true, + _ => false, + }, + match &e.op { + BinOp::Shl(_) | BinOp::Lt(_) => true, + _ => false, + }, + ); let left_prec = leading_precedence( &e.left, #[cfg(feature = "full")] @@ -3246,21 +3254,12 @@ pub(crate) mod printing { ); let binop_prec = Precedence::of_binop(&e.op); - let (mut left_needs_group, right_needs_group) = match binop_prec { + let (left_needs_group, right_needs_group) = match binop_prec { Precedence::Assign => (left_prec <= Precedence::Range, right_prec < binop_prec), Precedence::Compare => (left_prec <= binop_prec, right_prec <= binop_prec), _ => (left_prec < binop_prec, right_prec <= binop_prec), }; - // These cases require parenthesization independently of precedence. - if let BinOp::Lt(_) | BinOp::Shl(_) = &e.op { - // `x as i32 < y` has the parser thinking that `i32 < y` is the - // beginning of a path type. It starts trying to parse `x as (i32 < - // y ...` instead of `(x as i32) < ...`. We need to convince it - // _not_ to do that. - left_needs_group |= classify::confusable_with_adjacent_lt(&e.left); - } - print_subexpression( &e.left, left_needs_group, @@ -3341,7 +3340,7 @@ pub(crate) mod printing { Precedence::Unambiguous }; #[cfg(feature = "full")] - let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true); + let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false); let func_precedence = leading_precedence( &e.func, #[cfg(feature = "full")] @@ -3550,7 +3549,7 @@ pub(crate) mod printing { ) { outer_attrs_to_tokens(&e.attrs, tokens); #[cfg(feature = "full")] - let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true); + let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false); let obj_precedence = leading_precedence( &e.expr, #[cfg(feature = "full")] diff --git a/src/fixup.rs b/src/fixup.rs index 536da4e499..7292be6615 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -101,6 +101,15 @@ pub(crate) struct FixupContext { // let _ = return + 1; // no paren because '+' cannot begin expr // next_operator_can_begin_expr: bool, + + // This is the difference between: + // + // let _ = x as u8 + T; + // + // let _ = (x as u8) < T; + // + // Without parens, the latter would want to parse `u8 Self { FixupContext { next_operator_can_begin_expr, + next_operator_can_begin_generics, ..self.leftmost_subexpression() } } @@ -245,38 +257,48 @@ impl FixupContext { /// Determines the effective precedence of a left subexpression. Some /// expressions have lower precedence when adjacent to particular operators. pub fn leading_precedence(self, expr: &Expr) -> Precedence { - if self.next_operator_can_begin_expr { - match expr { - // Decrease precedence of value-less jumps when followed by an - // operator that would otherwise get interpreted as beginning a - // value for the jump. - Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) => return Precedence::Jump, - _ => {} + match expr { + // Decrease precedence of value-less jumps when followed by an + // operator that would otherwise get interpreted as beginning a + // value for the jump. + Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) + if self.next_operator_can_begin_expr => + { + Precedence::Jump + } + Expr::Cast(cast) + if self.next_operator_can_begin_generics + && classify::trailing_unparameterized_path(&cast.ty) => + { + Precedence::MIN } + _ => Precedence::of(expr), } - Precedence::of(expr) } /// Determines the effective precedence of a right subexpression. Some /// expressions have higher precedence on the right side of a binary /// operator than on the left. pub fn trailing_precedence(self, expr: &Expr) -> Precedence { - if !self.parenthesize_exterior_jump { - match expr { - // Increase precedence of expressions that extend to the end of - // current statement or group. - Expr::Break(_) - | Expr::Closure(_) - | Expr::Let(_) - | Expr::Return(_) - | Expr::Yield(_) => { - return Precedence::Prefix; - } - Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, - _ => {} + match expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. + Expr::Break(_) | Expr::Closure(_) | Expr::Let(_) | Expr::Return(_) | Expr::Yield(_) + if !self.parenthesize_exterior_jump => + { + Precedence::Prefix + } + Expr::Range(e) if e.start.is_none() && !self.parenthesize_exterior_jump => { + Precedence::Prefix + } + Expr::Cast(cast) + if self.next_operator_can_begin_generics + && classify::trailing_unparameterized_path(&cast.ty) => + { + Precedence::MIN } + _ => Precedence::of(expr), } - Precedence::of(expr) } } diff --git a/src/lib.rs b/src/lib.rs index 96596844a3..1ecf817f5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -329,10 +329,7 @@ mod bigint; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub mod buffer; -#[cfg(any( - all(feature = "parsing", feature = "full"), - all(feature = "printing", any(feature = "full", feature = "derive")), -))] +#[cfg(all(any(feature = "parsing", feature = "printing"), feature = "full"))] mod classify; mod custom_keyword; diff --git a/tests/test_expr.rs b/tests/test_expr.rs index 11d0f86c50..d20cce8d6a 100644 --- a/tests/test_expr.rs +++ b/tests/test_expr.rs @@ -660,7 +660,7 @@ fn test_fixup() { quote! { 0 + (0 + 0) }, quote! { (a = b) = c }, quote! { (x as i32) < 0 }, - quote! { (1 + x as i32) < 0 }, + quote! { 1 + (x as i32) < 0 }, quote! { (1 + 1).abs() }, quote! { (lo..hi)[..] }, quote! { (a..b)..(c..d) }, From d47e532913bb9138cc47a6a3756aeead9ad2d08a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 6 Jul 2024 23:15:28 -0700 Subject: [PATCH 53/66] Rearrange logic of FixupContext precedence methods --- src/fixup.rs | 56 ++++++++++++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/fixup.rs b/src/fixup.rs index 7292be6615..b8605a7d17 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -257,48 +257,48 @@ impl FixupContext { /// Determines the effective precedence of a left subexpression. Some /// expressions have lower precedence when adjacent to particular operators. pub fn leading_precedence(self, expr: &Expr) -> Precedence { - match expr { + if self.next_operator_can_begin_expr { // Decrease precedence of value-less jumps when followed by an // operator that would otherwise get interpreted as beginning a // value for the jump. - Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) - if self.next_operator_can_begin_expr => - { - Precedence::Jump + if let Expr::Break(_) | Expr::Return(_) | Expr::Yield(_) = expr { + return Precedence::Jump; } - Expr::Cast(cast) - if self.next_operator_can_begin_generics - && classify::trailing_unparameterized_path(&cast.ty) => - { - Precedence::MIN - } - _ => Precedence::of(expr), } + self.precedence(expr) } /// Determines the effective precedence of a right subexpression. Some /// expressions have higher precedence on the right side of a binary /// operator than on the left. pub fn trailing_precedence(self, expr: &Expr) -> Precedence { - match expr { - // Increase precedence of expressions that extend to the end of - // current statement or group. - Expr::Break(_) | Expr::Closure(_) | Expr::Let(_) | Expr::Return(_) | Expr::Yield(_) - if !self.parenthesize_exterior_jump => - { - Precedence::Prefix - } - Expr::Range(e) if e.start.is_none() && !self.parenthesize_exterior_jump => { - Precedence::Prefix + if !self.parenthesize_exterior_jump { + match expr { + // Increase precedence of expressions that extend to the end of + // current statement or group. + Expr::Break(_) + | Expr::Closure(_) + | Expr::Let(_) + | Expr::Return(_) + | Expr::Yield(_) => { + return Precedence::Prefix; + } + Expr::Range(e) if e.start.is_none() => return Precedence::Prefix, + _ => {} } - Expr::Cast(cast) - if self.next_operator_can_begin_generics - && classify::trailing_unparameterized_path(&cast.ty) => - { - Precedence::MIN + } + self.precedence(expr) + } + + fn precedence(self, expr: &Expr) -> Precedence { + if self.next_operator_can_begin_generics { + if let Expr::Cast(cast) = expr { + if classify::trailing_unparameterized_path(&cast.ty) { + return Precedence::MIN; + } } - _ => Precedence::of(expr), } + Precedence::of(expr) } } From 628e2f7003d17ae0c02d0da076577001e62015a3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 7 Jul 2024 18:20:51 -0700 Subject: [PATCH 54/66] Ignore needless_update clippy lint With #[cfg...], sometimes all the fields containing updates are configured out and that's fine. warning: struct update has no effect, all the fields in the struct have already been specified --> src/fixup.rs:235:15 | 235 | ..self.leftmost_subexpression() | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_update = note: `#[warn(clippy::needless_update)]` on by default --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 1ecf817f5a..5390f2edf3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -285,6 +285,7 @@ clippy::must_use_candidate, clippy::needless_doctest_main, clippy::needless_pass_by_value, + clippy::needless_update, clippy::never_loop, clippy::range_plus_one, clippy::redundant_else, From 678dbc2e50904de7b80f10f4d355be5536a8bceb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 7 Jul 2024 18:34:53 -0700 Subject: [PATCH 55/66] Update test suite to nightly-2024-07-08 --- tests/common/eq.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/common/eq.rs b/tests/common/eq.rs index 4ce3f05027..11d391d80e 100644 --- a/tests/common/eq.rs +++ b/tests/common/eq.rs @@ -166,7 +166,7 @@ use rustc_ast::token::{ self, CommentKind, Delimiter, IdentIsRaw, Lit, Nonterminal, Token, TokenKind, }; use rustc_ast::tokenstream::{ - AttrTokenStream, AttrTokenTree, AttributesData, DelimSpacing, DelimSpan, LazyAttrTokenStream, + AttrTokenStream, AttrTokenTree, AttrsTarget, DelimSpacing, DelimSpan, LazyAttrTokenStream, Spacing, TokenStream, TokenTree, }; use rustc_data_structures::packed::Pu128; @@ -470,7 +470,7 @@ spanless_eq_struct!(AssocItemConstraint; id ident gen_args kind span); spanless_eq_struct!(AttrItem; unsafety path args tokens); spanless_eq_struct!(AttrTokenStream; 0); spanless_eq_struct!(Attribute; kind id style span); -spanless_eq_struct!(AttributesData; attrs tokens); +spanless_eq_struct!(AttrsTarget; attrs tokens); spanless_eq_struct!(BareFnTy; safety ext generic_params decl decl_span); spanless_eq_struct!(BindingMode; 0 1); spanless_eq_struct!(Block; stmts id rules span tokens could_be_bare_literal); @@ -546,7 +546,7 @@ spanless_eq_enum!(AssocItemKind; Const(0) Fn(0) Type(0) MacCall(0) Delegation(0) spanless_eq_enum!(AttrArgs; Empty Delimited(0) Eq(0 1)); spanless_eq_enum!(AttrArgsEq; Ast(0) Hir(0)); spanless_eq_enum!(AttrStyle; Outer Inner); -spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) Attributes(0)); +spanless_eq_enum!(AttrTokenTree; Token(0 1) Delimited(0 1 2 3) AttrsTarget(0)); spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt); spanless_eq_enum!(BlockCheckMode; Default Unsafe(0)); spanless_eq_enum!(BorrowKind; Ref Raw); From f1daf234e942ffda27ed45ec67aa6cd984081c2a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 7 Jul 2024 17:56:56 -0700 Subject: [PATCH 56/66] Enable expression fixups in 'derive' mode --- src/classify.rs | 14 ++- src/expr.rs | 223 ++++++++++++------------------------------------ src/fixup.rs | 38 ++++++++- src/lib.rs | 7 +- 4 files changed, 108 insertions(+), 174 deletions(-) diff --git a/src/classify.rs b/src/classify.rs index ab735f142c..42732e6d8d 100644 --- a/src/classify.rs +++ b/src/classify.rs @@ -1,11 +1,19 @@ +#[cfg(feature = "full")] use crate::expr::Expr; +#[cfg(any(feature = "printing", feature = "full"))] use crate::generics::TypeParamBound; +#[cfg(any(feature = "printing", feature = "full"))] use crate::path::{Path, PathArguments}; +#[cfg(any(feature = "printing", feature = "full"))] use crate::punctuated::Punctuated; +#[cfg(any(feature = "printing", feature = "full"))] use crate::ty::{ReturnType, Type}; +#[cfg(feature = "full")] use proc_macro2::{Delimiter, TokenStream, TokenTree}; +#[cfg(any(feature = "printing", feature = "full"))] use std::ops::ControlFlow; +#[cfg(feature = "full")] pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { match expr { Expr::Macro(expr) => !expr.mac.delimiter.is_brace(), @@ -13,6 +21,7 @@ pub(crate) fn requires_semi_to_be_stmt(expr: &Expr) -> bool { } } +#[cfg(feature = "full")] pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { match expr { Expr::If(_) @@ -57,7 +66,7 @@ pub(crate) fn requires_comma_to_be_match_arm(expr: &Expr) -> bool { } } -#[cfg(feature = "printing")] +#[cfg(all(feature = "printing", feature = "full"))] pub(crate) fn confusable_with_adjacent_block(mut expr: &Expr) -> bool { let mut stack = Vec::new(); @@ -199,7 +208,7 @@ pub(crate) fn trailing_unparameterized_path(mut ty: &Type) -> bool { } /// Whether the expression's first token is the label of a loop/block. -#[cfg(feature = "printing")] +#[cfg(all(feature = "printing", feature = "full"))] pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { loop { match expr { @@ -252,6 +261,7 @@ pub(crate) fn expr_leading_label(mut expr: &Expr) -> bool { } /// Whether the expression's last token is `}`. +#[cfg(feature = "full")] pub(crate) fn expr_trailing_brace(mut expr: &Expr) -> bool { loop { match expr { diff --git a/src/expr.rs b/src/expr.rs index c130fa9285..e4a7b0e1c1 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -2995,9 +2995,7 @@ pub(crate) mod printing { ExprMethodCall, ExprParen, ExprPath, ExprReference, ExprStruct, ExprUnary, FieldValue, Index, Member, }; - #[cfg(feature = "full")] use crate::fixup::FixupContext; - #[cfg(feature = "full")] use crate::op::BinOp; use crate::path; use crate::precedence::Precedence; @@ -3034,13 +3032,9 @@ pub(crate) mod printing { expr: &Expr, needs_group: bool, tokens: &mut TokenStream, - #[cfg(feature = "full")] mut fixup: FixupContext, + mut fixup: FixupContext, ) { - #[cfg(not(feature = "full"))] - let do_print_expr = |tokens: &mut TokenStream| expr.to_tokens(tokens); - - #[cfg(feature = "full")] - let do_print_expr = { + if needs_group { // If we are surrounding the whole cond in parentheses, such as: // // if (return Struct {}) {} @@ -3052,11 +3046,10 @@ pub(crate) mod printing { // // if x == (Struct {}) {} // - if needs_group { - fixup = FixupContext::NONE; - } - |tokens: &mut TokenStream| print_expr(expr, tokens, fixup) - }; + fixup = FixupContext::NONE; + } + + let do_print_expr = |tokens: &mut TokenStream| print_expr(expr, tokens, fixup); if needs_group { token::Paren::default().surround(tokens, do_print_expr); @@ -3065,20 +3058,26 @@ pub(crate) mod printing { } } - #[cfg(feature = "full")] pub(crate) fn print_expr(expr: &Expr, tokens: &mut TokenStream, mut fixup: FixupContext) { + #[cfg(feature = "full")] let needs_group = fixup.would_cause_statement_boundary(expr); + #[cfg(not(feature = "full"))] + let needs_group = false; + if needs_group { fixup = FixupContext::NONE; } let do_print_expr = |tokens: &mut TokenStream| match expr { Expr::Array(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Assign(e) => print_expr_assign(e, tokens, fixup), Expr::Async(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Await(e) => print_expr_await(e, tokens, fixup), Expr::Binary(e) => print_expr_binary(e, tokens, fixup), Expr::Block(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Break(e) => print_expr_break(e, tokens, fixup), Expr::Call(e) => print_expr_call(e, tokens, fixup), Expr::Cast(e) => print_expr_cast(e, tokens, fixup), @@ -3089,8 +3088,10 @@ pub(crate) mod printing { Expr::ForLoop(e) => e.to_tokens(tokens), Expr::Group(e) => e.to_tokens(tokens), Expr::If(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Index(e) => print_expr_index(e, tokens, fixup), Expr::Infer(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Let(e) => print_expr_let(e, tokens, fixup), Expr::Lit(e) => e.to_tokens(tokens), Expr::Loop(e) => e.to_tokens(tokens), @@ -3099,11 +3100,14 @@ pub(crate) mod printing { Expr::MethodCall(e) => print_expr_method_call(e, tokens, fixup), Expr::Paren(e) => e.to_tokens(tokens), Expr::Path(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Range(e) => print_expr_range(e, tokens, fixup), Expr::Reference(e) => print_expr_reference(e, tokens, fixup), Expr::Repeat(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Return(e) => print_expr_return(e, tokens, fixup), Expr::Struct(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Try(e) => print_expr_try(e, tokens, fixup), Expr::TryBlock(e) => e.to_tokens(tokens), Expr::Tuple(e) => e.to_tokens(tokens), @@ -3111,7 +3115,11 @@ pub(crate) mod printing { Expr::Unsafe(e) => e.to_tokens(tokens), Expr::Verbatim(e) => e.to_tokens(tokens), Expr::While(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Yield(e) => print_expr_yield(e, tokens, fixup), + + #[cfg(not(feature = "full"))] + _ => unreachable!(), }; if needs_group { @@ -3121,20 +3129,6 @@ pub(crate) mod printing { } } - fn leading_precedence(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { - #[cfg(feature = "full")] - return fixup.leading_precedence(e); - #[cfg(not(feature = "full"))] - return Precedence::of(e); - } - - fn trailing_precedence(e: &Expr, #[cfg(feature = "full")] fixup: FixupContext) -> Precedence { - #[cfg(feature = "full")] - return fixup.trailing_precedence(e); - #[cfg(not(feature = "full"))] - return Precedence::of(e); - } - #[cfg(feature = "full")] #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprArray { @@ -3166,7 +3160,7 @@ pub(crate) mod printing { e.eq_token.to_tokens(tokens); print_subexpression( &e.right, - trailing_precedence(&e.right, fixup) < Precedence::Assign, + fixup.trailing_precedence(&e.right) < Precedence::Assign, tokens, fixup.subsequent_subexpression(), ); @@ -3207,24 +3201,15 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprBinary { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_binary( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_binary(self, tokens, FixupContext::NONE); } } - fn print_expr_binary( - e: &ExprBinary, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_binary(e: &ExprBinary, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); - #[cfg(feature = "full")] let left_fixup = fixup.leftmost_subexpression_with_begin_operator( + #[cfg(feature = "full")] match &e.op { BinOp::Sub(_) | BinOp::Mul(_) @@ -3241,38 +3226,22 @@ pub(crate) mod printing { _ => false, }, ); - let left_prec = leading_precedence( - &e.left, - #[cfg(feature = "full")] - left_fixup, - ); - - let right_prec = trailing_precedence( - &e.right, - #[cfg(feature = "full")] - fixup, - ); let binop_prec = Precedence::of_binop(&e.op); + let left_prec = left_fixup.leading_precedence(&e.left); + let right_prec = fixup.trailing_precedence(&e.right); let (left_needs_group, right_needs_group) = match binop_prec { Precedence::Assign => (left_prec <= Precedence::Range, right_prec < binop_prec), Precedence::Compare => (left_prec <= binop_prec, right_prec <= binop_prec), _ => (left_prec < binop_prec, right_prec <= binop_prec), }; - print_subexpression( - &e.left, - left_needs_group, - tokens, - #[cfg(feature = "full")] - left_fixup, - ); + print_subexpression(&e.left, left_needs_group, tokens, left_fixup); e.op.to_tokens(tokens); print_subexpression( &e.right, right_needs_group, tokens, - #[cfg(feature = "full")] fixup.subsequent_subexpression(), ); } @@ -3318,20 +3287,11 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprCall { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_call( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_call(self, tokens, FixupContext::NONE); } } - fn print_expr_call( - e: &ExprCall, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_call(e: &ExprCall, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); let call_precedence = if let Expr::Field(_) = &*e.func { @@ -3339,18 +3299,15 @@ pub(crate) mod printing { } else { Precedence::Unambiguous }; - #[cfg(feature = "full")] - let func_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false); - let func_precedence = leading_precedence( - &e.func, + let func_fixup = fixup.leftmost_subexpression_with_begin_operator( #[cfg(feature = "full")] - func_fixup, + true, + false, ); print_subexpression( &e.func, - func_precedence < call_precedence, + func_fixup.leading_precedence(&e.func) < call_precedence, tokens, - #[cfg(feature = "full")] func_fixup, ); @@ -3362,26 +3319,16 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprCast { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_cast( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_cast(self, tokens, FixupContext::NONE); } } - fn print_expr_cast( - e: &ExprCast, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_cast(e: &ExprCast, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.expr, Precedence::of(&e.expr) < Precedence::Cast, tokens, - #[cfg(feature = "full")] fixup.leftmost_subexpression(), ); e.as_token.to_tokens(tokens); @@ -3438,26 +3385,16 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprField { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_field( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_field(self, tokens, FixupContext::NONE); } } - fn print_expr_field( - e: &ExprField, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_field(e: &ExprField, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.base, Precedence::of(&e.base) < Precedence::Unambiguous, tokens, - #[cfg(feature = "full")] fixup.leftmost_subexpression_with_dot(), ); e.dot_token.to_tokens(tokens); @@ -3533,33 +3470,21 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprIndex { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_index( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_index(self, tokens, FixupContext::NONE); } } - fn print_expr_index( - e: &ExprIndex, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_index(e: &ExprIndex, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); - #[cfg(feature = "full")] - let obj_fixup = fixup.leftmost_subexpression_with_begin_operator(true, false); - let obj_precedence = leading_precedence( - &e.expr, + let obj_fixup = fixup.leftmost_subexpression_with_begin_operator( #[cfg(feature = "full")] - obj_fixup, + true, + false, ); print_subexpression( &e.expr, - obj_precedence < Precedence::Unambiguous, + obj_fixup.leading_precedence(&e.expr) < Precedence::Unambiguous, tokens, - #[cfg(feature = "full")] obj_fixup, ); e.bracket_token.surround(tokens, |tokens| { @@ -3656,26 +3581,16 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprMethodCall { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_method_call( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_method_call(self, tokens, FixupContext::NONE); } } - fn print_expr_method_call( - e: &ExprMethodCall, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_method_call(e: &ExprMethodCall, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); print_subexpression( &e.receiver, Precedence::of(&e.receiver) < Precedence::Unambiguous, tokens, - #[cfg(feature = "full")] fixup.leftmost_subexpression_with_dot(), ); e.dot_token.to_tokens(tokens); @@ -3727,7 +3642,7 @@ pub(crate) mod printing { if let Some(end) = &e.end { print_subexpression( end, - trailing_precedence(end, fixup) <= Precedence::Range, + fixup.trailing_precedence(end) <= Precedence::Range, tokens, fixup.subsequent_subexpression(), ); @@ -3737,33 +3652,18 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprReference { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_reference( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_reference(self, tokens, FixupContext::NONE); } } - fn print_expr_reference( - e: &ExprReference, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_reference(e: &ExprReference, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); e.and_token.to_tokens(tokens); e.mutability.to_tokens(tokens); - let prec = trailing_precedence( - &e.expr, - #[cfg(feature = "full")] - fixup, - ); print_subexpression( &e.expr, - prec < Precedence::Prefix, + fixup.trailing_precedence(&e.expr) < Precedence::Prefix, tokens, - #[cfg(feature = "full")] fixup.subsequent_subexpression(), ); } @@ -3864,32 +3764,17 @@ pub(crate) mod printing { #[cfg_attr(docsrs, doc(cfg(feature = "printing")))] impl ToTokens for ExprUnary { fn to_tokens(&self, tokens: &mut TokenStream) { - print_expr_unary( - self, - tokens, - #[cfg(feature = "full")] - FixupContext::NONE, - ); + print_expr_unary(self, tokens, FixupContext::NONE); } } - fn print_expr_unary( - e: &ExprUnary, - tokens: &mut TokenStream, - #[cfg(feature = "full")] fixup: FixupContext, - ) { + fn print_expr_unary(e: &ExprUnary, tokens: &mut TokenStream, fixup: FixupContext) { outer_attrs_to_tokens(&e.attrs, tokens); e.op.to_tokens(tokens); - let prec = trailing_precedence( - &e.expr, - #[cfg(feature = "full")] - fixup, - ); print_subexpression( &e.expr, - prec < Precedence::Prefix, + fixup.trailing_precedence(&e.expr) < Precedence::Prefix, tokens, - #[cfg(feature = "full")] fixup.subsequent_subexpression(), ); } diff --git a/src/fixup.rs b/src/fixup.rs index b8605a7d17..58ed9e73d4 100644 --- a/src/fixup.rs +++ b/src/fixup.rs @@ -13,6 +13,7 @@ pub(crate) struct FixupContext { // // match x {}; // not when its own statement // + #[cfg(feature = "full")] stmt: bool, // This is the difference between: @@ -44,6 +45,7 @@ pub(crate) struct FixupContext { // Example: `$match;` // // No parentheses required. + #[cfg(feature = "full")] leftmost_subexpression_in_stmt: bool, // Print expression such that it can be parsed as a match arm. @@ -59,6 +61,7 @@ pub(crate) struct FixupContext { // _ => m! {} - 1, // binary subtraction operator // } // + #[cfg(feature = "full")] match_arm: bool, // This is almost equivalent to `leftmost_subexpression_in_stmt`, other than @@ -74,6 +77,7 @@ pub(crate) struct FixupContext { // _ => m! {} - 1, // no parens // } // + #[cfg(feature = "full")] leftmost_subexpression_in_match_arm: bool, // This is the difference between: @@ -84,6 +88,7 @@ pub(crate) struct FixupContext { // () if let _ = Struct {} => {} // no parens // } // + #[cfg(feature = "full")] parenthesize_exterior_struct_lit: bool, // This is the difference between: @@ -92,6 +97,7 @@ pub(crate) struct FixupContext { // // let _ = 1 + (return 1) + 1; // needs parens // + #[cfg(feature = "full")] parenthesize_exterior_jump: bool, // This is the difference between: @@ -100,6 +106,7 @@ pub(crate) struct FixupContext { // // let _ = return + 1; // no paren because '+' cannot begin expr // + #[cfg(feature = "full")] next_operator_can_begin_expr: bool, // This is the difference between: @@ -116,18 +123,26 @@ impl FixupContext { /// The default amount of fixing is minimal fixing. Fixups should be turned /// on in a targeted fashion where needed. pub const NONE: Self = FixupContext { + #[cfg(feature = "full")] stmt: false, + #[cfg(feature = "full")] leftmost_subexpression_in_stmt: false, + #[cfg(feature = "full")] match_arm: false, + #[cfg(feature = "full")] leftmost_subexpression_in_match_arm: false, + #[cfg(feature = "full")] parenthesize_exterior_struct_lit: false, + #[cfg(feature = "full")] parenthesize_exterior_jump: false, + #[cfg(feature = "full")] next_operator_can_begin_expr: false, next_operator_can_begin_generics: false, }; /// Create the initial fixup for printing an expression in statement /// position. + #[cfg(feature = "full")] pub fn new_stmt() -> Self { FixupContext { stmt: true, @@ -137,6 +152,7 @@ impl FixupContext { /// Create the initial fixup for printing an expression as the right-hand /// side of a match arm. + #[cfg(feature = "full")] pub fn new_match_arm() -> Self { FixupContext { match_arm: true, @@ -148,6 +164,7 @@ impl FixupContext { /// of an `if` or `while`. There are a few other positions which are /// grammatically equivalent and also use this, such as the iterator /// expression in `for` and the scrutinee in `match`. + #[cfg(feature = "full")] pub fn new_condition() -> Self { FixupContext { parenthesize_exterior_struct_lit: true, @@ -168,11 +185,16 @@ impl FixupContext { /// `-$a` nor `[$a]` have one. pub fn leftmost_subexpression(self) -> Self { FixupContext { + #[cfg(feature = "full")] stmt: false, + #[cfg(feature = "full")] leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt, + #[cfg(feature = "full")] match_arm: false, + #[cfg(feature = "full")] leftmost_subexpression_in_match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + #[cfg(feature = "full")] parenthesize_exterior_jump: true, ..self } @@ -184,10 +206,15 @@ impl FixupContext { /// subexpressions. pub fn leftmost_subexpression_with_dot(self) -> Self { FixupContext { + #[cfg(feature = "full")] stmt: self.stmt || self.leftmost_subexpression_in_stmt, + #[cfg(feature = "full")] leftmost_subexpression_in_stmt: false, + #[cfg(feature = "full")] match_arm: self.match_arm || self.leftmost_subexpression_in_match_arm, + #[cfg(feature = "full")] leftmost_subexpression_in_match_arm: false, + #[cfg(feature = "full")] parenthesize_exterior_jump: true, ..self } @@ -198,10 +225,11 @@ impl FixupContext { /// first token of an expression. pub fn leftmost_subexpression_with_begin_operator( self, - next_operator_can_begin_expr: bool, + #[cfg(feature = "full")] next_operator_can_begin_expr: bool, next_operator_can_begin_generics: bool, ) -> Self { FixupContext { + #[cfg(feature = "full")] next_operator_can_begin_expr, next_operator_can_begin_generics, ..self.leftmost_subexpression() @@ -218,9 +246,13 @@ impl FixupContext { /// `$a.f($b)`. pub fn subsequent_subexpression(self) -> Self { FixupContext { + #[cfg(feature = "full")] stmt: false, + #[cfg(feature = "full")] leftmost_subexpression_in_stmt: false, + #[cfg(feature = "full")] match_arm: false, + #[cfg(feature = "full")] leftmost_subexpression_in_match_arm: false, ..self } @@ -231,6 +263,7 @@ impl FixupContext { /// /// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has /// examples. + #[cfg(feature = "full")] pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool { (self.leftmost_subexpression_in_stmt && !classify::requires_semi_to_be_stmt(expr)) || ((self.stmt || self.leftmost_subexpression_in_stmt) && matches!(expr, Expr::Let(_))) @@ -249,6 +282,7 @@ impl FixupContext { /// /// - `true && false`, because otherwise this would be misinterpreted as a /// "let chain". + #[cfg(feature = "full")] pub fn needs_group_as_let_scrutinee(self, expr: &Expr) -> bool { self.parenthesize_exterior_struct_lit && classify::confusable_with_adjacent_block(expr) || self.trailing_precedence(expr) < Precedence::Let @@ -257,6 +291,7 @@ impl FixupContext { /// Determines the effective precedence of a left subexpression. Some /// expressions have lower precedence when adjacent to particular operators. pub fn leading_precedence(self, expr: &Expr) -> Precedence { + #[cfg(feature = "full")] if self.next_operator_can_begin_expr { // Decrease precedence of value-less jumps when followed by an // operator that would otherwise get interpreted as beginning a @@ -272,6 +307,7 @@ impl FixupContext { /// expressions have higher precedence on the right side of a binary /// operator than on the left. pub fn trailing_precedence(self, expr: &Expr) -> Precedence { + #[cfg(feature = "full")] if !self.parenthesize_exterior_jump { match expr { // Increase precedence of expressions that extend to the end of diff --git a/src/lib.rs b/src/lib.rs index 5390f2edf3..dce19ca554 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -330,7 +330,10 @@ mod bigint; #[cfg_attr(docsrs, doc(cfg(feature = "parsing")))] pub mod buffer; -#[cfg(all(any(feature = "parsing", feature = "printing"), feature = "full"))] +#[cfg(any( + all(feature = "parsing", feature = "full"), + all(feature = "printing", any(feature = "full", feature = "derive")), +))] mod classify; mod custom_keyword; @@ -384,7 +387,7 @@ mod file; #[cfg_attr(docsrs, doc(cfg(feature = "full")))] pub use crate::file::File; -#[cfg(all(feature = "full", feature = "printing"))] +#[cfg(all(any(feature = "full", feature = "derive"), feature = "printing"))] mod fixup; #[cfg(any(feature = "full", feature = "derive"))] From 935c1e1817d411a02d09d2315ed533df12f70ace Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 7 Jul 2024 18:43:15 -0700 Subject: [PATCH 57/66] Configure out more full-only expression kinds in print_expr --- src/expr.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/expr.rs b/src/expr.rs index e4a7b0e1c1..62ebdad857 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -3069,33 +3069,44 @@ pub(crate) mod printing { } let do_print_expr = |tokens: &mut TokenStream| match expr { + #[cfg(feature = "full")] Expr::Array(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Assign(e) => print_expr_assign(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Async(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Await(e) => print_expr_await(e, tokens, fixup), Expr::Binary(e) => print_expr_binary(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Block(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Break(e) => print_expr_break(e, tokens, fixup), Expr::Call(e) => print_expr_call(e, tokens, fixup), Expr::Cast(e) => print_expr_cast(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Closure(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Const(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Continue(e) => e.to_tokens(tokens), Expr::Field(e) => print_expr_field(e, tokens, fixup), + #[cfg(feature = "full")] Expr::ForLoop(e) => e.to_tokens(tokens), Expr::Group(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::If(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Index(e) => print_expr_index(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Infer(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Let(e) => print_expr_let(e, tokens, fixup), Expr::Lit(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Loop(e) => e.to_tokens(tokens), Expr::Macro(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Match(e) => e.to_tokens(tokens), Expr::MethodCall(e) => print_expr_method_call(e, tokens, fixup), Expr::Paren(e) => e.to_tokens(tokens), @@ -3103,17 +3114,22 @@ pub(crate) mod printing { #[cfg(feature = "full")] Expr::Range(e) => print_expr_range(e, tokens, fixup), Expr::Reference(e) => print_expr_reference(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Repeat(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Return(e) => print_expr_return(e, tokens, fixup), Expr::Struct(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Try(e) => print_expr_try(e, tokens, fixup), + #[cfg(feature = "full")] Expr::TryBlock(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::Tuple(e) => e.to_tokens(tokens), Expr::Unary(e) => print_expr_unary(e, tokens, fixup), + #[cfg(feature = "full")] Expr::Unsafe(e) => e.to_tokens(tokens), Expr::Verbatim(e) => e.to_tokens(tokens), + #[cfg(feature = "full")] Expr::While(e) => e.to_tokens(tokens), #[cfg(feature = "full")] Expr::Yield(e) => print_expr_yield(e, tokens, fixup), From 5c67e2689791db44258d99402ae6d05b1898d9a3 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 8 Jul 2024 11:34:35 -0700 Subject: [PATCH 58/66] Release 2.0.70 --- 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 0aa7899ee0..900df89b9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.69" +version = "2.0.70" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index dce19ca554..2724c8e46a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.69")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.70")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 0889f26734..66b814e269 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.69", + "version": "2.0.70", "types": [ { "ident": "Abi", From dd7e269f577dc33bcf92bec2583f7e53609081fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Enrique=20Mu=C3=B1oz=20Mart=C3=ADn?= Date: Fri, 12 Jul 2024 09:36:19 +0200 Subject: [PATCH 59/66] Remove mut from Puntuated::get() --- src/punctuated.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/punctuated.rs b/src/punctuated.rs index ab2e7d9879..b26ed647f1 100644 --- a/src/punctuated.rs +++ b/src/punctuated.rs @@ -93,7 +93,7 @@ impl Punctuated { } /// Borrows the element at the given index. - pub fn get(&mut self, index: usize) -> Option<&T> { + pub fn get(&self, index: usize) -> Option<&T> { if let Some((value, _punct)) = self.inner.get(index) { Some(value) } else if index == self.inner.len() { From f34dc7bb53185a11f3aa45fc691488547c8c76ee Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 12 Jul 2024 06:02:52 -0700 Subject: [PATCH 60/66] Release 2.0.71 --- 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 900df89b9a..d37acd143d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.70" +version = "2.0.71" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 2724c8e46a..61dfd18bbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.70")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.71")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 66b814e269..4b4d0e3f48 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.70", + "version": "2.0.71", "types": [ { "ident": "Abi", From bed32d23ce08bea0a0be2491427605402b3fce9b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 13 Jul 2024 15:16:15 -0400 Subject: [PATCH 61/66] Parse use<> precise capturing as Verbatim --- src/generics.rs | 21 +++++++++++++++++++++ tests/test_ty.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/src/generics.rs b/src/generics.rs index c755151d4b..f2136aa5d8 100644 --- a/src/generics.rs +++ b/src/generics.rs @@ -772,6 +772,27 @@ pub(crate) mod parsing { let begin = input.fork(); + if cfg!(feature = "full") && input.peek(Token![use]) { + input.parse::()?; + input.parse::()?; + while !input.peek(Token![>]) { + if input.peek(Lifetime) { + input.parse::()?; + } else if input.peek(Ident) { + input.parse::()?; + } else { + break; + } + if input.peek(Token![,]) { + input.parse::()?; + } else { + break; + } + } + input.parse::]>()?; + return Ok(TypeParamBound::Verbatim(verbatim::between(&begin, input))); + } + let content; let (paren_token, content) = if input.peek(token::Paren) { (Some(parenthesized!(content in input)), &content) diff --git a/tests/test_ty.rs b/tests/test_ty.rs index f1ced9ea37..d85479de45 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -395,3 +395,50 @@ fn test_tuple_comma() { } "###); } + +#[test] +fn test_impl_trait_use() { + let tokens = quote! { + impl Sized + use<'_, 'a, A, Test> + }; + + snapshot!(tokens as Type, @r###" + Type::ImplTrait { + bounds: [ + TypeParamBound::Trait(TraitBound { + path: Path { + segments: [ + PathSegment { + ident: "Sized", + }, + ], + }, + }), + Token![+], + TypeParamBound::Verbatim(`use < '_ , 'a , A , Test >`), + ], + } + "###); + + let trailing = quote! { + impl Sized + use<'_,> + }; + + snapshot!(trailing as Type, @r###" + Type::ImplTrait { + bounds: [ + TypeParamBound::Trait(TraitBound { + path: Path { + segments: [ + PathSegment { + ident: "Sized", + }, + ], + }, + }), + Token![+], + TypeParamBound::Verbatim(`use < '_ , >`), + ], + } + "###); +} From 788f8cb9e15608f333f4bdd843c2cd10774cb56f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 21 Jul 2024 15:49:02 -0700 Subject: [PATCH 62/66] Improve errors on unexpected token in precise capture bound --- src/generics.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/generics.rs b/src/generics.rs index f2136aa5d8..9a5d9b3bc3 100644 --- a/src/generics.rs +++ b/src/generics.rs @@ -775,18 +775,24 @@ pub(crate) mod parsing { if cfg!(feature = "full") && input.peek(Token![use]) { input.parse::()?; input.parse::()?; - while !input.peek(Token![>]) { - if input.peek(Lifetime) { + loop { + let lookahead = input.lookahead1(); + if lookahead.peek(Lifetime) { input.parse::()?; - } else if input.peek(Ident) { + } else if lookahead.peek(Ident) { input.parse::()?; - } else { + } else if lookahead.peek(Token![>]) { break; + } else { + return Err(lookahead.error()); } - if input.peek(Token![,]) { + let lookahead = input.lookahead1(); + if lookahead.peek(Token![,]) { input.parse::()?; - } else { + } else if lookahead.peek(Token![>]) { break; + } else { + return Err(lookahead.error()); } } input.parse::]>()?; From 378f4e2be3b0b2912b1d1b5ac2a39e64bd7f05db Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 21 Jul 2024 15:54:05 -0700 Subject: [PATCH 63/66] Update test suite to nightly-2024-07-21 --- tests/repo/mod.rs | 43 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index 9c9088ae1a..7ebbb760a3 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -15,10 +15,49 @@ use std::path::{Path, PathBuf}; use tar::Archive; use walkdir::{DirEntry, WalkDir}; -const REVISION: &str = "becebb3158149a115cad8a402612e25436a7e37b"; +const REVISION: &str = "5069856495870486134dd2ca0b0e2516308c5c2a"; #[rustfmt::skip] static EXCLUDE_FILES: &[&str] = &[ + // TODO + "compiler/rustc_infer/src/infer/need_type_info.rs", + "compiler/rustc_lint/src/context/diagnostics.rs", + "library/std/src/sys/pal/uefi/helpers.rs", + "src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs", + "src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs", + "src/tools/miri/tests/pass/tail_call.rs", + "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs", + "src/tools/rustfmt/tests/target/return-type-notation.rs", + "src/tools/rustfmt/tests/target/unsafe_attributes.rs", + "src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs", + "tests/mir-opt/building/match/never_patterns.rs", + "tests/mir-opt/tail_call_drops.rs", + "tests/pretty/postfix-match/simple-matches.rs", + "tests/rustdoc/unsafe-extern-blocks.rs", + "tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs", + "tests/ui/attributes/unsafe/unsafe-attributes.rs", + "tests/ui/delegation/body-identity-glob.rs", + "tests/ui/delegation/body-identity-list.rs", + "tests/ui/delegation/fn-header.rs", + "tests/ui/delegation/glob-glob.rs", + "tests/ui/delegation/glob-override.rs", + "tests/ui/delegation/glob.rs", + "tests/ui/delegation/impl-trait.rs", + "tests/ui/delegation/list.rs", + "tests/ui/delegation/macro-inside-glob.rs", + "tests/ui/delegation/macro-inside-list.rs", + "tests/ui/delegation/method-call-priority.rs", + "tests/ui/delegation/rename.rs", + "tests/ui/delegation/self-coercion.rs", + "tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs", + "tests/ui/explicit-tail-calls/ctfe-arg-move.rs", + "tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs", + "tests/ui/explicit-tail-calls/drop-order.rs", + "tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs", + "tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs", + "tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs", + "tests/ui/unpretty/expanded-exhaustive.rs", + // TODO: explicit tail calls: `become _g()` // https://github.com/dtolnay/syn/issues/1501 "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs", @@ -104,7 +143,6 @@ static EXCLUDE_FILES: &[&str] = &[ // https://github.com/dtolnay/syn/issues/1630 "src/tools/rustfmt/tests/source/postfix-match/pf-match.rs", "src/tools/rustfmt/tests/target/postfix-match/pf-match.rs", - "tests/pretty/postfix-match.rs", "tests/ui/match/postfix-match/no-unused-parens.rs", "tests/ui/match/postfix-match/pf-match-chain.rs", "tests/ui/match/postfix-match/postfix-match.rs", @@ -234,7 +272,6 @@ static EXCLUDE_FILES: &[&str] = &[ // Placeholder syntax for "throw expressions" "compiler/rustc_errors/src/translation.rs", "compiler/rustc_expand/src/module.rs", - "compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs", "src/tools/clippy/tests/ui/needless_return.rs", "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0204_yeet_expr.rs", "tests/pretty/yeet-expr.rs", From a3f2f5050ee141c32b84a45e784bb00bb185f86a Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 21 Jul 2024 16:00:41 -0700 Subject: [PATCH 64/66] Categorize newly failing rust repo source files --- tests/repo/mod.rs | 72 ++++++++++++++++++++++++++--------------------- 1 file changed, 40 insertions(+), 32 deletions(-) diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index 7ebbb760a3..f4f30704b3 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -19,48 +19,34 @@ const REVISION: &str = "5069856495870486134dd2ca0b0e2516308c5c2a"; #[rustfmt::skip] static EXCLUDE_FILES: &[&str] = &[ - // TODO - "compiler/rustc_infer/src/infer/need_type_info.rs", + // TODO: parenthesization of `{ (match () {})() }` "compiler/rustc_lint/src/context/diagnostics.rs", + + // TODO: `unsafe static`, `safe fn` + "src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs", + "tests/rustdoc/unsafe-extern-blocks.rs", + "tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs", + + // TODO: unsafe attributes: `#[unsafe(path::to)]` + "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs", + "src/tools/rustfmt/tests/target/unsafe_attributes.rs", + "tests/ui/attributes/unsafe/unsafe-attributes.rs", + "tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs", + + // TODO: vararg in function pointer type: `extern fn(_: *mut _, _: ...)` "library/std/src/sys/pal/uefi/helpers.rs", + + // TODO: explicit tail calls: `become _g()` + // https://github.com/dtolnay/syn/issues/1501 "src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs", "src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs", "src/tools/miri/tests/pass/tail_call.rs", - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs", - "src/tools/rustfmt/tests/target/return-type-notation.rs", - "src/tools/rustfmt/tests/target/unsafe_attributes.rs", - "src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs", - "tests/mir-opt/building/match/never_patterns.rs", + "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs", "tests/mir-opt/tail_call_drops.rs", - "tests/pretty/postfix-match/simple-matches.rs", - "tests/rustdoc/unsafe-extern-blocks.rs", - "tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs", - "tests/ui/attributes/unsafe/unsafe-attributes.rs", - "tests/ui/delegation/body-identity-glob.rs", - "tests/ui/delegation/body-identity-list.rs", - "tests/ui/delegation/fn-header.rs", - "tests/ui/delegation/glob-glob.rs", - "tests/ui/delegation/glob-override.rs", - "tests/ui/delegation/glob.rs", - "tests/ui/delegation/impl-trait.rs", - "tests/ui/delegation/list.rs", - "tests/ui/delegation/macro-inside-glob.rs", - "tests/ui/delegation/macro-inside-list.rs", - "tests/ui/delegation/method-call-priority.rs", - "tests/ui/delegation/rename.rs", - "tests/ui/delegation/self-coercion.rs", "tests/ui/explicit-tail-calls/ctfe-arg-good-borrow.rs", "tests/ui/explicit-tail-calls/ctfe-arg-move.rs", "tests/ui/explicit-tail-calls/ctfe-collatz-multi-rec.rs", "tests/ui/explicit-tail-calls/drop-order.rs", - "tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs", - "tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs", - "tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs", - "tests/ui/unpretty/expanded-exhaustive.rs", - - // TODO: explicit tail calls: `become _g()` - // https://github.com/dtolnay/syn/issues/1501 - "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0209_become_expr.rs", "tests/ui/explicit-tail-calls/return-lifetime-sub.rs", // TODO: non-lifetime binders: `where for<'a, T> &'a Struct: Trait` @@ -76,6 +62,7 @@ static EXCLUDE_FILES: &[&str] = &[ // TODO: return type notation: `where T: Trait` // https://github.com/dtolnay/syn/issues/1434 "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs", + "src/tools/rustfmt/tests/target/return-type-notation.rs", "tests/ui/associated-type-bounds/return-type-notation/basic.rs", "tests/ui/associated-type-bounds/return-type-notation/unpretty-parenthesized.rs", "tests/ui/feature-gates/feature-gate-return_type_notation.rs", @@ -101,7 +88,9 @@ static EXCLUDE_FILES: &[&str] = &[ // TODO: `!` as a pattern // https://github.com/dtolnay/syn/issues/1546 + "tests/mir-opt/building/match/never_patterns.rs", "tests/ui/rfcs/rfc-0000-never_patterns/diverges.rs", + "tests/ui/rfcs/rfc-0000-never_patterns/use-bindings.rs", // TODO: async trait bounds: `impl async Fn()` // https://github.com/dtolnay/syn/issues/1628 @@ -118,6 +107,7 @@ static EXCLUDE_FILES: &[&str] = &[ "tests/ui/async-await/async-closures/captures.rs", "tests/ui/async-await/async-closures/constrained-but-no-upvars-yet.rs", "tests/ui/async-await/async-closures/drop.rs", + "tests/ui/async-await/async-closures/force-move-due-to-inferred-kind.rs", "tests/ui/async-await/async-closures/mangle.rs", "tests/ui/async-await/async-closures/moro-example.rs", "tests/ui/async-await/async-closures/move-is-async-fn.rs", @@ -143,6 +133,7 @@ static EXCLUDE_FILES: &[&str] = &[ // https://github.com/dtolnay/syn/issues/1630 "src/tools/rustfmt/tests/source/postfix-match/pf-match.rs", "src/tools/rustfmt/tests/target/postfix-match/pf-match.rs", + "tests/pretty/postfix-match/simple-matches.rs", "tests/ui/match/postfix-match/no-unused-parens.rs", "tests/ui/match/postfix-match/pf-match-chain.rs", "tests/ui/match/postfix-match/postfix-match.rs", @@ -150,10 +141,23 @@ static EXCLUDE_FILES: &[&str] = &[ // TODO: delegation // https://github.com/dtolnay/syn/issues/1580 "tests/pretty/delegation.rs", + "tests/ui/delegation/body-identity-glob.rs", + "tests/ui/delegation/body-identity-list.rs", "tests/ui/delegation/explicit-paths-in-traits-pass.rs", "tests/ui/delegation/explicit-paths-pass.rs", "tests/ui/delegation/explicit-paths-signature-pass.rs", + "tests/ui/delegation/fn-header.rs", + "tests/ui/delegation/glob-glob.rs", + "tests/ui/delegation/glob-override.rs", + "tests/ui/delegation/glob.rs", + "tests/ui/delegation/impl-trait.rs", + "tests/ui/delegation/list.rs", + "tests/ui/delegation/macro-inside-glob.rs", + "tests/ui/delegation/macro-inside-list.rs", + "tests/ui/delegation/method-call-priority.rs", "tests/ui/delegation/parse.rs", + "tests/ui/delegation/rename.rs", + "tests/ui/delegation/self-coercion.rs", // TODO: for await // https://github.com/dtolnay/syn/issues/1631 @@ -172,6 +176,9 @@ static EXCLUDE_FILES: &[&str] = &[ "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0208_closure_range_method_call.rs", "src/tools/rustfmt/tests/source/issue-4808.rs", + // Several of the above + "tests/ui/unpretty/expanded-exhaustive.rs", + // Compile-fail expr parameter in const generic position: f::<1 + 2>() "tests/ui/const-generics/early/closing-args-token.rs", "tests/ui/const-generics/early/const-expression-parameter.rs", @@ -272,6 +279,7 @@ static EXCLUDE_FILES: &[&str] = &[ // Placeholder syntax for "throw expressions" "compiler/rustc_errors/src/translation.rs", "compiler/rustc_expand/src/module.rs", + "compiler/rustc_infer/src/infer/need_type_info.rs", "src/tools/clippy/tests/ui/needless_return.rs", "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0204_yeet_expr.rs", "tests/pretty/yeet-expr.rs", From 87401bf9b8220c933e5f784ae5ecc1bfa369e09d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 21 Jul 2024 16:30:43 -0700 Subject: [PATCH 65/66] Add issue links for missing syntax support --- tests/repo/mod.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/repo/mod.rs b/tests/repo/mod.rs index f4f30704b3..26f4c4886b 100644 --- a/tests/repo/mod.rs +++ b/tests/repo/mod.rs @@ -23,17 +23,20 @@ static EXCLUDE_FILES: &[&str] = &[ "compiler/rustc_lint/src/context/diagnostics.rs", // TODO: `unsafe static`, `safe fn` + // https://github.com/dtolnay/syn/issues/1675 "src/tools/rustfmt/tests/target/unsafe_extern_blocks.rs", "tests/rustdoc/unsafe-extern-blocks.rs", "tests/ui/rust-2024/unsafe-extern-blocks/safe-items.rs", // TODO: unsafe attributes: `#[unsafe(path::to)]` + // https://github.com/dtolnay/syn/issues/1710 "src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs", "src/tools/rustfmt/tests/target/unsafe_attributes.rs", "tests/ui/attributes/unsafe/unsafe-attributes.rs", "tests/ui/rust-2024/unsafe-attributes/unsafe-attribute-marked.rs", // TODO: vararg in function pointer type: `extern fn(_: *mut _, _: ...)` + // https://github.com/dtolnay/syn/issues/1711 "library/std/src/sys/pal/uefi/helpers.rs", // TODO: explicit tail calls: `become _g()` From c59828ff6f52e2d5d7069900d6577863ea220d48 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 21 Jul 2024 16:39:08 -0700 Subject: [PATCH 66/66] Release 2.0.72 --- 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 d37acd143d..8af231a039 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "syn" -version = "2.0.71" +version = "2.0.72" authors = ["David Tolnay "] categories = ["development-tools::procedural-macro-helpers", "parser-implementations"] description = "Parser for Rust source code" diff --git a/src/lib.rs b/src/lib.rs index 61dfd18bbb..516a68662b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,7 +249,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/2.0.71")] +#![doc(html_root_url = "https://docs.rs/syn/2.0.72")] #![cfg_attr(docsrs, feature(doc_cfg))] #![deny(unsafe_op_in_unsafe_fn)] #![allow(non_camel_case_types)] diff --git a/syn.json b/syn.json index 4b4d0e3f48..08f2366a5f 100644 --- a/syn.json +++ b/syn.json @@ -1,5 +1,5 @@ { - "version": "2.0.71", + "version": "2.0.72", "types": [ { "ident": "Abi",