Skip to content

Commit 3dc45e1

Browse files
Rollup merge of #158256 - Mark-Simulacrum:no-panic-pm-parsing, r=bjorn3
Avoid parser 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. The long-term fix should be to get rid of those FatalErrors (and in general all diagnostics that actually get emitted out during parsing, not just returned), but this seems like a reasonable improvement in the meantime. 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. r? bjorn3
2 parents b674511 + a89705b commit 3dc45e1

4 files changed

Lines changed: 45 additions & 34 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: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ use proc_macro::*;
77
use self::Mode::*;
88

99
// FIXME: all cases should become `NormalOk` or `NormalErr`
10+
//
11+
// And .stderr should be empty (no diagnostics should get emitted from fallible parsing in the proc
12+
// macro).
1013
#[derive(PartialEq, Clone, Copy)]
1114
enum Mode {
1215
NormalOk,
1316
NormalErr,
1417
OtherError,
15-
OtherWithPanic,
1618
}
1719

1820
fn print_unspanned<T>(s: &str) -> Result<T, LexError>
@@ -43,12 +45,11 @@ where
4345
assert!(t.is_err());
4446
}
4547
OtherError => {
46-
print_unspanned::<T>(s);
47-
}
48-
OtherWithPanic => {
49-
if catch_unwind(|| print_unspanned::<T>(s)).is_ok() {
50-
eprintln!("{s} did not panic");
51-
}
48+
let t = print_unspanned::<T>(s);
49+
// For now we assert OK here, but in the future this should all move to NormalErr.
50+
// Any case that's failing this should go to NormalErr, probably after verifying that a
51+
// diagnostic did get emitted.
52+
assert!(t.is_ok());
5253
}
5354
}
5455
}
@@ -136,18 +137,18 @@ pub fn run() {
136137
// FIXME: all of the cases below should return an Err and emit no diagnostics, but don't yet.
137138

138139
// emits diagnostics and returns LexError
139-
lit("r'r'", OtherError);
140-
lit("c'r'", OtherError);
141-
lit("\u{2000}", OtherError);
140+
lit("r'r'", NormalErr);
141+
lit("c'r'", NormalErr);
142+
lit("\u{2000}", NormalErr);
142143

143144
// emits diagnostic and returns a seemingly valid tokenstream
144145
stream("r'r'", OtherError);
145146
stream("c'r'", OtherError);
146147
stream("\u{2000}", OtherError);
147148

148149
for parse in [stream as fn(&str, Mode), lit] {
149-
// emits diagnostic(s), then panics
150-
parse("r#", OtherWithPanic);
150+
// emits diagnostic(s), then returns LexError
151+
parse("r#", NormalErr);
151152

152153
// emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. })
153154
parse("0b2", OtherError);
@@ -158,9 +159,10 @@ pub fn run() {
158159
"'
159160
'", OtherError,
160161
);
161-
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherWithPanic);
162-
163-
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
164-
parse("/*a*/ 0b2 //", OtherError);
162+
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), NormalErr);
165163
}
164+
165+
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
166+
lit("/*a*/ 0b2 //", NormalErr);
167+
stream("/*a*/ 0b2 //", OtherError);
166168
}

tests/ui/proc-macro/nonfatal-parsing.stderr

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,15 +130,6 @@ LL | nonfatal_parsing::run!();
130130
|
131131
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
132132

133-
error: invalid digit for a base 2 literal
134-
--> $DIR/nonfatal-parsing.rs:15:5
135-
|
136-
LL | nonfatal_parsing::run!();
137-
| ^^^^^^^^^^^^^^^^^^^^^^^^
138-
|
139-
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
140-
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
141-
142133
error: found invalid character; only `#` is allowed in raw string delimitation: \u{0}
143134
--> <proc-macro source code>:1:1
144135
|
@@ -199,6 +190,15 @@ error: invalid digit for a base 2 literal
199190
LL | /*a*/ 0b2 //
200191
| ^
201192

193+
error: invalid digit for a base 2 literal
194+
--> $DIR/nonfatal-parsing.rs:15:5
195+
|
196+
LL | nonfatal_parsing::run!();
197+
| ^^^^^^^^^^^^^^^^^^^^^^^^
198+
|
199+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
200+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
201+
202202
error: aborting due to 22 previous errors
203203

204204
For more information about this error, try `rustc --explain E0768`.

tests/ui/proc-macro/nonfatal-parsing.stdout

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,19 @@ Err(LexError("not a literal"))
5252
Ok(TokenStream [Ident { ident: "r", span: Span }, Literal { kind: Char, symbol: "r", suffix: None, span: Span }])
5353
Ok(TokenStream [Ident { ident: "c", span: Span }, Literal { kind: Char, symbol: "r", suffix: None, span: Span }])
5454
Ok(TokenStream [])
55+
Err(LexError("failed to parse to tokenstream"))
5556
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }])
5657
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: Span }])
5758
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: Span }])
5859
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: Span }])
5960
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: Span }])
60-
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }])
61+
Err(LexError("failed to parse to tokenstream"))
62+
Err(LexError("failed to parse to literal"))
6163
Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span })
6264
Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: Span })
6365
Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: Span })
6466
Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: Span })
6567
Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: Span })
68+
Err(LexError("failed to parse to literal"))
6669
Err(LexError("comment or whitespace around literal"))
70+
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: Span }])

0 commit comments

Comments
 (0)