33//! This module contains the code for creating and emitting diagnostics.
44
55#![ doc( html_root_url = "https://doc.rust-lang.org/nightly/" ) ]
6-
76#![ feature( crate_visibility_modifier) ]
87#![ cfg_attr( unix, feature( libc) ) ]
98#![ feature( nll) ]
109#![ feature( optin_builtin_traits) ]
1110
1211pub use emitter:: ColorConfig ;
1312
13+ use log:: debug;
1414use Level :: * ;
1515
16- use emitter:: { Emitter , EmitterWriter , is_case_difference } ;
16+ use emitter:: { is_case_difference , Emitter , EmitterWriter } ;
1717use registry:: Registry ;
18- use rustc_data_structures:: sync:: { self , Lrc , Lock } ;
1918use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
2019use rustc_data_structures:: stable_hasher:: StableHasher ;
20+ use rustc_data_structures:: sync:: { self , Lock , Lrc } ;
2121use syntax_pos:: source_map:: SourceMap ;
22- use syntax_pos:: { Loc , Span , MultiSpan } ;
22+ use syntax_pos:: { Loc , MultiSpan , Span } ;
2323
2424use std:: borrow:: Cow ;
2525use std:: cell:: Cell ;
26- use std:: { error, fmt} ;
2726use std:: panic;
2827use std:: path:: Path ;
28+ use std:: { error, fmt} ;
2929
30- use termcolor:: { ColorSpec , Color } ;
30+ use termcolor:: { Color , ColorSpec } ;
3131
32+ pub mod annotate_snippet_emitter_writer;
3233mod diagnostic;
3334mod diagnostic_builder;
3435pub mod emitter;
35- pub mod annotate_snippet_emitter_writer ;
36- mod snippet ;
36+ pub mod json ;
37+ mod lock ;
3738pub mod registry;
39+ mod snippet;
3840mod styled_buffer;
39- mod lock;
40- pub mod json;
4141pub use snippet:: Style ;
4242
4343pub type PResult < ' a , T > = Result < T , DiagnosticBuilder < ' a > > ;
@@ -146,16 +146,15 @@ pub struct SubstitutionPart {
146146impl CodeSuggestion {
147147 /// Returns the assembled code suggestions, whether they should be shown with an underline
148148 /// and whether the substitution only differs in capitalization.
149- pub fn splice_lines (
150- & self ,
151- cm : & SourceMap ,
152- ) -> Vec < ( String , Vec < SubstitutionPart > , bool ) > {
149+ pub fn splice_lines ( & self , cm : & SourceMap ) -> Vec < ( String , Vec < SubstitutionPart > , bool ) > {
153150 use syntax_pos:: { CharPos , Pos } ;
154151
155- fn push_trailing ( buf : & mut String ,
156- line_opt : Option < & Cow < ' _ , str > > ,
157- lo : & Loc ,
158- hi_opt : Option < & Loc > ) {
152+ fn push_trailing (
153+ buf : & mut String ,
154+ line_opt : Option < & Cow < ' _ , str > > ,
155+ lo : & Loc ,
156+ hi_opt : Option < & Loc > ,
157+ ) {
159158 let ( lo, hi_opt) = ( lo. col . to_usize ( ) , hi_opt. map ( |hi| hi. col . to_usize ( ) ) ) ;
160159 if let Some ( line) = line_opt {
161160 if let Some ( lo) = line. char_indices ( ) . map ( |( i, _) | i) . nth ( lo) {
@@ -174,67 +173,80 @@ impl CodeSuggestion {
174173
175174 assert ! ( !self . substitutions. is_empty( ) ) ;
176175
177- self . substitutions . iter ( ) . cloned ( ) . map ( |mut substitution| {
178- // Assumption: all spans are in the same file, and all spans
179- // are disjoint. Sort in ascending order.
180- substitution. parts . sort_by_key ( |part| part. span . lo ( ) ) ;
181-
182- // Find the bounding span.
183- let lo = substitution. parts . iter ( ) . map ( |part| part. span . lo ( ) ) . min ( ) . unwrap ( ) ;
184- let hi = substitution. parts . iter ( ) . map ( |part| part. span . hi ( ) ) . max ( ) . unwrap ( ) ;
185- let bounding_span = Span :: with_root_ctxt ( lo, hi) ;
186- let lines = cm. span_to_lines ( bounding_span) . unwrap ( ) ;
187- assert ! ( !lines. lines. is_empty( ) ) ;
188-
189- // To build up the result, we do this for each span:
190- // - push the line segment trailing the previous span
191- // (at the beginning a "phantom" span pointing at the start of the line)
192- // - push lines between the previous and current span (if any)
193- // - if the previous and current span are not on the same line
194- // push the line segment leading up to the current span
195- // - splice in the span substitution
196- //
197- // Finally push the trailing line segment of the last span
198- let fm = & lines. file ;
199- let mut prev_hi = cm. lookup_char_pos ( bounding_span. lo ( ) ) ;
200- prev_hi. col = CharPos :: from_usize ( 0 ) ;
201-
202- let mut prev_line = fm. get_line ( lines. lines [ 0 ] . line_index ) ;
203- let mut buf = String :: new ( ) ;
204-
205- for part in & substitution. parts {
206- let cur_lo = cm. lookup_char_pos ( part. span . lo ( ) ) ;
207- if prev_hi. line == cur_lo. line {
208- push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, Some ( & cur_lo) ) ;
209- } else {
210- push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
211- // push lines between the previous and current span (if any)
212- for idx in prev_hi. line ..( cur_lo. line - 1 ) {
213- if let Some ( line) = fm. get_line ( idx) {
214- buf. push_str ( line. as_ref ( ) ) ;
215- buf. push ( '\n' ) ;
176+ self . substitutions
177+ . iter ( )
178+ . filter ( |subst| {
179+ // Suggestions coming from macros can have malformed spans. This is a heavy
180+ // handed approach to avoid ICEs by ignoring the suggestion outright.
181+ let invalid = subst. parts . iter ( ) . any ( |item| cm. is_valid_span ( item. span ) . is_err ( ) ) ;
182+ if invalid {
183+ debug ! ( "splice_lines: suggestion contains an invalid span: {:?}" , subst) ;
184+ }
185+ !invalid
186+ } )
187+ . cloned ( )
188+ . map ( |mut substitution| {
189+ // Assumption: all spans are in the same file, and all spans
190+ // are disjoint. Sort in ascending order.
191+ substitution. parts . sort_by_key ( |part| part. span . lo ( ) ) ;
192+
193+ // Find the bounding span.
194+ let lo = substitution. parts . iter ( ) . map ( |part| part. span . lo ( ) ) . min ( ) . unwrap ( ) ;
195+ let hi = substitution. parts . iter ( ) . map ( |part| part. span . hi ( ) ) . max ( ) . unwrap ( ) ;
196+ let bounding_span = Span :: with_root_ctxt ( lo, hi) ;
197+ let lines = cm. span_to_lines ( bounding_span) . unwrap ( ) ;
198+ assert ! ( !lines. lines. is_empty( ) ) ;
199+
200+ // To build up the result, we do this for each span:
201+ // - push the line segment trailing the previous span
202+ // (at the beginning a "phantom" span pointing at the start of the line)
203+ // - push lines between the previous and current span (if any)
204+ // - if the previous and current span are not on the same line
205+ // push the line segment leading up to the current span
206+ // - splice in the span substitution
207+ //
208+ // Finally push the trailing line segment of the last span
209+ let fm = & lines. file ;
210+ let mut prev_hi = cm. lookup_char_pos ( bounding_span. lo ( ) ) ;
211+ prev_hi. col = CharPos :: from_usize ( 0 ) ;
212+
213+ let mut prev_line = fm. get_line ( lines. lines [ 0 ] . line_index ) ;
214+ let mut buf = String :: new ( ) ;
215+
216+ for part in & substitution. parts {
217+ let cur_lo = cm. lookup_char_pos ( part. span . lo ( ) ) ;
218+ if prev_hi. line == cur_lo. line {
219+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, Some ( & cur_lo) ) ;
220+ } else {
221+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
222+ // push lines between the previous and current span (if any)
223+ for idx in prev_hi. line ..( cur_lo. line - 1 ) {
224+ if let Some ( line) = fm. get_line ( idx) {
225+ buf. push_str ( line. as_ref ( ) ) ;
226+ buf. push ( '\n' ) ;
227+ }
228+ }
229+ if let Some ( cur_line) = fm. get_line ( cur_lo. line - 1 ) {
230+ let end = std:: cmp:: min ( cur_line. len ( ) , cur_lo. col . to_usize ( ) ) ;
231+ buf. push_str ( & cur_line[ ..end] ) ;
216232 }
217233 }
218- if let Some ( cur_line) = fm. get_line ( cur_lo. line - 1 ) {
219- let end = std:: cmp:: min ( cur_line. len ( ) , cur_lo. col . to_usize ( ) ) ;
220- buf. push_str ( & cur_line[ ..end] ) ;
221- }
234+ buf. push_str ( & part. snippet ) ;
235+ prev_hi = cm. lookup_char_pos ( part. span . hi ( ) ) ;
236+ prev_line = fm. get_line ( prev_hi. line - 1 ) ;
222237 }
223- buf. push_str ( & part. snippet ) ;
224- prev_hi = cm. lookup_char_pos ( part. span . hi ( ) ) ;
225- prev_line = fm. get_line ( prev_hi. line - 1 ) ;
226- }
227- let only_capitalization = is_case_difference ( cm, & buf, bounding_span) ;
228- // if the replacement already ends with a newline, don't print the next line
229- if !buf. ends_with ( '\n' ) {
230- push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
231- }
232- // remove trailing newlines
233- while buf. ends_with ( '\n' ) {
234- buf. pop ( ) ;
235- }
236- ( buf, substitution. parts , only_capitalization)
237- } ) . collect ( )
238+ let only_capitalization = is_case_difference ( cm, & buf, bounding_span) ;
239+ // if the replacement already ends with a newline, don't print the next line
240+ if !buf. ends_with ( '\n' ) {
241+ push_trailing ( & mut buf, prev_line. as_ref ( ) , & prev_hi, None ) ;
242+ }
243+ // remove trailing newlines
244+ while buf. ends_with ( '\n' ) {
245+ buf. pop ( ) ;
246+ }
247+ ( buf, substitution. parts , only_capitalization)
248+ } )
249+ . collect ( )
238250 }
239251}
240252
@@ -257,7 +269,7 @@ impl error::Error for ExplicitBug {
257269 }
258270}
259271
260- pub use diagnostic:: { Diagnostic , SubDiagnostic , DiagnosticStyledString , DiagnosticId } ;
272+ pub use diagnostic:: { Diagnostic , DiagnosticId , DiagnosticStyledString , SubDiagnostic } ;
261273pub use diagnostic_builder:: DiagnosticBuilder ;
262274
263275/// A handler deals with errors and other compiler output.
@@ -360,11 +372,7 @@ impl Handler {
360372 Self :: with_tty_emitter_and_flags (
361373 color_config,
362374 cm,
363- HandlerFlags {
364- can_emit_warnings,
365- treat_err_as_bug,
366- .. Default :: default ( )
367- } ,
375+ HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default :: default ( ) } ,
368376 )
369377 }
370378
@@ -391,17 +399,13 @@ impl Handler {
391399 ) -> Self {
392400 Handler :: with_emitter_and_flags (
393401 emitter,
394- HandlerFlags {
395- can_emit_warnings,
396- treat_err_as_bug,
397- .. Default :: default ( )
398- } ,
402+ HandlerFlags { can_emit_warnings, treat_err_as_bug, ..Default :: default ( ) } ,
399403 )
400404 }
401405
402406 pub fn with_emitter_and_flags (
403407 emitter : Box < dyn Emitter + sync:: Send > ,
404- flags : HandlerFlags
408+ flags : HandlerFlags ,
405409 ) -> Self {
406410 Self {
407411 flags,
@@ -457,7 +461,10 @@ impl Handler {
457461 old_diag. level = Bug ;
458462 old_diag. note ( & format ! (
459463 "{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})" ,
460- file!( ) , line!( ) , span, key
464+ file!( ) ,
465+ line!( ) ,
466+ span,
467+ key
461468 ) ) ;
462469 inner. emit_diag_at_span ( old_diag, span) ;
463470 panic ! ( ExplicitBug ) ;
@@ -779,7 +786,7 @@ impl HandlerInner {
779786 let s = match self . deduplicated_err_count {
780787 0 => return ,
781788 1 => "aborting due to previous error" . to_string ( ) ,
782- count => format ! ( "aborting due to {} previous errors" , count)
789+ count => format ! ( "aborting due to {} previous errors" , count) ,
783790 } ;
784791 if self . treat_err_as_bug ( ) {
785792 return ;
@@ -804,16 +811,22 @@ impl HandlerInner {
804811 error_codes. sort ( ) ;
805812 if error_codes. len ( ) > 1 {
806813 let limit = if error_codes. len ( ) > 9 { 9 } else { error_codes. len ( ) } ;
807- self . failure ( & format ! ( "Some errors have detailed explanations: {}{}" ,
808- error_codes[ ..limit] . join( ", " ) ,
809- if error_codes. len( ) > 9 { "..." } else { "." } ) ) ;
810- self . failure ( & format ! ( "For more information about an error, try \
814+ self . failure ( & format ! (
815+ "Some errors have detailed explanations: {}{}" ,
816+ error_codes[ ..limit] . join( ", " ) ,
817+ if error_codes. len( ) > 9 { "..." } else { "." }
818+ ) ) ;
819+ self . failure ( & format ! (
820+ "For more information about an error, try \
811821 `rustc --explain {}`.",
812- & error_codes[ 0 ] ) ) ;
822+ & error_codes[ 0 ]
823+ ) ) ;
813824 } else {
814- self . failure ( & format ! ( "For more information about this error, try \
825+ self . failure ( & format ! (
826+ "For more information about this error, try \
815827 `rustc --explain {}`.",
816- & error_codes[ 0 ] ) ) ;
828+ & error_codes[ 0 ]
829+ ) ) ;
817830 }
818831 }
819832 }
@@ -880,7 +893,7 @@ impl HandlerInner {
880893 }
881894
882895 /// Emit an error; level should be `Error` or `Fatal`.
883- fn emit_error ( & mut self , level : Level , msg : & str , ) {
896+ fn emit_error ( & mut self , level : Level , msg : & str ) {
884897 if self . treat_err_as_bug ( ) {
885898 self . bug ( msg) ;
886899 }
@@ -910,13 +923,10 @@ impl HandlerInner {
910923 ( 0 , _) => return ,
911924 ( 1 , 1 ) => "aborting due to `-Z treat-err-as-bug=1`" . to_string ( ) ,
912925 ( 1 , _) => return ,
913- ( count, as_bug) => {
914- format ! (
915- "aborting after {} errors due to `-Z treat-err-as-bug={}`" ,
916- count,
917- as_bug,
918- )
919- }
926+ ( count, as_bug) => format ! (
927+ "aborting after {} errors due to `-Z treat-err-as-bug={}`" ,
928+ count, as_bug,
929+ ) ,
920930 } ;
921931 panic ! ( s) ;
922932 }
@@ -946,20 +956,16 @@ impl Level {
946956 let mut spec = ColorSpec :: new ( ) ;
947957 match self {
948958 Bug | Fatal | Error => {
949- spec. set_fg ( Some ( Color :: Red ) )
950- . set_intense ( true ) ;
959+ spec. set_fg ( Some ( Color :: Red ) ) . set_intense ( true ) ;
951960 }
952961 Warning => {
953- spec. set_fg ( Some ( Color :: Yellow ) )
954- . set_intense ( cfg ! ( windows) ) ;
962+ spec. set_fg ( Some ( Color :: Yellow ) ) . set_intense ( cfg ! ( windows) ) ;
955963 }
956964 Note => {
957- spec. set_fg ( Some ( Color :: Green ) )
958- . set_intense ( true ) ;
965+ spec. set_fg ( Some ( Color :: Green ) ) . set_intense ( true ) ;
959966 }
960967 Help => {
961- spec. set_fg ( Some ( Color :: Cyan ) )
962- . set_intense ( true ) ;
968+ spec. set_fg ( Some ( Color :: Cyan ) ) . set_intense ( true ) ;
963969 }
964970 FailureNote => { }
965971 Cancelled => unreachable ! ( ) ,
0 commit comments