summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors')
-rw-r--r--compiler/rustc_errors/Cargo.toml10
-rw-r--r--compiler/rustc_errors/messages.ftl (renamed from compiler/rustc_errors/locales/en-US.ftl)0
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs5
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs3
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs26
-rw-r--r--compiler/rustc_errors/src/emitter.rs123
-rw-r--r--compiler/rustc_errors/src/lib.rs9
-rw-r--r--compiler/rustc_errors/src/lock.rs81
-rw-r--r--compiler/rustc_errors/src/snippet.rs65
9 files changed, 221 insertions, 101 deletions
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index cadd53fbd..e1ead08ea 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -25,8 +25,14 @@ termize = "0.1.1"
serde = { version = "1.0.125", features = [ "derive" ] }
serde_json = "1.0.59"
-[target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3", features = [ "handleapi", "synchapi", "winbase" ] }
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.46.0"
+features = [
+ "Win32_Foundation",
+ "Win32_Security",
+ "Win32_System_Threading",
+ "Win32_System_WindowsProgramming",
+]
[features]
rustc_use_parallel_compiler = ['rustc_error_messages/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_errors/locales/en-US.ftl b/compiler/rustc_errors/messages.ftl
index dde1d6c0a..dde1d6c0a 100644
--- a/compiler/rustc_errors/locales/en-US.ftl
+++ b/compiler/rustc_errors/messages.ftl
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index d8879bf70..9872b3bda 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -202,7 +202,10 @@ impl AnnotateSnippetEmitterWriter {
annotations: annotations
.iter()
.map(|annotation| SourceAnnotation {
- range: (annotation.start_col, annotation.end_col),
+ range: (
+ annotation.start_col.display,
+ annotation.end_col.display,
+ ),
label: annotation.label.as_deref().unwrap_or_default(),
annotation_type: annotation_type_for_level(*level),
})
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 9ed8ab674..29c692128 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -880,6 +880,7 @@ impl Diagnostic {
///
/// This is intended to be used for suggestions that are *very* obvious in what the changes
/// need to be from the message, but we still want other tools to be able to apply them.
+ #[rustc_lint_diagnostics]
pub fn tool_only_span_suggestion(
&mut self,
sp: Span,
@@ -956,7 +957,7 @@ impl Diagnostic {
// 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>> {
+ pub fn args(&self) -> impl Iterator<Item = DiagnosticArg<'_, 'static>> {
self.args.iter()
}
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index e82bad67b..65f8a61a3 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -1,4 +1,4 @@
-use crate::fluent_generated as fluent;
+use crate::{fluent_generated as fluent, AddToDiagnostic};
use crate::{DiagnosticArgValue, DiagnosticBuilder, Handler, IntoDiagnostic, IntoDiagnosticArg};
use rustc_ast as ast;
use rustc_ast_pretty::pprust;
@@ -6,6 +6,7 @@ use rustc_hir as hir;
use rustc_lint_defs::Level;
use rustc_span::edition::Edition;
use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol};
+use rustc_span::Span;
use rustc_target::abi::TargetDataLayoutErrors;
use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple};
use rustc_type_ir as type_ir;
@@ -276,3 +277,26 @@ impl IntoDiagnostic<'_, !> for TargetDataLayoutErrors<'_> {
}
}
}
+
+/// Utility struct used to apply a single label while highlighting multiple spans
+pub struct SingleLabelManySpans {
+ pub spans: Vec<Span>,
+ pub label: &'static str,
+ pub kind: LabelKind,
+}
+impl AddToDiagnostic for SingleLabelManySpans {
+ fn add_to_diagnostic_with<F>(self, diag: &mut crate::Diagnostic, _: F) {
+ match self.kind {
+ LabelKind::Note => diag.span_note(self.spans, self.label),
+ LabelKind::Label => diag.span_labels(self.spans, self.label),
+ LabelKind::Help => diag.span_help(self.spans, self.label),
+ };
+ }
+}
+
+/// The kind of label to attach when using [`SingleLabelManySpans`]
+pub enum LabelKind {
+ Note,
+ Label,
+ Help,
+}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 211bbf4f5..fe44799ef 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -12,7 +12,9 @@ use Destination::*;
use rustc_span::source_map::SourceMap;
use rustc_span::{FileLines, SourceFile, Span};
-use crate::snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, Style, StyledString};
+use crate::snippet::{
+ Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
+};
use crate::styled_buffer::StyledBuffer;
use crate::translation::{to_fluent_args, Translate};
use crate::{
@@ -858,7 +860,7 @@ impl EmitterWriter {
let mut short_start = true;
for ann in &line.annotations {
if let AnnotationType::MultilineStart(depth) = ann.annotation_type {
- if source_string.chars().take(ann.start_col).all(|c| c.is_whitespace()) {
+ if source_string.chars().take(ann.start_col.display).all(|c| c.is_whitespace()) {
let style = if ann.is_primary {
Style::UnderlinePrimary
} else {
@@ -1093,15 +1095,15 @@ impl EmitterWriter {
'_',
line_offset + pos,
width_offset + depth,
- (code_offset + annotation.start_col).saturating_sub(left),
+ (code_offset + annotation.start_col.display).saturating_sub(left),
style,
);
}
_ if self.teach => {
buffer.set_style_range(
line_offset,
- (code_offset + annotation.start_col).saturating_sub(left),
- (code_offset + annotation.end_col).saturating_sub(left),
+ (code_offset + annotation.start_col.display).saturating_sub(left),
+ (code_offset + annotation.end_col.display).saturating_sub(left),
style,
annotation.is_primary,
);
@@ -1133,7 +1135,7 @@ impl EmitterWriter {
for p in line_offset + 1..=line_offset + pos {
buffer.putc(
p,
- (code_offset + annotation.start_col).saturating_sub(left),
+ (code_offset + annotation.start_col.display).saturating_sub(left),
'|',
style,
);
@@ -1169,9 +1171,9 @@ impl EmitterWriter {
let style =
if annotation.is_primary { Style::LabelPrimary } else { Style::LabelSecondary };
let (pos, col) = if pos == 0 {
- (pos + 1, (annotation.end_col + 1).saturating_sub(left))
+ (pos + 1, (annotation.end_col.display + 1).saturating_sub(left))
} else {
- (pos + 2, annotation.start_col.saturating_sub(left))
+ (pos + 2, annotation.start_col.display.saturating_sub(left))
};
if let Some(ref label) = annotation.label {
buffer.puts(line_offset + pos, code_offset + col, label, style);
@@ -1208,7 +1210,7 @@ impl EmitterWriter {
} else {
('-', Style::UnderlineSecondary)
};
- for p in annotation.start_col..annotation.end_col {
+ for p in annotation.start_col.display..annotation.end_col.display {
buffer.putc(
line_offset + 1,
(code_offset + p).saturating_sub(left),
@@ -1405,7 +1407,7 @@ impl EmitterWriter {
// Account for newlines to align output to its label.
for (line, text) in normalize_whitespace(&text).lines().enumerate() {
buffer.append(
- 0 + line,
+ line,
&format!(
"{}{}",
if line == 0 { String::new() } else { " ".repeat(label_width) },
@@ -1459,7 +1461,7 @@ impl EmitterWriter {
&annotated_file.file.name,
line.line_index
),
- annotations[0].start_col + 1,
+ annotations[0].start_col.file + 1,
),
Style::LineAndColumn,
);
@@ -1546,7 +1548,7 @@ impl EmitterWriter {
buffer.prepend(buffer_msg_line_offset + 1, "::: ", Style::LineNumber);
let loc = if let Some(first_line) = annotated_file.lines.first() {
let col = if let Some(first_annotation) = first_line.annotations.first() {
- format!(":{}", first_annotation.start_col + 1)
+ format!(":{}", first_annotation.start_col.file + 1)
} else {
String::new()
};
@@ -1607,8 +1609,8 @@ impl EmitterWriter {
let mut span_left_margin = usize::MAX;
for line in &annotated_file.lines {
for ann in &line.annotations {
- span_left_margin = min(span_left_margin, ann.start_col);
- span_left_margin = min(span_left_margin, ann.end_col);
+ span_left_margin = min(span_left_margin, ann.start_col.display);
+ span_left_margin = min(span_left_margin, ann.end_col.display);
}
}
if span_left_margin == usize::MAX {
@@ -1625,11 +1627,12 @@ impl EmitterWriter {
annotated_file.file.get_line(line.line_index - 1).map_or(0, |s| s.len()),
);
for ann in &line.annotations {
- span_right_margin = max(span_right_margin, ann.start_col);
- span_right_margin = max(span_right_margin, ann.end_col);
+ span_right_margin = max(span_right_margin, ann.start_col.display);
+ span_right_margin = max(span_right_margin, ann.end_col.display);
// FIXME: account for labels not in the same line
let label_right = ann.label.as_ref().map_or(0, |l| l.len() + 1);
- label_right_margin = max(label_right_margin, ann.end_col + label_right);
+ label_right_margin =
+ max(label_right_margin, ann.end_col.display + label_right);
}
}
@@ -1829,6 +1832,12 @@ impl EmitterWriter {
}
let show_code_change = if has_deletion && !is_multiline {
DisplaySuggestion::Diff
+ } else if let [part] = &parts[..]
+ && part.snippet.ends_with('\n')
+ && part.snippet.trim() == complete.trim()
+ {
+ // We are adding a line(s) of code before code that was already there.
+ DisplaySuggestion::Add
} else if (parts.len() != 1 || parts[0].snippet.trim() != complete.trim())
&& !is_multiline
{
@@ -1876,7 +1885,10 @@ impl EmitterWriter {
row_num += line_end - line_start;
}
let mut unhighlighted_lines = Vec::new();
+ let mut last_pos = 0;
+ let mut is_item_attribute = false;
for (line_pos, (line, highlight_parts)) in lines.by_ref().zip(highlights).enumerate() {
+ last_pos = line_pos;
debug!(%line_pos, %line, ?highlight_parts);
// Remember lines that are not highlighted to hide them if needed
@@ -1884,6 +1896,12 @@ impl EmitterWriter {
unhighlighted_lines.push((line_pos, line));
continue;
}
+ if highlight_parts.len() == 1
+ && line.trim().starts_with("#[")
+ && line.trim().ends_with(']')
+ {
+ is_item_attribute = true;
+ }
match unhighlighted_lines.len() {
0 => (),
@@ -1895,7 +1913,7 @@ impl EmitterWriter {
self.draw_code_line(
&mut buffer,
&mut row_num,
- &Vec::new(),
+ &[],
p + line_start,
l,
show_code_change,
@@ -1915,11 +1933,11 @@ impl EmitterWriter {
let last_line = unhighlighted_lines.pop();
let first_line = unhighlighted_lines.drain(..).next();
- first_line.map(|(p, l)| {
+ if let Some((p, l)) = first_line {
self.draw_code_line(
&mut buffer,
&mut row_num,
- &Vec::new(),
+ &[],
p + line_start,
l,
show_code_change,
@@ -1927,16 +1945,16 @@ impl EmitterWriter {
&file_lines,
is_multiline,
)
- });
+ }
buffer.puts(row_num, max_line_num_len - 1, "...", Style::LineNumber);
row_num += 1;
- last_line.map(|(p, l)| {
+ if let Some((p, l)) = last_line {
self.draw_code_line(
&mut buffer,
&mut row_num,
- &Vec::new(),
+ &[],
p + line_start,
l,
show_code_change,
@@ -1944,14 +1962,14 @@ impl EmitterWriter {
&file_lines,
is_multiline,
)
- });
+ }
}
}
self.draw_code_line(
&mut buffer,
&mut row_num,
- highlight_parts,
+ &highlight_parts,
line_pos + line_start,
line,
show_code_change,
@@ -1960,13 +1978,41 @@ impl EmitterWriter {
is_multiline,
)
}
+ if let DisplaySuggestion::Add = show_code_change && is_item_attribute {
+ // The suggestion adds an entire line of code, ending on a newline, so we'll also
+ // print the *following* line, to provide context of what we're advicing people to
+ // do. Otherwise you would only see contextless code that can be confused for
+ // already existing code, despite the colors and UI elements.
+ // 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())
+ .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) {
+ let line = normalize_whitespace(&line);
+ self.draw_code_line(
+ &mut buffer,
+ &mut row_num,
+ &[],
+ line_num + last_pos + 1,
+ &line,
+ DisplaySuggestion::None,
+ max_line_num_len,
+ &file_lines,
+ is_multiline,
+ )
+ }
+ }
// This offset and the ones below need to be signed to account for replacement code
// that is shorter than the original code.
let mut offsets: Vec<(usize, isize)> = Vec::new();
// Only show an underline in the suggestions if the suggestion is not the
// entirety of the code being shown and the displayed code is not multiline.
- if let DisplaySuggestion::Diff | DisplaySuggestion::Underline = show_code_change {
+ if let DisplaySuggestion::Diff | DisplaySuggestion::Underline | DisplaySuggestion::Add =
+ show_code_change
+ {
draw_col_separator_no_space(&mut buffer, row_num, max_line_num_len + 1);
for part in parts {
let span_start_pos = sm.lookup_char_pos(part.span.lo()).col_display;
@@ -2176,7 +2222,7 @@ impl EmitterWriter {
&self,
buffer: &mut StyledBuffer,
row_num: &mut usize,
- highlight_parts: &Vec<SubstitutionHighlight>,
+ highlight_parts: &[SubstitutionHighlight],
line_num: usize,
line_to_add: &str,
show_code_change: DisplaySuggestion,
@@ -2232,7 +2278,7 @@ impl EmitterWriter {
}
} else if is_multiline {
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
- match &highlight_parts[..] {
+ match &highlight_parts {
[SubstitutionHighlight { start: 0, end }] if *end == line_to_add.len() => {
buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
}
@@ -2244,6 +2290,10 @@ impl EmitterWriter {
}
}
buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
+ } else if let DisplaySuggestion::Add = show_code_change {
+ buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
+ buffer.puts(*row_num, max_line_num_len + 1, "+ ", Style::Addition);
+ buffer.append(*row_num, &normalize_whitespace(line_to_add), Style::NoStyle);
} else {
buffer.puts(*row_num, 0, &self.maybe_anonymized(line_num), Style::LineNumber);
draw_col_separator(buffer, *row_num, max_line_num_len + 1);
@@ -2278,6 +2328,7 @@ enum DisplaySuggestion {
Underline,
Diff,
None,
+ Add,
}
impl FileWithAnnotatedLines {
@@ -2352,8 +2403,8 @@ impl FileWithAnnotatedLines {
depth: 1,
line_start: lo.line,
line_end: hi.line,
- start_col: lo.col_display,
- end_col: hi.col_display,
+ start_col: AnnotationColumn::from_loc(&lo),
+ end_col: AnnotationColumn::from_loc(&hi),
is_primary,
label,
overlaps_exactly: false,
@@ -2361,8 +2412,8 @@ impl FileWithAnnotatedLines {
multiline_annotations.push((lo.file, ml));
} else {
let ann = Annotation {
- start_col: lo.col_display,
- end_col: hi.col_display,
+ start_col: AnnotationColumn::from_loc(&lo),
+ end_col: AnnotationColumn::from_loc(&hi),
is_primary,
label,
annotation_type: AnnotationType::Singleline,
@@ -2551,7 +2602,13 @@ fn num_overlap(
(b_start..b_end + extra).contains(&a_start) || (a_start..a_end + extra).contains(&b_start)
}
fn overlaps(a1: &Annotation, a2: &Annotation, padding: usize) -> bool {
- num_overlap(a1.start_col, a1.end_col + padding, a2.start_col, a2.end_col, false)
+ num_overlap(
+ a1.start_col.display,
+ a1.end_col.display + padding,
+ a2.start_col.display,
+ a2.end_col.display,
+ false,
+ )
}
fn emit_to_destination(
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 09bf28ed4..d20b16890 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -6,7 +6,6 @@
#![feature(array_windows)]
#![feature(drain_filter)]
#![feature(if_let_guard)]
-#![feature(is_terminal)]
#![feature(adt_const_params)]
#![feature(let_chains)]
#![feature(never_type)]
@@ -76,7 +75,7 @@ pub use snippet::Style;
pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>;
pub type PResult<'a, T> = Result<T, PErr<'a>>;
-fluent_messages! { "../locales/en-US.ftl" }
+fluent_messages! { "../messages.ftl" }
// `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
// (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.)
@@ -331,7 +330,7 @@ impl CodeSuggestion {
});
buf.push_str(&part.snippet);
let cur_hi = sm.lookup_char_pos(part.span.hi());
- if prev_hi.line == cur_lo.line && cur_hi.line == cur_lo.line {
+ if cur_hi.line == cur_lo.line && !part.snippet.is_empty() {
// Account for the difference between the width of the current code and the
// snippet being suggested, so that the *later* suggestions are correctly
// aligned on the screen.
@@ -383,7 +382,9 @@ pub use diagnostic::{
DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic,
};
pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted};
-pub use diagnostic_impls::{DiagnosticArgFromDisplay, DiagnosticSymbolList};
+pub use diagnostic_impls::{
+ DiagnosticArgFromDisplay, DiagnosticSymbolList, LabelKind, SingleLabelManySpans,
+};
use std::backtrace::Backtrace;
/// A handler deals with errors and other compiler output.
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index a73472021..7db262abf 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -16,10 +16,12 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
use std::ffi::CString;
use std::io;
- use winapi::shared::ntdef::HANDLE;
- use winapi::um::handleapi::CloseHandle;
- use winapi::um::synchapi::{CreateMutexA, ReleaseMutex, WaitForSingleObject};
- use winapi::um::winbase::{INFINITE, WAIT_ABANDONED, WAIT_OBJECT_0};
+ use windows::{
+ core::PCSTR,
+ Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
+ Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject},
+ Win32::System::WindowsProgramming::INFINITE,
+ };
struct Handle(HANDLE);
@@ -42,49 +44,38 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
}
let cname = CString::new(name).unwrap();
- unsafe {
- // Create a named mutex, with no security attributes and also not
- // acquired when we create it.
- //
- // This will silently create one if it doesn't already exist, or it'll
- // open up a handle to one if it already exists.
- let mutex = CreateMutexA(std::ptr::null_mut(), 0, cname.as_ptr());
- if mutex.is_null() {
- panic!(
- "failed to create global mutex named `{}`: {}",
- name,
- io::Error::last_os_error()
- );
- }
- let mutex = Handle(mutex);
+ // Create a named mutex, with no security attributes and also not
+ // acquired when we create it.
+ //
+ // This will silently create one if it doesn't already exist, or it'll
+ // open up a handle to one if it already exists.
+ let mutex = unsafe { CreateMutexA(None, false, PCSTR::from_raw(cname.as_ptr().cast())) }
+ .unwrap_or_else(|_| panic!("failed to create global mutex named `{}`", name));
+ let mutex = Handle(mutex);
- // Acquire the lock through `WaitForSingleObject`.
- //
- // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
- //
- // A return value of `WAIT_ABANDONED` means that the previous holder of
- // the thread exited without calling `ReleaseMutex`. This can happen,
- // for example, when the compiler crashes or is interrupted via ctrl-c
- // or the like. In this case, however, we are still transferred
- // ownership of the lock so we continue.
- //
- // If an error happens.. well... that's surprising!
- match WaitForSingleObject(mutex.0, INFINITE) {
- WAIT_OBJECT_0 | WAIT_ABANDONED => {}
- code => {
- panic!(
- "WaitForSingleObject failed on global mutex named \
- `{}`: {} (ret={:x})",
- name,
- io::Error::last_os_error(),
- code
- );
- }
- }
-
- // Return a guard which will call `ReleaseMutex` when dropped.
- Box::new(Guard(mutex))
+ // Acquire the lock through `WaitForSingleObject`.
+ //
+ // A return value of `WAIT_OBJECT_0` means we successfully acquired it.
+ //
+ // A return value of `WAIT_ABANDONED` means that the previous holder of
+ // the thread exited without calling `ReleaseMutex`. This can happen,
+ // for example, when the compiler crashes or is interrupted via ctrl-c
+ // or the like. In this case, however, we are still transferred
+ // ownership of the lock so we continue.
+ //
+ // If an error happens.. well... that's surprising!
+ match unsafe { WaitForSingleObject(mutex.0, INFINITE) } {
+ WAIT_OBJECT_0 | WAIT_ABANDONED => (),
+ err => panic!(
+ "WaitForSingleObject failed on global mutex named `{}`: {} (ret={:x})",
+ name,
+ io::Error::last_os_error(),
+ err.0
+ ),
}
+
+ // Return a guard which will call `ReleaseMutex` when dropped.
+ Box::new(Guard(mutex))
}
#[cfg(not(windows))]
diff --git a/compiler/rustc_errors/src/snippet.rs b/compiler/rustc_errors/src/snippet.rs
index e4cc44c41..98eb70b5f 100644
--- a/compiler/rustc_errors/src/snippet.rs
+++ b/compiler/rustc_errors/src/snippet.rs
@@ -1,6 +1,6 @@
// Code for annotating snippets.
-use crate::Level;
+use crate::{Level, Loc};
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Line {
@@ -8,13 +8,39 @@ pub struct Line {
pub annotations: Vec<Annotation>,
}
+#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
+pub struct AnnotationColumn {
+ /// the (0-indexed) column for *display* purposes, counted in characters, not utf-8 bytes
+ pub display: usize,
+ /// the (0-indexed) column in the file, counted in characters, not utf-8 bytes.
+ ///
+ /// this may be different from `self.display`,
+ /// e.g. if the file contains hard tabs, because we convert tabs to spaces for error messages.
+ ///
+ /// for example:
+ /// ```text
+ /// (hard tab)hello
+ /// ^ this is display column 4, but file column 1
+ /// ```
+ ///
+ /// we want to keep around the correct file offset so that column numbers in error messages
+ /// are correct. (motivated by <https://github.com/rust-lang/rust/issues/109537>)
+ pub file: usize,
+}
+
+impl AnnotationColumn {
+ pub fn from_loc(loc: &Loc) -> AnnotationColumn {
+ AnnotationColumn { display: loc.col_display, file: loc.col.0 }
+ }
+}
+
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct MultilineAnnotation {
pub depth: usize,
pub line_start: usize,
pub line_end: usize,
- pub start_col: usize,
- pub end_col: usize,
+ pub start_col: AnnotationColumn,
+ pub end_col: AnnotationColumn,
pub is_primary: bool,
pub label: Option<String>,
pub overlaps_exactly: bool,
@@ -36,7 +62,12 @@ impl MultilineAnnotation {
pub fn as_start(&self) -> Annotation {
Annotation {
start_col: self.start_col,
- end_col: self.start_col + 1,
+ end_col: AnnotationColumn {
+ // these might not correspond to the same place anymore,
+ // but that's okay for our purposes
+ display: self.start_col.display + 1,
+ file: self.start_col.file + 1,
+ },
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineStart(self.depth),
@@ -45,7 +76,12 @@ impl MultilineAnnotation {
pub fn as_end(&self) -> Annotation {
Annotation {
- start_col: self.end_col.saturating_sub(1),
+ start_col: AnnotationColumn {
+ // these might not correspond to the same place anymore,
+ // but that's okay for our purposes
+ display: self.end_col.display.saturating_sub(1),
+ file: self.end_col.file.saturating_sub(1),
+ },
end_col: self.end_col,
is_primary: self.is_primary,
label: self.label.clone(),
@@ -55,8 +91,8 @@ impl MultilineAnnotation {
pub fn as_line(&self) -> Annotation {
Annotation {
- start_col: 0,
- end_col: 0,
+ start_col: Default::default(),
+ end_col: Default::default(),
is_primary: self.is_primary,
label: None,
annotation_type: AnnotationType::MultilineLine(self.depth),
@@ -92,14 +128,14 @@ pub enum AnnotationType {
#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
pub struct Annotation {
- /// Start column, 0-based indexing -- counting *characters*, not
- /// utf-8 bytes. Note that it is important that this field goes
+ /// Start column.
+ /// Note that it is important that this field goes
/// first, so that when we sort, we sort orderings by start
/// column.
- pub start_col: usize,
+ pub start_col: AnnotationColumn,
/// End column within the line (exclusive)
- pub end_col: usize,
+ pub end_col: AnnotationColumn,
/// Is this annotation derived from primary span
pub is_primary: bool,
@@ -118,12 +154,13 @@ impl Annotation {
matches!(self.annotation_type, AnnotationType::MultilineLine(_))
}
+ /// Length of this annotation as displayed in the stderr output
pub fn len(&self) -> usize {
// Account for usize underflows
- if self.end_col > self.start_col {
- self.end_col - self.start_col
+ if self.end_col.display > self.start_col.display {
+ self.end_col.display - self.start_col.display
} else {
- self.start_col - self.end_col
+ self.start_col.display - self.end_col.display
}
}