From 735d052f6f6f44d3f2710dbdf61b789fc2b3d3cd Mon Sep 17 00:00:00 2001 From: cyrgani Date: Tue, 4 Nov 2025 23:16:15 +0100 Subject: [PATCH] add larger test for `proc_macro` `FromStr` implementations --- .../auxiliary/nonfatal-parsing-body.rs | 104 +++++++++ .../proc-macro/auxiliary/nonfatal-parsing.rs | 11 + tests/ui/proc-macro/nonfatal-parsing.rs | 18 ++ tests/ui/proc-macro/nonfatal-parsing.stderr | 197 ++++++++++++++++++ tests/ui/proc-macro/nonfatal-parsing.stdout | 54 +++++ 5 files changed, 384 insertions(+) create mode 100644 tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs create mode 100644 tests/ui/proc-macro/auxiliary/nonfatal-parsing.rs create mode 100644 tests/ui/proc-macro/nonfatal-parsing.rs create mode 100644 tests/ui/proc-macro/nonfatal-parsing.stderr create mode 100644 tests/ui/proc-macro/nonfatal-parsing.stdout diff --git a/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs b/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs new file mode 100644 index 0000000000000..515fa8f7204c2 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/nonfatal-parsing-body.rs @@ -0,0 +1,104 @@ +use proc_macro::*; +use std::panic::catch_unwind; +use std::str::FromStr; + +fn stream(s: &str) { + println!("{:?}", TokenStream::from_str(s)); +} + +fn lit(s: &str) { + println!("{:?}", Literal::from_str(s)); +} + +fn stream_catch_unwind(s: &str) { + if catch_unwind(|| println!("{:?}", TokenStream::from_str(s))).is_ok() { + eprintln!("{s} did not panic"); + } +} + +fn lit_catch_unwind(s: &str) { + if catch_unwind(|| println!("{:?}", Literal::from_str(s))).is_ok() { + eprintln!("{s} did not panic"); + } +} + +pub fn run() { + // returns Ok(valid instance) + lit("123"); + lit("\"ab\""); + lit("\'b\'"); + lit("'b'"); + lit("b\"b\""); + lit("c\"b\""); + lit("cr\"b\""); + lit("b'b'"); + lit("256u8"); + lit("-256u8"); + stream("-256u8"); + lit("0b11111000000001111i16"); + lit("0xf32"); + lit("0b0f32"); + lit("2E4"); + lit("2.2E-4f64"); + lit("18u8E"); + lit("18.0u8E"); + lit("cr#\"// /* // \n */\"#"); + lit("'\\''"); + lit("'\\\''"); + lit(&format!("r{0}\"a\"{0}", "#".repeat(255))); + stream("fn main() { println!(\"Hello, world!\") }"); + stream("18.u8E"); + stream("18.0f32"); + stream("18.0f34"); + stream("18.bu8"); + stream("3//\n4"); + stream( + "\'c\'/*\n + */", + ); + stream("/*a*/ //"); + + println!("### ERRORS"); + + // returns Err(LexError) + lit("\'c\'/**/"); + lit(" 0"); + lit("0 "); + lit("0//"); + lit("3//\n4"); + lit("18.u8E"); + lit("/*a*/ //"); + // 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'"); + lit("c'r'"); + + // emits diagnostic and returns a seemingly valid tokenstream + stream("r'r'"); + stream("c'r'"); + + for (parse, parse_catch_unwind) in [ + (stream as fn(&str), stream_catch_unwind as fn(&str)), + (lit, lit_catch_unwind), + ] { + // emits diagnostic(s), then panics + parse_catch_unwind("1 ) 2"); + parse_catch_unwind("( x [ ) ]"); + parse_catch_unwind("r#"); + + // emits diagnostic(s), then returns Ok(Literal { kind: ErrWithGuar, .. }) + parse("0b2"); + parse("0bf32"); + parse("0b0.0f32"); + parse("'\''"); + parse( + "' +'", + ); + parse_catch_unwind(&format!("r{0}\"a\"{0}", "#".repeat(256))); + + // emits diagnostic, then, when parsing as a lit, returns LexError, otherwise ErrWithGuar + parse("/*a*/ 0b2 //"); + } +} diff --git a/tests/ui/proc-macro/auxiliary/nonfatal-parsing.rs b/tests/ui/proc-macro/auxiliary/nonfatal-parsing.rs new file mode 100644 index 0000000000000..75db8ee3c5fc8 --- /dev/null +++ b/tests/ui/proc-macro/auxiliary/nonfatal-parsing.rs @@ -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() +} diff --git a/tests/ui/proc-macro/nonfatal-parsing.rs b/tests/ui/proc-macro/nonfatal-parsing.rs new file mode 100644 index 0000000000000..2e91be494ea3e --- /dev/null +++ b/tests/ui/proc-macro/nonfatal-parsing.rs @@ -0,0 +1,18 @@ +//@ proc-macro: nonfatal-parsing.rs +//@ needs-unwind +//@ edition:2024 +//@ dont-require-annotations: ERROR +//@ ignore-backends: gcc +// FIXME: should be a check-pass test + +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 + // body::run(); +} diff --git a/tests/ui/proc-macro/nonfatal-parsing.stderr b/tests/ui/proc-macro/nonfatal-parsing.stderr new file mode 100644 index 0000000000000..00c5c6ecfa8ea --- /dev/null +++ b/tests/ui/proc-macro/nonfatal-parsing.stderr @@ -0,0 +1,197 @@ +error: prefix `r` is unknown + --> :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 + --> :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: `)` + --> :1:3 + | +LL | 1 ) 2 + | ^ unexpected closing delimiter + +error: unexpected closing delimiter: `]` + --> :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} + --> :1:1 + | +LL | r# + | ^^ + +error: invalid digit for a base 2 literal + --> :1:3 + | +LL | 0b2 + | ^ + +error[E0768]: no valid digits found for number + --> :1:1 + | +LL | 0bf32 + | ^^ + +error: binary float literal is not supported + --> :1:1 + | +LL | 0b0.0f32 + | ^^^^^ + +error: character constant must be escaped: `'` + --> :1:2 + | +LL | ''' + | ^ + | +help: escape the character + | +LL | '\'' + | + + +error: character constant must be escaped: `\n` + --> :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 + --> :1:1 + | +LL | r#######################################...################################################## + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^...^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid digit for a base 2 literal + --> :1:9 + | +LL | /*a*/ 0b2 // + | ^ + +error: aborting due to 22 previous errors + +For more information about this error, try `rustc --explain E0768`. diff --git a/tests/ui/proc-macro/nonfatal-parsing.stdout b/tests/ui/proc-macro/nonfatal-parsing.stdout new file mode 100644 index 0000000000000..e90382423da7e --- /dev/null +++ b/tests/ui/proc-macro/nonfatal-parsing.stdout @@ -0,0 +1,54 @@ +Ok(Literal { kind: Integer, symbol: "123", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Str, symbol: "ab", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Char, symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: ByteStr, symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: CStr, symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: CStrRaw(0), symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Byte, symbol: "b", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #25 bytes(301..325) }) +Ok(Literal { kind: Integer, symbol: "-256", suffix: Some("u8"), span: #25 bytes(301..325) }) +Ok(TokenStream [Punct { ch: '-', spacing: Alone, span: #25 bytes(301..325) }, Literal { kind: Integer, symbol: "256", suffix: Some("u8"), span: #25 bytes(301..325) }]) +Ok(Literal { kind: Integer, symbol: "0b11111000000001111", suffix: Some("i16"), span: #25 bytes(301..325) }) +Ok(Literal { kind: Integer, symbol: "0xf32", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Integer, symbol: "0b0", suffix: Some("f32"), span: #25 bytes(301..325) }) +Ok(Literal { kind: Float, symbol: "2E4", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Float, symbol: "2.2E-4", suffix: Some("f64"), span: #25 bytes(301..325) }) +Ok(Literal { kind: Integer, symbol: "18", suffix: Some("u8E"), span: #25 bytes(301..325) }) +Ok(Literal { kind: Float, symbol: "18.0", suffix: Some("u8E"), span: #25 bytes(301..325) }) +Ok(Literal { kind: CStrRaw(1), symbol: "// /* // \n */", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: Char, symbol: "\'", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: StrRaw(255), symbol: "a", suffix: None, span: #25 bytes(301..325) }) +Ok(TokenStream [Ident { ident: "fn", span: #25 bytes(301..325) }, Ident { ident: "main", span: #25 bytes(301..325) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: #25 bytes(301..325) }, Group { delimiter: Brace, stream: TokenStream [Ident { ident: "println", span: #25 bytes(301..325) }, Punct { ch: '!', spacing: Alone, span: #25 bytes(301..325) }, Group { delimiter: Parenthesis, stream: TokenStream [Literal { kind: Str, symbol: "Hello, world!", suffix: None, span: #25 bytes(301..325) }], span: #25 bytes(301..325) }], span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #25 bytes(301..325) }, Punct { ch: '.', spacing: Alone, span: #25 bytes(301..325) }, Ident { ident: "u8E", span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f32"), span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Float, symbol: "18.0", suffix: Some("f34"), span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "18", suffix: None, span: #25 bytes(301..325) }, Punct { ch: '.', spacing: Alone, span: #25 bytes(301..325) }, Ident { ident: "bu8", span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Integer, symbol: "3", suffix: None, span: #25 bytes(301..325) }, Literal { kind: Integer, symbol: "4", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: Char, symbol: "c", suffix: None, span: #25 bytes(301..325) }]) +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: #25 bytes(301..325) }, Literal { kind: Char, symbol: "r", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Ident { ident: "c", span: #25 bytes(301..325) }, Literal { kind: Char, symbol: "r", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #25 bytes(301..325) }]) +Ok(TokenStream [Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #25 bytes(301..325) }]) +Ok(Literal { kind: ErrWithGuar, symbol: "0b2", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: ErrWithGuar, symbol: "0b", suffix: Some("f32"), span: #25 bytes(301..325) }) +Ok(Literal { kind: ErrWithGuar, symbol: "0b0.0", suffix: Some("f32"), span: #25 bytes(301..325) }) +Ok(Literal { kind: ErrWithGuar, symbol: "'''", suffix: None, span: #25 bytes(301..325) }) +Ok(Literal { kind: ErrWithGuar, symbol: "'\n'", suffix: None, span: #25 bytes(301..325) }) +Err(LexError)