Skip to content

Commit c0e13c3

Browse files
authored
Rollup merge of rust-lang#148505 - cyrgani:pm-tests, r=madsmtm
add larger test for `proc_macro` `FromStr` implementations Currently, there are only few tests that check the output of `TokenStream::from_str` and `Literal::from_str` (which is somewhat understandable as the rustc implementation just delegates these calls to the parser). In preparation for both the standalone backend (rust-lang#130856) which will probably need to reimplement this logic as well as for removing panics from these functions (rust-lang#58736), this PR adds a test which shows the various messy ways of how these functions report errors and the return values for successful parses. Followup PRs such as rust-lang#147859 will change more and more of these "diagnostic + error"s into `LexErrors`. The test structure with the extra module is used to allow reusing it later easily for the standalone backend.
2 parents 518b428 + 7194c92 commit c0e13c3

File tree

5 files changed

+424
-0
lines changed

5 files changed

+424
-0
lines changed
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
use std::fmt::Debug;
2+
use std::panic::catch_unwind;
3+
use std::str::FromStr;
4+
5+
use proc_macro::*;
6+
7+
use self::Mode::*;
8+
9+
// FIXME: all cases should become `NormalOk` or `NormalErr`
10+
#[derive(PartialEq, Clone, Copy)]
11+
enum Mode {
12+
NormalOk,
13+
NormalErr,
14+
OtherError,
15+
OtherWithPanic,
16+
}
17+
18+
fn parse<T>(s: &str, mode: Mode)
19+
where
20+
T: FromStr<Err = LexError> + Debug,
21+
{
22+
match mode {
23+
NormalOk => {
24+
let t = T::from_str(s);
25+
println!("{:?}", t);
26+
assert!(t.is_ok());
27+
}
28+
NormalErr => {
29+
let t = T::from_str(s);
30+
println!("{:?}", t);
31+
assert!(t.is_err());
32+
}
33+
OtherError => {
34+
println!("{:?}", T::from_str(s));
35+
}
36+
OtherWithPanic => {
37+
if catch_unwind(|| println!("{:?}", T::from_str(s))).is_ok() {
38+
eprintln!("{s} did not panic");
39+
}
40+
}
41+
}
42+
}
43+
44+
fn stream(s: &str, mode: Mode) {
45+
parse::<TokenStream>(s, mode);
46+
}
47+
48+
fn lit(s: &str, mode: Mode) {
49+
parse::<Literal>(s, mode);
50+
if mode == NormalOk {
51+
let Ok(lit) = Literal::from_str(s) else {
52+
panic!("literal was not ok");
53+
};
54+
let Ok(stream) = TokenStream::from_str(s) else {
55+
panic!("tokenstream was not ok, but literal was");
56+
};
57+
let Some(tree) = stream.into_iter().next() else {
58+
panic!("tokenstream should have a tokentree");
59+
};
60+
if let TokenTree::Literal(tokenstream_lit) = tree {
61+
assert_eq!(lit.to_string(), tokenstream_lit.to_string());
62+
}
63+
}
64+
}
65+
66+
pub fn run() {
67+
// returns Ok(valid instance)
68+
lit("123", NormalOk);
69+
lit("\"ab\"", NormalOk);
70+
lit("\'b\'", NormalOk);
71+
lit("'b'", NormalOk);
72+
lit("b\"b\"", NormalOk);
73+
lit("c\"b\"", NormalOk);
74+
lit("cr\"b\"", NormalOk);
75+
lit("b'b'", NormalOk);
76+
lit("256u8", NormalOk);
77+
lit("-256u8", NormalOk);
78+
stream("-256u8", NormalOk);
79+
lit("0b11111000000001111i16", NormalOk);
80+
lit("0xf32", NormalOk);
81+
lit("0b0f32", NormalOk);
82+
lit("2E4", NormalOk);
83+
lit("2.2E-4f64", NormalOk);
84+
lit("18u8E", NormalOk);
85+
lit("18.0u8E", NormalOk);
86+
lit("cr#\"// /* // \n */\"#", NormalOk);
87+
lit("'\\''", NormalOk);
88+
lit("'\\\''", NormalOk);
89+
lit(&format!("r{0}\"a\"{0}", "#".repeat(255)), NormalOk);
90+
stream("fn main() { println!(\"Hello, world!\") }", NormalOk);
91+
stream("18.u8E", NormalOk);
92+
stream("18.0f32", NormalOk);
93+
stream("18.0f34", NormalOk);
94+
stream("18.bu8", NormalOk);
95+
stream("3//\n4", NormalOk);
96+
stream(
97+
"\'c\'/*\n
98+
*/",
99+
NormalOk,
100+
);
101+
stream("/*a*/ //", NormalOk);
102+
103+
println!("### ERRORS");
104+
105+
// returns Err(LexError)
106+
lit("\'c\'/**/", NormalErr);
107+
lit(" 0", NormalErr);
108+
lit("0 ", NormalErr);
109+
lit("0//", NormalErr);
110+
lit("3//\n4", NormalErr);
111+
lit("18.u8E", NormalErr);
112+
lit("/*a*/ //", NormalErr);
113+
// FIXME: all of the cases below should return an Err and emit no diagnostics, but don't yet.
114+
115+
// emits diagnostics and returns LexError
116+
lit("r'r'", OtherError);
117+
lit("c'r'", OtherError);
118+
119+
// emits diagnostic and returns a seemingly valid tokenstream
120+
stream("r'r'", OtherError);
121+
stream("c'r'", OtherError);
122+
123+
for parse in [stream as fn(&str, Mode), lit] {
124+
// emits diagnostic(s), then panics
125+
parse("1 ) 2", OtherWithPanic);
126+
parse("( x [ ) ]", OtherWithPanic);
127+
parse("r#", OtherWithPanic);
128+
129+
// emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. })
130+
parse("0b2", OtherError);
131+
parse("0bf32", OtherError);
132+
parse("0b0.0f32", OtherError);
133+
parse("'\''", OtherError);
134+
parse(
135+
"'
136+
'", OtherError,
137+
);
138+
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherWithPanic);
139+
140+
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
141+
parse("/*a*/ 0b2 //", OtherError);
142+
}
143+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
extern crate proc_macro;
2+
use proc_macro::*;
3+
4+
#[path = "nonfatal-parsing-body.rs"]
5+
mod body;
6+
7+
#[proc_macro]
8+
pub fn run(_: TokenStream) -> TokenStream {
9+
body::run();
10+
TokenStream::new()
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//@ proc-macro: nonfatal-parsing.rs
2+
//@ needs-unwind
3+
//@ edition: 2024
4+
//@ dont-require-annotations: ERROR
5+
//@ ignore-backends: gcc
6+
// FIXME: should be a run-pass test once invalidly parsed tokens no longer result in diagnostics
7+
8+
extern crate proc_macro;
9+
extern crate nonfatal_parsing;
10+
11+
#[path = "auxiliary/nonfatal-parsing-body.rs"]
12+
mod body;
13+
14+
fn main() {
15+
nonfatal_parsing::run!();
16+
// FIXME: enable this once the standalone backend exists
17+
// https://github.com/rust-lang/rust/issues/130856
18+
// body::run();
19+
}
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
error: prefix `r` is unknown
2+
--> <proc-macro source code>:1:1
3+
|
4+
LL | r'r'
5+
| ^ unknown prefix
6+
|
7+
= note: prefixed identifiers and literals are reserved since Rust 2021
8+
help: consider inserting whitespace here
9+
|
10+
LL | r 'r'
11+
| +
12+
13+
error: prefix `c` is unknown
14+
--> <proc-macro source code>:1:1
15+
|
16+
LL | c'r'
17+
| ^ unknown prefix
18+
|
19+
= note: prefixed identifiers and literals are reserved since Rust 2021
20+
help: consider inserting whitespace here
21+
|
22+
LL | c 'r'
23+
| +
24+
25+
error: unexpected closing delimiter: `)`
26+
--> $DIR/nonfatal-parsing.rs:15:5
27+
|
28+
LL | nonfatal_parsing::run!();
29+
| ^^^^^^^^^^^^^^^^^^^^^^^^ unexpected closing delimiter
30+
|
31+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
32+
33+
error: unexpected closing delimiter: `]`
34+
--> $DIR/nonfatal-parsing.rs:15:5
35+
|
36+
LL | nonfatal_parsing::run!();
37+
| -^^^^^^^^^^^^^^^^^^^^^^^
38+
| |
39+
| the nearest open delimiter
40+
| missing open `(` for this delimiter
41+
| unexpected closing delimiter
42+
|
43+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
44+
45+
error: found invalid character; only `#` is allowed in raw string delimitation: \u{0}
46+
--> $DIR/nonfatal-parsing.rs:15:5
47+
|
48+
LL | nonfatal_parsing::run!();
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^
50+
|
51+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
52+
53+
error: invalid digit for a base 2 literal
54+
--> $DIR/nonfatal-parsing.rs:15:5
55+
|
56+
LL | nonfatal_parsing::run!();
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^
58+
|
59+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
60+
61+
error[E0768]: no valid digits found for number
62+
--> $DIR/nonfatal-parsing.rs:15:5
63+
|
64+
LL | nonfatal_parsing::run!();
65+
| ^^^^^^^^^^^^^^^^^^^^^^^^
66+
|
67+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
68+
69+
error: binary float literal is not supported
70+
--> $DIR/nonfatal-parsing.rs:15:5
71+
|
72+
LL | nonfatal_parsing::run!();
73+
| ^^^^^^^^^^^^^^^^^^^^^^^^
74+
|
75+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
76+
77+
error: character constant must be escaped: `'`
78+
--> $DIR/nonfatal-parsing.rs:15:5
79+
|
80+
LL | nonfatal_parsing::run!();
81+
| ^^^^^^^^^^^^^^^^^^^^^^^^
82+
|
83+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
84+
help: escape the character
85+
|
86+
LL - nonfatal_parsing::run!();
87+
LL + nonfatal_parsing::run!(\';
88+
|
89+
90+
error: character constant must be escaped: `\n`
91+
--> $DIR/nonfatal-parsing.rs:15:5
92+
|
93+
LL | nonfatal_parsing::run!();
94+
| ^^^^^^^^^^^^^^^^^^^^^^^^
95+
|
96+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
97+
help: escape the character
98+
|
99+
LL - nonfatal_parsing::run!();
100+
LL + nonfatal_parsing::run!(\n;
101+
|
102+
103+
error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
104+
--> $DIR/nonfatal-parsing.rs:15:5
105+
|
106+
LL | nonfatal_parsing::run!();
107+
| ^^^^^^^^^^^^^^^^^^^^^^^^
108+
|
109+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
110+
111+
error: invalid digit for a base 2 literal
112+
--> $DIR/nonfatal-parsing.rs:15:5
113+
|
114+
LL | nonfatal_parsing::run!();
115+
| ^^^^^^^^^^^^^^^^^^^^^^^^
116+
|
117+
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
118+
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
119+
120+
error: unexpected closing delimiter: `)`
121+
--> <proc-macro source code>:1:3
122+
|
123+
LL | 1 ) 2
124+
| ^ unexpected closing delimiter
125+
126+
error: unexpected closing delimiter: `]`
127+
--> <proc-macro source code>:1:10
128+
|
129+
LL | ( x [ ) ]
130+
| - - ^ unexpected closing delimiter
131+
| | |
132+
| | missing open `(` for this delimiter
133+
| the nearest open delimiter
134+
135+
error: found invalid character; only `#` is allowed in raw string delimitation: \u{0}
136+
--> <proc-macro source code>:1:1
137+
|
138+
LL | r#
139+
| ^^
140+
141+
error: invalid digit for a base 2 literal
142+
--> <proc-macro source code>:1:3
143+
|
144+
LL | 0b2
145+
| ^
146+
147+
error[E0768]: no valid digits found for number
148+
--> <proc-macro source code>:1:1
149+
|
150+
LL | 0bf32
151+
| ^^
152+
153+
error: binary float literal is not supported
154+
--> <proc-macro source code>:1:1
155+
|
156+
LL | 0b0.0f32
157+
| ^^^^^
158+
159+
error: character constant must be escaped: `'`
160+
--> <proc-macro source code>:1:2
161+
|
162+
LL | '''
163+
| ^
164+
|
165+
help: escape the character
166+
|
167+
LL | '\''
168+
| +
169+
170+
error: character constant must be escaped: `\n`
171+
--> <proc-macro source code>:1:2
172+
|
173+
LL | '
174+
| __^
175+
LL | | '
176+
| |_^
177+
|
178+
help: escape the character
179+
|
180+
LL | '\n'
181+
| ++
182+
183+
error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
184+
--> <proc-macro source code>:1:1
185+
|
186+
LL | r#######################################...##################################################
187+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
188+
189+
error: invalid digit for a base 2 literal
190+
--> <proc-macro source code>:1:9
191+
|
192+
LL | /*a*/ 0b2 //
193+
| ^
194+
195+
error: aborting due to 22 previous errors
196+
197+
For more information about this error, try `rustc --explain E0768`.

0 commit comments

Comments
 (0)