mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-29 20:46:07 +03:00
Rollup merge of #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/rust#130856) which will probably need to reimplement this logic as well as for removing panics from these functions (rust-lang/rust#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/rust#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.
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
use std::fmt::Debug;
|
||||
use std::panic::catch_unwind;
|
||||
use std::str::FromStr;
|
||||
|
||||
use proc_macro::*;
|
||||
|
||||
use self::Mode::*;
|
||||
|
||||
// FIXME: all cases should become `NormalOk` or `NormalErr`
|
||||
#[derive(PartialEq, Clone, Copy)]
|
||||
enum Mode {
|
||||
NormalOk,
|
||||
NormalErr,
|
||||
OtherError,
|
||||
OtherWithPanic,
|
||||
}
|
||||
|
||||
fn parse<T>(s: &str, mode: Mode)
|
||||
where
|
||||
T: FromStr<Err = LexError> + Debug,
|
||||
{
|
||||
match mode {
|
||||
NormalOk => {
|
||||
let t = T::from_str(s);
|
||||
println!("{:?}", t);
|
||||
assert!(t.is_ok());
|
||||
}
|
||||
NormalErr => {
|
||||
let t = T::from_str(s);
|
||||
println!("{:?}", t);
|
||||
assert!(t.is_err());
|
||||
}
|
||||
OtherError => {
|
||||
println!("{:?}", T::from_str(s));
|
||||
}
|
||||
OtherWithPanic => {
|
||||
if catch_unwind(|| println!("{:?}", T::from_str(s))).is_ok() {
|
||||
eprintln!("{s} did not panic");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stream(s: &str, mode: Mode) {
|
||||
parse::<TokenStream>(s, mode);
|
||||
}
|
||||
|
||||
fn lit(s: &str, mode: Mode) {
|
||||
parse::<Literal>(s, mode);
|
||||
if mode == NormalOk {
|
||||
let Ok(lit) = Literal::from_str(s) else {
|
||||
panic!("literal was not ok");
|
||||
};
|
||||
let Ok(stream) = TokenStream::from_str(s) else {
|
||||
panic!("tokenstream was not ok, but literal was");
|
||||
};
|
||||
let Some(tree) = stream.into_iter().next() else {
|
||||
panic!("tokenstream should have a tokentree");
|
||||
};
|
||||
if let TokenTree::Literal(tokenstream_lit) = tree {
|
||||
assert_eq!(lit.to_string(), tokenstream_lit.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() {
|
||||
// returns Ok(valid instance)
|
||||
lit("123", NormalOk);
|
||||
lit("\"ab\"", NormalOk);
|
||||
lit("\'b\'", NormalOk);
|
||||
lit("'b'", NormalOk);
|
||||
lit("b\"b\"", NormalOk);
|
||||
lit("c\"b\"", NormalOk);
|
||||
lit("cr\"b\"", NormalOk);
|
||||
lit("b'b'", NormalOk);
|
||||
lit("256u8", NormalOk);
|
||||
lit("-256u8", NormalOk);
|
||||
stream("-256u8", NormalOk);
|
||||
lit("0b11111000000001111i16", NormalOk);
|
||||
lit("0xf32", NormalOk);
|
||||
lit("0b0f32", NormalOk);
|
||||
lit("2E4", NormalOk);
|
||||
lit("2.2E-4f64", NormalOk);
|
||||
lit("18u8E", NormalOk);
|
||||
lit("18.0u8E", NormalOk);
|
||||
lit("cr#\"// /* // \n */\"#", NormalOk);
|
||||
lit("'\\''", NormalOk);
|
||||
lit("'\\\''", NormalOk);
|
||||
lit(&format!("r{0}\"a\"{0}", "#".repeat(255)), NormalOk);
|
||||
stream("fn main() { println!(\"Hello, world!\") }", NormalOk);
|
||||
stream("18.u8E", NormalOk);
|
||||
stream("18.0f32", NormalOk);
|
||||
stream("18.0f34", NormalOk);
|
||||
stream("18.bu8", NormalOk);
|
||||
stream("3//\n4", NormalOk);
|
||||
stream(
|
||||
"\'c\'/*\n
|
||||
*/",
|
||||
NormalOk,
|
||||
);
|
||||
stream("/*a*/ //", NormalOk);
|
||||
|
||||
println!("### ERRORS");
|
||||
|
||||
// returns Err(LexError)
|
||||
lit("\'c\'/**/", NormalErr);
|
||||
lit(" 0", NormalErr);
|
||||
lit("0 ", NormalErr);
|
||||
lit("0//", NormalErr);
|
||||
lit("3//\n4", NormalErr);
|
||||
lit("18.u8E", NormalErr);
|
||||
lit("/*a*/ //", NormalErr);
|
||||
// FIXME: all of the cases below should return an Err and emit no diagnostics, but don't yet.
|
||||
|
||||
// emits diagnostics and returns LexError
|
||||
lit("r'r'", OtherError);
|
||||
lit("c'r'", OtherError);
|
||||
|
||||
// emits diagnostic and returns a seemingly valid tokenstream
|
||||
stream("r'r'", OtherError);
|
||||
stream("c'r'", OtherError);
|
||||
|
||||
for parse in [stream as fn(&str, Mode), lit] {
|
||||
// emits diagnostic(s), then panics
|
||||
parse("1 ) 2", OtherWithPanic);
|
||||
parse("( x [ ) ]", OtherWithPanic);
|
||||
parse("r#", OtherWithPanic);
|
||||
|
||||
// emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. })
|
||||
parse("0b2", OtherError);
|
||||
parse("0bf32", OtherError);
|
||||
parse("0b0.0f32", OtherError);
|
||||
parse("'\''", OtherError);
|
||||
parse(
|
||||
"'
|
||||
'", OtherError,
|
||||
);
|
||||
parse(&format!("r{0}\"a\"{0}", "#".repeat(256)), OtherWithPanic);
|
||||
|
||||
// emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar
|
||||
parse("/*a*/ 0b2 //", OtherError);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
extern crate proc_macro;
|
||||
use proc_macro::*;
|
||||
|
||||
#[path = "nonfatal-parsing-body.rs"]
|
||||
mod body;
|
||||
|
||||
#[proc_macro]
|
||||
pub fn run(_: TokenStream) -> TokenStream {
|
||||
body::run();
|
||||
TokenStream::new()
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
//@ proc-macro: nonfatal-parsing.rs
|
||||
//@ needs-unwind
|
||||
//@ edition: 2024
|
||||
//@ dont-require-annotations: ERROR
|
||||
//@ ignore-backends: gcc
|
||||
// FIXME: should be a run-pass test once invalidly parsed tokens no longer result in diagnostics
|
||||
|
||||
extern crate proc_macro;
|
||||
extern crate nonfatal_parsing;
|
||||
|
||||
#[path = "auxiliary/nonfatal-parsing-body.rs"]
|
||||
mod body;
|
||||
|
||||
fn main() {
|
||||
nonfatal_parsing::run!();
|
||||
// FIXME: enable this once the standalone backend exists
|
||||
// https://github.com/rust-lang/rust/issues/130856
|
||||
// body::run();
|
||||
}
|
||||
@@ -0,0 +1,197 @@
|
||||
error: prefix `r` is unknown
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | r'r'
|
||||
| ^ unknown prefix
|
||||
|
|
||||
= note: prefixed identifiers and literals are reserved since Rust 2021
|
||||
help: consider inserting whitespace here
|
||||
|
|
||||
LL | r 'r'
|
||||
| +
|
||||
|
||||
error: prefix `c` is unknown
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | c'r'
|
||||
| ^ unknown prefix
|
||||
|
|
||||
= note: prefixed identifiers and literals are reserved since Rust 2021
|
||||
help: consider inserting whitespace here
|
||||
|
|
||||
LL | c 'r'
|
||||
| +
|
||||
|
||||
error: unexpected closing delimiter: `)`
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ unexpected closing delimiter
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected closing delimiter: `]`
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| -^^^^^^^^^^^^^^^^^^^^^^^
|
||||
| |
|
||||
| the nearest open delimiter
|
||||
| missing open `(` for this delimiter
|
||||
| unexpected closing delimiter
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: found invalid character; only `#` is allowed in raw string delimitation: \u{0}
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid digit for a base 2 literal
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error[E0768]: no valid digits found for number
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: binary float literal is not supported
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: character constant must be escaped: `'`
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape the character
|
||||
|
|
||||
LL - nonfatal_parsing::run!();
|
||||
LL + nonfatal_parsing::run!(\';
|
||||
|
|
||||
|
||||
error: character constant must be escaped: `\n`
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
help: escape the character
|
||||
|
|
||||
LL - nonfatal_parsing::run!();
|
||||
LL + nonfatal_parsing::run!(\n;
|
||||
|
|
||||
|
||||
error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: invalid digit for a base 2 literal
|
||||
--> $DIR/nonfatal-parsing.rs:15:5
|
||||
|
|
||||
LL | nonfatal_parsing::run!();
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
|
||||
= note: this error originates in the macro `nonfatal_parsing::run` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: unexpected closing delimiter: `)`
|
||||
--> <proc-macro source code>:1:3
|
||||
|
|
||||
LL | 1 ) 2
|
||||
| ^ unexpected closing delimiter
|
||||
|
||||
error: unexpected closing delimiter: `]`
|
||||
--> <proc-macro source code>:1:10
|
||||
|
|
||||
LL | ( x [ ) ]
|
||||
| - - ^ unexpected closing delimiter
|
||||
| | |
|
||||
| | missing open `(` for this delimiter
|
||||
| the nearest open delimiter
|
||||
|
||||
error: found invalid character; only `#` is allowed in raw string delimitation: \u{0}
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | r#
|
||||
| ^^
|
||||
|
||||
error: invalid digit for a base 2 literal
|
||||
--> <proc-macro source code>:1:3
|
||||
|
|
||||
LL | 0b2
|
||||
| ^
|
||||
|
||||
error[E0768]: no valid digits found for number
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | 0bf32
|
||||
| ^^
|
||||
|
||||
error: binary float literal is not supported
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | 0b0.0f32
|
||||
| ^^^^^
|
||||
|
||||
error: character constant must be escaped: `'`
|
||||
--> <proc-macro source code>:1:2
|
||||
|
|
||||
LL | '''
|
||||
| ^
|
||||
|
|
||||
help: escape the character
|
||||
|
|
||||
LL | '\''
|
||||
| +
|
||||
|
||||
error: character constant must be escaped: `\n`
|
||||
--> <proc-macro source code>:1:2
|
||||
|
|
||||
LL | '
|
||||
| __^
|
||||
LL | | '
|
||||
| |_^
|
||||
|
|
||||
help: escape the character
|
||||
|
|
||||
LL | '\n'
|
||||
| ++
|
||||
|
||||
error: too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found 256
|
||||
--> <proc-macro source code>:1:1
|
||||
|
|
||||
LL | r#######################################...##################################################
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: invalid digit for a base 2 literal
|
||||
--> <proc-macro source code>:1:9
|
||||
|
|
||||
LL | /*a*/ 0b2 //
|
||||
| ^
|
||||
|
||||
error: aborting due to 22 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0768`.
|
||||
@@ -0,0 +1,54 @@
|
||||
Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: #44 bytes(361..385) })
|
||||
Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: #44 bytes(361..385) }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #44 bytes(361..385) }])
|
||||
Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: #44 bytes(361..385) })
|
||||
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) }])
|
||||
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) }])
|
||||
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: #44 bytes(361..385) }])
|
||||
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) }])
|
||||
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) }])
|
||||
Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [])
|
||||
### ERRORS
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Err(LexError)
|
||||
Ok(TokenStream [Ident { ident: "r", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Ident { ident: "c", span: #44 bytes(361..385) }, Literal { kind: Char, symbol: "r", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) }])
|
||||
Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #44 bytes(361..385) })
|
||||
Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #44 bytes(361..385) })
|
||||
Err(LexError)
|
||||
Reference in New Issue
Block a user