summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_errors
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_errors')
-rw-r--r--compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs5
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs16
-rw-r--r--compiler/rustc_errors/src/diagnostic_impls.rs2
-rw-r--r--compiler/rustc_errors/src/emitter.rs43
-rw-r--r--compiler/rustc_errors/src/json.rs24
-rw-r--r--compiler/rustc_errors/src/lib.rs62
6 files changed, 112 insertions, 40 deletions
diff --git a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
index a88fba6da..203e52912 100644
--- a/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
+++ b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs
@@ -91,7 +91,7 @@ fn annotation_type_for_level(level: Level) -> AnnotationType {
}
Level::Warning(_) => AnnotationType::Warning,
Level::Note | Level::OnceNote => AnnotationType::Note,
- Level::Help => AnnotationType::Help,
+ Level::Help | Level::OnceHelp => AnnotationType::Help,
// FIXME(#59346): Not sure how to map this level
Level::FailureNote => AnnotationType::Error,
Level::Allow => panic!("Should not call with Allow"),
@@ -169,7 +169,8 @@ impl AnnotateSnippetEmitterWriter {
.map(|line| {
// Ensure the source file is present before we try
// to load a string from it.
- source_map.ensure_source_file_source_present(file.clone());
+ // FIXME(#115869): support -Z ignore-directory-in-diagnostics-source-blocks
+ source_map.ensure_source_file_source_present(&file);
(
format!("{}", source_map.filename_for_diagnostics(&file.name)),
source_string(file.clone(), &line),
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index a96e317df..470f318eb 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -151,7 +151,12 @@ impl fmt::Display for DiagnosticLocation {
#[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
pub enum DiagnosticId {
Error(String),
- Lint { name: String, has_future_breakage: bool, is_force_warn: bool },
+ Lint {
+ name: String,
+ /// Indicates whether this lint should show up in cargo's future breakage report.
+ has_future_breakage: bool,
+ is_force_warn: bool,
+ },
}
/// A "sub"-diagnostic attached to a parent diagnostic.
@@ -270,6 +275,7 @@ impl Diagnostic {
| Level::Note
| Level::OnceNote
| Level::Help
+ | Level::OnceHelp
| Level::Allow
| Level::Expect(_) => false,
}
@@ -300,6 +306,7 @@ impl Diagnostic {
}
}
+ /// Indicates whether this diagnostic should show up in cargo's future breakage report.
pub fn has_future_breakage(&self) -> bool {
match self.code {
Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
@@ -532,6 +539,13 @@ impl Diagnostic {
self
}
+ /// Prints the span with a help above it.
+ /// This is like [`Diagnostic::help()`], but it gets its own span.
+ pub fn help_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
+ self.sub(Level::OnceHelp, msg, MultiSpan::new(), None);
+ self
+ }
+
/// Add a help message attached to this diagnostic with a customizable highlighted message.
pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
self.sub_with_highlights(Level::Help, msg, MultiSpan::new(), None);
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index a170e3a89..4f77f09b2 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -161,7 +161,7 @@ impl IntoDiagnosticArg for hir::ConstContext {
DiagnosticArgValue::Str(Cow::Borrowed(match self {
hir::ConstContext::ConstFn => "const_fn",
hir::ConstContext::Static(_) => "static",
- hir::ConstContext::Const => "const",
+ hir::ConstContext::Const { .. } => "const",
}))
}
}
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 0cae06881..d322cbe9d 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -8,7 +8,7 @@
//! The output types are defined in `rustc_session::config::ErrorOutputType`.
use rustc_span::source_map::SourceMap;
-use rustc_span::{FileLines, SourceFile, Span};
+use rustc_span::{FileLines, FileName, SourceFile, Span};
use crate::snippet::{
Annotation, AnnotationColumn, AnnotationType, Line, MultilineAnnotation, Style, StyledString,
@@ -24,7 +24,7 @@ use rustc_lint_defs::pluralize;
use derive_setters::Setters;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{DynSend, IntoDynSyncSend, Lrc};
use rustc_error_messages::{FluentArgs, SpanLabel};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use std::borrow::Cow;
@@ -188,6 +188,8 @@ impl Margin {
const ANONYMIZED_LINE_NUM: &str = "LL";
+pub type DynEmitter = dyn Emitter + DynSend;
+
/// Emitter trait for emitting errors.
pub trait Emitter: Translate {
/// Emit a structured diagnostic.
@@ -625,7 +627,7 @@ impl ColorConfig {
#[derive(Setters)]
pub struct EmitterWriter {
#[setters(skip)]
- dst: Destination,
+ dst: IntoDynSyncSend<Destination>,
sm: Option<Lrc<SourceMap>>,
fluent_bundle: Option<Lrc<FluentBundle>>,
#[setters(skip)]
@@ -633,6 +635,7 @@ pub struct EmitterWriter {
short_message: bool,
teach: bool,
ui_testing: bool,
+ ignored_directories_in_source_blocks: Vec<String>,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
@@ -655,13 +658,14 @@ impl EmitterWriter {
fn create(dst: Destination, fallback_bundle: LazyFallbackBundle) -> EmitterWriter {
EmitterWriter {
- dst,
+ dst: IntoDynSyncSend(dst),
sm: None,
fluent_bundle: None,
fallback_bundle,
short_message: false,
teach: false,
ui_testing: false,
+ ignored_directories_in_source_blocks: Vec::new(),
diagnostic_width: None,
macro_backtrace: false,
track_diagnostics: false,
@@ -1191,7 +1195,7 @@ impl EmitterWriter {
let will_be_emitted = |span: Span| {
!span.is_dummy() && {
let file = sm.lookup_source_file(span.hi());
- sm.ensure_source_file_source_present(file)
+ should_show_source_code(&self.ignored_directories_in_source_blocks, sm, &file)
}
};
@@ -1386,7 +1390,11 @@ impl EmitterWriter {
// Print out the annotate source lines that correspond with the error
for annotated_file in annotated_files {
// we can't annotate anything if the source is unavailable.
- if !sm.ensure_source_file_source_present(annotated_file.file.clone()) {
+ if !should_show_source_code(
+ &self.ignored_directories_in_source_blocks,
+ sm,
+ &annotated_file.file,
+ ) {
if !self.short_message {
// We'll just print an unannotated message.
for (annotation_id, line) in annotated_file.lines.iter().enumerate() {
@@ -2346,7 +2354,13 @@ impl FileWithAnnotatedLines {
}
let label = label.as_ref().map(|m| {
- emitter.translate_message(m, args).map_err(Report::new).unwrap().to_string()
+ normalize_whitespace(
+ &emitter
+ .translate_message(m, &args)
+ .map_err(Report::new)
+ .unwrap()
+ .to_string(),
+ )
});
if lo.line != hi.line {
@@ -2729,3 +2743,18 @@ pub fn is_case_difference(sm: &SourceMap, suggested: &str, sp: Span) -> bool {
// bug, but be defensive against that here.
&& found != suggested
}
+
+pub(crate) fn should_show_source_code(
+ ignored_directories: &[String],
+ sm: &SourceMap,
+ file: &SourceFile,
+) -> bool {
+ if !sm.ensure_source_file_source_present(file) {
+ return false;
+ }
+
+ let FileName::Real(name) = &file.name else { return true };
+ name.local_path()
+ .map(|path| ignored_directories.iter().all(|dir| !path.starts_with(dir)))
+ .unwrap_or(true)
+}
diff --git a/compiler/rustc_errors/src/json.rs b/compiler/rustc_errors/src/json.rs
index b8f58e305..0cb75c71b 100644
--- a/compiler/rustc_errors/src/json.rs
+++ b/compiler/rustc_errors/src/json.rs
@@ -12,7 +12,7 @@
use rustc_span::source_map::{FilePathMapping, SourceMap};
use termcolor::{ColorSpec, WriteColor};
-use crate::emitter::{Emitter, HumanReadableErrorType};
+use crate::emitter::{should_show_source_code, Emitter, HumanReadableErrorType};
use crate::registry::Registry;
use crate::translation::{to_fluent_args, Translate};
use crate::DiagnosticId;
@@ -22,7 +22,7 @@ use crate::{
};
use rustc_lint_defs::Applicability;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
use rustc_error_messages::FluentArgs;
use rustc_span::hygiene::ExpnData;
use rustc_span::Span;
@@ -38,13 +38,14 @@ use serde::Serialize;
mod tests;
pub struct JsonEmitter {
- dst: Box<dyn Write + Send>,
+ dst: IntoDynSyncSend<Box<dyn Write + Send>>,
registry: Option<Registry>,
sm: Lrc<SourceMap>,
fluent_bundle: Option<Lrc<FluentBundle>>,
fallback_bundle: LazyFallbackBundle,
pretty: bool,
ui_testing: bool,
+ ignored_directories_in_source_blocks: Vec<String>,
json_rendered: HumanReadableErrorType,
diagnostic_width: Option<usize>,
macro_backtrace: bool,
@@ -66,13 +67,14 @@ impl JsonEmitter {
terminal_url: TerminalUrl,
) -> JsonEmitter {
JsonEmitter {
- dst: Box::new(io::BufWriter::new(io::stderr())),
+ dst: IntoDynSyncSend(Box::new(io::BufWriter::new(io::stderr()))),
registry,
sm: source_map,
fluent_bundle,
fallback_bundle,
pretty,
ui_testing: false,
+ ignored_directories_in_source_blocks: Vec::new(),
json_rendered,
diagnostic_width,
macro_backtrace,
@@ -120,13 +122,14 @@ impl JsonEmitter {
terminal_url: TerminalUrl,
) -> JsonEmitter {
JsonEmitter {
- dst,
+ dst: IntoDynSyncSend(dst),
registry,
sm: source_map,
fluent_bundle,
fallback_bundle,
pretty,
ui_testing: false,
+ ignored_directories_in_source_blocks: Vec::new(),
json_rendered,
diagnostic_width,
macro_backtrace,
@@ -138,6 +141,10 @@ impl JsonEmitter {
pub fn ui_testing(self, ui_testing: bool) -> Self {
Self { ui_testing, ..self }
}
+
+ pub fn ignored_directories_in_source_blocks(self, value: Vec<String>) -> Self {
+ Self { ignored_directories_in_source_blocks: value, ..self }
+ }
}
impl Translate for JsonEmitter {
@@ -381,6 +388,7 @@ impl Diagnostic {
.track_diagnostics(je.track_diagnostics)
.terminal_url(je.terminal_url)
.ui_testing(je.ui_testing)
+ .ignored_directories_in_source_blocks(je.ignored_directories_in_source_blocks.clone())
.emit_diagnostic(diag);
let output = Arc::try_unwrap(output.0).unwrap().into_inner().unwrap();
let output = String::from_utf8(output).unwrap();
@@ -558,7 +566,11 @@ impl DiagnosticSpanLine {
.span_to_lines(span)
.map(|lines| {
// We can't get any lines if the source is unavailable.
- if !je.sm.ensure_source_file_source_present(lines.file.clone()) {
+ if !should_show_source_code(
+ &je.ignored_directories_in_source_blocks,
+ &je.sm,
+ &lines.file,
+ ) {
return vec![];
}
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 34518b537..b747a62b8 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -15,7 +15,7 @@
#![feature(box_patterns)]
#![feature(error_reporter)]
#![allow(incomplete_features)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#[macro_use]
extern crate rustc_macros;
@@ -30,11 +30,11 @@ pub use emitter::ColorConfig;
use rustc_lint_defs::LintExpectationId;
use Level::*;
-use emitter::{is_case_difference, Emitter, EmitterWriter};
+use emitter::{is_case_difference, DynEmitter, Emitter, EmitterWriter};
use registry::Registry;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
-use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc};
+use rustc_data_structures::sync::{Lock, Lrc};
use rustc_data_structures::AtomicRef;
pub use rustc_error_messages::{
fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
@@ -44,7 +44,7 @@ use rustc_fluent_macro::fluent_messages;
pub use rustc_lint_defs::{pluralize, Applicability};
use rustc_span::source_map::SourceMap;
pub use rustc_span::ErrorGuaranteed;
-use rustc_span::{Loc, Span};
+use rustc_span::{Loc, Span, DUMMY_SP};
use std::borrow::Cow;
use std::error::Report;
@@ -55,7 +55,9 @@ use std::num::NonZeroUsize;
use std::panic;
use std::path::{Path, PathBuf};
-use termcolor::{Color, ColorSpec};
+// Used by external projects such as `rust-gpu`.
+// See https://github.com/rust-lang/rust/pull/115393.
+pub use termcolor::{Color, ColorSpec, WriteColor};
pub mod annotate_snippet_emitter_writer;
mod diagnostic;
@@ -197,8 +199,14 @@ impl CodeSuggestion {
use rustc_span::{CharPos, Pos};
- /// Append to a buffer the remainder of the line of existing source code, and return the
- /// count of lines that have been added for accurate highlighting.
+ /// Extracts a substring from the provided `line_opt` based on the specified low and high indices,
+ /// appends it to the given buffer `buf`, and returns the count of newline characters in the substring
+ /// for accurate highlighting.
+ /// If `line_opt` is `None`, a newline character is appended to the buffer, and 0 is returned.
+ ///
+ /// ## Returns
+ ///
+ /// The count of newline characters in the extracted substring.
fn push_trailing(
buf: &mut String,
line_opt: Option<&Cow<'_, str>>,
@@ -206,22 +214,30 @@ impl CodeSuggestion {
hi_opt: Option<&Loc>,
) -> usize {
let mut line_count = 0;
+ // Convert CharPos to Usize, as CharPose is character offset
+ // Extract low index and high index
let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
if let Some(line) = line_opt {
if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
+ // Get high index while account for rare unicode and emoji with char_indices
let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
match hi_opt {
+ // If high index exist, take string from low to high index
Some(hi) if hi > lo => {
+ // count how many '\n' exist
line_count = line[lo..hi].matches('\n').count();
buf.push_str(&line[lo..hi])
}
Some(_) => (),
+ // If high index absence, take string from low index till end string.len
None => {
+ // count how many '\n' exist
line_count = line[lo..].matches('\n').count();
buf.push_str(&line[lo..])
}
}
}
+ // If high index is None
if hi_opt.is_none() {
buf.push('\n');
}
@@ -257,7 +273,7 @@ impl CodeSuggestion {
assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
// We can't splice anything if the source is unavailable.
- if !sm.ensure_source_file_source_present(lines.file.clone()) {
+ if !sm.ensure_source_file_source_present(&lines.file) {
return None;
}
@@ -414,7 +430,7 @@ struct HandlerInner {
err_count: usize,
warn_count: usize,
deduplicated_err_count: usize,
- emitter: IntoDynSyncSend<Box<dyn Emitter + sync::Send>>,
+ emitter: Box<DynEmitter>,
delayed_span_bugs: Vec<DelayedDiagnostic>,
delayed_good_path_bugs: Vec<DelayedDiagnostic>,
/// This flag indicates that an expected diagnostic was emitted and suppressed.
@@ -503,7 +519,7 @@ pub struct HandlerFlags {
/// If false, warning-level lints are suppressed.
/// (rustc: see `--allow warnings` and `--cap-lints`)
pub can_emit_warnings: bool,
- /// If true, error-level diagnostics are upgraded to bug-level.
+ /// If Some, the Nth error-level diagnostic is upgraded to bug-level.
/// (rustc: see `-Z treat-err-as-bug`)
pub treat_err_as_bug: Option<NonZeroUsize>,
/// If true, immediately emit diagnostics that would otherwise be buffered.
@@ -580,7 +596,7 @@ impl Handler {
self
}
- pub fn with_emitter(emitter: Box<dyn Emitter + sync::Send>) -> Self {
+ pub fn with_emitter(emitter: Box<DynEmitter>) -> Self {
Self {
inner: Lock::new(HandlerInner {
flags: HandlerFlags { can_emit_warnings: true, ..Default::default() },
@@ -589,7 +605,7 @@ impl Handler {
warn_count: 0,
deduplicated_err_count: 0,
deduplicated_warn_count: 0,
- emitter: IntoDynSyncSend(emitter),
+ emitter,
delayed_span_bugs: Vec::new(),
delayed_good_path_bugs: Vec::new(),
suppressed_expected_diag: false,
@@ -1374,7 +1390,7 @@ impl HandlerInner {
debug!(?self.emitted_diagnostics);
let already_emitted_sub = |sub: &mut SubDiagnostic| {
debug!(?sub);
- if sub.level != Level::OnceNote {
+ if sub.level != Level::OnceNote && sub.level != Level::OnceHelp {
return false;
}
let mut hasher = StableHasher::new();
@@ -1703,19 +1719,17 @@ impl HandlerInner {
match (
self.err_count() + self.lint_err_count,
self.delayed_bug_count(),
- self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0),
+ self.flags.treat_err_as_bug.map(|c| c.get()).unwrap(),
) {
(1, 0, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
(0, 1, 1) => panic!("aborting due delayed bug with `-Z treat-err-as-bug=1`"),
- (count, delayed_count, as_bug) => {
+ (count, delayed_count, val) => {
if delayed_count > 0 {
panic!(
- "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={as_bug}`",
+ "aborting after {count} errors and {delayed_count} delayed bugs due to `-Z treat-err-as-bug={val}`",
)
} else {
- panic!(
- "aborting after {count} errors due to `-Z treat-err-as-bug={as_bug}`",
- )
+ panic!("aborting after {count} errors due to `-Z treat-err-as-bug={val}`")
}
}
}
@@ -1738,7 +1752,7 @@ impl DelayedDiagnostic {
BacktraceStatus::Captured => {
let inner = &self.inner;
self.inner.subdiagnostic(DelayedAtWithNewline {
- span: inner.span.primary_span().unwrap(),
+ span: inner.span.primary_span().unwrap_or(DUMMY_SP),
emitted_at: inner.emitted_at.clone(),
note: self.note,
});
@@ -1748,7 +1762,7 @@ impl DelayedDiagnostic {
_ => {
let inner = &self.inner;
self.inner.subdiagnostic(DelayedAtWithoutNewline {
- span: inner.span.primary_span().unwrap(),
+ span: inner.span.primary_span().unwrap_or(DUMMY_SP),
emitted_at: inner.emitted_at.clone(),
note: self.note,
});
@@ -1776,6 +1790,8 @@ pub enum Level {
/// A note that is only emitted once.
OnceNote,
Help,
+ /// A help that is only emitted once.
+ OnceHelp,
FailureNote,
Allow,
Expect(LintExpectationId),
@@ -1800,7 +1816,7 @@ impl Level {
Note | OnceNote => {
spec.set_fg(Some(Color::Green)).set_intense(true);
}
- Help => {
+ Help | OnceHelp => {
spec.set_fg(Some(Color::Cyan)).set_intense(true);
}
FailureNote => {}
@@ -1815,7 +1831,7 @@ impl Level {
Fatal | Error { .. } => "error",
Warning(_) => "warning",
Note | OnceNote => "note",
- Help => "help",
+ Help | OnceHelp => "help",
FailureNote => "failure-note",
Allow => panic!("Shouldn't call on allowed error"),
Expect(_) => panic!("Shouldn't call on expected error"),