diff options
author | Kevin Mehall <[email protected]> | 2021-03-06 16:36:22 +0000 |
---|---|---|
committer | Kevin Mehall <[email protected]> | 2021-03-06 16:48:08 +0000 |
commit | 632fa8ef4a3c9e7440b79e04a9f7dd9bd23a4de4 (patch) | |
tree | 61dfaffb6b23173f53a7796dc6dfa80b50ef8726 | |
parent | 750d3cb84678b23a55092f2e4726e48ead37a9ff (diff) |
Fix TokenStream::from_str for input consisting of a single Group
TokenStream holds a `tt::Subtree` but assumes its `delimiter` is always
`None`. In particular, the iterator implementation iterates over the
inner `token_trees` and ignores the `delimiter`.
However, `TokenStream::from_str` violated this assumption when the input
consists of a single Group by producing a Subtree with an outer
delimiter, which was ignored as seen by a procedural macro.
In this case, wrap an extra level of Subtree around it.
Fixes #7810
Fixes #7875
-rw-r--r-- | crates/proc_macro_srv/src/rustc_server.rs | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs index 14c853c77..f02b0af60 100644 --- a/crates/proc_macro_srv/src/rustc_server.rs +++ b/crates/proc_macro_srv/src/rustc_server.rs | |||
@@ -34,7 +34,16 @@ impl TokenStream { | |||
34 | } | 34 | } |
35 | 35 | ||
36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { | 36 | pub fn with_subtree(subtree: tt::Subtree) -> Self { |
37 | TokenStream { subtree } | 37 | if subtree.delimiter.is_some() { |
38 | TokenStream { | ||
39 | subtree: tt::Subtree { | ||
40 | token_trees: vec![TokenTree::Subtree(subtree)], | ||
41 | delimiter: None, | ||
42 | }, | ||
43 | } | ||
44 | } else { | ||
45 | TokenStream { subtree } | ||
46 | } | ||
38 | } | 47 | } |
39 | 48 | ||
40 | pub fn is_empty(&self) -> bool { | 49 | pub fn is_empty(&self) -> bool { |
@@ -185,7 +194,7 @@ pub mod token_stream { | |||
185 | mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; | 194 | mbe::parse_to_token_tree(src).ok_or("Failed to parse from mbe")?; |
186 | 195 | ||
187 | let subtree = subtree_replace_token_ids_with_unspecified(subtree); | 196 | let subtree = subtree_replace_token_ids_with_unspecified(subtree); |
188 | Ok(TokenStream { subtree }) | 197 | Ok(TokenStream::with_subtree(subtree)) |
189 | } | 198 | } |
190 | } | 199 | } |
191 | 200 | ||
@@ -779,4 +788,27 @@ mod tests { | |||
779 | 788 | ||
780 | assert_eq!(s.to_string(), "struct T {}"); | 789 | assert_eq!(s.to_string(), "struct T {}"); |
781 | } | 790 | } |
791 | |||
792 | #[test] | ||
793 | fn test_rustc_server_from_str() { | ||
794 | use std::str::FromStr; | ||
795 | let subtree_paren_a = tt::TokenTree::Subtree(tt::Subtree { | ||
796 | delimiter: Some(tt::Delimiter { | ||
797 | id: tt::TokenId::unspecified(), | ||
798 | kind: tt::DelimiterKind::Parenthesis, | ||
799 | }), | ||
800 | token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { | ||
801 | text: "a".into(), | ||
802 | id: tt::TokenId::unspecified(), | ||
803 | }))], | ||
804 | }); | ||
805 | |||
806 | let t1 = TokenStream::from_str("(a)").unwrap(); | ||
807 | assert_eq!(t1.subtree.token_trees.len(), 1); | ||
808 | assert_eq!(t1.subtree.token_trees[0], subtree_paren_a); | ||
809 | |||
810 | let t2 = TokenStream::from_str("(a);").unwrap(); | ||
811 | assert_eq!(t2.subtree.token_trees.len(), 2); | ||
812 | assert_eq!(t2.subtree.token_trees[0], subtree_paren_a); | ||
813 | } | ||
782 | } | 814 | } |