Skip to content

Commit 62534aa

Browse files
committed
Fix parsing logic in proc_macro::quote
1 parent 6840234 commit 62534aa

10 files changed

+504
-91
lines changed

library/proc_macro/src/quote.rs

Lines changed: 276 additions & 83 deletions
Large diffs are not rendered by default.

tests/ui/proc-macro/quote/auxiliary/basic.rs

Lines changed: 86 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,15 @@ use proc_macro::*;
1111

1212
#[proc_macro]
1313
pub fn run_tests(_: TokenStream) -> TokenStream {
14+
test_sep1();
15+
test_sep2();
16+
test_sep_group1();
17+
test_sep_group2();
18+
test_dollar_dollar1();
19+
test_dollar_dollar2();
20+
test_dollar_dollar3();
21+
test_dollar_dollar4();
22+
1423
test_quote_impl();
1524
test_substitution();
1625
test_iter();
@@ -50,6 +59,75 @@ pub fn run_tests(_: TokenStream) -> TokenStream {
5059
TokenStream::new()
5160
}
5261

62+
fn test_sep1() {
63+
let iter = ["a", "b"].into_iter();
64+
let tokens = quote!($($iter) << *);
65+
66+
let expected = "\"a\" << \"b\"";
67+
assert_eq!(expected, tokens.to_string());
68+
}
69+
70+
fn test_sep2() {
71+
let iter1 = ["a", "b"].into_iter();
72+
let iter2 = [1, 2, 3];
73+
let tokens = quote!($($iter1) ($($iter1) $($iter2),* A) *);
74+
75+
let expected = "\"a\" ($(\"b\") 1i32 , 2i32 , 3i32 A) \"b\"";
76+
assert_eq!(expected, tokens.to_string());
77+
}
78+
79+
fn test_sep_group1() {
80+
let x = "X";
81+
let iter = ["a", "b"].into_iter();
82+
let tokens = quote!($($x) >> $($iter) << *);
83+
84+
let expected = "$(\"X\") >> \"a\" << \"b\"";
85+
assert_eq!(expected, tokens.to_string());
86+
}
87+
88+
fn test_sep_group2() {
89+
let x = "X";
90+
let iter = ["a", "b"].into_iter();
91+
let tokens = quote!($($x) >> > $($iter) << *);
92+
93+
let expected = "$(\"X\") >> > \"a\" << \"b\"";
94+
assert_eq!(expected, tokens.to_string());
95+
}
96+
97+
fn test_dollar_dollar1() {
98+
let iter = ["a", "b"].into_iter();
99+
let tokens = quote!($$ x $($$ x $iter)*);
100+
101+
let expected = "$x $x \"a\" $x \"b\"";
102+
assert_eq!(expected, tokens.to_string());
103+
}
104+
105+
fn test_dollar_dollar2() {
106+
let iter = ["a", "b", "c"].into_iter();
107+
let tokens = quote!($($iter) $$ *);
108+
109+
let expected = "\"a\" $ \"b\" $ \"c\"";
110+
assert_eq!(expected, tokens.to_string());
111+
}
112+
113+
fn test_dollar_dollar3() {
114+
let x = "X";
115+
let iter = ["a", "b", "c"].into_iter();
116+
let tokens = quote!($($x)$$($x),*);
117+
118+
let expected = "$(\"X\") $ (\"X\"),*";
119+
assert_eq!(expected, tokens.to_string());
120+
}
121+
122+
fn test_dollar_dollar4() {
123+
let x = "X";
124+
let iter = ["a", "b", "c"].into_iter();
125+
let tokens = quote!($($x)$$y$($iter)*);
126+
127+
let expected = "$(\"X\") $y \"a\" \"b\" \"c\"";
128+
assert_eq!(expected, tokens.to_string());
129+
}
130+
53131
// Based on https://github.com/dtolnay/quote/blob/0245506323a3616daa2ee41c6ad0b871e4d78ae4/tests/test.rs
54132
//
55133
// FIXME(quote):
@@ -106,7 +184,7 @@ fn test_iter() {
106184

107185
assert_eq!("X, X, X, X,", quote!($($primes,)*).to_string());
108186

109-
assert_eq!("X, X, X, X", quote!($($primes),*).to_string());
187+
assert_eq!("X , X , X , X", quote!($($primes),*).to_string());
110188
}
111189

112190
fn test_array() {
@@ -320,7 +398,7 @@ fn test_fancy_repetition() {
320398
$($foo: $bar),*
321399
};
322400

323-
let expected = r#""a" : true, "b" : false"#;
401+
let expected = r#""a" : true , "b" : false"#;
324402
assert_eq!(expected, tokens.to_string());
325403
}
326404

@@ -333,7 +411,7 @@ fn test_nested_fancy_repetition() {
333411
),*
334412
};
335413

336-
let expected = "'a' 'b' 'c', 'x' 'y' 'z'";
414+
let expected = "'a' 'b' 'c' , 'x' 'y' 'z'";
337415
assert_eq!(expected, tokens.to_string());
338416
}
339417

@@ -345,7 +423,7 @@ fn test_duplicate_name_repetition() {
345423
$($foo: $foo),*
346424
};
347425

348-
let expected = r#""a" : "a", "b" : "b" "a" : "a", "b" : "b""#;
426+
let expected = r#""a" : "a" , "b" : "b" "a" : "a" , "b" : "b""#;
349427
assert_eq!(expected, tokens.to_string());
350428
}
351429

@@ -356,7 +434,7 @@ fn test_duplicate_name_repetition_no_copy() {
356434
$($foo: $foo),*
357435
};
358436

359-
let expected = r#""a" : "a", "b" : "b""#;
437+
let expected = r#""a" : "a" , "b" : "b""#;
360438
assert_eq!(expected, tokens.to_string());
361439
}
362440

@@ -369,7 +447,7 @@ fn test_btreeset_repetition() {
369447
$($set: $set),*
370448
};
371449

372-
let expected = r#""a" : "a", "b" : "b""#;
450+
let expected = r#""a" : "a" , "b" : "b""#;
373451
assert_eq!(expected, tokens.to_string());
374452
}
375453

@@ -378,7 +456,7 @@ fn test_variable_name_conflict() {
378456
// fine, if a little confusing when debugging.
379457
let _i = vec!['a', 'b'];
380458
let tokens = quote! { $($_i),* };
381-
let expected = "'a', 'b'";
459+
let expected = "'a' , 'b'";
382460
assert_eq!(expected, tokens.to_string());
383461
}
384462

@@ -390,7 +468,7 @@ fn test_nonrep_in_repetition() {
390468
$($rep $rep : $nonrep $nonrep),*
391469
};
392470

393-
let expected = r#""a" "a" : "c" "c", "b" "b" : "c" "c""#;
471+
let expected = r#""a" "a" : "c" "c" , "b" "b" : "c" "c""#;
394472
assert_eq!(expected, tokens.to_string());
395473
}
396474

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(proc_macro_quote)]
2+
3+
extern crate proc_macro;
4+
5+
use proc_macro::quote;
6+
7+
fn main() {
8+
let arr = [1, 2, 3];
9+
quote! { ${$arr}* }; //~ ERROR the trait bound `[{integer}; 3]: ToTokens` is not satisfied [E0277]
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `[{integer}; 3]: ToTokens` is not satisfied
2+
--> $DIR/not-quotable-repetition-group-brace.rs:9:5
3+
|
4+
LL | quote! { ${$arr}* };
5+
| ^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| the trait `ToTokens` is not implemented for `[{integer}; 3]`
8+
| required by a bound introduced by this call
9+
|
10+
= help: the following other types implement trait `ToTokens`:
11+
&T
12+
&mut T
13+
Box<T>
14+
CString
15+
Cow<'_, T>
16+
Option<T>
17+
Rc<T>
18+
bool
19+
and 24 others
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(proc_macro_quote)]
2+
3+
extern crate proc_macro;
4+
5+
use proc_macro::quote;
6+
7+
fn main() {
8+
let arr = [1, 2, 3];
9+
quote! { $[$arr]* }; //~ ERROR the trait bound `[{integer}; 3]: ToTokens` is not satisfied [E0277]
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `[{integer}; 3]: ToTokens` is not satisfied
2+
--> $DIR/not-quotable-repetition-group-bracket.rs:9:5
3+
|
4+
LL | quote! { $[$arr]* };
5+
| ^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| the trait `ToTokens` is not implemented for `[{integer}; 3]`
8+
| required by a bound introduced by this call
9+
|
10+
= help: the following other types implement trait `ToTokens`:
11+
&T
12+
&mut T
13+
Box<T>
14+
CString
15+
Cow<'_, T>
16+
Option<T>
17+
Rc<T>
18+
bool
19+
and 24 others
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#![feature(proc_macro_quote)]
2+
3+
extern crate proc_macro;
4+
5+
use proc_macro::quote;
6+
7+
macro_rules! do_quote {
8+
($dollar:tt $content:expr) => {
9+
proc_macro::quote!($dollar $content *) //~ ERROR the trait bound `[{integer}; 3]: ToTokens` is not satisfied [E0277]
10+
};
11+
}
12+
13+
fn main() {
14+
let arr = [1, 2, 3];
15+
do_quote!($ f!($arr));
16+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0277]: the trait bound `[{integer}; 3]: ToTokens` is not satisfied
2+
--> $DIR/not-quotable-repetition-group-none.rs:9:9
3+
|
4+
LL | proc_macro::quote!($dollar $content *)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToTokens` is not implemented for `[{integer}; 3]`
6+
...
7+
LL | do_quote!($ f!($arr));
8+
| ---------------------
9+
| |
10+
| required by a bound introduced by this call
11+
| in this macro invocation
12+
|
13+
= help: the following other types implement trait `ToTokens`:
14+
&T
15+
&mut T
16+
Box<T>
17+
CString
18+
Cow<'_, T>
19+
Option<T>
20+
Rc<T>
21+
bool
22+
and 24 others
23+
= note: this error originates in the macro `proc_macro::quote` which comes from the expansion of the macro `do_quote` (in Nightly builds, run with -Z macro-backtrace for more info)
24+
25+
error: aborting due to 1 previous error
26+
27+
For more information about this error, try `rustc --explain E0277`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#![feature(proc_macro_quote)]
2+
3+
extern crate proc_macro;
4+
5+
use proc_macro::quote;
6+
7+
fn main() {
8+
let arr = [1, 2, 3];
9+
quote! { $($arr) $$ x .. false [] * }; //~ ERROR the trait bound `[{integer}; 3]: ToTokens` is not satisfied [E0277]
10+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0277]: the trait bound `[{integer}; 3]: ToTokens` is not satisfied
2+
--> $DIR/not-quotable-repetition-invalid-separator.rs:9:5
3+
|
4+
LL | quote! { $($arr) $$ x .. false [] * };
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
6+
| |
7+
| the trait `ToTokens` is not implemented for `[{integer}; 3]`
8+
| required by a bound introduced by this call
9+
|
10+
= help: the following other types implement trait `ToTokens`:
11+
&T
12+
&mut T
13+
Box<T>
14+
CString
15+
Cow<'_, T>
16+
Option<T>
17+
Rc<T>
18+
bool
19+
and 24 others
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)