From 1f3c926c589e5448e1e2e28029a4842574e31c5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Kijewski?= Date: Thu, 31 Jul 2025 18:25:58 +0200 Subject: [PATCH] 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 . --- askama_parser/src/expr.rs | 12 ++-- askama_parser/src/tests.rs | 15 +++++ ...testcase-minimized-derive-6573215117017088 | 1 + testing/tests/ui/raw-prefix.rs | 60 +++++++++++++++++ testing/tests/ui/raw-prefix.stderr | 64 +++++++++++++++++++ 5 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 fuzzing/fuzz/artifacts/derive/clusterfuzz-testcase-minimized-derive-6573215117017088 diff --git a/askama_parser/src/expr.rs b/askama_parser/src/expr.rs index 63533a4f..af799ae7 100644 --- a/askama_parser/src/expr.rs +++ b/askama_parser/src/expr.rs @@ -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!( diff --git a/askama_parser/src/tests.rs b/askama_parser/src/tests.rs index e58dd1dc..6ac9c63b 100644 --- a/askama_parser/src/tests.rs +++ b/askama_parser/src/tests.rs @@ -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 . + 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"), + ); + } +} diff --git a/fuzzing/fuzz/artifacts/derive/clusterfuzz-testcase-minimized-derive-6573215117017088 b/fuzzing/fuzz/artifacts/derive/clusterfuzz-testcase-minimized-derive-6573215117017088 new file mode 100644 index 00000000..90a3d77e --- /dev/null +++ b/fuzzing/fuzz/artifacts/derive/clusterfuzz-testcase-minimized-derive-6573215117017088 @@ -0,0 +1 @@ +ÿÿÿ{{z!{r#self}}}ÿ ÿqÿø \ No newline at end of file diff --git a/testing/tests/ui/raw-prefix.rs b/testing/tests/ui/raw-prefix.rs index 857826fe..cceca6ae 100644 --- a/testing/tests/ui/raw-prefix.rs +++ b/testing/tests/ui/raw-prefix.rs @@ -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: +// . +// Regression test for . + +#[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() {} diff --git a/testing/tests/ui/raw-prefix.stderr b/testing/tests/ui/raw-prefix.stderr index 195d7847..5bb15ed0 100644 --- a/testing/tests/ui/raw-prefix.stderr +++ b/testing/tests/ui/raw-prefix.stderr @@ -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 + --> :1:8 + "crate) }}" + --> tests/ui/raw-prefix.rs:129:14 + | +129 | source = "{{ z!(r#crate) }}", + | ^^^^^^^^^^^^^^^^^^^ + +error: `self` cannot be a raw identifier + --> :1:8 + "self) }}" + --> tests/ui/raw-prefix.rs:136:14 + | +136 | source = "{{ z!(r#self) }}", + | ^^^^^^^^^^^^^^^^^^ + +error: `Self` cannot be a raw identifier + --> :1:8 + "Self) }}" + --> tests/ui/raw-prefix.rs:143:14 + | +143 | source = "{{ z!(r#Self) }}", + | ^^^^^^^^^^^^^^^^^^ + +error: `super` cannot be a raw identifier + --> :1:8 + "super) }}" + --> tests/ui/raw-prefix.rs:150:14 + | +150 | source = "{{ z!(r#super) }}", + | ^^^^^^^^^^^^^^^^^^^ + +error: only one `#` is allowed in raw identifier delimitation + --> :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 + --> :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 + --> :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 + --> :1:6 + "r##super) }}" + --> tests/ui/raw-prefix.rs:178:14 + | +178 | source = "{{ z!(r##super) }}", + | ^^^^^^^^^^^^^^^^^^^^