parser: r#self is not a valid raw identifier in macro calls

It's not a valid raw identifier anywhere, actually, but the other cases
(in a path, as a field name, as a macro name) were already handled.

Resolves <https://issues.oss-fuzz.com/issues/435218013>.
This commit is contained in:
René Kijewski 2025-07-31 18:25:58 +02:00 committed by René Kijewski
parent d12afffc26
commit 1f3c926c58
5 changed files with 148 additions and 4 deletions

View File

@ -12,8 +12,8 @@ use winnow::token::{one_of, take_until};
use crate::node::CondTest;
use crate::{
CharLit, ErrorContext, Level, Num, ParseResult, PathOrIdentifier, StrLit, StrPrefix, WithSpan,
char_lit, cut_error, filter, identifier, keyword, not_suffix_with_hash, num_lit,
path_or_identifier, skip_ws0, skip_ws1, str_lit, ws,
can_be_variable_name, char_lit, cut_error, filter, identifier, keyword, not_suffix_with_hash,
num_lit, path_or_identifier, skip_ws0, skip_ws1, str_lit, ws,
};
macro_rules! expr_prec_layer {
@ -985,7 +985,7 @@ impl<'a> Suffix<'a> {
} else if hashes == 0 {
// a simple identifier
Ok(())
} else if opt(identifier).parse_next(i)?.is_some() {
} else if let Some(id) = opt(identifier).parse_next(i)? {
// got a raw identifier
if str_kind.is_some() {
@ -1005,7 +1005,11 @@ impl<'a> Suffix<'a> {
)
} else {
// a raw identifier like `r#async`
Ok(())
if !can_be_variable_name(id) {
cut_error!(format!("`{id}` cannot be a raw identifier"), id)
} else {
Ok(())
}
}
} else {
cut_error!(

View File

@ -1632,3 +1632,18 @@ fn test_isolated_cr_in_raw_string() {
.contains("a bare CR (Mac linebreak) is not allowed in string literals"),
);
}
#[test]
fn test_macro_call_illegal_raw_identifier() {
// Regression test for <https://issues.oss-fuzz.com/issues/435218013>.
let syntax = Syntax::default();
for id in ["crate", "self", "Self", "super"] {
assert!(
Ast::from_str(&format!("{{{{ z!(r#{id}) }}}}"), None, &syntax)
.unwrap_err()
.to_string()
.contains("cannot be a raw identifier"),
);
}
}

View File

@ -0,0 +1 @@
ÿÿÿ{{z!{r#self}}}ÿ ÿqÿø

View File

@ -120,4 +120,64 @@ struct UnseparatedPrefixedStrings2;
#[template(source = r##"{{ z!(c""r#""#) }}"##, ext = "txt")]
struct UnseparatedPrefixedStrings3;
// `r#self`, `r#Self`, `r#crate` and `r#super` are not valid raw identifiers:
// <https://doc.rust-lang.org/reference/identifiers.html>.
// Regression test for <https://issues.oss-fuzz.com/issues/435218013>.
#[derive(Template)]
#[template(
source = "{{ z!(r#crate) }}",
ext = "txt"
)]
struct RawIdentifierCrate;
#[derive(Template)]
#[template(
source = "{{ z!(r#self) }}",
ext = "txt"
)]
struct RawIdentifierSelf;
#[derive(Template)]
#[template(
source = "{{ z!(r#Self) }}",
ext = "txt"
)]
struct RawIdentifierSelfTy;
#[derive(Template)]
#[template(
source = "{{ z!(r#super) }}",
ext = "txt"
)]
struct RawIdentifierSuper;
#[derive(Template)]
#[template(
source = "{{ z!(r##crate) }}",
ext = "txt"
)]
struct RawIdentifierCrateTooManyHashes;
#[derive(Template)]
#[template(
source = "{{ z!(r##self) }}",
ext = "txt"
)]
struct RawIdentifierSelfTooManyHashes;
#[derive(Template)]
#[template(
source = "{{ z!(r##Self) }}",
ext = "txt"
)]
struct RawIdentifierSelfTyTooManyHashes;
#[derive(Template)]
#[template(
source = "{{ z!(r##super) }}",
ext = "txt"
)]
struct RawIdentifierSuperTooManyHashes;
fn main() {}

View File

@ -133,3 +133,67 @@ error: you are missing a space to separate two string literals
|
120 | #[template(source = r##"{{ z!(c""r#""#) }}"##, ext = "txt")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
error: `crate` cannot be a raw identifier
--> <source attribute>:1:8
"crate) }}"
--> tests/ui/raw-prefix.rs:129:14
|
129 | source = "{{ z!(r#crate) }}",
| ^^^^^^^^^^^^^^^^^^^
error: `self` cannot be a raw identifier
--> <source attribute>:1:8
"self) }}"
--> tests/ui/raw-prefix.rs:136:14
|
136 | source = "{{ z!(r#self) }}",
| ^^^^^^^^^^^^^^^^^^
error: `Self` cannot be a raw identifier
--> <source attribute>:1:8
"Self) }}"
--> tests/ui/raw-prefix.rs:143:14
|
143 | source = "{{ z!(r#Self) }}",
| ^^^^^^^^^^^^^^^^^^
error: `super` cannot be a raw identifier
--> <source attribute>:1:8
"super) }}"
--> tests/ui/raw-prefix.rs:150:14
|
150 | source = "{{ z!(r#super) }}",
| ^^^^^^^^^^^^^^^^^^^
error: only one `#` is allowed in raw identifier delimitation
--> <source attribute>:1:6
"r##crate) }}"
--> tests/ui/raw-prefix.rs:157:14
|
157 | source = "{{ z!(r##crate) }}",
| ^^^^^^^^^^^^^^^^^^^^
error: only one `#` is allowed in raw identifier delimitation
--> <source attribute>:1:6
"r##self) }}"
--> tests/ui/raw-prefix.rs:164:14
|
164 | source = "{{ z!(r##self) }}",
| ^^^^^^^^^^^^^^^^^^^
error: only one `#` is allowed in raw identifier delimitation
--> <source attribute>:1:6
"r##Self) }}"
--> tests/ui/raw-prefix.rs:171:14
|
171 | source = "{{ z!(r##Self) }}",
| ^^^^^^^^^^^^^^^^^^^
error: only one `#` is allowed in raw identifier delimitation
--> <source attribute>:1:6
"r##super) }}"
--> tests/ui/raw-prefix.rs:178:14
|
178 | source = "{{ z!(r##super) }}",
| ^^^^^^^^^^^^^^^^^^^^