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