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