diff --git a/src/config/summary.rs b/src/config/summary.rs index 53d2c0a2f20..1ef6d18a540 100644 --- a/src/config/summary.rs +++ b/src/config/summary.rs @@ -23,6 +23,9 @@ pub struct Summary { // Code is valid, but it is impossible to format it properly. has_formatting_errors: bool, + // Code contains macro call that was unable to format. + pub(crate) has_macro_format_failure: bool, + // Failed a check, such as the license check or other opt-in checking. has_check_errors: bool, @@ -80,6 +83,10 @@ impl Summary { self.has_check_errors } + pub(crate) fn has_macro_formatting_failure(&self) -> bool { + self.has_macro_format_failure + } + pub fn add_operational_error(&mut self) { self.has_operational_errors = true; } @@ -100,6 +107,10 @@ impl Summary { self.has_diff = true; } + pub(crate) fn add_macro_foramt_failure(&mut self) { + self.has_macro_format_failure = true; + } + pub fn has_no_errors(&self) -> bool { !(self.has_operational_errors || self.has_parsing_errors diff --git a/src/lib.rs b/src/lib.rs index 02307a8dc6d..8d4cbb51b5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -422,13 +422,14 @@ fn format_ast<F>( config: &Config, report: FormatReport, mut after_file: F, -) -> Result<(FileMap, bool), io::Error> +) -> Result<(FileMap, bool, bool), io::Error> where F: FnMut(&FileName, &mut String, &[(usize, usize)], &FormatReport) -> Result<bool, io::Error>, { let mut result = FileMap::new(); // diff mode: check if any files are differing let mut has_diff = false; + let mut has_macro_rewrite_failure = false; let skip_children = config.skip_children(); for (path, module) in modules::list_files(krate, parse_session.codemap())? { @@ -472,10 +473,12 @@ where } }; + has_macro_rewrite_failure |= visitor.macro_rewrite_failure; + result.push((path.clone(), visitor.buffer)); } - Ok((result, has_diff)) + Ok((result, has_diff, has_macro_rewrite_failure)) } /// Returns true if the line with the given line number was skipped by `#[rustfmt::skip]`. @@ -686,6 +689,7 @@ fn format_snippet(snippet: &str, config: &Config) -> Option<String> { config.set().hide_parse_errors(true); match format_input(input, &config, Some(&mut out)) { // `format_input()` returns an empty string on parsing error. + Ok((summary, _)) if summary.has_macro_formatting_failure() => None, Ok(..) if out.is_empty() && !snippet.is_empty() => None, Ok(..) => String::from_utf8(out).ok(), Err(..) => None, @@ -902,7 +906,7 @@ fn format_input_inner<T: Write>( } match format_result { - Ok((file_map, has_diff)) => { + Ok((file_map, has_diff, has_macro_rewrite_failure)) => { if report.has_warnings() { summary.add_formatting_error(); } @@ -911,6 +915,10 @@ fn format_input_inner<T: Write>( summary.add_diff(); } + if has_macro_rewrite_failure { + summary.add_macro_foramt_failure(); + } + Ok((summary, file_map, report)) } Err(e) => Err((From::from(e), summary)), diff --git a/src/macros.rs b/src/macros.rs index ae95acaf301..9053aaebd90 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -129,6 +129,15 @@ fn rewrite_macro_name(path: &ast::Path, extra_ident: Option<ast::Ident>) -> Stri } } +// Use this on failing to format the macro call. +fn return_original_snippet_with_failure_marked( + context: &RewriteContext, + span: Span, +) -> Option<String> { + context.macro_rewrite_failure.replace(true); + Some(context.snippet(span).to_owned()) +} + pub fn rewrite_macro( mac: &ast::Mac, extra_ident: Option<ast::Ident>, @@ -138,6 +147,9 @@ pub fn rewrite_macro( ) -> Option<String> { context.inside_macro.replace(true); let result = rewrite_macro_inner(mac, extra_ident, context, shape, position); + if result.is_none() { + context.macro_rewrite_failure.replace(true); + } context.inside_macro.replace(false); result } @@ -196,7 +208,7 @@ pub fn rewrite_macro_inner( loop { match parse_macro_arg(&mut parser) { Some(arg) => arg_vec.push(arg), - None => return Some(context.snippet(mac.span).to_owned()), + None => return return_original_snippet_with_failure_marked(context, mac.span), } match parser.token { @@ -216,13 +228,17 @@ pub fn rewrite_macro_inner( break; } } - None => return Some(context.snippet(mac.span).to_owned()), + None => { + return return_original_snippet_with_failure_marked( + context, mac.span, + ) + } } } } - return Some(context.snippet(mac.span).to_owned()); + return return_original_snippet_with_failure_marked(context, mac.span); } - _ => return Some(context.snippet(mac.span).to_owned()), + _ => return return_original_snippet_with_failure_marked(context, mac.span), } parser.bump(); diff --git a/src/rewrite.rs b/src/rewrite.rs index 00c03a3c879..90b613df6c4 100644 --- a/src/rewrite.rs +++ b/src/rewrite.rs @@ -39,6 +39,8 @@ pub struct RewriteContext<'a> { // When rewriting chain, veto going multi line except the last element pub force_one_line_chain: RefCell<bool>, pub snippet_provider: &'a SnippetProvider<'a>, + // Used for `format_snippet` + pub(crate) macro_rewrite_failure: RefCell<bool>, pub(crate) report: FormatReport, } diff --git a/src/visitor.rs b/src/visitor.rs index 4a0ce4399a4..7d676770421 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -70,6 +70,7 @@ pub struct FmtVisitor<'a> { pub snippet_provider: &'a SnippetProvider<'a>, pub line_number: usize, pub skipped_range: Vec<(usize, usize)>, + pub macro_rewrite_failure: bool, pub(crate) report: FormatReport, } @@ -519,7 +520,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { // 1 = ; let shape = self.shape().sub_width(1).unwrap(); - let rewrite = rewrite_macro(mac, ident, &self.get_context(), shape, pos); + let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos)); self.push_rewrite(mac.span, rewrite); } @@ -578,6 +579,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { snippet_provider, line_number: 0, skipped_range: vec![], + macro_rewrite_failure: false, report, } } @@ -736,6 +738,20 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { } } + pub fn with_context<F>(&mut self, f: F) -> Option<String> + where + F: Fn(&RewriteContext) -> Option<String>, + { + let result; + let macro_rewrite_failure = { + let context = self.get_context(); + result = f(&context); + unsafe { *context.macro_rewrite_failure.as_ptr() } + }; + self.macro_rewrite_failure |= macro_rewrite_failure; + result + } + pub fn get_context(&self) -> RewriteContext { RewriteContext { parse_session: self.parse_session, @@ -746,6 +762,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> { is_if_else_block: RefCell::new(false), force_one_line_chain: RefCell::new(false), snippet_provider: self.snippet_provider, + macro_rewrite_failure: RefCell::new(false), report: self.report.clone(), } } diff --git a/tests/source/macro_rules.rs b/tests/source/macro_rules.rs index 5ed5f905883..fdcde7f6f59 100644 --- a/tests/source/macro_rules.rs +++ b/tests/source/macro_rules.rs @@ -204,3 +204,30 @@ macro_rules! foo { macro_rules! __wundergraph_expand_sqlite_mutation { ( $mutation_name:ident $((context = $($context:tt)*))*{ $( $entity_name:ident( $(insert = $insert:ident,)* $(update = $update:ident,)* $(delete = $($delete:tt)+)* ), )* } ) => {}; } + +// #2607 +macro_rules! bench { + ($ty:ident) => { + criterion_group!( + name = benches; + config = ::common_bench::reduced_samples(); + targets = call, map; + ); + }; +} + +// #2770 +macro_rules! save_regs { + () => { + asm!("push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11" + :::: "intel", "volatile"); + }; +} diff --git a/tests/target/issue-2523.rs b/tests/target/issue-2523.rs index 6805f7ec2ca..d908831c21c 100644 --- a/tests/target/issue-2523.rs +++ b/tests/target/issue-2523.rs @@ -2,7 +2,7 @@ // Do not unindent macro calls in comment with unformattable syntax. //! ```rust -//! let x = 3; +//! let x = 3 ; //! some_macro!(pub fn fn foo() ( //! println!("Don't unindent me!"); //! )); diff --git a/tests/target/macro_rules.rs b/tests/target/macro_rules.rs index c366d75cf91..66790091f86 100644 --- a/tests/target/macro_rules.rs +++ b/tests/target/macro_rules.rs @@ -246,3 +246,30 @@ macro_rules! __wundergraph_expand_sqlite_mutation { } ) => {}; } + +// #2607 +macro_rules! bench { + ($ty:ident) => { + criterion_group!( + name = benches; + config = ::common_bench::reduced_samples(); + targets = call, map; + ); + }; +} + +// #2770 +macro_rules! save_regs { + () => { + asm!("push rax + push rcx + push rdx + push rsi + push rdi + push r8 + push r9 + push r10 + push r11" + :::: "intel", "volatile"); + }; +}