@@ -17,7 +17,7 @@ use emitter::{Emitter, EmitterWriter};
1717use registry:: Registry ;
1818
1919use rustc_data_structures:: sync:: { self , Lrc , Lock } ;
20- use rustc_data_structures:: fx:: FxHashSet ;
20+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
2121use rustc_data_structures:: stable_hasher:: StableHasher ;
2222
2323use std:: borrow:: Cow ;
@@ -326,6 +326,18 @@ struct HandlerInner {
326326 /// this handler. These hashes is used to avoid emitting the same error
327327 /// twice.
328328 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 ,
329341}
330342
331343fn default_track_diagnostic ( _: & Diagnostic ) { }
@@ -354,7 +366,9 @@ pub struct HandlerFlags {
354366
355367impl Drop for HandlerInner {
356368 fn drop ( & mut self ) {
357- if self . err_count == 0 {
369+ self . emit_stashed_diagnostics ( ) ;
370+
371+ if !self . has_errors ( ) {
358372 let bugs = std:: mem:: replace ( & mut self . delayed_span_bugs , Vec :: new ( ) ) ;
359373 let has_bugs = !bugs. is_empty ( ) ;
360374 for bug in bugs {
@@ -419,6 +433,7 @@ impl Handler {
419433 taught_diagnostics : Default :: default ( ) ,
420434 emitted_diagnostic_codes : Default :: default ( ) ,
421435 emitted_diagnostics : Default :: default ( ) ,
436+ stashed_diagnostics : Default :: default ( ) ,
422437 } ) ,
423438 }
424439 }
@@ -445,6 +460,31 @@ impl Handler {
445460 inner. emitted_diagnostics = Default :: default ( ) ;
446461 inner. deduplicated_err_count = 0 ;
447462 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 ( ) ;
448488 }
449489
450490 pub fn struct_dummy ( & self ) -> DiagnosticBuilder < ' _ > {
@@ -617,23 +657,23 @@ impl Handler {
617657 }
618658
619659 pub fn err_count ( & self ) -> usize {
620- self . inner . borrow ( ) . err_count
660+ self . inner . borrow ( ) . err_count ( )
621661 }
622662
623663 pub fn has_errors ( & self ) -> bool {
624- self . err_count ( ) > 0
664+ self . inner . borrow ( ) . has_errors ( )
625665 }
626666
627667 pub fn print_error_count ( & self , registry : & Registry ) {
628668 self . inner . borrow_mut ( ) . print_error_count ( registry)
629669 }
630670
631671 pub fn abort_if_errors ( & self ) {
632- self . inner . borrow ( ) . abort_if_errors ( )
672+ self . inner . borrow_mut ( ) . abort_if_errors ( )
633673 }
634674
635675 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 ( )
637677 }
638678
639679 pub fn must_teach ( & self , code : & DiagnosticId ) -> bool {
@@ -671,6 +711,12 @@ impl HandlerInner {
671711 self . emitter . emit_diagnostic ( & db) ;
672712 }
673713
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+
674720 fn emit_diagnostic ( & mut self , diagnostic : & Diagnostic ) {
675721 if diagnostic. cancelled ( ) {
676722 return ;
@@ -713,10 +759,12 @@ impl HandlerInner {
713759 }
714760
715761 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 )
717763 }
718764
719765 fn print_error_count ( & mut self , registry : & Registry ) {
766+ self . emit_stashed_diagnostics ( ) ;
767+
720768 let s = match self . deduplicated_err_count {
721769 0 => return ,
722770 1 => "aborting due to previous error" . to_string ( ) ,
@@ -760,14 +808,26 @@ impl HandlerInner {
760808 }
761809 }
762810
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 {
765823 FatalError . raise ( ) ;
766824 }
767825 }
768826
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 ( ) {
771831 FatalError . raise ( ) ;
772832 }
773833 }
@@ -826,7 +886,7 @@ impl HandlerInner {
826886
827887 fn panic_if_treat_err_as_bug ( & self ) {
828888 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 ) ) {
830890 ( 0 , _) => return ,
831891 ( 1 , 1 ) => "aborting due to `-Z treat-err-as-bug=1`" . to_string ( ) ,
832892 ( 1 , _) => return ,
0 commit comments