Skip to content

Commit 9935c83

Browse files
Avoid panics bubbling out to proc macros
Currently, rustc can emit a FatalError diagnostic during parsing of literals and tokenstreams. These are handled under the hood as a panic, which means that proc-macro code needed to catch_unwind if it wanted to fallibly parse some code. These still emit diagnostics, so in practice this isn't a full fix, but it at least makes the interface on the macro side a bit more uniform. This is primarily motivated by wasm proc macros which can't use catch_unwind and so this lets the test's output be the same with and without them.
1 parent 9030e34 commit 9935c83

3 files changed

Lines changed: 61 additions & 58 deletions

File tree

compiler/rustc_expand/src/proc_macro_server.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -490,9 +490,11 @@ impl server::Server for Rustc<'_, '_> {
490490
fn literal_from_str(&mut self, s: &str) -> Result<Literal<Self::Span, Self::Symbol>, String> {
491491
let name = FileName::proc_macro_source_code(s);
492492

493-
let mut parser =
493+
let mut parser = rustc_errors::catch_fatal_errors(|| {
494494
new_parser_from_source_str(self.psess(), name, s.to_owned(), StripTokens::Nothing)
495-
.map_err(cancel_diags_into_string)?;
495+
})
496+
.map_err(|_| String::from("failed to parse to literal"))?
497+
.map_err(cancel_diags_into_string)?;
496498

497499
let first_span = parser.token.span.data();
498500
let minus_present = parser.eat(exp!(Minus));
@@ -569,12 +571,15 @@ impl server::Server for Rustc<'_, '_> {
569571
}
570572

571573
fn ts_from_str(&mut self, src: &str) -> Result<Self::TokenStream, String> {
572-
source_str_to_stream(
573-
self.psess(),
574-
FileName::proc_macro_source_code(src),
575-
src.to_string(),
576-
Some(self.call_site),
577-
)
574+
rustc_errors::catch_fatal_errors(|| {
575+
source_str_to_stream(
576+
self.psess(),
577+
FileName::proc_macro_source_code(src),
578+
src.to_string(),
579+
Some(self.call_site),
580+
)
581+
})
582+
.map_err(|_| String::from("failed to parse to tokenstream"))?
578583
.map_err(cancel_diags_into_string)
579584
}
580585

tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ enum Mode {
1212
NormalOk,
1313
NormalErr,
1414
OtherError,
15-
OtherWithPanic,
1615
}
1716

1817
fn parse<T>(s: &str, mode: Mode)
@@ -33,11 +32,6 @@ where
3332
OtherError => {
3433
println!("{:?}", T::from_str(s));
3534
}
36-
OtherWithPanic => {
37-
if catch_unwind(|| println!("{:?}", T::from_str(s))).is_ok() {
38-
eprintln!("{s} did not panic");
39-
}
40-
}
4135
}
4236
}
4337

@@ -126,7 +120,7 @@ pub fn run() {
126120

127121
for parse in [stream as fn(&str, Mode), lit] {
128122
// emits diagnostic(s), then panics
129-
parse("r#", OtherWithPanic);
123+
parse("r#", OtherError);
130124

131125
// emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. })
132126
parse("0b2", OtherError);
@@ -137,7 +131,7 @@ pub fn run() {
137131
"'
138132
'", OtherError,
139133
);
140-
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherWithPanic);
134+
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherError);
141135

142136
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
143137
parse("/*a*/ 0b2 //", OtherError);
Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: #44 bytes(361..385) })
2-
Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: #44 bytes(361..385) })
3-
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) })
4-
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) })
5-
Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: #44 bytes(361..385) })
6-
Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: #44 bytes(361..385) })
7-
Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: #44 bytes(361..385) })
8-
Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: #44 bytes(361..385) })
9-
Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) })
10-
Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: #44 bytes(361..385) })
11-
Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: #44 bytes(361..385) }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) }])
12-
Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: #44 bytes(361..385) })
13-
Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: #44 bytes(361..385) })
14-
Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: #44 bytes(361..385) })
15-
Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: #44 bytes(361..385) })
16-
Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: #44 bytes(361..385) })
17-
Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: #44 bytes(361..385) })
18-
Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: #44 bytes(361..385) })
19-
Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: #44 bytes(361..385) })
20-
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) })
21-
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) })
22-
Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: #44 bytes(361..385) })
23-
Ok(TokenStream [Ident { ident: "fn", span: #44 bytes(361..385) }, Ident { ident: "main", span: #44 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #44 bytes(361..385) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "println", span: #44 bytes(361..385) }, Punct { ch: '!', spacing: Alone, span: #44 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [Literal { kind: Str, symbol: "Hello, world!", suffix: None, span: #44 bytes(361..385) }], span: #44 bytes(361..385) }], span: #44 bytes(361..385) }])
24-
Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #44 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #44 bytes(361..385) }, Ident { ident: "u8E", span: #44 bytes(361..385) }])
25-
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: #44 bytes(361..385) }])
26-
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: #44 bytes(361..385) }])
27-
Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #44 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #44 bytes(361..385) }, Ident { ident: "bu8", span: #44 bytes(361..385) }])
28-
Ok(TokenStream [Literal { kind: Integer, symbol: "3", suffix: None, span: #44 bytes(361..385) }, Literal { kind: Integer, symbol: "4", suffix: None, span: #44 bytes(361..385) }])
29-
Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: #44 bytes(361..385) }])
1+
Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: #40 bytes(361..385) })
2+
Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: #40 bytes(361..385) })
3+
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #40 bytes(361..385) })
4+
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #40 bytes(361..385) })
5+
Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: #40 bytes(361..385) })
6+
Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: #40 bytes(361..385) })
7+
Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: #40 bytes(361..385) })
8+
Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: #40 bytes(361..385) })
9+
Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #40 bytes(361..385) })
10+
Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: #40 bytes(361..385) })
11+
Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: #40 bytes(361..385) }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #40 bytes(361..385) }])
12+
Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: #40 bytes(361..385) })
13+
Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: #40 bytes(361..385) })
14+
Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: #40 bytes(361..385) })
15+
Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: #40 bytes(361..385) })
16+
Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: #40 bytes(361..385) })
17+
Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: #40 bytes(361..385) })
18+
Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: #40 bytes(361..385) })
19+
Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: #40 bytes(361..385) })
20+
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #40 bytes(361..385) })
21+
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #40 bytes(361..385) })
22+
Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: #40 bytes(361..385) })
23+
Ok(TokenStream [Ident { ident: "fn", span: #40 bytes(361..385) }, Ident { ident: "main", span: #40 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #40 bytes(361..385) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "println", span: #40 bytes(361..385) }, Punct { ch: '!', spacing: Alone, span: #40 bytes(361..385) }, Group { delimiter: Parenthesis, stream: TokenStream [Literal { kind: Str, symbol: "Hello, world!", suffix: None, span: #40 bytes(361..385) }], span: #40 bytes(361..385) }], span: #40 bytes(361..385) }])
24+
Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #40 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #40 bytes(361..385) }, Ident { ident: "u8E", span: #40 bytes(361..385) }])
25+
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: #40 bytes(361..385) }])
26+
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: #40 bytes(361..385) }])
27+
Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #40 bytes(361..385) }, Punct { ch: '.', spacing: Alone, span: #40 bytes(361..385) }, Ident { ident: "bu8", span: #40 bytes(361..385) }])
28+
Ok(TokenStream [Literal { kind: Integer, symbol: "3", suffix: None, span: #40 bytes(361..385) }, Literal { kind: Integer, symbol: "4", suffix: None, span: #40 bytes(361..385) }])
29+
Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: #40 bytes(361..385) }])
3030
Ok(TokenStream [])
3131
### ERRORS
3232
Err(LexError("comment or whitespace around literal"))
@@ -42,17 +42,21 @@ Err(LexError("unexpected closing delimiter: `)`"))
4242
Err(LexError("unexpected closing delimiter: `]`"))
4343
Err(LexError("not a literal"))
4444
Err(LexError("not a literal"))
45-
Ok(TokenStream [Ident { ident: "r", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }])
46-
Ok(TokenStream [Ident { ident: "c", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }])
47-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }])
48-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) }])
49-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) }])
50-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) }])
51-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) }])
52-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }])
53-
Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) })
54-
Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) })
55-
Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) })
56-
Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) })
57-
Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) })
45+
Ok(TokenStream [Ident { ident: "r", span: #40 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #40 bytes(361..385) }])
46+
Ok(TokenStream [Ident { ident: "c", span: #40 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #40 bytes(361..385) }])
47+
Err(LexError("failed to parse to tokenstream"))
48+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #40 bytes(361..385) }])
49+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #40 bytes(361..385) }])
50+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #40 bytes(361..385) }])
51+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #40 bytes(361..385) }])
52+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #40 bytes(361..385) }])
53+
Err(LexError("failed to parse to tokenstream"))
54+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #40 bytes(361..385) }])
55+
Err(LexError("failed to parse to literal"))
56+
Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #40 bytes(361..385) })
57+
Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #40 bytes(361..385) })
58+
Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #40 bytes(361..385) })
59+
Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #40 bytes(361..385) })
60+
Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #40 bytes(361..385) })
61+
Err(LexError("failed to parse to literal"))
5862
Err(LexError("comment or whitespace around literal"))

0 commit comments

Comments
 (0)