17
17
18
18
use middle:: ty;
19
19
use middle:: typeck;
20
+ use middle:: privacy;
21
+ use middle:: resolve;
20
22
21
23
use std:: hashmap:: HashSet ;
22
24
use syntax:: ast:: * ;
23
25
use syntax:: ast_map;
24
- use syntax:: ast_util:: def_id_of_def;
26
+ use syntax:: ast_util:: { def_id_of_def, is_local } ;
25
27
use syntax:: attr;
26
28
use syntax:: parse:: token;
27
29
use syntax:: visit:: Visitor ;
@@ -71,15 +73,6 @@ fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
71
73
}
72
74
}
73
75
74
- // The context we're in. If we're in a public context, then public symbols are
75
- // marked reachable. If we're in a private context, then only trait
76
- // implementations are marked reachable.
77
- #[ deriving( Clone , Eq ) ]
78
- enum PrivacyContext {
79
- PublicContext ,
80
- PrivateContext ,
81
- }
82
-
83
76
// Information needed while computing reachability.
84
77
struct ReachableContext {
85
78
// The type context.
@@ -92,108 +85,8 @@ struct ReachableContext {
92
85
// A worklist of item IDs. Each item ID in this worklist will be inlined
93
86
// and will be scanned for further references.
94
87
worklist : @mut ~[ NodeId ] ,
95
- }
96
-
97
- struct ReachableVisitor {
98
- reachable_symbols : @mut HashSet < NodeId > ,
99
- worklist : @mut ~[ NodeId ] ,
100
- }
101
-
102
- impl Visitor < PrivacyContext > for ReachableVisitor {
103
-
104
- fn visit_item ( & mut self , item: @item, privacy_context : PrivacyContext ) {
105
-
106
- match item. node {
107
- item_fn( * ) => {
108
- if privacy_context == PublicContext {
109
- self . reachable_symbols . insert ( item. id ) ;
110
- }
111
- if item_might_be_inlined ( item) {
112
- self . worklist . push ( item. id )
113
- }
114
- }
115
- item_struct( ref struct_def, _) => {
116
- match struct_def. ctor_id {
117
- Some ( ctor_id) if
118
- privacy_context == PublicContext => {
119
- self . reachable_symbols . insert ( ctor_id) ;
120
- }
121
- Some ( _) | None => { }
122
- }
123
- }
124
- item_enum( ref enum_def, _) => {
125
- if privacy_context == PublicContext {
126
- for variant in enum_def. variants . iter ( ) {
127
- self . reachable_symbols . insert ( variant. node . id ) ;
128
- }
129
- }
130
- }
131
- item_impl( ref generics, ref trait_ref, _, ref methods) => {
132
- // XXX(pcwalton): We conservatively assume any methods
133
- // on a trait implementation are reachable, when this
134
- // is not the case. We could be more precise by only
135
- // treating implementations of reachable or cross-
136
- // crate traits as reachable.
137
-
138
- let should_be_considered_public = |method : @method | {
139
- ( method. vis == public &&
140
- privacy_context == PublicContext ) ||
141
- trait_ref. is_some ( )
142
- } ;
143
-
144
- // Mark all public methods as reachable.
145
- for & method in methods. iter ( ) {
146
- if should_be_considered_public ( method) {
147
- self . reachable_symbols . insert ( method. id ) ;
148
- }
149
- }
150
-
151
- if generics_require_inlining ( generics) {
152
- // If the impl itself has generics, add all public
153
- // symbols to the worklist.
154
- for & method in methods. iter ( ) {
155
- if should_be_considered_public ( method) {
156
- self . worklist . push ( method. id )
157
- }
158
- }
159
- } else {
160
- // Otherwise, add only public methods that have
161
- // generics to the worklist.
162
- for method in methods. iter ( ) {
163
- let generics = & method. generics ;
164
- let attrs = & method. attrs ;
165
- if generics_require_inlining ( generics) ||
166
- attributes_specify_inlining ( * attrs) ||
167
- should_be_considered_public ( * method) {
168
- self . worklist . push ( method. id )
169
- }
170
- }
171
- }
172
- }
173
- item_trait( _, _, ref trait_methods) => {
174
- // Mark all provided methods as reachable.
175
- if privacy_context == PublicContext {
176
- for trait_method in trait_methods. iter ( ) {
177
- match * trait_method {
178
- provided( method) => {
179
- self . reachable_symbols . insert ( method. id ) ;
180
- self . worklist . push ( method. id )
181
- }
182
- required( _) => { }
183
- }
184
- }
185
- }
186
- }
187
- _ => { }
188
- }
189
-
190
- if item. vis == public && privacy_context == PublicContext {
191
- visit:: walk_item ( self , item, PublicContext )
192
- } else {
193
- visit:: walk_item ( self , item, PrivateContext )
194
- }
195
- }
196
-
88
+ // Known reexports of modules
89
+ exp_map2 : resolve:: ExportMap2 ,
197
90
}
198
91
199
92
struct MarkSymbolVisitor {
@@ -256,31 +149,17 @@ impl Visitor<()> for MarkSymbolVisitor {
256
149
257
150
impl ReachableContext {
258
151
// Creates a new reachability computation context.
259
- fn new ( tcx : ty:: ctxt , method_map : typeck:: method_map )
260
- -> ReachableContext {
152
+ fn new ( tcx : ty:: ctxt , method_map : typeck:: method_map ,
153
+ exp_map2 : resolve :: ExportMap2 ) -> ReachableContext {
261
154
ReachableContext {
262
155
tcx : tcx,
263
156
method_map : method_map,
264
157
reachable_symbols : @mut HashSet :: new ( ) ,
265
158
worklist : @mut ~[ ] ,
159
+ exp_map2 : exp_map2,
266
160
}
267
161
}
268
162
269
- // Step 1: Mark all public symbols, and add all public symbols that might
270
- // be inlined to a worklist.
271
- fn mark_public_symbols ( & self , crate : & Crate ) {
272
- let reachable_symbols = self . reachable_symbols ;
273
- let worklist = self . worklist ;
274
-
275
- let mut visitor = ReachableVisitor {
276
- reachable_symbols : reachable_symbols,
277
- worklist : worklist,
278
- } ;
279
-
280
-
281
- visit:: walk_crate ( & mut visitor, crate , PublicContext ) ;
282
- }
283
-
284
163
// Returns true if the given def ID represents a local item that is
285
164
// eligible for inlining and false otherwise.
286
165
fn def_id_represents_local_inlined_item ( tcx : ty:: ctxt , def_id : DefId )
@@ -352,6 +231,19 @@ impl ReachableContext {
352
231
}
353
232
}
354
233
234
+ fn propagate_mod ( & self , id : NodeId ) {
235
+ match self . exp_map2 . find ( & id) {
236
+ Some ( l) => {
237
+ for reexport in l. iter ( ) {
238
+ if reexport. reexport && is_local ( reexport. def_id ) {
239
+ self . worklist . push ( reexport. def_id . node ) ;
240
+ }
241
+ }
242
+ }
243
+ None => { }
244
+ }
245
+ }
246
+
355
247
// Step 2: Mark all symbols that the symbols on the worklist touch.
356
248
fn propagate ( & self ) {
357
249
let mut visitor = self . init_visitor ( ) ;
@@ -373,6 +265,18 @@ impl ReachableContext {
373
265
item_fn( _, _, _, _, ref search_block) => {
374
266
visit:: walk_block ( & mut visitor, search_block, ( ) )
375
267
}
268
+ // Our recursion into modules involves looking up their
269
+ // public reexports and the destinations of those
270
+ // exports. Privacy will put them in the worklist, but
271
+ // we won't find them in the ast_map, so this is where
272
+ // we deal with publicly re-exported items instead.
273
+ item_mod( * ) => { self . propagate_mod ( item. id ) ; }
274
+ // These are normal, nothing reachable about these
275
+ // inherently and their children are already in the
276
+ // worklist
277
+ item_struct( * ) | item_impl( * ) | item_static( * ) |
278
+ item_enum( * ) | item_ty( * ) | item_trait( * ) |
279
+ item_foreign_mod( * ) => { }
376
280
_ => {
377
281
self . tcx . sess . span_bug ( item. span ,
378
282
"found non-function item \
@@ -382,10 +286,8 @@ impl ReachableContext {
382
286
}
383
287
Some ( & ast_map:: node_trait_method( trait_method, _, _) ) => {
384
288
match * trait_method {
385
- required( ref ty_method) => {
386
- self . tcx . sess . span_bug ( ty_method. span ,
387
- "found required method in \
388
- worklist?!")
289
+ required( * ) => {
290
+ // Keep going, nothing to get exported
389
291
}
390
292
provided( ref method) => {
391
293
visit:: walk_block ( & mut visitor, & method. body , ( ) )
@@ -395,6 +297,10 @@ impl ReachableContext {
395
297
Some ( & ast_map:: node_method( ref method, _, _) ) => {
396
298
visit:: walk_block ( & mut visitor, & method. body , ( ) )
397
299
}
300
+ // Nothing to recurse on for these
301
+ Some ( & ast_map:: node_foreign_item( * ) ) |
302
+ Some ( & ast_map:: node_variant( * ) ) |
303
+ Some ( & ast_map:: node_struct_ctor( * ) ) => { }
398
304
Some ( _) => {
399
305
let ident_interner = token:: get_ident_interner ( ) ;
400
306
let desc = ast_map:: node_id_to_str ( self . tcx . items ,
@@ -404,6 +310,9 @@ impl ReachableContext {
404
310
worklist: {}",
405
311
desc) )
406
312
}
313
+ None if search_item == CRATE_NODE_ID => {
314
+ self . propagate_mod ( search_item) ;
315
+ }
407
316
None => {
408
317
self . tcx . sess . bug ( format ! ( "found unmapped ID in worklist: \
409
318
{}",
@@ -429,7 +338,8 @@ impl ReachableContext {
429
338
430
339
pub fn find_reachable ( tcx : ty:: ctxt ,
431
340
method_map : typeck:: method_map ,
432
- crate : & Crate )
341
+ exp_map2 : resolve:: ExportMap2 ,
342
+ exported_items : & privacy:: ExportedItems )
433
343
-> @mut HashSet < NodeId > {
434
344
// XXX(pcwalton): We only need to mark symbols that are exported. But this
435
345
// is more complicated than just looking at whether the symbol is `pub`,
@@ -442,11 +352,13 @@ pub fn find_reachable(tcx: ty::ctxt,
442
352
// is to have the name resolution pass mark all targets of a `pub use` as
443
353
// "must be reachable".
444
354
445
- let reachable_context = ReachableContext :: new ( tcx, method_map) ;
355
+ let reachable_context = ReachableContext :: new ( tcx, method_map, exp_map2 ) ;
446
356
447
- // Step 1: Mark all public symbols, and add all public symbols that might
448
- // be inlined to a worklist.
449
- reachable_context. mark_public_symbols ( crate ) ;
357
+ // Step 1: Seed the worklist with all nodes which were found to be public as
358
+ // a result of the privacy pass
359
+ for & id in exported_items. iter ( ) {
360
+ reachable_context. worklist . push ( id) ;
361
+ }
450
362
451
363
// Step 2: Mark all symbols that the symbols on the worklist touch.
452
364
reachable_context. propagate ( ) ;
0 commit comments