summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:11:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:13:23 +0000
commit20431706a863f92cb37dc512fef6e48d192aaf2c (patch)
tree2867f13f5fd5437ba628c67d7f87309ccadcd286 /compiler/rustc_errors
parentReleasing progress-linux version 1.65.0+dfsg1-2~progress7.99u1. (diff)
downloadrustc-20431706a863f92cb37dc512fef6e48d192aaf2c.tar.xz
rustc-20431706a863f92cb37dc512fef6e48d192aaf2c.zip
Merging upstream version 1.66.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_errors')
-rw-r--r--compiler/rustc_errors/Cargo.toml3
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs262
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs99
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs222
-rw-r--r--compiler/rustc_errors/src/emitter.rs4
-rw-r--r--compiler/rustc_errors/src/json.rs4
-rw-r--r--compiler/rustc_errors/src/lib.rs81
-rw-r--r--compiler/rustc_errors/src/translation.rs34
9 files changed, 508 insertions, 205 deletions
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<FluentValue<'source>> for DiagnosticArgValue<'source> {
fn into(self) -> FluentValue<'source> {
match self {
@@ -165,22 +52,24 @@ impl<'source> Into<FluentValue<'source>> 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<F>(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<SubDiagnostic>,
pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
- args: Vec<DiagnosticArg<'static>>,
+ args: FxHashMap<DiagnosticArgName<'static>, 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 }],
@@ -787,8 +691,32 @@ impl Diagnostic {
suggestions: impl Iterator<Item = String>,
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<SubdiagnosticMessage>,
+ suggestions: impl Iterator<Item = String>,
+ 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<SubdiagnosticMessage>,
suggestions: impl Iterator<Item = Vec<(Span, String)>>,
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<S: Into<MultiSpan>>(&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<Item = DiagnosticArg<'a, 'static>> {
+ self.args.iter()
}
pub fn set_arg(
@@ -938,7 +898,7 @@ impl Diagnostic {
name: impl Into<Cow<'static, str>>,
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<SubdiagnosticMessage>,
) -> 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<T>
+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<DiagnosticMessage>) -> 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<DiagnosticMessage>,
+ ) -> 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<DiagnosticMessage>) -> 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<T, DiagnosticBuilder<'a, ErrorGuaranteed>>;
+pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
+pub type PResult<'a, T> = Result<T, PErr<'a>>;
// `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<DiagnosticId>,
- /// Used to suggest rustc --explain <error code>
+ /// Used to suggest rustc --explain `<error code>`
emitted_diagnostic_codes: FxIndexSet<DiagnosticId>,
/// 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<Diagnostic>,
@@ -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<Item = DiagnosticArg<'a, 'static>>,
+ ) -> 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<Item = DiagnosticArg<'iter, 'arg>>,
+) -> 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),
};