aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Mehall <[email protected]>2021-03-06 16:36:22 +0000
committerKevin Mehall <[email protected]>2021-03-06 16:48:08 +0000
commit632fa8ef4a3c9e7440b79e04a9f7dd9bd23a4de4 (patch)
tree61dfaffb6b23173f53a7796dc6dfa80b50ef8726
parent750d3cb84678b23a55092f2e4726e48ead37a9ff (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.rs36
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}