@@ -41,6 +41,7 @@ trait MacroGenerable: Sized {
41
41
42
42
// Fold this node or list of nodes using the given folder.
43
43
fn fold_with < F : Folder > ( self , folder : & mut F ) -> Self ;
44
+ fn visit_with < ' v , V : Visitor < ' v > > ( & ' v self , visitor : & mut V ) ;
44
45
45
46
// Return a placeholder expansion to allow compilation to continue after an erroring expansion.
46
47
fn dummy ( span : Span ) -> Self ;
@@ -50,7 +51,9 @@ trait MacroGenerable: Sized {
50
51
}
51
52
52
53
macro_rules! impl_macro_generable {
53
- ( $( $ty: ty: $kind_name: expr, . $make: ident, $( . $fold: ident) * $( lift . $fold_elt: ident) * ,
54
+ ( $( $ty: ty: $kind_name: expr, . $make: ident,
55
+ $( . $fold: ident) * $( lift . $fold_elt: ident) * ,
56
+ $( . $visit: ident) * $( lift . $visit_elt: ident) * ,
54
57
|$span: ident| $dummy: expr; ) * ) => { $(
55
58
impl MacroGenerable for $ty {
56
59
fn kind_name( ) -> & ' static str { $kind_name }
@@ -59,21 +62,27 @@ macro_rules! impl_macro_generable {
59
62
$( folder. $fold( self ) ) *
60
63
$( self . into_iter( ) . flat_map( |item| folder. $fold_elt ( item) ) . collect( ) ) *
61
64
}
65
+ fn visit_with<' v, V : Visitor <' v>>( & ' v self , visitor: & mut V ) {
66
+ $( visitor. $visit( self ) ) *
67
+ $( for item in self . as_slice( ) { visitor. $visit_elt ( item) } ) *
68
+ }
62
69
fn dummy( $span: Span ) -> Self { $dummy }
63
70
}
64
71
) * }
65
72
}
66
73
67
74
impl_macro_generable ! {
68
- P <ast:: Expr >: "expression" , . make_expr, . fold_expr, |span| DummyResult :: raw_expr( span) ;
69
- P <ast:: Pat >: "pattern" , . make_pat, . fold_pat, |span| P ( DummyResult :: raw_pat( span) ) ;
70
- P <ast:: Ty >: "type" , . make_ty, . fold_ty, |span| DummyResult :: raw_ty( span) ;
71
- SmallVector <ast:: ImplItem >:
72
- "impl item" , . make_impl_items, lift . fold_impl_item, |_span| SmallVector :: zero( ) ;
73
- SmallVector <P <ast:: Item >>:
74
- "item" , . make_items, lift . fold_item, |_span| SmallVector :: zero( ) ;
75
+ P <ast:: Pat >: "pattern" , . make_pat, . fold_pat, . visit_pat, |span| P ( DummyResult :: raw_pat( span) ) ;
76
+ P <ast:: Ty >: "type" , . make_ty, . fold_ty, . visit_ty, |span| DummyResult :: raw_ty( span) ;
77
+ P <ast:: Expr >:
78
+ "expression" , . make_expr, . fold_expr, . visit_expr, |span| DummyResult :: raw_expr( span) ;
75
79
SmallVector <ast:: Stmt >:
76
- "statement" , . make_stmts, lift . fold_stmt, |_span| SmallVector :: zero( ) ;
80
+ "statement" , . make_stmts, lift . fold_stmt, lift . visit_stmt, |_span| SmallVector :: zero( ) ;
81
+ SmallVector <P <ast:: Item >>:
82
+ "item" , . make_items, lift . fold_item, lift . visit_item, |_span| SmallVector :: zero( ) ;
83
+ SmallVector <ast:: ImplItem >:
84
+ "impl item" , . make_impl_items, lift . fold_impl_item, lift . visit_impl_item,
85
+ |_span| SmallVector :: zero( ) ;
77
86
}
78
87
79
88
impl MacroGenerable for Option < P < ast:: Expr > > {
@@ -85,6 +94,9 @@ impl MacroGenerable for Option<P<ast::Expr>> {
85
94
fn fold_with < F : Folder > ( self , folder : & mut F ) -> Self {
86
95
self . and_then ( |expr| folder. fold_opt_expr ( expr) )
87
96
}
97
+ fn visit_with < ' v , V : Visitor < ' v > > ( & ' v self , visitor : & mut V ) {
98
+ self . as_ref ( ) . map ( |expr| visitor. visit_expr ( expr) ) ;
99
+ }
88
100
}
89
101
90
102
pub fn expand_expr ( expr : ast:: Expr , fld : & mut MacroExpander ) -> P < ast:: Expr > {
@@ -320,6 +332,7 @@ fn expand_mac_invoc<T>(mac: ast::Mac, ident: Option<Ident>, attrs: Vec<ast::Attr
320
332
321
333
let marked = expanded. fold_with ( & mut Marker { mark : mark, expn_id : Some ( fld. cx . backtrace ( ) ) } ) ;
322
334
let configured = marked. fold_with ( & mut fld. strip_unconfigured ( ) ) ;
335
+ fld. load_macros ( & configured) ;
323
336
let fully_expanded = configured. fold_with ( fld) ;
324
337
fld. cx . bt_pop ( ) ;
325
338
fully_expanded
@@ -742,15 +755,6 @@ fn expand_annotatable(a: Annotatable,
742
755
}
743
756
result
744
757
} ,
745
- ast:: ItemKind :: ExternCrate ( _) => {
746
- // We need to error on `#[macro_use] extern crate` when it isn't at the
747
- // crate root, because `$crate` won't work properly.
748
- let allows_macros = fld. cx . syntax_env . is_crate_root ( ) ;
749
- for def in fld. cx . loader . load_crate ( & it, allows_macros) {
750
- fld. cx . insert_macro ( def) ;
751
- }
752
- SmallVector :: one ( it)
753
- } ,
754
758
_ => noop_fold_item ( it, fld) ,
755
759
} . into_iter ( ) . map ( |i| Annotatable :: Item ( i) ) . collect ( ) ,
756
760
@@ -999,6 +1003,40 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
999
1003
& self . cx . parse_sess . span_diagnostic ,
1000
1004
self . cx . feature_gated_cfgs )
1001
1005
}
1006
+
1007
+ fn load_macros < T : MacroGenerable > ( & mut self , node : & T ) {
1008
+ struct MacroLoadingVisitor < ' a , ' b : ' a > {
1009
+ cx : & ' a mut ExtCtxt < ' b > ,
1010
+ at_crate_root : bool ,
1011
+ }
1012
+
1013
+ impl < ' a , ' b , ' v > Visitor < ' v > for MacroLoadingVisitor < ' a , ' b > {
1014
+ fn visit_mac ( & mut self , _: & ' v ast:: Mac ) { }
1015
+ fn visit_item ( & mut self , item : & ' v ast:: Item ) {
1016
+ if let ast:: ItemKind :: ExternCrate ( ..) = item. node {
1017
+ // We need to error on `#[macro_use] extern crate` when it isn't at the
1018
+ // crate root, because `$crate` won't work properly.
1019
+ for def in self . cx . loader . load_crate ( item, self . at_crate_root ) {
1020
+ self . cx . insert_macro ( def) ;
1021
+ }
1022
+ } else {
1023
+ let at_crate_root = :: std:: mem:: replace ( & mut self . at_crate_root , false ) ;
1024
+ visit:: walk_item ( self , item) ;
1025
+ self . at_crate_root = at_crate_root;
1026
+ }
1027
+ }
1028
+ fn visit_block ( & mut self , block : & ' v ast:: Block ) {
1029
+ let at_crate_root = :: std:: mem:: replace ( & mut self . at_crate_root , false ) ;
1030
+ visit:: walk_block ( self , block) ;
1031
+ self . at_crate_root = at_crate_root;
1032
+ }
1033
+ }
1034
+
1035
+ node. visit_with ( & mut MacroLoadingVisitor {
1036
+ at_crate_root : self . cx . syntax_env . is_crate_root ( ) ,
1037
+ cx : self . cx ,
1038
+ } ) ;
1039
+ }
1002
1040
}
1003
1041
1004
1042
impl < ' a , ' b > Folder for MacroExpander < ' a , ' b > {
@@ -1142,7 +1180,7 @@ impl<'feat> ExpansionConfig<'feat> {
1142
1180
1143
1181
pub fn expand_crate ( mut cx : ExtCtxt ,
1144
1182
user_exts : Vec < NamedSyntaxExtension > ,
1145
- c : Crate ) -> ( Crate , HashSet < Name > ) {
1183
+ mut c : Crate ) -> ( Crate , HashSet < Name > ) {
1146
1184
if std_inject:: no_core ( & c) {
1147
1185
cx. crate_root = None ;
1148
1186
} else if std_inject:: no_std ( & c) {
@@ -1157,6 +1195,10 @@ pub fn expand_crate(mut cx: ExtCtxt,
1157
1195
expander. cx . syntax_env . insert ( name, extension) ;
1158
1196
}
1159
1197
1198
+ let items = SmallVector :: many ( c. module . items ) ;
1199
+ expander. load_macros ( & items) ;
1200
+ c. module . items = items. into ( ) ;
1201
+
1160
1202
let err_count = cx. parse_sess . span_diagnostic . err_count ( ) ;
1161
1203
let mut ret = expander. fold_crate ( c) ;
1162
1204
ret. exported_macros = expander. cx . exported_macros . clone ( ) ;
0 commit comments