mirror of
https://github.com/askama-rs/askama.git
synced 2025-09-29 22:11:17 +00:00
Fix wrong macro argument parsing
This commit is contained in:
parent
e8d2391d48
commit
1f31021632
@ -927,6 +927,35 @@ impl<'a> Suffix<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn lifetime<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, ()> {
|
||||||
|
// Before the 2021 edition, we can have whitespace characters between "r#" and the
|
||||||
|
// identifier so we allow it here.
|
||||||
|
let start = *i;
|
||||||
|
'\''.parse_next(i)?;
|
||||||
|
let Some((is_raw, identifier)) = opt(alt((
|
||||||
|
('r', '#', identifier).map(|(_, _, ident)| (true, ident)),
|
||||||
|
(identifier, not(peek('#'))).map(|(ident, _)| (false, ident)),
|
||||||
|
)))
|
||||||
|
.parse_next(i)?
|
||||||
|
else {
|
||||||
|
return cut_error!("wrong lifetime format", **start);
|
||||||
|
};
|
||||||
|
if !is_raw {
|
||||||
|
if crate::is_rust_keyword(identifier) {
|
||||||
|
return cut_error!(
|
||||||
|
"a non-raw lifetime cannot be named like an existing keyword",
|
||||||
|
**start,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if ["Self", "self", "crate", "super", "_"].contains(&identifier) {
|
||||||
|
return cut_error!(format!("`{identifier}` cannot be a raw lifetime"), **start,);
|
||||||
|
}
|
||||||
|
if opt(peek('\'')).parse_next(i)?.is_some() {
|
||||||
|
return cut_error!("unexpected `'` after lifetime", **start);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn token<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Token> {
|
fn token<'a>(i: &mut InputStream<'a>) -> ParseResult<'a, Token> {
|
||||||
// <https://doc.rust-lang.org/reference/tokens.html>
|
// <https://doc.rust-lang.org/reference/tokens.html>
|
||||||
let some_other = alt((
|
let some_other = alt((
|
||||||
@ -936,8 +965,7 @@ impl<'a> Suffix<'a> {
|
|||||||
num_lit.value(Token::SomeOther),
|
num_lit.value(Token::SomeOther),
|
||||||
// keywords + (raw) identifiers + raw strings
|
// keywords + (raw) identifiers + raw strings
|
||||||
identifier_or_prefixed_string.value(Token::SomeOther),
|
identifier_or_prefixed_string.value(Token::SomeOther),
|
||||||
// lifetimes
|
lifetime.value(Token::SomeOther),
|
||||||
('\'', identifier, not(peek('\''))).value(Token::SomeOther),
|
|
||||||
// comments
|
// comments
|
||||||
line_comment.value(Token::SomeOther),
|
line_comment.value(Token::SomeOther),
|
||||||
block_comment.value(Token::SomeOther),
|
block_comment.value(Token::SomeOther),
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
˙˙˙{{z!{'r#}}}˙ ˙s˙
|
@ -630,3 +630,19 @@ fn test_macro_caller_is_defined_check() {
|
|||||||
"no caller defined|this time with caller"
|
"no caller defined|this time with caller"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This test ensures that raw lifetimes are correctly handled.
|
||||||
|
#[test]
|
||||||
|
fn test_macro_raw_lifetime() {
|
||||||
|
macro_rules! test {
|
||||||
|
('r#ignore_me) => {
|
||||||
|
"ok"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(source = r##"{{ test!('r#ignore_me) }}"##, ext = "txt")]
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
assert_eq!(Foo.render().unwrap(), "ok");
|
||||||
|
}
|
||||||
|
34
testing/tests/ui/macro-args-hashtag.rs
Normal file
34
testing/tests/ui/macro-args-hashtag.rs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// This test ensures that we have the right error if a `#` character isn't prepended by
|
||||||
|
// a whitespace character and also that lifetimes are correctly handled.
|
||||||
|
|
||||||
|
use askama::Template;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(
|
||||||
|
source = r###"{{z!{'r#}}}"###,
|
||||||
|
ext = "html"
|
||||||
|
)]
|
||||||
|
struct Example;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(
|
||||||
|
source = r###"{{z!{'r# y}}}"###,
|
||||||
|
ext = "html"
|
||||||
|
)]
|
||||||
|
struct Example2;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(
|
||||||
|
source = r###"{{z!{'break}}}"###,
|
||||||
|
ext = "html"
|
||||||
|
)]
|
||||||
|
struct Example3;
|
||||||
|
|
||||||
|
#[derive(Template)]
|
||||||
|
#[template(
|
||||||
|
source = r###"{{z!{'r#self}}}"###,
|
||||||
|
ext = "html"
|
||||||
|
)]
|
||||||
|
struct Example4;
|
||||||
|
|
||||||
|
fn main() {}
|
31
testing/tests/ui/macro-args-hashtag.stderr
Normal file
31
testing/tests/ui/macro-args-hashtag.stderr
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
error: wrong lifetime format
|
||||||
|
--> <source attribute>:1:5
|
||||||
|
"'r#}}}"
|
||||||
|
--> tests/ui/macro-args-hashtag.rs:8:14
|
||||||
|
|
|
||||||
|
8 | source = r###"{{z!{'r#}}}"###,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: wrong lifetime format
|
||||||
|
--> <source attribute>:1:5
|
||||||
|
"'r# y}}}"
|
||||||
|
--> tests/ui/macro-args-hashtag.rs:15:14
|
||||||
|
|
|
||||||
|
15 | source = r###"{{z!{'r# y}}}"###,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: a non-raw lifetime cannot be named like an existing keyword
|
||||||
|
--> <source attribute>:1:5
|
||||||
|
"'break}}}"
|
||||||
|
--> tests/ui/macro-args-hashtag.rs:22:14
|
||||||
|
|
|
||||||
|
22 | source = r###"{{z!{'break}}}"###,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: `self` cannot be a raw lifetime
|
||||||
|
--> <source attribute>:1:5
|
||||||
|
"'r#self}}}"
|
||||||
|
--> tests/ui/macro-args-hashtag.rs:29:14
|
||||||
|
|
|
||||||
|
29 | source = r###"{{z!{'r#self}}}"###,
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
Loading…
x
Reference in New Issue
Block a user