From cf94bdc0742c13e2a0cac864c478b8626b266e1b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 17 Apr 2024 14:11:38 +0200 Subject: Merging upstream version 1.66.0+dfsg1. Signed-off-by: Daniel Baumann --- compiler/rustc_errors/Cargo.toml | 3 +- .../src/annotate_snippet_emitter_writer.rs | 4 +- compiler/rustc_errors/src/diagnostic.rs | 262 +++++++++------------ compiler/rustc_errors/src/diagnostic_builder.rs | 99 ++++++-- compiler/rustc_errors/src/diagnostic_impls.rs | 222 +++++++++++++++++ compiler/rustc_errors/src/emitter.rs | 4 +- compiler/rustc_errors/src/json.rs | 4 +- compiler/rustc_errors/src/lib.rs | 81 ++++++- compiler/rustc_errors/src/translation.rs | 34 ++- 9 files changed, 508 insertions(+), 205 deletions(-) create mode 100644 compiler/rustc_errors/src/diagnostic_impls.rs (limited to 'compiler/rustc_errors') diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index c36ca11fa..7803a0792 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -4,10 +4,11 @@ version = "0.0.0" edition = "2021" [lib] -doctest = false [dependencies] tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index b32fc3c71..f14b8ee32 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -7,7 +7,7 @@ use crate::emitter::FileWithAnnotatedLines; use crate::snippet::Line; -use crate::translation::Translate; +use crate::translation::{to_fluent_args, Translate}; use crate::{ CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, Emitter, FluentBundle, LazyFallbackBundle, Level, MultiSpan, Style, SubDiagnostic, @@ -46,7 +46,7 @@ impl Translate for AnnotateSnippetEmitterWriter { impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, diag: &Diagnostic) { - let fluent_args = self.to_fluent_args(diag.args()); + let fluent_args = to_fluent_args(diag.args()); let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args); diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index a774b52c8..23f29a24f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -1,21 +1,17 @@ use crate::snippet::Style; use crate::{ - CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, + CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan, SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, }; use rustc_data_structures::fx::FxHashMap; use rustc_error_messages::FluentValue; -use rustc_hir as hir; use rustc_lint_defs::{Applicability, LintExpectationId}; use rustc_span::edition::LATEST_STABLE_EDITION; -use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; -use rustc_span::{edition::Edition, Span, DUMMY_SP}; -use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; +use rustc_span::symbol::Symbol; +use rustc_span::{Span, DUMMY_SP}; use std::borrow::Cow; use std::fmt; use std::hash::{Hash, Hasher}; -use std::num::ParseIntError; -use std::path::{Path, PathBuf}; /// Error type for `Diagnostic`'s `suggestions` field, indicating that /// `.disable_suggestions()` was called on the `Diagnostic`. @@ -25,7 +21,11 @@ pub struct SuggestionsDisabled; /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of /// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of /// diagnostic emission. -pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>); +pub type DiagnosticArg<'iter, 'source> = + (&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>); + +/// Name of a diagnostic argument. +pub type DiagnosticArgName<'source> = Cow<'source, str>; /// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted /// to a `FluentValue` by the emitter to be used in diagnostic translation. @@ -35,7 +35,7 @@ pub enum DiagnosticArgValue<'source> { Number(usize), } -/// Converts a value of a type into a `DiagnosticArg` (typically a field of a `SessionDiagnostic` +/// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic` /// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type /// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*` /// crates to implement this. @@ -43,119 +43,6 @@ pub trait IntoDiagnosticArg { fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; } -pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display); - -impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.0.to_string().into_diagnostic_arg() - } -} - -impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> { - fn from(t: &'a dyn fmt::Display) -> Self { - DiagnosticArgFromDisplay(t) - } -} - -impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> { - fn from(t: &'a T) -> Self { - DiagnosticArgFromDisplay(t) - } -} - -macro_rules! into_diagnostic_arg_using_display { - ($( $ty:ty ),+ $(,)?) => { - $( - impl IntoDiagnosticArg for $ty { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } - } - )+ - } -} - -into_diagnostic_arg_using_display!( - i8, - u8, - i16, - u16, - i32, - u32, - i64, - u64, - i128, - u128, - std::io::Error, - std::num::NonZeroU32, - hir::Target, - Edition, - Ident, - MacroRulesNormalizedIdent, - ParseIntError, - StackProtector, - &TargetTriple, - SplitDebuginfo -); - -impl IntoDiagnosticArg for bool { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - if self { - DiagnosticArgValue::Str(Cow::Borrowed("true")) - } else { - DiagnosticArgValue::Str(Cow::Borrowed("false")) - } - } -} - -impl IntoDiagnosticArg for char { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self))) - } -} - -impl IntoDiagnosticArg for Symbol { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_ident_string().into_diagnostic_arg() - } -} - -impl<'a> IntoDiagnosticArg for &'a str { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - self.to_string().into_diagnostic_arg() - } -} - -impl IntoDiagnosticArg for String { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self)) - } -} - -impl<'a> IntoDiagnosticArg for &'a Path { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) - } -} - -impl IntoDiagnosticArg for PathBuf { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) - } -} - -impl IntoDiagnosticArg for usize { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Number(self) - } -} - -impl IntoDiagnosticArg for PanicStrategy { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) - } -} - impl<'source> Into> for DiagnosticArgValue<'source> { fn into(self) -> FluentValue<'source> { match self { @@ -165,22 +52,24 @@ impl<'source> Into> for DiagnosticArgValue<'source> { } } -impl IntoDiagnosticArg for hir::ConstContext { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Borrowed(match self { - hir::ConstContext::ConstFn => "constant function", - hir::ConstContext::Static(_) => "static", - hir::ConstContext::Const => "constant", - })) - } -} - /// Trait implemented by error types. This should not be implemented manually. Instead, use -/// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic]. -#[rustc_diagnostic_item = "AddSubdiagnostic"] -pub trait AddSubdiagnostic { +/// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic]. +#[cfg_attr(bootstrap, rustc_diagnostic_item = "AddSubdiagnostic")] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "AddToDiagnostic")] +pub trait AddToDiagnostic +where + Self: Sized, +{ /// Add a subdiagnostic to an existing diagnostic. - fn add_to_diagnostic(self, diag: &mut Diagnostic); + fn add_to_diagnostic(self, diag: &mut Diagnostic) { + self.add_to_diagnostic_with(diag, |_, m| m); + } + + /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used + /// (to optionally perform eager translation). + fn add_to_diagnostic_with(self, diag: &mut Diagnostic, f: F) + where + F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage; } /// Trait implemented by lint types. This should not be implemented manually. Instead, use @@ -188,7 +77,12 @@ pub trait AddSubdiagnostic { #[rustc_diagnostic_item = "DecorateLint"] pub trait DecorateLint<'a, G: EmissionGuarantee> { /// Decorate and emit a lint. - fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>); + fn decorate_lint<'b>( + self, + diag: &'b mut DiagnosticBuilder<'a, G>, + ) -> &'b mut DiagnosticBuilder<'a, G>; + + fn msg(&self) -> DiagnosticMessage; } #[must_use] @@ -203,7 +97,7 @@ pub struct Diagnostic { pub span: MultiSpan, pub children: Vec, pub suggestions: Result, SuggestionsDisabled>, - args: Vec>, + args: FxHashMap, DiagnosticArgValue<'static>>, /// This is not used for highlighting or rendering any error message. Rather, it can be used /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of @@ -295,7 +189,7 @@ impl Diagnostic { span: MultiSpan::new(), children: vec![], suggestions: Ok(vec![]), - args: vec![], + args: Default::default(), sort_span: DUMMY_SP, is_lint: false, } @@ -338,9 +232,10 @@ impl Diagnostic { // The lint index inside the attribute is manually transferred here. let lint_index = expectation_id.get_lint_index(); expectation_id.set_lint_index(None); - let mut stable_id = *unstable_to_stable + let mut stable_id = unstable_to_stable .get(&expectation_id) - .expect("each unstable `LintExpectationId` must have a matching stable id"); + .expect("each unstable `LintExpectationId` must have a matching stable id") + .normalize(); stable_id.set_lint_index(lint_index); *expectation_id = stable_id; @@ -672,6 +567,11 @@ impl Diagnostic { style: SuggestionStyle, ) -> &mut Self { assert!(!suggestion.is_empty()); + debug_assert!( + !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: suggestion @@ -749,6 +649,10 @@ impl Diagnostic { applicability: Applicability, style: SuggestionStyle, ) -> &mut Self { + debug_assert!( + !(sp.is_empty() && suggestion.to_string().is_empty()), + "Span must not be empty and have no suggestion" + ); self.push_suggestion(CodeSuggestion { substitutions: vec![Substitution { parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], @@ -786,9 +690,33 @@ impl Diagnostic { msg: impl Into, suggestions: impl Iterator, applicability: Applicability, + ) -> &mut Self { + self.span_suggestions_with_style( + sp, + msg, + suggestions, + applicability, + SuggestionStyle::ShowCode, + ) + } + + /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`]. + pub fn span_suggestions_with_style( + &mut self, + sp: Span, + msg: impl Into, + suggestions: impl Iterator, + applicability: Applicability, + style: SuggestionStyle, ) -> &mut Self { let mut suggestions: Vec<_> = suggestions.collect(); suggestions.sort(); + + debug_assert!( + !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + let substitutions = suggestions .into_iter() .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }) @@ -796,22 +724,33 @@ impl Diagnostic { self.push_suggestion(CodeSuggestion { substitutions, msg: self.subdiagnostic_message_to_diagnostic_message(msg), - style: SuggestionStyle::ShowCode, + style, applicability, }); self } - /// Prints out a message with multiple suggested edits of the code. - /// See also [`Diagnostic::span_suggestion()`]. + /// Prints out a message with multiple suggested edits of the code, where each edit consists of + /// multiple parts. + /// See also [`Diagnostic::multipart_suggestion()`]. pub fn multipart_suggestions( &mut self, msg: impl Into, suggestions: impl Iterator>, applicability: Applicability, ) -> &mut Self { + let suggestions: Vec<_> = suggestions.collect(); + debug_assert!( + !(suggestions + .iter() + .flat_map(|suggs| suggs) + .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())), + "Span must not be empty and have no suggestion" + ); + self.push_suggestion(CodeSuggestion { substitutions: suggestions + .into_iter() .map(|sugg| Substitution { parts: sugg .into_iter() @@ -825,6 +764,7 @@ impl Diagnostic { }); self } + /// Prints out a message with a suggested edit of the code. If the suggestion is presented /// inline, it will only show the message and not the suggestion. /// @@ -890,13 +830,30 @@ impl Diagnostic { self } - /// Add a subdiagnostic from a type that implements `SessionSubdiagnostic` - see - /// [rustc_macros::SessionSubdiagnostic]. - pub fn subdiagnostic(&mut self, subdiagnostic: impl AddSubdiagnostic) -> &mut Self { + /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see + /// [rustc_macros::Subdiagnostic]). + pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self { subdiagnostic.add_to_diagnostic(self); self } + /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see + /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages + /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of + /// interpolated variables). + pub fn eager_subdiagnostic( + &mut self, + handler: &crate::Handler, + subdiagnostic: impl AddToDiagnostic, + ) -> &mut Self { + subdiagnostic.add_to_diagnostic_with(self, |diag, msg| { + let args = diag.args(); + let msg = diag.subdiagnostic_message_to_diagnostic_message(msg); + handler.eagerly_translate(msg, args) + }); + self + } + pub fn set_span>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); if let Some(span) = self.span.primary_span() { @@ -929,8 +886,11 @@ impl Diagnostic { self } - pub fn args(&self) -> &[DiagnosticArg<'static>] { - &self.args + // Exact iteration order of diagnostic arguments shouldn't make a difference to output because + // they're only used in interpolation. + #[allow(rustc::potential_query_instability)] + pub fn args<'a>(&'a self) -> impl Iterator> { + self.args.iter() } pub fn set_arg( @@ -938,7 +898,7 @@ impl Diagnostic { name: impl Into>, arg: impl IntoDiagnosticArg, ) -> &mut Self { - self.args.push((name.into(), arg.into_diagnostic_arg())); + self.args.insert(name.into(), arg.into_diagnostic_arg()); self } @@ -949,7 +909,7 @@ impl Diagnostic { /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by /// combining it with the primary message of the diagnostic (if translatable, otherwise it just /// passes the user's string along). - fn subdiagnostic_message_to_diagnostic_message( + pub(crate) fn subdiagnostic_message_to_diagnostic_message( &self, attr: impl Into, ) -> DiagnosticMessage { diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 7e29dc207..9b41234dc 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -5,6 +5,7 @@ use crate::{ }; use crate::{Handler, Level, MultiSpan, StashKey}; use rustc_lint_defs::Applicability; +use rustc_span::source_map::Spanned; use rustc_span::Span; use std::borrow::Cow; @@ -13,6 +14,28 @@ use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::thread::panicking; +/// Trait implemented by error types. This should not be implemented manually. Instead, use +/// `#[derive(Diagnostic)]` -- see [rustc_macros::Diagnostic]. +#[cfg_attr(bootstrap, rustc_diagnostic_item = "SessionDiagnostic")] +#[cfg_attr(not(bootstrap), rustc_diagnostic_item = "IntoDiagnostic")] +pub trait IntoDiagnostic<'a, T: EmissionGuarantee = ErrorGuaranteed> { + /// Write out as a diagnostic out of `Handler`. + #[must_use] + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, T>; +} + +impl<'a, T, E> IntoDiagnostic<'a, E> for Spanned +where + T: IntoDiagnostic<'a, E>, + E: EmissionGuarantee, +{ + fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, E> { + let mut diag = self.node.into_diagnostic(handler); + diag.set_span(self.span); + diag + } +} + /// Used for emitting structured error messages and other diagnostic information. /// /// If there is some state in a downstream crate you would like to @@ -232,6 +255,56 @@ impl EmissionGuarantee for () { } } +/// Marker type which enables implementation of `create_note` and `emit_note` functions for +/// note-without-error struct diagnostics. +#[derive(Copy, Clone)] +pub struct Noted; + +impl<'a> DiagnosticBuilder<'a, Noted> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { + let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); + Self::new_diagnostic_note(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } +} + +impl EmissionGuarantee for Noted { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + handler.emit_diagnostic(&mut db.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + + Noted + } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_note(handler, msg) + } +} + impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. @@ -570,7 +643,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { forward!(pub fn subdiagnostic( &mut self, - subdiagnostic: impl crate::AddSubdiagnostic + subdiagnostic: impl crate::AddToDiagnostic ) -> &mut Self); } @@ -619,27 +692,3 @@ macro_rules! struct_span_err { macro_rules! error_code { ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }}; } - -/// Wrapper around a `DiagnosticBuilder` for creating lints. -pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>); - -impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> { - #[rustc_lint_diagnostics] - /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`. - pub fn build(mut self, msg: impl Into) -> DiagnosticBuilder<'a, G> { - self.0.set_primary_message(msg); - self.0.set_is_lint(); - self.0 - } - - /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`. - pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> { - LintDiagnosticBuilder(err) - } -} - -impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> { - pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> { - LintDiagnosticBuilder(self.0.forget_guarantee()) - } -} diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs new file mode 100644 index 000000000..7640b2919 --- /dev/null +++ b/compiler/rustc_errors/src/diagnostic_impls.rs @@ -0,0 +1,222 @@ +use crate::{ + fluent, DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg, +}; +use rustc_ast as ast; +use rustc_ast_pretty::pprust; +use rustc_hir as hir; +use rustc_lint_defs::Level; +use rustc_span::edition::Edition; +use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; +use rustc_target::abi::TargetDataLayoutErrors; +use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; +use std::borrow::Cow; +use std::fmt; +use std::num::ParseIntError; +use std::path::{Path, PathBuf}; + +pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display); + +impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.0.to_string().into_diagnostic_arg() + } +} + +impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> { + fn from(t: &'a dyn fmt::Display) -> Self { + DiagnosticArgFromDisplay(t) + } +} + +impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> { + fn from(t: &'a T) -> Self { + DiagnosticArgFromDisplay(t) + } +} + +macro_rules! into_diagnostic_arg_using_display { + ($( $ty:ty ),+ $(,)?) => { + $( + impl IntoDiagnosticArg for $ty { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } + } + )+ + } +} + +into_diagnostic_arg_using_display!( + i8, + u8, + i16, + u16, + i32, + u32, + i64, + u64, + i128, + u128, + std::io::Error, + std::num::NonZeroU32, + hir::Target, + Edition, + Ident, + MacroRulesNormalizedIdent, + ParseIntError, + StackProtector, + &TargetTriple, + SplitDebuginfo +); + +impl IntoDiagnosticArg for bool { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + if self { + DiagnosticArgValue::Str(Cow::Borrowed("true")) + } else { + DiagnosticArgValue::Str(Cow::Borrowed("false")) + } + } +} + +impl IntoDiagnosticArg for char { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self))) + } +} + +impl IntoDiagnosticArg for Symbol { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_ident_string().into_diagnostic_arg() + } +} + +impl<'a> IntoDiagnosticArg for &'a str { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + self.to_string().into_diagnostic_arg() + } +} + +impl IntoDiagnosticArg for String { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self)) + } +} + +impl<'a> IntoDiagnosticArg for &'a Path { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + +impl IntoDiagnosticArg for PathBuf { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) + } +} + +impl IntoDiagnosticArg for usize { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Number(self) + } +} + +impl IntoDiagnosticArg for PanicStrategy { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) + } +} + +impl IntoDiagnosticArg for hir::ConstContext { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + hir::ConstContext::ConstFn => "constant function", + hir::ConstContext::Static(_) => "static", + hir::ConstContext::Const => "constant", + })) + } +} + +impl IntoDiagnosticArg for ast::Path { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self))) + } +} + +impl IntoDiagnosticArg for ast::token::Token { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(pprust::token_to_string(&self)) + } +} + +impl IntoDiagnosticArg for ast::token::TokenKind { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(pprust::token_kind_to_string(&self)) + } +} + +impl IntoDiagnosticArg for Level { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Borrowed(match self { + Level::Allow => "-A", + Level::Warn => "-W", + Level::ForceWarn(_) => "--force-warn", + Level::Deny => "-D", + Level::Forbid => "-F", + Level::Expect(_) => { + unreachable!("lints with the level of `expect` should not run this code"); + } + })) + } +} + +impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> { + fn into_diagnostic(self, handler: &Handler) -> DiagnosticBuilder<'_, !> { + let mut diag; + match self { + TargetDataLayoutErrors::InvalidAddressSpace { addr_space, err, cause } => { + diag = handler.struct_fatal(fluent::errors_target_invalid_address_space); + diag.set_arg("addr_space", addr_space); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InvalidBits { kind, bit, cause, err } => { + diag = handler.struct_fatal(fluent::errors_target_invalid_bits); + diag.set_arg("kind", kind); + diag.set_arg("bit", bit); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::MissingAlignment { cause } => { + diag = handler.struct_fatal(fluent::errors_target_missing_alignment); + diag.set_arg("cause", cause); + diag + } + TargetDataLayoutErrors::InvalidAlignment { cause, err } => { + diag = handler.struct_fatal(fluent::errors_target_invalid_alignment); + diag.set_arg("cause", cause); + diag.set_arg("err", err); + diag + } + TargetDataLayoutErrors::InconsistentTargetArchitecture { dl, target } => { + diag = handler.struct_fatal(fluent::errors_target_inconsistent_architecture); + diag.set_arg("dl", dl); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InconsistentTargetPointerWidth { pointer_size, target } => { + diag = handler.struct_fatal(fluent::errors_target_inconsistent_pointer_width); + diag.set_arg("pointer_size", pointer_size); + diag.set_arg("target", target); + diag + } + TargetDataLayoutErrors::InvalidBitsSize { err } => { + diag = handler.struct_fatal(fluent::errors_target_invalid_bits_size); + diag.set_arg("err", err); + diag + } + } + } +} diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 66fbb8f12..cd6413bc3 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -14,7 +14,7 @@ use rustc_span::{FileLines, SourceFile, Span}; use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString}; use crate::styled_buffer::StyledBuffer; -use crate::translation::Translate; +use crate::translation::{to_fluent_args, Translate}; use crate::{ CodeSuggestion, Diagnostic, DiagnosticId, DiagnosticMessage, FluentBundle, Handler, LazyFallbackBundle, Level, MultiSpan, SubDiagnostic, SubstitutionHighlight, SuggestionStyle, @@ -535,7 +535,7 @@ impl Emitter for EmitterWriter { } fn emit_diagnostic(&mut self, diag: &Diagnostic) { - let fluent_args = self.to_fluent_args(diag.args()); + let fluent_args = to_fluent_args(diag.args()); let mut children = diag.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&diag, &fluent_args); diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 1680c6acc..4cc7be47f 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -13,7 +13,7 @@ use rustc_span::source_map::{FilePathMapping, SourceMap}; use crate::emitter::{Emitter, HumanReadableErrorType}; use crate::registry::Registry; -use crate::translation::Translate; +use crate::translation::{to_fluent_args, Translate}; use crate::DiagnosticId; use crate::{ CodeSuggestion, FluentBundle, LazyFallbackBundle, MultiSpan, SpanLabel, SubDiagnostic, @@ -312,7 +312,7 @@ struct UnusedExterns<'a, 'b, 'c> { impl Diagnostic { fn from_errors_diagnostic(diag: &crate::Diagnostic, je: &JsonEmitter) -> Diagnostic { - let args = je.to_fluent_args(diag.args()); + let args = to_fluent_args(diag.args()); let sugg = diag.suggestions.iter().flatten().map(|sugg| { let translated_message = je.translate_message(&sugg.msg, &args); Diagnostic { diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a7b01feeb..0963ea71f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -7,7 +7,6 @@ #![feature(if_let_guard)] #![feature(adt_const_params)] #![feature(let_chains)] -#![cfg_attr(bootstrap, feature(let_else))] #![feature(never_type)] #![feature(result_option_inspect)] #![feature(rustc_attrs)] @@ -31,7 +30,7 @@ use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::{self, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ - fallback_fluent_bundle, fluent, fluent_bundle, DiagnosticMessage, FluentBundle, + fallback_fluent_bundle, fluent, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, DEFAULT_LOCALE_RESOURCES, }; @@ -52,6 +51,7 @@ use termcolor::{Color, ColorSpec}; pub mod annotate_snippet_emitter_writer; mod diagnostic; mod diagnostic_builder; +mod diagnostic_impls; pub mod emitter; pub mod json; mod lock; @@ -60,15 +60,17 @@ mod snippet; mod styled_buffer; pub mod translation; +pub use diagnostic_builder::IntoDiagnostic; pub use snippet::Style; -pub type PResult<'a, T> = Result>; +pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>; +pub type PResult<'a, T> = Result>; // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. -// (See also the comment on `DiagnosticBuilder`'s `diagnostic` field.) +// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.) #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, ()>, 16); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64", not(bootstrap)))] +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16); #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)] @@ -370,10 +372,11 @@ impl fmt::Display for ExplicitBug { impl error::Error for ExplicitBug {} pub use diagnostic::{ - AddSubdiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, - DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, + AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId, + DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, LintDiagnosticBuilder}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; +pub use diagnostic_impls::DiagnosticArgFromDisplay; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. @@ -410,7 +413,7 @@ struct HandlerInner { /// would be unnecessary repetition. taught_diagnostics: FxHashSet, - /// Used to suggest rustc --explain + /// Used to suggest rustc --explain `` emitted_diagnostic_codes: FxIndexSet, /// This set contains a hash of every diagnostic that has been emitted by @@ -436,11 +439,11 @@ struct HandlerInner { /// have been converted. check_unstable_expect_diagnostics: bool, - /// Expected [`Diagnostic`]s store a [`LintExpectationId`] as part of + /// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of /// the lint level. [`LintExpectationId`]s created early during the compilation /// (before `HirId`s have been defined) are not stable and can therefore not be /// stored on disk. This buffer stores these diagnostics until the ID has been - /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`]s are the + /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][diagnostic::Diagnostic]s are the /// submitted for storage and added to the list of fulfilled expectations. unstable_expect_diagnostics: Vec, @@ -459,6 +462,10 @@ pub enum StashKey { ItemNoType, UnderscoreForArrayLengths, EarlySyntaxWarning, + CallIntoMethod, + /// When an invalid lifetime e.g. `'2` should be reinterpreted + /// as a char literal in the parser + LifetimeIsChar, } fn default_track_diagnostic(_: &Diagnostic) {} @@ -596,6 +603,17 @@ impl Handler { } } + /// Translate `message` eagerly with `args`. + pub fn eagerly_translate<'a>( + &self, + message: DiagnosticMessage, + args: impl Iterator>, + ) -> SubdiagnosticMessage { + let inner = self.inner.borrow(); + let args = crate::translation::to_fluent_args(args); + SubdiagnosticMessage::Eager(inner.emitter.translate_message(&message, &args).to_string()) + } + // This is here to not allow mutation of flags; // as of this writing it's only used in tests in librustc_middle. pub fn can_emit_warnings(&self) -> bool { @@ -1028,6 +1046,39 @@ impl Handler { self.inner.borrow_mut().emit_diagnostic(diagnostic) } + pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed { + self.create_err(err).emit() + } + + pub fn create_err<'a>( + &'a self, + err: impl IntoDiagnostic<'a>, + ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { + err.into_diagnostic(self) + } + + pub fn create_warning<'a>( + &'a self, + warning: impl IntoDiagnostic<'a, ()>, + ) -> DiagnosticBuilder<'a, ()> { + warning.into_diagnostic(self) + } + + pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { + self.create_warning(warning).emit() + } + + pub fn create_fatal<'a>( + &'a self, + fatal: impl IntoDiagnostic<'a, !>, + ) -> DiagnosticBuilder<'a, !> { + fatal.into_diagnostic(self) + } + + pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, !>) -> ! { + self.create_fatal(fatal).emit() + } + fn emit_diag_at_span( &self, mut diag: Diagnostic, @@ -1100,6 +1151,12 @@ impl Handler { ); std::mem::take(&mut self.inner.borrow_mut().fulfilled_expectations) } + + pub fn flush_delayed(&self) { + let mut inner = self.inner.lock(); + let bugs = std::mem::replace(&mut inner.delayed_span_bugs, Vec::new()); + inner.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); + } } impl HandlerInner { @@ -1171,7 +1228,7 @@ impl HandlerInner { if let Some(expectation_id) = diagnostic.level.get_expectation_id() { self.suppressed_expected_diag = true; - self.fulfilled_expectations.insert(expectation_id); + self.fulfilled_expectations.insert(expectation_id.normalize()); } if matches!(diagnostic.level, Warning(_)) diff --git a/compiler/rustc_errors/src/translation.rs b/compiler/rustc_errors/src/translation.rs index 4f407badb..a7737b467 100644 --- a/compiler/rustc_errors/src/translation.rs +++ b/compiler/rustc_errors/src/translation.rs @@ -4,6 +4,27 @@ use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; use std::borrow::Cow; +/// Convert diagnostic arguments (a rustc internal type that exists to implement +/// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. +/// +/// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then +/// passed around as a reference thereafter. +pub fn to_fluent_args<'iter, 'arg: 'iter>( + iter: impl Iterator>, +) -> FluentArgs<'arg> { + let mut args = if let Some(size) = iter.size_hint().1 { + FluentArgs::with_capacity(size) + } else { + FluentArgs::new() + }; + + for (k, v) in iter { + args.set(k.clone(), v.clone()); + } + + args +} + pub trait Translate { /// Return `FluentBundle` with localized diagnostics for the locale requested by the user. If no /// language was requested by the user then this will be `None` and `fallback_fluent_bundle` @@ -15,15 +36,6 @@ pub trait Translate { /// unavailable for the requested locale. fn fallback_fluent_bundle(&self) -> &FluentBundle; - /// Convert diagnostic arguments (a rustc internal type that exists to implement - /// `Encodable`/`Decodable`) into `FluentArgs` which is necessary to perform translation. - /// - /// Typically performed once for each diagnostic at the start of `emit_diagnostic` and then - /// passed around as a reference thereafter. - fn to_fluent_args<'arg>(&self, args: &[DiagnosticArg<'arg>]) -> FluentArgs<'arg> { - FromIterator::from_iter(args.iter().cloned()) - } - /// Convert `DiagnosticMessage`s to a string, performing translation if necessary. fn translate_messages( &self, @@ -43,7 +55,9 @@ pub trait Translate { ) -> Cow<'_, str> { trace!(?message, ?args); let (identifier, attr) = match message { - DiagnosticMessage::Str(msg) => return Cow::Borrowed(&msg), + DiagnosticMessage::Str(msg) | DiagnosticMessage::Eager(msg) => { + return Cow::Borrowed(&msg); + } DiagnosticMessage::FluentIdentifier(identifier, attr) => (identifier, attr), }; -- cgit v1.2.3