@@ -33,6 +33,7 @@ use std::collections::HashMap;
33
33
use std:: fmt;
34
34
use std:: io:: { self , stdout, BufRead , Write } ;
35
35
use std:: iter:: repeat;
36
+ use std:: panic:: { catch_unwind, AssertUnwindSafe } ;
36
37
use std:: path:: PathBuf ;
37
38
use std:: rc:: Rc ;
38
39
use std:: time:: Duration ;
@@ -537,43 +538,48 @@ fn parse_input<'sess>(
537
538
input : Input ,
538
539
parse_session : & ' sess ParseSess ,
539
540
config : & Config ,
540
- ) -> Result < ast:: Crate , Option < DiagnosticBuilder < ' sess > > > {
541
- let result = match input {
542
- Input :: File ( file) => {
543
- let mut parser = parse:: new_parser_from_file ( parse_session, & file) ;
544
- parser. cfg_mods = false ;
545
- if config. skip_children ( ) {
546
- parser. recurse_into_file_modules = false ;
547
- }
548
- parser. parse_crate_mod ( )
549
- }
550
- Input :: Text ( text) => {
551
- let mut parser = parse:: new_parser_from_source_str (
552
- parse_session,
553
- FileName :: Custom ( "stdin" . to_owned ( ) ) ,
554
- text,
555
- ) ;
556
- parser. cfg_mods = false ;
557
- if config. skip_children ( ) {
558
- parser. recurse_into_file_modules = false ;
559
- }
560
- parser. parse_crate_mod ( )
561
- }
541
+ ) -> Result < ast:: Crate , ParseError < ' sess > > {
542
+ let mut parser = match input {
543
+ Input :: File ( file) => parse:: new_parser_from_file ( parse_session, & file) ,
544
+ Input :: Text ( text) => parse:: new_parser_from_source_str (
545
+ parse_session,
546
+ FileName :: Custom ( "stdin" . to_owned ( ) ) ,
547
+ text,
548
+ ) ,
562
549
} ;
563
550
551
+ parser. cfg_mods = false ;
552
+ if config. skip_children ( ) {
553
+ parser. recurse_into_file_modules = false ;
554
+ }
555
+
556
+ let mut parser = AssertUnwindSafe ( parser) ;
557
+ let result = catch_unwind ( move || parser. 0 . parse_crate_mod ( ) ) ;
558
+
564
559
match result {
565
- Ok ( c ) => {
560
+ Ok ( Ok ( c ) ) => {
566
561
if parse_session. span_diagnostic . has_errors ( ) {
567
562
// Bail out if the parser recovered from an error.
568
- Err ( None )
563
+ Err ( ParseError :: Recovered )
569
564
} else {
570
565
Ok ( c)
571
566
}
572
567
}
573
- Err ( e) => Err ( Some ( e) ) ,
568
+ Ok ( Err ( e) ) => Err ( ParseError :: Error ( e) ) ,
569
+ Err ( _) => Err ( ParseError :: Panic ) ,
574
570
}
575
571
}
576
572
573
+ /// All the ways that parsing can fail.
574
+ enum ParseError < ' sess > {
575
+ /// There was an error, but the parser recovered.
576
+ Recovered ,
577
+ /// There was an error (supplied) and parsing failed.
578
+ Error ( DiagnosticBuilder < ' sess > ) ,
579
+ /// The parser panicked.
580
+ Panic ,
581
+ }
582
+
577
583
/// Format the given snippet. The snippet is expected to be *complete* code.
578
584
/// When we cannot parse the given snippet, this function returns `None`.
579
585
pub fn format_snippet ( snippet : & str , config : & Config ) -> Option < String > {
@@ -682,9 +688,18 @@ pub fn format_input<T: Write>(
682
688
683
689
let krate = match parse_input ( input, & parse_session, config) {
684
690
Ok ( krate) => krate,
685
- Err ( diagnostic) => {
686
- if let Some ( mut diagnostic) = diagnostic {
687
- diagnostic. emit ( ) ;
691
+ Err ( err) => {
692
+ match err {
693
+ ParseError :: Error ( mut diagnostic) => diagnostic. emit ( ) ,
694
+ ParseError :: Panic => {
695
+ // Note that if you see this message and want more information,
696
+ // then go to `parse_input` and run the parse function without
697
+ // `catch_unwind` so rustfmt panics and you can get a backtrace.
698
+ should_emit_verbose ( & main_file, config, || {
699
+ println ! ( "The Rust parser panicked" )
700
+ } ) ;
701
+ }
702
+ ParseError :: Recovered => { }
688
703
}
689
704
summary. add_parsing_error ( ) ;
690
705
return Ok ( ( summary, FileMap :: new ( ) , FormatReport :: new ( ) ) ) ;
@@ -693,10 +708,6 @@ pub fn format_input<T: Write>(
693
708
694
709
summary. mark_parse_time ( ) ;
695
710
696
- if parse_session. span_diagnostic . has_errors ( ) {
697
- summary. add_parsing_error ( ) ;
698
- }
699
-
700
711
// Suppress error output after parsing.
701
712
let silent_emitter = Box :: new ( EmitterWriter :: new (
702
713
Box :: new ( Vec :: new ( ) ) ,
0 commit comments