@@ -17,7 +17,7 @@ use rustc_errors::emitter::Emitter;
17
17
use rustc_errors:: translation:: Translate ;
18
18
use rustc_errors:: {
19
19
DiagCtxt , DiagnosticArgName , DiagnosticArgValue , DiagnosticBuilder , DiagnosticMessage , ErrCode ,
20
- FatalError , FluentBundle , Level , Style ,
20
+ FatalError , FluentBundle , Level , MultiSpan , Style ,
21
21
} ;
22
22
use rustc_fs_util:: link_or_copy;
23
23
use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
@@ -999,11 +999,28 @@ pub(crate) enum Message<B: WriteBackendMethods> {
999
999
/// process another codegen unit.
1000
1000
pub struct CguMessage ;
1001
1001
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.
1002
1010
struct Diagnostic {
1003
- msgs : Vec < ( DiagnosticMessage , Style ) > ,
1004
- args : FxHashMap < DiagnosticArgName , DiagnosticArgValue > ,
1011
+ level : Level ,
1012
+ messages : Vec < ( DiagnosticMessage , Style ) > ,
1005
1013
code : Option < ErrCode > ,
1006
- lvl : Level ,
1014
+ children : Vec < Subdiagnostic > ,
1015
+ args : FxHashMap < DiagnosticArgName , DiagnosticArgValue > ,
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 ) > ,
1007
1024
}
1008
1025
1009
1026
#[ derive( PartialEq , Clone , Copy , Debug ) ]
@@ -1812,23 +1829,29 @@ impl Translate for SharedEmitter {
1812
1829
}
1813
1830
1814
1831
impl Emitter for SharedEmitter {
1815
- fn emit_diagnostic ( & mut self , diag : rustc_errors:: Diagnostic ) {
1816
- let args: FxHashMap < DiagnosticArgName , DiagnosticArgValue > =
1817
- diag. args ( ) . 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 = diag. replace_args ( FxHashMap :: 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
+ ) ;
1832
1855
drop ( self . sender . send ( SharedEmitterMessage :: AbortIfErrors ) ) ;
1833
1856
}
1834
1857
@@ -1854,11 +1877,21 @@ impl SharedEmitterMain {
1854
1877
1855
1878
match message {
1856
1879
Ok ( SharedEmitterMessage :: Diagnostic ( diag) ) => {
1880
+ // The diagnostic has been received on the main thread.
1881
+ // Convert it back to a full `Diagnostic` and emit.
1857
1882
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 ( ) ;
1862
1895
d. replace_args ( diag. args ) ;
1863
1896
dcx. emit_diagnostic ( d) ;
1864
1897
}
0 commit comments