summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 03:59:35 +0000
commitd1b2d29528b7794b41e66fc2136e395a02f8529b (patch)
treea4a17504b260206dec3cf55b2dca82929a348ac2 /compiler/rustc_errors
parentReleasing progress-linux version 1.72.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.tar.xz
rustc-d1b2d29528b7794b41e66fc2136e395a02f8529b.zip
Merging upstream version 1.73.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.toml1
-rw-r--r--compiler/rustc_errors/messages.ftl22
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs20
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs10
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs4
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs69
-rw-r--r--compiler/rustc_errors/src/emitter.rs271
-rw-r--r--compiler/rustc_errors/src/json.rs40
-rw-r--r--compiler/rustc_errors/src/json/tests.rs2
-rw-r--r--compiler/rustc_errors/src/lib.rs182
-rw-r--r--compiler/rustc_errors/src/markdown/parse.rs2
-rw-r--r--compiler/rustc_errors/src/markdown/term.rs2
-rw-r--r--compiler/rustc_errors/src/markdown/tests/term.rs2
13 files changed, 334 insertions, 293 deletions
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index e8bcd7c11..faab9f09d 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -25,6 +25,7 @@ annotate-snippets = "0.9"
termize = "0.1.1"
serde = { version = "1.0.125", features = [ "derive" ] }
serde_json = "1.0.59"
+derive_setters = "0.1.6"
[target.'cfg(windows)'.dependencies.windows]
version = "0.48.0"
diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl
index 8e8223c3c..d68dba0be 100644
--- a/compiler/rustc_errors/messages.ftl
+++ b/compiler/rustc_errors/messages.ftl
@@ -1,3 +1,25 @@
+errors_delayed_at_with_newline =
+ delayed at {$emitted_at}
+ {$note}
+
+errors_delayed_at_without_newline =
+ delayed at {$emitted_at} - {$note}
+
+errors_expected_lifetime_parameter =
+ expected lifetime {$count ->
+ [1] parameter
+ *[other] parameters
+ }
+
+errors_indicate_anonymous_lifetime =
+ indicate the anonymous {$count ->
+ [1] lifetime
+ *[other] lifetimes
+ }
+
+errors_invalid_flushed_delayed_diagnostic_level =
+ `flushed_delayed` got diagnostic with level {$level}, instead of the expected `DelayedBug`
+
errors_target_inconsistent_architecture =
inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index 9872b3bda..a88fba6da 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -157,10 +157,8 @@ impl AnnotateSnippetEmitterWriter {
{
annotated_files.swap(0, pos);
}
- // owned: line source, line index, annotations
- type Owned = (String, usize, Vec<crate::snippet::Annotation>);
- let filename = source_map.filename_for_diagnostics(&primary_lo.file.name);
- let origin = filename.to_string_lossy();
+ // owned: file name, line source, line index, annotations
+ type Owned = (String, String, usize, Vec<crate::snippet::Annotation>);
let annotated_files: Vec<Owned> = annotated_files
.into_iter()
.flat_map(|annotated_file| {
@@ -169,7 +167,15 @@ impl AnnotateSnippetEmitterWriter {
.lines
.into_iter()
.map(|line| {
- (source_string(file.clone(), &line), line.line_index, line.annotations)
+ // Ensure the source file is present before we try
+ // to load a string from it.
+ source_map.ensure_source_file_source_present(file.clone());
+ (
+ format!("{}", source_map.filename_for_diagnostics(&file.name)),
+ source_string(file.clone(), &line),
+ line.line_index,
+ line.annotations,
+ )
})
.collect::<Vec<Owned>>()
})
@@ -192,11 +198,11 @@ impl AnnotateSnippetEmitterWriter {
},
slices: annotated_files
.iter()
- .map(|(source, line_index, annotations)| {
+ .map(|(file_name, source, line_index, annotations)| {
Slice {
source,
line_start: *line_index,
- origin: Some(&origin),
+ origin: Some(&file_name),
// FIXME(#59346): Not really sure when `fold` should be true or false
fold: false,
annotations: annotations
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index ed0d06ed0..a96e317df 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -420,13 +420,13 @@ impl Diagnostic {
let expected_label = if expected_label.is_empty() {
"expected".to_string()
} else {
- format!("expected {}", expected_label)
+ format!("expected {expected_label}")
};
let found_label = found_label.to_string();
let found_label = if found_label.is_empty() {
"found".to_string()
} else {
- format!("found {}", found_label)
+ format!("found {found_label}")
};
let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
(expected_label.len() - found_label.len(), 0)
@@ -439,13 +439,13 @@ impl Diagnostic {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
- msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
+ msg.push((format!("`{expected_extra}\n"), Style::NoStyle));
msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle));
msg.extend(found.0.iter().map(|x| match *x {
StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
}));
- msg.push((format!("`{}", found_extra), Style::NoStyle));
+ msg.push((format!("`{found_extra}"), Style::NoStyle));
// For now, just attach these as notes.
self.highlighted_note(msg);
@@ -454,7 +454,7 @@ impl Diagnostic {
pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
self.highlighted_note(vec![
- (format!("`{}` from trait: `", name), Style::NoStyle),
+ (format!("`{name}` from trait: `"), Style::NoStyle),
(signature, Style::Highlight),
("`".to_string(), Style::NoStyle),
]);
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 08ff2cfba..5e23ae655 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -536,7 +536,9 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
}
};
- if handler.flags.dont_buffer_diagnostics || handler.flags.treat_err_as_bug.is_some() {
+ if handler.inner.lock().flags.dont_buffer_diagnostics
+ || handler.inner.lock().flags.treat_err_as_bug.is_some()
+ {
self.emit();
return None;
}
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 10fe7fc74..a170e3a89 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,3 +1,4 @@
+use crate::diagnostic::DiagnosticLocation;
use crate::{fluent_generated as fluent, AddToDiagnostic};
use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
use rustc_ast as ast;
@@ -10,6 +11,7 @@ use rustc_span::Span;
use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use rustc_type_ir as type_ir;
+use std::backtrace::Backtrace;
use std::borrow::Cow;
use std::fmt;
use std::num::ParseIntError;
@@ -102,7 +104,7 @@ impl IntoDiagnosticArg for bool {
impl IntoDiagnosticArg for char {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
- DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self)))
+ DiagnosticArgValue::Str(Cow::Owned(format!("{self:?}")))
}
}
@@ -164,6 +166,12 @@ impl IntoDiagnosticArg for hir::ConstContext {
}
}
+impl IntoDiagnosticArg for ast::Expr {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::Owned(pprust::expr_to_string(&self)))
+ }
+}
+
impl IntoDiagnosticArg for ast::Path {
fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
DiagnosticArgValue::Str(Cow::Owned(pprust::path_to_string(&self)))
@@ -311,3 +319,62 @@ pub enum LabelKind {
Label,
Help,
}
+
+#[derive(Subdiagnostic)]
+#[label(errors_expected_lifetime_parameter)]
+pub struct ExpectedLifetimeParameter {
+ #[primary_span]
+ pub span: Span,
+ pub count: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[note(errors_delayed_at_with_newline)]
+pub struct DelayedAtWithNewline {
+ #[primary_span]
+ pub span: Span,
+ pub emitted_at: DiagnosticLocation,
+ pub note: Backtrace,
+}
+#[derive(Subdiagnostic)]
+#[note(errors_delayed_at_without_newline)]
+pub struct DelayedAtWithoutNewline {
+ #[primary_span]
+ pub span: Span,
+ pub emitted_at: DiagnosticLocation,
+ pub note: Backtrace,
+}
+
+impl IntoDiagnosticArg for DiagnosticLocation {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::from(self.to_string()))
+ }
+}
+
+impl IntoDiagnosticArg for Backtrace {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::from(self.to_string()))
+ }
+}
+
+#[derive(Subdiagnostic)]
+#[note(errors_invalid_flushed_delayed_diagnostic_level)]
+pub struct InvalidFlushedDelayedDiagnosticLevel {
+ #[primary_span]
+ pub span: Span,
+ pub level: rustc_errors::Level,
+}
+impl IntoDiagnosticArg for rustc_errors::Level {
+ fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+ DiagnosticArgValue::Str(Cow::from(self.to_string()))
+ }
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(errors_indicate_anonymous_lifetime, code = "{suggestion}", style = "verbose")]
+pub struct IndicateAnonymousLifetime {
+ #[primary_span]
+ pub span: Span,
+ pub count: usize,
+ pub suggestion: String,
+}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 9d4d159fd..0cae06881 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -7,8 +7,6 @@
//!
//! The output types are defined in `rustc_session::config::ErrorOutputType`.
-use Destination::*;
-
use rustc_span::source_map::SourceMap;
use rustc_span::{FileLines, SourceFile, Span};
@@ -24,6 +22,7 @@ use crate::{
};
use rustc_lint_defs::pluralize;
+use derive_setters::Setters;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_data_structures::sync::Lrc;
use rustc_error_messages::{FluentArgs, SpanLabel};
@@ -35,8 +34,8 @@ use std::io::prelude::*;
use std::io::{self, IsTerminal};
use std::iter;
use std::path::Path;
-use termcolor::{Ansi, BufferWriter, ColorChoice, ColorSpec, StandardStream};
-use termcolor::{Buffer, Color, WriteColor};
+use termcolor::{Ansi, Buffer, BufferWriter, ColorChoice, ColorSpec, StandardStream};
+use termcolor::{Color, WriteColor};
/// Default column width, used in tests and when terminal dimensions cannot be determined.
const DEFAULT_COLUMN_WIDTH: usize = 140;
@@ -60,31 +59,15 @@ impl HumanReadableErrorType {
}
pub fn new_emitter(
self,
- dst: Box<dyn Write + Send>,
- source_map: Option<Lrc<SourceMap>>,
- bundle: Option<Lrc<FluentBundle>>,
+ mut dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle,
- teach: bool,
- diagnostic_width: Option<usize>,
- macro_backtrace: bool,
- track_diagnostics: bool,
- terminal_url: TerminalUrl,
) -> EmitterWriter {
let (short, color_config) = self.unzip();
let color = color_config.suggests_using_colors();
- EmitterWriter::new(
- dst,
- source_map,
- bundle,
- fallback_bundle,
- short,
- teach,
- color,
- diagnostic_width,
- macro_backtrace,
- track_diagnostics,
- terminal_url,
- )
+ if !dst.supports_color() && color {
+ dst = Box::new(Ansi::new(dst));
+ }
+ EmitterWriter::new(dst, fallback_bundle).short_message(short)
}
}
@@ -279,12 +262,12 @@ pub trait Emitter: Translate {
let msg = if substitution.is_empty() || sugg.style.hide_inline() {
// This substitution is only removal OR we explicitly don't want to show the
// code inline (`hide_inline`). Therefore, we don't show the substitution.
- format!("help: {}", &msg)
+ format!("help: {msg}")
} else {
// Show the default suggestion text with the substitution
format!(
"help: {}{}: `{}`",
- &msg,
+ msg,
if self.source_map().is_some_and(|sm| is_case_difference(
sm,
substitution,
@@ -639,10 +622,13 @@ impl ColorConfig {
}
/// Handles the writing of `HumanReadableErrorType::Default` and `HumanReadableErrorType::Short`
+#[derive(Setters)]
pub struct EmitterWriter {
+ #[setters(skip)]
dst: Destination,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
+ #[setters(skip)]
fallback_bundle: LazyFallbackBundle,
short_message: bool,
teach: bool,
@@ -662,65 +648,32 @@ pub struct FileWithAnnotatedLines {
}
impl EmitterWriter {
- pub fn stderr(
- color_config: ColorConfig,
- source_map: Option<Lrc<SourceMap>>,
- fluent_bundle: Option<Lrc<FluentBundle>>,
- fallback_bundle: LazyFallbackBundle,
- short_message: bool,
- teach: bool,
- diagnostic_width: Option<usize>,
- macro_backtrace: bool,
- track_diagnostics: bool,
- terminal_url: TerminalUrl,
- ) -> EmitterWriter {
- let dst = Destination::from_stderr(color_config);
+ pub fn stderr(color_config: ColorConfig, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
+ let dst = from_stderr(color_config);
+ Self::create(dst, fallback_bundle)
+ }
+
+ fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
EmitterWriter {
dst,
- sm: source_map,
- fluent_bundle,
+ sm: None,
+ fluent_bundle: None,
fallback_bundle,
- short_message,
- teach,
+ short_message: false,
+ teach: false,
ui_testing: false,
- diagnostic_width,
- macro_backtrace,
- track_diagnostics,
- terminal_url,
+ diagnostic_width: None,
+ macro_backtrace: false,
+ track_diagnostics: false,
+ terminal_url: TerminalUrl::No,
}
}
pub fn new(
- dst: Box<dyn Write + Send>,
- source_map: Option<Lrc<SourceMap>>,
- fluent_bundle: Option<Lrc<FluentBundle>>,
+ dst: Box<dyn WriteColor + Send>,
fallback_bundle: LazyFallbackBundle,
- short_message: bool,
- teach: bool,
- colored: bool,
- diagnostic_width: Option<usize>,
- macro_backtrace: bool,
- track_diagnostics: bool,
- terminal_url: TerminalUrl,
) -> EmitterWriter {
- EmitterWriter {
- dst: Raw(dst, colored),
- sm: source_map,
- fluent_bundle,
- fallback_bundle,
- short_message,
- teach,
- ui_testing: false,
- diagnostic_width,
- macro_backtrace,
- track_diagnostics,
- terminal_url,
- }
- }
-
- pub fn ui_testing(mut self, ui_testing: bool) -> Self {
- self.ui_testing = ui_testing;
- self
+ Self::create(dst, fallback_bundle)
}
fn maybe_anonymized(&self, line_num: usize) -> Cow<'static, str> {
@@ -1982,7 +1935,7 @@ impl EmitterWriter {
// We special case `#[derive(_)]\n` and other attribute suggestions, because those
// are the ones where context is most useful.
let file_lines = sm
- .span_to_lines(span.primary_span().unwrap().shrink_to_hi())
+ .span_to_lines(parts[0].span.shrink_to_hi())
.expect("span_to_lines failed when emitting suggestion");
let line_num = sm.lookup_char_pos(parts[0].span.lo()).line;
if let Some(line) = file_lines.file.get_line(line_num - 1) {
@@ -2145,7 +2098,7 @@ impl EmitterWriter {
&mut self.dst,
self.short_message,
) {
- panic!("failed to emit error: {}", e)
+ panic!("failed to emit error: {e}")
}
}
if !self.short_message {
@@ -2161,7 +2114,7 @@ impl EmitterWriter {
true,
None,
) {
- panic!("failed to emit error: {}", err);
+ panic!("failed to emit error: {err}");
}
}
for sugg in suggestions {
@@ -2180,7 +2133,7 @@ impl EmitterWriter {
true,
None,
) {
- panic!("failed to emit error: {}", e);
+ panic!("failed to emit error: {e}");
}
}
SuggestionStyle::HideCodeInline
@@ -2193,22 +2146,21 @@ impl EmitterWriter {
&Level::Help,
max_line_num_len,
) {
- panic!("failed to emit error: {}", e);
+ panic!("failed to emit error: {e}");
}
}
}
}
}
}
- Err(e) => panic!("failed to emit error: {}", e),
+ Err(e) => panic!("failed to emit error: {e}"),
}
- let mut dst = self.dst.writable();
- match writeln!(dst) {
- Err(e) => panic!("failed to emit error: {}", e),
+ match writeln!(self.dst) {
+ Err(e) => panic!("failed to emit error: {e}"),
_ => {
- if let Err(e) = dst.flush() {
- panic!("failed to emit error: {}", e)
+ if let Err(e) = self.dst.flush() {
+ panic!("failed to emit error: {e}")
}
}
}
@@ -2618,8 +2570,6 @@ fn emit_to_destination(
) -> io::Result<()> {
use crate::lock;
- let mut dst = dst.writable();
-
// In order to prevent error message interleaving, where multiple error lines get intermixed
// when multiple compiler processes error simultaneously, we emit errors with additional
// steps.
@@ -2635,7 +2585,8 @@ fn emit_to_destination(
let _buffer_lock = lock::acquire_global_lock("rustc_errors");
for (pos, line) in rendered_buffer.iter().enumerate() {
for part in line {
- dst.apply_style(*lvl, part.style)?;
+ let style = part.style.color_spec(*lvl);
+ dst.set_color(&style)?;
write!(dst, "{}", part.text)?;
dst.reset()?;
}
@@ -2647,61 +2598,69 @@ fn emit_to_destination(
Ok(())
}
-pub enum Destination {
- Terminal(StandardStream),
- Buffered(BufferWriter),
- // The bool denotes whether we should be emitting ansi color codes or not
- Raw(Box<(dyn Write + Send)>, bool),
-}
+pub type Destination = Box<(dyn WriteColor + Send)>;
-pub enum WritableDst<'a> {
- Terminal(&'a mut StandardStream),
- Buffered(&'a mut BufferWriter, Buffer),
- Raw(&'a mut (dyn Write + Send)),
- ColoredRaw(Ansi<&'a mut (dyn Write + Send)>),
+struct Buffy {
+ buffer_writer: BufferWriter,
+ buffer: Buffer,
}
-impl Destination {
- fn from_stderr(color: ColorConfig) -> Destination {
- let choice = color.to_color_choice();
- // On Windows we'll be performing global synchronization on the entire
- // system for emitting rustc errors, so there's no need to buffer
- // anything.
- //
- // On non-Windows we rely on the atomicity of `write` to ensure errors
- // don't get all jumbled up.
- if cfg!(windows) {
- Terminal(StandardStream::stderr(choice))
- } else {
- Buffered(BufferWriter::stderr(choice))
- }
+impl Write for Buffy {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.buffer.write(buf)
}
- fn writable(&mut self) -> WritableDst<'_> {
- match *self {
- Destination::Terminal(ref mut t) => WritableDst::Terminal(t),
- Destination::Buffered(ref mut t) => {
- let buf = t.buffer();
- WritableDst::Buffered(t, buf)
- }
- Destination::Raw(ref mut t, false) => WritableDst::Raw(t),
- Destination::Raw(ref mut t, true) => WritableDst::ColoredRaw(Ansi::new(t)),
+ fn flush(&mut self) -> io::Result<()> {
+ self.buffer_writer.print(&self.buffer)?;
+ self.buffer.clear();
+ Ok(())
+ }
+}
+
+impl Drop for Buffy {
+ fn drop(&mut self) {
+ if !self.buffer.is_empty() {
+ self.flush().unwrap();
+ panic!("buffers need to be flushed in order to print their contents");
}
}
+}
+impl WriteColor for Buffy {
fn supports_color(&self) -> bool {
- match *self {
- Self::Terminal(ref stream) => stream.supports_color(),
- Self::Buffered(ref buffer) => buffer.buffer().supports_color(),
- Self::Raw(_, supports_color) => supports_color,
- }
+ self.buffer.supports_color()
+ }
+
+ fn set_color(&mut self, spec: &ColorSpec) -> io::Result<()> {
+ self.buffer.set_color(spec)
+ }
+
+ fn reset(&mut self) -> io::Result<()> {
+ self.buffer.reset()
+ }
+}
+
+fn from_stderr(color: ColorConfig) -> Destination {
+ let choice = color.to_color_choice();
+ // On Windows we'll be performing global synchronization on the entire
+ // system for emitting rustc errors, so there's no need to buffer
+ // anything.
+ //
+ // On non-Windows we rely on the atomicity of `write` to ensure errors
+ // don't get all jumbled up.
+ if cfg!(windows) {
+ Box::new(StandardStream::stderr(choice))
+ } else {
+ let buffer_writer = BufferWriter::stderr(choice);
+ let buffer = buffer_writer.buffer();
+ Box::new(Buffy { buffer_writer, buffer })
}
}
-impl<'a> WritableDst<'a> {
- fn apply_style(&mut self, lvl: Level, style: Style) -> io::Result<()> {
+impl Style {
+ fn color_spec(&self, lvl: Level) -> ColorSpec {
let mut spec = ColorSpec::new();
- match style {
+ match self {
Style::Addition => {
spec.set_fg(Some(Color::Green)).set_intense(true);
}
@@ -2746,53 +2705,7 @@ impl<'a> WritableDst<'a> {
spec.set_bold(true);
}
}
- self.set_color(&spec)
- }
-
- fn set_color(&mut self, color: &ColorSpec) -> io::Result<()> {
- match *self {
- WritableDst::Terminal(ref mut t) => t.set_color(color),
- WritableDst::Buffered(_, ref mut t) => t.set_color(color),
- WritableDst::ColoredRaw(ref mut t) => t.set_color(color),
- WritableDst::Raw(_) => Ok(()),
- }
- }
-
- fn reset(&mut self) -> io::Result<()> {
- match *self {
- WritableDst::Terminal(ref mut t) => t.reset(),
- WritableDst::Buffered(_, ref mut t) => t.reset(),
- WritableDst::ColoredRaw(ref mut t) => t.reset(),
- WritableDst::Raw(_) => Ok(()),
- }
- }
-}
-
-impl<'a> Write for WritableDst<'a> {
- fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
- match *self {
- WritableDst::Terminal(ref mut t) => t.write(bytes),
- WritableDst::Buffered(_, ref mut buf) => buf.write(bytes),
- WritableDst::Raw(ref mut w) => w.write(bytes),
- WritableDst::ColoredRaw(ref mut t) => t.write(bytes),
- }
- }
-
- fn flush(&mut self) -> io::Result<()> {
- match *self {
- WritableDst::Terminal(ref mut t) => t.flush(),
- WritableDst::Buffered(_, ref mut buf) => buf.flush(),
- WritableDst::Raw(ref mut w) => w.flush(),
- WritableDst::ColoredRaw(ref mut w) => w.flush(),
- }
- }
-}
-
-impl<'a> Drop for WritableDst<'a> {
- fn drop(&mut self) {
- if let WritableDst::Buffered(ref mut dst, ref mut buf) = self {
- drop(dst.print(buf));
- }
+ spec
}
}
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index f32d6b96b..b8f58e305 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -10,6 +10,7 @@
// FIXME: spec the JSON output properly.
use rustc_span::source_map::{FilePathMapping, SourceMap};
+use termcolor::{ColorSpec, WriteColor};
use crate::emitter::{Emitter, HumanReadableErrorType};
use crate::registry::Registry;
@@ -159,7 +160,7 @@ impl Emitter for JsonEmitter {
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
- panic!("failed to print diagnostics: {:?}", e);
+ panic!("failed to print diagnostics: {e:?}");
}
}
@@ -172,7 +173,7 @@ impl Emitter for JsonEmitter {
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
- panic!("failed to print notification: {:?}", e);
+ panic!("failed to print notification: {e:?}");
}
}
@@ -194,7 +195,7 @@ impl Emitter for JsonEmitter {
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
- panic!("failed to print future breakage report: {:?}", e);
+ panic!("failed to print future breakage report: {e:?}");
}
}
@@ -208,7 +209,7 @@ impl Emitter for JsonEmitter {
}
.and_then(|_| self.dst.flush());
if let Err(e) = result {
- panic!("failed to print unused externs: {:?}", e);
+ panic!("failed to print unused externs: {e:?}");
}
}
@@ -356,20 +357,29 @@ impl Diagnostic {
self.0.lock().unwrap().flush()
}
}
+ impl WriteColor for BufWriter {
+ fn supports_color(&self) -> bool {
+ false
+ }
+
+ fn set_color(&mut self, _spec: &ColorSpec) -> io::Result<()> {
+ Ok(())
+ }
+
+ fn reset(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+ }
let buf = BufWriter::default();
let output = buf.clone();
je.json_rendered
- .new_emitter(
- Box::new(buf),
- Some(je.sm.clone()),
- je.fluent_bundle.clone(),
- je.fallback_bundle.clone(),
- false,
- je.diagnostic_width,
- je.macro_backtrace,
- je.track_diagnostics,
- je.terminal_url,
- )
+ .new_emitter(Box::new(buf), je.fallback_bundle.clone())
+ .sm(Some(je.sm.clone()))
+ .fluent_bundle(je.fluent_bundle.clone())
+ .diagnostic_width(je.diagnostic_width)
+ .macro_backtrace(je.macro_backtrace)
+ .track_diagnostics(je.track_diagnostics)
+ .terminal_url(je.terminal_url)
.ui_testing(je.ui_testing)
.emit_diagnostic(diag);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs
index 671dc449e..1f9a2981e 100644
--- a/compiler/rustc_errors/src/json/tests.rs
+++ b/compiler/rustc_errors/src/json/tests.rs
@@ -64,7 +64,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) {
);
let span = Span::with_root_ctxt(BytePos(span.0), BytePos(span.1));
- let handler = Handler::with_emitter(true, None, Box::new(je));
+ let handler = Handler::with_emitter(Box::new(je));
handler.span_err(span, "foo");
let bytes = output.lock().unwrap();
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index b9db25103..34518b537 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -15,6 +15,7 @@
#![feature(box_patterns)]
#![feature(error_reporter)]
#![allow(incomplete_features)]
+#![cfg_attr(not(bootstrap), allow(internal_features))]
#[macro_use]
extern crate rustc_macros;
@@ -22,6 +23,8 @@ extern crate rustc_macros;
#[macro_use]
extern crate tracing;
+extern crate self as rustc_errors;
+
pub use emitter::ColorConfig;
use rustc_lint_defs::LintExpectationId;
@@ -47,9 +50,10 @@ use std::borrow::Cow;
use std::error::Report;
use std::fmt;
use std::hash::Hash;
+use std::io::Write;
use std::num::NonZeroUsize;
use std::panic;
-use std::path::Path;
+use std::path::{Path, PathBuf};
use termcolor::{Color, ColorSpec};
@@ -376,13 +380,16 @@ pub struct ExplicitBug;
/// rather than a failed assertion, etc.
pub struct DelayedBugPanic;
+use crate::diagnostic_impls::{DelayedAtWithNewline, DelayedAtWithoutNewline};
pub use diagnostic::{
AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgValue, DiagnosticId,
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
pub use diagnostic_impls::{
- DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
+ DiagnosticArgFromDisplay, DiagnosticSymbolList, ExpectedLifetimeParameter,
+ IndicateAnonymousLifetime, InvalidFlushedDelayedDiagnosticLevel, LabelKind,
+ SingleLabelManySpans,
};
use std::backtrace::{Backtrace, BacktraceStatus};
@@ -390,7 +397,6 @@ use std::backtrace::{Backtrace, BacktraceStatus};
/// Certain errors (fatal, bug, unimpl) may cause immediate exit,
/// others log errors for later reporting.
pub struct Handler {
- flags: HandlerFlags,
inner: Lock<HandlerInner>,
}
@@ -446,11 +452,11 @@ struct HandlerInner {
/// have been converted.
check_unstable_expect_diagnostics: bool,
- /// Expected [`Diagnostic`][diagnostic::Diagnostic]s store a [`LintExpectationId`] as part of
+ /// Expected [`Diagnostic`][struct@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`][diagnostic::Diagnostic]s are the
+ /// replaced by a stable [`LintExpectationId`]. The [`Diagnostic`][struct@diagnostic::Diagnostic]s are the
/// submitted for storage and added to the list of fulfilled expectations.
unstable_expect_diagnostics: Vec<Diagnostic>,
@@ -461,6 +467,10 @@ struct HandlerInner {
///
/// [RFC-2383]: https://rust-lang.github.io/rfcs/2383-lint-reasons.html
fulfilled_expectations: FxHashSet<LintExpectationId>,
+
+ /// The file where the ICE information is stored. This allows delayed_span_bug backtraces to be
+ /// stored along side the main panic backtrace.
+ ice_file: Option<PathBuf>,
}
/// A key denoting where from a diagnostic was stashed.
@@ -544,63 +554,36 @@ impl Drop for HandlerInner {
impl Handler {
pub fn with_tty_emitter(
- color_config: ColorConfig,
- can_emit_warnings: bool,
- treat_err_as_bug: Option<NonZeroUsize>,
sm: Option<Lrc<SourceMap>>,
- fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
) -> Self {
- Self::with_tty_emitter_and_flags(
- color_config,
- sm,
- fluent_bundle,
- fallback_bundle,
- HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
- )
+ let emitter = Box::new(EmitterWriter::stderr(ColorConfig::Auto, fallback_bundle).sm(sm));
+ Self::with_emitter(emitter)
+ }
+ pub fn disable_warnings(mut self) -> Self {
+ self.inner.get_mut().flags.can_emit_warnings = false;
+ self
}
- pub fn with_tty_emitter_and_flags(
- color_config: ColorConfig,
- sm: Option<Lrc<SourceMap>>,
- fluent_bundle: Option<Lrc<FluentBundle>>,
- fallback_bundle: LazyFallbackBundle,
- flags: HandlerFlags,
- ) -> Self {
- let emitter = Box::new(EmitterWriter::stderr(
- color_config,
- sm,
- fluent_bundle,
- fallback_bundle,
- false,
- false,
- None,
- flags.macro_backtrace,
- flags.track_diagnostics,
- TerminalUrl::No,
- ));
- Self::with_emitter_and_flags(emitter, flags)
- }
-
- pub fn with_emitter(
- can_emit_warnings: bool,
- treat_err_as_bug: Option<NonZeroUsize>,
- emitter: Box<dyn Emitter + sync::Send>,
- ) -> Self {
- Handler::with_emitter_and_flags(
- emitter,
- HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
- )
+ pub fn treat_err_as_bug(mut self, treat_err_as_bug: NonZeroUsize) -> Self {
+ self.inner.get_mut().flags.treat_err_as_bug = Some(treat_err_as_bug);
+ self
}
- pub fn with_emitter_and_flags(
- emitter: Box<dyn Emitter + sync::Send>,
- flags: HandlerFlags,
- ) -> Self {
+ pub fn with_flags(mut self, flags: HandlerFlags) -> Self {
+ self.inner.get_mut().flags = flags;
+ self
+ }
+
+ pub fn with_ice_file(mut self, ice_file: PathBuf) -> Self {
+ self.inner.get_mut().ice_file = Some(ice_file);
+ self
+ }
+
+ pub fn with_emitter(emitter: Box<dyn Emitter + sync::Send>) -> Self {
Self {
- flags,
inner: Lock::new(HandlerInner {
- flags,
+ flags: HandlerFlags { can_emit_warnings: true, ..Default::default() },
lint_err_count: 0,
err_count: 0,
warn_count: 0,
@@ -618,6 +601,7 @@ impl Handler {
check_unstable_expect_diagnostics: false,
unstable_expect_diagnostics: Vec::new(),
fulfilled_expectations: Default::default(),
+ ice_file: None,
}),
}
}
@@ -645,7 +629,7 @@ impl Handler {
// 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 {
- self.flags.can_emit_warnings
+ self.inner.lock().flags.can_emit_warnings
}
/// Resets the diagnostic error count as well as the cached emitted diagnostics.
@@ -991,7 +975,7 @@ impl Handler {
self.emit_diag_at_span(Diagnostic::new_with_code(Warning(None), Some(code), msg), span);
}
- pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
+ pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<String>) -> ! {
self.inner.borrow_mut().span_bug(span, msg)
}
@@ -1000,7 +984,7 @@ impl Handler {
pub fn delay_span_bug(
&self,
span: impl Into<MultiSpan>,
- msg: impl Into<DiagnosticMessage>,
+ msg: impl Into<String>,
) -> ErrorGuaranteed {
self.inner.borrow_mut().delay_span_bug(span, msg)
}
@@ -1473,7 +1457,7 @@ impl HandlerInner {
let _ = self.fatal(errors);
}
(_, _) => {
- let _ = self.fatal(format!("{}; {}", &errors, &warnings));
+ let _ = self.fatal(format!("{errors}; {warnings}"));
}
}
@@ -1584,8 +1568,8 @@ impl HandlerInner {
}
#[track_caller]
- fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
- self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
+ fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: impl Into<String>) -> ! {
+ self.emit_diag_at_span(Diagnostic::new(Bug, msg.into()), sp);
panic::panic_any(ExplicitBug);
}
@@ -1598,7 +1582,7 @@ impl HandlerInner {
fn delay_span_bug(
&mut self,
sp: impl Into<MultiSpan>,
- msg: impl Into<DiagnosticMessage>,
+ msg: impl Into<String>,
) -> ErrorGuaranteed {
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
@@ -1607,9 +1591,9 @@ impl HandlerInner {
self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
- self.span_bug(sp, msg);
+ self.span_bug(sp, msg.into());
}
- let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg);
+ let mut diagnostic = Diagnostic::new(Level::DelayedBug, msg.into());
diagnostic.set_span(sp.into());
self.emit_diagnostic(&mut diagnostic).unwrap()
}
@@ -1657,8 +1641,21 @@ impl HandlerInner {
explanation: impl Into<DiagnosticMessage> + Copy,
) {
let mut no_bugs = true;
+ // If backtraces are enabled, also print the query stack
+ let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0");
for bug in bugs {
- let mut bug = bug.decorate();
+ if let Some(file) = self.ice_file.as_ref()
+ && let Ok(mut out) = std::fs::File::options().create(true).append(true).open(file)
+ {
+ let _ = write!(
+ &mut out,
+ "delayed span bug: {}\n{}\n",
+ bug.inner.styled_message().iter().filter_map(|(msg, _)| msg.as_str()).collect::<String>(),
+ &bug.note
+ );
+ }
+ let mut bug =
+ if backtrace || self.ice_file.is_none() { bug.decorate() } else { bug.inner };
if no_bugs {
// Put the overall explanation before the `DelayedBug`s, to
@@ -1671,11 +1668,10 @@ impl HandlerInner {
if bug.level != Level::DelayedBug {
// NOTE(eddyb) not panicking here because we're already producing
// an ICE, and the more information the merrier.
- bug.note(format!(
- "`flushed_delayed` got diagnostic with level {:?}, \
- instead of the expected `DelayedBug`",
- bug.level,
- ));
+ bug.subdiagnostic(InvalidFlushedDelayedDiagnosticLevel {
+ span: bug.span.primary_span().unwrap(),
+ level: bug.level,
+ });
}
bug.level = Level::Bug;
@@ -1714,13 +1710,11 @@ impl HandlerInner {
(count, delayed_count, as_bug) => {
if delayed_count > 0 {
panic!(
- "aborting after {} errors and {} delayed bugs due to `-Z treat-err-as-bug={}`",
- count, delayed_count, as_bug,
+ "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={as_bug}`",
)
} else {
panic!(
- "aborting after {} errors due to `-Z treat-err-as-bug={}`",
- count, as_bug,
+ "aborting after {count} errors due to `-Z treat-err-as-bug={as_bug}`",
)
}
}
@@ -1742,12 +1736,22 @@ impl DelayedDiagnostic {
fn decorate(mut self) -> Diagnostic {
match self.note.status() {
BacktraceStatus::Captured => {
- self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
+ let inner = &self.inner;
+ self.inner.subdiagnostic(DelayedAtWithNewline {
+ span: inner.span.primary_span().unwrap(),
+ emitted_at: inner.emitted_at.clone(),
+ note: self.note,
+ });
}
// Avoid the needless newline when no backtrace has been captured,
// the display impl should just be a single line.
_ => {
- self.inner.note(format!("delayed at {} - {}", self.inner.emitted_at, self.note));
+ let inner = &self.inner;
+ self.inner.subdiagnostic(DelayedAtWithoutNewline {
+ span: inner.span.primary_span().unwrap(),
+ emitted_at: inner.emitted_at.clone(),
+ note: self.note,
+ });
}
}
@@ -1839,20 +1843,36 @@ pub fn add_elided_lifetime_in_path_suggestion(
incl_angl_brckt: bool,
insertion_span: Span,
) {
- diag.span_label(path_span, format!("expected lifetime parameter{}", pluralize!(n)));
+ diag.subdiagnostic(ExpectedLifetimeParameter { span: path_span, count: n });
if !source_map.is_span_accessible(insertion_span) {
// Do not try to suggest anything if generated by a proc-macro.
return;
}
let anon_lts = vec!["'_"; n].join(", ");
let suggestion =
- if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
- diag.span_suggestion_verbose(
- insertion_span.shrink_to_hi(),
- format!("indicate the anonymous lifetime{}", pluralize!(n)),
+ if incl_angl_brckt { format!("<{anon_lts}>") } else { format!("{anon_lts}, ") };
+
+ diag.subdiagnostic(IndicateAnonymousLifetime {
+ span: insertion_span.shrink_to_hi(),
+ count: n,
suggestion,
- Applicability::MachineApplicable,
- );
+ });
+}
+
+pub fn report_ambiguity_error<'a, G: EmissionGuarantee>(
+ db: &mut DiagnosticBuilder<'a, G>,
+ ambiguity: rustc_lint_defs::AmbiguityErrorDiag,
+) {
+ db.span_label(ambiguity.label_span, ambiguity.label_msg);
+ db.note(ambiguity.note_msg);
+ db.span_note(ambiguity.b1_span, ambiguity.b1_note_msg);
+ for help_msg in ambiguity.b1_help_msgs {
+ db.help(help_msg);
+ }
+ db.span_note(ambiguity.b2_span, ambiguity.b2_note_msg);
+ for help_msg in ambiguity.b2_help_msgs {
+ db.help(help_msg);
+ }
}
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
diff --git a/compiler/rustc_errors/src/markdown/parse.rs b/compiler/rustc_errors/src/markdown/parse.rs
index 362a451fd..d3a08da62 100644
--- a/compiler/rustc_errors/src/markdown/parse.rs
+++ b/compiler/rustc_errors/src/markdown/parse.rs
@@ -272,7 +272,7 @@ fn parse_ordered_li(buf: &[u8]) -> Parsed<'_> {
fn get_indented_section(buf: &[u8]) -> (&[u8], &[u8]) {
let mut end = buf.len();
for (idx, window) in buf.windows(2).enumerate() {
- let &[ch, next_ch] = window else {unreachable!("always 2 elements")};
+ let &[ch, next_ch] = window else { unreachable!("always 2 elements") };
if idx >= buf.len().saturating_sub(2) && next_ch == b'\n' {
// End of stream
end = buf.len().saturating_sub(1);
diff --git a/compiler/rustc_errors/src/markdown/term.rs b/compiler/rustc_errors/src/markdown/term.rs
index e45ba6d2c..88c3c8b9f 100644
--- a/compiler/rustc_errors/src/markdown/term.rs
+++ b/compiler/rustc_errors/src/markdown/term.rs
@@ -149,7 +149,7 @@ fn write_wrapping<B: io::Write>(
let Some((end_idx, _ch)) = iter.nth(ch_count) else {
// Write entire line
buf.write_all(to_write.as_bytes())?;
- cur.set(cur.get()+to_write.chars().count());
+ cur.set(cur.get() + to_write.chars().count());
break;
};
diff --git a/compiler/rustc_errors/src/markdown/tests/term.rs b/compiler/rustc_errors/src/markdown/tests/term.rs
index 3b31c6d62..6f68fb25a 100644
--- a/compiler/rustc_errors/src/markdown/tests/term.rs
+++ b/compiler/rustc_errors/src/markdown/tests/term.rs
@@ -63,7 +63,7 @@ fn test_wrapping_write() {
#[test]
fn test_output() {
// Capture `--bless` when run via ./x
- let bless = std::env::var("RUSTC_BLESS").unwrap_or_default() == "1";
+ let bless = std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
let ast = MdStream::parse_str(INPUT);
let bufwtr = BufferWriter::stderr(ColorChoice::Always);
let mut buffer = bufwtr.buffer();