diff options
| author | Laurențiu Nicola <lnicola@users.noreply.github.com> | 2025-02-10 06:07:06 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-10 06:07:06 +0000 |
| commit | 8fd713b7d3bc773b0911518c4e4ee7f1ac284220 (patch) | |
| tree | 1aa51f29a63a69ab827eb37366f0bcaada3da97e /compiler/rustc_errors/src | |
| parent | d4f7c7668fece15523ae6f38e437cad01ee5ded6 (diff) | |
| parent | 24d7a1490a8193350b006b7a5f71edd97a63afd1 (diff) | |
| download | rust-8fd713b7d3bc773b0911518c4e4ee7f1ac284220.tar.gz rust-8fd713b7d3bc773b0911518c4e4ee7f1ac284220.zip | |
Merge pull request #19126 from lnicola/sync-from-rust
minor: Sync from downstream
Diffstat (limited to 'compiler/rustc_errors/src')
| -rw-r--r-- | compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs | 15 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/diagnostic.rs | 51 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/emitter.rs | 44 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/json.rs | 56 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/json/tests.rs | 164 | ||||
| -rw-r--r-- | compiler/rustc_errors/src/lib.rs | 74 |
6 files changed, 233 insertions, 171 deletions
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs index b337e279400..f0636b600b7 100644 --- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs +++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs @@ -5,8 +5,9 @@ //! //! [annotate_snippets]: https://docs.rs/crate/annotate-snippets/ +use std::sync::Arc; + use annotate_snippets::{Renderer, Snippet}; -use rustc_data_structures::sync::Lrc; use rustc_error_messages::FluentArgs; use rustc_span::SourceFile; use rustc_span::source_map::SourceMap; @@ -22,8 +23,8 @@ use crate::{ /// Generates diagnostics using annotate-snippet pub struct AnnotateSnippetEmitter { - source_map: Option<Lrc<SourceMap>>, - fluent_bundle: Option<Lrc<FluentBundle>>, + source_map: Option<Arc<SourceMap>>, + fluent_bundle: Option<Arc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, /// If true, hides the longer explanation text @@ -80,7 +81,7 @@ impl Emitter for AnnotateSnippetEmitter { } /// Provides the source string for the given `line` of `file` -fn source_string(file: Lrc<SourceFile>, line: &Line) -> String { +fn source_string(file: Arc<SourceFile>, line: &Line) -> String { file.get_line(line.line_index - 1).map(|a| a.to_string()).unwrap_or_default() } @@ -102,8 +103,8 @@ fn annotation_level_for_level(level: Level) -> annotate_snippets::Level { impl AnnotateSnippetEmitter { pub fn new( - source_map: Option<Lrc<SourceMap>>, - fluent_bundle: Option<Lrc<FluentBundle>>, + source_map: Option<Arc<SourceMap>>, + fluent_bundle: Option<Arc<FluentBundle>>, fallback_bundle: LazyFallbackBundle, short_message: bool, macro_backtrace: bool, @@ -174,7 +175,7 @@ impl AnnotateSnippetEmitter { source_map.ensure_source_file_source_present(&file); ( format!("{}", source_map.filename_for_diagnostics(&file.name)), - source_string(Lrc::clone(&file), &line), + source_string(Arc::clone(&file), &line), line.line_index, line.annotations, ) diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 797dcd7b4d1..29a74ed3f4e 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic; +use std::path::PathBuf; use std::thread::panicking; use rustc_data_structures::fx::FxIndexMap; @@ -301,6 +302,7 @@ pub struct DiagInner { pub is_lint: Option<IsLint>, + pub long_ty_path: Option<PathBuf>, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. pub(crate) emitted_at: DiagLocation, @@ -324,6 +326,7 @@ impl DiagInner { args: Default::default(), sort_span: DUMMY_SP, is_lint: None, + long_ty_path: None, emitted_at: DiagLocation::caller(), } } @@ -641,7 +644,14 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { found_label: &dyn fmt::Display, found: DiagStyledString, ) -> &mut Self { - self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") + self.note_expected_found_extra( + expected_label, + expected, + found_label, + found, + DiagStyledString::normal(""), + DiagStyledString::normal(""), + ) } #[rustc_lint_diagnostics] @@ -651,8 +661,8 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected: DiagStyledString, found_label: &dyn fmt::Display, found: DiagStyledString, - expected_extra: &dyn fmt::Display, - found_extra: &dyn fmt::Display, + expected_extra: DiagStyledString, + found_extra: DiagStyledString, ) -> &mut Self { let expected_label = expected_label.to_string(); let expected_label = if expected_label.is_empty() { @@ -677,10 +687,13 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { expected_label ))]; msg.extend(expected.0); - msg.push(StringPart::normal(format!("`{expected_extra}\n"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(expected_extra.0); + msg.push(StringPart::normal(format!("\n"))); msg.push(StringPart::normal(format!("{}{} `", " ".repeat(found_padding), found_label))); msg.extend(found.0); - msg.push(StringPart::normal(format!("`{found_extra}"))); + msg.push(StringPart::normal(format!("`"))); + msg.extend(found_extra.0); // For now, just attach these as notes. self.highlighted_note(msg); @@ -1293,9 +1306,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on /// `self`. fn take_diag(&mut self) -> DiagInner { + if let Some(path) = &self.long_ty_path { + self.note(format!( + "the full name for the type has been written to '{}'", + path.display() + )); + self.note("consider using `--verbose` to print the full type name to the console"); + } Box::into_inner(self.diag.take().unwrap()) } + /// This method allows us to access the path of the file where "long types" are written to. + /// + /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set, + /// and if it has been then we add a note mentioning the file where the "long types" were + /// written to. + /// + /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing + /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that + /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the + /// user where we wrote the file to is only printed once at most, *and* it makes it much harder + /// to forget to set it. + /// + /// If the diagnostic hasn't been created before a "short ty string" is created, then you should + /// ensure that this method is called to set it `*diag.long_ty_path() = path`. + /// + /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a + /// scope, `diag.long_ty_path()` should be called once somewhere close by. + pub fn long_ty_path(&mut self) -> &mut Option<PathBuf> { + &mut self.long_ty_path + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index f938352820d..15cf285e7ff 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -14,10 +14,11 @@ use std::io::prelude::*; use std::io::{self, IsTerminal}; use std::iter; use std::path::Path; +use std::sync::Arc; use derive_setters::Setters; use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc}; +use rustc_data_structures::sync::{DynSend, IntoDynSyncSend}; use rustc_error_messages::{FluentArgs, SpanLabel}; use rustc_lexer; use rustc_lint_defs::pluralize; @@ -35,8 +36,8 @@ use crate::snippet::{ use crate::styled_buffer::StyledBuffer; use crate::translation::{Translate, to_fluent_args}; use crate::{ - CodeSuggestion, DiagCtxt, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, - Level, MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, + CodeSuggestion, DiagInner, DiagMessage, ErrCode, FluentBundle, LazyFallbackBundle, Level, + MultiSpan, Subdiag, SubstitutionHighlight, SuggestionStyle, TerminalUrl, }; /// Default column width, used in tests and when terminal dimensions cannot be determined. @@ -537,11 +538,10 @@ impl Emitter for HumanEmitter { } /// An emitter that does nothing when emitting a non-fatal diagnostic. -/// Fatal diagnostics are forwarded to `fatal_dcx` to avoid silent +/// Fatal diagnostics are forwarded to `fatal_emitter` to avoid silent /// failures of rustc, as witnessed e.g. in issue #89358. pub struct SilentEmitter { - pub fallback_bundle: LazyFallbackBundle, - pub fatal_dcx: DiagCtxt, + pub fatal_emitter: Box<dyn Emitter + DynSend>, pub fatal_note: Option<String>, pub emit_fatal_diagnostic: bool, } @@ -552,9 +552,7 @@ impl Translate for SilentEmitter { } fn fallback_fluent_bundle(&self) -> &FluentBundle { - // Ideally this field wouldn't be necessary and the fallback bundle in `fatal_dcx` would be - // used but the lock prevents this. - &self.fallback_bundle + self.fatal_emitter.fallback_fluent_bundle() } } @@ -563,12 +561,12 @@ impl Emitter for SilentEmitter { None } - fn emit_diagnostic(&mut self, mut diag: DiagInner, _registry: &Registry) { + fn emit_diagnostic(&mut self, mut diag: DiagInner, registry: &Registry) { if self.emit_fatal_diagnostic && diag.level == Level::Fatal { if let Some(fatal_note) = &self.fatal_note { diag.sub(Level::Note, fatal_note.clone(), MultiSpan::new()); } - self.fatal_dcx.handle().emit_diagnostic(diag); + self.fatal_emitter.emit_diagnostic(diag, registry); } } } @@ -613,8 +611,8 @@ pub enum OutputTheme { pub struct HumanEmitter { #[setters(skip)] dst: IntoDynSyncSend<Destination>, - sm: Option<Lrc<SourceMap>>, - fluent_bundle: Option<Lrc<FluentBundle>>, + sm: Option<Arc<SourceMap>>, + fluent_bundle: Option<Arc<FluentBundle>>, #[setters(skip)] fallback_bundle: LazyFallbackBundle, short_message: bool, @@ -631,7 +629,7 @@ pub struct HumanEmitter { #[derive(Debug)] pub(crate) struct FileWithAnnotatedLines { - pub(crate) file: Lrc<SourceFile>, + pub(crate) file: Arc<SourceFile>, pub(crate) lines: Vec<Line>, multiline_depth: usize, } @@ -715,7 +713,7 @@ impl HumanEmitter { fn render_source_line( &self, buffer: &mut StyledBuffer, - file: Lrc<SourceFile>, + file: Arc<SourceFile>, line: &Line, width_offset: usize, code_offset: usize, @@ -1694,7 +1692,7 @@ impl HumanEmitter { // Get the left-side margin to remove it let mut whitespace_margin = usize::MAX; for line_idx in 0..annotated_file.lines.len() { - let file = Lrc::clone(&annotated_file.file); + let file = Arc::clone(&annotated_file.file); let line = &annotated_file.lines[line_idx]; if let Some(source_string) = line.line_index.checked_sub(1).and_then(|l| file.get_line(l)) @@ -1767,7 +1765,7 @@ impl HumanEmitter { let column_width = if let Some(width) = self.diagnostic_width { width.saturating_sub(code_offset) - } else if self.ui_testing { + } else if self.ui_testing || cfg!(miri) { DEFAULT_COLUMN_WIDTH } else { termize::dimensions() @@ -1790,7 +1788,7 @@ impl HumanEmitter { let depths = self.render_source_line( &mut buffer, - Lrc::clone(&annotated_file.file), + Arc::clone(&annotated_file.file), &annotated_file.lines[line_idx], width_offset, code_offset, @@ -2979,7 +2977,7 @@ impl FileWithAnnotatedLines { ) -> Vec<FileWithAnnotatedLines> { fn add_annotation_to_file( file_vec: &mut Vec<FileWithAnnotatedLines>, - file: Lrc<SourceFile>, + file: Arc<SourceFile>, line_index: usize, ann: Annotation, ) { @@ -3116,7 +3114,7 @@ impl FileWithAnnotatedLines { // | baz add_annotation_to_file( &mut output, - Lrc::clone(&file), + Arc::clone(&file), ann.line_start, ann.as_start(), ); @@ -3143,12 +3141,12 @@ impl FileWithAnnotatedLines { .unwrap_or(ann.line_start); for line in ann.line_start + 1..until { // Every `|` that joins the beginning of the span (`___^`) to the end (`|__^`). - add_annotation_to_file(&mut output, Lrc::clone(&file), line, ann.as_line()); + add_annotation_to_file(&mut output, Arc::clone(&file), line, ann.as_line()); } let line_end = ann.line_end - 1; - let end_is_empty = file.get_line(line_end - 1).map_or(false, |s| !filter(&s)); + let end_is_empty = file.get_line(line_end - 1).is_some_and(|s| !filter(&s)); if middle < line_end && !end_is_empty { - add_annotation_to_file(&mut output, Lrc::clone(&file), line_end, ann.as_line()); + add_annotation_to_file(&mut output, Arc::clone(&file), line_end, ann.as_line()); } } else { end_ann.annotation_type = AnnotationType::Singleline; diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs index 97df7f9265a..7d7f364fec2 100644 --- a/compiler/rustc_errors/src/json.rs +++ b/compiler/rustc_errors/src/json.rs @@ -16,12 +16,12 @@ use std::sync::{Arc, Mutex}; use std::vec; use derive_setters::Setters; -use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; +use rustc_data_structures::sync::IntoDynSyncSend; use rustc_error_messages::FluentArgs; use rustc_lint_defs::Applicability; use rustc_span::Span; use rustc_span::hygiene::ExpnData; -use rustc_span::source_map::SourceMap; +use rustc_span::source_map::{FilePathMapping, SourceMap}; use serde::Serialize; use termcolor::{ColorSpec, WriteColor}; @@ -45,8 +45,8 @@ pub struct JsonEmitter { #[setters(skip)] dst: IntoDynSyncSend<Box<dyn Write + Send>>, #[setters(skip)] - sm: Lrc<SourceMap>, - fluent_bundle: Option<Lrc<FluentBundle>>, + sm: Option<Arc<SourceMap>>, + fluent_bundle: Option<Arc<FluentBundle>>, #[setters(skip)] fallback_bundle: LazyFallbackBundle, #[setters(skip)] @@ -65,7 +65,7 @@ pub struct JsonEmitter { impl JsonEmitter { pub fn new( dst: Box<dyn Write + Send>, - sm: Lrc<SourceMap>, + sm: Option<Arc<SourceMap>>, fallback_bundle: LazyFallbackBundle, pretty: bool, json_rendered: HumanReadableErrorType, @@ -171,7 +171,7 @@ impl Emitter for JsonEmitter { } fn source_map(&self) -> Option<&SourceMap> { - Some(&self.sm) + self.sm.as_deref() } fn should_show_explain(&self) -> bool { @@ -369,9 +369,9 @@ impl Diagnostic { ColorConfig::Always | ColorConfig::Auto => dst = Box::new(termcolor::Ansi::new(dst)), ColorConfig::Never => {} } - HumanEmitter::new(dst, Lrc::clone(&je.fallback_bundle)) + HumanEmitter::new(dst, Arc::clone(&je.fallback_bundle)) .short_message(short) - .sm(Some(Lrc::clone(&je.sm))) + .sm(je.sm.clone()) .fluent_bundle(je.fluent_bundle.clone()) .diagnostic_width(je.diagnostic_width) .macro_backtrace(je.macro_backtrace) @@ -458,22 +458,34 @@ impl DiagnosticSpan { mut backtrace: impl Iterator<Item = ExpnData>, je: &JsonEmitter, ) -> DiagnosticSpan { - let start = je.sm.lookup_char_pos(span.lo()); + let empty_source_map; + let sm = match &je.sm { + Some(s) => s, + None => { + span = rustc_span::DUMMY_SP; + empty_source_map = Arc::new(SourceMap::new(FilePathMapping::empty())); + empty_source_map + .new_source_file(std::path::PathBuf::from("empty.rs").into(), String::new()); + &empty_source_map + } + }; + let start = sm.lookup_char_pos(span.lo()); // If this goes from the start of a line to the end and the replacement // is an empty string, increase the length to include the newline so we don't // leave an empty line if start.col.0 == 0 - && suggestion.map_or(false, |(s, _)| s.is_empty()) - && let Ok(after) = je.sm.span_to_next_source(span) + && let Some((suggestion, _)) = suggestion + && suggestion.is_empty() + && let Ok(after) = sm.span_to_next_source(span) && after.starts_with('\n') { span = span.with_hi(span.hi() + rustc_span::BytePos(1)); } - let end = je.sm.lookup_char_pos(span.hi()); + let end = sm.lookup_char_pos(span.hi()); let backtrace_step = backtrace.next().map(|bt| { let call_site = Self::from_span_full(bt.call_site, false, None, None, backtrace, je); let def_site_span = Self::from_span_full( - je.sm.guess_head_span(bt.def_site), + sm.guess_head_span(bt.def_site), false, None, None, @@ -488,7 +500,7 @@ impl DiagnosticSpan { }); DiagnosticSpan { - file_name: je.sm.filename_for_diagnostics(&start.file.name).to_string(), + file_name: sm.filename_for_diagnostics(&start.file.name).to_string(), byte_start: start.file.original_relative_byte_pos(span.lo()).0, byte_end: start.file.original_relative_byte_pos(span.hi()).0, line_start: start.line, @@ -558,19 +570,20 @@ impl DiagnosticSpanLine { /// `span` within the line. fn from_span(span: Span, je: &JsonEmitter) -> Vec<DiagnosticSpanLine> { je.sm - .span_to_lines(span) - .map(|lines| { + .as_ref() + .and_then(|sm| { + let lines = sm.span_to_lines(span).ok()?; // We can't get any lines if the source is unavailable. if !should_show_source_code( &je.ignored_directories_in_source_blocks, - &je.sm, + &sm, &lines.file, ) { - return vec![]; + return None; } let sf = &*lines.file; - lines + let span_lines = lines .lines .iter() .map(|line| { @@ -581,8 +594,9 @@ impl DiagnosticSpanLine { line.end_col.0 + 1, ) }) - .collect() + .collect(); + Some(span_lines) }) - .unwrap_or_else(|_| vec![]) + .unwrap_or_default() } } diff --git a/compiler/rustc_errors/src/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs index 0de555b83d3..40973e8e5d8 100644 --- a/compiler/rustc_errors/src/json/tests.rs +++ b/compiler/rustc_errors/src/json/tests.rs @@ -39,7 +39,7 @@ impl<T: Write> Write for Shared<T> { /// Test the span yields correct positions in JSON. fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { rustc_span::create_default_session_globals_then(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); + let sm = Arc::new(SourceMap::new(FilePathMapping::empty())); sm.new_source_file(Path::new("test.rs").to_owned().into(), code.to_owned()); let fallback_bundle = crate::fallback_fluent_bundle(vec![crate::DEFAULT_LOCALE_RESOURCE], false); @@ -47,7 +47,7 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { let output = Arc::new(Mutex::new(Vec::new())); let je = JsonEmitter::new( Box::new(Shared { data: output.clone() }), - sm, + Some(sm), fallback_bundle, true, // pretty HumanReadableErrorType::Short, @@ -69,96 +69,128 @@ fn test_positions(code: &str, span: (u32, u32), expected_output: SpanTestData) { #[test] fn empty() { - test_positions(" ", (0, 1), SpanTestData { - byte_start: 0, - byte_end: 1, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }) + test_positions( + " ", + (0, 1), + SpanTestData { + byte_start: 0, + byte_end: 1, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }, + ) } #[test] fn bom() { - test_positions("\u{feff} ", (0, 1), SpanTestData { - byte_start: 3, - byte_end: 4, - line_start: 1, - column_start: 1, - line_end: 1, - column_end: 2, - }) + test_positions( + "\u{feff} ", + (0, 1), + SpanTestData { + byte_start: 3, + byte_end: 4, + line_start: 1, + column_start: 1, + line_end: 1, + column_end: 2, + }, + ) } #[test] fn lf_newlines() { - test_positions("\nmod foo;\nmod bar;\n", (5, 12), SpanTestData { - byte_start: 5, - byte_end: 12, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }) + test_positions( + "\nmod foo;\nmod bar;\n", + (5, 12), + SpanTestData { + byte_start: 5, + byte_end: 12, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) } #[test] fn crlf_newlines() { - test_positions("\r\nmod foo;\r\nmod bar;\r\n", (5, 12), SpanTestData { - byte_start: 6, - byte_end: 14, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }) + test_positions( + "\r\nmod foo;\r\nmod bar;\r\n", + (5, 12), + SpanTestData { + byte_start: 6, + byte_end: 14, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) } #[test] fn crlf_newlines_with_bom() { - test_positions("\u{feff}\r\nmod foo;\r\nmod bar;\r\n", (5, 12), SpanTestData { - byte_start: 9, - byte_end: 17, - line_start: 2, - column_start: 5, - line_end: 3, - column_end: 3, - }) + test_positions( + "\u{feff}\r\nmod foo;\r\nmod bar;\r\n", + (5, 12), + SpanTestData { + byte_start: 9, + byte_end: 17, + line_start: 2, + column_start: 5, + line_end: 3, + column_end: 3, + }, + ) } #[test] fn span_before_crlf() { - test_positions("foo\r\nbar", (2, 3), SpanTestData { - byte_start: 2, - byte_end: 3, - line_start: 1, - column_start: 3, - line_end: 1, - column_end: 4, - }) + test_positions( + "foo\r\nbar", + (2, 3), + SpanTestData { + byte_start: 2, + byte_end: 3, + line_start: 1, + column_start: 3, + line_end: 1, + column_end: 4, + }, + ) } #[test] fn span_on_crlf() { - test_positions("foo\r\nbar", (3, 4), SpanTestData { - byte_start: 3, - byte_end: 5, - line_start: 1, - column_start: 4, - line_end: 2, - column_end: 1, - }) + test_positions( + "foo\r\nbar", + (3, 4), + SpanTestData { + byte_start: 3, + byte_end: 5, + line_start: 1, + column_start: 4, + line_end: 2, + column_end: 1, + }, + ) } #[test] fn span_after_crlf() { - test_positions("foo\r\nbar", (4, 5), SpanTestData { - byte_start: 5, - byte_end: 6, - line_start: 2, - column_start: 1, - line_end: 2, - column_end: 2, - }) + test_positions( + "foo\r\nbar", + (4, 5), + SpanTestData { + byte_start: 5, + byte_end: 6, + line_start: 2, + column_start: 1, + line_end: 2, + column_end: 2, + }, + ) } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index cc5eb9c335e..9af17db9a6e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -35,6 +35,7 @@ use std::backtrace::{Backtrace, BacktraceStatus}; use std::borrow::Cow; use std::cell::Cell; use std::error::Report; +use std::ffi::OsStr; use std::hash::Hash; use std::io::Write; use std::num::NonZero; @@ -58,13 +59,13 @@ use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::Lock; +use rustc_data_structures::sync::{DynSend, Lock}; pub use rustc_error_messages::{ DiagMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_lint_defs::LintExpectationId; -pub use rustc_lint_defs::{Applicability, pluralize}; +pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -675,57 +676,44 @@ impl DiagCtxt { Self { inner: Lock::new(DiagCtxtInner::new(emitter)) } } - pub fn make_silent( - &self, - fallback_bundle: LazyFallbackBundle, - fatal_note: Option<String>, - emit_fatal_diagnostic: bool, - ) { - self.wrap_emitter(|old_dcx| { - Box::new(emitter::SilentEmitter { - fallback_bundle, - fatal_dcx: DiagCtxt { inner: Lock::new(old_dcx) }, - fatal_note, - emit_fatal_diagnostic, - }) - }); - } - - fn wrap_emitter<F>(&self, f: F) - where - F: FnOnce(DiagCtxtInner) -> Box<DynEmitter>, - { - // A empty type that implements `Emitter` so that a `DiagCtxtInner` can be constructed - // to temporarily swap in place of the real one, which will be used in constructing - // its replacement. + pub fn make_silent(&self, fatal_note: Option<String>, emit_fatal_diagnostic: bool) { + // An empty type that implements `Emitter` to temporarily swap in place of the real one, + // which will be used in constructing its replacement. struct FalseEmitter; impl Emitter for FalseEmitter { fn emit_diagnostic(&mut self, _: DiagInner, _: &Registry) { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn source_map(&self) -> Option<&SourceMap> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } impl translation::Translate for FalseEmitter { fn fluent_bundle(&self) -> Option<&FluentBundle> { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } fn fallback_fluent_bundle(&self) -> &FluentBundle { - unimplemented!("false emitter must only used during `wrap_emitter`") + unimplemented!("false emitter must only used during `make_silent`") } } let mut inner = self.inner.borrow_mut(); - let mut prev_dcx = DiagCtxtInner::new(Box::new(FalseEmitter)); - std::mem::swap(&mut *inner, &mut prev_dcx); - let new_emitter = f(prev_dcx); - let mut new_dcx = DiagCtxtInner::new(new_emitter); - std::mem::swap(&mut *inner, &mut new_dcx); + let mut prev_emitter = Box::new(FalseEmitter) as Box<dyn Emitter + DynSend>; + std::mem::swap(&mut inner.emitter, &mut prev_emitter); + let new_emitter = Box::new(emitter::SilentEmitter { + fatal_emitter: prev_emitter, + fatal_note, + emit_fatal_diagnostic, + }); + inner.emitter = new_emitter; + } + + pub fn set_emitter(&self, emitter: Box<dyn Emitter + DynSend>) { + self.inner.borrow_mut().emitter = emitter; } /// Translate `message` eagerly with `args` to `SubdiagMessage::Eager`. @@ -1060,8 +1048,8 @@ impl<'a> DiagCtxtHandle<'a> { /// bad results, such as spurious/uninteresting additional errors -- when /// returning an error `Result` is difficult. pub fn abort_if_errors(&self) { - if self.has_errors().is_some() { - FatalError.raise(); + if let Some(guar) = self.has_errors() { + guar.raise_fatal(); } } @@ -1717,7 +1705,7 @@ impl DiagCtxtInner { let bugs: Vec<_> = std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(); - let backtrace = std::env::var_os("RUST_BACKTRACE").map_or(true, |x| &x != "0"); + let backtrace = std::env::var_os("RUST_BACKTRACE").as_deref() != Some(OsStr::new("0")); let decorate = backtrace || self.ice_file.is_none(); let mut out = self .ice_file @@ -1998,18 +1986,6 @@ pub fn a_or_an(s: &str) -> &'static str { } } -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" -pub fn display_list_with_comma_and<T: std::fmt::Display>(v: &[T]) -> String { - match v { - [] => "".to_string(), - [a] => a.to_string(), - [a, b] => format!("{a} and {b}"), - [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)), - } -} - #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TerminalUrl { No, |
