diff options
Diffstat (limited to 'compiler/rustc_errors')
| -rw-r--r-- | compiler/rustc_errors/Cargo.toml | 5 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 89 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 6 |
4 files changed, 93 insertions, 30 deletions
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml index f37b6fb748f..67a17ce88fa 100644 --- a/compiler/rustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -14,7 +14,6 @@ rustc_error_codes = { path = "../rustc_error_codes" } rustc_error_messages = { path = "../rustc_error_messages" } rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hashes = { path = "../rustc_hashes" } -rustc_hir_id = { path = "../rustc_hir_id" } rustc_index = { path = "../rustc_index" } rustc_lexer = { path = "../rustc_lexer" } rustc_lint_defs = { path = "../rustc_lint_defs" } @@ -22,10 +21,10 @@ rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } serde = { version = "1.0.125", features = ["derive"] } -serde_json = "1.0.59" +serde_json.workspace = true termcolor = "1.2.0" termize = "0.2" -tracing = "0.1" +tracing.workspace = true # tidy-alphabetical-end [target.'cfg(windows)'.dependencies.windows] diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 43ce886975c..96a4ed3218f 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -577,6 +577,29 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { self.level = Level::DelayedBug; } + /// Make emitting this diagnostic fatal + /// + /// Changes the level of this diagnostic to Fatal, and importantly also changes the emission guarantee. + /// This is sound for errors that would otherwise be printed, but now simply exit the process instead. + /// This function still gives an emission guarantee, the guarantee is now just that it exits fatally. + /// For delayed bugs this is different, since those are buffered. If we upgrade one to fatal, another + /// might now be ignored. + #[rustc_lint_diagnostics] + #[track_caller] + pub fn upgrade_to_fatal(mut self) -> Diag<'a, FatalAbort> { + assert!( + matches!(self.level, Level::Error), + "upgrade_to_fatal: cannot upgrade {:?} to Fatal: not an error", + self.level + ); + self.level = Level::Fatal; + + // Take is okay since we immediately rewrap it in another diagnostic. + // i.e. we do emit it despite defusing the original diagnostic's drop bomb. + let diag = self.diag.take(); + Diag { dcx: self.dcx, diag, _marker: PhantomData } + } + with_fn! { with_span_label, /// Appends a labeled span to the diagnostic. /// diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 749bba5de12..b94370e8e9b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1462,7 +1462,7 @@ impl HumanEmitter { max_line_num_len: usize, is_secondary: bool, is_cont: bool, - ) -> io::Result<()> { + ) -> io::Result<CodeWindowStatus> { let mut buffer = StyledBuffer::new(); if !msp.has_primary_spans() && !msp.has_span_labels() && is_secondary && !self.short_message @@ -1575,12 +1575,14 @@ impl HumanEmitter { } let mut annotated_files = FileWithAnnotatedLines::collect_annotations(self, args, msp); trace!("{annotated_files:#?}"); + let mut code_window_status = CodeWindowStatus::Open; // Make sure our primary file comes first let primary_span = msp.primary_span().unwrap_or_default(); let (Some(sm), false) = (self.sm.as_ref(), primary_span.is_dummy()) else { // If we don't have span information, emit and exit - return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message); + return emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message) + .map(|_| code_window_status); }; let primary_lo = sm.lookup_char_pos(primary_span.lo()); if let Ok(pos) = @@ -1589,6 +1591,9 @@ impl HumanEmitter { annotated_files.swap(0, pos); } + // An end column separator should be emitted when a file with with a + // source, is followed by one without a source + let mut col_sep_before_no_show_source = false; let annotated_files_len = annotated_files.len(); // Print out the annotate source lines that correspond with the error for (file_idx, annotated_file) in annotated_files.into_iter().enumerate() { @@ -1599,6 +1604,26 @@ impl HumanEmitter { &annotated_file.file, ) { if !self.short_message { + // Add an end column separator when a file without a source + // comes after one with a source + // ╭▸ $DIR/deriving-meta-unknown-trait.rs:1:10 + // │ + // LL │ #[derive(Eqr)] + // │ ━━━ + // ╰╴ (<- It prints *this* line) + // ╭▸ $SRC_DIR/core/src/cmp.rs:356:0 + // │ + // ╰╴note: similarly named derive macro `Eq` defined here + if col_sep_before_no_show_source { + let buffer_msg_line_offset = buffer.num_lines(); + self.draw_col_separator_end( + &mut buffer, + buffer_msg_line_offset, + max_line_num_len + 1, + ); + } + col_sep_before_no_show_source = false; + // We'll just print an unannotated message. for (annotation_id, line) in annotated_file.lines.iter().enumerate() { let mut annotations = line.annotations.clone(); @@ -1639,29 +1664,42 @@ impl HumanEmitter { } line_idx += 1; } - for (label, is_primary) in labels.into_iter() { + if is_cont + && file_idx == annotated_files_len - 1 + && annotation_id == annotated_file.lines.len() - 1 + && !labels.is_empty() + { + code_window_status = CodeWindowStatus::Closed; + } + let labels_len = labels.len(); + for (label_idx, (label, is_primary)) in labels.into_iter().enumerate() { let style = if is_primary { Style::LabelPrimary } else { Style::LabelSecondary }; - let pipe = self.col_separator(); - buffer.prepend(line_idx, &format!(" {pipe}"), Style::LineNumber); - for _ in 0..max_line_num_len { - buffer.prepend(line_idx, " ", Style::NoStyle); - } + self.draw_col_separator_no_space( + &mut buffer, + line_idx, + max_line_num_len + 1, + ); line_idx += 1; - let chr = self.note_separator(); - buffer.append(line_idx, &format!(" {chr} note: "), style); - for _ in 0..max_line_num_len { - buffer.prepend(line_idx, " ", Style::NoStyle); - } + self.draw_note_separator( + &mut buffer, + line_idx, + max_line_num_len + 1, + label_idx != labels_len - 1, + ); + buffer.append(line_idx, "note", Style::MainHeaderMsg); + buffer.append(line_idx, ": ", Style::NoStyle); buffer.append(line_idx, label, style); line_idx += 1; } } } continue; + } else { + col_sep_before_no_show_source = true; } // print out the span location and spacer before we print the annotated source @@ -1976,7 +2014,7 @@ impl HumanEmitter { // final step: take our styled buffer, render it, then output it emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; - Ok(()) + Ok(code_window_status) } fn column_width(&self, code_offset: usize) -> usize { @@ -2491,7 +2529,7 @@ impl HumanEmitter { !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden), ) { - Ok(()) => { + Ok(code_window_status) => { if !children.is_empty() || suggestions.iter().any(|s| s.style != SuggestionStyle::CompletelyHidden) { @@ -2502,7 +2540,7 @@ impl HumanEmitter { { // We'll continue the vertical bar to point into the next note. self.draw_col_separator_no_space(&mut buffer, 0, max_line_num_len + 1); - } else { + } else if matches!(code_window_status, CodeWindowStatus::Open) { // We'll close the vertical bar to visually end the code window. self.draw_col_separator_end(&mut buffer, 0, max_line_num_len + 1); } @@ -2829,10 +2867,11 @@ impl HumanEmitter { } } - fn note_separator(&self) -> char { + fn note_separator(&self, is_cont: bool) -> &'static str { match self.theme { - OutputTheme::Ascii => '=', - OutputTheme::Unicode => '╰', + OutputTheme::Ascii => "= ", + OutputTheme::Unicode if is_cont => "├ ", + OutputTheme::Unicode => "╰ ", } } @@ -2945,11 +2984,7 @@ impl HumanEmitter { col: usize, is_cont: bool, ) { - let chr = match self.theme { - OutputTheme::Ascii => "= ", - OutputTheme::Unicode if is_cont => "├ ", - OutputTheme::Unicode => "╰ ", - }; + let chr = self.note_separator(is_cont); buffer.puts(line, col, chr, Style::LineNumber); } @@ -3050,6 +3085,12 @@ enum DisplaySuggestion { Add, } +#[derive(Clone, Copy, Debug)] +enum CodeWindowStatus { + Closed, + Open, +} + impl FileWithAnnotatedLines { /// Preprocess all the annotations so that they are grouped by file and by line number /// This helps us quickly iterate over the whole message (including secondary file spans) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 38c5716348f..71fc54f0d33 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -61,7 +61,6 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, into_diag_arg_using_display, }; use rustc_hashes::Hash128; -use rustc_hir_id::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; @@ -110,13 +109,14 @@ rustc_data_structures::static_assert_size!(PResult<'_, bool>, 24); /// Used to avoid depending on `rustc_middle` in `rustc_attr_parsing`. /// Always the `TyCtxt`. pub trait LintEmitter: Copy { + type Id: Copy; #[track_caller] fn emit_node_span_lint( self, lint: &'static Lint, - hir_id: HirId, + hir_id: Self::Id, span: impl Into<MultiSpan>, - decorator: impl for<'a> LintDiagnostic<'a, ()>, + decorator: impl for<'a> LintDiagnostic<'a, ()> + DynSend + 'static, ); } |
