@@ -724,7 +724,10 @@ impl EmitterWriter {
724724 }
725725 match write ! ( & mut self . dst, "\n " ) {
726726 Err ( e) => panic ! ( "failed to emit error: {}" , e) ,
727- _ => ( )
727+ _ => match self . dst . flush ( ) {
728+ Err ( e) => panic ! ( "failed to emit error: {}" , e) ,
729+ _ => ( )
730+ }
728731 }
729732 }
730733}
@@ -749,6 +752,21 @@ fn overlaps(a1: &Annotation, a2: &Annotation) -> bool {
749752fn emit_to_destination ( rendered_buffer : & Vec < Vec < StyledString > > ,
750753 lvl : & Level ,
751754 dst : & mut Destination ) -> io:: Result < ( ) > {
755+ use lock;
756+
757+ // In order to prevent error message interleaving, where multiple error lines get intermixed
758+ // when multiple compiler processes error simultaneously, we emit errors with additional
759+ // steps.
760+ //
761+ // On Unix systems, we write into a buffered terminal rather than directly to a terminal. When
762+ // the .flush() is called we take the buffer created from the buffered writes and write it at
763+ // one shot. Because the Unix systems use ANSI for the colors, which is a text-based styling
764+ // scheme, this buffered approach works and maintains the styling.
765+ //
766+ // On Windows, styling happens through calls to a terminal API. This prevents us from using the
767+ // same buffering approach. Instead, we use a global Windows mutex, which we acquire long
768+ // enough to output the full error message, then we release.
769+ let _buffer_lock = lock:: acquire_global_lock ( "rustc_errors" ) ;
752770 for line in rendered_buffer {
753771 for part in line {
754772 dst. apply_style ( lvl. clone ( ) , part. style ) ?;
@@ -757,6 +775,7 @@ fn emit_to_destination(rendered_buffer: &Vec<Vec<StyledString>>,
757775 }
758776 write ! ( dst, "\n " ) ?;
759777 }
778+ dst. flush ( ) ?;
760779 Ok ( ( ) )
761780}
762781
@@ -783,14 +802,74 @@ fn stderr_isatty() -> bool {
783802 }
784803}
785804
805+ pub type BufferedStderr = term:: Terminal < Output = BufferedWriter > + Send ;
806+
786807pub enum Destination {
787808 Terminal ( Box < term:: StderrTerminal > ) ,
809+ BufferedTerminal ( Box < BufferedStderr > ) ,
788810 Raw ( Box < Write + Send > ) ,
789811}
790812
813+ /// Buffered writer gives us a way on Unix to buffer up an entire error message before we output
814+ /// it. This helps to prevent interleaving of multiple error messages when multiple compiler
815+ /// processes error simultaneously
816+ pub struct BufferedWriter {
817+ buffer : Vec < u8 > ,
818+ }
819+
820+ impl BufferedWriter {
821+ // note: we use _new because the conditional compilation at its use site may make this
822+ // this function unused on some platforms
823+ fn _new ( ) -> BufferedWriter {
824+ BufferedWriter {
825+ buffer : vec ! [ ]
826+ }
827+ }
828+ }
829+
830+ impl Write for BufferedWriter {
831+ fn write ( & mut self , buf : & [ u8 ] ) -> io:: Result < usize > {
832+ for b in buf {
833+ self . buffer . push ( * b) ;
834+ }
835+ Ok ( buf. len ( ) )
836+ }
837+ fn flush ( & mut self ) -> io:: Result < ( ) > {
838+ let mut stderr = io:: stderr ( ) ;
839+ let result = ( || {
840+ stderr. write_all ( & self . buffer ) ?;
841+ stderr. flush ( )
842+ } ) ( ) ;
843+ self . buffer . clear ( ) ;
844+ result
845+ }
846+ }
847+
791848impl Destination {
849+ #[ cfg( not( windows) ) ]
850+ /// When not on Windows, prefer the buffered terminal so that we can buffer an entire error
851+ /// to be emitted at one time.
852+ fn from_stderr ( ) -> Destination {
853+ let stderr: Option < Box < BufferedStderr > > =
854+ term:: TerminfoTerminal :: new ( BufferedWriter :: _new ( ) )
855+ . map ( |t| Box :: new ( t) as Box < BufferedStderr > ) ;
856+
857+ match stderr {
858+ Some ( t) => BufferedTerminal ( t) ,
859+ None => Raw ( Box :: new ( io:: stderr ( ) ) ) ,
860+ }
861+ }
862+
863+ #[ cfg( windows) ]
864+ /// Return a normal, unbuffered terminal when on Windows.
792865 fn from_stderr ( ) -> Destination {
793- match term:: stderr ( ) {
866+ let stderr: Option < Box < term:: StderrTerminal > > =
867+ term:: TerminfoTerminal :: new ( io:: stderr ( ) )
868+ . map ( |t| Box :: new ( t) as Box < term:: StderrTerminal > )
869+ . or_else ( || term:: WinConsole :: new ( io:: stderr ( ) ) . ok ( )
870+ . map ( |t| Box :: new ( t) as Box < term:: StderrTerminal > ) ) ;
871+
872+ match stderr {
794873 Some ( t) => Terminal ( t) ,
795874 None => Raw ( Box :: new ( io:: stderr ( ) ) ) ,
796875 }
@@ -839,6 +918,7 @@ impl Destination {
839918 fn start_attr ( & mut self , attr : term:: Attr ) -> io:: Result < ( ) > {
840919 match * self {
841920 Terminal ( ref mut t) => { t. attr ( attr) ?; }
921+ BufferedTerminal ( ref mut t) => { t. attr ( attr) ?; }
842922 Raw ( _) => { }
843923 }
844924 Ok ( ( ) )
@@ -847,6 +927,7 @@ impl Destination {
847927 fn reset_attrs ( & mut self ) -> io:: Result < ( ) > {
848928 match * self {
849929 Terminal ( ref mut t) => { t. reset ( ) ?; }
930+ BufferedTerminal ( ref mut t) => { t. reset ( ) ?; }
850931 Raw ( _) => { }
851932 }
852933 Ok ( ( ) )
@@ -857,12 +938,14 @@ impl Write for Destination {
857938 fn write ( & mut self , bytes : & [ u8 ] ) -> io:: Result < usize > {
858939 match * self {
859940 Terminal ( ref mut t) => t. write ( bytes) ,
941+ BufferedTerminal ( ref mut t) => t. write ( bytes) ,
860942 Raw ( ref mut w) => w. write ( bytes) ,
861943 }
862944 }
863945 fn flush ( & mut self ) -> io:: Result < ( ) > {
864946 match * self {
865947 Terminal ( ref mut t) => t. flush ( ) ,
948+ BufferedTerminal ( ref mut t) => t. flush ( ) ,
866949 Raw ( ref mut w) => w. flush ( ) ,
867950 }
868951 }
0 commit comments