1717
1818use middle:: ty;
1919use middle:: typeck;
20+ use middle:: privacy;
21+ use middle:: resolve;
2022
2123use std:: hashmap:: HashSet ;
2224use syntax:: ast:: * ;
2325use syntax:: ast_map;
24- use syntax:: ast_util:: def_id_of_def;
26+ use syntax:: ast_util:: { def_id_of_def, is_local } ;
2527use syntax:: attr;
2628use syntax:: parse:: token;
2729use syntax:: visit:: Visitor ;
@@ -71,15 +73,6 @@ fn trait_method_might_be_inlined(trait_method: &trait_method) -> bool {
7173 }
7274}
7375
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-
8376// Information needed while computing reachability.
8477struct ReachableContext {
8578 // The type context.
@@ -92,108 +85,8 @@ struct ReachableContext {
9285 // A worklist of item IDs. Each item ID in this worklist will be inlined
9386 // and will be scanned for further references.
9487 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 ,
19790}
19891
19992struct MarkSymbolVisitor {
@@ -256,31 +149,17 @@ impl Visitor<()> for MarkSymbolVisitor {
256149
257150impl ReachableContext {
258151 // 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 {
261154 ReachableContext {
262155 tcx : tcx,
263156 method_map : method_map,
264157 reachable_symbols : @mut HashSet :: new ( ) ,
265158 worklist : @mut ~[ ] ,
159+ exp_map2 : exp_map2,
266160 }
267161 }
268162
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-
284163 // Returns true if the given def ID represents a local item that is
285164 // eligible for inlining and false otherwise.
286165 fn def_id_represents_local_inlined_item ( tcx : ty:: ctxt , def_id : DefId )
@@ -352,6 +231,19 @@ impl ReachableContext {
352231 }
353232 }
354233
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+
355247 // Step 2: Mark all symbols that the symbols on the worklist touch.
356248 fn propagate ( & self ) {
357249 let mut visitor = self . init_visitor ( ) ;
@@ -373,6 +265,18 @@ impl ReachableContext {
373265 item_fn( _, _, _, _, ref search_block) => {
374266 visit:: walk_block ( & mut visitor, search_block, ( ) )
375267 }
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( * ) => { }
376280 _ => {
377281 self . tcx . sess . span_bug ( item. span ,
378282 "found non-function item \
@@ -382,10 +286,8 @@ impl ReachableContext {
382286 }
383287 Some ( & ast_map:: node_trait_method( trait_method, _, _) ) => {
384288 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
389291 }
390292 provided( ref method) => {
391293 visit:: walk_block ( & mut visitor, & method. body , ( ) )
@@ -395,6 +297,10 @@ impl ReachableContext {
395297 Some ( & ast_map:: node_method( ref method, _, _) ) => {
396298 visit:: walk_block ( & mut visitor, & method. body , ( ) )
397299 }
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( * ) ) => { }
398304 Some ( _) => {
399305 let ident_interner = token:: get_ident_interner ( ) ;
400306 let desc = ast_map:: node_id_to_str ( self . tcx . items ,
@@ -404,6 +310,9 @@ impl ReachableContext {
404310 worklist: {}",
405311 desc) )
406312 }
313+ None if search_item == CRATE_NODE_ID => {
314+ self . propagate_mod ( search_item) ;
315+ }
407316 None => {
408317 self . tcx . sess . bug ( format ! ( "found unmapped ID in worklist: \
409318 {}",
@@ -429,7 +338,8 @@ impl ReachableContext {
429338
430339pub fn find_reachable ( tcx : ty:: ctxt ,
431340 method_map : typeck:: method_map ,
432- crate : & Crate )
341+ exp_map2 : resolve:: ExportMap2 ,
342+ exported_items : & privacy:: ExportedItems )
433343 -> @mut HashSet < NodeId > {
434344 // XXX(pcwalton): We only need to mark symbols that are exported. But this
435345 // is more complicated than just looking at whether the symbol is `pub`,
@@ -442,11 +352,13 @@ pub fn find_reachable(tcx: ty::ctxt,
442352 // is to have the name resolution pass mark all targets of a `pub use` as
443353 // "must be reachable".
444354
445- let reachable_context = ReachableContext :: new ( tcx, method_map) ;
355+ let reachable_context = ReachableContext :: new ( tcx, method_map, exp_map2 ) ;
446356
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+ }
450362
451363 // Step 2: Mark all symbols that the symbols on the worklist touch.
452364 reachable_context. propagate ( ) ;
0 commit comments