1 //! Tests specific to declarative macros, aka macros by example. This covers
2 //! both stable `macro_rules!` macros as well as unstable `macro` macros.
9 use expect_test::expect;
11 use crate::macro_expansion_tests::check;
14 fn token_mapping_smoke_test() {
19 ( struct $ident:ident ) => {
21 map: ::std::collections::HashSet<()>,
27 f!(struct MyTraitMap2);
30 // call ids will be shifted by Shift(27)
33 (#1 struct#2 $#3ident#4:#5ident#6 )#1 =#7>#8 {#9
34 struct#10 $#11ident#12 {#13
35 map#14:#15 :#16:#17std#18:#19:#20collections#21:#22:#23HashSet#24<#25(#26)#26>#27,#28
41 // f!(struct#1 MyTraitMap2#2);
42 struct#10 MyTraitMap2#29 {#13
43 map#14:#15 ::std#18::collections#21::HashSet#24<#25(#26)#26>#27,#28
53 macro_rules! impl_froms {
54 ($e:ident: $($v:ident),*) => {
56 impl From<$v> for $e {
57 fn from(it: $v) -> $e { $e::$v(it) }
62 impl_froms!(TokenTree: Leaf, Subtree);
65 macro_rules! impl_froms {
66 ($e:ident: $($v:ident),*) => {
68 impl From<$v> for $e {
69 fn from(it: $v) -> $e { $e::$v(it) }
74 impl From<Leaf> for TokenTree {
75 fn from(it: Leaf) -> TokenTree {
79 impl From<Subtree> for TokenTree {
80 fn from(it: Subtree) -> TokenTree {
81 TokenTree::Subtree(it)
89 fn expansion_does_not_parse_as_expression() {
96 fn f() { let _ = stmts!(); }
103 fn f() { let _ = /* error: could not convert tokens */; }
109 fn wrong_nesting_level() {
113 ($($i:ident);*) => ($i)
119 ($($i:ident);*) => ($i)
121 /* error: expected simple binding, found nested binding `i` */
127 fn match_by_first_token_literally() {
131 ($i:ident) => ( mod $i {} );
132 (= $i:ident) => ( fn $i() {} );
133 (+ $i:ident) => ( struct $i; )
141 ($i:ident) => ( mod $i {} );
142 (= $i:ident) => ( fn $i() {} );
143 (+ $i:ident) => ( struct $i; )
153 fn match_by_last_token_literally() {
157 ($i:ident) => ( mod $i {} );
158 ($i:ident =) => ( fn $i() {} );
159 ($i:ident +) => ( struct $i; )
167 ($i:ident) => ( mod $i {} );
168 ($i:ident =) => ( fn $i() {} );
169 ($i:ident +) => ( struct $i; )
179 fn match_by_ident() {
183 ($i:ident) => ( mod $i {} );
184 (spam $i:ident) => ( fn $i() {} );
185 (eggs $i:ident) => ( struct $i; )
193 ($i:ident) => ( mod $i {} );
194 (spam $i:ident) => ( fn $i() {} );
195 (eggs $i:ident) => ( struct $i; )
205 fn match_by_separator_token() {
209 ($($i:ident),*) => ($(mod $i {} )*);
210 ($($i:ident)#*) => ($(fn $i() {} )*);
211 ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
222 ($($i:ident),*) => ($(mod $i {} )*);
223 ($($i:ident)#*) => ($(fn $i() {} )*);
224 ($i:ident ,# $ j:ident) => ( struct $i; struct $ j; )
240 fn test_match_group_pattern_with_multiple_defs() {
244 ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
250 ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
261 fn test_match_group_pattern_with_multiple_statement() {
265 ($($i:ident),*) => ( fn baz() { $($i ();)* } );
271 ($($i:ident),*) => ( fn baz() { $($i ();)* } );
282 fn test_match_group_pattern_with_multiple_statement_without_semi() {
286 ($($i:ident),*) => ( fn baz() { $($i() );* } );
292 ($($i:ident),*) => ( fn baz() { $($i() );* } );
303 fn test_match_group_empty_fixed_token() {
307 ($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
313 ($($i:ident)* #abc) => ( fn baz() { $($i ();)* } );
321 fn test_match_group_in_subtree() {
325 (fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
327 m! { fn baz { a b } }
331 (fn $name:ident { $($i:ident)* } ) => ( fn $name() { $($i ();)* } );
342 fn test_expr_order() {
346 ($ i:expr) => { fn bar() { $ i * 3; } }
353 ($ i:expr) => { fn bar() { $ i * 3; } }
375 // INT_NUMBER@9..10 "1"
378 // INT_NUMBER@11..12 "2"
379 // R_PAREN@12..13 ")"
382 // INT_NUMBER@14..15 "3"
383 // SEMICOLON@15..16 ";"
384 // R_CURLY@16..17 "}"
391 fn test_match_group_with_multichar_sep() {
395 (fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
397 m! (fn baz { true false } );
401 (fn $name:ident { $($i:literal)* }) => ( fn $name() -> bool { $($i)&&* } );
412 (fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
414 m! (fn baz { true && false } );
418 (fn $name:ident { $($i:literal)&&* }) => ( fn $name() -> bool { $($i)&&* } );
428 fn test_match_group_zero_match() {
431 macro_rules! m { ( $($i:ident)* ) => (); }
435 macro_rules! m { ( $($i:ident)* ) => (); }
442 fn test_match_group_in_group() {
446 [ $( ( $($i:ident)* ) )* ] => [ ok![$( ( $($i)* ) )*]; ]
452 [ $( ( $($i:ident)* ) )* ] => [ ok![$( ( $($i)* ) )*]; ]
460 fn test_expand_to_item_list() {
463 macro_rules! structs {
464 ($($i:ident),*) => { $(struct $i { field: u32 } )* }
471 macro_rules! structs {
472 ($($i:ident),*) => { $(struct $i { field: u32 } )* }
483 // STRUCT_KW@0..6 "struct"
486 // RECORD_FIELD_LIST@9..20
488 // RECORD_FIELD@10..19
490 // IDENT@10..15 "field"
494 // PATH_SEGMENT@16..19
496 // IDENT@16..19 "u32"
497 // R_CURLY@19..20 "}"
499 // STRUCT_KW@20..26 "struct"
501 // IDENT@26..29 "Bar"
502 // RECORD_FIELD_LIST@29..40
503 // L_CURLY@29..30 "{"
504 // RECORD_FIELD@30..39
506 // IDENT@30..35 "field"
510 // PATH_SEGMENT@36..39
512 // IDENT@36..39 "u32"
513 // R_CURLY@39..40 "}"
520 fn test_two_idents() {
524 ($i:ident, $j:ident) => { fn foo() { let a = $i; let b = $j; } }
530 ($i:ident, $j:ident) => { fn foo() { let a = $i; let b = $j; } }
541 fn test_tt_to_stmts() {
578 // INT_NUMBER@5..6 "0"
579 // SEMICOLON@6..7 ";"
590 // INT_NUMBER@9..11 "10"
593 // INT_NUMBER@12..13 "1"
594 // SEMICOLON@13..14 ";"
597 // PATH_SEGMENT@14..15
607 fn test_match_literal() {
611 ('(') => { fn l_paren() {} }
617 ('(') => { fn l_paren() {} }
625 fn test_parse_macro_def_simple() {
626 cov_mark::check!(parse_macro_def_simple);
629 macro m($id:ident) { fn $id() {} }
633 macro m($id:ident) { fn $id() {} }
640 fn test_parse_macro_def_rules() {
641 cov_mark::check!(parse_macro_def_rules);
646 ($id:ident) => { fn $id() {} }
652 ($id:ident) => { fn $id() {} }
660 fn test_macro_2_0_panic_2015() {
684 ($p:path) => { fn foo() { let a = $p; } }
689 m! { bar::<u8>::baz::<u8> }
693 ($p:path) => { fn foo() { let a = $p; } }
701 let a = bar::<u8>::baz::<u8> ;
708 fn test_two_paths() {
712 ($i:path, $j:path) => { fn foo() { let a = $ i; let b = $j; } }
718 ($i:path, $j:path) => { fn foo() { let a = $ i; let b = $j; } }
729 fn test_path_with_path() {
733 ($p:path) => { fn foo() { let a = $p::bar; } }
739 ($p:path) => { fn foo() { let a = $p::bar; } }
753 ($e:expr) => { fn bar() { $e; } }
756 m! { 2 + 2 * baz(3).quux() }
760 ($e:expr) => { fn bar() { $e; } }
771 fn test_last_expr() {
775 ($($item:expr),*) => {{
776 let mut v = Vec::new();
788 ($($item:expr),*) => {{
789 let mut v = Vec::new();
797 let mut v = Vec::new();
809 fn test_expr_with_attr() {
812 macro_rules! m { ($a:expr) => { ok!(); } }
816 macro_rules! m { ($a:expr) => { ok!(); } }
827 ($t:ty) => ( fn bar() -> $t {} )
833 ($t:ty) => ( fn bar() -> $t {} )
835 fn bar() -> Baz<u8> {}
841 fn test_ty_with_complex_type() {
845 ($t:ty) => ( fn bar() -> $ t {} )
850 m! { extern "Rust" fn() -> Ret }
854 ($t:ty) => ( fn bar() -> $ t {} )
857 fn bar() -> & 'a Baz<u8> {}
859 fn bar() -> extern "Rust"fn() -> Ret {}
869 ($p:pat) => { fn foo() { let $p; } }
875 ($p:pat) => { fn foo() { let $p; } }
889 ($s:stmt) => ( fn bar() { $s; } )
896 ($s:stmt) => ( fn bar() { $s; } )
909 fn test_single_item() {
912 macro_rules! m { ($i:item) => ( $i ) }
916 macro_rules! m { ($i:item) => ( $i ) }
923 fn test_all_items() {
926 macro_rules! m { ($($i:item)*) => ($($i )*) }
944 macro_rules! m { ($($i:item)*) => ($($i )*) }
968 macro_rules! m { ($b:block) => { fn foo() $b } }
972 macro_rules! m { ($b:block) => { fn foo() $b } }
985 ($m:meta) => ( #[$m] fn bar() {} )
987 m! { cfg(target_os = "windows") }
992 ($m:meta) => ( #[$m] fn bar() {} )
994 #[cfg(target_os = "windows")] fn bar() {}
995 #[hello::world] fn bar() {}
1001 fn test_meta_doc_comments() {
1002 cov_mark::check!(test_meta_doc_comments);
1006 ($(#[$m:meta])+) => ( $(#[$m])+ fn bar() {} )
1009 /// Single Line Doc 1
1017 ($(#[$m:meta])+) => ( $(#[$m])+ fn bar() {} )
1019 #[doc = " Single Line Doc 1"]
1020 #[doc = "\n MultiLines Doc\n "] fn bar() {}
1026 fn test_meta_extended_key_value_attributes() {
1030 (#[$m:meta]) => ( #[$m] fn bar() {} )
1032 m! { #[doc = concat!("The `", "bla", "` lang item.")] }
1036 (#[$m:meta]) => ( #[$m] fn bar() {} )
1038 #[doc = concat!("The `", "bla", "` lang item.")] fn bar() {}
1044 fn test_meta_doc_comments_non_latin() {
1048 ($(#[$ m:meta])+) => ( $(#[$m])+ fn bar() {} )
1051 /// 錦瑟無端五十弦,一弦一柱思華年。
1059 ($(#[$ m:meta])+) => ( $(#[$m])+ fn bar() {} )
1061 #[doc = " 錦瑟無端五十弦,一弦一柱思華年。"]
1062 #[doc = "\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\n "] fn bar() {}
1068 fn test_meta_doc_comments_escaped_characters() {
1072 ($(#[$m:meta])+) => ( $(#[$m])+ fn bar() {} )
1080 ($(#[$m:meta])+) => ( $(#[$m])+ fn bar() {} )
1082 #[doc = " \\ \" \'"] fn bar() {}
1088 fn test_tt_block() {
1091 macro_rules! m { ($tt:tt) => { fn foo() $tt } }
1095 macro_rules! m { ($tt:tt) => { fn foo() $tt } }
1104 fn test_tt_group() {
1107 macro_rules! m { ($($tt:tt)*) => { $($tt)* } }
1111 macro_rules! m { ($($tt:tt)*) => { $($tt)* } }
1118 fn test_tt_composite() {
1121 macro_rules! m { ($tt:tt) => { ok!(); } }
1126 macro_rules! m { ($tt:tt) => { ok!(); } }
1128 /* error: leftover tokens */ok!();
1134 fn test_tt_composite2() {
1137 macro_rules! m { ($($tt:tt)*) => { abs!(=> $($tt)*); } }
1141 macro_rules! m { ($($tt:tt)*) => { abs!(=> $($tt)*); } }
1148 fn test_tt_with_composite_without_space() {
1149 // Test macro input without any spaces
1150 // See https://github.com/rust-analyzer/rust-analyzer/issues/6692
1153 macro_rules! m { ($ op:tt, $j:path) => ( ok!(); ) }
1157 macro_rules! m { ($ op:tt, $j:path) => ( ok!(); ) }
1164 fn test_underscore() {
1167 macro_rules! m { ($_:tt) => { ok!(); } }
1171 macro_rules! m { ($_:tt) => { ok!(); } }
1178 fn test_underscore_not_greedily() {
1181 // `_` overlaps with `$a:ident` but rustc matches it under the `_` token.
1183 ($($a:ident)* _) => { ok!(); }
1187 // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`.
1189 ($($a:expr => $b:ident)* _ => $c:expr) => { ok!(); }
1191 m2![a => b c => d _ => ou]
1194 // `_` overlaps with `$a:ident` but rustc matches it under the `_` token.
1196 ($($a:ident)* _) => { ok!(); }
1200 // `_ => ou` overlaps with `$a:expr => $b:ident` but rustc matches it under `_ => $c:expr`.
1202 ($($a:expr => $b:ident)* _ => $c:expr) => { ok!(); }
1210 fn test_underscore_flavors() {
1213 macro_rules! m1 { ($a:ty) => { ok!(); } }
1216 macro_rules! m2 { ($a:lifetime) => { ok!(); } }
1220 macro_rules! m1 { ($a:ty) => { ok!(); } }
1223 macro_rules! m2 { ($a:lifetime) => { ok!(); } }
1230 fn test_vertical_bar_with_pat() {
1233 macro_rules! m { (|$pat:pat| ) => { ok!(); } }
1237 macro_rules! m { (|$pat:pat| ) => { ok!(); } }
1244 fn test_dollar_crate_lhs_is_not_meta() {
1248 ($crate) => { err!(); };
1255 ($crate) => { err!(); };
1264 fn test_lifetime() {
1268 ($lt:lifetime) => { struct Ref<$lt>{ s: &$ lt str } }
1274 ($lt:lifetime) => { struct Ref<$lt>{ s: &$ lt str } }
1288 ($type:ty, $lit:literal) => { const VALUE: $type = $ lit; };
1294 ($type:ty, $lit:literal) => { const VALUE: $type = $ lit; };
1296 const VALUE: u8 = 0;
1303 ($type:ty, $lit:literal) => { const VALUE: $ type = $ lit; };
1309 ($type:ty, $lit:literal) => { const VALUE: $ type = $ lit; };
1311 const VALUE: i32 = -1;
1317 fn test_boolean_is_ident() {
1321 ($lit0:literal, $lit1:literal) => { const VALUE: (bool, bool) = ($lit0, $lit1); };
1327 ($lit0:literal, $lit1:literal) => { const VALUE: (bool, bool) = ($lit0, $lit1); };
1329 const VALUE: (bool, bool) = (true , false );
1339 ($vis:vis $name:ident) => { $vis fn $name() {} }
1346 ($vis:vis $name:ident) => { $vis fn $name() {} }
1355 fn test_inner_macro_rules() {
1359 ($a:ident, $b:ident, $c:tt) => {
1360 macro_rules! inner {
1361 ($bi:ident) => { fn $bi() -> u8 { $c } }
1365 fn $b() -> u8 { $c }
1372 ($a:ident, $b:ident, $c:tt) => {
1373 macro_rules! inner {
1374 ($bi:ident) => { fn $bi() -> u8 { $c } }
1378 fn $b() -> u8 { $c }
1381 macro_rules !inner {
1397 fn test_expr_after_path_colons() {
1401 ($k:expr) => { fn f() { K::$k; } }
1408 ($k:expr) => { fn f() { K::$k; } }
1410 /* parse error: expected identifier */
1411 /* parse error: expected SEMICOLON */
1412 /* parse error: expected SEMICOLON */
1413 /* parse error: expected expression */
1417 // MACRO_ITEMS@0..19
1432 // PATH_SEGMENT@6..7
1437 // L_PAREN@9..10 "("
1442 // PATH_SEGMENT@10..11
1446 // L_PAREN@11..12 "("
1448 // STRING@12..15 "\"0\""
1449 // R_PAREN@15..16 ")"
1451 // R_PAREN@16..17 ")"
1452 // SEMICOLON@17..18 ";"
1453 // R_CURLY@18..19 "}"
1460 fn test_match_is_not_greedy() {
1464 ($($i:ident $(,)*),*) => {};
1470 ($($i:ident $(,)*),*) => {};
1478 fn expr_interpolation() {
1481 macro_rules! m { ($expr:expr) => { map($expr) } }
1483 let _ = m!(x + foo);
1487 macro_rules! m { ($expr:expr) => { map($expr) } }
1489 let _ = map((x+foo));
1496 fn mbe_are_not_attributes() {
1499 macro_rules! error {
1507 macro_rules! error {