3
3
//! This module contains the code for creating and emitting diagnostics.
4
4
5
5
#![ doc( html_root_url = "https://doc.rust-lang.org/nightly/" ) ]
6
-
7
6
#![ feature( crate_visibility_modifier) ]
8
7
#![ cfg_attr( unix, feature( libc) ) ]
9
8
#![ feature( nll) ]
10
9
#![ feature( optin_builtin_traits) ]
11
10
12
11
pub use emitter:: ColorConfig ;
13
12
13
+ use log:: debug;
14
14
use Level :: * ;
15
15
16
- use emitter:: { Emitter , EmitterWriter , is_case_difference } ;
16
+ use emitter:: { is_case_difference , Emitter , EmitterWriter } ;
17
17
use registry:: Registry ;
18
- use rustc_data_structures:: sync:: { self , Lrc , Lock } ;
19
18
use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap } ;
20
19
use rustc_data_structures:: stable_hasher:: StableHasher ;
20
+ use rustc_data_structures:: sync:: { self , Lock , Lrc } ;
21
21
use syntax_pos:: source_map:: SourceMap ;
22
- use syntax_pos:: { Loc , Span , MultiSpan } ;
22
+ use syntax_pos:: { Loc , MultiSpan , Span } ;
23
23
24
24
use std:: borrow:: Cow ;
25
25
use std:: cell:: Cell ;
26
- use std:: { error, fmt} ;
27
26
use std:: panic;
28
27
use std:: path:: Path ;
28
+ use std:: { error, fmt} ;
29
29
30
- use termcolor:: { ColorSpec , Color } ;
30
+ use termcolor:: { Color , ColorSpec } ;
31
31
32
+ pub mod annotate_snippet_emitter_writer;
32
33
mod diagnostic;
33
34
mod diagnostic_builder;
34
35
pub mod emitter;
35
- pub mod annotate_snippet_emitter_writer ;
36
- mod snippet ;
36
+ pub mod json ;
37
+ mod lock ;
37
38
pub mod registry;
39
+ mod snippet;
38
40
mod styled_buffer;
39
- mod lock;
40
- pub mod json;
41
41
pub use snippet:: Style ;
42
42
43
43
pub type PResult < ' a , T > = Result < T , DiagnosticBuilder < ' a > > ;
@@ -146,16 +146,15 @@ pub struct SubstitutionPart {
146
146
impl CodeSuggestion {
147
147
/// Returns the assembled code suggestions, whether they should be shown with an underline
148
148
/// 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 ) > {
153
150
use syntax_pos:: { CharPos , Pos } ;
154
151
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
+ ) {
159
158
let ( lo, hi_opt) = ( lo. col . to_usize ( ) , hi_opt. map ( |hi| hi. col . to_usize ( ) ) ) ;
160
159
if let Some ( line) = line_opt {
161
160
if let Some ( lo) = line. char_indices ( ) . map ( |( i, _) | i) . nth ( lo) {
@@ -174,67 +173,80 @@ impl CodeSuggestion {
174
173
175
174
assert ! ( !self . substitutions. is_empty( ) ) ;
176
175
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] ) ;
216
232
}
217
233
}
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 ) ;
222
237
}
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 ( )
238
250
}
239
251
}
240
252
@@ -257,7 +269,7 @@ impl error::Error for ExplicitBug {
257
269
}
258
270
}
259
271
260
- pub use diagnostic:: { Diagnostic , SubDiagnostic , DiagnosticStyledString , DiagnosticId } ;
272
+ pub use diagnostic:: { Diagnostic , DiagnosticId , DiagnosticStyledString , SubDiagnostic } ;
261
273
pub use diagnostic_builder:: DiagnosticBuilder ;
262
274
263
275
/// A handler deals with errors and other compiler output.
@@ -360,11 +372,7 @@ impl Handler {
360
372
Self :: with_tty_emitter_and_flags (
361
373
color_config,
362
374
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 ( ) } ,
368
376
)
369
377
}
370
378
@@ -391,17 +399,13 @@ impl Handler {
391
399
) -> Self {
392
400
Handler :: with_emitter_and_flags (
393
401
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 ( ) } ,
399
403
)
400
404
}
401
405
402
406
pub fn with_emitter_and_flags (
403
407
emitter : Box < dyn Emitter + sync:: Send > ,
404
- flags : HandlerFlags
408
+ flags : HandlerFlags ,
405
409
) -> Self {
406
410
Self {
407
411
flags,
@@ -457,7 +461,10 @@ impl Handler {
457
461
old_diag. level = Bug ;
458
462
old_diag. note ( & format ! (
459
463
"{}:{}: already existing stashed diagnostic with (span = {:?}, key = {:?})" ,
460
- file!( ) , line!( ) , span, key
464
+ file!( ) ,
465
+ line!( ) ,
466
+ span,
467
+ key
461
468
) ) ;
462
469
inner. emit_diag_at_span ( old_diag, span) ;
463
470
panic ! ( ExplicitBug ) ;
@@ -779,7 +786,7 @@ impl HandlerInner {
779
786
let s = match self . deduplicated_err_count {
780
787
0 => return ,
781
788
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) ,
783
790
} ;
784
791
if self . treat_err_as_bug ( ) {
785
792
return ;
@@ -804,16 +811,22 @@ impl HandlerInner {
804
811
error_codes. sort ( ) ;
805
812
if error_codes. len ( ) > 1 {
806
813
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 \
811
821
`rustc --explain {}`.",
812
- & error_codes[ 0 ] ) ) ;
822
+ & error_codes[ 0 ]
823
+ ) ) ;
813
824
} else {
814
- self . failure ( & format ! ( "For more information about this error, try \
825
+ self . failure ( & format ! (
826
+ "For more information about this error, try \
815
827
`rustc --explain {}`.",
816
- & error_codes[ 0 ] ) ) ;
828
+ & error_codes[ 0 ]
829
+ ) ) ;
817
830
}
818
831
}
819
832
}
@@ -880,7 +893,7 @@ impl HandlerInner {
880
893
}
881
894
882
895
/// 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 ) {
884
897
if self . treat_err_as_bug ( ) {
885
898
self . bug ( msg) ;
886
899
}
@@ -910,13 +923,10 @@ impl HandlerInner {
910
923
( 0 , _) => return ,
911
924
( 1 , 1 ) => "aborting due to `-Z treat-err-as-bug=1`" . to_string ( ) ,
912
925
( 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
+ ) ,
920
930
} ;
921
931
panic ! ( s) ;
922
932
}
@@ -946,20 +956,16 @@ impl Level {
946
956
let mut spec = ColorSpec :: new ( ) ;
947
957
match self {
948
958
Bug | Fatal | Error => {
949
- spec. set_fg ( Some ( Color :: Red ) )
950
- . set_intense ( true ) ;
959
+ spec. set_fg ( Some ( Color :: Red ) ) . set_intense ( true ) ;
951
960
}
952
961
Warning => {
953
- spec. set_fg ( Some ( Color :: Yellow ) )
954
- . set_intense ( cfg ! ( windows) ) ;
962
+ spec. set_fg ( Some ( Color :: Yellow ) ) . set_intense ( cfg ! ( windows) ) ;
955
963
}
956
964
Note => {
957
- spec. set_fg ( Some ( Color :: Green ) )
958
- . set_intense ( true ) ;
965
+ spec. set_fg ( Some ( Color :: Green ) ) . set_intense ( true ) ;
959
966
}
960
967
Help => {
961
- spec. set_fg ( Some ( Color :: Cyan ) )
962
- . set_intense ( true ) ;
968
+ spec. set_fg ( Some ( Color :: Cyan ) ) . set_intense ( true ) ;
963
969
}
964
970
FailureNote => { }
965
971
Cancelled => unreachable ! ( ) ,
0 commit comments