11use crate :: diagnostic:: IntoDiagnosticArg ;
22use crate :: {
33 Diagnostic , DiagnosticId , DiagnosticMessage , DiagnosticStyledString , ErrorGuaranteed ,
4- SubdiagnosticMessage ,
4+ ExplicitBug , SubdiagnosticMessage ,
55} ;
66use crate :: { Handler , Level , MultiSpan , StashKey } ;
77use rustc_lint_defs:: Applicability ;
@@ -12,6 +12,7 @@ use std::borrow::Cow;
1212use std:: fmt:: { self , Debug } ;
1313use std:: marker:: PhantomData ;
1414use std:: ops:: { Deref , DerefMut } ;
15+ use std:: panic;
1516use std:: thread:: panicking;
1617
1718/// Trait implemented by error types. This should not be implemented manually. Instead, use
@@ -308,6 +309,58 @@ impl EmissionGuarantee for Noted {
308309 }
309310}
310311
312+ /// Marker type which enables implementation of `create_bug` and `emit_bug` functions for
313+ /// bug struct diagnostics.
314+ #[ derive( Copy , Clone ) ]
315+ pub struct Bug ;
316+
317+ impl < ' a > DiagnosticBuilder < ' a , Bug > {
318+ /// Convenience function for internal use, clients should use one of the
319+ /// `struct_*` methods on [`Handler`].
320+ #[ track_caller]
321+ pub ( crate ) fn new_bug ( handler : & ' a Handler , message : impl Into < DiagnosticMessage > ) -> Self {
322+ let diagnostic = Diagnostic :: new_with_code ( Level :: Bug , None , message) ;
323+ Self :: new_diagnostic_bug ( handler, diagnostic)
324+ }
325+
326+ /// Creates a new `DiagnosticBuilder` with an already constructed
327+ /// diagnostic.
328+ pub ( crate ) fn new_diagnostic_bug ( handler : & ' a Handler , diagnostic : Diagnostic ) -> Self {
329+ debug ! ( "Created new diagnostic bug" ) ;
330+ Self {
331+ inner : DiagnosticBuilderInner {
332+ state : DiagnosticBuilderState :: Emittable ( handler) ,
333+ diagnostic : Box :: new ( diagnostic) ,
334+ } ,
335+ _marker : PhantomData ,
336+ }
337+ }
338+ }
339+
340+ impl EmissionGuarantee for Bug {
341+ fn diagnostic_builder_emit_producing_guarantee ( db : & mut DiagnosticBuilder < ' _ , Self > ) -> Self {
342+ match db. inner . state {
343+ // First `.emit()` call, the `&Handler` is still available.
344+ DiagnosticBuilderState :: Emittable ( handler) => {
345+ db. inner . state = DiagnosticBuilderState :: AlreadyEmittedOrDuringCancellation ;
346+
347+ handler. emit_diagnostic ( & mut db. inner . diagnostic ) ;
348+ }
349+ // `.emit()` was previously called, disallowed from repeating it.
350+ DiagnosticBuilderState :: AlreadyEmittedOrDuringCancellation => { }
351+ }
352+ // Then panic. No need to return the marker type.
353+ panic:: panic_any ( ExplicitBug ) ;
354+ }
355+
356+ fn make_diagnostic_builder (
357+ handler : & Handler ,
358+ msg : impl Into < DiagnosticMessage > ,
359+ ) -> DiagnosticBuilder < ' _ , Self > {
360+ DiagnosticBuilder :: new_bug ( handler, msg)
361+ }
362+ }
363+
311364impl < ' a > DiagnosticBuilder < ' a , !> {
312365 /// Convenience function for internal use, clients should use one of the
313366 /// `struct_*` methods on [`Handler`].
0 commit comments