let bounding_span = Span::with_root_ctxt(lo, hi);
// The different spans might belong to different contexts, if so ignore suggestion.
let lines = sm.span_to_lines(bounding_span).ok()?;
- assert!(!lines.lines.is_empty());
+ 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()) {
+ return None;
+ }
// To build up the result, we do this for each span:
// - push the line segment trailing the previous span
let sf = &lines.file;
let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
prev_hi.col = CharPos::from_usize(0);
-
- let mut prev_line = sf.get_line(lines.lines[0].line_index);
+ let mut prev_line =
+ lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
let mut buf = String::new();
for part in &substitution.parts {
}
}
if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
- let end = std::cmp::min(cur_line.len(), cur_lo.col.to_usize());
+ let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
+ Some((i, _)) => i,
+ None => cur_line.len(),
+ };
buf.push_str(&cur_line[..end]);
}
}
/// The stashed diagnostics count towards the total error count.
/// When `.abort_if_errors()` is called, these are also emitted.
stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
+
+ /// The warning count, used for a recap upon finishing
+ deduplicated_warn_count: usize,
}
/// A key denoting where from a diagnostic was stashed.
flags,
err_count: 0,
deduplicated_err_count: 0,
+ deduplicated_warn_count: 0,
emitter,
delayed_span_bugs: Vec::new(),
taught_diagnostics: Default::default(),
}
// This is here to not allow mutation of flags;
- // as of this writing it's only used in tests in librustc.
+ // 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
}
let mut inner = self.inner.borrow_mut();
inner.err_count = 0;
inner.deduplicated_err_count = 0;
+ inner.deduplicated_warn_count = 0;
// actually free the underlying memory (which `clear` would not do)
inner.delayed_span_bugs = Default::default();
self.emitter.emit_diagnostic(diagnostic);
if diagnostic.is_error() {
self.deduplicated_err_count += 1;
+ } else if diagnostic.level == Warning {
+ self.deduplicated_warn_count += 1;
}
}
if diagnostic.is_error() {
fn print_error_count(&mut self, registry: &Registry) {
self.emit_stashed_diagnostics();
- let s = match self.deduplicated_err_count {
- 0 => return,
+ let warnings = match self.deduplicated_warn_count {
+ 0 => String::new(),
+ 1 => "1 warning emitted".to_string(),
+ count => format!("{} warnings emitted", count),
+ };
+ let errors = match self.deduplicated_err_count {
+ 0 => String::new(),
1 => "aborting due to previous error".to_string(),
count => format!("aborting due to {} previous errors", count),
};
return;
}
- let _ = self.fatal(&s);
+ match (errors.len(), warnings.len()) {
+ (0, 0) => return,
+ (0, _) => self.emit_diagnostic(&Diagnostic::new(Level::Warning, &warnings)),
+ (_, 0) => {
+ let _ = self.fatal(&errors);
+ }
+ (_, _) => {
+ let _ = self.fatal(&format!("{}; {}", &errors, &warnings));
+ }
+ }
let can_show_explain = self.emitter.should_show_explain();
let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
));
self.failure(&format!(
"For more information about an error, try \
- `rustc --explain {}`.",
+ `rustc --explain {}`.",
&error_codes[0]
));
} else {
self.failure(&format!(
"For more information about this error, try \
- `rustc --explain {}`.",
+ `rustc --explain {}`.",
&error_codes[0]
));
}