Rollup merge of #152235 - JonathanBrouwer:convert_parse, r=JonathanBrouwer

Convert to inline diagnostics in `rustc_parse`

This was the most annoying one by far, had to make a few changes to the representation of two errors (no user-facing changes tho), these changes are in separate commits for clarity :)

For https://github.com/rust-lang/rust/issues/151366
r? @jdonszelmann
This commit is contained in:
Jonathan Brouwer 2026-02-07 13:06:34 +01:00 committed by GitHub
commit 828b9c2cdf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 1448 additions and 1796 deletions

View file

@ -4381,7 +4381,6 @@ dependencies = [
"rustc_data_structures",
"rustc_errors",
"rustc_feature",
"rustc_fluent_macro",
"rustc_index",
"rustc_lexer",
"rustc_macros",

View file

@ -114,7 +114,6 @@ pub fn default_translator() -> Translator {
pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
// tidy-alphabetical-start
rustc_lint::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
// tidy-alphabetical-end
];

View file

@ -53,10 +53,9 @@ pub struct Compiler {
pub(crate) fn parse_cfg(dcx: DiagCtxtHandle<'_>, cfgs: Vec<String>) -> Cfg {
cfgs.into_iter()
.map(|s| {
let psess = ParseSess::emitter_with_note(
vec![rustc_parse::DEFAULT_LOCALE_RESOURCE],
format!("this occurred on the command line: `--cfg={s}`"),
);
let psess = ParseSess::emitter_with_note(format!(
"this occurred on the command line: `--cfg={s}`"
));
let filename = FileName::cfg_spec_source_code(&s);
macro_rules! error {
@ -125,10 +124,9 @@ pub(crate) fn parse_check_cfg(dcx: DiagCtxtHandle<'_>, specs: Vec<String>) -> Ch
let mut check_cfg = CheckCfg { exhaustive_names, exhaustive_values, ..CheckCfg::default() };
for s in specs {
let psess = ParseSess::emitter_with_note(
vec![rustc_parse::DEFAULT_LOCALE_RESOURCE],
format!("this occurred on the command line: `--check-cfg={s}`"),
);
let psess = ParseSess::emitter_with_note(format!(
"this occurred on the command line: `--check-cfg={s}`"
));
let filename = FileName::cfg_spec_source_code(&s);
const VISIT: &str =

View file

@ -3,6 +3,7 @@ use fluent_syntax::ast::{Expression, InlineExpression, Pattern, PatternElement};
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::Path;
use syn::ext::IdentExt;
use synstructure::{Structure, VariantInfo};
use crate::diagnostics::error::span_err;
@ -100,7 +101,7 @@ fn verify_fluent_message(msg_span: Span, message_str: &str, variant: Option<&Var
.bindings()
.iter()
.flat_map(|b| b.ast().ident.as_ref())
.map(|id| id.to_string())
.map(|id| id.unraw().to_string())
.collect();
for variable in variable_references(&message) {
if !fields.iter().any(|f| f == variable) {
@ -155,6 +156,8 @@ const ALLOWED_CAPITALIZED_WORDS: &[&str] = &[
"MIR",
"NaNs",
"OK",
"Rust",
"Unicode",
"VS",
// tidy-alphabetical-end
];

View file

@ -12,7 +12,6 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -75,8 +75,6 @@ const _: () = {
}
};
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
// Unwrap the result if `Ok`, otherwise emit the diagnostics and abort.
pub fn unwrap_or_emit_fatal<T>(expr: Result<T, Vec<Diag<'_>>>) -> T {
match expr {

View file

@ -3,7 +3,7 @@ use rustc_ast::token::{self, MetaVarKind};
use rustc_ast::tokenstream::ParserRange;
use rustc_ast::{AttrItemKind, Attribute, attr};
use rustc_errors::codes::*;
use rustc_errors::{Diag, PResult};
use rustc_errors::{Diag, PResult, inline_fluent};
use rustc_span::{BytePos, Span};
use thin_vec::ThinVec;
use tracing::debug;
@ -13,7 +13,7 @@ use super::{
Trailing, UsePreAttrPos,
};
use crate::parser::FnContext;
use crate::{errors, exp, fluent_generated as fluent};
use crate::{errors, exp};
// Public for rustfmt usage
#[derive(Debug)]
@ -68,7 +68,7 @@ impl<'a> Parser<'a> {
let span = self.token.span;
let mut err = self
.dcx()
.struct_span_err(span, fluent::parse_inner_doc_comment_not_permitted);
.struct_span_err(span, inline_fluent!("expected outer doc comment"));
err.code(E0753);
if let Some(replacement_span) = self.annotate_following_item_if_applicable(
&mut err,
@ -79,10 +79,12 @@ impl<'a> Parser<'a> {
},
true,
) {
err.note(fluent::parse_note);
err.note(inline_fluent!(
"inner doc comments like this (starting with `//!` or `/*!`) can only appear before items"
));
err.span_suggestion_verbose(
replacement_span,
fluent::parse_suggestion,
inline_fluent!("you might have meant to write a regular comment"),
"",
rustc_errors::Applicability::MachineApplicable,
);
@ -207,13 +209,25 @@ impl<'a> Parser<'a> {
AllowConstBlockItems::Yes,
) {
Ok(Some(item)) => {
// FIXME(#100717)
err.arg("item", item.kind.descr());
err.span_label(item.span, fluent::parse_label_does_not_annotate_this);
err.span_label(
item.span,
match attr_type {
OuterAttributeType::Attribute => {
inline_fluent!("the inner attribute doesn't annotate this {$item}")
}
OuterAttributeType::DocComment | OuterAttributeType::DocBlockComment => {
inline_fluent!("the inner doc comment doesn't annotate this {$item}")
}
},
);
if suggest_to_outer {
err.span_suggestion_verbose(
replacement_span,
fluent::parse_sugg_change_inner_to_outer,
match attr_type {
OuterAttributeType::Attribute => inline_fluent!("to annotate the {$item}, change the attribute from inner to outer style"),
OuterAttributeType::DocComment | OuterAttributeType::DocBlockComment => inline_fluent!("to annotate the {$item}, change the doc comment from inner to outer style"),
},
match attr_type {
OuterAttributeType::Attribute => "",
OuterAttributeType::DocBlockComment => "*",
@ -244,28 +258,42 @@ impl<'a> Parser<'a> {
self.dcx()
.struct_span_err(
attr_sp,
fluent::parse_inner_attr_not_permitted_after_outer_doc_comment,
inline_fluent!(
"an inner attribute is not permitted following an outer doc comment"
),
)
.with_span_label(
attr_sp,
inline_fluent!("not permitted following an outer doc comment"),
)
.with_span_label(attr_sp, fluent::parse_label_attr)
.with_span_label(
prev_doc_comment_span,
fluent::parse_label_prev_doc_comment,
inline_fluent!("previous doc comment"),
)
}
Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }) => self
.dcx()
.struct_span_err(
attr_sp,
fluent::parse_inner_attr_not_permitted_after_outer_attr,
inline_fluent!(
"an inner attribute is not permitted following an outer attribute"
),
)
.with_span_label(attr_sp, fluent::parse_label_attr)
.with_span_label(prev_outer_attr_sp, fluent::parse_label_prev_attr),
Some(InnerAttrForbiddenReason::InCodeBlock) | None => {
self.dcx().struct_span_err(attr_sp, fluent::parse_inner_attr_not_permitted)
}
.with_span_label(
attr_sp,
inline_fluent!("not permitted following an outer attribute"),
)
.with_span_label(
prev_outer_attr_sp,
inline_fluent!("previous outer attribute"),
),
Some(InnerAttrForbiddenReason::InCodeBlock) | None => self.dcx().struct_span_err(
attr_sp,
inline_fluent!("an inner attribute is not permitted in this context"),
),
};
diag.note(fluent::parse_inner_attr_explanation);
diag.note(inline_fluent!("inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files"));
if self
.annotate_following_item_if_applicable(
&mut diag,
@ -275,7 +303,9 @@ impl<'a> Parser<'a> {
)
.is_some()
{
diag.note(fluent::parse_outer_attr_explanation);
diag.note(inline_fluent!(
"outer attributes, like `#[test]`, annotate the item following them"
));
};
diag.emit();
}

View file

@ -13,7 +13,7 @@ use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
Applicability, Diag, DiagCtxtHandle, ErrorGuaranteed, PResult, Subdiagnostic, Suggestions,
pluralize,
inline_fluent, pluralize,
};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
@ -41,10 +41,10 @@ use crate::errors::{
TernaryOperatorSuggestion, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, WrapType,
};
use crate::exp;
use crate::parser::FnContext;
use crate::parser::attr::InnerAttrPolicy;
use crate::parser::item::IsDotDotDot;
use crate::{exp, fluent_generated as fluent};
/// Creates a placeholder argument.
pub(super) fn dummy_arg(ident: Ident, guar: ErrorGuaranteed) -> Param {
@ -1272,7 +1272,7 @@ impl<'a> Parser<'a> {
// We made sense of it. Improve the error message.
e.span_suggestion_verbose(
binop.span.shrink_to_lo(),
fluent::parse_sugg_turbofish_syntax,
inline_fluent!("use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments"),
"::",
Applicability::MaybeIncorrect,
);

View file

@ -727,25 +727,26 @@ impl<'a> Parser<'a> {
);
let args_span = self.look_ahead(1, |t| t.span).to(span_after_type);
let suggestion = errors::ComparisonOrShiftInterpretedAsGenericSugg {
left: expr.span.shrink_to_lo(),
right: expr.span.shrink_to_hi(),
};
match self.token.kind {
token::Lt => {
self.dcx().emit_err(errors::ComparisonInterpretedAsGeneric {
comparison: self.token.span,
r#type: path,
args: args_span,
suggestion,
suggestion: errors::ComparisonInterpretedAsGenericSugg {
left: expr.span.shrink_to_lo(),
right: expr.span.shrink_to_hi(),
},
})
}
token::Shl => self.dcx().emit_err(errors::ShiftInterpretedAsGeneric {
shift: self.token.span,
r#type: path,
args: args_span,
suggestion,
suggestion: errors::ShiftInterpretedAsGenericSugg {
left: expr.span.shrink_to_lo(),
right: expr.span.shrink_to_hi(),
},
}),
_ => {
// We can end up here even without `<` being the next token, for

View file

@ -11,7 +11,7 @@ use rustc_ast::{
};
use rustc_ast_pretty::pprust;
use rustc_errors::codes::*;
use rustc_errors::{Applicability, PResult, StashKey, struct_span_code_err};
use rustc_errors::{Applicability, PResult, StashKey, inline_fluent, struct_span_code_err};
use rustc_session::lint::builtin::VARARGS_WITHOUT_PATTERN;
use rustc_span::edit_distance::edit_distance;
use rustc_span::edition::Edition;
@ -26,7 +26,7 @@ use super::{
Parser, PathStyle, Recovered, Trailing, UsePreAttrPos,
};
use crate::errors::{self, FnPointerCannotBeAsync, FnPointerCannotBeConst, MacroExpandsToAdtField};
use crate::{exp, fluent_generated as fluent};
use crate::exp;
impl<'a> Parser<'a> {
/// Parses a source module as a crate. This is the main entry point for the parser.
@ -1721,7 +1721,7 @@ impl<'a> Parser<'a> {
if this.token == token::Bang {
if let Err(err) = this.unexpected() {
err.with_note(fluent::parse_macro_expands_to_enum_variant).emit();
err.with_note(inline_fluent!("macros cannot expand to enum variants")).emit();
}
this.bump();

View file

@ -25,10 +25,6 @@ use crate::lexer::StripTokens;
use crate::parser::{AllowConstBlockItems, ForceCollect, Parser};
use crate::{new_parser_from_source_str, source_str_to_stream, unwrap_or_emit_fatal};
fn psess() -> ParseSess {
ParseSess::new(vec![crate::DEFAULT_LOCALE_RESOURCE])
}
fn filename(sm: &SourceMap, path: &str) -> FileName {
FileName::Real(sm.path_mapping().to_real_filename(sm.working_dir(), PathBuf::from(path)))
}
@ -46,7 +42,7 @@ fn string_to_parser(psess: &ParseSess, source_str: String) -> Parser<'_> {
fn create_test_handler(theme: OutputTheme) -> (DiagCtxt, Arc<SourceMap>, Arc<Mutex<Vec<u8>>>) {
let output = Arc::new(Mutex::new(Vec::new()));
let source_map = Arc::new(SourceMap::new(FilePathMapping::empty()));
let translator = Translator::with_fallback_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false);
let translator = Translator::with_fallback_bundle(vec![], false);
let shared: Box<dyn Write + Send> = Box::new(Shared { data: output.clone() });
let auto_stream = AutoStream::never(shared);
let dcx = DiagCtxt::new(Box::new(
@ -93,7 +89,7 @@ where
/// Maps a string to tts, using a made-up filename.
pub(crate) fn string_to_stream(source_str: String) -> TokenStream {
let psess = psess();
let psess = ParseSess::new(vec![]);
unwrap_or_emit_fatal(source_str_to_stream(
&psess,
filename(psess.source_map(), "bogofile"),
@ -2243,12 +2239,12 @@ fn sp(a: u32, b: u32) -> Span {
/// Parses a string, return an expression.
fn string_to_expr(source_str: String) -> Box<ast::Expr> {
with_error_checking_parse(source_str, &psess(), |p| p.parse_expr())
with_error_checking_parse(source_str, &ParseSess::new(vec![]), |p| p.parse_expr())
}
/// Parses a string, returns an item.
fn string_to_item(source_str: String) -> Option<Box<ast::Item>> {
with_error_checking_parse(source_str, &psess(), |p| {
with_error_checking_parse(source_str, &ParseSess::new(vec![]), |p| {
p.parse_item(ForceCollect::No, AllowConstBlockItems::Yes)
})
}
@ -2484,7 +2480,7 @@ let mut fflags: c_int = wb();
#[test]
fn crlf_doc_comments() {
create_default_session_globals_then(|| {
let psess = psess();
let psess = ParseSess::new(vec![]);
let name_1 = FileName::Custom("crlf_source_1".to_string());
let source = "/// doc comment\r\nfn foo() {}".to_string();
@ -2519,7 +2515,7 @@ fn ttdelim_span() {
}
create_default_session_globals_then(|| {
let psess = psess();
let psess = ParseSess::new(vec![]);
let expr = parse_expr_from_source_str(
filename(psess.source_map(), "foo"),
"foo!( fn main() { body } )".to_string(),
@ -2555,7 +2551,7 @@ fn look_ahead() {
let sym_S = Symbol::intern("S");
let raw_no = IdentIsRaw::No;
let psess = psess();
let psess = ParseSess::new(vec![]);
let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
// Current position is the `fn`.
@ -2630,7 +2626,7 @@ fn look_ahead_non_outermost_stream() {
let sym_S = Symbol::intern("S");
let raw_no = IdentIsRaw::No;
let psess = psess();
let psess = ParseSess::new(vec![]);
let mut p = string_to_parser(&psess, "mod m { fn f(x: u32) { x } struct S; }".to_string());
// Move forward to the `fn`, which is not within the outermost token
@ -2662,7 +2658,7 @@ fn look_ahead_non_outermost_stream() {
#[test]
fn debug_lookahead() {
create_default_session_globals_then(|| {
let psess = psess();
let psess = ParseSess::new(vec![]);
let mut p = string_to_parser(&psess, "fn f(x: u32) { x } struct S;".to_string());
// Current position is the `fn`.
@ -2883,7 +2879,7 @@ fn debug_lookahead() {
#[test]
fn out_of_line_mod() {
create_default_session_globals_then(|| {
let psess = psess();
let psess = ParseSess::new(vec![]);
let item = parse_item_from_source_str(
filename(psess.source_map(), "foo"),
"mod foo { struct S; mod this_does_not_exist; }".to_owned(),

View file

@ -313,8 +313,8 @@ impl ParseSess {
}
}
pub fn emitter_with_note(locale_resources: Vec<&'static str>, note: String) -> Self {
let translator = Translator::with_fallback_bundle(locale_resources, false);
pub fn emitter_with_note(note: String) -> Self {
let translator = Translator::with_fallback_bundle(vec![], false);
let sm = Arc::new(SourceMap::new(FilePathMapping::empty()));
let emitter = Box::new(AnnotateSnippetEmitter::new(
stderr_destination(ColorConfig::Auto),

View file

@ -10,6 +10,9 @@
//@ needs-symlink
//@ needs-subprocess
// FIXME(151366) Currently `-Ztranslate-additional-ftl` is currently broken
//@ ignore-test
#![deny(warnings)]
use std::path::{Path, PathBuf};

View file

@ -29,7 +29,7 @@ pub fn main() {
}
fn parse() {
let psess = ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE]);
let psess = ParseSess::new(vec![]);
let path = Path::new(file!());
let path = path.canonicalize().unwrap();

View file

@ -219,7 +219,7 @@ fn main() {
}
fn run() {
let psess = ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE]);
let psess = ParseSess::new(vec![]);
iter_exprs(2, &mut |mut e| {
// If the pretty printer is correct, then `parse(print(e))` should be identical to `e`,

View file

@ -196,7 +196,7 @@ fn main() -> ExitCode {
};
rustc_span::create_default_session_globals_then(|| {
let psess = &ParseSess::new(vec![rustc_parse::DEFAULT_LOCALE_RESOURCE]);
let psess = &ParseSess::new(vec![]);
for &source_code in EXPRS {
let Some(expr) = parse_expr(psess, source_code) else {