diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 631ed54cc024b..2aac669d744a9 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -128,6 +128,17 @@ impl<'a> Diagnostic<'a, ()> } } +/// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait. +pub struct DiagDecorator)>(pub F); + +impl<'a, F: FnOnce(&mut Diag<'_, ()>)> Diagnostic<'a, ()> for DiagDecorator { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let mut diag = Diag::new(dcx, level, ""); + (self.0)(&mut diag); + diag + } +} + /// Trait implemented by error types. This should not be implemented manually. Instead, use /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. #[rustc_diagnostic_item = "Subdiagnostic"] diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 0a111538fc89a..a96eceb6c715d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -36,8 +36,8 @@ pub use anstyle::{ pub use codes::*; pub use decorate_diag::{BufferedEarlyLint, DecorateDiagCompat, LintBuffer}; pub use diagnostic::{ - BugAbort, Diag, DiagInner, DiagLocation, DiagStyledString, Diagnostic, EmissionGuarantee, - FatalAbort, StringPart, Subdiag, Subdiagnostic, + BugAbort, Diag, DiagDecorator, DiagInner, DiagLocation, DiagStyledString, Diagnostic, + EmissionGuarantee, FatalAbort, StringPart, Subdiag, Subdiagnostic, }; pub use diagnostic_impls::{ DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, diff --git a/compiler/rustc_lint/src/default_could_be_derived.rs b/compiler/rustc_lint/src/default_could_be_derived.rs index 0db2f6a3565c7..9d4b79a45453a 100644 --- a/compiler/rustc_lint/src/default_could_be_derived.rs +++ b/compiler/rustc_lint/src/default_could_be_derived.rs @@ -1,5 +1,5 @@ use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{Applicability, Diag}; +use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_hir as hir; use rustc_middle::ty; use rustc_middle::ty::TyCtxt; @@ -147,50 +147,59 @@ impl<'tcx> LateLintPass<'tcx> for DefaultCouldBeDerived { let hir_id = cx.tcx.local_def_id_to_hir_id(impl_id); let span = cx.tcx.hir_span_with_body(hir_id); - cx.tcx.node_span_lint(DEFAULT_OVERRIDES_DEFAULT_FIELDS, hir_id, span, |diag| { - mk_lint(cx.tcx, diag, type_def_id, orig_fields, fields, span); - }); + cx.tcx.emit_node_span_lint( + DEFAULT_OVERRIDES_DEFAULT_FIELDS, + hir_id, + span, + WrongDefaultImpl { tcx: cx.tcx, type_def_id, orig_fields, fields, impl_span: span }, + ); } } -fn mk_lint( - tcx: TyCtxt<'_>, - diag: &mut Diag<'_, ()>, +struct WrongDefaultImpl<'a, 'hir, 'tcx> { + tcx: TyCtxt<'tcx>, type_def_id: DefId, - orig_fields: FxHashMap>, - fields: &[hir::ExprField<'_>], + orig_fields: FxHashMap>, + fields: &'a [hir::ExprField<'hir>], impl_span: Span, -) { - diag.primary_message("`Default` impl doesn't use the declared default field values"); - - // For each field in the struct expression - // - if the field in the type has a default value, it should be removed - // - elif the field is an expression that could be a default value, it should be used as the - // field's default value (FIXME: not done). - // - else, we wouldn't touch this field, it would remain in the manual impl - let mut removed_all_fields = true; - for field in fields { - if orig_fields.get(&field.ident.name).and_then(|f| f.default).is_some() { - diag.span_label(field.expr.span, "this field has a default value"); - } else { - removed_all_fields = false; +} + +impl<'a, 'b, 'hir, 'tcx> Diagnostic<'a, ()> for WrongDefaultImpl<'b, 'hir, 'tcx> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { tcx, type_def_id, orig_fields, fields, impl_span } = self; + let mut diag = + Diag::new(dcx, level, "`Default` impl doesn't use the declared default field values"); + + // For each field in the struct expression + // - if the field in the type has a default value, it should be removed + // - elif the field is an expression that could be a default value, it should be used as the + // field's default value (FIXME: not done). + // - else, we wouldn't touch this field, it would remain in the manual impl + let mut removed_all_fields = true; + for field in fields { + if orig_fields.get(&field.ident.name).and_then(|f| f.default).is_some() { + diag.span_label(field.expr.span, "this field has a default value"); + } else { + removed_all_fields = false; + } } - } - if removed_all_fields { - let msg = "to avoid divergence in behavior between `Struct { .. }` and \ - `::default()`, derive the `Default`"; - diag.multipart_suggestion( - msg, - vec![ - (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()), - (impl_span, String::new()), - ], - Applicability::MachineApplicable, - ); - } else { - let msg = "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ - avoid them diverging over time"; - diag.help(msg); + if removed_all_fields { + diag.multipart_suggestion( + "to avoid divergence in behavior between `Struct { .. }` and \ + `::default()`, derive the `Default`", + vec![ + (tcx.def_span(type_def_id).shrink_to_lo(), "#[derive(Default)] ".to_string()), + (impl_span, String::new()), + ], + Applicability::MachineApplicable, + ); + } else { + diag.help( + "use the default values in the `impl` with `Struct { mandatory_field, .. }` to \ + avoid them diverging over time", + ); + } + diag } } diff --git a/compiler/rustc_lint/src/transmute.rs b/compiler/rustc_lint/src/transmute.rs index cbb9ca6aa00f1..4ee25ac008eb7 100644 --- a/compiler/rustc_lint/src/transmute.rs +++ b/compiler/rustc_lint/src/transmute.rs @@ -357,15 +357,24 @@ fn check_unnecessary_transmute<'tcx>( _ => return, }; - cx.tcx.node_span_lint(UNNECESSARY_TRANSMUTES, expr.hir_id, expr.span, |diag| { - diag.primary_message("unnecessary transmute"); - if let Some(sugg) = sugg { - diag.multipart_suggestion("replace this with", sugg, Applicability::MachineApplicable); - } - if let Some(help) = help { - diag.help(help); - } - }); + cx.tcx.emit_node_span_lint( + UNNECESSARY_TRANSMUTES, + expr.hir_id, + expr.span, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message("unnecessary transmute"); + if let Some(sugg) = sugg { + diag.multipart_suggestion( + "replace this with", + sugg, + Applicability::MachineApplicable, + ); + } + if let Some(help) = help { + diag.help(help); + } + }), + ); } #[derive(Diagnostic)] diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 628d358146846..06e4a287460b2 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -564,9 +564,14 @@ impl<'tcx> TyCtxt<'tcx> { unmarked: impl FnOnce(Span, DefId), ) -> bool { let soft_handler = |lint, span, msg: String| { - self.node_span_lint(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { - lint.primary_message(msg); - }) + self.emit_node_span_lint( + lint, + id.unwrap_or(hir::CRATE_HIR_ID), + span, + rustc_errors::DiagDecorator(|lint| { + lint.primary_message(msg); + }), + ); }; let eval_result = self.eval_stability_allow_unstable(def_id, id, span, method_span, allow_unstable); diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 89034981cbd64..00ac8e66cda75 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -139,15 +139,15 @@ impl<'tcx> TyCtxt<'tcx> { let mir_body = self.mir_for_ctfe(cid.instance.def_id()); if mir_body.is_polymorphic { let Some(local_def_id) = ct.def.as_local() else { return }; - self.node_span_lint( + self.emit_node_span_lint( lint::builtin::CONST_EVALUATABLE_UNCHECKED, self.local_def_id_to_hir_id(local_def_id), self.def_span(ct.def), - |lint| { + rustc_errors::DiagDecorator(|lint| { lint.primary_message( "cannot use constants which depend on generic parameters in types", ); - }, + }), ) } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 64af9e7f0998b..80f748f640871 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -38,6 +38,7 @@ use rustc_hir::lang_items::LangItem; use rustc_hir::limit::Limit; use rustc_hir::{self as hir, CRATE_HIR_ID, HirId, Node, TraitCandidate, find_attr}; use rustc_index::IndexVec; +use rustc_macros::Diagnostic; use rustc_session::Session; use rustc_session::config::CrateType; use rustc_session::cstore::{CrateStoreDyn, Untracked}; @@ -1685,6 +1686,12 @@ impl<'tcx> TyCtxt<'tcx> { } pub fn report_unused_features(self) { + #[derive(Diagnostic)] + #[diag("feature `{$feature}` is declared but not used")] + struct UnusedFeature { + feature: Symbol, + } + // Collect first to avoid holding the lock while linting. let used_features = self.sess.used_features.lock(); let unused_features = self @@ -1703,13 +1710,11 @@ impl<'tcx> TyCtxt<'tcx> { .collect::>(); for (feature, span) in unused_features { - self.node_span_lint( + self.emit_node_span_lint( rustc_session::lint::builtin::UNUSED_FEATURES, CRATE_HIR_ID, span, - |lint| { - lint.primary_message(format!("feature `{}` is declared but not used", feature)); - }, + UnusedFeature { feature }, ); } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/migration.rs b/compiler/rustc_mir_build/src/thir/pattern/migration.rs index 9a5cc08e6c4c5..96021704d3292 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/migration.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/migration.rs @@ -55,10 +55,15 @@ impl<'a> PatMigration<'a> { self.format_subdiagnostics(&mut err); err.emit(); } else { - tcx.node_span_lint(lint::builtin::RUST_2024_INCOMPATIBLE_PAT, pat_id, spans, |diag| { - diag.primary_message(primary_message); - self.format_subdiagnostics(diag); - }); + tcx.emit_node_span_lint( + lint::builtin::RUST_2024_INCOMPATIBLE_PAT, + pat_id, + spans, + rustc_errors::DiagDecorator(|diag| { + diag.primary_message(primary_message); + self.format_subdiagnostics(diag); + }), + ); } } diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 6f0f9cc23a55d..00b67b6564594 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -19,11 +19,11 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( caller_def_id: DefId, callee_only: &[&'a str], ) { - tcx.node_span_lint( + tcx.emit_node_span_lint( lint::builtin::INLINE_ALWAYS_MISMATCHING_TARGET_FEATURES, tcx.local_def_id_to_hir_id(caller_def_id.as_local().unwrap()), call_span, - |lint| { + rustc_errors::DiagDecorator(|lint| { let callee = tcx.def_path_str(callee_def_id); let caller = tcx.def_path_str(caller_def_id); @@ -46,7 +46,7 @@ pub(crate) fn emit_inline_always_target_feature_diagnostic<'a, 'tcx>( format!("#[target_feature(enable = \"{feats}\")]\n"), lint::Applicability::MaybeIncorrect, ); - }, + }), ); } diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index e66aa6bc4a9ea..fa9d617604e50 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -578,10 +578,15 @@ fn report_conflicting_impls<'tcx>( let lint = match kind { FutureCompatOverlapErrorKind::LeakCheck => COHERENCE_LEAK_CHECK, }; - tcx.node_span_lint(lint, tcx.local_def_id_to_hir_id(impl_def_id), impl_span, |err| { - err.primary_message(msg()); - decorate(tcx, &overlap, impl_span, err); - }); + tcx.emit_node_span_lint( + lint, + tcx.local_def_id_to_hir_id(impl_def_id), + impl_span, + rustc_errors::DiagDecorator(|err| { + err.primary_message(msg()); + decorate(tcx, &overlap, impl_span, err); + }), + ); Ok(()) } } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index c472c20a7dc71..2171ca9897799 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -799,14 +799,7 @@ impl<'tcx> ExtraInfo<'tcx> { } fn error_invalid_codeblock_attr(&self, msg: impl Into) { - self.tcx.node_span_lint( - crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.local_def_id_to_hir_id(self.def_id), - self.sp, - |lint| { - lint.primary_message(msg); - }, - ); + self.error_invalid_codeblock_attr_with_help(msg, |_| {}); } fn error_invalid_codeblock_attr_with_help( @@ -814,14 +807,14 @@ impl<'tcx> ExtraInfo<'tcx> { msg: impl Into, f: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>), ) { - self.tcx.node_span_lint( + self.tcx.emit_node_span_lint( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, self.tcx.local_def_id_to_hir_id(self.def_id), self.sp, - |lint| { + rustc_errors::DiagDecorator(|lint| { lint.primary_message(msg); f(lint); - }, + }), ); } } diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index 39116061f4854..40dfdb890d66f 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -6,6 +6,7 @@ //! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doctests. use rustc_hir as hir; +use rustc_macros::Diagnostic; use rustc_middle::lint::{LevelAndSource, LintLevelSource}; use rustc_session::lint; use tracing::debug; @@ -116,6 +117,14 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - } pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) { + #[derive(Diagnostic)] + #[diag("missing code example in this documentation")] + struct MissingCodeExample; + + #[derive(Diagnostic)] + #[diag("documentation test in private item")] + struct DoctestInPrivateItem; + let Some(hir_id) = DocContext::as_local_hir_id(cx.tcx, item.item_id) else { // If non-local, no need to check anything. return; @@ -129,20 +138,21 @@ pub(crate) fn look_for_tests(cx: &DocContext<'_>, dox: &str, item: &Item) { if should_have_doc_example(cx, item) { debug!("reporting error for {item:?} (hir_id={hir_id:?})"); let sp = item.attr_span(cx.tcx); - cx.tcx.node_span_lint(crate::lint::MISSING_DOC_CODE_EXAMPLES, hir_id, sp, |lint| { - lint.primary_message("missing code example in this documentation"); - }); + cx.tcx.emit_node_span_lint( + crate::lint::MISSING_DOC_CODE_EXAMPLES, + hir_id, + sp, + MissingCodeExample, + ); } } else if tests.found_tests > 0 && !cx.cache.effective_visibilities.is_exported(cx.tcx, item.item_id.expect_def_id()) { - cx.tcx.node_span_lint( + cx.tcx.emit_node_span_lint( crate::lint::PRIVATE_DOC_TESTS, hir_id, item.attr_span(cx.tcx), - |lint| { - lint.primary_message("documentation test in private item"); - }, + DoctestInPrivateItem, ); } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 697b35ad8e85b..3e68ed950ce16 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1914,61 +1914,70 @@ fn report_diagnostic( let sp = item.attr_span(tcx); - tcx.node_span_lint(lint, hir_id, sp, |lint| { - lint.primary_message(msg); - - let (span, link_range) = match link_range { - MarkdownLinkRange::Destination(md_range) => { - let mut md_range = md_range.clone(); - let sp = - source_span_for_markdown_range(tcx, dox, &md_range, &item.attrs.doc_strings) - .map(|(mut sp, _)| { - while dox.as_bytes().get(md_range.start) == Some(&b' ') - || dox.as_bytes().get(md_range.start) == Some(&b'`') - { - md_range.start += 1; - sp = sp.with_lo(sp.lo() + BytePos(1)); - } - while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') - || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') - { - md_range.end -= 1; - sp = sp.with_hi(sp.hi() - BytePos(1)); - } - sp - }); - (sp, MarkdownLinkRange::Destination(md_range)) - } - MarkdownLinkRange::WholeLink(md_range) => ( - source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings) - .map(|(sp, _)| sp), - link_range.clone(), - ), - }; + tcx.emit_node_span_lint( + lint, + hir_id, + sp, + rustc_errors::DiagDecorator(|lint| { + lint.primary_message(msg); + + let (span, link_range) = match link_range { + MarkdownLinkRange::Destination(md_range) => { + let mut md_range = md_range.clone(); + let sp = source_span_for_markdown_range( + tcx, + dox, + &md_range, + &item.attrs.doc_strings, + ) + .map(|(mut sp, _)| { + while dox.as_bytes().get(md_range.start) == Some(&b' ') + || dox.as_bytes().get(md_range.start) == Some(&b'`') + { + md_range.start += 1; + sp = sp.with_lo(sp.lo() + BytePos(1)); + } + while dox.as_bytes().get(md_range.end - 1) == Some(&b' ') + || dox.as_bytes().get(md_range.end - 1) == Some(&b'`') + { + md_range.end -= 1; + sp = sp.with_hi(sp.hi() - BytePos(1)); + } + sp + }); + (sp, MarkdownLinkRange::Destination(md_range)) + } + MarkdownLinkRange::WholeLink(md_range) => ( + source_span_for_markdown_range(tcx, dox, md_range, &item.attrs.doc_strings) + .map(|(sp, _)| sp), + link_range.clone(), + ), + }; - if let Some(sp) = span { - lint.span(sp); - } else { - // blah blah blah\nblah\nblah [blah] blah blah\nblah blah - // ^ ~~~~ - // | link_range - // last_new_line_offset - let md_range = link_range.inner_range().clone(); - let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1); - let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); - - // Print the line containing the `md_range` and manually mark it with '^'s. - lint.note(format!( - "the link appears in this line:\n\n{line}\n\ + if let Some(sp) = span { + lint.span(sp); + } else { + // blah blah blah\nblah\nblah [blah] blah blah\nblah blah + // ^ ~~~~ + // | link_range + // last_new_line_offset + let md_range = link_range.inner_range().clone(); + let last_new_line_offset = dox[..md_range.start].rfind('\n').map_or(0, |n| n + 1); + let line = dox[last_new_line_offset..].lines().next().unwrap_or(""); + + // Print the line containing the `md_range` and manually mark it with '^'s. + lint.note(format!( + "the link appears in this line:\n\n{line}\n\ {indicator: { + buffer: &'a Buffer, + code_block: RustCodeBlock, + span: Span, + is_precise_span: bool, + } + + impl<'a, 'b> Diagnostic<'a, ()> for CodeblockError<'b> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { buffer, code_block, span, is_precise_span } = self; + + let mut lint = Diag::new( + dcx, + level, + if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" + }, + ); + + let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; + let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; + + let explanation = if is_ignore { + "`ignore` code blocks require valid Rust code for syntax highlighting; \ + mark blocks that do not contain Rust code as text" + } else { + "mark blocks that do not contain Rust code as text" + }; + + if is_precise_span { + if is_ignore { + // Giving an accurate suggestion is hard because `ignore` might not have come + // first in the list. Just give a `help` instead. + lint.span_help( + span.from_inner(InnerSpan::new(0, 3)), + format!("{explanation}: ```text"), + ); + } else if empty_block { + lint.span_suggestion( + span.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), + explanation, + "text", + Applicability::MachineApplicable, + ); + } + } else if empty_block || is_ignore { + lint.help(format!("{explanation}: ```text")); + } + + // FIXME(#67563): Provide more context for these errors by displaying the spans inline. + for message in buffer.messages.iter() { + lint.note(message.clone()); + } + + lint + } + } + let buffer = Arc::new(Lock::new(Buffer::default())); let emitter = BufferEmitter { buffer: Arc::clone(&buffer) }; let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); let dcx = DiagCtxt::new(Box::new(emitter)).disable_warnings(); - let source = dox[code_block.code] + let source = dox[code_block.code.clone()] .lines() .map(|line| crate::html::markdown::map_line(line).for_code()) .intersperse(Cow::Borrowed("\n")) @@ -75,11 +135,8 @@ fn check_rust_syntax( return; }; - let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced; - let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None; - // The span and whether it is precise or not. - let (sp, precise_span) = match source_span_for_markdown_range( + let (span, is_precise_span) = match source_span_for_markdown_range( cx.tcx, dox, &code_block.range, @@ -89,51 +146,16 @@ fn check_rust_syntax( None => (item.attr_span(cx.tcx), false), }; - let msg = if buffer.has_errors { - "could not parse code block as Rust code" - } else { - "Rust code block is empty" - }; - // Finally build and emit the completed diagnostic. // All points of divergence have been handled earlier so this can be // done the same way whether the span is precise or not. let hir_id = cx.tcx.local_def_id_to_hir_id(local_id); - cx.tcx.node_span_lint(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, |lint| { - lint.primary_message(msg); - - let explanation = if is_ignore { - "`ignore` code blocks require valid Rust code for syntax highlighting; \ - mark blocks that do not contain Rust code as text" - } else { - "mark blocks that do not contain Rust code as text" - }; - - if precise_span { - if is_ignore { - // giving an accurate suggestion is hard because `ignore` might not have come first in the list. - // just give a `help` instead. - lint.span_help( - sp.from_inner(InnerSpan::new(0, 3)), - format!("{explanation}: ```text"), - ); - } else if empty_block { - lint.span_suggestion( - sp.from_inner(InnerSpan::new(0, 3)).shrink_to_hi(), - explanation, - "text", - Applicability::MachineApplicable, - ); - } - } else if empty_block || is_ignore { - lint.help(format!("{explanation}: ```text")); - } - - // FIXME(#67563): Provide more context for these errors by displaying the spans inline. - for message in buffer.messages.iter() { - lint.note(message.clone()); - } - }); + cx.tcx.emit_node_span_lint( + crate::lint::INVALID_RUST_CODEBLOCKS, + hir_id, + span, + CodeblockError { buffer: &buffer, code_block, span, is_precise_span }, + ); } #[derive(Default)] diff --git a/src/librustdoc/passes/lint/html_tags.rs b/src/librustdoc/passes/lint/html_tags.rs index 4e374fe3cd56a..86b8e7b6f86aa 100644 --- a/src/librustdoc/passes/lint/html_tags.rs +++ b/src/librustdoc/passes/lint/html_tags.rs @@ -21,86 +21,91 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & Some((sp, _)) => sp, None => item.attr_span(tcx), }; - tcx.node_span_lint(crate::lint::INVALID_HTML_TAGS, hir_id, sp, |lint| { - use rustc_lint_defs::Applicability; + tcx.emit_node_span_lint( + crate::lint::INVALID_HTML_TAGS, + hir_id, + sp, + rustc_errors::DiagDecorator(|lint| { + use rustc_lint_defs::Applicability; - lint.primary_message(msg); + lint.primary_message(msg); - // If a tag looks like ``, it might actually be a generic. - // We don't try to detect stuff `` because that's not valid HTML, - // and we don't try to detect stuff `` because that's not valid Rust. - let mut generics_end = range.end; - if is_open_tag - && dox[..generics_end].ends_with('>') - && let Some(mut generics_start) = extract_path_backwards(dox, range.start) - { - while generics_start != 0 - && generics_end < dox.len() - && dox.as_bytes()[generics_start - 1] == b'<' - && dox.as_bytes()[generics_end] == b'>' + // If a tag looks like ``, it might actually be a generic. + // We don't try to detect stuff `` because that's not valid HTML, + // and we don't try to detect stuff `` because that's not valid Rust. + let mut generics_end = range.end; + if is_open_tag + && dox[..generics_end].ends_with('>') + && let Some(mut generics_start) = extract_path_backwards(dox, range.start) { - generics_end += 1; - generics_start -= 1; - if let Some(new_start) = extract_path_backwards(dox, generics_start) { - generics_start = new_start; + while generics_start != 0 + && generics_end < dox.len() + && dox.as_bytes()[generics_start - 1] == b'<' + && dox.as_bytes()[generics_end] == b'>' + { + generics_end += 1; + generics_start -= 1; + if let Some(new_start) = extract_path_backwards(dox, generics_start) { + generics_start = new_start; + } + if let Some(new_end) = extract_path_forward(dox, generics_end) { + generics_end = new_end; + } } if let Some(new_end) = extract_path_forward(dox, generics_end) { generics_end = new_end; } + let generics_sp = match source_span_for_markdown_range( + tcx, + dox, + &(generics_start..generics_end), + &item.attrs.doc_strings, + ) { + Some((sp, _)) => sp, + None => item.attr_span(tcx), + }; + // Sometimes, we only extract part of a path. For example, consider this: + // + // <[u32] as IntoIter>::Item + // ^^^^^ unclosed HTML tag `u32` + // + // We don't have any code for parsing fully-qualified trait paths. + // In theory, we could add it, but doing it correctly would require + // parsing the entire path grammar, which is problematic because of + // overlap between the path grammar and Markdown. + // + // The example above shows that ambiguity. Is `[u32]` intended to be an + // intra-doc link to the u32 primitive, or is it intended to be a slice? + // + // If the below conditional were removed, we would suggest this, which is + // not what the user probably wants. + // + // <[u32] as `IntoIter`>::Item + // + // We know that the user actually wants to wrap the whole thing in a code + // block, but the only reason we know that is because `u32` does not, in + // fact, implement IntoIter. If the example looks like this: + // + // <[Vec] as IntoIter::Item + // + // The ideal fix would be significantly different. + if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') + || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') + { + return; + } + // multipart form is chosen here because ``Vec`` would be confusing. + lint.multipart_suggestion( + "try marking as source code", + vec![ + (generics_sp.shrink_to_lo(), String::from("`")), + (generics_sp.shrink_to_hi(), String::from("`")), + ], + Applicability::MaybeIncorrect, + ); } - if let Some(new_end) = extract_path_forward(dox, generics_end) { - generics_end = new_end; - } - let generics_sp = match source_span_for_markdown_range( - tcx, - dox, - &(generics_start..generics_end), - &item.attrs.doc_strings, - ) { - Some((sp, _)) => sp, - None => item.attr_span(tcx), - }; - // Sometimes, we only extract part of a path. For example, consider this: - // - // <[u32] as IntoIter>::Item - // ^^^^^ unclosed HTML tag `u32` - // - // We don't have any code for parsing fully-qualified trait paths. - // In theory, we could add it, but doing it correctly would require - // parsing the entire path grammar, which is problematic because of - // overlap between the path grammar and Markdown. - // - // The example above shows that ambiguity. Is `[u32]` intended to be an - // intra-doc link to the u32 primitive, or is it intended to be a slice? - // - // If the below conditional were removed, we would suggest this, which is - // not what the user probably wants. - // - // <[u32] as `IntoIter`>::Item - // - // We know that the user actually wants to wrap the whole thing in a code - // block, but the only reason we know that is because `u32` does not, in - // fact, implement IntoIter. If the example looks like this: - // - // <[Vec] as IntoIter::Item - // - // The ideal fix would be significantly different. - if (generics_start > 0 && dox.as_bytes()[generics_start - 1] == b'<') - || (generics_end < dox.len() && dox.as_bytes()[generics_end] == b'>') - { - return; - } - // multipart form is chosen here because ``Vec`` would be confusing. - lint.multipart_suggestion( - "try marking as source code", - vec![ - (generics_sp.shrink_to_lo(), String::from("`")), - (generics_sp.shrink_to_hi(), String::from("`")), - ], - Applicability::MaybeIncorrect, - ); - } - }); + }), + ); }; let mut tagp = TagParser::new(); diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index e49f54f6df946..84dba5d2f1153 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -1,7 +1,7 @@ use std::ops::Range; use rustc_ast::NodeId; -use rustc_errors::SuggestionStyle; +use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level, SuggestionStyle}; use rustc_hir::HirId; use rustc_hir::def::{DefKind, DocLinkResMap, Namespace, Res}; use rustc_lint_defs::Applicability; @@ -9,8 +9,8 @@ use rustc_resolve::rustdoc::pulldown_cmark::{ BrokenLink, BrokenLinkCallback, CowStr, Event, LinkType, OffsetIter, Parser, Tag, }; use rustc_resolve::rustdoc::{prepare_to_doc_link_resolution, source_span_for_markdown_range}; -use rustc_span::Symbol; use rustc_span::def_id::DefId; +use rustc_span::{Span, Symbol}; use crate::clean::Item; use crate::clean::utils::{find_nearest_parent_module, inherits_doc_hidden}; @@ -154,6 +154,42 @@ fn check_inline_or_reference_unknown_redundancy( link_data: LinkData, (open, close): (u8, u8), ) -> Option<()> { + struct RedundantExplicitLinks { + explicit_span: Span, + display_span: Span, + link_span: Span, + display_link: String, + } + + impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinks { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { explicit_span, display_span, link_span, display_link } = self; + + let mut diag = Diag::new(dcx, level, "redundant explicit link target") + .with_span_label( + explicit_span, + "explicit target is redundant", + ) + .with_span_label( + display_span, + "because label contains path that resolves to same destination", + ) + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ); + // FIXME (GuillaumeGomez): We cannot use `derive(Diagnostic)` because of this method. + // FIXME2 (GuillaumeGomez): Why isn't there a `with_` equivalent for this method? + diag.span_suggestion_with_style( + link_span, + "remove explicit link target", + format!("[{}]", display_link), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + diag + } + } + let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); let (dest_res, display_res) = @@ -192,13 +228,17 @@ fn check_inline_or_reference_unknown_redundancy( return None; }; - cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| { - lint.primary_message("redundant explicit link target") - .span_label(explicit_span, "explicit target is redundant") - .span_label(display_span, "because label contains path that resolves to same destination") - .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") - .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - }); + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + explicit_span, + RedundantExplicitLinks { + explicit_span, + display_span, + link_span, + display_link: link_data.display_link, + }, + ); } None @@ -215,6 +255,41 @@ fn check_reference_redundancy( dest: &CowStr<'_>, link_data: LinkData, ) -> Option<()> { + struct RedundantExplicitLinkTarget { + explicit_span: Span, + display_span: Span, + def_span: Span, + link_span: Span, + display_link: String, + } + + impl<'a> Diagnostic<'a, ()> for RedundantExplicitLinkTarget { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + let Self { explicit_span, display_span, def_span, link_span, display_link } = self; + + let mut diag = Diag::new(dcx, level, "redundant explicit link target") + .with_span_label(explicit_span, "explicit target is redundant") + .with_span_label( + display_span, + "because label contains path that resolves to same destination", + ) + .with_span_note(def_span, "referenced explicit link target defined here") + .with_note( + "when a link's destination is not specified,\nthe label is used to resolve intra-doc links" + ); + // FIXME (GuillaumeGomez): We cannot use `derive(Diagnostic)` because of this method. + // FIXME2 (GuillaumeGomez): Why isn't there a `with_` equivalent for this method? + diag.span_suggestion_with_style( + link_span, + "remove explicit link target", + format!("[{}]", display_link), + Applicability::MaybeIncorrect, + SuggestionStyle::ShowAlways, + ); + diag + } + } + let (resolvable_link, resolvable_link_range) = (&link_data.resolvable_link?, &link_data.resolvable_link_range?); let (dest_res, display_res) = @@ -259,14 +334,18 @@ fn check_reference_redundancy( &item.attrs.doc_strings, )?; - cx.tcx.node_span_lint(crate::lint::REDUNDANT_EXPLICIT_LINKS, hir_id, explicit_span, |lint| { - lint.primary_message("redundant explicit link target") - .span_label(explicit_span, "explicit target is redundant") - .span_label(display_span, "because label contains path that resolves to same destination") - .span_note(def_span, "referenced explicit link target defined here") - .note("when a link's destination is not specified,\nthe label is used to resolve intra-doc links") - .span_suggestion_with_style(link_span, "remove explicit link target", format!("[{}]", link_data.display_link), Applicability::MaybeIncorrect, SuggestionStyle::ShowAlways); - }); + cx.tcx.emit_node_span_lint( + crate::lint::REDUNDANT_EXPLICIT_LINKS, + hir_id, + explicit_span, + RedundantExplicitLinkTarget { + explicit_span, + display_span, + def_span, + link_span, + display_link: link_data.display_link, + }, + ); } None diff --git a/src/librustdoc/passes/lint/unescaped_backticks.rs b/src/librustdoc/passes/lint/unescaped_backticks.rs index b791e024545fd..4c33b82d14b44 100644 --- a/src/librustdoc/passes/lint/unescaped_backticks.rs +++ b/src/librustdoc/passes/lint/unescaped_backticks.rs @@ -52,7 +52,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & None => item.attr_span(tcx), }; - tcx.node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, |lint| { + tcx.emit_node_span_lint(crate::lint::UNESCAPED_BACKTICKS, hir_id, span, rustc_errors::DiagDecorator(|lint| { lint.primary_message("unescaped backtick"); let mut help_emitted = false; @@ -156,7 +156,7 @@ pub(crate) fn visit_item(cx: &DocContext<'_>, item: &Item, hir_id: HirId, dox: & '\\', "if you meant to use a literal backtick, escape it", ); - }); + })); } Event::Code(_) => { let element = element_stack diff --git a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr index 41164e99e6d0b..0558def70cfff 100644 --- a/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr +++ b/tests/ui/coherence/coherence-fn-covariant-bound-vs-static.stderr @@ -6,9 +6,9 @@ LL | impl Trait for for<'r> fn(fn(&'r ())) {} LL | impl<'a> Trait for fn(fn(&'a ())) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'r> fn(fn(&'r ()))` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-fn-implied-bounds.stderr b/tests/ui/coherence/coherence-fn-implied-bounds.stderr index ece3288989d74..aaad1acb22353 100644 --- a/tests/ui/coherence/coherence-fn-implied-bounds.stderr +++ b/tests/ui/coherence/coherence-fn-implied-bounds.stderr @@ -7,9 +7,9 @@ LL | LL | impl Trait for for<'c> fn(&'c &'c u32, &'c &'c u32) -> &'c u32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a &'b u32, &'b &'a u32) -> &'b u32` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here --> $DIR/coherence-fn-implied-bounds.rs:15:9 | diff --git a/tests/ui/coherence/coherence-fn-inputs.stderr b/tests/ui/coherence/coherence-fn-inputs.stderr index 75df33913a97c..6a0f2ee2b1c2a 100644 --- a/tests/ui/coherence/coherence-fn-inputs.stderr +++ b/tests/ui/coherence/coherence-fn-inputs.stderr @@ -6,9 +6,9 @@ LL | impl Trait for for<'a, 'b> fn(&'a u32, &'b u32) {} LL | impl Trait for for<'c> fn(&'c u32, &'c u32) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u32, &'b u32)` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-free-vs-bound-region.stderr b/tests/ui/coherence/coherence-free-vs-bound-region.stderr index e45cf5ad3a4c5..9884e1b041ad7 100644 --- a/tests/ui/coherence/coherence-free-vs-bound-region.stderr +++ b/tests/ui/coherence/coherence-free-vs-bound-region.stderr @@ -7,9 +7,9 @@ LL | LL | impl TheTrait for fn(&u8) { | ^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&u8)` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details note: the lint level is defined here --> $DIR/coherence-free-vs-bound-region.rs:10:9 | diff --git a/tests/ui/coherence/coherence-subtyping.stderr b/tests/ui/coherence/coherence-subtyping.stderr index f380ea878291a..7817d929da976 100644 --- a/tests/ui/coherence/coherence-subtyping.stderr +++ b/tests/ui/coherence/coherence-subtyping.stderr @@ -7,9 +7,9 @@ LL | LL | impl TheTrait for for<'a> fn(&'a u8, &'a u8) -> &'a u8 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a, 'b> fn(&'a u8, &'b u8) -> &'a u8` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default warning: 1 warning emitted diff --git a/tests/ui/coherence/coherence-wasm-bindgen.stderr b/tests/ui/coherence/coherence-wasm-bindgen.stderr index 939f1fce9a40a..65c64b9beece0 100644 --- a/tests/ui/coherence/coherence-wasm-bindgen.stderr +++ b/tests/ui/coherence/coherence-wasm-bindgen.stderr @@ -13,10 +13,10 @@ LL | | A: RefFromWasmAbi, LL | | R: ReturnWasmAbi, | |_____________________^ conflicting implementation for `&dyn Fn(&_) -> _` | - = warning: the behavior may change in a future release - = note: for more information, see issue #56105 = note: downstream crates may implement trait `FromWasmAbi` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = warning: the behavior may change in a future release + = note: for more information, see issue #56105 note: the lint level is defined here --> $DIR/coherence-wasm-bindgen.rs:10:9 | diff --git a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr index 8d59cbc3466ba..697a1bc81dbf2 100644 --- a/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr +++ b/tests/ui/coherence/negative-coherence-placeholder-region-constraints-on-unification.explicit.stderr @@ -6,10 +6,10 @@ LL | impl FnMarker for fn(T) {} LL | impl FnMarker for fn(&T) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `fn(&_)` | - = warning: the behavior may change in a future release - = note: for more information, see issue #56105 = note: downstream crates may implement trait `Marker` for type `&_` = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details + = warning: the behavior may change in a future release + = note: for more information, see issue #56105 note: the lint level is defined here --> $DIR/negative-coherence-placeholder-region-constraints-on-unification.rs:4:11 | diff --git a/tests/ui/const-generics/invariant.stderr b/tests/ui/const-generics/invariant.stderr index 095219f6e5fae..465f708d8f132 100644 --- a/tests/ui/const-generics/invariant.stderr +++ b/tests/ui/const-generics/invariant.stderr @@ -7,9 +7,9 @@ LL | impl SadBee for for<'a> fn(&'a ()) { LL | impl SadBee for fn(&'static ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `for<'a> fn(&'a ())` | + = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = warning: the behavior may change in a future release = note: for more information, see issue #56105 - = note: this behavior recently changed as a result of a bug fix; see rust-lang/rust#56105 for details = note: `#[warn(coherence_leak_check)]` (part of `#[warn(future_incompatible)]`) on by default error[E0308]: mismatched types diff --git a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr index 01fcfdc8be6ee..4963e80ec8ccd 100644 --- a/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr +++ b/tests/ui/pattern/rfc-3627-match-ergonomics-2024/migration_lint.stderr @@ -4,13 +4,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Foo(mut x) = &Foo(0); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:25:9 | LL | let Foo(mut x) = &Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see note: the lint level is defined here --> $DIR/migration_lint.rs:7:9 | @@ -27,13 +27,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Foo(mut x) = &mut Foo(0); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:30:9 | LL | let Foo(mut x) = &mut Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(mut x) = &mut Foo(0); @@ -45,13 +45,13 @@ error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2 LL | let Foo(ref x) = &Foo(0); | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:35:9 | LL | let Foo(ref x) = &Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: remove the unnecessary binding modifier | LL - let Foo(ref x) = &Foo(0); @@ -64,13 +64,13 @@ error: cannot explicitly borrow within an implicitly-borrowing pattern in Rust 2 LL | let Foo(ref x) = &mut Foo(0); | ^^^ explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:40:9 | LL | let Foo(ref x) = &mut Foo(0); | ^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(ref x) = &mut Foo(0); @@ -82,13 +82,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&x) = &Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:57:9 | LL | let Foo(&x) = &Foo(&0); | ^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&x) = &Foo(&0); @@ -100,13 +100,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&mut x) = &Foo(&mut 0); | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:62:9 | LL | let Foo(&mut x) = &Foo(&mut 0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&mut x) = &Foo(&mut 0); @@ -118,13 +118,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&x) = &mut Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:67:9 | LL | let Foo(&x) = &mut Foo(&0); | ^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&x) = &mut Foo(&0); @@ -136,13 +136,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&mut x) = &mut Foo(&mut 0); | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:72:9 | LL | let Foo(&mut x) = &mut Foo(&mut 0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &mut Foo(&mut x) = &mut Foo(&mut 0); @@ -154,13 +154,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&x) = &&&&&Some(&0u8) { | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:81:12 | LL | if let Some(&x) = &&&&&Some(&0u8) { | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&x) = &&&&&Some(&0u8) { @@ -172,13 +172,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:87:12 | LL | if let Some(&mut x) = &&&&&Some(&mut 0u8) { | ^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&Some(&mut x) = &&&&&Some(&mut 0u8) { @@ -190,13 +190,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&x) = &&&&&mut Some(&0u8) { | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:93:12 | LL | if let Some(&x) = &&&&&mut Some(&0u8) { | ^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | if let &&&&&mut Some(&x) = &&&&&mut Some(&0u8) { @@ -208,13 +208,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { | ^^^^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:99:12 | LL | if let Some(&mut Some(Some(x))) = &mut Some(&mut Some(&mut Some(0u8))) { | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &mut Some(&mut Some(&mut Some(ref mut x))) = &mut Some(&mut Some(&mut Some(0u8))) { @@ -226,13 +226,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:111:9 | LL | let Struct { a, mut b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using variable binding modes | LL | let &Struct { ref a, mut b, ref c } = &Struct { a: 0, b: 0, c: 0 }; @@ -246,13 +246,13 @@ LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:117:9 | LL | let Struct { a: &a, b, ref c } = &Struct { a: &0, b: &0, c: &0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &Struct { a: &a, ref b, ref c } = &Struct { a: &0, b: &0, c: &0 }; @@ -266,13 +266,13 @@ LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:124:12 | LL | if let Struct { a: &Some(a), b: Some(&b), c: Some(c) } = | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | if let &Struct { a: &Some(a), b: &Some(&b), c: &Some(ref c) } = @@ -306,8 +306,6 @@ LL | let [&mut [ref a]] = &mut [&mut &[0]]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:145:15 | @@ -318,6 +316,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [&mut [ref a]] = &mut [&mut &[0]]; | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let &mut [&mut &[ref a]] = &mut [&mut &[0]]; @@ -329,13 +329,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let [&(_)] = &[&0]; | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:150:9 | LL | let [&(_)] = &[&0]; | ^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&(_)] = &[&0]; @@ -349,13 +349,13 @@ LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; | | | explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:157:9 | LL | let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: remove the unnecessary binding modifiers | LL - let Struct { ref a, ref b, c } = &Struct { a: 0, b: 0, c: 0 }; @@ -370,13 +370,13 @@ LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; | | | explicit `ref` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:164:9 | LL | let Struct { ref a, ref mut b, c } = &mut Struct { a: 0, b: 0, c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&mut _` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &mut Struct { ref a, ref mut b, ref mut c } = &mut Struct { a: 0, b: 0, c: 0 }; @@ -390,13 +390,13 @@ LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:172:9 | LL | let Struct { a: &[ref a], b: &mut [[b]], c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &mut &Struct { a: &[ref a], b: &mut [&[ref b]], ref c } = &mut &Struct { a: &[0], b: &mut [&[0]], c: 0 }; @@ -408,13 +408,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let Foo(&ref a) = &Foo(&0); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:180:9 | LL | let Foo(&ref a) = &Foo(&0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &Foo(&ref a) = &Foo(&0); @@ -426,13 +426,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:186:9 | LL | let (&a, b, [c], [(d, [e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); | ^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(&a, ref b, &[ref c], &mut [&mut (ref d, &[ref e])]) = &(&0, 0, &[0], &mut [&mut (0, &[0])]); @@ -444,13 +444,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:196:9 | LL | let (a, [b], [mut c]) = &(0, &mut [0], &[0]); | ^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using variable binding modes | LL | let &(ref a, &mut [ref b], &[mut c]) = &(0, &mut [0], &[0]); @@ -464,13 +464,13 @@ LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:204:9 | LL | let (&a, (b, &[ref c])) = &(&0, &mut (0, &[0])); | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns and borrow explicitly using a variable binding mode | LL | let &(&a, &mut (ref b, &[ref c])) = &(&0, &mut (0, &[0])); @@ -482,13 +482,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let [mut a @ b] = &[0]; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:212:9 | LL | let [mut a @ b] = &[0]; | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[mut a @ ref b] = &[0]; @@ -500,13 +500,13 @@ error: cannot mutably bind by value within an implicitly-borrowing pattern in Ru LL | let [a @ mut b] = &[0]; | ^^^ `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:219:9 | LL | let [a @ mut b] = &[0]; | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern and borrow explicitly using a variable binding mode | LL | let &[ref a @ mut b] = &[0]; @@ -520,8 +520,6 @@ LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:226:31 | @@ -532,6 +530,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [Foo(&ref a @ ref b), Foo(&ref c @ d)] = [&Foo(&0); 2]; | ^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ ref b), &Foo(&ref c @ d)] = [&Foo(&0); 2]; @@ -545,8 +545,6 @@ LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | | | reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:235:33 | @@ -557,6 +555,8 @@ note: matching on a reference type with a non-reference pattern implicitly borro | LL | let [Foo(&ref a @ [ref b]), Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; | ^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on these references with reference patterns to avoid implicitly borrowing | LL | let [&Foo(&ref a @ [ref b]), &Foo(&ref c @ [d])] = [&Foo(&[0]); 2]; @@ -586,13 +586,13 @@ error: cannot explicitly dereference within an implicitly-borrowing pattern in R LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; | ^ reference pattern not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:249:9 | LL | let [&migration_lint_macros::bind_ref!(a)] = &[&0]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &[&migration_lint_macros::bind_ref!(a)] = &[&0]; @@ -606,13 +606,13 @@ LL | let (mut a, ref b) = &(0, 0); | | | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:255:9 | LL | let (mut a, ref b) = &(0, 0); | ^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, ref b) = &(0, 0); @@ -626,13 +626,13 @@ LL | let (mut a, &b) = &(0, &0); | | | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:261:9 | LL | let (mut a, &b) = &(0, &0); | ^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, &b) = &(0, &0); @@ -647,13 +647,13 @@ LL | let (mut a, ref b, &c) = &(0, 0, &0); | | explicit `ref` binding modifier not allowed when implicitly borrowing | `mut` binding modifier not allowed when implicitly borrowing | - = warning: this changes meaning in Rust 2024 - = note: for more information, see note: matching on a reference type with a non-reference pattern implicitly borrows the contents --> $DIR/migration_lint.rs:267:9 | LL | let (mut a, ref b, &c) = &(0, 0, &0); | ^^^^^^^^^^^^^^^^^^ this non-reference pattern matches on a reference type `&_` + = warning: this changes meaning in Rust 2024 + = note: for more information, see help: match on the reference with a reference pattern to avoid implicitly borrowing | LL | let &(mut a, ref b, &c) = &(0, 0, &0);