@@ -17,7 +17,7 @@ use rustc_errors::emitter::Emitter;
1717use rustc_errors:: translation:: Translate ;
1818use rustc_errors:: {
1919 DiagCtxt , DiagnosticArgMap , DiagnosticBuilder , DiagnosticMessage , ErrCode , FatalError ,
20- FluentBundle , Level , Style ,
20+ FluentBundle , Level , MultiSpan , Style ,
2121} ;
2222use rustc_fs_util:: link_or_copy;
2323use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
@@ -999,11 +999,28 @@ pub(crate) enum Message<B: WriteBackendMethods> {
999999/// process another codegen unit.
10001000pub struct CguMessage ;
10011001
1002+ // A cut-down version of `rustc_errors::Diagnostic` that impls `Send`, which
1003+ // can be used to send diagnostics from codegen threads to the main thread.
1004+ // It's missing the following fields from `rustc_errors::Diagnostic`.
1005+ // - `span`: because `MultiSpan` doesn't impl `Send`.
1006+ // - `suggestions`: because it doesn't impl `Send`, and is not worth the complexity.
1007+ // - `sort_span`: because `Span` doesn't impl `Send`.
1008+ // - `is_lint`: because lints aren't relevant during codegen.
1009+ // - `emitted_at`: not worth the complexity.
10021010struct Diagnostic {
1003- msgs : Vec < ( DiagnosticMessage , Style ) > ,
1004- args : DiagnosticArgMap ,
1011+ level : Level ,
1012+ messages : Vec < ( DiagnosticMessage , Style ) > ,
10051013 code : Option < ErrCode > ,
1006- lvl : Level ,
1014+ children : Vec < Subdiagnostic > ,
1015+ args : DiagnosticArgMap ,
1016+ }
1017+
1018+ // A cut-down version of `rustc_errors::SubDiagnostic` that impls `Send`. It's
1019+ // missing the following fields from `rustc_errors::SubDiagnostic`.
1020+ // - `span`: because `MultiSpan` doesn't impl `Send`.
1021+ pub struct Subdiagnostic {
1022+ level : Level ,
1023+ messages : Vec < ( DiagnosticMessage , Style ) > ,
10071024}
10081025
10091026#[ derive( PartialEq , Clone , Copy , Debug ) ]
@@ -1812,23 +1829,29 @@ impl Translate for SharedEmitter {
18121829}
18131830
18141831impl Emitter for SharedEmitter {
1815- fn emit_diagnostic ( & mut self , diag : rustc_errors:: Diagnostic ) {
1816- let args: DiagnosticArgMap =
1817- diag. args . iter ( ) . map ( |( name, arg) | ( name. clone ( ) , arg. clone ( ) ) ) . collect ( ) ;
1818- drop ( self . sender . send ( SharedEmitterMessage :: Diagnostic ( Diagnostic {
1819- msgs : diag. messages . clone ( ) ,
1820- args : args. clone ( ) ,
1821- code : diag. code ,
1822- lvl : diag. level ( ) ,
1823- } ) ) ) ;
1824- for child in & diag. children {
1825- drop ( self . sender . send ( SharedEmitterMessage :: Diagnostic ( Diagnostic {
1826- msgs : child. messages . clone ( ) ,
1827- args : args. clone ( ) ,
1828- code : None ,
1829- lvl : child. level ,
1830- } ) ) ) ;
1831- }
1832+ fn emit_diagnostic ( & mut self , mut diag : rustc_errors:: Diagnostic ) {
1833+ // Check that we aren't missing anything interesting when converting to
1834+ // the cut-down local `Diagnostic`.
1835+ assert_eq ! ( diag. span, MultiSpan :: new( ) ) ;
1836+ assert_eq ! ( diag. suggestions, Ok ( vec![ ] ) ) ;
1837+ assert_eq ! ( diag. sort_span, rustc_span:: DUMMY_SP ) ;
1838+ assert_eq ! ( diag. is_lint, None ) ;
1839+ // No sensible check for `diag.emitted_at`.
1840+
1841+ let args = mem:: replace ( & mut diag. args , DiagnosticArgMap :: default ( ) ) ;
1842+ drop (
1843+ self . sender . send ( SharedEmitterMessage :: Diagnostic ( Diagnostic {
1844+ level : diag. level ( ) ,
1845+ messages : diag. messages ,
1846+ code : diag. code ,
1847+ children : diag
1848+ . children
1849+ . into_iter ( )
1850+ . map ( |child| Subdiagnostic { level : child. level , messages : child. messages } )
1851+ . collect ( ) ,
1852+ args,
1853+ } ) ) ,
1854+ ) ;
18321855 drop ( self . sender . send ( SharedEmitterMessage :: AbortIfErrors ) ) ;
18331856 }
18341857
@@ -1854,11 +1877,21 @@ impl SharedEmitterMain {
18541877
18551878 match message {
18561879 Ok ( SharedEmitterMessage :: Diagnostic ( diag) ) => {
1880+ // The diagnostic has been received on the main thread.
1881+ // Convert it back to a full `Diagnostic` and emit.
18571882 let dcx = sess. dcx ( ) ;
1858- let mut d = rustc_errors:: Diagnostic :: new_with_messages ( diag. lvl , diag. msgs ) ;
1859- if let Some ( code) = diag. code {
1860- d. code ( code) ;
1861- }
1883+ let mut d =
1884+ rustc_errors:: Diagnostic :: new_with_messages ( diag. level , diag. messages ) ;
1885+ d. code = diag. code ;
1886+ d. children = diag
1887+ . children
1888+ . into_iter ( )
1889+ . map ( |sub| rustc_errors:: SubDiagnostic {
1890+ level : sub. level ,
1891+ messages : sub. messages ,
1892+ span : MultiSpan :: new ( ) ,
1893+ } )
1894+ . collect ( ) ;
18621895 d. args = diag. args ;
18631896 dcx. emit_diagnostic ( d) ;
18641897 }
0 commit comments