From d3cf4117bd75a67cc188935d92f8a616446ab4bb Mon Sep 17 00:00:00 2001 From: Max Niederman Date: Sun, 6 Oct 2024 23:09:30 -0700 Subject: [PATCH 01/16] cover guard patterns in rustfmt --- src/patterns.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/patterns.rs b/src/patterns.rs index 6fe2d4a8520..7bc699b07b0 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -48,7 +48,8 @@ fn is_short_pattern_inner(pat: &ast::Pat) -> bool { | ast::PatKind::MacCall(..) | ast::PatKind::Slice(..) | ast::PatKind::Path(..) - | ast::PatKind::Range(..) => false, + | ast::PatKind::Range(..) + | ast::PatKind::Guard(..) => false, ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1, ast::PatKind::TupleStruct(_, ref path, ref subpats) => { path.segments.len() <= 1 && subpats.len() <= 1 @@ -340,6 +341,7 @@ impl Rewrite for Pat { .map(|inner_pat| format!("({})", inner_pat)), PatKind::Err(_) => Err(RewriteError::Unknown), PatKind::Deref(_) => Err(RewriteError::Unknown), + PatKind::Guard(..) => Err(RewriteError::Unknown), } } } From 74dceee6c476817ca3d0ad3a253fb2542ac0f690 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 24 Nov 2024 22:57:33 +0100 Subject: [PATCH 02/16] Fix rustfmt according to review --- src/patterns.rs | 4 ++-- tests/target/guard_patterns.rs | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/target/guard_patterns.rs diff --git a/src/patterns.rs b/src/patterns.rs index 7bc699b07b0..7b4730eadc8 100644 --- a/src/patterns.rs +++ b/src/patterns.rs @@ -339,9 +339,9 @@ impl Rewrite for Pat { .max_width_error(shape.width, self.span)?, ) .map(|inner_pat| format!("({})", inner_pat)), - PatKind::Err(_) => Err(RewriteError::Unknown), + PatKind::Guard(..) => Ok(context.snippet(self.span).to_string()), PatKind::Deref(_) => Err(RewriteError::Unknown), - PatKind::Guard(..) => Err(RewriteError::Unknown), + PatKind::Err(_) => Err(RewriteError::Unknown), } } } diff --git a/tests/target/guard_patterns.rs b/tests/target/guard_patterns.rs new file mode 100644 index 00000000000..2e4667b916c --- /dev/null +++ b/tests/target/guard_patterns.rs @@ -0,0 +1,12 @@ +#![feature(guard_patterns)] + +fn main() { + match user.subscription_plan() { + (Plan::Regular if user.credit() >= 100) | (Plan::Premium if user.credit() >= 80) => { + // Complete the transaction. + } + _ => { + // The user doesn't have enough credit, return an error message. + } + } +} From 7be9019b991ebc1d2dc6a5fe553d699c72ae694e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 9 Nov 2024 18:30:13 +0000 Subject: [PATCH 03/16] Store a single copy of the error registry in DiagCtxt And pass this to the individual emitters when necessary. --- src/parse/session.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/parse/session.rs b/src/parse/session.rs index 54ad56ed3f3..63cc8794cea 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -3,6 +3,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_errors::emitter::{DynEmitter, Emitter, HumanEmitter, SilentEmitter, stderr_destination}; +use rustc_errors::registry::Registry; use rustc_errors::translation::Translate; use rustc_errors::{ColorConfig, Diag, DiagCtxt, DiagInner, Level as DiagnosticLevel}; use rustc_session::parse::ParseSess as RawParseSess; @@ -38,10 +39,10 @@ struct SilentOnIgnoredFilesEmitter { } impl SilentOnIgnoredFilesEmitter { - fn handle_non_ignoreable_error(&mut self, diag: DiagInner) { + fn handle_non_ignoreable_error(&mut self, diag: DiagInner, registry: &Registry) { self.has_non_ignorable_parser_errors = true; self.can_reset.store(false, Ordering::Release); - self.emitter.emit_diagnostic(diag); + self.emitter.emit_diagnostic(diag, registry); } } @@ -60,9 +61,9 @@ impl Emitter for SilentOnIgnoredFilesEmitter { None } - fn emit_diagnostic(&mut self, diag: DiagInner) { + fn emit_diagnostic(&mut self, diag: DiagInner, registry: &Registry) { if diag.level() == DiagnosticLevel::Fatal { - return self.handle_non_ignoreable_error(diag); + return self.handle_non_ignoreable_error(diag, registry); } if let Some(primary_span) = &diag.span.primary_span() { let file_name = self.source_map.span_to_filename(*primary_span); @@ -80,7 +81,7 @@ impl Emitter for SilentOnIgnoredFilesEmitter { } }; } - self.handle_non_ignoreable_error(diag); + self.handle_non_ignoreable_error(diag, registry); } } @@ -358,7 +359,7 @@ mod tests { None } - fn emit_diagnostic(&mut self, _diag: DiagInner) { + fn emit_diagnostic(&mut self, _diag: DiagInner, _registry: &Registry) { self.num_emitted_errors.fetch_add(1, Ordering::Release); } } @@ -412,6 +413,7 @@ mod tests { SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), source, ); + let registry = Registry::new(&[]); let mut emitter = build_emitter( Lrc::clone(&num_emitted_errors), Lrc::clone(&can_reset_errors), @@ -420,7 +422,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, Some(span)); - emitter.emit_diagnostic(fatal_diagnostic); + emitter.emit_diagnostic(fatal_diagnostic, ®istry); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -437,6 +439,7 @@ mod tests { SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), source, ); + let registry = Registry::new(&[]); let mut emitter = build_emitter( Lrc::clone(&num_emitted_errors), Lrc::clone(&can_reset_errors), @@ -445,7 +448,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic, ®istry); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 0); assert_eq!(can_reset_errors.load(Ordering::Acquire), true); } @@ -461,6 +464,7 @@ mod tests { SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("foo.rs"))), source, ); + let registry = Registry::new(&[]); let mut emitter = build_emitter( Lrc::clone(&num_emitted_errors), Lrc::clone(&can_reset_errors), @@ -469,7 +473,7 @@ mod tests { ); let span = MultiSpan::from_span(mk_sp(BytePos(0), BytePos(1))); let non_fatal_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(span)); - emitter.emit_diagnostic(non_fatal_diagnostic); + emitter.emit_diagnostic(non_fatal_diagnostic, ®istry); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 1); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } @@ -497,6 +501,7 @@ mod tests { SourceMapFileName::Real(RealFileName::LocalPath(PathBuf::from("fatal.rs"))), fatal_source, ); + let registry = Registry::new(&[]); let mut emitter = build_emitter( Lrc::clone(&num_emitted_errors), Lrc::clone(&can_reset_errors), @@ -508,9 +513,9 @@ mod tests { let bar_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(bar_span)); let foo_diagnostic = build_diagnostic(DiagnosticLevel::Warning, Some(foo_span)); let fatal_diagnostic = build_diagnostic(DiagnosticLevel::Fatal, None); - emitter.emit_diagnostic(bar_diagnostic); - emitter.emit_diagnostic(foo_diagnostic); - emitter.emit_diagnostic(fatal_diagnostic); + emitter.emit_diagnostic(bar_diagnostic, ®istry); + emitter.emit_diagnostic(foo_diagnostic, ®istry); + emitter.emit_diagnostic(fatal_diagnostic, ®istry); assert_eq!(num_emitted_errors.load(Ordering::Acquire), 2); assert_eq!(can_reset_errors.load(Ordering::Acquire), false); } From 6b12b6b5cc9879dfb106952ba51fa946aa2d836d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 5 Dec 2024 21:19:08 +0000 Subject: [PATCH 04/16] Keep track of parse errors in `mod`s and don't emit resolve errors for paths involving them When we expand a `mod foo;` and parse `foo.rs`, we now track whether that file had an unrecovered parse error that reached the end of the file. If so, we keep that information around. When resolving a path like `foo::bar`, we do not emit any errors for "`bar` not found in `foo`", as we know that the parse error might have caused `bar` to not be parsed and accounted for. When this happens in an existing project, every path referencing `foo` would be an irrelevant compile error. Instead, we now skip emitting anything until `foo.rs` is fixed. Tellingly enough, we didn't have any test for errors caused by `mod` expansion. Fix #97734. --- src/items.rs | 2 +- src/modules.rs | 7 +++---- src/visitor.rs | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/items.rs b/src/items.rs index 18932587f1f..c3debc2f4f0 100644 --- a/src/items.rs +++ b/src/items.rs @@ -3597,7 +3597,7 @@ pub(crate) fn rewrite_extern_crate( pub(crate) fn is_mod_decl(item: &ast::Item) -> bool { !matches!( item.kind, - ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) + ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _, _)) ) } diff --git a/src/modules.rs b/src/modules.rs index 493b04f16c6..a40ee7f66a9 100644 --- a/src/modules.rs +++ b/src/modules.rs @@ -316,12 +316,11 @@ impl<'ast, 'psess, 'c> ModResolver<'ast, 'psess> { self.directory = directory; } match (sub_mod.ast_mod_kind, sub_mod.items) { - (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _))), _) => { + (Some(Cow::Borrowed(ast::ModKind::Loaded(items, _, _, _))), _) => { self.visit_mod_from_ast(items) } - (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _))), _) | (_, Cow::Owned(items)) => { - self.visit_mod_outside_ast(items) - } + (Some(Cow::Owned(ast::ModKind::Loaded(items, _, _, _))), _) + | (_, Cow::Owned(items)) => self.visit_mod_outside_ast(items), (_, _) => Ok(()), } } diff --git a/src/visitor.rs b/src/visitor.rs index 9b116b620b7..805e13b7803 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -927,7 +927,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { let ident_str = rewrite_ident(&self.get_context(), ident).to_owned(); self.push_str(&ident_str); - if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind { + if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans, _) = mod_kind { let ast::ModSpans { inner_span, inject_use_span: _, From 05c9d68692aece9c3fa743c3111b9b3affbd9266 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 10 Dec 2024 19:41:48 +0000 Subject: [PATCH 05/16] Fix tools --- src/expr.rs | 3 ++- src/types.rs | 25 +++++++++++++++++++++++++ src/utils.rs | 1 + tests/source/unsafe-binders.rs | 11 +++++++++++ tests/target/unsafe-binders.rs | 9 +++++++++ 5 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/source/unsafe-binders.rs create mode 100644 tests/target/unsafe-binders.rs diff --git a/src/expr.rs b/src/expr.rs index 77c9818b66b..16b7e7aa709 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -413,7 +413,8 @@ pub(crate) fn format_expr( ast::ExprKind::FormatArgs(..) | ast::ExprKind::Type(..) | ast::ExprKind::IncludedBytes(..) - | ast::ExprKind::OffsetOf(..) => { + | ast::ExprKind::OffsetOf(..) + | ast::ExprKind::UnsafeBinderCast(..) => { // These don't normally occur in the AST because macros aren't expanded. However, // rustfmt tries to parse macro arguments when formatting macros, so it's not totally // impossible for rustfmt to come across one of these nodes when formatting a file. diff --git a/src/types.rs b/src/types.rs index dd4a788c002..f8b713117f4 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1016,6 +1016,31 @@ impl Rewrite for ast::Ty { let pat = pat.rewrite_result(context, shape)?; Ok(format!("{ty} is {pat}")) } + ast::TyKind::UnsafeBinder(ref binder) => { + let mut result = String::new(); + if let Some(ref lifetime_str) = + rewrite_bound_params(context, shape, &binder.generic_params) + { + result.push_str("unsafe<"); + result.push_str(lifetime_str); + result.push_str("> "); + } + + let inner_ty_shape = if context.use_block_indent() { + shape + .offset_left(result.len()) + .max_width_error(shape.width, self.span())? + } else { + shape + .visual_indent(result.len()) + .sub_width(result.len()) + .max_width_error(shape.width, self.span())? + }; + + let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?; + result.push_str(&rewrite); + Ok(result) + } } } } diff --git a/src/utils.rs b/src/utils.rs index 0ca34a79491..ba4a4c045f1 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -504,6 +504,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) | ast::ExprKind::OffsetOf(..) + | ast::ExprKind::UnsafeBinderCast(..) | ast::ExprKind::Let(..) | ast::ExprKind::Path(..) | ast::ExprKind::Range(..) diff --git a/tests/source/unsafe-binders.rs b/tests/source/unsafe-binders.rs new file mode 100644 index 00000000000..ccf7c8bb9af --- /dev/null +++ b/tests/source/unsafe-binders.rs @@ -0,0 +1,11 @@ +fn foo() -> unsafe<'a> +&'a () {} + +struct Foo { + x: unsafe<'a> +&'a (), +} + +struct Bar(unsafe<'a> &'a ()); + +impl Trait for unsafe<'a> &'a () {} diff --git a/tests/target/unsafe-binders.rs b/tests/target/unsafe-binders.rs new file mode 100644 index 00000000000..9d308f4a894 --- /dev/null +++ b/tests/target/unsafe-binders.rs @@ -0,0 +1,9 @@ +fn foo() -> unsafe<'a> &'a () {} + +struct Foo { + x: unsafe<'a> &'a (), +} + +struct Bar(unsafe<'a> &'a ()); + +impl Trait for unsafe<'a> &'a () {} From de1c33c28faac99c66203851cd4c7fd41c39a1e9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Dec 2024 14:13:04 +1100 Subject: [PATCH 06/16] Change the lookahead in `MacroParser::new`. As it happens, lookahead values of 0, 1, and 2 all work fine here, due to the structure of the code. (Values or 3 or greater cause test failures.) This commit changes the lookahead to zero because that will facilitate cleanups in subsequent commits. --- src/macros.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/macros.rs b/src/macros.rs index 4083d9398f6..fa281cab724 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1190,7 +1190,7 @@ impl<'a> MacroParser<'a> { // (`(` ... `)` `=>` `{` ... `}`)* fn parse(&mut self) -> Option { let mut branches = vec![]; - while self.toks.look_ahead(1).is_some() { + while self.toks.look_ahead(0).is_some() { branches.push(self.parse_branch()?); } From 46a1d705ff12a6bb1ad9029e114bb3ac6ea99b75 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Dec 2024 12:29:04 +1100 Subject: [PATCH 07/16] Simplify `RefTokenTreeCursor::look_ahead`. It's only ever used with a lookahead of 0, so this commit removes the lookahead and renames it `peek`. --- src/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index fa281cab724..dad074440b4 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1190,7 +1190,7 @@ impl<'a> MacroParser<'a> { // (`(` ... `)` `=>` `{` ... `}`)* fn parse(&mut self) -> Option { let mut branches = vec![]; - while self.toks.look_ahead(0).is_some() { + while self.toks.peek().is_some() { branches.push(self.parse_branch()?); } @@ -1237,7 +1237,7 @@ impl<'a> MacroParser<'a> { span, }, _, - )) = self.toks.look_ahead(0) + )) = self.toks.peek() { hi = span.hi(); self.toks.next(); From cbec1df363962c3b3c2449a2f388b349bb62413a Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Dec 2024 14:38:09 +1100 Subject: [PATCH 08/16] Rename `RefTokenTreeCursor`. Because `TokenStreamIter` is a much better name for a `TokenStream` iterator. Also rename the `TokenStream::trees` method as `TokenStream::iter`, and some local variables. --- src/macros.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index dad074440b4..ea8ca38cb77 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -13,7 +13,7 @@ use std::collections::HashMap; use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind}; -use rustc_ast::tokenstream::{RefTokenTreeCursor, TokenStream, TokenTree}; +use rustc_ast::tokenstream::{TokenStream, TokenStreamIter, TokenTree}; use rustc_ast::{ast, ptr}; use rustc_ast_pretty::pprust; use rustc_span::{ @@ -443,7 +443,7 @@ pub(crate) fn rewrite_macro_def( } let ts = def.body.tokens.clone(); - let mut parser = MacroParser::new(ts.trees()); + let mut parser = MacroParser::new(ts.iter()); let parsed_def = match parser.parse() { Some(def) => def, None => return snippet, @@ -794,7 +794,7 @@ impl MacroArgParser { self.buf.clear(); } - fn add_meta_variable(&mut self, iter: &mut RefTokenTreeCursor<'_>) -> Option<()> { + fn add_meta_variable(&mut self, iter: &mut TokenStreamIter<'_>) -> Option<()> { match iter.next() { Some(&TokenTree::Token( Token { @@ -826,7 +826,7 @@ impl MacroArgParser { &mut self, inner: Vec, delim: Delimiter, - iter: &mut RefTokenTreeCursor<'_>, + iter: &mut TokenStreamIter<'_>, ) -> Option<()> { let mut buffer = String::new(); let mut first = true; @@ -926,7 +926,7 @@ impl MacroArgParser { /// Returns a collection of parsed macro def's arguments. fn parse(mut self, tokens: TokenStream) -> Option> { - let mut iter = tokens.trees(); + let mut iter = tokens.iter(); while let Some(tok) = iter.next() { match tok { @@ -1063,7 +1063,7 @@ fn format_macro_args( } fn span_for_token_stream(token_stream: &TokenStream) -> Option { - token_stream.trees().next().map(|tt| tt.span()) + token_stream.iter().next().map(|tt| tt.span()) } // We should insert a space if the next token is a: @@ -1179,18 +1179,18 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D // A very simple parser that just parses a macros 2.0 definition into its branches. // Currently we do not attempt to parse any further than that. struct MacroParser<'a> { - toks: RefTokenTreeCursor<'a>, + iter: TokenStreamIter<'a>, } impl<'a> MacroParser<'a> { - const fn new(toks: RefTokenTreeCursor<'a>) -> Self { - Self { toks } + const fn new(iter: TokenStreamIter<'a>) -> Self { + Self { iter } } // (`(` ... `)` `=>` `{` ... `}`)* fn parse(&mut self) -> Option { let mut branches = vec![]; - while self.toks.peek().is_some() { + while self.iter.peek().is_some() { branches.push(self.parse_branch()?); } @@ -1199,13 +1199,13 @@ impl<'a> MacroParser<'a> { // `(` ... `)` `=>` `{` ... `}` fn parse_branch(&mut self) -> Option { - let tok = self.toks.next()?; + let tok = self.iter.next()?; let (lo, args_paren_kind) = match tok { TokenTree::Token(..) => return None, &TokenTree::Delimited(delimited_span, _, d, _) => (delimited_span.open.lo(), d), }; let args = TokenStream::new(vec![tok.clone()]); - match self.toks.next()? { + match self.iter.next()? { TokenTree::Token( Token { kind: TokenKind::FatArrow, @@ -1215,7 +1215,7 @@ impl<'a> MacroParser<'a> { ) => {} _ => return None, } - let (mut hi, body, whole_body) = match self.toks.next()? { + let (mut hi, body, whole_body) = match self.iter.next()? { TokenTree::Token(..) => return None, TokenTree::Delimited(delimited_span, ..) => { let data = delimited_span.entire().data(); @@ -1237,10 +1237,10 @@ impl<'a> MacroParser<'a> { span, }, _, - )) = self.toks.peek() + )) = self.iter.peek() { hi = span.hi(); - self.toks.next(); + self.iter.next(); } Some(MacroBranch { span: mk_sp(lo, hi), From 3aadb3183501ed8b8bf10a52fe58ced48a6f42b3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 13 Dec 2024 21:07:58 +1100 Subject: [PATCH 09/16] Only have one source of truth for keywords. `rustc_symbol` is the source of truth for keywords. rustdoc has its own implicit definition of keywords, via the `is_doc_keyword`. It (presumably) intends to include all keywords, but it omits `yeet`. rustfmt has its own explicit list of Rust keywords. It also (presumably) intends to include all keywords, but it omits `await`, `builtin`, `gen`, `macro_rules`, `raw`, `reuse`, `safe`, and `yeet`. Also, it does linear searches through this list, which is inefficient. This commit fixes all of the above problems by introducing a new predicate `is_any_keyword` in rustc and using it in rustdoc and rustfmt. It documents that it's not the right predicate in most cases. --- src/parse/macros/mod.rs | 87 ++++++----------------------------------- 1 file changed, 12 insertions(+), 75 deletions(-) diff --git a/src/parse/macros/mod.rs b/src/parse/macros/mod.rs index 7271e73db8d..680a35f7e03 100644 --- a/src/parse/macros/mod.rs +++ b/src/parse/macros/mod.rs @@ -4,8 +4,7 @@ use rustc_ast::{ast, ptr}; use rustc_parse::MACRO_ARGUMENTS; use rustc_parse::parser::{ForceCollect, Parser, Recovery}; use rustc_session::parse::ParseSess; -use rustc_span::Symbol; -use rustc_span::symbol::{self, kw}; +use rustc_span::symbol; use crate::macros::MacroArg; use crate::rewrite::RewriteContext; @@ -82,18 +81,18 @@ pub(crate) struct ParsedMacroArgs { } fn check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { - for &keyword in RUST_KW.iter() { - if parser.token.is_keyword(keyword) - && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma) - { - parser.bump(); - return Some(MacroArg::Keyword( - symbol::Ident::with_dummy_span(keyword), - parser.prev_token.span, - )); - } + if parser.token.is_any_keyword() + && parser.look_ahead(1, |t| *t == TokenKind::Eof || *t == TokenKind::Comma) + { + let keyword = parser.token.ident().unwrap().0.name; + parser.bump(); + Some(MacroArg::Keyword( + symbol::Ident::with_dummy_span(keyword), + parser.prev_token.span, + )) + } else { + None } - None } pub(crate) fn parse_macro_args( @@ -169,65 +168,3 @@ pub(crate) fn parse_expr( let mut parser = build_parser(context, tokens); parser.parse_expr().ok() } - -const RUST_KW: [Symbol; 59] = [ - kw::PathRoot, - kw::DollarCrate, - kw::Underscore, - kw::As, - kw::Box, - kw::Break, - kw::Const, - kw::Continue, - kw::Crate, - kw::Else, - kw::Enum, - kw::Extern, - kw::False, - kw::Fn, - kw::For, - kw::If, - kw::Impl, - kw::In, - kw::Let, - kw::Loop, - kw::Match, - kw::Mod, - kw::Move, - kw::Mut, - kw::Pub, - kw::Ref, - kw::Return, - kw::SelfLower, - kw::SelfUpper, - kw::Static, - kw::Struct, - kw::Super, - kw::Trait, - kw::True, - kw::Type, - kw::Unsafe, - kw::Use, - kw::Where, - kw::While, - kw::Abstract, - kw::Become, - kw::Do, - kw::Final, - kw::Macro, - kw::Override, - kw::Priv, - kw::Typeof, - kw::Unsized, - kw::Virtual, - kw::Yield, - kw::Dyn, - kw::Async, - kw::Try, - kw::UnderscoreLifetime, - kw::StaticLifetime, - kw::Auto, - kw::Catch, - kw::Default, - kw::Union, -]; From 994b55e7b2bdb2ea1dc558f5ede97048a1fc1da9 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 4 Dec 2024 15:55:06 +1100 Subject: [PATCH 10/16] Speed up `Parser::expected_token_types`. The parser pushes a `TokenType` to `Parser::expected_token_types` on every call to the various `check`/`eat` methods, and clears it on every call to `bump`. Some of those `TokenType` values are full tokens that require cloning and dropping. This is a *lot* of work for something that is only used in error messages and it accounts for a significant fraction of parsing execution time. This commit overhauls `TokenType` so that `Parser::expected_token_types` can be implemented as a bitset. This requires changing `TokenType` to a C-style parameterless enum, and adding `TokenTypeSet` which uses a `u128` for the bits. (The new `TokenType` has 105 variants.) The new types `ExpTokenPair` and `ExpKeywordPair` are now arguments to the `check`/`eat` methods. This is for maximum speed. The elements in the pairs are always statically known; e.g. a `token::BinOp(token::Star)` is always paired with a `TokenType::Star`. So we now compute `TokenType`s in advance and pass them in to `check`/`eat` rather than the current approach of constructing them on insertion into `expected_token_types`. Values of these pair types can be produced by the new `exp!` macro, which is used at every `check`/`eat` call site. The macro is for convenience, allowing any pair to be generated from a single identifier. The ident/keyword filtering in `expected_one_of_not_found` is no longer necessary. It was there to account for some sloppiness in `TokenKind`/`TokenType` comparisons. The existing `TokenType` is moved to a new file `token_type.rs`, and all its new infrastructure is added to that file. There is more boilerplate code than I would like, but I can't see how to make it shorter. --- src/parse/macros/cfg_if.rs | 11 ++++++----- src/parse/macros/lazy_static.rs | 17 +++++++++-------- src/parse/parser.rs | 5 ++--- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/parse/macros/cfg_if.rs b/src/parse/macros/cfg_if.rs index ec771f96a3f..0b7b6c4d361 100644 --- a/src/parse/macros/cfg_if.rs +++ b/src/parse/macros/cfg_if.rs @@ -2,6 +2,7 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use rustc_ast::ast; use rustc_ast::token::{Delimiter, TokenKind}; +use rustc_parse::exp; use rustc_parse::parser::ForceCollect; use rustc_span::symbol::kw; @@ -31,7 +32,7 @@ fn parse_cfg_if_inner<'a>( while parser.token.kind != TokenKind::Eof { if process_if_cfg { - if !parser.eat_keyword(kw::If) { + if !parser.eat_keyword(exp!(If)) { return Err("Expected `if`"); } @@ -55,7 +56,7 @@ fn parse_cfg_if_inner<'a>( })?; } - if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) { + if !parser.eat(exp!(OpenBrace)) { return Err("Expected an opening brace"); } @@ -78,15 +79,15 @@ fn parse_cfg_if_inner<'a>( } } - if !parser.eat(&TokenKind::CloseDelim(Delimiter::Brace)) { + if !parser.eat(exp!(CloseBrace)) { return Err("Expected a closing brace"); } - if parser.eat(&TokenKind::Eof) { + if parser.eat(exp!(Eof)) { break; } - if !parser.eat_keyword(kw::Else) { + if !parser.eat_keyword(exp!(Else)) { return Err("Expected `else`"); } diff --git a/src/parse/macros/lazy_static.rs b/src/parse/macros/lazy_static.rs index b6de5f8691c..cbe81004e22 100644 --- a/src/parse/macros/lazy_static.rs +++ b/src/parse/macros/lazy_static.rs @@ -1,8 +1,9 @@ use rustc_ast::ast; use rustc_ast::ptr::P; -use rustc_ast::token::TokenKind; +use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; -use rustc_span::symbol::{self, kw}; +use rustc_parse::exp; +use rustc_span::symbol; use crate::rewrite::RewriteContext; @@ -31,19 +32,19 @@ pub(crate) fn parse_lazy_static( } } } - while parser.token.kind != TokenKind::Eof { + while parser.token.kind != token::Eof { // Parse a `lazy_static!` item. // FIXME: These `eat_*` calls should be converted to `parse_or` to avoid // silently formatting malformed lazy-statics. let vis = parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No); - let _ = parser.eat_keyword(kw::Static); - let _ = parser.eat_keyword(kw::Ref); + let _ = parser.eat_keyword(exp!(Static)); + let _ = parser.eat_keyword(exp!(Ref)); let id = parse_or!(parse_ident); - let _ = parser.eat(&TokenKind::Colon); + let _ = parser.eat(exp!(Colon)); let ty = parse_or!(parse_ty); - let _ = parser.eat(&TokenKind::Eq); + let _ = parser.eat(exp!(Eq)); let expr = parse_or!(parse_expr); - let _ = parser.eat(&TokenKind::Semi); + let _ = parser.eat(exp!(Semi)); result.push((vis, id, ty, expr)); } diff --git a/src/parse/parser.rs b/src/parse/parser.rs index 28b4c2b612f..f357aed66c2 100644 --- a/src/parse/parser.rs +++ b/src/parse/parser.rs @@ -1,11 +1,10 @@ use std::panic::{AssertUnwindSafe, catch_unwind}; use std::path::{Path, PathBuf}; -use rustc_ast::token::TokenKind; use rustc_ast::{ast, attr, ptr}; use rustc_errors::Diag; use rustc_parse::parser::Parser as RawParser; -use rustc_parse::{new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; +use rustc_parse::{exp, new_parser_from_file, new_parser_from_source_str, unwrap_or_emit_fatal}; use rustc_span::{Span, sym}; use thin_vec::ThinVec; @@ -107,7 +106,7 @@ impl<'a> Parser<'a> { let result = catch_unwind(AssertUnwindSafe(|| { let mut parser = unwrap_or_emit_fatal(new_parser_from_file(psess.inner(), path, Some(span))); - match parser.parse_mod(&TokenKind::Eof) { + match parser.parse_mod(exp!(Eof)) { Ok((a, i, spans)) => Some((a, i, spans.inner_span)), Err(e) => { e.emit(); From c6a272b2d1d64cd512dacba921cfb4ff6a1a5da5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 22 Dec 2024 22:09:59 +0000 Subject: [PATCH 11/16] Make sure we don't lose default struct value when formatting struct --- src/items.rs | 5 +++++ src/spanned.rs | 1 + tests/source/default-field-values.rs | 18 ++++++++++++++++++ tests/target/default-field-values.rs | 18 ++++++++++++++++++ 4 files changed, 42 insertions(+) create mode 100644 tests/source/default-field-values.rs create mode 100644 tests/target/default-field-values.rs diff --git a/src/items.rs b/src/items.rs index c3debc2f4f0..e7d0fba048b 100644 --- a/src/items.rs +++ b/src/items.rs @@ -1944,6 +1944,11 @@ pub(crate) fn rewrite_struct_field( shape: Shape, lhs_max_width: usize, ) -> RewriteResult { + // FIXME(default_field_values): Implement formatting. + if field.default.is_some() { + return Err(RewriteError::Unknown); + } + if contains_skip(&field.attrs) { return Ok(context.snippet(field.span()).to_owned()); } diff --git a/src/spanned.rs b/src/spanned.rs index db7c3486e71..6b3e40b9115 100644 --- a/src/spanned.rs +++ b/src/spanned.rs @@ -144,6 +144,7 @@ impl Spanned for ast::GenericParam { impl Spanned for ast::FieldDef { fn span(&self) -> Span { + // FIXME(default_field_values): This needs to be adjusted. span_with_attrs_lo_hi!(self, self.span.lo(), self.ty.span.hi()) } } diff --git a/tests/source/default-field-values.rs b/tests/source/default-field-values.rs new file mode 100644 index 00000000000..622f9640d0d --- /dev/null +++ b/tests/source/default-field-values.rs @@ -0,0 +1,18 @@ +#![feature(default_struct_values)] + +// Test for now that nightly default field values are left alone for now. + +struct Foo { + default_field: Spacing = /* uwu */ 0, +} + +struct Foo2 { + #[rustfmt::skip] + default_field: Spacing = /* uwu */ 0, +} + +a_macro!( + struct Foo2 { + default_field: Spacing = /* uwu */ 0, + } +); diff --git a/tests/target/default-field-values.rs b/tests/target/default-field-values.rs new file mode 100644 index 00000000000..622f9640d0d --- /dev/null +++ b/tests/target/default-field-values.rs @@ -0,0 +1,18 @@ +#![feature(default_struct_values)] + +// Test for now that nightly default field values are left alone for now. + +struct Foo { + default_field: Spacing = /* uwu */ 0, +} + +struct Foo2 { + #[rustfmt::skip] + default_field: Spacing = /* uwu */ 0, +} + +a_macro!( + struct Foo2 { + default_field: Spacing = /* uwu */ 0, + } +); From ba8ee715244642c5d5fd48bf8971b40f11b0a119 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 30 Dec 2024 17:06:44 +0000 Subject: [PATCH 12/16] Stabilize style_edition 2024 in-tree --- src/bin/main.rs | 11 ++++------- src/config/mod.rs | 4 ++-- src/config/options.rs | 1 - 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index c7d3a060d54..4078484ff10 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -568,10 +568,6 @@ impl GetOptsOptions { if let Some(ref file_lines) = matches.opt_str("file-lines") { options.file_lines = file_lines.parse()?; } - if let Some(ref edition_str) = matches.opt_str("style-edition") { - options.style_edition = - Some(style_edition_from_style_edition_str(edition_str)?); - } } else { let mut unstable_options = vec![]; if matches.opt_present("skip-children") { @@ -583,9 +579,6 @@ impl GetOptsOptions { if matches.opt_present("file-lines") { unstable_options.push("`--file-lines`"); } - if matches.opt_present("style-edition") { - unstable_options.push("`--style-edition`"); - } if !unstable_options.is_empty() { let s = if unstable_options.len() == 1 { "" } else { "s" }; return Err(format_err!( @@ -661,6 +654,10 @@ impl GetOptsOptions { } } + if let Some(ref edition_str) = matches.opt_str("style-edition") { + options.style_edition = Some(style_edition_from_style_edition_str(edition_str)?); + } + Ok(options) } diff --git a/src/config/mod.rs b/src/config/mod.rs index ea257c0a8ba..7355adc9f9d 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -29,7 +29,7 @@ pub(crate) mod style_edition; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: // -// `name: value type, default value, is stable, description;` +// `name: value type, is stable, description;` create_config! { // Fundamental stuff max_width: MaxWidth, true, "Maximum width of each line"; @@ -149,7 +149,7 @@ create_config! { blank_lines_lower_bound: BlankLinesLowerBound, false, "Minimum number of blank lines which must be put between items"; edition: EditionConfig, true, "The edition of the parser (RFC 2052)"; - style_edition: StyleEditionConfig, false, "The edition of the Style Guide (RFC 3338)"; + style_edition: StyleEditionConfig, true, "The edition of the Style Guide (RFC 3338)"; version: VersionConfig, false, "Version of formatting rules"; inline_attribute_width: InlineAttributeWidth, false, "Write an item and its attribute on the same line \ diff --git a/src/config/options.rs b/src/config/options.rs index c526b5c678f..bbc99a2dced 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -511,7 +511,6 @@ pub enum StyleEdition { Edition2021, #[value = "2024"] #[doc_hint = "2024"] - #[unstable_variant] /// [Edition 2024](). Edition2024, } From f8741991415f359f70c9ea6b2258286f6fd134d4 Mon Sep 17 00:00:00 2001 From: rustfmt bot Date: Thu, 2 Jan 2025 02:12:09 +0000 Subject: [PATCH 13/16] chore: bump rustfmt toolchain to nightly-2025-01-02 Bumping the toolchain version as part of a git subtree push current toolchain (nightly-2024-12-02): - 1.85.0-nightly (5e1440ae5 2024-12-01) latest toolchain (nightly-2025-01-02): - 1.85.0-nightly (45d11e51b 2025-01-01) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 7cd537279d2..348664bc168 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2024-12-02" +channel = "nightly-2025-01-02" components = ["llvm-tools", "rustc-dev"] From ab98945cc4416cb62a86313b21d105e3e93fa942 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 1 Jan 2025 21:44:17 -0500 Subject: [PATCH 14/16] chore: fixes needed for subtree-push --- src/types.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/types.rs b/src/types.rs index 39c6390cb3f..6180a4dac13 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1015,14 +1015,11 @@ impl Rewrite for ast::Ty { } let inner_ty_shape = if context.use_block_indent() { - shape - .offset_left(result.len()) - .max_width_error(shape.width, self.span())? + shape.offset_left(result.len(), self.span())? } else { shape .visual_indent(result.len()) - .sub_width(result.len()) - .max_width_error(shape.width, self.span())? + .sub_width(result.len(), self.span())? }; let rewrite = binder.inner_ty.rewrite_result(context, inner_ty_shape)?; From f649c4c1771db3f9a6e4edeabde69978d2c0a340 Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 1 Jan 2025 22:10:06 -0500 Subject: [PATCH 15/16] make `style-edition` a stable option on the CLI --- src/bin/main.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/bin/main.rs b/src/bin/main.rs index 12dcba73b55..b72bad873d9 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -135,6 +135,12 @@ fn make_opts() -> Options { "Rust edition to use", "[2015|2018|2021|2024]", ); + opts.optopt( + "", + "style-edition", + "The edition of the Style Guide (unstable).", + "[2015|2018|2021|2024]", + ); opts.optopt( "", "color", @@ -186,12 +192,6 @@ fn make_opts() -> Options { "skip-children", "Don't reformat child modules (unstable).", ); - opts.optopt( - "", - "style-edition", - "The edition of the Style Guide (unstable).", - "[2015|2018|2021|2024]", - ); } opts.optflag("v", "verbose", "Print verbose output"); @@ -628,6 +628,10 @@ impl GetOptsOptions { options.edition = Some(edition_from_edition_str(edition_str)?); } + if let Some(ref edition_str) = matches.opt_str("style-edition") { + options.style_edition = Some(style_edition_from_style_edition_str(edition_str)?); + } + if matches.opt_present("backup") { options.backup = true; } @@ -654,10 +658,6 @@ impl GetOptsOptions { } } - if let Some(ref edition_str) = matches.opt_str("style-edition") { - options.style_edition = Some(style_edition_from_style_edition_str(edition_str)?); - } - Ok(options) } From 7397eee4875fbe8cbcb582f5f5a199deee83f13d Mon Sep 17 00:00:00 2001 From: Yacin Tmimi Date: Wed, 1 Jan 2025 23:08:35 -0500 Subject: [PATCH 16/16] add `#![feature(unsafe_binders)]` annotation to tests --- tests/source/unsafe-binders.rs | 2 ++ tests/target/unsafe-binders.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/source/unsafe-binders.rs b/tests/source/unsafe-binders.rs index ccf7c8bb9af..df23cd172bb 100644 --- a/tests/source/unsafe-binders.rs +++ b/tests/source/unsafe-binders.rs @@ -1,3 +1,5 @@ +#![feature(unsafe_binders)] + fn foo() -> unsafe<'a> &'a () {} diff --git a/tests/target/unsafe-binders.rs b/tests/target/unsafe-binders.rs index 9d308f4a894..a4009637d2b 100644 --- a/tests/target/unsafe-binders.rs +++ b/tests/target/unsafe-binders.rs @@ -1,3 +1,5 @@ +#![feature(unsafe_binders)] + fn foo() -> unsafe<'a> &'a () {} struct Foo {