diff --git a/compiler/rustc_errors/src/decorate_diag.rs b/compiler/rustc_errors/src/decorate_diag.rs index 61dd8f0493f9..321591469889 100644 --- a/compiler/rustc_errors/src/decorate_diag.rs +++ b/compiler/rustc_errors/src/decorate_diag.rs @@ -1,3 +1,5 @@ +use std::any::Any; + /// This module provides types and traits for buffering lints until later in compilation. use rustc_ast::node_id::NodeId; use rustc_data_structures::fx::FxIndexMap; @@ -10,9 +12,11 @@ /// We can't implement `Diagnostic` for `BuiltinLintDiag`, because decorating some of its /// variants requires types we don't have yet. So, handle that case separately. pub enum DecorateDiagCompat { + /// The third argument of the closure is a `Session`. However, due to the dependency tree, + /// we don't have access to `rustc_session` here, so we downcast it when needed. Dynamic( Box< - dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level) -> Diag<'a, ()> + dyn for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()> + DynSync + DynSend + 'static, @@ -30,7 +34,7 @@ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { impl Diagnostic<'a, ()> + DynSync + DynSend + 'static> From for DecorateDiagCompat { #[inline] fn from(d: D) -> Self { - Self::Dynamic(Box::new(|dcx, level| d.into_diag(dcx, level))) + Self::Dynamic(Box::new(|dcx, level, _| d.into_diag(dcx, level))) } } @@ -97,6 +101,26 @@ pub fn dyn_buffer_lint< node_id: NodeId, span: impl Into, callback: F, + ) { + self.add_early_lint(BufferedEarlyLint { + lint_id: LintId::of(lint), + node_id, + span: Some(span.into()), + diagnostic: DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))), + }); + } + + pub fn dyn_buffer_lint_any< + F: for<'a> FnOnce(DiagCtxtHandle<'a>, Level, &dyn Any) -> Diag<'a, ()> + + DynSend + + DynSync + + 'static, + >( + &mut self, + lint: &'static Lint, + node_id: NodeId, + span: impl Into, + callback: F, ) { self.add_early_lint(BufferedEarlyLint { lint_id: LintId::of(lint), diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 9525a45d55f1..7acf95d77d40 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -7,7 +7,6 @@ use std::path::PathBuf; use std::thread::panicking; -use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_error_messages::{DiagArgMap, DiagArgName, DiagArgValue, IntoDiagArg}; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -119,16 +118,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { } } -impl<'a> Diagnostic<'a, ()> - for Box< - dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level) -> Diag<'b, ()> + DynSync + DynSend + 'static, - > -{ - fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { - self(dcx, level) - } -} - /// Type used to emit diagnostic through a closure instead of implementing the `Diagnostic` trait. pub struct DiagDecorator)>(pub F); diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index 7d9c2e8327b9..635185be1cb7 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -15,9 +15,9 @@ use rustc_span::{DUMMY_SP, Ident, Span}; use tracing::debug; -use crate::DecorateBuiltinLint; use crate::context::{EarlyContext, LintContext, LintStore}; use crate::passes::{EarlyLintPass, EarlyLintPassObject}; +use crate::{DecorateBuiltinLint, DiagAndSess}; pub(super) mod diagnostics; @@ -49,8 +49,12 @@ fn check_id(&mut self, id: ast::NodeId) { }, ); } - DecorateDiagCompat::Dynamic(d) => { - self.context.opt_span_lint(lint_id.lint, span, d); + DecorateDiagCompat::Dynamic(callback) => { + self.context.opt_span_lint( + lint_id.lint, + span, + DiagAndSess { callback, sess: self.context.sess() }, + ); } } } diff --git a/compiler/rustc_lint/src/early/diagnostics.rs b/compiler/rustc_lint/src/early/diagnostics.rs index 19dc1c40e6d3..aee16526dfc0 100644 --- a/compiler/rustc_lint/src/early/diagnostics.rs +++ b/compiler/rustc_lint/src/early/diagnostics.rs @@ -1,5 +1,7 @@ +use std::any::Any; use std::borrow::Cow; +use rustc_data_structures::sync::DynSend; use rustc_errors::{ Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level, elided_lifetime_in_path_suggestion, @@ -13,6 +15,19 @@ mod check_cfg; +pub struct DiagAndSess<'sess> { + pub callback: Box< + dyn for<'b> FnOnce(DiagCtxtHandle<'b>, Level, &dyn Any) -> Diag<'b, ()> + DynSend + 'static, + >, + pub sess: &'sess Session, +} + +impl<'a> Diagnostic<'a, ()> for DiagAndSess<'_> { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> { + (self.callback)(dcx, level, self.sess) + } +} + /// This is a diagnostic struct that will decorate a `BuiltinLintDiag` /// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed. pub struct DecorateBuiltinLint<'sess, 'tcx> { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 74f258b42b00..9e0f04e82b47 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -509,22 +509,26 @@ pub(crate) fn lint_if_path_starts_with_module( return; } - let (replacement, applicability) = - match self.tcx.sess.source_map().span_to_snippet(root_span) { - Ok(ref s) => { - // FIXME(Manishearth) ideally the emitting code - // can tell us whether or not this is global - let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; - - (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) - } - Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), - }; - self.lint_buffer.dyn_buffer_lint( + self.lint_buffer.dyn_buffer_lint_any( ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, node_id, root_span, - move |dcx, level| { + move |dcx, level, sess| { + let (replacement, applicability) = match sess + .downcast_ref::() + .expect("expected a `Session`") + .source_map() + .span_to_snippet(root_span) + { + Ok(ref s) => { + // FIXME(Manishearth) ideally the emitting code + // can tell us whether or not this is global + let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" }; + + (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable) + } + Err(_) => ("crate::".to_string(), Applicability::HasPlaceholders), + }; errors::AbsPathWithModule { sugg: errors::AbsPathWithModuleSugg { span: root_span, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 3128e67724ca..5bd7ea502dba 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3641,49 +3641,48 @@ pub(crate) fn maybe_report_lifetime_uses( match use_set { Some(LifetimeUseSet::Many) => {} Some(LifetimeUseSet::One { use_span, use_ctxt }) => { - debug!(?param.ident, ?param.ident.span, ?use_span); - - let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let param_ident = param.ident; let deletion_span = if param.bounds.is_empty() { deletion_span() } else { None }; - - let tcx = self.r.tcx; - let param_ident = param.ident; - let sugg_data = deletion_span.map(|deletion_span| { - if elidable { - let use_span = - tcx.sess.source_map().span_extend_while_whitespace(use_span); - (deletion_span, use_span, String::new()) - } else { - (deletion_span, use_span, "'_".to_owned()) - } - }); - self.r.lint_buffer.dyn_buffer_lint( + self.r.lint_buffer.dyn_buffer_lint_any( lint::builtin::SINGLE_USE_LIFETIMES, param.id, - param.ident.span, - move |dcx, level| { - let suggestion = - sugg_data.map(|(deletion_span, use_span, replace_lt)| { - // issue 107998 for the case such as a wrong function pointer type - // `deletion_span` is empty and there is no need to report lifetime uses here - let deletion_span = if deletion_span.is_empty() { - None - } else { - Some(deletion_span) - }; - errors::SingleUseLifetimeSugg { - deletion_span, - use_span, - replace_lt, - } - }); - let param_span = param_ident.span; - debug!(?param_span, ?use_span, ?deletion_span); + param_ident.span, + move |dcx, level, sess| { + debug!(?param_ident, ?param_ident.span, ?use_span); + let elidable = matches!(use_ctxt, LifetimeCtxt::Ref); + let suggestion = if let Some(deletion_span) = deletion_span { + let (use_span, replace_lt) = if elidable { + let use_span = sess + .downcast_ref::() + .expect("expected a `Session`") + .source_map() + .span_extend_while_whitespace(use_span); + (use_span, String::new()) + } else { + (use_span, "'_".to_owned()) + }; + debug!(?deletion_span, ?use_span); + + // issue 107998 for the case such as a wrong function pointer type + // `deletion_span` is empty and there is no need to report lifetime uses here + let deletion_span = if deletion_span.is_empty() { + None + } else { + Some(deletion_span) + }; + Some(errors::SingleUseLifetimeSugg { + deletion_span, + use_span, + replace_lt, + }) + } else { + None + }; errors::SingleUseLifetime { suggestion, - param_span, + param_span: param_ident.span, use_span, ident: param_ident, } diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 65a15dba4287..8251050b6aea 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -344,7 +344,7 @@ pub fn dyn_buffer_lint< lint, Some(span.into()), node_id, - DecorateDiagCompat::Dynamic(Box::new(callback)), + DecorateDiagCompat::Dynamic(Box::new(|dcx, level, _| callback(dcx, level))), ) }