Remove BuiltinDiag usage in rustc_parse

This commit is contained in:
Guillaume Gomez
2026-03-20 17:24:42 +01:00
parent bb689c41aa
commit 0e3e647e2e
6 changed files with 148 additions and 161 deletions
@@ -1,6 +1,5 @@
use std::borrow::Cow;
use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
use rustc_errors::{
Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
elided_lifetime_in_path_suggestion,
@@ -10,7 +9,6 @@
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_session::lint::BuiltinLintDiag;
use rustc_span::BytePos;
use tracing::debug;
use crate::lints;
@@ -28,32 +26,6 @@ pub struct DecorateBuiltinLint<'sess, 'tcx> {
impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
match self.diagnostic {
BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
let spans: Vec<_> = content
.char_indices()
.filter_map(|(i, c)| {
TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
let lo = comment_span.lo() + BytePos(2 + i as u32);
(c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
})
})
.collect();
let characters = spans
.iter()
.map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
.collect();
let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
spans: spans.iter().map(|(_c, span)| *span).collect(),
});
lints::UnicodeTextFlow {
comment_span,
characters,
suggestions,
num_codepoints: spans.len(),
}
.into_diag(dcx, level)
}
BuiltinLintDiag::AbsPathWithModule(mod_span) => {
let (replacement, applicability) =
match self.sess.source_map().span_to_snippet(mod_span) {
@@ -153,23 +125,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
}
.into_diag(dcx, level)
}
BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix {
label: label_span,
suggestion: label_span.shrink_to_hi(),
prefix,
}
.into_diag(dcx, level),
BuiltinLintDiag::RawPrefix(label_span) => {
lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
.into_diag(dcx, level)
}
BuiltinLintDiag::ReservedString { is_string, suggestion } => {
if is_string {
lints::ReservedString { suggestion }.into_diag(dcx, level)
} else {
lints::ReservedMultihash { suggestion }.into_diag(dcx, level)
}
}
BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
let suggestion = match sugg {
Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
-90
View File
@@ -3019,46 +3019,6 @@ pub(crate) struct IllFormedAttributeInput {
pub docs: &'static str,
}
#[derive(Diagnostic)]
#[diag("unicode codepoint changing visible direction of text present in comment")]
#[note(
"these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
)]
pub(crate) struct UnicodeTextFlow {
#[label(
"{$num_codepoints ->
[1] this comment contains an invisible unicode text flow control codepoint
*[other] this comment contains invisible unicode text flow control codepoints
}"
)]
pub comment_span: Span,
#[subdiagnostic]
pub characters: Vec<UnicodeCharNoteSub>,
#[subdiagnostic]
pub suggestions: Option<UnicodeTextFlowSuggestion>,
pub num_codepoints: usize,
}
#[derive(Subdiagnostic)]
#[label("{$c_debug}")]
pub(crate) struct UnicodeCharNoteSub {
#[primary_span]
pub span: Span,
pub c_debug: String,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
"if their presence wasn't intentional, you can remove them",
applicability = "machine-applicable",
style = "hidden"
)]
pub(crate) struct UnicodeTextFlowSuggestion {
#[suggestion_part(code = "")]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag(
"absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition"
@@ -3192,34 +3152,6 @@ pub(crate) struct PatternsInFnsWithoutBodySub {
pub ident: Ident,
}
#[derive(Diagnostic)]
#[diag("prefix `{$prefix}` is unknown")]
pub(crate) struct ReservedPrefix {
#[label("unknown prefix")]
pub label: Span,
#[suggestion(
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
pub prefix: String,
}
#[derive(Diagnostic)]
#[diag("prefix `'r` is reserved")]
pub(crate) struct RawPrefix {
#[label("reserved prefix")]
pub label: Span,
#[suggestion(
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag("where clause not allowed here")]
#[note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information")]
@@ -3405,28 +3337,6 @@ pub(crate) enum MutRefSugg {
#[diag("`use` of a local item without leading `self::`, `super::`, or `crate::`")]
pub(crate) struct UnqualifiedLocalImportsDiag;
#[derive(Diagnostic)]
#[diag("will be parsed as a guarded string in Rust 2024")]
pub(crate) struct ReservedString {
#[suggestion(
"insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag("reserved token in Rust 2024")]
pub(crate) struct ReservedMultihash {
#[suggestion(
"insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag("direct cast of function item into an integer")]
pub(crate) struct FunctionCastsAsIntegerDiag<'tcx> {
-8
View File
@@ -678,15 +678,7 @@ pub enum BuiltinLintDiag {
ident: Ident,
is_foreign: bool,
},
ReservedPrefix(Span, String),
/// `'r#` in edition < 2021.
RawPrefix(Span),
/// `##` or `#"` in edition < 2024.
ReservedString {
is_string: bool,
suggestion: Span,
},
UnicodeTextFlow(Span, String),
DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
SingleUseLifetime {
/// Span of the parameter which declares this lifetime.
+90
View File
@@ -4517,3 +4517,93 @@ pub(crate) struct BreakWithLabelAndLoopSub {
#[suggestion_part(code = ")")]
pub right: Span,
}
#[derive(Diagnostic)]
#[diag("prefix `'r` is reserved")]
pub(crate) struct RawPrefix {
#[label("reserved prefix")]
pub label: Span,
#[suggestion(
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag("unicode codepoint changing visible direction of text present in comment")]
#[note(
"these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen"
)]
pub(crate) struct UnicodeTextFlow {
#[label(
"{$num_codepoints ->
[1] this comment contains an invisible unicode text flow control codepoint
*[other] this comment contains invisible unicode text flow control codepoints
}"
)]
pub comment_span: Span,
#[subdiagnostic]
pub characters: Vec<UnicodeCharNoteSub>,
#[subdiagnostic]
pub suggestions: Option<UnicodeTextFlowSuggestion>,
pub num_codepoints: usize,
}
#[derive(Subdiagnostic)]
#[label("{$c_debug}")]
pub(crate) struct UnicodeCharNoteSub {
#[primary_span]
pub span: Span,
pub c_debug: String,
}
#[derive(Subdiagnostic)]
#[multipart_suggestion(
"if their presence wasn't intentional, you can remove them",
applicability = "machine-applicable",
style = "hidden"
)]
pub(crate) struct UnicodeTextFlowSuggestion {
#[suggestion_part(code = "")]
pub spans: Vec<Span>,
}
#[derive(Diagnostic)]
#[diag("prefix `{$prefix}` is unknown")]
pub(crate) struct ReservedPrefix {
#[label("unknown prefix")]
pub label: Span,
#[suggestion(
"insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
pub prefix: String,
}
#[derive(Diagnostic)]
#[diag("will be parsed as a guarded string in Rust 2024")]
pub(crate) struct ReservedStringLint {
#[suggestion(
"insert whitespace here to avoid this being parsed as a guarded string in Rust 2024",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
#[derive(Diagnostic)]
#[diag("reserved token in Rust 2024")]
pub(crate) struct ReservedMultihashLint {
#[suggestion(
"insert whitespace here to avoid this being parsed as a forbidden token in Rust 2024",
code = " ",
applicability = "machine-applicable"
)]
pub suggestion: Span,
}
+51 -8
View File
@@ -4,12 +4,11 @@
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::{TEXT_FLOW_CONTROL_CHARS, contains_text_flow_control_chars};
use rustc_errors::codes::*;
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, StashKey};
use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, StashKey};
use rustc_lexer::{
Base, Cursor, DocStyle, FrontmatterAllowed, LiteralKind, RawStrError, is_horizontal_whitespace,
};
use rustc_literal_escaper::{EscapeError, Mode, check_for_errors};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
TEXT_DIRECTION_CODEPOINT_IN_COMMENT, TEXT_DIRECTION_CODEPOINT_IN_LITERAL,
@@ -388,7 +387,10 @@ fn next_token_from_cursor(&mut self) -> (Token, bool) {
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::RawPrefix(prefix_span),
errors::RawPrefix {
label: prefix_span,
suggestion: prefix_span.shrink_to_hi()
},
);
// Reset the state so we just lex the `'r`.
@@ -498,11 +500,41 @@ fn lint_unicode_text_flow(&self, start: BytePos) {
let content = self.str_from(content_start);
if contains_text_flow_control_chars(content) {
let span = self.mk_sp(start, self.pos);
self.psess.buffer_lint(
let content = content.to_string();
self.psess.dyn_buffer_lint(
TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()),
move |dcx, level| {
let spans: Vec<_> = content
.char_indices()
.filter_map(|(i, c)| {
TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
let lo = span.lo() + BytePos(2 + i as u32);
(c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
})
})
.collect();
let characters = spans
.iter()
.map(|&(c, span)| errors::UnicodeCharNoteSub {
span,
c_debug: format!("{c:?}"),
})
.collect();
let suggestions =
(!spans.is_empty()).then_some(errors::UnicodeTextFlowSuggestion {
spans: spans.iter().map(|(_c, span)| *span).collect(),
});
errors::UnicodeTextFlow {
comment_span: span,
characters,
suggestions,
num_codepoints: spans.len(),
}
.into_diag(dcx, level)
},
);
}
}
@@ -1038,7 +1070,11 @@ fn report_unknown_prefix(&self, start: BytePos) {
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()),
errors::ReservedPrefix {
label: prefix_span,
suggestion: prefix_span.shrink_to_hi(),
prefix: prefix.to_string(),
},
);
}
}
@@ -1112,11 +1148,18 @@ fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) ->
})
} else {
// Before Rust 2024, only emit a lint for migration.
self.psess.buffer_lint(
self.psess.dyn_buffer_lint(
RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
span,
ast::CRATE_NODE_ID,
BuiltinLintDiag::ReservedString { is_string, suggestion: space_span },
move |dcx, level| {
if is_string {
errors::ReservedStringLint { suggestion: space_span }.into_diag(dcx, level)
} else {
errors::ReservedMultihashLint { suggestion: space_span }
.into_diag(dcx, level)
}
},
);
// For backwards compatibility, roll back to after just the first `#`
+7 -10
View File
@@ -19,7 +19,7 @@
StmtKind, Ty, TyKind, UnOp, UnsafeBinderCastKind, YieldKind,
};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{Applicability, Diag, Diagnostic, PResult, StashKey, Subdiagnostic};
use rustc_errors::{Applicability, Diag, PResult, StashKey, Subdiagnostic};
use rustc_literal_escaper::unescape_char;
use rustc_session::errors::{ExprParenthesesNeeded, report_lit_error};
use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP;
@@ -1921,18 +1921,15 @@ fn parse_expr_break(&mut self) -> PResult<'a, Box<Expr>> {
}
{
let span = expr.span;
self.psess.dyn_buffer_lint(
self.psess.buffer_lint(
BREAK_WITH_LABEL_AND_LOOP,
lo.to(expr.span),
ast::CRATE_NODE_ID,
move |dcx, level| {
errors::BreakWithLabelAndLoop {
sub: errors::BreakWithLabelAndLoopSub {
left: span.shrink_to_lo(),
right: span.shrink_to_hi(),
},
}
.into_diag(dcx, level)
errors::BreakWithLabelAndLoop {
sub: errors::BreakWithLabelAndLoopSub {
left: span.shrink_to_lo(),
right: span.shrink_to_hi(),
},
},
);
}