1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#![allow(clippy::non_ascii_literal)]
use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, TokenStream, TokenTree};
use std::panic;
use syn::parse::discouraged::Speculative as _;
use syn::parse::{Parse, ParseStream, Parser, Result};
use syn::{parenthesized, Token};
#[test]
#[should_panic(expected = "fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_sources() {
struct BreakRules;
impl Parse for BreakRules {
fn parse(input1: ParseStream) -> Result<Self> {
let nested = |input2: ParseStream| {
input1.advance_to(input2);
Ok(Self)
};
nested.parse_str("")
}
}
syn::parse_str::<BreakRules>("").unwrap();
}
#[test]
#[should_panic(expected = "fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_between_brackets() {
struct BreakRules;
impl Parse for BreakRules {
fn parse(input: ParseStream) -> Result<Self> {
let a;
let b;
parenthesized!(a in input);
parenthesized!(b in input);
a.advance_to(&b);
Ok(Self)
}
}
syn::parse_str::<BreakRules>("()()").unwrap();
}
#[test]
#[should_panic(expected = "fork was not derived from the advancing parse stream")]
fn smuggled_speculative_cursor_into_brackets() {
struct BreakRules;
impl Parse for BreakRules {
fn parse(input: ParseStream) -> Result<Self> {
let a;
parenthesized!(a in input);
input.advance_to(&a);
Ok(Self)
}
}
syn::parse_str::<BreakRules>("()").unwrap();
}
#[test]
fn trailing_empty_none_group() {
fn parse(input: ParseStream) -> Result<()> {
input.parse::<Token![+]>()?;
let content;
parenthesized!(content in input);
content.parse::<Token![+]>()?;
Ok(())
}
// `+ ( + «∅ ∅» ) «∅ «∅ ∅» ∅»`
let tokens = TokenStream::from_iter([
TokenTree::Punct(Punct::new('+', Spacing::Alone)),
TokenTree::Group(Group::new(
Delimiter::Parenthesis,
TokenStream::from_iter([
TokenTree::Punct(Punct::new('+', Spacing::Alone)),
TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
]),
)),
TokenTree::Group(Group::new(Delimiter::None, TokenStream::new())),
TokenTree::Group(Group::new(
Delimiter::None,
TokenStream::from_iter([TokenTree::Group(Group::new(
Delimiter::None,
TokenStream::new(),
))]),
)),
]);
parse.parse2(tokens).unwrap();
}
#[test]
fn test_unwind_safe() {
fn parse(input: ParseStream) -> Result<Ident> {
let thread_result = panic::catch_unwind(|| input.parse());
thread_result.unwrap()
}
parse.parse_str("throw").unwrap();
}
|