Rollup merge of #152351 - JonathanBrouwer:remove_subdiag, r=nnethercote

Remove `SubdiagMessage` in favour of the identical `DiagMessage`

For https://github.com/rust-lang/rust/issues/151366
Just some more cleanup :)
SubdiagMessage is now identical to DiagMessage, so there's no point in having both of them
This commit is contained in:
Jonathan Brouwer 2026-02-10 13:00:47 +01:00 committed by GitHub
commit 70ef5048d4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 56 additions and 162 deletions

View file

@ -230,38 +230,6 @@ pub fn fallback_fluent_bundle(
})))
}
/// Abstraction over a message in a subdiagnostic (i.e. label, note, help, etc) to support both
/// translatable and non-translatable diagnostic messages.
///
/// Translatable messages for subdiagnostics are typically attributes attached to a larger Fluent
/// message so messages of this type must be combined with a `DiagMessage` (using
/// `DiagMessage::with_subdiagnostic_message`) before rendering. However, subdiagnostics from
/// the `Subdiagnostic` derive refer to Fluent identifiers directly.
#[rustc_diagnostic_item = "SubdiagMessage"]
pub enum SubdiagMessage {
/// Non-translatable diagnostic message.
Str(Cow<'static, str>),
/// An inline Fluent message. Instances of this variant are generated by the
/// `Subdiagnostic` derive.
Inline(Cow<'static, str>),
}
impl From<String> for SubdiagMessage {
fn from(s: String) -> Self {
SubdiagMessage::Str(Cow::Owned(s))
}
}
impl From<&'static str> for SubdiagMessage {
fn from(s: &'static str) -> Self {
SubdiagMessage::Str(Cow::Borrowed(s))
}
}
impl From<Cow<'static, str>> for SubdiagMessage {
fn from(s: Cow<'static, str>) -> Self {
SubdiagMessage::Str(s)
}
}
/// Abstraction over a message in a diagnostic to support both translatable and non-translatable
/// diagnostic messages.
///
@ -281,18 +249,6 @@ pub enum DiagMessage {
}
impl DiagMessage {
/// Given a `SubdiagMessage` which may contain a Fluent attribute, create a new
/// `DiagMessage` that combines that attribute with the Fluent identifier of `self`.
///
/// - If the `SubdiagMessage` is non-translatable then return the message as a `DiagMessage`.
/// - If `self` is non-translatable then return `self`'s message.
pub fn with_subdiagnostic_message(&self, sub: SubdiagMessage) -> Self {
match sub {
SubdiagMessage::Str(s) => DiagMessage::Str(s),
SubdiagMessage::Inline(s) => DiagMessage::Inline(s),
}
}
pub fn as_str(&self) -> Option<&str> {
match self {
DiagMessage::Str(s) => Some(s),
@ -317,20 +273,6 @@ impl From<Cow<'static, str>> for DiagMessage {
}
}
/// Translating *into* a subdiagnostic message from a diagnostic message is a little strange - but
/// the subdiagnostic functions (e.g. `span_label`) take a `SubdiagMessage` and the
/// subdiagnostic derive refers to typed identifiers that are `DiagMessage`s, so need to be
/// able to convert between these, as much as they'll be converted back into `DiagMessage`
/// using `with_subdiagnostic_message` eventually. Don't use this other than for the derive.
impl From<DiagMessage> for SubdiagMessage {
fn from(val: DiagMessage) -> Self {
match val {
DiagMessage::Str(s) => SubdiagMessage::Str(s),
DiagMessage::Inline(s) => SubdiagMessage::Inline(s),
}
}
}
/// A span together with some additional data.
#[derive(Clone, Debug)]
pub struct SpanLabel {

View file

@ -17,8 +17,7 @@ use tracing::debug;
use crate::{
CodeSuggestion, DiagCtxtHandle, DiagMessage, ErrCode, ErrorGuaranteed, ExplicitBug, Level,
MultiSpan, StashKey, Style, SubdiagMessage, Substitution, SubstitutionPart, SuggestionStyle,
Suggestions,
MultiSpan, StashKey, Style, Substitution, SubstitutionPart, SuggestionStyle, Suggestions,
};
pub type DiagArgMap = FxIndexMap<DiagArgName, DiagArgValue>;
@ -325,30 +324,8 @@ impl DiagInner {
}
}
// See comment on `Diag::subdiagnostic_message_to_diagnostic_message`.
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
let msg =
self.messages.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
msg.with_subdiagnostic_message(attr.into())
}
pub(crate) fn sub(
&mut self,
level: Level,
message: impl Into<SubdiagMessage>,
span: MultiSpan,
) {
let sub = Subdiag {
level,
messages: vec![(
self.subdiagnostic_message_to_diagnostic_message(message),
Style::NoStyle,
)],
span,
};
pub(crate) fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
let sub = Subdiag { level, messages: vec![(message.into(), Style::NoStyle)], span };
self.children.push(sub);
}
@ -609,9 +586,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// the diagnostic was constructed. However, the label span is *not* considered a
/// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
/// primary.
pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagMessage>) -> &mut Self {
let msg = self.subdiagnostic_message_to_diagnostic_message(label);
self.span.push_span_label(span, msg);
pub fn span_label(&mut self, span: Span, label: impl Into<DiagMessage>) -> &mut Self {
self.span.push_span_label(span, label.into());
self
} }
@ -713,7 +689,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_note,
/// Add a note attached to this diagnostic.
pub fn note(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
pub fn note(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Note, msg, MultiSpan::new());
self
} }
@ -733,7 +709,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
}
/// This is like [`Diag::note()`], but it's only printed once.
pub fn note_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
pub fn note_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::OnceNote, msg, MultiSpan::new());
self
}
@ -744,7 +720,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_note(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
) -> &mut Self {
self.sub(Level::Note, msg, sp.into());
self
@ -755,7 +731,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_note_once<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
) -> &mut Self {
self.sub(Level::OnceNote, msg, sp.into());
self
@ -763,7 +739,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_warn,
/// Add a warning attached to this diagnostic.
pub fn warn(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
pub fn warn(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Warning, msg, MultiSpan::new());
self
} }
@ -773,7 +749,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_warn<S: Into<MultiSpan>>(
&mut self,
sp: S,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
) -> &mut Self {
self.sub(Level::Warning, msg, sp.into());
self
@ -781,13 +757,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
with_fn! { with_help,
/// Add a help message attached to this diagnostic.
pub fn help(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
pub fn help(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::Help, msg, MultiSpan::new());
self
} }
/// This is like [`Diag::help()`], but it's only printed once.
pub fn help_once(&mut self, msg: impl Into<SubdiagMessage>) -> &mut Self {
pub fn help_once(&mut self, msg: impl Into<DiagMessage>) -> &mut Self {
self.sub(Level::OnceHelp, msg, MultiSpan::new());
self
}
@ -814,7 +790,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_help(
&mut self,
sp: impl Into<MultiSpan>,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
) -> &mut Self {
self.sub(Level::Help, msg, sp.into());
self
@ -866,7 +842,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// In other words, multiple changes need to be applied as part of this suggestion.
pub fn multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -882,7 +858,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// In other words, multiple changes need to be applied as part of this suggestion.
pub fn multipart_suggestion_verbose(
&mut self,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -897,7 +873,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// [`Diag::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
pub fn multipart_suggestion_with_style(
&mut self,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
mut suggestion: Vec<(Span, String)>,
applicability: Applicability,
style: SuggestionStyle,
@ -924,7 +900,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self.push_suggestion(CodeSuggestion {
substitutions: vec![Substitution { parts }],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
msg: msg.into(),
style,
applicability,
});
@ -939,7 +915,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// improve understandability.
pub fn tool_only_multipart_suggestion(
&mut self,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: Vec<(Span, String)>,
applicability: Applicability,
) -> &mut Self {
@ -972,7 +948,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestion(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
@ -990,7 +966,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestion_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
style: SuggestionStyle,
@ -1003,7 +979,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
substitutions: vec![Substitution {
parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
}],
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
msg: msg.into(),
style,
applicability,
});
@ -1015,7 +991,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestion_verbose(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
@ -1035,7 +1011,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestions(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestions: impl IntoIterator<Item = String>,
applicability: Applicability,
) -> &mut Self {
@ -1051,7 +1027,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestions_with_style(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestions: impl IntoIterator<Item = String>,
applicability: Applicability,
style: SuggestionStyle,
@ -1068,7 +1044,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
.collect();
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
msg: msg.into(),
style,
applicability,
});
@ -1080,7 +1056,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// See also [`Diag::multipart_suggestion()`].
pub fn multipart_suggestions(
&mut self,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
applicability: Applicability,
) -> &mut Self {
@ -1112,7 +1088,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self.push_suggestion(CodeSuggestion {
substitutions,
msg: self.subdiagnostic_message_to_diagnostic_message(msg),
msg: msg.into(),
style: SuggestionStyle::ShowAlways,
applicability,
});
@ -1127,7 +1103,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestion_short(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
@ -1150,7 +1126,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn span_suggestion_hidden(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
@ -1172,7 +1148,7 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
msg: impl Into<SubdiagMessage>,
msg: impl Into<DiagMessage>,
suggestion: impl ToString,
applicability: Applicability,
) -> &mut Self {
@ -1200,10 +1176,9 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
/// one value will clobber the other. Eagerly translating the
/// diagnostic uses the variables defined right then, before the
/// clobbering occurs.
pub fn eagerly_translate(&self, msg: impl Into<SubdiagMessage>) -> SubdiagMessage {
pub fn eagerly_translate(&self, msg: impl Into<DiagMessage>) -> DiagMessage {
let args = self.args.iter();
let msg = self.subdiagnostic_message_to_diagnostic_message(msg.into());
self.dcx.eagerly_translate(msg, args)
self.dcx.eagerly_translate(msg.into(), args)
}
with_fn! { with_span,
@ -1256,31 +1231,18 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> {
self
} }
/// Helper function that takes a `SubdiagMessage` and returns a `DiagMessage` by
/// combining it with the primary message of the diagnostic (if translatable, otherwise it just
/// passes the user's string along).
pub(crate) fn subdiagnostic_message_to_diagnostic_message(
&self,
attr: impl Into<SubdiagMessage>,
) -> DiagMessage {
self.deref().subdiagnostic_message_to_diagnostic_message(attr)
}
/// Convenience function for internal use, clients should use one of the
/// public methods above.
///
/// Used by `proc_macro_server` for implementing `server::Diagnostic`.
pub fn sub(&mut self, level: Level, message: impl Into<SubdiagMessage>, span: MultiSpan) {
pub fn sub(&mut self, level: Level, message: impl Into<DiagMessage>, span: MultiSpan) {
self.deref_mut().sub(level, message, span);
}
/// Convenience function for internal use, clients should use one of the
/// public methods above.
fn sub_with_highlights(&mut self, level: Level, messages: Vec<StringPart>, span: MultiSpan) {
let messages = messages
.into_iter()
.map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.content), m.style))
.collect();
let messages = messages.into_iter().map(|m| (m.content.into(), m.style)).collect();
let sub = Subdiag { level, messages, span };
self.children.push(sub);
}

View file

@ -57,8 +57,8 @@ use rustc_data_structures::sync::{DynSend, Lock};
use rustc_data_structures::{AtomicRef, assert_matches};
pub use rustc_error_messages::{
DiagArg, DiagArgFromDisplay, DiagArgName, DiagArgValue, DiagMessage, FluentBundle, IntoDiagArg,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage,
fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, fallback_fluent_bundle,
fluent_bundle, into_diag_arg_using_display,
};
use rustc_hashes::Hash128;
use rustc_lint_defs::LintExpectationId;
@ -488,12 +488,12 @@ impl DiagCtxt {
self.inner.borrow_mut().emitter = emitter;
}
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
/// Translate `message` eagerly with `args` to `DiagMessage::Eager`.
pub fn eagerly_translate<'a>(
&self,
message: DiagMessage,
args: impl Iterator<Item = DiagArg<'a>>,
) -> SubdiagMessage {
) -> DiagMessage {
let inner = self.inner.borrow();
inner.eagerly_translate(message, args)
}
@ -1423,13 +1423,13 @@ impl DiagCtxtInner {
self.has_errors().or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
}
/// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`.
/// Translate `message` eagerly with `args` to `DiagMessage::Eager`.
fn eagerly_translate<'a>(
&self,
message: DiagMessage,
args: impl Iterator<Item = DiagArg<'a>>,
) -> SubdiagMessage {
SubdiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args)))
) -> DiagMessage {
DiagMessage::Str(Cow::from(self.eagerly_translate_to_string(message, args)))
}
/// Translate `message` eagerly with `args` to `String`.
@ -1450,10 +1450,9 @@ impl DiagCtxtInner {
fn eagerly_translate_for_subdiag(
&self,
diag: &DiagInner,
msg: impl Into<SubdiagMessage>,
) -> SubdiagMessage {
let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
self.eagerly_translate(msg, diag.args.iter())
msg: impl Into<DiagMessage>,
) -> DiagMessage {
self.eagerly_translate(msg.into(), diag.args.iter())
}
fn flush_delayed(&mut self) {

View file

@ -7,7 +7,7 @@ mod prelude_edition_lints;
pub(crate) mod probe;
mod suggest;
use rustc_errors::{Applicability, Diag, SubdiagMessage};
use rustc_errors::{Applicability, Diag, DiagMessage};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
@ -127,7 +127,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn suggest_method_call(
&self,
err: &mut Diag<'_>,
msg: impl Into<SubdiagMessage> + std::fmt::Debug,
msg: impl Into<DiagMessage> + std::fmt::Debug,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &hir::Expr<'tcx>,

View file

@ -373,7 +373,6 @@ symbols! {
Str,
String,
StructuralPartialEq,
SubdiagMessage,
Subdiagnostic,
SymbolIntern,
Sync,

View file

@ -135,8 +135,7 @@ translation.
### Messages
All of rustc's traditional diagnostic APIs (e.g. `struct_span_err` or `note`)
take any message that can be converted into a `DiagMessage` (or
`SubdiagMessage`).
take any message that can be converted into a `DiagMessage`.
[`rustc_error_messages::DiagMessage`] can represent legacy non-translatable
diagnostic messages and translatable messages. Non-translatable messages are
@ -149,14 +148,7 @@ with an attribute).
Fluent resource (described in more detail below), or `DiagMessage`s will
either be created in the macro-generated code of a diagnostic derive.
`rustc_error_messages::SubdiagMessage` is similar, it can correspond to a
legacy non-translatable diagnostic message or the name of an attribute to a
Fluent message. Translatable `SubdiagMessage`s must be combined with a
`DiagMessage` (using `DiagMessage::with_subdiagnostic_message`) to
be emitted (an attribute name on its own is meaningless without a corresponding
message identifier, which is what `DiagMessage` provides).
Both `DiagMessage` and `SubdiagMessage` implement `Into` for any
`DiagMessage` implements `Into` for any
type that can be converted into a string, and converts these into
non-translatable diagnostics - this keeps all existing diagnostic calls
working.

View file

@ -8,7 +8,7 @@
//! Thank you!
//! ~The `INTERNAL_METADATA_COLLECTOR` lint
use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan, SubdiagMessage};
use rustc_errors::{Applicability, Diag, DiagMessage, MultiSpan};
#[cfg(debug_assertions)]
use rustc_errors::{EmissionGuarantee, SubstitutionPart, Suggestions};
use rustc_hir::HirId;
@ -155,7 +155,7 @@ pub fn span_lint_and_help<T: LintContext>(
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
help_span: Option<Span>,
help: impl Into<SubdiagMessage>,
help: impl Into<DiagMessage>,
) {
#[expect(clippy::disallowed_methods)]
cx.span_lint(lint, span, |diag| {
@ -216,7 +216,7 @@ pub fn span_lint_and_note<T: LintContext>(
span: impl Into<MultiSpan>,
msg: impl Into<DiagMessage>,
note_span: Option<Span>,
note: impl Into<SubdiagMessage>,
note: impl Into<DiagMessage>,
) {
#[expect(clippy::disallowed_methods)]
cx.span_lint(lint, span, |diag| {
@ -390,7 +390,7 @@ pub fn span_lint_and_sugg<T: LintContext>(
lint: &'static Lint,
sp: Span,
msg: impl Into<DiagMessage>,
help: impl Into<SubdiagMessage>,
help: impl Into<DiagMessage>,
sugg: String,
applicability: Applicability,
) {

View file

@ -19,7 +19,7 @@ extern crate rustc_session;
extern crate rustc_span;
extern crate core;
use rustc_errors::{Applicability, DiagMessage, SubdiagMessage};
use rustc_errors::{Applicability, DiagMessage};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::Span;

View file

@ -26,7 +26,7 @@ extern crate rustc_middle;
use rustc_middle::ty::Ty;
extern crate rustc_errors;
use rustc_errors::{Applicability, DiagMessage, ErrCode, MultiSpan, SubdiagMessage};
use rustc_errors::{Applicability, DiagMessage, ErrCode, MultiSpan};
extern crate rustc_session;

View file

@ -17,7 +17,7 @@ extern crate rustc_session;
extern crate rustc_span;
extern crate core;
use rustc_errors::{Applicability, DiagMessage, SubdiagMessage};
use rustc_errors::{Applicability, DiagMessage};
use rustc_macros::Subdiagnostic;
use rustc_span::Span;