@@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter};
17
17
use registry:: Registry ;
18
18
19
19
use rustc_data_structures:: sync:: { self , Lrc , Lock } ;
20
- use rustc_data_structures:: fx:: FxHashSet ;
20
+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
21
21
use rustc_data_structures:: stable_hasher:: StableHasher ;
22
22
23
23
use std:: borrow:: Cow ;
@@ -326,6 +326,18 @@ struct HandlerInner {
326
326
/// this handler. These hashes is used to avoid emitting the same error
327
327
/// twice.
328
328
emitted_diagnostics : FxHashSet < u128 > ,
329
+
330
+ /// Stashed diagnostics emitted in one stage of the compiler that may be
331
+ /// stolen by other stages (e.g. to improve them and add more information).
332
+ /// The stashed diagnostics count towards the total error count.
333
+ /// When `.abort_if_errors()` is called, these are also emitted.
334
+ stashed_diagnostics : FxIndexMap < ( Span , StashKey ) , Diagnostic > ,
335
+ }
336
+
337
+ /// A key denoting where from a diagnostic was stashed.
338
+ #[ derive( Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Debug ) ]
339
+ pub enum StashKey {
340
+ ItemNoType ,
329
341
}
330
342
331
343
fn default_track_diagnostic ( _: & Diagnostic ) { }
@@ -354,7 +366,9 @@ pub struct HandlerFlags {
354
366
355
367
impl Drop for HandlerInner {
356
368
fn drop ( & mut self ) {
357
- if self . err_count == 0 {
369
+ self . emit_stashed_diagnostics ( ) ;
370
+
371
+ if !self . has_errors ( ) {
358
372
let bugs = std:: mem:: replace ( & mut self . delayed_span_bugs , Vec :: new ( ) ) ;
359
373
let has_bugs = !bugs. is_empty ( ) ;
360
374
for bug in bugs {
@@ -419,6 +433,7 @@ impl Handler {
419
433
taught_diagnostics : Default :: default ( ) ,
420
434
emitted_diagnostic_codes : Default :: default ( ) ,
421
435
emitted_diagnostics : Default :: default ( ) ,
436
+ stashed_diagnostics : Default :: default ( ) ,
422
437
} ) ,
423
438
}
424
439
}
@@ -445,6 +460,31 @@ impl Handler {
445
460
inner. emitted_diagnostics = Default :: default ( ) ;
446
461
inner. deduplicated_err_count = 0 ;
447
462
inner. err_count = 0 ;
463
+ inner. stashed_diagnostics . clear ( ) ;
464
+ }
465
+
466
+ /// Stash a given diagnostic with the given `Span` and `StashKey` as the key for later stealing.
467
+ /// If the diagnostic with this `(span, key)` already exists, this will result in an ICE.
468
+ pub fn stash_diagnostic ( & self , span : Span , key : StashKey , diag : Diagnostic ) {
469
+ if let Some ( old) = self . inner . borrow_mut ( ) . stashed_diagnostics . insert ( ( span, key) , diag) {
470
+ // We are removing a previously stashed diagnostic which should not happen.
471
+ // Create a builder and drop it on the floor to get an ICE.
472
+ drop ( DiagnosticBuilder :: new_diagnostic ( self , old) ) ;
473
+ }
474
+ }
475
+
476
+ /// Steal a previously stashed diagnostic with the given `Span` and `StashKey` as the key.
477
+ pub fn steal_diagnostic ( & self , span : Span , key : StashKey ) -> Option < DiagnosticBuilder < ' _ > > {
478
+ self . inner
479
+ . borrow_mut ( )
480
+ . stashed_diagnostics
481
+ . remove ( & ( span, key) )
482
+ . map ( |diag| DiagnosticBuilder :: new_diagnostic ( self , diag) )
483
+ }
484
+
485
+ /// Emit all stashed diagnostics.
486
+ pub fn emit_stashed_diagnostics ( & self ) {
487
+ self . inner . borrow_mut ( ) . emit_stashed_diagnostics ( ) ;
448
488
}
449
489
450
490
pub fn struct_dummy ( & self ) -> DiagnosticBuilder < ' _ > {
@@ -617,23 +657,23 @@ impl Handler {
617
657
}
618
658
619
659
pub fn err_count ( & self ) -> usize {
620
- self . inner . borrow ( ) . err_count
660
+ self . inner . borrow ( ) . err_count ( )
621
661
}
622
662
623
663
pub fn has_errors ( & self ) -> bool {
624
- self . err_count ( ) > 0
664
+ self . inner . borrow ( ) . has_errors ( )
625
665
}
626
666
627
667
pub fn print_error_count ( & self , registry : & Registry ) {
628
668
self . inner . borrow_mut ( ) . print_error_count ( registry)
629
669
}
630
670
631
671
pub fn abort_if_errors ( & self ) {
632
- self . inner . borrow ( ) . abort_if_errors ( )
672
+ self . inner . borrow_mut ( ) . abort_if_errors ( )
633
673
}
634
674
635
675
pub fn abort_if_errors_and_should_abort ( & self ) {
636
- self . inner . borrow ( ) . abort_if_errors_and_should_abort ( )
676
+ self . inner . borrow_mut ( ) . abort_if_errors_and_should_abort ( )
637
677
}
638
678
639
679
pub fn must_teach ( & self , code : & DiagnosticId ) -> bool {
@@ -671,6 +711,12 @@ impl HandlerInner {
671
711
self . emitter . emit_diagnostic ( & db) ;
672
712
}
673
713
714
+ /// Emit all stashed diagnostics.
715
+ fn emit_stashed_diagnostics ( & mut self ) {
716
+ let diags = self . stashed_diagnostics . drain ( ..) . map ( |x| x. 1 ) . collect :: < Vec < _ > > ( ) ;
717
+ diags. iter ( ) . for_each ( |diag| self . emit_diagnostic ( diag) ) ;
718
+ }
719
+
674
720
fn emit_diagnostic ( & mut self , diagnostic : & Diagnostic ) {
675
721
if diagnostic. cancelled ( ) {
676
722
return ;
@@ -713,10 +759,12 @@ impl HandlerInner {
713
759
}
714
760
715
761
fn treat_err_as_bug ( & self ) -> bool {
716
- self . flags . treat_err_as_bug . map ( |c| self . err_count >= c) . unwrap_or ( false )
762
+ self . flags . treat_err_as_bug . map ( |c| self . err_count ( ) >= c) . unwrap_or ( false )
717
763
}
718
764
719
765
fn print_error_count ( & mut self , registry : & Registry ) {
766
+ self . emit_stashed_diagnostics ( ) ;
767
+
720
768
let s = match self . deduplicated_err_count {
721
769
0 => return ,
722
770
1 => "aborting due to previous error" . to_string ( ) ,
@@ -760,14 +808,26 @@ impl HandlerInner {
760
808
}
761
809
}
762
810
763
- fn abort_if_errors_and_should_abort ( & self ) {
764
- if self . err_count > 0 && !self . continue_after_error {
811
+ fn err_count ( & self ) -> usize {
812
+ self . err_count + self . stashed_diagnostics . len ( )
813
+ }
814
+
815
+ fn has_errors ( & self ) -> bool {
816
+ self . err_count ( ) > 0
817
+ }
818
+
819
+ fn abort_if_errors_and_should_abort ( & mut self ) {
820
+ self . emit_stashed_diagnostics ( ) ;
821
+
822
+ if self . has_errors ( ) && !self . continue_after_error {
765
823
FatalError . raise ( ) ;
766
824
}
767
825
}
768
826
769
- fn abort_if_errors ( & self ) {
770
- if self . err_count > 0 {
827
+ fn abort_if_errors ( & mut self ) {
828
+ self . emit_stashed_diagnostics ( ) ;
829
+
830
+ if self . has_errors ( ) {
771
831
FatalError . raise ( ) ;
772
832
}
773
833
}
@@ -826,7 +886,7 @@ impl HandlerInner {
826
886
827
887
fn panic_if_treat_err_as_bug ( & self ) {
828
888
if self . treat_err_as_bug ( ) {
829
- let s = match ( self . err_count , self . flags . treat_err_as_bug . unwrap_or ( 0 ) ) {
889
+ let s = match ( self . err_count ( ) , self . flags . treat_err_as_bug . unwrap_or ( 0 ) ) {
830
890
( 0 , _) => return ,
831
891
( 1 , 1 ) => "aborting due to `-Z treat-err-as-bug=1`" . to_string ( ) ,
832
892
( 1 , _) => return ,
0 commit comments