1 //! Diagnostics creation and emission for `rustc`.
2 //!
3 //! This module contains the code for creating and emitting diagnostics.
4
5 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
6 #![feature(crate_visibility_modifier)]
7 #![feature(backtrace)]
8 #![cfg_attr(bootstrap, feature(extended_key_value_attributes))]
9 #![feature(format_args_capture)]
10 #![feature(iter_zip)]
11 #![feature(nll)]
12
13 #[macro_use]
14 extern crate rustc_macros;
15
16 pub use emitter::ColorConfig;
17
18 use tracing::debug;
19 use Level::*;
20
21 use emitter::{is_case_difference, Emitter, EmitterWriter};
22 use registry::Registry;
23 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
24 use rustc_data_structures::stable_hasher::StableHasher;
25 use rustc_data_structures::sync::{self, Lock, Lrc};
26 use rustc_data_structures::AtomicRef;
27 use rustc_lint_defs::FutureBreakage;
28 pub use rustc_lint_defs::{pluralize, Applicability};
29 use rustc_serialize::json::Json;
30 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
31 use rustc_span::source_map::SourceMap;
32 use rustc_span::{Loc, MultiSpan, Span};
33
34 use std::borrow::Cow;
35 use std::hash::{Hash, Hasher};
36 use std::num::NonZeroUsize;
37 use std::panic;
38 use std::path::Path;
39 use std::{error, fmt};
40
41 use termcolor::{Color, ColorSpec};
42
43 pub mod annotate_snippet_emitter_writer;
44 mod diagnostic;
45 mod diagnostic_builder;
46 pub mod emitter;
47 pub mod json;
48 mod lock;
49 pub mod registry;
50 mod snippet;
51 mod styled_buffer;
52 pub use snippet::Style;
53
54 pub type PResult<'a, T> = Result<T, DiagnosticBuilder<'a>>;
55
56 // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger.
57 // (See also the comment on `DiagnosticBuilderInner`.)
58 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
59 rustc_data_structures::static_assert_size!(PResult<'_, bool>, 16);
60
61 #[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, Encodable, Decodable)]
62 pub enum SuggestionStyle {
63 /// Hide the suggested code when displaying this suggestion inline.
64 HideCodeInline,
65 /// Always hide the suggested code but display the message.
66 HideCodeAlways,
67 /// Do not display this suggestion in the cli output, it is only meant for tools.
68 CompletelyHidden,
69 /// Always show the suggested code.
70 /// This will *not* show the code if the suggestion is inline *and* the suggested code is
71 /// empty.
72 ShowCode,
73 /// Always show the suggested code independently.
74 ShowAlways,
75 }
76
77 impl SuggestionStyle {
hide_inline(&self) -> bool78 fn hide_inline(&self) -> bool {
79 !matches!(*self, SuggestionStyle::ShowCode)
80 }
81 }
82
83 #[derive(Clone, Debug, PartialEq, Default)]
84 pub struct ToolMetadata(pub Option<Json>);
85
86 impl ToolMetadata {
new(json: Json) -> Self87 fn new(json: Json) -> Self {
88 ToolMetadata(Some(json))
89 }
90
is_set(&self) -> bool91 fn is_set(&self) -> bool {
92 self.0.is_some()
93 }
94 }
95
96 impl Hash for ToolMetadata {
hash<H: Hasher>(&self, _state: &mut H)97 fn hash<H: Hasher>(&self, _state: &mut H) {}
98 }
99
100 // Doesn't really need to round-trip
101 impl<D: Decoder> Decodable<D> for ToolMetadata {
decode(_d: &mut D) -> Result<Self, D::Error>102 fn decode(_d: &mut D) -> Result<Self, D::Error> {
103 Ok(ToolMetadata(None))
104 }
105 }
106
107 impl<S: Encoder> Encodable<S> for ToolMetadata {
encode(&self, e: &mut S) -> Result<(), S::Error>108 fn encode(&self, e: &mut S) -> Result<(), S::Error> {
109 match &self.0 {
110 None => e.emit_unit(),
111 Some(json) => json.encode(e),
112 }
113 }
114 }
115
116 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
117 pub struct CodeSuggestion {
118 /// Each substitute can have multiple variants due to multiple
119 /// applicable suggestions
120 ///
121 /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
122 /// `foo` and `bar` on their own:
123 ///
124 /// ```
125 /// vec![
126 /// Substitution { parts: vec![(0..3, "a"), (4..7, "b")] },
127 /// Substitution { parts: vec![(0..3, "x"), (4..7, "y")] },
128 /// ]
129 /// ```
130 ///
131 /// or by replacing the entire span:
132 ///
133 /// ```
134 /// vec![
135 /// Substitution { parts: vec![(0..7, "a.b")] },
136 /// Substitution { parts: vec![(0..7, "x.y")] },
137 /// ]
138 /// ```
139 pub substitutions: Vec<Substitution>,
140 pub msg: String,
141 /// Visual representation of this suggestion.
142 pub style: SuggestionStyle,
143 /// Whether or not the suggestion is approximate
144 ///
145 /// Sometimes we may show suggestions with placeholders,
146 /// which are useful for users but not useful for
147 /// tools like rustfix
148 pub applicability: Applicability,
149 /// Tool-specific metadata
150 pub tool_metadata: ToolMetadata,
151 }
152
153 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
154 /// See the docs on `CodeSuggestion::substitutions`
155 pub struct Substitution {
156 pub parts: Vec<SubstitutionPart>,
157 }
158
159 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
160 pub struct SubstitutionPart {
161 pub span: Span,
162 pub snippet: String,
163 }
164
165 impl CodeSuggestion {
166 /// Returns the assembled code suggestions, whether they should be shown with an underline
167 /// and whether the substitution only differs in capitalization.
splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec<SubstitutionPart>, bool)>168 pub fn splice_lines(&self, sm: &SourceMap) -> Vec<(String, Vec<SubstitutionPart>, bool)> {
169 use rustc_span::{CharPos, Pos};
170
171 fn push_trailing(
172 buf: &mut String,
173 line_opt: Option<&Cow<'_, str>>,
174 lo: &Loc,
175 hi_opt: Option<&Loc>,
176 ) {
177 let (lo, hi_opt) = (lo.col.to_usize(), hi_opt.map(|hi| hi.col.to_usize()));
178 if let Some(line) = line_opt {
179 if let Some(lo) = line.char_indices().map(|(i, _)| i).nth(lo) {
180 let hi_opt = hi_opt.and_then(|hi| line.char_indices().map(|(i, _)| i).nth(hi));
181 match hi_opt {
182 Some(hi) if hi > lo => buf.push_str(&line[lo..hi]),
183 Some(_) => (),
184 None => buf.push_str(&line[lo..]),
185 }
186 }
187 if hi_opt.is_none() {
188 buf.push('\n');
189 }
190 }
191 }
192
193 assert!(!self.substitutions.is_empty());
194
195 self.substitutions
196 .iter()
197 .filter(|subst| {
198 // Suggestions coming from macros can have malformed spans. This is a heavy
199 // handed approach to avoid ICEs by ignoring the suggestion outright.
200 let invalid = subst.parts.iter().any(|item| sm.is_valid_span(item.span).is_err());
201 if invalid {
202 debug!("splice_lines: suggestion contains an invalid span: {:?}", subst);
203 }
204 !invalid
205 })
206 .cloned()
207 .filter_map(|mut substitution| {
208 // Assumption: all spans are in the same file, and all spans
209 // are disjoint. Sort in ascending order.
210 substitution.parts.sort_by_key(|part| part.span.lo());
211
212 // Find the bounding span.
213 let lo = substitution.parts.iter().map(|part| part.span.lo()).min()?;
214 let hi = substitution.parts.iter().map(|part| part.span.hi()).max()?;
215 let bounding_span = Span::with_root_ctxt(lo, hi);
216 // The different spans might belong to different contexts, if so ignore suggestion.
217 let lines = sm.span_to_lines(bounding_span).ok()?;
218 assert!(!lines.lines.is_empty() || bounding_span.is_dummy());
219
220 // We can't splice anything if the source is unavailable.
221 if !sm.ensure_source_file_source_present(lines.file.clone()) {
222 return None;
223 }
224
225 // To build up the result, we do this for each span:
226 // - push the line segment trailing the previous span
227 // (at the beginning a "phantom" span pointing at the start of the line)
228 // - push lines between the previous and current span (if any)
229 // - if the previous and current span are not on the same line
230 // push the line segment leading up to the current span
231 // - splice in the span substitution
232 //
233 // Finally push the trailing line segment of the last span
234 let sf = &lines.file;
235 let mut prev_hi = sm.lookup_char_pos(bounding_span.lo());
236 prev_hi.col = CharPos::from_usize(0);
237 let mut prev_line =
238 lines.lines.get(0).and_then(|line0| sf.get_line(line0.line_index));
239 let mut buf = String::new();
240
241 for part in &substitution.parts {
242 let cur_lo = sm.lookup_char_pos(part.span.lo());
243 if prev_hi.line == cur_lo.line {
244 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, Some(&cur_lo));
245 } else {
246 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
247 // push lines between the previous and current span (if any)
248 for idx in prev_hi.line..(cur_lo.line - 1) {
249 if let Some(line) = sf.get_line(idx) {
250 buf.push_str(line.as_ref());
251 buf.push('\n');
252 }
253 }
254 if let Some(cur_line) = sf.get_line(cur_lo.line - 1) {
255 let end = match cur_line.char_indices().nth(cur_lo.col.to_usize()) {
256 Some((i, _)) => i,
257 None => cur_line.len(),
258 };
259 buf.push_str(&cur_line[..end]);
260 }
261 }
262 buf.push_str(&part.snippet);
263 prev_hi = sm.lookup_char_pos(part.span.hi());
264 prev_line = sf.get_line(prev_hi.line - 1);
265 }
266 let only_capitalization = is_case_difference(sm, &buf, bounding_span);
267 // if the replacement already ends with a newline, don't print the next line
268 if !buf.ends_with('\n') {
269 push_trailing(&mut buf, prev_line.as_ref(), &prev_hi, None);
270 }
271 // remove trailing newlines
272 while buf.ends_with('\n') {
273 buf.pop();
274 }
275 Some((buf, substitution.parts, only_capitalization))
276 })
277 .collect()
278 }
279 }
280
281 pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker};
282
283 /// Signifies that the compiler died with an explicit call to `.bug`
284 /// or `.span_bug` rather than a failed assertion, etc.
285 #[derive(Copy, Clone, Debug)]
286 pub struct ExplicitBug;
287
288 impl fmt::Display for ExplicitBug {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result289 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290 write!(f, "parser internal bug")
291 }
292 }
293
294 impl error::Error for ExplicitBug {}
295
296 pub use diagnostic::{Diagnostic, DiagnosticId, DiagnosticStyledString, SubDiagnostic};
297 pub use diagnostic_builder::DiagnosticBuilder;
298 use std::backtrace::Backtrace;
299
300 /// A handler deals with errors and other compiler output.
301 /// Certain errors (fatal, bug, unimpl) may cause immediate exit,
302 /// others log errors for later reporting.
303 pub struct Handler {
304 flags: HandlerFlags,
305 inner: Lock<HandlerInner>,
306 }
307
308 /// This inner struct exists to keep it all behind a single lock;
309 /// this is done to prevent possible deadlocks in a multi-threaded compiler,
310 /// as well as inconsistent state observation.
311 struct HandlerInner {
312 flags: HandlerFlags,
313 /// The number of errors that have been emitted, including duplicates.
314 ///
315 /// This is not necessarily the count that's reported to the user once
316 /// compilation ends.
317 err_count: usize,
318 warn_count: usize,
319 deduplicated_err_count: usize,
320 emitter: Box<dyn Emitter + sync::Send>,
321 delayed_span_bugs: Vec<Diagnostic>,
322 delayed_good_path_bugs: Vec<DelayedDiagnostic>,
323
324 /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid
325 /// emitting the same diagnostic with extended help (`--teach`) twice, which
326 /// would be unnecessary repetition.
327 taught_diagnostics: FxHashSet<DiagnosticId>,
328
329 /// Used to suggest rustc --explain <error code>
330 emitted_diagnostic_codes: FxHashSet<DiagnosticId>,
331
332 /// This set contains a hash of every diagnostic that has been emitted by
333 /// this handler. These hashes is used to avoid emitting the same error
334 /// twice.
335 emitted_diagnostics: FxHashSet<u128>,
336
337 /// Stashed diagnostics emitted in one stage of the compiler that may be
338 /// stolen by other stages (e.g. to improve them and add more information).
339 /// The stashed diagnostics count towards the total error count.
340 /// When `.abort_if_errors()` is called, these are also emitted.
341 stashed_diagnostics: FxIndexMap<(Span, StashKey), Diagnostic>,
342
343 /// The warning count, used for a recap upon finishing
344 deduplicated_warn_count: usize,
345
346 future_breakage_diagnostics: Vec<Diagnostic>,
347 }
348
349 /// A key denoting where from a diagnostic was stashed.
350 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
351 pub enum StashKey {
352 ItemNoType,
353 }
354
default_track_diagnostic(_: &Diagnostic)355 fn default_track_diagnostic(_: &Diagnostic) {}
356
357 pub static TRACK_DIAGNOSTICS: AtomicRef<fn(&Diagnostic)> =
358 AtomicRef::new(&(default_track_diagnostic as fn(&_)));
359
360 #[derive(Copy, Clone, Default)]
361 pub struct HandlerFlags {
362 /// If false, warning-level lints are suppressed.
363 /// (rustc: see `--allow warnings` and `--cap-lints`)
364 pub can_emit_warnings: bool,
365 /// If true, error-level diagnostics are upgraded to bug-level.
366 /// (rustc: see `-Z treat-err-as-bug`)
367 pub treat_err_as_bug: Option<NonZeroUsize>,
368 /// If true, immediately emit diagnostics that would otherwise be buffered.
369 /// (rustc: see `-Z dont-buffer-diagnostics` and `-Z treat-err-as-bug`)
370 pub dont_buffer_diagnostics: bool,
371 /// If true, immediately print bugs registered with `delay_span_bug`.
372 /// (rustc: see `-Z report-delayed-bugs`)
373 pub report_delayed_bugs: bool,
374 /// Show macro backtraces.
375 /// (rustc: see `-Z macro-backtrace`)
376 pub macro_backtrace: bool,
377 /// If true, identical diagnostics are reported only once.
378 pub deduplicate_diagnostics: bool,
379 }
380
381 impl Drop for HandlerInner {
drop(&mut self)382 fn drop(&mut self) {
383 self.emit_stashed_diagnostics();
384
385 if !self.has_errors() {
386 let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new());
387 self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued");
388 }
389
390 if !self.has_any_message() {
391 let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new());
392 self.flush_delayed(
393 bugs.into_iter().map(DelayedDiagnostic::decorate).collect(),
394 "no warnings or errors encountered even though `delayed_good_path_bugs` issued",
395 );
396 }
397 }
398 }
399
400 impl Handler {
with_tty_emitter( color_config: ColorConfig, can_emit_warnings: bool, treat_err_as_bug: Option<NonZeroUsize>, sm: Option<Lrc<SourceMap>>, ) -> Self401 pub fn with_tty_emitter(
402 color_config: ColorConfig,
403 can_emit_warnings: bool,
404 treat_err_as_bug: Option<NonZeroUsize>,
405 sm: Option<Lrc<SourceMap>>,
406 ) -> Self {
407 Self::with_tty_emitter_and_flags(
408 color_config,
409 sm,
410 HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
411 )
412 }
413
with_tty_emitter_and_flags( color_config: ColorConfig, sm: Option<Lrc<SourceMap>>, flags: HandlerFlags, ) -> Self414 pub fn with_tty_emitter_and_flags(
415 color_config: ColorConfig,
416 sm: Option<Lrc<SourceMap>>,
417 flags: HandlerFlags,
418 ) -> Self {
419 let emitter = Box::new(EmitterWriter::stderr(
420 color_config,
421 sm,
422 false,
423 false,
424 None,
425 flags.macro_backtrace,
426 ));
427 Self::with_emitter_and_flags(emitter, flags)
428 }
429
with_emitter( can_emit_warnings: bool, treat_err_as_bug: Option<NonZeroUsize>, emitter: Box<dyn Emitter + sync::Send>, ) -> Self430 pub fn with_emitter(
431 can_emit_warnings: bool,
432 treat_err_as_bug: Option<NonZeroUsize>,
433 emitter: Box<dyn Emitter + sync::Send>,
434 ) -> Self {
435 Handler::with_emitter_and_flags(
436 emitter,
437 HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default::default() },
438 )
439 }
440
with_emitter_and_flags( emitter: Box<dyn Emitter + sync::Send>, flags: HandlerFlags, ) -> Self441 pub fn with_emitter_and_flags(
442 emitter: Box<dyn Emitter + sync::Send>,
443 flags: HandlerFlags,
444 ) -> Self {
445 Self {
446 flags,
447 inner: Lock::new(HandlerInner {
448 flags,
449 err_count: 0,
450 warn_count: 0,
451 deduplicated_err_count: 0,
452 deduplicated_warn_count: 0,
453 emitter,
454 delayed_span_bugs: Vec::new(),
455 delayed_good_path_bugs: Vec::new(),
456 taught_diagnostics: Default::default(),
457 emitted_diagnostic_codes: Default::default(),
458 emitted_diagnostics: Default::default(),
459 stashed_diagnostics: Default::default(),
460 future_breakage_diagnostics: Vec::new(),
461 }),
462 }
463 }
464
465 // This is here to not allow mutation of flags;
466 // as of this writing it's only used in tests in librustc_middle.
can_emit_warnings(&self) -> bool467 pub fn can_emit_warnings(&self) -> bool {
468 self.flags.can_emit_warnings
469 }
470
471 /// Resets the diagnostic error count as well as the cached emitted diagnostics.
472 ///
473 /// NOTE: *do not* call this function from rustc. It is only meant to be called from external
474 /// tools that want to reuse a `Parser` cleaning the previously emitted diagnostics as well as
475 /// the overall count of emitted error diagnostics.
reset_err_count(&self)476 pub fn reset_err_count(&self) {
477 let mut inner = self.inner.borrow_mut();
478 inner.err_count = 0;
479 inner.warn_count = 0;
480 inner.deduplicated_err_count = 0;
481 inner.deduplicated_warn_count = 0;
482
483 // actually free the underlying memory (which `clear` would not do)
484 inner.delayed_span_bugs = Default::default();
485 inner.delayed_good_path_bugs = Default::default();
486 inner.taught_diagnostics = Default::default();
487 inner.emitted_diagnostic_codes = Default::default();
488 inner.emitted_diagnostics = Default::default();
489 inner.stashed_diagnostics = Default::default();
490 }
491
492 /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic)493 pub fn stash_diagnostic(&self, span: Span, key: StashKey, diag: Diagnostic) {
494 let mut inner = self.inner.borrow_mut();
495 // FIXME(Centril, #69537): Consider reintroducing panic on overwriting a stashed diagnostic
496 // if/when we have a more robust macro-friendly replacement for `(span, key)` as a key.
497 // See the PR for a discussion.
498 inner.stashed_diagnostics.insert((span, key), diag);
499 }
500
501 /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>>502 pub fn steal_diagnostic(&self, span: Span, key: StashKey) -> Option<DiagnosticBuilder<'_>> {
503 self.inner
504 .borrow_mut()
505 .stashed_diagnostics
506 .remove(&(span, key))
507 .map(|diag| DiagnosticBuilder::new_diagnostic(self, diag))
508 }
509
510 /// Emit all stashed diagnostics.
emit_stashed_diagnostics(&self)511 pub fn emit_stashed_diagnostics(&self) {
512 self.inner.borrow_mut().emit_stashed_diagnostics();
513 }
514
515 /// Construct a dummy builder with `Level::Cancelled`.
516 ///
517 /// Using this will neither report anything to the user (e.g. a warning),
518 /// nor will compilation cancel as a result.
struct_dummy(&self) -> DiagnosticBuilder<'_>519 pub fn struct_dummy(&self) -> DiagnosticBuilder<'_> {
520 DiagnosticBuilder::new(self, Level::Cancelled, "")
521 }
522
523 /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_>524 pub fn struct_span_warn(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
525 let mut result = self.struct_warn(msg);
526 result.set_span(span);
527 result
528 }
529
530 /// Construct a builder at the `Allow` level at the given `span` and with the `msg`.
struct_span_allow( &self, span: impl Into<MultiSpan>, msg: &str, ) -> DiagnosticBuilder<'_>531 pub fn struct_span_allow(
532 &self,
533 span: impl Into<MultiSpan>,
534 msg: &str,
535 ) -> DiagnosticBuilder<'_> {
536 let mut result = self.struct_allow(msg);
537 result.set_span(span);
538 result
539 }
540
541 /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
542 /// Also include a code.
struct_span_warn_with_code( &self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, ) -> DiagnosticBuilder<'_>543 pub fn struct_span_warn_with_code(
544 &self,
545 span: impl Into<MultiSpan>,
546 msg: &str,
547 code: DiagnosticId,
548 ) -> DiagnosticBuilder<'_> {
549 let mut result = self.struct_span_warn(span, msg);
550 result.code(code);
551 result
552 }
553
554 /// Construct a builder at the `Warning` level with the `msg`.
struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_>555 pub fn struct_warn(&self, msg: &str) -> DiagnosticBuilder<'_> {
556 let mut result = DiagnosticBuilder::new(self, Level::Warning, msg);
557 if !self.flags.can_emit_warnings {
558 result.cancel();
559 }
560 result
561 }
562
563 /// Construct a builder at the `Allow` level with the `msg`.
struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_>564 pub fn struct_allow(&self, msg: &str) -> DiagnosticBuilder<'_> {
565 DiagnosticBuilder::new(self, Level::Allow, msg)
566 }
567
568 /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_>569 pub fn struct_span_err(&self, span: impl Into<MultiSpan>, msg: &str) -> DiagnosticBuilder<'_> {
570 let mut result = self.struct_err(msg);
571 result.set_span(span);
572 result
573 }
574
575 /// Construct a builder at the `Error` level at the given `span`, with the `msg`, and `code`.
struct_span_err_with_code( &self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, ) -> DiagnosticBuilder<'_>576 pub fn struct_span_err_with_code(
577 &self,
578 span: impl Into<MultiSpan>,
579 msg: &str,
580 code: DiagnosticId,
581 ) -> DiagnosticBuilder<'_> {
582 let mut result = self.struct_span_err(span, msg);
583 result.code(code);
584 result
585 }
586
587 /// Construct a builder at the `Error` level with the `msg`.
588 // FIXME: This method should be removed (every error should have an associated error code).
struct_err(&self, msg: &str) -> DiagnosticBuilder<'_>589 pub fn struct_err(&self, msg: &str) -> DiagnosticBuilder<'_> {
590 DiagnosticBuilder::new(self, Level::Error, msg)
591 }
592
593 /// Construct a builder at the `Error` level with the `msg` and the `code`.
struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_>594 pub fn struct_err_with_code(&self, msg: &str, code: DiagnosticId) -> DiagnosticBuilder<'_> {
595 let mut result = self.struct_err(msg);
596 result.code(code);
597 result
598 }
599
600 /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
struct_span_fatal( &self, span: impl Into<MultiSpan>, msg: &str, ) -> DiagnosticBuilder<'_>601 pub fn struct_span_fatal(
602 &self,
603 span: impl Into<MultiSpan>,
604 msg: &str,
605 ) -> DiagnosticBuilder<'_> {
606 let mut result = self.struct_fatal(msg);
607 result.set_span(span);
608 result
609 }
610
611 /// Construct a builder at the `Fatal` level at the given `span`, with the `msg`, and `code`.
struct_span_fatal_with_code( &self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, ) -> DiagnosticBuilder<'_>612 pub fn struct_span_fatal_with_code(
613 &self,
614 span: impl Into<MultiSpan>,
615 msg: &str,
616 code: DiagnosticId,
617 ) -> DiagnosticBuilder<'_> {
618 let mut result = self.struct_span_fatal(span, msg);
619 result.code(code);
620 result
621 }
622
623 /// Construct a builder at the `Error` level with the `msg`.
struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_>624 pub fn struct_fatal(&self, msg: &str) -> DiagnosticBuilder<'_> {
625 DiagnosticBuilder::new(self, Level::Fatal, msg)
626 }
627
628 /// Construct a builder at the `Help` level with the `msg`.
struct_help(&self, msg: &str) -> DiagnosticBuilder<'_>629 pub fn struct_help(&self, msg: &str) -> DiagnosticBuilder<'_> {
630 DiagnosticBuilder::new(self, Level::Help, msg)
631 }
632
633 /// Construct a builder at the `Note` level with the `msg`.
struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_>634 pub fn struct_note_without_error(&self, msg: &str) -> DiagnosticBuilder<'_> {
635 DiagnosticBuilder::new(self, Level::Note, msg)
636 }
637
span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> !638 pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
639 self.emit_diag_at_span(Diagnostic::new(Fatal, msg), span);
640 FatalError.raise()
641 }
642
span_fatal_with_code( &self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId, ) -> !643 pub fn span_fatal_with_code(
644 &self,
645 span: impl Into<MultiSpan>,
646 msg: &str,
647 code: DiagnosticId,
648 ) -> ! {
649 self.emit_diag_at_span(Diagnostic::new_with_code(Fatal, Some(code), msg), span);
650 FatalError.raise()
651 }
652
span_err(&self, span: impl Into<MultiSpan>, msg: &str)653 pub fn span_err(&self, span: impl Into<MultiSpan>, msg: &str) {
654 self.emit_diag_at_span(Diagnostic::new(Error, msg), span);
655 }
656
span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId)657 pub fn span_err_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
658 self.emit_diag_at_span(Diagnostic::new_with_code(Error, Some(code), msg), span);
659 }
660
span_warn(&self, span: impl Into<MultiSpan>, msg: &str)661 pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: &str) {
662 self.emit_diag_at_span(Diagnostic::new(Warning, msg), span);
663 }
664
span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId)665 pub fn span_warn_with_code(&self, span: impl Into<MultiSpan>, msg: &str, code: DiagnosticId) {
666 self.emit_diag_at_span(Diagnostic::new_with_code(Warning, Some(code), msg), span);
667 }
668
span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> !669 pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: &str) -> ! {
670 self.inner.borrow_mut().span_bug(span, msg)
671 }
672
673 #[track_caller]
delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str)674 pub fn delay_span_bug(&self, span: impl Into<MultiSpan>, msg: &str) {
675 self.inner.borrow_mut().delay_span_bug(span, msg)
676 }
677
delay_good_path_bug(&self, msg: &str)678 pub fn delay_good_path_bug(&self, msg: &str) {
679 self.inner.borrow_mut().delay_good_path_bug(msg)
680 }
681
span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str)682 pub fn span_bug_no_panic(&self, span: impl Into<MultiSpan>, msg: &str) {
683 self.emit_diag_at_span(Diagnostic::new(Bug, msg), span);
684 }
685
span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str)686 pub fn span_note_without_error(&self, span: impl Into<MultiSpan>, msg: &str) {
687 self.emit_diag_at_span(Diagnostic::new(Note, msg), span);
688 }
689
span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_>690 pub fn span_note_diag(&self, span: Span, msg: &str) -> DiagnosticBuilder<'_> {
691 let mut db = DiagnosticBuilder::new(self, Note, msg);
692 db.set_span(span);
693 db
694 }
695
696 // NOTE: intentionally doesn't raise an error so rustc_codegen_ssa only reports fatal errors in the main thread
fatal(&self, msg: &str) -> FatalError697 pub fn fatal(&self, msg: &str) -> FatalError {
698 self.inner.borrow_mut().fatal(msg)
699 }
700
err(&self, msg: &str)701 pub fn err(&self, msg: &str) {
702 self.inner.borrow_mut().err(msg);
703 }
704
warn(&self, msg: &str)705 pub fn warn(&self, msg: &str) {
706 let mut db = DiagnosticBuilder::new(self, Warning, msg);
707 db.emit();
708 }
709
note_without_error(&self, msg: &str)710 pub fn note_without_error(&self, msg: &str) {
711 DiagnosticBuilder::new(self, Note, msg).emit();
712 }
713
bug(&self, msg: &str) -> !714 pub fn bug(&self, msg: &str) -> ! {
715 self.inner.borrow_mut().bug(msg)
716 }
717
err_count(&self) -> usize718 pub fn err_count(&self) -> usize {
719 self.inner.borrow().err_count()
720 }
721
has_errors(&self) -> bool722 pub fn has_errors(&self) -> bool {
723 self.inner.borrow().has_errors()
724 }
has_errors_or_delayed_span_bugs(&self) -> bool725 pub fn has_errors_or_delayed_span_bugs(&self) -> bool {
726 self.inner.borrow().has_errors_or_delayed_span_bugs()
727 }
728
print_error_count(&self, registry: &Registry)729 pub fn print_error_count(&self, registry: &Registry) {
730 self.inner.borrow_mut().print_error_count(registry)
731 }
732
take_future_breakage_diagnostics(&self) -> Vec<Diagnostic>733 pub fn take_future_breakage_diagnostics(&self) -> Vec<Diagnostic> {
734 std::mem::take(&mut self.inner.borrow_mut().future_breakage_diagnostics)
735 }
736
abort_if_errors(&self)737 pub fn abort_if_errors(&self) {
738 self.inner.borrow_mut().abort_if_errors()
739 }
740
741 /// `true` if we haven't taught a diagnostic with this code already.
742 /// The caller must then teach the user about such a diagnostic.
743 ///
744 /// Used to suppress emitting the same error multiple times with extended explanation when
745 /// calling `-Zteach`.
must_teach(&self, code: &DiagnosticId) -> bool746 pub fn must_teach(&self, code: &DiagnosticId) -> bool {
747 self.inner.borrow_mut().must_teach(code)
748 }
749
force_print_diagnostic(&self, db: Diagnostic)750 pub fn force_print_diagnostic(&self, db: Diagnostic) {
751 self.inner.borrow_mut().force_print_diagnostic(db)
752 }
753
emit_diagnostic(&self, diagnostic: &Diagnostic)754 pub fn emit_diagnostic(&self, diagnostic: &Diagnostic) {
755 self.inner.borrow_mut().emit_diagnostic(diagnostic)
756 }
757
emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>)758 fn emit_diag_at_span(&self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
759 let mut inner = self.inner.borrow_mut();
760 inner.emit_diagnostic(diag.set_span(sp));
761 }
762
emit_artifact_notification(&self, path: &Path, artifact_type: &str)763 pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
764 self.inner.borrow_mut().emit_artifact_notification(path, artifact_type)
765 }
766
emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>)767 pub fn emit_future_breakage_report(&self, diags: Vec<(FutureBreakage, Diagnostic)>) {
768 self.inner.borrow_mut().emitter.emit_future_breakage_report(diags)
769 }
770
emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str])771 pub fn emit_unused_externs(&self, lint_level: &str, unused_externs: &[&str]) {
772 self.inner.borrow_mut().emit_unused_externs(lint_level, unused_externs)
773 }
774
delay_as_bug(&self, diagnostic: Diagnostic)775 pub fn delay_as_bug(&self, diagnostic: Diagnostic) {
776 self.inner.borrow_mut().delay_as_bug(diagnostic)
777 }
778 }
779
780 impl HandlerInner {
must_teach(&mut self, code: &DiagnosticId) -> bool781 fn must_teach(&mut self, code: &DiagnosticId) -> bool {
782 self.taught_diagnostics.insert(code.clone())
783 }
784
force_print_diagnostic(&mut self, db: Diagnostic)785 fn force_print_diagnostic(&mut self, db: Diagnostic) {
786 self.emitter.emit_diagnostic(&db);
787 }
788
789 /// Emit all stashed diagnostics.
emit_stashed_diagnostics(&mut self)790 fn emit_stashed_diagnostics(&mut self) {
791 let diags = self.stashed_diagnostics.drain(..).map(|x| x.1).collect::<Vec<_>>();
792 diags.iter().for_each(|diag| self.emit_diagnostic(diag));
793 }
794
emit_diagnostic(&mut self, diagnostic: &Diagnostic)795 fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
796 if diagnostic.cancelled() {
797 return;
798 }
799
800 if diagnostic.has_future_breakage() {
801 self.future_breakage_diagnostics.push(diagnostic.clone());
802 }
803
804 if diagnostic.level == Warning && !self.flags.can_emit_warnings {
805 if diagnostic.has_future_breakage() {
806 (*TRACK_DIAGNOSTICS)(diagnostic);
807 }
808 return;
809 }
810
811 (*TRACK_DIAGNOSTICS)(diagnostic);
812
813 if diagnostic.level == Allow {
814 return;
815 }
816
817 if let Some(ref code) = diagnostic.code {
818 self.emitted_diagnostic_codes.insert(code.clone());
819 }
820
821 let already_emitted = |this: &mut Self| {
822 let mut hasher = StableHasher::new();
823 diagnostic.hash(&mut hasher);
824 let diagnostic_hash = hasher.finish();
825 !this.emitted_diagnostics.insert(diagnostic_hash)
826 };
827
828 // Only emit the diagnostic if we've been asked to deduplicate and
829 // haven't already emitted an equivalent diagnostic.
830 if !(self.flags.deduplicate_diagnostics && already_emitted(self)) {
831 self.emitter.emit_diagnostic(diagnostic);
832 if diagnostic.is_error() {
833 self.deduplicated_err_count += 1;
834 } else if diagnostic.level == Warning {
835 self.deduplicated_warn_count += 1;
836 }
837 }
838 if diagnostic.is_error() {
839 self.bump_err_count();
840 } else {
841 self.bump_warn_count();
842 }
843 }
844
emit_artifact_notification(&mut self, path: &Path, artifact_type: &str)845 fn emit_artifact_notification(&mut self, path: &Path, artifact_type: &str) {
846 self.emitter.emit_artifact_notification(path, artifact_type);
847 }
848
emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str])849 fn emit_unused_externs(&mut self, lint_level: &str, unused_externs: &[&str]) {
850 self.emitter.emit_unused_externs(lint_level, unused_externs);
851 }
852
treat_err_as_bug(&self) -> bool853 fn treat_err_as_bug(&self) -> bool {
854 self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get())
855 }
856
print_error_count(&mut self, registry: &Registry)857 fn print_error_count(&mut self, registry: &Registry) {
858 self.emit_stashed_diagnostics();
859
860 let warnings = match self.deduplicated_warn_count {
861 0 => String::new(),
862 1 => "1 warning emitted".to_string(),
863 count => format!("{} warnings emitted", count),
864 };
865 let errors = match self.deduplicated_err_count {
866 0 => String::new(),
867 1 => "aborting due to previous error".to_string(),
868 count => format!("aborting due to {} previous errors", count),
869 };
870 if self.treat_err_as_bug() {
871 return;
872 }
873
874 match (errors.len(), warnings.len()) {
875 (0, 0) => return,
876 (0, _) => self.emit_diagnostic(&Diagnostic::new(Level::Warning, &warnings)),
877 (_, 0) => {
878 let _ = self.fatal(&errors);
879 }
880 (_, _) => {
881 let _ = self.fatal(&format!("{}; {}", &errors, &warnings));
882 }
883 }
884
885 let can_show_explain = self.emitter.should_show_explain();
886 let are_there_diagnostics = !self.emitted_diagnostic_codes.is_empty();
887 if can_show_explain && are_there_diagnostics {
888 let mut error_codes = self
889 .emitted_diagnostic_codes
890 .iter()
891 .filter_map(|x| match &x {
892 DiagnosticId::Error(s) => {
893 if let Ok(Some(_explanation)) = registry.try_find_description(s) {
894 Some(s.clone())
895 } else {
896 None
897 }
898 }
899 _ => None,
900 })
901 .collect::<Vec<_>>();
902 if !error_codes.is_empty() {
903 error_codes.sort();
904 if error_codes.len() > 1 {
905 let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
906 self.failure(&format!(
907 "Some errors have detailed explanations: {}{}",
908 error_codes[..limit].join(", "),
909 if error_codes.len() > 9 { "..." } else { "." }
910 ));
911 self.failure(&format!(
912 "For more information about an error, try \
913 `rustc --explain {}`.",
914 &error_codes[0]
915 ));
916 } else {
917 self.failure(&format!(
918 "For more information about this error, try \
919 `rustc --explain {}`.",
920 &error_codes[0]
921 ));
922 }
923 }
924 }
925 }
926
err_count(&self) -> usize927 fn err_count(&self) -> usize {
928 self.err_count + self.stashed_diagnostics.len()
929 }
930
has_errors(&self) -> bool931 fn has_errors(&self) -> bool {
932 self.err_count() > 0
933 }
has_errors_or_delayed_span_bugs(&self) -> bool934 fn has_errors_or_delayed_span_bugs(&self) -> bool {
935 self.has_errors() || !self.delayed_span_bugs.is_empty()
936 }
has_any_message(&self) -> bool937 fn has_any_message(&self) -> bool {
938 self.err_count() > 0 || self.warn_count > 0
939 }
940
abort_if_errors(&mut self)941 fn abort_if_errors(&mut self) {
942 self.emit_stashed_diagnostics();
943
944 if self.has_errors() {
945 FatalError.raise();
946 }
947 }
948
span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> !949 fn span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) -> ! {
950 self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp);
951 panic::panic_any(ExplicitBug);
952 }
953
emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>)954 fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into<MultiSpan>) {
955 self.emit_diagnostic(diag.set_span(sp));
956 }
957
958 #[track_caller]
delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str)959 fn delay_span_bug(&mut self, sp: impl Into<MultiSpan>, msg: &str) {
960 // This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
961 // incrementing `err_count` by one, so we need to +1 the comparing.
962 // FIXME: Would be nice to increment err_count in a more coherent way.
963 if self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() + 1 >= c.get()) {
964 // FIXME: don't abort here if report_delayed_bugs is off
965 self.span_bug(sp, msg);
966 }
967 let mut diagnostic = Diagnostic::new(Level::Bug, msg);
968 diagnostic.set_span(sp.into());
969 diagnostic.note(&format!("delayed at {}", std::panic::Location::caller()));
970 self.delay_as_bug(diagnostic)
971 }
972
delay_good_path_bug(&mut self, msg: &str)973 fn delay_good_path_bug(&mut self, msg: &str) {
974 let diagnostic = Diagnostic::new(Level::Bug, msg);
975 if self.flags.report_delayed_bugs {
976 self.emit_diagnostic(&diagnostic);
977 }
978 let backtrace = std::backtrace::Backtrace::force_capture();
979 self.delayed_good_path_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
980 }
981
failure(&mut self, msg: &str)982 fn failure(&mut self, msg: &str) {
983 self.emit_diagnostic(&Diagnostic::new(FailureNote, msg));
984 }
985
fatal(&mut self, msg: &str) -> FatalError986 fn fatal(&mut self, msg: &str) -> FatalError {
987 self.emit_error(Fatal, msg);
988 FatalError
989 }
990
err(&mut self, msg: &str)991 fn err(&mut self, msg: &str) {
992 self.emit_error(Error, msg);
993 }
994
995 /// Emit an error; level should be `Error` or `Fatal`.
emit_error(&mut self, level: Level, msg: &str)996 fn emit_error(&mut self, level: Level, msg: &str) {
997 if self.treat_err_as_bug() {
998 self.bug(msg);
999 }
1000 self.emit_diagnostic(&Diagnostic::new(level, msg));
1001 }
1002
bug(&mut self, msg: &str) -> !1003 fn bug(&mut self, msg: &str) -> ! {
1004 self.emit_diagnostic(&Diagnostic::new(Bug, msg));
1005 panic::panic_any(ExplicitBug);
1006 }
1007
delay_as_bug(&mut self, diagnostic: Diagnostic)1008 fn delay_as_bug(&mut self, diagnostic: Diagnostic) {
1009 if self.flags.report_delayed_bugs {
1010 self.emit_diagnostic(&diagnostic);
1011 }
1012 self.delayed_span_bugs.push(diagnostic);
1013 }
1014
flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str)1015 fn flush_delayed(&mut self, bugs: Vec<Diagnostic>, explanation: &str) {
1016 let has_bugs = !bugs.is_empty();
1017 for bug in bugs {
1018 self.emit_diagnostic(&bug);
1019 }
1020 if has_bugs {
1021 panic!("{}", explanation);
1022 }
1023 }
1024
bump_err_count(&mut self)1025 fn bump_err_count(&mut self) {
1026 self.err_count += 1;
1027 self.panic_if_treat_err_as_bug();
1028 }
1029
bump_warn_count(&mut self)1030 fn bump_warn_count(&mut self) {
1031 self.warn_count += 1;
1032 }
1033
panic_if_treat_err_as_bug(&self)1034 fn panic_if_treat_err_as_bug(&self) {
1035 if self.treat_err_as_bug() {
1036 match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) {
1037 (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"),
1038 (0, _) | (1, _) => {}
1039 (count, as_bug) => panic!(
1040 "aborting after {} errors due to `-Z treat-err-as-bug={}`",
1041 count, as_bug,
1042 ),
1043 }
1044 }
1045 }
1046 }
1047
1048 struct DelayedDiagnostic {
1049 inner: Diagnostic,
1050 note: Backtrace,
1051 }
1052
1053 impl DelayedDiagnostic {
with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self1054 fn with_backtrace(diagnostic: Diagnostic, backtrace: Backtrace) -> Self {
1055 DelayedDiagnostic { inner: diagnostic, note: backtrace }
1056 }
1057
decorate(mut self) -> Diagnostic1058 fn decorate(mut self) -> Diagnostic {
1059 self.inner.note(&format!("delayed at {}", self.note));
1060 self.inner
1061 }
1062 }
1063
1064 #[derive(Copy, PartialEq, Clone, Hash, Debug, Encodable, Decodable)]
1065 pub enum Level {
1066 Bug,
1067 Fatal,
1068 Error,
1069 Warning,
1070 Note,
1071 Help,
1072 Cancelled,
1073 FailureNote,
1074 Allow,
1075 }
1076
1077 impl fmt::Display for Level {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1078 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1079 self.to_str().fmt(f)
1080 }
1081 }
1082
1083 impl Level {
color(self) -> ColorSpec1084 fn color(self) -> ColorSpec {
1085 let mut spec = ColorSpec::new();
1086 match self {
1087 Bug | Fatal | Error => {
1088 spec.set_fg(Some(Color::Red)).set_intense(true);
1089 }
1090 Warning => {
1091 spec.set_fg(Some(Color::Yellow)).set_intense(cfg!(windows));
1092 }
1093 Note => {
1094 spec.set_fg(Some(Color::Green)).set_intense(true);
1095 }
1096 Help => {
1097 spec.set_fg(Some(Color::Cyan)).set_intense(true);
1098 }
1099 FailureNote => {}
1100 Allow | Cancelled => unreachable!(),
1101 }
1102 spec
1103 }
1104
to_str(self) -> &'static str1105 pub fn to_str(self) -> &'static str {
1106 match self {
1107 Bug => "error: internal compiler error",
1108 Fatal | Error => "error",
1109 Warning => "warning",
1110 Note => "note",
1111 Help => "help",
1112 FailureNote => "failure-note",
1113 Cancelled => panic!("Shouldn't call on cancelled error"),
1114 Allow => panic!("Shouldn't call on allowed error"),
1115 }
1116 }
1117
is_failure_note(&self) -> bool1118 pub fn is_failure_note(&self) -> bool {
1119 matches!(*self, FailureNote)
1120 }
1121 }
1122
add_elided_lifetime_in_path_suggestion( source_map: &SourceMap, db: &mut DiagnosticBuilder<'_>, n: usize, path_span: Span, incl_angl_brckt: bool, insertion_span: Span, anon_lts: String, )1123 pub fn add_elided_lifetime_in_path_suggestion(
1124 source_map: &SourceMap,
1125 db: &mut DiagnosticBuilder<'_>,
1126 n: usize,
1127 path_span: Span,
1128 incl_angl_brckt: bool,
1129 insertion_span: Span,
1130 anon_lts: String,
1131 ) {
1132 let (replace_span, suggestion) = if incl_angl_brckt {
1133 (insertion_span, anon_lts)
1134 } else {
1135 // When possible, prefer a suggestion that replaces the whole
1136 // `Path<T>` expression with `Path<'_, T>`, rather than inserting `'_, `
1137 // at a point (which makes for an ugly/confusing label)
1138 if let Ok(snippet) = source_map.span_to_snippet(path_span) {
1139 // But our spans can get out of whack due to macros; if the place we think
1140 // we want to insert `'_` isn't even within the path expression's span, we
1141 // should bail out of making any suggestion rather than panicking on a
1142 // subtract-with-overflow or string-slice-out-out-bounds (!)
1143 // FIXME: can we do better?
1144 if insertion_span.lo().0 < path_span.lo().0 {
1145 return;
1146 }
1147 let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize;
1148 if insertion_index > snippet.len() {
1149 return;
1150 }
1151 let (before, after) = snippet.split_at(insertion_index);
1152 (path_span, format!("{}{}{}", before, anon_lts, after))
1153 } else {
1154 (insertion_span, anon_lts)
1155 }
1156 };
1157 db.span_suggestion(
1158 replace_span,
1159 &format!("indicate the anonymous lifetime{}", pluralize!(n)),
1160 suggestion,
1161 Applicability::MachineApplicable,
1162 );
1163 }
1164
1165 // Useful type to use with `Result<>` indicate that an error has already
1166 // been reported to the user, so no need to continue checking.
1167 #[derive(Clone, Copy, Debug, Encodable, Decodable, Hash, PartialEq, Eq)]
1168 pub struct ErrorReported;
1169
1170 rustc_data_structures::impl_stable_hash_via_hash!(ErrorReported);
1171