]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_errors/src/diagnostic_builder.rs
Auto merge of #100812 - Nilstrieb:revert-let-chains-nightly, r=Mark-Simulacrum
[rust.git] / compiler / rustc_errors / src / diagnostic_builder.rs
1 use crate::diagnostic::IntoDiagnosticArg;
2 use crate::{
3     Diagnostic, DiagnosticId, DiagnosticMessage, DiagnosticStyledString, ErrorGuaranteed,
4     SubdiagnosticMessage,
5 };
6 use crate::{Handler, Level, MultiSpan, StashKey};
7 use rustc_lint_defs::Applicability;
8
9 use rustc_span::Span;
10 use std::borrow::Cow;
11 use std::fmt::{self, Debug};
12 use std::marker::PhantomData;
13 use std::ops::{Deref, DerefMut};
14 use std::thread::panicking;
15 use tracing::debug;
16
17 /// Used for emitting structured error messages and other diagnostic information.
18 ///
19 /// If there is some state in a downstream crate you would like to
20 /// access in the methods of `DiagnosticBuilder` here, consider
21 /// extending `HandlerFlags`, accessed via `self.handler.flags`.
22 #[must_use]
23 #[derive(Clone)]
24 pub struct DiagnosticBuilder<'a, G: EmissionGuarantee> {
25     inner: DiagnosticBuilderInner<'a>,
26     _marker: PhantomData<G>,
27 }
28
29 /// This type exists only for `DiagnosticBuilder::forget_guarantee`, because it:
30 /// 1. lacks the `G` parameter and therefore `DiagnosticBuilder<G1>` can be
31 ///    converted into `DiagnosticBuilder<G2>` while reusing the `inner` field
32 /// 2. can implement the `Drop` "bomb" instead of `DiagnosticBuilder`, as it
33 ///    contains all of the data (`state` + `diagnostic`) of `DiagnosticBuilder`
34 ///
35 /// The `diagnostic` field is not `Copy` and can't be moved out of whichever
36 /// type implements the `Drop` "bomb", but because of the above two facts, that
37 /// never needs to happen - instead, the whole `inner: DiagnosticBuilderInner`
38 /// can be moved out of a `DiagnosticBuilder` and into another.
39 #[must_use]
40 #[derive(Clone)]
41 struct DiagnosticBuilderInner<'a> {
42     state: DiagnosticBuilderState<'a>,
43
44     /// `Diagnostic` is a large type, and `DiagnosticBuilder` is often used as a
45     /// return value, especially within the frequently-used `PResult` type.
46     /// In theory, return value optimization (RVO) should avoid unnecessary
47     /// copying. In practice, it does not (at the time of writing).
48     diagnostic: Box<Diagnostic>,
49 }
50
51 #[derive(Clone)]
52 enum DiagnosticBuilderState<'a> {
53     /// Initial state of a `DiagnosticBuilder`, before `.emit()` or `.cancel()`.
54     ///
55     /// The `Diagnostic` will be emitted through this `Handler`.
56     Emittable(&'a Handler),
57
58     /// State of a `DiagnosticBuilder`, after `.emit()` or *during* `.cancel()`.
59     ///
60     /// The `Diagnostic` will be ignored when calling `.emit()`, and it can be
61     /// assumed that `.emit()` was previously called, to end up in this state.
62     ///
63     /// While this is also used by `.cancel()`, this state is only observed by
64     /// the `Drop` `impl` of `DiagnosticBuilderInner`, as `.cancel()` takes
65     /// `self` by-value specifically to prevent any attempts to `.emit()`.
66     ///
67     // FIXME(eddyb) currently this doesn't prevent extending the `Diagnostic`,
68     // despite that being potentially lossy, if important information is added
69     // *after* the original `.emit()` call.
70     AlreadyEmittedOrDuringCancellation,
71 }
72
73 // `DiagnosticBuilderState` should be pointer-sized.
74 rustc_data_structures::static_assert_size!(
75     DiagnosticBuilderState<'_>,
76     std::mem::size_of::<&Handler>()
77 );
78
79 /// Trait for types that `DiagnosticBuilder::emit` can return as a "guarantee"
80 /// (or "proof") token that the emission happened.
81 pub trait EmissionGuarantee: Sized {
82     /// Implementation of `DiagnosticBuilder::emit`, fully controlled by each
83     /// `impl` of `EmissionGuarantee`, to make it impossible to create a value
84     /// of `Self` without actually performing the emission.
85     #[track_caller]
86     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self;
87
88     /// Creates a new `DiagnosticBuilder` that will return this type of guarantee.
89     #[track_caller]
90     fn make_diagnostic_builder(
91         handler: &Handler,
92         msg: impl Into<DiagnosticMessage>,
93     ) -> DiagnosticBuilder<'_, Self>;
94 }
95
96 /// Private module for sealing the `IsError` helper trait.
97 mod sealed_level_is_error {
98     use crate::Level;
99
100     /// Sealed helper trait for statically checking that a `Level` is an error.
101     pub(crate) trait IsError<const L: Level> {}
102
103     impl IsError<{ Level::Bug }> for () {}
104     impl IsError<{ Level::DelayedBug }> for () {}
105     impl IsError<{ Level::Fatal }> for () {}
106     // NOTE(eddyb) `Level::Error { lint: true }` is also an error, but lints
107     // don't need error guarantees, as their levels are always dynamic.
108     impl IsError<{ Level::Error { lint: false } }> for () {}
109 }
110
111 impl<'a> DiagnosticBuilder<'a, ErrorGuaranteed> {
112     /// Convenience function for internal use, clients should use one of the
113     /// `struct_*` methods on [`Handler`].
114     pub(crate) fn new_guaranteeing_error<M: Into<DiagnosticMessage>, const L: Level>(
115         handler: &'a Handler,
116         message: M,
117     ) -> Self
118     where
119         (): sealed_level_is_error::IsError<L>,
120     {
121         Self {
122             inner: DiagnosticBuilderInner {
123                 state: DiagnosticBuilderState::Emittable(handler),
124                 diagnostic: Box::new(Diagnostic::new_with_code(L, None, message)),
125             },
126             _marker: PhantomData,
127         }
128     }
129
130     /// Discard the guarantee `.emit()` would return, in favor of having the
131     /// type `DiagnosticBuilder<'a, ()>`. This may be necessary whenever there
132     /// is a common codepath handling both errors and warnings.
133     pub fn forget_guarantee(self) -> DiagnosticBuilder<'a, ()> {
134         DiagnosticBuilder { inner: self.inner, _marker: PhantomData }
135     }
136 }
137
138 // FIXME(eddyb) make `ErrorGuaranteed` impossible to create outside `.emit()`.
139 impl EmissionGuarantee for ErrorGuaranteed {
140     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
141         match db.inner.state {
142             // First `.emit()` call, the `&Handler` is still available.
143             DiagnosticBuilderState::Emittable(handler) => {
144                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
145
146                 let guar = handler.emit_diagnostic(&mut db.inner.diagnostic);
147
148                 // Only allow a guarantee if the `level` wasn't switched to a
149                 // non-error - the field isn't `pub`, but the whole `Diagnostic`
150                 // can be overwritten with a new one, thanks to `DerefMut`.
151                 assert!(
152                     db.inner.diagnostic.is_error(),
153                     "emitted non-error ({:?}) diagnostic \
154                      from `DiagnosticBuilder<ErrorGuaranteed>`",
155                     db.inner.diagnostic.level,
156                 );
157                 guar.unwrap()
158             }
159             // `.emit()` was previously called, disallowed from repeating it,
160             // but can take advantage of the previous `.emit()`'s guarantee
161             // still being applicable (i.e. as a form of idempotency).
162             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {
163                 // Only allow a guarantee if the `level` wasn't switched to a
164                 // non-error - the field isn't `pub`, but the whole `Diagnostic`
165                 // can be overwritten with a new one, thanks to `DerefMut`.
166                 assert!(
167                     db.inner.diagnostic.is_error(),
168                     "`DiagnosticBuilder<ErrorGuaranteed>`'s diagnostic \
169                      became non-error ({:?}), after original `.emit()`",
170                     db.inner.diagnostic.level,
171                 );
172                 ErrorGuaranteed::unchecked_claim_error_was_emitted()
173             }
174         }
175     }
176
177     fn make_diagnostic_builder(
178         handler: &Handler,
179         msg: impl Into<DiagnosticMessage>,
180     ) -> DiagnosticBuilder<'_, Self> {
181         DiagnosticBuilder::new_guaranteeing_error::<_, { Level::Error { lint: false } }>(
182             handler, msg,
183         )
184     }
185 }
186
187 impl<'a> DiagnosticBuilder<'a, ()> {
188     /// Convenience function for internal use, clients should use one of the
189     /// `struct_*` methods on [`Handler`].
190     pub(crate) fn new<M: Into<DiagnosticMessage>>(
191         handler: &'a Handler,
192         level: Level,
193         message: M,
194     ) -> Self {
195         let diagnostic = Diagnostic::new_with_code(level, None, message);
196         Self::new_diagnostic(handler, diagnostic)
197     }
198
199     /// Creates a new `DiagnosticBuilder` with an already constructed
200     /// diagnostic.
201     pub(crate) fn new_diagnostic(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
202         debug!("Created new diagnostic");
203         Self {
204             inner: DiagnosticBuilderInner {
205                 state: DiagnosticBuilderState::Emittable(handler),
206                 diagnostic: Box::new(diagnostic),
207             },
208             _marker: PhantomData,
209         }
210     }
211 }
212
213 // FIXME(eddyb) should there be a `Option<ErrorGuaranteed>` impl as well?
214 impl EmissionGuarantee for () {
215     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
216         match db.inner.state {
217             // First `.emit()` call, the `&Handler` is still available.
218             DiagnosticBuilderState::Emittable(handler) => {
219                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
220
221                 handler.emit_diagnostic(&mut db.inner.diagnostic);
222             }
223             // `.emit()` was previously called, disallowed from repeating it.
224             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
225         }
226     }
227
228     fn make_diagnostic_builder(
229         handler: &Handler,
230         msg: impl Into<DiagnosticMessage>,
231     ) -> DiagnosticBuilder<'_, Self> {
232         DiagnosticBuilder::new(handler, Level::Warning(None), msg)
233     }
234 }
235
236 impl<'a> DiagnosticBuilder<'a, !> {
237     /// Convenience function for internal use, clients should use one of the
238     /// `struct_*` methods on [`Handler`].
239     pub(crate) fn new_fatal(handler: &'a Handler, message: impl Into<DiagnosticMessage>) -> Self {
240         let diagnostic = Diagnostic::new_with_code(Level::Fatal, None, message);
241         Self::new_diagnostic_fatal(handler, diagnostic)
242     }
243
244     /// Creates a new `DiagnosticBuilder` with an already constructed
245     /// diagnostic.
246     pub(crate) fn new_diagnostic_fatal(handler: &'a Handler, diagnostic: Diagnostic) -> Self {
247         debug!("Created new diagnostic");
248         Self {
249             inner: DiagnosticBuilderInner {
250                 state: DiagnosticBuilderState::Emittable(handler),
251                 diagnostic: Box::new(diagnostic),
252             },
253             _marker: PhantomData,
254         }
255     }
256 }
257
258 impl EmissionGuarantee for ! {
259     fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self {
260         match db.inner.state {
261             // First `.emit()` call, the `&Handler` is still available.
262             DiagnosticBuilderState::Emittable(handler) => {
263                 db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
264
265                 handler.emit_diagnostic(&mut db.inner.diagnostic);
266             }
267             // `.emit()` was previously called, disallowed from repeating it.
268             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
269         }
270         // Then fatally error, returning `!`
271         crate::FatalError.raise()
272     }
273
274     fn make_diagnostic_builder(
275         handler: &Handler,
276         msg: impl Into<DiagnosticMessage>,
277     ) -> DiagnosticBuilder<'_, Self> {
278         DiagnosticBuilder::new_fatal(handler, msg)
279     }
280 }
281
282 /// In general, the `DiagnosticBuilder` uses deref to allow access to
283 /// the fields and methods of the embedded `diagnostic` in a
284 /// transparent way. *However,* many of the methods are intended to
285 /// be used in a chained way, and hence ought to return `self`. In
286 /// that case, we can't just naively forward to the method on the
287 /// `diagnostic`, because the return type would be a `&Diagnostic`
288 /// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes
289 /// it easy to declare such methods on the builder.
290 macro_rules! forward {
291     // Forward pattern for &mut self -> &mut Self
292     (
293         $(#[$attrs:meta])*
294         pub fn $n:ident(&mut self, $($name:ident: $ty:ty),* $(,)?) -> &mut Self
295     ) => {
296         $(#[$attrs])*
297         #[doc = concat!("See [`Diagnostic::", stringify!($n), "()`].")]
298         pub fn $n(&mut self, $($name: $ty),*) -> &mut Self {
299             self.inner.diagnostic.$n($($name),*);
300             self
301         }
302     };
303 }
304
305 impl<G: EmissionGuarantee> Deref for DiagnosticBuilder<'_, G> {
306     type Target = Diagnostic;
307
308     fn deref(&self) -> &Diagnostic {
309         &self.inner.diagnostic
310     }
311 }
312
313 impl<G: EmissionGuarantee> DerefMut for DiagnosticBuilder<'_, G> {
314     fn deref_mut(&mut self) -> &mut Diagnostic {
315         &mut self.inner.diagnostic
316     }
317 }
318
319 impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
320     /// Emit the diagnostic.
321     #[track_caller]
322     pub fn emit(&mut self) -> G {
323         G::diagnostic_builder_emit_producing_guarantee(self)
324     }
325
326     /// Emit the diagnostic unless `delay` is true,
327     /// in which case the emission will be delayed as a bug.
328     ///
329     /// See `emit` and `delay_as_bug` for details.
330     #[track_caller]
331     pub fn emit_unless(&mut self, delay: bool) -> G {
332         if delay {
333             self.downgrade_to_delayed_bug();
334         }
335         self.emit()
336     }
337
338     /// Cancel the diagnostic (a structured diagnostic must either be emitted or
339     /// cancelled or it will panic when dropped).
340     ///
341     /// This method takes `self` by-value to disallow calling `.emit()` on it,
342     /// which may be expected to *guarantee* the emission of an error, either
343     /// at the time of the call, or through a prior `.emit()` call.
344     pub fn cancel(mut self) {
345         self.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation;
346         drop(self);
347     }
348
349     /// Stashes diagnostic for possible later improvement in a different,
350     /// later stage of the compiler. The diagnostic can be accessed with
351     /// the provided `span` and `key` through [`Handler::steal_diagnostic()`].
352     ///
353     /// As with `buffer`, this is unless the handler has disabled such buffering.
354     pub fn stash(self, span: Span, key: StashKey) {
355         if let Some((diag, handler)) = self.into_diagnostic() {
356             handler.stash_diagnostic(span, key, diag);
357         }
358     }
359
360     /// Converts the builder to a `Diagnostic` for later emission,
361     /// unless handler has disabled such buffering, or `.emit()` was called.
362     pub fn into_diagnostic(mut self) -> Option<(Diagnostic, &'a Handler)> {
363         let handler = match self.inner.state {
364             // No `.emit()` calls, the `&Handler` is still available.
365             DiagnosticBuilderState::Emittable(handler) => handler,
366             // `.emit()` was previously called, nothing we can do.
367             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {
368                 return None;
369             }
370         };
371
372         if handler.flags.dont_buffer_diagnostics || handler.flags.treat_err_as_bug.is_some() {
373             self.emit();
374             return None;
375         }
376
377         // Take the `Diagnostic` by replacing it with a dummy.
378         let dummy = Diagnostic::new(Level::Allow, DiagnosticMessage::Str("".to_string()));
379         let diagnostic = std::mem::replace(&mut *self.inner.diagnostic, dummy);
380
381         // Disable the ICE on `Drop`.
382         self.cancel();
383
384         // Logging here is useful to help track down where in logs an error was
385         // actually emitted.
386         debug!("buffer: diagnostic={:?}", diagnostic);
387
388         Some((diagnostic, handler))
389     }
390
391     /// Buffers the diagnostic for later emission,
392     /// unless handler has disabled such buffering.
393     pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
394         buffered_diagnostics.extend(self.into_diagnostic().map(|(diag, _)| diag));
395     }
396
397     /// Delay emission of this diagnostic as a bug.
398     ///
399     /// This can be useful in contexts where an error indicates a bug but
400     /// typically this only happens when other compilation errors have already
401     /// happened. In those cases this can be used to defer emission of this
402     /// diagnostic as a bug in the compiler only if no other errors have been
403     /// emitted.
404     ///
405     /// In the meantime, though, callsites are required to deal with the "bug"
406     /// locally in whichever way makes the most sense.
407     #[track_caller]
408     pub fn delay_as_bug(&mut self) {
409         self.downgrade_to_delayed_bug();
410         self.emit();
411     }
412
413     forward!(
414         #[track_caller]
415         pub fn downgrade_to_delayed_bug(&mut self,) -> &mut Self
416     );
417
418     forward!(
419     /// Appends a labeled span to the diagnostic.
420     ///
421     /// Labels are used to convey additional context for the diagnostic's primary span. They will
422     /// be shown together with the original diagnostic's span, *not* with spans added by
423     /// `span_note`, `span_help`, etc. Therefore, if the primary span is not displayable (because
424     /// the span is `DUMMY_SP` or the source code isn't found), labels will not be displayed
425     /// either.
426     ///
427     /// Implementation-wise, the label span is pushed onto the [`MultiSpan`] that was created when
428     /// the diagnostic was constructed. However, the label span is *not* considered a
429     /// ["primary span"][`MultiSpan`]; only the `Span` supplied when creating the diagnostic is
430     /// primary.
431     pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self);
432
433     forward!(
434     /// Labels all the given spans with the provided label.
435     /// See [`Diagnostic::span_label()`] for more information.
436     pub fn span_labels(
437         &mut self,
438         spans: impl IntoIterator<Item = Span>,
439         label: impl AsRef<str>,
440     ) -> &mut Self);
441
442     forward!(pub fn note_expected_found(
443         &mut self,
444         expected_label: &dyn fmt::Display,
445         expected: DiagnosticStyledString,
446         found_label: &dyn fmt::Display,
447         found: DiagnosticStyledString,
448     ) -> &mut Self);
449
450     forward!(pub fn note_expected_found_extra(
451         &mut self,
452         expected_label: &dyn fmt::Display,
453         expected: DiagnosticStyledString,
454         found_label: &dyn fmt::Display,
455         found: DiagnosticStyledString,
456         expected_extra: &dyn fmt::Display,
457         found_extra: &dyn fmt::Display,
458     ) -> &mut Self);
459
460     forward!(pub fn note_unsuccessful_coercion(
461         &mut self,
462         expected: DiagnosticStyledString,
463         found: DiagnosticStyledString,
464     ) -> &mut Self);
465
466     forward!(pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
467     forward!(pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
468     forward!(pub fn span_note(
469         &mut self,
470         sp: impl Into<MultiSpan>,
471         msg: impl Into<SubdiagnosticMessage>,
472     ) -> &mut Self);
473     forward!(pub fn span_note_once(
474         &mut self,
475         sp: impl Into<MultiSpan>,
476         msg: impl Into<SubdiagnosticMessage>,
477     ) -> &mut Self);
478     forward!(pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
479     forward!(pub fn span_warn(
480         &mut self,
481         sp: impl Into<MultiSpan>,
482         msg: impl Into<SubdiagnosticMessage>,
483     ) -> &mut Self);
484     forward!(pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self);
485     forward!(pub fn span_help(
486         &mut self,
487         sp: impl Into<MultiSpan>,
488         msg: impl Into<SubdiagnosticMessage>,
489     ) -> &mut Self);
490     forward!(pub fn help_use_latest_edition(&mut self,) -> &mut Self);
491     forward!(pub fn set_is_lint(&mut self,) -> &mut Self);
492
493     forward!(pub fn disable_suggestions(&mut self,) -> &mut Self);
494     forward!(pub fn clear_suggestions(&mut self,) -> &mut Self);
495
496     forward!(pub fn multipart_suggestion(
497         &mut self,
498         msg: impl Into<SubdiagnosticMessage>,
499         suggestion: Vec<(Span, String)>,
500         applicability: Applicability,
501     ) -> &mut Self);
502     forward!(pub fn multipart_suggestion_verbose(
503         &mut self,
504         msg: impl Into<SubdiagnosticMessage>,
505         suggestion: Vec<(Span, String)>,
506         applicability: Applicability,
507     ) -> &mut Self);
508     forward!(pub fn tool_only_multipart_suggestion(
509         &mut self,
510         msg: impl Into<SubdiagnosticMessage>,
511         suggestion: Vec<(Span, String)>,
512         applicability: Applicability,
513     ) -> &mut Self);
514     forward!(pub fn span_suggestion(
515         &mut self,
516         sp: Span,
517         msg: impl Into<SubdiagnosticMessage>,
518         suggestion: impl ToString,
519         applicability: Applicability,
520     ) -> &mut Self);
521     forward!(pub fn span_suggestions(
522         &mut self,
523         sp: Span,
524         msg: impl Into<SubdiagnosticMessage>,
525         suggestions: impl Iterator<Item = String>,
526         applicability: Applicability,
527     ) -> &mut Self);
528     forward!(pub fn multipart_suggestions(
529         &mut self,
530         msg: impl Into<SubdiagnosticMessage>,
531         suggestions: impl Iterator<Item = Vec<(Span, String)>>,
532         applicability: Applicability,
533     ) -> &mut Self);
534     forward!(pub fn span_suggestion_short(
535         &mut self,
536         sp: Span,
537         msg: impl Into<SubdiagnosticMessage>,
538         suggestion: impl ToString,
539         applicability: Applicability,
540     ) -> &mut Self);
541     forward!(pub fn span_suggestion_verbose(
542         &mut self,
543         sp: Span,
544         msg: impl Into<SubdiagnosticMessage>,
545         suggestion: impl ToString,
546         applicability: Applicability,
547     ) -> &mut Self);
548     forward!(pub fn span_suggestion_hidden(
549         &mut self,
550         sp: Span,
551         msg: impl Into<SubdiagnosticMessage>,
552         suggestion: impl ToString,
553         applicability: Applicability,
554     ) -> &mut Self);
555     forward!(pub fn tool_only_span_suggestion(
556         &mut self,
557         sp: Span,
558         msg: impl Into<SubdiagnosticMessage>,
559         suggestion: impl ToString,
560         applicability: Applicability,
561     ) -> &mut Self);
562
563     forward!(pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self);
564     forward!(pub fn set_span(&mut self, sp: impl Into<MultiSpan>) -> &mut Self);
565     forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self);
566     forward!(pub fn set_arg(
567         &mut self,
568         name: impl Into<Cow<'static, str>>,
569         arg: impl IntoDiagnosticArg,
570     ) -> &mut Self);
571
572     forward!(pub fn subdiagnostic(
573         &mut self,
574         subdiagnostic: impl crate::AddSubdiagnostic
575     ) -> &mut Self);
576 }
577
578 impl<G: EmissionGuarantee> Debug for DiagnosticBuilder<'_, G> {
579     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
580         self.inner.diagnostic.fmt(f)
581     }
582 }
583
584 /// Destructor bomb - a `DiagnosticBuilder` must be either emitted or cancelled
585 /// or we emit a bug.
586 impl Drop for DiagnosticBuilderInner<'_> {
587     fn drop(&mut self) {
588         match self.state {
589             // No `.emit()` or `.cancel()` calls.
590             DiagnosticBuilderState::Emittable(handler) => {
591                 if !panicking() {
592                     handler.emit_diagnostic(&mut Diagnostic::new(
593                         Level::Bug,
594                         DiagnosticMessage::Str(
595                             "the following error was constructed but not emitted".to_string(),
596                         ),
597                     ));
598                     handler.emit_diagnostic(&mut self.diagnostic);
599                     panic!("error was constructed but not emitted");
600                 }
601             }
602             // `.emit()` was previously called, or maybe we're during `.cancel()`.
603             DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {}
604         }
605     }
606 }
607
608 #[macro_export]
609 macro_rules! struct_span_err {
610     ($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
611         $session.struct_span_err_with_code(
612             $span,
613             &format!($($message)*),
614             $crate::error_code!($code),
615         )
616     })
617 }
618
619 #[macro_export]
620 macro_rules! error_code {
621     ($code:ident) => {{ $crate::DiagnosticId::Error(stringify!($code).to_owned()) }};
622 }
623
624 /// Wrapper around a `DiagnosticBuilder` for creating lints.
625 pub struct LintDiagnosticBuilder<'a, G: EmissionGuarantee>(DiagnosticBuilder<'a, G>);
626
627 impl<'a, G: EmissionGuarantee> LintDiagnosticBuilder<'a, G> {
628     #[rustc_lint_diagnostics]
629     /// Return the inner `DiagnosticBuilder`, first setting the primary message to `msg`.
630     pub fn build(mut self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'a, G> {
631         self.0.set_primary_message(msg);
632         self.0.set_is_lint();
633         self.0
634     }
635
636     /// Create a `LintDiagnosticBuilder` from some existing `DiagnosticBuilder`.
637     pub fn new(err: DiagnosticBuilder<'a, G>) -> LintDiagnosticBuilder<'a, G> {
638         LintDiagnosticBuilder(err)
639     }
640 }
641
642 impl<'a> LintDiagnosticBuilder<'a, ErrorGuaranteed> {
643     pub fn forget_guarantee(self) -> LintDiagnosticBuilder<'a, ()> {
644         LintDiagnosticBuilder(self.0.forget_guarantee())
645     }
646 }