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